Skip to content

Commit c9a16b1

Browse files
bracevacnatsukagami
authored andcommitted
Rendering of CapSet types
1 parent 088d043 commit c9a16b1

File tree

4 files changed

+62
-35
lines changed

4 files changed

+62
-35
lines changed

local/project/dummy/capturevars.scala

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
package dummy
22

33
import language.experimental.captureChecking
4+
import caps.*
45

56
trait Test:
6-
type T[-C^]
7+
val a: AnyRef^
8+
val b: AnyRef^
9+
type Ordinary
10+
type Ordinary2 >: Int <: String
11+
type T[-C^ >: {a,b}]
712
type U[+C^]
813
type C^
9-
type D^
10-
def foo[C^](x: T[C]): Unit
11-
def bar(x: T[{}]): Unit
12-
def baz(x: T[{caps.cap}]): Unit
14+
type D^ >: {C} <: {a,b}
15+
type E^ <: C
16+
type F^ <: {D,E}
17+
def foo[C^ >: {a,b}](x: T[C]): Unit
18+
def bar(x: T[{a,b}]): Unit
19+
def baz(x: T[{a,b,caps.cap}]): Unit
1320
def foo2[C^](x: U[C]): Unit
14-
def bar2(x: U[{}]): Unit
21+
def bar2(x: U[{a,b,cap}]): Unit
1522
def baz2(x: U[{caps.cap}]): Unit
16-
def test[E^, F^ >: {caps.cap} <: {}](x: T[E], y: U[F]): Unit
23+
def test[E^, F^ >: {caps.cap} <: {}](x: T[{E,a,b}], y: U[F]): Unit

scaladoc/src/dotty/tools/scaladoc/cc/CaptureOps.scala

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ extension (using qctx: Quotes)(tpe: qctx.reflect.TypeRepr) // FIXME clean up and
9393
def isAnyFunction: Boolean = tpe.typeSymbol.fullName.startsWith("scala.Function")
9494

9595
def isAnyContextFunction: Boolean = tpe.typeSymbol.fullName.startsWith("scala.ContextFunction")
96+
97+
def isCapSet: Boolean = tpe.typeSymbol == CaptureDefs.Caps_CapSet
98+
99+
def isCapSetPure: Boolean =
100+
tpe.isCapSet && tpe.match
101+
case CapturingType(_, refs) => refs.isEmpty
102+
case _ => true
103+
104+
def isCapSetCap: Boolean =
105+
tpe.isCapSet && tpe.match
106+
case CapturingType(_, List(ref)) => ref.isCaptureRoot
107+
case _ => false
96108
end extension
97109

98110
/** Matches `import scala.language.experimental.captureChecking` */
@@ -136,14 +148,14 @@ def decomposeCaptureRefs(using qctx: Quotes)(typ0: qctx.reflect.TypeRepr): Optio
136148
def include(t: TypeRepr): Boolean = { buffer += t; true }
137149
def traverse(typ: TypeRepr): Boolean =
138150
typ match
151+
case t if t.typeSymbol == defn.NothingClass => true
139152
case OrType(t1, t2) => traverse(t1) && traverse(t2)
140153
case t @ ThisType(_) => include(t)
141154
case t @ TermRef(_, _) => include(t)
142155
case t @ ParamRef(_, _) => include(t)
143156
case t @ ReachCapability(_) => include(t)
144157
case t @ ReadOnlyCapability(_) => include(t)
145-
case t if t.typeSymbol == defn.NothingClass => true
146-
// TODO: are atoms only ever the above? Then we could refine the return type
158+
case t : TypeRef => include(t) // FIXME: does this need a more refined check?
147159
case _ => report.warning(s"Unexpected type tree $typ while trying to extract capture references from $typ0"); false // TODO remove warning eventually
148160
if traverse(typ0) then Some(buffer.toList) else None
149161
end decomposeCaptureRefs

scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package dotty.tools.scaladoc.tasty
33
import dotty.tools.scaladoc._
44
import dotty.tools.scaladoc.{Signature => DSignature}
55

6+
import dotty.tools.scaladoc.cc.CaptureDefs
7+
68
import scala.quoted._
79

810
import SymOps._

scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ trait TypesSupport:
6262
private def tpe(using Quotes)(symbol: reflect.Symbol)(using inCC: Option[Any]): SSignature =
6363
import SymOps._
6464
val dri: Option[DRI] = Option(symbol).filterNot(_.isHiddenByVisibility).map(_.dri)
65-
if inCC.isDefined then
65+
if inCC.isDefined then // we are in the context of a capture set and want paths to be rendered plainly
6666
dotty.tools.scaladoc.Plain(symbol.normalizedName).l
6767
else
6868
dotty.tools.scaladoc.Type(symbol.normalizedName, dri).l
@@ -124,9 +124,9 @@ trait TypesSupport:
124124
++ keyword(" & ").l
125125
++ inParens(inner(right, skipThisTypePrefix), shouldWrapInParens(right, tp, false))
126126
case ByNameType(CapturingType(tpe, refs)) =>
127-
renderByNameArrow(using q)(Some(refs), skipThisTypePrefix) ++ (plain(" ") :: inner(tpe, skipThisTypePrefix))
127+
emitByNameArrow(using q)(Some(refs), skipThisTypePrefix) ++ (plain(" ") :: inner(tpe, skipThisTypePrefix))
128128
case ByNameType(tpe) =>
129-
renderByNameArrow(using q)(None, skipThisTypePrefix) ++ (plain(" ") :: inner(tpe, skipThisTypePrefix))
129+
emitByNameArrow(using q)(None, skipThisTypePrefix) ++ (plain(" ") :: inner(tpe, skipThisTypePrefix))
130130
case ConstantType(constant) =>
131131
plain(constant.show).l
132132
case ThisType(tpe) =>
@@ -137,12 +137,14 @@ trait TypesSupport:
137137
inner(tpe, skipThisTypePrefix) :+ plain("*")
138138
case AppliedType(repeatedClass, Seq(tpe)) if isRepeated(repeatedClass) =>
139139
inner(tpe, skipThisTypePrefix) :+ plain("*")
140-
case CapturingType(base, refs) => base match
141-
case t @ AppliedType(base, args) if t.isFunctionType =>
142-
functionType(base, args, skipThisTypePrefix)(using inCC = Some(refs))
143-
case t : Refinement if t.isFunctionType =>
144-
inner(base, skipThisTypePrefix)(using inCC = Some(refs))
145-
case _ => inner(base, skipThisTypePrefix) ++ renderCapturing(refs, skipThisTypePrefix)
140+
case CapturingType(base, refs) =>
141+
base match
142+
case t @ AppliedType(base, args) if t.isFunctionType =>
143+
functionType(base, args, skipThisTypePrefix)(using inCC = Some(refs))
144+
case t : Refinement if t.isFunctionType =>
145+
inner(base, skipThisTypePrefix)(using inCC = Some(refs))
146+
case t if t.isCapSet => emitCaptureSet(refs, skipThisTypePrefix, omitCap = false)
147+
case _ => inner(base, skipThisTypePrefix) ++ emitCapturing(refs, skipThisTypePrefix)
146148
case AnnotatedType(tpe, _) =>
147149
inner(tpe, skipThisTypePrefix)
148150
case tl @ TypeLambda(params, paramBounds, AppliedType(tpe, args))
@@ -221,7 +223,7 @@ trait TypesSupport:
221223
inCC match
222224
case None | Some(Nil) => keyword(arrPrefix + "->").l
223225
case Some(List(c)) if c.isCaptureRoot => keyword(arrPrefix + "=>").l
224-
case Some(refs) => keyword(arrPrefix + "->") :: renderCaptureSet(refs, skipThisTypePrefix)
226+
case Some(refs) => keyword(arrPrefix + "->") :: emitCaptureSet(refs, skipThisTypePrefix)
225227
else keyword(arrPrefix + "=>").l
226228
val resType = inner(m.resType, skipThisTypePrefix)(using inCC = None)
227229
paramList ++ (plain(" ") :: arrow) ++ (plain(" ") :: resType)
@@ -275,6 +277,8 @@ trait TypesSupport:
275277
case _ => topLevelProcess(t, skipThisTypePrefix)
276278
}) ++ plain("]").l
277279

280+
case t : TypeRef if t.isCapSet => emitCaptureSet(Nil, skipThisTypePrefix)
281+
278282
case tp @ TypeRef(qual, typeName) =>
279283
qual match {
280284
case r: RecursiveThis => tpe(s"this.$typeName").l
@@ -362,7 +366,7 @@ trait TypesSupport:
362366
inCC: Option[List[reflect.TypeRepr]],
363367
): SSignature =
364368
import reflect._
365-
val arrow = plain(" ") :: (renderFunctionArrow(using q)(funTy, inCC, skipThisTypePrefix) ++ plain(" ").l)
369+
val arrow = plain(" ") :: (emitFunctionArrow(using q)(funTy, inCC, skipThisTypePrefix) ++ plain(" ").l)
366370
given Option[List[TypeRepr]] = None // FIXME: this is ugly
367371
args match
368372
case Nil => Nil
@@ -378,7 +382,10 @@ trait TypesSupport:
378382

