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);
|
KotlinType targetType = reconstructBareType(right, possiblyBareTarget, subjectType, context.trace, components.builtIns);
|
||||||
|
|
||||||
if (subjectType != null) {
|
if (subjectType != null) {
|
||||||
checkBinaryWithTypeRHS(expression, contextWithNoExpectedType, targetType, subjectType);
|
checkBinaryWithTypeRHS(expression, context, targetType, subjectType);
|
||||||
DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
|
DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
|
||||||
if (operationType == AS_KEYWORD) {
|
if (operationType == AS_KEYWORD) {
|
||||||
DataFlowValue value = createDataFlowValue(left, subjectType, context);
|
DataFlowValue value = createDataFlowValue(left, subjectType, context);
|
||||||
@@ -384,7 +384,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
Collection<KotlinType> possibleTypes = components.dataFlowAnalyzer.getAllPossibleTypes(
|
Collection<KotlinType> possibleTypes = components.dataFlowAnalyzer.getAllPossibleTypes(
|
||||||
expression.getLeft(), context.dataFlowInfo, actualType, context);
|
expression.getLeft(), context.dataFlowInfo, actualType, context);
|
||||||
|
|
||||||
boolean checkExactType = checkExactTypeForUselessCast(expression);
|
boolean checkExactType = shouldCheckForExactType(expression, context.expectedType);
|
||||||
for (KotlinType possibleType : possibleTypes) {
|
for (KotlinType possibleType : possibleTypes) {
|
||||||
boolean castIsUseless = checkExactType
|
boolean castIsUseless = checkExactType
|
||||||
? isExactTypeCast(possibleType, targetType)
|
? 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) {
|
private static boolean isExactTypeCast(KotlinType candidateType, KotlinType targetType) {
|
||||||
return candidateType.equals(targetType) && isExtensionFunctionType(candidateType) == isExtensionFunctionType(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);
|
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")
|
@TestMetadata("AsNothing.kt")
|
||||||
public void testAsNothing() throws Exception {
|
public void testAsNothing() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/AsNothing.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/AsNothing.kt");
|
||||||
@@ -2926,6 +2932,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("kt614.kt")
|
||||||
public void testKt614() throws Exception {
|
public void testKt614() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/kt614.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/kt614.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user