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 DOUBLE = new ClassDescriptor("Double");
|
||||||
private static final ClassDescriptor BOOLEAN = new ClassDescriptor("Boolean");
|
private static final ClassDescriptor BOOLEAN = new ClassDescriptor("Boolean");
|
||||||
private static final ClassDescriptor STRING = new ClassDescriptor("String");
|
private static final ClassDescriptor STRING = new ClassDescriptor("String");
|
||||||
private static final ClassDescriptor UNIT = new ClassDescriptor("Unit");
|
|
||||||
|
|
||||||
public static final int TUPLE_COUNT = 22;
|
public static final int TUPLE_COUNT = 22;
|
||||||
private static final ClassDescriptor[] TUPLE = new ClassDescriptor[TUPLE_COUNT];
|
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) {
|
private Type substitute(Map<TypeParameterDescriptor, TypeProjection> parameterValues, Type subject) {
|
||||||
List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
|
List<TypeProjection> newArguments = new ArrayList<TypeProjection>();
|
||||||
for (TypeProjection argument : subject.getArguments()) {
|
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);
|
return specializeType(subject, newArguments);
|
||||||
}
|
}
|
||||||
@@ -121,10 +121,82 @@ public class JetTypeChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkSubtypeForTheSameConstructor(Type subtype, Type supertype) {
|
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;
|
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) {
|
private static List<TypeProjection> toProjections(List<Type> arguments) {
|
||||||
List<TypeProjection> result = new ArrayList<TypeProjection>();
|
List<TypeProjection> result = new ArrayList<TypeProjection>();
|
||||||
for (Type argument : arguments) {
|
for (Type argument : arguments) {
|
||||||
result.add(new TypeProjection(Variance.OUT_VARIANCE, argument));
|
result.add(new TypeProjection(ProjectionKind.OUT_ONLY, argument));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,19 +4,19 @@ package org.jetbrains.jet.lang.types;
|
|||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class TypeProjection {
|
public class TypeProjection {
|
||||||
private final Variance projection;
|
private final ProjectionKind projection;
|
||||||
private final Type type;
|
private final Type type;
|
||||||
|
|
||||||
public TypeProjection(Variance projection, Type type) {
|
public TypeProjection(ProjectionKind projection, Type type) {
|
||||||
this.projection = projection;
|
this.projection = projection;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeProjection(Type type) {
|
public TypeProjection(Type type) {
|
||||||
this(Variance.INVARIANT, type);
|
this(ProjectionKind.NO_PROJECTION, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Variance getProjection() {
|
public ProjectionKind getProjectionKind() {
|
||||||
return projection;
|
return projection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,10 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
|||||||
assertSubtype("(Double)", "(Double)");
|
assertSubtype("(Double)", "(Double)");
|
||||||
assertSubtype("(Unit)", "(Unit)");
|
assertSubtype("(Unit)", "(Unit)");
|
||||||
|
|
||||||
|
assertNotSubtype("(Unit)", "(Int)");
|
||||||
|
|
||||||
|
assertSubtype("(Unit)", "(Any)");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertSubtype(String type1, String type2) {
|
private void assertSubtype(String type1, String type2) {
|
||||||
@@ -153,10 +157,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
|||||||
JetTypeElement typeElement = typeNode.getTypeElement();
|
JetTypeElement typeElement = typeNode.getTypeElement();
|
||||||
List<JetTypeReference> argumentElements = typeNode.getTypeArguments();
|
List<JetTypeReference> argumentElements = typeNode.getTypeArguments();
|
||||||
|
|
||||||
final List<Type> arguments = new ArrayList<Type>();
|
final List<Type> arguments = toTypes(argumentElements);
|
||||||
for (JetTypeReference argumentElement : argumentElements) {
|
|
||||||
arguments.add(toType(argumentElement));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO annotations
|
// TODO annotations
|
||||||
final Type[] result = new Type[1];
|
final Type[] result = new Type[1];
|
||||||
@@ -169,7 +170,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
|||||||
@Override
|
@Override
|
||||||
public void visitTupleType(JetTupleType type) {
|
public void visitTupleType(JetTupleType type) {
|
||||||
// TODO labels
|
// TODO labels
|
||||||
result[0] = TupleType.getTupleType(arguments);
|
result[0] = TupleType.getTupleType(toTypes(type.getComponentTypeRefs()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -181,6 +182,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
|||||||
return result[0];
|
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 {
|
public void testImplicitConversions() throws Exception {
|
||||||
assertConvertibleTo("1", JetStandardTypes.getByte());
|
assertConvertibleTo("1", JetStandardTypes.getByte());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user