Skip to content

Commit ddbd82b

Browse files
committed
Better printing of capabilities in error messages
- Special case in some situations so that we only print the name, not the underlying type. - Print TermParamRefs like other singleton types
1 parent c01f86f commit ddbd82b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+155
-172
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,9 @@ object Capabilities:
788788
case _: Maybe => MaybeCapability(c1)
789789
case _ => c1
790790

791+
def showAsCapability(using Context) =
792+
i"capability ${ctx.printer.toTextCapability(this).show}"
793+
791794
def toText(printer: Printer): Text = printer.toTextCapability(this)
792795
end Capability
793796

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

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,24 +1300,23 @@ object CaptureSet:
13001300
case cs: Var =>
13011301
if !cs.levelOK(elem) then
13021302
val levelStr = elem match
1303-
case ref: TermRef => i", defined in ${ref.symbol.maybeOwner}"
1304-
case _ => ""
1305-
i"""capability ${elem}$levelStr
1306-
|cannot be included in outer capture set $cs"""
1303+
case ref: TermRef => i", defined in ${ref.symbol.maybeOwner}\n"
1304+
case _ => " "
1305+
i"""${elem.showAsCapability}${levelStr}cannot be included in outer capture set $cs"""
13071306
else if !elem.tryClassifyAs(cs.classifier) then
1308-
i"""capability ${elem} is not classified as ${cs.classifier}, therefore it
1307+
i"""${elem.showAsCapability} is not classified as ${cs.classifier}, therefore it
13091308
|cannot be included in capture set $cs of ${cs.classifier} elements"""
13101309
else if cs.isBadRoot(elem) then
13111310
elem match
13121311
case elem: FreshCap =>
1313-
i"""local capability $elem created in ${elem.ccOwner}
1312+
i"""local ${elem.showAsCapability} created in ${elem.ccOwner}
13141313
|cannot be included in outer capture set $cs"""
13151314
case _ =>
1316-
i"universal capability $elem cannot be included in capture set $cs"
1315+
i"universal ${elem.showAsCapability} cannot be included in capture set $cs"
13171316
else
1318-
i"capability $elem cannot be included in capture set $cs"
1317+
i"${elem.showAsCapability} cannot be included in capture set $cs"
13191318
case _ =>
1320-
i"capability $elem is not included in capture set $cs$why"
1319+
i"${elem.showAsCapability} is not included in capture set $cs$why"
13211320

