one more case of KT-445 Don't allow deep instanceof for erased parameters

===
(a : List<out Any>) is List<out Int>
===
This commit is contained in:
Stepan Koltsov
2011-12-01 17:41:13 +04:00
parent a003e6d2e4
commit 52c1e9a950
4 changed files with 56 additions and 27 deletions
@@ -248,7 +248,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (typeChecker.isSubtypeOf(actualType, targetType)) { if (typeChecker.isSubtypeOf(actualType, targetType)) {
context.trace.report(USELESS_CAST.on(expression, expression.getOperationSign())); context.trace.report(USELESS_CAST.on(expression, expression.getOperationSign()));
} else { } else {
if (isCastErased(actualType, targetType)) { if (isCastErased(actualType, targetType, typeChecker)) {
context.trace.report(Errors.UNCHECKED_CAST.on(expression, actualType, targetType)); context.trace.report(Errors.UNCHECKED_CAST.on(expression, actualType, targetType));
} }
} }
@@ -259,46 +259,70 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
* Check if assignment from ActualType to TargetType is erased. * Check if assignment from ActualType to TargetType is erased.
* It is an error in "is" statement and warning in "as". * It is an error in "is" statement and warning in "as".
*/ */
public static boolean isCastErased(JetType actualType, JetType targetType) { public static boolean isCastErased(JetType actualType, JetType targetType, JetTypeChecker typeChecker) {
if (!(targetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor)) { if (!(targetType.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor)) {
// TODO: what if it is TypeParameterDescriptor? // TODO: what if it is TypeParameterDescriptor?
return false; return false;
} }
JetType targetTypeClerared = TypeUtils.makeUnsubstitutedType( {
(ClassDescriptor) targetType.getConstructor().getDeclarationDescriptor(), null); Multimap<TypeConstructor, TypeProjection> typeSubstitutionMap =
TypeUtils.buildDeepSubstitutionMultimap(targetType);
Multimap<TypeConstructor, TypeProjection> clearTypeSubstitutionMap = for (int i = 0; i < actualType.getConstructor().getParameters().size(); ++i) {
TypeUtils.buildDeepSubstitutionMultimap(targetTypeClerared); TypeProjection actualTypeParameter = actualType.getArguments().get(i);
TypeParameterDescriptor subjectTypeParameterDescriptor = actualType.getConstructor().getParameters().get(i);
Set<JetType> clearSubstituted = new HashSet<JetType>(); if (subjectTypeParameterDescriptor.isReified()) {
continue;
}
for (int i = 0; i < actualType.getConstructor().getParameters().size(); ++i) { Collection<TypeProjection> subst = typeSubstitutionMap.get(subjectTypeParameterDescriptor.getTypeConstructor());
TypeParameterDescriptor subjectTypeParameterDescriptor = actualType.getConstructor().getParameters().get(i); for (TypeProjection proj : subst) {
//if (!proj.getType().equals(actualTypeParameter.getType())) {
Collection<TypeProjection> subst = clearTypeSubstitutionMap.get(subjectTypeParameterDescriptor.getTypeConstructor()); if (!typeChecker.isSubtypeOf(actualTypeParameter.getType(), proj.getType())) {
for (TypeProjection proj : subst) { return true;
clearSubstituted.add(proj.getType()); }
}
} }
} }
for (int i = 0; i < targetType.getConstructor().getParameters().size(); ++i) { {
TypeParameterDescriptor typeParameter = targetType.getConstructor().getParameters().get(i); JetType targetTypeClerared = TypeUtils.makeUnsubstitutedType(
TypeProjection typeProjection = targetType.getArguments().get(i); (ClassDescriptor) targetType.getConstructor().getDeclarationDescriptor(), null);
if (typeParameter.isReified()) { Multimap<TypeConstructor, TypeProjection> clearTypeSubstitutionMap =
continue; TypeUtils.buildDeepSubstitutionMultimap(targetTypeClerared);
Set<JetType> clearSubstituted = new HashSet<JetType>();
for (int i = 0; i < actualType.getConstructor().getParameters().size(); ++i) {
TypeParameterDescriptor subjectTypeParameterDescriptor = actualType.getConstructor().getParameters().get(i);
Collection<TypeProjection> subst = clearTypeSubstitutionMap.get(subjectTypeParameterDescriptor.getTypeConstructor());
for (TypeProjection proj : subst) {
clearSubstituted.add(proj.getType());
}
} }
// "is List<*>" for (int i = 0; i < targetType.getConstructor().getParameters().size(); ++i) {
if (typeProjection.equals(TypeUtils.makeStarProjection(typeParameter))) { TypeParameterDescriptor typeParameter = targetType.getConstructor().getParameters().get(i);
continue; TypeProjection typeProjection = targetType.getArguments().get(i);
}
// if parameter is mapped to nothing then it is erased if (typeParameter.isReified()) {
if (!clearSubstituted.contains(typeParameter.getDefaultType())) { continue;
return true; }
// "is List<*>"
if (typeProjection.equals(TypeUtils.makeStarProjection(typeParameter))) {
continue;
}
// if parameter is mapped to nothing then it is erased
if (!clearSubstituted.contains(typeParameter.getDefaultType())) {
return true;
}
} }
} }
return false; return false;
@@ -246,7 +246,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
return; return;
} }
if (BasicExpressionTypingVisitor.isCastErased(subjectType, type)) { if (BasicExpressionTypingVisitor.isCastErased(subjectType, type, context.semanticServices.getTypeChecker())) {
context.trace.report(Errors.CANNOT_CHECK_FOR_ERASED.on(reportErrorOn, type)); context.trace.report(Errors.CANNOT_CHECK_FOR_ERASED.on(reportErrorOn, type));
} }
} }
@@ -0,0 +1,5 @@
// +JDK
import java.util.List
fun f(a : List<out Any>) = a is <!CANNOT_CHECK_FOR_ERASED!>List<out Int><!>
@@ -4,5 +4,5 @@
class IdUnavailableException() : Exception() {} class IdUnavailableException() : Exception() {}
fun <T : Any> T.getJavaClass() : Class<T> { fun <T : Any> T.getJavaClass() : Class<T> {
return ((this <!CAST_NEVER_SUCCEEDS!>as<!> Object).getClass()) as Class<T> // Some error here, because of Exception() used above. ?!!! return <!UNCHECKED_CAST!>((this <!CAST_NEVER_SUCCEEDS!>as<!> Object).getClass()) as Class<T><!> // Some error here, because of Exception() used above. ?!!!
} }