@@ -191,7 +191,7 @@ class ClassfileParser(
191
191
192
192
setClassInfo(moduleRoot, staticInfo, fromScala2 = false )
193
193
194
- classInfo = parseAttributes(classRoot.symbol, classInfo )
194
+ classInfo = parseAttributes(classInfo).complete( classRoot.symbol)
195
195
if (isAnnotation)
196
196
// classInfo must be a TempClassInfoType and not a TempPolyType,
197
197
// because Java annotations cannot have type parameters.
@@ -227,26 +227,28 @@ class ClassfileParser(
227
227
val sflags =
228
228
if (method) Flags .Method | methodTranslation.flags(jflags)
229
229
else fieldTranslation.flags(jflags)
230
- val name = pool.getName(in.nextChar)
231
- if (! sflags.isOneOf(Flags .PrivateOrArtifact ) || name.name == nme.CONSTRUCTOR ) {
230
+ val preName = pool.getName(in.nextChar)
231
+ if (! sflags.isOneOf(Flags .PrivateOrArtifact ) || preName.name == nme.CONSTRUCTOR ) {
232
+ val isVarargs = sflags.is(Flags .Method ) && (jflags & JAVA_ACC_VARARGS ) != 0
233
+ val info = pool.getType(in.nextChar, isVarargs) // info
234
+ val attrCompleter = parseAttributes(info, isVarargs)
235
+ val completer = memberCompleter(attrCompleter, preName.name, jflags, info)
232
236
val member = newSymbol(
233
- getOwner(jflags), name .name, sflags, memberCompleter ,
237
+ getOwner(jflags), preName .name, sflags, completer ,
234
238
getPrivateWithin(jflags), coord = start)
235
239
getScope(jflags).enter(member)
236
240
}
237
- // skip rest of member for now
238
- in.nextChar // info
239
- skipAttributes()
241
+ else {
242
+ in.nextChar // info
243
+ skipAttributes()
244
+ }
240
245
}
241
246
242
- val memberCompleter : LazyType = new LazyType {
247
+ def memberCompleter ( attrCompleter : AttributeCompleter , name : SimpleName , jflags : Int , info : Type ) : LazyType = new LazyType {
243
248
244
- def complete (denot : SymDenotation )(using Context ): Unit = withReader(classfile) { (using in) =>
245
- in.bp = denot.symbol.coord.toIndex
249
+ def complete (denot : SymDenotation )(using Context ): Unit = {
246
250
val sym = denot.symbol
247
- val jflags = in.nextChar
248
251
val isEnum = (jflags & JAVA_ACC_ENUM ) != 0
249
- val name = pool.getName(in.nextChar).name
250
252
val isConstructor = name eq nme.CONSTRUCTOR
251
253
252
254
/** Strip leading outer param from constructor and trailing access tag for
@@ -282,10 +284,9 @@ class ClassfileParser(
282
284
addConstructorTypeParams(denot)
283
285
}
284
286
285
- val isVarargs = denot.is(Flags .Method ) && (jflags & JAVA_ACC_VARARGS ) != 0
286
- denot.info = pool.getType(in.nextChar, isVarargs)
287
+ denot.info = info
287
288
if (isConstructor) normalizeConstructorParams()
288
- denot.info = translateTempPoly(parseAttributes (sym, denot.info, isVarargs ))
289
+ denot.info = translateTempPoly(attrCompleter.complete (sym))
289
290
if (isConstructor) normalizeConstructorInfo()
290
291
291
292
if (ctx.explicitNulls) denot.info = JavaNullInterop .nullifyMember(denot.symbol, denot.info, isEnum)
@@ -604,38 +605,63 @@ class ClassfileParser(
604
605
None // ignore malformed annotations
605
606
}
606
607
607
- def parseAttributes (sym : Symbol , symtype : Type , isVarargs : Boolean = false )(using ctx : Context , in : DataReader ): Type = {
608
+ abstract class AttributeCompleter {
609
+ private val effectList = new ArrayBuffer [Context => Unit ]()
610
+ inline def later (inline op : Context ?=> Unit ): Unit =
611
+ effectList.append((ctx : Context ) => op(using ctx)) // TODO: avoid closure creation
612
+
613
+ protected def force ()(using ctx : Context ): Unit =
614
+ effectList.foreach(_.apply(ctx))
615
+
616
+ def complete (sym : Symbol )(using Context ): Type
617
+ }
618
+
619
+ // invariant: `in` should not be captured inside the result function
620
+ def parseAttributes (symtype : Type , isVarargs : Boolean = false )(using ctx : Context , in : DataReader ): AttributeCompleter = {
621
+ var sym : Symbol = null // placeholder
608
622
var newType = symtype
609
623
624
+ val res = new AttributeCompleter {
625
+ def complete (symIn : Symbol )(using Context ): Type = {
626
+ sym = symIn
627
+ force()
628
+ cook.apply(newType)
629
+ }
630
+ }
631
+
632
+ import res .later
633
+
610
634
def parseAttribute (): Unit = {
611
635
val attrName = pool.getName(in.nextChar).name.toTypeName
612
636
val attrLen = in.nextInt
613
637
val end = in.bp + attrLen
614
638
attrName match {
615
639
case tpnme.SignatureATTR =>
616
640
val sig = pool.getExternalName(in.nextChar)
617
- newType = sigToType(sig.value, sym, isVarargs)
618
- if (ctx.debug && ctx.verbose)
619
- println(" " + sym + " ; signature = " + sig + " type = " + newType)
641
+ later {
642
+ newType = sigToType(sig.value, sym, isVarargs)
643
+ if (ctx.debug && ctx.verbose)
644
+ println(" " + sym + " ; signature = " + sig + " type = " + newType)
645
+ }
620
646
621
647
case tpnme.SyntheticATTR =>
622
- sym.setFlag(Flags .SyntheticArtifact )
648
+ later { sym.setFlag(Flags .SyntheticArtifact ) }
623
649
624
650
case tpnme.BridgeATTR =>
625
- sym.setFlag(Flags .Bridge )
651
+ later { sym.setFlag(Flags .Bridge ) }
626
652
627
653
case tpnme.DeprecatedATTR =>
628
654
val msg = Literal (Constant (" see corresponding Javadoc for more information." ))
629
655
val since = Literal (Constant (" " ))
630
- sym.addAnnotation(Annotation (defn.DeprecatedAnnot , msg, since))
656
+ later { sym.addAnnotation(Annotation (defn.DeprecatedAnnot , msg, since)) }
631
657
632
658
case tpnme.ConstantValueATTR =>
633
659
val c = pool.getConstant(in.nextChar, symtype)
634
660
if (c ne null ) newType = ConstantType (c)
635
661
else report.warning(s " Invalid constant in attribute of ${sym.showLocated} while parsing ${classfile}" )
636
662
637
663
case tpnme.AnnotationDefaultATTR =>
638
- sym.addAnnotation(Annotation (defn.AnnotationDefaultAnnot , Nil ))
664
+ later { sym.addAnnotation(Annotation (defn.AnnotationDefaultAnnot , Nil )) }
639
665
640
666
// Java annotations on classes / methods / fields with RetentionPolicy.RUNTIME
641
667
case tpnme.RuntimeVisibleAnnotationATTR
@@ -652,12 +678,14 @@ class ClassfileParser(
652
678
parseExceptions(attrLen)
653
679
654
680
case tpnme.CodeATTR =>
655
- if (sym.owner.isAllOf(Flags .JavaInterface )) {
656
- sym.resetFlag(Flags .Deferred )
657
- sym.owner.resetFlag(Flags .PureInterface )
658
- report.log(s " $sym in ${sym.owner} is a java8+ default method. " )
659
- }
660
681
in.skip(attrLen)
682
+ later {
683
+ if (sym.owner.isAllOf(Flags .JavaInterface )) {
684
+ sym.resetFlag(Flags .Deferred )
685
+ sym.owner.resetFlag(Flags .PureInterface )
686
+ report.log(s " $sym in ${sym.owner} is a java8+ default method. " )
687
+ }
688
+ }
661
689
662
690
case _ =>
663
691
}
@@ -673,18 +701,19 @@ class ClassfileParser(
673
701
for (n <- 0 until nClasses) {
674
702
// FIXME: this performs an equivalent of getExceptionTypes instead of getGenericExceptionTypes (SI-7065)
675
703
val cls = pool.getClassSymbol(in.nextChar.toInt)
676
- sym.addAnnotation(ThrowsAnnotation (cls.asClass))
704
+ later { sym.addAnnotation(ThrowsAnnotation (cls.asClass)) }
677
705
}
678
706
}
679
707
708
+
680
709
/** Parse a sequence of annotations and attaches them to the
681
710
* current symbol sym, except for the ScalaSignature annotation that it returns, if it is available. */
682
711
def parseAnnotations (len : Int ): Unit = {
683
712
val nAttr = in.nextChar
684
713
for (n <- 0 until nAttr)
685
714
parseAnnotation(in.nextChar) match {
686
715
case Some (annot) =>
687
- sym.addAnnotation(annot)
716
+ later { sym.addAnnotation(annot) }
688
717
case None =>
689
718
}
690
719
}
@@ -693,7 +722,7 @@ class ClassfileParser(
693
722
for (i <- 0 until in.nextChar)
694
723
parseAttribute()
695
724
696
- cook.apply(newType)
725
+ res
697
726
}
698
727
699
728
/** Annotations in Scala are assumed to get all their arguments as constructor
0 commit comments