From ea9e1bee852f2a5af1e8f55b3c7e707fc98cdc08 Mon Sep 17 00:00:00 2001 From: Alex Tkachman Date: Thu, 29 Sep 2011 12:55:35 +0300 Subject: [PATCH] array code gen rewrite and work in progress on outer type info --- .../jetbrains/jet/codegen/ClassCodegen.java | 5 - .../jetbrains/jet/codegen/CodegenUtil.java | 49 +++- .../jet/codegen/ConstructorFrameMap.java | 5 +- .../jet/codegen/ExpressionCodegen.java | 131 ++++++++--- .../codegen/ImplementationBodyCodegen.java | 190 +++++++++------- .../jetbrains/jet/codegen/JetTypeMapper.java | 56 ++++- .../jetbrains/jet/codegen/SignatureUtil.java | 10 +- .../org/jetbrains/jet/codegen/StackValue.java | 25 ++- .../jet/codegen/intrinsics/ArraySize.java | 29 ++- .../jet/lang/types/JetStandardLibrary.java | 17 +- .../codegen/controlStructures/forIntArray.jet | 14 ++ .../controlStructures/forNullableIntArray.jet | 16 ++ idea/testData/codegen/regressions/kt326.jet | 34 ++- idea/testData/codegen/traits/stdlib.jet | 20 +- idea/testData/codegen/typeInfo/inner.jet | 15 ++ .../jetbrains/jet/codegen/ArrayGenTest.java | 14 +- .../jet/codegen/ControlStructuresTest.java | 13 +- .../jet/codegen/NamespaceGenTest.java | 21 +- .../org/jetbrains/jet/codegen/TraitsTest.java | 2 - .../jetbrains/jet/codegen/TypeInfoTest.java | 4 + stdlib/src/jet/arrays/JetArray.java | 67 ++++++ stdlib/src/jet/arrays/JetBoolArray.java | 35 +++ stdlib/src/jet/arrays/JetByteArray.java | 35 +++ stdlib/src/jet/arrays/JetCharArray.java | 35 +++ stdlib/src/jet/arrays/JetDoubleArray.java | 35 +++ stdlib/src/jet/arrays/JetFloatArray.java | 35 +++ stdlib/src/jet/arrays/JetGenericArray.java | 38 ++++ stdlib/src/jet/arrays/JetIntArray.java | 35 +++ stdlib/src/jet/arrays/JetLongArray.java | 35 +++ stdlib/src/jet/arrays/JetShortArray.java | 35 +++ stdlib/src/jet/typeinfo/TypeInfo.java | 212 +++++++++++++----- 31 files changed, 1035 insertions(+), 232 deletions(-) create mode 100644 idea/testData/codegen/controlStructures/forIntArray.jet create mode 100644 idea/testData/codegen/controlStructures/forNullableIntArray.jet create mode 100644 idea/testData/codegen/typeInfo/inner.jet create mode 100644 stdlib/src/jet/arrays/JetArray.java create mode 100644 stdlib/src/jet/arrays/JetBoolArray.java create mode 100644 stdlib/src/jet/arrays/JetByteArray.java create mode 100644 stdlib/src/jet/arrays/JetCharArray.java create mode 100644 stdlib/src/jet/arrays/JetDoubleArray.java create mode 100644 stdlib/src/jet/arrays/JetFloatArray.java create mode 100644 stdlib/src/jet/arrays/JetGenericArray.java create mode 100644 stdlib/src/jet/arrays/JetIntArray.java create mode 100644 stdlib/src/jet/arrays/JetLongArray.java create mode 100644 stdlib/src/jet/arrays/JetShortArray.java diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java index 0a13ef4158d..60dc3bc46f0 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -45,9 +45,4 @@ public class ClassCodegen { } - public static void newTypeInfo(InstructionAdapter v, boolean isNullable, Type asmType) { - v.aconst(asmType); - v.iconst(isNullable?1:0); - v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;"); - } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index 562dcd33014..3e3fe413c90 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -1,9 +1,12 @@ package org.jetbrains.jet.codegen; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; import org.objectweb.asm.Type; @@ -43,7 +46,7 @@ public class CodegenUtil { return getOuterClassDescriptor(classDescriptor) != null && !isClassObject(classDescriptor); } - public static ClassDescriptor getOuterClassDescriptor(ClassDescriptor descriptor) { + public static ClassDescriptor getOuterClassDescriptor(DeclarationDescriptor descriptor) { DeclarationDescriptor outerDescriptor = descriptor.getContainingDeclaration(); while(outerDescriptor != null) { if(outerDescriptor instanceof ClassDescriptor) @@ -54,6 +57,48 @@ public class CodegenUtil { return (ClassDescriptor) outerDescriptor; } + public static boolean hasOuterTypeInfo(ClassDescriptor descriptor) { + ClassDescriptor outerClassDescriptor = getOuterClassDescriptor(descriptor); + if(outerClassDescriptor == null) + return false; + + if(outerClassDescriptor.getTypeConstructor().getParameters().size() > 0) + return true; + + return hasOuterTypeInfo(outerClassDescriptor); + } + + public static boolean hasTypeInfoField(JetType type) { + if(type.getConstructor().getParameters().size() > 0) + return true; + + for (JetType jetType : type.getConstructor().getSupertypes()) { + if(hasTypeInfoField(jetType)) + return true; + } + + ClassDescriptor outerClassDescriptor = getOuterClassDescriptor(type.getConstructor().getDeclarationDescriptor()); + if(outerClassDescriptor == null) + return false; + + return hasTypeInfoField(outerClassDescriptor.getDefaultType()); + } + + public static boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) { + if(!exceptOwn) { + if(!isInterface(type)) + if(hasTypeInfoField(type)) + return true; + } + + for (JetType jetType : type.getConstructor().getSupertypes()) { + if(hasDerivedTypeInfoField(jetType, false)) + return true; + } + + return false; + } + public static Type arrayElementType(Type type) { return Type.getType(type.getDescriptor().substring(1)); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java b/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java index f9be40b26c5..17a134befac 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java @@ -17,11 +17,9 @@ public class ConstructorFrameMap extends FrameMap { private int myFirstTypeParameter = -1; private int myTypeParameterCount = 0; - public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor, OwnerKind kind) { + public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorDescriptor descriptor, ClassDescriptor classDescriptor, OwnerKind kind) { enterTemp(); // this - ClassDescriptor classDescriptor = null; if (descriptor != null) { - classDescriptor = descriptor.getContainingDeclaration(); if (CodegenUtil.hasThis0(classDescriptor)) { myOuterThisIndex = enterTemp(); // outer class instance } @@ -37,7 +35,6 @@ public class ConstructorFrameMap extends FrameMap { enter(parameter, explicitArgTypes.get(i).getSize()); } - if (classDescriptor != null) { myTypeParameterCount = classDescriptor.getTypeConstructor().getParameters().size(); if (kind == OwnerKind.IMPLEMENTATION) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 096e1b3aa51..d7a50da4a27 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -200,7 +200,7 @@ public class ExpressionCodegen extends JetVisitor { final JetExpression loopRange = expression.getLoopRange(); final JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, loopRange); Type loopRangeType = typeMapper.mapType(expressionType); - if (loopRangeType.getSort() == Type.ARRAY) { + if (state.getStandardLibrary().getArray().equals(expressionType.getConstructor().getDeclarationDescriptor())) { new ForInArrayLoopGenerator(expression, loopRangeType).invoke(); return StackValue.none(); } @@ -364,6 +364,7 @@ public class ExpressionCodegen extends JetVisitor { protected void generatePrologue() { myLengthVar = myMap.enterTemp(); gen(expression.getLoopRange(), loopRangeType); + derefArray(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getLoopRange())); v.arraylength(); v.store(myLengthVar, Type.INT_TYPE); myIndexVar = myMap.enterTemp(); @@ -377,9 +378,10 @@ public class ExpressionCodegen extends JetVisitor { v.ificmpge(end); gen(expression.getLoopRange(), loopRangeType); // array + derefArray(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression.getLoopRange())); v.load(myIndexVar, Type.INT_TYPE); - v.aload(CodegenUtil.arrayElementType(loopRangeType)); - StackValue.onStack(CodegenUtil.arrayElementType(loopRangeType)).put(asmParamType, v); + v.aload(asmParamType); + StackValue.onStack(asmParamType).put(asmParamType, v); v.store(lookupLocal(parameterDescriptor), asmParamType); } @@ -1622,9 +1624,10 @@ public class ExpressionCodegen extends JetVisitor { } else if (constructorDescriptor instanceof ConstructorDescriptor) { //noinspection ConstantConditions - type = typeMapper.mapType(bindingContext.get(BindingContext.EXPRESSION_TYPE, expression), OwnerKind.IMPLEMENTATION); - if (type.getSort() == Type.ARRAY) { - generateNewArray(expression, type); + JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); + type = typeMapper.mapType(expressionType, OwnerKind.IMPLEMENTATION); + if (state.getStandardLibrary().getArray().equals(expressionType.getConstructor().getDeclarationDescriptor())) { + generateNewArray(expression, expressionType); } else { ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration(); @@ -1682,9 +1685,7 @@ public class ExpressionCodegen extends JetVisitor { return type; } - private void generateNewArray(JetCallExpression expression, Type type) { - JetType arrayType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression); - + private void generateNewArray(JetCallExpression expression, JetType arrayType) { List args = expression.getValueArguments(); if (args.size() != 1) { throw new CompilationException("array constructor requires one value argument"); @@ -1694,23 +1695,53 @@ public class ExpressionCodegen extends JetVisitor { JetType elementType = typeMapper.getGenericsElementType(arrayType); if(elementType != null) { generateTypeInfo(elementType); - v.invokestatic("jet/typeinfo/TypeInfo", "newArray", "(ILjet/typeinfo/TypeInfo;)[Ljava/lang/Object;"); - v.checkcast(type); + v.invokestatic("jet/arrays/JetArray", "newArray", "(ILjet/typeinfo/TypeInfo;)Ljet/arrays/JetArray;"); } else { - v.newarray(CodegenUtil.arrayElementType(type)); + elementType = arrayType.getArguments().get(0).getType(); + JetStandardLibrary standardLibrary = state.getStandardLibrary(); + if (elementType.equals(standardLibrary.getIntType())) { + v.invokestatic("jet/arrays/JetArray", "newIntArray", "(I)Ljet/arrays/JetIntArray;"); + } + else if (elementType.equals(standardLibrary.getLongType())) { + v.invokestatic("jet/arrays/JetArray", "newLongArray", "(I)Ljet/arrays/JetLongArray;"); + } + else if (elementType.equals(standardLibrary.getShortType())) { + v.invokestatic("jet/arrays/JetArray", "newShortArray", "(I)Ljet/arrays/JetShortArray;"); + } + else if (elementType.equals(standardLibrary.getByteType())) { + v.invokestatic("jet/arrays/JetArray", "newByteArray", "(I)Ljet/arrays/JetByteArray;"); + } + else if (elementType.equals(standardLibrary.getCharType())) { + v.invokestatic("jet/arrays/JetArray", "newCharArray", "(I)Ljet/arrays/JetCharArray;"); + } + else if (elementType.equals(standardLibrary.getFloatType())) { + v.invokestatic("jet/arrays/JetArray", "newFloatArray", "(I)Ljet/arrays/JetFloatArray;"); + } + else if (elementType.equals(standardLibrary.getDoubleType())) { + v.invokestatic("jet/arrays/JetArray", "newDoubleArray", "(I)Ljet/arrays/JetDoubleArray;"); + } + else if (elementType.equals(standardLibrary.getBooleanType())) { + v.invokestatic("jet/arrays/JetArray", "newBoolArray", "(I)Ljet/arrays/JetBoolArray;"); + } + else { + generateTypeInfo(elementType); + v.invokestatic("jet/arrays/JetArray", "newGenericArray", "(ILjet/typeinfo/TypeInfo;)Ljet/arrays/JetGenericArray;"); + } } } @Override public StackValue visitArrayAccessExpression(JetArrayAccessExpression expression, StackValue receiver) { final JetExpression array = expression.getArrayExpression(); - final Type arrayType = expressionType(array); + JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, array); + final Type arrayType = type == null ? Type.VOID_TYPE : typeMapper.mapType(type); gen(array, arrayType); + derefArray(type); generateArrayIndex(expression); - if (arrayType.getSort() == Type.ARRAY) { - final Type elementType = CodegenUtil.arrayElementType(arrayType); - return StackValue.arrayElement(elementType); + if (state.getStandardLibrary().getArray().equals(type.getConstructor().getDeclarationDescriptor())) { + JetType elementType = type.getArguments().get(0).getType(); + return StackValue.arrayElement(typeMapper.mapType(elementType), typeMapper.isGenericsArray(type)); } else { final PsiElement declaration = BindingContextUtils.resolveToDeclarationPsiElement(bindingContext, expression); @@ -1733,6 +1764,46 @@ public class ExpressionCodegen extends JetVisitor { } } + public void derefArray(JetType type) { + if (state.getStandardLibrary().getArray().equals(type.getConstructor().getDeclarationDescriptor())) { + JetType elementType = type.getArguments().get(0).getType(); + JetStandardLibrary standardLibrary = state.getStandardLibrary(); + if (elementType.equals(standardLibrary.getIntType())) { + v.getfield("jet/arrays/JetIntArray", "array", "[I"); + } + else if (elementType.equals(standardLibrary.getLongType())) { + v.getfield("jet/arrays/JetLongArray", "array", "[J"); + } + else if (elementType.equals(standardLibrary.getShortType())) { + v.getfield("jet/arrays/JetShortArray", "array", "[S"); + } + else if (elementType.equals(standardLibrary.getByteType())) { + v.getfield("jet/arrays/JetByteArray", "array", "[B"); + } + else if (elementType.equals(standardLibrary.getCharType())) { + v.getfield("jet/arrays/JetCharArray", "array", "[C"); + } + else if (elementType.equals(standardLibrary.getFloatType())) { + v.getfield("jet/arrays/JetFloatArray", "array", "[F"); + } + else if (elementType.equals(standardLibrary.getDoubleType())) { + v.getfield("jet/arrays/JetDoubleArray", "array", "[D"); + } + else if (elementType.equals(standardLibrary.getBooleanType())) { + v.getfield("jet/arrays/JetBooleanArray", "array", "[Z"); + } + else { + if(typeMapper.isGenericsArray(type)) { + v.visitTypeInsn(Opcodes.CHECKCAST, "jet/arrays/JetArray"); + } + else { + v.getfield("jet/arrays/JetGenericArray", "array", "[Ljava/lang/Object;"); + v.visitTypeInsn(Opcodes.CHECKCAST, "[" + typeMapper.mapType(elementType).getDescriptor()); + } + } + } + } + private void generateArrayIndex(JetArrayAccessExpression expression) { final List indices = expression.getIndexExpressions(); for (JetExpression index : indices) { @@ -1989,9 +2060,9 @@ public class ExpressionCodegen extends JetVisitor { return; } - if(jetType.getArguments().size() == 0 && !(declarationDescriptor instanceof JavaClassDescriptor)) { + if(!CodegenUtil.hasTypeInfoField(jetType)) { // TODO: we need some better checks here - v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + v.getstatic(typeMapper.mapType(jetType, OwnerKind.IMPLEMENTATION).getInternalName(), "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;"); return; } @@ -2044,23 +2115,33 @@ public class ExpressionCodegen extends JetVisitor { return; } DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration(); - if (containingDeclaration == contextType() && contextType() instanceof ClassDescriptor) { + if (contextType() instanceof ClassDescriptor) { ClassDescriptor descriptor = (ClassDescriptor) contextType(); - JetType defaultType = descriptor.getDefaultType(); + JetType defaultType = ((ClassDescriptor)containingDeclaration).getDefaultType(); Type ownerType = typeMapper.mapType(defaultType); ownerType = JetTypeMapper.boxType(ownerType); - if(!CodegenUtil.isInterface(descriptor)) { - if (descriptor.getTypeConstructor().getParameters().size() > 0) { - v.load(0, JetTypeMapper.TYPE_OBJECT); - v.getfield(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + if (containingDeclaration == contextType()) { + if(!CodegenUtil.isInterface(descriptor)) { + if (CodegenUtil.hasTypeInfoField(defaultType)) { + v.load(0, JetTypeMapper.TYPE_OBJECT); + v.getfield(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + } + else { + v.getstatic(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + } } else { - v.getstatic(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); + v.load(0, JetTypeMapper.TYPE_OBJECT); + v.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); } } else { v.load(0, JetTypeMapper.TYPE_OBJECT); v.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); + while(descriptor != containingDeclaration) { + descriptor = CodegenUtil.getOuterClassDescriptor(descriptor); + v.invokevirtual("jet/typeinfo/TypeInfo", "getOuterTypeInfo", "()Ljet/typeinfo/TypeInfo;"); + } } v.aconst(ownerType); v.iconst(typeParameterDescriptor.getIndex()); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index b73520b3c54..bdf2d80bc06 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -8,7 +8,6 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.OverridingUtil; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; -import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lexer.JetTokens; @@ -99,6 +98,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ); v.visitSource(myClass.getContainingFile().getName(), null); + if(descriptor.getContainingDeclaration() instanceof ClassDescriptor) { + v.visitOuterClass(state.getTypeMapper().jvmType((ClassDescriptor) descriptor.getContainingDeclaration(), OwnerKind.IMPLEMENTATION).getInternalName(), null, null); + } + if(myClass instanceof JetClass) { AnnotationVisitor annotationVisitor = v.visitAnnotation("Ljet/typeinfo/JetSignature;", true); annotationVisitor.visit("value", SignatureUtil.classToSignature((JetClass)myClass, state.getBindingContext(), state.getTypeMapper())); @@ -205,7 +208,17 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { Method method; CallableMethod callableMethod; if (constructorDescriptor == null) { - method = new Method("", Type.VOID_TYPE, new Type[0]); + List parameterTypes = new ArrayList(); + if (CodegenUtil.hasThis0(descriptor)) { + parameterTypes.add(state.getTypeMapper().jvmType(CodegenUtil.getOuterClassDescriptor(descriptor), OwnerKind.IMPLEMENTATION)); + } + + List typeParameters = descriptor.getTypeConstructor().getParameters(); + for (int n = typeParameters.size(); n > 0; n--) { + parameterTypes.add(JetTypeMapper.TYPE_TYPEINFO); + } + + method = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); callableMethod = new CallableMethod("", method, Opcodes.INVOKESPECIAL, Collections.emptyList()); } else { @@ -220,13 +233,16 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { ? constructorDescriptor.getValueParameters() : Collections.emptyList(); - ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, kind); + ConstructorFrameMap frameMap = new ConstructorFrameMap(callableMethod, constructorDescriptor, descriptor, kind); final InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state); for(int slot = 0; slot != frameMap.getTypeParameterCount(); ++slot) { - codegen.addTypeParameter(constructorDescriptor.getTypeParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO)); + if(constructorDescriptor != null) + codegen.addTypeParameter(constructorDescriptor.getTypeParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO)); + else + codegen.addTypeParameter(descriptor.getTypeConstructor().getParameters().get(slot), StackValue.local(frameMap.getFirstTypeParameter() + slot, JetTypeMapper.TYPE_TYPEINFO)); } String classname = state.getTypeMapper().jvmName(descriptor, kind); @@ -241,7 +257,24 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { if (superCall == null || superCall instanceof JetDelegatorToSuperClass) { iv.load(0, Type.getType("L" + superClass + ";")); - iv.invokespecial(superClass, "", "()V"); + if(superCall == null) { + iv.invokespecial(superClass, "", "()V"); + } + else { + JetType superType = state.getBindingContext().get(BindingContext.TYPE, superCall.getTypeReference()); + List parameterTypes = new ArrayList(); + ClassDescriptor superClassDescriptor = (ClassDescriptor) superType.getConstructor().getDeclarationDescriptor(); + if (CodegenUtil.hasThis0(superClassDescriptor)) { + iv.load(1, JetTypeMapper.TYPE_OBJECT); + parameterTypes.add(state.getTypeMapper().jvmType(CodegenUtil.getOuterClassDescriptor(descriptor), OwnerKind.IMPLEMENTATION)); + } + for(TypeProjection typeParameterDescriptor : superType.getArguments()) { + codegen.generateTypeInfo(typeParameterDescriptor.getType()); + parameterTypes.add(JetTypeMapper.TYPE_TYPEINFO); + } + Method superCallMethod = new Method("", Type.VOID_TYPE, parameterTypes.toArray(new Type[parameterTypes.size()])); + iv.invokespecial(state.getTypeMapper().jvmName(superClassDescriptor, OwnerKind.IMPLEMENTATION), "", superCallMethod.getDescriptor()); + } } else { iv.load(0, classType); @@ -285,7 +318,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.putfield(classname, fieldName, interfaceDesc); } - if (frameMap.getFirstTypeParameter() > 0 && kind == OwnerKind.IMPLEMENTATION) { + if (CodegenUtil.hasTypeInfoField(descriptor.getDefaultType()) && kind == OwnerKind.IMPLEMENTATION) { generateTypeInfoInitializer(frameMap.getFirstTypeParameter(), frameMap.getTypeParameterCount(), iv); } @@ -473,7 +506,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { final MethodVisitor mv = v.visitMethod(flags, "", method.getSignature().getDescriptor(), null, null); mv.visitCode(); - ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, kind); + ConstructorFrameMap frameMap = new ConstructorFrameMap(method, constructorDescriptor, descriptor, kind); final InstructionAdapter iv = new InstructionAdapter(mv); ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state); @@ -507,17 +540,38 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { iv.aconst(state.getTypeMapper().jvmType(descriptor, OwnerKind.IMPLEMENTATION)); iv.iconst(0); - iv.iconst(typeParamCount); - iv.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION); - for (int i = 0; i < typeParamCount; i++) { - iv.dup(); - iv.iconst(i); - iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT); - iv.checkcast(JetTypeMapper.TYPE_TYPEINFOPROJECTION); - iv.astore(JetTypeMapper.TYPE_OBJECT); + if(CodegenUtil.hasOuterTypeInfo(descriptor)) { + iv.load(1, JetTypeMapper.TYPE_OBJECT); + iv.invokeinterface("jet/JetObject", "getTypeInfo", "()Ljet/typeinfo/TypeInfo;"); } - iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;"); + + if(typeParamCount != 0) { + iv.iconst(typeParamCount); + iv.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION); + + for (int i = 0; i < typeParamCount; i++) { + iv.dup(); + iv.iconst(i); + iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT); + iv.checkcast(JetTypeMapper.TYPE_TYPEINFOPROJECTION); + iv.astore(JetTypeMapper.TYPE_OBJECT); + } + + if(CodegenUtil.hasOuterTypeInfo(descriptor)) { + iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;ZLjet/typeinfo/TypeInfo;[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;"); + } + else + iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;"); + } + else { + if(CodegenUtil.hasOuterTypeInfo(descriptor)) { + iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;ZLjet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfo;"); + } + else + iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;"); + } + iv.invokevirtual(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$setTypeInfo", "(Ljet/typeinfo/TypeInfo;)V"); } @@ -617,8 +671,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return; JetType defaultType = descriptor.getDefaultType(); - if(isParametrizedClass(defaultType)) { - if(!hasDerivedTypeInfoField(defaultType, true)) { + if(CodegenUtil.hasTypeInfoField(defaultType)) { + if(!CodegenUtil.hasDerivedTypeInfoField(defaultType, true)) { v.visitField(Opcodes.ACC_PRIVATE, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null); @@ -642,51 +696,45 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { mv.visitMaxs(0, 0); mv.visitEnd(); } - else { - if(descriptor.getTypeConstructor().getParameters().isEmpty()) { - v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); - staticInitializerChunks.add(new CodeChunk() { - @Override - public void generate(InstructionAdapter v) { - JetTypeMapper typeMapper = state.getTypeMapper(); - ClassCodegen.newTypeInfo(v, false, typeMapper.jvmType(descriptor, OwnerKind.IMPLEMENTATION)); - v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); - } - }); - - final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null); - mv.visitCode(); - InstructionAdapter v = new InstructionAdapter(mv); - String owner = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION); - v.getstatic(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;"); - v.areturn(JetTypeMapper.TYPE_TYPEINFO); - mv.visitMaxs(0, 0); - mv.visitEnd(); - } - } } else { - v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "$typeInfo", "Ljet/typeinfo/TypeInfo;", null, null); - staticInitializerChunks.add(new CodeChunk() { - @Override - public void generate(InstructionAdapter v) { - JetTypeMapper typeMapper = state.getTypeMapper(); - ClassCodegen.newTypeInfo(v, false, typeMapper.jvmType(descriptor, OwnerKind.IMPLEMENTATION)); - v.putstatic(typeMapper.jvmName(descriptor, kind), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); - } - }); - - final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null); - mv.visitCode(); - InstructionAdapter v = new InstructionAdapter(mv); - String owner = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION); - v.getstatic(owner, "$typeInfo", "Ljet/typeinfo/TypeInfo;"); - v.areturn(JetTypeMapper.TYPE_TYPEINFO); - mv.visitMaxs(0, 0); - mv.visitEnd(); + genGetStaticGetTypeInfoMethod(); + staticTypeInfoField(); } } + private void genGetStaticGetTypeInfoMethod() { + final MethodVisitor mv = v.visitMethod(Opcodes.ACC_PUBLIC, "getTypeInfo", "()Ljet/typeinfo/TypeInfo;", null, null); + mv.visitCode(); + InstructionAdapter v = new InstructionAdapter(mv); + String owner = state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION); + v.getstatic(owner, "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;"); + v.areturn(JetTypeMapper.TYPE_TYPEINFO); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + + private void staticTypeInfoField() { + v.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;", null, null); + staticInitializerChunks.add(new CodeChunk() { + @Override + public void generate(InstructionAdapter v) { + JetTypeMapper typeMapper = state.getTypeMapper(); + v.aconst(typeMapper.jvmType(descriptor, OwnerKind.IMPLEMENTATION)); + v.iconst(0); + ClassDescriptor outerClassDescriptor = CodegenUtil.getOuterClassDescriptor(descriptor); + if(outerClassDescriptor == null) { + v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;"); + } + else { + v.getstatic(state.getTypeMapper().jvmName(outerClassDescriptor, OwnerKind.IMPLEMENTATION), "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;"); + v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;ZLjet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfo;"); + } + v.putstatic(typeMapper.jvmName(descriptor, kind), "$staticTypeInfo", "Ljet/typeinfo/TypeInfo;"); + } + }); + } + private void generateClassObject(JetClassObject declaration) { state.forClass().generate(context, declaration.getObjectDeclaration()); } @@ -737,30 +785,4 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { return sb.toString(); } - public static boolean isParametrizedClass(JetType type) { - if(type.getConstructor().getParameters().size() > 0) - return true; - - for (JetType jetType : type.getConstructor().getSupertypes()) { - if(isParametrizedClass(jetType)) - return true; - } - - return false; - } - - public static boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) { - if(!exceptOwn) { - if(!CodegenUtil.isInterface(type)) - if(isParametrizedClass(type)) - return true; - } - - for (JetType jetType : type.getConstructor().getSupertypes()) { - if(hasDerivedTypeInfoField(jetType, false)) - return true; - } - - return false; - } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 92f504660c3..20329f28752 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -40,12 +40,23 @@ public class JetTypeMapper { public static final Type JL_NUMBER_TYPE = Type.getObjectType("java/lang/Number"); public static final Type JL_STRING_BUILDER = Type.getObjectType("java/lang/StringBuilder"); + public static final Type ARRAY_INT_TYPE = Type.getObjectType("jet/arrays/JetIntArray"); + public static final Type ARRAY_LONG_TYPE = Type.getObjectType("jet/arrays/JetLongArray"); + public static final Type ARRAY_SHORT_TYPE = Type.getObjectType("jet/arrays/JetShortArray"); + public static final Type ARRAY_BYTE_TYPE = Type.getObjectType("jet/arrays/JetByteArray"); + public static final Type ARRAY_CHAR_TYPE = Type.getObjectType("jet/arrays/JetCharArray"); + public static final Type ARRAY_FLOAT_TYPE = Type.getObjectType("jet/arrays/JetFloatArray"); + public static final Type ARRAY_DOUBLE_TYPE = Type.getObjectType("jet/arrays/JetDoubleArray"); + public static final Type ARRAY_BOOL_TYPE = Type.getObjectType("jet/arrays/JetBoolArray"); + public static final Type ARRAY_GENERIC_TYPE = Type.getObjectType("jet/arrays/JetGenericArray"); + private final JetStandardLibrary standardLibrary; private final BindingContext bindingContext; private final Map classNamesForAnonymousClasses = new HashMap(); private final Map anonymousSubclassesCount = new HashMap(); private final HashMap knowTypes = new HashMap(); + private final HashMap knowArrayTypes = new HashMap(); public JetTypeMapper(JetStandardLibrary standardLibrary, BindingContext bindingContext) { this.standardLibrary = standardLibrary; @@ -377,9 +388,36 @@ public class JetTypeMapper { if (jetType.getArguments().size() != 1) { throw new UnsupportedOperationException("arrays must have one type argument"); } - TypeProjection memberType = jetType.getArguments().get(0); - Type elementType = mapType(memberType.getType()); - return Type.getType("[" + elementType.getDescriptor()); + JetType memberType = jetType.getArguments().get(0).getType(); + + if (memberType.equals(standardLibrary.getIntType())) { + return ARRAY_INT_TYPE; + } + if (memberType.equals(standardLibrary.getLongType())) { + return ARRAY_LONG_TYPE; + } + if (memberType.equals(standardLibrary.getShortType())) { + return ARRAY_SHORT_TYPE; + } + if (memberType.equals(standardLibrary.getByteType())) { + return ARRAY_BYTE_TYPE; + } + if (memberType.equals(standardLibrary.getCharType())) { + return ARRAY_CHAR_TYPE; + } + if (memberType.equals(standardLibrary.getFloatType())) { + return ARRAY_FLOAT_TYPE; + } + if (memberType.equals(standardLibrary.getDoubleType())) { + return ARRAY_DOUBLE_TYPE; + } + if (memberType.equals(standardLibrary.getBooleanType())) { + return ARRAY_BOOL_TYPE; + } + if(!isGenericsArray(jetType)) + return ARRAY_GENERIC_TYPE; + else + return TYPE_OBJECT; } if (JetStandardClasses.getAny().equals(descriptor)) { return Type.getType(Object.class); @@ -665,9 +703,21 @@ public class JetTypeMapper { knowTypes.put(standardLibrary.getNullableStringType(),"NULLABLE_STRING_TYPE_INFO"); knowTypes.put(standardLibrary.getTuple0Type(),"TUPLE0_TYPE_INFO"); knowTypes.put(standardLibrary.getNullableTuple0Type(),"NULLABLE_TUPLE0_TYPE_INFO"); + + knowArrayTypes.put(standardLibrary.getIntType(), "INT_ARRAY_TYPE_INFO"); + knowArrayTypes.put(standardLibrary.getLongType(), "LONG_ARRAY_TYPE_INFO"); + knowArrayTypes.put(standardLibrary.getShortType(),"SHORT_ARRAY_TYPE_INFO"); + knowArrayTypes.put(standardLibrary.getByteType(),"BYTE_ARRAY_TYPE_INFO"); + knowArrayTypes.put(standardLibrary.getCharType(),"CHAR_ARRAY_TYPE_INFO"); + knowArrayTypes.put(standardLibrary.getFloatType(),"FLOAT_ARRAY_TYPE_INFO"); + knowArrayTypes.put(standardLibrary.getDoubleType(),"DOUBLE_ARRAY_TYPE_INFO"); + knowArrayTypes.put(standardLibrary.getBooleanType(),"BOOLEAN_ARRAY_TYPE_INFO"); } public String isKnownTypeInfo(JetType jetType) { + if(standardLibrary.getArray().equals(jetType.getConstructor().getDeclarationDescriptor())) + return knowArrayTypes.get(jetType.getArguments().get(0).getType()); + return knowTypes.get(jetType); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java index 0bddcbbb7ec..2bcfbc5804d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/SignatureUtil.java @@ -1,19 +1,15 @@ package org.jetbrains.jet.codegen; -import jet.typeinfo.TypeInfoVariance; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.JetDelegationSpecifier; import org.jetbrains.jet.lang.psi.JetTypeParameter; import org.jetbrains.jet.lang.psi.JetTypeReference; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.TypeProjection; import org.jetbrains.jet.lang.types.Variance; -import org.objectweb.asm.Type; import java.util.List; @@ -44,7 +40,11 @@ public class SignatureUtil { sb.append(type.getDescriptor()); } else { - sb.append("T").append(descriptor.getName()).append(";"); + sb.append("T"); + sb.append(descriptor.getContainingDeclaration().getName()); + sb.append(";"); + sb.append(descriptor.getName()); + sb.append(";"); } if(!jetType.getArguments().isEmpty()) { sb.append("<"); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index 94b0504eeba..cf1c720923d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -13,7 +13,7 @@ import org.objectweb.asm.commons.Method; * @author yole */ public abstract class StackValue { - protected final Type type; + public final Type type; public StackValue(Type type) { this.type = type; @@ -75,8 +75,8 @@ public abstract class StackValue { return new Invert(stackValue); } - public static StackValue arrayElement(Type type) { - return new ArrayElement(type); + public static StackValue arrayElement(Type type, boolean genericsArray) { + return new ArrayElement(type, genericsArray); } public static StackValue collectionElement(Type type, CallableMethod getter, CallableMethod setter) { @@ -424,19 +424,32 @@ public abstract class StackValue { } private static class ArrayElement extends StackValue { - public ArrayElement(Type type) { + private boolean genericsArray; + + public ArrayElement(Type type, boolean genericsArray) { super(type); + this.genericsArray = genericsArray; } @Override public void put(Type type, InstructionAdapter v) { - v.aload(type); // assumes array and index are on the stack + if(genericsArray) { + v.invokevirtual("jet/arrays/JetArray", "get", "(I)Ljava/lang/Object;"); + } + else { + v.aload(this.type); // assumes array and index are on the stack + } coerce(type, v); } @Override public void store(InstructionAdapter v) { - v.astore(type); // assumes array and index are on the stack + if(genericsArray) { + v.invokevirtual("jet/arrays/JetArray", "set", "(ILjava/lang/Object;)V"); + } + else { + v.astore(type); // assumes array and index are on the stack + } } @Override diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java index 5752eff122a..68c92a29e72 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/ArraySize.java @@ -5,6 +5,7 @@ import org.jetbrains.jet.codegen.ExpressionCodegen; import org.jetbrains.jet.codegen.JetTypeMapper; import org.jetbrains.jet.codegen.StackValue; import org.jetbrains.jet.lang.psi.JetExpression; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.commons.InstructionAdapter; @@ -17,7 +18,33 @@ public class ArraySize implements IntrinsicMethod { @Override public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List arguments, StackValue receiver) { receiver.put(JetTypeMapper.TYPE_OBJECT, v); - v.arraylength(); + if(receiver.type.equals(JetTypeMapper.TYPE_OBJECT)) { + v.visitTypeInsn(Opcodes.CHECKCAST, "jet/arrays/JetArray"); + v.invokevirtual("jet/arrays/JetArray", "getSize", "()I"); + } + else { + if(receiver.type.equals(JetTypeMapper.ARRAY_BYTE_TYPE)) + v.getfield(receiver.type.getInternalName(), "array", "[B"); + else if(receiver.type.equals(JetTypeMapper.ARRAY_SHORT_TYPE)) + v.getfield(receiver.type.getInternalName(), "array", "[S"); + else if(receiver.type.equals(JetTypeMapper.ARRAY_INT_TYPE)) + v.getfield(receiver.type.getInternalName(), "array", "[I"); + else if(receiver.type.equals(JetTypeMapper.ARRAY_LONG_TYPE)) + v.getfield(receiver.type.getInternalName(), "array", "[J"); + else if(receiver.type.equals(JetTypeMapper.ARRAY_FLOAT_TYPE)) + v.getfield(receiver.type.getInternalName(), "array", "[F"); + else if(receiver.type.equals(JetTypeMapper.ARRAY_DOUBLE_TYPE)) + v.getfield(receiver.type.getInternalName(), "array", "[D"); + else if(receiver.type.equals(JetTypeMapper.ARRAY_CHAR_TYPE)) + v.getfield(receiver.type.getInternalName(), "array", "[C"); + else if(receiver.type.equals(JetTypeMapper.ARRAY_BOOL_TYPE)) + v.getfield(receiver.type.getInternalName(), "array", "[Z"); + else + v.getfield("jet/arrays/JetGenericArray", "array", "[Ljava/lang/Object;"); + + v.arraylength(); + } + return StackValue.onStack(Type.INT_TYPE); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java index 85a0476036e..180a350530e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardLibrary.java @@ -63,22 +63,23 @@ public class JetStandardLibrary { private final ClassDescriptor typeInfoClass; private final JetType byteType; - private final JetType nullableByteType; private final JetType charType; - private final JetType nullableCharType; private final JetType shortType; - private final JetType nullableShortType; private final JetType intType; - private final JetType nullableIntType; private final JetType longType; - private final JetType nullableLongType; private final JetType floatType; - private final JetType nullableFloatType; private final JetType doubleType; - private final JetType nullableDoubleType; private final JetType booleanType; - private final JetType nullableBooleanType; private final JetType stringType; + + private final JetType nullableByteType; + private final JetType nullableCharType; + private final JetType nullableShortType; + private final JetType nullableIntType; + private final JetType nullableLongType; + private final JetType nullableFloatType; + private final JetType nullableDoubleType; + private final JetType nullableBooleanType; private final JetType nullableTuple0Type; public JetType getTuple0Type() { diff --git a/idea/testData/codegen/controlStructures/forIntArray.jet b/idea/testData/codegen/controlStructures/forIntArray.jet new file mode 100644 index 00000000000..8bc6d71f3e9 --- /dev/null +++ b/idea/testData/codegen/controlStructures/forIntArray.jet @@ -0,0 +1,14 @@ +fun box() : String { + val a : Array = Array (5) + var i = 0 + var sum = 0 + for(el in 0..4) { + a[i] = i++ + } + for (el in a) { + sum = sum + el + } + if(sum != 10) return "a failed" + + return "OK" +} \ No newline at end of file diff --git a/idea/testData/codegen/controlStructures/forNullableIntArray.jet b/idea/testData/codegen/controlStructures/forNullableIntArray.jet new file mode 100644 index 00000000000..5877bfc97fc --- /dev/null +++ b/idea/testData/codegen/controlStructures/forNullableIntArray.jet @@ -0,0 +1,16 @@ +fun box() : String { + val b : Array = Array (5) + var i = 0 + var sum = 0 + while(i < 5) { + b[i] = i++ + } + sum = 0 + for (el in b) { + sum = sum + (el ?: 0) + } + System.out?.println(sum) + if(sum != 10) return "b failed" + + return "OK" +} \ No newline at end of file diff --git a/idea/testData/codegen/regressions/kt326.jet b/idea/testData/codegen/regressions/kt326.jet index cfd171f11e0..1c5d3b19fdf 100644 --- a/idea/testData/codegen/regressions/kt326.jet +++ b/idea/testData/codegen/regressions/kt326.jet @@ -1,22 +1,46 @@ namespace test -class List() { - val a : Array = Array(1) +class List(len: Int) { + val a : Array = Array(len) + + fun reverse() { + var i = 0 + var j = a.size-1 + while(i < j) { + val x = a[i] + a[i++] = a[j] + a[j--] = x + } + } } fun box() : String { - val a = List() + val d = List(1) + d.a[0] = 10 + println(d.a[0]) + + val a = List(1) a.a[0] = "1" println(a.a[0]) - val b = List() + val b = List(1) b.a[0] = 10 println(b.a[0]) - val c = List>() + val c = List>(1) c.a[0] = Array(4) println(c.a[0].size) + val e = List(5) + e.a[0] = 0 + e.a[1] = 1 + e.a[2] = 2 + e.a[3] = 3 + e.a[4] = 4 + e.reverse() + for(el in e.a) + println(el) + return "OK" } diff --git a/idea/testData/codegen/traits/stdlib.jet b/idea/testData/codegen/traits/stdlib.jet index 65b84bbe2e8..aa9fe5d5072 100644 --- a/idea/testData/codegen/traits/stdlib.jet +++ b/idea/testData/codegen/traits/stdlib.jet @@ -8,18 +8,22 @@ trait javaUtilIterator : java.util.Iterator { } } +class MyIterator(val array : ReadOnlyArray) : javaUtilIterator { + private var index = 0 + + override fun hasNext() : Boolean = index < array.size + + override fun next() : T = array.get(index++) +} + trait ReadOnlyArray : ISized, java.lang.Iterable { fun get(index : Int) : T - class MyIterator() : javaUtilIterator { - private var index = 0 - - override fun hasNext() : Boolean = index < size - - override fun next() : T = get(index++) + class Default { + fun check(v: Any) = v is T } - override fun iterator() : java.util.Iterator = MyIterator() + override fun iterator() : java.util.Iterator = MyIterator(this) } trait WriteOnlyArray : ISized { @@ -53,4 +57,4 @@ fun box() : String { System.out?.println(el) } return "OK" -} \ No newline at end of file +} diff --git a/idea/testData/codegen/typeInfo/inner.jet b/idea/testData/codegen/typeInfo/inner.jet new file mode 100644 index 00000000000..49db9252b35 --- /dev/null +++ b/idea/testData/codegen/typeInfo/inner.jet @@ -0,0 +1,15 @@ +class Box() { + open class Inner () { + fun isT(s : Any) = if(s is T) "OK" else "fail" + } + + class Inner2() : Inner() { + + } + + fun inner() = Inner2() +} + +fun box(): String { + return Box.inner().isT("OK") +} diff --git a/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java index 372ba4214d1..ff481bcc933 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ArrayGenTest.java @@ -1,5 +1,9 @@ package org.jetbrains.jet.codegen; +import jet.arrays.JetGenericArray; +import jet.arrays.JetIntArray; +import jet.typeinfo.TypeInfo; + import java.lang.reflect.Method; public class ArrayGenTest extends CodegenTestCase { @@ -9,6 +13,7 @@ public class ArrayGenTest extends CodegenTestCase { public void testKt326 () throws Exception { blackBoxFile("regressions/kt326.jet"); + System.out.println(generateToText()); } public void testCreateMultiInt () throws Exception { @@ -16,7 +21,8 @@ public class ArrayGenTest extends CodegenTestCase { Method foo = generateFunction(); Object invoke = foo.invoke(null); System.out.println(invoke.getClass()); - assertTrue(invoke instanceof int[][]); + assertTrue(invoke instanceof JetGenericArray); + assertTrue(((JetGenericArray)invoke).getTypeInfo() == TypeInfo.INT_ARRAY_TYPE_INFO); } public void testCreateMultiString () throws Exception { @@ -24,18 +30,16 @@ public class ArrayGenTest extends CodegenTestCase { Method foo = generateFunction(); Object invoke = foo.invoke(null); System.out.println(invoke.getClass()); - assertTrue(invoke instanceof String[][]); + assertTrue(invoke instanceof JetGenericArray); } public void testCreateMultiGenerics () throws Exception { - /* loadText("class L() { val a = Array(5) } fun foo() = L.a"); System.out.println(generateToText()); Method foo = generateFunction(); Object invoke = foo.invoke(null); System.out.println(invoke.getClass()); - assertTrue(invoke instanceof Integer[]); - */ + assertTrue(invoke instanceof JetIntArray); } public void testIntGenerics () throws Exception { diff --git a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java index 2e93fc8b561..03e5e5adbd3 100644 --- a/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/ControlStructuresTest.java @@ -1,5 +1,8 @@ package org.jetbrains.jet.codegen; +import jet.arrays.JetGenericArray; +import jet.typeinfo.TypeInfo; + import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; @@ -89,7 +92,7 @@ public class ControlStructuresTest extends CodegenTestCase { System.out.println(generateToText()); final Method main = generateFunction(); String[] args = new String[] { "IntelliJ", " ", "IDEA" }; - assertEquals("IntelliJ IDEA", main.invoke(null, new Object[] { args })); + assertEquals("IntelliJ IDEA", main.invoke(null, new Object[] { new JetGenericArray(args, TypeInfo.STRING_TYPE_INFO) })); } public void testForInRange() throws Exception { @@ -145,6 +148,14 @@ public class ControlStructuresTest extends CodegenTestCase { blackBoxFile("controlStructures/forUserType.jet"); } + public void testForIntArray() throws Exception { + blackBoxFile("controlStructures/forIntArray.jet"); + } + + public void testForNullableIntArray() throws Exception { + blackBoxFile("controlStructures/forNullableIntArray.jet"); + } + public void testKt237() throws Exception { blackBoxFile("regressions/kt237.jet"); } diff --git a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java index 437b57a6096..0f3432f1d09 100644 --- a/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/NamespaceGenTest.java @@ -2,6 +2,9 @@ package org.jetbrains.jet.codegen; import jet.IntRange; import jet.Tuple2; +import jet.arrays.JetGenericArray; +import jet.arrays.JetIntArray; +import jet.typeinfo.TypeInfo; import org.jetbrains.jet.parsing.JetParsingTest; import java.awt.*; @@ -19,7 +22,7 @@ public class NamespaceGenTest extends CodegenTestCase { System.out.println(text); final Method main = generateFunction(); - Object[] args = new Object[] { new String[0] }; + Object[] args = new Object[] { new JetGenericArray(0, TypeInfo.STRING_TYPE_INFO) }; main.invoke(null, args); } @@ -343,14 +346,14 @@ public class NamespaceGenTest extends CodegenTestCase { public void testArrayRead() throws Exception { loadText("fun foo(c: Array) = c[0]"); final Method main = generateFunction(); - assertEquals("main", main.invoke(null, new Object[] { new String[] { "main" } })); + assertEquals("main", main.invoke(null, new Object[] { new JetGenericArray(new String[] { "main" }, TypeInfo.STRING_TYPE_INFO) })); } public void testArrayWrite() throws Exception { loadText("fun foo(c: Array) { c[0] = \"jet\"; }"); final Method main = generateFunction(); String[] array = new String[] { null }; - main.invoke(null, new Object[] { array }); + main.invoke(null, new Object[] { new JetGenericArray(array, TypeInfo.STRING_TYPE_INFO) }); assertEquals("jet", array[0]); } @@ -359,22 +362,23 @@ public class NamespaceGenTest extends CodegenTestCase { System.out.println(generateToText()); final Method main = generateFunction(); int[] data = new int[] { 5 }; - main.invoke(null, new Object[] { data }); + main.invoke(null, new Object[] { new JetIntArray(data) }); assertEquals(10, data[0]); } public void testArrayNew() throws Exception { loadText("fun foo() = Array(4)"); + System.out.println(generateToText()); final Method main = generateFunction(); - int[] result = (int[]) main.invoke(null); - assertEquals(4, result.length); + JetIntArray result = (JetIntArray) main.invoke(null); + assertEquals(4, result.array.length); } public void testArraySize() throws Exception { loadText("fun foo(a: Array) = a.size"); System.out.println(generateToText()); final Method main = generateFunction(); - Object[] args = new Object[] { new int[4] }; + Object[] args = new Object[] { new JetIntArray(new int[4]) }; int result = (Integer) main.invoke(null, args); assertEquals(4, result); @@ -495,6 +499,7 @@ public class NamespaceGenTest extends CodegenTestCase { final Method main = generateFunction(); final String[] args = new String[] { "foo", "bar" }; //noinspection ImplicitArrayToString - assertEquals("s" + args.toString(), main.invoke(null, "s", args)); + JetGenericArray jetGenericArray = new JetGenericArray(args, TypeInfo.STRING_TYPE_INFO); + assertEquals("s" + jetGenericArray.toString(), main.invoke(null, "s", jetGenericArray)); } } diff --git a/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java b/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java index 07acb80f120..b805c7d2147 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TraitsTest.java @@ -18,11 +18,9 @@ public class TraitsTest extends CodegenTestCase { public void testMultiple () throws Exception { blackBoxFile("traits/multiple.jet"); - System.out.println(generateToText()); } public void testStdlib () throws Exception { blackBoxFile("traits/stdlib.jet"); - System.out.println(generateToText()); } } diff --git a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java index 687d42cb60d..f356e8da69f 100644 --- a/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/TypeInfoTest.java @@ -135,5 +135,9 @@ public class TypeInfoTest extends CodegenTestCase { System.out.println(generateToText()); } + public void testInner() throws Exception { + blackBoxFile("typeinfo/inner.jet"); + System.out.println(generateToText()); + } } diff --git a/stdlib/src/jet/arrays/JetArray.java b/stdlib/src/jet/arrays/JetArray.java new file mode 100644 index 00000000000..1a9eccdefac --- /dev/null +++ b/stdlib/src/jet/arrays/JetArray.java @@ -0,0 +1,67 @@ +package jet.arrays; + +import jet.JetObject; +import jet.typeinfo.TypeInfo; + +public abstract class JetArray implements JetObject { + public abstract T get(int index); + public abstract void set(int index, T value); + public abstract int getSize(); + + public static JetArray newArray(int length, TypeInfo elementTypeInfo) { + if(elementTypeInfo.equals(TypeInfo.BYTE_TYPE_INFO)) + return new JetByteArray(length); + if(elementTypeInfo.equals(TypeInfo.SHORT_TYPE_INFO)) + return new JetShortArray(length); + if(elementTypeInfo.equals(TypeInfo.INT_TYPE_INFO)) + return new JetIntArray(length); + if(elementTypeInfo.equals(TypeInfo.LONG_TYPE_INFO)) + return new JetShortArray(length); + if(elementTypeInfo.equals(TypeInfo.CHAR_TYPE_INFO)) + return new JetCharArray(length); + if(elementTypeInfo.equals(TypeInfo.BOOL_TYPE_INFO)) + return new JetBoolArray(length); + if(elementTypeInfo.equals(TypeInfo.FLOAT_TYPE_INFO)) + return new JetFloatArray(length); + if(elementTypeInfo.equals(TypeInfo.DOUBLE_TYPE_INFO)) + return new JetDoubleArray(length); + + return new JetGenericArray(length, elementTypeInfo); + } + + public static JetByteArray newByteArray(int length) { + return new JetByteArray(length); + } + + public static JetShortArray newShortArray(int length) { + return new JetShortArray(length); + } + + public static JetIntArray newIntArray(int length) { + return new JetIntArray(length); + } + + public static JetLongArray newLongArray(int length) { + return new JetLongArray(length); + } + + public static JetCharArray newCharArray(int length) { + return new JetCharArray(length); + } + + public static JetBoolArray newBoolArray(int length) { + return new JetBoolArray(length); + } + + public static JetFloatArray newFloatArray(int length) { + return new JetFloatArray(length); + } + + public static JetDoubleArray newDoubleArray(int length) { + return new JetDoubleArray(length); + } + + public static JetGenericArray newGenericArray(int length, TypeInfo typeInfo) { + return new JetGenericArray(length, typeInfo); + } +} diff --git a/stdlib/src/jet/arrays/JetBoolArray.java b/stdlib/src/jet/arrays/JetBoolArray.java new file mode 100644 index 00000000000..db17f72d7e6 --- /dev/null +++ b/stdlib/src/jet/arrays/JetBoolArray.java @@ -0,0 +1,35 @@ +package jet.arrays; + +import jet.typeinfo.TypeInfo; + +public final class JetBoolArray extends JetArray { + public final boolean[] array; + + public JetBoolArray(boolean[] array) { + this.array = array; + } + + public JetBoolArray(int length) { + this.array = new boolean[length]; + } + + @Override + public Boolean get(int index) { + return array[index]; + } + + @Override + public void set(int index, Boolean value) { + array[index] = value; + } + + @Override + public int getSize() { + return array.length; + } + + @Override + public TypeInfo getTypeInfo() { + return null; + } +} diff --git a/stdlib/src/jet/arrays/JetByteArray.java b/stdlib/src/jet/arrays/JetByteArray.java new file mode 100644 index 00000000000..e369e2ffdc2 --- /dev/null +++ b/stdlib/src/jet/arrays/JetByteArray.java @@ -0,0 +1,35 @@ +package jet.arrays; + +import jet.typeinfo.TypeInfo; + +public final class JetByteArray extends JetArray { + public final byte[] array; + + public JetByteArray(byte[] array) { + this.array = array; + } + + public JetByteArray(int length) { + this.array = new byte[length]; + } + + @Override + public Byte get(int index) { + return array[index]; + } + + @Override + public void set(int index, Byte value) { + array[index] = value; + } + + @Override + public int getSize() { + return array.length; + } + + @Override + public TypeInfo getTypeInfo() { + return null; + } +} diff --git a/stdlib/src/jet/arrays/JetCharArray.java b/stdlib/src/jet/arrays/JetCharArray.java new file mode 100644 index 00000000000..e17839ba151 --- /dev/null +++ b/stdlib/src/jet/arrays/JetCharArray.java @@ -0,0 +1,35 @@ +package jet.arrays; + +import jet.typeinfo.TypeInfo; + +public final class JetCharArray extends JetArray { + public final char[] array; + + public JetCharArray(char[] array) { + this.array = array; + } + + public JetCharArray(int length) { + this.array = new char[length]; + } + + @Override + public Character get(int index) { + return array[index]; + } + + @Override + public void set(int index, Character value) { + array[index] = value; + } + + @Override + public int getSize() { + return array.length; + } + + @Override + public TypeInfo getTypeInfo() { + return null; + } +} diff --git a/stdlib/src/jet/arrays/JetDoubleArray.java b/stdlib/src/jet/arrays/JetDoubleArray.java new file mode 100644 index 00000000000..bdf4acf9dff --- /dev/null +++ b/stdlib/src/jet/arrays/JetDoubleArray.java @@ -0,0 +1,35 @@ +package jet.arrays; + +import jet.typeinfo.TypeInfo; + +public final class JetDoubleArray extends JetArray { + public final double[] array; + + public JetDoubleArray(double[] array) { + this.array = array; + } + + public JetDoubleArray(int length) { + this.array = new double[length]; + } + + @Override + public Double get(int index) { + return array[index]; + } + + @Override + public void set(int index, Double value) { + array[index] = value; + } + + @Override + public int getSize() { + return array.length; + } + + @Override + public TypeInfo getTypeInfo() { + return null; + } +} diff --git a/stdlib/src/jet/arrays/JetFloatArray.java b/stdlib/src/jet/arrays/JetFloatArray.java new file mode 100644 index 00000000000..5e292c6f01f --- /dev/null +++ b/stdlib/src/jet/arrays/JetFloatArray.java @@ -0,0 +1,35 @@ +package jet.arrays; + +import jet.typeinfo.TypeInfo; + +public final class JetFloatArray extends JetArray { + public final float[] array; + + public JetFloatArray(float[] array) { + this.array = array; + } + + public JetFloatArray(int length) { + this.array = new float[length]; + } + + @Override + public Float get(int index) { + return array[index]; + } + + @Override + public void set(int index, Float value) { + array[index] = value; + } + + @Override + public int getSize() { + return array.length; + } + + @Override + public TypeInfo getTypeInfo() { + return null; + } +} diff --git a/stdlib/src/jet/arrays/JetGenericArray.java b/stdlib/src/jet/arrays/JetGenericArray.java new file mode 100644 index 00000000000..6bdfc924135 --- /dev/null +++ b/stdlib/src/jet/arrays/JetGenericArray.java @@ -0,0 +1,38 @@ +package jet.arrays; + +import jet.typeinfo.TypeInfo; + +public final class JetGenericArray extends JetArray { + public final T[] array; + private final TypeInfo typeInfo; + + public JetGenericArray(T[] array, TypeInfo typeInfo) { + this.array = array; + this.typeInfo = typeInfo; + } + + public JetGenericArray(int length, TypeInfo typeInfo) { + this.array = (T[]) TypeInfo.newArray(length, typeInfo); + this.typeInfo = typeInfo; + } + + @Override + public T get(int index) { + return array[index]; + } + + @Override + public void set(int index, T value) { + array[index] = value; + } + + @Override + public int getSize() { + return array.length; + } + + @Override + public TypeInfo getTypeInfo() { + return typeInfo; + } +} diff --git a/stdlib/src/jet/arrays/JetIntArray.java b/stdlib/src/jet/arrays/JetIntArray.java new file mode 100644 index 00000000000..74f93f9676e --- /dev/null +++ b/stdlib/src/jet/arrays/JetIntArray.java @@ -0,0 +1,35 @@ +package jet.arrays; + +import jet.typeinfo.TypeInfo; + +public final class JetIntArray extends JetArray { + public final int[] array; + + public JetIntArray(int[] array) { + this.array = array; + } + + public JetIntArray(int length) { + this.array = new int[length]; + } + + @Override + public Integer get(int index) { + return array[index]; + } + + @Override + public void set(int index, Integer value) { + array[index] = value; + } + + @Override + public int getSize() { + return array.length; + } + + @Override + public TypeInfo getTypeInfo() { + return null; + } +} diff --git a/stdlib/src/jet/arrays/JetLongArray.java b/stdlib/src/jet/arrays/JetLongArray.java new file mode 100644 index 00000000000..a14c8a1e520 --- /dev/null +++ b/stdlib/src/jet/arrays/JetLongArray.java @@ -0,0 +1,35 @@ +package jet.arrays; + +import jet.typeinfo.TypeInfo; + +public final class JetLongArray extends JetArray { + public final long[] array; + + public JetLongArray(long[] array) { + this.array = array; + } + + public JetLongArray(int length) { + this.array = new long[length]; + } + + @Override + public Long get(int index) { + return array[index]; + } + + @Override + public void set(int index, Long value) { + array[index] = value; + } + + @Override + public int getSize() { + return array.length; + } + + @Override + public TypeInfo getTypeInfo() { + return null; + } +} diff --git a/stdlib/src/jet/arrays/JetShortArray.java b/stdlib/src/jet/arrays/JetShortArray.java new file mode 100644 index 00000000000..0bd70544698 --- /dev/null +++ b/stdlib/src/jet/arrays/JetShortArray.java @@ -0,0 +1,35 @@ +package jet.arrays; + +import jet.typeinfo.TypeInfo; + +public final class JetShortArray extends JetArray { + public final short[] array; + + public JetShortArray(short[] array) { + this.array = array; + } + + public JetShortArray(int length) { + this.array = new short[length]; + } + + @Override + public Short get(int index) { + return array[index]; + } + + @Override + public void set(int index, Short value) { + array[index] = value; + } + + @Override + public int getSize() { + return array.length; + } + + @Override + public TypeInfo getTypeInfo() { + return null; + } +} diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index 4a49915511f..b948345ed1a 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -2,6 +2,7 @@ package jet.typeinfo; import jet.JetObject; import jet.Tuple0; +import jet.arrays.*; import java.lang.reflect.Array; import java.lang.reflect.Field; @@ -25,6 +26,16 @@ public abstract class TypeInfo implements JetObject { public static final TypeInfo BOOL_TYPE_INFO = getTypeInfo(Boolean.class, false); public static final TypeInfo FLOAT_TYPE_INFO = getTypeInfo(Float.class, false); public static final TypeInfo DOUBLE_TYPE_INFO = getTypeInfo(Double.class, false); + + public static final TypeInfo BYTE_ARRAY_TYPE_INFO = getTypeInfo(byte[].class, false); + public static final TypeInfo SHORT_ARRAY_TYPE_INFO = getTypeInfo(short[].class, false); + public static final TypeInfo INT_ARRAY_TYPE_INFO = getTypeInfo(int[].class, false); + public static final TypeInfo LONG_ARRAY_TYPE_INFO = getTypeInfo(long[].class, false); + public static final TypeInfo CHAR_ARRAY_TYPE_INFO = getTypeInfo(char[].class, false); + public static final TypeInfo BOOL_ARRAY_TYPE_INFO = getTypeInfo(boolean[].class, false); + public static final TypeInfo FLOAT_ARRAY_TYPE_INFO = getTypeInfo(float[].class, false); + public static final TypeInfo DOUBLE_ARRAY_TYPE_INFO = getTypeInfo(double[].class, false); + public static final TypeInfo STRING_TYPE_INFO = getTypeInfo(String.class, false); public static final TypeInfo TUPLE0_TYPE_INFO = getTypeInfo(Tuple0.class, false); @@ -40,7 +51,31 @@ public abstract class TypeInfo implements JetObject { public static final TypeInfo NULLABLE_TUPLE0_TYPE_INFO = getTypeInfo(Tuple0.class, true); public static Object [] newArray(int length, TypeInfo typeInfo) { - return (Object[]) Array.newInstance(((TypeInfoImpl) typeInfo).signature.klazz, length); + Signature signature = ((TypeInfoImpl) typeInfo).signature; + if(signature.klazz.isArray() && signature.klazz.getComponentType().isPrimitive()) { + Class componentType = signature.klazz.getComponentType(); + if(componentType == byte.class) + return (Object[]) Array.newInstance(JetByteArray.class, length); + if(componentType == short.class) + return (Object[]) Array.newInstance(JetShortArray.class, length); + if(componentType == int.class) + return (Object[]) Array.newInstance(JetIntArray.class, length); + if(componentType == long.class) + return (Object[]) Array.newInstance(JetLongArray.class, length); + if(componentType == char.class) + return (Object[]) Array.newInstance(JetCharArray.class, length); + if(componentType == boolean.class) + return (Object[]) Array.newInstance(JetBoolArray.class, length); + if(componentType == float.class) + return (Object[]) Array.newInstance(JetFloatArray.class, length); + if(componentType == double.class) + return (Object[]) Array.newInstance(JetDoubleArray.class, length); + + throw new IllegalStateException(); + } + else { + return (Object[]) Array.newInstance(signature.klazz, length); + } } public static TypeInfoProjection invariantProjection(final TypeInfo typeInfo) { @@ -71,6 +106,14 @@ public abstract class TypeInfo implements JetObject { return new TypeInfoImpl(klazz, nullable); } + public static TypeInfo getTypeInfo(Class klazz, boolean nullable, TypeInfo outerTypeInfo) { + return new TypeInfoImpl(klazz, nullable, outerTypeInfo); + } + + public static TypeInfo getTypeInfo(Class klazz, boolean nullable, TypeInfo outerTypeInfo, TypeInfoProjection[] projections) { + return new TypeInfoImpl(klazz, nullable, outerTypeInfo, projections); + } + public static TypeInfo getTypeInfo(Class klazz, boolean nullable, TypeInfoProjection[] projections) { return new TypeInfoImpl(klazz, nullable, projections); } @@ -81,22 +124,29 @@ public abstract class TypeInfo implements JetObject { public abstract int getProjectionCount(); + public abstract TypeInfo getOuterTypeInfo(); + public abstract TypeInfoProjection getProjection(int index); public abstract TypeInfo getArgumentType(Class klass, int index); - public abstract TypeInfo substitute(List myVars); + protected abstract TypeInfo substitute(List myVars); + + protected abstract TypeInfo substitute(TypeInfo outer, TypeInfoProjection[] projections); private static class TypeInfoVar extends TypeInfo { final int varIndex; + final Signature signature; final boolean nullable; - private TypeInfoVar(Integer varIndex) { + private TypeInfoVar(Signature signature, Integer varIndex) { + this.signature = signature; this.varIndex = varIndex; nullable = false; } - public TypeInfoVar(boolean nullable, int varIndex) { + public TypeInfoVar(Signature signature, boolean nullable, int varIndex) { + this.signature = signature; this.nullable = nullable; this.varIndex = varIndex; } @@ -116,6 +166,11 @@ public abstract class TypeInfo implements JetObject { return 0; } + @Override + public TypeInfo getOuterTypeInfo() { + return null; + } + @Override public TypeInfoProjection getProjection(int index) { throw new UnsupportedOperationException("Abstract TypeInfo"); @@ -132,7 +187,7 @@ public abstract class TypeInfo implements JetObject { } @Override - protected TypeInfo substitute(TypeInfoProjection[] projections) { + protected TypeInfo substitute(TypeInfo outer, TypeInfoProjection[] projections) { return projections[varIndex].getType(); } @@ -143,7 +198,7 @@ public abstract class TypeInfo implements JetObject { @Override public String toString() { - return "T:" + varIndex; + return "T:" + signature.klazz.getName() + ":" + varIndex; } } @@ -152,12 +207,22 @@ public abstract class TypeInfo implements JetObject { private final Signature signature; private final boolean nullable; private final TypeInfoProjection[] projections; + private final TypeInfo outerTypeInfo; - TypeInfoImpl(Class theClass, boolean nullable) { - this(theClass, nullable, EMPTY); + private TypeInfoImpl(Class theClass, boolean nullable) { + this(theClass, nullable, null, EMPTY); + } + + private TypeInfoImpl(Class theClass, boolean nullable, TypeInfo outerTypeInfo) { + this(theClass, nullable, outerTypeInfo, EMPTY); } private TypeInfoImpl(Class theClass, boolean nullable, TypeInfoProjection[] projections) { + this(theClass, nullable, null, projections); + } + + private TypeInfoImpl(Class theClass, boolean nullable, TypeInfo outerTypeInfo, TypeInfoProjection[] projections) { + this.outerTypeInfo = outerTypeInfo; this.signature = Parser.parse(theClass); this.nullable = nullable; this.projections = projections; @@ -187,14 +252,14 @@ public abstract class TypeInfo implements JetObject { if(klass == this.signature.klazz) return projections[index].getType(); else { - return getSuperTypeInfo(klass).substitute(projections).getArgumentType(klass, index); + return getSuperTypeInfo(klass).substitute(outerTypeInfo, projections).getArgumentType(klass, index); } } @Override public TypeInfo substitute(final List myVars) { if(projections.length == 0) - return new TypeInfoImpl(signature.klazz, nullable, EMPTY); + return new TypeInfoImpl(this.signature.klazz, nullable, EMPTY); else { TypeInfoProjection [] proj = new TypeInfoProjection[projections.length]; for(int i = 0; i != proj.length; ++i) { @@ -218,19 +283,19 @@ public abstract class TypeInfo implements JetObject { } }; } - return new TypeInfoImpl(signature.klazz, nullable, proj); + return new TypeInfoImpl(this.signature.klazz, nullable, proj); } } @Override - protected TypeInfo substitute(TypeInfoProjection[] prj) { + protected TypeInfo substitute(TypeInfo outer, TypeInfoProjection[] prj) { if(projections.length == 0) return new TypeInfoImpl(signature.klazz, nullable, EMPTY); else { TypeInfoProjection [] proj = new TypeInfoProjection[projections.length]; for(int i = 0; i != proj.length; ++i) { final int finalI = i; - final TypeInfo substitute = projections[finalI].getType().substitute(prj); + final TypeInfo substitute = projections[finalI].getType().substitute(outer, prj); proj[i] = new TypeInfoProjection(){ @Override @@ -299,6 +364,11 @@ public abstract class TypeInfo implements JetObject { return projections.length; } + @Override + public TypeInfo getOuterTypeInfo() { + return outerTypeInfo; + } + @Override public final String toString() { StringBuilder sb = new StringBuilder().append(signature.klazz.getName()); @@ -344,25 +414,27 @@ public abstract class TypeInfo implements JetObject { } - protected abstract TypeInfo substitute(TypeInfoProjection[] projections); - public static class Signature { + final Signature outer; final Class klazz; - final List variables; - final List superTypes; + + List variables; + Map varNames; + List superTypes; final HashMap superSignatures = new HashMap(); - public Signature(Class klazz, List variables, List superTypes) { + public Signature(Signature outer, Class klazz) { + this.outer = outer; this.klazz = klazz; - this.superTypes = superTypes; - this.variables = variables; - + } + + protected void afterParse() { List myVars = variables == null ? Collections.emptyList() : new LinkedList(); if(variables != null) for(int i = 0; i != variables.size(); ++i) - myVars.add(new TypeInfoVar(false, i)); - + myVars.add(new TypeInfoVar(this, false, i)); + for(TypeInfo superType : superTypes) { if(superType instanceof TypeInfoImpl) { TypeInfoImpl type = (TypeInfoImpl) superType; @@ -379,7 +451,7 @@ public abstract class TypeInfo implements JetObject { vars.add(substitute); } } - + for(Map.Entry entry : superSignature.superSignatures.entrySet()) { superSignatures.put(entry.getKey(), entry.getValue().substitute(vars)); } @@ -395,8 +467,6 @@ public abstract class TypeInfo implements JetObject { int cur; final char [] string; - Map variables; - final ClassLoader classLoader; Parser(String string, ClassLoader classLoader) { @@ -405,6 +475,9 @@ public abstract class TypeInfo implements JetObject { } public static Signature parse(Class klass) { + if(klass == null) + return null; + lock.readLock().lock(); Signature sig = map.get(klass); lock.readLock().unlock(); @@ -414,7 +487,6 @@ public abstract class TypeInfo implements JetObject { sig = map.get(klass); if (sig == null) { sig = internalParse(klass); - map.put(klass, sig); } lock.writeLock().unlock(); @@ -428,7 +500,13 @@ public abstract class TypeInfo implements JetObject { String value = annotation.value(); if(value != null) { Parser parser = new Parser(value, klass.getClassLoader()); - return new Signature(klass, parser.parseVars(), parser.parseTypes()); + Class enclosingClass = klass.getEnclosingClass(); + Signature signature = new Signature(parse(enclosingClass), klass); + map.put(klass, signature); + parser.parseVars(signature); + parser.parseTypes(signature); + signature.afterParse(); + return signature; } } return getGenericSignature(klass); @@ -437,21 +515,25 @@ public abstract class TypeInfo implements JetObject { private static Signature getGenericSignature(Class klass) { // todo complete impl + java.lang.reflect.Type genericSuperclass = klass.getGenericSuperclass(); + Signature signature = new Signature(parse(klass.getEnclosingClass()), klass); + TypeVariable[] typeParameters = klass.getTypeParameters(); - Map variables; - List vars; if(typeParameters == null || typeParameters.length == 0) { - variables = Collections.emptyMap(); - vars = Collections.emptyList(); + signature.varNames = Collections.emptyMap(); + signature.variables = Collections.emptyList(); } else { - variables = new HashMap(); - vars = new LinkedList(); + signature.varNames = new HashMap(); + signature.variables = new LinkedList(); + } + + if (typeParameters != null && typeParameters.length != 0) { for (int i = 0; i < typeParameters.length; i++) { TypeVariable typeParameter = typeParameters[i]; - variables.put(typeParameter.getName(), i); - final TypeInfoVar typeInfoVar = new TypeInfoVar(false, i); - vars.add(new TypeInfoProjection(){ + signature.varNames.put(typeParameter.getName(), i); + final TypeInfoVar typeInfoVar = new TypeInfoVar(signature, false, i); + signature.variables.add(new TypeInfoProjection(){ @Override public TypeInfoVariance getVariance() { @@ -471,29 +553,27 @@ public abstract class TypeInfo implements JetObject { } } - List types = new LinkedList(); - java.lang.reflect.Type genericSuperclass = klass.getGenericSuperclass(); - return new Signature(klass, vars, types); + return signature; } - public List parseVars() { - List list = null; + public void parseVars(Signature signature) { while(cur < string.length && string[cur] == 'T') { - if(list == null) { - list = new LinkedList(); - variables = new HashMap(); + if(signature.variables == null) { + signature.variables = new LinkedList(); + signature.varNames = new HashMap(); } cur++; - list.add(parseVar()); + signature.variables.add(parseVar(signature)); } - return list == null ? Collections.emptyList() : list; + signature.variables = signature.variables == null ? Collections.emptyList() : signature.variables; + signature.varNames = signature.varNames == null ? Collections.emptyMap() : signature.varNames; } - private TypeInfoProjection parseVar() { + private TypeInfoProjection parseVar(Signature signature) { final TypeInfoVariance variance = parseVariance(); String name = parseName(); - final TypeInfoVar typeInfoVar = new TypeInfoVar(variables.size()); - variables.put(name, variables.size()); + final TypeInfoVar typeInfoVar = new TypeInfoVar(signature, signature.variables.size()); + signature.varNames.put(name, signature.variables.size()); return new TypeInfoProjection(){ @Override public TypeInfoVariance getVariance() { @@ -536,18 +616,18 @@ public abstract class TypeInfo implements JetObject { } } - public List parseTypes() { + public void parseTypes(Signature signature) { List types = null; while(cur != string.length) { if(types == null) { types = new LinkedList(); } - types.add(parseType()); + types.add(parseType(signature)); } - return types == null ? Collections.emptyList() : types; + signature.superTypes = types == null ? Collections.emptyList() : types; } - private TypeInfo parseType() { + private TypeInfo parseType(Signature signature) { switch (string[cur]) { case 'L': cur++; @@ -565,7 +645,7 @@ public abstract class TypeInfo implements JetObject { while(string[cur] != '>') { if(proj == null) proj = new LinkedList(); - proj.add(parseProjection()); + proj.add(parseProjection(signature)); } cur++; } @@ -579,15 +659,16 @@ public abstract class TypeInfo implements JetObject { case 'T': cur++; - return parseTypeVar(); + return parseTypeVar(signature); default: throw new IllegalStateException(new String(string)); } } - private TypeInfo parseTypeVar() { + private TypeInfo parseTypeVar(Signature signature) { TypeInfoVariance variance = parseVariance(); + String klazz = parseName(); String name = parseName(); boolean nullable = false; if(string[cur] == '?') { @@ -595,12 +676,23 @@ public abstract class TypeInfo implements JetObject { cur++; } - return new TypeInfoVar(nullable, variables.get(name)); + if(klazz.equals(signature.klazz.getName())) + return new TypeInfoVar(signature, nullable, signature.varNames.get(name)); + else { + Signature sig = signature; + while(!klazz.equals(sig.klazz.getName())) { + sig = sig.outer; + if(sig == null) + throw new IllegalStateException(); + } + + return new TypeInfoVar(sig, nullable, sig.varNames.get(name)); + } } - private TypeInfoProjection parseProjection() { + private TypeInfoProjection parseProjection(Signature signature) { final TypeInfoVariance variance = parseVariance(); - final TypeInfo type = parseType(); + final TypeInfo type = parseType(signature); return new TypeInfoProjection(){ @Override public TypeInfoVariance getVariance() {