diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index a21ea8a50dc..5c83f20f4c4 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -26,6 +26,7 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; import org.objectweb.asm.commons.Method; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Stack; @@ -1153,43 +1154,61 @@ public class ExpressionCodegen extends JetVisitor { @Override public void visitNewExpression(JetNewExpression expression) { - final JetUserType constructorType = (JetUserType) expression.getTypeReference().getTypeElement(); + JetTypeReference typeReference = expression.getTypeReference(); + final JetUserType constructorType = (JetUserType) typeReference.getTypeElement(); final JetSimpleNameExpression constructorReference = constructorType.getReferenceExpression(); DeclarationDescriptor constructorDescriptor = bindingContext.resolveReferenceExpression(constructorReference); final PsiElement declaration = bindingContext.getDeclarationPsiElement(constructorDescriptor); + Type type; if (declaration instanceof PsiMethod) { - final PsiMethod constructor = (PsiMethod) declaration; - PsiClass javaClass = constructor.getContainingClass(); - Type type = JetTypeMapper.psiClassType(javaClass); - v.anew(type); - v.dup(); - final Method jvmConstructor = getMethodDescriptor(constructor); - pushMethodArguments(expression, jvmConstructor); - v.invokespecial(JetTypeMapper.jvmName(javaClass), "", jvmConstructor.getDescriptor()); - myStack.push(StackValue.onStack(type)); - return; + type = generateJavaConstructorCall(expression, (PsiMethod) declaration); } else if (constructorDescriptor instanceof ConstructorDescriptor) { - ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration(); - Type type = JetTypeMapper.jetImplementationType(classDecl); - v.anew(type); - v.dup(); - - Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION); - pushMethodArguments(expression, method); - - for (JetTypeReference typeArgumentReference : constructorType.getTypeArgumentsAsTypes()) { - JetType typeArgument = bindingContext.resolveTypeReference(typeArgumentReference); - // TODO is the makeNullable() call correct here? - ClassCodegen.newTypeInfo(v, typeMapper.mapType(TypeUtils.makeNullable(typeArgument))); + type = typeMapper.mapType(bindingContext.resolveTypeReference(typeReference), OwnerKind.IMPLEMENTATION); + if (type.getSort() == Type.ARRAY) { + generateNewArray(expression, type); } + else { + v.anew(type); + v.dup(); - v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "", method.getDescriptor()); - myStack.push(StackValue.onStack(type)); - return; + Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION); + pushMethodArguments(expression, method); + + for (JetTypeReference typeArgumentReference : constructorType.getTypeArgumentsAsTypes()) { + JetType typeArgument = bindingContext.resolveTypeReference(typeArgumentReference); + // TODO is the makeNullable() call correct here? + ClassCodegen.newTypeInfo(v, typeMapper.mapType(TypeUtils.makeNullable(typeArgument))); + } + + ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration(); + v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "", method.getDescriptor()); + } } + else { + throw new UnsupportedOperationException("don't know how to generate this new expression"); + } + myStack.push(StackValue.onStack(type)); + } - throw new UnsupportedOperationException("don't know how to generate this new expression"); + private Type generateJavaConstructorCall(JetNewExpression expression, PsiMethod constructor) { + PsiClass javaClass = constructor.getContainingClass(); + Type type = JetTypeMapper.psiClassType(javaClass); + v.anew(type); + v.dup(); + final Method jvmConstructor = getMethodDescriptor(constructor); + pushMethodArguments(expression, jvmConstructor); + v.invokespecial(JetTypeMapper.jvmName(javaClass), "", jvmConstructor.getDescriptor()); + return type; + } + + private void generateNewArray(JetNewExpression expression, Type type) { + List args = expression.getValueArguments(); + if (args.size() != 1) { + throw new CompilationException("array constructor requires one value argument"); + } + gen(args.get(0).getArgumentExpression(), Type.INT_TYPE); + v.newarray(type.getElementType()); } @Override @@ -1308,7 +1327,7 @@ public class ExpressionCodegen extends JetVisitor { if (!(descriptor instanceof ClassDescriptor)) { throw new UnsupportedOperationException("don't know how to handle non-class types in as/as?"); } - Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE); + Type type = typeMapper.mapType(jetType, OwnerKind.INTERFACE); gen(expression.getLeft(), OBJECT_TYPE); if (opToken == JetTokens.AS_SAFE) { generateInstanceOf(new Runnable() { @@ -1380,7 +1399,7 @@ public class ExpressionCodegen extends JetVisitor { if (leaveExpressionOnStack) { v.dup(); } - Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE); + Type type = typeMapper.mapType(jetType, OwnerKind.INTERFACE); v.instanceOf(type); } } @@ -1487,5 +1506,11 @@ public class ExpressionCodegen extends JetVisitor { } private static class CompilationException extends RuntimeException { + private CompilationException() { + } + + private CompilationException(String message) { + super(message); + } } } diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index c82d00dbb52..2414093a025 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import jet.typeinfo.TypeInfo; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -118,6 +119,10 @@ public class JetTypeMapper { } public Type mapType(final JetType jetType) { + return mapType(jetType, OwnerKind.INTERFACE); + } + + public Type mapType(final JetType jetType, OwnerKind kind) { if (jetType.equals(JetStandardClasses.getUnitType()) || jetType.equals(JetStandardClasses.getNothingType())) { return Type.VOID_TYPE; } @@ -191,7 +196,7 @@ public class JetTypeMapper { if (declaration instanceof PsiClass) { return psiClassType((PsiClass) declaration); } - return Type.getObjectType(jvmNameForInterface((ClassDescriptor) descriptor)); + return Type.getObjectType(jetJvmName((ClassDescriptor) descriptor, kind)); } throw new UnsupportedOperationException("Unknown type " + jetType); diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index fd74ebf0f0e..5184b5afd97 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -360,6 +360,13 @@ public class NamespaceGenTest extends CodegenTestCase { assertEquals(10, data[0]); } + public void testArrayNew() throws Exception { + loadText("fun foo() = new Array(4)"); + final Method main = generateFunction(); + int[] result = (int[]) main.invoke(null); + assertEquals(4, result.length); + } + public void testIntRange() throws Exception { loadText("fun foo() = 1..10"); final Method main = generateFunction();