diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java index 4582e2e5e6c..9b5888566d1 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java @@ -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 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 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; + } + } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 81d12c3f568..b062a56f417 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -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; - } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 27bcb22b9ba..da6f4dcd525 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -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 { 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 { 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 { 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 { } private void pushTypeArguments(JetCallElement expression) { -// todo when frontend calculates -// ResolvedCallImpl resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression()); -// if(resolvedCall != null) { -// Map 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 resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression()); + if(resolvedCall != null) { + Map 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 { 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 { 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); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index fcc3f8f0173..a7724378b36 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -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(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 9cf08cd2482..926b496e243 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -162,40 +162,6 @@ public class JetTypeMapper { return new Method(method.isConstructor() ? "" : 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 valueParameterTypes = new ArrayList(); - 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 valueParameterTypes = new ArrayList(); + 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 valueParameterTypes = new ArrayList(); 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; } diff --git a/idea/idea.iml b/idea/idea.iml index 23b8c669d6e..f59f50c0a63 100644 --- a/idea/idea.iml +++ b/idea/idea.iml @@ -20,6 +20,7 @@ + diff --git a/idea/testData/codegen/functions/defaultargs.jet b/idea/testData/codegen/functions/defaultargs.jet index 9486bf5b856..137e1b3be9e 100644 --- a/idea/testData/codegen/functions/defaultargs.jet +++ b/idea/testData/codegen/functions/defaultargs.jet @@ -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.toPrefixedString(prefix: String = "") = prefix + (this as java.lang.Object).toString() +fun 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" diff --git a/idea/testData/codegen/functions/namedargs.jet b/idea/testData/codegen/functions/namedargs.jet index e237c28f4d8..e69de29bb2d 100644 --- a/idea/testData/codegen/functions/namedargs.jet +++ b/idea/testData/codegen/functions/namedargs.jet @@ -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" -} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/FunctionGenTest.java b/idea/tests/org/jetbrains/jet/codegen/FunctionGenTest.java index 5f79fc05480..130148eb40b 100644 --- a/idea/tests/org/jetbrains/jet/codegen/FunctionGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/FunctionGenTest.java @@ -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 { diff --git a/stdlib/src/jet/typeinfo/JetParameterName.java b/stdlib/src/jet/typeinfo/JetParameterName.java new file mode 100644 index 00000000000..904da5dc449 --- /dev/null +++ b/stdlib/src/jet/typeinfo/JetParameterName.java @@ -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 (); +}