|
28 | 28 | import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionCallbacksImpl;
|
29 | 29 | import org.jetbrains.kotlin.resolve.calls.tower.LambdaContextInfo;
|
30 | 30 | import org.jetbrains.kotlin.resolve.scopes.*;
|
| 31 | +import org.jetbrains.kotlin.types.KotlinType; |
31 | 32 | import org.jetbrains.kotlin.types.error.ErrorTypeKind;
|
32 | 33 | import org.jetbrains.kotlin.types.error.ErrorUtils;
|
33 |
| -import org.jetbrains.kotlin.types.KotlinType; |
34 | 34 | import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
|
35 | 35 | import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
|
36 | 36 |
|
@@ -382,7 +382,51 @@ private KotlinTypeInfo getTypeOfLastExpressionInBlock(
|
382 | 382 | )
|
383 | 383 | );
|
384 | 384 |
|
385 |
| - if (context.expectedType == NO_EXPECTED_TYPE && statementExpression instanceof KtCallableReferenceExpression) { |
| 385 | + // This part is necessary for properly handling the case of calls like `foo { ::bar }`. |
| 386 | + // In NI, `::bar` shouldn't be eagerly resolved, but introduced as a postponed atom to the general inference system. |
| 387 | + // The correct definition for the case would be satisfaction of three conditions: |
| 388 | + // (1) lastStatement is KtCallableReferenceExpression |
| 389 | + // (2) expected type is not Unit |
| 390 | + // (3) lastStatement.parent.parent [statement -> block -> function literal] is a lambda that is handled by NI |
| 391 | + // |
| 392 | + // When the conditions are met, `createCallArgument` at `org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionCallbacksImpl.analyzeAndGetLambdaReturnArguments` |
| 393 | + // we just pick that last statement in the lambda. |
| 394 | + // |
| 395 | + // But due to a bug in initial implementation `createDontCareTypeInfoForNILambda` (third condition), it was checking that |
| 396 | + // "lastStatement has a NI lambda among one of the parents". |
| 397 | + // |
| 398 | + // That immediately leads to incorrectly treatment of cases like: |
| 399 | + // foo { |
| 400 | + // val x = if (b) { |
| 401 | + // ::baz <-- the problem is here |
| 402 | + // } else { |
| 403 | + // .... |
| 404 | + // } |
| 405 | + // println() |
| 406 | + // } |
| 407 | + // |
| 408 | + // The problem with the `::baz` is that it should not be processed as a postponed atom for the call, but it has been. |
| 409 | + // At the same time, it's being ignored by the NI (because it's not the last statement), thus left unresolved. |
| 410 | + // The bugs are described at KT-52270 and KT-55931. |
| 411 | + // |
| 412 | + // During attempt to fix KT-52270, instead of fixing the third condition (that is actually broken), the second one has been changed to |
| 413 | + // "expected type is NO_EXPECTED_TYPE". |
| 414 | + // That helped to the main use case from the issue, but still didn't help with KT-55931. |
| 415 | + // |
| 416 | + // But the actual problem is that brought another regression bug (KT-55729) because after that we started |
| 417 | + // resolving last-statement callable references with expected type eagerly as regular top-level references (without conversions). |
| 418 | + // So, conversions stopped working there since 1.8.0 |
| 419 | + // |
| 420 | + // While it might be tempting to revert the incorrect fix for KT-52270, and fix the third condition, we can't do it easily |
| 421 | + // because it should be a language feature (since it allows new green code), that can't be released in 1.8.10. |
| 422 | + // So, we're just trying to _partially_ revert the change, by allowing skipping reference not only in case of NO_EXPECTED_TYPE |
| 423 | + // but also in case we have non-trivial expected type AND lastStatement.parent.parent is function literal. |
| 424 | + // |
| 425 | + // That would mean that everything will work just the same as in 1.8.0, but the single case of |
| 426 | + // `expectSomeSpecificFunctionTypeReturnedFromLambda { ::functionNeededAConversion }` (that was been working in 1.7.20). |
| 427 | + // |
| 428 | + // On the KT-55931, currently we don't have plans to fix it until K2 (where it already seems to be fixed). |
| 429 | + if (isCallableReferenceShouldBeAttemptedToBeProcessedByNI(statementExpression, context, isUnitExpectedType)) { |
386 | 430 | KotlinTypeInfo typeInfo = createDontCareTypeInfoForNILambda(statementExpression, context);
|
387 | 431 | if (typeInfo != null) return typeInfo;
|
388 | 432 | }
|
@@ -430,6 +474,19 @@ private KotlinTypeInfo getTypeOfLastExpressionInBlock(
|
430 | 474 | return result;
|
431 | 475 | }
|
432 | 476 |
|
| 477 | + private static boolean isCallableReferenceShouldBeAttemptedToBeProcessedByNI( |
| 478 | + @NotNull KtExpression statementExpression, |
| 479 | + @NotNull ExpressionTypingContext context, |
| 480 | + boolean isUnitExpectedType |
| 481 | + ) { |
| 482 | + if (!(statementExpression instanceof KtCallableReferenceExpression)) return false; |
| 483 | + if (context.expectedType == NO_EXPECTED_TYPE) return true; |
| 484 | + // This is condition we added after 1.8.0 to fix KT-55729 (see the comment above its single usage) |
| 485 | + if (!isUnitExpectedType && statementExpression.getParent().getParent() instanceof KtFunctionLiteral) return true; |
| 486 | + |
| 487 | + return false; |
| 488 | + } |
| 489 | + |
433 | 490 | @Nullable
|
434 | 491 | private static KotlinTypeInfo createDontCareTypeInfoForNILambda(
|
435 | 492 | @NotNull KtExpression statementExpression,
|
|
0 commit comments