From 6c7751b0afb6d6c58f55eee35218f1d43d2e6941 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Wed, 3 May 2023 15:54:13 +0200 Subject: [PATCH] K2 Scripting: add support for script implicit receivers --- .../kotlin/fir/backend/Fir2IrVisitor.kt | 32 ++++++++++++------- .../experimental/jvmhost/test/CachingTest.kt | 2 +- .../test/ConstructorArgumentOrderTest.kt | 2 +- .../jvmhost/test/ScriptingHostTest.kt | 21 ++++++++++++ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index e36a2bfd52e..4d860cf5f9c 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -217,18 +217,28 @@ class Fir2IrVisitor( declarationStorage.createIrVariable(parameter, irScript, givenOrigin = IrDeclarationOrigin.SCRIPT_CALL_PARAMETER) } - irScript.thisReceiver = script.contextReceivers.find { it.customLabelName?.asString() == SCRIPT_SPECIAL_NAME_STRING }?.let { receiver -> - receiver.convertWithOffsets { startOffset, endOffset -> - irFactory.createValueParameter( - startOffset, endOffset, IrDeclarationOrigin.INSTANCE_RECEIVER, SpecialNames.THIS, receiver.typeRef.toIrType(), - isAssignable = false, IrValueParameterSymbolImpl(), UNDEFINED_PARAMETER_INDEX, - varargElementType = null, - isCrossinline = false, isNoinline = false, - isHidden = false, - ).also { - it.parent = irScript + // NOTE: index should correspond to one generated in the collectTowerDataElementsForScript + irScript.implicitReceiversParameters = script.contextReceivers.mapIndexedNotNull { index, receiver -> + val isSelf = receiver.customLabelName?.asString() == SCRIPT_SPECIAL_NAME_STRING + val name = + if (isSelf) SpecialNames.THIS + else Name.identifier("${receiver.labelName?.asStringStripSpecialMarkers() ?: SCRIPT_RECEIVER_NAME_PREFIX}_$index") + val origin = if (isSelf) IrDeclarationOrigin.INSTANCE_RECEIVER else IrDeclarationOrigin.SCRIPT_IMPLICIT_RECEIVER + val irReceiver = + receiver.convertWithOffsets { startOffset, endOffset -> + irFactory.createValueParameter( + startOffset, endOffset, origin, name, receiver.typeRef.toIrType(), isAssignable = false, + IrValueParameterSymbolImpl(), + if (isSelf) UNDEFINED_PARAMETER_INDEX else index, + varargElementType = null, isCrossinline = false, isNoinline = false, isHidden = false + ).also { + it.parent = irScript + } } - } + if (isSelf) { + irScript.thisReceiver = irReceiver + null + } else irReceiver } conversionScope.withParent(irScript) { diff --git a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/CachingTest.kt b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/CachingTest.kt index adef64d4c86..e7b575eb544 100644 --- a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/CachingTest.kt +++ b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/CachingTest.kt @@ -110,7 +110,7 @@ class CachingTest : TestCase() { } @Test - fun testImplicitReceiversWithJarCache() = expectTestToFailOnK2 { + fun testImplicitReceiversWithJarCache() { withTempDir("scriptingTestJarCache") { cacheDir -> val cache = TestCompiledScriptJarsCache(cacheDir) Assert.assertTrue(cache.baseDir.listFiles()!!.isEmpty()) diff --git a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ConstructorArgumentOrderTest.kt b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ConstructorArgumentOrderTest.kt index a539af9ef93..c0ccb15fb1a 100644 --- a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ConstructorArgumentOrderTest.kt +++ b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ConstructorArgumentOrderTest.kt @@ -24,7 +24,7 @@ class ConstructorArgumentsOrderTest { } @Test - fun testScriptWithImplicitReceiver() = expectTestToFailOnK2 { + fun testScriptWithImplicitReceiver() { val res = evalString("""println(receiverString)""") { implicitReceivers(ImplicitReceiverClass("Hello Receiver!")) } diff --git a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ScriptingHostTest.kt b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ScriptingHostTest.kt index a8be84acfdf..fe81b7e1edf 100644 --- a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ScriptingHostTest.kt +++ b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ScriptingHostTest.kt @@ -223,6 +223,27 @@ class ScriptingHostTest : TestCase() { Assert.assertEquals(greeting, output) } + @Test + fun testSimpleScriptWithImplicitReceiver() { + val greeting = listOf("3") + val script = "println(length)" + val definition = createJvmScriptDefinitionFromTemplate( + compilation = { + implicitReceivers(String::class) + }, + evaluation = { + implicitReceivers("abc") + } + ) + val output = captureOut { + val retVal = BasicJvmScriptingHost().eval( + script.toScriptSource(), definition.compilationConfiguration, definition.evaluationConfiguration + ).valueOrThrow().returnValue + if (retVal is ResultValue.Error) throw retVal.error + }.lines() + Assert.assertEquals(greeting, output) + } + @Test fun testProvidedPropertiesNullability() = expectTestToFailOnK2 { val stringType = KotlinType(String::class)