K2 Scripting: add support for script implicit receivers

This commit is contained in:
Ilya Chernikov
2023-05-03 15:54:13 +02:00
committed by Space Team
parent 480ea80fc4
commit 6c7751b0af
4 changed files with 44 additions and 13 deletions
@@ -217,18 +217,28 @@ class Fir2IrVisitor(
declarationStorage.createIrVariable(parameter, irScript, givenOrigin = IrDeclarationOrigin.SCRIPT_CALL_PARAMETER) declarationStorage.createIrVariable(parameter, irScript, givenOrigin = IrDeclarationOrigin.SCRIPT_CALL_PARAMETER)
} }
irScript.thisReceiver = script.contextReceivers.find { it.customLabelName?.asString() == SCRIPT_SPECIAL_NAME_STRING }?.let { receiver -> // NOTE: index should correspond to one generated in the collectTowerDataElementsForScript
receiver.convertWithOffsets { startOffset, endOffset -> irScript.implicitReceiversParameters = script.contextReceivers.mapIndexedNotNull { index, receiver ->
irFactory.createValueParameter( val isSelf = receiver.customLabelName?.asString() == SCRIPT_SPECIAL_NAME_STRING
startOffset, endOffset, IrDeclarationOrigin.INSTANCE_RECEIVER, SpecialNames.THIS, receiver.typeRef.toIrType(), val name =
isAssignable = false, IrValueParameterSymbolImpl(), UNDEFINED_PARAMETER_INDEX, if (isSelf) SpecialNames.THIS
varargElementType = null, else Name.identifier("${receiver.labelName?.asStringStripSpecialMarkers() ?: SCRIPT_RECEIVER_NAME_PREFIX}_$index")
isCrossinline = false, isNoinline = false, val origin = if (isSelf) IrDeclarationOrigin.INSTANCE_RECEIVER else IrDeclarationOrigin.SCRIPT_IMPLICIT_RECEIVER
isHidden = false, val irReceiver =
).also { receiver.convertWithOffsets { startOffset, endOffset ->
it.parent = irScript 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) { conversionScope.withParent(irScript) {
@@ -110,7 +110,7 @@ class CachingTest : TestCase() {
} }
@Test @Test
fun testImplicitReceiversWithJarCache() = expectTestToFailOnK2 { fun testImplicitReceiversWithJarCache() {
withTempDir("scriptingTestJarCache") { cacheDir -> withTempDir("scriptingTestJarCache") { cacheDir ->
val cache = TestCompiledScriptJarsCache(cacheDir) val cache = TestCompiledScriptJarsCache(cacheDir)
Assert.assertTrue(cache.baseDir.listFiles()!!.isEmpty()) Assert.assertTrue(cache.baseDir.listFiles()!!.isEmpty())
@@ -24,7 +24,7 @@ class ConstructorArgumentsOrderTest {
} }
@Test @Test
fun testScriptWithImplicitReceiver() = expectTestToFailOnK2 { fun testScriptWithImplicitReceiver() {
val res = evalString<ScriptWithImplicitReceiver>("""println(receiverString)""") { val res = evalString<ScriptWithImplicitReceiver>("""println(receiverString)""") {
implicitReceivers(ImplicitReceiverClass("Hello Receiver!")) implicitReceivers(ImplicitReceiverClass("Hello Receiver!"))
} }
@@ -223,6 +223,27 @@ class ScriptingHostTest : TestCase() {
Assert.assertEquals(greeting, output) Assert.assertEquals(greeting, output)
} }
@Test
fun testSimpleScriptWithImplicitReceiver() {
val greeting = listOf("3")
val script = "println(length)"
val definition = createJvmScriptDefinitionFromTemplate<SimpleScriptTemplate>(
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 @Test
fun testProvidedPropertiesNullability() = expectTestToFailOnK2 { fun testProvidedPropertiesNullability() = expectTestToFailOnK2 {
val stringType = KotlinType(String::class) val stringType = KotlinType(String::class)