Tmp
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt
index b0c8e67..a45deaf 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LazyTopDownAnalyzer.kt
@@ -52,9 +52,14 @@
     private val classifierUsageCheckers: Iterable<ClassifierUsageChecker>
 ) {
     fun analyzeDeclarations(
-        topDownAnalysisMode: TopDownAnalysisMode,
-        declarations: Collection<PsiElement>,
-        outerDataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY
+            topDownAnalysisMode: TopDownAnalysisMode,
+            declarations: Collection<PsiElement>,
+            /**
+             * DFA
+             *
+             * This parameter is actually used in LocalClassifierAnalyzer
+             */
+            outerDataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY
     ): TopDownAnalysisContext {
         val c = TopDownAnalysisContext(topDownAnalysisMode, outerDataFlowInfo, declarationScopeProvider)
 
@@ -198,6 +203,15 @@
             declaration.accept(visitor)
         }
 
+        /**
+         * DFA
+         *
+         * Here we need DFI because we may have to resolve function body
+         * And if it is local function, then DFI matters
+         * And it *can* be local function, because LocalClassifierAnalyzer re-uses LazyTopDownAnalyzer
+         *
+         * Same for properties ofc
+         */
         createFunctionDescriptors(c, functions)
 
         createPropertyDescriptors(c, topLevelFqNames, properties)
@@ -219,6 +233,9 @@
 
         overloadResolver.checkOverloads(c)
 
+        /**
+         * DFA
+         */
         bodyResolver.resolveBodies(c)
 
         resolveImportsInAllFiles(c)
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt
index b8aa75f..18a1b74 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt
@@ -370,28 +370,41 @@
                 if (type == null || (type.isError && !type.isFunctionPlaceholder)) {
                     matchStatus = ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE
                 } else if (!noExpectedType(expectedType)) {
+                    // argument has expected type
                     if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
+                        // and we have raw type mismatch. But wait, maybe we can get a smartcast!
                         val smartCast = smartCastValueArgumentTypeIfPossible(expression, newContext.expectedType, type, newContext)
                         if (smartCast == null) {
+                            // No smartcast too :(
+                            // It's already mismatch for sure, but let's check if we're passing nullable argument to non-nullable
+                            // parameter to provide better diagnostic
                             resultStatus = tryNotNullableArgument(type, expectedType) ?: OTHER_ERROR
                             matchStatus = ArgumentMatchStatus.TYPE_MISMATCH
                         } else {
+                            // Nice, we got smartcast, lets use it
                             resultingType = smartCast
                         }
                     } else if (ErrorUtils.containsUninferredParameter(expectedType)) {
+                        // Nice, type of argument is subtype of expected type
+                        // However, ArgumentTypeResolver.isSubtypeOfForArgumentType could return true if some types were
+                        // not inferred. Let's check this and if there are some, use appropriate match status
                         matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES
                     }
 
                     val spreadElement = argument.getSpreadElement()
                     if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
+                        // Oh shi~, we're using spread on the nullable argument. Usually this is forbidden,
+                        // but what if we have a smartcast around...
                         val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context)
                         val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
                             dataFlowValue, expectedType, expression, context,
                             call = null, recordExpressionType = false
                         )
                         if (smartCastResult == null || !smartCastResult.isCorrect) {
+                            // Nope, we don't, so report error
                             context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement))
                         }
+                        // Otherwise, we do have suitable smartcast, so everything is OK
                     }
                 }
                 argumentTypes.add(resultingType)
@@ -511,8 +524,13 @@
         val safeAccess = isExplicitReceiver && !implicitInvokeCheck && call.isSemanticallyEquivalentToSafeCall
         val expectedReceiverParameterType = if (safeAccess) TypeUtils.makeNullable(receiverParameter.type) else receiverParameter.type
 
+        // Inside getSmartCastReceiverResult:
+        // 1. Create DFV from receiverArgument
+        // 2. Pull DFI from context
+        // 3. Ask DFI about .getCollectedTypes()
         val smartCastSubtypingResult = smartCastManager.getSmartCastReceiverResult(receiverArgument, expectedReceiverParameterType, this)
         if (smartCastSubtypingResult == null) {
+            // Ok, we can't smartcast, give up
             tracing.wrongReceiverType(
                 trace, receiverParameter, receiverArgument,
                 this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall))
@@ -520,9 +538,12 @@
             return OTHER_ERROR
         }
 
+        // Here we have smartcast: either to type or to right nullability
+
         val notNullReceiverExpected = smartCastSubtypingResult != SmartCastManager.ReceiverSmartCastResult.OK
         val smartCastNeeded =
-            notNullReceiverExpected || !isCandidateVisibleOrExtensionReceiver(receiverArgument, null, isDispatchReceiver)
+                // TODO: Ask how the extension receiver is related here
+                notNullReceiverExpected || !isCandidateVisibleOrExtensionReceiver(receiverArgument, null, isDispatchReceiver)
         var reportUnsafeCall = false
 
         var nullableImplicitInvokeReceiver = false
@@ -539,19 +560,26 @@
             }
         }
 
+        // Again traverse all DataFlowInfo
         val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, this)
         val nullability = dataFlowInfo.getStableNullability(dataFlowValue)
+
         val expression = (receiverArgument as? ExpressionReceiver)?.expression
