Skip to content

Commit f61fe69

Browse files
committed
Allow this to subsume this.f if f is a use parameter
1 parent 23ff23d commit f61fe69

File tree

2 files changed

+37
-19
lines changed

2 files changed

+37
-19
lines changed

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

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -473,27 +473,28 @@ object Capabilities:
473473
case info: OrType => viaInfo(info.tp1)(test) && viaInfo(info.tp2)(test)
474474
case _ => false
475475

476+
def trySubpath(y: TermRef): Boolean =
477+
y.prefix.match
478+
case ypre: Capability =>
479+
this.subsumes(ypre)
480+
|| this.match
481+
case x @ TermRef(xpre: Capability, _) if x.symbol == y.symbol =>
482+
// To show `{x.f} <:< {y.f}`, it is important to prove `x` and `y`
483+
// are equvalent, which means `x =:= y` in terms of subtyping,
484+
// not just `{x} =:= {y}` in terms of subcapturing.
485+
// It is possible to construct two singleton types `x` and `y`,
486+
// which subsume each other, but are not equal references.
487+
// See `tests/neg-custom-args/captures/path-prefix.scala` for example.
488+
withMode(Mode.IgnoreCaptures):
489+
TypeComparer.isSameRef(xpre, ypre)
490+
case _ =>
491+
false
492+
case _ => false
493+
476494
try (this eq y)
477495
|| maxSubsumes(y, canAddHidden = !vs.isOpen)
478496
|| y.match
479-
case y: TermRef =>
480-
y.prefix.match
481-
case ypre: Capability =>
482-
this.subsumes(ypre)
483-
|| this.match
484-
case x @ TermRef(xpre: Capability, _) if x.symbol == y.symbol =>
485-
// To show `{x.f} <:< {y.f}`, it is important to prove `x` and `y`
486-
// are equvalent, which means `x =:= y` in terms of subtyping,
487-
// not just `{x} =:= {y}` in terms of subcapturing.
488-
// It is possible to construct two singleton types `x` and `y`,
489-
// which subsume each other, but are not equal references.
490-
// See `tests/neg-custom-args/captures/path-prefix.scala` for example.
491-
withMode(Mode.IgnoreCaptures):
492-
TypeComparer.isSameRef(xpre, ypre)
493-
case _ =>
494-
false
495-
case _ => false
496-
|| viaInfo(y.info)(subsumingRefs(this, _))
497+
case y: TermRef => trySubpath(y) || viaInfo(y.info)(subsumingRefs(this, _))
497498
case Maybe(y1) => this.stripMaybe.subsumes(y1)
498499
case ReadOnly(y1) => this.stripReadOnly.subsumes(y1)
499500
case y: TypeRef if y.derivesFrom(defn.Caps_CapSet) =>
@@ -507,6 +508,15 @@ object Capabilities:
507508
this.subsumes(hi)
508509
case _ =>
509510
y.captureSetOfInfo.elems.forall(this.subsumes)
511+
case Reach(y1: TermRef) =>
512+
val sym = y1.symbol
513+
def isUseClassParam: Boolean =
514+
sym.owner match
515+
case classSym: ClassSymbol =>
516+
val paramSym = classSym.primaryConstructor.paramNamed(sym.name)
517+
paramSym.isUseParam
518+
case _ => false
519+
isUseClassParam && trySubpath(y1)
510520
case _ => false
511521
|| this.match
512522
case Reach(x1) => x1.subsumes(y.stripReach)
@@ -858,4 +868,4 @@ object Capabilities:
858868
case tp1 => tp1
859869
end toResultInResults
860870

861-
end Capabilities
871+
end Capabilities
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import language.experimental.captureChecking
2+
import caps.*
3+
trait Runner:
4+
def run: () ->{this} Unit
5+
class Runner1(f: List[() => Unit]) extends Runner:
6+
def run: () ->{f*} Unit = f.head // error
7+
class Runner2(@use f: List[() => Unit]) extends Runner:
8+
def run: () ->{f*} Unit = f.head // ok

0 commit comments

Comments
 (0)