K2 Scripting: fix script this receiver handling in IR

also fix accessor lowering
This commit is contained in:
Ilya Chernikov
2023-05-03 15:54:13 +02:00
committed by Space Team
parent 07df03dbec
commit 02e2438d37
11 changed files with 48 additions and 23 deletions
@@ -206,7 +206,7 @@ fun FirReference.toSymbolForCall(
val property = declarationStorage.getIrPropertySymbol(boundSymbol).owner as? IrProperty val property = declarationStorage.getIrPropertySymbol(boundSymbol).owner as? IrProperty
property?.let { conversionScope.parentAccessorOfPropertyFromStack(it) }?.symbol property?.let { conversionScope.parentAccessorOfPropertyFromStack(it) }?.symbol
} }
is FirScriptSymbol -> declarationStorage.getCachedIrScript(boundSymbol.fir)?.thisReceiver?.symbol
else -> null else -> null
} }
} }
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.fir.backend.generators.OperatorExpressionGenerator
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.declarations.utils.isSealed
import org.jetbrains.kotlin.fir.declarations.utils.isSynthetic
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.deserialization.toQualifiedPropertyAccessExpression import org.jetbrains.kotlin.fir.deserialization.toQualifiedPropertyAccessExpression
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock import org.jetbrains.kotlin.fir.expressions.impl.FirContractCallBlock
@@ -41,10 +38,12 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.UNDEFINED_PARAMETER_INDEX
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrErrorTypeImpl
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.constructors
@@ -208,9 +207,25 @@ class Fir2IrVisitor(
return declarationStorage.getCachedIrScript(script)!!.also { irScript -> return declarationStorage.getCachedIrScript(script)!!.also { irScript ->
irScript.parent = conversionScope.parentFromStack() irScript.parent = conversionScope.parentFromStack()
declarationStorage.enterScope(irScript) declarationStorage.enterScope(irScript)
irScript.explicitCallParameters = script.parameters.map { parameter -> irScript.explicitCallParameters = script.parameters.map { parameter ->
declarationStorage.createIrVariable(parameter, irScript) 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
}
}
}
conversionScope.withParent(irScript) { conversionScope.withParent(irScript) {
for (statement in script.statements) { for (statement in script.statements) {
val irStatement = if (statement is FirDeclaration) { val irStatement = if (statement is FirDeclaration) {
@@ -0,0 +1,9 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.declarations.utils
const val SCRIPT_SPECIAL_NAME_STRING = "<script>"
const val SCRIPT_RECEIVER_NAME_PREFIX = "\$script_receiver"
@@ -445,9 +445,9 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
if (initializer != null) { if (initializer != null) {
field.initializer = initializer field.initializer = initializer
} }
property.addDefaultGetter(this, context.irBuiltIns)
} }
property.addDefaultGetter(this, context.irBuiltIns)
} }
} }
} }
@@ -488,11 +488,14 @@ private class ScriptToClassTransformer(
} }
} }
val scriptThisType = IrSimpleTypeImpl(irScriptClass.symbol, false, emptyList(), emptyList())
val scriptClassReceiver = val scriptClassReceiver =
irScript.thisReceiver?.transform(this, ScriptToClassTransformerContext(null, null, null, false)) ?: run { irScript.thisReceiver?.let {
it.type = scriptThisType
it.transform(this, ScriptToClassTransformerContext(null, null, null, false))
} ?: run {
context.symbolTable.enterScope(irScriptClass) context.symbolTable.enterScope(irScriptClass)
val thisType = IrSimpleTypeImpl(irScriptClass.symbol, false, emptyList(), emptyList()) val newReceiver = irScriptClass.createThisReceiverParameter(IrDeclarationOrigin.INSTANCE_RECEIVER, scriptThisType)
val newReceiver = irScriptClass.createThisReceiverParameter(IrDeclarationOrigin.INSTANCE_RECEIVER, thisType)
context.symbolTable.leaveScope(irScriptClass) context.symbolTable.leaveScope(irScriptClass)
newReceiver newReceiver
} }
@@ -689,14 +692,14 @@ private class ScriptToClassTransformer(
return super.visitMemberAccess(expression, data) as IrExpression return super.visitMemberAccess(expression, data) as IrExpression
} }
override fun visitGetField(expression: IrGetField, data: ScriptToClassTransformerContext): IrExpression { override fun visitFieldAccess(expression: IrFieldAccessExpression, data: ScriptToClassTransformerContext): IrExpression {
if (expression.receiver == null && expression.symbol.owner.needsScriptReceiver()) { if (expression.receiver == null && expression.symbol.owner.parent.let { it == irScript || it == irScriptClass }) {
expression.receiver = expression.receiver =
getAccessCallForScriptInstance( getAccessCallForScriptInstance(
data, expression.startOffset, expression.endOffset, expression.origin, originalReceiverParameter = null data, expression.startOffset, expression.endOffset, expression.origin, originalReceiverParameter = null
) )
} }
return super.visitGetField(expression, data) return super.visitFieldAccess(expression, data)
} }
override fun visitConstructorCall(expression: IrConstructorCall, data: ScriptToClassTransformerContext): IrExpression { override fun visitConstructorCall(expression: IrConstructorCall, data: ScriptToClassTransformerContext): IrExpression {
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM // IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND_K2: JVM_IR
// expected: rv: 42 // expected: rv: 42
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM // IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND_K2: JVM_IR
// expected: rv: abc // expected: rv: abc
@@ -1,6 +1,5 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM // IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND_K2: JVM_IR
// expected: rv: 42 // expected: rv: 42
@@ -1,6 +1,5 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM // IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND_K2: JVM_IR
// expected: rv: 42 // expected: rv: 42
@@ -1,6 +1,5 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM // IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND: JVM // IGNORE_BACKEND: JVM
// IGNORE_BACKEND_K2: JVM_IR
// expected: rv: 42 // expected: rv: 42
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM // IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, NATIVE, WASM
// IGNORE_BACKEND_K2: JVM_IR
// expected: rv: abc! // expected: rv: abc!
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.builder.* import org.jetbrains.kotlin.fir.declarations.builder.*
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.primaryConstructorIfAny import org.jetbrains.kotlin.fir.declarations.primaryConstructorIfAny
import org.jetbrains.kotlin.fir.declarations.utils.SCRIPT_SPECIAL_NAME_STRING
import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.providers.dependenciesSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.dependenciesSymbolProvider
import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.fir.symbols.SymbolInternals
@@ -52,7 +53,7 @@ class FirScriptConfiguratorExtensionImpl(
// TODO: rewrite/extract decision logic for clarity // TODO: rewrite/extract decision logic for clarity
configuration[ScriptCompilationConfiguration.baseClass]?.let { baseClass -> configuration[ScriptCompilationConfiguration.baseClass]?.let { baseClass ->
val baseClassFqn = FqName.fromSegments(baseClass.typeName.split(".")) val baseClassFqn = FqName.fromSegments(baseClass.typeName.split("."))
contextReceivers.add(buildContextReceiverWithFqName(baseClassFqn)) contextReceivers.add(buildContextReceiverWithFqName(baseClassFqn, Name.special(SCRIPT_SPECIAL_NAME_STRING)))
val baseClassSymbol = val baseClassSymbol =
session.dependenciesSymbolProvider.getClassLikeSymbolByClassId(ClassId(baseClassFqn.parent(), baseClassFqn.shortName())) session.dependenciesSymbolProvider.getClassLikeSymbolByClassId(ClassId(baseClassFqn.parent(), baseClassFqn.shortName()))
@@ -138,16 +139,19 @@ class FirScriptConfiguratorExtensionImpl(
configuration?.let { body.invoke(it) } configuration?.let { body.invoke(it) }
} }
private fun buildContextReceiverWithFqName(baseClassFqn: FqName) = private fun buildContextReceiverWithFqName(classFqn: FqName, customName: Name? = null) =
buildContextReceiver { buildContextReceiver {
typeRef = buildUserTypeRef { typeRef = buildUserTypeRef {
isMarkedNullable = false isMarkedNullable = false
qualifier.addAll( qualifier.addAll(
baseClassFqn.pathSegments().map { classFqn.pathSegments().map {
FirQualifierPartImpl(null, it, FirTypeArgumentListImpl(null)) FirQualifierPartImpl(null, it, FirTypeArgumentListImpl(null))
} }
) )
} }
if (customName != null) {
customLabelName = customName
}
} }
private val _knownAnnotationsForSamWithReceiver = hashSetOf<String>() private val _knownAnnotationsForSamWithReceiver = hashSetOf<String>()