Skip to content

Commit 979d7c5

Browse files
committed
Don't widen arguments for tracked class parameters
1 parent 5e158f5 commit 979d7c5

File tree

4 files changed

+35
-3
lines changed

4 files changed

+35
-3
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ object CheckCaptures:
4040
val name: String = "cc"
4141
val description: String = "capture checking"
4242

43+
/** An attachment to prevent widening of arguments to tracked parameters */
44+
val NoWiden: Property.Key[Unit] = Property.Key()
45+
4346
enum EnvKind derives CanEqual:
4447
case Regular // normal case
4548
case NestedInOwner // environment is a temporary one nested in the owner's environment,
@@ -829,6 +832,7 @@ class CheckCaptures extends Recheck, SymTransformer:
829832
// - the selection is either a trackable capture reference or a pure type, or
830833
// - if the selection is of a parameterless method capturing a ResultCap
831834
if noWiden(selType, pt)
835+
|| tree.hasAttachment(NoWiden)
832836
|| qualType.isBoxedCapturing
833837
|| selType.isBoxedCapturing
834838
|| selWiden.isBoxedCapturing
@@ -885,6 +889,11 @@ class CheckCaptures extends Recheck, SymTransformer:
885889
* TODO: Maybe not charge deep capture sets for consume?
886890
*/
887891
protected override def recheckArg(arg: Tree, formal: Type, pref: ParamRef, app: Apply)(using Context): Type =
892+
val meth = app.fun.symbol
893+
if meth.isPrimaryConstructor
894+
&& meth.owner.asClass.refiningGetterNamed(pref.paramName).is(Tracked)
895+
then
896+
arg.putAttachment(NoWiden, ())
888897
val instantiatedFormal = globalCapToLocal(formal, Origin.Formal(pref, app))
889898
val argType = recheck(arg, instantiatedFormal)
890899
.showing(i"recheck arg $arg vs $instantiatedFormal = $result", capt)
@@ -1980,7 +1989,7 @@ class CheckCaptures extends Recheck, SymTransformer:
19801989
* - do box adaptation
19811990
*/
19821991
def adapt(actual: Type, expected: Type, tree: Tree)(using Context): Type =
1983-
if noWiden(actual, expected) then
1992+
if noWiden(actual, expected) || tree.removeAttachment(NoWiden).isDefined then
19841993
expected match
19851994
case expected @ CapturingType(_, _) if expected.isBoxed =>
19861995
// actual is a singleton type and expected is of the form box x.type^cs.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
-- Error: tests/neg-custom-args/captures/i25251.scala:5:9 --------------------------------------------------------------
2+
5 | this.g() // error
3+
| ^^^^^^
4+
| Cannot call update method g of A.this
5+
| since the access is in method f, which is not an update method.
6+
-- Error: tests/neg-custom-args/captures/i25251.scala:6:8 --------------------------------------------------------------
7+
6 | ref.g() // error
8+
| ^^^^^
9+
| Cannot call update method g of ref
10+
| since the access is in method f, which is not an update method.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import caps.*
22
trait A extends Stateful:
33
def f() = /* read-only f */
44
val ref: this.type = this
5-
this.g()
6-
ref.g()
5+
this.g() // error
6+
ref.g() // error
77

88
update def g() = ???
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import language.experimental.captureChecking
2+
import language.experimental.modularity
3+
import caps.*
4+
5+
trait Collection[+T] extends Stateful:
6+
self: Collection[T]^ =>
7+
type Index
8+
9+
// slice should have its Index type member a subtype of the Collection's Index
10+
def getSlice(): (Collection[T] { type Index <: self.Index })^{this.rd} = new Slice(this)
11+
12+
class Slice[+T](tracked val coll: Collection[T]) extends Collection[T]:
13+
type Index = coll.Index

0 commit comments

Comments
 (0)