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 88ef0d690e8..24c3dc558da 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 @@ -602,7 +602,9 @@ class Fir2IrDeclarationStorage( Name.special("<$prefix-${correspondingProperty.name}>"), propertyAccessor?.visibility ?: correspondingProperty.visibility, correspondingProperty.modality, accessorReturnType, - isInline = false, isExternal = false, isTailrec = false, isSuspend = false, isExpect = false, + isInline = propertyAccessor?.isInline == true, + isExternal = propertyAccessor?.isExternal == true, + isTailrec = false, isSuspend = false, isExpect = false, isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE, isOperator = false ).apply { @@ -659,7 +661,8 @@ class Fir2IrDeclarationStorage( IrFieldImpl( startOffset, endOffset, origin, symbol, name, inferredType, - visibility, isFinal = isFinal, isExternal = false, + visibility, isFinal = isFinal, + isExternal = property.isExternal, isStatic = property.isStatic || parent !is IrClass, isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE ).also { @@ -712,8 +715,7 @@ class Fir2IrDeclarationStorage( isConst = property.isConst, isLateinit = property.isLateInit, isDelegated = property.delegate != null, - // TODO - isExternal = false, + isExternal = property.isExternal, isExpect = property.isExpect, isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE ).apply { diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 6e13e984597..1878c359774 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -940,16 +940,8 @@ class DeclarationsConverter( } val propertyVisibility = modifiers.getVisibility() - status = FirDeclarationStatusImpl(propertyVisibility, modifiers.getModality()).apply { - isExpect = modifiers.hasExpect() - isActual = modifiers.hasActual() - isOverride = modifiers.hasOverride() - isConst = modifiers.isConst() - isLateInit = modifiers.hasLateinit() - } - - val convertedAccessors = accessors.map { convertGetterOrSetter(it, returnType, propertyVisibility) } + val convertedAccessors = accessors.map { convertGetterOrSetter(it, returnType, propertyVisibility, modifiers) } this.getter = convertedAccessors.find { it.isGetter } ?: FirDefaultPropertyGetter(null, session, FirDeclarationOrigin.Source, returnType, propertyVisibility) this.setter = @@ -958,6 +950,19 @@ class DeclarationsConverter( ?: FirDefaultPropertySetter(null, session, FirDeclarationOrigin.Source, returnType, propertyVisibility) } else null + // Upward propagation of `inline` and `external` modifiers (from accessors to property) + // Note that, depending on `var` or `val`, checking setter's modifiers should be careful: for `val`, setter doesn't + // exist (null); for `var`, the retrieval of the specific modifier is supposed to be `true` + status = FirDeclarationStatusImpl(propertyVisibility, modifiers.getModality()).apply { + isExpect = modifiers.hasExpect() + isActual = modifiers.hasActual() + isOverride = modifiers.hasOverride() + isConst = modifiers.isConst() + isLateInit = modifiers.hasLateinit() + isInline = modifiers.hasInline() || (getter!!.isInline && setter?.isInline != false) + isExternal = modifiers.hasExternal() || (getter!!.isExternal && setter?.isExternal != false) + } + val receiver = delegateExpression?.let { expressionConverter.getAsFirExpression(it, "Should have delegate") } @@ -1031,7 +1036,8 @@ class DeclarationsConverter( private fun convertGetterOrSetter( getterOrSetter: LighterASTNode, propertyTypeRef: FirTypeRef, - propertyVisibility: Visibility + propertyVisibility: Visibility, + propertyModifiers: Modifier ): FirPropertyAccessor { var modifiers = Modifier() var isGetter = true @@ -1060,6 +1066,12 @@ class DeclarationsConverter( if (accessorVisibility == Visibilities.UNKNOWN) { accessorVisibility = propertyVisibility } + val status = + // Downward propagation of `inline` and `external` modifiers (from property to its accessors) + FirDeclarationStatusImpl(accessorVisibility, Modality.FINAL).apply { + isInline = propertyModifiers.hasInline() || modifiers.hasInline() + isExternal = propertyModifiers.hasExternal() || modifiers.hasExternal() + } val sourceElement = getterOrSetter.toFirSourceElement() if (block == null && expression == null) { return FirDefaultPropertyAccessor @@ -1073,6 +1085,7 @@ class DeclarationsConverter( ) .also { it.annotations += modifiers.annotations + it.status = status } } val target = FirFunctionTarget(labelName = null, isLambda = false) @@ -1083,7 +1096,7 @@ class DeclarationsConverter( returnTypeRef = returnType ?: if (isGetter) propertyTypeRef else implicitUnitType symbol = FirPropertyAccessorSymbol() this.isGetter = isGetter - status = FirDeclarationStatusImpl(accessorVisibility, Modality.FINAL) + this.status = status context.firFunctionTargets += target annotations += modifiers.annotations diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index d1c99a127a7..7ffecfd5635 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -261,6 +261,14 @@ class RawFirBuilder( ): FirPropertyAccessor { val accessorVisibility = if (this?.visibility != null && this.visibility != Visibilities.UNKNOWN) this.visibility else property.visibility + // Downward propagation of `inline` and `external` modifiers (from property to its accessors) + val status = + FirDeclarationStatusImpl(accessorVisibility, Modality.FINAL).apply { + isInline = property.hasModifier(INLINE_KEYWORD) || + this@toFirPropertyAccessor?.hasModifier(INLINE_KEYWORD) == true + isExternal = property.hasModifier(EXTERNAL_KEYWORD) || + this@toFirPropertyAccessor?.hasModifier(EXTERNAL_KEYWORD) == true + } if (this == null || !hasBody()) { val propertySource = property.toFirSourceElement() return FirDefaultPropertyAccessor @@ -276,6 +284,7 @@ class RawFirBuilder( if (this != null) { it.extractAnnotationsFrom(this) } + it.status = status } } val source = this.toFirSourceElement() @@ -290,7 +299,7 @@ class RawFirBuilder( returnTypeReference.toFirOrUnitType() } this.isGetter = isGetter - status = FirDeclarationStatusImpl(accessorVisibility, Modality.FINAL) + this.status = status extractAnnotationsTo(this) this@RawFirBuilder.context.firFunctionTargets += accessorTarget extractValueParametersTo(this, propertyTypeRef) @@ -1078,19 +1087,25 @@ class RawFirBuilder( expression = { delegateExpression }.toFirExpression("Should have delegate") } } else null + + getter = this@toFirProperty.getter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = true) + setter = if (isVar) { + this@toFirProperty.setter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = false) + } else null + + // Upward propagation of `inline` and `external` modifiers (from accessors to property) + // Note that, depending on `var` or `val`, checking setter's modifiers should be careful: for `val`, setter doesn't + // exist (null); for `var`, the retrieval of the specific modifier is supposed to be `true` status = FirDeclarationStatusImpl(visibility, modality).apply { isExpect = hasExpectModifier() isActual = hasActualModifier() isOverride = hasModifier(OVERRIDE_KEYWORD) isConst = hasModifier(CONST_KEYWORD) isLateInit = hasModifier(LATEINIT_KEYWORD) + isInline = hasModifier(INLINE_KEYWORD) || (getter!!.isInline && setter?.isInline != false) + isExternal = hasModifier(EXTERNAL_KEYWORD) || (getter!!.isExternal && setter?.isExternal != false) } - getter = this@toFirProperty.getter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = true) - setter = if (isVar) { - this@toFirProperty.setter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = false) - } else null - val receiver = delegateExpression?.toFirExpression("Should have delegate") generateAccessorsByDelegate( delegateBuilder, @@ -1350,6 +1365,7 @@ class RawFirBuilder( else -> null } val hasSubject = subjectExpression != null + @OptIn(FirContractViolation::class) val ref = FirExpressionRef() return buildWhenExpression { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt index ab4e26df117..e9cab442d8f 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/FirDeclarationUtil.kt @@ -63,6 +63,8 @@ inline val FirMemberDeclaration.isFromEnumClass: Boolean get() = status.isFromEn inline val FirPropertyAccessor.modality get() = status.modality inline val FirPropertyAccessor.visibility get() = status.visibility +inline val FirPropertyAccessor.isInline get() = status.isInline +inline val FirPropertyAccessor.isExternal get() = status.isExternal inline val FirPropertyAccessor.allowsToHaveFakeOverride: Boolean get() = !Visibilities.isPrivate(visibility) && visibility != Visibilities.INVISIBLE_FAKE diff --git a/compiler/testData/codegen/box/fullJdk/native/nativePropertyAccessors.kt b/compiler/testData/codegen/box/fullJdk/native/nativePropertyAccessors.kt index efe6d0c7ff6..a73f0b5b4dc 100644 --- a/compiler/testData/codegen/box/fullJdk/native/nativePropertyAccessors.kt +++ b/compiler/testData/codegen/box/fullJdk/native/nativePropertyAccessors.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // IGNORE_BACKEND: ANDROID diff --git a/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.fir.txt b/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.fir.txt index 84a7ff2def2..0fff177080b 100644 --- a/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.fir.txt +++ b/compiler/testData/ir/irText/expressions/implicitCastToTypeParameter.fir.txt @@ -29,12 +29,12 @@ FILE fqName: fileName:/implicitCastToTypeParameter.kt public open fun toString (): kotlin.String declared in kotlin.Any $this: VALUE_PARAMETER name: type:kotlin.Any PROPERTY name:asT visibility:public modality:FINAL [val] - FUN name: visibility:public modality:FINAL ($receiver:.Foo.>) returnType:T of .? + FUN name: visibility:public modality:FINAL ($receiver:.Foo.>) returnType:T of .? [inline] correspondingProperty: PROPERTY name:asT visibility:public modality:FINAL [val] TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any] $receiver: VALUE_PARAMETER name: type:.Foo.> BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun (): T of .? declared in ' + RETURN type=kotlin.Nothing from='public final fun (): T of .? [inline] declared in ' WHEN type=T of .? origin=IF BRANCH if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=T of . diff --git a/compiler/testData/ir/irText/expressions/typeParameterClassLiteral.fir.txt b/compiler/testData/ir/irText/expressions/typeParameterClassLiteral.fir.txt deleted file mode 100644 index 41cc21e4c34..00000000000 --- a/compiler/testData/ir/irText/expressions/typeParameterClassLiteral.fir.txt +++ /dev/null @@ -1,61 +0,0 @@ -FILE fqName: fileName:/typeParameterClassLiteral.kt - FUN name:classRefFun visibility:public modality:FINAL () returnType:kotlin.reflect.KClass.classRefFun> [inline] - TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any] - BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun classRefFun (): kotlin.reflect.KClass.classRefFun> [inline] declared in ' - CLASS_REFERENCE 'TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any]' type=kotlin.reflect.KClass.classRefFun> - FUN name:classRefExtFun visibility:public modality:FINAL ($receiver:kotlin.Any) returnType:kotlin.reflect.KClass.classRefExtFun> [inline] - TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any] - $receiver: VALUE_PARAMETER name: type:kotlin.Any - BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun classRefExtFun (): kotlin.reflect.KClass.classRefExtFun> [inline] declared in ' - CLASS_REFERENCE 'TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any]' type=kotlin.reflect.KClass.classRefExtFun> - PROPERTY name:classRefExtVal visibility:public modality:FINAL [val] - FUN name: visibility:public modality:FINAL ($receiver:T of .) returnType:kotlin.reflect.KClass.> - correspondingProperty: PROPERTY name:classRefExtVal visibility:public modality:FINAL [val] - TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any] - $receiver: VALUE_PARAMETER name: type:T of . - BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun (): kotlin.reflect.KClass.> declared in ' - CLASS_REFERENCE 'TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any]' type=kotlin.reflect.KClass.> - CLASS CLASS name:Host modality:FINAL visibility:public superTypes:[kotlin.Any] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Host - CONSTRUCTOR visibility:public <> () returnType:.Host [primary] - BLOCK_BODY - DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' - INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Host modality:FINAL visibility:public superTypes:[kotlin.Any]' - FUN name:classRefGenericMemberFun visibility:public modality:FINAL ($this:.Host) returnType:kotlin.reflect.KClass.Host.classRefGenericMemberFun> [inline] - TYPE_PARAMETER name:TF index:0 variance: superTypes:[kotlin.Any] - $this: VALUE_PARAMETER name: type:.Host - BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun classRefGenericMemberFun (): kotlin.reflect.KClass.Host.classRefGenericMemberFun> [inline] declared in .Host' - CLASS_REFERENCE 'TYPE_PARAMETER name:TF index:0 variance: superTypes:[kotlin.Any]' type=kotlin.reflect.KClass.Host.classRefGenericMemberFun> - FUN name:classRefGenericMemberExtFun visibility:public modality:FINAL ($this:.Host, $receiver:kotlin.Any) returnType:kotlin.reflect.KClass.Host.classRefGenericMemberExtFun> [inline] - TYPE_PARAMETER name:TF index:0 variance: superTypes:[kotlin.Any] - $this: VALUE_PARAMETER name: type:.Host - $receiver: VALUE_PARAMETER name: type:kotlin.Any - BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun classRefGenericMemberExtFun (): kotlin.reflect.KClass.Host.classRefGenericMemberExtFun> [inline] declared in .Host' - CLASS_REFERENCE 'TYPE_PARAMETER name:TF index:0 variance: superTypes:[kotlin.Any]' type=kotlin.reflect.KClass.Host.classRefGenericMemberExtFun> - PROPERTY name:classRefGenericMemberExtVal visibility:public modality:FINAL [val] - FUN name: visibility:public modality:FINAL ($this:.Host, $receiver:TV of .Host.) returnType:kotlin.reflect.KClass.Host.> - correspondingProperty: PROPERTY name:classRefGenericMemberExtVal visibility:public modality:FINAL [val] - TYPE_PARAMETER name:TV index:0 variance: superTypes:[kotlin.Any] - $this: VALUE_PARAMETER name: type:.Host - $receiver: VALUE_PARAMETER name: type:TV of .Host. - BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun (): kotlin.reflect.KClass.Host.> declared in .Host' - CLASS_REFERENCE 'TYPE_PARAMETER name:TV index:0 variance: superTypes:[kotlin.Any]' type=kotlin.reflect.KClass.Host.> - FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] - overridden: - public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any - $this: VALUE_PARAMETER name: type:kotlin.Any - VALUE_PARAMETER name:other index:0 type:kotlin.Any? - FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] - overridden: - public open fun hashCode (): kotlin.Int declared in kotlin.Any - $this: VALUE_PARAMETER name: type:kotlin.Any - FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] - overridden: - public open fun toString (): kotlin.String declared in kotlin.Any - $this: VALUE_PARAMETER name: type:kotlin.Any diff --git a/compiler/testData/ir/irText/expressions/typeParameterClassLiteral.kt b/compiler/testData/ir/irText/expressions/typeParameterClassLiteral.kt index 8d14a8d9901..7876d051e26 100644 --- a/compiler/testData/ir/irText/expressions/typeParameterClassLiteral.kt +++ b/compiler/testData/ir/irText/expressions/typeParameterClassLiteral.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL inline fun classRefFun() = T::class inline fun Any.classRefExtFun() = T::class