IR Scripting: fix capturing of the script parameter in a fun
This commit is contained in:
committed by
Space Team
parent
bf3a6f7678
commit
5e3f7184d1
@@ -608,83 +608,88 @@ class Fir2IrVisitor(
|
||||
): IrElement = whileAnalysing(session, thisReceiverExpression) {
|
||||
val calleeReference = thisReceiverExpression.calleeReference
|
||||
val boundSymbol = calleeReference.boundSymbol
|
||||
if (boundSymbol is FirClassSymbol) {
|
||||
// Object case
|
||||
val firClass = boundSymbol.fir as FirClass
|
||||
val irClass = if (firClass.origin == FirDeclarationOrigin.Source) {
|
||||
// We anyway can use 'else' branch as fallback, but
|
||||
// this is an additional check of FIR2IR invariants
|
||||
// (source classes should be already built when we analyze bodies)
|
||||
classifierStorage.getCachedIrClass(firClass)!!
|
||||
} else {
|
||||
classifierStorage.getIrClassSymbol(boundSymbol).owner
|
||||
}
|
||||
// NB: IR generates anonymous objects as classes, not singleton objects
|
||||
if (firClass is FirRegularClass && firClass.classKind == ClassKind.OBJECT && !isThisForClassPhysicallyAvailable(irClass)) {
|
||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||
IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol)
|
||||
when (boundSymbol) {
|
||||
is FirClassSymbol -> {
|
||||
// Object case
|
||||
val firClass = boundSymbol.fir as FirClass
|
||||
val irClass = if (firClass.origin == FirDeclarationOrigin.Source) {
|
||||
// We anyway can use 'else' branch as fallback, but
|
||||
// this is an additional check of FIR2IR invariants
|
||||
// (source classes should be already built when we analyze bodies)
|
||||
classifierStorage.getCachedIrClass(firClass)!!
|
||||
} else {
|
||||
classifierStorage.getIrClassSymbol(boundSymbol).owner
|
||||
}
|
||||
// NB: IR generates anonymous objects as classes, not singleton objects
|
||||
if (firClass is FirRegularClass && firClass.classKind == ClassKind.OBJECT && !isThisForClassPhysicallyAvailable(irClass)) {
|
||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||
IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val dispatchReceiver = conversionScope.dispatchReceiverParameter(irClass)
|
||||
if (dispatchReceiver != null) {
|
||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||
val thisRef = IrGetValueImpl(startOffset, endOffset, dispatchReceiver.type, dispatchReceiver.symbol)
|
||||
if (calleeReference.contextReceiverNumber != -1) {
|
||||
val constructorForCurrentlyGeneratedDelegatedConstructor =
|
||||
conversionScope.getConstructorForCurrentlyGeneratedDelegatedConstructor(irClass)
|
||||
val dispatchReceiver = conversionScope.dispatchReceiverParameter(irClass)
|
||||
if (dispatchReceiver != null) {
|
||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||
val thisRef = IrGetValueImpl(startOffset, endOffset, dispatchReceiver.type, dispatchReceiver.symbol)
|
||||
if (calleeReference.contextReceiverNumber != -1) {
|
||||
val constructorForCurrentlyGeneratedDelegatedConstructor =
|
||||
conversionScope.getConstructorForCurrentlyGeneratedDelegatedConstructor(irClass)
|
||||
|
||||
if (constructorForCurrentlyGeneratedDelegatedConstructor != null) {
|
||||
val constructorParameter =
|
||||
constructorForCurrentlyGeneratedDelegatedConstructor.valueParameters[calleeReference.contextReceiverNumber]
|
||||
IrGetValueImpl(startOffset, endOffset, constructorParameter.type, constructorParameter.symbol)
|
||||
if (constructorForCurrentlyGeneratedDelegatedConstructor != null) {
|
||||
val constructorParameter =
|
||||
constructorForCurrentlyGeneratedDelegatedConstructor.valueParameters[calleeReference.contextReceiverNumber]
|
||||
IrGetValueImpl(startOffset, endOffset, constructorParameter.type, constructorParameter.symbol)
|
||||
} else {
|
||||
val contextReceivers =
|
||||
components.classifierStorage.getFieldsWithContextReceiversForClass(irClass)
|
||||
?: error("Not defined context receivers for $irClass")
|
||||
|
||||
IrGetFieldImpl(
|
||||
startOffset, endOffset, contextReceivers[calleeReference.contextReceiverNumber].symbol,
|
||||
thisReceiverExpression.typeRef.toIrType(),
|
||||
thisRef,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val contextReceivers =
|
||||
components.classifierStorage.getFieldsWithContextReceiversForClass(irClass)
|
||||
?: error("Not defined context receivers for $irClass")
|
||||
|
||||
IrGetFieldImpl(
|
||||
startOffset, endOffset, contextReceivers[calleeReference.contextReceiverNumber].symbol,
|
||||
thisReceiverExpression.typeRef.toIrType(),
|
||||
thisRef,
|
||||
)
|
||||
thisRef
|
||||
}
|
||||
} else {
|
||||
thisRef
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (boundSymbol is FirScriptSymbol && calleeReference.contextReceiverNumber >= 0) {
|
||||
val firScript = boundSymbol.fir
|
||||
val irScript = declarationStorage.getCachedIrScript(firScript) ?: error("IrScript for ${firScript.name} not found")
|
||||
val receiverParameter = irScript.implicitReceiversParameters.find { it.index == calleeReference.contextReceiverNumber }
|
||||
if (receiverParameter != null) {
|
||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||
IrGetValueImpl(startOffset, endOffset, receiverParameter.type, receiverParameter.symbol)
|
||||
is FirScriptSymbol -> {
|
||||
val firScript = boundSymbol.fir
|
||||
val irScript = declarationStorage.getCachedIrScript(firScript) ?: error("IrScript for ${firScript.name} not found")
|
||||
val receiverParameter =
|
||||
irScript.implicitReceiversParameters.find { it.index == calleeReference.contextReceiverNumber } ?: irScript.thisReceiver
|
||||
if (receiverParameter != null) {
|
||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||
IrGetValueImpl(startOffset, endOffset, receiverParameter.type, receiverParameter.symbol)
|
||||
}
|
||||
} else {
|
||||
error("No script receiver found") // TODO: check if any valid situations possible here
|
||||
}
|
||||
} else {
|
||||
error("Expecting implicit receiver") // TODO: check if any valid situations possible here
|
||||
}
|
||||
} else if (boundSymbol is FirCallableSymbol) {
|
||||
val irFunction = when (boundSymbol) {
|
||||
is FirFunctionSymbol -> declarationStorage.getIrFunctionSymbol(boundSymbol).owner
|
||||
is FirPropertySymbol -> {
|
||||
val property = declarationStorage.getIrPropertySymbol(boundSymbol).owner as? IrProperty
|
||||
property?.let { conversionScope.parentAccessorOfPropertyFromStack(it) }
|
||||
is FirCallableSymbol -> {
|
||||
val irFunction = when (boundSymbol) {
|
||||
is FirFunctionSymbol -> declarationStorage.getIrFunctionSymbol(boundSymbol).owner
|
||||
is FirPropertySymbol -> {
|
||||
val property = declarationStorage.getIrPropertySymbol(boundSymbol).owner as? IrProperty
|
||||
property?.let { conversionScope.parentAccessorOfPropertyFromStack(it) }
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
val receiver = irFunction?.let { function ->
|
||||
if (calleeReference.contextReceiverNumber != -1)
|
||||
function.valueParameters[calleeReference.contextReceiverNumber]
|
||||
else
|
||||
function.extensionReceiverParameter
|
||||
}
|
||||
val receiver = irFunction?.let { function ->
|
||||
if (calleeReference.contextReceiverNumber != -1)
|
||||
function.valueParameters[calleeReference.contextReceiverNumber]
|
||||
else
|
||||
function.extensionReceiverParameter
|
||||
}
|
||||
|
||||
if (receiver != null) {
|
||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||
IrGetValueImpl(startOffset, endOffset, receiver.type, receiver.symbol)
|
||||
if (receiver != null) {
|
||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||
IrGetValueImpl(startOffset, endOffset, receiver.type, receiver.symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+58
-32
@@ -24,10 +24,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.toIrBasedKotlinType
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
||||
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.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.toIrConst
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
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) {
|
||||
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
|
||||
).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 explicitParameters = constructor.valueParameters.subList(
|
||||
explicitParamsStartIndex,
|
||||
@@ -265,6 +276,12 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
|
||||
if (earlierScriptField != null) {
|
||||
+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) ->
|
||||
+irSetField(
|
||||
irGet(irScriptClass.thisReceiver!!),
|
||||
@@ -328,7 +345,8 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
|
||||
|
||||
private fun createConstructor(
|
||||
irScriptClass: IrClass,
|
||||
irScript: IrScript
|
||||
irScript: IrScript,
|
||||
implicitReceiversFieldsWithParameters: ArrayList<Pair<IrField, IrValueParameter>>
|
||||
): IrConstructor =
|
||||
with(IrFunctionBuilder().apply {
|
||||
isPrimary = true
|
||||
@@ -349,18 +367,23 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext, val inner
|
||||
containerSource = containerSource,
|
||||
)
|
||||
}.also { irConstructor ->
|
||||
var parametersIndex = 0
|
||||
irConstructor.valueParameters = buildList {
|
||||
addIfNotNull(irScript.earlierScriptsParameter)
|
||||
irScript.earlierScriptsParameter?.let {
|
||||
add(it)
|
||||
++parametersIndex
|
||||
}
|
||||
addAll(irScript.explicitCallParameters.map {
|
||||
IrValueParameterImpl(
|
||||
it.startOffset, it.endOffset,
|
||||
IrDeclarationOrigin.SCRIPT_CALL_PARAMETER, IrValueParameterSymbolImpl(),
|
||||
it.name, index = 0,
|
||||
type = it.type, varargElementType = null,
|
||||
isCrossinline = false, isNoinline = false, isHidden = false, isAssignable = false
|
||||
it.name, index = parametersIndex++, type = it.type,
|
||||
varargElementType = null, isCrossinline = false, isNoinline = false, isHidden = false, isAssignable = false
|
||||
).also { it.parent = irScript }
|
||||
})
|
||||
addAll(irScript.implicitReceiversParameters)
|
||||
implicitReceiversFieldsWithParameters.forEach {(_, param) ->
|
||||
add(param)
|
||||
}
|
||||
addAll(irScript.providedPropertiesParameters)
|
||||
}
|
||||
irConstructor.parent = irScript
|
||||
@@ -525,7 +548,7 @@ private class ScriptToClassTransformer(
|
||||
createThisReceiverParameter(IrDeclarationOrigin.SCRIPT_THIS_RECEIVER, scriptClassReceiver.type)
|
||||
} else null
|
||||
}
|
||||
val isInScriptConstructor = this@transformFunctionChildren is IrConstructor && parent == irScript
|
||||
val isInScriptConstructor = this@transformFunctionChildren is IrConstructor && (parent == irScript || parent == irScriptClass)
|
||||
val dataForChildren =
|
||||
when {
|
||||
newDispatchReceiverParameter == null -> data
|
||||
@@ -842,25 +865,30 @@ private class ScriptToClassTransformer(
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue, data: ScriptToClassTransformerContext): IrExpression {
|
||||
val getVar = expression.symbol.owner as? IrVariable
|
||||
if (getVar != null) {
|
||||
if (irScript.explicitCallParameters.contains(getVar)) {
|
||||
val correspondingParam = irScriptClass.constructors.single().valueParameters.find {
|
||||
it.origin == IrDeclarationOrigin.SCRIPT_CALL_PARAMETER && it.name == getVar.name
|
||||
} ?: error("script explicit parameter ${getVar.name.asString()} not found")
|
||||
val correspondingVariable = expression.symbol.owner as? IrVariable
|
||||
val correspondingValueParameter = expression.symbol.owner as? IrValueParameter
|
||||
when {
|
||||
correspondingVariable != null && irScript.explicitCallParameters.contains(correspondingVariable) -> {
|
||||
val builder = context.createIrBuilder(expression.symbol)
|
||||
val newExpression =
|
||||
IrGetValueImpl(
|
||||
expression.startOffset, expression.endOffset,
|
||||
correspondingParam.type, correspondingParam.symbol,
|
||||
expression.origin
|
||||
)
|
||||
if (data.isInScriptConstructor) {
|
||||
val correspondingCtorParam = irScriptClass.constructors.single().valueParameters.find {
|
||||
it.origin == IrDeclarationOrigin.SCRIPT_CALL_PARAMETER && it.name == correspondingVariable.name
|
||||
} ?: 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)
|
||||
}
|
||||
} else if (irScript.needsReceiverProcessing) {
|
||||
val getValueParameter = expression.symbol.owner as? IrValueParameter
|
||||
if (getValueParameter != null && isValidNameForReceiver(getValueParameter.name)) {
|
||||
correspondingValueParameter != null && irScript.needsReceiverProcessing && isValidNameForReceiver(correspondingValueParameter.name) -> {
|
||||
val newExpression = getDispatchReceiverExpression(
|
||||
data, expression, getValueParameter.type, expression.origin, getValueParameter
|
||||
data, expression, correspondingValueParameter.type, expression.origin, correspondingValueParameter
|
||||
)
|
||||
if (newExpression != null) {
|
||||
return super.visitExpression(newExpression, data)
|
||||
@@ -945,11 +973,9 @@ private class ScriptFixLambdasTransformer(val irScriptClass: IrClass) : IrElemen
|
||||
}
|
||||
|
||||
|
||||
private class ScriptsToClassesSymbolRemapper(
|
||||
val scriptsToClasses: Map<IrScript, IrClass>
|
||||
) : SymbolRemapper.Empty() {
|
||||
private class ScriptsToClassesSymbolRemapper : SymbolRemapper.Empty() {
|
||||
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 =
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_K2: JVM_IR
|
||||
|
||||
// param: 10
|
||||
|
||||
|
||||
Reference in New Issue
Block a user