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