From 75e9e356690c1d5d7912abab607693de4539a951 Mon Sep 17 00:00:00 2001 From: "phx402@gmail.com" Date: Sun, 24 Apr 2016 20:26:30 +0100 Subject: [PATCH] Fixed incorrect "No cast needed" warning when casting from extension function to regular one and vise versa #KT-11780 Fixed --- .../BasicExpressionTypingVisitor.java | 22 ++++++++++++++++--- .../tests/cast/ExtensionAsNonExtension.kt | 10 +++++++++ .../tests/cast/ExtensionAsNonExtension.txt | 4 ++++ .../checkers/DiagnosticsTestGenerated.java | 6 +++++ 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/cast/ExtensionAsNonExtension.kt create mode 100644 compiler/testData/diagnostics/tests/cast/ExtensionAsNonExtension.txt 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 9127b0bf9cb..079a6e9f74b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -73,6 +73,8 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import static org.jetbrains.kotlin.builtins.FunctionTypesKt.isExtensionFunctionType; +import static org.jetbrains.kotlin.builtins.FunctionTypesKt.isFunctionType; import static org.jetbrains.kotlin.diagnostics.Errors.*; import static org.jetbrains.kotlin.lexer.KtTokens.*; import static org.jetbrains.kotlin.resolve.BindingContext.*; @@ -305,7 +307,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return; } KotlinTypeChecker typeChecker = KotlinTypeChecker.DEFAULT; - if (actualType.equals(targetType)) { + if (isExactTypeCast(actualType, targetType)) { // cast to itself: String as String context.trace.report(USELESS_CAST.on(expression)); return; @@ -316,8 +318,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { boolean checkExactType = checkExactTypeForUselessCast(expression); for (KotlinType possibleType : possibleTypes) { boolean castIsUseless = checkExactType - ? possibleType.equals(targetType) - : typeChecker.isSubtypeOf(possibleType, targetType); + ? isExactTypeCast(possibleType, targetType) + : isUpcast(possibleType, targetType, typeChecker); if (castIsUseless) { context.trace.report(USELESS_CAST.on(expression)); return; @@ -328,6 +330,20 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } } + private static boolean isExactTypeCast(KotlinType candidateType, KotlinType targetType) { + return candidateType.equals(targetType) && isExtensionFunctionType(candidateType) == isExtensionFunctionType(targetType); + } + + private static boolean isUpcast(KotlinType candidateType, KotlinType targetType, KotlinTypeChecker typeChecker) { + if (!typeChecker.isSubtypeOf(candidateType, targetType)) return false; + + if (isFunctionType(candidateType) && isFunctionType(targetType)) { + return isExtensionFunctionType(candidateType) == isExtensionFunctionType(targetType); + } + + return true; + } + // Casting an argument or a receiver to a supertype may be useful to select an exact overload of a method. // Casting to a supertype in other contexts is unlikely to be useful. private static boolean checkExactTypeForUselessCast(KtBinaryExpressionWithTypeRHS expression) { diff --git a/compiler/testData/diagnostics/tests/cast/ExtensionAsNonExtension.kt b/compiler/testData/diagnostics/tests/cast/ExtensionAsNonExtension.kt new file mode 100644 index 00000000000..b7dde7e3775 --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/ExtensionAsNonExtension.kt @@ -0,0 +1,10 @@ +fun f(a: (Int) -> Unit) { + a as Int.() -> Unit + + f1(a as Int.() -> Unit) +} + +fun f1(a: Int.() -> Unit) { + a as (Int) -> Unit + f(a as (Int) -> Unit) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/ExtensionAsNonExtension.txt b/compiler/testData/diagnostics/tests/cast/ExtensionAsNonExtension.txt new file mode 100644 index 00000000000..31d70ff2fda --- /dev/null +++ b/compiler/testData/diagnostics/tests/cast/ExtensionAsNonExtension.txt @@ -0,0 +1,4 @@ +package + +public fun f(/*0*/ a: (kotlin.Int) -> kotlin.Unit): kotlin.Unit +public fun f1(/*0*/ a: kotlin.Int.() -> kotlin.Unit): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 86e83b17c58..41fe6baad18 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -2247,6 +2247,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("ExtensionAsNonExtension.kt") + public void testExtensionAsNonExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/ExtensionAsNonExtension.kt"); + doTest(fileName); + } + @TestMetadata("IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt") public void testIsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt");