[FIR] Fix resolution of objects in presence of low-priority candidates

For CallKind.VariableAccess, the condition when to *skip* resolution of
objects was previously collector.isSuccess. This wasn't strict enough
because collector.isSuccess could be true when the best found candidate
has an applicability like RESOLVED_WITH_LOW_PRIORITY (e.g. from dynamic
scope or annotated with @LowPriorityInOverloadResolution). In these
cases, we do want to resolve objects. To fix this, the condition is
changed to collector.shouldStopResolve which is stricter.

#KT-57960 Fixed
This commit is contained in:
Kirill Rakhman
2023-04-17 18:31:50 +02:00
committed by Space Team
parent bc7aea1426
commit 8b47a4fa48
14 changed files with 228 additions and 2 deletions
@@ -39239,6 +39239,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt35210.kt");
}
@Test
@TestMetadata("lowPriorityTopLevelValAndObject.kt")
public void testLowPriorityTopLevelValAndObject() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/lowPriorityTopLevelValAndObject.kt");
}
@Test
@TestMetadata("moreOnlyInputTypes.kt")
public void testMoreOnlyInputTypes() throws Exception {
@@ -39239,6 +39239,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt35210.kt");
}
@Test
@TestMetadata("lowPriorityTopLevelValAndObject.kt")
public void testLowPriorityTopLevelValAndObject() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/lowPriorityTopLevelValAndObject.kt");
}
@Test
@TestMetadata("moreOnlyInputTypes.kt")
public void testMoreOnlyInputTypes() throws Exception {
@@ -39239,6 +39239,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt35210.kt");
}
@Test
@TestMetadata("lowPriorityTopLevelValAndObject.kt")
public void testLowPriorityTopLevelValAndObject() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/lowPriorityTopLevelValAndObject.kt");
}
@Test
@TestMetadata("moreOnlyInputTypes.kt")
public void testMoreOnlyInputTypes() throws Exception {
@@ -39335,6 +39335,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt35210.kt");
}
@Test
@TestMetadata("lowPriorityTopLevelValAndObject.kt")
public void testLowPriorityTopLevelValAndObject() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/lowPriorityTopLevelValAndObject.kt");
}
@Test
@TestMetadata("moreOnlyInputTypes.kt")
public void testMoreOnlyInputTypes() throws Exception {
@@ -51,7 +51,7 @@ open class CandidateCollector(
open fun shouldStopAtTheGroup(group: TowerGroup): Boolean =
shouldStopResolve && bestGroup < group
private val shouldStopResolve: Boolean
val shouldStopResolve: Boolean
get() = currentApplicability.shouldStopResolve
val isSuccess: Boolean
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
internal class CandidateFactoriesAndCollectors(
// Common calls
@@ -45,7 +46,11 @@ internal class TowerLevelHandler {
CallKind.VariableAccess -> {
processResult += towerLevel.processPropertiesByName(info, processor)
if (!collector.isSuccess && towerLevel is ScopeTowerLevel && !towerLevel.areThereExtensionReceiverOptions()) {
// Top-level properties win over objects. Therefore, if we find properties, we don't want to look for objects here.
// However, this only applies if the best current candidate applicability has shouldStopResolve == true. Exceptions to this
// are candidates from dynamic scopes or properties with @LowPriorityInOverloadResolution (from earlier or the same level),
// therefore we check for collector.shouldStopResolve and not collector.isSuccess.
if (!collector.shouldStopResolve && towerLevel is ScopeTowerLevel && !towerLevel.areThereExtensionReceiverOptions()) {
processResult += towerLevel.processObjectsByName(info, processor)
}
}
@@ -0,0 +1,52 @@
FILE: kt57960.kt
public final class Bar : R|kotlin/Any| {
public constructor(): R|Bar| {
super<R|kotlin/Any|>()
}
public final var toDOM: R|((Baz) -> kotlin/Any)?| = Null(null)
public get(): R|((Baz) -> kotlin/Any)?|
public set(value: R|((Baz) -> kotlin/Any)?|): R|kotlin/Unit|
}
public final class Baz : R|kotlin/Any| {
public constructor(): R|Baz| {
super<R|kotlin/Any|>()
}
public final var text: R|kotlin/String| = String()
public get(): R|kotlin/String|
public set(value: R|kotlin/String|): R|kotlin/Unit|
}
public final object Foo : R|kotlin/Any| {
private constructor(): R|Foo| {
super<R|kotlin/Any|>()
}
public final fun create2(toDOM: R|((Baz) -> kotlin/Any)?| = Null(null)): R|Bar| {
^create2 R|/jso|<R|Bar|>(<L> = jso@fun R|Bar|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=UNKNOWN> {
R|<local>/toDOM|?.{ $subj$.R|kotlin/let|<R|(Baz) -> kotlin/Any|, R|kotlin/Unit|>(<L> = let@fun <anonymous>(it: R|(Baz) -> kotlin/Any|): R|kotlin/Unit| <inline=Inline, kind=EXACTLY_ONCE> {
this@R|special/anonymous|.R|/Bar.toDOM| = R|<local>/it|
}
) }
}
)
}
}
private final fun buildSchemaNodes1(): R|kotlin/Unit| {
R|/jso|<R|dynamic|>(<L> = jso@fun R|dynamic|.<anonymous>(): R|kotlin/Unit| <inline=Inline, kind=UNKNOWN> {
Q|Foo|.R|/Foo.create2|(toDOM = create2@fun <anonymous>(domNode: R|Baz|): R|kotlin/Any| <inline=NoInline> {
^ R|<local>/domNode|.R|/Baz.text|
}
)
}
)
}
public final fun <T : R|kotlin/Any|> jso(): R|T| {
^jso R|kotlin/js/js|(String(({})))
}
public final inline fun <T : R|kotlin/Any|> jso(block: R|T.() -> kotlin/Unit|): R|T| {
^jso R|/jso|<R|T|>().R|kotlin/apply|<R|T|>(R|<local>/block|)
}
@@ -0,0 +1,34 @@
// FIR_IDENTICAL
// FIR_DUMP
// ISSUE: KT-57960
class Bar {
var toDOM: ((Baz) -> Any)? = null
}
class Baz {
var text: String = ""
}
object Foo {
fun create2(
toDOM: ((Baz) -> Any)? = null,
) = jso<Bar> {
toDOM?.let { this.toDOM = it }
}
}
private fun buildSchemaNodes1() {
jso<dynamic> {
Foo.create2(toDOM = { domNode -> domNode.text })
}
}
fun <T : Any> jso(): T =
js("({})")
inline fun <T : Any> jso(
block: T.() -> Unit,
): T =
jso<T>().apply(block)
@@ -0,0 +1,27 @@
FILE: objectAccessInLambdaWithDynamicReceiver.kt
public final fun jso(block: R|dynamic.() -> kotlin/Unit|): R|dynamic| {
^jso R|kotlin/js/js|(String(({}))).R|<dynamic>/apply|(vararg(R|<local>/block|))
}
public final class G : R|kotlin/Any| {
public constructor(): R|G| {
super<R|kotlin/Any|>()
}
public final companion object Companion : R|kotlin/Any| {
private constructor(): R|G.Companion| {
super<R|kotlin/Any|>()
}
public final val foo: R|kotlin/String| = String(string)
public get(): R|kotlin/String|
}
}
public final fun test(): R|kotlin/Unit| {
R|/jso|(<L> = jso@fun R|dynamic|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
R|/G.G|()
Q|G|.R|/G.Companion.foo|
}
)
}
@@ -0,0 +1,17 @@
// FIR_IDENTICAL
// FIR_DUMP
fun jso(block: dynamic.() -> Unit): dynamic = js("({})").apply(block)
class G {
companion object {
val foo = "string"
}
}
fun test() {
jso {
<!DEBUG_INFO_EXPRESSION_TYPE("G")!>G()<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>G.foo<!>
}
}
@@ -0,0 +1,37 @@
// FIR_IDENTICAL
// DIAGNOSTICS: -EXTENSION_SHADOWED_BY_MEMBER
// FILE: a.kt
package a
val bar get() = ""
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.LowPriorityInOverloadResolution
val baz get() = ""
// FILE: b.kt
package b
object bar
object baz {
val qux = 1
}
// FILE: test.kt
import a.*
import b.*
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
class Foo {
@kotlin.internal.LowPriorityInOverloadResolution
val bar = 1
@kotlin.internal.LowPriorityInOverloadResolution
val baz = 1
}
fun Foo.test() {
bar.length
baz.qux
}
@@ -40107,6 +40107,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/kt35210.kt");
}
@Test
@TestMetadata("lowPriorityTopLevelValAndObject.kt")
public void testLowPriorityTopLevelValAndObject() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/inference/annotationsForResolve/lowPriorityTopLevelValAndObject.kt");
}
@Test
@TestMetadata("moreOnlyInputTypes.kt")
public void testMoreOnlyInputTypes() throws Exception {
@@ -289,6 +289,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
runTest("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/inference.kt");
}
@Test
@TestMetadata("kt57960.kt")
public void testKt57960() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/kt57960.kt");
}
@Test
@TestMetadata("membersOfAny.kt")
public void testMembersOfAny() throws Exception {
@@ -313,6 +319,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
runTest("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/nullable.kt");
}
@Test
@TestMetadata("objectAccessInLambdaWithDynamicReceiver.kt")
public void testObjectAccessInLambdaWithDynamicReceiver() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/objectAccessInLambdaWithDynamicReceiver.kt");
}
@Test
@TestMetadata("overloading.kt")
public void testOverloading() throws Exception {
@@ -290,6 +290,12 @@ public class FirPsiJsOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiJ
runTest("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/inference.kt");
}
@Test
@TestMetadata("kt57960.kt")
public void testKt57960() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/kt57960.kt");
}
@Test
@TestMetadata("membersOfAny.kt")
public void testMembersOfAny() throws Exception {
@@ -314,6 +320,12 @@ public class FirPsiJsOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiJ
runTest("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/nullable.kt");
}
@Test
@TestMetadata("objectAccessInLambdaWithDynamicReceiver.kt")
public void testObjectAccessInLambdaWithDynamicReceiver() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/objectAccessInLambdaWithDynamicReceiver.kt");
}
@Test
@TestMetadata("overloading.kt")
public void testOverloading() throws Exception {