Skip to content

Commit b9818be

Browse files
committed
More detailed notes in error messages.
We now always give a reason in a TypeMismatch about which capture set inclusion failed.
1 parent 6178275 commit b9818be

Some content is hidden

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

72 files changed

+330
-121
lines changed

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

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,9 @@ object CaptureSet:
692692
*/
693693
private[CaptureSet] var rootLimit: Symbol | Null = null
694694

695+
def isBadRoot(elem: Capability)(using Context): Boolean =
696+
isBadRoot(rootLimit, elem)
697+
695698
private var myClassifier: ClassSymbol = defn.AnyClass
696699
def classifier: ClassSymbol = myClassifier
697700

@@ -749,7 +752,7 @@ object CaptureSet:
749752
assert(elem.isWellformed, elem)
750753
assert(!this.isInstanceOf[HiddenSet] || summon[VarState].isSeparating, summon[VarState])
751754
includeElem(elem)
752-
if isBadRoot(rootLimit, elem) then
755+
if isBadRoot(elem) then
753756
rootAddedHandler()
754757
val normElem = if isMaybeSet then elem else elem.stripMaybe
755758
// assert(id != 5 || elems.size != 3, this)
@@ -778,7 +781,7 @@ object CaptureSet:
778781
case _ => foldOver(b, t)
779782
find(false, binder)
780783

781-
private def levelOK(elem: Capability)(using Context): Boolean = elem match
784+
def levelOK(elem: Capability)(using Context): Boolean = elem match
782785
case _: FreshCap =>
783786
!level.isDefined
784787
|| ccState.symLevel(elem.ccOwner) <= level
@@ -1246,7 +1249,13 @@ object CaptureSet:
12461249
* when a subsumes check decides that an existential variable `ex` cannot be
12471250
* instantiated to the other capability `other`.
12481251
*/
1249-
case class ExistentialSubsumesFailure(val ex: ResultCap, val other: Capability) extends ErrorNote
1252+
case class ExistentialSubsumesFailure(val ex: ResultCap, val other: Capability) extends ErrorNote:
1253+
def description(using Context): String =
1254+
def reason =
1255+
if other.isTerminalCapability then ""
1256+
else " since that capability is not a `Sharable` capability"
1257+
i"""the existential capture root in ${ex.originalBinder.resType}
1258+
|cannot subsume the capability $other$reason."""
12501259

12511260
/** Failure indicating that `elem` cannot be included in `cs` */
12521261
case class IncludeFailure(cs: CaptureSet, elem: Capability, levelError: Boolean = false) extends ErrorNote, Showable:
@@ -1258,6 +1267,29 @@ object CaptureSet:
12581267
res.myTrace = cs1 :: this.myTrace
12591268
res
12601269

1270+
def description(using Context): String = cs match
1271+
case cs: Var =>
1272+
if !cs.levelOK(elem) then
1273+
val levelStr = elem match
1274+
case ref: TermRef => i", defined in ${ref.symbol.maybeOwner}"
1275+
case _ => ""
1276+
i"""capability ${elem}$levelStr
1277+
|cannot be included in outer capture set $cs"""
1278+
else if !elem.tryClassifyAs(cs.classifier) then
1279+
i"""capability ${elem} is not classified as ${cs.classifier}, therefore it
1280+
|cannot be included in capture set $cs of ${cs.classifier} elements"""
1281+
else if cs.isBadRoot(elem) then
1282+
elem match
1283+
case elem: FreshCap =>
1284+
i"""local capability $elem created in ${elem.ccOwner}
1285+
|cannot be included in outer capture set $cs"""
1286+
case _ =>
1287+
i"universal capability $elem cannot be included in capture set $cs"
1288+
else
1289+
i"capability $elem cannot be included in capture set $cs"
1290+
case _ =>
1291+
i"capability $elem is not included in capture set $cs"
1292+
12611293
override def toText(printer: Printer): Text =
12621294
inContext(printer.printerContext):
12631295
if levelError then
@@ -1274,7 +1306,11 @@ object CaptureSet:
12741306
* @param lo the lower type of the orginal type comparison, or NoType if not known
12751307
* @param hi the upper type of the orginal type comparison, or NoType if not known
12761308
*/
1277-
case class MutAdaptFailure(cs: CaptureSet, lo: Type = NoType, hi: Type = NoType) extends ErrorNote
1309+
case class MutAdaptFailure(cs: CaptureSet, lo: Type = NoType, hi: Type = NoType) extends ErrorNote:
1310+
def description(using Context): String =
1311+
def ofType(tp: Type) = if tp.exists then i"of the mutable type $tp" else "of a mutable type"
1312+
i"""$cs is an exclusive capture set ${ofType(hi)},
1313+
|it cannot subsume a read-only capture set ${ofType(lo)}."""
12781314

