@@ -66,32 +66,8 @@ object Annotations {
6666 def mapWith (tm : TypeMap )(using Context ): Annotation =
6767 tpd.allArguments(tree) match
6868 case Nil => this
69-
7069 case arg :: Nil if symbol.isRetainsLike =>
71- // Use a more efficient scheme to map retains and retainsByName annotations:
72- // 1. Map the type argument to a simple TypeTree instead of tree-mapping
73- // the original tree. TODO Try to use this scheme for other annotations that
74- // take only type arguments as well. We should wait until after 3.9 LTS to
75- // do this, though.
76- // 2. Sanitize the arguments to prevent compilation time blowup.
77- // 3. Drop the annotation entirely if CC is not enabled somewhere.
78-
79- def rebuild (tree : Tree , mappedType : Type ): Tree = tree match
80- case Apply (fn, Nil ) => cpy.Apply (tree)(rebuild(fn, mappedType), Nil )
81- case TypeApply (fn, arg :: Nil ) => cpy.TypeApply (tree)(fn, TypeTree (mappedType) :: Nil )
82- case Block (Nil , expr) => rebuild(expr, mappedType)
83-
84- if ! Feature .ccEnabledSomewhere then
85- EmptyAnnotation // strip retains-like annotations unless capture checking is enabled
86- else
87- val mappedType = sanitize(tm(arg.tpe))
88- if mappedType `eql` arg.tpe then
89- this
90- else if cc.ccConfig.newScheme then
91- CompactAnnotation (symbol.typeRef.appliedTo(mappedType))
92- else
93- derivedAnnotation(rebuild(tree, mappedType))
94-
70+ assert(false , s " unexpected symbol $symbol for ConcreteAnnotation $this in ${ctx.source}, this should be a CompactAnnotation " )
9571 case args =>
9672 // Checks if `tm` would result in any change by applying it to types
9773 // inside the annotations' arguments and checking if the resulting types
@@ -184,17 +160,35 @@ object Annotations {
184160 case ConstantType (c) => Some (c)
185161 case _ => None
186162
163+ /** Sanitize @retains arguments to approximate illegal types that could cause a compilation
164+ * time blowup before they are dropped ot detected. This means mapping all all skolems
165+ * (?n: T) to (?n: Any), and mapping all recursive captures that are not on CapSet to `^`.
166+ * Skolems and capturing types on types other than CapSet are not allowed in a
167+ * @retains annotation anyway, so the underlying type does not matter as long as it is also
168+ * illegal. See i24556.scala and i24556a.scala.
169+ */
170+ private def sanitize (tp : Type )(using Context ): Type = tp match
171+ case SkolemType (_) =>
172+ SkolemType (defn.AnyType )
173+ case tp @ AnnotatedType (parent, ann)
174+ if ann.symbol.isRetainsLike && parent.typeSymbol != defn.Caps_CapSet =>
175+ tp.derivedAnnotatedType(parent, ann.derivedClassAnnotation(defn.RetainsCapAnnot ))
176+ case tp @ OrType (tp1, tp2) =>
177+ tp.derivedOrType(sanitize(tp1), sanitize(tp2))
178+ case _ =>
179+ tp
180+
187181 override def mapWith (tm : TypeMap )(using Context ): Annotation =
188- def derived (tp : Type ) =
189- if tm.isRange(tp) then EmptyAnnotation else derivedAnnotation(tp)
190- def sanitizeArg (tp : Type ) = tp match
191- case tp @ AppliedType (tycon, args) =>
192- tp.derivedAppliedType(tycon, args.mapConserve(sanitize))
182+ val isRetains = symbol.isRetainsLike
183+ if isRetains && ! Feature .ccEnabledSomewhere then EmptyAnnotation
184+ else tm(tp) match
185+ case tp1 @ AppliedType (tycon, args) =>
186+ val args1 = if isRetains then args.mapConserve(sanitize) else args
187+ derivedAnnotation(tp1.derivedAppliedType(tycon, args1))
188+ case tp1 : TypeRef =>
189+ derivedAnnotation(tp1)
193190 case _ =>
194- tp
195- if ! symbol.isRetainsLike then derived(tm(tp))
196- else if Feature .ccEnabledSomewhere then derived(sanitizeArg(tm(tp)))
197- else EmptyAnnotation // strip retains-like annotations unless capture checking is enabled
191+ EmptyAnnotation
198192
199193 override def refersToParamOf (tl : TermLambda )(using Context ): Boolean =
200194 refersToLambdaParam(tp, tl)
@@ -203,25 +197,13 @@ object Annotations {
203197 override def eql (that : Annotation ) = that match
204198 case that : CompactAnnotation => this .tp `eql` that.tp
205199 case _ => false
206- end CompactAnnotation
207200
208- /** Sanitize @retains arguments to approximate illegal types that could cause a compilation
209- * time blowup before they are dropped ot detected. This means mapping all all skolems
210- * (?n: T) to (?n: Any), and mapping all recursive captures that are not on CapSet to `^`.
211- * Skolems and capturing types on types other than CapSet are not allowed in a
212- * @retains annotation anyway, so the underlying type does not matter as long as it is also
213- * illegal. See i24556.scala and i24556a.scala.
214- */
215- private def sanitize (tp : Type )(using Context ): Type = tp match
216- case SkolemType (_) =>
217- SkolemType (defn.AnyType )
218- case tp @ AnnotatedType (parent, ann)
219- if ann.symbol.isRetainsLike && parent.typeSymbol != defn.Caps_CapSet =>
220- tp.derivedAnnotatedType(parent, ann.derivedClassAnnotation(defn.RetainsCapAnnot ))
221- case tp @ OrType (tp1, tp2) =>
222- tp.derivedOrType(sanitize(tp1), sanitize(tp2))
223- case _ =>
224- tp
201+ object CompactAnnotation :
202+ def apply (tree : Tree )(using Context ): CompactAnnotation =
203+ val argTypes = tpd.allArguments(tree).map(_.tpe)
204+ apply(annotClass(tree).typeRef.appliedTo(argTypes))
205+
206+ end CompactAnnotation
225207
226208 private def isLambdaParam (t : Type , tl : TermLambda ): Boolean = t match
227209 case TermParamRef (tl1, _) => tl eq tl1
@@ -311,9 +293,12 @@ object Annotations {
311293
312294 object Annotation {
313295
314- def apply (tree : Tree ): Annotation = tree match
315- case tree : TypeTree => CompactAnnotation (tree.tpe)
316- case _ => ConcreteAnnotation (tree)
296+ def apply (tree : Tree )(using Context ): Annotation = tree match
297+ case tree : TypeTree =>
298+ CompactAnnotation (tree.tpe)
299+ case _ =>
300+ if annotClass(tree).isRetainsLike then CompactAnnotation (tree)
301+ else ConcreteAnnotation (tree)
317302
318303 def apply (cls : ClassSymbol , span : Span )(using Context ): Annotation =
319304 apply(cls, Nil , span)
@@ -328,7 +313,9 @@ object Annotations {
328313 apply(atp, arg :: Nil , span)
329314
330315 def apply (atp : Type , args : List [Tree ], span : Span )(using Context ): Annotation =
331- apply(New (atp, args).withSpan(span))
316+ if atp.typeSymbol.isRetainsLike && args.isEmpty
317+ then CompactAnnotation (atp)
318+ else apply(New (atp, args).withSpan(span))
332319
333320 /** Create an annotation where the tree is computed lazily. */
334321 def deferred (sym : Symbol )(treeFn : Context ?=> Tree ): Annotation =
@@ -370,7 +357,7 @@ object Annotations {
370357 * to indicate that the resulting typemap should drop the annotation
371358 * (in derivedAnnotatedType).
372359 */
373- @ sharable val EmptyAnnotation = Annotation (EmptyTree )
360+ @ sharable val EmptyAnnotation = ConcreteAnnotation (EmptyTree )
374361
375362 def ThrowsAnnotation (cls : ClassSymbol )(using Context ): Annotation = {
376363 val tref = cls.typeRef
0 commit comments