diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index a81f9e77a64..194aa8abe5f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -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 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); } diff --git a/compiler/testData/diagnostics/tests/cast/AsInBlockWithReturnType.kt b/compiler/testData/diagnostics/tests/cast/AsInBlockWithReturnType.kt new file mode 100644 index 00000000000..7ad7babe2d3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/AsInBlockWithReturnType.kt @@ -0,0 +1,52 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun runWithoutReturn(r: () -> Unit) = r() + +fun testRun() { + run { + 1 as Any + 1 as Any + } + + run { + 1 as Any + 1 as Any + } + + fun foo(): Int = 1 + + run { + foo() as Any + } + + run { + (if (true) 1 else 2) as Any + } + + run { + 1 as Int + 1 as Int + } + + runWithoutReturn { + 1 as Any + 1 as Any + } +} + +fun testReturn(): Number { + run { 1 as Number } + return run { 1 as Number } +} + +fun testDependent() { + listOf(1).map { + it as Any + it as Any + } + + listOf().map { it as Any? } +} + +fun listOf(vararg elements: T): List = TODO() +fun Iterable.map(transform: (T) -> R): List = TODO() \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/AsInBlockWithReturnType.txt b/compiler/testData/diagnostics/tests/cast/AsInBlockWithReturnType.txt new file mode 100644 index 00000000000..3e83f2b4a91 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/AsInBlockWithReturnType.txt @@ -0,0 +1,8 @@ +package + +public fun listOf(/*0*/ vararg elements: T /*kotlin.Array*/): kotlin.collections.List +public fun runWithoutReturn(/*0*/ r: () -> kotlin.Unit): kotlin.Unit +public fun testDependent(): kotlin.Unit +public fun testReturn(): kotlin.Number +public fun testRun(): kotlin.Unit +public fun kotlin.collections.Iterable.map(/*0*/ transform: (T) -> R): kotlin.collections.List diff --git a/compiler/testData/diagnostics/tests/cast/kt15161.kt b/compiler/testData/diagnostics/tests/cast/kt15161.kt new file mode 100644 index 00000000000..f4a9d94919e --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/kt15161.kt @@ -0,0 +1,6 @@ +class Array(e: E) { + val k = Array(1) { + 1 as Any + e as Any? + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/kt15161.txt b/compiler/testData/diagnostics/tests/cast/kt15161.txt new file mode 100644 index 00000000000..4d9fd6ac15b --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/kt15161.txt @@ -0,0 +1,9 @@ +package + +public final class Array { + public constructor Array(/*0*/ e: E) + public final val k: kotlin.Array + 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 72d237a2cae..d6e998c330b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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");