Fix for KT-7557: NoSuchMethodError when capturing receiver in object expression

#KT-7557 Fixed
   #KT-7769 Fixed
This commit is contained in:
Michael Bogdanov
2015-05-19 11:38:23 +03:00
parent 34100fff99
commit 319c5aec60
5 changed files with 102 additions and 7 deletions
@@ -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");
@@ -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");