Skip to content

Commit 5e3c75f

Browse files
committed
Special class for RetainingAnnotations
1 parent 53f1117 commit 5e3c75f

File tree

5 files changed

+72
-47
lines changed

5 files changed

+72
-47
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package dotty.tools
2+
package dotc
3+
package cc
4+
5+
import core.*
6+
import Types.*, Symbols.*, Contexts.*
7+
import Annotations.{Annotation, CompactAnnotation, EmptyAnnotation}
8+
import config.Feature
9+
10+
/** A class for annotations @retains, @retainsByName and @retainsCap */
11+
class RetainingAnnotation(tpe: Type) extends CompactAnnotation(tpe):
12+
13+
/** Sanitize @retains arguments to approximate illegal types that could cause a compilation
14+
* time blowup before they are dropped ot detected. This means mapping all all skolems
15+
* (?n: T) to (?n: Any), and mapping all recursive captures that are not on CapSet to `^`.
16+
* Skolems and capturing types on types other than CapSet are not allowed in a
17+
* @retains annotation anyway, so the underlying type does not matter as long as it is also
18+
* illegal. See i24556.scala and i24556a.scala.
19+
*/
20+
override protected def sanitize(tp: Type)(using Context): Type = tp match
21+
case SkolemType(_) =>
22+
SkolemType(defn.AnyType)
23+
case tp @ AnnotatedType(parent, ann)
24+
if ann.symbol.isRetainsLike && parent.typeSymbol != defn.Caps_CapSet =>
25+
tp.derivedAnnotatedType(parent, ann.derivedClassAnnotation(defn.RetainsCapAnnot))
26+
case tp @ OrType(tp1, tp2) =>
27+
tp.derivedOrType(sanitize(tp1), sanitize(tp2))
28+
case _ =>
29+
tp
30+
31+
override def mapWith(tm: TypeMap)(using Context): Annotation =
32+
if Feature.ccEnabledSomewhere then mapWithCtd(tm) else EmptyAnnotation
33+
34+
/*
35+
def toCaptureSet(using Context): CaptureSet =
36+
CaptureSet(argumentType(0).retainedElements*)
37+
*/
38+
end RetainingAnnotation

compiler/src/dotty/tools/dotc/cc/RetainingType.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@ package cc
44

55
import core.*
66
import Types.*, Symbols.*, Contexts.*
7-
import ast.tpd.*
8-
import Annotations.CompactAnnotation
9-
import Decorators.i
107

118
/** A builder and extractor for annotated types with @retains or @retainsByName annotations
129
* excluding CapturingTypes.
@@ -15,7 +12,7 @@ object RetainingType:
1512

1613
def apply(tp: Type, typeElems: Type, byName: Boolean = false)(using Context): Type =
1714
val annotCls = if byName then defn.RetainsByNameAnnot else defn.RetainsAnnot
18-
AnnotatedType(tp, CompactAnnotation(annotCls.typeRef.appliedTo(typeElems)))
15+
AnnotatedType(tp, RetainingAnnotation(annotCls.typeRef.appliedTo(typeElems)))
1916

2017
def unapply(tp: AnnotatedType)(using Context): Option[(Type, Type)] =
2118
val sym = tp.annot.symbol

compiler/src/dotty/tools/dotc/core/Annotations.scala

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import ast.tpd, tpd.*
77
import util.Spans.Span
88
import printing.{Showable, Printer}
99
import printing.Texts.Text
10-
import cc.isRetainsLike
10+
import cc.{isRetainsLike, RetainingAnnotation}
1111
import config.Feature
1212
import Decorators.*
1313

@@ -130,12 +130,12 @@ object Annotations {
130130
case class ConcreteAnnotation(t: Tree) extends Annotation:
131131
def tree(using Context): Tree = t
132132

133-
case class CompactAnnotation(tp: Type) extends Annotation:
134-
assert(tp.isInstanceOf[AppliedType | TypeRef], tp)
133+
class CompactAnnotation(val tpe: Type) extends Annotation:
134+
assert(tpe.isInstanceOf[AppliedType | TypeRef], tpe)
135135

136-
def tree(using Context) = TypeTree(tp)
136+
def tree(using Context) = TypeTree(tpe)
137137

138-
override def symbol(using Context) = tp.typeSymbol
138+
override def symbol(using Context) = tpe.typeSymbol
139139

140140
override def derivedAnnotation(tree: Tree)(using Context): Annotation =
141141
derivedAnnotation(tree.tpe)
@@ -144,12 +144,12 @@ object Annotations {
144144
derivedAnnotation(cls.typeRef)
145145

146146
def derivedAnnotation(tp: Type)(using Context): Annotation =
147-
if tp eq this.tp then this else CompactAnnotation(tp)
147+
if tp eq this.tpe then this else CompactAnnotation(tp)
148148

149149
override def arguments(using Context): List[Tree] =
150150
argumentTypes.map(TypeTree(_))
151151

152-
override def argumentTypes(using Context): List[Type] = tp.argTypes
152+
override def argumentTypes(using Context): List[Type] = tpe.argTypes
153153

154154
def argumentType(i: Int)(using Context): Type =
155155
val args = argumentTypes
@@ -160,49 +160,39 @@ object Annotations {
160160
case ConstantType(c) => Some(c)
161161
case _ => None
162162

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.
163+
/** A hook to transform the type argument of a mapped annotation. Overridden in
164+
* RetainingAnnotation to avoid compilation time blowups for annotations that
165+
* are not valid capture annotations.
169166
*/
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))
167+
protected def sanitize(tp: Type)(using Context): Type = tp
168+
169+
protected def mapWithCtd(tm: TypeMap)(using Context): Annotation = tm(tpe) match
170+
case tp1 @ AppliedType(tycon, args) =>
171+
derivedAnnotation(tp1.derivedAppliedType(tycon, args.mapConserve(sanitize)))
172+
case tp1: TypeRef =>
173+
derivedAnnotation(tp1)
178174
case _ =>
179-
tp
175+
EmptyAnnotation
180176

