[FIR] Fix tower priorities for invoke resolve

#KT-45316 Fixed
This commit is contained in:
Dmitriy Novozhilov
2021-03-11 17:42:55 +03:00
parent cfca7183e5
commit fc2d294b6c
7 changed files with 73 additions and 5 deletions
@@ -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");
@@ -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|<anonymous>| = object : R|R| {
private constructor(): R|<anonymous>| {
super<R|kotlin/Any|>()
}
public final fun render(fn: R|R.() -> kotlin/Int|): R|kotlin/Unit| {
lval result: R|kotlin/Int| = R|<local>/fn|.R|SubstitutionOverride<kotlin/Function1.invoke: R|kotlin/Int|>|(this@R|/<anonymous>|)
R|/takeInt|(R|<local>/result|)
}
}
}
@@ -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)
}
}
}
@@ -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 {
@@ -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 {
@@ -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,
@@ -70,7 +70,8 @@ class TowerGroup
private constructor(
private val code: Long,
private val debugKinds: Array<TowerGroupKind>,
private val invokeResolvePriority: InvokeResolvePriority = InvokeResolvePriority.NONE
private val invokeResolvePriority: InvokeResolvePriority = InvokeResolvePriority.NONE,
private val receiverGroup: TowerGroup? = null
) : Comparable<TowerGroup> {
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
}