diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 65702c8c8dd..690b92d50aa 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -7,11 +7,13 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.jet.resolve.DescriptorUtil; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; +import org.objectweb.asm.commons.Method; import java.util.List; import java.util.Stack; @@ -324,7 +326,8 @@ public class ExpressionCodegen extends JetVisitor { if (callee instanceof JetSimpleNameExpression) { DeclarationDescriptor funDescriptor = bindingContext.resolveReferenceExpression((JetSimpleNameExpression) callee); if (funDescriptor instanceof FunctionDescriptor) { - if (isNumberPrimitive(funDescriptor.getContainingDeclaration())) { + final DeclarationDescriptor functionParent = funDescriptor.getContainingDeclaration(); + if (isNumberPrimitive(functionParent)) { if (funDescriptor.getName().equals("inv")) { final StackValue value = myStack.pop(); // HACK we rely on the dot reference handler to put it on the stack final Type asmType = expressionType(expression); @@ -333,23 +336,41 @@ public class ExpressionCodegen extends JetVisitor { return; } } - PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(funDescriptor); - if (declarationPsiElement instanceof PsiMethod) { - PsiMethod method = (PsiMethod) declarationPsiElement; - pushMethodArguments(expression, method); - final boolean isStatic = method.hasModifierProperty(PsiModifier.STATIC); - v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, - JetTypeMapper.jvmName(method.getContainingClass()), - method.getName(), - getMethodDescriptor(method)); - final Type type = psiTypeToAsm(method.getReturnType()); - if (type != Type.VOID_TYPE) { - myStack.push(StackValue.onStack(type)); + if (expression.getParent() instanceof JetDotQualifiedExpression) { + final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent(); + if (!resolvesToClassOrPackage(parent.getReceiverExpression())) { + // we have a receiver on stack + myStack.pop().put(Type.getObjectType("java/lang/Object"), v); } } + + PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(funDescriptor); + Method methodDescriptor; + if (declarationPsiElement instanceof PsiMethod) { + PsiMethod psiMethod = (PsiMethod) declarationPsiElement; + methodDescriptor = getMethodDescriptor(psiMethod); + pushMethodArguments(expression, methodDescriptor); + + final boolean isStatic = psiMethod.hasModifierProperty(PsiModifier.STATIC); + v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, + JetTypeMapper.jvmName(psiMethod.getContainingClass()), + methodDescriptor.getName(), + methodDescriptor.getDescriptor()); + } else { - throw new UnsupportedOperationException("don't know how to generate call to " + declarationPsiElement); + if (functionParent instanceof NamespaceDescriptor && declarationPsiElement instanceof JetFunction) { + methodDescriptor = typeMapper.mapSignature((JetFunction) declarationPsiElement); + pushMethodArguments(expression, methodDescriptor); + final String owner = NamespaceCodegen.getJVMClassName(DescriptorUtil.getFQName(functionParent)); + v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor()); + } + else { + throw new UnsupportedOperationException("don't know how to generate call to " + declarationPsiElement); + } + } + if (methodDescriptor.getReturnType() != Type.VOID_TYPE) { + myStack.push(StackValue.onStack(methodDescriptor.getReturnType())); } } else { @@ -361,24 +382,23 @@ public class ExpressionCodegen extends JetVisitor { } } - private void pushMethodArguments(JetCall expression, PsiMethod method) { - PsiParameter[] parameters = method.getParameterList().getParameters(); - + private void pushMethodArguments(JetCall expression, Method method) { + final Type[] argTypes = method.getArgumentTypes(); List args = expression.getValueArguments(); for (int i = 0, argsSize = args.size(); i < argsSize; i++) { JetArgument arg = args.get(i); - gen(arg.getArgumentExpression(), psiTypeToAsm(parameters[i].getType())); + gen(arg.getArgumentExpression(), argTypes[i]); } } - private static String getMethodDescriptor(PsiMethod method) { + private static Method getMethodDescriptor(PsiMethod method) { Type returnType = method.isConstructor() ? Type.VOID_TYPE : psiTypeToAsm(method.getReturnType()); PsiParameter[] parameters = method.getParameterList().getParameters(); Type[] parameterTypes = new Type[parameters.length]; for (int i = 0; i < parameters.length; i++) { parameterTypes[i] = psiTypeToAsm(parameters [i].getType()); } - return Type.getMethodDescriptor(returnType, parameterTypes); + return new Method(method.getName(), Type.getMethodDescriptor(returnType, parameterTypes)); } private Type expressionType(JetExpression expr) { @@ -798,8 +818,9 @@ public class ExpressionCodegen extends JetVisitor { Type type = JetTypeMapper.psiClassType(javaClass); v.anew(type); v.dup(); - pushMethodArguments(expression, constructor); - v.invokespecial(JetTypeMapper.jvmName(javaClass), "", getMethodDescriptor(constructor)); + final Method constructorDescriptor = getMethodDescriptor(constructor); + pushMethodArguments(expression, constructorDescriptor); + v.invokespecial(JetTypeMapper.jvmName(javaClass), "", constructorDescriptor.getDescriptor()); myStack.push(StackValue.onStack(type)); return; } diff --git a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java index ce5e443093b..b59565627cb 100644 --- a/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -36,22 +36,7 @@ public class FunctionCodegen { } private void gen(JetFunction f) { - final List parameters = f.getValueParameters(); - Type[] parameterTypes = new Type[parameters.size()]; - for (int i = 0; i < parameters.size(); i++) { - parameterTypes[i] = typeMapper.mapType(bindingContext.resolveTypeReference(parameters.get(i).getTypeReference())); - } - final JetTypeReference returnTypeRef = f.getReturnTypeRef(); - Type returnType; - if (returnTypeRef == null) { - final FunctionDescriptor functionDescriptor = bindingContext.getFunctionDescriptor(f); - final JetType type = functionDescriptor.getUnsubstitutedReturnType(); - returnType = typeMapper.mapType(type); - } - else { - returnType = typeMapper.mapType(bindingContext.resolveTypeReference(returnTypeRef)); - } - Method method = new Method(f.getName(), returnType, parameterTypes); + Method method = typeMapper.mapSignature(f); final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, method.getName(), method.getDescriptor(), null, null); mv.visitCode(); @@ -60,12 +45,13 @@ public class FunctionCodegen { List parameDescrs = bindingContext.getFunctionDescriptor(f).getUnsubstitutedValueParameters(); + Type[] argTypes = method.getArgumentTypes(); for (int i = 0; i < parameDescrs.size(); i++) { ValueParameterDescriptor parameter = parameDescrs.get(i); - frameMap.enter(parameter, parameterTypes[i].getSize()); + frameMap.enter(parameter, argTypes[i].getSize()); } - ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, returnType); + ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, typeMapper, method.getReturnType()); bodyExpression.accept(codegen); generateReturn(mv, bodyExpression, codegen); mv.visitMaxs(0, 0); diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index adebe2cd025..38a20e3cd10 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -2,9 +2,15 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; +import org.jetbrains.jet.lang.psi.JetFunction; +import org.jetbrains.jet.lang.psi.JetParameter; +import org.jetbrains.jet.lang.psi.JetTypeReference; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.*; import org.objectweb.asm.Type; +import org.objectweb.asm.commons.Method; + +import java.util.List; /** * @author yole @@ -105,4 +111,23 @@ public class JetTypeMapper { throw new UnsupportedOperationException("Unknown type " + jetType); } + + public Method mapSignature(JetFunction f) { + final List parameters = f.getValueParameters(); + Type[] parameterTypes = new Type[parameters.size()]; + for (int i = 0; i < parameters.size(); i++) { + parameterTypes[i] = mapType(bindingContext.resolveTypeReference(parameters.get(i).getTypeReference())); + } + final JetTypeReference returnTypeRef = f.getReturnTypeRef(); + Type returnType; + if (returnTypeRef == null) { + final FunctionDescriptor functionDescriptor = bindingContext.getFunctionDescriptor(f); + final JetType type = functionDescriptor.getUnsubstitutedReturnType(); + returnType = mapType(type); + } + else { + returnType = mapType(bindingContext.resolveTypeReference(returnTypeRef)); + } + return new Method(f.getName(), returnType, parameterTypes); + } } diff --git a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java index 9cd32a6711c..be5929da431 100644 --- a/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/NamespaceCodegen.java @@ -54,6 +54,9 @@ public class NamespaceCodegen { } public static String getJVMClassName(String fqName) { + if (fqName.length() == 0) { + return "namespace"; + } return fqName.replace('.', '/') + "/namespace"; } diff --git a/idea/testData/codegen/functionCall.jet b/idea/testData/codegen/functionCall.jet new file mode 100644 index 00000000000..417b62f052d --- /dev/null +++ b/idea/testData/codegen/functionCall.jet @@ -0,0 +1,9 @@ +fun f() { + val x = new StringBuilder(); + g(x); + return x.toString(); +} + +fun g(sb: StringBuilder): Unit { + sb.append("foo"); +} diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index e742327062e..76dedc0880e 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -530,6 +530,13 @@ public class NamespaceGenTest extends LightCodeInsightFixtureTestCase { assertEquals(Boolean.FALSE, main.invoke(null, null, "jet")); } + public void testFunctionCall() throws Exception { + loadFile("functionCall.jet"); + System.out.println(generateToText()); + final Method main = generateFunction(); + assertEquals("foo", main.invoke(null)); + } + private void binOpTest(final String text, final Object arg1, final Object arg2, final Object expected) throws Exception { loadText(text); System.out.println(generateToText());