Move local fun callee generation to pushArgumentsWithCallReceiver.
Local fun callee generation via resolvedCall.resultingDescriptor not call
This commit is contained in:
@@ -1657,11 +1657,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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<StackValue, StackValue> 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(");
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user