diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 0300f37474f..6b982a090eb 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1657,11 +1657,6 @@ public class ExpressionCodegen extends JetVisitor implem } } - int index = lookupLocalIndex(descriptor); - if (index >= 0) { - return stackValueForLocal(descriptor, index); - } - if (descriptor instanceof PropertyDescriptor) { PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; @@ -1708,26 +1703,9 @@ public class ExpressionCodegen extends JetVisitor implem return StackValue.onStack(OBJECT_TYPE); } - StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false); - if (value != null) { - if (context.isSpecialStackValue(value)) { - return value; - } - - if (value instanceof StackValue.Composed) { - StackValue.Composed composed = (StackValue.Composed) value; - composed.prefix.put(OBJECT_TYPE, v); - value = composed.suffix; - } - - if (value instanceof StackValue.FieldForSharedVar) { - StackValue.FieldForSharedVar fieldForSharedVar = (StackValue.FieldForSharedVar) value; - Type sharedType = StackValue.sharedTypeForType(value.type); - v.visitFieldInsn(GETFIELD, fieldForSharedVar.owner.getInternalName(), fieldForSharedVar.name, - sharedType.getDescriptor()); - } - - return value; + StackValue localOrCaptured = findLocalOrCapturedValue(descriptor); + if (localOrCaptured != null) { + return localOrCaptured; } if (descriptor instanceof ValueParameterDescriptor && descriptor.getContainingDeclaration() instanceof ScriptDescriptor) { @@ -1744,6 +1722,37 @@ public class ExpressionCodegen extends JetVisitor implem throw new UnsupportedOperationException("don't know how to generate reference " + descriptor); } + @Nullable + public StackValue findLocalOrCapturedValue(@NotNull DeclarationDescriptor descriptor) { + int index = lookupLocalIndex(descriptor); + if (index >= 0) { + return stackValueForLocal(descriptor, index); + } + + StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false); + if (value == null) return null; + + if (context.isSpecialStackValue(value)) { + return value; + } + + if (value instanceof StackValue.Composed) { + StackValue.Composed composed = (StackValue.Composed) value; + composed.prefix.put(OBJECT_TYPE, v); + value = composed.suffix; + } + + if (value instanceof StackValue.FieldForSharedVar) { + StackValue.FieldForSharedVar fieldForSharedVar = (StackValue.FieldForSharedVar) value; + Type sharedType = StackValue.sharedTypeForType(value.type); + v.visitFieldInsn(GETFIELD, fieldForSharedVar.owner.getInternalName(), fieldForSharedVar.name, + sharedType.getDescriptor()); + } + + return value; + } + + private StackValue stackValueForLocal(DeclarationDescriptor descriptor, int index) { if (descriptor instanceof VariableDescriptor) { Type sharedVarType = typeMapper.getSharedVarType(descriptor); @@ -2010,25 +2019,6 @@ public class ExpressionCodegen extends JetVisitor implem Callable callable = resolveToCallable(accessibleFunctionDescriptor(fd), superCall); - if (callable instanceof CallableMethod) { - CallableMethod callableMethod = (CallableMethod) callable; - Type calleeType = callableMethod.getGenerateCalleeType(); - if (calleeType != null) { - assert !callableMethod.isNeedsThis() : "Method should have a receiver: " + resolvedCall.getResultingDescriptor(); - gen(call.getCalleeExpression(), calleeType); - } - } - - return invokeFunctionWithCalleeOnStack(call, receiver, resolvedCall, callable); - } - - @NotNull - private StackValue invokeFunctionWithCalleeOnStack( - @NotNull Call call, - @NotNull StackValue receiver, - @NotNull ResolvedCall resolvedCall, - @NotNull Callable callable - ) { if (callable instanceof CallableMethod) { CallableMethod callableMethod = (CallableMethod) callable; invokeMethodWithArguments(call, callableMethod, resolvedCall, receiver); @@ -2287,6 +2277,15 @@ public class ExpressionCodegen extends JetVisitor implem ) { CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); + //generate callee for local function + Type calleeType = callableMethod.getGenerateCalleeType(); + if (calleeType != null) { + StackValue value = findLocalOrCapturedValue(descriptor.getOriginal()); + assert value != null : "Local fun should be found in locals or in captured params: " + resolvedCall; + value.put(calleeType, v); + } + + //generate this (absent for local fun) and receiver if (!(descriptor instanceof ConstructorDescriptor)) { // otherwise already receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod); receiver.put(receiver.type, v); @@ -2530,12 +2529,7 @@ public class ExpressionCodegen extends JetVisitor implem } else { Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments); - Callable callable = codegen.resolveToCallable(codegen.accessibleFunctionDescriptor(referencedFunction), false); - StackValue receiver = generateCallee(codegen, callable); - if (extensionReceiver.exists()) { - receiver = StackValue.composed(receiver, receiverParameterStackValue(signature)); - } - result = codegen.invokeFunctionWithCalleeOnStack(call, receiver, fakeResolvedCall, callable); + result = codegen.invokeFunction(call, StackValue.none(), fakeResolvedCall); } InstructionAdapter v = codegen.v; @@ -2543,33 +2537,6 @@ public class ExpressionCodegen extends JetVisitor implem v.areturn(returnType); } - @NotNull - private StackValue generateCallee(@NotNull ExpressionCodegen codegen, @NotNull Callable callable) { - if (!(callable instanceof CallableMethod) || ((CallableMethod) callable).getGenerateCalleeType() == null) { - return StackValue.none(); - } - - // If referenced method is a CallableMethod with generateCalleeType != null, this means it's some kind of a closure - // (e.g. a local named function) and a non-trivial callee should be generated before calling invoke() - - BindingContext bindingContext = codegen.bindingContext; - ClassDescriptor closureClassOfReferenced = bindingContext.get(CLASS_FOR_FUNCTION, referencedFunction); - MutableClosure closureOfReferenced = bindingContext.get(CLOSURE, closureClassOfReferenced); - assert closureOfReferenced != null : - "Function mapped to CallableMethod with generateCalleeType != null must be a closure: " + referencedFunction; - if (isConst(closureOfReferenced)) { - // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance - // (instead of passing this instance to the constructor and storing as a field) - Type asmType = asmTypeForAnonymousClass(bindingContext, referencedFunction); - codegen.v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); - return StackValue.onStack(asmType); - } - else { - Type asmCallRefType = asmTypeForAnonymousClass(bindingContext, callableDescriptor); - return codegen.context.lookupInContext(referencedFunction, StackValue.local(0, asmCallRefType), state, false); - } - } - @NotNull private JetCallExpression constructFakeFunctionCall() { StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall("); diff --git a/compiler/testData/codegen/box/functions/localFunctions/kt4783.kt b/compiler/testData/codegen/box/functions/localFunctions/kt4783.kt new file mode 100644 index 00000000000..99902449e22 --- /dev/null +++ b/compiler/testData/codegen/box/functions/localFunctions/kt4783.kt @@ -0,0 +1,18 @@ +class T(val value: Int) { +} + +fun local() : Int { + + fun T.get(s: Int): Int { + return s * this.value + } + + var t = T(11) + return t[2] +} + +fun box() : String { + if (local() != 22) return "fail1 ${local()} " + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index aa25125d309..beff96793f6 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -2966,6 +2966,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/functions/localFunctions/kt4777.kt"); } + @TestMetadata("kt4783.kt") + public void testKt4783() throws Exception { + doTest("compiler/testData/codegen/box/functions/localFunctions/kt4783.kt"); + } + @TestMetadata("localFunctionInConstructor.kt") public void testLocalFunctionInConstructor() throws Exception { doTest("compiler/testData/codegen/box/functions/localFunctions/localFunctionInConstructor.kt");