Skip to content

Commit d85dacd

Browse files
committed
Several changes to var handling
- Mutable variables are no longer tracked - Variable definitions with `*` capability are allowed - But variable dereferences are not allowed if they capture `*`
1 parent cbff7a4 commit d85dacd

File tree

11 files changed

+50
-26
lines changed

11 files changed

+50
-26
lines changed

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ object CheckCaptures:
8989
elem.tpe match
9090
case ref: CaptureRef =>
9191
if !ref.canBeTracked then
92-
report.error(em"$elem cannot be tracked since it is not a parameter or a local variable", elem.srcPos)
92+
report.error(em"$elem cannot be tracked since it is not a parameter or local value", elem.srcPos)
9393
case tpe =>
9494
report.error(em"$elem: $tpe is not a legal element of a capture set", elem.srcPos)
9595

@@ -560,8 +560,6 @@ class CheckCaptures extends Recheck, SymTransformer:
560560
tpe
561561
case _: Try =>
562562
tpe
563-
case _: ValDef if tree.symbol.is(Mutable) =>
564-
tree.symbol.info
565563
case _ =>
566564
NoType
567565
def checkNotUniversal(tp: Type): Unit = tp.widenDealias match
@@ -746,7 +744,7 @@ class CheckCaptures extends Recheck, SymTransformer:
746744
val criticalSet = // the set which is not allowed to have `*`
747745
if covariant then cs1 // can't box with `*`
748746
else expected.captureSet // can't unbox with `*`
749-
if criticalSet.isUniversal then
747+
if criticalSet.isUniversal && expected.isValueType then
750748
// We can't box/unbox the universal capability. Leave `actual` as it is
751749
// so we get an error in checkConforms. This tends to give better error
752750
// messages than disallowing the root capability in `criticalSet`.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2790,7 +2790,7 @@ object Types {
27902790
((prefix eq NoPrefix)
27912791
|| symbol.is(ParamAccessor) && (prefix eq symbol.owner.thisType)
27922792
|| isRootCapability
2793-
) && !symbol.is(Method)
2793+
) && !symbol.isOneOf(UnstableValueFlags)
27942794

27952795
override def isRootCapability(using Context): Boolean =
27962796
name == nme.CAPTURE_ROOT && symbol == defn.captureRoot

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
272272
case tp: LazyRef if !printDebug =>
273273
try toText(tp.ref)
274274
catch case ex: Throwable => "..."
275+
case AnySelectionProto =>
276+
"a type that can be selected or applied"
275277
case tp: SelectionProto =>
276278
"?{ " ~ toText(tp.name) ~
277279
(Str(" ") provided !tp.name.toSimpleName.last.isLetterOrDigit) ~

compiler/src/dotty/tools/dotc/transform/Recheck.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ abstract class Recheck extends Phase, SymTransformer:
147147

148148
def recheckSelect(tree: Select, pt: Type)(using Context): Type =
149149
val Select(qual, name) = tree
150-
recheckSelection(tree, recheck(qual).widenIfUnstable, name, pt)
150+
recheckSelection(tree, recheck(qual, AnySelectionProto).widenIfUnstable, name, pt)
151151

152152
def recheckSelection(tree: Select, qualType: Type, name: Name,
153153
sharpen: Denotation => Denotation)(using Context): Type =

tests/disabled/neg-custom-args/captures/capt-wf.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ def test: Unit =
1717
val y = f(C()) // ok
1818
val y2 = f2(C()) // ok
1919
()
20+
var x11 = f
21+
val x12: {x11} Any = x11
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@annotation.capability class C
2+
3+
def test(c: C) =
4+
var x: {c} Any = ???
5+
val y: {x} Any = x // error

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
| ^^^^^^^^
99
| The expression's type box {*} () -> Unit is not allowed to capture the root capability `*`.
1010
| This usually means that a capability persists longer than its allowed lifetime.
11-
-- Error: tests/neg-custom-args/captures/usingLogFile.scala:31:6 -------------------------------------------------------
12-
31 | var later3: () => Unit = () => () // error
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14-
| The mutable variable's type box {*} () -> Unit is not allowed to capture the root capability `*`.
15-
| This usually means that a capability persists longer than its allowed lifetime.
11+
-- Error: tests/neg-custom-args/captures/usingLogFile.scala:33:2 -------------------------------------------------------
12+
33 | later3() // error
13+
| ^^^^^^
14+
| box {*} () -> Unit cannot be box-converted to a type that can be selected or applied
15+
| since one of their capture sets contains the root capability `*`
1616
-- Error: tests/neg-custom-args/captures/usingLogFile.scala:37:9 -------------------------------------------------------
1717
37 | later4.x() // error
1818
| ^^^^^^^^

