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) {
|
): 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) {
|
||||||
// Object case
|
is FirClassSymbol -> {
|
||||||
val firClass = boundSymbol.fir as FirClass
|
// Object case
|
||||||
val irClass = if (firClass.origin == FirDeclarationOrigin.Source) {
|
val firClass = boundSymbol.fir as FirClass
|
||||||
// We anyway can use 'else' branch as fallback, but
|
val irClass = if (firClass.origin == FirDeclarationOrigin.Source) {
|
||||||
// this is an additional check of FIR2IR invariants
|
// We anyway can use 'else' branch as fallback, but
|
||||||
// (source classes should be already built when we analyze bodies)
|
// this is an additional check of FIR2IR invariants
|
||||||
classifierStorage.getCachedIrClass(firClass)!!
|
// (source classes should be already built when we analyze bodies)
|
||||||
} else {
|
classifierStorage.getCachedIrClass(firClass)!!
|
||||||
classifierStorage.getIrClassSymbol(boundSymbol).owner
|
} 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)) {
|
// NB: IR generates anonymous objects as classes, not singleton objects
|
||||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
if (firClass is FirRegularClass && firClass.classKind == ClassKind.OBJECT && !isThisForClassPhysicallyAvailable(irClass)) {
|
||||||
IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol)
|
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||||
|
IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val dispatchReceiver = conversionScope.dispatchReceiverParameter(irClass)
|
val dispatchReceiver = conversionScope.dispatchReceiverParameter(irClass)
|
||||||
if (dispatchReceiver != null) {
|
if (dispatchReceiver != null) {
|
||||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||||
val thisRef = IrGetValueImpl(startOffset, endOffset, dispatchReceiver.type, dispatchReceiver.symbol)
|
val thisRef = IrGetValueImpl(startOffset, endOffset, dispatchReceiver.type, dispatchReceiver.symbol)
|
||||||
if (calleeReference.contextReceiverNumber != -1) {
|
if (calleeReference.contextReceiverNumber != -1) {
|
||||||
val constructorForCurrentlyGeneratedDelegatedConstructor =
|
val constructorForCurrentlyGeneratedDelegatedConstructor =
|
||||||
conversionScope.getConstructorForCurrentlyGeneratedDelegatedConstructor(irClass)
|
conversionScope.getConstructorForCurrentlyGeneratedDelegatedConstructor(irClass)
|
||||||
|
|
||||||
if (constructorForCurrentlyGeneratedDelegatedConstructor != null) {
|
if (constructorForCurrentlyGeneratedDelegatedConstructor != null) {
|
||||||
val constructorParameter =
|
val constructorParameter =
|
||||||
constructorForCurrentlyGeneratedDelegatedConstructor.valueParameters[calleeReference.contextReceiverNumber]
|
constructorForCurrentlyGeneratedDelegatedConstructor.valueParameters[calleeReference.contextReceiverNumber]
|
||||||
IrGetValueImpl(startOffset, endOffset, constructorParameter.type, constructorParameter.symbol)
|
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 {
|
} else {
|
||||||
val contextReceivers =
|
thisRef
|
||||||
components.classifierStorage.getFieldsWithContextReceiversForClass(irClass)
|
|
||||||
?: error("Not defined context receivers for $irClass")
|
|
||||||
|
|
||||||
IrGetFieldImpl(
|
|
||||||
startOffset, endOffset, contextReceivers[calleeReference.contextReceiverNumber].symbol,
|
|
||||||
thisReceiverExpression.typeRef.toIrType(),
|
|
||||||
thisRef,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
thisRef
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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 =
|
||||||
if (receiverParameter != null) {
|
irScript.implicitReceiversParameters.find { it.index == calleeReference.contextReceiverNumber } ?: irScript.thisReceiver
|
||||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
if (receiverParameter != null) {
|
||||||
IrGetValueImpl(startOffset, endOffset, receiverParameter.type, receiverParameter.symbol)
|
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) {
|
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 -> {
|
||||||
val property = declarationStorage.getIrPropertySymbol(boundSymbol).owner as? IrProperty
|
val property = declarationStorage.getIrPropertySymbol(boundSymbol).owner as? IrProperty
|
||||||
property?.let { conversionScope.parentAccessorOfPropertyFromStack(it) }
|
property?.let { conversionScope.parentAccessorOfPropertyFromStack(it) }
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
val receiver = irFunction?.let { function ->
|
val receiver = irFunction?.let { function ->
|
||||||
if (calleeReference.contextReceiverNumber != -1)
|
if (calleeReference.contextReceiverNumber != -1)
|
||||||
function.valueParameters[calleeReference.contextReceiverNumber]
|
function.valueParameters[calleeReference.contextReceiverNumber]
|
||||||
else
|
else
|
||||||
function.extensionReceiverParameter
|
function.extensionReceiverParameter
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||||
IrGetValueImpl(startOffset, endOffset, receiver.type, receiver.symbol)
|
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.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,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_K2: JVM_IR
|
|
||||||
|
|
||||||
// param: 10
|
// param: 10
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user