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:
phx402@gmail.com
2016-04-24 20:26:30 +01:00
committed by Stanislav Erokhin
parent 8920e67c5a
commit 75e9e35669
4 changed files with 39 additions and 3 deletions
@@ -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");