Update 'this' extension receiver when there's a smart cast
If 'this' (implicit or explicit) was used as an extension receiver, and the corresponding call required a smart-cast, this information was effectively lost in "old" resolution & inference, but is required by "old" JVM BE to generate proper CHECKCASTs.
This commit is contained in:
@@ -566,6 +566,9 @@ class CandidateResolver(
|
|||||||
if (isDispatchReceiver) {
|
if (isDispatchReceiver) {
|
||||||
candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType)
|
candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
candidateCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
|
||||||
|
}
|
||||||
if (!smartCastResult.isCorrect) {
|
if (!smartCastResult.isCorrect) {
|
||||||
// Error about unstable smart cast reported within checkAndRecordPossibleCast
|
// Error about unstable smart cast reported within checkAndRecordPossibleCast
|
||||||
return UNSTABLE_SMARTCAST_FOR_RECEIVER_ERROR
|
return UNSTABLE_SMARTCAST_FOR_RECEIVER_ERROR
|
||||||
|
|||||||
+2
@@ -67,4 +67,6 @@ public interface MutableResolvedCall<D extends CallableDescriptor> extends Resol
|
|||||||
boolean hasInferredReturnType();
|
boolean hasInferredReturnType();
|
||||||
|
|
||||||
void setSmartCastDispatchReceiverType(@NotNull KotlinType smartCastDispatchReceiverType);
|
void setSmartCastDispatchReceiverType(@NotNull KotlinType smartCastDispatchReceiverType);
|
||||||
|
|
||||||
|
void updateExtensionReceiverWithSmartCastIfNeeded(@NotNull KotlinType smartCastExtensionReceiverType);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -33,6 +33,8 @@ import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus;
|
|||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
|
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
|
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver;
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
import org.jetbrains.kotlin.types.TypeProjection;
|
import org.jetbrains.kotlin.types.TypeProjection;
|
||||||
@@ -60,7 +62,7 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
|
|||||||
private final D candidateDescriptor;
|
private final D candidateDescriptor;
|
||||||
private D resultingDescriptor; // Probably substituted
|
private D resultingDescriptor; // Probably substituted
|
||||||
private final ReceiverValue dispatchReceiver; // receiver object of a method
|
private final ReceiverValue dispatchReceiver; // receiver object of a method
|
||||||
private final ReceiverValue extensionReceiver; // receiver of an extension function
|
private ReceiverValue extensionReceiver; // receiver of an extension function
|
||||||
private final ExplicitReceiverKind explicitReceiverKind;
|
private final ExplicitReceiverKind explicitReceiverKind;
|
||||||
private final TypeSubstitutor knownTypeParametersSubstitutor;
|
private final TypeSubstitutor knownTypeParametersSubstitutor;
|
||||||
|
|
||||||
@@ -378,4 +380,14 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
|
|||||||
public KotlinType getSmartCastDispatchReceiverType() {
|
public KotlinType getSmartCastDispatchReceiverType() {
|
||||||
return smartCastDispatchReceiverType;
|
return smartCastDispatchReceiverType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateExtensionReceiverWithSmartCastIfNeeded(@NotNull KotlinType smartCastExtensionReceiverType) {
|
||||||
|
if (extensionReceiver instanceof ImplicitClassReceiver) {
|
||||||
|
extensionReceiver = new CastImplicitClassReceiver(
|
||||||
|
((ImplicitClassReceiver) extensionReceiver).getClassDescriptor(),
|
||||||
|
smartCastExtensionReceiverType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// FILE: Test.kt
|
||||||
|
open class KFoo {
|
||||||
|
fun foo(): String {
|
||||||
|
if (this is KFooBar) return bar
|
||||||
|
throw AssertionError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KFooBar : KFoo(), JBar
|
||||||
|
|
||||||
|
fun box(): String = KFooBar().foo()
|
||||||
|
|
||||||
|
// FILE: JBar.java
|
||||||
|
public interface JBar {
|
||||||
|
default String getBar() {
|
||||||
|
return "OK";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
open class KFoo {
|
||||||
|
fun foo(): String {
|
||||||
|
if (this is KFooQux) return qux
|
||||||
|
throw AssertionError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KFooQux : KFoo()
|
||||||
|
|
||||||
|
val KFooQux.qux get() = "OK"
|
||||||
|
|
||||||
|
fun box() = KFooQux().foo()
|
||||||
+12
@@ -17600,6 +17600,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19058.kt")
|
||||||
|
public void testKt19058() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/kt19058.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19100.kt")
|
||||||
|
public void testKt19100() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/kt19100.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambdaArgumentWithoutType.kt")
|
@TestMetadata("lambdaArgumentWithoutType.kt")
|
||||||
public void testLambdaArgumentWithoutType() throws Exception {
|
public void testLambdaArgumentWithoutType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt");
|
||||||
|
|||||||
@@ -17600,6 +17600,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19058.kt")
|
||||||
|
public void testKt19058() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/kt19058.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19100.kt")
|
||||||
|
public void testKt19100() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/kt19100.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambdaArgumentWithoutType.kt")
|
@TestMetadata("lambdaArgumentWithoutType.kt")
|
||||||
public void testLambdaArgumentWithoutType() throws Exception {
|
public void testLambdaArgumentWithoutType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt");
|
||||||
|
|||||||
@@ -17600,6 +17600,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19058.kt")
|
||||||
|
public void testKt19058() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/kt19058.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19100.kt")
|
||||||
|
public void testKt19100() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/kt19100.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambdaArgumentWithoutType.kt")
|
@TestMetadata("lambdaArgumentWithoutType.kt")
|
||||||
public void testLambdaArgumentWithoutType() throws Exception {
|
public void testLambdaArgumentWithoutType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt");
|
||||||
|
|||||||
@@ -21506,6 +21506,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19100.kt")
|
||||||
|
public void testKt19100() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/kt19100.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambdaArgumentWithoutType.kt")
|
@TestMetadata("lambdaArgumentWithoutType.kt")
|
||||||
public void testLambdaArgumentWithoutType() throws Exception {
|
public void testLambdaArgumentWithoutType() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user