Skip to content

Fix well-formed test for capabilities #23393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 15 additions & 16 deletions compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,24 +98,23 @@ object CheckCaptures:
* This check is performed at Typer.
*/
def checkWellformed(parent: Tree, ann: Tree)(using Context): Unit =
def check(elem: Type, pos: SrcPos): Unit = elem match
case ref: Capability =>
def check(elem: Type): Unit = elem match
case ref: TypeRef =>
val refSym = ref.symbol
if refSym.isType && !refSym.info.derivesFrom(defn.Caps_CapSet) then
report.error(em"$elem is not a legal element of a capture set", ann.srcPos)
case ref: CoreCapability =>
if !ref.isTrackableRef && !ref.isCapRef then
report.error(em"$elem cannot be tracked since it is not a parameter or local value", pos)
report.error(em"$elem cannot be tracked since it is not a parameter or local value", ann.srcPos)
case ReachCapability(ref) =>
check(ref)
if ref.isCapRef then
report.error(em"Cannot form a reach capability from `cap`", ann.srcPos)
case ReadOnlyCapability(ref) =>
check(ref)
case tpe =>
report.error(em"$elem: $tpe is not a legal element of a capture set", pos)
for elem <- ann.retainedSet.retainedElementsRaw do
elem match
case ref: TypeRef =>
val refSym = ref.symbol
if refSym.isType && !refSym.info.derivesFrom(defn.Caps_CapSet) then
report.error(em"$elem is not a legal element of a capture set", ann.srcPos)
case ReachCapability(ref) =>
check(ref, ann.srcPos)
case ReadOnlyCapability(ref) =>
check(ref, ann.srcPos)
case _ =>
check(elem, ann.srcPos)
report.error(em"$elem: $tpe is not a legal element of a capture set", ann.srcPos)
ann.retainedSet.retainedElementsRaw.foreach(check)

/** Under the sealed policy, report an error if some part of `tp` contains the
* root capability in its capture set or if it refers to a type parameter that
Expand Down
20 changes: 20 additions & 0 deletions tests/neg-custom-args/captures/caps-reach.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- [E040] Syntax Error: tests/neg-custom-args/captures/caps-reach.scala:9:46 -------------------------------------------
9 | val consumers4 = ListBuffer.empty[() ->{f.rd*} Unit] // error
| ^
| '}' expected, but identifier found
-- [E040] Syntax Error: tests/neg-custom-args/captures/caps-reach.scala:10:46 ------------------------------------------
10 | val consumers5 = ListBuffer.empty[() ->{f.rd.rd} Unit] // error
| ^
| '}' expected, but '.' found
-- [E040] Syntax Error: tests/neg-custom-args/captures/caps-reach.scala:11:46 ------------------------------------------
11 | val consumers6 = ListBuffer.empty[() ->{f * *} Unit] // error
| ^
| '}' expected, but identifier found
-- Error: tests/neg-custom-args/captures/caps-reach.scala:6:42 ---------------------------------------------------------
6 | val consumers1 = ListBuffer.empty[() ->{caps.cap*} Unit] // error
| ^^^^^^^^^
| Cannot form a reach capability from `cap`
-- Error: tests/neg-custom-args/captures/caps-reach.scala:7:42 ---------------------------------------------------------
7 | val consumers2 = ListBuffer.empty[() ->{caps.cap*.rd} Unit] // error
| ^^^^^^^^^^^^
| Cannot form a reach capability from `cap`
11 changes: 11 additions & 0 deletions tests/neg-custom-args/captures/caps-reach.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import language.experimental.captureChecking
import scala.collection.mutable.ListBuffer

class MyContainer:
val f: Object^ = ???
val consumers1 = ListBuffer.empty[() ->{caps.cap*} Unit] // error
val consumers2 = ListBuffer.empty[() ->{caps.cap*.rd} Unit] // error
val consumers3 = ListBuffer.empty[() ->{f*.rd} Unit] // ok
val consumers4 = ListBuffer.empty[() ->{f.rd*} Unit] // error
val consumers5 = ListBuffer.empty[() ->{f.rd.rd} Unit] // error
val consumers6 = ListBuffer.empty[() ->{f * *} Unit] // error
Loading