diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index eb7f92b8326..ccfe80570a6 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -134,68 +134,64 @@ public class JetTypeChecker { Type subArgumentType = subArgument.getType(); Type superArgumentType = superArgument.getType(); - switch (parameter.getVariance()) { - case INVARIANT: - switch (superArgument.getProjectionKind()) { - case NO_PROJECTION: - if (!equalTypes(subArgumentType, 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)) { + if (superArgument.getProjectionKind() != ProjectionKind.NEITHER_OUT_NOR_IN) { + switch (parameter.getVariance()) { + case INVARIANT: + switch (superArgument.getProjectionKind()) { + case NO_PROJECTION: + if (!equalTypes(subArgumentType, superArgumentType)) { return false; - } - break; - case NEITHER_OUT_NOR_IN: - case OUT_ONLY: - if (!isSubtypeOf(subArgumentType, superArgumentType)) { + } + break; + case OUT_ONLY: + if (!subArgument.getProjectionKind().allowsOutCalls()) { 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)) { + } + if (!isSubtypeOf(subArgumentType, superArgumentType)) { return false; - } - break; - } - break; + } + break; + case IN_ONLY: + 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; } diff --git a/idea/src/org/jetbrains/jet/lang/types/ProjectionKind.java b/idea/src/org/jetbrains/jet/lang/types/ProjectionKind.java index ea5d5b2c26a..14b1c08cea1 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ProjectionKind.java +++ b/idea/src/org/jetbrains/jet/lang/types/ProjectionKind.java @@ -4,15 +4,28 @@ package org.jetbrains.jet.lang.types; * @author abreslav */ public enum ProjectionKind { - OUT_ONLY("out"), - IN_ONLY("in"), - NEITHER_OUT_NOR_IN("*"), - NO_PROJECTION(""); + OUT_ONLY("out", false, true), + IN_ONLY("in", true, false), + NEITHER_OUT_NOR_IN("*", false, false), + NO_PROJECTION("", true, true); 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.allowsInCalls = allowsInCalls; + this.allowsOutCalls = allowsOutCalls; + + } + + public boolean allowsInCalls() { + return allowsInCalls; + } + + public boolean allowsOutCalls() { + return allowsOutCalls; } @Override diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index beeb3550993..25762ddcfc8 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -126,10 +126,6 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { assertSubtype("Float", "Float"); assertSubtype("Double", "Double"); assertSubtype("Unit", "Unit"); - assertSubtype("Unit", "()"); - assertSubtype("()", "Unit"); - assertSubtype("()", "()"); - assertSubtype("Boolean", "Any"); assertSubtype("Byte", "Any"); assertSubtype("Char", "Any"); @@ -150,6 +146,12 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { assertNotSubtype("Float", "Double"); assertNotSubtype("Double", "Int"); assertNotSubtype("Unit", "Int"); + } + + public void testTuples() throws Exception { + assertSubtype("Unit", "()"); + assertSubtype("()", "Unit"); + assertSubtype("()", "()"); assertSubtype("(Boolean)", "(Boolean)"); assertSubtype("(Byte)", "(Byte)"); @@ -183,6 +185,36 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { public void testProjections() throws Exception { assertSubtype("Base_T", "Base_T"); + assertNotSubtype("Base_T", "Base_T"); + + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + assertNotSubtype("Base_inT", "Base_inT"); + + assertSubtype("Base_outT", "Base_outT"); + assertSubtype("Base_outT", "Base_outT"); + assertNotSubtype("Base_outT", "Base_outT"); + + assertSubtype("Base_T", "Base_T"); + assertSubtype("Base_T", "Base_T"); + + assertSubtype("Base_T", "Base_T"); + assertSubtype("Base_T", "Base_T"); + + assertSubtype("Base_inT", "Base_inT"); + assertSubtype("Base_inT", "Base_inT"); + + assertSubtype("Base_outT", "Base_outT"); + assertSubtype("Base_outT", "Base_outT"); + + assertSubtype("Base_T", "Base_T<*>"); + assertSubtype("Base_T<*>", "Base_T<*>"); + assertSubtype("Base_T", "Base_T"); + assertSubtype("Base_T", "Base_T"); + + assertNotSubtype("Base_T", "Base_T"); + assertNotSubtype("Base_T", "Base_T"); + assertNotSubtype("Base_T<*>", "Base_T"); } public void testImplicitConversions() throws Exception { @@ -295,8 +327,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { private static List toTypeProjections(List argumentElements) { final List arguments = new ArrayList(); for (JetTypeProjection argumentElement : argumentElements) { - Type type = toType(argumentElement.getTypeReference()); - TypeProjection typeProjection = new TypeProjection(argumentElement.getProjectionKind(), type); + ProjectionKind projectionKind = argumentElement.getProjectionKind(); + 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); } return arguments;