-        if (nullability.canBeNull() && !nullability.canBeNonNull()) {
+        if (nullability.canBeNull() && !nullability.canBeNonNull()) { // I.e. receiver is definitely null
             if (!TypeUtils.isNullableType(expectedReceiverParameterType)) {
                 reportUnsafeCall = true
             }
+
+            // This 'if' can be false for 'Nothing?' (i.e. for 'null' constant)
             if (dataFlowValue.immanentNullability.canBeNonNull()) {
                 expression?.let { trace.record(BindingContext.SMARTCAST_NULL, it) }
             }
         } else if (!nullableImplicitInvokeReceiver && smartCastNeeded) {
+            // !nullability.canBeNull() || nullability.canBeNotNull() <=> canBeNotNull
             // Look if smart cast has some useful nullability info
 
+            // Why the hell we go and ask for smartcasts second time? We've already asked above
+            // Reminder: dataFlowValue was manually created from receiverArgument
             val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
                 dataFlowValue, expectedReceiverParameterType,
                 { possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) },
@@ -559,10 +587,13 @@
             )
 
             if (smartCastResult == null) {
+                // Sigh, no smartcast
                 if (notNullReceiverExpected) {
+                    // But dude, we wanted not null! This is unsafe, bruh
                     reportUnsafeCall = true
                 }
             } else {
+                // Ok we have some smartcast
                 if (isDispatchReceiver) {
                     candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType)
                 } else {
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.kt
index 22a32a1..385e788 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.kt
@@ -70,6 +70,34 @@
     }
 
     @JvmStatic
