diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java index 61b00a84293..e1862449dea 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java @@ -350,6 +350,15 @@ public class DataFlowAnalyzer { @NotNull ResolutionContext c ) { DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, c); + return getAllPossibleTypes(type, c, dataFlowValue); + } + + @NotNull + public static Collection getAllPossibleTypes( + @NotNull KotlinType type, + @NotNull ResolutionContext c, + @NotNull DataFlowValue dataFlowValue + ) { Collection possibleTypes = Sets.newHashSet(type); possibleTypes.addAll(c.dataFlowInfo.getStableTypes(dataFlowValue)); return possibleTypes; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt index 7df1b2f7f9e..554bef0949e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt @@ -436,21 +436,15 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping if (targetDescriptor != null && DescriptorUtils.isEnumEntry(targetDescriptor)) { context.trace.report(IS_ENUM_ENTRY.on(typeReferenceAfterIs)) } - val subjectTypeHasError = subjectType.containsError() - if (!subjectTypeHasError && !TypeUtils.isNullableType(subjectType) && targetType.isMarkedNullable) { + if (!subjectType.containsError() && !TypeUtils.isNullableType(subjectType) && targetType.isMarkedNullable) { val element = typeReferenceAfterIs.typeElement assert(element is KtNullableType) { "element must be instance of " + KtNullableType::class.java.name } context.trace.report(Errors.USELESS_NULLABLE_CHECK.on(element as KtNullableType)) } checkTypeCompatibility(context, targetType, subjectType, typeReferenceAfterIs) - if (!subjectTypeHasError && !targetType.containsError()) { - val possibleTypes = hashSetOf(subjectType) - possibleTypes.addAll(context.dataFlowInfo.getStableTypes(subjectDataFlowValue)) - val intersection = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, possibleTypes.map { it.upperIfFlexible() }) - if (intersection?.isSubtypeOf(targetType) ?: false) { - context.trace.report(Errors.USELESS_IS_CHECK.on(isCheck, !negated)) - } - } + + detectRedundantIs(context, subjectType, targetType, isCheck, negated, subjectDataFlowValue) + if (CastDiagnosticsUtil.isCastErased(subjectType, targetType, KotlinTypeChecker.DEFAULT)) { context.trace.report(Errors.CANNOT_CHECK_FOR_ERASED.on(typeReferenceAfterIs, targetType)) } @@ -459,6 +453,23 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping } } + private fun detectRedundantIs( + context: ExpressionTypingContext, + subjectType: KotlinType, + targetType: KotlinType, + isCheck: KtElement, + negated: Boolean, + subjectDataFlowValue: DataFlowValue + ) { + if (subjectType.containsError() || targetType.containsError()) return + + val possibleTypes = DataFlowAnalyzer.getAllPossibleTypes(subjectType, context, subjectDataFlowValue) + val intersection = TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, possibleTypes.map { it.upperIfFlexible() }) + if (intersection?.isSubtypeOf(targetType) ?: false) { + context.trace.report(Errors.USELESS_IS_CHECK.on(isCheck, !negated)) + } + } + private fun noChange(context: ExpressionTypingContext) = ConditionalDataFlowInfo(context.dataFlowInfo) /*