Considering variances when checking for erased casts.
This commit is contained in:
+2
-2
@@ -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();
|
||||
}
|
||||
|
||||
+18
-10
@@ -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>
|
||||
+1
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user