Subtyping tests with projections works

This commit is contained in:
Andrey Breslav
2011-01-26 18:49:57 +03:00
parent 1a6f7f5f79
commit d80d3a628d
3 changed files with 115 additions and 68 deletions
@@ -134,68 +134,64 @@ public class JetTypeChecker {
Type subArgumentType = subArgument.getType(); Type subArgumentType = subArgument.getType();
Type superArgumentType = superArgument.getType(); Type superArgumentType = superArgument.getType();
switch (parameter.getVariance()) { if (superArgument.getProjectionKind() != ProjectionKind.NEITHER_OUT_NOR_IN) {
case INVARIANT: switch (parameter.getVariance()) {
switch (superArgument.getProjectionKind()) { case INVARIANT:
case NO_PROJECTION: switch (superArgument.getProjectionKind()) {
if (!equalTypes(subArgumentType, superArgumentType)) { case NO_PROJECTION:
return false; if (!equalTypes(subArgumentType, superArgumentType)) {
}
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; return false;
} }
break; break;
case NEITHER_OUT_NOR_IN: case OUT_ONLY:
case OUT_ONLY: if (!subArgument.getProjectionKind().allowsOutCalls()) {
if (!isSubtypeOf(subArgumentType, superArgumentType)) {
return false; return false;
} }
break; if (!isSubtypeOf(subArgumentType, superArgumentType)) {
}
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; return false;
} }
break; break;
} case IN_ONLY:
break; if (!subArgument.getProjectionKind().allowsInCalls()) {
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 OUT_ONLY:
if (!isSubtypeOf(subArgumentType, superArgumentType)) {
return false;
}
break;
}
break;
case OUT_VARIANCE:
switch (superArgument.getProjectionKind()) {
case NO_PROJECTION:
case OUT_ONLY:
case IN_ONLY:
if (!isSubtypeOf(subArgumentType, superArgumentType)) {
return false;
}
break;
}
break;
}
} else {
// C< anything > is always a subtype of C<*>
} }
} }
return true; return true;
} }
@@ -4,15 +4,28 @@ package org.jetbrains.jet.lang.types;
* @author abreslav * @author abreslav
*/ */
public enum ProjectionKind { public enum ProjectionKind {
OUT_ONLY("out"), OUT_ONLY("out", false, true),
IN_ONLY("in"), IN_ONLY("in", true, false),
NEITHER_OUT_NOR_IN("*"), NEITHER_OUT_NOR_IN("*", false, false),
NO_PROJECTION(""); NO_PROJECTION("", true, true);
private final String text; private final String text;
private final boolean allowsInCalls;
private final boolean allowsOutCalls;
ProjectionKind(String text) { ProjectionKind(String text, boolean allowsInCalls, boolean allowsOutCalls) {
this.text = text; this.text = text;
this.allowsInCalls = allowsInCalls;
this.allowsOutCalls = allowsOutCalls;
}
public boolean allowsInCalls() {
return allowsInCalls;
}
public boolean allowsOutCalls() {
return allowsOutCalls;
} }
@Override @Override
@@ -126,10 +126,6 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertSubtype("Float", "Float"); assertSubtype("Float", "Float");
assertSubtype("Double", "Double"); assertSubtype("Double", "Double");
assertSubtype("Unit", "Unit"); assertSubtype("Unit", "Unit");
assertSubtype("Unit", "()");
assertSubtype("()", "Unit");
assertSubtype("()", "()");
assertSubtype("Boolean", "Any"); assertSubtype("Boolean", "Any");
assertSubtype("Byte", "Any"); assertSubtype("Byte", "Any");
assertSubtype("Char", "Any"); assertSubtype("Char", "Any");
@@ -150,6 +146,12 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertNotSubtype("Float", "Double"); assertNotSubtype("Float", "Double");
assertNotSubtype("Double", "Int"); assertNotSubtype("Double", "Int");
assertNotSubtype("Unit", "Int"); assertNotSubtype("Unit", "Int");
}
public void testTuples() throws Exception {
assertSubtype("Unit", "()");
assertSubtype("()", "Unit");
assertSubtype("()", "()");
assertSubtype("(Boolean)", "(Boolean)"); assertSubtype("(Boolean)", "(Boolean)");
assertSubtype("(Byte)", "(Byte)"); assertSubtype("(Byte)", "(Byte)");
@@ -183,6 +185,36 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
public void testProjections() throws Exception { public void testProjections() throws Exception {
assertSubtype("Base_T<Int>", "Base_T<Int>"); assertSubtype("Base_T<Int>", "Base_T<Int>");
assertNotSubtype("Base_T<Int>", "Base_T<Any>");
assertSubtype("Base_inT<Int>", "Base_inT<Int>");
assertSubtype("Base_inT<Any>", "Base_inT<Int>");
assertNotSubtype("Base_inT<Int>", "Base_inT<Any>");
assertSubtype("Base_outT<Int>", "Base_outT<Int>");
assertSubtype("Base_outT<Int>", "Base_outT<Any>");
assertNotSubtype("Base_outT<Any>", "Base_outT<Int>");
assertSubtype("Base_T<Int>", "Base_T<out Any>");
assertSubtype("Base_T<Any>", "Base_T<in Int>");
assertSubtype("Base_T<out Int>", "Base_T<out Int>");
assertSubtype("Base_T<in Int>", "Base_T<in Int>");
assertSubtype("Base_inT<out Int>", "Base_inT<out Int>");
assertSubtype("Base_inT<in Int>", "Base_inT<in Int>");
assertSubtype("Base_outT<out Int>", "Base_outT<out Int>");
assertSubtype("Base_outT<in Int>", "Base_outT<in Int>");
assertSubtype("Base_T<Int>", "Base_T<*>");
assertSubtype("Base_T<*>", "Base_T<*>");
assertSubtype("Base_T<Int>", "Base_T<out Any>");
assertSubtype("Base_T<Any>", "Base_T<in Int>");
assertNotSubtype("Base_T<out Any>", "Base_T<in Int>");
assertNotSubtype("Base_T<in Int>", "Base_T<out Int>");
assertNotSubtype("Base_T<*>", "Base_T<out Int>");
} }
public void testImplicitConversions() throws Exception { public void testImplicitConversions() throws Exception {
@@ -295,8 +327,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
private static List<TypeProjection> toTypeProjections(List<JetTypeProjection> argumentElements) { private static List<TypeProjection> toTypeProjections(List<JetTypeProjection> argumentElements) {
final List<TypeProjection> arguments = new ArrayList<TypeProjection>(); final List<TypeProjection> arguments = new ArrayList<TypeProjection>();
for (JetTypeProjection argumentElement : argumentElements) { for (JetTypeProjection argumentElement : argumentElements) {
Type type = toType(argumentElement.getTypeReference()); ProjectionKind projectionKind = argumentElement.getProjectionKind();
TypeProjection typeProjection = new TypeProjection(argumentElement.getProjectionKind(), type); Type type;
if (projectionKind == ProjectionKind.NEITHER_OUT_NOR_IN) {
type = null;
} else {
type = toType(argumentElement.getTypeReference());
}
TypeProjection typeProjection = new TypeProjection(projectionKind, type);
arguments.add(typeProjection); arguments.add(typeProjection);
} }
return arguments; return arguments;