Type infrastructure simplified

This commit is contained in:
Andrey Breslav
2011-01-27 16:06:11 +03:00
parent ae854b1e38
commit 820563a283
18 changed files with 303 additions and 500 deletions
@@ -7,6 +7,7 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
@@ -23,29 +24,48 @@ public class TypeResolver {
public Type resolveType(@NotNull final JetScope scope, @NotNull final JetTypeReference typeReference) { public Type resolveType(@NotNull final JetScope scope, @NotNull final JetTypeReference typeReference) {
final List<Attribute> attributes = AttributeResolver.INSTANCE.resolveAttributes(typeReference.getAttributes()); final List<Attribute> attributes = AttributeResolver.INSTANCE.resolveAttributes(typeReference.getAttributes());
JetTypeElement typeElement = typeReference.getTypeElement();
return resolveTypeElement(scope, attributes, typeElement, false);
}
private Type resolveTypeElement(final JetScope scope, final List<Attribute> attributes, JetTypeElement typeElement, final boolean nullable) {
final Type[] result = new Type[1]; final Type[] result = new Type[1];
typeReference.getTypeElement().accept(new JetVisitor() { typeElement.accept(new JetVisitor() {
@Override @Override
public void visitUserType(JetUserType type) { public void visitUserType(JetUserType type) {
ClassDescriptor classDescriptor = resolveClass(scope, type); ClassDescriptor classDescriptor = resolveClass(scope, type);
if (classDescriptor != null) { if (classDescriptor != null) {
result[0] = new ClassType( result[0] = new TypeImpl(
attributes, attributes,
classDescriptor, classDescriptor.getTypeConstructor(),
resolveTypeProjections(scope, type.getTypeArguments()) nullable,
resolveTypeProjections(scope, type.getTypeArguments()),
JetStandardClasses.STUB
); );
} else if (type.getTypeArguments().isEmpty()) { }
else if (type.getTypeArguments().isEmpty()) {
TypeParameterDescriptor typeParameterDescriptor = scope.getTypeParameterDescriptor(type.getReferencedName()); TypeParameterDescriptor typeParameterDescriptor = scope.getTypeParameterDescriptor(type.getReferencedName());
if (typeParameterDescriptor != null) { if (typeParameterDescriptor != null) {
result[0] = new TypeVariable(attributes, typeParameterDescriptor); result[0] = new TypeImpl(
attributes,
typeParameterDescriptor.getTypeConstructor(),
nullable || hasNullableBound(typeParameterDescriptor),
Collections.<TypeProjection>emptyList(),
JetStandardClasses.STUB
);
} }
} }
} }
@Override
public void visitNullableType(JetNullableType nullableType) {
result[0] = resolveTypeElement(scope, attributes, nullableType.getInnerType(), true);
}
@Override @Override
public void visitTupleType(JetTupleType type) { public void visitTupleType(JetTupleType type) {
// TODO labels // TODO labels
result[0] = TupleType.getTupleType(resolveTypes(scope, type.getComponentTypeRefs())); result[0] = JetStandardClasses.getTupleType(resolveTypes(scope, type.getComponentTypeRefs()));
} }
@Override @Override
@@ -54,11 +74,20 @@ public class TypeResolver {
} }
}); });
if (result[0] == null) { if (result[0] == null) {
return new ErrorType(typeReference); return ErrorType.createErrorType(typeElement.getText());
} }
return result[0]; return result[0];
} }
private boolean hasNullableBound(TypeParameterDescriptor typeParameterDescriptor) {
for (Type bound : typeParameterDescriptor.getUpperBounds()) {
if (bound.isNullable()) {
return true;
}
}
return false;
}
private List<Type> resolveTypes(JetScope scope, List<JetTypeReference> argumentElements) { private List<Type> resolveTypes(JetScope scope, List<JetTypeReference> argumentElements) {
final List<Type> arguments = new ArrayList<Type>(); final List<Type> arguments = new ArrayList<Type>();
for (JetTypeReference argumentElement : argumentElements) { for (JetTypeReference argumentElement : argumentElements) {
@@ -1,42 +0,0 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
*/
public class ClassType extends TypeImpl {
@NotNull
private final ClassDescriptor classDescriptor;
public ClassType(@NotNull List<Attribute> attributes, @NotNull ClassDescriptor classDescriptor, @NotNull List<TypeProjection> arguments) {
super(attributes, classDescriptor.getTypeConstructor(), arguments);
assert classDescriptor.getTypeConstructor().getParameters().size() == arguments.size() : classDescriptor.getTypeConstructor().getParameters().size() + " != " + arguments.size();
this.classDescriptor = classDescriptor;
}
public ClassType(ClassDescriptor classDescriptor) {
this(Collections.<Attribute>emptyList(), classDescriptor, Collections.<TypeProjection>emptyList());
assert classDescriptor.getTypeConstructor().getParameters().size() == 0;
}
@NotNull
public ClassDescriptor getClassDescriptor() {
return classDescriptor;
}
@Override
public Collection<MemberDescriptor> getMembers() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public <R, D> R accept(TypeVisitor<R, D> visitor, D data) {
return visitor.visitClassType(this, data);
}
}
@@ -1,45 +1,26 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import org.jetbrains.jet.lang.psi.JetTypeReference; import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
/** /**
* @author abreslav * @author abreslav
*/ */
public class ErrorType extends VisitableTypeImpl implements Type { public class ErrorType {
private final String debugLabel; private static final TypeMemberDomain ERROR_DOMAIN = new TypeMemberDomain() {
@Override
public ClassDescriptor getClassDescriptor(@NotNull Type type) {
throw new UnsupportedOperationException(); // TODO
}
};
private static final TypeConstructor ERROR = new TypeConstructor(Collections.<Attribute>emptyList(), "ERROR", Collections.<TypeParameterDescriptor>emptyList(), Collections.<Type>emptyList());
public ErrorType(JetTypeReference typeReference) { public static Type createErrorType(String debugMessage) {
super(Collections.<Attribute>emptyList()); return new TypeImpl(ERROR, ERROR_DOMAIN);
this.debugLabel = typeReference.getText();
assert debugLabel != null;
} }
@Override public static boolean isError(Type type) {
public TypeConstructor getConstructor() { return type.getConstructor() == ERROR;
throw new UnsupportedOperationException("Not found: " + debugLabel); // TODO
}
@Override
public List<TypeProjection> getArguments() {
throw new UnsupportedOperationException("Not found: " + debugLabel); // TODO
}
@Override
public Collection<MemberDescriptor> getMembers() {
throw new UnsupportedOperationException("Not found: " + debugLabel); // TODO
}
@Override
public <R, D> R accept(TypeVisitor<R, D> visitor, D data) {
return visitor.visitErrorType(this, data);
}
@Override
public String toString() {
return "!!!" + debugLabel + "!!!";
} }
} }
@@ -2,14 +2,34 @@ package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
/** /**
* @author abreslav * @author abreslav
*/ */
public class JetStandardClasses { public class JetStandardClasses {
private static final TypeConstructor NOTHING = new TypeConstructor(
Collections.<Attribute>emptyList(),
"Nothing",
Collections.<TypeParameterDescriptor>emptyList(),
new AbstractCollection<Type>() {
@Override
public boolean contains(Object o) {
return o instanceof Type;
}
@Override
public Iterator<Type> iterator() {
throw new UnsupportedOperationException();
}
@Override
public int size() {
throw new UnsupportedOperationException();
}
});
private static final ClassDescriptor ANY = new ClassDescriptor( private static final ClassDescriptor ANY = new ClassDescriptor(
Collections.<Attribute>emptyList(), Collections.<Attribute>emptyList(),
"Any", "Any",
@@ -17,7 +37,7 @@ public class JetStandardClasses {
Collections.<Type>emptySet() Collections.<Type>emptySet()
); );
private static final ClassType ANY_TYPE = new ClassType(ANY); private static final Type ANY_TYPE = new TypeImpl(ANY.getTypeConstructor(), TypeMemberDomain.EMPTY);
private static final ClassDescriptor BYTE = new ClassDescriptor("Byte"); private static final ClassDescriptor BYTE = new ClassDescriptor("Byte");
private static final ClassDescriptor CHAR = new ClassDescriptor("Char"); private static final ClassDescriptor CHAR = new ClassDescriptor("Char");
@@ -48,13 +68,33 @@ public class JetStandardClasses {
} }
} }
public static final TypeMemberDomain STUB = new TypeMemberDomain() {
@Override
public ClassDescriptor getClassDescriptor(@NotNull Type type) {
throw new UnsupportedOperationException(); // TODO
}
};
private static final Type BYTE_TYPE = new TypeImpl(getByte().getTypeConstructor(), STUB);
private static final Type CHAR_TYPE = new TypeImpl(getChar().getTypeConstructor(), STUB);
private static final Type SHORT_TYPE = new TypeImpl(getShort().getTypeConstructor(), STUB);
private static final Type INT_TYPE = new TypeImpl(getInt().getTypeConstructor(), STUB);
private static final Type LONG_TYPE = new TypeImpl(getLong().getTypeConstructor(), STUB);
private static final Type FLOAT_TYPE = new TypeImpl(getFloat().getTypeConstructor(), STUB);
private static final Type DOUBLE_TYPE = new TypeImpl(getDouble().getTypeConstructor(), STUB);
private static final Type BOOLEAN_TYPE = new TypeImpl(getBoolean().getTypeConstructor(), STUB);
private static final Type STRING_TYPE = new TypeImpl(getString().getTypeConstructor(), STUB);
private static final Type UNIT_TYPE = new TypeImpl(getTuple(0).getTypeConstructor(), STUB);
private static final Type NOTHING_TYPE = new TypeImpl(NOTHING, STUB);
private static final Type NULLABLE_NOTHING_TYPE = new TypeImpl(Collections.<Attribute>emptyList(), NOTHING, true, Collections.<TypeProjection>emptyList(), TypeMemberDomain.EMPTY);
@NotNull @NotNull
public static ClassDescriptor getAny() { public static ClassDescriptor getAny() {
return ANY; return ANY;
} }
@NotNull @NotNull
public static ClassType getAnyType() { public static Type getAnyType() {
return ANY_TYPE; return ANY_TYPE;
} }
@@ -108,9 +148,92 @@ public class JetStandardClasses {
return TUPLE[size]; return TUPLE[size];
} }
@NotNull public static Type getIntType() {
public static ClassDescriptor getLabeledTuple(int size) { return INT_TYPE;
}
public static Type getLongType() {
return LONG_TYPE;
}
public static Type getDoubleType() {
return DOUBLE_TYPE;
}
public static Type getFloatType() {
return FLOAT_TYPE;
}
public static Type getCharType() {
return CHAR_TYPE;
}
public static Type getBooleanType() {
return BOOLEAN_TYPE;
}
public static Type getStringType() {
return STRING_TYPE;
}
public static Type getByteType() {
return BYTE_TYPE;
}
public static Type getShortType() {
return SHORT_TYPE;
}
public static Type getUnitType() {
return UNIT_TYPE;
}
public static Type getNothingType() {
return NOTHING_TYPE;
}
public static Type getNullableNothingType() {
return NULLABLE_NOTHING_TYPE;
}
public static Type getTupleType(List<Attribute> attributes, List<Type> arguments) {
if (attributes.isEmpty() && arguments.isEmpty()) {
return getUnitType();
}
return new TypeImpl(attributes, getTuple(arguments.size()).getTypeConstructor(), false, toProjections(arguments), STUB);
}
public static Type getTupleType(List<Type> arguments) {
return getTupleType(Collections.<Attribute>emptyList(), arguments);
}
public static Type getTupleType(Type... arguments) {
return getTupleType(Collections.<Attribute>emptyList(), Arrays.asList(arguments));
}
public static Type getLabeledTupleType(List<Attribute> attributes, List<ParameterDescriptor> arguments) {
// TODO // TODO
return getTuple(size); return getTupleType(attributes, toTypes(arguments));
}
public static Type getLabeledTupleType(List<ParameterDescriptor> arguments) {
// TODO
return getLabeledTupleType(Collections.<Attribute>emptyList(), arguments);
}
private static List<TypeProjection> toProjections(List<Type> arguments) {
List<TypeProjection> result = new ArrayList<TypeProjection>();
for (Type argument : arguments) {
result.add(new TypeProjection(ProjectionKind.OUT_ONLY, argument));
}
return result;
}
private static List<Type> toTypes(List<ParameterDescriptor> labeledEntries) {
List<Type> result = new ArrayList<Type>();
for (ParameterDescriptor entry : labeledEntries) {
result.add(entry.getType());
}
return result;
} }
} }
@@ -1,64 +0,0 @@
package org.jetbrains.jet.lang.types;
import java.util.Collections;
/**
* @author abreslav
*/
public class JetStandardTypes {
private static final ClassType ANY_TYPE = new ClassType(JetStandardClasses.getAny());
private static final ClassType BYTE = new ClassType(JetStandardClasses.getByte());
private static final ClassType CHAR = new ClassType(JetStandardClasses.getChar());
private static final ClassType SHORT = new ClassType(JetStandardClasses.getShort());
private static final ClassType INT = new ClassType(JetStandardClasses.getInt());
private static final ClassType LONG = new ClassType(JetStandardClasses.getLong());
private static final ClassType FLOAT = new ClassType(JetStandardClasses.getFloat());
private static final ClassType DOUBLE = new ClassType(JetStandardClasses.getDouble());
private static final ClassType BOOLEAN = new ClassType(JetStandardClasses.getBoolean());
private static final ClassType STRING = new ClassType(JetStandardClasses.getString());
private static final TupleType UNIT = TupleType.UNIT;
public static ClassType getInt() {
return INT;
}
public static ClassType getLong() {
return LONG;
}
public static ClassType getDouble() {
return DOUBLE;
}
public static ClassType getFloat() {
return FLOAT;
}
public static ClassType getChar() {
return CHAR;
}
public static ClassType getBoolean() {
return BOOLEAN;
}
public static ClassType getString() {
return STRING;
}
public static ClassType getByte() {
return BYTE;
}
public static ClassType getShort() {
return SHORT;
}
public static TupleType getUnit() {
return UNIT;
}
public static Type getAny() {
return ANY_TYPE;
}
}
@@ -15,6 +15,8 @@ import java.util.Map;
* @author abreslav * @author abreslav
*/ */
public class JetTypeChecker { public class JetTypeChecker {
public static final JetTypeChecker INSTANCE = new JetTypeChecker();
public Type getType(JetExpression expression) { public Type getType(JetExpression expression) {
final Type[] result = new Type[1]; final Type[] result = new Type[1];
expression.accept(new JetVisitor() { expression.accept(new JetVisitor() {
@@ -22,24 +24,26 @@ public class JetTypeChecker {
public void visitConstantExpression(JetConstantExpression expression) { public void visitConstantExpression(JetConstantExpression expression) {
IElementType elementType = expression.getNode().getElementType(); IElementType elementType = expression.getNode().getElementType();
if (elementType == JetNodeTypes.INTEGER_CONSTANT) { if (elementType == JetNodeTypes.INTEGER_CONSTANT) {
result[0] = JetStandardTypes.getInt(); result[0] = JetStandardClasses.getIntType();
} else if (elementType == JetNodeTypes.LONG_CONSTANT) { } else if (elementType == JetNodeTypes.LONG_CONSTANT) {
result[0] = JetStandardTypes.getLong(); result[0] = JetStandardClasses.getLongType();
} else if (elementType == JetNodeTypes.FLOAT_CONSTANT) { } else if (elementType == JetNodeTypes.FLOAT_CONSTANT) {
String text = expression.getText(); String text = expression.getText();
assert text.length() > 0; assert text.length() > 0;
char lastChar = text.charAt(text.length() - 1); char lastChar = text.charAt(text.length() - 1);
if (lastChar == 'f' || lastChar == 'F') { if (lastChar == 'f' || lastChar == 'F') {
result[0] = JetStandardTypes.getFloat(); result[0] = JetStandardClasses.getFloatType();
} else { } else {
result[0] = JetStandardTypes.getDouble(); result[0] = JetStandardClasses.getDoubleType();
} }
} else if (elementType == JetNodeTypes.BOOLEAN_CONSTANT) { } else if (elementType == JetNodeTypes.BOOLEAN_CONSTANT) {
result[0] = JetStandardTypes.getBoolean(); result[0] = JetStandardClasses.getBooleanType();
} else if (elementType == JetNodeTypes.CHARACTER_CONSTANT) { } else if (elementType == JetNodeTypes.CHARACTER_CONSTANT) {
result[0] = JetStandardTypes.getChar(); result[0] = JetStandardClasses.getCharType();
} else if (elementType == JetNodeTypes.STRING_CONSTANT) { } else if (elementType == JetNodeTypes.STRING_CONSTANT) {
result[0] = JetStandardTypes.getString(); result[0] = JetStandardClasses.getStringType();
} else if (elementType == JetNodeTypes.NULL) {
result[0] = JetStandardClasses.getNullableNothingType();
} else { } else {
throw new IllegalArgumentException("Unsupported constant: " + expression); throw new IllegalArgumentException("Unsupported constant: " + expression);
} }
@@ -52,7 +56,7 @@ public class JetTypeChecker {
for (JetExpression entry : entries) { for (JetExpression entry : entries) {
types.add(getType(entry)); types.add(getType(entry));
} }
result[0] = TupleType.getTupleType(types); result[0] = JetStandardClasses.getTupleType(types);
} }
@Override @Override
@@ -68,8 +72,10 @@ public class JetTypeChecker {
} }
public boolean isSubtypeOf(Type subtype, Type supertype) { public boolean isSubtypeOf(Type subtype, Type supertype) {
@Nullable if (!supertype.isNullable() && subtype.isNullable()) {
Type closestSupertype = findCorrespondingSupertype(subtype, supertype); return false;
}
@Nullable Type closestSupertype = findCorrespondingSupertype(subtype, supertype);
if (closestSupertype == null) { if (closestSupertype == null) {
return false; return false;
} }
@@ -95,30 +101,24 @@ public class JetTypeChecker {
} }
private Type substituteForParameters(Type context, Type subject) { private Type substituteForParameters(Type context, Type subject) {
Map<TypeParameterDescriptor, TypeProjection> parameterValues = new HashMap<TypeParameterDescriptor, TypeProjection>(); Map<TypeConstructor, TypeProjection> parameterValues = new HashMap<TypeConstructor, TypeProjection>();
List<TypeParameterDescriptor> parameters = context.getConstructor().getParameters(); List<TypeParameterDescriptor> parameters = context.getConstructor().getParameters();
List<TypeProjection> contextArguments = context.getArguments(); List<TypeProjection> contextArguments = context.getArguments();
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
TypeParameterDescriptor parameter = parameters.get(i); TypeParameterDescriptor parameter = parameters.get(i);
TypeProjection value = contextArguments.get(i); TypeProjection value = contextArguments.get(i);
parameterValues.put(parameter, value); parameterValues.put(parameter.getTypeConstructor(), value);
} }
return substitute(parameterValues, subject); return substitute(parameterValues, subject);
} }
@NotNull @NotNull
private Type substitute(Map<TypeParameterDescriptor, TypeProjection> parameterValues, Type subject) { private Type substitute(Map<TypeConstructor, TypeProjection> parameterValues, Type subject) {
if (subject instanceof TypeVariable) { TypeProjection value = parameterValues.get(subject.getConstructor());
TypeVariable typeVariable = (TypeVariable) subject; if (value != null) {
TypeProjection value = parameterValues.get(typeVariable.getTypeParameterDescriptor()); return value.getType();
if (value == null) {
return typeVariable;
}
Type type = value.getType();
assert type != null;
return type;
} }
List<TypeProjection> newArguments = new ArrayList<TypeProjection>(); List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
for (TypeProjection argument : subject.getArguments()) { for (TypeProjection argument : subject.getArguments()) {
@@ -128,13 +128,7 @@ public class JetTypeChecker {
} }
private Type specializeType(Type type, List<TypeProjection> newArguments) { private Type specializeType(Type type, List<TypeProjection> newArguments) {
return type.accept(new TypeVisitor<Type, List<TypeProjection>>() { return new TypeImpl(type.getAttributes(), type.getConstructor(), type.isNullable(), newArguments, type.getMemberDomain());
@Override
public Type visitClassType(ClassType classType, List<TypeProjection> newArguments) {
return new ClassType(classType.getAttributes(), classType.getClassDescriptor(), newArguments);
}
}, newArguments);
} }
private boolean checkSubtypeForTheSameConstructor(Type subtype, Type supertype) { private boolean checkSubtypeForTheSameConstructor(Type subtype, Type supertype) {
@@ -212,7 +206,7 @@ public class JetTypeChecker {
return true; return true;
} }
private boolean equalTypes(Type type1, Type type2) { public boolean equalTypes(Type type1, Type type2) {
if (!type1.getConstructor().equals(type2.getConstructor())) { if (!type1.getConstructor().equals(type2.getConstructor())) {
return false; return false;
} }
@@ -1,46 +0,0 @@
package org.jetbrains.jet.lang.types;
import java.util.*;
/**
* @author abreslav
*/
public class NothingType extends TypeImpl {
public static final TypeConstructor NOTHING = new TypeConstructor(
Collections.<Attribute>emptyList(),
"Nothing",
Collections.<TypeParameterDescriptor>emptyList(),
new AbstractCollection<Type>() {
@Override
public boolean contains(Object o) {
return o instanceof Type;
}
@Override
public Iterator<Type> iterator() {
throw new UnsupportedOperationException();
}
@Override
public int size() {
throw new UnsupportedOperationException();
}
});
// TODO: attributes seem wrong here
public NothingType(List<Attribute> attributes) {
super(attributes, NOTHING, Collections.<TypeProjection>emptyList());
}
@Override
public Collection<MemberDescriptor> getMembers() {
return Collections.emptySet();
}
@Override
public <R, D> R accept(TypeVisitor<R, D> visitor, D data) {
return visitor.visitNothingType(this, data);
}
}
@@ -1,33 +0,0 @@
package org.jetbrains.jet.lang.types;
import java.util.Collection;
import java.util.List;
/**
* @author abreslav
*/
public class NullableType extends VisitableTypeImpl {
public NullableType(List<Attribute> attributes) {
super(attributes);
}
@Override
public TypeConstructor getConstructor() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public List<TypeProjection> getArguments() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public Collection<MemberDescriptor> getMembers() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public <R, D> R accept(TypeVisitor<R, D> visitor, D data) {
return visitor.visitNullableType(this, data);
}
}
@@ -1,33 +0,0 @@
package org.jetbrains.jet.lang.types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
*/
public class ThisType extends TypeImpl {
public ThisType(List<Attribute> attributes, ClassDescriptor thisClass) {
super(attributes, thisClass.getTypeConstructor(), toArguments(thisClass.getTypeConstructor().getParameters()));
}
private static List<TypeProjection> toArguments(List<TypeParameterDescriptor> parameters) {
List<TypeProjection> result = new ArrayList<TypeProjection>();
for (TypeParameterDescriptor parameter : parameters) {
result.add(new TypeProjection(new TypeVariable(Collections.<Attribute>emptyList(), parameter)));
}
return result;
}
@Override
public Collection<MemberDescriptor> getMembers() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public <R, D> R accept(TypeVisitor<R, D> visitor, D data) {
return visitor.visitThisType(this, data);
}
}
@@ -1,66 +0,0 @@
package org.jetbrains.jet.lang.types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
*/
public class TupleType extends TypeImpl {
public static final TupleType UNIT = new TupleType(Collections.<Attribute>emptyList(), Collections.<Type>emptyList());
public static TupleType getTupleType(List<Attribute> attributes, List<Type> arguments) {
if (attributes.isEmpty() && arguments.isEmpty()) {
return UNIT;
}
return new TupleType(attributes, arguments);
}
public static TupleType getTupleType(List<Type> arguments) {
return getTupleType(Collections.<Attribute>emptyList(), arguments);
}
public static TupleType getLabeledTupleType(List<Attribute> attributes, List<ParameterDescriptor> arguments) {
return getTupleType(attributes, toTypes(arguments));
}
public static TupleType getLabeledTupleType(List<ParameterDescriptor> arguments) {
return getLabeledTupleType(Collections.<Attribute>emptyList(), arguments);
}
private TupleType(List<Attribute> attributes, List<Type> arguments) {
super(attributes, JetStandardClasses.getTuple(arguments.size()).getTypeConstructor(), toProjections(arguments));
}
@Override
public Collection<MemberDescriptor> getMembers() {
throw new UnsupportedOperationException("Not implemented"); // TODO
}
@Override
public <R, D> R accept(TypeVisitor<R, D> visitor, D data) {
return visitor.visitTupleType(this, data);
}
private static List<TypeProjection> toProjections(List<Type> arguments) {
List<TypeProjection> result = new ArrayList<TypeProjection>();
for (Type argument : arguments) {
result.add(new TypeProjection(ProjectionKind.OUT_ONLY, argument));
}
return result;
}
private static List<Type> toTypes(List<ParameterDescriptor> labeledEntries) {
List<Type> result = new ArrayList<Type>();
for (ParameterDescriptor entry : labeledEntries) {
result.add(entry.getType());
}
return result;
}
}
@@ -1,18 +1,18 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import java.util.Collection; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
/** /**
* @author abreslav * @author abreslav
*/ */
public interface Type extends Annotated { public interface Type extends Annotated {
TypeConstructor getConstructor(); @NotNull TypeConstructor getConstructor();
List<TypeProjection> getArguments(); @NotNull List<TypeProjection> getArguments();
boolean isNullable();
Collection<MemberDescriptor> getMembers(); @NotNull TypeMemberDomain getMemberDomain();
<R, D> R accept(TypeVisitor<R, D> visitor, D data); @NotNull Type getNullableVersion();
<R> R acceptNoData(TypeVisitor<R, ?> visitor);
void acceptVoid(TypeVisitor<?, ?> visitor);
} }
@@ -1,20 +1,38 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
/** /**
* @author abreslav * @author abreslav
*/ */
public abstract class TypeImpl extends VisitableTypeImpl { public final class TypeImpl extends AnnotatedImpl implements Type {
private final TypeConstructor constructor; private final TypeConstructor constructor;
private final List<TypeProjection> arguments; private final List<TypeProjection> arguments;
private final boolean nullable;
private final TypeMemberDomain memberDomain;
public TypeImpl(List<Attribute> attributes, TypeConstructor constructor, List<TypeProjection> arguments) { public TypeImpl(List<Attribute> attributes, TypeConstructor constructor, boolean nullable, List<TypeProjection> arguments, TypeMemberDomain memberDomain) {
super(attributes); super(attributes);
this.constructor = constructor; this.constructor = constructor;
this.nullable = nullable;
this.arguments = arguments; this.arguments = arguments;
this.memberDomain = memberDomain;
}
public TypeImpl(TypeConstructor constructor, TypeMemberDomain memberDomain) {
this(Collections.<Attribute>emptyList(), constructor, false, Collections.<TypeProjection>emptyList(), memberDomain);
}
@Override
public Type getNullableVersion() {
if (isNullable()) {
return this;
}
// TODO: cache these?
return new TypeImpl(getAttributes(), constructor, true, arguments, memberDomain);
} }
@Override @Override
@@ -27,9 +45,19 @@ public abstract class TypeImpl extends VisitableTypeImpl {
return arguments; return arguments;
} }
@Override
public boolean isNullable() {
return nullable;
}
@Override
public TypeMemberDomain getMemberDomain() {
return memberDomain;
}
@Override @Override
public String toString() { public String toString() {
return constructor + (arguments.isEmpty() ? "" : "<" + argumentsToString() + ">"); return constructor + (arguments.isEmpty() ? "" : "<" + argumentsToString() + ">") + (isNullable() ? "?" : "");
} }
private StringBuilder argumentsToString() { private StringBuilder argumentsToString() {
@@ -0,0 +1,19 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author abreslav
*/
public interface TypeMemberDomain {
TypeMemberDomain EMPTY = new TypeMemberDomain() {
@Override
public ClassDescriptor getClassDescriptor(@NotNull Type type) {
return null;
}
};
@Nullable ClassDescriptor getClassDescriptor(@NotNull Type type);
// ...
}
@@ -19,7 +19,7 @@ public class TypeParameterDescriptor extends NamedAnnotatedImpl {
// TODO: Should we actually pass the attributes on to the type constructor? // TODO: Should we actually pass the attributes on to the type constructor?
this.typeConstructor = new TypeConstructor( this.typeConstructor = new TypeConstructor(
attributes, attributes,
name, "&" + name,
Collections.<TypeParameterDescriptor>emptyList(), Collections.<TypeParameterDescriptor>emptyList(),
upperBounds); upperBounds);
} }
@@ -35,4 +35,9 @@ public class TypeParameterDescriptor extends NamedAnnotatedImpl {
public TypeConstructor getTypeConstructor() { public TypeConstructor getTypeConstructor() {
return typeConstructor; return typeConstructor;
} }
@Override
public String toString() {
return typeConstructor.toString();
}
} }
@@ -1,40 +0,0 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
*/
public class TypeVariable extends TypeImpl {
private final TypeParameterDescriptor typeParameterDescriptor;
public TypeVariable(@NotNull List<Attribute> attributes, @NotNull TypeParameterDescriptor typeParameter) {
super(attributes, typeParameter.getTypeConstructor(), Collections.<TypeProjection>emptyList());
this.typeParameterDescriptor = typeParameter;
}
public TypeParameterDescriptor getTypeParameterDescriptor() {
return typeParameterDescriptor;
}
@Override
public Collection<MemberDescriptor> getMembers() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public <R, D> R accept(TypeVisitor<R, D> visitor, D data) {
return visitor.visitTypeVariable(this, data);
}
@Override
public String toString() {
return "&" + super.toString();
}
}
@@ -1,38 +0,0 @@
package org.jetbrains.jet.lang.types;
/**
* @author abreslav
*/
public class TypeVisitor<R, D> {
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 visitErrorType(ErrorType errorType, D data) {
return visitType(errorType, data);
}
public R visitNullableType(NullableType nullableType, D data) {
return visitType(nullableType, data);
}
public R visitType(Type type, D data) {
throw new UnsupportedOperationException(); // TODO
}
}
@@ -1,22 +0,0 @@
package org.jetbrains.jet.lang.types;
import java.util.List;
/**
* @author abreslav
*/
public abstract class VisitableTypeImpl extends AnnotatedImpl implements Type {
public VisitableTypeImpl(List<Attribute> attributes) {
super(attributes);
}
@Override
public <R> R acceptNoData(TypeVisitor<R, ?> visitor) {
return accept(visitor, null);
}
@Override
public void acceptVoid(TypeVisitor<?, ?> visitor) {
accept(visitor, null);
}
}
@@ -29,33 +29,41 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
} }
public void testConstants() throws Exception { public void testConstants() throws Exception {
assertType("1", JetStandardTypes.getInt()); assertType("1", JetStandardClasses.getIntType());
assertType("0x1", JetStandardTypes.getInt()); assertType("0x1", JetStandardClasses.getIntType());
assertType("0X1", JetStandardTypes.getInt()); assertType("0X1", JetStandardClasses.getIntType());
assertType("0b1", JetStandardTypes.getInt()); assertType("0b1", JetStandardClasses.getIntType());
assertType("0B1", JetStandardTypes.getInt()); assertType("0B1", JetStandardClasses.getIntType());
assertType("1l", JetStandardTypes.getLong()); assertType("1l", JetStandardClasses.getLongType());
assertType("1L", JetStandardTypes.getLong()); assertType("1L", JetStandardClasses.getLongType());
assertType("1.0", JetStandardTypes.getDouble()); assertType("1.0", JetStandardClasses.getDoubleType());
assertType("1.0d", JetStandardTypes.getDouble()); assertType("1.0d", JetStandardClasses.getDoubleType());
assertType("1.0D", JetStandardTypes.getDouble()); assertType("1.0D", JetStandardClasses.getDoubleType());
assertType("0x1.fffffffffffffp1023", JetStandardTypes.getDouble()); assertType("0x1.fffffffffffffp1023", JetStandardClasses.getDoubleType());
assertType("1.0f", JetStandardTypes.getFloat()); assertType("1.0f", JetStandardClasses.getFloatType());
assertType("1.0F", JetStandardTypes.getFloat()); assertType("1.0F", JetStandardClasses.getFloatType());
assertType("0x1.fffffffffffffp1023f", JetStandardTypes.getFloat()); assertType("0x1.fffffffffffffp1023f", JetStandardClasses.getFloatType());
assertType("true", JetStandardTypes.getBoolean()); assertType("true", JetStandardClasses.getBooleanType());
assertType("false", JetStandardTypes.getBoolean()); assertType("false", JetStandardClasses.getBooleanType());
assertType("'d'", JetStandardTypes.getChar()); assertType("'d'", JetStandardClasses.getCharType());
assertType("\"d\"", JetStandardTypes.getString()); assertType("\"d\"", JetStandardClasses.getStringType());
assertType("\"\"\"d\"\"\"", JetStandardTypes.getString()); assertType("\"\"\"d\"\"\"", JetStandardClasses.getStringType());
assertType("()", JetStandardTypes.getUnit()); assertType("()", JetStandardClasses.getUnitType());
assertType("null", JetStandardClasses.getNullableNothingType());
}
public void testTupleConstants() throws Exception {
assertType("()", JetStandardClasses.getUnitType());
assertType("(1, 'a')", JetStandardClasses.getTupleType(JetStandardClasses.getIntType(), JetStandardClasses.getCharType()));
} }
public void testBasicSubtyping() throws Exception { public void testBasicSubtyping() throws Exception {
@@ -170,7 +178,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
} }
public void testImplicitConversions() throws Exception { public void testImplicitConversions() throws Exception {
assertConvertibleTo("1", JetStandardTypes.getByte()); assertConvertibleTo("1", JetStandardClasses.getByteType());
} }
private static void assertSubtype(String type1, String type2) { private static void assertSubtype(String type1, String type2) {
@@ -184,7 +192,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
private static void assertSubtypingRelation(String type1, String type2, boolean expected) { private static void assertSubtypingRelation(String type1, String type2, boolean expected) {
Type typeNode1 = TypeResolver.INSTANCE.resolveType(ClassDefinitions.BASIC_SCOPE, JetChangeUtil.createType(getProject(), type1)); Type typeNode1 = TypeResolver.INSTANCE.resolveType(ClassDefinitions.BASIC_SCOPE, JetChangeUtil.createType(getProject(), type1));
Type typeNode2 = TypeResolver.INSTANCE.resolveType(ClassDefinitions.BASIC_SCOPE, JetChangeUtil.createType(getProject(), type2)); Type typeNode2 = TypeResolver.INSTANCE.resolveType(ClassDefinitions.BASIC_SCOPE, JetChangeUtil.createType(getProject(), type2));
boolean result = new JetTypeChecker().isSubtypeOf( boolean result = JetTypeChecker.INSTANCE.isSubtypeOf(
typeNode1, typeNode1,
typeNode2); typeNode2);
String modifier = expected ? "not " : ""; String modifier = expected ? "not " : "";
@@ -195,21 +203,21 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression); JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression);
assertTrue( assertTrue(
expression + " must be convertible to " + type, expression + " must be convertible to " + type,
new JetTypeChecker().isConvertibleTo(jetExpression, type)); JetTypeChecker.INSTANCE.isConvertibleTo(jetExpression, type));
} }
private static void assertNotConvertibleTo(String expression, Type type) { private static void assertNotConvertibleTo(String expression, Type type) {
JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression); JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression);
assertFalse( assertFalse(
expression + " must not be convertible to " + type, expression + " must not be convertible to " + type,
new JetTypeChecker().isConvertibleTo(jetExpression, type)); JetTypeChecker.INSTANCE.isConvertibleTo(jetExpression, type));
} }
private static void assertType(String expression, Type expectedType) { private static void assertType(String expression, Type expectedType) {
Project project = getProject(); Project project = getProject();
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression); JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
Type type = new JetTypeChecker().getType(jetExpression); Type type = JetTypeChecker.INSTANCE.getType(jetExpression);
assertEquals(type, expectedType); assertTrue(type + "!=" + expectedType, JetTypeChecker.INSTANCE.equalTypes(type, expectedType));
} }
private static class ClassDefinitions { private static class ClassDefinitions {