Skip to content

Commit 8b33e02

Browse files
committed
New CC scheme: let class subsume function fields deeply
1 parent 606268f commit 8b33e02

File tree

2 files changed

+33
-34
lines changed

2 files changed

+33
-34
lines changed

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

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -482,27 +482,30 @@ object Capabilities:
482482
case info: OrType => viaInfo(info.tp1)(test) && viaInfo(info.tp2)(test)
483483
case _ => false
484484

485+
def trySubpath(y: TermRef, trySamePrefix: Boolean = true): Boolean =
486+
y.prefix.match
487+
case ypre: Capability =>
488+
this.subsumes(ypre)
489+
|| trySamePrefix
490+
&& this.match
491+
case x @ TermRef(xpre: Capability, _) if x.symbol == y.symbol =>
492+
// To show `{x.f} <:< {y.f}`, it is important to prove `x` and `y`
493+
// are equvalent, which means `x =:= y` in terms of subtyping,
494+
// not just `{x} =:= {y}` in terms of subcapturing.
495+
// It is possible to construct two singleton types `x` and `y`,
496+
// which subsume each other, but are not equal references.
497+
// See `tests/neg-custom-args/captures/path-prefix.scala` for example.
498+
withMode(Mode.IgnoreCaptures):
499+
TypeComparer.isSameRef(xpre, ypre)
500+
case _ =>
501+
false
502+
case _ => false
503+
485504
try (this eq y)
486505
|| maxSubsumes(y, canAddHidden = !vs.isOpen)
487506
|| y.match
488507
case y: TermRef =>
489-
y.prefix.match
490-
case ypre: Capability =>
491-
this.subsumes(ypre)
492-
|| this.match
493-
case x @ TermRef(xpre: Capability, _) if x.symbol == y.symbol =>
494-
// To show `{x.f} <:< {y.f}`, it is important to prove `x` and `y`
495-
// are equvalent, which means `x =:= y` in terms of subtyping,
496-
// not just `{x} =:= {y}` in terms of subcapturing.
497-
// It is possible to construct two singleton types `x` and `y`,
498-
// which subsume each other, but are not equal references.
499-
// See `tests/neg-custom-args/captures/path-prefix.scala` for example.
500-
withMode(Mode.IgnoreCaptures):
501-
TypeComparer.isSameRef(xpre, ypre)
502-
case _ =>
503-
false
504-
case _ => false
505-
|| viaInfo(y.info)(subsumingRefs(this, _))
508+
trySubpath(y) || viaInfo(y.info)(subsumingRefs(this, _))
506509
case Maybe(y1) => this.stripMaybe.subsumes(y1)
507510
case ReadOnly(y1) => this.stripReadOnly.subsumes(y1)
508511
case y: TypeRef if y.derivesFrom(defn.Caps_CapSet) =>
@@ -516,6 +519,12 @@ object Capabilities:
516519
this.subsumes(hi)
517520
case _ =>
518521
y.captureSetOfInfo.elems.forall(this.subsumes)
522+
case Reach(y1: TermRef) =>
523+
def isClassFunctionParam: Boolean =
524+
def isClassParam = y1.symbol.is(ParamAccessor)
525+
def isFunctionType = defn.isFunctionType(y1.widenDealias)
526+
isClassParam && isFunctionType
527+
isClassFunctionParam && trySubpath(y1, trySamePrefix = false)
519528
case _ => false
520529
|| this.match
521530
case Reach(x1) => x1.subsumes(y.stripReach)

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

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -766,21 +766,7 @@ class CheckCaptures extends Recheck, SymTransformer:
766766
val appType = resultToFresh(
767767
super.recheckApplication(tree, qualType, funType, argTypes),
768768
Origin.ResultInstance(funType, tree.symbol))
769-
val qualCaptures = qualType.captureSet
770-
val argCaptures =
771-
for (argType, formal) <- argTypes.lazyZip(funType.paramInfos) yield
772-
if formal.hasAnnotation(defn.UseAnnot) then argType.deepCaptureSet else argType.captureSet
773-
appType match
774-
case appType @ CapturingType(appType1, refs)
775-
if qualType.exists
776-
&& !tree.fun.symbol.isConstructor
777-
&& qualCaptures.mightSubcapture(refs)
778-
&& argCaptures.forall(_.mightSubcapture(refs)) =>
779-
val callCaptures = argCaptures.foldLeft(qualCaptures)(_ ++ _)
780-
appType.derivedCapturingType(appType1, callCaptures)
781-
.showing(i"narrow $tree: $appType, refs = $refs, qual-cs = ${qualType.captureSet} = $result", capt)
782-
case appType =>
783-
appType
769+
appType
784770

785771
private def isDistinct(xs: List[Type]): Boolean = xs match
786772
case x :: xs1 => xs1.isEmpty || !xs1.contains(x) && isDistinct(xs1)
@@ -832,8 +818,12 @@ class CheckCaptures extends Recheck, SymTransformer:
832818
for (getterName, argType) <- mt.paramNames.lazyZip(argTypes) do
833819
val getter = cls.info.member(getterName).suchThat(_.isRefiningParamAccessor).symbol
834820
if !getter.is(Private) && getter.hasTrackedParts then
835-
refined = refined.refinedOverride(getterName, argType.unboxed) // Yichen you might want to check this
836-
allCaptures ++= argType.captureSet
821+
refined = refined.refinedOverride(getterName, argType.unboxed) // TODO: This looks unsound.
822+
// Try to find an counter-example.
823+
if defn.isFunctionType(argType.widenDealias) then
824+
allCaptures ++= argType.deepCaptureSet
825+
else
826+
allCaptures ++= argType.captureSet
837827
(refined, allCaptures)
838828

839829
/** Augment result type of constructor with refinements and captures.

0 commit comments

Comments
 (0)