Fixed incorrect "No cast needed" warning when casting from extension function to regular one and vise versa
#KT-11780 Fixed
This commit is contained in:
committed by
Stanislav Erokhin
parent
8920e67c5a
commit
75e9e35669
+19
-3
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user