Considering variances when checking for erased casts.

This commit is contained in:
Evgeny Gerashchenko
2012-11-08 17:22:50 +04:00
parent b3311f717d
commit e691a0bc93
9 changed files with 56 additions and 12 deletions
@@ -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();
}
@@ -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<TypeParameterDescriptor> superTypeParameters = supertype.getConstructor().getParameters();
List<TypeParameterDescriptor> superParameters = supertype.getConstructor().getParameters();
{
Multimap<TypeConstructor, TypeProjection> 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<TypeProjection> 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<TypeProjection> 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<JetType> clearSubstituted = new HashSet<JetType>();
for (TypeParameterDescriptor superTypeParameter : superTypeParameters) {
for (TypeParameterDescriptor superTypeParameter : superParameters) {
Collection<TypeProjection> substituted = clearTypeSubstitutionMap.get(superTypeParameter.getTypeConstructor());
for (TypeProjection substitutedProjection : substituted) {
clearSubstituted.add(substitutedProjection.getType());
@@ -0,0 +1 @@
fun f(a: MutableList<out Number>) = a is MutableList<out Hashable>
@@ -0,0 +1 @@
fun f(a: MutableList<String>) = a is MutableList<out CharSequence>
@@ -0,0 +1 @@
fun f(a: List<Number>) = a is List<Hashable>
@@ -0,0 +1 @@
fun f(a: MutableList<String>) = a is <!CANNOT_CHECK_FOR_ERASED!>MutableList<CharSequence><!>
@@ -0,0 +1 @@
fun f(a: MutableList<in String>) = a is <!CANNOT_CHECK_FOR_ERASED!>MutableList<CharSequence><!>
@@ -0,0 +1 @@
fun f(a: List<Hashable>) = a is <!CANNOT_CHECK_FOR_ERASED!>List<Number><!>
@@ -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");