diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java index debad9b6218..3018bb09ead 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/checker/TypeCheckingProcedure.java @@ -48,12 +48,12 @@ public class TypeCheckingProcedure { return null; } - private static JetType getOutType(TypeParameterDescriptor parameter, TypeProjection argument) { + public static JetType getOutType(TypeParameterDescriptor parameter, TypeProjection argument) { boolean isOutProjected = argument.getProjectionKind() == IN_VARIANCE || parameter.getVariance() == IN_VARIANCE; return isOutProjected ? parameter.getUpperBoundsAsType() : argument.getType(); } - private static JetType getInType(TypeParameterDescriptor parameter, TypeProjection argument) { + public static JetType getInType(TypeParameterDescriptor parameter, TypeProjection argument) { boolean isOutProjected = argument.getProjectionKind() == OUT_VARIANCE || parameter.getVariance() == OUT_VARIANCE; return isOutProjected ? KotlinBuiltIns.getInstance().getNothingType() : argument.getType(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 4622569ba9f..f88184d67b7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -45,6 +45,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; +import org.jetbrains.jet.lang.types.checker.TypeCheckingProcedure; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lexer.JetTokens; @@ -293,23 +294,30 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return false; } - List superTypeParameters = supertype.getConstructor().getParameters(); + List superParameters = supertype.getConstructor().getParameters(); { Multimap subtypeSubstitutionMap = SubstitutionUtils.buildDeepSubstitutionMultimap(subtype); - for (int i = 0; i < superTypeParameters.size(); i++) { - TypeProjection superTypeArgument = supertype.getArguments().get(i); - TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i); + for (int i = 0; i < superParameters.size(); i++) { + TypeProjection superArgument = supertype.getArguments().get(i); + TypeParameterDescriptor parameter = superParameters.get(i); - if (superTypeParameter.isReified()) { + if (parameter.isReified()) { continue; } - Collection substituted = subtypeSubstitutionMap.get(superTypeParameter.getTypeConstructor()); - for (TypeProjection substitutedProjection : substituted) { - //if (!substitutedProjection.getType().equals(superTypeArgument.getType())) { - if (!typeChecker.isSubtypeOf(superTypeArgument.getType(), substitutedProjection.getType())) { // TODO hides error + Collection substituted = subtypeSubstitutionMap.get(parameter.getTypeConstructor()); + for (TypeProjection substitutedArgument : substituted) { + JetType superIn = TypeCheckingProcedure.getInType(parameter, superArgument); + JetType superOut = TypeCheckingProcedure.getOutType(parameter, superArgument); + + JetType subIn = TypeCheckingProcedure.getInType(parameter, substitutedArgument); + JetType subOut = TypeCheckingProcedure.getOutType(parameter, substitutedArgument); + + if (typeChecker.isSubtypeOf(superOut, subOut) && typeChecker.isSubtypeOf(subIn, superIn)) { + // super type range must be subset of sub type range + } else { return true; } } @@ -325,7 +333,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { Set clearSubstituted = new HashSet(); - for (TypeParameterDescriptor superTypeParameter : superTypeParameters) { + for (TypeParameterDescriptor superTypeParameter : superParameters) { Collection substituted = clearTypeSubstitutionMap.get(superTypeParameter.getTypeConstructor()); for (TypeProjection substitutedProjection : substituted) { clearSubstituted.add(substitutedProjection.getType()); diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOut.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOut.kt new file mode 100644 index 00000000000..47400289be2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOut.kt @@ -0,0 +1 @@ +fun f(a: MutableList) = a is MutableList diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOut2.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOut2.kt new file mode 100644 index 00000000000..6f7bc4f981a --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOut2.kt @@ -0,0 +1 @@ +fun f(a: MutableList) = a is MutableList diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOutAtClass.kt b/compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOutAtClass.kt new file mode 100644 index 00000000000..51395925aad --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOutAtClass.kt @@ -0,0 +1 @@ +fun f(a: List) = a is List diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedDisallowDifferentArgInvariantPosition.kt b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowDifferentArgInvariantPosition.kt new file mode 100644 index 00000000000..430c47fdc50 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowDifferentArgInvariantPosition.kt @@ -0,0 +1 @@ +fun f(a: MutableList) = a is MutableList \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromIn.kt b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromIn.kt new file mode 100644 index 00000000000..88768eca603 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromIn.kt @@ -0,0 +1 @@ +fun f(a: MutableList) = a is MutableList \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOutAtClass.kt b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOutAtClass.kt new file mode 100644 index 00000000000..f7399ac62e2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOutAtClass.kt @@ -0,0 +1 @@ +fun f(a: List) = a is List diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index eb567d57145..e32c19c88a0 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -713,6 +713,21 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/cast/AsErasedWarning.kt"); } + @TestMetadata("IsErasedAllowFromOut.kt") + public void testIsErasedAllowFromOut() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOut.kt"); + } + + @TestMetadata("IsErasedAllowFromOut2.kt") + public void testIsErasedAllowFromOut2() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOut2.kt"); + } + + @TestMetadata("IsErasedAllowFromOutAtClass.kt") + public void testIsErasedAllowFromOutAtClass() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowFromOutAtClass.kt"); + } + @TestMetadata("IsErasedAllowParameterSubtype.kt") public void testIsErasedAllowParameterSubtype() throws Exception { doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowParameterSubtype.kt"); @@ -728,16 +743,31 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowSameParameterParameter.kt"); } + @TestMetadata("IsErasedDisallowDifferentArgInvariantPosition.kt") + public void testIsErasedDisallowDifferentArgInvariantPosition() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowDifferentArgInvariantPosition.kt"); + } + @TestMetadata("IsErasedDisallowFromAny.kt") public void testIsErasedDisallowFromAny() throws Exception { doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromAny.kt"); } + @TestMetadata("IsErasedDisallowFromIn.kt") + public void testIsErasedDisallowFromIn() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromIn.kt"); + } + @TestMetadata("IsErasedDisallowFromOut.kt") public void testIsErasedDisallowFromOut() throws Exception { doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOut.kt"); } + @TestMetadata("IsErasedDisallowFromOutAtClass.kt") + public void testIsErasedDisallowFromOutAtClass() throws Exception { + doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOutAtClass.kt"); + } + @TestMetadata("IsErasedStar.kt") public void testIsErasedStar() throws Exception { doTest("compiler/testData/diagnostics/tests/cast/IsErasedStar.kt");