Implement missing invoke resolution branch with context receivers

#KT-61937 fixed
Note: the current implementation only resolves for a single receiver
in each group. See KT-62712 and KT-62709 for the followup.
This commit is contained in:
Ilya Chernikov
2023-10-18 10:57:52 +02:00
committed by Space Team
parent b89d8a65a1
commit 268d058bbb
17 changed files with 172 additions and 1 deletions
@@ -12687,6 +12687,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt");
}
@Test
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/lambdaReceiverFromContext.kt");
}
@Test
@TestMetadata("lazy.kt")
public void testLazy() throws Exception {
@@ -12687,6 +12687,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt");
}
@Test
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/lambdaReceiverFromContext.kt");
}
@Test
@TestMetadata("lazy.kt")
public void testLazy() throws Exception {
@@ -12687,6 +12687,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt");
}
@Test
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/lambdaReceiverFromContext.kt");
}
@Test
@TestMetadata("lazy.kt")
public void testLazy() throws Exception {
@@ -12693,6 +12693,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt");
}
@Test
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/lambdaReceiverFromContext.kt");
}
@Test
@TestMetadata("lazy.kt")
public void testLazy() throws Exception {
@@ -17883,6 +17883,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/extensionClasses/generics.kt");
}
@Test
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/codegen/box/extensionClasses/lambdaReceiverFromContext.kt");
}
@Test
@TestMetadata("multiple.kt")
public void testMultiple() throws Exception {
@@ -17883,6 +17883,12 @@ public class FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated
runTest("compiler/testData/codegen/box/extensionClasses/generics.kt");
}
@Test
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/codegen/box/extensionClasses/lambdaReceiverFromContext.kt");
}
@Test
@TestMetadata("multiple.kt")
public void testMultiple() throws Exception {
@@ -17883,6 +17883,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/extensionClasses/generics.kt");
}
@Test
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/codegen/box/extensionClasses/lambdaReceiverFromContext.kt");
}
@Test
@TestMetadata("multiple.kt")
public void testMultiple() throws Exception {
@@ -443,6 +443,22 @@ private class InvokeFunctionResolveTask(
ExplicitReceiverKind.DISPATCH_RECEIVER
)
}
for ((depth, contextReceiverGroup) in towerDataElementsForName.contextReceiverGroups) {
val towerGroup =
TowerGroup
.ContextReceiverGroup(depth)
.InvokeExtensionWithImplicitReceiver
.withGivenInvokeReceiverGroup(InvokeResolvePriority.INVOKE_EXTENSION)
val towerLevel = invokeReceiverValue.toMemberScopeTowerLevel()
// TODO: resolve for all receivers in the group, but implement the ambiguity diagnostics first. See KT-62712 and KT-69709
contextReceiverGroup.singleOrNull()?.let { contextReceiverValue ->
processLevel(
towerLevel,
info.withReceiverAsArgument(contextReceiverValue.receiverExpression), towerGroup,
ExplicitReceiverKind.EXTENSION_RECEIVER
)
}
}
}
private suspend fun processLevelForRegularInvoke(
@@ -542,7 +542,12 @@ class BodyResolveContext(
val forMembersResolution =
statics
.addLocalScope(parameterScope)
.addContextReceiverGroup(towerElementsForScript.implicitReceivers)
// TODO: temporary solution for avoiding problem described in KT-62712, flatten back after fix
.let { baseCtx ->
towerElementsForScript.implicitReceivers.fold(baseCtx) { ctx, it ->
ctx.addContextReceiverGroup(listOf(it))
}
}
val newContexts = FirRegularTowerDataContexts(
regular = forMembersResolution,
@@ -0,0 +1,22 @@
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND_K1: ANY
// !LANGUAGE: +ContextReceivers
class Ctx(val value: Int)
fun Ctx.foo() = value + 4
context(Ctx)
class A {
fun bar(body: Ctx.() -> Int): Int {
return foo() *
body()
}
}
fun box(): String {
val res = with(Ctx(3)) {
A().bar { this.value * 2 }
}
return if (res == 42) "OK" else "NOK: $res"
}
@@ -0,0 +1,13 @@
// !LANGUAGE: +ContextReceivers
class Ctx
fun Ctx.foo() {}
context(Ctx)
class A {
fun bar(body: Ctx.() -> Unit) {
foo()
body()
}
}
@@ -0,0 +1,13 @@
// !LANGUAGE: +ContextReceivers
class Ctx
fun Ctx.foo() {}
context(Ctx)
class A {
fun bar(body: Ctx.() -> Unit) {
foo()
body<!NO_VALUE_FOR_PARAMETER!>()<!>
}
}
@@ -12693,6 +12693,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/labelsFromClassNameForbidden.kt");
}
@Test
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/diagnostics/tests/extensions/contextReceivers/lambdaReceiverFromContext.kt");
}
@Test
@TestMetadata("lazy.kt")
public void testLazy() throws Exception {
@@ -17883,6 +17883,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/extensionClasses/generics.kt");
}
@Test
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/codegen/box/extensionClasses/lambdaReceiverFromContext.kt");
}
@Test
@TestMetadata("multiple.kt")
public void testMultiple() throws Exception {
@@ -17883,6 +17883,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/extensionClasses/generics.kt");
}
@Test
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/codegen/box/extensionClasses/lambdaReceiverFromContext.kt");
}
@Test
@TestMetadata("multiple.kt")
public void testMultiple() throws Exception {
@@ -14829,6 +14829,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/extensionClasses/generics.kt");
}
@TestMetadata("lambdaReceiverFromContext.kt")
public void testLambdaReceiverFromContext() throws Exception {
runTest("compiler/testData/codegen/box/extensionClasses/lambdaReceiverFromContext.kt");
}
@TestMetadata("multiple.kt")
public void testMultiple() throws Exception {
runTest("compiler/testData/codegen/box/extensionClasses/multiple.kt");
@@ -292,6 +292,43 @@ class ScriptingHostTest : TestCase() {
Assert.assertEquals(result, output)
}
fun testScriptImplicitReceiversTransitiveVisibility() {
val result = listOf("42")
val script = """
import kotlin.script.experimental.jvmhost.test.forScript.p1.TestClass
fun TestClass.foo() = 6
fun test(body: TestClass.() -> Int): Int {
return foo() *
body()
}
println(test { 7 })
""".trimIndent()
val definition = createJvmScriptDefinitionFromTemplate<SimpleScriptTemplate>(
compilation = {
updateClasspath(classpathFromClass<kotlin.script.experimental.jvmhost.test.forScript.p1.TestClass>())
implicitReceivers(
kotlin.script.experimental.jvmhost.test.forScript.p1.TestClass::class,
)
},
evaluation = {
implicitReceivers(
kotlin.script.experimental.jvmhost.test.forScript.p1.TestClass(""),
)
}
)
val output = captureOut {
val evalRes = BasicJvmScriptingHost().eval(
script.toScriptSource(), definition.compilationConfiguration, definition.evaluationConfiguration
)
val retVal = evalRes.valueOrThrow().returnValue
if (retVal is ResultValue.Error) throw retVal.error
}.lines()
Assert.assertEquals(result, output)
}
@Test
fun testProvidedPropertiesNullability() {
val stringType = KotlinType(String::class)