Don't report useless cast in lambda if it has influence on return type
#KT-15161 Fixed #KT-12690 Fixed
This commit is contained in:
+12
-2
@@ -315,7 +315,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
KotlinType targetType = reconstructBareType(right, possiblyBareTarget, subjectType, context.trace, components.builtIns);
|
||||
|
||||
if (subjectType != null) {
|
||||
checkBinaryWithTypeRHS(expression, contextWithNoExpectedType, targetType, subjectType);
|
||||
checkBinaryWithTypeRHS(expression, context, targetType, subjectType);
|
||||
DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
|
||||
if (operationType == AS_KEYWORD) {
|
||||
DataFlowValue value = createDataFlowValue(left, subjectType, context);
|
||||
@@ -384,7 +384,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
Collection<KotlinType> possibleTypes = components.dataFlowAnalyzer.getAllPossibleTypes(
|
||||
expression.getLeft(), context.dataFlowInfo, actualType, context);
|
||||
|
||||
boolean checkExactType = checkExactTypeForUselessCast(expression);
|
||||
boolean checkExactType = shouldCheckForExactType(expression, context.expectedType);
|
||||
for (KotlinType possibleType : possibleTypes) {
|
||||
boolean castIsUseless = checkExactType
|
||||
? isExactTypeCast(possibleType, targetType)
|
||||
@@ -399,6 +399,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldCheckForExactType(KtBinaryExpressionWithTypeRHS expression, KotlinType expectedType) {
|
||||
if (TypeUtils.noExpectedType(expectedType)) {
|
||||
return checkExactTypeForUselessCast(expression);
|
||||
}
|
||||
|
||||
// If expected type is parameterized, then cast has an effect on inference, therefore it isn't a useless cast
|
||||
// Otherwise, we are interested in situation like: `a: Any? = 1 as Int?`
|
||||
return TypeUtils.isDontCarePlaceholder(expectedType);
|
||||
}
|
||||
|
||||
private static boolean isExactTypeCast(KotlinType candidateType, KotlinType targetType) {
|
||||
return candidateType.equals(targetType) && isExtensionFunctionType(candidateType) == isExtensionFunctionType(targetType);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun runWithoutReturn(r: () -> Unit) = r()
|
||||
|
||||
fun testRun() {
|
||||
run {
|
||||
1 <!USELESS_CAST!>as Any<!>
|
||||
1 as Any
|
||||
}
|
||||
|
||||
run<Any> {
|
||||
1 <!USELESS_CAST!>as Any<!>
|
||||
1 <!USELESS_CAST!>as Any<!>
|
||||
}
|
||||
|
||||
fun foo(): Int = 1
|
||||
|
||||
run {
|
||||
foo() as Any
|
||||
}
|
||||
|
||||
run {
|
||||
(if (true) 1 else 2) as Any
|
||||
}
|
||||
|
||||
run<Int?> {
|
||||
1 <!USELESS_CAST!>as Int<!>
|
||||
1 <!USELESS_CAST!>as Int<!>
|
||||
}
|
||||
|
||||
runWithoutReturn {
|
||||
1 <!USELESS_CAST!>as Any<!>
|
||||
1 <!USELESS_CAST!>as Any<!>
|
||||
}
|
||||
}
|
||||
|
||||
fun testReturn(): Number {
|
||||
run { 1 as Number }
|
||||
return run { 1 <!USELESS_CAST!>as Number<!> }
|
||||
}
|
||||
|
||||
fun <T> testDependent() {
|
||||
listOf(1).map {
|
||||
it <!USELESS_CAST!>as Any<!>
|
||||
it as Any
|
||||
}
|
||||
|
||||
listOf<T>().map { it as Any? }
|
||||
}
|
||||
|
||||
fun <T> listOf(vararg elements: T): List<T> = TODO()
|
||||
fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> = TODO()
|
||||
@@ -0,0 +1,8 @@
|
||||
package
|
||||
|
||||
public fun </*0*/ T> listOf(/*0*/ vararg elements: T /*kotlin.Array<out T>*/): kotlin.collections.List<T>
|
||||
public fun runWithoutReturn(/*0*/ r: () -> kotlin.Unit): kotlin.Unit
|
||||
public fun </*0*/ T> testDependent(): kotlin.Unit
|
||||
public fun testReturn(): kotlin.Number
|
||||
public fun testRun(): kotlin.Unit
|
||||
public fun </*0*/ T, /*1*/ R> kotlin.collections.Iterable<T>.map(/*0*/ transform: (T) -> R): kotlin.collections.List<R>
|
||||
@@ -0,0 +1,6 @@
|
||||
class Array<E>(e: E) {
|
||||
val k = Array(1) {
|
||||
1 <!USELESS_CAST!>as Any<!>
|
||||
e as Any?
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package
|
||||
|
||||
public final class Array</*0*/ E> {
|
||||
public constructor Array</*0*/ E>(/*0*/ e: E)
|
||||
public final val k: kotlin.Array<kotlin.Any?>
|
||||
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
|
||||
}
|
||||
@@ -2680,6 +2680,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("AsInBlockWithReturnType.kt")
|
||||
public void testAsInBlockWithReturnType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/AsInBlockWithReturnType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("AsNothing.kt")
|
||||
public void testAsNothing() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/AsNothing.kt");
|
||||
@@ -2926,6 +2932,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt15161.kt")
|
||||
public void testKt15161() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/kt15161.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt614.kt")
|
||||
public void testKt614() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/kt614.kt");
|
||||
|
||||
Reference in New Issue
Block a user