+    /*
+    1. [Special case] 'null', 'Nothing?': special DFV
+    2. [Special case] error-type: special DFV
+    3. [Special case] '!!': force non-null DFV to prevent issues with generics
+    4. Block, if, when, elvis: stable DFV for complex expression
+    5. Qualified expression:
+            - selector info, when receiver is package or class
+            - NO, when receiver is NO
+            - QualifiedInfo otherwise. Stability = min(stability of receiver, stability of selector)
+    6. 'is', 'as': NO
+    7. 'as?': SafeCastInfo. stability <=> stability of subject
+    8. '++', '--': PostfixInfo. stability <=> stability of argument
+    9. 'this': Receiver(target)
+    10. Property.
+        Check if this property is either: 'var', has open or custom getter, declared in other module.
+        If so, then it is unstable.
+        Otherwise it is stable.
+    11. Local variable/function parameter.
+            - 'val': stable value
+            - 'var': generally, unstable, but can be relaxed for some cases
+                - if no one writes in this 'var', then it is considered stable
+                - if inside closure: generally, unstable, but can be relaxed for some cases:
+                    - if all writers are reliably "before" closured access, then considered stable
+                - if not inside closure, but has closure writers: generally, unstable, but can be relaxed for some cases:
+                    - if all closure writers are provably "after" access, then considered stable
+        NB. Also consider implicit receivers, and create QualifiedInfo, if it is present
+
+     */
     fun createDataFlowValue(
         expression: KtExpression,
         type: KotlinType,
@@ -92,6 +120,8 @@
             //
             // But there are some problem with types built on type parameters, e.g.
             // fun <T : Any?> foo(x: T) = x!!.hashCode() // there no way in type system to denote that `x!!` is not nullable
+            //
+            // This is closely connected with 'immanentlyNotNull' checks in the second part of 'SmartCastManager.checkAndRecordPossibleCast()'
             return DataFlowValue(
                 ExpressionIdentifierInfo(expression),
                 type,
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt
index 42988fc..926a4e5 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt
@@ -102,8 +102,7 @@
         }
 
         val identifierInfo = value.identifierInfo
-        if (affectReceiver && !nullability.canBeNull() &&
-            languageVersionSettings.supportsFeature(LanguageFeature.SafeCallBoundSmartCasts)) {
+        if (affectReceiver && !nullability.canBeNull() && languageVersionSettings.supportsFeature(LanguageFeature.SafeCallBoundSmartCasts)) {
             when (identifierInfo) {
                 is IdentifierInfo.Qualified -> {
                     val receiverType = identifierInfo.receiverType
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt
index 2419a68..b4b2913 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt
+++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt
@@ -82,18 +82,27 @@
         return dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings)
     }
 
+    // Checks if `receiverArgument` can be cast to `receiverParameterType` with smartcasts taken into consideration
     fun getSmartCastReceiverResult(
         receiverArgument: ReceiverValue,
         receiverParameterType: KotlinType,
         context: ResolutionContext<*>
     ): ReceiverSmartCastResult? {
+        // Ok, let's just check if some cast is known with exact types
         getSmartCastReceiverResultWithGivenNullability(receiverArgument, receiverParameterType, context)?.let {
+            // We have some cast with exact type
+            // Noe that it also returns for plain subtypes
             return it
         }
 
+        // No luck here, but maybe we can find suitable cast for nullable reciever?
         val nullableParameterType = TypeUtils.makeNullable(receiverParameterType)
+
         return when {
+        // Still no luck, return 'null'
             getSmartCastReceiverResultWithGivenNullability(receiverArgument, nullableParameterType, context) == null -> null
+
+        // Found cast, but note that we've expanded nullability, so no matters what we've found, it's still "NOT_NULL_EXPECTED"
             else -> ReceiverSmartCastResult.SMARTCAST_NEEDED_OR_NOT_NULL_EXPECTED
         }
     }
@@ -115,6 +124,7 @@
 
     enum class ReceiverSmartCastResult {
         OK,
+        // Fun fact -- it is used only in SmartCastManager
         SMARTCAST_NEEDED_OR_NOT_NULL_EXPECTED
     }
 
@@ -130,14 +140,21 @@
         ) {
             if (KotlinBuiltIns.isNullableNothing(type)) return
             if (dataFlowValue.isStable) {
+                // Smartcast is possible, lets try to do this!
+
                 val oldSmartCasts = trace[SMARTCAST, expression]
                 val newSmartCast = SingleSmartCast(call, type)
                 if (oldSmartCasts != null) {
+                    // There already was some smartcast on that expression
+
+                    // Let's check if this SMARTCAST slice (for the same expression!) already contains cast for this particular 'call'
                     val oldType = oldSmartCasts.type(call)
                     if (oldType != null && oldType != type) {
+                        // Oops, this slice already contains smartcast for this particular 'call'
                         throw AssertionError("Rewriting key $call for smart cast on ${expression.text}")
                     }
                 }
+                // Ok, either there was no SMARTCAST slice at all for this 'expression', or it didn't contain a cast for this particular call
                 trace.record(SMARTCAST, expression, oldSmartCasts?.let { it + newSmartCast } ?: newSmartCast)
                 if (recordExpressionType) {
                     //TODO
@@ -145,6 +162,7 @@
                     trace.recordType(expression, type)
                 }
             } else {
+                // Unstable data
                 trace.report(SMARTCAST_IMPOSSIBLE.on(expression, type, expression.text, dataFlowValue.kind.description))
             }
         }
@@ -160,6 +178,16 @@
             return checkAndRecordPossibleCast(dataFlowValue, expectedType, null, expression, c, call, recordExpressionType)
         }
 
+        /*
+        Semantics of this method:
+        1. Take 'dataFlowValue'
+        2. Pull 'dataFlowInfo' from 'c' and get all types for that 'dataFlowValue'
+        3. If some of that types matches 'expectedType' and 'additionalPredicate' (if any), then record smartcast/error (i.e. diagnostic) with stability taken into consideration
+           (can also involve some additional hoops for implicit receiver)
+
+        IF NO TYPES WERE MATCHED ON PREVIOUS STEP, THEN:
+        4.
+         */
         fun checkAndRecordPossibleCast(
             dataFlowValue: DataFlowValue,
             expectedType: KotlinType,
@@ -171,14 +199,24 @@
         ): SmartCastResult? {
             val calleeExpression = call?.calleeExpression
             for (possibleType in c.dataFlowInfo.getCollectedTypes(dataFlowValue, c.languageVersionSettings)) {
+                // Check another type from smartcast
                 if (ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType) &&
                     (additionalPredicate == null || additionalPredicate(possibleType))
                 ) {
+                    // This type suits us!
                     if (expression != null) {
+                        // records cast if DFV is stable (with rewrite checks) OR records SMARTCAST_IMPOSSIBLE if DFV is unstable
                         recordCastOrError(expression, possibleType, c.trace, dataFlowValue, call, recordExpressionType)
                     } else if (calleeExpression != null && dataFlowValue.isStable) {
+                        // This is the case when we have implicit receiver (e.g. in cases like 'with(a) { if (this is String) ... }'
+                        // or in the body of extension function)
+                        //
+                        // Here we have to invent additional diagnostic on call itself
                         val receiver = (dataFlowValue.identifierInfo as? IdentifierInfo.Receiver)?.value
                         if (receiver is ImplicitReceiver) {
+                            // This is the case #2
+
+                            // dat logic duplication tho (see above)
                             val oldSmartCasts = c.trace[IMPLICIT_RECEIVER_SMARTCAST, calleeExpression]
                             val newSmartCasts = ImplicitSmartCasts(receiver, possibleType)
                             if (oldSmartCasts != null) {
@@ -192,14 +230,17 @@
                             }
                             c.trace.record(IMPLICIT_RECEIVER_SMARTCAST, calleeExpression,
                                            oldSmartCasts?.let { it + newSmartCasts } ?: newSmartCasts)
-
                         }
                     }
+
+                    // ...but who the fuck is going to report this smartcast? :(
                     return SmartCastResult(possibleType, dataFlowValue.isStable)
                 }
             }
 
             if (!c.dataFlowInfo.getCollectedNullability(dataFlowValue).canBeNull() && !expectedType.isMarkedNullable) {
+                // Ok, this value can't be null, and we expect not-null
+
                 // Handling cases like:
                 // fun bar(x: Any) {}
                 // fun <T : Any?> foo(x: T) {
@@ -208,23 +249,45 @@
                 //      }
                 // }
                 //
-                // It doesn't handled by lower code with getPossibleTypes because smart cast of T after `x != null` is still has same type T.
+                // It doesn't handled by upper code with getCollectedTypes because smart cast of T after `x != null` is still has same type T.
                 // But at the same time we're sure that `x` can't be null and just check for such cases manually
 
                 // E.g. in case x!! when x has type of T where T is type parameter with nullable upper bounds
                 // x!! is immanently not null (see DataFlowValueFactory.createDataFlowValue for expression)
+
+
+                // Segment below is much easier to understand if considered without 'immanentlyNotNull' flag
+
+                // Essentially, this is fast path for cases when 'dataFlowValue.type' can be casted to 'expected type'
+                // with the help of smartcasts.
                 val immanentlyNotNull = !dataFlowValue.immanentNullability.canBeNull()
                 val nullableExpectedType = TypeUtils.makeNullable(expectedType)
 
+                // Let's check if types are suitable modulo nullability smartcast
                 if (ArgumentTypeResolver.isSubtypeOfForArgumentType(dataFlowValue.type, nullableExpectedType) &&
                     (additionalPredicate == null || additionalPredicate(dataFlowValue.type))
                 ) {
+                    // Ok, dataFlowValue.type <: expectedType?
+                    // AND
+                    // we know what dataFlowValue can be casted to not-null, and we expect not-null
+                    // =>
+                    // let's record smartcast!
                     if (!immanentlyNotNull && expression != null) {
+                        // Let's record smartcast!
                         recordCastOrError(expression, dataFlowValue.type, c.trace, dataFlowValue, call, recordExpressionType)
                     }
 
                     return SmartCastResult(dataFlowValue.type, immanentlyNotNull || dataFlowValue.isStable)
                 }
+                // Now, why do we even have that 'immanentlyNotNull' flag?
+                // Because it indicates that we're doing '!!'-assertion on generic type with nullable upper bound, which should be
+                // handled separately if it is in call chain (i.e. in cases like 'x!!.foo) because we have no other place to
+                // handle this case (compare that with cases like 'x!!; x.length' - here first statement provides DFI that x != null,
+                // and we already see it in the second statement)
+
+
+                // Ok, so we can't transform 'dataFlowValue' to 'expectedType' via nullability smartcast
+                // We say here: let's try again, but we will try to find cast to the nullable expected type
                 return checkAndRecordPossibleCast(dataFlowValue, nullableExpectedType, expression, c, call, recordExpressionType)
             }
 
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java
index f26cd4b..e978ff5 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java
@@ -173,6 +173,9 @@
         return components.dataFlowAnalyzer.checkType(typeInfo, expression, context); // TODO : Extensions to this
     }
 
