Considering variances when checking for erased casts.
This commit is contained in:
+2
-2
@@ -48,12 +48,12 @@ public class TypeCheckingProcedure {
|
|||||||
return null;
|
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;
|
boolean isOutProjected = argument.getProjectionKind() == IN_VARIANCE || parameter.getVariance() == IN_VARIANCE;
|
||||||
return isOutProjected ? parameter.getUpperBoundsAsType() : argument.getType();
|
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;
|
boolean isOutProjected = argument.getProjectionKind() == OUT_VARIANCE || parameter.getVariance() == OUT_VARIANCE;
|
||||||
return isOutProjected ? KotlinBuiltIns.getInstance().getNothingType() : argument.getType();
|
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.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
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.lang.types.lang.KotlinBuiltIns;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
|
|
||||||
@@ -293,23 +294,30 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TypeParameterDescriptor> superTypeParameters = supertype.getConstructor().getParameters();
|
List<TypeParameterDescriptor> superParameters = supertype.getConstructor().getParameters();
|
||||||
{
|
{
|
||||||
Multimap<TypeConstructor, TypeProjection> subtypeSubstitutionMap =
|
Multimap<TypeConstructor, TypeProjection> subtypeSubstitutionMap =
|
||||||
SubstitutionUtils.buildDeepSubstitutionMultimap(subtype);
|
SubstitutionUtils.buildDeepSubstitutionMultimap(subtype);
|
||||||
|
|
||||||
for (int i = 0; i < superTypeParameters.size(); i++) {
|
for (int i = 0; i < superParameters.size(); i++) {
|
||||||
TypeProjection superTypeArgument = supertype.getArguments().get(i);
|
TypeProjection superArgument = supertype.getArguments().get(i);
|
||||||
TypeParameterDescriptor superTypeParameter = superTypeParameters.get(i);
|
TypeParameterDescriptor parameter = superParameters.get(i);
|
||||||
|
|
||||||
if (superTypeParameter.isReified()) {
|
if (parameter.isReified()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<TypeProjection> substituted = subtypeSubstitutionMap.get(superTypeParameter.getTypeConstructor());
|
Collection<TypeProjection> substituted = subtypeSubstitutionMap.get(parameter.getTypeConstructor());
|
||||||
for (TypeProjection substitutedProjection : substituted) {
|
for (TypeProjection substitutedArgument : substituted) {
|
||||||
//if (!substitutedProjection.getType().equals(superTypeArgument.getType())) {
|
JetType superIn = TypeCheckingProcedure.getInType(parameter, superArgument);
|
||||||
if (!typeChecker.isSubtypeOf(superTypeArgument.getType(), substitutedProjection.getType())) { // TODO hides error
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,7 +333,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
|
|
||||||
Set<JetType> clearSubstituted = new HashSet<JetType>();
|
Set<JetType> clearSubstituted = new HashSet<JetType>();
|
||||||
|
|
||||||
for (TypeParameterDescriptor superTypeParameter : superTypeParameters) {
|
for (TypeParameterDescriptor superTypeParameter : superParameters) {
|
||||||
Collection<TypeProjection> substituted = clearTypeSubstitutionMap.get(superTypeParameter.getTypeConstructor());
|
Collection<TypeProjection> substituted = clearTypeSubstitutionMap.get(superTypeParameter.getTypeConstructor());
|
||||||
for (TypeProjection substitutedProjection : substituted) {
|
for (TypeProjection substitutedProjection : substituted) {
|
||||||
clearSubstituted.add(substitutedProjection.getType());
|
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");
|
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")
|
@TestMetadata("IsErasedAllowParameterSubtype.kt")
|
||||||
public void testIsErasedAllowParameterSubtype() throws Exception {
|
public void testIsErasedAllowParameterSubtype() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/cast/IsErasedAllowParameterSubtype.kt");
|
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");
|
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")
|
@TestMetadata("IsErasedDisallowFromAny.kt")
|
||||||
public void testIsErasedDisallowFromAny() throws Exception {
|
public void testIsErasedDisallowFromAny() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromAny.kt");
|
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")
|
@TestMetadata("IsErasedDisallowFromOut.kt")
|
||||||
public void testIsErasedDisallowFromOut() throws Exception {
|
public void testIsErasedDisallowFromOut() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOut.kt");
|
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")
|
@TestMetadata("IsErasedStar.kt")
|
||||||
public void testIsErasedStar() throws Exception {
|
public void testIsErasedStar() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/cast/IsErasedStar.kt");
|
doTest("compiler/testData/diagnostics/tests/cast/IsErasedStar.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user