From 52c1e9a9501b940cbf46ac22245e6681c8d31409 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Thu, 1 Dec 2011 17:41:13 +0400 Subject: [PATCH] one more case of KT-445 Don't allow deep instanceof for erased parameters === (a : List) is List === --- .../BasicExpressionTypingVisitor.java | 74 ++++++++++++------- .../PatternMatchingTypingVisitor.java | 2 +- .../tests/cast/IsErasedDisallowFromOut.jet | 5 ++ .../diagnostics/tests/regressions/kt498.jet | 2 +- 4 files changed, 56 insertions(+), 27 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOut.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 1e95b4414b6..475acc8f65e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -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 typeSubstitutionMap = + TypeUtils.buildDeepSubstitutionMultimap(targetType); - Multimap 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 clearSubstituted = new HashSet(); + if (subjectTypeParameterDescriptor.isReified()) { + continue; + } - for (int i = 0; i < actualType.getConstructor().getParameters().size(); ++i) { - TypeParameterDescriptor subjectTypeParameterDescriptor = actualType.getConstructor().getParameters().get(i); - - Collection subst = clearTypeSubstitutionMap.get(subjectTypeParameterDescriptor.getTypeConstructor()); - for (TypeProjection proj : subst) { - clearSubstituted.add(proj.getType()); + Collection 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 clearTypeSubstitutionMap = + TypeUtils.buildDeepSubstitutionMultimap(targetTypeClerared); + + Set clearSubstituted = new HashSet(); + + for (int i = 0; i < actualType.getConstructor().getParameters().size(); ++i) { + TypeParameterDescriptor subjectTypeParameterDescriptor = actualType.getConstructor().getParameters().get(i); + + Collection 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; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java index f5c277970bb..eba525b41f7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java @@ -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)); } } diff --git a/compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOut.jet b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOut.jet new file mode 100644 index 00000000000..b0cd9a510a0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/IsErasedDisallowFromOut.jet @@ -0,0 +1,5 @@ +// +JDK + +import java.util.List + +fun f(a : List) = a is List diff --git a/compiler/testData/diagnostics/tests/regressions/kt498.jet b/compiler/testData/diagnostics/tests/regressions/kt498.jet index 91e85567a83..fcb1e8abd61 100644 --- a/compiler/testData/diagnostics/tests/regressions/kt498.jet +++ b/compiler/testData/diagnostics/tests/regressions/kt498.jet @@ -4,5 +4,5 @@ class IdUnavailableException() : Exception() {} fun T.getJavaClass() : Class { - return ((this as Object).getClass()) as Class // Some error here, because of Exception() used above. ?!!! + return ((this as Object).getClass()) as Class // Some error here, because of Exception() used above. ?!!! }