diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 50d7f4b52a7..60572a256b5 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -750,6 +750,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/syntheticPropertiesWrongImplicitReceiver.kt"); } + @TestMetadata("twoLocalLambdasWithSameName.kt") + public void testTwoLocalLambdasWithSameName() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/twoLocalLambdasWithSameName.kt"); + } + @TestMetadata("typeAliasWithNotNullBound.kt") public void testTypeAliasWithNotNullBound() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/typeAliasWithNotNullBound.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/callResolution/twoLocalLambdasWithSameName.fir.txt b/compiler/fir/analysis-tests/testData/resolve/callResolution/twoLocalLambdasWithSameName.fir.txt new file mode 100644 index 00000000000..f48539a16f7 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/callResolution/twoLocalLambdasWithSameName.fir.txt @@ -0,0 +1,19 @@ +FILE: twoLocalLambdasWithSameName.kt + public abstract interface R : R|kotlin/Any| { + } + public final fun takeInt(x: R|kotlin/Int|): R|kotlin/Unit| { + } + public final fun test(fn: R|R.() -> kotlin/String|): R|kotlin/Unit| { + lval renderer: R|| = object : R|R| { + private constructor(): R|| { + super() + } + + public final fun render(fn: R|R.() -> kotlin/Int|): R|kotlin/Unit| { + lval result: R|kotlin/Int| = R|/fn|.R|SubstitutionOverride|(this@R|/|) + R|/takeInt|(R|/result|) + } + + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/callResolution/twoLocalLambdasWithSameName.kt b/compiler/fir/analysis-tests/testData/resolve/callResolution/twoLocalLambdasWithSameName.kt new file mode 100644 index 00000000000..8e13009a5c5 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/callResolution/twoLocalLambdasWithSameName.kt @@ -0,0 +1,13 @@ +// ISSUE: KT-45316 +interface R + +fun takeInt(x: Int) {} + +fun test(fn: R.() -> String) { // (1) + val renderer = object : R { + fun render(fn: R.() -> Int) { // (2) + val result = fn() + takeInt(result) + } + } +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index c7b0e097d72..f981b0a3753 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -869,6 +869,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/syntheticPropertiesWrongImplicitReceiver.kt"); } + @Test + @TestMetadata("twoLocalLambdasWithSameName.kt") + public void testTwoLocalLambdasWithSameName() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/twoLocalLambdasWithSameName.kt"); + } + @Test @TestMetadata("typeAliasWithNotNullBound.kt") public void testTypeAliasWithNotNullBound() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index d79063baea4..31bdc2aca4f 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -876,6 +876,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/syntheticPropertiesWrongImplicitReceiver.kt"); } + @Test + @TestMetadata("twoLocalLambdasWithSameName.kt") + public void testTwoLocalLambdasWithSameName() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/twoLocalLambdasWithSameName.kt"); + } + @Test @TestMetadata("typeAliasWithNotNullBound.kt") public void testTypeAliasWithNotNullBound() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt index a06f03705ca..ca9c25afa32 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/FirInvokeResolveTowerExtension.kt @@ -331,8 +331,11 @@ private class InvokeFunctionResolveTask( candidateFactory, ) { - override fun interceptTowerGroup(towerGroup: TowerGroup): TowerGroup = - maxOf(towerGroup.InvokeResolvePriority(InvokeResolvePriority.COMMON_INVOKE), receiverGroup) + override fun interceptTowerGroup(towerGroup: TowerGroup): TowerGroup { + val invokeGroup = towerGroup.InvokeResolvePriority(InvokeResolvePriority.COMMON_INVOKE) + val max = maxOf(invokeGroup, receiverGroup) + return max.InvokeReceiver(receiverGroup) + } suspend fun runResolverForInvoke( info: CallInfo, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt index 25c59b9207f..cd7df595927 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/tower/TowerGroup.kt @@ -70,7 +70,8 @@ class TowerGroup private constructor( private val code: Long, private val debugKinds: Array, - private val invokeResolvePriority: InvokeResolvePriority = InvokeResolvePriority.NONE + private val invokeResolvePriority: InvokeResolvePriority = InvokeResolvePriority.NONE, + private val receiverGroup: TowerGroup? = null ) : Comparable { companion object { @@ -183,6 +184,8 @@ private constructor( fun TopPrioritized(depth: Int) = kindOf(TowerGroupKind.TopPrioritized(depth)) + fun InvokeReceiver(receiverGroup: TowerGroup) = TowerGroup(code, debugKinds, invokeResolvePriority, receiverGroup) + // Treating `a.foo()` common calls as more prioritized than `a.foo.invoke()` // It's not the same as TowerGroupKind because it's not about tower levels, but rather a different dimension semantically. // It could be implemented via another TowerGroupKind, but it's not clear what priority should be assigned to the new TowerGroupKind @@ -203,13 +206,23 @@ private constructor( } if (index < other.debugKinds.size) return -1 - return invokeResolvePriority.compareTo(other.invokeResolvePriority) + val actualResult = invokeResolvePriority.compareTo(other.invokeResolvePriority) + if (actualResult == 0) { + return if (receiverGroup == null || other.receiverGroup == null) 0 + else receiverGroup.debugCompareTo(other.receiverGroup) + } + return actualResult } override fun compareTo(other: TowerGroup): Int = run { val result = java.lang.Long.compareUnsigned(code, other.code) if (result != 0) return@run result - return@run invokeResolvePriority.compareTo(other.invokeResolvePriority) + val actualResult = invokeResolvePriority.compareTo(other.invokeResolvePriority) + if (actualResult == 0) { + return@run if (receiverGroup == null || other.receiverGroup == null) 0 + else receiverGroup.compareTo(other.receiverGroup) + } + return@run actualResult }.also { if (DEBUG) { val debugResult = debugCompareTo(other) @@ -226,6 +239,9 @@ private constructor( if (code != other.code) return false if (DEBUG) require(this.debugKinds.contentEquals(other.debugKinds)) { "Equals inconsistent: $this vs $other" } if (invokeResolvePriority != other.invokeResolvePriority) return false + if (receiverGroup != null && other.receiverGroup != null) { + if (receiverGroup != other.receiverGroup) return false + } return true }