expressions as functions
This commit is contained in:
@@ -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("<init>", 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);
|
||||
|
||||
@@ -36,14 +36,9 @@ public abstract class CodegenContext {
|
||||
HashMap<JetType,Integer> typeInfoConstants;
|
||||
HashMap<DeclarationDescriptor, DeclarationDescriptor> 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() {
|
||||
|
||||
@@ -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.<AnnotationDescriptor>emptyList(),
|
||||
"invoke");
|
||||
|
||||
invokeDescriptor.initialize(fd.getReceiverParameter().exists() ? fd.getReceiverParameter().getType() : null,
|
||||
fd.getExpectedThisObject(),
|
||||
Collections.<TypeParameterDescriptor>emptyList(),
|
||||
fd.getValueParameters(),
|
||||
fd.getReturnType(),
|
||||
Modality.FINAL, Visibility.PUBLIC);
|
||||
return invokeDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<StackValue, StackValue> {
|
||||
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<StackValue, StackValue> {
|
||||
|
||||
@Override
|
||||
public StackValue visitSimpleNameExpression(JetSimpleNameExpression expression, StackValue receiver) {
|
||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
|
||||
ResolvedCall<? extends CallableDescriptor> 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<StackValue, StackValue> {
|
||||
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<StackValue, StackValue> {
|
||||
}
|
||||
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<StackValue, StackValue> {
|
||||
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<StackValue, StackValue> {
|
||||
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<StackValue, StackValue> {
|
||||
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<StackValue, StackValue> {
|
||||
|
||||
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<? extends CallableDescriptor> 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<StackValue, StackValue> {
|
||||
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<StackValue, StackValue> {
|
||||
}
|
||||
}
|
||||
|
||||
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<StackValue, StackValue> {
|
||||
}
|
||||
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<StackValue, StackValue> {
|
||||
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);
|
||||
|
||||
+8
-1
@@ -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<StackValue> args = new ArrayList<StackValue>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ public class CallResolver {
|
||||
return null;
|
||||
}
|
||||
|
||||
FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(scope.getContainingDeclaration(), Collections.<AnnotationDescriptor>emptyList(), "[for expression " + calleeExpression.getText() + "]");
|
||||
FunctionDescriptorImpl functionDescriptor = new ExpressionAsFunctionDescriptor(scope.getContainingDeclaration(), "[for expression " + calleeExpression.getText() + "]");
|
||||
FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, calleeType);
|
||||
ResolvedCallImpl<FunctionDescriptor> resolvedCall = ResolvedCallImpl.<FunctionDescriptor>create(functionDescriptor);
|
||||
resolvedCall.setReceiverArgument(call.getExplicitReceiver());
|
||||
|
||||
+21
@@ -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.<AnnotationDescriptor>emptyList(), name);
|
||||
}
|
||||
}
|
||||
@@ -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) = { t.toString() }
|
||||
|
||||
fun fooT2<T>(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<String>("mama"))() != "mama") return "test 8 failed";
|
||||
if( (fooT2<String>("mama"))("papa") != "mamapapa") return "test 9 failed";
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
class X<T> () {
|
||||
fun getTypeChecker() = { (a : Any) => a is T }
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
val c = X<String>().getTypeChecker()
|
||||
if(c(10)) return "fail"
|
||||
if(!c("lala")) return "fail"
|
||||
return "OK"
|
||||
}
|
||||
@@ -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 : T) : fun() : T {
|
||||
return {t}
|
||||
}
|
||||
|
||||
fun fooT2<T>() : fun(t : T) : T {
|
||||
return {it}
|
||||
}
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
args.foo()()
|
||||
|
||||
args.foo1()(1)
|
||||
|
||||
foo2()({})
|
||||
(foo2()){}
|
||||
|
||||
val a = fooT1(1)()
|
||||
a : Int
|
||||
|
||||
val b = fooT2<Int>()(1)
|
||||
b : Int
|
||||
fooT2()(1) // : Any?
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public class DefaultJetObject implements JetObject {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeInfo<?> getTypeInfo() {
|
||||
public final TypeInfo<?> getTypeInfo() {
|
||||
return typeInfo;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user