tests/fixes

This commit is contained in:
Alex Tkachman
2011-10-20 07:25:22 +02:00
parent efa9a25ea5
commit 417bb26646
10 changed files with 150 additions and 118 deletions
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
@@ -18,9 +19,9 @@ public class CallableMethod implements Callable {
private final int invokeOpcode;
private final List<Type> valueParameterTypes;
private boolean acceptsTypeArguments = false;
private boolean needsReceiverOnStack = false;
private boolean ownerFromCall = false;
private ClassDescriptor receiverClass = null;
private DeclarationDescriptor thisClass = null;
private DeclarationDescriptor receiverClass = null;
private Type generateCalleeType = null;
public CallableMethod(String owner, Method signature, int invokeOpcode, List<Type> valueParameterTypes) {
@@ -58,13 +59,12 @@ public class CallableMethod implements Callable {
this.acceptsTypeArguments = acceptsTypeArguments;
}
public void setNeedsReceiver(@Nullable ClassDescriptor receiverClass) {
needsReceiverOnStack = true;
public void setNeedsReceiver(@Nullable DeclarationDescriptor receiverClass) {
this.receiverClass = receiverClass;
}
public boolean needsReceiverOnStack() {
return needsReceiverOnStack;
public void setNeedsThis(@Nullable DeclarationDescriptor receiverClass) {
this.thisClass = receiverClass;
}
public boolean isOwnerFromCall() {
@@ -75,10 +75,6 @@ public class CallableMethod implements Callable {
this.ownerFromCall = ownerFromCall;
}
public ClassDescriptor getReceiverClass() {
return receiverClass;
}
void invoke(InstructionAdapter v) {
v.visitMethodInsn(getInvokeOpcode(), getOwner(), getSignature().getName(), getSignature().getDescriptor());
}
@@ -98,4 +94,17 @@ public class CallableMethod implements Callable {
desc = desc.replace("(", "(L" + getOwner() + ";");
v.visitMethodInsn(Opcodes.INVOKESTATIC, getInvokeOpcode() == Opcodes.INVOKEINTERFACE ? getOwner() + "$$TImpl" : getOwner(), getSignature().getName() + "$default", desc);
}
public boolean isNeedsThis() {
return thisClass != null;
}
public boolean isNeedsReceiver() {
return receiverClass != null;
}
public DeclarationDescriptor getThisClass() {
return thisClass;
}
}
@@ -4,10 +4,7 @@
package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.Pair;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -260,15 +257,4 @@ public class ClosureCodegen extends FunctionOrClosureCodegen {
signatureWriter.visitClassType(rawRetType.getInternalName());
signatureWriter.visitEnd();
}
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(null);
}
result.requestGenerateCallee(Type.getObjectType(getInternalClassName(fd)));
return result;
}
}
@@ -27,6 +27,8 @@ import org.objectweb.asm.commons.Method;
import java.util.*;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
/**
* @author max
* @author yole
@@ -77,6 +79,17 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
this.intrinsics = state.getIntrinsics();
}
private 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() {
return state;
}
@@ -983,7 +996,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
callableMethod = typeMapper.mapToCallableMethod((PsiNamedElement) declarationPsiElement, null);
}
else if (fd instanceof VariableAsFunctionDescriptor) {
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
callableMethod = asCallableMethod((FunctionDescriptor) fd);
}
else if (fd instanceof FunctionDescriptor) {
callableMethod = typeMapper.mapToCallableMethod((FunctionDescriptor) fd, null);
@@ -1018,13 +1031,27 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
if (callableMethod.isOwnerFromCall()) {
setOwnerFromCall(callableMethod, expression);
}
if (callableMethod.needsReceiverOnStack()) {
if (receiver == StackValue.none()) {
ClassDescriptor receiverClass = callableMethod.getReceiverClass();
receiver = receiverClass == null ? thisExpression() : generateThisOrOuter(receiverClass);
if (callableMethod.isNeedsThis()) {
if(callableMethod.isNeedsReceiver()) {
generateThisOrOuter((ClassDescriptor) callableMethod.getThisClass()).put(JetTypeMapper.TYPE_OBJECT, v);
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
}
else {
if (receiver == StackValue.none()) {
generateThisOrOuter((ClassDescriptor) callableMethod.getThisClass()).put(JetTypeMapper.TYPE_OBJECT, v);;
}
else {
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
}
}
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
}
else {
if (callableMethod.isNeedsReceiver()) {
receiver.put(JetTypeMapper.TYPE_OBJECT, v);
}
}
int mask = pushMethodArguments(expression, callableMethod.getValueParameterTypes());
if (callableMethod.acceptsTypeArguments()) {
pushTypeArguments(expression);
@@ -1790,23 +1817,19 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
private void pushTypeArguments(JetCallElement expression) {
// todo when frontend calculates
// ResolvedCallImpl<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
// if(resolvedCall != null) {
// Map<TypeParameterDescriptor, JetType> typeArguments = resolvedCall.getTypeArguments();
// CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
// for (TypeParameterDescriptor typeParameterDescriptor : resultingDescriptor.getTypeParameters()) {
// JetType jetType = typeArguments.get(typeParameterDescriptor);
// generateTypeInfo(jetType);
// }
// }
// else {
// for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) {
// pushTypeArgument(jetTypeArgument);
// }
// }
for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) {
pushTypeArgument(jetTypeArgument);
ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
if(resolvedCall != null) {
Map<TypeParameterDescriptor, JetType> typeArguments = resolvedCall.getTypeArguments();
CallableDescriptor resultingDescriptor = resolvedCall.getCandidateDescriptor();
for (TypeParameterDescriptor typeParameterDescriptor : resultingDescriptor.getTypeParameters()) {
JetType jetType = typeArguments.get(typeParameterDescriptor);
generateTypeInfo(jetType);
}
}
else {
for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) {
pushTypeArgument(jetTypeArgument);
}
}
}
@@ -1820,7 +1843,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
Type type = JetTypeMapper.psiClassType(javaClass);
v.anew(type);
v.dup();
final CallableMethod callableMethod = JetTypeMapper.mapToCallableMethod(constructor);
final CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructor);
invokeMethodWithArguments(callableMethod, expression);
return type;
}
@@ -1916,7 +1939,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
assert declaration != null : "No declaration found for " + expression.getText();
final CallableMethod accessor;
if (declaration instanceof PsiMethod) {
accessor = JetTypeMapper.mapToCallableMethod((PsiMethod) declaration);
accessor = typeMapper.mapToCallableMethod((PsiMethod) declaration);
}
else if (declaration instanceof JetNamedFunction) {
accessor = typeMapper.mapToCallableMethod((JetNamedFunction) declaration, null);
@@ -63,6 +63,14 @@ public class FunctionCodegen {
if (isAbstract) flags |= ACC_ABSTRACT;
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
if(kind != OwnerKind.TRAIT_IMPL) {
int start = functionDescriptor.getReceiverParameter().exists() ? 1 : 0;
for(int i = 0; i != paramDescrs.size(); ++i) {
AnnotationVisitor annotationVisitor = mv.visitParameterAnnotation(i + start, "jet/typeinfo/JetParameterName", true);
annotationVisitor.visit("value", paramDescrs.get(i).getName());
annotationVisitor.visitEnd();
}
}
if (!isAbstract) {
mv.visitCode();
FrameMap frameMap = context.prepareFrame();
@@ -162,40 +162,6 @@ public class JetTypeMapper {
return new Method(method.isConstructor() ? "<init>" : method.getName(), Type.getMethodDescriptor(returnType, parameterTypes));
}
static CallableMethod mapToCallableMethod(PsiMethod method) {
final PsiClass containingClass = method.getContainingClass();
String owner = jvmName(containingClass);
Method signature = getMethodDescriptor(method);
List<Type> valueParameterTypes = new ArrayList<Type>();
Collections.addAll(valueParameterTypes, signature.getArgumentTypes());
int opcode;
boolean needsReceiver = false;
boolean ownerFromCall = false;
if (method.isConstructor()) {
opcode = Opcodes.INVOKESPECIAL;
}
else if (method.hasModifierProperty(PsiModifier.STATIC)) {
opcode = Opcodes.INVOKESTATIC;
}
else {
needsReceiver = true;
assert containingClass != null;
if (containingClass.isInterface()) {
opcode = Opcodes.INVOKEINTERFACE;
}
else {
opcode = Opcodes.INVOKEVIRTUAL;
}
ownerFromCall = true;
}
final CallableMethod result = new CallableMethod(owner, signature, opcode, valueParameterTypes);
if (needsReceiver) {
result.setNeedsReceiver(null);
}
result.setOwnerFromCall(ownerFromCall);
return result;
}
public static Type getBoxedType(final Type type) {
switch (type.getSort()) {
case Type.BYTE:
@@ -518,18 +484,49 @@ public class JetTypeMapper {
return mapToCallableMethod(functionDescriptor, kind);
}
CallableMethod mapToCallableMethod(PsiMethod method) {
final PsiClass containingClass = method.getContainingClass();
String owner = jvmName(containingClass);
Method signature = getMethodDescriptor(method);
List<Type> valueParameterTypes = new ArrayList<Type>();
Collections.addAll(valueParameterTypes, signature.getArgumentTypes());
int opcode;
boolean ownerFromCall = false;
DeclarationDescriptor thisClass = null;
if (method.isConstructor()) {
opcode = Opcodes.INVOKESPECIAL;
}
else if (method.hasModifierProperty(PsiModifier.STATIC)) {
opcode = Opcodes.INVOKESTATIC;
}
else {
assert containingClass != null;
if (containingClass.isInterface()) {
opcode = Opcodes.INVOKEINTERFACE;
}
else {
opcode = Opcodes.INVOKEVIRTUAL;
}
ownerFromCall = true;
thisClass = JetStandardClasses.getAny(); // todo - this is hack, correct descriptor needed
}
final CallableMethod result = new CallableMethod(owner, signature, opcode, valueParameterTypes);
result.setNeedsThis(thisClass);
result.setOwnerFromCall(ownerFromCall);
return result;
}
public CallableMethod mapToCallableMethod(FunctionDescriptor functionDescriptor, OwnerKind kind) {
final DeclarationDescriptor functionParent = functionDescriptor.getContainingDeclaration();
final List<Type> valueParameterTypes = new ArrayList<Type>();
Method descriptor = mapSignature(functionDescriptor.getOriginal(), valueParameterTypes, kind);
String owner;
int invokeOpcode;
boolean needsReceiver;
ClassDescriptor receiverClass = null;
ClassDescriptor thisClass;
if (functionParent instanceof NamespaceDescriptor) {
owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent));
invokeOpcode = Opcodes.INVOKESTATIC;
needsReceiver = functionDescriptor.getReceiverParameter().exists();
thisClass = null;
}
else if (functionParent instanceof ClassDescriptor) {
ClassDescriptor containingClass = (ClassDescriptor) functionParent;
@@ -537,8 +534,7 @@ public class JetTypeMapper {
invokeOpcode = CodegenUtil.isInterface(containingClass)
? Opcodes.INVOKEINTERFACE
: Opcodes.INVOKEVIRTUAL;
needsReceiver = true;
receiverClass = containingClass;
thisClass = containingClass;
}
else {
throw new UnsupportedOperationException("unknown function parent");
@@ -546,9 +542,11 @@ public class JetTypeMapper {
final CallableMethod result = new CallableMethod(owner, descriptor, invokeOpcode, valueParameterTypes);
result.setAcceptsTypeArguments(true);
if (needsReceiver) {
result.setNeedsReceiver(receiverClass);
result.setNeedsThis(thisClass);
if(functionDescriptor.getReceiverParameter().exists()) {
result.setNeedsReceiver(functionDescriptor.getReceiverParameter().getType().getConstructor().getDeclarationDescriptor());
}
return result;
}
+1
View File
@@ -20,6 +20,7 @@
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="stdlib" />
<orderEntry type="module" module-name="cli" />
</component>
</module>
@@ -13,7 +13,7 @@ trait A {
fun bar(arg: Int = 240) : Int = bar2(arg/2)
}
open abstract class B() : A {
open abstract class B() : A, java.lang.Object() {
fun foo(arg: Int = 239 + 1) : Int = arg
abstract fun foo2(arg: Int = 239) : Int
@@ -23,15 +23,29 @@ open abstract class B() : A {
class C() : B() {
override fun foo2(arg: Int) : Int = arg
fun Any.toMyPrefixedString(prefix: String = "", suffix: String="") : String = prefix + " " + suffix
fun testReceiver() : String {
val res : String = "mama".toMyPrefixedString("111", "222")
System.out?.println(res)
return res
}
override fun toString() : String = "CCC"
}
// fun <T> T.toPrefixedString(prefix: String = "") = prefix + (this as java.lang.Object).toString()
fun <T> T.toPrefixedString(prefix: String = "", suffix: String="") = prefix + (this as java.lang.Object).toString() + suffix
fun box() : String {
val expected = (true, true, true, " ")
// if("mama".toPrefixedString("papa") != "papamama") return "fail"
// if("mama".toPrefixedString() != "mama") return "fail"
if("mama".toPrefixedString(suffix="321", prefix="papa") != "papamama321") return "fail"
if("mama".toPrefixedString(prefix="papa") != "papamama") return "fail"
if("mama".toPrefixedString("papa", "239") != "papamama239") return "fail"
if("mama".toPrefixedString("papa") != "papamama") return "fail"
if("mama".toPrefixedString() != "mama") return "fail"
if(C().testReceiver() != "111 222") return "fail"
if(C().bar(10) != 5) return "fail"
if(C().bar() != 120) return "fail"
if(C().foo(10) != 10) return "fail"
@@ -1,19 +0,0 @@
fun reformat(
str : String,
normalizeCase : Boolean = true,
uppercaseFirstLetter : Boolean = true,
divideByCamelHumps : Boolean = false,
wordSeparator : String = " "
) =
(normalizeCase, uppercaseFirstLetter, divideByCamelHumps, wordSeparator)
fun box() : String {
val expected = (true, true, false, " ")
if(reformat("", true, true, false, " ") != expected) return "fail"
// if(reformat(str="", wordSeparator=" ") != expected) return "fail"
// if(reformat("", true, true, false) != expected) return "fail"
// if(reformat("", true, true) != expected) return "fail"
// if(reformat("", true) != expected) return "fail"
// if(reformat("") != expected) return "fail"
return "OK"
}
@@ -6,10 +6,7 @@ package org.jetbrains.jet.codegen;
public class FunctionGenTest extends CodegenTestCase {
public void testDefaultArgs() throws Exception {
blackBoxFile("functions/defaultargs.jet");
}
public void testNamedArgs() throws Exception {
blackBoxFile("functions/defaultargs.jet");
System.out.println(generateToText());
}
public void testNoThisNoClosure() throws Exception {
@@ -0,0 +1,15 @@
package jet.typeinfo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author alex.tkachman
*/
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface JetParameterName {
String value ();
}