12791315
/** A VarState serves as a snapshot mechanism that can undo
12801316
* additions of elements or super sets if an operation fails

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

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,37 +1278,11 @@ class CheckCaptures extends Recheck, SymTransformer:
12781278
type BoxErrors = mutable.ListBuffer[Message] | Null
12791279

12801280
private def errorNotes(notes: List[TypeComparer.ErrorNote])(using Context): Addenda =
1281-
val printableNotes = notes.filter:
1282-
case IncludeFailure(_, _, true) => true
1283-
case _: ExistentialSubsumesFailure | _: MutAdaptFailure => true
1284-
case _ => false
1285-
if printableNotes.isEmpty then NothingToAdd
1281+
if notes.isEmpty then NothingToAdd
12861282
else new Addenda:
1287-
override def toAdd(using Context) = printableNotes.map: note =>
1288-
val msg = note match
1289-
case IncludeFailure(cs, ref, _) =>
1290-
if ref.core.isCapOrFresh then
1291-
i"""the universal capability $ref
1292-
|cannot be included in capture set $cs"""
1293-
else
1294-
val levelStr = ref match
1295-
case ref: TermRef => i", defined in ${ref.symbol.maybeOwner}"
1296-
case _ => ""
1297-
i"""reference ${ref}$levelStr
1298-
|cannot be included in outer capture set $cs"""
1299-
case ExistentialSubsumesFailure(ex, other) =>
1300-
def since =
1301-
if other.isTerminalCapability then ""
1302-
else " since that capability is not a `Sharable` capability"
1303-
i"""the existential capture root in ${ex.originalBinder.resType}
1304-
|cannot subsume the capability $other$since"""
1305-
case MutAdaptFailure(cs, lo, hi) =>
1306-
def ofType(tp: Type) = if tp.exists then i"of the mutable type $tp" else "of a mutable type"
1307-
i"""$cs is an exclusive capture set ${ofType(hi)},
1308-
|it cannot subsume a read-only capture set ${ofType(lo)}."""
1283+
override def toAdd(using Context) = notes.map: note =>
13091284
i"""
1310-
|Note that ${msg.toString}"""
1311-
1285+
|Note that ${note.description}."""
13121286

13131287
/** Addendas for error messages that show where we have under-approximated by
13141288
* mapping a a capability in contravariant position to the empty set because

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3361,6 +3361,9 @@ object TypeComparer {
33613361
*/
33623362
def kind: Class[?] = getClass
33633363

