Fix false "useless cast" when target type is flexible

#KT-17820 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2017-05-15 11:24:05 +03:00
parent a8f1e32dec
commit ac8fbce249
5 changed files with 50 additions and 4 deletions
@@ -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<KotlinType>,
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)
@@ -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))
}
}
@@ -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() <!USELESS_CAST!>as Foo<!>
Foo.create() <!USELESS_CAST!>as Foo?<!>
Foo.createN() <!USELESS_CAST!>as Foo?<!>
Foo.createNN() <!USELESS_CAST!>as Foo?<!>
}
@@ -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
}
@@ -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");