Skip to content

Commit 26cb21b

Browse files
authored
Fix well-formed test for capabilities (#23393)
- Disallow cap* - Do allow f*.rd
2 parents 50d245f + 2d832eb commit 26cb21b

File tree

3 files changed

+46
-16
lines changed

3 files changed

+46
-16
lines changed

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

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,24 +98,23 @@ object CheckCaptures:
9898
* This check is performed at Typer.
9999
*/
100100
def checkWellformed(parent: Tree, ann: Tree)(using Context): Unit =
101-
def check(elem: Type, pos: SrcPos): Unit = elem match
102-
case ref: Capability =>
101+
def check(elem: Type): Unit = elem match
102+
case ref: TypeRef =>
103+
val refSym = ref.symbol
104+
if refSym.isType && !refSym.info.derivesFrom(defn.Caps_CapSet) then
105+
report.error(em"$elem is not a legal element of a capture set", ann.srcPos)
106+
case ref: CoreCapability =>
103107
if !ref.isTrackableRef && !ref.isCapRef then
104-
report.error(em"$elem cannot be tracked since it is not a parameter or local value", pos)
108+
report.error(em"$elem cannot be tracked since it is not a parameter or local value", ann.srcPos)
109+
case ReachCapability(ref) =>
110+
check(ref)
111+
if ref.isCapRef then
112+
report.error(em"Cannot form a reach capability from `cap`", ann.srcPos)
113+
case ReadOnlyCapability(ref) =>
114+
check(ref)
105115
case tpe =>
106-
report.error(em"$elem: $tpe is not a legal element of a capture set", pos)
107-
for elem <- ann.retainedSet.retainedElementsRaw do
108-
elem match
109-
case ref: TypeRef =>
110-
val refSym = ref.symbol
111-
if refSym.isType && !refSym.info.derivesFrom(defn.Caps_CapSet) then
112-
report.error(em"$elem is not a legal element of a capture set", ann.srcPos)
113-
case ReachCapability(ref) =>
114-
check(ref, ann.srcPos)
115-
case ReadOnlyCapability(ref) =>
116-
check(ref, ann.srcPos)
117-
case _ =>
118-
check(elem, ann.srcPos)
116+
report.error(em"$elem: $tpe is not a legal element of a capture set", ann.srcPos)
117+
ann.retainedSet.retainedElementsRaw.foreach(check)
119118

120119
/** Under the sealed policy, report an error if some part of `tp` contains the
121120
* root capability in its capture set or if it refers to a type parameter that
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-- [E040] Syntax Error: tests/neg-custom-args/captures/caps-reach.scala:9:46 -------------------------------------------
2+
9 | val consumers4 = ListBuffer.empty[() ->{f.rd*} Unit] // error
3+
| ^
4+
| '}' expected, but identifier found
5+
-- [E040] Syntax Error: tests/neg-custom-args/captures/caps-reach.scala:10:46 ------------------------------------------
6+
10 | val consumers5 = ListBuffer.empty[() ->{f.rd.rd} Unit] // error
7+
| ^
8+
| '}' expected, but '.' found
9+
-- [E040] Syntax Error: tests/neg-custom-args/captures/caps-reach.scala:11:46 ------------------------------------------
10+
11 | val consumers6 = ListBuffer.empty[() ->{f * *} Unit] // error
11+
| ^
12+
| '}' expected, but identifier found
13+
-- Error: tests/neg-custom-args/captures/caps-reach.scala:6:42 ---------------------------------------------------------
14+
6 | val consumers1 = ListBuffer.empty[() ->{caps.cap*} Unit] // error
15+
| ^^^^^^^^^
16+
| Cannot form a reach capability from `cap`
17+
-- Error: tests/neg-custom-args/captures/caps-reach.scala:7:42 ---------------------------------------------------------
18+
7 | val consumers2 = ListBuffer.empty[() ->{caps.cap*.rd} Unit] // error
19+
| ^^^^^^^^^^^^
20+
| Cannot form a reach capability from `cap`
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import language.experimental.captureChecking
2+
import scala.collection.mutable.ListBuffer
3+
4+
class MyContainer:
5+
val f: Object^ = ???
6+
val consumers1 = ListBuffer.empty[() ->{caps.cap*} Unit] // error
7+
val consumers2 = ListBuffer.empty[() ->{caps.cap*.rd} Unit] // error
8+
val consumers3 = ListBuffer.empty[() ->{f*.rd} Unit] // ok
9+
val consumers4 = ListBuffer.empty[() ->{f.rd*} Unit] // error
10+
val consumers5 = ListBuffer.empty[() ->{f.rd.rd} Unit] // error
11+
val consumers6 = ListBuffer.empty[() ->{f * *} Unit] // error

0 commit comments

Comments
 (0)