[FIR2IR] Refactor Fir2IrVisitor.visitThisReceiverExpression

Extract processing of different kinds of bound symbol into separate
  functions to improve readability
This commit is contained in:
Dmitriy Novozhilov
2023-08-22 13:37:23 +03:00
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(