181177
override def mapWith(tm: TypeMap)(using Context): Annotation =
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)
190-
case _ =>
191-
EmptyAnnotation
178+
assert(!symbol.isRetainsLike)
179+
mapWithCtd(tm)
192180

193181
override def refersToParamOf(tl: TermLambda)(using Context): Boolean =
194-
refersToLambdaParam(tp, tl)
182+
refersToLambdaParam(tpe, tl)
195183

196-
override def hash: Int = tp.hash
184+
override def hash: Int = tpe.hash
197185
override def eql(that: Annotation) = that match
198-
case that: CompactAnnotation => this.tp `eql` that.tp
186+
case that: CompactAnnotation => this.tpe `eql` that.tpe
199187
case _ => false
200188

201189
object CompactAnnotation:
190+
def apply(tp: Type)(using Context): CompactAnnotation =
191+
if tp.typeSymbol.isRetainsLike then RetainingAnnotation(tp)
192+
else new CompactAnnotation(tp)
202193
def apply(tree: Tree)(using Context): CompactAnnotation =
203194
val argTypes = tpd.allArguments(tree).map(_.tpe)
204195
apply(annotClass(tree).typeRef.appliedTo(argTypes))
205-
206196
end CompactAnnotation
207197

208198
private def isLambdaParam(t: Type, tl: TermLambda): Boolean = t match
@@ -314,7 +304,7 @@ object Annotations {
314304

315305
def apply(atp: Type, args: List[Tree], span: Span)(using Context): Annotation =
316306
if atp.typeSymbol.isRetainsLike && args.isEmpty
317-
then CompactAnnotation(atp)
307+
then RetainingAnnotation(atp)
318308
else apply(New(atp, args).withSpan(span))
319309

320310
/** Create an annotation where the tree is computed lazily. */

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4228,9 +4228,9 @@ object Types extends TypeUtils {
42284228
if ann.symbol.isRetainsLike then
42294229
range(
42304230
AnnotatedType(parent1,
4231-
CompactAnnotation(defn.RetainsAnnot.typeRef.appliedTo(defn.NothingType))),
4231+
RetainingAnnotation(defn.RetainsAnnot.typeRef.appliedTo(defn.NothingType))),
42324232
AnnotatedType(parent1,
4233-
CompactAnnotation(defn.RetainsCapAnnot.appliedRef)))
4233+
RetainingAnnotation(defn.RetainsCapAnnot.appliedRef)))
42344234
else
42354235
parent1
42364236
case _ => mapOver(tp)

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,10 +286,10 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
286286
withLength:
287287
pickleType(tpe.parent, richTypes)
288288
tpe.annot match
289-
case CompactAnnotation(tp) => pickleType(tp)
290-
case _ =>
291-
pickleTree(tpe.annot.tree)
292-
annotatedTypeTrees += tpe.annot.tree
289+
case ann: CompactAnnotation => pickleType(ann.tpe)
290+
case ann =>
291+
pickleTree(ann.tree)
292+
annotatedTypeTrees += ann.tree
293293
case tpe: AndType =>
294294
writeByte(ANDtype)
295295
withLength { pickleType(tpe.tp1, richTypes); pickleType(tpe.tp2, richTypes) }

0 commit comments

Comments
 (0)