379383
private def typeBound(using Quotes)(t: reflect.TypeRepr, low: Boolean, skipThisTypePrefix: Boolean)(using elideThis: reflect.ClassDef, originalOwner: reflect.Symbol) =
380384
import reflect._
381-
val ignore = if (low) t.typeSymbol == defn.NothingClass else t.typeSymbol == defn.AnyClass
385+
val ignore = low && (ccEnabled && t.isCapSetPure
386+
|| t.typeSymbol == defn.NothingClass)
387+
|| !low && (ccEnabled && t.isCapSetCap
388+
|| t.typeSymbol == defn.AnyClass)
382389
val prefix = keyword(if low then " >: " else " <: ")
383390
t match {
384391
case l: TypeLambda => prefix :: inParens(inner(l, skipThisTypePrefix)(using elideThis, originalOwner))
@@ -482,37 +489,36 @@ trait TypesSupport:
482489
case AnnotatedType(tr, _) => stripAnnotated(tr)
483490
case other => other
484491

485-
private def renderCapability(using Quotes)(ref: reflect.TypeRepr, skipThisTypePrefix: Boolean)(
492+
private def emitCapability(using Quotes)(ref: reflect.TypeRepr, skipThisTypePrefix: Boolean)(
486493
using elideThis: reflect.ClassDef, originalOwner: reflect.Symbol
487494
): SSignature =
488495
import reflect._
489496
ref match
490-
case ReachCapability(c) => renderCapability(c, skipThisTypePrefix) :+ Keyword("*")
491-
case ReadOnlyCapability(c) => renderCapability(c, skipThisTypePrefix) :+ Keyword(".rd")
497+
case ReachCapability(c) => emitCapability(c, skipThisTypePrefix) :+ Keyword("*")
498+
case ReadOnlyCapability(c) => emitCapability(c, skipThisTypePrefix) :+ Keyword(".rd")
492499
case ThisType(_) => List(Keyword("this"))
493500
case t => inner(t, skipThisTypePrefix)(using skipTypeSuffix = true, inCC = Some(Nil))
494501

495-
private def renderCaptureSet(using Quotes)(refs: List[reflect.TypeRepr], skipThisTypePrefix: Boolean)(
502+
private def emitCaptureSet(using Quotes)(refs: List[reflect.TypeRepr], skipThisTypePrefix: Boolean, omitCap: Boolean = true)(
496503
using elideThis: reflect.ClassDef, originalOwner: reflect.Symbol
497504
): SSignature =
498-
import dotty.tools.scaladoc.tasty.NameNormalizer._
499505
import reflect._
500506
refs match
501-
case List(ref) if ref.isCaptureRoot => Nil
507+
case List(ref) if omitCap && ref.isCaptureRoot => Nil
502508
case refs =>
503-
val res0 = refs.map(renderCapability(_, skipThisTypePrefix))
509+
val res0 = refs.map(emitCapability(_, skipThisTypePrefix))
504510
val res1 = res0 match
505511
case Nil => Nil
506512
case other => other.reduce((r, e) => r ++ (List(Plain(", ")) ++ e))
507513
Plain("{") :: (res1 ++ List(Plain("}")))
508514

509-
private def renderCapturing(using Quotes)(refs: List[reflect.TypeRepr], skipThisTypePrefix: Boolean)(
515+
private def emitCapturing(using Quotes)(refs: List[reflect.TypeRepr], skipThisTypePrefix: Boolean)(
510516
using elideThis: reflect.ClassDef, originalOwner: reflect.Symbol
511517
): SSignature =
512518
import reflect._
513-
Keyword("^") :: renderCaptureSet(refs, skipThisTypePrefix)
519+
Keyword("^") :: emitCaptureSet(refs, skipThisTypePrefix)
514520

515-
private def renderFunctionArrow(using q: Quotes)(funTy: reflect.TypeRepr, captures: Option[List[reflect.TypeRepr]], skipThisTypePrefix: Boolean)(
521+
private def emitFunctionArrow(using Quotes)(funTy: reflect.TypeRepr, captures: Option[List[reflect.TypeRepr]], skipThisTypePrefix: Boolean)(
516522
using elideThis: reflect.ClassDef, originalOwner: reflect.Symbol
517523
): SSignature =
518524
import reflect._
@@ -530,16 +536,16 @@ trait TypesSupport:
530536
else if isImpureFun then
531537
List(Keyword(prefix + "=>"))
532538
else
533-
report.error(s"Cannot render function arrow: expected a (Context)Function* or Impure(Context)Function*, but got: ${funTy.show}")
539+
report.error(s"Cannot emit function arrow: expected a (Context)Function* or Impure(Context)Function*, but got: ${funTy.show}")
534540
Nil
535541
case Some(refs) =>
536542
// there is some capture set
537543
refs match
538544
case Nil => List(Keyword(prefix + "->"))
539545
case List(ref) if ref.isCaptureRoot => List(Keyword(prefix + "=>"))
540-
case refs => Keyword(prefix + "->") :: renderCaptureSet(using q)(refs, skipThisTypePrefix)
546+
case refs => Keyword(prefix + "->") :: emitCaptureSet(refs, skipThisTypePrefix)
541547

542-
private def renderByNameArrow(using Quotes)(captures: Option[List[reflect.TypeRepr]], skipThisTypePrefix: Boolean)(
548+
private def emitByNameArrow(using Quotes)(captures: Option[List[reflect.TypeRepr]], skipThisTypePrefix: Boolean)(
543549
using elideThis: reflect.ClassDef, originalOwner: reflect.Symbol
544550
): SSignature =
545-
renderFunctionArrow(CaptureDefs.Function1.typeRef, captures, skipThisTypePrefix)
551+
emitFunctionArrow(CaptureDefs.Function1.typeRef, captures, skipThisTypePrefix)

0 commit comments

Comments
 (0)