55
66package org.jetbrains.kotlin.fir.deserialization
77
8+ import org.jetbrains.kotlin.descriptors.EffectiveVisibility
89import org.jetbrains.kotlin.descriptors.Modality
10+ import org.jetbrains.kotlin.descriptors.Visibility
911import org.jetbrains.kotlin.fir.FirModuleData
1012import org.jetbrains.kotlin.fir.FirSession
1113import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr
@@ -14,7 +16,8 @@ import org.jetbrains.kotlin.fir.declarations.builder.*
1416import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyBackingField
1517import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
1618import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
17- import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
19+ import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusWithLazyEffectiveVisibility
20+ import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
1821import org.jetbrains.kotlin.fir.declarations.utils.sourceElement
1922import org.jetbrains.kotlin.fir.expressions.FirAnnotation
2023import org.jetbrains.kotlin.fir.expressions.FirExpression
@@ -114,6 +117,7 @@ class FirDeserializationContext(
114117 typeParameterProtos = emptyList(),
115118 containerSource,
116119 outerClassSymbol = null ,
120+ outerClassEffectiveVisibility = EffectiveVisibility .Public ,
117121 containingDeclarationSymbol = null
118122 )
119123
@@ -126,7 +130,8 @@ class FirDeserializationContext(
126130 flexibleTypeFactory : FirTypeDeserializer .FlexibleTypeFactory ,
127131 constDeserializer : FirConstDeserializer ,
128132 containerSource : DeserializedContainerSource ? ,
129- outerClassSymbol : FirRegularClassSymbol
133+ outerClassSymbol : FirRegularClassSymbol ,
134+ outerClassEffectiveVisibility : EffectiveVisibility ,
130135 ): FirDeserializationContext = createRootContext(
131136 nameResolver,
132137 TypeTable (classProto.typeTable),
@@ -140,6 +145,7 @@ class FirDeserializationContext(
140145 classProto.typeParameterList,
141146 containerSource,
142147 outerClassSymbol,
148+ outerClassEffectiveVisibility,
143149 outerClassSymbol
144150 )
145151
@@ -156,6 +162,7 @@ class FirDeserializationContext(
156162 typeParameterProtos : List <ProtoBuf .TypeParameter >,
157163 containerSource : DeserializedContainerSource ? ,
158164 outerClassSymbol : FirRegularClassSymbol ? ,
165+ outerClassEffectiveVisibility : EffectiveVisibility ,
159166 containingDeclarationSymbol : FirBasedSymbol <* >?
160167 ): FirDeserializationContext {
161168 return FirDeserializationContext (
@@ -209,10 +216,10 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
209216 origin = FirDeclarationOrigin .Library
210217 this .name = name
211218 val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(flags))
212- status = FirResolvedDeclarationStatusImpl (
219+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (
213220 visibility,
214221 Modality .FINAL ,
215- visibility.toEffectiveVisibility (owner = null )
222+ visibility.toLazyEffectiveVisibility (owner = null ),
216223 ).apply {
217224 isExpect = Flags .IS_EXPECT_CLASS .get(flags)
218225 isActual = false
@@ -242,15 +249,15 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
242249 val getterFlags = if (proto.hasGetterFlags()) proto.getterFlags else defaultAccessorFlags
243250 val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(getterFlags))
244251 val accessorModality = ProtoEnumFlags .modality(Flags .MODALITY .get(getterFlags))
245- val effectiveVisibility = visibility.toEffectiveVisibility (classSymbol)
252+ val effectiveVisibility = visibility.toLazyEffectiveVisibility (classSymbol)
246253 return if (Flags .IS_NOT_DEFAULT .get(getterFlags)) {
247254 buildPropertyAccessor {
248255 moduleData = c.moduleData
249256 origin = FirDeclarationOrigin .Library
250257 this .returnTypeRef = returnTypeRef
251258 resolvePhase = FirResolvePhase .ANALYZED_DEPENDENCIES
252259 isGetter = true
253- status = FirResolvedDeclarationStatusImpl (visibility, accessorModality, effectiveVisibility).apply {
260+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (visibility, accessorModality, effectiveVisibility).apply {
254261 isInline = Flags .IS_INLINE_ACCESSOR .get(getterFlags)
255262 isExternal = Flags .IS_EXTERNAL_ACCESSOR .get(getterFlags)
256263 }
@@ -262,14 +269,12 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
262269 }
263270 } else {
264271 FirDefaultPropertyGetter (
265- null ,
272+ source = null ,
266273 c.moduleData,
267274 FirDeclarationOrigin .Library ,
268275 returnTypeRef,
269- visibility,
270276 propertySymbol,
271- propertyModality,
272- effectiveVisibility,
277+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (visibility, propertyModality, effectiveVisibility),
273278 resolvePhase = FirResolvePhase .ANALYZED_DEPENDENCIES ,
274279 )
275280 }.apply {
@@ -295,15 +300,15 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
295300 val setterFlags = if (proto.hasSetterFlags()) proto.setterFlags else defaultAccessorFlags
296301 val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(setterFlags))
297302 val accessorModality = ProtoEnumFlags .modality(Flags .MODALITY .get(setterFlags))
298- val effectiveVisibility = visibility.toEffectiveVisibility (classSymbol)
303+ val effectiveVisibility = visibility.toLazyEffectiveVisibility (classSymbol)
299304 return if (Flags .IS_NOT_DEFAULT .get(setterFlags)) {
300305 buildPropertyAccessor {
301306 moduleData = c.moduleData
302307 origin = FirDeclarationOrigin .Library
303308 this .returnTypeRef = FirImplicitUnitTypeRef (source)
304309 resolvePhase = FirResolvePhase .ANALYZED_DEPENDENCIES
305310 isGetter = false
306- status = FirResolvedDeclarationStatusImpl (visibility, accessorModality, effectiveVisibility).apply {
311+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (visibility, accessorModality, effectiveVisibility).apply {
307312 isInline = Flags .IS_INLINE_ACCESSOR .get(setterFlags)
308313 isExternal = Flags .IS_EXTERNAL_ACCESSOR .get(setterFlags)
309314 }
@@ -322,14 +327,12 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
322327 }
323328 } else {
324329 FirDefaultPropertySetter (
325- null ,
330+ source = null ,
326331 c.moduleData,
327332 FirDeclarationOrigin .Library ,
328333 returnTypeRef,
329- visibility,
330334 propertySymbol,
331- propertyModality,
332- effectiveVisibility,
335+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (visibility, propertyModality, effectiveVisibility),
333336 resolvePhase = FirResolvePhase .ANALYZED_DEPENDENCIES ,
334337 )
335338 }.apply {
@@ -394,7 +397,11 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
394397 dispatchReceiverType = c.dispatchReceiver
395398 isLocal = false
396399 val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(flags))
397- status = FirResolvedDeclarationStatusImpl (visibility, propertyModality, visibility.toEffectiveVisibility(classSymbol)).apply {
400+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (
401+ visibility,
402+ propertyModality,
403+ visibility.toLazyEffectiveVisibility(classSymbol)
404+ ).apply {
398405 isExpect = Flags .IS_EXPECT_PROPERTY .get(flags)
399406 isActual = false
400407 isOverride = false
@@ -546,10 +553,10 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
546553
547554 name = callableName
548555 val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(flags))
549- status = FirResolvedDeclarationStatusImpl (
556+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (
550557 visibility,
551558 ProtoEnumFlags .modality(Flags .MODALITY .get(flags)),
552- visibility.toEffectiveVisibility (classSymbol)
559+ visibility.toLazyEffectiveVisibility (classSymbol)
553560 ).apply {
554561 isExpect = Flags .IS_EXPECT_FUNCTION .get(flags)
555562 isActual = false
@@ -625,10 +632,10 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
625632 returnTypeRef = delegatedSelfType
626633 val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(flags))
627634 val isInner = classBuilder.status.isInner
628- status = FirResolvedDeclarationStatusImpl (
635+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (
629636 visibility,
630637 Modality .FINAL ,
631- visibility.toEffectiveVisibility (classBuilder.symbol)
638+ visibility.toLazyEffectiveVisibility (classBuilder.symbol)
632639 ).apply {
633640 // We don't store information about expect modifier on constructors
634641 // It is inherited from containing class
@@ -718,4 +725,40 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
718725
719726 private fun ProtoBuf.Type.toTypeRef (context : FirDeserializationContext ): FirResolvedTypeRef =
720727 context.typeDeserializer.typeRef(this )
728+
729+ private fun Visibility.toLazyEffectiveVisibility (owner : FirClassLikeSymbol <* >? ): Lazy <EffectiveVisibility > {
730+ return this .toLazyEffectiveVisibility(owner, c.session, forClass = false )
731+ }
732+ }
733+
734+ fun Visibility.toLazyEffectiveVisibility (
735+ owner : FirClassLikeSymbol <* >? ,
736+ session : FirSession ,
737+ forClass : Boolean
738+ ): Lazy <EffectiveVisibility > {
739+ /*
740+ * `lowerBound` operation for `EffectiveVisibility.Protected` involves subtyping between container classes.
741+ * In some cases, during deserialization, this subtyping might lead to the infinite recursion.
742+ * Consider the following example:
743+ *
744+ * ```
745+ * class Outer {
746+ * protected class Inner(protected val x: Any)
747+ * }
748+ * ```
749+ *
750+ * Here `Inner` class has effective visibility `protected (in Outer)` and `x` has `protected (in Inner)`.
751+ * So to perform the `lowerBound` operation between these two visibilities, the compiler needs to check the
752+ * subtyping between the `Outer` and `Inner`. BUT this happens during the deserialization in the following chain:
753+ * `deserialize Outer -> deserialize Inner -> deserialize x`, and no class symbols are published yet (neither
754+ * FIR element for them is created). So when subtyping tries to access supertypes of any of these classes, it triggers
755+ * deserialization once again which leads to stack overflow eventually.
756+ *
757+ * Due to this situation, we cannot compute the effective visibility eagerly, so we postpone its computation
758+ */
759+ return lazy(LazyThreadSafetyMode .PUBLICATION ) l@{
760+ val selfEffectiveVisibility = this .toEffectiveVisibility(owner, forClass = forClass)
761+ val parentEffectiveVisibility = owner?.effectiveVisibility ? : EffectiveVisibility .Public
762+ parentEffectiveVisibility.lowerBound(selfEffectiveVisibility, session.typeContext)
763+ }
721764}
0 commit comments