+    /*
+    Veeeeeery suspicious
+    */
     @Override
     public KotlinTypeInfo visitParenthesizedExpression(@NotNull KtParenthesizedExpression expression, ExpressionTypingContext context) {
         KtExpression innerExpression = expression.getExpression();
@@ -190,6 +193,10 @@
         return result;
     }
 
+
+    /*
+    Returns the same data-flow info, as in the context
+     */
     @Override
     public KotlinTypeInfo visitConstantExpression(@NotNull KtConstantExpression expression, ExpressionTypingContext context) {
         IElementType elementType = expression.getNode().getElementType();
@@ -293,6 +300,9 @@
         }
     }
 
+    /*
+    Returns the same info + maybe enhances it with "as"-cast info
+     */
     @Override
     public KotlinTypeInfo visitBinaryWithTypeRHSExpression(
             @NotNull KtBinaryExpressionWithTypeRHS expression,
@@ -658,6 +668,9 @@
         return components.doubleColonExpressionResolver.visitClassLiteralExpression(expression, c);
     }
 
+    /*
+    Seems like no extra data-flow hoops, but have to re-check
+     */
     @Override
     public KotlinTypeInfo visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression, ExpressionTypingContext c) {
         return components.doubleColonExpressionResolver.visitCallableReferenceExpression(expression, c);
@@ -819,6 +832,9 @@
                                                      contextWithExpectedType.replaceDataFlowInfo(typeInfo.getDataFlowInfo()));
     }
 
