Skip to content

Commit

Permalink
Refine rule for this widening
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
odersky committed Oct 2, 2021
1 parent ca932ca commit c568038
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 6 deletions.
9 changes: 8 additions & 1 deletion compiler/src/dotty/tools/dotc/cc/CaptureSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ sealed abstract class CaptureSet extends Showable:
/** Is this capture set definitely non-empty? */
final def isNotEmpty: Boolean = !elems.isEmpty

/** Cast to variable. @pre: @isConst */
/** Cast to Const. @pre: isConst */
def asConst: Const = this match
case c: Const => c
case v: Var =>
assert(v.isConst)
Const(v.elems)

/** Cast to variable. @pre: !isConst */
def asVar: Var =
assert(!isConst)
asInstanceOf[Var]
Expand Down
12 changes: 8 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/CheckCaptures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -325,10 +325,14 @@ class CheckCaptures extends Recheck:
override def recheckRHS(tree: Tree, pt: Type, sym: Symbol)(using Context): Type =
val pt1 = pt match
case CapturingType(core, refs, _)
if sym.owner.isClass
&& refs.elems.contains(sym.owner.thisType)
&& sym.paramSymss.forall(_.forall(p => p.isType || p.info.captureSet.isAlwaysEmpty)) =>
pt.derivedCapturingType(core, refs ++ sym.owner.asClass.givenSelfType.captureSet)
if sym.owner.isClass && refs.elems.contains(sym.owner.thisType) =>
val paramCaptures =
sym.paramSymss.flatten.foldLeft(CaptureSet.empty) { (cs, p) =>
val pcs = p.info.captureSet
(cs ++ (if pcs.isConst then pcs else CaptureSet.universal)).asConst
}
val declaredCaptures = sym.owner.asClass.givenSelfType.captureSet
pt.derivedCapturingType(core, refs ++ (declaredCaptures -- paramCaptures))
case _ =>
pt
recheck(tree, pt1)
Expand Down
2 changes: 1 addition & 1 deletion tests/neg-custom-args/captures/lazylists1.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
25 | def concat(other: {f} LazyList[A]): {this} LazyList[A] = ??? : ({xs, f} LazyList[A]) // error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Found: {xs, f} LazyList[A]
| Required: {Mapped.this} LazyList[A]
| Required: {Mapped.this, xs} LazyList[A]

longer explanation available when compiling with `-explain`
1 change: 1 addition & 0 deletions tests/pos-custom-args/captures/lazylists.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ extension [A](xs: {*} LazyList[A])
def isEmpty = false
def head: B = f(xs.head)
def tail: {this} LazyList[B] = xs.tail.map(f) // OK
def concat(other: {f} LazyList[A]): {this, f} LazyList[A] = ??? : ({xs, f} LazyList[A]) // OK
new Mapped

def test(cap1: Cap, cap2: Cap) =
Expand Down

0 comments on commit c568038

Please sign in to comment.