diff --git a/.idea/libraries/annotations.xml b/.idea/libraries/annotations.xml new file mode 100644 index 00000000000..5183e286398 --- /dev/null +++ b/.idea/libraries/annotations.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/idea/idea.iml b/idea/idea.iml index 9c112d636ff..d07235464f2 100644 --- a/idea/idea.iml +++ b/idea/idea.iml @@ -21,7 +21,6 @@ - diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index 97f0cd3dda7..dc8f9961c02 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -56,10 +56,8 @@ public class ClassCodegen { public static void newTypeInfo(InstructionAdapter v, boolean isNullable, Type asmType) { - v.anew(JetTypeMapper.TYPE_TYPEINFO); - v.dup(); v.aconst(asmType); v.iconst(isNullable?1:0); - v.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;Z)V"); + v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;"); } } diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index fff6e384af8..521ae9e361a 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -18,6 +18,7 @@ import org.jetbrains.jet.lang.resolve.java.JavaClassDescriptor; 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.lang.types.Variance; import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; @@ -1949,29 +1950,39 @@ public class ExpressionCodegen extends JetVisitor { return; } - v.anew(JetTypeMapper.TYPE_TYPEINFO); - v.dup(); v.aconst(jvmType); v.iconst(jetType.isNullable()?1:0); List arguments = jetType.getArguments(); if (arguments.size() > 0) { v.iconst(arguments.size()); - v.newarray(JetTypeMapper.TYPE_TYPEINFO); + v.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION); for (int i = 0, argumentsSize = arguments.size(); i < argumentsSize; i++) { TypeProjection argument = arguments.get(i); v.dup(); v.iconst(i); generateTypeInfo(argument.getType()); + genTypeInfoToProjection(v, argument.getProjectionKind()); v.astore(JetTypeMapper.TYPE_OBJECT); } - v.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfo;)V"); + v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;"); } else { - v.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;Z)V"); + v.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z)Ljet/typeinfo/TypeInfo;"); } } + public static void genTypeInfoToProjection(InstructionAdapter v, Variance variance) { + if(variance == Variance.INVARIANT) + v.invokestatic("jet/typeinfo/TypeInfo", "invariantProjection", "(Ljet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfoProjection;"); + else if(variance == Variance.IN_VARIANCE) + v.invokestatic("jet/typeinfo/TypeInfo", "inProjection", "(Ljet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfoProjection;"); + else if(variance == Variance.OUT_VARIANCE) + v.invokestatic("jet/typeinfo/TypeInfo", "outProjection", "(Ljet/typeinfo/TypeInfo;)Ljet/typeinfo/TypeInfoProjection;"); + else + throw new UnsupportedOperationException(variance.toString()); + } + private void loadTypeParameterTypeInfo(TypeParameterDescriptor typeParameterDescriptor) { final StackValue value = typeParameterExpressions.get(typeParameterDescriptor); if (value != null) { @@ -1982,7 +1993,7 @@ public class ExpressionCodegen extends JetVisitor { if (containingDeclaration == contextType() && contextType() instanceof ClassDescriptor) { loadTypeInfo(typeMapper, (ClassDescriptor) contextType(), v); v.iconst(typeParameterDescriptor.getIndex()); - v.invokevirtual("jet/typeinfo/TypeInfo", "getTypeParameter", "(I)Ljet/typeinfo/TypeInfo;"); + v.invokevirtual("jet/typeinfo/TypeInfo", "getArgumentType", "(I)Ljet/typeinfo/TypeInfo;"); return; } throw new UnsupportedOperationException("don't know what this type parameter resolves to"); diff --git a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 6d019b6a771..8f1be52b429 100644 --- a/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.lexer.JetTokens; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; @@ -389,21 +390,20 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { protected void generateTypeInfoInitializer(int firstTypeParameter, int typeParamCount, InstructionAdapter iv) { iv.load(0, JetTypeMapper.TYPE_OBJECT); - iv.anew(JetTypeMapper.TYPE_TYPEINFO); - iv.dup(); iv.aconst(state.getTypeMapper().jvmType(descriptor, OwnerKind.INTERFACE)); iv.iconst(0); iv.iconst(typeParamCount); - iv.newarray(JetTypeMapper.TYPE_TYPEINFO); + iv.newarray(JetTypeMapper.TYPE_TYPEINFOPROJECTION); for (int i = 0; i < typeParamCount; i++) { iv.dup(); iv.iconst(i); iv.load(firstTypeParameter + i, JetTypeMapper.TYPE_OBJECT); + ExpressionCodegen.genTypeInfoToProjection(iv, Variance.INVARIANT); iv.astore(JetTypeMapper.TYPE_OBJECT); } - iv.invokespecial("jet/typeinfo/TypeInfo", "", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfo;)V"); + iv.invokestatic("jet/typeinfo/TypeInfo", "getTypeInfo", "(Ljava/lang/Class;Z[Ljet/typeinfo/TypeInfoProjection;)Ljet/typeinfo/TypeInfo;"); iv.putfield(state.getTypeMapper().jvmName(descriptor, OwnerKind.IMPLEMENTATION), "$typeInfo", "Ljet/typeinfo/TypeInfo;"); } diff --git a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java index 40522b08121..d48c8eec52e 100644 --- a/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java +++ b/idea/src/org/jetbrains/jet/codegen/JetTypeMapper.java @@ -4,6 +4,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import jet.JetObject; import jet.typeinfo.TypeInfo; +import jet.typeinfo.TypeInfoProjection; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; @@ -23,6 +24,7 @@ import java.util.*; public class JetTypeMapper { public static final Type TYPE_OBJECT = Type.getObjectType("java/lang/Object"); public static final Type TYPE_TYPEINFO = Type.getType(TypeInfo.class); + public static final Type TYPE_TYPEINFOPROJECTION = Type.getType(TypeInfoProjection.class); public static final Type TYPE_JET_OBJECT = Type.getType(JetObject.class); public static final Type TYPE_CLASS = Type.getType(Class.class); public static final Type TYPE_NOTHING = Type.getObjectType("jet/Nothing"); diff --git a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java index e398c7d605a..fb7d05ede1e 100644 --- a/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java +++ b/idea/src/org/jetbrains/jet/plugin/structureView/JetStructureViewElement.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.plugin.structureView; import com.intellij.ide.structureView.StructureViewTreeElement; import com.intellij.ide.util.treeView.smartTree.TreeElement; import com.intellij.navigation.ItemPresentation; +import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.NavigatablePsiElement; @@ -68,6 +69,7 @@ public class JetStructureViewElement implements StructureViewTreeElement { ? PsiIconUtil.getProvidersIcon(myElement, open ? Iconable.ICON_FLAG_OPEN : Iconable.ICON_FLAG_CLOSED) : null; } + }; } diff --git a/idea/testData/codegen/patternMatching/is.jet b/idea/testData/codegen/patternMatching/is.jet new file mode 100644 index 00000000000..a5b5f33195f --- /dev/null +++ b/idea/testData/codegen/patternMatching/is.jet @@ -0,0 +1,11 @@ +fun typeName(a: Any?) : String { + return when(a) { + is java.util.ArrayList => "array list" + else => "no idea" + } +} + +fun box() : String { + if(typeName(java.util.ArrayList ()) != "array list") return "array list failed" + return "OK" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java index 13aaf4b19e2..c82f9a4847d 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PatternMatchingTest.java @@ -47,6 +47,12 @@ public class PatternMatchingTest extends CodegenTestCase { assertEquals("something", foo.invoke(null, 19)); } + public void testIs() throws Exception { + loadFile(); + blackBox(); + System.out.println(generateToText()); + } + public void testRange() throws Exception { loadFile(); System.out.println(generateToText()); diff --git a/stdlib/src/jet/typeinfo/TypeInfo.java b/stdlib/src/jet/typeinfo/TypeInfo.java index 55f848c7b2c..f93bf29bad6 100644 --- a/stdlib/src/jet/typeinfo/TypeInfo.java +++ b/stdlib/src/jet/typeinfo/TypeInfo.java @@ -1,6 +1,7 @@ package jet.typeinfo; import jet.JetObject; +import org.jetbrains.annotations.NotNull; import java.lang.reflect.Field; import java.util.Arrays; @@ -8,60 +9,101 @@ import java.util.Arrays; /** * @author abreslav * @author yole + * @author alex.tkachman */ -public class TypeInfo implements JetObject { +public abstract class TypeInfo implements JetObject { + public static final TypeInfo BYTE_TYPE_INFO = getTypeInfo(Byte.class, false); + public static final TypeInfo SHORT_TYPE_INFO = getTypeInfo(Short.class, false); + public static final TypeInfo INT_TYPE_INFO = getTypeInfo(Integer.class, false); + public static final TypeInfo LONG_TYPE_INFO = getTypeInfo(Long.class, false); + public static final TypeInfo CHAR_TYPE_INFO = getTypeInfo(Character.class, false); + 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); + private TypeInfo typeInfo; private final Class theClass; private final boolean nullable; - private final TypeInfo[] typeParameters; + private final TypeInfoProjection[] projections; - public TypeInfo(Class theClass, boolean nullable) { + private TypeInfo(Class theClass, boolean nullable) { this.theClass = theClass; this.nullable = nullable; - this.typeParameters = null; + this.projections = null; } - public TypeInfo(Class theClass, boolean nullable, TypeInfo[] typeParameters) { + private TypeInfo(Class theClass, boolean nullable, TypeInfoProjection[] projections) { this.theClass = theClass; this.nullable = nullable; - this.typeParameters = typeParameters; + this.projections = projections; } - public Object getClassObject() { + public static TypeInfoProjection invariantProjection(final TypeInfo typeInfo) { + return (TypeInfoImpl) typeInfo; + } + + public static TypeInfoProjection inProjection(TypeInfo typeInfo) { + return new TypeInfoProjection.TypeInfoProjectionImpl(typeInfo) { + @NotNull + @Override + public TypeInfoVariance getVariance() { + return TypeInfoVariance.IN_VARIANCE; + } + }; + } + + public static TypeInfoProjection outProjection(TypeInfo typeInfo) { + return new TypeInfoProjection.TypeInfoProjectionImpl(typeInfo) { + @NotNull + @Override + public TypeInfoVariance getVariance() { + return TypeInfoVariance.OUT_VARIANCE; + } + }; + } + + public static TypeInfo getTypeInfo(Class klazz, boolean nullable) { + return new TypeInfoImpl(klazz, nullable); + } + + public static TypeInfo getTypeInfo(Class klazz, boolean nullable, TypeInfoProjection[] projections) { + return new TypeInfoImpl(klazz, nullable, projections); + } + + public final Object getClassObject() { try { final Class implClass = theClass.getClassLoader().loadClass(theClass.getCanonicalName() + "$$Impl"); final Field classobj = implClass.getField("$classobj"); return classobj.get(null); - } - catch(Exception e) { + } catch (Exception e) { return null; } } - public boolean isInstance(Object obj) { + public final boolean isInstance(Object obj) { + if (obj == null) return nullable; + if (obj instanceof JetObject) { return ((JetObject) obj).getTypeInfo().isSubtypeOf(this); } - if(obj == null) - return nullable; return theClass.isAssignableFrom(obj.getClass()); // TODO } - public boolean isSubtypeOf(TypeInfo superType) { - if (!superType.theClass.isAssignableFrom(theClass)) { - return false; - } + public final boolean isSubtypeOf(TypeInfo superType) { if (nullable && !superType.nullable) { return false; } - if (typeParameters != null) { - if (superType.typeParameters == null || superType.typeParameters.length != typeParameters.length) { + if (!superType.theClass.isAssignableFrom(theClass)) { + return false; + } + if (projections != null) { + if (superType.projections == null || superType.projections.length != projections.length) { throw new IllegalArgumentException("inconsistent type infos for the same class"); } - for (int i = 0; i < typeParameters.length; i++) { + for (int i = 0; i < projections.length; i++) { // TODO handle variance here - if (!typeParameters [i].equals(superType.typeParameters [i])) { + if (!projections[i].equals(superType.projections[i])) { return false; } } @@ -69,12 +111,16 @@ public class TypeInfo implements JetObject { return true; } - public TypeInfo getTypeParameter(int index) { - return typeParameters[index]; + public final TypeInfoProjection getProjection(int index) { + return projections[index]; + } + + public final TypeInfo getArgumentType(int index) { + return projections[index].getType(); } @Override - public TypeInfo getTypeInfo() { + public final TypeInfo getTypeInfo() { if (typeInfo == null) { // TODO: Implementation must be lazy, otherwise the result would be of an infinite size throw new UnsupportedOperationException(); // TODO @@ -83,7 +129,7 @@ public class TypeInfo implements JetObject { } @Override - public boolean equals(Object o) { + public final boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; @@ -91,37 +137,50 @@ public class TypeInfo implements JetObject { if (!theClass.equals(typeInfo.theClass)) return false; if (nullable != typeInfo.nullable) return false; - if (!Arrays.equals(typeParameters, typeInfo.typeParameters)) return false; + if (!Arrays.equals(projections, typeInfo.projections)) return false; return true; } @Override - public int hashCode() { - return 31 * theClass.hashCode() + (typeParameters != null ? Arrays.hashCode(typeParameters) : 0); + public final int hashCode() { + return 31 * theClass.hashCode() + (projections != null ? Arrays.hashCode(projections) : 0); } @Override - public String toString() { + public final String toString() { StringBuilder sb = new StringBuilder().append(theClass.getName()); - if(typeParameters != null && typeParameters.length != 0) { + if (projections != null && projections.length != 0) { sb.append("<"); - for(int i = 0; i != typeParameters.length-1; ++i) { - sb.append(typeParameters[i].toString()).append(","); + for (int i = 0; i != projections.length - 1; ++i) { + sb.append(projections[i].toString()).append(","); } - sb.append(typeParameters[typeParameters.length - 1].toString()).append(">"); + sb.append(projections[projections.length - 1].toString()).append(">"); } - if(nullable) + if (nullable) sb.append("?"); return sb.toString(); } - public static final TypeInfo BYTE_TYPE_INFO = new TypeInfo(Byte.class, false); - public static final TypeInfo SHORT_TYPE_INFO = new TypeInfo(Short.class, false); - public static final TypeInfo INT_TYPE_INFO = new TypeInfo(Integer.class, false); - public static final TypeInfo LONG_TYPE_INFO = new TypeInfo(Long.class, false); - public static final TypeInfo CHAR_TYPE_INFO = new TypeInfo(Character.class, false); - public static final TypeInfo BOOL_TYPE_INFO = new TypeInfo(Boolean.class, false); - public static final TypeInfo FLOAT_TYPE_INFO = new TypeInfo(Float.class, false); - public static final TypeInfo DOUBLE_TYPE_INFO = new TypeInfo(Double.class, false); + private static class TypeInfoImpl extends TypeInfo implements TypeInfoProjection { + TypeInfoImpl(Class klazz, boolean nullable) { + super(klazz, nullable); + } + + TypeInfoImpl(Class klazz, boolean nullable, TypeInfoProjection[] projections) { + super(klazz, nullable, projections); + } + + @NotNull + @Override + public TypeInfoVariance getVariance() { + return TypeInfoVariance.INVARIANT; + } + + @NotNull + @Override + public TypeInfo getType() { + return this; + } + } } diff --git a/stdlib/src/jet/typeinfo/TypeInfoProjection.java b/stdlib/src/jet/typeinfo/TypeInfoProjection.java new file mode 100644 index 00000000000..381383c05f4 --- /dev/null +++ b/stdlib/src/jet/typeinfo/TypeInfoProjection.java @@ -0,0 +1,50 @@ +package jet.typeinfo; + +import org.jetbrains.annotations.NotNull; + +/** + * @author alex.tkachman + */ +public interface TypeInfoProjection { + @NotNull + TypeInfoVariance getVariance(); + + @NotNull + TypeInfo getType(); + + abstract class TypeInfoProjectionImpl implements TypeInfoProjection { + @NotNull private final TypeInfo type; + + TypeInfoProjectionImpl(@NotNull TypeInfo typeInfo) { + this.type = typeInfo; + } + + @Override + @NotNull + public final TypeInfo getType() { + return type; + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TypeInfoProjectionImpl that = (TypeInfoProjectionImpl) o; + // no need to compare variance as we compared classes already + return type.equals(that.type); + } + + @Override + public final int hashCode() { + int result = type.hashCode(); + result = 31 * result + (getVariance().hashCode()); + return result; + } + + @Override + public final String toString() { + return (getVariance() == TypeInfoVariance.INVARIANT ? "" : getVariance().toString() + " ") + type; + } + } +} diff --git a/stdlib/src/jet/typeinfo/TypeInfoVariance.java b/stdlib/src/jet/typeinfo/TypeInfoVariance.java new file mode 100644 index 00000000000..410d45e3c49 --- /dev/null +++ b/stdlib/src/jet/typeinfo/TypeInfoVariance.java @@ -0,0 +1,21 @@ +package jet.typeinfo; + +/** + * @author alex.tkachman + */ +public enum TypeInfoVariance { + INVARIANT("") , + IN_VARIANCE("in"), + OUT_VARIANCE("out"); + + private final String label; + + TypeInfoVariance(String label) { + this.label = label; + } + + @Override + public String toString() { + return label; + } +} diff --git a/stdlib/stdlib.iml b/stdlib/stdlib.iml index d5c07432750..0e9d8224de4 100644 --- a/stdlib/stdlib.iml +++ b/stdlib/stdlib.iml @@ -7,6 +7,7 @@ +