Skip to content

Commit 2be1b41

Browse files
committed
New scheme
1 parent 1df49f1 commit 2be1b41

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+710
-593
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ class Compiler {
8383
new PatternMatcher) :: // Compile pattern matches
8484
List(new TestRecheck.Pre) :: // Test only: run rechecker, enabled under -Yrecheck-test
8585
List(new TestRecheck) :: // Test only: run rechecker, enabled under -Yrecheck-test
86-
List(new cc.AddTryOwners) :: // Add symbols as owners of try blocks, enabled under captureChecking
8786
List(new cc.Setup) :: // Preparations for check captures phase, enabled under captureChecking
8887
List(new cc.CheckCaptures) :: // Check captures, enabled under captureChecking
8988
List(new ElimOpaque, // Turn opaque into normal aliases

compiler/src/dotty/tools/dotc/ast/Desugar.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ object desugar {
437437
private def toDefParam(tparam: TypeDef, keepAnnotations: Boolean): TypeDef = {
438438
var mods = tparam.rawMods
439439
if (!keepAnnotations) mods = mods.withAnnotations(Nil)
440-
tparam.withMods(mods & EmptyFlags | Param)
440+
tparam.withMods(mods & (EmptyFlags | Sealed) | Param)
441441
}
442442
private def toDefParam(vparam: ValDef, keepAnnotations: Boolean, keepDefault: Boolean): ValDef = {
443443
var mods = vparam.rawMods

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

+13-97
Original file line numberDiff line numberDiff line change
@@ -99,31 +99,13 @@ trait FollowAliases extends TypeMap:
9999
if t2 ne t1 then return t2
100100
mapOver(t)
101101

102-
class mapRoots(from0: CaptureRoot, to: CaptureRoot)(using Context) extends DeepTypeMap, BiTypeMap, FollowAliases:
103-
val from = from0.followAlias
104-
105-
//override val toString = i"mapRoots($from, $to)"
106-
107-
def apply(t: Type): Type =
108-
if t eq from then to
109-
else t match
110-
case t: CaptureRoot.Var if ccConfig.constrainRootsWhenMapping && t.unifiesWith(from) =>
111-
to
112-
case t @ Setup.Box(t1) =>
113-
t.derivedBox(this(t1))
114-
case _ =>
115-
mapOverFollowingAliases(t)
116-
117-
def inverse = mapRoots(to, from)
118-
end mapRoots
119-
120102
extension (tree: Tree)
121103

122104
/** Map tree with CaptureRef type to its type, throw IllegalCaptureRef otherwise */
123105
def toCaptureRef(using Context): CaptureRef = tree match
124106
case QualifiedRoot(outer) =>
125107
ctx.owner.levelOwnerNamed(outer)
126-
.orElse(defn.captureRoot) // non-existing outer roots are reported in Setup's checkQualifiedRoots
108+
.orElse(defn.RootClass) // non-existing outer roots are reported in Setup's checkQualifiedRoots
127109
.localRoot.termRef
128110
case _ => tree.tpe match
129111
case ref: CaptureRef => ref
@@ -301,32 +283,6 @@ extension (tp: Type)
301283
mapOver(t)
302284
tm(tp)
303285

304-
def hasUniversalRootOf(sym: Symbol)(using Context): Boolean =
305-
306-
def isOwnRoot(tp: Type)(using Context): Boolean =
307-
tp.isCapabilityClassRef
308-
|| tp.dealias.match
309-
case tp: TermRef =>
310-
tp.isGenericRootCapability || tp.localRootOwner == sym
311-
case _ =>
312-
false
313-
314-
tp.dealiasKeepAnnots match
315-
case tp @ AnnotatedType(parent, annot) =>
316-
val found = annot match
317-
case CaptureAnnotation(refs, _) => refs.elems.exists(isOwnRoot(_))
318-
case _ => annot.tree.retainedElems.exists(tree => isOwnRoot(tree.tpe))
319-
found || parent.hasUniversalRootOf(sym)
320-
case tp: TypeRef =>
321-
tp.isRef(defn.Caps_Cap) || tp.isCapabilityClassRef
322-
case tp: LazyRef =>
323-
tp.ref.hasUniversalRootOf(sym)
324-
case tp: TypeVar =>
325-
tp.underlying.hasUniversalRootOf(sym)
326-
case _ =>
327-
tp.isCapabilityClassRef
328-
end hasUniversalRootOf
329-
330286
extension (cls: ClassSymbol)
331287

332288
def pureBaseClass(using Context): Option[Symbol] =
@@ -382,19 +338,6 @@ extension (sym: Symbol)
382338
&& sym != defn.Caps_unsafeBox
383339
&& sym != defn.Caps_unsafeUnbox
384340

385-
def takesCappedParamIn(info: Type)(using Context): Boolean =
386-
info.dealias.stripPoly match
387-
case mt: MethodType =>
388-
(mt.paramInfos.exists(_.hasUniversalRootOf(sym)) || takesCappedParamIn(mt.resType))
389-
//.showing(i"takes capped param1 $sym: $mt = $result")
390-
case AppliedType(fn, args) if defn.isFunctionClass(fn.typeSymbol) =>
391-
args.init.exists(_.hasUniversalRootOf(sym)) || takesCappedParamIn(args.last)
392-
case defn.RefinedFunctionOf(rinfo) =>
393-
takesCappedParamIn(rinfo)
394-
//.showing(i"takes capped param2 $sym: $rinfo = $result")
395-
case _ =>
396-
false
397-
398341
def isTrackedSomewhere(using Context): Boolean =
399342
val search = new TypeAccumulator[Boolean]:
400343
def apply(found: Boolean, tp: Type) =
@@ -404,31 +347,18 @@ extension (sym: Symbol)
404347

405348
// TODO Also include vals (right now they are manually entered in levelOwners by Setup)
406349
def isLevelOwner(using Context): Boolean =
407-
val symd = sym.denot
408-
def isCaseClassSynthetic = // TODO drop
409-
symd.maybeOwner.isClass && symd.owner.is(Case) && symd.is(Synthetic) && symd.info.firstParamNames.isEmpty
410-
def classQualifies =
411-
if sym.isEffectivelyFinal then
412-
takesCappedParamIn(symd.primaryConstructor.info)
413-
|| symd.asClass.givenSelfType.hasUniversalRootOf(sym)
414-
else
415-
!sym.isPureClass
416-
def compute =
417-
if symd.isClass then
418-
symd.is(CaptureChecked) && classQualifies || symd.isRoot
419-
else
420-
(symd.is(Method, butNot = Accessor)
421-
|| symd.isTerm && !symd.isOneOf(TermParamOrAccessor | Mutable))
422-
&& (!symd.owner.isClass
423-
|| symd.owner.is(CaptureChecked)
424-
|| Synthetics.needsTransform(symd)
425-
)
426-
&& (!symd.isAnonymousFunction || sym.definedLocalRoot.exists)
427-
&& takesCappedParamIn(symd.info)
428-
&& { ccSetup.println(i"Level owner $sym"); true }
429-
430-
ccState.isLevelOwner.getOrElseUpdate(sym, compute)
431-
end isLevelOwner
350+
sym.isClass
351+
|| sym.is(Method, butNot = Accessor)// && !sym.isAnonymousFunction // TODO enable?
352+
353+
/** The level owner enclosing `sym` which has the given name, or NoSymbol if none exists.
354+
*/
355+
def levelOwnerNamed(name: String)(using Context): Symbol =
356+
def recur(sym: Symbol): Symbol =
357+
if sym.name.toString == name then
358+
if sym.isLevelOwner then sym else NoSymbol
359+
else if sym == defn.RootClass then NoSymbol
360+
else recur(sym.owner)
361+
recur(sym)
432362

433363
/** The owner of the current level. Qualifying owners are
434364
* - methods other than constructors and anonymous functions
@@ -444,20 +374,6 @@ extension (sym: Symbol)
444374
else recur(sym.owner)
445375
recur(sym)
446376

447-
/** The level owner enclosing `sym` which has the given name, or NoSymbol if none exists.
448-
* If name refers to a val that has a closure as rhs, we return the closure as level
449-
* owner.
450-
*/
451-
def levelOwnerNamed(name: String)(using Context): Symbol =
452-
def recur(sym: Symbol): Symbol =
453-
if sym.name.toString == name then
454-
if sym.isLevelOwner then sym
455-
else NoSymbol
456-
else if sym == defn.RootClass then NoSymbol
457-
else recur(sym.owner)
458-
recur(sym)
459-
.showing(i"find outer $sym [ $name ] = $result", capt)
460-
461377
/** The parameter with type caps.Cap in the leading term parameter section,
462378
* or NoSymbol, if none exists.
463379
*/

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ object CaptureRoot:
5959
*/
6060
def freshEnclosedBy(rs: CaptureRoot*)(using Context): CaptureRoot =
6161
val r = fresh
62-
if rs.forall(_.encloses(r)) then r else throw NoCommonRoot(rs*)
62+
if rs.forall(_.encloses(r)) then r else throw CaptureRoot.NoCommonRoot(rs*)
6363

6464
def computeHash(bs: Binders): Int = hash
6565
def hash: Int = System.identityHashCode(this)
@@ -107,7 +107,7 @@ object CaptureRoot:
107107
r1.alias = r2
108108
r2.outerLimit =
109109
r1.outerLimit.maxNested(r2.outerLimit,
110-
onConflict = (_, _) => throw NoCommonRoot(r1, r2))
110+
onConflict = (_, _) => throw CaptureRoot.NoCommonRoot(r1, r2))
111111
r2.innerLimit = r1.innerLimit.minNested(r2.innerLimit)
112112
true
113113
else
@@ -129,7 +129,7 @@ object CaptureRoot:
129129
else (r1, r2) match
130130
case (r1: TermRef, r2: TermRef) =>
131131
r1.localRootOwner.maxNested(r2.localRootOwner,
132-
onConflict = (_, _) => throw NoCommonRoot(r1, r2)
132+
onConflict = (_, _) => throw CaptureRoot.NoCommonRoot(r1, r2)
133133
).termRef
134134
case (r1: TermRef, r2: Var) =>
135135
r2.freshEnclosedBy(r1, r2)

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

+46-46
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,6 @@ sealed abstract class CaptureSet extends Showable:
6161
*/
6262
def levelLimit: Symbol
6363

64-
def rootSet(using Context): CaptureSet =
65-
assert(levelLimit.exists, this)
66-
levelLimit.localRoot.termRef.singletonCaptureSet
67-
6864
/** Is this capture set definitely non-empty? */
6965
final def isNotEmpty: Boolean = !elems.isEmpty
7066

@@ -144,16 +140,30 @@ sealed abstract class CaptureSet extends Showable:
144140
extension (x: CaptureRef)(using Context)
145141
private def subsumes(y: CaptureRef) =
146142
(x eq y)
143+
|| x.isSuperRootOf(y)
147144
|| y.match
148-
case y: TermRef => (y.prefix eq x) || y.isLocalRootCapability && x.isSuperRootOf(y)
149-
case y: CaptureRoot.Var => x.isSuperRootOf(y)
145+
case y: TermRef => y.prefix eq x
150146
case _ => false
151147
|| (x.isGenericRootCapability || y.isRootCapability && x.isRootCapability)
152148
&& ctx.property(LooseRootChecking).isDefined
153149

154-
private def isSuperRootOf(y: CaptureRoot) = x match
155-
case x: CaptureRoot =>
156-
x.isGenericRootCapability || x.isLocalRootCapability && y.encloses(x)
150+
/** x <:< cap, cap[x] <:< cap
151+
* cap[y] <:< cap[x] if y encloses x
152+
* y <:< cap[x] if y's level owner encloses x's local root owner
153+
*/
154+
private def isSuperRootOf(y: CaptureRef): Boolean = x match
155+
case x: TermRef =>
156+
if x.isGenericRootCapability then true
157+
else if x.isLocalRootCapability && !y.isGenericRootCapability then
158+
val xowner = x.localRootOwner
159+
y match
160+
case y: TermRef =>
161+
xowner.isContainedIn(y.symbol.levelOwner)
162+
case y: ThisType =>
163+
xowner.isContainedIn(y.cls)
164+
case _ =>
165+
false
166+
else false
157167
case _ => false
158168
end extension
159169

@@ -207,9 +217,10 @@ sealed abstract class CaptureSet extends Showable:
207217
def recur(elems: List[CaptureRef]): CompareResult = elems match
208218
case elem :: elems1 =>
209219
var result = that.tryInclude(elem, this)
210-
if !result.isOK && !elem.isRootCapability && summon[VarState] != FrozenState then
220+
if !result.isOK then
211221
ccState.levelError = ccState.levelError.orElse(result.levelError)
212-
result = result.orElse(elem.captureSetOfInfo.subCaptures(that))
222+
if !elem.isRootCapability && summon[VarState] != FrozenState then
223+
result = result.orElse(elem.captureSetOfInfo.subCaptures(that))
213224
if result.isOK then
214225
recur(elems1)
215226
else
@@ -322,22 +333,6 @@ sealed abstract class CaptureSet extends Showable:
322333
def substParams(tl: BindingType, to: List[Type])(using Context) =
323334
map(Substituters.SubstParamsMap(tl, to))
324335

325-
/** The capture root that corresponds to this capture set. This is:
326-
* - if the capture set is a Var with a defined level limit, the
327-
* associated capture root,
328-
* - otherwise, if the set is nonempty, the innermost root such
329-
* that some element of the set subcaptures this root,
330-
* - otherwise, if the set is empty, `default`.
331-
*/
332-
def impliedRoot(default: CaptureRoot)(using Context): CaptureRoot =
333-
if levelLimit.exists then levelLimit.localRoot.termRef
334-
else if elems.isEmpty then default
335-
else elems.toList
336-
.map:
337-
case elem: CaptureRoot if elem.isLocalRootCapability => elem
338-
case elem => elem.captureSetOfInfo.impliedRoot(default)
339-
.reduce((x: CaptureRoot, y: CaptureRoot) => CaptureRoot.lub(x, y))
340-
341336
/** Invoke handler if this set has (or later aquires) the root capability `cap` */
342337
def disallowRootCapability(handler: () => Context ?=> Unit)(using Context): this.type =
343338
if isUniversal then handler()
@@ -459,7 +454,7 @@ object CaptureSet:
459454
varId += 1
460455
varId
461456

462-
//assert(id != 95)
457+
//assert(id != 40)
463458

464459
override val levelLimit =
465460
if directOwner.exists then directOwner.levelOwner else NoSymbol
@@ -525,12 +520,15 @@ object CaptureSet:
525520
if elem.isGenericRootCapability then rootAddedHandler()
526521
newElemAddedHandler(elem)
527522
// assert(id != 5 || elems.size != 3, this)
528-
(CompareResult.OK /: deps) { (r, dep) =>
523+
val res = (CompareResult.OK /: deps) { (r, dep) =>
529524
r.andAlso(dep.tryInclude(elem, this))
530525
}.addToTrace(this)
526+
if !res.isOK then elems -= elem
527+
res
531528

532529
private def levelOK(elem: CaptureRef)(using Context): Boolean =
533-
!levelLimit.exists
530+
if elem.isGenericRootCapability then !noUniversal
531+
else !levelLimit.exists
534532
|| elem.match
535533
case elem: TermRef =>
536534
var sym = elem.symbol
@@ -571,15 +569,15 @@ object CaptureSet:
571569
else if elems.exists(_.isRootCapability) then
572570
CaptureSet(elems.filter(_.isRootCapability).toList*)
573571
else if computingApprox then
574-
rootSet
572+
universal
575573
else
576574
computingApprox = true
577575
try computeApprox(origin).ensuring(_.isConst)
578576
finally computingApprox = false
579577

580578
/** The intersection of all upper approximations of dependent sets */
581579
protected def computeApprox(origin: CaptureSet)(using Context): CaptureSet =
582-
(rootSet /: deps) { (acc, sup) => acc ** sup.upperApprox(this) }
580+
(universal /: deps) { (acc, sup) => acc ** sup.upperApprox(this) }
583581

584582
/** Widen the variable's elements to its upper approximation and
585583
* mark it as constant from now on. This is used for contra-variant type variables
@@ -720,7 +718,7 @@ object CaptureSet:
720718
if source eq origin then
721719
// it's a mapping of origin, so not a superset of `origin`,
722720
// therefore don't contribute to the intersection.
723-
rootSet
721+
universal
724722
else
725723
source.upperApprox(this).map(tm)
726724

@@ -788,7 +786,7 @@ object CaptureSet:
788786
if source eq origin then
789787
// it's a filter of origin, so not a superset of `origin`,
790788
// therefore don't contribute to the intersection.
791-
rootSet
789+
universal
792790
else
793791
source.upperApprox(this).filter(p)
794792

@@ -819,7 +817,7 @@ object CaptureSet:
819817
if (origin eq cs1) || (origin eq cs2) then
820818
// it's a combination of origin with some other set, so not a superset of `origin`,
821819
// therefore don't contribute to the intersection.
822-
rootSet
820+
universal
823821
else
824822
CaptureSet(elemIntersection(cs1.upperApprox(this), cs2.upperApprox(this)))
825823

@@ -1010,10 +1008,6 @@ object CaptureSet:
10101008
def ofInfo(ref: CaptureRef)(using Context): CaptureSet = ref match
10111009
case ref: TermRef if ref.isRootCapability =>
10121010
ref.singletonCaptureSet
1013-
case ref: TermRef if ref.symbol.isLevelOwner =>
1014-
ofType(ref.underlying, followResult = true).filter(
1015-
ref.symbol.localRoot.termRef != _)
1016-
// TODO: Can replace filter with - ref.symbol.localRoot.termRef when we drop level nesting
10171011
case _ =>
10181012
ofType(ref.underlying, followResult = true)
10191013

@@ -1095,12 +1089,18 @@ object CaptureSet:
10951089
override def toAdd(using Context) =
10961090
for CompareResult.LevelError(cs, ref) <- ccState.levelError.toList yield
10971091
ccState.levelError = None
1098-
val levelStr = ref match
1099-
case ref: TermRef => i", defined in ${ref.symbol.maybeOwner}"
1100-
case _ => ""
1101-
i"""
1102-
|
1103-
|Note that reference ${ref}$levelStr
1104-
|cannot be included in outer capture set $cs which is associated with ${cs.levelLimit}"""
1092+
if ref.isGenericRootCapability then
1093+
i"""
1094+
|
1095+
|Note that the universal capability `cap`
1096+
|cannot be included in capture set $cs"""
1097+
else
1098+
val levelStr = ref match
1099+
case ref: TermRef => i", defined in ${ref.symbol.maybeOwner}"
1100+
case _ => ""
1101+
i"""
1102+
|
1103+
|Note that reference ${ref}$levelStr
1104+
|cannot be included in outer capture set $cs which is associated with ${cs.levelLimit}"""
11051105

11061106
end CaptureSet

0 commit comments

Comments
 (0)