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:
+49
-25
@@ -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;
|
||||||
|
|||||||
+1
-1
@@ -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. ?!!!
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user