Subtyping for type constructor applications with projections
This commit is contained in:
@@ -28,7 +28,6 @@ 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];
|
||||
|
||||
@@ -110,7 +110,7 @@ public class JetTypeChecker {
|
||||
private Type substitute(Map<TypeParameterDescriptor, TypeProjection> parameterValues, Type subject) {
|
||||
List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
|
||||
for (TypeProjection argument : subject.getArguments()) {
|
||||
newArguments.add(new TypeProjection(argument.getProjection(), substitute(parameterValues, argument.getType())));
|
||||
newArguments.add(new TypeProjection(argument.getProjectionKind(), substitute(parameterValues, argument.getType())));
|
||||
}
|
||||
return specializeType(subject, newArguments);
|
||||
}
|
||||
@@ -121,10 +121,82 @@ public class JetTypeChecker {
|
||||
}
|
||||
|
||||
private boolean checkSubtypeForTheSameConstructor(Type subtype, Type supertype) {
|
||||
assert subtype.getConstructor().equals(supertype.getConstructor());
|
||||
TypeConstructor constructor = subtype.getConstructor();
|
||||
assert constructor.equals(supertype.getConstructor());
|
||||
|
||||
List<TypeProjection> subArguments = subtype.getArguments();
|
||||
List<TypeProjection> superArguments = supertype.getArguments();
|
||||
List<TypeParameterDescriptor> parameters = constructor.getParameters();
|
||||
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
|
||||
TypeParameterDescriptor parameter = parameters.get(i);
|
||||
TypeProjection subArgument = subArguments.get(i);
|
||||
TypeProjection superArgument = superArguments.get(i);
|
||||
|
||||
Type subArgumentType = subArgument.getType();
|
||||
Type superArgumentType = superArgument.getType();
|
||||
switch (parameter.getVariance()) {
|
||||
case INVARIANT:
|
||||
switch (superArgument.getProjectionKind()) {
|
||||
case NO_PROJECTION:
|
||||
if (!subArgumentType.equals(superArgumentType)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case NEITHER_OUT_NOR_IN:
|
||||
if (!isSubtypeOf(subArgumentType, superArgumentType)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OUT_ONLY:
|
||||
if (subArgument.getProjectionKind() != ProjectionKind.OUT_ONLY) {
|
||||
return false;
|
||||
}
|
||||
if (!isSubtypeOf(subArgumentType, superArgumentType)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case IN_ONLY:
|
||||
if (subArgument.getProjectionKind() != ProjectionKind.IN_ONLY) {
|
||||
return false;
|
||||
}
|
||||
if (!isSubtypeOf(superArgumentType, subArgumentType)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IN_VARIANCE:
|
||||
switch (superArgument.getProjectionKind()) {
|
||||
case NO_PROJECTION:
|
||||
case IN_ONLY:
|
||||
if (!isSubtypeOf(superArgumentType, subArgumentType)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case NEITHER_OUT_NOR_IN:
|
||||
case OUT_ONLY:
|
||||
if (!isSubtypeOf(subArgumentType, superArgumentType)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OUT_VARIANCE:
|
||||
switch (superArgument.getProjectionKind()) {
|
||||
case NO_PROJECTION:
|
||||
case OUT_ONLY:
|
||||
case NEITHER_OUT_NOR_IN:
|
||||
case IN_ONLY:
|
||||
if (!isSubtypeOf(subArgumentType, superArgumentType)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.jetbrains.jet.lang.types;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
*/
|
||||
public enum ProjectionKind {
|
||||
OUT_ONLY("out"),
|
||||
IN_ONLY("in"),
|
||||
NEITHER_OUT_NOR_IN("*"),
|
||||
NO_PROJECTION("");
|
||||
|
||||
private final String text;
|
||||
|
||||
ProjectionKind(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class TupleType extends TypeImpl {
|
||||
private static List<TypeProjection> toProjections(List<Type> arguments) {
|
||||
List<TypeProjection> result = new ArrayList<TypeProjection>();
|
||||
for (Type argument : arguments) {
|
||||
result.add(new TypeProjection(Variance.OUT_VARIANCE, argument));
|
||||
result.add(new TypeProjection(ProjectionKind.OUT_ONLY, argument));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@ package org.jetbrains.jet.lang.types;
|
||||
* @author abreslav
|
||||
*/
|
||||
public class TypeProjection {
|
||||
private final Variance projection;
|
||||
private final ProjectionKind projection;
|
||||
private final Type type;
|
||||
|
||||
public TypeProjection(Variance projection, Type type) {
|
||||
public TypeProjection(ProjectionKind projection, Type type) {
|
||||
this.projection = projection;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public TypeProjection(Type type) {
|
||||
this(Variance.INVARIANT, type);
|
||||
this(ProjectionKind.NO_PROJECTION, type);
|
||||
}
|
||||
|
||||
public Variance getProjection() {
|
||||
public ProjectionKind getProjectionKind() {
|
||||
return projection;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,10 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
assertSubtype("(Double)", "(Double)");
|
||||
assertSubtype("(Unit)", "(Unit)");
|
||||
|
||||
assertNotSubtype("(Unit)", "(Int)");
|
||||
|
||||
assertSubtype("(Unit)", "(Any)");
|
||||
|
||||
}
|
||||
|
||||
private void assertSubtype(String type1, String type2) {
|
||||
@@ -153,10 +157,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
JetTypeElement typeElement = typeNode.getTypeElement();
|
||||
List<JetTypeReference> argumentElements = typeNode.getTypeArguments();
|
||||
|
||||
final List<Type> arguments = new ArrayList<Type>();
|
||||
for (JetTypeReference argumentElement : argumentElements) {
|
||||
arguments.add(toType(argumentElement));
|
||||
}
|
||||
final List<Type> arguments = toTypes(argumentElements);
|
||||
|
||||
// TODO annotations
|
||||
final Type[] result = new Type[1];
|
||||
@@ -169,7 +170,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
@Override
|
||||
public void visitTupleType(JetTupleType type) {
|
||||
// TODO labels
|
||||
result[0] = TupleType.getTupleType(arguments);
|
||||
result[0] = TupleType.getTupleType(toTypes(type.getComponentTypeRefs()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -181,6 +182,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
return result[0];
|
||||
}
|
||||
|
||||
private List<Type> toTypes(List<JetTypeReference> argumentElements) {
|
||||
final List<Type> arguments = new ArrayList<Type>();
|
||||
for (JetTypeReference argumentElement : argumentElements) {
|
||||
arguments.add(toType(argumentElement));
|
||||
}
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public void testImplicitConversions() throws Exception {
|
||||
assertConvertibleTo("1", JetStandardTypes.getByte());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user