Skip to content

Commit 744a3d4

Browse files
committed
Try to pick the most informative note to display
1 parent 7ca78b1 commit 744a3d4

File tree

10 files changed

+249
-28
lines changed

10 files changed

+249
-28
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,18 @@ object CaptureSet:
13171317
case _ =>
13181318
false
13191319

1320+
/** An include failure F1 covers another include failure F2 unless F2
1321+
* strictly subsumes F1, which means they describe the same capture sets
1322+
* and the element in F2 is more specific than the element in F1.
1323+
*/
1324+
override def covers(other: Note)(using Context) = other match
1325+
case other @ IncludeFailure(cs1, elem1, _) =>
1326+
val strictlySubsumes =
1327+
cs.elems == cs1.elems
1328+
&& elem1.singletonCaptureSet.mightSubcapture(elem.singletonCaptureSet)
1329+
!strictlySubsumes
1330+
case _ => false
1331+
13201332
def trailing(msg: String)(using Context): String =
13211333
i"""
13221334
|
@@ -1387,13 +1399,19 @@ object CaptureSet:
13871399
* @param hi the upper type of the orginal type comparison, or NoType if not known
13881400
*/
13891401
case class MutAdaptFailure(cs: CaptureSet, lo: Type = NoType, hi: Type = NoType) extends Note:
1402+
13901403
def render(using Context): String =
13911404
def ofType(tp: Type) = if tp.exists then i"of the mutable type $tp" else "of a mutable type"
13921405
i"""
13931406
|
13941407
|Note that $cs is an exclusive capture set ${ofType(hi)},
13951408
|it cannot subsume a read-only capture set ${ofType(lo)}."""
13961409

1410+
// Show only one failure of this kind
1411+
override def covers(other: Note)(using Context) =
1412+
other.isInstanceOf[MutAdaptFailure]
1413+
end MutAdaptFailure
1414+
13971415
/** A VarState serves as a snapshot mechanism that can undo
13981416
* additions of elements or super sets if an operation fails
13991417
*/

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3324,12 +3324,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
33243324
def reduceMatchWith[T](op: MatchReducer => T)(using Context): T =
33253325
inSubComparer(matchReducer)(op)
33263326

3327-
/** Add given note, provided there is not yet an error note with
3328-
* the same class as `note`.
3327+
/** Add given note, provided there is not yet an error note that covers `note`
3328+
* If the new note is added, any existing note covered by it is removed first.
33293329
*/
3330-
def addErrorNote(note: Note): Unit =
3331-
if errorNotes.forall(_._2.getClass != note.getClass) then
3332-
errorNotes = (recCount, note) :: errorNotes
3330+
def addErrorNote(note: Note)(using Context): Unit =
3331+
if !errorNotes.exists(_._2.covers(note)) then
3332+
errorNotes = (recCount, note) :: errorNotes.filterConserve(n => !note.covers(n._2))
33333333
assert(maxErrorLevel <= recCount)
33343334
maxErrorLevel = recCount
33353335

compiler/src/dotty/tools/dotc/reporting/Message.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ object Message:
4343

4444
/** A note can produce an added string for an error message */
4545
abstract class Note:
46-
46+
4747
/** Should the note be shown before the actual message or after?
4848
* Default is after.
4949
*/
@@ -52,6 +52,13 @@ object Message:
5252
/** The note rendered as part of an error message */
5353
def render(using Context): String
5454

55+
/** If note N1 covers note N2 then N1 and N2 won't be shown together in
56+
* an error message. Instead we show the note that's strictly better in terms
57+
* of the "covers" partial ordering, or, if there's no strict wionner, the first
58+
* added note.
59+
*/
60+
def covers(other: Note)(using Context): Boolean = false
61+
5562
object Note:
5663
def apply(msg: Context ?=> String) = new Note:
5764
def render(using Context) = msg

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
| Found: (d : Test.D^)
55
| Required: Test.D^{c1}
66
|
7-
| Note that capability cap is not included in capture set {c1}.
7+
| Note that capability d is not included in capture set {c1}.
88
|
9-
| where: ^ and cap refer to a fresh root capability in the type of value d
9+
| where: ^ refers to a fresh root capability in the type of value d
1010
|
1111
| longer explanation available when compiling with `-explain`
1212
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/cc-poly-2.scala:16:20 ------------------------------------
@@ -15,6 +15,6 @@
1515
| Found: (x : Test.D^{d})
1616
| Required: Test.D^{c1}
1717
|
18-
| Note that capability d is not included in capture set {c1}.
18+
| Note that capability x is not included in capture set {c1}.
1919
|
2020
| longer explanation available when compiling with `-explain`

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
| Found: (io : IO^)
55
| Required: IO^²
66
|
7-
| Note that capability cap is not included in capture set {cap²}
8-
| because cap in method setIO is not visible from cap² in variable myIO.
7+
| Note that capability io is not included in capture set {cap}
8+
| because (io : IO^) in method setIO is not visible from cap in variable myIO.
99
|
10-
| where: ^ and cap refer to a fresh root capability in the type of parameter io
11-
| ^² and cap² refer to a fresh root capability in the type of variable myIO
10+
| where: ^ refers to a fresh root capability in the type of parameter io
11+
| ^² and cap refer to a fresh root capability in the type of variable myIO
1212
|
1313
| longer explanation available when compiling with `-explain`
1414
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i23431.scala:11:13 ---------------------------------------
@@ -17,11 +17,11 @@
1717
| Found: (io2 : IO^)
1818
| Required: IO^²
1919
|
20-
| Note that capability cap is not included in capture set {cap²}
21-
| because cap in an enclosing function is not visible from cap² in variable myIO.
20+
| Note that capability io2 is not included in capture set {cap}
21+
| because (io2 : IO^) in an enclosing function is not visible from cap in variable myIO.
2222
|
23-
| where: ^ and cap refer to a fresh root capability in the type of parameter io2
24-
| ^² and cap² refer to a fresh root capability in the type of variable myIO
23+
| where: ^ refers to a fresh root capability in the type of parameter io2
24+
| ^² and cap refer to a fresh root capability in the type of variable myIO
2525
|
2626
| longer explanation available when compiling with `-explain`
2727
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i23431.scala:12:12 ---------------------------------------

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
| Found: (b : B{val elem1: A^{a}; val elem2: A^{a}}^{cap, a})
55
| Required: B^{async}
66
|
7-
| Note that capability cap is not included in capture set {async}.
7+
| Note that capability b is not included in capture set {async}.
88
|
99
| where: cap is a fresh root capability in the type of value b
1010
|

tests/neg-custom-args/captures/outer-var.check

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
| Found: (q : () => Unit)
55
| Required: () ->{p, q²} Unit
66
|
7-
| Note that capability cap is not included in capture set {p, q²}.
7+
| Note that capability q is not included in capture set {p, q²}.
88
|
9-
| where: => and cap refer to a fresh root capability in the type of parameter q
10-
| q is a parameter in method inner
11-
| q² is a parameter in method test
9+
| where: => refers to a fresh root capability in the type of parameter q
10+
| q is a parameter in method inner
11+
| q² is a parameter in method test
1212
|
1313
| longer explanation available when compiling with `-explain`
1414
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/outer-var.scala:13:9 -------------------------------------
@@ -39,9 +39,9 @@
3939
| Found: (q : () => Unit)
4040
| Required: () ->{p} Unit
4141
|
42-
| Note that capability cap cannot be included in capture set {p} of variable y.
42+
| Note that capability q cannot be included in capture set {p} of variable y.
4343
|
44-
| where: => and cap refer to a fresh root capability in the type of parameter q
44+
| where: => refers to a fresh root capability in the type of parameter q
4545
|
4646
| longer explanation available when compiling with `-explain`
4747
-- Error: tests/neg-custom-args/captures/outer-var.scala:17:57 ---------------------------------------------------------

tests/neg-custom-args/captures/scope-extrude-mut.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
| Found: (a1 : A^)
55
| Required: A^²
66
|
7-
| Note that capability cap is not included in capture set {cap²}
8-
| because cap in method b is not visible from cap² in variable a.
7+
| Note that capability a1 is not included in capture set {cap}
8+
| because (a1 : A^) in method b is not visible from cap in variable a.
99
|
10-
| where: ^ and cap refer to a fresh root capability classified as Mutable in the type of value a1
11-
| ^² and cap² refer to a fresh root capability classified as Mutable in the type of variable a
10+
| where: ^ refers to a fresh root capability classified as Mutable in the type of value a1
11+
| ^² and cap refer to a fresh root capability classified as Mutable in the type of variable a
1212
|
1313
| longer explanation available when compiling with `-explain`
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:9:8 -------------------------------
2+
9 | v = x // error
3+
| ^
4+
| Found: (x : IO)
5+
| Required: IO^
6+
|
7+
| Note that capability x is not included in capture set {cap}
8+
| because (x : IO) in method f1 is not visible from cap in variable v.
9+
|
10+
| where: ^ and cap refer to a fresh root capability classified as SharedCapability in the type of variable v
11+
|
12+
| longer explanation available when compiling with `-explain`
13+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:10:8 ------------------------------
14+
10 | w = g // error
15+
| ^
16+
| Found: () ->{x} Unit
17+
| Required: () => Unit
18+
|
19+
| Note that capability x is not included in capture set {cap}
20+
| because (x : IO) in method f1 is not visible from cap in variable w.
21+
|
22+
| where: => and cap refer to a fresh root capability in the type of variable w
23+
|
24+
| longer explanation available when compiling with `-explain`
25+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:19:11 -----------------------------
26+
19 | withFile(io => io) // error
27+
| ^^^^^^^^
28+
|Capability io outlives its scope: it leaks into outer capture set 's1 which is owned by method test.
29+
|The leakage occurred when trying to match the following types:
30+
|
31+
|Found: (io: IO^'s2) ->'s3 IO^{io}
32+
|Required: IO^ => IO^'s1
33+
|
34+
|where: => refers to a fresh root capability created in method test when checking argument to parameter op of method withFile
35+
| ^ refers to the universal root capability
36+
|
37+
| longer explanation available when compiling with `-explain`
38+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:20:11 -----------------------------
39+
20 | withFile(id) // error
40+
| ^^
41+
|Capability x outlives its scope: it leaks into outer capture set 's4 which is owned by method test.
42+
|The leakage occurred when trying to match the following types:
43+
|
44+
|Found: (x: IO^) ->'s5 IO^{x}
45+
|Required: IO^ => IO^'s4
46+
|
47+
|where: => refers to a fresh root capability created in method test when checking argument to parameter op of method withFile
48+
| ^ refers to the universal root capability
49+
|
50+
| longer explanation available when compiling with `-explain`
51+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:21:11 -----------------------------
52+
21 | withFile(x => id(x)) // error
53+
| ^^^^^^^^^^
54+
|Capability x outlives its scope: it leaks into outer capture set 's6 which is owned by method test.
55+
|The leakage occurred when trying to match the following types:
56+
|
57+
|Found: (x: IO^'s7) ->'s8 IO^{x}
58+
|Required: IO^ => IO^'s6
59+
|
60+
|where: => refers to a fresh root capability created in method test when checking argument to parameter op of method withFile
61+
| ^ refers to the universal root capability
62+
|
63+
| longer explanation available when compiling with `-explain`
64+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:22:11 -----------------------------
65+
22 | withFile(id2) // error, note mentions cap since we never have a more specific include failure
66+
| ^^^
67+
|Capability cap outlives its scope: it leaks into outer capture set 's9 which is owned by method test.
68+
|The leakage occurred when trying to match the following types:
69+
|
70+
|Found: (x: IO^) ->'s10 IO^²
71+
|Required: IO^ => IO^'s9
72+
|
73+
|where: => refers to a fresh root capability created in method test when checking argument to parameter op of method withFile
74+
| ^ refers to the universal root capability
75+
| ^² refers to a root capability associated with the result type of (x: IO^): IO^²
76+
| cap is a root capability associated with the result type of (x: IO^): IO^'s9
77+
|
78+
| longer explanation available when compiling with `-explain`
79+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:23:11 -----------------------------
80+
23 | withFile(x => id2(x)) // error, note mentions cap since we never have a more specific include failure
81+
| ^^^^^^^^^^^
82+
|Capability cap outlives its scope: it leaks into outer capture set 's11 which is owned by method test.
83+
|The leakage occurred when trying to match the following types:
84+
|
85+
|Found: (x: IO^'s12) ->'s13 IO^
86+
|Required: IO^² => IO^'s11
87+
|
88+
|where: => refers to a fresh root capability created in method test when checking argument to parameter op of method withFile
89+
| ^ refers to a root capability associated with the result type of (x: IO^'s12): IO^
90+
| ^² refers to the universal root capability
91+
| cap is a root capability associated with the result type of (x: IO^²): IO^'s11
92+
|
93+
| longer explanation available when compiling with `-explain`
94+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:24:11 -----------------------------
95+
24 | withFile(identity) // error, note mentions cap since we never have a more specific include failure
96+
| ^^^^^^^^
97+
|Capability cap outlives its scope: it leaks into outer capture set 's14 which is owned by method test.
98+
|The leakage occurred when trying to match the following types:
99+
|
100+
|Found: (x: IO^'s15) ->'s16 IO^'s17
101+
|Required: IO^ => IO^'s14
102+
|
103+
|where: => refers to a fresh root capability created in method test when checking argument to parameter op of method withFile
104+
| ^ refers to the universal root capability
105+
| cap is a root capability associated with the result type of (x: IO^): IO^'s14
106+
|
107+
| longer explanation available when compiling with `-explain`
108+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:25:11 -----------------------------
109+
25 | withFile(x => identity(x)) // error, note mentions cap since we never have a more specific include failure
110+
| ^^^^^^^^^^^^^^^^
111+
|Capability cap outlives its scope: it leaks into outer capture set 's18 which is owned by method test.
112+
|The leakage occurred when trying to match the following types:
113+
|
114+
|Found: (x: IO^'s19) ->'s20 IO^'s21
115+
|Required: IO^ => IO^'s18
116+
|
117+
|where: => refers to a fresh root capability created in method test when checking argument to parameter op of method withFile
118+
| ^ refers to the universal root capability
119+
| cap is a root capability associated with the result type of (x: IO^): IO^'s18
120+
|
121+
| longer explanation available when compiling with `-explain`
122+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:27:12 -----------------------------
123+
27 | withFile: io => // error
124+
| ^
125+
|Capability io outlives its scope: it leaks into outer capture set 's22 which is owned by method test.
126+
|The leakage occurred when trying to match the following types:
127+
|
128+
|Found: (io: IO^'s23) ->'s24 () ->{io} Unit
129+
|Required: IO^ => () ->'s22 Unit
130+
|
131+
|where: => refers to a fresh root capability created in method test when checking argument to parameter op of method withFile
132+
| ^ refers to the universal root capability
133+
28 | () => println(io)
134+
|
135+
| longer explanation available when compiling with `-explain`
136+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:30:21 -----------------------------
137+
30 | val f2: IO => IO = (x: IO) => x // error
138+
| ^^^^^^^^^^^^
139+
| Found: (x: IO^) ->'s25 IO^{x}
140+
| Required: IO^ => IO^²
141+
|
142+
| Note that capability x is not included in capture set {cap}
143+
| because (x : IO) is not visible from cap in value f2.
144+
|
145+
| where: => refers to a fresh root capability in the type of value f2
146+
| ^ refers to the universal root capability
147+
| ^² and cap refer to a fresh root capability classified as SharedCapability in the type of value f2
148+
|
149+
| longer explanation available when compiling with `-explain`
150+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/scope-extrusions.scala:32:21 -----------------------------
151+
32 | val f4: IO => IO = f3 // error
152+
| ^^
153+
| Found: (f3 : (x$0: IO) ->{} IO^{x$0})
154+
| Required: IO^ => IO^²
155+
|
156+
| Note that capability x$0 is not included in capture set {cap}
157+
| because (x$0 : IO) is not visible from cap in value f4.
158+
|
159+
| where: => refers to a fresh root capability in the type of value f4
160+
| ^ refers to the universal root capability
161+
| ^² and cap refer to a fresh root capability classified as SharedCapability in the type of value f4
162+
|
163+
| longer explanation available when compiling with `-explain`
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Tests quality of error messages
2+
class IO extends caps.SharedCapability
3+
4+
def test(io: IO): Unit =
5+
var v: IO = io
6+
var w: () => Unit = () => ()
7+
def f1(x: IO) =
8+
def g() = println(x)
9+
v = x // error
10+
w = g // error
11+
12+
def withFile[T](op: IO => T): T =
13+
val io = IO()
14+
op(io)
15+
16+
def id(x: IO): x.type = x
17+
def id2(x: IO): IO = x
18+
19+
withFile(io => io) // error
20+
withFile(id) // error
21+
withFile(x => id(x)) // error
22+
withFile(id2) // error, note mentions cap since we never have a more specific include failure
23+
withFile(x => id2(x)) // error, note mentions cap since we never have a more specific include failure
24+
withFile(identity) // error, note mentions cap since we never have a more specific include failure
25+
withFile(x => identity(x)) // error, note mentions cap since we never have a more specific include failure
26+
27+
withFile: io => // error
28+
() => println(io)
29+
30+
val f2: IO => IO = (x: IO) => x // error
31+
val f3 = (x: IO) => x
32+
val f4: IO => IO = f3 // error
33+

0 commit comments

Comments
 (0)