22
22
import com .intellij .psi .util .PsiTreeUtil ;
23
23
import org .jetbrains .annotations .NotNull ;
24
24
import org .jetbrains .annotations .Nullable ;
25
+ import org .jetbrains .kotlin .JetNodeTypes ;
25
26
import org .jetbrains .kotlin .builtins .KotlinBuiltIns ;
26
27
import org .jetbrains .kotlin .descriptors .*;
27
28
import org .jetbrains .kotlin .diagnostics .Errors ;
@@ -139,10 +140,14 @@ public JetTypeInfo visitIfExpression(JetIfExpression ifExpression, ExpressionTyp
139
140
resultDataFlowInfo = thenDataFlowInfo .or (elseDataFlowInfo );
140
141
}
141
142
else if (thenType == null || (jumpInThen && !jumpInElse )) {
142
- resultDataFlowInfo = elseDataFlowInfo ;
143
+ resultDataFlowInfo = elseDataFlowInfo . jump () ;
143
144
}
144
145
else if (elseType == null || (jumpInElse && !jumpInThen )) {
145
- resultDataFlowInfo = thenDataFlowInfo ;
146
+ resultDataFlowInfo = thenDataFlowInfo .jump ();
147
+ }
148
+ // || jumpInElse: it is always false after jumpInThen check
149
+ else if (jumpInThen ) {
150
+ resultDataFlowInfo = thenDataFlowInfo .or (elseDataFlowInfo ).jump ();
146
151
}
147
152
else {
148
153
resultDataFlowInfo = thenDataFlowInfo .or (elseDataFlowInfo );
@@ -169,7 +174,7 @@ private JetTypeInfo getTypeInfoWhenOnlyOneBranchIsPresent(
169
174
JetType type = typeInfo .getType ();
170
175
DataFlowInfo dataFlowInfo ;
171
176
if (type != null && KotlinBuiltIns .isNothing (type )) {
172
- dataFlowInfo = otherInfo ;
177
+ dataFlowInfo = otherInfo . jump () ;
173
178
} else {
174
179
dataFlowInfo = typeInfo .getDataFlowInfo ().or (otherInfo );
175
180
}
@@ -182,6 +187,11 @@ public JetTypeInfo visitWhileExpression(@NotNull JetWhileExpression expression,
182
187
return visitWhileExpression (expression , context , false );
183
188
}
184
189
190
+ private static boolean isTrueConstant (JetExpression condition ) {
191
+ return (condition != null && condition .getNode ().getElementType () == JetNodeTypes .BOOLEAN_CONSTANT &&
192
+ "true" .equals (condition .getText ()));
193
+ }
194
+
185
195
public JetTypeInfo visitWhileExpression (JetWhileExpression expression , ExpressionTypingContext contextWithExpectedType , boolean isStatement ) {
186
196
if (!isStatement ) return DataFlowUtils .illegalStatementType (expression , contextWithExpectedType , facade );
187
197
@@ -191,17 +201,27 @@ public JetTypeInfo visitWhileExpression(JetWhileExpression expression, Expressio
191
201
DataFlowInfo dataFlowInfo = checkCondition (context .scope , condition , context );
192
202
193
203
JetExpression body = expression .getBody ();
204
+ // Special case: while (true)
205
+ // In this case we must record data flow information at the nearest break / continue and
206
+ // .and it with entrance data flow information, because while body until break is executed at least once in this case
207
+ // See KT-6284
208
+ ExpressionTypingServices .LoopJetTypeInfo bodyTypeInfo = null ;
194
209
if (body != null ) {
195
210
WritableScopeImpl scopeToExtend = newWritableScopeImpl (context , "Scope extended in while's condition" );
196
211
DataFlowInfo conditionInfo = DataFlowUtils .extractDataFlowInfoFromCondition (condition , true , context ).and (dataFlowInfo );
197
- components .expressionTypingServices .getBlockReturnedTypeWithWritableScope (
212
+ bodyTypeInfo = components .expressionTypingServices .getBlockReturnedTypeWithWritableScope (
198
213
scopeToExtend , Collections .singletonList (body ),
199
214
CoercionStrategy .NO_COERCION , context .replaceDataFlowInfo (conditionInfo ));
200
215
}
201
216
202
217
if (!containsJumpOutOfLoop (expression , context )) {
203
218
dataFlowInfo = DataFlowUtils .extractDataFlowInfoFromCondition (condition , false , context ).and (dataFlowInfo );
204
219
}
220
+
221
+ // While (true) only should be considered here
222
+ if (bodyTypeInfo != null && isTrueConstant (condition )) {
223
+ dataFlowInfo = dataFlowInfo .and (bodyTypeInfo .getJumpFlowInfo ());
224
+ }
205
225
return DataFlowUtils .checkType (components .builtIns .getUnitType (), expression , contextWithExpectedType , dataFlowInfo );
206
226
}
207
227
@@ -255,13 +275,17 @@ public JetTypeInfo visitDoWhileExpression(JetDoWhileExpression expression, Expre
255
275
contextWithExpectedType .replaceExpectedType (NO_EXPECTED_TYPE ).replaceContextDependency (INDEPENDENT );
256
276
JetExpression body = expression .getBody ();
257
277
JetScope conditionScope = context .scope ;
278
+ // Here we must record data flow information at the end of the body (or at the first jump, to be precise) and
279
+ // .and it with entrance data flow information, because do-while body is executed at least once
280
+ // See KT-6283
281
+ ExpressionTypingServices .LoopJetTypeInfo bodyTypeInfo = null ;
258
282
if (body instanceof JetFunctionLiteralExpression ) {
259
283
JetFunctionLiteralExpression function = (JetFunctionLiteralExpression ) body ;
260
284
JetFunctionLiteral functionLiteral = function .getFunctionLiteral ();
261
285
if (!functionLiteral .hasParameterSpecification ()) {
262
286
WritableScope writableScope = newWritableScopeImpl (context , "do..while body scope" );
263
287
conditionScope = writableScope ;
264
- components .expressionTypingServices .getBlockReturnedTypeWithWritableScope (
288
+ bodyTypeInfo = components .expressionTypingServices .getBlockReturnedTypeWithWritableScope (
265
289
writableScope , functionLiteral .getBodyExpression ().getStatements (), CoercionStrategy .NO_COERCION , context );
266
290
context .trace .record (BindingContext .BLOCK , function );
267
291
}
@@ -279,7 +303,7 @@ else if (body != null) {
279
303
else {
280
304
block = Collections .<JetElement >singletonList (body );
281
305
}
282
- components .expressionTypingServices .getBlockReturnedTypeWithWritableScope (
306
+ bodyTypeInfo = components .expressionTypingServices .getBlockReturnedTypeWithWritableScope (
283
307
writableScope , block , CoercionStrategy .NO_COERCION , context );
284
308
}
285
309
JetExpression condition = expression .getCondition ();
@@ -291,6 +315,9 @@ else if (body != null) {
291
315
else {
292
316
dataFlowInfo = context .dataFlowInfo ;
293
317
}
318
+ if (bodyTypeInfo != null ) {
319
+ dataFlowInfo = dataFlowInfo .and (bodyTypeInfo .getJumpFlowInfo ());
320
+ }
294
321
return DataFlowUtils .checkType (components .builtIns .getUnitType (), expression , contextWithExpectedType , dataFlowInfo );
295
322
}
296
323
@@ -512,13 +539,13 @@ private static boolean isClassInitializer(@NotNull Pair<FunctionDescriptor, PsiE
512
539
@ Override
513
540
public JetTypeInfo visitBreakExpression (@ NotNull JetBreakExpression expression , ExpressionTypingContext context ) {
514
541
LabelResolver .INSTANCE .resolveControlLabel (expression , context );
515
- return DataFlowUtils .checkType (components .builtIns .getNothingType (), expression , context , context .dataFlowInfo );
542
+ return DataFlowUtils .checkType (components .builtIns .getNothingType (), expression , context , context .dataFlowInfo . jump () );
516
543
}
517
544
518
545
@ Override
519
546
public JetTypeInfo visitContinueExpression (@ NotNull JetContinueExpression expression , ExpressionTypingContext context ) {
520
547
LabelResolver .INSTANCE .resolveControlLabel (expression , context );
521
- return DataFlowUtils .checkType (components .builtIns .getNothingType (), expression , context , context .dataFlowInfo );
548
+ return DataFlowUtils .checkType (components .builtIns .getNothingType (), expression , context , context .dataFlowInfo . jump () );
522
549
}
523
550
524
551
@ NotNull
0 commit comments