fix for broken test. (this, receiver) handling normalized

This commit is contained in:
Alex Tkachman
2011-11-12 19:13:26 +02:00
parent 3fcb75ba1d
commit 396376c013
6 changed files with 121 additions and 77 deletions
@@ -1,7 +1,9 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.objectweb.asm.Opcodes; import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.InstructionAdapter;
@@ -18,8 +20,9 @@ public class CallableMethod implements Callable {
private final Method signature; private final Method signature;
private int invokeOpcode; private int invokeOpcode;
private final List<Type> valueParameterTypes; private final List<Type> valueParameterTypes;
private DeclarationDescriptor thisClass = null; private ClassDescriptor thisClass = null;
private DeclarationDescriptor receiverClass = null;
private FunctionDescriptor receiverFunction = null;
private Type generateCalleeType = null; private Type generateCalleeType = null;
public CallableMethod(String owner, Method signature, int invokeOpcode, List<Type> valueParameterTypes) { public CallableMethod(String owner, Method signature, int invokeOpcode, List<Type> valueParameterTypes) {
@@ -45,11 +48,11 @@ public class CallableMethod implements Callable {
return valueParameterTypes; return valueParameterTypes;
} }
public void setNeedsReceiver(@Nullable DeclarationDescriptor receiverClass) { public void setNeedsReceiver(@Nullable FunctionDescriptor receiverClass) {
this.receiverClass = receiverClass; this.receiverFunction = receiverClass;
} }
public void setNeedsThis(@Nullable DeclarationDescriptor receiverClass) { public void setNeedsThis(@Nullable ClassDescriptor receiverClass) {
this.thisClass = receiverClass; this.thisClass = receiverClass;
} }
@@ -78,10 +81,14 @@ public class CallableMethod implements Callable {
} }
public boolean isNeedsReceiver() { public boolean isNeedsReceiver() {
return receiverClass != null; return receiverFunction != null;
} }
public DeclarationDescriptor getThisClass() { public ClassDescriptor getThisClass() {
return thisClass; return thisClass;
} }
public FunctionDescriptor getReceiverFunction() {
return receiverFunction;
}
} }
@@ -45,6 +45,17 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
return new Method("invoke", JetTypeMapper.TYPE_OBJECT, args); return new Method("invoke", JetTypeMapper.TYPE_OBJECT, args);
} }
public static CallableMethod asCallableMethod(FunctionDescriptor fd) {
Method descriptor = erasedInvokeSignature(fd);
String owner = getInternalClassName(fd);
final CallableMethod result = new CallableMethod(owner, descriptor, INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes()));
if (fd.getReceiverParameter().exists()) {
result.setNeedsReceiver(fd);
}
result.requestGenerateCallee(Type.getObjectType(getInternalClassName(fd)));
return result;
}
public Method invokeSignature(FunctionDescriptor fd) { public Method invokeSignature(FunctionDescriptor fd) {
return state.getTypeMapper().mapSignature("invoke", fd); return state.getTypeMapper().mapSignature("invoke", fd);
} }
@@ -1,6 +1,7 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import gnu.trove.THashSet;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.JetClass;
@@ -13,6 +14,7 @@ import org.jetbrains.jet.lang.types.JetType;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* @author abreslav * @author abreslav
@@ -142,4 +144,29 @@ public class CodegenUtil {
Modality.FINAL, Visibility.PUBLIC); Modality.FINAL, Visibility.PUBLIC);
return invokeDescriptor; return invokeDescriptor;
} }
public static boolean isSubclass(ClassDescriptor subClass, ClassDescriptor superClass) {
Set<JetType> allSuperTypes = new THashSet<JetType>();
addSuperTypes(subClass.getDefaultType(), allSuperTypes);
final DeclarationDescriptor superOriginal = superClass.getOriginal();
for (JetType superType : allSuperTypes) {
final DeclarationDescriptor descriptor = superType.getConstructor().getDeclarationDescriptor();
if (descriptor != null && superOriginal.equals(descriptor.getOriginal())) {
return true;
}
}
return false;
}
private static void addSuperTypes(JetType type, Set<JetType> set) {
set.add(type);
for (JetType jetType : type.getConstructor().getSupertypes()) {
addSuperTypes(jetType, set);
}
}
} }
@@ -4,7 +4,6 @@ import com.intellij.openapi.editor.Document;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
@@ -15,7 +14,10 @@ import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.calls.*; import org.jetbrains.jet.lang.resolve.calls.*;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ClassReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
@@ -27,8 +29,6 @@ import org.objectweb.asm.commons.Method;
import java.util.*; import java.util.*;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
/** /**
* @author max * @author max
* @author yole * @author yole
@@ -79,17 +79,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
this.intrinsics = state.getIntrinsics(); this.intrinsics = state.getIntrinsics();
} }
private static CallableMethod asCallableMethod(FunctionDescriptor fd) {
Method descriptor = ClosureCodegen.erasedInvokeSignature(fd);
String owner = ClosureCodegen.getInternalClassName(fd);
final CallableMethod result = new CallableMethod(owner, descriptor, INVOKEVIRTUAL, Arrays.asList(descriptor.getArgumentTypes()));
if (fd.getReceiverParameter().exists()) {
result.setNeedsReceiver(fd.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor());
}
result.requestGenerateCallee(Type.getObjectType(ClosureCodegen.getInternalClassName(fd)));
return result;
}
public GenerationState getState() { public GenerationState getState() {
return state; return state;
} }
@@ -1021,7 +1010,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (expression.getParent() instanceof JetQualifiedExpression) { if (expression.getParent() instanceof JetQualifiedExpression) {
final JetExpression receiverExpression = ((JetQualifiedExpression) expression.getParent()).getReceiverExpression(); final JetExpression receiverExpression = ((JetQualifiedExpression) expression.getParent()).getReceiverExpression();
if (receiverExpression instanceof JetSuperExpression) { if (receiverExpression instanceof JetSuperExpression) {
assert receiver == StackValue.none();
superCall = true; superCall = true;
receiver = StackValue.thisOrOuter(this, context.getThisDescriptor());
JetSuperExpression superExpression = (JetSuperExpression) receiverExpression; JetSuperExpression superExpression = (JetSuperExpression) receiverExpression;
PsiElement enclosingElement = bindingContext.get(BindingContext.LABEL_TARGET, superExpression.getTargetLabel()); PsiElement enclosingElement = bindingContext.get(BindingContext.LABEL_TARGET, superExpression.getTargetLabel());
ClassDescriptor enclosed = (ClassDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, enclosingElement); ClassDescriptor enclosed = (ClassDescriptor) bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, enclosingElement);
@@ -1033,17 +1024,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} }
fd = c.getAccessor(fd); fd = c.getAccessor(fd);
superCall = false; superCall = false;
receiver = StackValue.thisOrOuter(this, enclosed);
} }
} }
} }
} }
Callable callableMethod = resolveToCallable(fd, superCall); Callable callable = resolveToCallable(fd, superCall);
return invokeCallable(fd, callableMethod, expression, receiver);
}
@Nullable
private StackValue invokeCallable(DeclarationDescriptor fd, Callable callable, JetCallExpression expression, StackValue receiver) {
if (callable instanceof CallableMethod) { if (callable instanceof CallableMethod) {
final CallableMethod callableMethod = (CallableMethod) callable; final CallableMethod callableMethod = (CallableMethod) callable;
invokeMethodWithArguments(callableMethod, expression, receiver); invokeMethodWithArguments(callableMethod, expression, receiver);
@@ -1079,11 +1066,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
CallableMethod callableMethod; CallableMethod callableMethod;
if (fd instanceof VariableAsFunctionDescriptor) { if (fd instanceof VariableAsFunctionDescriptor) {
assert !superCall; assert !superCall;
callableMethod = asCallableMethod((FunctionDescriptor) fd); callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
} }
else if (fd instanceof ExpressionAsFunctionDescriptor) { else if (fd instanceof ExpressionAsFunctionDescriptor) {
FunctionDescriptor invoke = CodegenUtil.createInvoke((ExpressionAsFunctionDescriptor) fd); FunctionDescriptor invoke = CodegenUtil.createInvoke((ExpressionAsFunctionDescriptor) fd);
callableMethod = asCallableMethod(invoke); callableMethod = ClosureCodegen.asCallableMethod(invoke);
} }
else if (fd instanceof FunctionDescriptor) { else if (fd instanceof FunctionDescriptor) {
callableMethod = typeMapper.mapToCallableMethod((FunctionDescriptor) fd, superCall, OwnerKind.IMPLEMENTATION); callableMethod = typeMapper.mapToCallableMethod((FunctionDescriptor) fd, superCall, OwnerKind.IMPLEMENTATION);
@@ -1108,17 +1095,30 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
public void invokeMethodWithArguments(CallableMethod callableMethod, JetCallElement expression, StackValue receiver) { public void invokeMethodWithArguments(CallableMethod callableMethod, JetCallElement expression, StackValue receiver) {
final Type calleeType = callableMethod.getGenerateCalleeType(); final Type calleeType = callableMethod.getGenerateCalleeType();
if (calleeType != null && expression instanceof JetCallExpression) { if (calleeType != null && expression instanceof JetCallExpression) {
assert !callableMethod.isNeedsThis();
gen(expression.getCalleeExpression(), calleeType); gen(expression.getCalleeExpression(), calleeType);
} }
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
assert resolvedCall != null;
FunctionDescriptor callableDescriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
boolean hasThis = resolvedCall.getThisObject().exists();
boolean hasReceiver = resolvedCall.getReceiverArgument().exists();
if (callableMethod.isNeedsThis()) { if (callableMethod.isNeedsThis()) {
if(callableMethod.isNeedsReceiver()) { if(callableMethod.isNeedsReceiver()) {
generateThisOrOuter((ClassDescriptor) callableMethod.getThisClass()).put(JetTypeMapper.TYPE_OBJECT, v); generateFromResolvedCall(resolvedCall.getThisObject());
receiver.put(JetTypeMapper.TYPE_OBJECT, v); if(receiver == StackValue.none()) {
generateFromResolvedCall(resolvedCall.getReceiverArgument());
}
else {
receiver.put(typeMapper.mapType(callableMethod.getReceiverFunction().getReceiverParameter().getType()), v);
}
} }
else { else {
if (receiver == StackValue.none()) { if (receiver == StackValue.none()) {
generateThisOrOuter((ClassDescriptor) callableMethod.getThisClass()).put(JetTypeMapper.TYPE_OBJECT, v); generateFromResolvedCall(resolvedCall.getThisObject());
} }
else { else {
receiver.put(JetTypeMapper.TYPE_OBJECT, v); receiver.put(JetTypeMapper.TYPE_OBJECT, v);
@@ -1128,13 +1128,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
else { else {
if (callableMethod.isNeedsReceiver()) { if (callableMethod.isNeedsReceiver()) {
if (receiver == StackValue.none()) { if (receiver == StackValue.none()) {
v.load(0, JetTypeMapper.TYPE_OBJECT); generateFromResolvedCall(resolvedCall.getReceiverArgument());
} }
else else
receiver.put(callableMethod.getSignature().getArgumentTypes()[0], v); receiver.put(callableMethod.getSignature().getArgumentTypes()[0], v);
} }
} }
int mask = pushMethodArguments(expression, callableMethod.getValueParameterTypes()); int mask = pushMethodArguments(expression, callableMethod.getValueParameterTypes());
pushTypeArguments(expression); pushTypeArguments(expression);
if(mask == 0) if(mask == 0)
@@ -1143,6 +1143,24 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
callableMethod.invokeWithDefault(v, mask); callableMethod.invokeWithDefault(v, mask);
} }
private void generateFromResolvedCall(ReceiverDescriptor descriptor) {
if(descriptor instanceof ClassReceiver) {
ClassReceiver classReceiver = (ClassReceiver) descriptor;
generateThisOrOuter((ClassDescriptor) classReceiver.getDeclarationDescriptor()).put(typeMapper.mapType(descriptor.getType()), v);
}
else if(descriptor instanceof ExtensionReceiver) {
ExtensionReceiver extensionReceiver = (ExtensionReceiver) descriptor;
generateReceiver((FunctionDescriptor) extensionReceiver.getDeclarationDescriptor()).put(typeMapper.mapType(descriptor.getType()), v);
}
else if(descriptor instanceof ExpressionReceiver) {
ExpressionReceiver expressionReceiver = (ExpressionReceiver) descriptor;
genToJVMStack(expressionReceiver.getExpression());
}
else {
throw new UnsupportedOperationException();
}
}
private static JetExpression getReceiverForSelector(PsiElement expression) { private static JetExpression getReceiverForSelector(PsiElement expression) {
if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) { if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) {
final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent(); final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
@@ -1151,31 +1169,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return null; return null;
} }
private static boolean isSubclass(ClassDescriptor subClass, ClassDescriptor superClass) {
Set<JetType> allSuperTypes = new THashSet<JetType>();
addSuperTypes(subClass.getDefaultType(), allSuperTypes);
final DeclarationDescriptor superOriginal = superClass.getOriginal();
for (JetType superType : allSuperTypes) {
final DeclarationDescriptor descriptor = superType.getConstructor().getDeclarationDescriptor();
if (descriptor != null && superOriginal.equals(descriptor.getOriginal())) {
return true;
}
}
return false;
}
private static void addSuperTypes(JetType type, Set<JetType> set) {
set.add(type);
for (JetType jetType : type.getConstructor().getSupertypes()) {
addSuperTypes(jetType, set);
}
}
private StackValue generateReceiver(FunctionDescriptor descriptor) { private StackValue generateReceiver(FunctionDescriptor descriptor) {
assert context instanceof CodegenContext.FunctionContext; assert context instanceof CodegenContext.FunctionContext;
CodegenContext.FunctionContext cur = (CodegenContext.FunctionContext) context; CodegenContext.FunctionContext cur = (CodegenContext.FunctionContext) context;
@@ -1184,21 +1177,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} }
return context.lookupInContext(descriptor, v, StackValue.local(0, JetTypeMapper.TYPE_OBJECT)); 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) { public StackValue generateThisOrOuter(ClassDescriptor calleeContainingClass) {
@@ -1209,7 +1187,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if(cur instanceof CodegenContext.MethodContext && !(cur instanceof CodegenContext.ConstructorContext)) if(cur instanceof CodegenContext.MethodContext && !(cur instanceof CodegenContext.ConstructorContext))
cur = cur.getParentContext(); cur = cur.getParentContext();
if (isSubclass(cur.getThisDescriptor(), calleeContainingClass)) { if (CodegenUtil.isSubclass(cur.getThisDescriptor(), calleeContainingClass)) {
Type type = typeMapper.mapType(calleeContainingClass.getDefaultType()); Type type = typeMapper.mapType(calleeContainingClass.getDefaultType());
result.put(JetTypeMapper.TYPE_OBJECT, v); result.put(JetTypeMapper.TYPE_OBJECT, v);
return StackValue.onStack(type); return StackValue.onStack(type);
@@ -341,7 +341,7 @@ public class JetTypeMapper {
if(isInterface && superCall) { if(isInterface && superCall) {
descriptor = mapSignature(functionDescriptor.getOriginal(), valueParameterTypes, OwnerKind.TRAIT_IMPL); descriptor = mapSignature(functionDescriptor.getOriginal(), valueParameterTypes, OwnerKind.TRAIT_IMPL);
} }
thisClass = containingClass; thisClass = (ClassDescriptor) functionParent;
} }
else { else {
throw new UnsupportedOperationException("unknown function parent"); throw new UnsupportedOperationException("unknown function parent");
@@ -350,7 +350,7 @@ public class JetTypeMapper {
final CallableMethod result = new CallableMethod(owner, descriptor, invokeOpcode, valueParameterTypes); final CallableMethod result = new CallableMethod(owner, descriptor, invokeOpcode, valueParameterTypes);
result.setNeedsThis(thisClass); result.setNeedsThis(thisClass);
if(functionDescriptor.getReceiverParameter().exists()) { if(functionDescriptor.getReceiverParameter().exists()) {
result.setNeedsReceiver(functionDescriptor.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor()); result.setNeedsReceiver(functionDescriptor);
} }
return result; return result;
@@ -1,6 +1,7 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
@@ -239,6 +240,10 @@ public abstract class StackValue {
return new Composed(prefix, suffix); return new Composed(prefix, suffix);
} }
public static StackValue thisOrOuter(ExpressionCodegen codegen, ClassDescriptor descriptor) {
return new ThisOuter(codegen, descriptor);
}
private static class None extends StackValue { private static class None extends StackValue {
public static None INSTANCE = new None(); public static None INSTANCE = new None();
private None() { private None() {
@@ -817,4 +822,20 @@ public abstract class StackValue {
suffix.store(v); suffix.store(v);
} }
} }
private static class ThisOuter extends StackValue {
private ExpressionCodegen codegen;
private ClassDescriptor descriptor;
public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor) {
super(JetTypeMapper.TYPE_OBJECT);
this.codegen = codegen;
this.descriptor = descriptor;
}
@Override
public void put(Type type, InstructionAdapter v) {
codegen.generateThisOrOuter(descriptor);
}
}
} }