diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index 82dd0cdceb0..f0a53db2392 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -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) + } } } } diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt index b579920696e..fb98247e51a 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt @@ -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> ): 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 -) : 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 = diff --git a/compiler/testData/codegen/script/parameterClosure.kts b/compiler/testData/codegen/script/parameterClosure.kts index cd6f65c3f1c..3bd48dd6ef2 100644 --- a/compiler/testData/codegen/script/parameterClosure.kts +++ b/compiler/testData/codegen/script/parameterClosure.kts @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_K2: JVM_IR // param: 10