tests/neg-custom-args/captures/usingLogFile.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ object Test2:
2828
private val later2 = usingLogFile { f => Cell(() => f.write(0)) }
2929
later2.x() // error
3030

31-
var later3: () => Unit = () => () // error
31+
var later3: () => Unit = () => ()
3232
usingLogFile { f => later3 = () => f.write(0) }
33-
later3()
33+
later3() // error
3434

3535
var later4: Cell[() => Unit] = Cell(() => ())
3636
usingLogFile { f => later4 = Cell(() => f.write(0)) }

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

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,28 @@
55
| Required: () -> Unit
66
|
77
| longer explanation available when compiling with `-explain`
8-
-- Error: tests/neg-custom-args/captures/vars.scala:13:6 ---------------------------------------------------------------
9-
13 | var a: String => String = f // error
10-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
11-
| The mutable variable's type box {*} String -> String is not allowed to capture the root capability `*`.
12-
| This usually means that a capability persists longer than its allowed lifetime.
13-
-- Error: tests/neg-custom-args/captures/vars.scala:15:4 ---------------------------------------------------------------
14-
15 | b.head // error
8+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/vars.scala:15:10 -----------------------------------------
9+
15 | val u = a // error
10+
| ^
11+
| Found: (a : box {*} String -> String)
12+
| Required: {*} (x$0: ? String) -> ? String
13+
|
14+
| longer explanation available when compiling with `-explain`
15+
-- Error: tests/neg-custom-args/captures/vars.scala:16:2 ---------------------------------------------------------------
16+
16 | a("") // error
17+
| ^
18+
| box {*} String -> String cannot be box-converted to a type that can be selected or applied
19+
| since one of their capture sets contains the root capability `*`
20+
-- Error: tests/neg-custom-args/captures/vars.scala:17:4 ---------------------------------------------------------------
21+
17 | b.head // error
1522
| ^^^^^^
1623
| The expression's type box {*} String -> String is not allowed to capture the root capability `*`.
1724
| This usually means that a capability persists longer than its allowed lifetime.
18-
-- Error: tests/neg-custom-args/captures/vars.scala:30:8 ---------------------------------------------------------------
19-
30 | local { cap3 => // error
25+
-- Error: tests/neg-custom-args/captures/vars.scala:32:8 ---------------------------------------------------------------
26+
32 | local { cap3 => // error
2027
| ^
2128
| The expression's type box {*} (x$0: ? String) -> ? String is not allowed to capture the root capability `*`.
2229
| This usually means that a capability persists longer than its allowed lifetime.
23-
31 | def g(x: String): String = if cap3 == cap3 then "" else "a"
24-
32 | g
25-
33 | }
30+
33 | def g(x: String): String = if cap3 == cap3 then "" else "a"
31+
34 | g
32+
35 | }

tests/neg-custom-args/captures/vars.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ def test(cap1: Cap, cap2: Cap) =
1010
val z2 = () => { x = identity }
1111
val z2c: () -> Unit = z2 // error
1212

13-
var a: String => String = f // error
13+
var a: String => String = f // was error, now OK
1414
var b: List[String => String] = Nil // was error, now OK
15+
val u = a // error
16+
a("") // error
1517
b.head // error
1618

1719
def scope =
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import caps.unsafeUnbox
2+
type ErrorHandler = (Int, String) => Unit
3+
4+
var defaultIncompleteHandler: ErrorHandler = ???
5+
var incompleteHandler: ErrorHandler = defaultIncompleteHandler
6+
//val x = incompleteHandler.unsafeUnbox
7+
8+

0 commit comments

Comments
 (0)