Fix for KT-7557: NoSuchMethodError when capturing receiver in object expression
#KT-7557 Fixed #KT-7769 Fixed
This commit is contained in:
@@ -58,6 +58,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*;
|
||||
import org.jetbrains.kotlin.serialization.*;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver;
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
|
||||
@@ -75,6 +76,7 @@ import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
|
||||
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
|
||||
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getSecondaryConstructors;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
@@ -1281,12 +1283,15 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expr) {
|
||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr);
|
||||
|
||||
DeclarationDescriptor toLookup;
|
||||
if (isLocalFunction(descriptor)) {
|
||||
toLookup = descriptor;
|
||||
lookupInContext(descriptor);
|
||||
}
|
||||
else if (descriptor instanceof CallableMemberDescriptor) {
|
||||
toLookup = descriptor.getContainingDeclaration();
|
||||
ResolvedCall<? extends CallableDescriptor> call = getResolvedCall(expr, bindingContext);
|
||||
if (call != null) {
|
||||
lookupReceiver(call.getDispatchReceiver());
|
||||
lookupReceiver(call.getExtensionReceiver());
|
||||
}
|
||||
}
|
||||
else if (descriptor instanceof VariableDescriptor) {
|
||||
if (descriptor.getContainingDeclaration() instanceof ConstructorDescriptor) {
|
||||
@@ -1294,10 +1299,26 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
(ClassDescriptor) descriptor.getContainingDeclaration().getContainingDeclaration();
|
||||
if (classDescriptor == ImplementationBodyCodegen.this.descriptor) return;
|
||||
}
|
||||
toLookup = descriptor;
|
||||
lookupInContext(descriptor);
|
||||
}
|
||||
else return;
|
||||
}
|
||||
|
||||
private void lookupReceiver(@NotNull ReceiverValue value) {
|
||||
if (value instanceof ThisReceiver) {
|
||||
if (value instanceof ExtensionReceiver) {
|
||||
ReceiverParameterDescriptor parameter =
|
||||
((ExtensionReceiver) value).getDeclarationDescriptor().getExtensionReceiverParameter();
|
||||
assert parameter != null : "Extension receiver should exist: " + ((ExtensionReceiver) value).getDeclarationDescriptor();
|
||||
lookupInContext(parameter);
|
||||
}
|
||||
else {
|
||||
lookupInContext(((ThisReceiver) value).getDeclarationDescriptor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void lookupInContext(@NotNull DeclarationDescriptor toLookup) {
|
||||
context.lookupInContext(toLookup, StackValue.LOCAL_0, state, true);
|
||||
}
|
||||
|
||||
@@ -1307,13 +1328,13 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
assert descriptor instanceof CallableDescriptor ||
|
||||
descriptor instanceof ClassDescriptor : "'This' reference target should be class or callable descriptor but was " + descriptor;
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
context.lookupInContext(descriptor, StackValue.LOCAL_0, state, true);
|
||||
lookupInContext(descriptor);
|
||||
}
|
||||
|
||||
if (descriptor instanceof CallableDescriptor) {
|
||||
ReceiverParameterDescriptor parameter = ((CallableDescriptor) descriptor).getExtensionReceiverParameter();
|
||||
if (parameter != null) {
|
||||
context.lookupInContext(parameter, StackValue.LOCAL_0, state, true);
|
||||
lookupInContext(parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
interface B<T> {
|
||||
val bar: T
|
||||
}
|
||||
|
||||
fun String.foo() = object : B<String> {
|
||||
override val bar: String = length().toString()
|
||||
}
|
||||
|
||||
class C {
|
||||
|
||||
fun String.extension() = this.length()
|
||||
|
||||
fun String.fooInClass() = object : B<String> {
|
||||
override val bar: String = extension().toString()
|
||||
}
|
||||
|
||||
fun String.fooInClassNoReceiver() = object : B<String> {
|
||||
override val bar: String = "123".extension().toString()
|
||||
}
|
||||
|
||||
fun fooInClass(s: String) = s.fooInClass().bar
|
||||
|
||||
fun fooInClassNoReceiver(s: String) = s.fooInClassNoReceiver().bar
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var result = "Hello, world!".foo().bar
|
||||
if (result != "13") return "fail 1: $result"
|
||||
|
||||
result = C().fooInClass("Hello, world!")
|
||||
|
||||
if (result != "13") return "fail 2: $result"
|
||||
|
||||
result = C().fooInClassNoReceiver("Hello, world!")
|
||||
|
||||
if (result != "3") return "fail 3: $result"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
interface B<T> {
|
||||
val bar: T
|
||||
}
|
||||
|
||||
class S(val value: String) {
|
||||
|
||||
fun bar() = value
|
||||
|
||||
fun foo(): B<String> {
|
||||
val p = S("OK");
|
||||
return object : B<String> {
|
||||
//we shouldn't capture this@S in such case
|
||||
override val bar: String = p.bar()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return S("fail").foo().bar
|
||||
}
|
||||
|
||||
// 0 this$0
|
||||
@@ -161,6 +161,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt7769.kt")
|
||||
public void testKt7769() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/kt7769.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noFlagAnnotations.kt")
|
||||
public void testNoFlagAnnotations() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/noFlagAnnotations.kt");
|
||||
|
||||
+6
@@ -1537,6 +1537,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/closures"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("captureExtensionReceiver.kt")
|
||||
public void testCaptureExtensionReceiver() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/captureExtensionReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("capturedLocalGenericFun.kt")
|
||||
public void testCapturedLocalGenericFun() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/closures/capturedLocalGenericFun.kt");
|
||||
|
||||
Reference in New Issue
Block a user