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