From d847d00d6f0f63ea307d0472e76cc222d366015a Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 17 Aug 2023 15:36:54 +0300 Subject: [PATCH] [FIR2IR] Get rid of most of usages IrSymbol.owner from CallAndReferenceGenerator ^KT-60924 --- .../kotlin/fir/backend/ConversionUtils.kt | 35 +++ .../fir/backend/Fir2IrDeclarationStorage.kt | 5 +- .../kotlin/fir/backend/IrBuiltInsOverFir.kt | 14 + .../backend/generators/AdapterGenerator.kt | 19 +- .../generators/CallAndReferenceGenerator.kt | 252 +++++++++--------- ...LightTreeBlackBoxCodegenTestGenerated.java | 6 + .../FirPsiBlackBoxCodegenTestGenerated.java | 6 + .../referenceToTypealiasConstructorInLet.kt | 21 ++ .../IrBlackBoxCodegenTestGenerated.java | 6 + ...kBoxCodegenWithIrInlinerTestGenerated.java | 6 + .../LightAnalysisModeTestGenerated.java | 5 + 11 files changed, 244 insertions(+), 131 deletions(-) create mode 100644 compiler/testData/codegen/box/callableReference/referenceToTypealiasConstructorInLet.kt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt index 094706542d1..2f18517ec97 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt @@ -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.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) +} diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt index d1d04a41297..04aef3cd8c3 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt @@ -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 diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt index 3586688764e..3d9257e7a27 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt @@ -472,6 +472,20 @@ class IrBuiltInsOverFir( ) } + fun getNonBuiltInFunctionsWithFirCounterpartByExtensionReceiver( + name: Name, + vararg packageNameSegments: String, + ): Map> { + 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() private val kFunctionNMap = mutableMapOf() private val suspendFunctionNMap = mutableMapOf() diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt index c115b7dcbd9..cf3ee9d9178 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/AdapterGenerator.kt @@ -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 invoke(T): R - !actualReturnType.isUnit() && !actualReturnType.isTypeParameter() + !actualReturnType.isUnit && actualReturnType.toSymbol(components.session) !is FirTypeParameterSymbol } /** diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index 3cbc52e8945..ece9b05d108 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -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() ?.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?, typeParameters: List?, @@ -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) } } diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java index 83735273c9e..933d3031a35 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java @@ -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 { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java index 0ceab170158..037082a4011 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java @@ -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 { diff --git a/compiler/testData/codegen/box/callableReference/referenceToTypealiasConstructorInLet.kt b/compiler/testData/codegen/box/callableReference/referenceToTypealiasConstructorInLet.kt new file mode 100644 index 00000000000..b3e4a4fd818 --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/referenceToTypealiasConstructorInLet.kt @@ -0,0 +1,21 @@ +// TARGET_BACKEND: JVM_IR +// WITH_STDLIB +// FULL_JDK + +import java.util.EnumMap + +enum class SomeEnum { + A, B +} + +typealias SomeMap = EnumMap + +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) +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index ab385a6d547..292915f39e5 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -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 { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java index a2649496223..bd3fd4d7428 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java @@ -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 { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index b92afb28c0c..a8278e935db 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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");