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.Collections;
|
||||||
import java.util.List;
|
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.diagnostics.Errors.*;
|
||||||
import static org.jetbrains.kotlin.lexer.KtTokens.*;
|
import static org.jetbrains.kotlin.lexer.KtTokens.*;
|
||||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||||
@@ -305,7 +307,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
KotlinTypeChecker typeChecker = KotlinTypeChecker.DEFAULT;
|
KotlinTypeChecker typeChecker = KotlinTypeChecker.DEFAULT;
|
||||||
if (actualType.equals(targetType)) {
|
if (isExactTypeCast(actualType, targetType)) {
|
||||||
// cast to itself: String as String
|
// cast to itself: String as String
|
||||||
context.trace.report(USELESS_CAST.on(expression));
|
context.trace.report(USELESS_CAST.on(expression));
|
||||||
return;
|
return;
|
||||||
@@ -316,8 +318,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
boolean checkExactType = checkExactTypeForUselessCast(expression);
|
boolean checkExactType = checkExactTypeForUselessCast(expression);
|
||||||
for (KotlinType possibleType : possibleTypes) {
|
for (KotlinType possibleType : possibleTypes) {
|
||||||
boolean castIsUseless = checkExactType
|
boolean castIsUseless = checkExactType
|
||||||
? possibleType.equals(targetType)
|
? isExactTypeCast(possibleType, targetType)
|
||||||
: typeChecker.isSubtypeOf(possibleType, targetType);
|
: isUpcast(possibleType, targetType, typeChecker);
|
||||||
if (castIsUseless) {
|
if (castIsUseless) {
|
||||||
context.trace.report(USELESS_CAST.on(expression));
|
context.trace.report(USELESS_CAST.on(expression));
|
||||||
return;
|
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 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.
|
// Casting to a supertype in other contexts is unlikely to be useful.
|
||||||
private static boolean checkExactTypeForUselessCast(KtBinaryExpressionWithTypeRHS expression) {
|
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);
|
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")
|
@TestMetadata("IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt")
|
||||||
public void testIsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric() throws Exception {
|
public void testIsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/cast/IsErasedAllowForDerivedWithOneSubstitutedAndOneSameGeneric.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user