[FIR2IR] Refactor Fir2IrVisitor.visitThisReceiverExpression
Extract processing of different kinds of bound symbol into separate functions to improve readability
This commit is contained in:
committed by
Space Team
parent
5148c70579
commit
0cbce42185
@@ -677,119 +677,139 @@ class Fir2IrVisitor(
|
|||||||
callGenerator.injectGetValueCall(thisReceiverExpression, calleeReference)?.let { return it }
|
callGenerator.injectGetValueCall(thisReceiverExpression, calleeReference)?.let { return it }
|
||||||
}
|
}
|
||||||
|
|
||||||
when (boundSymbol) {
|
val convertedExpression = when (boundSymbol) {
|
||||||
is FirClassSymbol -> {
|
is FirClassSymbol -> generateThisReceiverAccessForClass(thisReceiverExpression, boundSymbol)
|
||||||
// Object case
|
is FirScriptSymbol -> generateThisReceiverAccessForScript(thisReceiverExpression, boundSymbol)
|
||||||
val firClass = boundSymbol.fir as FirClass
|
is FirCallableSymbol -> generateThisReceiverAccessForCallable(thisReceiverExpression, boundSymbol)
|
||||||
val irClassSymbol = if (firClass.origin.fromSource || firClass.origin.generated) {
|
else -> null
|
||||||
// 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)!!.symbol
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* The only case when we can refer to non-source this is resolution to companion object of parent
|
|
||||||
* class in some constructor scope:
|
|
||||||
*
|
|
||||||
* // MODULE: lib
|
|
||||||
* abstract class Base {
|
|
||||||
* companion object {
|
|
||||||
* fun foo(): Int = 1
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* // MODULE: app(lib)
|
|
||||||
* class Derived(
|
|
||||||
* val x: Int = foo() // this: Base.Companion
|
|
||||||
* ) : Base()
|
|
||||||
*/
|
|
||||||
classifierStorage.getIrClassSymbol(boundSymbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firClass.classKind.isObject && shouldGenerateReceiverAsSingletonReference(irClassSymbol)) {
|
if (convertedExpression != null) {
|
||||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
convertedExpression
|
||||||
val irType = boundSymbol.defaultType().toIrType()
|
} else {
|
||||||
IrGetObjectValueImpl(startOffset, endOffset, irType, irClassSymbol)
|
visitQualifiedAccessExpression(thisReceiverExpression, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val irClass = conversionScope.findDeclarationInParentsStack<IrClass>(irClassSymbol)
|
private fun generateThisReceiverAccessForClass(
|
||||||
|
thisReceiverExpression: FirThisReceiverExpression,
|
||||||
|
firClassSymbol: FirClassSymbol<*>,
|
||||||
|
): IrElement? {
|
||||||
|
// Object case
|
||||||
|
val calleeReference = thisReceiverExpression.calleeReference
|
||||||
|
val firClass = firClassSymbol.fir
|
||||||
|
val irClassSymbol = if (firClass.origin.fromSource || firClass.origin.generated) {
|
||||||
|
// 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)!!.symbol
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* The only case when we can refer to non-source this is resolution to companion object of parent
|
||||||
|
* class in some constructor scope:
|
||||||
|
*
|
||||||
|
* // MODULE: lib
|
||||||
|
* abstract class Base {
|
||||||
|
* companion object {
|
||||||
|
* fun foo(): Int = 1
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // MODULE: app(lib)
|
||||||
|
* class Derived(
|
||||||
|
* val x: Int = foo() // this: Base.Companion
|
||||||
|
* ) : Base()
|
||||||
|
*/
|
||||||
|
classifierStorage.getIrClassSymbol(firClassSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
val dispatchReceiver = conversionScope.dispatchReceiverParameter(irClass)
|
if (firClass.classKind.isObject && shouldGenerateReceiverAsSingletonReference(irClassSymbol)) {
|
||||||
if (dispatchReceiver != null) {
|
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||||
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
val irType = firClassSymbol.defaultType().toIrType()
|
||||||
val thisRef = callGenerator.findInjectedValue(calleeReference)?.let {
|
IrGetObjectValueImpl(startOffset, endOffset, irType, irClassSymbol)
|
||||||
callGenerator.useInjectedValue(it, calleeReference, startOffset, endOffset)
|
|
||||||
} ?: IrGetValueImpl(startOffset, endOffset, dispatchReceiver.type, dispatchReceiver.symbol)
|
|
||||||
if (calleeReference.contextReceiverNumber != -1) {
|
|
||||||
val constructorForCurrentlyGeneratedDelegatedConstructor =
|
|
||||||
conversionScope.getConstructorForCurrentlyGeneratedDelegatedConstructor(irClass.symbol)
|
|
||||||
|
|
||||||
if (constructorForCurrentlyGeneratedDelegatedConstructor != null) {
|
|
||||||
val constructorParameter =
|
|
||||||
constructorForCurrentlyGeneratedDelegatedConstructor.valueParameters[calleeReference.contextReceiverNumber]
|
|
||||||
IrGetValueImpl(startOffset, endOffset, constructorParameter.type, constructorParameter.symbol)
|
|
||||||
} else {
|
|
||||||
val contextReceivers =
|
|
||||||
components.classifierStorage.getFieldsWithContextReceiversForClass(irClass, firClass)
|
|
||||||
require(contextReceivers.size > calleeReference.contextReceiverNumber) {
|
|
||||||
"Not defined context receiver #${calleeReference.contextReceiverNumber} for $irClass. " +
|
|
||||||
"Context receivers found: $contextReceivers"
|
|
||||||
}
|
|
||||||
|
|
||||||
IrGetFieldImpl(
|
|
||||||
startOffset, endOffset, contextReceivers[calleeReference.contextReceiverNumber].symbol,
|
|
||||||
thisReceiverExpression.resolvedType.toIrType(),
|
|
||||||
thisRef,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
thisRef
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is FirCallableSymbol -> {
|
|
||||||
val irFunction = when (boundSymbol) {
|
|
||||||
is FirFunctionSymbol -> {
|
|
||||||
val functionSymbol = declarationStorage.getIrFunctionSymbol(boundSymbol)
|
|
||||||
conversionScope.findDeclarationInParentsStack<IrSimpleFunction>(functionSymbol)
|
|
||||||
}
|
|
||||||
is FirPropertySymbol -> {
|
|
||||||
val property = declarationStorage.getIrPropertySymbol(boundSymbol) as? IrPropertySymbol
|
|
||||||
property?.let { conversionScope.parentAccessorOfPropertyFromStack(it) }
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return visitQualifiedAccessExpression(thisReceiverExpression, data)
|
|
||||||
|
val irClass = conversionScope.findDeclarationInParentsStack<IrClass>(irClassSymbol)
|
||||||
|
|
||||||
|
val dispatchReceiver = conversionScope.dispatchReceiverParameter(irClass) ?: return null
|
||||||
|
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||||
|
val thisRef = callGenerator.findInjectedValue(calleeReference)?.let {
|
||||||
|
callGenerator.useInjectedValue(it, calleeReference, startOffset, endOffset)
|
||||||
|
} ?: IrGetValueImpl(startOffset, endOffset, dispatchReceiver.type, dispatchReceiver.symbol)
|
||||||
|
|
||||||
|
if (calleeReference.contextReceiverNumber == -1) {
|
||||||
|
return thisRef
|
||||||
|
}
|
||||||
|
|
||||||
|
val constructorForCurrentlyGeneratedDelegatedConstructor =
|
||||||
|
conversionScope.getConstructorForCurrentlyGeneratedDelegatedConstructor(irClass.symbol)
|
||||||
|
|
||||||
|
if (constructorForCurrentlyGeneratedDelegatedConstructor != null) {
|
||||||
|
val constructorParameter =
|
||||||
|
constructorForCurrentlyGeneratedDelegatedConstructor.valueParameters[calleeReference.contextReceiverNumber]
|
||||||
|
IrGetValueImpl(startOffset, endOffset, constructorParameter.type, constructorParameter.symbol)
|
||||||
|
} else {
|
||||||
|
val contextReceivers =
|
||||||
|
components.classifierStorage.getFieldsWithContextReceiversForClass(irClass, firClass)
|
||||||
|
require(contextReceivers.size > calleeReference.contextReceiverNumber) {
|
||||||
|
"Not defined context receiver #${calleeReference.contextReceiverNumber} for $irClass. " +
|
||||||
|
"Context receivers found: $contextReceivers"
|
||||||
|
}
|
||||||
|
|
||||||
|
IrGetFieldImpl(
|
||||||
|
startOffset, endOffset, contextReceivers[calleeReference.contextReceiverNumber].symbol,
|
||||||
|
thisReceiverExpression.resolvedType.toIrType(),
|
||||||
|
thisRef,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateThisReceiverAccessForScript(
|
||||||
|
thisReceiverExpression: FirThisReceiverExpression,
|
||||||
|
firScriptSymbol: FirScriptSymbol
|
||||||
|
): IrElement {
|
||||||
|
val calleeReference = thisReceiverExpression.calleeReference
|
||||||
|
val firScript = firScriptSymbol.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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateThisReceiverAccessForCallable(
|
||||||
|
thisReceiverExpression: FirThisReceiverExpression,
|
||||||
|
firCallableSymbol: FirCallableSymbol<*>
|
||||||
|
): IrElement? {
|
||||||
|
val calleeReference = thisReceiverExpression.calleeReference
|
||||||
|
val irFunction = when (firCallableSymbol) {
|
||||||
|
is FirFunctionSymbol -> {
|
||||||
|
val functionSymbol = declarationStorage.getIrFunctionSymbol(firCallableSymbol)
|
||||||
|
conversionScope.findDeclarationInParentsStack<IrSimpleFunction>(functionSymbol)
|
||||||
|
}
|
||||||
|
is FirPropertySymbol -> {
|
||||||
|
val property = declarationStorage.getIrPropertySymbol(firCallableSymbol) as? IrPropertySymbol
|
||||||
|
property?.let { conversionScope.parentAccessorOfPropertyFromStack(it) }
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
val receiver = if (calleeReference.contextReceiverNumber != -1) {
|
||||||
|
irFunction.valueParameters[calleeReference.contextReceiverNumber]
|
||||||
|
} else {
|
||||||
|
irFunction.extensionReceiverParameter
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
|
||||||
|
IrGetValueImpl(startOffset, endOffset, receiver.type, receiver.symbol)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitInaccessibleReceiverExpression(
|
override fun visitInaccessibleReceiverExpression(
|
||||||
|
|||||||
Reference in New Issue
Block a user