1
- package dotty .tools .scaladoc .cc
1
+ package dotty .tools .scaladoc
2
+
3
+ package cc
2
4
3
5
import scala .quoted ._
4
6
5
7
object CaptureDefs :
6
- /** The name of the `retains` annotation. */
7
- val RetainsName : String = " scala.annotation.retains"
8
-
9
- /** The name of the `retainsCap` annotation. */
10
- val RetainsCapName : String = " scala.annotation.retainsCap"
8
+ // these should become part of the reflect API in the distant future
9
+ def retains (using qctx : Quotes ) = qctx.reflect.Symbol .requiredClass(" scala.annotation.retains" )
10
+ def retainsCap (using qctx : Quotes ) = qctx.reflect.Symbol .requiredClass(" scala.annotation.retainsCap" )
11
+ def retainsByName (using qctx : Quotes ) = qctx.reflect.Symbol .requiredClass(" scala.annotation.retainsByName" )
12
+ def CapsModule (using qctx : Quotes ) = qctx.reflect.Symbol .requiredPackage(" scala.caps" )
13
+ def captureRoot (using qctx : Quotes ) = qctx.reflect.Symbol .requiredPackage(" scala.caps.cap" )
14
+ def Caps_Capability (using qctx : Quotes ) = qctx.reflect.Symbol .requiredClass(" scala.caps.Capability" )
15
+ def Caps_CapSet (using qctx : Quotes ) = qctx.reflect.Symbol .requiredClass(" scala.caps.CapSet" )
16
+ def Caps_Mutable (using qctx : Quotes ) = qctx.reflect.Symbol .requiredClass(" scala.caps.Mutable" )
17
+ def Caps_SharedCapability (using qctx : Quotes ) = qctx.reflect.Symbol .requiredClass(" scala.caps.SharedCapability" )
11
18
12
- /** The name of the `retainsByName` annotation. */
13
- val RetainsByNameName : String = " scala.annotation.retainsByName "
19
+ def UseAnnot ( using qctx : Quotes ) = qctx.reflect. Symbol .requiredClass( " scala.caps.use " )
20
+ def ConsumeAnnot ( using qctx : Quotes ) = qctx.reflect. Symbol .requiredClass( " scala.caps.consume " )
14
21
15
- def retains (using qctx : Quotes ) = qctx.reflect.Symbol .requiredClass(RetainsName )
16
- def retainsCap (using qctx : Quotes ) = qctx.reflect.Symbol .requiredClass(RetainsCapName )
17
- def retainsByName (using qctx : Quotes ) = qctx.reflect.Symbol .requiredClass(RetainsByNameName )
18
22
end CaptureDefs
19
23
20
- extension (using qctx : Quotes )(term : qctx.reflect.Term )
21
-
22
- /** Is this term a `retains`* annotations from capturing types? */
24
+ extension (using qctx : Quotes )(ann : qctx.reflect.Symbol )
25
+ /** This symbol is one of `retains` or `retainsCap` */
23
26
def isRetains : Boolean =
24
- val sym = term.tpe match
25
- case qctx.reflect.AppliedType (base, _) => base.typeSymbol
26
- case other => other.typeSymbol
27
- sym == CaptureDefs .retains
28
- || sym == CaptureDefs .retainsCap
29
- || sym == CaptureDefs .retainsByName
27
+ ann == CaptureDefs .retains || ann == CaptureDefs .retainsCap
28
+
29
+ /** This symbol is one of `retains`, `retainsCap`, or `retainsByName` */
30
+ def isRetainsLike : Boolean =
31
+ ann.isRetains || ann == CaptureDefs .retainsByName
32
+ end extension
33
+
34
+ extension (using qctx : Quotes )(tpe : qctx.reflect.TypeRepr )
35
+ def isCaptureRoot : Boolean = tpe.termSymbol == CaptureDefs .captureRoot
36
+ end extension
37
+
38
+ /** Decompose capture sets in the union-type-encoding into the sequence of atomic `TypeRepr`s.
39
+ * Returns `None` if the type is not a capture set.
40
+ */
41
+ def decomposeCaptureRefs (using qctx : Quotes )(typ0 : qctx.reflect.TypeRepr ): Option [List [qctx.reflect.TypeRepr ]] =
42
+ import qctx .reflect ._
43
+ val buffer = collection.mutable.ListBuffer .empty[TypeRepr ]
44
+ def traverse (typ : TypeRepr ): Boolean =
45
+ typ match
46
+ case OrType (t1, t2) => traverse(t1) && traverse(t2)
47
+ case t @ ThisType (_) => buffer += t; true
48
+ case t @ TermRef (_, _) => buffer += t; true
49
+ case t @ ParamRef (_, _) => buffer += t; true
50
+ // TODO: are atoms only ever the above? Then we could refine the return type
51
+ case _ => report.warning(s " Unexpected type tree $typ while trying to extract capture references from $typ0" ); System .exit(1 ); false // TODO remove warning eventually
52
+ if traverse(typ0) then Some (buffer.toList) else None
53
+ end decomposeCaptureRefs
54
+
55
+ object CaptureSetType :
56
+ def unapply (using qctx : Quotes )(tt : qctx.reflect.TypeTree ): Option [List [qctx.reflect.TypeRepr ]] = decomposeCaptureRefs(tt.tpe)
57
+ end CaptureSetType
58
+
59
+ object CapturingType :
60
+ def unapply (using qctx : Quotes )(typ : qctx.reflect.TypeRepr ): Option [(qctx.reflect.TypeRepr , List [qctx.reflect.TypeRepr ])] =
61
+ import qctx .reflect ._
62
+ typ match
63
+ case AnnotatedType (base, Apply (TypeApply (Select (New (annot), _), List (CaptureSetType (refs))), Nil )) if annot.symbol.isRetainsLike =>
64
+ Some ((base, refs))
65
+ case AnnotatedType (base, Apply (Select (New (annot), _), Nil )) if annot.symbol == CaptureDefs .retainsCap =>
66
+ Some ((base, List (CaptureDefs .captureRoot.termRef)))
67
+ case _ => None
68
+ end CapturingType
69
+
70
+ def renderCaptureSet (using qctx : Quotes )(refs : List [qctx.reflect.TypeRepr ]): List [SignaturePart ] =
71
+ import dotty .tools .scaladoc .tasty .NameNormalizer ._
72
+ import qctx .reflect ._
73
+ refs match
74
+ case List (ref) if ref.isCaptureRoot => List (Keyword (" ^" ))
75
+ case refs =>
76
+ val res0 = refs.map { ref =>
77
+ ref match
78
+ case ThisType (_) => List (Keyword (" this" ))
79
+ case TermRef (_, sym) => List (Plain (sym)) // FIXME: use type other than Plain, can we have clickable links to say, caps.cap and other things?
80
+ case pf @ ParamRef (tpe, i) => List (Plain (tpe.asInstanceOf [MethodType ].paramNames(i))) // FIXME: not sure if this covers all cases
81
+ case _ => List (Plain (" <unknown>" ))
82
+ }
83
+ val res1 = res0 match
84
+ case Nil => Nil
85
+ case other => other.reduce((r, e) => r ++ (List (Plain (" , " )) ++ e))
86
+ Keyword (" ^" ) :: Plain (" {" ) :: (res1 ++ List (Plain (" }" )))
0 commit comments