Skip to content

Commit 9884855

Browse files
committed
Enable local roots
1 parent f2aa33c commit 9884855

File tree

10 files changed

+76
-34
lines changed

10 files changed

+76
-34
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import collection.mutable
1717
private val Captures: Key[CaptureSet] = Key()
1818
private val BoxedType: Key[BoxedTypeCache] = Key()
1919

20-
private val enableRootMapping = false
20+
private val enableRootMapping = true
2121

2222
/** Switch whether unpickled function types and byname types should be mapped to
2323
* impure types. With the new gradual typing using Fluid capture sets, this should

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

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,28 +1075,29 @@ class CheckCaptures extends Recheck, SymTransformer:
10751075
}
10761076
assert(roots.nonEmpty)
10771077
for case root: ClassSymbol <- roots do
1078-
checkSelfAgainstParents(root, root.baseClasses)
1079-
val selfType = root.asClass.classInfo.selfType
1080-
interpolator(startingVariance = -1).traverse(selfType)
1081-
if !root.isEffectivelySealed then
1082-
def matchesExplicitRefsInBaseClass(refs: CaptureSet, cls: ClassSymbol): Boolean =
1083-
cls.baseClasses.tail.exists { psym =>
1084-
val selfType = psym.asClass.givenSelfType
1085-
selfType.exists && selfType.captureSet.elems == refs.elems
1086-
}
1087-
selfType match
1088-
case CapturingType(_, refs: CaptureSet.Var)
1089-
if !refs.elems.exists(_.isRootCapability) && !matchesExplicitRefsInBaseClass(refs, root) =>
1090-
// Forbid inferred self types unless they are already implied by an explicit
1091-
// self type in a parent.
1092-
report.error(
1093-
em"""$root needs an explicitly declared self type since its
1094-
|inferred self type $selfType
1095-
|is not visible in other compilation units that define subclasses.""",
1096-
root.srcPos)
1097-
case _ =>
1098-
parentTrees -= root
1099-
capt.println(i"checked $root with $selfType")
1078+
inContext(ctx.withOwner(root)):
1079+
checkSelfAgainstParents(root, root.baseClasses)
1080+
val selfType = root.asClass.classInfo.selfType
1081+
interpolator(startingVariance = -1).traverse(selfType)
1082+
if !root.isEffectivelySealed then
1083+
def matchesExplicitRefsInBaseClass(refs: CaptureSet, cls: ClassSymbol): Boolean =
1084+
cls.baseClasses.tail.exists { psym =>
1085+
val selfType = psym.asClass.givenSelfType
1086+
selfType.exists && selfType.captureSet.elems == refs.elems
1087+
}
1088+
selfType match
1089+
case CapturingType(_, refs: CaptureSet.Var)
1090+
if !refs.elems.exists(_.isRootCapability) && !matchesExplicitRefsInBaseClass(refs, root) =>
1091+
// Forbid inferred self types unless they are already implied by an explicit
1092+
// self type in a parent.
1093+
report.error(
1094+
em"""$root needs an explicitly declared self type since its
1095+
|inferred self type $selfType
1096+
|is not visible in other compilation units that define subclasses.""",
1097+
root.srcPos)
1098+
case _ =>
1099+
parentTrees -= root
1100+
capt.println(i"checked $root with $selfType")
11001101
end checkSelfTypes
11011102

11021103
/** Heal ill-formed capture sets in the type parameter.

tests/neg-custom-args/captures/cc-this2.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
-- Error: tests/neg-custom-args/captures/cc-this2/D_2.scala:2:6 --------------------------------------------------------
33
2 |class D extends C: // error
44
|^
5-
|reference (caps.cap : caps.Root) is not included in the allowed capture set {} of pure base class class C
5+
|reference (cap : caps.Root) is not included in the allowed capture set {} of pure base class class C
66
3 | this: D^ =>

tests/neg-custom-args/captures/cc-this5.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
-- Error: tests/neg-custom-args/captures/cc-this5.scala:16:20 ----------------------------------------------------------
22
16 | def f = println(c) // error
33
| ^
4-
| (c : Cap^) cannot be referenced here; it is not included in the allowed capture set {}
5-
| of the enclosing class A
4+
| (c : Cap^{cap[test]}) cannot be referenced here; it is not included in the allowed capture set {}
5+
| of the enclosing class A
66
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/cc-this5.scala:21:15 -------------------------------------
77
21 | val x: A = this // error
88
| ^^^^

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
-- Error: tests/neg-custom-args/captures/eta.scala:6:20 ----------------------------------------------------------------
99
6 | bar( () => f ) // error
1010
| ^
11-
| (f : Proc^) cannot be referenced here; it is not included in the allowed capture set {}
11+
| (f : () => Unit) cannot be referenced here; it is not included in the allowed capture set {}
1212
| of an enclosing function literal with expected type () -> box () ->? Unit

tests/neg-custom-args/captures/exception-definitions.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
-- Error: tests/neg-custom-args/captures/exception-definitions.scala:2:6 -----------------------------------------------
22
2 |class Err extends Exception: // error
33
|^
4-
|reference (caps.cap : caps.Root) is not included in the allowed capture set {} of pure base class class Throwable
4+
|reference (cap : caps.Root) is not included in the allowed capture set {} of pure base class class Throwable
55
3 | self: Err^ =>
66
-- Error: tests/neg-custom-args/captures/exception-definitions.scala:7:12 ----------------------------------------------
77
7 | val x = c // error
88
| ^
9-
|(c : Any^) cannot be referenced here; it is not included in the allowed capture set {} of pure base class class Throwable
9+
|(c : Any^{cap[test]}) cannot be referenced here; it is not included in the allowed capture set {} of pure base class class Throwable
1010
-- Error: tests/neg-custom-args/captures/exception-definitions.scala:8:8 -----------------------------------------------
1111
8 | class Err3(c: Any^) extends Exception // error
1212
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylist.scala:35:29 -------------------------------------
99
35 | val ref1c: LazyList[Int] = ref1 // error
1010
| ^^^^
11-
| Found: (ref1 : lazylists.LazyCons[Int]{val xs: () ->{cap1} lazylists.LazyList[Int]^}^{cap1})
12-
| Required: lazylists.LazyList[Int]
11+
| Found: (ref1 : lazylists.LazyCons[Int]{val xs: () ->{cap1} lazylists.LazyList[Int]^{cap[LazyCons]}}^{cap1})
12+
| Required: lazylists.LazyList[Int]
1313
|
1414
| longer explanation available when compiling with `-explain`
1515
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylist.scala:37:36 -------------------------------------
@@ -37,6 +37,6 @@
3737
22 | def tail: LazyList[Nothing]^ = ??? // error overriding
3838
| ^
3939
| error overriding method tail in class LazyList of type -> lazylists.LazyList[Nothing];
40-
| method tail of type -> lazylists.LazyList[Nothing]^ has incompatible type
40+
| method tail of type -> lazylists.LazyList[Nothing]^{cap[tail]} has incompatible type
4141
|
4242
| longer explanation available when compiling with `-explain`

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
-- Error: tests/neg-custom-args/captures/lazylists2.scala:40:20 --------------------------------------------------------
2626
40 | def head: B = f(xs.head) // error
2727
| ^
28-
|(f : A => B) cannot be referenced here; it is not included in the allowed capture set {xs} of the self type of class Mapped
28+
|(f : A ->{cap[map3]} B) cannot be referenced here; it is not included in the allowed capture set {xs} of the self type of class Mapped
2929
-- Error: tests/neg-custom-args/captures/lazylists2.scala:41:48 --------------------------------------------------------
3030
41 | def tail: LazyList[B]^{this}= xs.tail.map(f) // error
3131
| ^
32-
|(f : A => B) cannot be referenced here; it is not included in the allowed capture set {xs} of the self type of class Mapped
32+
|(f : A ->{cap[map3]} B) cannot be referenced here; it is not included in the allowed capture set {xs} of the self type of class Mapped
3333
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:45:4 ------------------------------------
3434
45 | final class Mapped extends LazyList[B]: // error
3535
| ^
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Error: tests/neg-custom-args/captures/levels.scala:15:11 ------------------------------------------------------------
2+
15 | r.setV(g) // error
3+
| ^
4+
| reference (cap3 : CC^) is not included in the allowed capture set ?
5+
| of an enclosing function literal with expected type box (x$0: String) ->? String
6+
|
7+
| Note that reference (cap3 : CC^), defined at level 2
8+
| cannot be included in outer capture set ?, defined at level 1 in method test
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class CC
2+
3+
def test(cap1: CC^) =
4+
5+
class Ref[T](init: T):
6+
private var v: T = init
7+
def setV(x: T): Unit = v = x
8+
def getV: T = v
9+
10+
val r = Ref((x: String) => x)
11+
12+
def scope =
13+
val cap3: CC^ = ???
14+
def g(x: String): String = if cap3 == cap3 then "" else "a"
15+
r.setV(g) // error
16+
()
17+
18+
/*
19+
Explicit:
20+
cap is local root of enclosing method or class, can be overridden by qualifying it.
21+
i.e. cap[name]
22+
23+
On method instantiation: All uses of cap --> cap of caller
24+
On class instantiation: All uses of cap, or local cap of clsss --> cap of caller
25+
26+
Alternative solution: root variables
27+
- track minimal & maximal level
28+
- updated via subsumption tests, root added handler for prefix/member
29+
30+
roots: Implicitly: outer <: inner
31+
32+
def withFile[T]((local: Root) ?=> op: File^{local}) => T]): T
33+
*/

0 commit comments

Comments
 (0)