+    /*
+    Practically no non-trivial data-flow manipulations except for casually forcing non-nullability of argument.
+     */
     private KotlinTypeInfo visitExclExclExpression(@NotNull KtUnaryExpression expression, @NotNull ExpressionTypingContext context) {
         KtExpression baseExpression = expression.getBaseExpression();
         assert baseExpression != null;
@@ -847,6 +863,7 @@
         assert baseTypeInfo != null : "Base expression was not processed: " + expression;
         KotlinType baseType = baseTypeInfo.getType();
         if (baseType == null) {
+            // Can get here in case of esoteric red code, like "java.lang.System!!"
             return baseTypeInfo;
         }
         DataFlowInfo dataFlowInfo = baseTypeInfo.getDataFlowInfo();
@@ -1254,6 +1271,8 @@
         KotlinTypeInfo leftTypeInfo = BindingContextUtils.getRecordedTypeInfo(left, context.trace.getBindingContext());
         boolean isLeftFunctionLiteral = ArgumentTypeResolver.isFunctionLiteralArgument(left, context);
         boolean isLeftCallableReference = ArgumentTypeResolver.isCallableReferenceArgument(left, context);
+
+        // Hoops with function literals and callable references
         if (leftTypeInfo == null && (isLeftFunctionLiteral || isLeftCallableReference)) {
             DiagnosticFactory0<PsiElement> diagnosticFactory =
                     isLeftFunctionLiteral ? USELESS_ELVIS_ON_LAMBDA_EXPRESSION : USELESS_ELVIS_ON_CALLABLE_REFERENCE;
@@ -1261,6 +1280,8 @@
             return TypeInfoFactoryKt.noTypeInfo(context);
         }
         assert leftTypeInfo != null : "Left expression was not processed: " + expression;
+
+        // USELESS_ELVIS diagnostics
         KotlinType leftType = leftTypeInfo.getType();
         if (isKnownToBeNotNull(left, leftType, context)) {
             context.trace.report(USELESS_ELVIS.on(expression, leftType));
@@ -1268,45 +1289,60 @@
         else if (KtPsiUtil.isNullConstant(right) && leftType != null && !FlexibleTypesKt.isNullabilityFlexible(leftType)) {
             context.trace.report(USELESS_ELVIS_RIGHT_IS_NULL.on(expression));
         }
+
+        // Hoops with function literals and callable references
         KotlinTypeInfo rightTypeInfo = BindingContextUtils.getRecordedTypeInfo(right, context.trace.getBindingContext());
         if (rightTypeInfo == null && ArgumentTypeResolver.isFunctionLiteralOrCallableReference(right, context)) {
             // the type is computed later in call completer according to the '?:' semantics as a function
             return TypeInfoFactoryKt.noTypeInfo(context);
         }
+
         assert rightTypeInfo != null : "Right expression was not processed: " + expression;
-        boolean loopBreakContinuePossible = leftTypeInfo.getJumpOutPossible() || rightTypeInfo.getJumpOutPossible();
         KotlinType rightType = rightTypeInfo.getType();
 
+        // DataFlowShit starts here
+        boolean loopBreakContinuePossible = leftTypeInfo.getJumpOutPossible() || rightTypeInfo.getJumpOutPossible();
+
         // Only left argument DFA is taken into account here: we cannot be sure that right argument is joined
         // (we merge it with right DFA if right argument contains no jump outside)
-        DataFlowInfo dataFlowInfo = resolvedCall.getDataFlowInfoForArguments().getInfo(call.getValueArguments().get(1));
+        DataFlowInfo resultDataFlowInfo = resolvedCall.getDataFlowInfoForArguments().getInfo(call.getValueArguments().get(1));
+
 
         KotlinType type = resolvedCall.getResultingDescriptor().getReturnType();
         if (type == null ||
             rightType == null ||
-            leftType == null && KotlinBuiltIns.isNothing(rightType)) return TypeInfoFactoryKt.noTypeInfo(dataFlowInfo);
+            leftType == null && KotlinBuiltIns.isNothing(rightType)
+        ) {
+            return TypeInfoFactoryKt.noTypeInfo(resultDataFlowInfo);
+        }
 
         if (leftType != null) {
+            // This one is about logic "if right value is somehow breaks flow, then left is non-null"
             DataFlowValue leftValue = createDataFlowValue(left, leftType, context);
             DataFlowInfo rightDataFlowInfo = resolvedCall.getDataFlowInfoForArguments().getResultInfo();
             boolean jumpInRight = KotlinBuiltIns.isNothing(rightType);
             DataFlowValue nullValue = DataFlowValue.nullValue(components.builtIns);
+
             // left argument is considered not-null if it's not-null also in right part or if we have jump in right part
             if (jumpInRight || !rightDataFlowInfo.getStableNullability(leftValue).canBeNull()) {
-                dataFlowInfo = dataFlowInfo.disequate(leftValue, nullValue, components.languageVersionSettings);
+                resultDataFlowInfo = resultDataFlowInfo.disequate(leftValue, nullValue, components.languageVersionSettings);
+
+                // Here we cover cases like "(x as? Foo) ?: return". Since 1.2, we have SafeCastCheckBoundSmartCasts language feature,
+                // which cover such cases more generally
                 if (left instanceof KtBinaryExpressionWithTypeRHS) {
-                    dataFlowInfo = establishSubtypingForTypeRHS((KtBinaryExpressionWithTypeRHS) left, dataFlowInfo, context,
+                    resultDataFlowInfo = establishSubtypingForTypeRHS((KtBinaryExpressionWithTypeRHS) left, resultDataFlowInfo, context,
                                                                 components.languageVersionSettings);
                 }
             }
+
             DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(expression, type, context);
-            dataFlowInfo =
-                    dataFlowInfo.assign(resultValue, leftValue, components.languageVersionSettings)
+            resultDataFlowInfo =
+                    resultDataFlowInfo.assign(resultValue, leftValue, components.languageVersionSettings)
                     .disequate(resultValue, nullValue, components.languageVersionSettings);
             if (!jumpInRight) {
                 DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context);
                 rightDataFlowInfo = rightDataFlowInfo.assign(resultValue, rightValue, components.languageVersionSettings);
-                dataFlowInfo = dataFlowInfo.or(rightDataFlowInfo);
+                resultDataFlowInfo = resultDataFlowInfo.or(rightDataFlowInfo);
             }
         }
 
@@ -1316,16 +1352,24 @@
             type = TypeUtils.makeNotNullable(type);
         }
         if (context.contextDependency == DEPENDENT) {
-            return TypeInfoFactoryKt.createTypeInfo(type, dataFlowInfo);
+            return TypeInfoFactoryKt.createTypeInfo(type, resultDataFlowInfo);
         }
 
         // If break or continue was possible, take condition check info as the jump info
+        // components.dataFlowAnalyzer.createCheckedTypeInfo(type, contextWithExpectedType, expression);
+        // <=> checkType(TypeInfoFactoryKt.createTypeInfo(type, context), expression, context)
+        // <=> TypeInfoFactoryKt.createTypeInfo(type, context).replaceType(checkType(type), expression, context)
+        // <=> TypeInfoFactoryKT.createTypeInfo(checkType(type), expression, context
+
         return TypeInfoFactoryKt.createTypeInfo(components.dataFlowAnalyzer.checkType(type, expression, contextWithExpectedType),
-                                                dataFlowInfo,
+                                                resultDataFlowInfo,
                                                 loopBreakContinuePossible,
                                                 context.dataFlowInfo);
     }
 
+    /*
+    Obsolete, see comment at use-site
+     */
     @NotNull
     private static DataFlowInfo establishSubtypingForTypeRHS(
             @NotNull KtBinaryExpressionWithTypeRHS left,
@@ -1348,10 +1392,24 @@
         return dataFlowInfo;
     }
 
