Skip to content

Commit d6a2659

Browse files
committed
Refine rule for this widening
We now widen the expected type of the right hand side of a class member as follows: Add all references of the declared type of this that are not subsumed by a capture set of a parameter type.
1 parent 7ba98d3 commit d6a2659

File tree

3 files changed

+17
-5
lines changed

3 files changed

+17
-5
lines changed

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,14 @@ sealed abstract class CaptureSet extends Showable:
4949
/** Is this capture set definitely non-empty? */
5050
final def isNotEmpty: Boolean = !elems.isEmpty
5151

52-
/** Cast to variable. @pre: @isConst */
52+
/** Cast to Const. @pre: isConst */
53+
def asConst: Const = this match
54+
case c: Const => c
55+
case v: Var =>
56+
assert(v.isConst)
57+
Const(v.elems)
58+
59+
/** Cast to variable. @pre: !isConst */
5360
def asVar: Var =
5461
assert(!isConst)
5562
asInstanceOf[Var]

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

+8-4
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,14 @@ class CheckCaptures extends Recheck:
325325
override def recheckRHS(tree: Tree, pt: Type, sym: Symbol)(using Context): Type =
326326
val pt1 = pt match
327327
case CapturingType(core, refs, _)
328-
if sym.owner.isClass
329-
&& refs.elems.contains(sym.owner.thisType)
330-
&& sym.paramSymss.forall(_.forall(p => p.isType || p.info.captureSet.isAlwaysEmpty)) =>
331-
pt.derivedCapturingType(core, refs ++ sym.owner.asClass.givenSelfType.captureSet)
328+
if sym.owner.isClass && refs.elems.contains(sym.owner.thisType) =>
329+
val paramCaptures =
330+
sym.paramSymss.flatten.foldLeft(CaptureSet.empty) { (cs, p) =>
331+
val pcs = p.info.captureSet
332+
(cs ++ (if pcs.isConst then pcs else CaptureSet.universal)).asConst
333+
}
334+
val declaredCaptures = sym.owner.asClass.givenSelfType.captureSet
335+
pt.derivedCapturingType(core, refs ++ (declaredCaptures -- paramCaptures))
332336
case _ =>
333337
pt
334338
recheck(tree, pt1)

tests/pos-custom-args/captures/lazylists.scala

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extension [A](xs: {*} LazyList[A])
2121
def isEmpty = false
2222
def head: B = f(xs.head)
2323
def tail: {this} LazyList[B] = xs.tail.map(f) // OK
24+
def concat(other: {f} LazyList[A]): {this, f} LazyList[A] = ??? : ({xs, f} LazyList[A]) // OK
2425
new Mapped
2526

2627
def test(cap1: Cap, cap2: Cap) =

0 commit comments

Comments
 (0)