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:
Mikhail Zarechenskiy
2017-04-05 04:37:04 +03:00
parent 30d6af7aae
commit 12db3a263e
6 changed files with 99 additions and 2 deletions
@@ -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>
+6
View File
@@ -0,0 +1,6 @@
class Array<E>(e: E) {
val k = Array(1) {
1 <!USELESS_CAST!>as Any<!>
e as Any?
}
}
+9
View File
@@ -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");