Skip to content

Commit 78e5fa4

Browse files
committed
Avoi intersections in typing selections and applications
Use either the qualifier type or the result type depending on a pre-check using a new method `mightSubcapture`.
1 parent ef00273 commit 78e5fa4

File tree

2 files changed

+19
-11
lines changed

2 files changed

+19
-11
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ sealed abstract class CaptureSet extends Showable:
111111
/** {x} <:< this where <:< is subcapturing, but treating all variables
112112
* as frozen.
113113
*/
114-
def accountsFor(x: CaptureRef)(using ctx: Context): Boolean =
114+
def accountsFor(x: CaptureRef)(using Context): Boolean =
115115
reporting.trace(i"$this accountsFor $x, ${x.captureSetOfInfo}?", show = true) {
116116
elems.exists(_.subsumes(x))
117117
|| !x.isRootCapability && x.captureSetOfInfo.subCaptures(this, frozen = true).isOK
@@ -122,12 +122,19 @@ sealed abstract class CaptureSet extends Showable:
122122
* for `x` in a state where we assume all supersets of `x` have just the elements
123123
* known at this point.
124124
*/
125-
def mightAccountFor(x: CaptureRef)(using ctx: Context): Boolean =
125+
def mightAccountFor(x: CaptureRef)(using Context): Boolean =
126126
reporting.trace(i"$this mightAccountFor $x, ${x.captureSetOfInfo}?", show = true) {
127127
elems.exists(_.subsumes(x))
128128
|| !x.isRootCapability && x.captureSetOfInfo.elems.forall(mightAccountFor)
129129
}
130130

131+
/** A more optimistic version of subCaptures used to choose one of two typing rules
132+
* for selctions and applications. `cs1 mightSubcapture cs2` if `cs2` might account for
133+
* every element currently known to be in `cs1`.
134+
*/
135+
def mightSubcapture(that: CaptureSet)(using Context): Boolean =
136+
elems.forall(that.mightAccountFor)
137+
131138
/** The subcapturing test */
132139
final def subCaptures(that: CaptureSet, frozen: Boolean)(using Context): CompareResult =
133140
subCaptures(that)(using ctx, if frozen then FrozenState else VarState())

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,10 @@ class CheckCaptures extends Recheck, SymTransformer:
246246
else
247247
val qualCs = qualType.captureSet
248248
//println(i"intersect $qualType, ${selType.widen}, $qualCs, $selCs")
249-
if selCs.subCaptures(qualCs, frozen = true).isOK then selType
250-
else selType.widen.stripCapturing.capturing(selCs ** qualCs)
249+
if qualCs.mightSubcapture(selCs) then
250+
selType.widen.stripCapturing.capturing(qualCs)
251+
else
252+
selType
251253
}//.showing(i"recheck sel $tree, $qualType = $result")
252254

253255
override def recheckClosure(tree: Closure, pt: Type)(using Context): Type =
@@ -412,13 +414,12 @@ class CheckCaptures extends Recheck, SymTransformer:
412414
case tp @ CapturingType(tp1, refs) =>
413415
tree.fun match
414416
case Select(qual, nme.apply)
415-
if defn.isFunctionType(qual.tpe.widen) =>
416-
qual.tpe match
417-
case ref: CaptureRef
418-
if ref.isTracked && tree.args.forall(_.tpe.captureSet.isAlwaysEmpty) =>
419-
tp.derivedCapturingType(tp1, refs ** ref.singletonCaptureSet)
420-
.showing(i"narrow $tree: $tp --> $result", capt)
421-
case _ => tp
417+
if defn.isFunctionType(qual.tpe.widen)
418+
&& tree.args.forall(_.tpe.captureSet.isAlwaysEmpty)
419+
&& qual.tpe.captureSet.mightSubcapture(refs)
420+
=>
421+
tp.derivedCapturingType(tp1, qual.tpe.captureSet)
422+
.showing(i"narrow $tree: $tp --> $result", capt)
422423
case _ => tp
423424
case tp => tp
424425

0 commit comments

Comments
 (0)