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)) {
context.trace.report(USELESS_CAST.on(expression, expression.getOperationSign()));
} else {
if (isCastErased(actualType, targetType)) {
if (isCastErased(actualType, targetType, typeChecker)) {
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.
* 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)) {
// TODO: what if it is TypeParameterDescriptor?
return false;
}
JetType targetTypeClerared = TypeUtils.makeUnsubstitutedType(
(ClassDescriptor) targetType.getConstructor().getDeclarationDescriptor(), null);
{
Multimap<TypeConstructor, TypeProjection> typeSubstitutionMap =
TypeUtils.buildDeepSubstitutionMultimap(targetType);
Multimap<TypeConstructor, TypeProjection> clearTypeSubstitutionMap =
TypeUtils.buildDeepSubstitutionMultimap(targetTypeClerared);
for (int i = 0; i < actualType.getConstructor().getParameters().size(); ++i) {
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) {
TypeParameterDescriptor subjectTypeParameterDescriptor = actualType.getConstructor().getParameters().get(i);
Collection<TypeProjection> subst = clearTypeSubstitutionMap.get(subjectTypeParameterDescriptor.getTypeConstructor());
for (TypeProjection proj : subst) {
clearSubstituted.add(proj.getType());
Collection<TypeProjection> subst = typeSubstitutionMap.get(subjectTypeParameterDescriptor.getTypeConstructor());
for (TypeProjection proj : subst) {
//if (!proj.getType().equals(actualTypeParameter.getType())) {
if (!typeChecker.isSubtypeOf(actualTypeParameter.getType(), proj.getType())) {
return true;
}
}
}
}
for (int i = 0; i < targetType.getConstructor().getParameters().size(); ++i) {
TypeParameterDescriptor typeParameter = targetType.getConstructor().getParameters().get(i);
TypeProjection typeProjection = targetType.getArguments().get(i);
{
JetType targetTypeClerared = TypeUtils.makeUnsubstitutedType(
(ClassDescriptor) targetType.getConstructor().getDeclarationDescriptor(), null);
if (typeParameter.isReified()) {
continue;
Multimap<TypeConstructor, TypeProjection> clearTypeSubstitutionMap =
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<*>"
if (typeProjection.equals(TypeUtils.makeStarProjection(typeParameter))) {
continue;
}
for (int i = 0; i < targetType.getConstructor().getParameters().size(); ++i) {
TypeParameterDescriptor typeParameter = targetType.getConstructor().getParameters().get(i);
TypeProjection typeProjection = targetType.getArguments().get(i);
// if parameter is mapped to nothing then it is erased
if (!clearSubstituted.contains(typeParameter.getDefaultType())) {
return true;
if (typeParameter.isReified()) {
continue;
}
// "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;
@@ -246,7 +246,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
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));
}
}
@@ -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() {}
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. ?!!!
}