local functions
This commit is contained in:
@@ -83,7 +83,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
|
|||||||
return state.getTypeMapper().mapSignature("invoke", fd);
|
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 Pair<String, ClassBuilder> nameAndVisitor = state.forAnonymousSubclass(fun);
|
||||||
|
|
||||||
final FunctionDescriptor funDescriptor = (FunctionDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, 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);
|
generateBridge(name, funDescriptor, fun, cv);
|
||||||
captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
|
captureThis = generateBody(funDescriptor, cv, (JetDeclarationWithBody) fun);
|
||||||
ClassDescriptor thisDescriptor = context.getThisDescriptor();
|
ClassDescriptor thisDescriptor = context.getThisDescriptor();
|
||||||
final Type enclosingType = thisDescriptor == null ? null : state.getTypeMapper().mapType(thisDescriptor.getDefaultType());
|
final Type enclosingType = thisDescriptor == null ? null : state.getTypeMapper().mapType(thisDescriptor.getDefaultType());
|
||||||
if (enclosingType == null)
|
if (enclosingType == null)
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class CodegenUtil {
|
|||||||
return hasDerivedTypeInfoField(type);
|
return hasDerivedTypeInfoField(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NamedFunctionDescriptor createInvoke(ExpressionAsFunctionDescriptor fd) {
|
public static NamedFunctionDescriptor createInvoke(FunctionDescriptor fd) {
|
||||||
int arity = fd.getValueParameters().size();
|
int arity = fd.getValueParameters().size();
|
||||||
NamedFunctionDescriptorImpl invokeDescriptor = new NamedFunctionDescriptorImpl(
|
NamedFunctionDescriptorImpl invokeDescriptor = new NamedFunctionDescriptorImpl(
|
||||||
fd.getExpectedThisObject().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity),
|
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");
|
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
|
@Override
|
||||||
public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) {
|
public StackValue visitSuperExpression(JetSuperExpression expression, StackValue data) {
|
||||||
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
|
||||||
@@ -712,6 +707,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
return generateBlock(statements);
|
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
|
@Override
|
||||||
public StackValue visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, StackValue receiver) {
|
public StackValue visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, StackValue receiver) {
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
@@ -720,40 +726,44 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
return generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
|
return generateBlock(expression.getFunctionLiteral().getBodyExpression().getStatements());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ClosureCodegen closureCodegen = new ClosureCodegen(state, this, context);
|
return genClosure(expression);
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
public StackValue visitObjectLiteralExpression(JetObjectLiteralExpression expression, StackValue receiver) {
|
public StackValue visitObjectLiteralExpression(JetObjectLiteralExpression expression, StackValue receiver) {
|
||||||
ObjectOrClosureCodegen closureCodegen = new ObjectOrClosureCodegen(this, context, state);
|
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());
|
final Type type = sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getOutType());
|
||||||
myFrameMap.enter(variableDescriptor, type.getSize());
|
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();
|
StackValue answer = StackValue.none();
|
||||||
@@ -831,6 +846,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
v.mark(blockEnd);
|
v.mark(blockEnd);
|
||||||
|
|
||||||
for (JetElement statement : statements) {
|
for (JetElement statement : statements) {
|
||||||
|
if(statement instanceof JetNamedFunction) {
|
||||||
|
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, statement);
|
||||||
|
myFrameMap.leave(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
if (statement instanceof JetProperty) {
|
if (statement instanceof JetProperty) {
|
||||||
JetProperty var = (JetProperty) statement;
|
JetProperty var = (JetProperty) statement;
|
||||||
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var);
|
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var);
|
||||||
@@ -946,13 +966,18 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
|
|
||||||
int index = lookupLocal(descriptor);
|
int index = lookupLocal(descriptor);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
Type sharedVarType = typeMapper.getSharedVarType(descriptor);
|
if(descriptor instanceof VariableDescriptor) {
|
||||||
final JetType outType = ((VariableDescriptor) descriptor).getOutType();
|
Type sharedVarType = typeMapper.getSharedVarType(descriptor);
|
||||||
if(sharedVarType != null) {
|
final JetType outType = ((VariableDescriptor) descriptor).getOutType();
|
||||||
return StackValue.shared(index, asmType(outType));
|
if(sharedVarType != null) {
|
||||||
|
return StackValue.shared(index, asmType(outType));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return StackValue.local(index, asmType(outType));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return StackValue.local(index, asmType(outType));
|
return StackValue.local(index, TYPE_OBJECT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (descriptor instanceof PropertyDescriptor) {
|
else if (descriptor instanceof PropertyDescriptor) {
|
||||||
@@ -1266,8 +1291,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
assert !superCall;
|
assert !superCall;
|
||||||
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
|
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
|
||||||
}
|
}
|
||||||
else if (fd instanceof ExpressionAsFunctionDescriptor) {
|
else if (fd instanceof ExpressionAsFunctionDescriptor || (fd instanceof NamedFunctionDescriptor && fd.getContainingDeclaration() instanceof FunctionDescriptor)) {
|
||||||
NamedFunctionDescriptor invoke = CodegenUtil.createInvoke((ExpressionAsFunctionDescriptor) fd);
|
NamedFunctionDescriptor invoke = CodegenUtil.createInvoke((FunctionDescriptor) fd);
|
||||||
callableMethod = ClosureCodegen.asCallableMethod(invoke);
|
callableMethod = ClosureCodegen.asCallableMethod(invoke);
|
||||||
}
|
}
|
||||||
else if (fd instanceof FunctionDescriptor) {
|
else if (fd instanceof FunctionDescriptor) {
|
||||||
|
|||||||
@@ -827,6 +827,10 @@ public class JetTypeMapper {
|
|||||||
if(descriptor instanceof PropertyDescriptor) {
|
if(descriptor instanceof PropertyDescriptor) {
|
||||||
return StackValue.sharedTypeForType(mapType(((PropertyDescriptor) descriptor).getReceiverParameter().getType()));
|
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) {
|
else if (descriptor instanceof FunctionDescriptor) {
|
||||||
return StackValue.sharedTypeForType(mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType()));
|
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 {
|
public void testFunction () throws InvocationTargetException, IllegalAccessException {
|
||||||
blackBoxFile("functions/functionExpression.jet");
|
blackBoxFile("functions/functionExpression.jet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testLocalFunction () throws InvocationTargetException, IllegalAccessException {
|
||||||
|
blackBoxFile("functions/localFunction.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user