5
5
6
6
package org.jetbrains.kotlin.fir.deserialization
7
7
8
+ import org.jetbrains.kotlin.descriptors.EffectiveVisibility
8
9
import org.jetbrains.kotlin.descriptors.Modality
10
+ import org.jetbrains.kotlin.descriptors.Visibility
9
11
import org.jetbrains.kotlin.fir.FirModuleData
10
12
import org.jetbrains.kotlin.fir.FirSession
11
13
import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr
@@ -14,7 +16,8 @@ import org.jetbrains.kotlin.fir.declarations.builder.*
14
16
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyBackingField
15
17
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
16
18
import 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
18
21
import org.jetbrains.kotlin.fir.declarations.utils.sourceElement
19
22
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
20
23
import org.jetbrains.kotlin.fir.expressions.FirExpression
@@ -114,6 +117,7 @@ class FirDeserializationContext(
114
117
typeParameterProtos = emptyList(),
115
118
containerSource,
116
119
outerClassSymbol = null ,
120
+ outerClassEffectiveVisibility = EffectiveVisibility .Public ,
117
121
containingDeclarationSymbol = null
118
122
)
119
123
@@ -126,7 +130,8 @@ class FirDeserializationContext(
126
130
flexibleTypeFactory : FirTypeDeserializer .FlexibleTypeFactory ,
127
131
constDeserializer : FirConstDeserializer ,
128
132
containerSource : DeserializedContainerSource ? ,
129
- outerClassSymbol : FirRegularClassSymbol
133
+ outerClassSymbol : FirRegularClassSymbol ,
134
+ outerClassEffectiveVisibility : EffectiveVisibility ,
130
135
): FirDeserializationContext = createRootContext(
131
136
nameResolver,
132
137
TypeTable (classProto.typeTable),
@@ -140,6 +145,7 @@ class FirDeserializationContext(
140
145
classProto.typeParameterList,
141
146
containerSource,
142
147
outerClassSymbol,
148
+ outerClassEffectiveVisibility,
143
149
outerClassSymbol
144
150
)
145
151
@@ -156,6 +162,7 @@ class FirDeserializationContext(
156
162
typeParameterProtos : List <ProtoBuf .TypeParameter >,
157
163
containerSource : DeserializedContainerSource ? ,
158
164
outerClassSymbol : FirRegularClassSymbol ? ,
165
+ outerClassEffectiveVisibility : EffectiveVisibility ,
159
166
containingDeclarationSymbol : FirBasedSymbol <* >?
160
167
): FirDeserializationContext {
161
168
return FirDeserializationContext (
@@ -209,10 +216,10 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
209
216
origin = FirDeclarationOrigin .Library
210
217
this .name = name
211
218
val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(flags))
212
- status = FirResolvedDeclarationStatusImpl (
219
+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (
213
220
visibility,
214
221
Modality .FINAL ,
215
- visibility.toEffectiveVisibility (owner = null )
222
+ visibility.toLazyEffectiveVisibility (owner = null ),
216
223
).apply {
217
224
isExpect = Flags .IS_EXPECT_CLASS .get(flags)
218
225
isActual = false
@@ -242,15 +249,15 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
242
249
val getterFlags = if (proto.hasGetterFlags()) proto.getterFlags else defaultAccessorFlags
243
250
val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(getterFlags))
244
251
val accessorModality = ProtoEnumFlags .modality(Flags .MODALITY .get(getterFlags))
245
- val effectiveVisibility = visibility.toEffectiveVisibility (classSymbol)
252
+ val effectiveVisibility = visibility.toLazyEffectiveVisibility (classSymbol)
246
253
return if (Flags .IS_NOT_DEFAULT .get(getterFlags)) {
247
254
buildPropertyAccessor {
248
255
moduleData = c.moduleData
249
256
origin = FirDeclarationOrigin .Library
250
257
this .returnTypeRef = returnTypeRef
251
258
resolvePhase = FirResolvePhase .ANALYZED_DEPENDENCIES
252
259
isGetter = true
253
- status = FirResolvedDeclarationStatusImpl (visibility, accessorModality, effectiveVisibility).apply {
260
+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (visibility, accessorModality, effectiveVisibility).apply {
254
261
isInline = Flags .IS_INLINE_ACCESSOR .get(getterFlags)
255
262
isExternal = Flags .IS_EXTERNAL_ACCESSOR .get(getterFlags)
256
263
}
@@ -262,14 +269,12 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
262
269
}
263
270
} else {
264
271
FirDefaultPropertyGetter (
265
- null ,
272
+ source = null ,
266
273
c.moduleData,
267
274
FirDeclarationOrigin .Library ,
268
275
returnTypeRef,
269
- visibility,
270
276
propertySymbol,
271
- propertyModality,
272
- effectiveVisibility,
277
+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (visibility, propertyModality, effectiveVisibility),
273
278
resolvePhase = FirResolvePhase .ANALYZED_DEPENDENCIES ,
274
279
)
275
280
}.apply {
@@ -295,15 +300,15 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
295
300
val setterFlags = if (proto.hasSetterFlags()) proto.setterFlags else defaultAccessorFlags
296
301
val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(setterFlags))
297
302
val accessorModality = ProtoEnumFlags .modality(Flags .MODALITY .get(setterFlags))
298
- val effectiveVisibility = visibility.toEffectiveVisibility (classSymbol)
303
+ val effectiveVisibility = visibility.toLazyEffectiveVisibility (classSymbol)
299
304
return if (Flags .IS_NOT_DEFAULT .get(setterFlags)) {
300
305
buildPropertyAccessor {
301
306
moduleData = c.moduleData
302
307
origin = FirDeclarationOrigin .Library
303
308
this .returnTypeRef = FirImplicitUnitTypeRef (source)
304
309
resolvePhase = FirResolvePhase .ANALYZED_DEPENDENCIES
305
310
isGetter = false
306
- status = FirResolvedDeclarationStatusImpl (visibility, accessorModality, effectiveVisibility).apply {
311
+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (visibility, accessorModality, effectiveVisibility).apply {
307
312
isInline = Flags .IS_INLINE_ACCESSOR .get(setterFlags)
308
313
isExternal = Flags .IS_EXTERNAL_ACCESSOR .get(setterFlags)
309
314
}
@@ -322,14 +327,12 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
322
327
}
323
328
} else {
324
329
FirDefaultPropertySetter (
325
- null ,
330
+ source = null ,
326
331
c.moduleData,
327
332
FirDeclarationOrigin .Library ,
328
333
returnTypeRef,
329
- visibility,
330
334
propertySymbol,
331
- propertyModality,
332
- effectiveVisibility,
335
+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (visibility, propertyModality, effectiveVisibility),
333
336
resolvePhase = FirResolvePhase .ANALYZED_DEPENDENCIES ,
334
337
)
335
338
}.apply {
@@ -394,7 +397,11 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
394
397
dispatchReceiverType = c.dispatchReceiver
395
398
isLocal = false
396
399
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 {
398
405
isExpect = Flags .IS_EXPECT_PROPERTY .get(flags)
399
406
isActual = false
400
407
isOverride = false
@@ -546,10 +553,10 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
546
553
547
554
name = callableName
548
555
val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(flags))
549
- status = FirResolvedDeclarationStatusImpl (
556
+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (
550
557
visibility,
551
558
ProtoEnumFlags .modality(Flags .MODALITY .get(flags)),
552
- visibility.toEffectiveVisibility (classSymbol)
559
+ visibility.toLazyEffectiveVisibility (classSymbol)
553
560
).apply {
554
561
isExpect = Flags .IS_EXPECT_FUNCTION .get(flags)
555
562
isActual = false
@@ -625,10 +632,10 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
625
632
returnTypeRef = delegatedSelfType
626
633
val visibility = ProtoEnumFlags .visibility(Flags .VISIBILITY .get(flags))
627
634
val isInner = classBuilder.status.isInner
628
- status = FirResolvedDeclarationStatusImpl (
635
+ status = FirResolvedDeclarationStatusWithLazyEffectiveVisibility (
629
636
visibility,
630
637
Modality .FINAL ,
631
- visibility.toEffectiveVisibility (classBuilder.symbol)
638
+ visibility.toLazyEffectiveVisibility (classBuilder.symbol)
632
639
).apply {
633
640
// We don't store information about expect modifier on constructors
634
641
// It is inherited from containing class
@@ -718,4 +725,40 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
718
725
719
726
private fun ProtoBuf.Type.toTypeRef (context : FirDeserializationContext ): FirResolvedTypeRef =
720
727
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
+ }
721
764
}
0 commit comments