+    /*
+    Nothing too special, just regular linear data-flow juggling, but note that order is different:
+    1. Resolve *right* expression in basic context, get data flow info after right ("dataFlowInfo")
+
+    2. Resolve *whole* call in the context of right-expression ("contextWithDataFlow")
+       Note that it will compute data-flow info for left-expression too, as part of resolving arguments of desugared call
+
+    3. Get data flow info for *left* expression in the "contextWithDataFlow" (will just take already computed data-flow info from trace), "flowForLeft"
+
+    4. Return 'and'-merged flow for left and flow for right (orly??) <=> dataFlowInfo && flowForLeft
+       Note that implementation doesn't create new TypeInfo and instead mutates 'rightTypeInfo', which is quite confusing tbh.
+       Also note that 'and'-merging flow for left and right is most probably not correct (similar to 'and'-merging in DataFlowInfoForArguments),
+       but luckily we don't have (yet) constructions with non-trivial enough flow to break this.
+     */
     @NotNull
     public KotlinTypeInfo checkInExpression(
             @NotNull KtElement callElement,
-            @NotNull KtSimpleNameExpression operationSign,
+            @NotNull KtSimpleNameExpression operationSign, // either "in" or "!in"
             @NotNull ValueArgument leftArgument,
             @Nullable KtExpression right,
             @NotNull ExpressionTypingContext context
@@ -1378,8 +1436,8 @@
         ensureBooleanResult(operationSign, OperatorNameConventions.CONTAINS, containsType, context);
 
         if (left != null) {
-            dataFlowInfo = facade.getTypeInfo(left, contextWithDataFlow).getDataFlowInfo().and(dataFlowInfo);
-            rightTypeInfo = rightTypeInfo.replaceDataFlowInfo(dataFlowInfo);
+            DataFlowInfo flowForLeft = facade.getTypeInfo(left, contextWithDataFlow).getDataFlowInfo();
+            rightTypeInfo = rightTypeInfo.replaceDataFlowInfo(flowForLeft);
         }
 
         if (resolutionResult.isSuccess()) {
@@ -1490,6 +1548,12 @@
         return declarationInIllegalContext(property, context);
     }
 
+    /*
+    Very trivial manipulations:
+        - resolve lhs in basic context
+        - resolve rhs in context with info from lhs
+        - use rhs resulting info (resolvedCall.dataFlowInfoForArguments.resultInfo) as result
+     */
     @NotNull
     private KotlinTypeInfo getTypeInfoForBinaryCall(
             @NotNull Name name,
@@ -1676,6 +1740,13 @@
         return resolveArrayAccessSpecialMethod(arrayAccessExpression, null, context, context.trace, true, false);
     }
 
+    /*
+    1. Take data flow for array call (e.g. for "foo()" in "foo()[bar(), baz(), bak()]", "arrayTypeInfo"
+    2. If there are any indices, take data flow for all indices computation (as usual, this is resolved as call, and indices are arguments, so resulting info is
+       bound to the last argument)
+    3. If there are rightHandSide (for 'set'-method), then take data flow for it instead (it's not obvious, but it *will* contain info about indices, because both
+       indices and RHS are analyzed during synthethic-call resolution as arguments, and dataFlow for them is already recorded)
+     */
     @NotNull
     private KotlinTypeInfo resolveArrayAccessSpecialMethod(
             @NotNull KtArrayAccessExpression arrayAccessExpression,
@@ -1700,6 +1771,9 @@
         Call call = isGet
                     ? CallMaker.makeArrayGetCall(receiver, arrayAccessExpression, Call.CallType.ARRAY_GET_METHOD)
                     : CallMaker.makeArraySetCall(receiver, arrayAccessExpression, rightHandSide, Call.CallType.ARRAY_SET_METHOD);
+
+        // As a side effect, this call will record typeinfo for rightHandSide
+        // Quite logical, if you think about it, but totally not obvious from a first glance
         OverloadResolutionResults<FunctionDescriptor> functionResults = components.callResolver.resolveCallWithGivenName(
                 context, call, arrayAccessExpression, isGet ? OperatorNameConventions.GET : OperatorNameConventions.SET);
 
@@ -1711,6 +1785,11 @@
         }
 
         if (!isGet) {
+            // Surprise-surprise: though that looks like we're saying here:
+            // "Take context info(which is empty atm), and resolve 'rightHandSide' in that context, and then *OVERWRITE* current info with it"
+            // And one could (rightfully) think that this is wrong, because it obviously won't contain data-flow information about indices
+            // But no!
+            // In face, getTypeInfo will take out cached type info, calculated by someone else, which apparently *does* contain info about indices
             resultTypeInfo = facade.getTypeInfo(rightHandSide, context);
         }
 
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java
index 0a9341a..850d601 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java
@@ -251,6 +251,33 @@
         return visitWhileExpression(expression, context, false);
     }
 
+    /*
+    0. Check if it is used as statement, exit with reporting, if so
+    1. Launch PreliminaryLoopVisitor to clear DFI for all variables assigned in loop
+    2. Extract type info from body:
+        - If body is present, then resolve its body in context with DFI = "(condition == true) && (condition finished)"
+        - Otherwise, use empty type info
+    3. Infer outer info:
+        Step a. Initialize "result: DataFlowInfo" with context data flow info (remember, it has already all assigned variables cleared)
+        Step b. Update "result &= dfi(condition finished)".
+        Step c. If there is no jumpout in body, then update "result &= dfi(condition == true)"
+        Step d. If it is 'while(true)', then further update 'result &= jumpOutInfo' <=> 'result &= dfi(first break in loop body) - assignedVariablesInfo'
+
+    Possible higher-level logic:
+    0. Check if it is used as statement, exit with reporting
+    1. dataFlowResults = analyzer.analyzeWhileLoop(whileExpression, context)
+        - launches PreliminiaryLoopVisitor, clears DFI for all variables assigned in loop
+        - extracts "condition == true"
+        - extracts "condition finished"
+        - ? returns some lightweight view, maybe even lazy one
+    2. contextForBody = dataFlowResults.getContextForBodyResultion()
+        - returns context with "(condition == true) && (condition finished)"
+    3. Resolve body in contextForBody. This will return "dataFlowInfoForBlock"
+    4. analyzer.feed(dataFlowInfoForBlock) // submit info about body into analyzer, analyzer will decide what should be done about it
+    5. return analyzer.loopResultInfo
+
+     */
+
     public KotlinTypeInfo visitWhileExpression(KtWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
         if (!isStatement) return components.dataFlowAnalyzer.illegalStatementType(expression, contextWithExpectedType, facade);
 
@@ -344,6 +371,22 @@
         return visitDoWhileExpression(expression, context, false);
     }
 
