diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt index 45774518c14..580f512beae 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt @@ -57,8 +57,18 @@ internal fun FirMemberDeclaration.isEffectivelyExternal( ): Boolean { if (this.isExternal) return true - // NB: [MemberDescriptor.isEffectivelyExternal] checks property accessors for property and vice versa. - // But, raw FIR creation already did such upward/downward propagation of modifiers. + if (this is FirPropertyAccessor) { + // Check containing property + val property = context.containingDeclarations.last() as FirProperty + return property.isEffectivelyExternal(containingClass, context) + } + + if (this is FirProperty) { + // Property is effectively external if all accessors are external + if (getter?.isExternal == true && (!isVar || setter?.isExternal == true)) { + return true + } + } return containingClass != null && isInsideExternalClass(containingClass, context) } diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt index c2b90070abd..c59a68e1c9e 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirMemberDeserializer.kt @@ -337,7 +337,6 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) { isOverride = false isConst = Flags.IS_CONST.get(flags) isLateInit = Flags.IS_LATEINIT.get(flags) - isInline = Flags.IS_INLINE.get(flags) isExternal = Flags.IS_EXTERNAL_PROPERTY.get(flags) } 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 11489333aff..3f6a2923f33 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 @@ -1099,17 +1099,13 @@ class DeclarationsConverter( } } 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(isClassOrObject = false)).apply { isExpect = modifiers.hasExpect() || classWrapper?.hasExpect() == true 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) + isExternal = modifiers.hasExternal() } val receiver = delegateExpression?.let { 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 123eb9ccd78..fed1edc3fef 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 @@ -1341,17 +1341,13 @@ open class RawFirBuilder( getter = this@toFirProperty.getter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = true) setter = this@toFirProperty.setter.toFirPropertyAccessor(this@toFirProperty, propertyType, isGetter = false) - // 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() || containingClassOrObject?.hasExpectModifier() == true 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) + isExternal = hasModifier(EXTERNAL_KEYWORD) } val receiver = delegateExpression?.toFirExpression("Should have delegate") diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/external.lazyBodies.txt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/external.lazyBodies.txt index 464c7064a50..3123e1a79f2 100644 --- a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/external.lazyBodies.txt +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/external.lazyBodies.txt @@ -20,6 +20,6 @@ FILE: external.kt public? set(value: Int): R|kotlin/Unit| { LAZY_BLOCK } } - public? final? external var z: Int + public? final? var z: Int public? external get(): Int public? external set(value: Int): R|kotlin/Unit| diff --git a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/external.txt b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/external.txt index 5f3cb7c7ee4..d32a5cb65b4 100644 --- a/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/external.txt +++ b/compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/external.txt @@ -21,6 +21,6 @@ FILE: external.kt } } - public? final? external var z: Int + public? final? var z: Int public? external get(): Int public? external set(value: Int): R|kotlin/Unit| diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt index c47c168da62..4256414eb53 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt @@ -314,50 +314,45 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM if (memberDeclaration.isExternal) { print("external ") } - if (memberDeclaration is FirCallableMemberDeclaration<*>) { - if (memberDeclaration.isOverride) { - print("override ") - } - if (memberDeclaration.isStatic) { - print("static ") - } + if (memberDeclaration.isOverride) { + print("override ") } - if (memberDeclaration is FirRegularClass) { - if (memberDeclaration.isInner) { - print("inner ") - } - if (memberDeclaration.isCompanion) { - print("companion ") - } - if (memberDeclaration.isData) { - print("data ") - } - if (memberDeclaration.isInline) { - print("inline ") - } - } else if (memberDeclaration is FirSimpleFunction) { - if (memberDeclaration.isOperator) { - print("operator ") - } - if (memberDeclaration.isInfix) { - print("infix ") - } - if (memberDeclaration.isInline) { - print("inline ") - } - if (memberDeclaration.isTailRec) { - print("tailrec ") - } - if (memberDeclaration.isSuspend) { - print("suspend ") - } - } else if (memberDeclaration is FirProperty) { - if (memberDeclaration.isConst) { - print("const ") - } - if (memberDeclaration.isLateInit) { - print("lateinit ") - } + if (memberDeclaration.isStatic) { + print("static ") + } + if (memberDeclaration.isInner) { + print("inner ") + } + + // `companion/data` modifiers are only valid for FirRegularClass, but we render them to make sure they are not + // incorrectly loaded for other declarations during deserialization. + if (memberDeclaration.status.isCompanion) { + print("companion ") + } + if (memberDeclaration.status.isData) { + print("data ") + } + + if (memberDeclaration.isInline) { + print("inline ") + } + if (memberDeclaration.isOperator) { + print("operator ") + } + if (memberDeclaration.isInfix) { + print("infix ") + } + if (memberDeclaration.isTailRec) { + print("tailrec ") + } + if (memberDeclaration.isSuspend) { + print("suspend ") + } + if (memberDeclaration.isConst) { + print("const ") + } + if (memberDeclaration.isLateInit) { + print("lateinit ") } visitDeclaration(memberDeclaration) 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 03a7517ab73..59b85d11c2a 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 @@ -49,16 +49,13 @@ inline val FirClass<*>.isEnumClass: Boolean inline val FirRegularClass.modality get() = status.modality inline val FirRegularClass.isSealed get() = status.modality == Modality.SEALED inline val FirRegularClass.isAbstract get() = status.modality == Modality.ABSTRACT +inline val FirRegularClass.isFun get() = status.isFun +inline val FirRegularClass.isCompanion get() = status.isCompanion +inline val FirRegularClass.isData get() = status.isData inline val FirRegularClass.canHaveAbstractDeclaration: Boolean get() = isAbstract || isSealed || isEnumClass -inline val FirRegularClass.isInner get() = status.isInner -inline val FirRegularClass.isCompanion get() = status.isCompanion -inline val FirRegularClass.isData get() = status.isData -inline val FirRegularClass.isInline get() = status.isInline -inline val FirRegularClass.isFun get() = status.isFun - inline val FirMemberDeclaration.modality get() = status.modality inline val FirMemberDeclaration.isAbstract get() = status.modality == Modality.ABSTRACT inline val FirMemberDeclaration.isOpen get() = status.modality == Modality.OPEN @@ -92,7 +89,6 @@ inline val FirMemberDeclaration.isConst: Boolean get() = status.isConst inline val FirMemberDeclaration.isLateInit: Boolean get() = status.isLateInit inline val FirMemberDeclaration.isFromSealedClass: Boolean get() = status.isFromSealedClass inline val FirMemberDeclaration.isFromEnumClass: Boolean get() = status.isFromEnumClass -inline val FirMemberDeclaration.isFun: Boolean get() = status.isFun inline val FirFunction<*>.hasBody get() = body != null