From bf3e896464e689043b19a70fb6bd4dfb8196084a Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 19 Jul 2017 11:56:42 +0300 Subject: [PATCH] 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. --- .../kotlin/resolve/calls/CandidateResolver.kt | 3 +++ .../calls/model/MutableResolvedCall.java | 2 ++ .../resolve/calls/model/ResolvedCallImpl.java | 14 +++++++++++++- .../codegen/box/smartCasts/kt19058.kt | 19 +++++++++++++++++++ .../codegen/box/smartCasts/kt19100.kt | 12 ++++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 12 ++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 12 ++++++++++++ .../LightAnalysisModeTestGenerated.java | 12 ++++++++++++ .../semantics/JsCodegenBoxTestGenerated.java | 6 ++++++ 9 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/codegen/box/smartCasts/kt19058.kt create mode 100644 compiler/testData/codegen/box/smartCasts/kt19100.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt index c8edfe81d8e..807f10bec6d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -566,6 +566,9 @@ class CandidateResolver( if (isDispatchReceiver) { candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType) } + else { + candidateCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType) + } if (!smartCastResult.isCorrect) { // Error about unstable smart cast reported within checkAndRecordPossibleCast return UNSTABLE_SMARTCAST_FOR_RECEIVER_ERROR diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/MutableResolvedCall.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/MutableResolvedCall.java index 9b1968f1d19..e18ad4ac416 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/MutableResolvedCall.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/MutableResolvedCall.java @@ -67,4 +67,6 @@ public interface MutableResolvedCall extends Resol boolean hasInferredReturnType(); void setSmartCastDispatchReceiverType(@NotNull KotlinType smartCastDispatchReceiverType); + + void updateExtensionReceiverWithSmartCastIfNeeded(@NotNull KotlinType smartCastExtensionReceiverType); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java index a4935cd76b9..73be3a9dbe0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/model/ResolvedCallImpl.java @@ -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.ResolutionCandidate; 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.types.KotlinType; import org.jetbrains.kotlin.types.TypeProjection; @@ -60,7 +62,7 @@ public class ResolvedCallImpl implements MutableRe private final D candidateDescriptor; private D resultingDescriptor; // Probably substituted 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 TypeSubstitutor knownTypeParametersSubstitutor; @@ -378,4 +380,14 @@ public class ResolvedCallImpl implements MutableRe public KotlinType getSmartCastDispatchReceiverType() { return smartCastDispatchReceiverType; } + + @Override + public void updateExtensionReceiverWithSmartCastIfNeeded(@NotNull KotlinType smartCastExtensionReceiverType) { + if (extensionReceiver instanceof ImplicitClassReceiver) { + extensionReceiver = new CastImplicitClassReceiver( + ((ImplicitClassReceiver) extensionReceiver).getClassDescriptor(), + smartCastExtensionReceiverType + ); + } + } } diff --git a/compiler/testData/codegen/box/smartCasts/kt19058.kt b/compiler/testData/codegen/box/smartCasts/kt19058.kt new file mode 100644 index 00000000000..0bf2c376954 --- /dev/null +++ b/compiler/testData/codegen/box/smartCasts/kt19058.kt @@ -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"; + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/smartCasts/kt19100.kt b/compiler/testData/codegen/box/smartCasts/kt19100.kt new file mode 100644 index 00000000000..43113a91d5e --- /dev/null +++ b/compiler/testData/codegen/box/smartCasts/kt19100.kt @@ -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() \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 47a31875548..444c795607b 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -17600,6 +17600,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes 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") public void testLambdaArgumentWithoutType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 6af9e5fd91a..54242d1b47b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -17600,6 +17600,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { 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") public void testLambdaArgumentWithoutType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index a18e7494ba7..b922373dadc 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -17600,6 +17600,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes 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") public void testLambdaArgumentWithoutType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 2babc736eb7..17b1e3b5c96 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -21506,6 +21506,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { 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") public void testLambdaArgumentWithoutType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt");