local functions
This commit is contained in:
@@ -83,7 +83,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
|
||||
return state.getTypeMapper().mapSignature("invoke", fd);
|
||||
}
|
||||
|
||||
public GeneratedAnonymousClassDescriptor gen(JetFunctionLiteralExpression fun) {
|
||||
public GeneratedAnonymousClassDescriptor gen(JetExpression fun) {
|
||||
final Pair<String, ClassBuilder> nameAndVisitor = state.forAnonymousSubclass(fun);
|
||||
|
||||
final FunctionDescriptor funDescriptor = (FunctionDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, fun);
|
||||
@@ -115,7 +115,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
|
||||
|
||||
|
||||
generateBridge(name, funDescriptor, fun, cv);
|
||||
captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
|
||||
captureThis = generateBody(funDescriptor, cv, (JetDeclarationWithBody) fun);
|
||||
ClassDescriptor thisDescriptor = context.getThisDescriptor();
|
||||
final Type enclosingType = thisDescriptor == null ? null : state.getTypeMapper().mapType(thisDescriptor.getDefaultType());
|
||||
if (enclosingType == null)
|
||||
|
||||
@@ -88,7 +88,7 @@ public class CodegenUtil {
|
||||
return hasDerivedTypeInfoField(type);
|
||||
}
|
||||
|
||||
public static NamedFunctionDescriptor createInvoke(ExpressionAsFunctionDescriptor fd) {
|
||||
public static NamedFunctionDescriptor createInvoke(FunctionDescriptor fd) {
|
||||
int arity = fd.getValueParameters().size();
|
||||
NamedFunctionDescriptorImpl invokeDescriptor = new NamedFunctionDescriptorImpl(
|
||||
fd.getExpectedThisObject().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity),
|
||||
|
||||
@@ -161,11 +161,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitNamedFunction(JetNamedFunction function, StackValue data) {
|
||||
throw new UnsupportedOperationException("Codegen for local functions is not yet implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) {
|
||||
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
||||
@@ -712,6 +707,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return generateBlock(statements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitNamedFunction(JetNamedFunction function, StackValue data) {
|
||||
assert data == StackValue.none();
|
||||
StackValue closure = genClosure(function);
|
||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
|
||||
int index = myFrameMap.getIndex(descriptor);
|
||||
closure.put(TYPE_OBJECT, v);
|
||||
v.store(index, TYPE_OBJECT);
|
||||
return StackValue.none();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, StackValue receiver) {
|
||||
//noinspection ConstantConditions
|
||||
@@ -720,40 +726,44 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
return generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
|
||||
}
|
||||
else {
|
||||
ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context);
|
||||
final GeneratedAnonymousClassDescriptor closure = closureCodegen.gen(expression);
|
||||
|
||||
if(closureCodegen.isConst()) {
|
||||
v.invokestatic(closure.getClassname(), "$getInstance", "()L" + closure.getClassname() + ";");
|
||||
}
|
||||
else {
|
||||
v.anew(Type.getObjectType(closure.getClassname()));
|
||||
v.dup();
|
||||
|
||||
final Method cons = closure.getConstructor();
|
||||
|
||||
int k = 0;
|
||||
if (closure.isCaptureThis()) {
|
||||
k++;
|
||||
v.load(0, TYPE_OBJECT);
|
||||
}
|
||||
|
||||
if (closure.isCaptureReceiver() != null) {
|
||||
k++;
|
||||
v.load(context.getContextDescriptor().getContainingDeclaration() instanceof NamespaceDescriptor ? 0: 1, closure.isCaptureReceiver());
|
||||
}
|
||||
|
||||
for (int i = 0; i < closure.getArgs().size(); i++) {
|
||||
StackValue arg = closure.getArgs().get(i);
|
||||
arg.put(cons.getArgumentTypes()[i+k], v);
|
||||
}
|
||||
|
||||
v.invokespecial(closure.getClassname(), "<init>", cons.getDescriptor());
|
||||
}
|
||||
return StackValue.onStack(Type.getObjectType(closure.getClassname()));
|
||||
return genClosure(expression);
|
||||
}
|
||||
}
|
||||
|
||||
private StackValue genClosure(JetExpression expression) {
|
||||
ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context);
|
||||
final GeneratedAnonymousClassDescriptor closure = closureCodegen.gen(expression);
|
||||
|
||||
if(closureCodegen.isConst()) {
|
||||
v.invokestatic(closure.getClassname(), "$getInstance", "()L" + closure.getClassname() + ";");
|
||||
}
|
||||
else {
|
||||
v.anew(Type.getObjectType(closure.getClassname()));
|
||||
v.dup();
|
||||
|
||||
final Method cons = closure.getConstructor();
|
||||
|
||||
int k = 0;
|
||||
if (closure.isCaptureThis()) {
|
||||
k++;
|
||||
v.load(0, TYPE_OBJECT);
|
||||
}
|
||||
|
||||
if (closure.isCaptureReceiver() != null) {
|
||||
k++;
|
||||
v.load(context.getContextDescriptor().getContainingDeclaration() instanceof NamespaceDescriptor ? 0: 1, closure.isCaptureReceiver());
|
||||
}
|
||||
|
||||
for (int i = 0; i < closure.getArgs().size(); i++) {
|
||||
StackValue arg = closure.getArgs().get(i);
|
||||
arg.put(cons.getArgumentTypes()[i+k], v);
|
||||
}
|
||||
|
||||
v.invokespecial(closure.getClassname(), "<init>", cons.getDescriptor());
|
||||
}
|
||||
return StackValue.onStack(Type.getObjectType(closure.getClassname()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitObjectLiteralExpression(JetObjectLiteralExpression expression, StackValue receiver) {
|
||||
ObjectOrClosureCodegen closureCodegen = new ObjectOrClosureCodegen(this, context, state);
|
||||
@@ -811,6 +821,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
final Type type = sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getOutType());
|
||||
myFrameMap.enter(variableDescriptor, type.getSize());
|
||||
}
|
||||
|
||||
if(statement instanceof JetNamedFunction) {
|
||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, statement);
|
||||
myFrameMap.enter(descriptor, 1);
|
||||
}
|
||||
}
|
||||
|
||||
StackValue answer = StackValue.none();
|
||||
@@ -831,6 +846,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
v.mark(blockEnd);
|
||||
|
||||
for (JetElement statement : statements) {
|
||||
if(statement instanceof JetNamedFunction) {
|
||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, statement);
|
||||
myFrameMap.leave(descriptor);
|
||||
}
|
||||
|
||||
if (statement instanceof JetProperty) {
|
||||
JetProperty var = (JetProperty) statement;
|
||||
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var);
|
||||
@@ -946,13 +966,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
|
||||
int index = lookupLocal(descriptor);
|
||||
if (index >= 0) {
|
||||
Type sharedVarType = typeMapper.getSharedVarType(descriptor);
|
||||
final JetType outType = ((VariableDescriptor) descriptor).getOutType();
|
||||
if(sharedVarType != null) {
|
||||
return StackValue.shared(index, asmType(outType));
|
||||
if(descriptor instanceof VariableDescriptor) {
|
||||
Type sharedVarType = typeMapper.getSharedVarType(descriptor);
|
||||
final JetType outType = ((VariableDescriptor) descriptor).getOutType();
|
||||
if(sharedVarType != null) {
|
||||
return StackValue.shared(index, asmType(outType));
|
||||
}
|
||||
else {
|
||||
return StackValue.local(index, asmType(outType));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return StackValue.local(index, asmType(outType));
|
||||
return StackValue.local(index, TYPE_OBJECT);
|
||||
}
|
||||
}
|
||||
else if (descriptor instanceof PropertyDescriptor) {
|
||||
@@ -1266,8 +1291,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
assert !superCall;
|
||||
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
|
||||
}
|
||||
else if (fd instanceof ExpressionAsFunctionDescriptor) {
|
||||
NamedFunctionDescriptor invoke = CodegenUtil.createInvoke((ExpressionAsFunctionDescriptor) fd);
|
||||
else if (fd instanceof ExpressionAsFunctionDescriptor || (fd instanceof NamedFunctionDescriptor && fd.getContainingDeclaration() instanceof FunctionDescriptor)) {
|
||||
NamedFunctionDescriptor invoke = CodegenUtil.createInvoke((FunctionDescriptor) fd);
|
||||
callableMethod = ClosureCodegen.asCallableMethod(invoke);
|
||||
}
|
||||
else if (fd instanceof FunctionDescriptor) {
|
||||
|
||||
@@ -827,6 +827,10 @@ public class JetTypeMapper {
|
||||
if(descriptor instanceof PropertyDescriptor) {
|
||||
return StackValue.sharedTypeForType(mapType(((PropertyDescriptor) descriptor).getReceiverParameter().getType()));
|
||||
}
|
||||
else if (descriptor instanceof NamedFunctionDescriptor && descriptor.getContainingDeclaration() instanceof FunctionDescriptor) {
|
||||
PsiElement psiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
|
||||
return Type.getObjectType(classNameForAnonymousClass((JetElement) psiElement));
|
||||
}
|
||||
else if (descriptor instanceof FunctionDescriptor) {
|
||||
return StackValue.sharedTypeForType(mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType()));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
fun box() : String {
|
||||
var seed = 0
|
||||
fun local(x: Int) {
|
||||
fun deep() {
|
||||
seed += x
|
||||
}
|
||||
fun deep2(x : Int) {
|
||||
seed += x
|
||||
}
|
||||
fun Int.iter() {
|
||||
seed += this
|
||||
}
|
||||
|
||||
deep()
|
||||
deep2(-x)
|
||||
x.iter()
|
||||
seed += x
|
||||
}
|
||||
|
||||
for(i in 1..5) {
|
||||
fun Int.iter() {
|
||||
seed += this
|
||||
}
|
||||
|
||||
local(i)
|
||||
(-i).iter()
|
||||
}
|
||||
|
||||
|
||||
return if(seed == 15) "OK" else seed.toString()
|
||||
}
|
||||
@@ -48,4 +48,8 @@ public class FunctionGenTest extends CodegenTestCase {
|
||||
public void testFunction () throws InvocationTargetException, IllegalAccessException {
|
||||
blackBoxFile("functions/functionExpression.jet");
|
||||
}
|
||||
|
||||
public void testLocalFunction () throws InvocationTargetException, IllegalAccessException {
|
||||
blackBoxFile("functions/localFunction.kt");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user