KT-9371 Callable reference resolve should not prefer one of the overloads by some magic reasons
#KT-9371 Fixed
This commit is contained in:
+15
-7
@@ -45,6 +45,8 @@ public class ResolutionResultsHandler {
|
|||||||
@NotNull ResolutionTask task,
|
@NotNull ResolutionTask task,
|
||||||
@NotNull Collection<MutableResolvedCall<D>> candidates
|
@NotNull Collection<MutableResolvedCall<D>> candidates
|
||||||
) {
|
) {
|
||||||
|
boolean resolveOverloads = task.checkArguments == CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS; // todo rename CheckArgumentTypesMode
|
||||||
|
|
||||||
Set<MutableResolvedCall<D>> successfulCandidates = Sets.newLinkedHashSet();
|
Set<MutableResolvedCall<D>> successfulCandidates = Sets.newLinkedHashSet();
|
||||||
Set<MutableResolvedCall<D>> failedCandidates = Sets.newLinkedHashSet();
|
Set<MutableResolvedCall<D>> failedCandidates = Sets.newLinkedHashSet();
|
||||||
Set<MutableResolvedCall<D>> incompleteCandidates = Sets.newLinkedHashSet();
|
Set<MutableResolvedCall<D>> incompleteCandidates = Sets.newLinkedHashSet();
|
||||||
@@ -68,10 +70,10 @@ public class ResolutionResultsHandler {
|
|||||||
// TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific
|
// TODO : maybe it's better to filter overrides out first, and only then look for the maximally specific
|
||||||
|
|
||||||
if (!successfulCandidates.isEmpty() || !incompleteCandidates.isEmpty()) {
|
if (!successfulCandidates.isEmpty() || !incompleteCandidates.isEmpty()) {
|
||||||
return computeSuccessfulResult(task, successfulCandidates, incompleteCandidates);
|
return computeSuccessfulResult(task, successfulCandidates, incompleteCandidates, resolveOverloads);
|
||||||
}
|
}
|
||||||
else if (!failedCandidates.isEmpty()) {
|
else if (!failedCandidates.isEmpty()) {
|
||||||
return computeFailedResult(task, failedCandidates);
|
return computeFailedResult(task, failedCandidates, resolveOverloads);
|
||||||
}
|
}
|
||||||
if (!candidatesWithWrongReceiver.isEmpty()) {
|
if (!candidatesWithWrongReceiver.isEmpty()) {
|
||||||
task.tracing.unresolvedReferenceWrongReceiver(task.trace, candidatesWithWrongReceiver);
|
task.tracing.unresolvedReferenceWrongReceiver(task.trace, candidatesWithWrongReceiver);
|
||||||
@@ -85,12 +87,13 @@ public class ResolutionResultsHandler {
|
|||||||
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> computeSuccessfulResult(
|
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> computeSuccessfulResult(
|
||||||
@NotNull ResolutionTask task,
|
@NotNull ResolutionTask task,
|
||||||
@NotNull Set<MutableResolvedCall<D>> successfulCandidates,
|
@NotNull Set<MutableResolvedCall<D>> successfulCandidates,
|
||||||
@NotNull Set<MutableResolvedCall<D>> incompleteCandidates
|
@NotNull Set<MutableResolvedCall<D>> incompleteCandidates,
|
||||||
|
boolean resolveOverloads
|
||||||
) {
|
) {
|
||||||
Set<MutableResolvedCall<D>> successfulAndIncomplete = Sets.newLinkedHashSet();
|
Set<MutableResolvedCall<D>> successfulAndIncomplete = Sets.newLinkedHashSet();
|
||||||
successfulAndIncomplete.addAll(successfulCandidates);
|
successfulAndIncomplete.addAll(successfulCandidates);
|
||||||
successfulAndIncomplete.addAll(incompleteCandidates);
|
successfulAndIncomplete.addAll(incompleteCandidates);
|
||||||
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(successfulAndIncomplete, true);
|
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(successfulAndIncomplete, true, resolveOverloads);
|
||||||
if (results.isSingleResult()) {
|
if (results.isSingleResult()) {
|
||||||
MutableResolvedCall<D> resultingCall = results.getResultingCall();
|
MutableResolvedCall<D> resultingCall = results.getResultingCall();
|
||||||
resultingCall.getTrace().moveAllMyDataTo(task.trace);
|
resultingCall.getTrace().moveAllMyDataTo(task.trace);
|
||||||
@@ -122,7 +125,8 @@ public class ResolutionResultsHandler {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> computeFailedResult(
|
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> computeFailedResult(
|
||||||
@NotNull ResolutionTask task,
|
@NotNull ResolutionTask task,
|
||||||
@NotNull Set<MutableResolvedCall<D>> failedCandidates
|
@NotNull Set<MutableResolvedCall<D>> failedCandidates,
|
||||||
|
boolean resolveOverloads
|
||||||
) {
|
) {
|
||||||
if (failedCandidates.size() != 1) {
|
if (failedCandidates.size() != 1) {
|
||||||
// This is needed when there are several overloads some of which are OK but for nullability of the receiver,
|
// This is needed when there are several overloads some of which are OK but for nullability of the receiver,
|
||||||
@@ -139,7 +143,7 @@ public class ResolutionResultsHandler {
|
|||||||
if (severityLevel.contains(ARGUMENTS_MAPPING_ERROR)) {
|
if (severityLevel.contains(ARGUMENTS_MAPPING_ERROR)) {
|
||||||
return recordFailedInfo(task, thisLevel);
|
return recordFailedInfo(task, thisLevel);
|
||||||
}
|
}
|
||||||
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(thisLevel, false);
|
OverloadResolutionResultsImpl<D> results = chooseAndReportMaximallySpecific(thisLevel, false, resolveOverloads);
|
||||||
return recordFailedInfo(task, results.getResultingCalls());
|
return recordFailedInfo(task, results.getResultingCalls());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +182,8 @@ public class ResolutionResultsHandler {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(
|
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(
|
||||||
@NotNull Set<MutableResolvedCall<D>> candidates,
|
@NotNull Set<MutableResolvedCall<D>> candidates,
|
||||||
boolean discriminateGenerics
|
boolean discriminateGenerics,
|
||||||
|
boolean resolveOverloads
|
||||||
) {
|
) {
|
||||||
if (candidates.size() == 1) {
|
if (candidates.size() == 1) {
|
||||||
return OverloadResolutionResultsImpl.success(candidates.iterator().next());
|
return OverloadResolutionResultsImpl.success(candidates.iterator().next());
|
||||||
@@ -188,6 +193,9 @@ public class ResolutionResultsHandler {
|
|||||||
if (noOverrides.size() == 1) {
|
if (noOverrides.size() == 1) {
|
||||||
return OverloadResolutionResultsImpl.success(noOverrides.iterator().next());
|
return OverloadResolutionResultsImpl.success(noOverrides.iterator().next());
|
||||||
}
|
}
|
||||||
|
else if (!resolveOverloads) {
|
||||||
|
return OverloadResolutionResultsImpl.ambiguity(noOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
MutableResolvedCall<D> maximallySpecific = overloadingConflictResolver.findMaximallySpecific(noOverrides, false);
|
MutableResolvedCall<D> maximallySpecific = overloadingConflictResolver.findMaximallySpecific(noOverrides, false);
|
||||||
if (maximallySpecific != null) {
|
if (maximallySpecific != null) {
|
||||||
|
|||||||
+1
-1
@@ -7,4 +7,4 @@ fun foo(s: String) {}
|
|||||||
|
|
||||||
val x1 = ofType<() -> Unit>(::foo)
|
val x1 = ofType<() -> Unit>(::foo)
|
||||||
val x2 = ofType<(String) -> Unit>(::foo)
|
val x2 = ofType<(String) -> Unit>(::foo)
|
||||||
val x3 = ofType<(Int) -> Unit>(<!TYPE_MISMATCH!>::foo<!>)
|
val x3 = ofType<(Int) -> Unit>(::<!NONE_APPLICABLE!>foo<!>)
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
fun foo() {}
|
fun foo() {}
|
||||||
fun foo(s: String) {}
|
fun foo(s: String) {}
|
||||||
|
|
||||||
val x1 = ::foo
|
val x1 = ::<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>
|
||||||
val x2: () -> Unit = ::foo
|
val x2: () -> Unit = ::foo
|
||||||
val x3: (String) -> Unit = ::foo
|
val x3: (String) -> Unit = ::foo
|
||||||
val x4: (Int) -> Unit = <!TYPE_MISMATCH!>::foo<!>
|
val x4: (Int) -> Unit = ::<!NONE_APPLICABLE!>foo<!>
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public val x1: kotlin.reflect.KFunction0<kotlin.Unit>
|
public val x1: [ERROR : Type for ::foo]
|
||||||
public val x2: () -> kotlin.Unit
|
public val x2: () -> kotlin.Unit
|
||||||
public val x3: (kotlin.String) -> kotlin.Unit
|
public val x3: (kotlin.String) -> kotlin.Unit
|
||||||
public val x4: (kotlin.Int) -> kotlin.Unit
|
public val x4: (kotlin.Int) -> kotlin.Unit
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// !CHECK_TYPE
|
||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION
|
||||||
|
import kotlin.reflect.KFunction1
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
open fun bar() {}
|
||||||
|
|
||||||
|
fun bas() {}
|
||||||
|
}
|
||||||
|
class B: A() {
|
||||||
|
override fun bar() {}
|
||||||
|
|
||||||
|
fun bas(i: Int) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun A.foo() {}
|
||||||
|
fun B.foo() {}
|
||||||
|
|
||||||
|
fun fas() {}
|
||||||
|
fun fas(i: Int = 1) {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
B::<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> // todo KT-9601 Chose maximally specific function in callable reference
|
||||||
|
|
||||||
|
B::bar checkType { _<KFunction1<B, Unit>>() }
|
||||||
|
|
||||||
|
B::<!OVERLOAD_RESOLUTION_AMBIGUITY!>bas<!>
|
||||||
|
|
||||||
|
::<!OVERLOAD_RESOLUTION_AMBIGUITY!>fas<!>
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun fas(): kotlin.Unit
|
||||||
|
public fun fas(/*0*/ i: kotlin.Int = ...): kotlin.Unit
|
||||||
|
public fun test(): kotlin.Unit
|
||||||
|
public fun A.foo(): kotlin.Unit
|
||||||
|
public fun B.foo(): kotlin.Unit
|
||||||
|
|
||||||
|
public open class A {
|
||||||
|
public constructor A()
|
||||||
|
public open fun bar(): kotlin.Unit
|
||||||
|
public final fun bas(): kotlin.Unit
|
||||||
|
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 final class B : A {
|
||||||
|
public constructor B()
|
||||||
|
public open override /*1*/ fun bar(): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun bas(): kotlin.Unit
|
||||||
|
public final fun bas(/*0*/ i: kotlin.Int): kotlin.Unit
|
||||||
|
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
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION
|
||||||
|
// KT-9601 Chose maximally specific function in callable reference
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
fun foo(a: Any) {}
|
||||||
|
fun fas(a: Int) {}
|
||||||
|
}
|
||||||
|
class B: A() {
|
||||||
|
fun foo(a: Int) {}
|
||||||
|
fun fas(a: Any) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
B::<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!>
|
||||||
|
B::<!OVERLOAD_RESOLUTION_AMBIGUITY!>fas<!>
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun test(): kotlin.Unit
|
||||||
|
|
||||||
|
public open class A {
|
||||||
|
public constructor A()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final fun fas(/*0*/ a: kotlin.Int): kotlin.Unit
|
||||||
|
public final fun foo(/*0*/ a: kotlin.Any): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class B : A {
|
||||||
|
public constructor B()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final fun fas(/*0*/ a: kotlin.Any): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun fas(/*0*/ a: kotlin.Int): kotlin.Unit
|
||||||
|
public final override /*1*/ /*fake_override*/ fun foo(/*0*/ a: kotlin.Any): kotlin.Unit
|
||||||
|
public final fun foo(/*0*/ a: kotlin.Int): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -6,5 +6,5 @@ fun foo(s: String) {}
|
|||||||
fun bar(f: () -> Unit) = 1
|
fun bar(f: () -> Unit) = 1
|
||||||
fun bar(f: (String) -> Unit) = 2
|
fun bar(f: (String) -> Unit) = 2
|
||||||
|
|
||||||
val x1 = ::foo <!USELESS_CAST!>as () -> Unit<!>
|
val x1 = ::<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> as () -> Unit
|
||||||
val x2 = bar(<!UNCHECKED_CAST!>::foo as (String) -> Unit<!>)
|
val x2 = bar(::<!OVERLOAD_RESOLUTION_AMBIGUITY!>foo<!> as (String) -> Unit)
|
||||||
+1
-1
@@ -6,5 +6,5 @@ fun foo(i: Int) {}
|
|||||||
|
|
||||||
val fn1: (Int) -> Unit = ::foo
|
val fn1: (Int) -> Unit = ::foo
|
||||||
val fn2: (IntArray) -> Unit = ::foo
|
val fn2: (IntArray) -> Unit = ::foo
|
||||||
val fn3: (Int, Int) -> Unit = <!TYPE_MISMATCH!>::foo<!>
|
val fn3: (Int, Int) -> Unit = ::<!NONE_APPLICABLE!>foo<!>
|
||||||
val fn4: (Array<String>) -> Unit = ::foo
|
val fn4: (Array<String>) -> Unit = ::foo
|
||||||
@@ -2015,6 +2015,18 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("overloads.kt")
|
||||||
|
public void testOverloads() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/resolve/overloads.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("overloadsMember.kt")
|
||||||
|
public void testOverloadsMember() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/resolve/overloadsMember.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("valVsFun.kt")
|
@TestMetadata("valVsFun.kt")
|
||||||
public void testValVsFun() throws Exception {
|
public void testValVsFun() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/resolve/valVsFun.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/resolve/valVsFun.kt");
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
import kotlin.reflect.KMutableProperty1
|
||||||
|
|
||||||
open class A(var msg:String) {
|
open class A(var msg:String) {
|
||||||
}
|
}
|
||||||
@@ -21,7 +22,7 @@ fun box(): String {
|
|||||||
val a = A("Test")
|
val a = A("Test")
|
||||||
|
|
||||||
var refAExt = A::ext
|
var refAExt = A::ext
|
||||||
var refBExt = B::ext
|
var refBExt: KMutableProperty1<B, String> = B::ext
|
||||||
|
|
||||||
assertEquals("ext", refAExt.name)
|
assertEquals("ext", refAExt.name)
|
||||||
assertEquals("ext", refBExt.name)
|
assertEquals("ext", refBExt.name)
|
||||||
|
|||||||
Reference in New Issue
Block a user