13221321
override def toText(printer: Printer): Text =
13231322
inContext(printer.printerContext):

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,6 @@ class PlainPrinter(_ctx: Context) extends Printer {
242242
selectionString(tp)
243243
else
244244
toTextPrefixOf(tp) ~ selectionString(tp)
245-
case tp: TermParamRef =>
246-
ParamRefNameString(tp) ~ hashStr(tp.binder) ~ ".type"
247245
case tp: TypeParamRef =>
248246
val suffix =
249247
if showNestingLevel then

docs/_docs/reference/experimental/cc.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ followed by `^`. We'll see that this turns the parameter into a _capability_ who
4343

4444
If we now try to define the problematic value `later`, we get a static error:
4545
```
46-
| val later = usingLogFile { f => () => f.write(0) }
47-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
48-
|The expression's type () => Unit is not allowed to capture the root capability `cap`.
49-
|This usually means that a capability persists longer than its allowed lifetime.
46+
|val later = usingLogFile { f => () => f.write(0) } // error
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
48+
|Found: (f: java.io.FileOutputStream^?) ->? () ->{f} Unit
49+
|Required: java.io.FileOutputStream^ => () ->? Unit
50+
|
51+
|Note that capability f cannot be included in outer capture set ?.
5052
```
5153
In this case, it was easy to see that the `logFile` capability escapes in the closure passed to `usingLogFile`. But capture checking also works for more complex cases.
5254
For instance, capture checking is able to distinguish between the following safe code:

tests/neg-custom-args/captures/box-adapt-cases.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
| ^^^^^^^^^^^^^^^^
44
| Found: (cap: Cap^{io}) ->{io} Int
55
| Required: Cap^{io} -> Int
6-
| Note that capability (io : Cap^) is not included in capture set {}.
6+
| Note that capability io is not included in capture set {}.
77
|
88
| longer explanation available when compiling with `-explain`
99
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/box-adapt-cases.scala:29:10 ------------------------------
1010
29 | x.value(cap => cap.use()) // error
1111
| ^^^^^^^^^^^^^^^^
1212
| Found: (cap: Cap^?) ->{io, fs} Int
1313
| Required: Cap^{io, fs} ->{io} Int
14-
| Note that capability (fs : Cap^) is not included in capture set {io}.
14+
| Note that capability fs is not included in capture set {io}.
1515
|
1616
| longer explanation available when compiling with `-explain`

tests/neg-custom-args/captures/byname.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,22 @@
1212
|
1313
|where: ?=> refers to a fresh root capability created in method test when checking argument to parameter ff of method h
1414
|
15-
|Note that capability (cap1 : Cap) is not included in capture set {cap2}.
15+
|Note that capability cap1 is not included in capture set {cap2}.
1616
|
1717
| longer explanation available when compiling with `-explain`
1818
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:19:5 ----------------------------------------
1919
19 | h(g()) // error
2020
| ^^^
2121
| Found: () ?->{cap2} I^?
2222
| Required: () ?->{cap1} I
23-
| Note that capability (cap2 : Cap) is not included in capture set {cap1}.
23+
| Note that capability cap2 is not included in capture set {cap1}.
2424
|
2525
| longer explanation available when compiling with `-explain`
2626
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:22:5 ----------------------------------------
2727
22 | h2(() => g())() // error
2828
| ^^^^^^^^^
2929
| Found: () ->{cap2} I^?
3030
| Required: () ->{cap1} I
31-
| Note that capability (cap2 : Cap) is not included in capture set {cap1}.
31+
| Note that capability cap2 is not included in capture set {cap1}.
3232
|
3333
| longer explanation available when compiling with `-explain`

tests/neg-custom-args/captures/capt-depfun.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
|
77
| where: => refers to a fresh root capability in the type of value dc
88
|
9-
| Note that capability (y : C^) is not included in capture set {}.
9+
| Note that capability y is not included in capture set {}.
1010
|
1111
| longer explanation available when compiling with `-explain`

tests/neg-custom-args/captures/capt1.check

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,23 @@
33
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44
| Found: () ->{x} C
55
| Required: () -> C
6-
| Note that capability (x : C^) is not included in capture set {}.
6+
| Note that capability x is not included in capture set {}.
77
|
88
| longer explanation available when compiling with `-explain`
99
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:8:2 ------------------------------------------
1010
8 | () => if x == null then y else y // error
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212
| Found: () ->{x} C^?
1313
| Required: Matchable
14-
| Note that capability (x : C^) is not included in capture set {}.
14+
| Note that capability x is not included in capture set {}.
1515
|
1616
| longer explanation available when compiling with `-explain`
1717
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:15:2 -----------------------------------------
1818
15 | def f(y: Int) = if x == null then y else y // error
1919
| ^
2020
| Found: (y: Int) ->{x} Int
2121
| Required: Matchable
22-
| Note that capability (x : C^) is not included in capture set {}.
22+
| Note that capability x is not included in capture set {}.
2323
16 | f
2424
|
2525
| longer explanation available when compiling with `-explain`
@@ -28,7 +28,7 @@
2828
| ^
2929
| Found: A^{x}
3030
| Required: A
31-
| Note that capability (x : C^) is not included in capture set {}.
31+
| Note that capability x is not included in capture set {}.
3232
23 | def m() = if x == null then y else y
3333
24 | F(22)
3434
|
@@ -38,7 +38,7 @@
3838
| ^
3939
| Found: A^{x}
4040
| Required: A
41-
| Note that capability (x : C^) is not included in capture set {}.
41+
| Note that capability x is not included in capture set {}.
4242
28 | def m() = if x == null then y else y
4343
|
4444
| longer explanation available when compiling with `-explain`

tests/neg-custom-args/captures/cc-glb.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
| ^^
44
| Found: (x1 : (Foo[T] & Foo[Any])^{io})
55
| Required: Foo[T]
6-
| Note that capability (io : Cap^) is not included in capture set {}.
6+
| Note that capability io is not included in capture set {}.
77
|
88
| longer explanation available when compiling with `-explain`

tests/neg-custom-args/captures/cc-poly-2.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
| ^
1515
| Found: (x : Test.D^{d})
1616
| Required: Test.D^{c1}
17-
| Note that capability (d : Test.D^) is not included in capture set {c1}.
17+
| Note that capability d is not included in capture set {c1}.
1818
|
1919
| longer explanation available when compiling with `-explain`

0 commit comments

Comments
 (0)