IR Scripting: fix capturing of the script parameter in a fun

This commit is contained in:
Ilya Chernikov
2023-06-15 11:47:51 +02:00
committed by Space Team
parent bf3a6f7678
commit 5e3f7184d1
3 changed files with 127 additions and 97 deletions
@@ -608,7 +608,8 @@ class Fir2IrVisitor(
): IrElement = whileAnalysing(session, thisReceiverExpression) { ): IrElement = whileAnalysing(session, thisReceiverExpression) {
val calleeReference = thisReceiverExpression.calleeReference val calleeReference = thisReceiverExpression.calleeReference
val boundSymbol = calleeReference.boundSymbol val boundSymbol = calleeReference.boundSymbol
if (boundSymbol is FirClassSymbol) { when (boundSymbol) {
is FirClassSymbol -> {
// Object case // Object case
val firClass = boundSymbol.fir as FirClass val firClass = boundSymbol.fir as FirClass
val irClass = if (firClass.origin == FirDeclarationOrigin.Source) { val irClass = if (firClass.origin == FirDeclarationOrigin.Source) {
@@ -654,18 +655,21 @@ class Fir2IrVisitor(
} }
} }
} }
} else if (boundSymbol is FirScriptSymbol && calleeReference.contextReceiverNumber >= 0) { }
is FirScriptSymbol -> {
val firScript = boundSymbol.fir val firScript = boundSymbol.fir
val irScript = declarationStorage.getCachedIrScript(firScript) ?: error("IrScript for ${firScript.name} not found") val irScript = declarationStorage.getCachedIrScript(firScript) ?: error("IrScript for ${firScript.name} not found")
val receiverParameter = irScript.implicitReceiversParameters.find { it.index == calleeReference.contextReceiverNumber } val receiverParameter =
irScript.implicitReceiversParameters.find { it.index == calleeReference.contextReceiverNumber } ?: irScript.thisReceiver
if (receiverParameter != null) { if (receiverParameter != null) {
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset -> return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
IrGetValueImpl(startOffset, endOffset, receiverParameter.type, receiverParameter.symbol) IrGetValueImpl(startOffset, endOffset, receiverParameter.type, receiverParameter.symbol)
} }
} else { } else {
error("Expecting implicit receiver") // TODO: check if any valid situations possible here error("No script receiver found") // TODO: check if any valid situations possible here
} }
} else if (boundSymbol is FirCallableSymbol) { }
is FirCallableSymbol -> {
val irFunction = when (boundSymbol) { val irFunction = when (boundSymbol) {
is FirFunctionSymbol -> declarationStorage.getIrFunctionSymbol(boundSymbol).owner is FirFunctionSymbol -> declarationStorage.getIrFunctionSymbol(boundSymbol).owner
is FirPropertySymbol -> { is FirPropertySymbol -> {
@@ -688,6 +692,7 @@ class Fir2IrVisitor(
} }
} }
} }
}
// TODO handle qualified "this" in instance methods of non-inner classes (inner class cases are handled by InnerClassesLowering) // TODO handle qualified "this" in instance methods of non-inner classes (inner class cases are handled by InnerClassesLowering)
return visitQualifiedAccessExpression(thisReceiverExpression, data) return visitQualifiedAccessExpression(thisReceiverExpression, data)
} }
@@ -24,10 +24,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.interpreter.toIrConst import org.jetbrains.kotlin.ir.interpreter.toIrConst
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
@@ -75,7 +72,7 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
} }
} }
val symbolRemapper = ScriptsToClassesSymbolRemapper(scriptsToClasses) val symbolRemapper = ScriptsToClassesSymbolRemapper()
for ((irScript, irScriptClass) in scriptsToClasses) { for ((irScript, irScriptClass) in scriptsToClasses) {
finalizeScriptClass(irScriptClass, irScript, symbolRemapper) finalizeScriptClass(irScriptClass, irScript, symbolRemapper)
@@ -237,7 +234,21 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
(this as? IrDeclaration)?.let { defaultContext.copy( topLevelDeclaration = it) } ?: defaultContext (this as? IrDeclaration)?.let { defaultContext.copy( topLevelDeclaration = it) } ?: defaultContext
).transform(lambdaPatcher, ScriptFixLambdasTransformerContext()) ).transform(lambdaPatcher, ScriptFixLambdasTransformerContext())
(irScript.constructor?.patchForClass() as? IrConstructor ?: createConstructor(irScriptClass, irScript)).also { constructor -> val explicitParametersWithFields = irScript.explicitCallParameters.map { parameter ->
val field = irScriptClass.addField {
startOffset = parameter.startOffset
endOffset = parameter.endOffset
origin = IrDeclarationOrigin.SCRIPT_CALL_PARAMETER
name = parameter.name
type = parameter.type
visibility = DescriptorVisibilities.LOCAL
isFinal = true
}
parameter to field
}
(irScript.constructor?.patchForClass() as? IrConstructor
?: createConstructor(irScriptClass, irScript, implicitReceiversFieldsWithParameters)).also { constructor ->
val explicitParamsStartIndex = if (irScript.earlierScriptsParameter == null) 0 else 1 val explicitParamsStartIndex = if (irScript.earlierScriptsParameter == null) 0 else 1
val explicitParameters = constructor.valueParameters.subList( val explicitParameters = constructor.valueParameters.subList(
explicitParamsStartIndex, explicitParamsStartIndex,
@@ -265,6 +276,12 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
if (earlierScriptField != null) { if (earlierScriptField != null) {
+irSetField(irGet(irScriptClass.thisReceiver!!), earlierScriptField, irGet(irScript.earlierScriptsParameter!!)) +irSetField(irGet(irScriptClass.thisReceiver!!), earlierScriptField, irGet(irScript.earlierScriptsParameter!!))
} }
explicitParametersWithFields.forEach { (parameter, field) ->
+irSetField(
irGet(irScriptClass.thisReceiver!!),
field, irGet(parameter.type, explicitParameters.find { it.name == parameter.name }!!.symbol)
)
}
implicitReceiversFieldsWithParameters.forEach { (field, correspondingParameter) -> implicitReceiversFieldsWithParameters.forEach { (field, correspondingParameter) ->
+irSetField( +irSetField(
irGet(irScriptClass.thisReceiver!!), irGet(irScriptClass.thisReceiver!!),
@@ -328,7 +345,8 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
private fun createConstructor( private fun createConstructor(
irScriptClass: IrClass, irScriptClass: IrClass,
irScript: IrScript irScript: IrScript,
implicitReceiversFieldsWithParameters: ArrayList<Pair<IrField, IrValueParameter>>
): IrConstructor = ): IrConstructor =
with(IrFunctionBuilder().apply { with(IrFunctionBuilder().apply {
isPrimary = true isPrimary = true
@@ -349,18 +367,23 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
containerSource = containerSource, containerSource = containerSource,
) )
}.also { irConstructor -> }.also { irConstructor ->
var parametersIndex = 0
irConstructor.valueParameters = buildList { irConstructor.valueParameters = buildList {
addIfNotNull(irScript.earlierScriptsParameter) irScript.earlierScriptsParameter?.let {
add(it)
++parametersIndex
}
addAll(irScript.explicitCallParameters.map { addAll(irScript.explicitCallParameters.map {
IrValueParameterImpl( IrValueParameterImpl(
it.startOffset, it.endOffset, it.startOffset, it.endOffset,
IrDeclarationOrigin.SCRIPT_CALL_PARAMETER, IrValueParameterSymbolImpl(), IrDeclarationOrigin.SCRIPT_CALL_PARAMETER, IrValueParameterSymbolImpl(),
it.name, index = 0, it.name, index = parametersIndex++, type = it.type,
type = it.type, varargElementType = null, varargElementType = null, isCrossinline = false, isNoinline = false, isHidden = false, isAssignable = false
isCrossinline = false, isNoinline = false, isHidden = false, isAssignable = false
).also { it.parent = irScript } ).also { it.parent = irScript }
}) })
addAll(irScript.implicitReceiversParameters) implicitReceiversFieldsWithParameters.forEach {(_, param) ->
add(param)
}
addAll(irScript.providedPropertiesParameters) addAll(irScript.providedPropertiesParameters)
} }
irConstructor.parent = irScript irConstructor.parent = irScript
@@ -525,7 +548,7 @@ private class ScriptToClassTransformer(
createThisReceiverParameter(IrDeclarationOrigin.SCRIPT_THIS_RECEIVER, scriptClassReceiver.type) createThisReceiverParameter(IrDeclarationOrigin.SCRIPT_THIS_RECEIVER, scriptClassReceiver.type)
} else null } else null
} }
val isInScriptConstructor = this@transformFunctionChildren is IrConstructor && parent == irScript val isInScriptConstructor = this@transformFunctionChildren is IrConstructor && (parent == irScript || parent == irScriptClass)
val dataForChildren = val dataForChildren =
when { when {
newDispatchReceiverParameter == null -> data newDispatchReceiverParameter == null -> data
@@ -842,25 +865,30 @@ private class ScriptToClassTransformer(
} }
override fun visitGetValue(expression: IrGetValue, data: ScriptToClassTransformerContext): IrExpression { override fun visitGetValue(expression: IrGetValue, data: ScriptToClassTransformerContext): IrExpression {
val getVar = expression.symbol.owner as? IrVariable val correspondingVariable = expression.symbol.owner as? IrVariable
if (getVar != null) { val correspondingValueParameter = expression.symbol.owner as? IrValueParameter
if (irScript.explicitCallParameters.contains(getVar)) { when {
val correspondingParam = irScriptClass.constructors.single().valueParameters.find { correspondingVariable != null && irScript.explicitCallParameters.contains(correspondingVariable) -> {
it.origin == IrDeclarationOrigin.SCRIPT_CALL_PARAMETER && it.name == getVar.name val builder = context.createIrBuilder(expression.symbol)
} ?: error("script explicit parameter ${getVar.name.asString()} not found")
val newExpression = val newExpression =
IrGetValueImpl( if (data.isInScriptConstructor) {
expression.startOffset, expression.endOffset, val correspondingCtorParam = irScriptClass.constructors.single().valueParameters.find {
correspondingParam.type, correspondingParam.symbol, it.origin == IrDeclarationOrigin.SCRIPT_CALL_PARAMETER && it.name == correspondingVariable.name
expression.origin } ?: error("script explicit parameter ${correspondingVariable.name.asString()} not found")
) builder.irGet(correspondingCtorParam.type, correspondingCtorParam.symbol)
} else {
val correspondingField = irScriptClass.declarations.find {
it is IrField && it.origin == IrDeclarationOrigin.SCRIPT_CALL_PARAMETER && it.name == correspondingVariable.name
} ?: error("script explicit parameter ${correspondingVariable.name.asString()} corresponding property not found")
val scriptReceiver =
getAccessCallForScriptInstance(data, expression.startOffset, expression.endOffset, expression.origin, null)
builder.irGetField(scriptReceiver, correspondingField as IrField)
}
return super.visitExpression(newExpression, data) return super.visitExpression(newExpression, data)
} }
} else if (irScript.needsReceiverProcessing) { correspondingValueParameter != null && irScript.needsReceiverProcessing && isValidNameForReceiver(correspondingValueParameter.name) -> {
val getValueParameter = expression.symbol.owner as? IrValueParameter
if (getValueParameter != null && isValidNameForReceiver(getValueParameter.name)) {
val newExpression = getDispatchReceiverExpression( val newExpression = getDispatchReceiverExpression(
data, expression, getValueParameter.type, expression.origin, getValueParameter data, expression, correspondingValueParameter.type, expression.origin, correspondingValueParameter
) )
if (newExpression != null) { if (newExpression != null) {
return super.visitExpression(newExpression, data) return super.visitExpression(newExpression, data)
@@ -945,11 +973,9 @@ private class ScriptFixLambdasTransformer(val irScriptClass: IrClass) : IrElemen
} }
private class ScriptsToClassesSymbolRemapper( private class ScriptsToClassesSymbolRemapper : SymbolRemapper.Empty() {
val scriptsToClasses: Map<IrScript, IrClass>
) : SymbolRemapper.Empty() {
override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol = override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol =
(symbol.owner as? IrScript)?.let { scriptsToClasses[it] }?.symbol ?: symbol (symbol.owner as? IrScript)?.targetClass ?: symbol
} }
private inline fun IrClass.addAnonymousInitializer(builder: IrFunctionBuilder.() -> Unit = {}): IrAnonymousInitializer = private inline fun IrClass.addAnonymousInitializer(builder: IrFunctionBuilder.() -> Unit = {}): IrAnonymousInitializer =
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_K2: JVM_IR
// param: 10 // param: 10