@Override
  public KotlinTypeInfo visitTryExpression(
      @NotNull KtTryExpression expression, ExpressionTypingContext typingContext) {
    ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT);
    KtExpression tryBlock = expression.getTryBlock();
    List<KtCatchClause> catchClauses = expression.getCatchClauses();
    KtFinallySection finallyBlock = expression.getFinallyBlock();
    List<KotlinType> types = new ArrayList<KotlinType>();
    for (KtCatchClause catchClause : catchClauses) {
      KtParameter catchParameter = catchClause.getCatchParameter();
      KtExpression catchBody = catchClause.getCatchBody();
      if (catchParameter != null) {
        components.identifierChecker.checkDeclaration(catchParameter, context.trace);
        ModifiersChecker.ModifiersCheckingProcedure modifiersChecking =
            components.modifiersChecker.withTrace(context.trace);
        modifiersChecking.checkParameterHasNoValOrVar(
            catchParameter, VAL_OR_VAR_ON_CATCH_PARAMETER);
        ModifierCheckerCore.INSTANCE$.check(catchParameter, context.trace, null);

        VariableDescriptor variableDescriptor =
            components.descriptorResolver.resolveLocalVariableDescriptor(
                context.scope, catchParameter, context.trace);
        KotlinType throwableType = components.builtIns.getThrowable().getDefaultType();
        components.dataFlowAnalyzer.checkType(
            variableDescriptor.getType(),
            catchParameter,
            context.replaceExpectedType(throwableType));
        if (catchBody != null) {
          LexicalWritableScope catchScope = newWritableScopeImpl(context, "Catch scope");
          catchScope.addVariableDescriptor(variableDescriptor);
          KotlinType type =
              facade.getTypeInfo(catchBody, context.replaceScope(catchScope)).getType();
          if (type != null) {
            types.add(type);
          }
        }
      }
    }

    KotlinTypeInfo result = TypeInfoFactoryKt.noTypeInfo(context);
    if (finallyBlock != null) {
      result =
          facade.getTypeInfo(
              finallyBlock.getFinalExpression(), context.replaceExpectedType(NO_EXPECTED_TYPE));
    }

    KotlinType type = facade.getTypeInfo(tryBlock, context).getType();
    if (type != null) {
      types.add(type);
    }
    if (types.isEmpty()) {
      return result.clearType();
    } else {
      return result.replaceType(CommonSupertypes.commonSupertype(types));
    }
  }
  @NotNull
  public KotlinType getBodyExpressionType(
      @NotNull BindingTrace trace,
      @NotNull LexicalScope outerScope,
      @NotNull DataFlowInfo dataFlowInfo,
      @NotNull KtDeclarationWithBody function,
      @NotNull FunctionDescriptor functionDescriptor) {
    KtExpression bodyExpression = function.getBodyExpression();
    assert bodyExpression != null;
    LexicalScope functionInnerScope =
        FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);

    ExpressionTypingContext context =
        ExpressionTypingContext.newContext(
            trace, functionInnerScope, dataFlowInfo, NO_EXPECTED_TYPE);
    KotlinTypeInfo typeInfo =
        expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody());

    KotlinType type = typeInfo.getType();
    if (type != null) {
      return type;
    } else {
      return ErrorUtils.createErrorType("Error function type");
    }
  }
  /*package*/ void checkFunctionReturnType(
      KtDeclarationWithBody function, ExpressionTypingContext context) {
    KtExpression bodyExpression = function.getBodyExpression();
    if (bodyExpression == null) return;

    boolean blockBody = function.hasBlockBody();
    ExpressionTypingContext newContext =
        blockBody ? context.replaceExpectedType(NO_EXPECTED_TYPE) : context;

    expressionTypingFacade.getTypeInfo(bodyExpression, newContext, blockBody);
  }
 @NotNull
 public KotlinTypeInfo getTypeInfo(
     @NotNull LexicalScope scope,
     @NotNull KtExpression expression,
     @NotNull KotlinType expectedType,
     @NotNull DataFlowInfo dataFlowInfo,
     @NotNull BindingTrace trace,
     boolean isStatement) {
   ExpressionTypingContext context =
       ExpressionTypingContext.newContext(trace, scope, dataFlowInfo, expectedType);
   return expressionTypingFacade.getTypeInfo(expression, context, isStatement);
 }
 @Override
 public KotlinTypeInfo visitThrowExpression(
     @NotNull KtThrowExpression expression, ExpressionTypingContext context) {
   KtExpression thrownExpression = expression.getThrownExpression();
   if (thrownExpression != null) {
     KotlinType throwableType = components.builtIns.getThrowable().getDefaultType();
     facade.getTypeInfo(
         thrownExpression,
         context
             .replaceExpectedType(throwableType)
             .replaceScope(context.scope)
             .replaceContextDependency(INDEPENDENT));
   }
   return components.dataFlowAnalyzer.createCheckedTypeInfo(
       components.builtIns.getNothingType(), context, expression);
 }
  private KotlinTypeInfo getTypeOfLastExpressionInBlock(
      @NotNull KtExpression statementExpression,
      @NotNull ExpressionTypingContext context,
      @NotNull CoercionStrategy coercionStrategyForLastExpression,
      @NotNull ExpressionTypingInternals blockLevelVisitor) {
    if (context.expectedType != NO_EXPECTED_TYPE) {
      KotlinType expectedType;
      if (context.expectedType == UNIT_EXPECTED_TYPE
          || // the first check is necessary to avoid invocation 'isUnit(UNIT_EXPECTED_TYPE)'
          (coercionStrategyForLastExpression == COERCION_TO_UNIT
              && KotlinBuiltIns.isUnit(context.expectedType))) {
        expectedType = UNIT_EXPECTED_TYPE;
      } else {
        expectedType = context.expectedType;
      }

      return blockLevelVisitor.getTypeInfo(
          statementExpression, context.replaceExpectedType(expectedType), true);
    }
    KotlinTypeInfo result = blockLevelVisitor.getTypeInfo(statementExpression, context, true);
    if (coercionStrategyForLastExpression == COERCION_TO_UNIT) {
      boolean mightBeUnit = false;
      if (statementExpression instanceof KtDeclaration) {
        mightBeUnit = true;
      }
      if (statementExpression instanceof KtBinaryExpression) {
        KtBinaryExpression binaryExpression = (KtBinaryExpression) statementExpression;
        IElementType operationType = binaryExpression.getOperationToken();
        //noinspection SuspiciousMethodCalls
        if (operationType == KtTokens.EQ
            || OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
          mightBeUnit = true;
        }
      }
      if (mightBeUnit) {
        // ExpressionTypingVisitorForStatements should return only null or Unit for declarations and
        // assignments,
        // but (for correct assignment / initialization analysis) data flow info must be preserved
        assert result.getType() == null || KotlinBuiltIns.isUnit(result.getType());
        result = result.replaceType(expressionTypingComponents.builtIns.getUnitType());
      }
    }
    return result;
  }
 public void checkFunctionReturnType(
     @NotNull LexicalScope functionInnerScope,
     @NotNull KtDeclarationWithBody function,
     @NotNull FunctionDescriptor functionDescriptor,
     @NotNull DataFlowInfo dataFlowInfo,
     @Nullable KotlinType expectedReturnType,
     BindingTrace trace) {
   if (expectedReturnType == null) {
     expectedReturnType = functionDescriptor.getReturnType();
     if (!function.hasBlockBody() && !function.hasDeclaredReturnType()) {
       expectedReturnType = NO_EXPECTED_TYPE;
     }
   }
   checkFunctionReturnType(
       function,
       ExpressionTypingContext.newContext(
           trace,
           functionInnerScope,
           dataFlowInfo,
           expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE));
 }
  @NotNull
  public KotlinTypeInfo getBlockReturnedType(
      @NotNull KtBlockExpression expression,
      @NotNull CoercionStrategy coercionStrategyForLastExpression,
      @NotNull ExpressionTypingContext context) {
    List<KtExpression> block = StatementFilterKt.filterStatements(statementFilter, expression);

    DeclarationDescriptor containingDescriptor = context.scope.getOwnerDescriptor();
    LexicalWritableScope scope =
        new LexicalWritableScope(
            context.scope,
            containingDescriptor,
            false,
            null,
            new TraceBasedRedeclarationHandler(context.trace),
            LexicalScopeKind.CODE_BLOCK);
    scope.changeLockLevel(LexicalWritableScope.LockLevel.BOTH);

    KotlinTypeInfo r;
    if (block.isEmpty()) {
      r =
          expressionTypingComponents.dataFlowAnalyzer.createCheckedTypeInfo(
              expressionTypingComponents.builtIns.getUnitType(), context, expression);
    } else {
      r =
          getBlockReturnedTypeWithWritableScope(
              scope,
              block,
              coercionStrategyForLastExpression,
              context.replaceStatementFilter(statementFilter));
    }
    scope.changeLockLevel(LexicalWritableScope.LockLevel.READING);

    if (containingDescriptor instanceof ScriptDescriptor) {
      context.trace.record(
          BindingContext.SCRIPT_SCOPE, (ScriptDescriptor) containingDescriptor, scope);
    }

    return r;
  }
  @NotNull
  private DataFlowInfo checkCondition(
      @NotNull LexicalScope scope,
      @Nullable KtExpression condition,
      ExpressionTypingContext context) {
    if (condition != null) {
      KotlinTypeInfo typeInfo =
          facade.getTypeInfo(
              condition,
              context
                  .replaceScope(scope)
                  .replaceExpectedType(components.builtIns.getBooleanType())
                  .replaceContextDependency(INDEPENDENT));
      KotlinType conditionType = typeInfo.getType();

      if (conditionType != null && !components.builtIns.isBooleanOrSubtype(conditionType)) {
        context.trace.report(TYPE_MISMATCH_IN_CONDITION.on(condition, conditionType));
      }

      return typeInfo.getDataFlowInfo();
    }
    return context.dataFlowInfo;
  }
 @NotNull
 private KotlinTypeInfo getTypeInfoWhenOnlyOneBranchIsPresent(
     @NotNull KtExpression presentBranch,
     @NotNull LexicalWritableScope presentScope,
     @NotNull DataFlowInfo presentInfo,
     @NotNull DataFlowInfo otherInfo,
     @NotNull ExpressionTypingContext context,
     @NotNull KtIfExpression ifExpression,
     boolean isStatement) {
   ExpressionTypingContext newContext =
       context
           .replaceDataFlowInfo(presentInfo)
           .replaceExpectedType(NO_EXPECTED_TYPE)
           .replaceContextDependency(INDEPENDENT);
   KotlinTypeInfo typeInfo =
       components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
           presentScope,
           Collections.singletonList(presentBranch),
           CoercionStrategy.NO_COERCION,
           newContext);
   KotlinType type = typeInfo.getType();
   DataFlowInfo dataFlowInfo;
   if (type != null && KotlinBuiltIns.isNothing(type)) {
     dataFlowInfo = otherInfo;
   } else {
     dataFlowInfo = typeInfo.getDataFlowInfo().or(otherInfo);
   }
   return components
       .dataFlowAnalyzer
       .checkImplicitCast(
           components.dataFlowAnalyzer.checkType(
               typeInfo.replaceType(components.builtIns.getUnitType()), ifExpression, context),
           ifExpression,
           context,
           isStatement)
       .replaceDataFlowInfo(dataFlowInfo);
 }
  /**
   * Visits block statements propagating data flow information from the first to the last.
   * Determines block returned type and data flow information at the end of the block AND at the
   * nearest jump point from the block beginning.
   */
  /*package*/ KotlinTypeInfo getBlockReturnedTypeWithWritableScope(
      @NotNull LexicalWritableScope scope,
      @NotNull List<? extends KtElement> block,
      @NotNull CoercionStrategy coercionStrategyForLastExpression,
      @NotNull ExpressionTypingContext context) {
    if (block.isEmpty()) {
      return TypeInfoFactoryKt.createTypeInfo(
          expressionTypingComponents.builtIns.getUnitType(), context);
    }

    ExpressionTypingInternals blockLevelVisitor =
        new ExpressionTypingVisitorDispatcher.ForBlock(
            expressionTypingComponents, annotationChecker, scope);
    ExpressionTypingContext newContext =
        context.replaceScope(scope).replaceExpectedType(NO_EXPECTED_TYPE);

    KotlinTypeInfo result = TypeInfoFactoryKt.noTypeInfo(context);
    // Jump point data flow info
    DataFlowInfo beforeJumpInfo = newContext.dataFlowInfo;
    boolean jumpOutPossible = false;
    for (Iterator<? extends KtElement> iterator = block.iterator(); iterator.hasNext(); ) {
      KtElement statement = iterator.next();
      if (!(statement instanceof KtExpression)) {
        continue;
      }
      KtExpression statementExpression = (KtExpression) statement;
      if (!iterator.hasNext()) {
        result =
            getTypeOfLastExpressionInBlock(
                statementExpression,
                newContext.replaceExpectedType(context.expectedType),
                coercionStrategyForLastExpression,
                blockLevelVisitor);
        if (result.getType() != null
            && statementExpression.getParent() instanceof KtBlockExpression) {
          DataFlowValue lastExpressionValue =
              DataFlowValueFactory.createDataFlowValue(
                  statementExpression, result.getType(), context);
          DataFlowValue blockExpressionValue =
              DataFlowValueFactory.createDataFlowValue(
                  (KtBlockExpression) statementExpression.getParent(), result.getType(), context);
          result =
              result.replaceDataFlowInfo(
                  result.getDataFlowInfo().assign(blockExpressionValue, lastExpressionValue));
        }
      } else {
        result =
            blockLevelVisitor.getTypeInfo(
                statementExpression,
                newContext.replaceContextDependency(ContextDependency.INDEPENDENT),
                true);
      }

      DataFlowInfo newDataFlowInfo = result.getDataFlowInfo();
      // If jump is not possible, we take new data flow info before jump
      if (!jumpOutPossible) {
        beforeJumpInfo = result.getJumpFlowInfo();
        jumpOutPossible = result.getJumpOutPossible();
      }
      if (newDataFlowInfo != context.dataFlowInfo) {
        newContext = newContext.replaceDataFlowInfo(newDataFlowInfo);
        // We take current data flow info if jump there is not possible
      }
      blockLevelVisitor =
          new ExpressionTypingVisitorDispatcher.ForBlock(
              expressionTypingComponents, annotationChecker, scope);
    }
    return result.replaceJumpOutPossible(jumpOutPossible).replaceJumpFlowInfo(beforeJumpInfo);
  }
  @Override
  public KotlinTypeInfo visitReturnExpression(
      @NotNull KtReturnExpression expression, ExpressionTypingContext context) {
    KtElement labelTargetElement = LabelResolver.INSTANCE.resolveControlLabel(expression, context);

    KtExpression returnedExpression = expression.getReturnedExpression();

    KotlinType expectedType = NO_EXPECTED_TYPE;
    KotlinType resultType = components.builtIns.getNothingType();
    KtDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, KtDeclaration.class);

    if (parentDeclaration instanceof KtParameter) {
      // In a default value for parameter
      context.trace.report(RETURN_NOT_ALLOWED.on(expression));
    }

    if (expression.getTargetLabel() == null) {
      while (parentDeclaration instanceof KtMultiDeclaration) {
        // TODO: It's hacking fix for KT-5100: Strange "Return is not allowed here" for
        // multi-declaration initializer with elvis expression
        parentDeclaration = PsiTreeUtil.getParentOfType(parentDeclaration, KtDeclaration.class);
      }

      assert parentDeclaration != null
          : "Can't find parent declaration for " + expression.getText();
      DeclarationDescriptor declarationDescriptor =
          context.trace.get(DECLARATION_TO_DESCRIPTOR, parentDeclaration);
      Pair<FunctionDescriptor, PsiElement> containingFunInfo =
          BindingContextUtils.getContainingFunctionSkipFunctionLiterals(
              declarationDescriptor, false);
      FunctionDescriptor containingFunctionDescriptor = containingFunInfo.getFirst();

      if (containingFunctionDescriptor != null) {
        if (!InlineUtil.checkNonLocalReturnUsage(
                containingFunctionDescriptor, expression, context.trace)
            || isClassInitializer(containingFunInfo)) {
          // Unqualified, in a function literal
          context.trace.report(RETURN_NOT_ALLOWED.on(expression));
          resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);
        }

        expectedType =
            getFunctionExpectedReturnType(
                containingFunctionDescriptor, (KtElement) containingFunInfo.getSecond(), context);
      } else {
        // Outside a function
        context.trace.report(RETURN_NOT_ALLOWED.on(expression));
        resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);
      }
    } else if (labelTargetElement != null) {
      SimpleFunctionDescriptor functionDescriptor = context.trace.get(FUNCTION, labelTargetElement);
      if (functionDescriptor != null) {
        expectedType =
            getFunctionExpectedReturnType(functionDescriptor, labelTargetElement, context);
        if (!InlineUtil.checkNonLocalReturnUsage(functionDescriptor, expression, context.trace)) {
          // Qualified, non-local
          context.trace.report(RETURN_NOT_ALLOWED.on(expression));
          resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);
        }
      } else {
        context.trace.report(NOT_A_RETURN_LABEL.on(expression, expression.getLabelName()));
      }
    }
    if (returnedExpression != null) {
      facade.getTypeInfo(
          returnedExpression,
          context
              .replaceExpectedType(expectedType)
              .replaceScope(context.scope)
              .replaceContextDependency(INDEPENDENT));
    } else {
      if (expectedType != null
          && !noExpectedType(expectedType)
          && !KotlinBuiltIns.isUnit(expectedType)
          && !isDontCarePlaceholder(expectedType)) // for lambda with implicit return type Unit
      {
        context.trace.report(RETURN_TYPE_MISMATCH.on(expression, expectedType));
      }
    }
    return components.dataFlowAnalyzer.createCheckedTypeInfo(resultType, context, expression);
  }
  public KotlinTypeInfo visitForExpression(
      KtForExpression expression,
      ExpressionTypingContext contextWithExpectedType,
      boolean isStatement) {
    if (!isStatement)
      return components.dataFlowAnalyzer.illegalStatementType(
          expression, contextWithExpectedType, facade);

    ExpressionTypingContext context =
        contextWithExpectedType
            .replaceExpectedType(NO_EXPECTED_TYPE)
            .replaceContextDependency(INDEPENDENT);
    // Preliminary analysis
    PreliminaryLoopVisitor loopVisitor = PreliminaryLoopVisitor.visitLoop(expression);
    context =
        context.replaceDataFlowInfo(
            loopVisitor.clearDataFlowInfoForAssignedLocalVariables(context.dataFlowInfo));

    KtExpression loopRange = expression.getLoopRange();
    KotlinType expectedParameterType = null;
    KotlinTypeInfo loopRangeInfo;
    if (loopRange != null) {
      ExpressionReceiver loopRangeReceiver =
          getExpressionReceiver(facade, loopRange, context.replaceScope(context.scope));
      loopRangeInfo = facade.getTypeInfo(loopRange, context);
      if (loopRangeReceiver != null) {
        expectedParameterType =
            components.forLoopConventionsChecker.checkIterableConvention(
                loopRangeReceiver, context);
      }
    } else {
      loopRangeInfo = TypeInfoFactoryKt.noTypeInfo(context);
    }

    LexicalWritableScope loopScope = newWritableScopeImpl(context, "Scope with for-loop index");

    KtParameter loopParameter = expression.getLoopParameter();
    if (loopParameter != null) {
      VariableDescriptor variableDescriptor =
          createLoopParameterDescriptor(loopParameter, expectedParameterType, context);
      components
          .modifiersChecker
          .withTrace(context.trace)
          .checkModifiersForLocalDeclaration(loopParameter, variableDescriptor);
      components.identifierChecker.checkDeclaration(loopParameter, context.trace);

      loopScope.addVariableDescriptor(variableDescriptor);
    } else {
      KtMultiDeclaration multiParameter = expression.getMultiParameter();
      if (multiParameter != null && loopRange != null) {
        KotlinType elementType =
            expectedParameterType == null
                ? ErrorUtils.createErrorType("Loop range has no type")
                : expectedParameterType;
        TransientReceiver iteratorNextAsReceiver = new TransientReceiver(elementType);
        components.annotationResolver.resolveAnnotationsWithArguments(
            loopScope, multiParameter.getModifierList(), context.trace);
        components.multiDeclarationResolver.defineLocalVariablesFromMultiDeclaration(
            loopScope, multiParameter, iteratorNextAsReceiver, loopRange, context);
        components
            .modifiersChecker
            .withTrace(context.trace)
            .checkModifiersForMultiDeclaration(multiParameter);
        components
            .modifiersChecker
            .withTrace(context.trace)
            .checkParameterHasNoValOrVar(multiParameter, VAL_OR_VAR_ON_LOOP_MULTI_PARAMETER);
        components.identifierChecker.checkDeclaration(multiParameter, context.trace);
      }
    }

    KtExpression body = expression.getBody();
    KotlinTypeInfo bodyTypeInfo;
    if (body != null) {
      bodyTypeInfo =
          components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
              loopScope,
              Collections.singletonList(body),
              CoercionStrategy.NO_COERCION,
              context.replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo()));
    } else {
      bodyTypeInfo = loopRangeInfo;
    }

    return components
        .dataFlowAnalyzer
        .checkType(
            bodyTypeInfo.replaceType(components.builtIns.getUnitType()),
            expression,
            contextWithExpectedType)
        .replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo());
  }
  public KotlinTypeInfo visitDoWhileExpression(
      KtDoWhileExpression expression,
      ExpressionTypingContext contextWithExpectedType,
      boolean isStatement) {
    if (!isStatement)
      return components.dataFlowAnalyzer.illegalStatementType(
          expression, contextWithExpectedType, facade);

    ExpressionTypingContext context =
        contextWithExpectedType
            .replaceExpectedType(NO_EXPECTED_TYPE)
            .replaceContextDependency(INDEPENDENT);
    KtExpression body = expression.getBody();
    LexicalScope conditionScope = context.scope;
    // Preliminary analysis
    PreliminaryLoopVisitor loopVisitor = PreliminaryLoopVisitor.visitLoop(expression);
    context =
        context.replaceDataFlowInfo(
            loopVisitor.clearDataFlowInfoForAssignedLocalVariables(context.dataFlowInfo));
    // Here we must record data flow information at the end of the body (or at the first jump, to be
    // precise) and
    // .and it with entrance data flow information, because do-while body is executed at least once
    // See KT-6283
    KotlinTypeInfo bodyTypeInfo;
    if (body instanceof KtFunctionLiteralExpression) {
      // As a matter of fact, function literal is always unused at this point
      bodyTypeInfo = facade.getTypeInfo(body, context.replaceScope(context.scope));
    } else if (body != null) {
      LexicalWritableScope writableScope = newWritableScopeImpl(context, "do..while body scope");
      conditionScope = writableScope;
      List<KtExpression> block;
      if (body instanceof KtBlockExpression) {
        block = ((KtBlockExpression) body).getStatements();
      } else {
        block = Collections.singletonList(body);
      }
      bodyTypeInfo =
          components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
              writableScope, block, CoercionStrategy.NO_COERCION, context);
    } else {
      bodyTypeInfo = TypeInfoFactoryKt.noTypeInfo(context);
    }
    KtExpression condition = expression.getCondition();
    DataFlowInfo conditionDataFlowInfo = checkCondition(conditionScope, condition, context);
    DataFlowInfo dataFlowInfo;
    // Without jumps out, condition is entered and false, with jumps out, we know nothing about it
    if (!containsJumpOutOfLoop(expression, context)) {
      dataFlowInfo =
          components
              .dataFlowAnalyzer
              .extractDataFlowInfoFromCondition(condition, false, context)
              .and(conditionDataFlowInfo);
    } else {
      dataFlowInfo = context.dataFlowInfo;
    }
    // Here we must record data flow information at the end of the body (or at the first jump, to be
    // precise) and
    // .and it with entrance data flow information, because do-while body is executed at least once
    // See KT-6283
    // NB: it's really important to do it for non-empty body which is not a function literal
    // If it's a function literal, it appears always unused so it's no matter what we do at this
    // point
    if (body != null) {
      // We should take data flow info from the first jump point,
      // but without affecting changing variables
      dataFlowInfo =
          dataFlowInfo.and(
              loopVisitor.clearDataFlowInfoForAssignedLocalVariables(
                  bodyTypeInfo.getJumpFlowInfo()));
    }
    return components
        .dataFlowAnalyzer
        .checkType(
            bodyTypeInfo.replaceType(components.builtIns.getUnitType()),
            expression,
            contextWithExpectedType)
        .replaceDataFlowInfo(dataFlowInfo);
  }
  public KotlinTypeInfo visitWhileExpression(
      KtWhileExpression expression,
      ExpressionTypingContext contextWithExpectedType,
      boolean isStatement) {
    if (!isStatement)
      return components.dataFlowAnalyzer.illegalStatementType(
          expression, contextWithExpectedType, facade);

    ExpressionTypingContext context =
        contextWithExpectedType
            .replaceExpectedType(NO_EXPECTED_TYPE)
            .replaceContextDependency(INDEPENDENT);
    // Preliminary analysis
    PreliminaryLoopVisitor loopVisitor = PreliminaryLoopVisitor.visitLoop(expression);
    context =
        context.replaceDataFlowInfo(
            loopVisitor.clearDataFlowInfoForAssignedLocalVariables(context.dataFlowInfo));

    KtExpression condition = expression.getCondition();
    // Extract data flow info from condition itself without taking value into account
    DataFlowInfo dataFlowInfo = checkCondition(context.scope, condition, context);

    KtExpression body = expression.getBody();
    KotlinTypeInfo bodyTypeInfo;
    DataFlowInfo conditionInfo =
        components
            .dataFlowAnalyzer
            .extractDataFlowInfoFromCondition(condition, true, context)
            .and(dataFlowInfo);
    if (body != null) {
      LexicalWritableScope scopeToExtend =
          newWritableScopeImpl(context, "Scope extended in while's condition");
      bodyTypeInfo =
          components.expressionTypingServices.getBlockReturnedTypeWithWritableScope(
              scopeToExtend,
              Collections.singletonList(body),
              CoercionStrategy.NO_COERCION,
              context.replaceDataFlowInfo(conditionInfo));
    } else {
      bodyTypeInfo = TypeInfoFactoryKt.noTypeInfo(conditionInfo);
    }

    // Condition is false at this point only if there is no jumps outside
    if (!containsJumpOutOfLoop(expression, context)) {
      dataFlowInfo =
          components
              .dataFlowAnalyzer
              .extractDataFlowInfoFromCondition(condition, false, context)
              .and(dataFlowInfo);
    }

    // Special case: while (true)
    // In this case we must record data flow information at the nearest break / continue and
    // .and it with entrance data flow information, because while body until break is executed at
    // least once in this case
    // See KT-6284
    if (body != null && KtPsiUtil.isTrueConstant(condition)) {
      // We should take data flow info from the first jump point,
      // but without affecting changing variables
      dataFlowInfo =
          dataFlowInfo.and(
              loopVisitor.clearDataFlowInfoForAssignedLocalVariables(
                  bodyTypeInfo.getJumpFlowInfo()));
    }
    return components
        .dataFlowAnalyzer
        .checkType(
            bodyTypeInfo.replaceType(components.builtIns.getUnitType()),
            expression,
            contextWithExpectedType)
        .replaceDataFlowInfo(dataFlowInfo);
  }
 @NotNull
 public KotlinTypeInfo getTypeInfo(
     @NotNull KtExpression expression, @NotNull ResolutionContext resolutionContext) {
   return expressionTypingFacade.getTypeInfo(
       expression, ExpressionTypingContext.newContext(resolutionContext));
 }
  public KotlinTypeInfo visitIfExpression(
      KtIfExpression ifExpression,
      ExpressionTypingContext contextWithExpectedType,
      boolean isStatement) {
    ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE);
    KtExpression condition = ifExpression.getCondition();
    DataFlowInfo conditionDataFlowInfo = checkCondition(context.scope, condition, context);

    KtExpression elseBranch = ifExpression.getElse();
    KtExpression thenBranch = ifExpression.getThen();

    LexicalWritableScope thenScope = newWritableScopeImpl(context, "Then scope");
    LexicalWritableScope elseScope = newWritableScopeImpl(context, "Else scope");
    DataFlowInfo thenInfo =
        components
            .dataFlowAnalyzer
            .extractDataFlowInfoFromCondition(condition, true, context)
            .and(conditionDataFlowInfo);
    DataFlowInfo elseInfo =
        components
            .dataFlowAnalyzer
            .extractDataFlowInfoFromCondition(condition, false, context)
            .and(conditionDataFlowInfo);

    if (elseBranch == null) {
      if (thenBranch != null) {
        KotlinTypeInfo result =
            getTypeInfoWhenOnlyOneBranchIsPresent(
                thenBranch,
                thenScope,
                thenInfo,
                elseInfo,
                contextWithExpectedType,
                ifExpression,
                isStatement);
        // If jump was possible, take condition check info as the jump info
        return result.getJumpOutPossible()
            ? result.replaceJumpOutPossible(true).replaceJumpFlowInfo(conditionDataFlowInfo)
            : result;
      }
      return TypeInfoFactoryKt.createTypeInfo(
          components.dataFlowAnalyzer.checkImplicitCast(
              components.builtIns.getUnitType(),
              ifExpression,
              contextWithExpectedType,
              isStatement),
          thenInfo.or(elseInfo));
    }
    if (thenBranch == null) {
      return getTypeInfoWhenOnlyOneBranchIsPresent(
          elseBranch,
          elseScope,
          elseInfo,
          thenInfo,
          contextWithExpectedType,
          ifExpression,
          isStatement);
    }
    KtPsiFactory psiFactory = KtPsiFactoryKt.KtPsiFactory(ifExpression);
    KtBlockExpression thenBlock = psiFactory.wrapInABlockWrapper(thenBranch);
    KtBlockExpression elseBlock = psiFactory.wrapInABlockWrapper(elseBranch);
    Call callForIf =
        createCallForSpecialConstruction(
            ifExpression, ifExpression, Lists.newArrayList(thenBlock, elseBlock));
    MutableDataFlowInfoForArguments dataFlowInfoForArguments =
        createDataFlowInfoForArgumentsForIfCall(callForIf, thenInfo, elseInfo);
    ResolvedCall<FunctionDescriptor> resolvedCall =
        components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
            callForIf,
            ResolveConstruct.IF,
            Lists.newArrayList("thenBranch", "elseBranch"),
            Lists.newArrayList(false, false),
            contextWithExpectedType,
            dataFlowInfoForArguments);

    BindingContext bindingContext = context.trace.getBindingContext();
    KotlinTypeInfo thenTypeInfo =
        BindingContextUtils.getRecordedTypeInfo(thenBranch, bindingContext);
    KotlinTypeInfo elseTypeInfo =
        BindingContextUtils.getRecordedTypeInfo(elseBranch, bindingContext);
    assert thenTypeInfo != null
        : "'Then' branch of if expression  was not processed: " + ifExpression;
    assert elseTypeInfo != null
        : "'Else' branch of if expression  was not processed: " + ifExpression;
    boolean loopBreakContinuePossible =
        thenTypeInfo.getJumpOutPossible() || elseTypeInfo.getJumpOutPossible();

    KotlinType thenType = thenTypeInfo.getType();
    KotlinType elseType = elseTypeInfo.getType();
    DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo();
    DataFlowInfo elseDataFlowInfo = elseTypeInfo.getDataFlowInfo();

    boolean jumpInThen = thenType != null && KotlinBuiltIns.isNothing(thenType);
    boolean jumpInElse = elseType != null && KotlinBuiltIns.isNothing(elseType);

    DataFlowInfo resultDataFlowInfo;
    if (thenType == null && elseType == null) {
      resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo);
    } else if (thenType == null || (jumpInThen && !jumpInElse)) {
      resultDataFlowInfo = elseDataFlowInfo;
    } else if (elseType == null || (jumpInElse && !jumpInThen)) {
      resultDataFlowInfo = thenDataFlowInfo;
    } else {
      resultDataFlowInfo = thenDataFlowInfo.or(elseDataFlowInfo);
    }

    KotlinType resultType = resolvedCall.getResultingDescriptor().getReturnType();
    // If break or continue was possible, take condition check info as the jump info
    return TypeInfoFactoryKt.createTypeInfo(
        components.dataFlowAnalyzer.checkImplicitCast(
            resultType, ifExpression, contextWithExpectedType, isStatement),
        resultDataFlowInfo,
        loopBreakContinuePossible,
        conditionDataFlowInfo);
  }