Skip to content

Commit 4e84ac4

Browse files
committed
Align handling of covariant capturesets with description
Still missing: - going to .super for other variables - maybe capabilities
1 parent 070b877 commit 4e84ac4

File tree

3 files changed

+9
-20
lines changed

3 files changed

+9
-20
lines changed

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

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -701,24 +701,17 @@ object CaptureSet:
701701
if mapped.isConst then CompareResult.OK
702702
else if mapped.asVar.recordDepsState() then { addAsDependentTo(mapped); CompareResult.OK }
703703
else CompareResult.Fail(this :: Nil)
704-
else if !isFixpoint then
705-
// We did not yet observe the !isFixpoint condition in our tests, but it's a
706-
// theoretical possibility. In that case, it would be inconsistent to both
707-
// add `elem` to the set and back-propagate it. But if `{elem} <:< tm(elem)`
708-
// and the variance of the set is positive, we can soundly add `tm(ref)` to
709-
// the set while back-propagating `ref` as before. Otherwise there's nothing
710-
// obvious left to do except fail (which is always sound).
711-
if variance > 0
712-
&& elem.singletonCaptureSet.subCaptures(mapped, frozen = true).isOK then
713-
// widen to fixpoint. mapped is known to be a fixpoint since tm is idempotent.
714-
// The widening is sound, but loses completeness.
715-
addMapped
716-
else
717-
failNoFixpoint
718704
else if accountsFor(elem) then
719705
CompareResult.OK
720-
else
706+
else if variance > 0 then
707+
// we can soundly add nothing to source and `x` to this set
708+
addNewElem(elem)
709+
else if isFixpoint then
710+
// We can soundly add `x` to both this set and source since `f(x) = x`
721711
addNewElem(elem).andAlso(propagate)
712+
else
713+
// we are out of options; fail (which is always sound).
714+
failNoFixpoint
722715
end tryInclude
723716

724717
override def computeApprox(origin: CaptureSet)(using Context): CaptureSet =

tests/neg-custom-args/captures/usingLogFile.check

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,3 @@
1010
44 | val later = usingFile("out", f => (y: Int) => xs.foreach(x => f.write(x + y))) // error
1111
| ^^^^^^^^^
1212
| local reference f leaks into outer capture set of type parameter T of method usingFile
13-
-- Error: tests/neg-custom-args/captures/usingLogFile.scala:52:16 ------------------------------------------------------
14-
52 | val later = usingFile("logfile", // error !!! but should be ok, since we can widen `l` to `file` instead of to `cap`
15-
| ^^^^^^^^^
16-
| local reference l leaks into outer capture set of type parameter T of method usingFile

tests/neg-custom-args/captures/usingLogFile.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,6 @@ object Test3:
4949
op(logger)
5050

5151
def test =
52-
val later = usingFile("logfile", // error !!! but should be ok, since we can widen `l` to `file` instead of to `cap`
52+
val later = usingFile("logfile", // now ok
5353
usingLogger(_, l => () => l.log("test")))
5454
later()

0 commit comments

Comments
 (0)