Skip to content

Commit 351851a

Browse files
committed
Improve printing of capturing types
Avoid explicit retains annotations also outside phase cc
1 parent 13a5341 commit 351851a

File tree

6 files changed

+46
-12
lines changed

6 files changed

+46
-12
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@ def retainedElems(tree: Tree)(using Context): List[Tree] = tree match
1717
case Apply(_, Typed(SeqLiteral(elems, _), _) :: Nil) => elems
1818
case _ => Nil
1919

20+
class IllegalCaptureRef(tpe: Type) extends Exception
21+
2022
extension (tree: Tree)
2123

22-
def toCaptureRef(using Context): CaptureRef = tree.tpe.asInstanceOf[CaptureRef]
24+
def toCaptureRef(using Context): CaptureRef = tree.tpe match
25+
case ref: CaptureRef => ref
26+
case tpe => throw IllegalCaptureRef(tpe)
2327

2428
def toCaptureSet(using Context): CaptureSet =
2529
tree.getAttachment(Captures) match

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ sealed abstract class CaptureSet extends Showable:
4949
/** Is this capture set definitely non-empty? */
5050
final def isNotEmpty: Boolean = !elems.isEmpty
5151

52+
final def isUniversal(using Context) =
53+
elems.exists {
54+
case ref: TermRef => ref.symbol == defn.captureRoot
55+
case _ => false
56+
}
57+
5258
/** Cast to variable. @pre: @isConst */
5359
def asVar: Var =
5460
assert(!isConst)

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,20 @@ object CapturingType:
1212
else AnnotatedType(parent, CaptureAnnotation(refs, boxed))
1313

1414
def unapply(tp: AnnotatedType)(using Context): Option[(Type, CaptureSet, Boolean)] =
15-
if ctx.phase == Phases.checkCapturesPhase && tp.annot.symbol == defn.RetainsAnnot then
15+
if ctx.phase == Phases.checkCapturesPhase then EventuallyCapturingType.unapply(tp)
16+
else None
17+
18+
end CapturingType
19+
20+
object EventuallyCapturingType:
21+
22+
def unapply(tp: AnnotatedType)(using Context): Option[(Type, CaptureSet, Boolean)] =
23+
if tp.annot.symbol == defn.RetainsAnnot then
1624
tp.annot match
1725
case ann: CaptureAnnotation => Some((tp.parent, ann.refs, ann.boxed))
1826
case ann => Some((tp.parent, ann.tree.toCaptureSet, ann.tree.isBoxedCapturing))
1927
else None
2028

21-
end CapturingType
29+
end EventuallyCapturingType
30+
31+

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import util.SourcePosition
1515
import scala.util.control.NonFatal
1616
import scala.annotation.switch
1717
import config.Config
18-
import cc.{CapturingType, CaptureSet}
18+
import cc.{EventuallyCapturingType, CaptureSet}
1919

2020
class PlainPrinter(_ctx: Context) extends Printer {
2121

@@ -140,6 +140,9 @@ class PlainPrinter(_ctx: Context) extends Printer {
140140
+ defn.ObjectClass
141141
+ defn.FromJavaObjectSymbol
142142

143+
def toText(cs: CaptureSet): Text =
144+
"{" ~ Text(cs.elems.toList.map(toTextCaptureRef), ", ") ~ "}"
145+
143146
def toText(tp: Type): Text = controlled {
144147
homogenize(tp) match {
145148
case tp: TypeType =>
@@ -189,7 +192,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
189192
keywordStr(" match ") ~ "{" ~ casesText ~ "}" ~
190193
(" <: " ~ toText(bound) provided !bound.isAny)
191194
}.close
192-
case CapturingType(parent, refs, boxed) =>
195+
case EventuallyCapturingType(parent, refs, boxed) =>
193196
def box = Str("box ") provided boxed
194197
if printDebug && !refs.isConst then
195198
changePrec(GlobalPrec)(box ~ s"$refs " ~ toText(parent))
@@ -198,11 +201,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
198201
else if !refs.isConst && refs.elems.isEmpty then
199202
changePrec(GlobalPrec)("?" ~ " " ~ toText(parent))
200203
else if Config.printCaptureSetsAsPrefix then
201-
changePrec(GlobalPrec)(
202-
box ~ "{"
203-
~ Text(refs.elems.toList.map(toTextCaptureRef), ", ")
204-
~ "} "
205-
~ toText(parent))
204+
changePrec(GlobalPrec)(box ~ toText(refs) ~ " " ~ toText(parent))
206205
else
207206
changePrec(InfixPrec)(toText(parent) ~ " retains " ~ box ~ toText(refs.toRetainsTypeArg))
208207
case tp: PreviousErrorType if ctx.settings.XprintTypes.value =>

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import Annotations.Annotation
1515
import Denotations._
1616
import SymDenotations._
1717
import StdNames.{nme, tpnme}
18-
import ast.{Trees, untpd}
18+
import ast.{Trees, tpd, untpd}
1919
import typer.{Implicits, Namer, Applications}
2020
import typer.ProtoTypes._
2121
import Trees._
@@ -25,10 +25,12 @@ import NameKinds.{WildcardParamName, DefaultGetterName}
2525
import util.Chars.isOperatorPart
2626
import transform.TypeUtils._
2727
import transform.SymUtils._
28+
import config.Config
2829

2930
import language.implicitConversions
3031
import dotty.tools.dotc.util.{NameTransformer, SourcePosition}
3132
import dotty.tools.dotc.ast.untpd.{MemberDef, Modifiers, PackageDef, RefTree, Template, TypeDef, ValOrDefDef}
33+
import cc.{EventuallyCapturingType, CaptureSet, toCaptureSet, IllegalCaptureRef}
3234

3335
class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
3436

@@ -602,7 +604,17 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
602604
case tree: Template =>
603605
toTextTemplate(tree)
604606
case Annotated(arg, annot) =>
605-
toTextLocal(arg) ~~ annotText(annot.symbol.enclosingClass, annot)
607+
def captureSet =
608+
annot.asInstanceOf[tpd.Tree].toCaptureSet
609+
def toTextAnnot =
610+
toTextLocal(arg) ~~ annotText(annot.symbol.enclosingClass, annot)
611+
def toTextRetainsAnnot =
612+
try changePrec(GlobalPrec)(toText(captureSet) ~ " " ~ toText(arg))
613+
catch case ex: IllegalCaptureRef => toTextAnnot
614+
if annot.symbol.maybeOwner == defn.RetainsAnnot
615+
&& ctx.settings.Ycc.value && Config.printCaptureSetsAsPrefix && !printDebug
616+
then toTextRetainsAnnot
617+
else toTextAnnot
606618
case EmptyTree =>
607619
"<empty>"
608620
case TypedSplice(t) =>

compiler/src/dotty/tools/dotc/typer/CheckCaptures.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ class CheckCaptures extends Recheck:
138138
case _ =>
139139
tp
140140

141+
/** Turn plain function types into dependent function types, so that
142+
* we can refer to the parameter in capture sets
143+
*/
141144
def addFunctionRefinements(tp: Type): Type = tp match
142145
case tp @ AppliedType(tycon, args) =>
143146
if defn.isNonRefinedFunction(tp) then

0 commit comments

Comments
 (0)