diff --git a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java index 84faf016cec..18ca9a27ef9 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java @@ -14,7 +14,7 @@ public class ClassDescriptor extends MemberDescriptorImpl implements MemberDomai public ClassDescriptor( List annotations, - String name, List typeParameters, Collection superclasses) { + String name, List typeParameters, Collection superclasses) { super(annotations, name); this.typeConstructor = new TypeConstructor(annotations, name, typeParameters, superclasses); } diff --git a/idea/src/org/jetbrains/jet/lang/types/ClassType.java b/idea/src/org/jetbrains/jet/lang/types/ClassType.java index 60fd0fe8909..6b04d349aa0 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ClassType.java +++ b/idea/src/org/jetbrains/jet/lang/types/ClassType.java @@ -30,4 +30,9 @@ public class ClassType extends TypeImpl { public Collection getMembers() { throw new UnsupportedOperationException(); // TODO } + + @Override + public R accept(TypeVisitor visitor, D data) { + return visitor.visitClassType(this, data); + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index 634841fd5f6..6c4b25783f5 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -1,6 +1,10 @@ package org.jetbrains.jet.lang.types; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; import java.util.Collections; +import java.util.List; /** * @author abreslav @@ -24,48 +28,91 @@ public class JetStandardClasses { private static final ClassDescriptor DOUBLE = new ClassDescriptor("Double"); private static final ClassDescriptor BOOLEAN = new ClassDescriptor("Boolean"); private static final ClassDescriptor STRING = new ClassDescriptor("String"); + private static final ClassDescriptor UNIT = new ClassDescriptor("Unit"); + public static final int TUPLE_COUNT = 22; + private static final ClassDescriptor[] TUPLE = new ClassDescriptor[TUPLE_COUNT]; + static { + for (int i = 0; i < TUPLE_COUNT; i++) { + List parameters = new ArrayList(); + for (int j = 0; j < i; j++) { + parameters.add(new TypeParameterDescriptor( + Collections.emptyList(), + "T" + j, + Variance.OUT_VARIANCE, + Collections.emptySet())); + } + TUPLE[i] = new ClassDescriptor( + Collections.emptyList(), + "Tuple" + i, + parameters, + Collections.singleton(JetStandardClasses.getAnyType())); + } + } + + @NotNull public static ClassDescriptor getAny() { return ANY; } + @NotNull public static ClassType getAnyType() { return ANY_TYPE; } + @NotNull public static ClassDescriptor getByte() { return BYTE; } + @NotNull public static ClassDescriptor getChar() { return CHAR; } + @NotNull public static ClassDescriptor getShort() { return SHORT; } + @NotNull public static ClassDescriptor getInt() { return INT; } + @NotNull public static ClassDescriptor getLong() { return LONG; } + @NotNull public static ClassDescriptor getFloat() { return FLOAT; } + @NotNull public static ClassDescriptor getDouble() { return DOUBLE; } + @NotNull public static ClassDescriptor getBoolean() { return BOOLEAN; } + @NotNull public static ClassDescriptor getString() { return STRING; } + + @NotNull + public static ClassDescriptor getTuple(int size) { + return TUPLE[size]; + } + + @NotNull + public static ClassDescriptor getLabeledTuple(int size) { + // TODO + return getTuple(size); + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index 9607dbd5e0d..8940e51dcf0 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -6,7 +6,9 @@ import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.lang.psi.*; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author abreslav @@ -74,10 +76,6 @@ public class JetTypeChecker { return checkSubtypeForTheSameConstructor(closestSupertype, supertype); } - private boolean checkSubtypeForTheSameConstructor(Type closestSupertype, Type supertype) { - throw new UnsupportedOperationException(); // TODO - } - // This method returns the supertype of the first parameter that has the same constructor // as the second parameter, applying the substitution of type arguments to it @Nullable @@ -89,10 +87,44 @@ public class JetTypeChecker { for (Type immediateSupertype : constructor.getSupertypes()) { Type correspondingSupertype = findCorrespondingSupertype(immediateSupertype, supertype); if (correspondingSupertype != null) { - return correspondingSupertype; + return substituteForParameters(subtype, correspondingSupertype); } } return null; } + private Type substituteForParameters(Type context, Type subject) { + Map parameterValues = new HashMap(); + + List parameters = context.getConstructor().getParameters(); + List contextArguments = context.getArguments(); + for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { + TypeParameterDescriptor parameter = parameters.get(i); + TypeProjection value = contextArguments.get(i); + parameterValues.put(parameter, value); + } + + return substitute(parameterValues, subject); + } + + private Type substitute(Map parameterValues, Type subject) { + List newArguments = new ArrayList(); + for (TypeProjection argument : subject.getArguments()) { + newArguments.add(new TypeProjection(argument.getProjection(), substitute(parameterValues, argument.getType()))); + } + return specializeType(subject, newArguments); + } + + private Type specializeType(Type type, List newArguments) { + // TODO + return type; + } + + private boolean checkSubtypeForTheSameConstructor(Type subtype, Type supertype) { + assert subtype.getConstructor().equals(supertype.getConstructor()); + + // TODO + return true; + } + } diff --git a/idea/src/org/jetbrains/jet/lang/types/NothingType.java b/idea/src/org/jetbrains/jet/lang/types/NothingType.java index 9659d8de8a3..7038502bf0b 100644 --- a/idea/src/org/jetbrains/jet/lang/types/NothingType.java +++ b/idea/src/org/jetbrains/jet/lang/types/NothingType.java @@ -38,4 +38,9 @@ public class NothingType extends TypeImpl { public Collection getMembers() { return Collections.emptySet(); } + + @Override + public R accept(TypeVisitor visitor, D data) { + return visitor.visitNothingType(this, data); + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/ThisType.java b/idea/src/org/jetbrains/jet/lang/types/ThisType.java index 8135e1ac977..bbf04dfc7f7 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ThisType.java +++ b/idea/src/org/jetbrains/jet/lang/types/ThisType.java @@ -25,4 +25,9 @@ public class ThisType extends TypeImpl { public Collection getMembers() { throw new UnsupportedOperationException(); // TODO } + + @Override + public R accept(TypeVisitor visitor, D data) { + return visitor.visitThisType(this, data); + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/TupleType.java b/idea/src/org/jetbrains/jet/lang/types/TupleType.java index 8af202b74a0..61a5922b741 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TupleType.java +++ b/idea/src/org/jetbrains/jet/lang/types/TupleType.java @@ -10,29 +10,8 @@ import java.util.List; */ public class TupleType extends TypeImpl { - public static final int TUPLE_COUNT = 22; - private static final TypeConstructor[] TUPLE = new TypeConstructor[TUPLE_COUNT]; - public static final TupleType UNIT = new TupleType(Collections.emptyList(), Collections.emptyList()); - static { - for (int i = 0; i < TUPLE_COUNT; i++) { - List parameters = new ArrayList(); - for (int j = 0; j < i; j++) { - parameters.add(new TypeParameterDescriptor( - Collections.emptyList(), - "T" + j, - Variance.OUT_VARIANCE, - Collections.emptySet())); - } - TUPLE[i] = new TypeConstructor( - Collections.emptyList(), - "Tuple" + i, - parameters, - Collections.singleton(JetStandardTypes.getAny())); - } - } - public static TupleType getTupleType(List annotations, List arguments) { if (annotations.isEmpty() && arguments.isEmpty()) { return UNIT; @@ -56,7 +35,7 @@ public class TupleType extends TypeImpl { private TupleType(List annotations, List arguments) { - super(annotations, TUPLE[arguments.size()], toProjections(arguments)); + super(annotations, JetStandardClasses.getTuple(arguments.size()).getTypeConstructor(), toProjections(arguments)); } @Override @@ -64,6 +43,11 @@ public class TupleType extends TypeImpl { throw new UnsupportedOperationException("Not implemented"); // TODO } + @Override + public R accept(TypeVisitor visitor, D data) { + return visitor.visitTupleType(this, data); + } + private static List toProjections(List arguments) { List result = new ArrayList(); for (Type argument : arguments) { diff --git a/idea/src/org/jetbrains/jet/lang/types/Type.java b/idea/src/org/jetbrains/jet/lang/types/Type.java index 93faf98f626..25f5bc4d98d 100644 --- a/idea/src/org/jetbrains/jet/lang/types/Type.java +++ b/idea/src/org/jetbrains/jet/lang/types/Type.java @@ -11,4 +11,8 @@ public interface Type extends Annotated { List getArguments(); Collection getMembers(); + + R accept(TypeVisitor visitor, D data); + R acceptNoData(TypeVisitor visitor); + void acceptVoid(TypeVisitor visitor); } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeConstructor.java b/idea/src/org/jetbrains/jet/lang/types/TypeConstructor.java index 4577ec0c1f9..37fe781e77d 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeConstructor.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeConstructor.java @@ -8,10 +8,10 @@ import java.util.List; */ public class TypeConstructor extends AnnotatedImpl { private final List parameters; - private final Collection supertypes; + private final Collection supertypes; private final String debugName; - public TypeConstructor(List annotations, String debugName, List parameters, Collection supertypes) { + public TypeConstructor(List annotations, String debugName, List parameters, Collection supertypes) { super(annotations); this.debugName = debugName; this.parameters = parameters; @@ -22,7 +22,7 @@ public class TypeConstructor extends AnnotatedImpl { return parameters; } - public Collection getSupertypes() { + public Collection getSupertypes() { return supertypes; } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeImpl.java b/idea/src/org/jetbrains/jet/lang/types/TypeImpl.java index 26bfec55684..4cf4e32eb86 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeImpl.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeImpl.java @@ -43,4 +43,14 @@ public abstract class TypeImpl extends AnnotatedImpl implements Type { } return stringBuilder; } + + @Override + public R acceptNoData(TypeVisitor visitor) { + return accept(visitor, null); + } + + @Override + public void acceptVoid(TypeVisitor visitor) { + accept(visitor, null); + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeVariable.java b/idea/src/org/jetbrains/jet/lang/types/TypeVariable.java index 39f1bcac2ba..8061ba2f7cd 100644 --- a/idea/src/org/jetbrains/jet/lang/types/TypeVariable.java +++ b/idea/src/org/jetbrains/jet/lang/types/TypeVariable.java @@ -19,4 +19,9 @@ public class TypeVariable extends TypeImpl { public Collection getMembers() { throw new javax.help.UnsupportedOperationException(); // TODO } + + @Override + public R accept(TypeVisitor visitor, D data) { + return visitor.visitTypeVariable(this, data); + } } diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeVisitor.java b/idea/src/org/jetbrains/jet/lang/types/TypeVisitor.java new file mode 100644 index 00000000000..27f48335334 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/TypeVisitor.java @@ -0,0 +1,30 @@ +package org.jetbrains.jet.lang.types; + +/** + * @author abreslav + */ +public class TypeVisitor { + public R visitNothingType(NothingType nothingType, D data) { + return visitType(nothingType, data); + } + + public R visitTupleType(TupleType tupleType, D data) { + return visitType(tupleType, data); + } + + public R visitTypeVariable(TypeVariable typeVariable, D data) { + return visitType(typeVariable, data); + } + + public R visitClassType(ClassType classType, D data) { + return visitType(classType, data); + } + + public R visitThisType(ThisType thisType, D data) { + return visitType(thisType, data); + } + + public R visitType(Type type, D data) { + throw new UnsupportedOperationException(); // TODO + } +} diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index 9b0b9db7488..d63b5f99fa4 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -10,6 +10,7 @@ import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.parsing.JetParsingTest; import java.io.File; +import java.util.ArrayList; import java.util.List; /** @@ -36,6 +37,10 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { return JetStandardClasses.getFloat(); } else if ("Double".equals(name)) { return JetStandardClasses.getDouble(); + } else if ("Unit".equals(name)) { + return JetStandardClasses.getTuple(0); + } else if ("Any".equals(name)) { + return JetStandardClasses.getAny(); } fail("Type not found: " + name); throw new IllegalStateException(); @@ -92,6 +97,17 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { assertSubtype("Double", "Double"); assertSubtype("Unit", "Unit"); + assertSubtype("Boolean", "Any"); + assertSubtype("Byte", "Any"); + assertSubtype("Char", "Any"); + assertSubtype("Short", "Any"); + assertSubtype("Int", "Any"); + assertSubtype("Long", "Any"); + assertSubtype("Float", "Any"); + assertSubtype("Double", "Any"); + assertSubtype("Unit", "Any"); + assertSubtype("Any", "Any"); + assertNotSubtype("Boolean", "Byte"); assertNotSubtype("Byte", "Short"); assertNotSubtype("Char", "Int"); @@ -100,7 +116,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { assertNotSubtype("Long", "Double"); assertNotSubtype("Float", "Double"); assertNotSubtype("Double", "Int"); - assertNotSubtype("Unit", "Unit"); + assertNotSubtype("Unit", "Int"); assertSubtype("(Boolean)", "(Boolean)"); assertSubtype("(Byte)", "(Byte)"); @@ -128,14 +144,21 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { boolean result = new JetTypeChecker().isSubtypeOf( typeNode1, typeNode2); - assertTrue(typeNode1 + " is not a subtype of " + typeNode2, result == expected); + String modifier = expected ? "not " : ""; + assertTrue(typeNode1 + " is " + modifier + "a subtype of " + typeNode2, result == expected); } private Type toType(JetTypeReference typeNode) { List attributes = typeNode.getAttributes(); JetTypeElement typeElement = typeNode.getTypeElement(); - List typeArguments = typeNode.getTypeArguments(); + List argumentElements = typeNode.getTypeArguments(); + final List arguments = new ArrayList(); + for (JetTypeReference argumentElement : argumentElements) { + arguments.add(toType(argumentElement)); + } + + // TODO annotations final Type[] result = new Type[1]; typeElement.accept(new JetVisitor() { @Override @@ -143,9 +166,15 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { result[0] = new ClassType(TypeResolver.INSTANCE.resolveClass(BASIC_SCOPE, type)); } + @Override + public void visitTupleType(JetTupleType type) { + // TODO labels + result[0] = TupleType.getTupleType(arguments); + } + @Override public void visitJetElement(JetElement elem) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("Unsupported type: " + elem); } });