local functions

This commit is contained in:
Alex Tkachman
2012-01-29 16:19:47 +03:00
parent 656689c576
commit c62bbdc5df
6 changed files with 110 additions and 46 deletions
@@ -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");
}
}