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 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 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);
  }