From 8a8bdc9ff41c78477d21be51b71f1b4c9b6dcd5a Mon Sep 17 00:00:00 2001 From: Ivan Kochurkin Date: Tue, 25 Jan 2022 21:06:18 +0300 Subject: [PATCH] [FIR2IR] Fix synthetic property reference in delegate expression --- .../kotlin/fir/backend/ConversionUtils.kt | 40 ++++++++++++------- .../kotlin/fir/backend/Fir2IrVisitor.kt | 27 ++++++++++--- .../generators/CallAndReferenceGenerator.kt | 5 ++- .../generators/ClassMemberGenerator.kt | 2 +- .../delegateToAnother/genericJavaProperty.kt | 4 +- .../delegatedProperty/javaDelegateTopLevel.kt | 4 -- .../provideDelegate/javaDelegate.fir.ir.txt | 4 +- 7 files changed, 54 insertions(+), 32 deletions(-) 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 23b9db19591..84582c46ec5 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 @@ -170,13 +170,15 @@ private fun FirBasedSymbol<*>.toSymbolForCall( classifierStorage: Fir2IrClassifierStorage, declarationStorage: Fir2IrDeclarationStorage, preferGetter: Boolean, - explicitReceiver: FirExpression? = null + explicitReceiver: FirExpression? = null, + isDelegate: Boolean = false ) = when (this) { is FirCallableSymbol<*> -> unwrapCallRepresentative().toSymbolForCall( dispatchReceiver, declarationStorage, preferGetter, - explicitReceiver + explicitReceiver, + isDelegate ) is FirClassifierSymbol<*> -> toSymbol(session, classifierStorage) else -> error("Unknown symbol: $this") @@ -189,11 +191,12 @@ fun FirReference.toSymbolForCall( declarationStorage: Fir2IrDeclarationStorage, conversionScope: Fir2IrConversionScope, preferGetter: Boolean = true, - explicitReceiver: FirExpression? = null // Actual only for callable references + explicitReceiver: FirExpression? = null, // Actual only for callable references + isDelegate: Boolean = false ): IrSymbol? { return when (this) { is FirResolvedNamedReference -> - resolvedSymbol.toSymbolForCall(dispatchReceiver, session, classifierStorage, declarationStorage, preferGetter, explicitReceiver) + resolvedSymbol.toSymbolForCall(dispatchReceiver, session, classifierStorage, declarationStorage, preferGetter, explicitReceiver, isDelegate) is FirErrorNamedReference -> candidateSymbol?.toSymbolForCall( dispatchReceiver, @@ -201,7 +204,8 @@ fun FirReference.toSymbolForCall( classifierStorage, declarationStorage, preferGetter, - explicitReceiver + explicitReceiver, + isDelegate ) is FirThisReference -> { when (val boundSymbol = boundSymbol) { @@ -222,7 +226,8 @@ private fun FirCallableSymbol<*>.toSymbolForCall( dispatchReceiver: FirExpression, declarationStorage: Fir2IrDeclarationStorage, preferGetter: Boolean, - explicitReceiver: FirExpression? = null + explicitReceiver: FirExpression? = null, + isDelegate: Boolean = false ): IrSymbol? { val dispatchReceiverLookupTag = when (dispatchReceiver) { is FirNoReceiverExpression -> { @@ -242,15 +247,20 @@ private fun FirCallableSymbol<*>.toSymbolForCall( } return when (this) { is FirSimpleSyntheticPropertySymbol -> { - (fir as? FirSyntheticProperty)?.let { syntheticProperty -> - val delegateSymbol = if (preferGetter) { - syntheticProperty.getter.delegate.symbol - } else { - syntheticProperty.setter?.delegate?.symbol - ?: throw AssertionError("Written synthetic property must have a setter") - } - delegateSymbol.unwrapCallRepresentative().toSymbolForCall(dispatchReceiver, declarationStorage, preferGetter) - } ?: declarationStorage.getIrPropertySymbol(this) + if (isDelegate) { + declarationStorage.getIrPropertySymbol(this) + } else { + (fir as? FirSyntheticProperty)?.let { syntheticProperty -> + val delegateSymbol = if (preferGetter) { + syntheticProperty.getter.delegate.symbol + } else { + syntheticProperty.setter?.delegate?.symbol + ?: throw AssertionError("Written synthetic property must have a setter") + } + delegateSymbol.unwrapCallRepresentative() + .toSymbolForCall(dispatchReceiver, declarationStorage, preferGetter, isDelegate = false) + } ?: declarationStorage.getIrPropertySymbol(this) + } } is FirFunctionSymbol<*> -> declarationStorage.getIrFunctionSymbol(this, dispatchReceiverLookupTag) is FirPropertySymbol -> declarationStorage.getIrPropertySymbol(this, dispatchReceiverLookupTag) 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 1b4d6916ef7..861f40989c4 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 @@ -270,7 +270,7 @@ class Fir2IrVisitor( val delegate = variable.delegate if (delegate != null) { val irProperty = declarationStorage.createIrLocalDelegatedProperty(variable, conversionScope.parentFromStack()) - irProperty.delegate.initializer = convertToIrExpression(delegate) + irProperty.delegate.initializer = convertToIrExpression(delegate, isDelegate = true) conversionScope.withFunction(irProperty.getter) { memberGenerator.convertFunctionContent(irProperty.getter, variable.getter, null) } @@ -456,7 +456,8 @@ class Fir2IrVisitor( } } } else if (boundSymbol is FirCallableSymbol) { - val receiverSymbol = calleeReference.toSymbolForCall(FirNoReceiverExpression, session, classifierStorage, declarationStorage, conversionScope) + val receiverSymbol = + calleeReference.toSymbolForCall(FirNoReceiverExpression, session, classifierStorage, declarationStorage, conversionScope) val receiver = (receiverSymbol?.owner as? IrSimpleFunction)?.extensionReceiverParameter if (receiver != null) { return thisReceiverExpression.convertWithOffsets { startOffset, endOffset -> @@ -499,10 +500,18 @@ class Fir2IrVisitor( } override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Any?): IrElement { + return convertCallableReferenceAccess(callableReferenceAccess, false) + } + + private fun convertCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, isDelegate: Boolean): IrElement { val explicitReceiverExpression = convertToIrReceiverExpression( callableReferenceAccess.explicitReceiver, callableReferenceAccess.calleeReference, callableReferenceAccess ) - return callGenerator.convertToIrCallableReference(callableReferenceAccess, explicitReceiverExpression) + return callGenerator.convertToIrCallableReference( + callableReferenceAccess, + explicitReceiverExpression, + isDelegate = isDelegate + ) } override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: Any?): IrElement { @@ -525,7 +534,11 @@ class Fir2IrVisitor( return accept(this@Fir2IrVisitor, null) as IrStatement } - internal fun convertToIrExpression(expression: FirExpression, annotationMode: Boolean = false): IrExpression { + internal fun convertToIrExpression( + expression: FirExpression, + annotationMode: Boolean = false, + isDelegate: Boolean = false + ): IrExpression { return when (expression) { is FirBlock -> expression.convertToIrExpressionOrBlock( if (expression.source?.kind == KtFakeSourceElementKind.DesugaredForLoop) IrStatementOrigin.FOR_LOOP else null @@ -541,10 +554,14 @@ class Fir2IrVisitor( when (unwrappedExpression) { is FirFunctionCall -> convertToIrCall(unwrappedExpression, annotationMode) is FirArrayOfCall -> convertToArrayOfCall(unwrappedExpression, annotationMode) + is FirCallableReferenceAccess -> convertCallableReferenceAccess(unwrappedExpression, isDelegate) else -> expression.accept(this, null) as IrExpression } } else { - expression.accept(this, null) as IrExpression + when (unwrappedExpression) { + is FirCallableReferenceAccess -> convertCallableReferenceAccess(unwrappedExpression, isDelegate) + else -> expression.accept(this, null) as IrExpression + } } } }.let { 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 cb3534acddd..668ad961180 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 @@ -61,7 +61,8 @@ class CallAndReferenceGenerator( fun convertToIrCallableReference( callableReferenceAccess: FirCallableReferenceAccess, - explicitReceiverExpression: IrExpression? + explicitReceiverExpression: IrExpression?, + isDelegate: Boolean ): IrExpression { val type = approximateFunctionReferenceType(callableReferenceAccess.typeRef.coneType).toIrType() @@ -79,7 +80,7 @@ class CallAndReferenceGenerator( val symbol = callableReferenceAccess.calleeReference.toSymbolForCall( callableReferenceAccess.dispatchReceiver, session, classifierStorage, declarationStorage, conversionScope, - explicitReceiver = callableReferenceAccess.explicitReceiver + explicitReceiver = callableReferenceAccess.explicitReceiver, isDelegate = isDelegate ) // val x by y -> // val `x$delegate` = y diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt index db112945e3d..3ad72267ec3 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/ClassMemberGenerator.kt @@ -217,7 +217,7 @@ internal class ClassMemberGenerator( if (initializer == null && initializerExpression != null) { initializer = irFactory.createExpressionBody( run { - val irExpression = visitor.convertToIrExpression(initializerExpression) + val irExpression = visitor.convertToIrExpression(initializerExpression, isDelegate = property.delegate != null) if (property.delegate == null) { with(visitor.implicitCastInserter) { irExpression.cast(initializerExpression, initializerExpression.typeRef, property.returnTypeRef) diff --git a/compiler/testData/codegen/box/delegatedProperty/delegateToAnother/genericJavaProperty.kt b/compiler/testData/codegen/box/delegatedProperty/delegateToAnother/genericJavaProperty.kt index ec66aa50683..680c44935e7 100644 --- a/compiler/testData/codegen/box/delegatedProperty/delegateToAnother/genericJavaProperty.kt +++ b/compiler/testData/codegen/box/delegatedProperty/delegateToAnother/genericJavaProperty.kt @@ -1,6 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: REPEATED_ANNOTATION at val y9; fir2ir produces an IrFunctionReference of type KProperty0 instead of an IrPropertyReference // WITH_REFLECT // WITH_STDLIB // FILE: J.java @@ -34,6 +32,6 @@ fun box(): String { val y6 by @Anno() (((j2)::value)) val y7 by (@Anno() ((j2)::value)) val y8 by ((@Anno() (j2)::value)) - val y9 by @Anno() ((@Anno() (j2)::value)) + val y9 by @Anno() (j2)::value return x + y } diff --git a/compiler/testData/codegen/box/delegatedProperty/javaDelegateTopLevel.kt b/compiler/testData/codegen/box/delegatedProperty/javaDelegateTopLevel.kt index 91d5127d381..77d79e33e91 100644 --- a/compiler/testData/codegen/box/delegatedProperty/javaDelegateTopLevel.kt +++ b/compiler/testData/codegen/box/delegatedProperty/javaDelegateTopLevel.kt @@ -1,8 +1,4 @@ // TARGET_BACKEND: JVM -// IGNORE_BACKEND_FIR: JVM_IR -// FIR status: V -// Caused by: java.lang.AssertionError: Unexpected IR element found during code generation. Either code generation for it is not implemented, or it should have been lowered: -// FUNCTION_REFERENCE 'public open fun getFoo (): @[FlexibleNullability] kotlin.String? declared in .J' type=kotlin.reflect.KMutableProperty0<@[FlexibleNullability] kotlin.String?> origin=null reflectionTarget= // WITH_STDLIB // MODULE: jjj diff --git a/compiler/testData/ir/irText/declarations/provideDelegate/javaDelegate.fir.ir.txt b/compiler/testData/ir/irText/declarations/provideDelegate/javaDelegate.fir.ir.txt index 222919de037..bd73b9143cf 100644 --- a/compiler/testData/ir/irText/declarations/provideDelegate/javaDelegate.fir.ir.txt +++ b/compiler/testData/ir/irText/declarations/provideDelegate/javaDelegate.fir.ir.txt @@ -2,7 +2,7 @@ FILE fqName:k fileName:/box.kt PROPERTY name:p1 visibility:public modality:FINAL [delegated,var] FIELD PROPERTY_DELEGATE name:p1$delegate type:kotlin.reflect.KMutableProperty0<@[FlexibleNullability] kotlin.String?> visibility:private [final,static] EXPRESSION_BODY - FUNCTION_REFERENCE 'public open fun getFoo (): @[FlexibleNullability] kotlin.String? declared in .J' type=kotlin.reflect.KMutableProperty0<@[FlexibleNullability] kotlin.String?> origin=null reflectionTarget= + PROPERTY_REFERENCE 'public open foo: @[FlexibleNullability] kotlin.String? [var]' field=null getter='public open fun (): @[FlexibleNullability] kotlin.String? declared in .J' setter='public open fun (: @[FlexibleNullability] kotlin.String?): kotlin.Unit declared in .J' type=kotlin.reflect.KMutableProperty0<@[FlexibleNullability] kotlin.String?> origin=null $this: CONSTRUCTOR_CALL 'public constructor () [primary] declared in .J' type=.J origin=null FUN DELEGATED_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String? correspondingProperty: PROPERTY name:p1 visibility:public modality:FINAL [delegated,var] @@ -26,7 +26,7 @@ FILE fqName:k fileName:/box.kt PROPERTY name:p2 visibility:public modality:FINAL [delegated,var] FIELD PROPERTY_DELEGATE name:p2$delegate type:kotlin.reflect.KMutableProperty0<@[FlexibleNullability] kotlin.String?> visibility:private [final,static] EXPRESSION_BODY - FUNCTION_REFERENCE 'public open fun getFoo (): @[FlexibleNullability] kotlin.String? declared in .J' type=kotlin.reflect.KMutableProperty0<@[FlexibleNullability] kotlin.String?> origin=null reflectionTarget= + PROPERTY_REFERENCE 'public open foo: @[FlexibleNullability] kotlin.String? [var]' field=null getter='public open fun (): @[FlexibleNullability] kotlin.String? declared in .J' setter='public open fun (: @[FlexibleNullability] kotlin.String?): kotlin.Unit declared in .J' type=kotlin.reflect.KMutableProperty0<@[FlexibleNullability] kotlin.String?> origin=null $this: CONSTRUCTOR_CALL 'public constructor () [primary] declared in .J' type=.J origin=null FUN DELEGATED_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> () returnType:@[FlexibleNullability] kotlin.String? correspondingProperty: PROPERTY name:p2 visibility:public modality:FINAL [delegated,var]