+    /*
+    0. Check if it is used as statement, returning with diagnostic if so
+    1. Launch PreliminaryVisitor to clear all info about variables assigned in loop
+    2. Extract body info:
+        - if body is present, then resolve it in current context (remember, it has already all asigned variables cleared)
+        - otherwise, no type info
+    3. Resolve condition:
+        - use context DFI (*NOT* a body DFI!)
+        - use *BODY* scope (hello, nice "feature" of using val's, declared in do-while body, in condition)
+    4. Infer outer info:
+        Step a.
+            - If no jumpouts in body, then we initialize "result" to "dfi(condition == true) && dfi(condition finished)"
+            - If there are jumpouts in body, then initialize "result" to context dfi (dfi at the enter of loop - all assigned variables)
+        Step b. Update "result" with "result &= jumpOutInfo" <=> "result &= dataFlowInfoAtFirstBreak - allAssignedVariables"
+
+     */
     public KotlinTypeInfo visitDoWhileExpression(KtDoWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
         if (!isStatement) return components.dataFlowAnalyzer.illegalStatementType(expression, contextWithExpectedType, facade);
 
@@ -411,6 +454,17 @@
         return visitForExpression(expression, context, false);
     }
 
+    /*
+    0. If used as statement, return with diagnostic
+    1. Launch loopVisitor to clear all info for all assigned variables, producing context'
+    2. Extract loopRangeInfo
+        - if loopRangeExpression is present, then resolve it in context'
+        - otherwise, use empty type info
+    3. Extract body type info:
+        - if body is present, then resolve it in context of loopRangeInfo
+        - otherwise, use empty type info
+    4. Use loopRangeInfo as outer info
+     */
     public KotlinTypeInfo visitForExpression(KtForExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
         if (!isStatement) return components.dataFlowAnalyzer.illegalStatementType(expression, contextWithExpectedType, facade);
 
@@ -503,6 +557,22 @@
         return variableDescriptor;
     }
 
+    /*
+    0. Let context' = current contexxt with no context dependency
+    1. Extract info from try-block in context'
+    2. Infer info at the end of try-catch, "tryOutputContext":
+        Step a. initialize to context'.dataFlowInfo
+        Step b. If it is possible to fall-through at least one catch-clause (i.e. not every catch-clause ends with jumpout),
+                then launch PreliminaryVisitor and clear info for all assigned variables in 'try'
+    3. If there is a finally clause, then resolve it in "tryOutputContext" context
+    4. Infer info at the end of the whole try-expression (with all catches and finaly-clause, if any), "result":
+        Step a. Initialize "result" to "tryOutputContext", i.e. very conservative info (it is <= context info)
+        Step b. If finally is present, then we're sure that it is executed.
+                Update "result" to the finally's info
+        Step c. If finally is not present, but fall-through is impossible, then we're sure that try-block is executed.
+                Update "result" to the info at the end of the try-block, "tryResult".
+    5. Return "result"
+     */
     @Override
     public KotlinTypeInfo visitTryExpression(@NotNull KtTryExpression expression, ExpressionTypingContext typingContext) {
         ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT);
@@ -565,6 +635,7 @@
         if (type != null) {
             types.add(type);
         }
+
         if (types.isEmpty()) {
             return result.clearType();
         }
@@ -607,6 +678,10 @@
     }
 
     @Override
+    /*
+    No data-flow manipulations whatsoever, in the end it returns context.dataFlowInfo, though that's highly obscure and
+    non-obvious at the first glance
+     */
     public KotlinTypeInfo visitReturnExpression(@NotNull KtReturnExpression expression, ExpressionTypingContext context) {
         KtElement labelTargetElement = LabelResolver.INSTANCE.resolveControlLabel(expression, context);
 
diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java
index ffe01d5..f501955 100644
--- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java
+++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java
@@ -122,6 +122,37 @@
         return !typeHasOverriddenEquals(type, lookupElement);
     }
 
+    /*
+    Visits PSI-tree which contains some boolean condition, and extracts
+    data flow info, given that it is known that this 'condition' is equal to 'conditionValue'.
+
+    1. For 'is'-expression: just take recorded DFI from trace
+       Intricacies:
+         - check that it indeed brings us subtype infromation. Case chasing: "if operator isn't inverted
+           and 'conditionValue' == true, then record subtyping; if operator is inverted and 'conditionValue == false',
+           then record subtyping; otherwise do not record anything (we don't have a notion of "not-subtype-of" in compiler)
+
+    2. For binary operator: do recursive calls on arguments and merge DFI
+       Intricacies:
+         - short-circuit logic
+         - choosing right operator for merging (case chasing: if operator is '&&' and 'conditionValue == true', then
+           merge with 'AND'; if operator is '||' and 'conditionValue == false', then merge with 'OR'; ...)
+
+    3. For equals operator: equate 'left' and 'right'
+       Intricacies:
+         - Identity equals
+         - choosing right operator (equate vs. disequate + inversion in case of 'conditionValue == false')
+
+    4. For elvis: lower
+        'E ?: false' -> 'E == true',
+        'E ?: true' -> 'E == false'
+       where "E" is some expression of nullable type
+
+    5. For unary negation: recruse with inverted 'conditionValue'
+
+    6. For everything else: just take recorded DFI from trace
+
+     */
     @NotNull
     public DataFlowInfo extractDataFlowInfoFromCondition(
             @Nullable KtExpression condition,
@@ -270,6 +301,20 @@
     }
 
     @NotNull
