[NI] Report warning if candidate was chosen using only @OverloadResolutionByLambdaReturnType

This commit is contained in:
Dmitriy Novozhilov
2020-05-21 15:18:07 +03:00
parent 82ce2e7b7c
commit a604404bff
9 changed files with 64 additions and 3 deletions
@@ -759,6 +759,8 @@ public interface Errors {
DiagnosticFactory1<PsiElement, TypeParameterDescriptor> TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING = DiagnosticFactory1.create(WARNING); DiagnosticFactory1<PsiElement, TypeParameterDescriptor> TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING = DiagnosticFactory1.create(WARNING);
DiagnosticFactory1<PsiElement, KotlinType> REIFIED_TYPE_FORBIDDEN_SUBSTITUTION = DiagnosticFactory1.create(ERROR); DiagnosticFactory1<PsiElement, KotlinType> REIFIED_TYPE_FORBIDDEN_SUBSTITUTION = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, KotlinType> REIFIED_TYPE_UNSAFE_SUBSTITUTION = DiagnosticFactory1.create(WARNING); DiagnosticFactory1<PsiElement, KotlinType> REIFIED_TYPE_UNSAFE_SUBSTITUTION = DiagnosticFactory1.create(WARNING);
DiagnosticFactory0<KtElement> CANDIDATE_CHOSEN_USING_OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION = DiagnosticFactory0.create(WARNING);
DiagnosticFactory3<KtReferenceExpression, ClassifierDescriptor, WrongResolutionToClassifier, String> RESOLUTION_TO_CLASSIFIER = DiagnosticFactory3<KtReferenceExpression, ClassifierDescriptor, WrongResolutionToClassifier, String> RESOLUTION_TO_CLASSIFIER =
DiagnosticFactory3.create(ERROR); DiagnosticFactory3.create(ERROR);
@@ -896,6 +896,7 @@ public class DefaultErrorMessages {
MAP.put(REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, "Cannot use ''{0}'' as reified type parameter", RENDER_TYPE); MAP.put(REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, "Cannot use ''{0}'' as reified type parameter", RENDER_TYPE);
MAP.put(REIFIED_TYPE_UNSAFE_SUBSTITUTION, "It may be not safe to use ''{0}'' as an argument for a reified type parameter. Use a non-generic type or * if possible", RENDER_TYPE); MAP.put(REIFIED_TYPE_UNSAFE_SUBSTITUTION, "It may be not safe to use ''{0}'' as an argument for a reified type parameter. Use a non-generic type or * if possible", RENDER_TYPE);
MAP.put(TYPE_PARAMETERS_NOT_ALLOWED, "Type parameters are not allowed here"); MAP.put(TYPE_PARAMETERS_NOT_ALLOWED, "Type parameters are not allowed here");
MAP.put(CANDIDATE_CHOSEN_USING_OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION, "Candidate was choosen only by @OverloadResolutionByLambdaReturnType annotation");
MAP.put(TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER, "Type parameter of a property must be used in its receiver type"); MAP.put(TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER, "Type parameter of a property must be used in its receiver type");
@@ -77,6 +77,9 @@ class DiagnosticReporterByTrackingStrategy(
trace.report(factory.on(it, typeVariable.originalTypeParameter)) trace.report(factory.on(it, typeVariable.originalTypeParameter))
} }
} }
CandidateChosenUsingOverloadResolutionByLambdaAnnotation::class.java -> {
trace.report(CANDIDATE_CHOSEN_USING_OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION.on(psiKotlinCall.psiCall.callElement))
}
} }
} }
@@ -155,6 +155,7 @@ class KotlinCallResolver(
if (maximallySpecificCandidates.size > 1) { if (maximallySpecificCandidates.size > 1) {
maximallySpecificCandidates = candidates.toMutableSet().apply { removeAll(candidatesWithAnnotation) } maximallySpecificCandidates = candidates.toMutableSet().apply { removeAll(candidatesWithAnnotation) }
maximallySpecificCandidates.singleOrNull()?.addDiagnostic(CandidateChosenUsingOverloadResolutionByLambdaAnnotation())
} }
} }
} }
@@ -243,3 +243,9 @@ class NotEnoughInformationForLambdaParameter(
reporter.onCallArgument(lambdaArgument, this) reporter.onCallArgument(lambdaArgument, this)
} }
} }
class CandidateChosenUsingOverloadResolutionByLambdaAnnotation : KotlinCallDiagnostic(RESOLVED) {
override fun report(reporter: DiagnosticReporter) {
reporter.onCall(this)
}
}
@@ -1,3 +1,4 @@
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// Auto-generated by org.jetbrains.kotlin.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT! // Auto-generated by org.jetbrains.kotlin.generators.tests.GenerateRangesCodegenTestData. DO NOT EDIT!
// WITH_RUNTIME // WITH_RUNTIME
@@ -45,4 +45,17 @@ fun test_4() {
fun test_5() { fun test_5() {
val x = <!AMBIGUITY!>create<!>("") { 1 } val x = <!AMBIGUITY!>create<!>("") { 1 }
takeInt(x) takeInt(x)
} }
interface A
interface B
interface C : A, B
@OverloadResolutionByLambdaReturnType
fun foo(f: () -> A): Int = 1
fun foo(f: () -> B): String = ""
fun test_6(c: C) {
val x = <!AMBIGUITY!>foo<!> { c }
takeString(x)
}
@@ -30,7 +30,7 @@ fun test_2() {
} }
fun test_3() { fun test_3() {
val x = create <!TYPE_MISMATCH!>{ <!CONSTANT_EXPECTED_TYPE_MISMATCH!>1.0<!> }<!> val x = <!CANDIDATE_CHOSEN_USING_OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION!>create <!TYPE_MISMATCH!>{ <!CONSTANT_EXPECTED_TYPE_MISMATCH!>1.0<!> }<!><!>
} }
@OverloadResolutionByLambdaReturnType @OverloadResolutionByLambdaReturnType
@@ -45,4 +45,17 @@ fun test_4() {
fun test_5() { fun test_5() {
val x = create("") { 1 } val x = create("") { 1 }
takeInt(x) takeInt(x)
} }
interface A
interface B
interface C : A, B
@OverloadResolutionByLambdaReturnType
fun foo(f: () -> A): Int = 1
fun foo(f: () -> B): String = ""
fun test_6(c: C) {
val x = <!CANDIDATE_CHOSEN_USING_OVERLOAD_RESOLUTION_BY_LAMBDA_ANNOTATION!>foo { c }<!>
takeString(x)
}
@@ -4,6 +4,8 @@ package
public fun create(/*0*/ f: (kotlin.Int) -> kotlin.String): kotlin.String public fun create(/*0*/ f: (kotlin.Int) -> kotlin.String): kotlin.String
@kotlin.OverloadResolutionByLambdaReturnType public fun </*0*/ K> create(/*0*/ x: K, /*1*/ f: (K) -> kotlin.Int): kotlin.Int @kotlin.OverloadResolutionByLambdaReturnType public fun </*0*/ K> create(/*0*/ x: K, /*1*/ f: (K) -> kotlin.Int): kotlin.Int
public fun </*0*/ T> create(/*0*/ x: T, /*1*/ f: (T) -> kotlin.String): kotlin.String public fun </*0*/ T> create(/*0*/ x: T, /*1*/ f: (T) -> kotlin.String): kotlin.String
@kotlin.OverloadResolutionByLambdaReturnType public fun foo(/*0*/ f: () -> A): kotlin.Int
public fun foo(/*0*/ f: () -> B): kotlin.String
public fun takeInt(/*0*/ s: kotlin.Int): kotlin.Unit public fun takeInt(/*0*/ s: kotlin.Int): kotlin.Unit
public fun takeString(/*0*/ s: kotlin.String): kotlin.Unit public fun takeString(/*0*/ s: kotlin.String): kotlin.Unit
public fun test_1(): kotlin.Unit public fun test_1(): kotlin.Unit
@@ -11,6 +13,25 @@ public fun test_2(): kotlin.Unit
public fun test_3(): kotlin.Unit public fun test_3(): kotlin.Unit
public fun test_4(): kotlin.Unit public fun test_4(): kotlin.Unit
public fun test_5(): kotlin.Unit public fun test_5(): kotlin.Unit
public fun test_6(/*0*/ c: C): kotlin.Unit
public interface A {
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
}
public interface B {
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
}
public interface C : A, B {
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
package kotlin { package kotlin {