3364+
def description(using Context): String
3365+
end ErrorNote
3366+
33643367
/** A richer compare result, returned by `testSubType` and `test`. */
33653368
enum CompareResult:
33663369
case OK, OKwithGADTUsed, OKwithOpaquesUsed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +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 {}.
67
|
78
| longer explanation available when compiling with `-explain`
89
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/box-adapt-cases.scala:29:10 ------------------------------
910
29 | x.value(cap => cap.use()) // error
1011
| ^^^^^^^^^^^^^^^^
1112
| Found: (cap: Cap^?) ->{io, fs} Int
1213
| Required: Cap^{io, fs} ->{io} Int
14+
| Note that capability (fs : Cap^) is not included in capture set {io}.
1315
|
1416
| longer explanation available when compiling with `-explain`

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +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}.
16+
|
1517
| longer explanation available when compiling with `-explain`
1618
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:19:5 ----------------------------------------
1719
19 | h(g()) // error
1820
| ^^^
1921
| Found: () ?->{cap2} I^?
2022
| Required: () ?->{cap1} I
23+
| Note that capability (cap2 : Cap) is not included in capture set {cap1}.
2124
|
2225
| longer explanation available when compiling with `-explain`
2326
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:22:5 ----------------------------------------
2427
22 | h2(() => g())() // error
2528
| ^^^^^^^^^
2629
| Found: () ->{cap2} I^?
2730
| Required: () ->{cap1} I
31+
| Note that capability (cap2 : Cap) is not included in capture set {cap1}.
2832
|
2933
| longer explanation available when compiling with `-explain`

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +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 {}.
10+
|
911
| longer explanation available when compiling with `-explain`

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,23 @@
33
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44
| Found: () ->{x} C^?
55
| Required: () -> C
6+
| Note that capability (x : C^) is not included in capture set {}.
67
|
78
| longer explanation available when compiling with `-explain`
89
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:8:2 ------------------------------------------
910
8 | () => if x == null then y else y // error
1011
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1112
| Found: () ->{x} C^?
1213
| Required: Matchable
14+
| Note that capability (x : C^) is not included in capture set {}.
1315
|
1416
| longer explanation available when compiling with `-explain`
1517
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:15:2 -----------------------------------------
1618
15 | def f(y: Int) = if x == null then y else y // error
1719
| ^
1820
| Found: (y: Int) ->{x} Int
1921
| Required: Matchable
22+
| Note that capability (x : C^) is not included in capture set {}.
2023
16 | f
2124
|
2225
| longer explanation available when compiling with `-explain`
@@ -25,6 +28,7 @@
2528
| ^
2629
| Found: A^{x}
2730
| Required: A
31+
| Note that capability (x : C^) is not included in capture set {}.
2832
23 | def m() = if x == null then y else y
2933
24 | F(22)
3034
|
@@ -34,6 +38,7 @@
3438
| ^
3539
| Found: A^{x}
3640
| Required: A
41+
| Note that capability (x : C^) is not included in capture set {}.
3742
28 | def m() = if x == null then y else y
3843
|
3944
| longer explanation available when compiling with `-explain`
@@ -52,6 +57,8 @@
5257
|
5358
|where: ^ refers to a fresh root capability created in value z2 when checking argument to parameter a of method h
5459
|
60+
|Note that capability (x : C^) is not included in capture set {}.
61+
|
5562
| longer explanation available when compiling with `-explain`
5663
-- Error: tests/neg-custom-args/captures/capt1.scala:38:13 -------------------------------------------------------------
5764
38 | val z3 = h[(() -> Cap) @retains[x.type]](() => x)(() => C()) // error

tests/neg-custom-args/captures/cc-existential-conformance.check

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
| x is a value in method test
1010
| x² is a reference to a value parameter
1111
|
12+
| Note that capability <cap of (x: A): B^> is not included in capture set {cap}.
13+
|
1214
| longer explanation available when compiling with `-explain`
1315
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/cc-existential-conformance.scala:9:29 --------------------
1416
9 | val z: A -> (x: A) -> B^ = y // error
@@ -18,8 +20,7 @@
1820
|
1921
| where: ^ refers to a root capability associated with the result type of (x: A): B^
2022
|
21-
| Note that the existential capture root in B^
22-
| cannot subsume the capability y* since that capability is not a `Sharable` capability
23+
| Note that capability y* is not included in capture set {<cap of (x: A): B^>}.
2324
|
2425
| longer explanation available when compiling with `-explain`
2526
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/cc-existential-conformance.scala:13:19 -------------------
@@ -33,6 +34,8 @@
3334
| x is a value in method test2
3435
| x² is a reference to a value parameter
3536
|
37+
| Note that capability <cap of (x: A): B^> is not included in capture set {cap}.
38+
|
3639
| longer explanation available when compiling with `-explain`
3740
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/cc-existential-conformance.scala:14:24 -------------------
3841
14 | val z: (x: A) -> B^ = y // error
@@ -42,7 +45,6 @@
4245
|
4346
| where: ^ refers to a root capability associated with the result type of (x: A): B^
4447
|
45-
| Note that the existential capture root in B^
46-
| cannot subsume the capability y* since that capability is not a `Sharable` capability
48+
| Note that capability y* is not included in capture set {<cap of (x: A): B^>}.
4749
|
4850
| longer explanation available when compiling with `-explain`

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +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 {}.
67
|
78
| longer explanation available when compiling with `-explain`

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
|
77
| where: ^ refers to a fresh root capability in the type of value d
88
|
9+
| Note that capability cap is not included in capture set {c1}.
10+
|
911
| longer explanation available when compiling with `-explain`
1012
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/cc-poly-2.scala:16:20 ------------------------------------
1113
16 | val _: D^{c1} = x // error
1214
| ^
1315
| Found: (x : Test.D^{d})
1416
| Required: Test.D^{c1}
17+
| Note that capability (d : Test.D^) is not included in capture set {c1}.
1518
|
1619
| longer explanation available when compiling with `-explain`

0 commit comments

Comments
 (0)