K2: discriminate candidates with adaptations in the first place in ConeOverloadConflictResolver

Before this commit, we discriminated particular candidates with callable
reference adaptations during resolution stages.
After disabling compatibility mode for new inference, it's not so,
but now we discriminate similar candidates in ConeOverloadConflictResolver;
more precisely, it's candidates with callable reference adaptation
in their postponed atoms.
This does not allow going up the tower,
but allows to select better candidate at similar tower level.

Related to KT-63558, KT-64307, KT-64308
This commit is contained in:
Mikhail Glukhikh
2023-12-19 11:02:03 +01:00
committed by Space Team
parent 087edc026d
commit d3a0a6cabe
10 changed files with 130 additions and 9 deletions
@@ -21926,6 +21926,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/j+k/recursiveSelfTypes.kt");
}
@Test
@TestMetadata("runnableOrCallable.kt")
public void testRunnableOrCallable() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/runnableOrCallable.kt");
}
@Test
@TestMetadata("safeCallDefinitelyNotNull.kt")
public void testSafeCallDefinitelyNotNull() throws Exception {
@@ -21926,6 +21926,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/j+k/recursiveSelfTypes.kt");
}
@Test
@TestMetadata("runnableOrCallable.kt")
public void testRunnableOrCallable() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/runnableOrCallable.kt");
}
@Test
@TestMetadata("safeCallDefinitelyNotNull.kt")
public void testSafeCallDefinitelyNotNull() throws Exception {
@@ -21920,6 +21920,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/j+k/recursiveSelfTypes.kt");
}
@Test
@TestMetadata("runnableOrCallable.kt")
public void testRunnableOrCallable() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/runnableOrCallable.kt");
}
@Test
@TestMetadata("safeCallDefinitelyNotNull.kt")
public void testSafeCallDefinitelyNotNull() throws Exception {
@@ -21926,6 +21926,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/j+k/recursiveSelfTypes.kt");
}
@Test
@TestMetadata("runnableOrCallable.kt")
public void testRunnableOrCallable() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/runnableOrCallable.kt");
}
@Test
@TestMetadata("safeCallDefinitelyNotNull.kt")
public void testSafeCallDefinitelyNotNull() throws Exception {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
@@ -13,9 +14,11 @@ import org.jetbrains.kotlin.fir.declarations.utils.isActual
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.inference.ConeTypeParameterBasedTypeVariable
import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents
import org.jetbrains.kotlin.fir.resolve.inference.ResolvedCallableReferenceAtom
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.scopes.impl.overrides
@@ -79,10 +82,15 @@ class ConeOverloadConflictResolver(
candidates
// The same logic as at
val noOverrides = filterOverrides(fixedCandidates)
val candidatesWithoutOverrides = filterOverrides(fixedCandidates)
val noCompatibilityMode = inferenceComponents.session.languageVersionSettings.supportsFeature(
LanguageFeature.DisableCompatibilityModeForNewInference
)
return chooseMaximallySpecificCandidates(
noOverrides,
candidatesWithoutOverrides,
// (in compatibility mode the next two are already filtered on tower resolver level)
discriminateLowPrioritySAMs = noCompatibilityMode,
discriminateAdaptationsInPostponedAtoms = noCompatibilityMode,
discriminateGenerics,
discriminateAbstracts,
discriminateSAMs = true,
@@ -156,6 +164,8 @@ class ConeOverloadConflictResolver(
private fun chooseMaximallySpecificCandidates(
candidates: Set<Candidate>,
discriminateLowPrioritySAMs: Boolean,
discriminateAdaptationsInPostponedAtoms: Boolean,
discriminateGenerics: Boolean,
discriminateAbstracts: Boolean,
// Only set to 'false' by recursive calls when the relevant discrimination kind has been already applied
@@ -163,9 +173,42 @@ class ConeOverloadConflictResolver(
discriminateSuspendConversions: Boolean,
discriminateByUnwrappedSmartCastOrigin: Boolean,
): Set<Candidate> {
val withoutLowPrioritySAM = candidates.filterTo(mutableSetOf()) { !it.shouldHaveLowPriorityDueToSAM(transformerComponents) }
if (withoutLowPrioritySAM.size == 1) {
return withoutLowPrioritySAM
if (discriminateLowPrioritySAMs) {
val filtered = candidates.filterTo(mutableSetOf()) { !it.shouldHaveLowPriorityDueToSAM(transformerComponents) }
when (filtered.size) {
1 -> return filtered
0, candidates.size -> {
}
else -> return chooseMaximallySpecificCandidates(
filtered,
discriminateLowPrioritySAMs = false,
discriminateAdaptationsInPostponedAtoms,
discriminateGenerics,
discriminateAbstracts,
discriminateSAMs,
discriminateSuspendConversions,
discriminateByUnwrappedSmartCastOrigin,
)
}
}
if (discriminateAdaptationsInPostponedAtoms) {
val filtered = candidates.filterTo(mutableSetOf()) { !it.hasPostponedAtomWithAdaptation() }
when (filtered.size) {
1 -> return filtered
0, candidates.size -> {
}
else -> return chooseMaximallySpecificCandidates(
filtered,
discriminateLowPrioritySAMs,
discriminateAdaptationsInPostponedAtoms = false,
discriminateGenerics,
discriminateAbstracts,
discriminateSAMs,
discriminateSuspendConversions,
discriminateByUnwrappedSmartCastOrigin,
)
}
}
findMaximallySpecificCall(candidates, false)?.let { return setOf(it) }
@@ -181,7 +224,10 @@ class ConeOverloadConflictResolver(
0, candidates.size -> {
}
else -> return chooseMaximallySpecificCandidates(
filtered, discriminateGenerics,
filtered,
discriminateLowPrioritySAMs,
discriminateAdaptationsInPostponedAtoms,
discriminateGenerics,
discriminateAbstracts,
discriminateSAMs = false,
discriminateSuspendConversions,
@@ -198,6 +244,8 @@ class ConeOverloadConflictResolver(
}
else -> return chooseMaximallySpecificCandidates(
filtered,
discriminateLowPrioritySAMs,
discriminateAdaptationsInPostponedAtoms,
discriminateGenerics,
discriminateAbstracts,
discriminateSAMs,
@@ -215,6 +263,8 @@ class ConeOverloadConflictResolver(
}
else -> return chooseMaximallySpecificCandidates(
filtered,
discriminateLowPrioritySAMs,
discriminateAdaptationsInPostponedAtoms,
discriminateGenerics,
discriminateAbstracts = false,
discriminateSAMs,
@@ -259,6 +309,8 @@ class ConeOverloadConflictResolver(
}
else -> return chooseMaximallySpecificCandidates(
filtered,
discriminateLowPrioritySAMs,
discriminateAdaptationsInPostponedAtoms,
discriminateGenerics,
discriminateAbstracts,
discriminateSAMs,
@@ -276,6 +328,13 @@ class ConeOverloadConflictResolver(
return candidates
}
private fun Candidate.hasPostponedAtomWithAdaptation(): Boolean {
return postponedAtoms.any {
it is ResolvedCallableReferenceAtom &&
(it.resultingReference as? FirNamedReferenceWithCandidate)?.candidate?.callableReferenceAdaptation != null
}
}
private fun findMaximallySpecificCall(
candidates: Set<Candidate>,
discriminateGenerics: Boolean,
@@ -0,0 +1,18 @@
// !CHECK_TYPE
// !DIAGNOSTICS: -UNUSED_PARAMETER
import kotlin.reflect.*
interface A
interface B : A
fun A.foo() {}
fun take(f: (A) -> Unit) {}
fun take(f: () -> Unit) {}
fun test() {
B::foo checkType { _<KFunction1<B, Unit>>() }
take(B::<!INAPPLICABLE_CANDIDATE!>foo<!>)
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// !CHECK_TYPE
// !DIAGNOSTICS: -UNUSED_PARAMETER
@@ -20,6 +20,6 @@ public interface Executor {
fun f(): String = "test"
class A {
fun schedule1(e: Executor): Future<String> = <!RETURN_TYPE_MISMATCH!>e.submit(::f)<!>
fun schedule1(e: Executor): Future<String> = e.submit(::f)
fun schedule2(e: Executor): Future<String> = <!RETURN_TYPE_MISMATCH!>e.submit { f() }<!>
}
@@ -0,0 +1,15 @@
// FIR_IDENTICAL
// FULL_JDK
// JVM_TARGET: 1.8
import java.util.concurrent.*
abstract class Logger(val service: ScheduledExecutorService) {
lateinit var future: ScheduledFuture<CompletableFuture<Void>>
abstract fun flush(): CompletableFuture<Void>
fun init() {
future = service.schedule(this::flush, 0L, TimeUnit.MILLISECONDS)
}
}
@@ -21926,6 +21926,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/j+k/recursiveSelfTypes.kt");
}
@Test
@TestMetadata("runnableOrCallable.kt")
public void testRunnableOrCallable() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/runnableOrCallable.kt");
}
@Test
@TestMetadata("safeCallDefinitelyNotNull.kt")
public void testSafeCallDefinitelyNotNull() throws Exception {