Subtyping tests with projections works
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user