+    /*
+    If expected type is not present, trivial, or not denotable -- then do not check anything.
+    Also omit trivial checks (if expression is already subtype of expected type)
+
+    Then:
+        - for constant expressions, check its type via CompileTimeConstantChecker in light mode
+        - for when expression, do nothing
+        - for all the rest, try to get smartcast, and return, if suitable is found.
+
+    Otherwise, there's type mismatch and we have to report it properly:
+        - Special case: type mismatch was because of type projections
+        - Special case: type mismatch was because of Scala-like function syntax
+        - Otherwise, just report generic "Expected X but got Y"
+     */
     private KotlinType checkTypeInternal(
             @NotNull KotlinType expressionType,
             @NotNull KtExpression expression,
@@ -307,6 +352,12 @@
         return expressionType;
     }
 
+    /*
+    1. Record expected type
+        - Needed for IDE, and ControlFlowAnalyzer
+    2. Call into cehckTypeInternal
+    3. Run additional type checkers
+     */
     @Nullable
     public KotlinType checkType(
             @Nullable KotlinType expressionType,
@@ -405,6 +456,9 @@
     }
 
     @NotNull
+    /*
+    Returns the same dataflow, as in the passed context
+     */
     public KotlinTypeInfo createCompileTimeConstantTypeInfo(
             @NotNull CompileTimeConstant<?> value,
             @NotNull KtExpression expression,
diff --git a/compiler/testData/diagnostics/tests/smartCasts/foobar.kt b/compiler/testData/diagnostics/tests/smartCasts/foobar.kt
new file mode 100644
index 0000000..6213d0a
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/smartCasts/foobar.kt
@@ -0,0 +1,11 @@
+fun bar(x: Array<Int>?, y: Int?) {
+    if (y!! in x!!) {
+        y.inc()
+        x.size
+    } else {
+        y.inc()
+        x.size
+    }
+    y.inc()
+    x.size
+}
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/tests/smartCasts/foobar.txt b/compiler/testData/diagnostics/tests/smartCasts/foobar.txt
new file mode 100644
index 0000000..e0de512
--- /dev/null
+++ b/compiler/testData/diagnostics/tests/smartCasts/foobar.txt
@@ -0,0 +1,11 @@
+package
+
+public fun </*0*/ T : Foo?> text(/*0*/ x: T): kotlin.Unit
+public fun kotlin.Int.bar(): kotlin.Int
+
+public interface Foo {
+    public abstract val length: kotlin.Int
+    public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
diff --git a/compiler/testData/diagnostics/testsWithStdLib/dontCommitTmp.kt b/compiler/testData/diagnostics/testsWithStdLib/dontCommitTmp.kt
new file mode 100644
index 0000000..ab48e6a
--- /dev/null
+++ b/compiler/testData/diagnostics/testsWithStdLib/dontCommitTmp.kt
@@ -0,0 +1,13 @@
+val flag: Boolean = false
+
+fun test1(x: Int?) {
+    var z: Int? = null
+
+    z = x ?: if (flag) 42 else 239
+
+    val y = x ?: 42
+
+    z.inc()
+    y.inc()
+
+}
\ No newline at end of file
diff --git a/compiler/testData/diagnostics/testsWithStdLib/dontCommitTmp.txt b/compiler/testData/diagnostics/testsWithStdLib/dontCommitTmp.txt
new file mode 100644
index 0000000..8072ce3
--- /dev/null
+++ b/compiler/testData/diagnostics/testsWithStdLib/dontCommitTmp.txt
@@ -0,0 +1,12 @@
+package
+
+public fun test(/*0*/ foo: Foo): kotlin.Unit
+public fun kotlin.Int.bar(): kotlin.Int
+
+public interface Foo {
+    public abstract val length: kotlin.Int
+    public abstract val list: kotlin.collections.List<kotlin.Int>
+    public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
+    public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
+    public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
+}
diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java
index 23b359b..a5d328f 100644
--- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java
@@ -20585,6 +20585,12 @@
                 doTest(fileName);
             }
 
+            @TestMetadata("foobar.kt")
+            public void testFoobar() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/foobar.kt");
+                doTest(fileName);
+            }
+
             @TestMetadata("genericIntersection.kt")
             public void testGenericIntersection() throws Exception {
                 String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/genericIntersection.kt");
diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java
index 2f197b4..440021e 100644
--- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java
@@ -55,6 +55,12 @@
         doTest(fileName);
     }
 
+    @TestMetadata("dontCommitTmp.kt")
+    public void testDontCommitTmp() throws Exception {
+        String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/dontCommitTmp.kt");
+        doTest(fileName);
+    }
+
     @TestMetadata("elvisOnJavaList.kt")
     public void testElvisOnJavaList() throws Exception {
         String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/elvisOnJavaList.kt");
diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
index 76cf622..a583904 100644
--- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
@@ -55,6 +55,12 @@
         doTest(fileName);
     }
 
+    @TestMetadata("dontCommitTmp.kt")
+    public void testDontCommitTmp() throws Exception {
+        String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/dontCommitTmp.kt");
+        doTest(fileName);
+    }
+
     @TestMetadata("elvisOnJavaList.kt")
     public void testElvisOnJavaList() throws Exception {
         String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/elvisOnJavaList.kt");
diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java
index 1e6c167..80290ce 100644
--- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java
@@ -20585,6 +20585,12 @@
                 doTest(fileName);
             }
 
+            @TestMetadata("foobar.kt")
+            public void testFoobar() throws Exception {
+                String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/foobar.kt");
+                doTest(fileName);
+            }
+
             @TestMetadata("genericIntersection.kt")
             public void testGenericIntersection() throws Exception {
                 String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/genericIntersection.kt");