From cfc41361ac12e62b21e6832e6601eae8b3050317 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Tue, 8 Nov 2011 22:45:48 +0100 Subject: [PATCH] expressions as functions --- .../jetbrains/jet/codegen/ClosureCodegen.java | 52 +++++++---- .../jetbrains/jet/codegen/CodegenContext.java | 55 ++++++----- .../jetbrains/jet/codegen/CodegenUtil.java | 26 +++++- .../jet/codegen/ExpressionCodegen.java | 93 ++++++++++++++----- .../GeneratedAnonymousClassDescriptor.java | 9 +- .../jet/codegen/GenerationState.java | 2 +- .../jet/codegen/ObjectOrClosureCodegen.java | 48 +++++++--- .../org/jetbrains/jet/codegen/StackValue.java | 12 ++- .../jet/lang/resolve/calls/CallResolver.java | 2 +- .../calls/ExpressionAsFunctionDescriptor.java | 21 +++++ .../codegen/functions/functionExpression.jet | 25 +++++ .../codegen/functions/withtypeparams.jet | 10 ++ .../jet/codegen/FunctionGenTest.java | 51 +--------- stdlib/src/jet/DefaultJetObject.java | 2 +- 14 files changed, 268 insertions(+), 140 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionAsFunctionDescriptor.java create mode 100644 compiler/testData/codegen/functions/functionExpression.jet create mode 100644 compiler/testData/codegen/functions/withtypeparams.jet diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 6f3ec66699d..10e9857f40d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -85,7 +85,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { final Type enclosingType = thisDescriptor == null ? null : Type.getObjectType(thisDescriptor.getName()); if (enclosingType == null) captureThis = false; - final Method constructor = generateConstructor(funClass, captureThis, fun, funDescriptor.getReturnType()); + final Method constructor = generateConstructor(funClass, fun); if (captureThis) { cv.newField(fun, 0, "this$0", enclosingType.getDescriptor(), null, null); @@ -97,10 +97,12 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { cv.done(); - final GeneratedAnonymousClassDescriptor answer = new GeneratedAnonymousClassDescriptor(name, constructor, captureThis); + final GeneratedAnonymousClassDescriptor answer = new GeneratedAnonymousClassDescriptor(name, constructor, captureThis, captureReceiver); for (DeclarationDescriptor descriptor : closure.keySet()) { - final EnclosedValueDescriptor valueDescriptor = closure.get(descriptor); - answer.addArg(valueDescriptor.getOuterValue()); + if(descriptor instanceof VariableDescriptor) { + final EnclosedValueDescriptor valueDescriptor = closure.get(descriptor); + answer.addArg(valueDescriptor.getOuterValue()); + } } return answer; } @@ -144,7 +146,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this); FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state); fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor); - return closureContext.isOuterWasUsed(); + return closureContext.outerWasUsed; } private void generateBridge(String className, FunctionDescriptor funDescriptor, JetFunctionLiteralExpression fun, ClassBuilder cv) { @@ -185,26 +187,36 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { mv.visitEnd(); } - private Method generateConstructor(String funClass, boolean captureThis, JetFunctionLiteralExpression fun, JetType returnType) { - int argCount = closure.size(); + private Method generateConstructor(String funClass, JetFunctionLiteralExpression fun) { + int argCount = captureThis ? 1 : 0; - if (captureThis) { - argCount++; + for (DeclarationDescriptor descriptor : closure.keySet()) { + if(descriptor instanceof VariableDescriptor) { + argCount++; + } + else if(descriptor instanceof FunctionDescriptor) { + captureReceiver = state.getTypeMapper().mapType(((FunctionDescriptor) descriptor).getReceiverParameter().getType()); + argCount++; + } } Type[] argTypes = new Type[argCount]; - int i = 0; if (captureThis) { - i = 1; - argTypes[0] = Type.getObjectType(context.getThisDescriptor().getName()); + argTypes[i++] = Type.getObjectType(context.getThisDescriptor().getName()); + } + + if (captureReceiver != null) { + argTypes[i++] = captureReceiver; } for (DeclarationDescriptor descriptor : closure.keySet()) { - final Type sharedVarType = exprContext.getSharedVarType(descriptor); - final Type type = sharedVarType != null ? sharedVarType : state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType()); - argTypes[i++] = type; + if(descriptor instanceof VariableDescriptor) { + final Type sharedVarType = exprContext.getSharedVarType(descriptor); + final Type type = sharedVarType != null ? sharedVarType : state.getTypeMapper().mapType(((VariableDescriptor) descriptor).getOutType()); + argTypes[i++] = type; + } } final Method constructor = new Method("", Type.VOID_TYPE, argTypes); @@ -225,11 +237,15 @@ public class ClosureCodegen extends ObjectOrClosureCodegen { final String fieldName; if (captureThis && i == 1) { fieldName = "this$0"; - captureThis = false; } else { - fieldName = "$" + (i); - i++; + if (captureReceiver != null && (captureThis && i == 2 || !captureThis && i == 1)) { + fieldName = "receiver$0"; + } + else { + fieldName = "$" + (i); + i++; + } } StackValue.field(type, name, fieldName, false).store(iv); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java index 49013ecafb3..f8e4dbc469c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenContext.java @@ -36,14 +36,9 @@ public abstract class CodegenContext { HashMap typeInfoConstants; HashMap accessors; - protected DeclarationDescriptor outerDescriptor; - protected DeclarationDescriptor outerReceiverDescriptor; - protected StackValue outerExpression; - protected StackValue outerReceiverExpression; - - protected boolean outerWasUsed = false; + protected boolean outerWasUsed ; public CodegenContext(DeclarationDescriptor contextType, OwnerKind contextKind, @Nullable CodegenContext parentContext, @Nullable ObjectOrClosureCodegen closureCodegen) { this.contextType = contextType; @@ -54,7 +49,7 @@ public abstract class CodegenContext { protected abstract ClassDescriptor getThisDescriptor (); - protected DeclarationDescriptor getReceiverDescriptor() { + protected FunctionDescriptor getReceiverDescriptor() { return null; } @@ -139,16 +134,18 @@ public abstract class CodegenContext { } } - public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v) { + public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v, StackValue result) { final ObjectOrClosureCodegen top = closure; if (top != null) { - final StackValue answer = top.lookupInContext(d); - if (answer != null) return answer; + final StackValue answer = top.lookupInContext(d, result); + if (answer != null) + return result == null ? answer : StackValue.composed(result, answer); - getOuterExpression(null).put(JetTypeMapper.TYPE_OBJECT, v); + StackValue outer = getOuterExpression(null); + result = result == null ? outer : StackValue.composed(result, outer); } - return parentContext != null ? parentContext.lookupInContext(d, v) : null; + return parentContext != null ? parentContext.lookupInContext(d, v, result) : null; } public Type enclosingClassType() { @@ -229,32 +226,34 @@ public abstract class CodegenContext { return accessor; } - public boolean isOuterWasUsed() { - return outerWasUsed; - } - - public StackValue getReceiverExpression() { + public StackValue getReceiverExpression(JetTypeMapper typeMapper) { assert getReceiverDescriptor() != null; - return getThisDescriptor() != null ? local1 : local0; - } - - public StackValue getThisExpression() { - assert getThisDescriptor() != null; - return local0; + Type asmType = typeMapper.mapType(getReceiverDescriptor().getReceiverParameter().getType()); + return getThisDescriptor() != null ? StackValue.local(1, asmType) : StackValue.local(0, asmType); } public abstract static class FunctionContext extends CodegenContext { - final DeclarationDescriptor receiverDescriptor; + final FunctionDescriptor receiverDescriptor; public FunctionContext(FunctionDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @Nullable ObjectOrClosureCodegen closureCodegen) { super(contextType, contextKind, parentContext, closureCodegen); - receiverDescriptor = contextType.getReceiverParameter().exists() ? contextType.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor() : null; + receiverDescriptor = contextType.getReceiverParameter().exists() ? contextType : null; } @Override - protected DeclarationDescriptor getReceiverDescriptor() { + protected FunctionDescriptor getReceiverDescriptor() { return receiverDescriptor; } + + public FunctionContext getOuterFunction() { + CodegenContext c = getParentContext(); + while(c != null) { + if(c instanceof FunctionContext) + return (FunctionContext) c; + c = c.getParentContext(); + } + return null; + } } public static class MethodContext extends FunctionContext { @@ -267,8 +266,8 @@ public abstract class CodegenContext { return getParentContext().getThisDescriptor(); } - public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v) { - return getParentContext().lookupInContext(d, v); + public StackValue lookupInContext(DeclarationDescriptor d, InstructionAdapter v, StackValue result) { + return getParentContext().lookupInContext(d, v, result); } public Type enclosingClassType() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index bc7489e1c52..ef3f606f1e3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -1,15 +1,17 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.ClassKind; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.JetNamedDeclaration; import org.jetbrains.jet.lang.psi.JetNamespace; +import org.jetbrains.jet.lang.resolve.calls.ExpressionAsFunctionDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; +import java.util.Collections; import java.util.List; /** @@ -124,4 +126,20 @@ public class CodegenUtil { } return jetClass.getName(); } + + public static FunctionDescriptor createInvoke(ExpressionAsFunctionDescriptor fd) { + int arity = fd.getValueParameters().size(); + FunctionDescriptorImpl invokeDescriptor = new FunctionDescriptorImpl( + fd.getExpectedThisObject().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity), + Collections.emptyList(), + "invoke"); + + invokeDescriptor.initialize(fd.getReceiverParameter().exists() ? fd.getReceiverParameter().getType() : null, + fd.getExpectedThisObject(), + Collections.emptyList(), + fd.getValueParameters(), + fd.getReturnType(), + Modality.FINAL, Visibility.PUBLIC); + return invokeDescriptor; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 45682099f46..67857237d6b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -15,6 +15,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.calls.*; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.Label; @@ -584,6 +585,10 @@ public class ExpressionCodegen extends JetVisitor { v.load(0, JetTypeMapper.TYPE_OBJECT); } + if (closure.isCaptureReceiver() != null) { + 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], v); @@ -738,7 +743,15 @@ public class ExpressionCodegen extends JetVisitor { @Override public StackValue visitSimpleNameExpression(JetSimpleNameExpression expression, StackValue receiver) { - DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression); + ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression); + + DeclarationDescriptor descriptor; + if(resolvedCall == null) { + descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression); + } + else + descriptor = resolvedCall.getResultingDescriptor(); + if (descriptor instanceof NamespaceDescriptor) return StackValue.none(); // No code to generate if (descriptor instanceof VariableAsFunctionDescriptor) { @@ -813,7 +826,14 @@ public class ExpressionCodegen extends JetVisitor { final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField, isSuper ? (JetSuperExpression)r : null); if (!isStatic) { if (receiver == StackValue.none()) { - receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration()); + if(resolvedCall == null) + receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration()); + else { + if(resolvedCall.getThisObject() instanceof ExtensionReceiver) + receiver = generateReceiver((FunctionDescriptor) ((ExtensionReceiver)resolvedCall.getThisObject()).getDeclarationDescriptor()); + else + receiver = generateThisOrOuter((ClassDescriptor) propertyDescriptor.getContainingDeclaration()); + } } JetType receiverType = bindingContext.get(BindingContext.EXPRESSION_TYPE, r); receiver.put(receiverType != null && !isSuper? typeMapper.mapType(receiverType) : JetTypeMapper.TYPE_OBJECT, v); @@ -856,13 +876,16 @@ public class ExpressionCodegen extends JetVisitor { } else { // receiver - StackValue.local(0, JetTypeMapper.TYPE_OBJECT).put(JetTypeMapper.TYPE_OBJECT, v); - - final StackValue value = context.lookupInContext(descriptor, v); + StackValue value = context.lookupInContext(descriptor, v, StackValue.local(0, JetTypeMapper.TYPE_OBJECT)); if (value == null) { throw new UnsupportedOperationException("don't know how to generate reference " + descriptor); } + if(value instanceof StackValue.Composed) { + StackValue.Composed composed = (StackValue.Composed) value; + composed.prefix.put(JetTypeMapper.TYPE_OBJECT, v); + value = composed.suffix; + } if(value instanceof StackValue.FieldForSharedVar) { StackValue.FieldForSharedVar fieldForSharedVar = (StackValue.FieldForSharedVar) value; Type sharedType = StackValue.sharedTypeForType(value.type); @@ -911,7 +934,10 @@ public class ExpressionCodegen extends JetVisitor { public StackValue intermediateValueForProperty(PropertyDescriptor propertyDescriptor, final boolean forceField, @Nullable JetSuperExpression superExpression) { boolean isSuper = superExpression != null; - DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration().getOriginal(); + DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); + assert containingDeclaration != null; + containingDeclaration = containingDeclaration.getOriginal(); + boolean isStatic = containingDeclaration instanceof NamespaceDescriptorImpl; propertyDescriptor = propertyDescriptor.getOriginal(); boolean isInsideClass = ((containingDeclaration == context.getThisDescriptor()) || @@ -932,7 +958,7 @@ public class ExpressionCodegen extends JetVisitor { if(isSuper) { PsiElement enclosingElement = bindingContext.get(BindingContext.LABEL_TARGET, superExpression.getTargetLabel()); ClassDescriptor enclosed = (ClassDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, enclosingElement); - if(!CodegenUtil.isInterface(propertyDescriptor.getContainingDeclaration())) { + if(!CodegenUtil.isInterface(containingDeclaration)) { if(enclosed != null && enclosed != context.getThisDescriptor()) { CodegenContext c = context; while(c.getContextDescriptor() != enclosed) { @@ -1055,6 +1081,10 @@ public class ExpressionCodegen extends JetVisitor { assert !superCall; callableMethod = asCallableMethod((FunctionDescriptor) fd); } + else if (fd instanceof ExpressionAsFunctionDescriptor) { + FunctionDescriptor invoke = CodegenUtil.createInvoke((ExpressionAsFunctionDescriptor) fd); + callableMethod = asCallableMethod(invoke); + } else if (fd instanceof FunctionDescriptor) { callableMethod = typeMapper.mapToCallableMethod((FunctionDescriptor) fd, superCall, OwnerKind.IMPLEMENTATION); } @@ -1066,14 +1096,13 @@ public class ExpressionCodegen extends JetVisitor { private DeclarationDescriptor resolveCalleeDescriptor(JetCallExpression call) { JetExpression callee = call.getCalleeExpression(); - if (!(callee instanceof JetReferenceExpression)) { - throw new UnsupportedOperationException("Don't know how to generate a call to " + callee); - } - DeclarationDescriptor funDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) callee); - if (funDescriptor == null) { + ResolvedCall resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, callee); + if(resolvedCall == null) { + assert callee != null; throw new CompilationException("Cannot resolve: " + callee.getText()); } - return funDescriptor; + + return resolvedCall.getResultingDescriptor(); } public void invokeMethodWithArguments(CallableMethod callableMethod, JetCallElement expression, StackValue receiver) { @@ -1102,7 +1131,7 @@ public class ExpressionCodegen extends JetVisitor { v.load(0, JetTypeMapper.TYPE_OBJECT); } else - receiver.put(JetTypeMapper.TYPE_OBJECT, v); + receiver.put(callableMethod.getSignature().getArgumentTypes()[0], v); } } @@ -1147,11 +1176,33 @@ public class ExpressionCodegen extends JetVisitor { } } + private StackValue generateReceiver(FunctionDescriptor descriptor) { + assert context instanceof CodegenContext.FunctionContext; + CodegenContext.FunctionContext cur = (CodegenContext.FunctionContext) context; + if (cur.getReceiverDescriptor() == descriptor) { + return cur.getReceiverExpression(typeMapper); + } + + return context.lookupInContext(descriptor, v, StackValue.local(0, JetTypeMapper.TYPE_OBJECT)); +// assert context instanceof CodegenContext.FunctionContext; +// CodegenContext.FunctionContext cur = (CodegenContext.FunctionContext) context; +// +// StackValue result = StackValue.local(0, JetTypeMapper.TYPE_OBJECT); +// while (cur != null) { +// +// if (cur.getReceiverDescriptor() == descriptor) { +// return cur.getReceiverExpression(typeMapper); +// } +// +// result = cur.getOuterExpression(result); +// cur = cur.getOuterFunction(); +// } +// +// throw new UnsupportedOperationException("Don't know how to generate receiver for " + descriptor); + } + public StackValue generateThisOrOuter(ClassDescriptor calleeContainingClass) { CodegenContext cur = context; - if(cur.getReceiverDescriptor() == calleeContainingClass) { - return cur.getReceiverExpression(); - } StackValue result = StackValue.local(0, JetTypeMapper.TYPE_OBJECT); while (cur != null) { @@ -2071,9 +2122,7 @@ public class ExpressionCodegen extends JetVisitor { } else { if(descriptor instanceof FunctionDescriptor) { - FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; - Type type = typeMapper.mapType(functionDescriptor.getReceiverParameter().getType()); - return StackValue.local(descriptor.getContainingDeclaration() instanceof NamespaceDescriptor ? 0 : 1, type); + return generateReceiver((FunctionDescriptor) descriptor); } throw new UnsupportedOperationException(); } @@ -2362,8 +2411,8 @@ public class ExpressionCodegen extends JetVisitor { return; } DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration(); - if (context.getThisDescriptor() instanceof ClassDescriptor) { - ClassDescriptor descriptor = (ClassDescriptor) context.getThisDescriptor(); + if (context.getThisDescriptor() != null) { + ClassDescriptor descriptor = context.getThisDescriptor(); assert containingDeclaration != null; JetType defaultType = ((ClassDescriptor)containingDeclaration).getDefaultType(); Type ownerType = typeMapper.mapType(defaultType); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java b/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java index 14e70f0ef96..6040127d723 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GeneratedAnonymousClassDescriptor.java @@ -3,6 +3,7 @@ */ package org.jetbrains.jet.codegen; +import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; import java.util.ArrayList; @@ -12,12 +13,14 @@ public class GeneratedAnonymousClassDescriptor { private final String classname; private Method constructor; private final boolean captureThis; + private final Type captureReceiver; private List args = new ArrayList(); - public GeneratedAnonymousClassDescriptor(String classname, Method constructor, boolean captureThis) { + public GeneratedAnonymousClassDescriptor(String classname, Method constructor, boolean captureThis, Type captureReceiver) { this.classname = classname; this.constructor = constructor; this.captureThis = captureThis; + this.captureReceiver = captureReceiver; } public String getClassname() { @@ -39,4 +42,8 @@ public class GeneratedAnonymousClassDescriptor { public boolean isCaptureThis() { return captureThis; } + + public Type isCaptureReceiver() { + return captureReceiver; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java index 7b9ddd28fab..8025a67b5ce 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/GenerationState.java @@ -126,7 +126,7 @@ public class GenerationState { ConstructorDescriptor constructorDescriptor = closure.state.getBindingContext().get(BindingContext.CONSTRUCTOR, objectDeclaration); CallableMethod callableMethod = closure.state.getTypeMapper().mapToCallableMethod(constructorDescriptor, OwnerKind.IMPLEMENTATION); - return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, callableMethod.getSignature(), false); + return new GeneratedAnonymousClassDescriptor(nameAndVisitor.first, callableMethod.getSignature(), objectContext.outerWasUsed, null); } public static void prepareAnonymousClasses(JetElement aClass, final JetTypeMapper typeMapper) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java index f2b2f2302a6..09762edce74 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ObjectOrClosureCodegen.java @@ -1,8 +1,6 @@ package org.jetbrains.jet.codegen; -import org.jetbrains.jet.lang.descriptors.ClassDescriptorImpl; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; @@ -16,6 +14,7 @@ import java.util.Map; */ public class ObjectOrClosureCodegen { protected boolean captureThis; + protected Type captureReceiver; public final GenerationState state; protected final ExpressionCodegen exprContext; @@ -30,13 +29,16 @@ public class ObjectOrClosureCodegen { this.state = state; } - public StackValue lookupInContext(DeclarationDescriptor d) { + public StackValue lookupInContext(DeclarationDescriptor d, StackValue result) { + EnclosedValueDescriptor answer = closure.get(d); + if (answer != null) { + StackValue innerValue = answer.getInnerValue(); + return result != null ? innerValue : StackValue.composed(result, innerValue); + } + if (d instanceof VariableDescriptor) { VariableDescriptor vd = (VariableDescriptor) d; - EnclosedValueDescriptor answer = closure.get(vd); - if (answer != null) return answer.getInnerValue(); - final int idx = exprContext.lookupLocal(vd); if (idx < 0) return null; @@ -56,14 +58,36 @@ public class ObjectOrClosureCodegen { return innerValue; } + if(d instanceof FunctionDescriptor) { + // we are looking for receiver + FunctionDescriptor fd = (FunctionDescriptor) d; + + // we generate method + assert context instanceof CodegenContext.FunctionContext; + + CodegenContext.FunctionContext fcontext = (CodegenContext.FunctionContext) context; + + if(fcontext.getReceiverDescriptor() != fd) + return null; + + Type type = state.getTypeMapper().mapType(fcontext.getReceiverDescriptor().getReceiverParameter().getType()); + boolean isStatic = fcontext.getContextDescriptor().getContainingDeclaration() instanceof NamespaceDescriptor; + StackValue outerValue = StackValue.local(isStatic ? 0 : 1, type); + final String fieldName = "receiver$0"; + StackValue innerValue = StackValue.field(type, name, fieldName, false); + + cv.newField(null, Opcodes.ACC_PUBLIC, fieldName, type.getDescriptor(), null, null); + + answer = new EnclosedValueDescriptor(d, innerValue, outerValue); + closure.put(d, answer); + + return innerValue; + } + return null; } - public boolean isCaptureThis() { - return captureThis; - } - public boolean isConst () { - return !captureThis && closure.isEmpty(); + return !captureThis && captureReceiver != null && closure.isEmpty(); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index a0404d2d404..9c2431d3981 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -795,9 +795,9 @@ public abstract class StackValue { } } - private static class Composed extends StackValue { - private StackValue prefix; - private StackValue suffix; + public static class Composed extends StackValue { + public final StackValue prefix; + public final StackValue suffix; public Composed(StackValue prefix, StackValue suffix) { super(suffix.type); @@ -810,5 +810,11 @@ public abstract class StackValue { prefix.put(prefix.type, v); suffix.put(type, v); } + + @Override + public void store(InstructionAdapter v) { + prefix.put(JetTypeMapper.TYPE_OBJECT, v); + suffix.store(v); + } } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index f3187bfe83c..3817321a726 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -187,7 +187,7 @@ public class CallResolver { return null; } - FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(scope.getContainingDeclaration(), Collections.emptyList(), "[for expression " + calleeExpression.getText() + "]"); + FunctionDescriptorImpl functionDescriptor = new ExpressionAsFunctionDescriptor(scope.getContainingDeclaration(), "[for expression " + calleeExpression.getText() + "]"); FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, calleeType); ResolvedCallImpl resolvedCall = ResolvedCallImpl.create(functionDescriptor); resolvedCall.setReceiverArgument(call.getExplicitReceiver()); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionAsFunctionDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionAsFunctionDescriptor.java new file mode 100644 index 00000000000..ba4d91f3983 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionAsFunctionDescriptor.java @@ -0,0 +1,21 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; +import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.JetStandardClasses; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Collections; +import java.util.List; + +/** + * @author alex.tkachman + */ +public class ExpressionAsFunctionDescriptor extends FunctionDescriptorImpl { + public ExpressionAsFunctionDescriptor(DeclarationDescriptor containingDeclaration, String name) { + super(containingDeclaration, Collections.emptyList(), name); + } +} diff --git a/compiler/testData/codegen/functions/functionExpression.jet b/compiler/testData/codegen/functions/functionExpression.jet new file mode 100644 index 00000000000..6e9611f2441 --- /dev/null +++ b/compiler/testData/codegen/functions/functionExpression.jet @@ -0,0 +1,25 @@ +fun Any.foo1() : fun(): String { + return { "239" + this } +} + +fun Int.foo2() : fun(i : Int) : Int { + return { x => x + this } +} + +fun fooT1(t : T) = { t.toString() } + +fun fooT2(t: T) = { (x:T) => t.toString() + x.toString() } + +fun box() : String { + if( (10.foo1())() != "23910") return "foo1 fail" + if( (10.foo2())(1) != 11 ) return "foo2 fail" + + if(1.{Int.() => this + 1}() != 2) return "test 3 failed"; + if( {1}() != 1) return "test 4 failed"; + if( {(x : Int) => x}(1) != 1) return "test 5 failed"; + if( 1.{Int.(x : Int) => x + this}(1) != 2) return "test 6 failed"; + if( 1.({Int.() => this})() != 1) return "test 7 failed"; + if( (fooT1("mama"))() != "mama") return "test 8 failed"; + if( (fooT2("mama"))("papa") != "mamapapa") return "test 9 failed"; + return "OK" +} diff --git a/compiler/testData/codegen/functions/withtypeparams.jet b/compiler/testData/codegen/functions/withtypeparams.jet new file mode 100644 index 00000000000..291ebe1c04b --- /dev/null +++ b/compiler/testData/codegen/functions/withtypeparams.jet @@ -0,0 +1,10 @@ +class X () { + fun getTypeChecker() = { (a : Any) => a is T } +} + +fun box() : String { + val c = X().getTypeChecker() + if(c(10)) return "fail" + if(!c("lala")) return "fail" + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java index 0a3a3950b4c..ceacbc22fe6 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/FunctionGenTest.java @@ -80,55 +80,8 @@ public class FunctionGenTest extends CodegenTestCase { public void testKt395 () { blackBoxFile("regressions/kt395.jet"); } -/* + public void testFunction () throws InvocationTargetException, IllegalAccessException { - loadText("fun Any.foo() : fun(): String {\n" + - " return { \"239\" + this }\n" + - "}\n" + - "fun box() : String {\n" + - " return if((10.foo())() == \"23910\") \"OK\" else \"fail\"" + - "}" + - ""); - System.out.println(generateToText()); - Method foo = generateFunction(); - assertTrue((Boolean) foo.invoke(null, "lala")); - assertFalse((Boolean) foo.invoke(null, "mama")); + blackBoxFile("functions/functionExpression.jet"); } - -fun Any.foo() : fun() : Unit { - return {} -} - -fun Any.foo1() : fun(i : Int) : Unit { - return {} -} - -fun foo2() : fun(i : fun()) : Unit { - return {} -} - -fun fooT1(t : T) : fun() : T { - return {t} -} - -fun fooT2() : fun(t : T) : T { - return {it} -} - -fun main(args : Array) { - args.foo()() - - args.foo1()(1) - - foo2()({}) - (foo2()){} - - val a = fooT1(1)() - a : Int - - val b = fooT2()(1) - b : Int - fooT2()(1) // : Any? -} - */ } diff --git a/stdlib/src/jet/DefaultJetObject.java b/stdlib/src/jet/DefaultJetObject.java index 017a47df4a7..e5ce4f43185 100644 --- a/stdlib/src/jet/DefaultJetObject.java +++ b/stdlib/src/jet/DefaultJetObject.java @@ -13,7 +13,7 @@ public class DefaultJetObject implements JetObject { } @Override - public TypeInfo getTypeInfo() { + public final TypeInfo getTypeInfo() { return typeInfo; } }