[FIR2IR] Get rid of most of usages IrSymbol.owner from CallAndReferenceGenerator

^KT-60924
This commit is contained in:
Dmitriy Novozhilov
2023-08-17 15:36:54 +03:00
committed by Space Team
parent ff1c38872e
commit d847d00d6f
11 changed files with 244 additions and 131 deletions
@@ -814,3 +814,38 @@ fun FirExpression.asCompileTimeIrInitializer(components: Fir2IrComponents): IrEx
else -> null
}
}
/**
* Note: for componentN call, we have to change the type here (to the original component type) to keep compatibility with PSI2IR
* Some backend optimizations related to withIndex() probably depend on this type: index should always be Int
* See e.g. forInStringWithIndexWithExplicitlyTypedIndexVariable.kt from codegen box tests
*
* [predefinedType] is needed for case, when this function is used to convert some variable access, and
* default IR type, for it is already known
* It's not correct to always use converted [this.returnTypeRef] in one particular case:
*
* val <T> T.some: T
* get() = ...
* set(value) {
* field = value <----
* }
*
* Here `value` has type `T`. In FIR there is one type parameter `T` for the whole property
* But in IR we have different type parameters for getter and setter. And by default `toIrType()` transforms
* `T` as type parameter of getter, but here we are in context of the setter. And in CallAndReferenceGenerator.convertToIrCall
* we already know that `value` should have type `T[set-some]`, so this type is provided as [predefinedType]
*
* The alternative could be to determine outside that we are in scope of setter and pass type origin, but it's
* much more complicated and messy
*/
context(Fir2IrComponents)
internal fun FirVariable.irTypeForPotentiallyComponentCall(predefinedType: IrType? = null): IrType {
val typeRef = when (val initializer = initializer) {
is FirComponentCall -> initializer.resolvedType
else -> {
if (predefinedType != null) return predefinedType
this.returnTypeRef.coneType
}
}
return typeRef.toIrType(typeConverter)
}
@@ -1526,10 +1526,7 @@ class Fir2IrDeclarationStorage(
irParent: IrDeclarationParent,
givenOrigin: IrDeclarationOrigin? = null
): IrVariable = convertCatching(variable) {
// Note: for components call, we have to change type here (to original component type) to keep compatibility with PSI2IR
// Some backend optimizations related to withIndex() probably depend on this type: index should always be Int
// See e.g. forInStringWithIndexWithExplicitlyTypedIndexVariable.kt from codegen box tests
val type = ((variable.initializer as? FirComponentCall)?.resolvedType ?: variable.returnTypeRef.coneType).toIrType()
val type = variable.irTypeForPotentiallyComponentCall()
// Some temporary variables are produced in RawFirBuilder, but we consistently use special names for them.
val origin = when {
givenOrigin != null -> givenOrigin
@@ -472,6 +472,20 @@ class IrBuiltInsOverFir(
)
}
fun getNonBuiltInFunctionsWithFirCounterpartByExtensionReceiver(
name: Name,
vararg packageNameSegments: String,
): Map<IrClassifierSymbol, Pair<FirNamedFunctionSymbol, IrSimpleFunctionSymbol>> {
return getFunctionsByKey(
name,
*packageNameSegments,
mapKey = { symbol ->
with(components) { symbol.fir.receiverParameter?.typeRef?.toIrType(typeConverter)?.classifierOrNull }
},
mapValue = { firSymbol, irSymbol -> firSymbol to irSymbol }
)
}
private val functionNMap = mutableMapOf<Int, IrClass>()
private val kFunctionNMap = mutableMapOf<Int, IrClass>()
private val suspendFunctionNMap = mutableMapOf<Int, IrClass>()
@@ -87,10 +87,12 @@ internal class AdapterGenerator(
internal fun needToGenerateAdaptedCallableReference(
callableReferenceAccess: FirCallableReferenceAccess,
type: IrSimpleType,
function: IrFunction
): Boolean =
needSuspendConversion(type, function) || needCoercionToUnit(type, function) ||
function: FirFunction
): Boolean {
return needSuspendConversion(type, function) ||
needCoercionToUnit(type, function) ||
hasVarargOrDefaultArguments(callableReferenceAccess)
}
/**
* For example,
@@ -100,8 +102,9 @@ internal class AdapterGenerator(
*
* At the use site, instead of referenced, we can put the suspend lambda as an adapter.
*/
private fun needSuspendConversion(type: IrSimpleType, function: IrFunction): Boolean =
type.isSuspendFunction() && !function.isSuspend
private fun needSuspendConversion(type: IrSimpleType, function: FirFunction): Boolean {
return type.isSuspendFunction() && !function.isSuspend
}
/**
* For example,
@@ -111,12 +114,12 @@ internal class AdapterGenerator(
*
* At the use site, instead of referenced, we can put the adapter: { ... -> referenced(...) }
*/
private fun needCoercionToUnit(type: IrSimpleType, function: IrFunction): Boolean {
private fun needCoercionToUnit(type: IrSimpleType, function: FirFunction): Boolean {
val expectedReturnType = type.arguments.last().typeOrNull
val actualReturnType = function.returnType
val actualReturnType = function.returnTypeRef.coneType
return expectedReturnType?.isUnit() == true &&
// In case of an external function whose return type is a type parameter, e.g., operator fun <T, R> invoke(T): R
!actualReturnType.isUnit() && !actualReturnType.isTypeParameter()
!actualReturnType.isUnit && actualReturnType.toSymbol(components.session) !is FirTypeParameterSymbol
}
/**
@@ -9,18 +9,18 @@ import com.intellij.openapi.progress.ProcessCanceledException
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
import org.jetbrains.kotlin.fir.declarations.utils.isMethodOfAny
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationCall
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
import org.jetbrains.kotlin.fir.resolve.calls.getExpectedType
@@ -44,12 +44,11 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator.commonSuperType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.runIf
class CallAndReferenceGenerator(
private val components: Fir2IrComponents,
@@ -65,7 +64,6 @@ class CallAndReferenceGenerator(
private fun ConeKotlinType.toIrType(): IrType =
with(typeConverter) { toIrType(conversionScope.defaultConversionTypeOrigin()) }
@OptIn(IrSymbolInternals::class)
fun convertToIrCallableReference(
callableReferenceAccess: FirCallableReferenceAccess,
explicitReceiverExpression: IrExpression?,
@@ -101,20 +99,19 @@ class CallAndReferenceGenerator(
return callableReferenceAccess.convertWithOffsets { startOffset, endOffset ->
when (symbol) {
is IrPropertySymbol -> {
val referencedProperty = symbol.owner
val referencedPropertyGetter = referencedProperty.getter
val referencedPropertySetterSymbol =
if (callableReferenceAccess.resolvedType.isKMutableProperty(session)) referencedProperty.setter?.symbol
else null
val referencedPropertyGetterSymbol = declarationStorage.findGetterOfProperty(symbol)
val referencedPropertySetterSymbol = runIf(callableReferenceAccess.resolvedType.isKMutableProperty(session)) {
declarationStorage.findSetterOfProperty(symbol)
}
val backingFieldSymbol = when {
referencedPropertyGetter != null -> null
else -> referencedProperty.backingField?.symbol
referencedPropertyGetterSymbol != null -> null
else -> declarationStorage.findBackingFieldOfProperty(symbol)
}
IrPropertyReferenceImpl(
startOffset, endOffset, type, symbol,
typeArgumentsCount = referencedPropertyGetter?.typeParameters?.size ?: 0,
typeArgumentsCount = callableReferenceAccess.toResolvedCallableSymbol()?.fir?.typeParameters?.size ?: 0,
field = backingFieldSymbol,
getter = referencedPropertyGetter?.symbol,
getter = referencedPropertyGetterSymbol,
setter = referencedPropertySetterSymbol,
origin = origin
).applyTypeArguments(callableReferenceAccess).applyReceivers(callableReferenceAccess, explicitReceiverExpression)
@@ -123,40 +120,43 @@ class CallAndReferenceGenerator(
is IrLocalDelegatedPropertySymbol -> {
IrLocalDelegatedPropertyReferenceImpl(
startOffset, endOffset, type, symbol,
delegate = symbol.owner.delegate.symbol,
getter = symbol.owner.getter.symbol,
setter = symbol.owner.setter?.symbol,
delegate = declarationStorage.findDelegateVariableOfProperty(symbol),
getter = declarationStorage.findGetterOfProperty(symbol),
setter = declarationStorage.findSetterOfProperty(symbol),
origin = origin
)
}
is IrFieldSymbol -> {
val referencedField = symbol.owner
val propertySymbol = referencedField.correspondingPropertySymbol
val field = (callableSymbol as FirFieldSymbol).fir
val propertySymbol = declarationStorage.findPropertyForBackingField(symbol)
?: run {
// In case of [IrField] without the corresponding property, we've created it directly from [FirField].
// Since it's used as a field reference, we need a bogus property as a placeholder.
val firSymbol =
(callableReferenceAccess.calleeReference as FirResolvedNamedReference).resolvedSymbol as FirFieldSymbol
declarationStorage.getOrCreateIrPropertyByPureField(firSymbol.fir, referencedField.parent).symbol
@OptIn(IrSymbolInternals::class)
declarationStorage.getOrCreateIrPropertyByPureField(firSymbol.fir, symbol.owner.parent).symbol
}
IrPropertyReferenceImpl(
startOffset, endOffset, type,
propertySymbol,
typeArgumentsCount = 0,
field = symbol,
getter = if (referencedField.isStatic) null else propertySymbol.owner.getter?.symbol,
setter = if (referencedField.isStatic) null else propertySymbol.owner.setter?.symbol,
getter = runIf(!field.isStatic) { declarationStorage.findGetterOfProperty(propertySymbol) },
setter = runIf(!field.isStatic) { declarationStorage.findSetterOfProperty(propertySymbol) },
origin
).applyReceivers(callableReferenceAccess, explicitReceiverExpression)
}
is IrFunctionSymbol -> {
assert(type.isFunctionTypeOrSubtype()) {
"Callable reference whose symbol refers to a function should be of functional type."
require(type is IrSimpleType)
var function = callableReferenceAccess.calleeReference.toResolvedFunctionSymbol()!!.fir
if (function is FirConstructor) {
// The number of type parameters of typealias constructor may mismatch with that number in the original constructor.
// And for IR, we need to use the original constructor as a source of truth
function = function.originalConstructorIfTypeAlias ?: function
}
type as IrSimpleType
val function = symbol.owner
if (adapterGenerator.needToGenerateAdaptedCallableReference(callableReferenceAccess, type, function)) {
// Receivers are being applied inside
with(adapterGenerator) {
@@ -165,13 +165,10 @@ class CallAndReferenceGenerator(
generateAdaptedCallableReference(callableReferenceAccess, explicitReceiverExpression, symbol, adaptedType)
}
} else {
val klass = function.parent as? IrClass
val typeArgumentCount = function.typeParameters.size +
if (function is IrConstructor) klass?.typeParameters?.size ?: 0 else 0
IrFunctionReferenceImpl(
startOffset, endOffset, type, symbol,
typeArgumentsCount = typeArgumentCount,
valueArgumentsCount = function.valueParameters.size,
typeArgumentsCount = function.typeParameters.size,
valueArgumentsCount = function.valueParameters.size + function.contextReceivers.size,
reflectionTarget = symbol
).applyTypeArguments(callableReferenceAccess)
.applyReceivers(callableReferenceAccess, explicitReceiverExpression)
@@ -363,7 +360,6 @@ class CallAndReferenceGenerator(
return IrGetValueImpl(startOffset, endOffset, type, injectedValue.irParameterSymbol, origin)
}
@OptIn(IrSymbolInternals::class)
fun convertToIrCall(
qualifiedAccess: FirQualifiedAccessExpression,
type: ConeKotlinType,
@@ -449,8 +445,9 @@ class CallAndReferenceGenerator(
is IrLocalDelegatedPropertySymbol -> {
IrCallImpl(
startOffset, endOffset, irType, symbol.owner.getter.symbol,
typeArgumentsCount = symbol.owner.getter.typeParameters.size,
startOffset, endOffset, irType,
declarationStorage.findGetterOfProperty(symbol),
typeArgumentsCount = calleeReference.toResolvedCallableSymbol()!!.fir.typeParameters.size,
valueArgumentsCount = 0,
origin = IrStatementOrigin.GET_LOCAL_PROPERTY,
superQualifierSymbol = dispatchReceiver.superQualifierSymbol()
@@ -458,19 +455,23 @@ class CallAndReferenceGenerator(
}
is IrPropertySymbol -> {
val getter = symbol.owner.getter
val backingField = symbol.owner.backingField
val property = calleeReference.toResolvedPropertySymbol()!!.fir
val getterSymbol = declarationStorage.findGetterOfProperty(symbol)
val backingFieldSymbol = declarationStorage.findBackingFieldOfProperty(symbol)
when {
getter != null -> IrCallImpl(
startOffset, endOffset, irType, getter.symbol,
typeArgumentsCount = getter.typeParameters.size,
valueArgumentsCount = getter.valueParameters.size,
origin = IrStatementOrigin.GET_PROPERTY,
superQualifierSymbol = dispatchReceiver.superQualifierSymbol()
)
getterSymbol != null -> {
IrCallImpl(
startOffset, endOffset, irType,
getterSymbol,
typeArgumentsCount = property.typeParameters.size,
valueArgumentsCount = property.contextReceivers.size,
origin = IrStatementOrigin.GET_PROPERTY,
superQualifierSymbol = dispatchReceiver.superQualifierSymbol()
)
}
backingField != null -> IrGetFieldImpl(
startOffset, endOffset, backingField.symbol, irType,
backingFieldSymbol != null -> IrGetFieldImpl(
startOffset, endOffset, backingFieldSymbol, irType,
superQualifierSymbol = dispatchReceiver.superQualifierSymbol()
)
@@ -496,11 +497,12 @@ class CallAndReferenceGenerator(
}
is IrValueSymbol -> {
val variable = calleeReference.toResolvedVariableSymbol()!!.fir
IrGetValueImpl(
// Note: sometimes we change an IR type of local variable
// (see component call case: Fir2IrDeclarationStorage.createIrVariable -> val type = ...)
// That's why we should use here v the IR variable type and not FIR converted type (to prevent IR inconsistency)
startOffset, endOffset, symbol.owner.type, symbol,
startOffset, endOffset,
// Note: there is a case with componentN function when IR type of variable differs from FIR type
variable.irTypeForPotentiallyComponentCall(predefinedType = irType),
symbol,
origin = if (variableAsFunctionMode) IrStatementOrigin.VARIABLE_AS_FUNCTION
else calleeReference.statementOrigin()
)
@@ -575,7 +577,6 @@ class CallAndReferenceGenerator(
internal fun findInjectedValue(calleeReference: FirReference) = extensions.findInjectedValue(calleeReference, conversionScope)
@OptIn(IrSymbolInternals::class)
fun convertToIrSetCall(variableAssignment: FirVariableAssignment, explicitReceiverExpression: IrExpression?): IrExpression {
try {
val type = irBuiltIns.unitType
@@ -614,12 +615,13 @@ class CallAndReferenceGenerator(
}
is IrLocalDelegatedPropertySymbol -> {
val setter = symbol.owner.setter
val firProperty = calleeReference.toResolvedPropertySymbol()!!.fir
val setterSymbol = declarationStorage.findSetterOfProperty(symbol)
when {
setter != null -> IrCallImpl(
startOffset, endOffset, type, setter.symbol,
typeArgumentsCount = setter.typeParameters.size,
valueArgumentsCount = setter.valueParameters.size,
setterSymbol != null -> IrCallImpl(
startOffset, endOffset, type, setterSymbol,
typeArgumentsCount = firProperty.typeParameters.size,
valueArgumentsCount = 1 + firProperty.contextReceivers.size,
origin = origin,
superQualifierSymbol = variableAssignment.dispatchReceiver.superQualifierSymbol()
).apply {
@@ -632,29 +634,29 @@ class CallAndReferenceGenerator(
}
is IrPropertySymbol -> {
val irProperty = symbol.owner
val setter = irProperty.setter
var backingField = irProperty.backingField
val setterSymbol = declarationStorage.findSetterOfProperty(symbol)
var backingFieldSymbol = declarationStorage.findBackingFieldOfProperty(symbol)
val firProperty = calleeReference.toResolvedPropertySymbol()!!.fir
// If we found neither a setter nor a backing field, check if we have an override (possibly fake) of a val with
// backing field. This can happen in a class initializer where `this` was smart-casted. See KT-57105.
if (setter == null && backingField == null) {
backingField = irProperty.overriddenBackingFieldOrNull()
if (setterSymbol == null && backingFieldSymbol == null) {
backingFieldSymbol = symbol.overriddenBackingFieldOrNull()
}
when {
setter != null -> IrCallImpl(
startOffset, endOffset, type, setter.symbol,
typeArgumentsCount = setter.typeParameters.size,
valueArgumentsCount = setter.valueParameters.size,
setterSymbol != null -> IrCallImpl(
startOffset, endOffset, type, setterSymbol,
typeArgumentsCount = firProperty.typeParameters.size,
valueArgumentsCount = 1 + firProperty.contextReceivers.size,
origin = origin,
superQualifierSymbol = variableAssignment.dispatchReceiver.superQualifierSymbol()
).apply {
putValueArgument(putContextReceiverArguments(lValue), assignedValue)
}
backingField != null -> IrSetFieldImpl(
startOffset, endOffset, backingField.symbol, type,
backingFieldSymbol != null -> IrSetFieldImpl(
startOffset, endOffset, backingFieldSymbol, type,
origin = null, // NB: to be consistent with PSI2IR, origin should be null here
superQualifierSymbol = variableAssignment.dispatchReceiver.superQualifierSymbol()
).apply {
@@ -666,9 +668,10 @@ class CallAndReferenceGenerator(
}
is IrSimpleFunctionSymbol -> {
val firFunction = calleeReference.toResolvedFunctionSymbol()?.fir
IrCallImpl(
startOffset, endOffset, type, symbol,
typeArgumentsCount = symbol.owner.typeParameters.size,
typeArgumentsCount = firFunction?.typeParameters?.size ?: 0,
valueArgumentsCount = 1,
origin = origin
).apply {
@@ -694,14 +697,13 @@ class CallAndReferenceGenerator(
}
@OptIn(IrSymbolInternals::class)
private fun IrProperty.overriddenBackingFieldOrNull(): IrField? {
return overriddenSymbols.firstNotNullOfOrNull {
private fun IrPropertySymbol.overriddenBackingFieldOrNull(): IrFieldSymbol? {
return owner.overriddenSymbols.firstNotNullOfOrNull {
val owner = it.owner
owner.backingField ?: owner.overriddenBackingFieldOrNull()
owner.backingField?.symbol ?: it.overriddenBackingFieldOrNull()
}
}
@OptIn(IrSymbolInternals::class)
fun convertToIrConstructorCall(annotation: FirAnnotation): IrExpression {
val coneType = annotation.annotationTypeRef.coneTypeSafe<ConeLookupTagBasedType>()
?.fullyExpandedType(session) as? ConeLookupTagBasedType
@@ -714,7 +716,6 @@ class CallAndReferenceGenerator(
)
}
val irClass = symbol.owner
val firConstructorSymbol = annotation.toResolvedCallableSymbol() as? FirConstructorSymbol
?: run {
// Fallback for FirReferencePlaceholderForResolvedAnnotations from jar
@@ -732,7 +733,7 @@ class CallAndReferenceGenerator(
}
constructorSymbol
} ?: return@convertWithOffsets IrErrorCallExpressionImpl(
startOffset, endOffset, type, "No annotation constructor found: ${irClass.name}"
startOffset, endOffset, type, "No annotation constructor found: $symbol"
)
val irConstructor = declarationStorage.getIrConstructorSymbol(firConstructorSymbol)
@@ -837,7 +838,6 @@ class CallAndReferenceGenerator(
return Triple(valueParameters, argumentMapping, substitutor)
}
@OptIn(IrSymbolInternals::class)
internal fun IrExpression.applyCallArguments(
statement: FirStatement?,
): IrExpression {
@@ -872,7 +872,7 @@ class CallAndReferenceGenerator(
}
}
} else {
val name = if (this is IrCallImpl) symbol.owner.name else "???"
val name = if (this is IrCallImpl) symbol.signature.toString() else "???"
IrErrorCallExpressionImpl(
startOffset, endOffset, type,
"Cannot bind $argumentsCount arguments to $name call with $valueArgumentsCount parameters"
@@ -1049,7 +1049,6 @@ class CallAndReferenceGenerator(
return this
}
@OptIn(IrSymbolInternals::class)
private fun IrExpression.applyImplicitIntegerCoercionIfNeeded(
argument: FirExpression,
parameter: FirValueParameter?
@@ -1059,56 +1058,64 @@ class CallAndReferenceGenerator(
if (parameter == null || !parameter.isMarkedWithImplicitIntegerCoercion) return this
if (!argument.getExpectedType(parameter).fullyExpandedType(session).isUnsignedTypeOrNullableUnsignedType) return this
fun IrExpression.applyToElement(argument: FirExpression, conversionFunction: IrSimpleFunctionSymbol): IrExpression =
if (argument.isIntegerLiteralOrOperatorCall() ||
fun IrExpression.applyToElement(
argument: FirExpression,
firConversionFunction: FirNamedFunctionSymbol,
irConversionFunction: IrSimpleFunctionSymbol,
): IrExpression {
return if (argument.isIntegerLiteralOrOperatorCall() ||
argument.calleeReference?.toResolvedCallableSymbol()?.let {
it.resolvedStatus.isConst && it.isMarkedWithImplicitIntegerCoercion
} == true
) {
IrCallImpl(
startOffset, endOffset,
conversionFunction.owner.returnType,
conversionFunction,
firConversionFunction.fir.returnTypeRef.toIrType(),
irConversionFunction,
typeArgumentsCount = 0,
valueArgumentsCount = 0
).apply {
extensionReceiver = this@applyToElement
}
} else this@applyToElement
if (parameter.isMarkedWithImplicitIntegerCoercion) {
if (this is IrVarargImpl && argument is FirVarargArgumentsExpression) {
val targetTypeFqName = varargElementType.classFqName ?: return this
val conversionFunctions = irBuiltIns.getNonBuiltInFunctionsByExtensionReceiver(
Name.identifier("to" + targetTypeFqName.shortName().asString()),
StandardNames.BUILT_INS_PACKAGE_NAME.asString()
)
if (conversionFunctions.isNotEmpty()) {
elements.forEachIndexed { i, irVarargElement ->
val targetFun = argument.arguments[i].resolvedType.toIrType().classifierOrNull?.let { conversionFunctions[it] }
if (targetFun != null && irVarargElement is IrExpression) {
elements[i] =
irVarargElement.applyToElement(argument.arguments[i], targetFun)
}
}
}
return this
} else {
val targetIrType = parameter.returnTypeRef.toIrType()
val targetTypeFqName = targetIrType.classFqName ?: return this
val conversionFunctions = irBuiltIns.getNonBuiltInFunctionsByExtensionReceiver(
Name.identifier("to" + targetTypeFqName.shortName().asString()),
StandardNames.BUILT_INS_PACKAGE_NAME.asString()
)
val sourceTypeClassifier = argument.resolvedType.toIrType().classifierOrNull ?: return this
val conversionFunction = conversionFunctions[sourceTypeClassifier] ?: return this
return this.applyToElement(argument, conversionFunction)
this@applyToElement
}
}
return this
return when {
parameter.isMarkedWithImplicitIntegerCoercion -> when {
this is IrVarargImpl && argument is FirVarargArgumentsExpression -> {
val targetTypeFqName = varargElementType.classFqName ?: return this
val conversionFunctions = irBuiltIns.getNonBuiltInFunctionsWithFirCounterpartByExtensionReceiver(
Name.identifier("to" + targetTypeFqName.shortName().asString()),
StandardNames.BUILT_INS_PACKAGE_NAME.asString()
)
if (conversionFunctions.isNotEmpty()) {
elements.forEachIndexed { i, irVarargElement ->
if (irVarargElement !is IrExpression) return@forEachIndexed
val argumentClassifier = argument.arguments[i].resolvedType.toIrType().classifierOrNull ?: return@forEachIndexed
val (targetFirFun, targetIrFun) = conversionFunctions[argumentClassifier] ?: return@forEachIndexed
elements[i] = irVarargElement.applyToElement(argument.arguments[i], targetFirFun, targetIrFun)
}
}
this
}
else -> {
val targetIrType = parameter.returnTypeRef.toIrType()
val targetTypeFqName = targetIrType.classFqName ?: return this
val conversionFunctions = irBuiltIns.getNonBuiltInFunctionsWithFirCounterpartByExtensionReceiver(
Name.identifier("to" + targetTypeFqName.shortName().asString()),
StandardNames.BUILT_INS_PACKAGE_NAME.asString()
)
val sourceTypeClassifier = argument.resolvedType.toIrType().classifierOrNull ?: return this
val (firConversionFunction, irConversionFunction) = conversionFunctions[sourceTypeClassifier] ?: return this
this.applyToElement(argument, firConversionFunction, irConversionFunction)
}
}
else -> this
}
}
internal fun IrExpression.applyTypeArguments(access: FirQualifiedAccessExpression): IrExpression {
@@ -1159,7 +1166,6 @@ class CallAndReferenceGenerator(
}
}
@OptIn(IrSymbolInternals::class)
private fun IrExpression.applyTypeArguments(
typeArguments: List<FirTypeProjection>?,
typeParameters: List<FirTypeParameter>?,
@@ -1185,7 +1191,7 @@ class CallAndReferenceGenerator(
}
return this
} else {
val name = if (this is IrCallImpl) symbol.owner.name else "???"
val name = if (this is IrCallImpl) symbol.signature.toString() else "???"
return IrErrorExpressionImpl(
startOffset, endOffset, type,
"Cannot bind $argumentsCount type arguments to $name call with $typeArgumentsCount type parameters"
@@ -1213,7 +1219,6 @@ class CallAndReferenceGenerator(
?: explicitReceiverExpression
}
@OptIn(IrSymbolInternals::class)
private fun IrExpression.applyReceivers(
qualifiedAccess: FirQualifiedAccessExpression,
explicitReceiverExpression: IrExpression?,
@@ -1223,10 +1228,17 @@ class CallAndReferenceGenerator(
val resolvedFirSymbol = qualifiedAccess.toResolvedCallableSymbol()
if (resolvedFirSymbol?.dispatchReceiverType != null) {
val baseDispatchReceiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
var firDispatchReceiver = qualifiedAccess.dispatchReceiver.takeUnless { it is FirNoReceiverExpression }
if (firDispatchReceiver is FirPropertyAccessExpression && firDispatchReceiver.calleeReference is FirSuperReference) {
firDispatchReceiver = firDispatchReceiver.dispatchReceiver
}
val notFromAny = !resolvedFirSymbol.isFunctionFromAny()
val notAnInterface = firDispatchReceiver?.resolvedType?.toRegularClassSymbol(session)?.isInterface != true
dispatchReceiver =
if (!resolvedFirSymbol.isFunctionFromAny() || baseDispatchReceiver?.type?.classOrNull?.owner?.isInterface != true) {
if (notFromAny || notAnInterface) {
baseDispatchReceiver
} else {
requireNotNull(baseDispatchReceiver)
// NB: for FE 1.0, this type cast is added by InterfaceObjectCallsLowering
// However, it doesn't work for FIR due to different f/o structure
// (FIR calls Any method directly, but FE 1.0 calls its interface f/o instead)
@@ -1259,8 +1271,10 @@ class CallAndReferenceGenerator(
}
is IrFieldAccessExpression -> {
val ownerField = symbol.owner
if (!ownerField.isStatic) {
val firDeclaration = qualifiedAccess.toResolvedCallableSymbol()!!.fir.propertyIfBackingField
// Top-level properties are considered as static in IR
val fieldIsStatic = firDeclaration.isStatic || (firDeclaration is FirProperty && !firDeclaration.isLocal && firDeclaration.containingClassLookupTag() == null)
if (!fieldIsStatic) {
receiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
}
}
@@ -3717,6 +3717,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/callableReference/referenceToGenericSyntheticProperty.kt");
}
@Test
@TestMetadata("referenceToTypealiasConstructorInLet.kt")
public void testReferenceToTypealiasConstructorInLet() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/referenceToTypealiasConstructorInLet.kt");
}
@Test
@TestMetadata("staticMethod.kt")
public void testStaticMethod() throws Exception {
@@ -3717,6 +3717,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/callableReference/referenceToGenericSyntheticProperty.kt");
}
@Test
@TestMetadata("referenceToTypealiasConstructorInLet.kt")
public void testReferenceToTypealiasConstructorInLet() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/referenceToTypealiasConstructorInLet.kt");
}
@Test
@TestMetadata("staticMethod.kt")
public void testStaticMethod() throws Exception {
@@ -0,0 +1,21 @@
// TARGET_BACKEND: JVM_IR
// WITH_STDLIB
// FULL_JDK
import java.util.EnumMap
enum class SomeEnum {
A, B
}
typealias SomeMap = EnumMap<SomeEnum, String>
fun test(oldMap: SomeMap, key: SomeEnum): String {
val newMap = oldMap.let(::SomeMap)
return newMap.getValue(key)
}
fun box(): String {
val map = EnumMap(mapOf(SomeEnum.A to "OK"))
return test(map, SomeEnum.A)
}
@@ -3717,6 +3717,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/callableReference/referenceToGenericSyntheticProperty.kt");
}
@Test
@TestMetadata("referenceToTypealiasConstructorInLet.kt")
public void testReferenceToTypealiasConstructorInLet() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/referenceToTypealiasConstructorInLet.kt");
}
@Test
@TestMetadata("staticMethod.kt")
public void testStaticMethod() throws Exception {
@@ -3717,6 +3717,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/callableReference/referenceToGenericSyntheticProperty.kt");
}
@Test
@TestMetadata("referenceToTypealiasConstructorInLet.kt")
public void testReferenceToTypealiasConstructorInLet() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/referenceToTypealiasConstructorInLet.kt");
}
@Test
@TestMetadata("staticMethod.kt")
public void testStaticMethod() throws Exception {
@@ -3256,6 +3256,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/callableReference/referenceToGenericSyntheticProperty.kt");
}
@TestMetadata("referenceToTypealiasConstructorInLet.kt")
public void testReferenceToTypealiasConstructorInLet() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/referenceToTypealiasConstructorInLet.kt");
}
@TestMetadata("staticMethod.kt")
public void testStaticMethod() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/staticMethod.kt");