diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/CastDiagnosticsUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/CastDiagnosticsUtil.kt index 3fbf0e8fa7c..d16097d4259 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/CastDiagnosticsUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/CastDiagnosticsUtil.kt @@ -213,13 +213,14 @@ object CastDiagnosticsUtil { return isRefinementUseless(possibleTypes, refinedTargetType, typeChecker, shouldCheckForExactType(expression, context.expectedType)) } + // It is a warning "useless cast" for `as` and a warning "redundant is" for `is` fun isRefinementUseless( possibleTypes: Collection, targetType: KotlinType, typeChecker: KotlinTypeChecker, shouldCheckForExactType: Boolean ): Boolean { - val intersectedType = TypeIntersector.intersectTypes(typeChecker, possibleTypes) ?: return false + val intersectedType = TypeIntersector.intersectTypes(typeChecker, possibleTypes.map { it.upperIfFlexible() }) ?: return false return if (shouldCheckForExactType) isExactTypeCast(intersectedType, targetType) 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 554bef0949e..0b9db5e62c9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt @@ -40,7 +40,6 @@ import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.* import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo import org.jetbrains.kotlin.types.typeUtil.containsError -import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import java.util.* class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTypingInternals) : ExpressionTypingVisitor(facade) { @@ -464,8 +463,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping 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) { + if (CastDiagnosticsUtil.isRefinementUseless(possibleTypes, targetType, KotlinTypeChecker.DEFAULT, false)) { context.trace.report(Errors.USELESS_IS_CHECK.on(isCheck, !negated)) } } diff --git a/compiler/testData/diagnostics/tests/cast/FlexibleTargetType.kt b/compiler/testData/diagnostics/tests/cast/FlexibleTargetType.kt new file mode 100644 index 00000000000..ad11f75fe95 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/FlexibleTargetType.kt @@ -0,0 +1,26 @@ +// FILE: Foo.java + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class Foo { + static Foo create() { return null; } + + @Nullable + static Foo createN() { return null; } + + @NotNull + static Foo createNN() { return null; } +} + +// FILE: sample.kt + +fun test() { + Foo.create() as Foo + Foo.createN() as Foo + Foo.createNN() as Foo + + Foo.create() as Foo? + Foo.createN() as Foo? + Foo.createNN() as Foo? +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/FlexibleTargetType.txt b/compiler/testData/diagnostics/tests/cast/FlexibleTargetType.txt new file mode 100644 index 00000000000..e8d4bf6e82f --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/FlexibleTargetType.txt @@ -0,0 +1,15 @@ +package + +public fun test(): kotlin.Unit + +public open class Foo { + public constructor Foo() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public/*package*/ open fun create(): Foo! + @org.jetbrains.annotations.Nullable public/*package*/ open fun createN(): Foo? + @org.jetbrains.annotations.NotNull public/*package*/ open fun createNN(): Foo +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 146bc4344d7..22de66cf3e8 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -2746,6 +2746,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("FlexibleTargetType.kt") + public void testFlexibleTargetType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/FlexibleTargetType.kt"); + doTest(fileName); + } + @TestMetadata("IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt") public void testIsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt");