K2: Complete property-candidate before starting invoke resolution
Before this commit, for property candidates in K2 their types wasn't inferred/susbtituted properly. So, when candidate for fooBar.liveLoaded.invoke() was created, the type of `fooBar.liveLoaded` was just X type parameter for which there is no any `bar()` functions in its member scope. While proposed semantics is a bit different from K1, where both property and invoke candidates are united into common system, it doesn't contradict to the specification (https://kotlinlang.org/spec/overload-resolution.html#callables-and-invoke-convention) which says explicitly that invoke-convention should be desugared as `r.foo.invoke()`, thus `r.foo` should be completed independently. Also, this strategy supports some reasonable use-cases like KT-58259 while it's still a breaking change but for more artificial-looking situations (see KT-58260) and should be passed through the language committee. The changes in stubTypeReceiverRestriction* tests looks consistent because of how `genericLambda` now works (with full completion of property call). NB: The code is going to be red once KT-54667 is fixed and also there's already similar diagnostic in K1 (INFERRED_INTO_DECLARED_UPPER_BOUNDS) ^KT-58142 Fixed ^KT-58259 Fixed ^KT-58260 Related
This commit is contained in:
committed by
Space Team
parent
481becb342
commit
7b46c59d57
+18
@@ -26869,6 +26869,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/resolve/invoke"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("completePropertyBeforeInvoke.kt")
|
||||
public void testCompletePropertyBeforeInvoke() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/completePropertyBeforeInvoke.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionValueAsNonExtension.kt")
|
||||
public void testExtensionValueAsNonExtension() throws Exception {
|
||||
@@ -26929,6 +26935,18 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeAsMemberExtensionToExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeCommonSystem.kt")
|
||||
public void testInvokeCommonSystem() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeCommonSystem.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeCommonSystem2.kt")
|
||||
public void testInvokeCommonSystem2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeCommonSystem2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeNonExtensionLambdaInContext.kt")
|
||||
public void testInvokeNonExtensionLambdaInContext() throws Exception {
|
||||
|
||||
+18
@@ -26869,6 +26869,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/resolve/invoke"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("completePropertyBeforeInvoke.kt")
|
||||
public void testCompletePropertyBeforeInvoke() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/completePropertyBeforeInvoke.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionValueAsNonExtension.kt")
|
||||
public void testExtensionValueAsNonExtension() throws Exception {
|
||||
@@ -26929,6 +26935,18 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeAsMemberExtensionToExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeCommonSystem.kt")
|
||||
public void testInvokeCommonSystem() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeCommonSystem.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeCommonSystem2.kt")
|
||||
public void testInvokeCommonSystem2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeCommonSystem2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeNonExtensionLambdaInContext.kt")
|
||||
public void testInvokeNonExtensionLambdaInContext() throws Exception {
|
||||
|
||||
+18
@@ -26869,6 +26869,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/resolve/invoke"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("completePropertyBeforeInvoke.kt")
|
||||
public void testCompletePropertyBeforeInvoke() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/completePropertyBeforeInvoke.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionValueAsNonExtension.kt")
|
||||
public void testExtensionValueAsNonExtension() throws Exception {
|
||||
@@ -26929,6 +26935,18 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeAsMemberExtensionToExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeCommonSystem.kt")
|
||||
public void testInvokeCommonSystem() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeCommonSystem.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeCommonSystem2.kt")
|
||||
public void testInvokeCommonSystem2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeCommonSystem2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeNonExtensionLambdaInContext.kt")
|
||||
public void testInvokeNonExtensionLambdaInContext() throws Exception {
|
||||
|
||||
+18
@@ -26881,6 +26881,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/resolve/invoke"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true, "multiplatform");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("completePropertyBeforeInvoke.kt")
|
||||
public void testCompletePropertyBeforeInvoke() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/completePropertyBeforeInvoke.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionValueAsNonExtension.kt")
|
||||
public void testExtensionValueAsNonExtension() throws Exception {
|
||||
@@ -26941,6 +26947,18 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeAsMemberExtensionToExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeCommonSystem.kt")
|
||||
public void testInvokeCommonSystem() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeCommonSystem.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeCommonSystem2.kt")
|
||||
public void testInvokeCommonSystem2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeCommonSystem2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeNonExtensionLambdaInContext.kt")
|
||||
public void testInvokeNonExtensionLambdaInContext() throws Exception {
|
||||
|
||||
+2
@@ -329,6 +329,8 @@ private fun BodyResolveComponents.createExplicitReceiverForInvokeByCallable(
|
||||
}
|
||||
source = info.fakeSourceForImplicitInvokeCallReceiver
|
||||
}.build().let {
|
||||
callCompleter.completeCall(it, ResolutionMode.ReceiverResolution).result
|
||||
}.let {
|
||||
transformQualifiedAccessUsingSmartcastInfo(it)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND_K2: JVM_IR, JS_IR, NATIVE
|
||||
// FIR status: ARGUMENT_TYPE_MISMATCH at ok.z(fail), actual String, expected T
|
||||
// MODULE: lib
|
||||
// FILE: l1.kt
|
||||
|
||||
@@ -13,4 +11,4 @@ fun test(ok: String, fail: String) = ok.z(fail)
|
||||
// MODULE: main(lib)
|
||||
// FILE: main.kt
|
||||
|
||||
fun box() = test("OK", "FAIL")
|
||||
fun box() = test("OK", "FAIL")
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ fun test5() {
|
||||
val <T> T.genericLambda: T.((T) -> Unit) -> Unit get() = {}
|
||||
|
||||
fun test6() {
|
||||
b {
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>b<!> {
|
||||
extension()
|
||||
genericLambda { }
|
||||
genericLambda { it.extension() }
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ fun test5() {
|
||||
val <T> T.genericLambda: T.((T) -> Unit) -> Unit get() = {}
|
||||
|
||||
fun test6() {
|
||||
b {
|
||||
<!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>b<!> {
|
||||
extension()
|
||||
genericLambda { }
|
||||
genericLambda { it.extension() }
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// FIR_IDENTICAL
|
||||
// ISSUE: KT-58142
|
||||
interface XTrackableLoading {
|
||||
val <X> Property<LoadingValue<X>>.liveLoaded: X
|
||||
get(): X = TODO()
|
||||
}
|
||||
|
||||
interface LoadingValue<T>
|
||||
|
||||
interface Property<T>
|
||||
|
||||
interface AsyncModule {
|
||||
fun bar() {}
|
||||
}
|
||||
operator fun <T : AsyncModule, R> T.invoke(handler: T.() -> R): R = TODO()
|
||||
|
||||
fun XTrackableLoading.foo(fooBar: Property<LoadingValue<AsyncModule>>) {
|
||||
fooBar.liveLoaded {
|
||||
bar()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// ISSUE: KT-58259
|
||||
|
||||
interface Box<T> {
|
||||
val value: T
|
||||
}
|
||||
|
||||
interface Res {
|
||||
operator fun invoke() {}
|
||||
}
|
||||
|
||||
val <X> Box<X>.foo: X get() = TODO()
|
||||
|
||||
fun foo(p: Box<Res>) {
|
||||
p.value.invoke() // OK
|
||||
p.value() // OK
|
||||
|
||||
p.foo.invoke() // OK
|
||||
// Error in K1, OK in K2
|
||||
p.foo()
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// ISSUE: KT-58259
|
||||
|
||||
interface Box<T> {
|
||||
val value: T
|
||||
}
|
||||
|
||||
interface Res {
|
||||
operator fun invoke() {}
|
||||
}
|
||||
|
||||
val <X> Box<X>.foo: X get() = TODO()
|
||||
|
||||
fun foo(p: Box<Res>) {
|
||||
p.value.invoke() // OK
|
||||
p.value() // OK
|
||||
|
||||
p.foo.invoke() // OK
|
||||
// Error in K1, OK in K2
|
||||
p.<!FUNCTION_EXPECTED!>foo<!>()
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// ISSUE: KT-58260
|
||||
|
||||
interface Box<T>
|
||||
|
||||
interface Res<E>
|
||||
|
||||
operator fun <F> Res<F>.invoke(f: F): F = TODO()
|
||||
|
||||
val <X> Box<in X>.foo: Res<X> get() = TODO()
|
||||
|
||||
fun foo(p: Box<in Any?>) {
|
||||
p.foo("").<!UNRESOLVED_REFERENCE!>length<!>
|
||||
p.foo.invoke("").<!UNRESOLVED_REFERENCE!>length<!>
|
||||
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>p.foo("")<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>p.foo.invoke("")<!>
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// ISSUE: KT-58260
|
||||
|
||||
interface Box<T>
|
||||
|
||||
interface Res<E>
|
||||
|
||||
operator fun <F> Res<F>.invoke(f: F): F = TODO()
|
||||
|
||||
val <X> Box<in X>.foo: Res<X> get() = TODO()
|
||||
|
||||
fun foo(p: Box<in Any?>) {
|
||||
p.foo("").length
|
||||
p.foo.invoke("").<!UNRESOLVED_REFERENCE!>length<!>
|
||||
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>p.foo("")<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>p.foo.invoke("")<!>
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
FILE fqName:<root> fileName:/variableAsFunctionCallWithGenerics.kt
|
||||
PROPERTY name:gk visibility:public modality:FINAL [val]
|
||||
FUN name:<get-gk> visibility:public modality:FINAL <T> ($receiver:T of <root>.<get-gk>) returnType:kotlin.Function0<T of <root>.<get-gk>>
|
||||
correspondingProperty: PROPERTY name:gk visibility:public modality:FINAL [val]
|
||||
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.CharSequence] reified:false
|
||||
$receiver: VALUE_PARAMETER name:<this> type:T of <root>.<get-gk>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun <get-gk> <T> (): kotlin.Function0<T of <root>.<get-gk>> declared in <root>'
|
||||
FUN_EXPR type=kotlin.Function0<T of <root>.<get-gk>> origin=LAMBDA
|
||||
FUN LOCAL_FUNCTION_FOR_LAMBDA name:<anonymous> visibility:local modality:FINAL <> () returnType:T of <root>.<get-gk>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='local final fun <anonymous> (): T of <root>.<get-gk> declared in <root>.<get-gk>'
|
||||
GET_VAR '<this>: T of <root>.<get-gk> declared in <root>.<get-gk>' type=T of <root>.<get-gk> origin=null
|
||||
FUN name:testGeneric1 visibility:public modality:FINAL <> (x:kotlin.String) returnType:T of <root>.<get-gk>
|
||||
VALUE_PARAMETER name:x index:0 type:kotlin.String
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun testGeneric1 (x: kotlin.String): T of <root>.<get-gk> declared in <root>'
|
||||
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=T of <root>.<get-gk> origin=INVOKE
|
||||
$this: CALL 'public final fun <get-gk> <T> (): kotlin.Function0<T of <root>.<get-gk>> declared in <root>' type=kotlin.Function0<kotlin.String> origin=GET_PROPERTY
|
||||
<T>: kotlin.String
|
||||
$receiver: GET_VAR 'x: kotlin.String declared in <root>.testGeneric1' type=kotlin.String origin=null
|
||||
PROPERTY name:kt26531Val visibility:public modality:FINAL [val]
|
||||
FUN name:<get-kt26531Val> visibility:public modality:FINAL <T> ($receiver:T of <root>.<get-kt26531Val>) returnType:kotlin.Function0<T of <root>.<get-kt26531Val>>
|
||||
correspondingProperty: PROPERTY name:kt26531Val visibility:public modality:FINAL [val]
|
||||
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false
|
||||
$receiver: VALUE_PARAMETER name:<this> type:T of <root>.<get-kt26531Val>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun <get-kt26531Val> <T> (): kotlin.Function0<T of <root>.<get-kt26531Val>> declared in <root>'
|
||||
FUN_EXPR type=kotlin.Function0<T of <root>.<get-kt26531Val>> origin=ANONYMOUS_FUNCTION
|
||||
FUN LOCAL_FUNCTION name:<no name provided> visibility:local modality:FINAL <> () returnType:T of <root>.<get-kt26531Val>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='local final fun <no name provided> (): T of <root>.<get-kt26531Val> declared in <root>.<get-kt26531Val>'
|
||||
GET_VAR '<this>: T of <root>.<get-kt26531Val> declared in <root>.<get-kt26531Val>' type=T of <root>.<get-kt26531Val> origin=null
|
||||
FUN name:kt26531 visibility:public modality:FINAL <> () returnType:T of <root>.<get-kt26531Val>
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun kt26531 (): T of <root>.<get-kt26531Val> declared in <root>'
|
||||
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=T of <root>.<get-kt26531Val> origin=INVOKE
|
||||
$this: CALL 'public final fun <get-kt26531Val> <T> (): kotlin.Function0<T of <root>.<get-kt26531Val>> declared in <root>' type=kotlin.Function0<kotlin.Int> origin=GET_PROPERTY
|
||||
<T>: kotlin.Int
|
||||
$receiver: CONST Int type=kotlin.Int value=7
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
val <T : CharSequence> T.gk: Function0<T>
|
||||
get(): Function0<T> {
|
||||
return local fun <anonymous>(): T {
|
||||
return <this>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun testGeneric1(x: String): T {
|
||||
return x.<get-gk><String>().invoke()
|
||||
}
|
||||
|
||||
val <T : Any?> T.kt26531Val: Function0<T>
|
||||
get(): Function0<T> {
|
||||
return local fun <no name provided>(): T {
|
||||
return <this>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun kt26531(): T {
|
||||
return 7.<get-kt26531Val><Int>().invoke()
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
val <T : CharSequence> T.gk: () -> T
|
||||
get() = { -> this }
|
||||
|
||||
|
||||
Generated
+18
@@ -27653,6 +27653,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/resolve/invoke"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("completePropertyBeforeInvoke.kt")
|
||||
public void testCompletePropertyBeforeInvoke() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/completePropertyBeforeInvoke.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("extensionValueAsNonExtension.kt")
|
||||
public void testExtensionValueAsNonExtension() throws Exception {
|
||||
@@ -27713,6 +27719,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeAsMemberExtensionToExplicitReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeCommonSystem.kt")
|
||||
public void testInvokeCommonSystem() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeCommonSystem.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeCommonSystem2.kt")
|
||||
public void testInvokeCommonSystem2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/resolve/invoke/invokeCommonSystem2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invokeNonExtensionLambdaInContext.kt")
|
||||
public void testInvokeNonExtensionLambdaInContext() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user