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:
Dmitry Petrov
2017-07-19 11:56:42 +03:00
parent c9d54d7110
commit bf3e896464
9 changed files with 91 additions and 1 deletions
@@ -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
@@ -67,4 +67,6 @@ public interface MutableResolvedCall<D extends CallableDescriptor> extends Resol
boolean hasInferredReturnType();
void setSmartCastDispatchReceiverType(@NotNull KotlinType smartCastDispatchReceiverType);
void updateExtensionReceiverWithSmartCastIfNeeded(@NotNull KotlinType smartCastExtensionReceiverType);
}
@@ -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<D extends CallableDescriptor> 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<D extends CallableDescriptor> 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
);
}
}
}
+19
View File
@@ -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";
}
}
+12
View File
@@ -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()
@@ -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");
@@ -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");
@@ -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");
@@ -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");