Skip to content

Commit 2724ac7

Browse files
committed
Generalize new rule for applications
Allow impure arguments
1 parent 78e5fa4 commit 2724ac7

File tree

1 file changed

+21
-12
lines changed

1 file changed

+21
-12
lines changed

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

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,16 @@ class CheckCaptures extends Recheck, SymTransformer:
238238
else i"references $cs1 are not all"
239239
report.error(i"$header included in allowed capture set ${res.blocking}", pos)
240240

241+
/** A specialized implementation of the selection rule.
242+
*
243+
* E |- f: Cf { m: Cr R }
244+
* ------------------------
245+
* E |- f.m: C R
246+
*
247+
* The implementation picks as `C` one of `{f}` or `Cr`, depending on the
248+
* outcome of a `mightSubcapture` test. It picks `{f}` if this might subcapture Cr
249+
* and Cr otherwise.
250+
*/
241251
override def recheckSelection(tree: Select, qualType: Type, name: Name)(using Context) = {
242252
val selType = super.recheckSelection(tree, qualType, name)
243253
val selCs = selType.widen.captureSet
@@ -395,18 +405,16 @@ class CheckCaptures extends Recheck, SymTransformer:
395405
finally curEnv = curEnv.outer
396406
recheckFinish(result, arg, pt)
397407

398-
/** A specialized implementation of the apply rule from https://github.com/lampepfl/dotty/discussions/14387:
408+
/** A specialized implementation of the apply rule.
399409
*
400-
* E |- f: Cf (Ra -> Cr Rr)
401-
* E |- a: Ra
402-
* ------------------------
403-
* E |- f a: Cr /\ {f} Rr
410+
* E |- f: Cf (Ra -> Cr Rr)
411+
* E |- a: Ra
412+
* ------------------------
413+
* E |- f a: C Rr
404414
*
405-
* Specialized for the case where `f` is a tracked and the arguments are pure.
406-
* This replaces the previous rule #13657 while still allowing the code in pos/lazylists1.scala.
407-
* We could consider generalizing to the case where the function arguments have non-empty
408-
* capture sets as suggested in #14387, but that would make capture set computations more complex,
409-
* so we should also evaluate the performance impact.
415+
* The implementation picks as `C` one of `{f, a}` or `Cr`, depending on the
416+
* outcome of a `mightSubcapture` test. It picks `{f, a}` if this might subcapture Cr
417+
* and Cr otherwise.
410418
*/
411419
override def recheckApply(tree: Apply, pt: Type)(using Context): Type =
412420
includeCallCaptures(tree.symbol, tree.srcPos)
@@ -415,10 +423,11 @@ class CheckCaptures extends Recheck, SymTransformer:
415423
tree.fun match
416424
case Select(qual, nme.apply)
417425
if defn.isFunctionType(qual.tpe.widen)
418-
&& tree.args.forall(_.tpe.captureSet.isAlwaysEmpty)
419426
&& qual.tpe.captureSet.mightSubcapture(refs)
427+
&& tree.args.forall(_.tpe.captureSet.mightSubcapture(refs))
420428
=>
421-
tp.derivedCapturingType(tp1, qual.tpe.captureSet)
429+
tp.derivedCapturingType(tp1, tree.args.foldLeft(qual.tpe.captureSet)((cs, arg) =>
430+
cs ++ arg.tpe.captureSet))
422431
.showing(i"narrow $tree: $tp --> $result", capt)
423432
case _ => tp
424433
case tp => tp

0 commit comments

Comments
 (0)