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 f88184d67b7..6fe3fbebbfe 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 @@ -283,7 +283,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { * Check if assignment from supertype to subtype is erased. * It is an error in "is" statement and warning in "as". */ - public static boolean isCastErased(JetType supertype, JetType subtype, JetTypeChecker typeChecker) { + public static boolean isCastErased(@NotNull JetType supertype, @NotNull JetType subtype, @NotNull JetTypeChecker typeChecker) { if (!(subtype.getConstructor().getDeclarationDescriptor() instanceof ClassDescriptor)) { // TODO: what if it is TypeParameterDescriptor? return false; @@ -294,72 +294,85 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return false; } + return hasDowncastsInTypeArguments(supertype, subtype, typeChecker) || hasErasedTypeArguments(supertype, subtype); + } + + private static boolean hasDowncastsInTypeArguments( + @NotNull JetType supertype, + @NotNull JetType subtype, + @NotNull JetTypeChecker typeChecker + ) { List superParameters = supertype.getConstructor().getParameters(); - { - Multimap subtypeSubstitutionMap = - SubstitutionUtils.buildDeepSubstitutionMultimap(subtype); + Multimap subtypeSubstitutionMap = + SubstitutionUtils.buildDeepSubstitutionMultimap(subtype); - for (int i = 0; i < superParameters.size(); i++) { - TypeProjection superArgument = supertype.getArguments().get(i); - TypeParameterDescriptor parameter = superParameters.get(i); + for (int i = 0; i < superParameters.size(); i++) { + TypeProjection superArgument = supertype.getArguments().get(i); + TypeParameterDescriptor parameter = superParameters.get(i); - if (parameter.isReified()) { - continue; - } - - Collection substituted = subtypeSubstitutionMap.get(parameter.getTypeConstructor()); - for (TypeProjection substitutedArgument : substituted) { - JetType superIn = TypeCheckingProcedure.getInType(parameter, superArgument); - 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; - } - } - } - } - - { - JetType subtypeCleared = TypeUtils.makeUnsubstitutedType( - (ClassDescriptor) subtype.getConstructor().getDeclarationDescriptor(), null); - - Multimap clearTypeSubstitutionMap = - SubstitutionUtils.buildDeepSubstitutionMultimap(subtypeCleared); - - Set clearSubstituted = new HashSet(); - - for (TypeParameterDescriptor superTypeParameter : superParameters) { - Collection substituted = clearTypeSubstitutionMap.get(superTypeParameter.getTypeConstructor()); - for (TypeProjection substitutedProjection : substituted) { - clearSubstituted.add(substitutedProjection.getType()); - } + if (parameter.isReified()) { + continue; } - List subTypeParameters = subtype.getConstructor().getParameters(); - for (int i = 0; i < subTypeParameters.size(); i++) { - TypeParameterDescriptor typeParameter = subTypeParameters.get(i); + Collection substituted = subtypeSubstitutionMap.get(parameter.getTypeConstructor()); + for (TypeProjection substitutedArgument : substituted) { + JetType superIn = TypeCheckingProcedure.getInType(parameter, superArgument); + JetType superOut = TypeCheckingProcedure.getOutType(parameter, superArgument); - if (typeParameter.isReified()) { - continue; - } + JetType subIn = TypeCheckingProcedure.getInType(parameter, substitutedArgument); + JetType subOut = TypeCheckingProcedure.getOutType(parameter, substitutedArgument); - // "is List<*>" - TypeProjection typeArgument = subtype.getArguments().get(i); - if (typeArgument.equals(SubstitutionUtils.makeStarProjection(typeParameter))) { - continue; - } - - // if parameter is mapped to nothing then it is erased - if (!clearSubstituted.contains(typeParameter.getDefaultType())) { + if (typeChecker.isSubtypeOf(superOut, subOut) && typeChecker.isSubtypeOf(subIn, superIn)) { + // super type range must be subset of sub type range + } else { return true; } } } + + return false; + } + + private static boolean hasErasedTypeArguments( + @NotNull JetType supertype, + @NotNull JetType subtype + ) { + JetType subtypeCleared = TypeUtils.makeUnsubstitutedType( + (ClassDescriptor) subtype.getConstructor().getDeclarationDescriptor(), null); + + Multimap clearTypeSubstitutionMap = + SubstitutionUtils.buildDeepSubstitutionMultimap(subtypeCleared); + + Set clearSubstituted = new HashSet(); + + List superParameters = supertype.getConstructor().getParameters(); + for (TypeParameterDescriptor superTypeParameter : superParameters) { + Collection substituted = clearTypeSubstitutionMap.get(superTypeParameter.getTypeConstructor()); + for (TypeProjection substitutedProjection : substituted) { + clearSubstituted.add(substitutedProjection.getType()); + } + } + + List subTypeParameters = subtype.getConstructor().getParameters(); + for (int i = 0; i < subTypeParameters.size(); i++) { + TypeParameterDescriptor typeParameter = subTypeParameters.get(i); + + if (typeParameter.isReified()) { + continue; + } + + // "is List<*>" + TypeProjection typeArgument = subtype.getArguments().get(i); + if (typeArgument.equals(SubstitutionUtils.makeStarProjection(typeParameter))) { + continue; + } + + // if parameter is mapped to nothing then it is erased + if (!clearSubstituted.contains(typeParameter.getDefaultType())) { + return true; + } + } + return false; }