From d3a0a6cabe0c5fc54080be8ec7727b34d0b71310 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 19 Dec 2023 11:02:03 +0100 Subject: [PATCH] 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 --- ...CompilerTestFE10TestdataTestGenerated.java | 6 ++ ...sticCompilerFE10TestDataTestGenerated.java | 6 ++ ...eeOldFrontendDiagnosticsTestGenerated.java | 6 ++ ...siOldFrontendDiagnosticsTestGenerated.java | 6 ++ .../calls/ConeOverloadConflictResolver.kt | 73 +++++++++++++++++-- .../function/extensionToSupertype.fir.kt | 18 +++++ .../function/extensionToSupertype.kt | 1 - ...AdaptationForReferenceCompatibility.fir.kt | 2 +- .../tests/j+k/runnableOrCallable.kt | 15 ++++ .../test/runners/DiagnosticTestGenerated.java | 6 ++ 10 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/callableReference/function/extensionToSupertype.fir.kt create mode 100644 compiler/testData/diagnostics/tests/j+k/runnableOrCallable.kt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index 52b68678bad..7f4c37e509c 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -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 { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index 594b55f84a8..27c46aa40fd 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -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 { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index bb54b201722..8befaff6917 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -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 { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index d7ae2eb1d2e..c37c3cd9169 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -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 { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt index 878bff8b6a3..abb28198b74 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConeOverloadConflictResolver.kt @@ -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, + 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 { - 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, discriminateGenerics: Boolean, diff --git a/compiler/testData/diagnostics/tests/callableReference/function/extensionToSupertype.fir.kt b/compiler/testData/diagnostics/tests/callableReference/function/extensionToSupertype.fir.kt new file mode 100644 index 00000000000..80b76b078fb --- /dev/null +++ b/compiler/testData/diagnostics/tests/callableReference/function/extensionToSupertype.fir.kt @@ -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 { _>() } + + take(B::foo) +} diff --git a/compiler/testData/diagnostics/tests/callableReference/function/extensionToSupertype.kt b/compiler/testData/diagnostics/tests/callableReference/function/extensionToSupertype.kt index ef1fa5e6a85..806d960ee23 100644 --- a/compiler/testData/diagnostics/tests/callableReference/function/extensionToSupertype.kt +++ b/compiler/testData/diagnostics/tests/callableReference/function/extensionToSupertype.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL // !CHECK_TYPE // !DIAGNOSTICS: -UNUSED_PARAMETER diff --git a/compiler/testData/diagnostics/tests/callableReference/unitAdaptationForReferenceCompatibility.fir.kt b/compiler/testData/diagnostics/tests/callableReference/unitAdaptationForReferenceCompatibility.fir.kt index 0138885a64c..de30df9b0cc 100644 --- a/compiler/testData/diagnostics/tests/callableReference/unitAdaptationForReferenceCompatibility.fir.kt +++ b/compiler/testData/diagnostics/tests/callableReference/unitAdaptationForReferenceCompatibility.fir.kt @@ -20,6 +20,6 @@ public interface Executor { fun f(): String = "test" class A { - fun schedule1(e: Executor): Future = e.submit(::f) + fun schedule1(e: Executor): Future = e.submit(::f) fun schedule2(e: Executor): Future = e.submit { f() } } diff --git a/compiler/testData/diagnostics/tests/j+k/runnableOrCallable.kt b/compiler/testData/diagnostics/tests/j+k/runnableOrCallable.kt new file mode 100644 index 00000000000..6a88cabd0d0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/runnableOrCallable.kt @@ -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> + + abstract fun flush(): CompletableFuture + + fun init() { + future = service.schedule(this::flush, 0L, TimeUnit.MILLISECONDS) + } +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index f37f43eb908..689eee4ed9f 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -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 {