Skip to content

Commit d674405

Browse files
committed
Drop healTypeParam
Replace healing by assertions that these cases cannot happen anymore.
1 parent 99f5628 commit d674405

File tree

2 files changed

+22
-56
lines changed

2 files changed

+22
-56
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ object ccConfig:
5959
*/
6060
inline val alwaysRepeatRun = false
6161

62+
/** After capture checking, check that no capture set contains ParamRefs that are outside
63+
* its scope. This used to occur and was fixed by healTypeParam. It should no longer
64+
* occur now.
65+
*/
66+
inline val postCheckCapturesets = false
67+
6268
/** If true, turn on separation checking */
6369
def useSepChecks(using Context): Boolean =
6470
Feature.sourceVersion.stable.isAtLeast(SourceVersion.`3.7`)

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

Lines changed: 16 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,65 +1807,26 @@ class CheckCaptures extends Recheck, SymTransformer:
18071807
capt.println(i"checked $root with $selfType")
18081808
end checkSelfTypes
18091809

1810-
/** Heal ill-formed capture sets in the type parameter.
1811-
*
1812-
* We can push parameter refs into a capture set in type parameters
1813-
* that this type parameter can't see.
1814-
* For example, when capture checking the following expression:
1815-
*
1816-
* def usingLogFile[T](op: File^ => T): T = ...
1817-
*
1818-
* usingLogFile[box ?1 () -> Unit] { (f: File^) => () => { f.write(0) } }
1819-
*
1820-
* We may propagate `f` into ?1, making ?1 ill-formed.
1821-
* This also causes soundness issues, since `f` in ?1 should be widened to `cap`,
1822-
* giving rise to an error that `cap` cannot be included in a boxed capture set.
1823-
*
1824-
* To solve this, we still allow ?1 to capture parameter refs like `f`, but
1825-
* compensate this by pushing the widened capture set of `f` into ?1.
1826-
* This solves the soundness issue caused by the ill-formness of ?1.
1810+
/** Check ill-formed capture sets in a type parameter. We used to be able to
1811+
* push parameter refs into a capture set in type parameters that this type
1812+
* parameter can't see. We used to heal this by replacing illegal refs by their
1813+
* underlying capture sets. But now these should no longer be necessary, so
1814+
* instead of errors we use assertions.
18271815
*/
1828-
private def healTypeParam(tree: Tree, paramName: TypeName, meth: Symbol)(using Context): Unit =
1816+
private def checkTypeParam(tree: Tree, paramName: TypeName, meth: Symbol)(using Context): Unit =
18291817
val checker = new TypeTraverser:
18301818
private var allowed: SimpleIdentitySet[TermParamRef] = SimpleIdentitySet.empty
18311819

1832-
private def isAllowed(ref: CaptureRef): Boolean = ref match
1833-
case ref: TermParamRef => allowed.contains(ref)
1834-
case _ => true
1835-
1836-
private def healCaptureSet(cs: CaptureSet): Unit =
1837-
cs.ensureWellformed: elem =>
1838-
ctx ?=>
1839-
var seen = new util.HashSet[CaptureRef]
1840-
def recur(ref: CaptureRef): Unit = ref.stripReach match
1841-
case ref: TermParamRef
1842-
if !allowed.contains(ref) && !seen.contains(ref) =>
1843-
seen += ref
1844-
if ref.isRootCapability then
1845-
report.error(i"escaping local reference $ref", tree.srcPos)
1846-
else
1847-
val widened = ref.captureSetOfInfo
1848-
val added = widened.filter(isAllowed(_))
1849-
capt.println(i"heal $ref in $cs by widening to $added")
1850-
if !added.subCaptures(cs).isOK then
1851-
val location = if meth.exists then i" of ${meth.showLocated}" else ""
1852-
val paramInfo =
1853-
if ref.paramName.info.kind.isInstanceOf[UniqueNameKind]
1854-
then i"${ref.paramName} from ${ref.binder}"
1855-
else i"${ref.paramName}"
1856-
val debugSetInfo = if ctx.settings.YccDebug.value then i" $cs" else ""
1857-
report.error(
1858-
i"local reference $paramInfo leaks into outer capture set$debugSetInfo of type parameter $paramName$location",
1859-
tree.srcPos)
1860-
else
1861-
widened.elems.foreach(recur)
1862-
case _ =>
1863-
recur(elem)
1820+
private def checkCaptureSet(cs: CaptureSet): Unit =
1821+
for elem <- cs.elems do
1822+
elem.stripReach match
1823+
case ref: TermParamRef => assert(allowed.contains(ref))
1824+
case _ =>
18641825

18651826
def traverse(tp: Type) =
18661827
tp match
18671828
case CapturingType(parent, refs) =>
1868-
healCaptureSet(refs)
1829+
checkCaptureSet(refs)
18691830
traverse(parent)
18701831
case defn.RefinedFunctionOf(rinfo: MethodType) =>
18711832
traverse(rinfo)
@@ -1880,7 +1841,7 @@ class CheckCaptures extends Recheck, SymTransformer:
18801841

18811842
if tree.isInstanceOf[InferredTypeTree] then
18821843
checker.traverse(tree.nuType)
1883-
end healTypeParam
1844+
end checkTypeParam
18841845

18851846
/** Under the unsealed policy: Arrays are like vars, check that their element types
18861847
* do not contains `cap` (in fact it would work also to check on array creation
@@ -1904,9 +1865,7 @@ class CheckCaptures extends Recheck, SymTransformer:
19041865
traverseChildren(t)
19051866
check.traverse(tp)
19061867

1907-
/** Perform the following kinds of checks
1908-
* - Check that arguments of TypeApplys and AppliedTypes conform to their bounds.
1909-
* - Heal ill-formed capture sets of type parameters. See `healTypeParam`.
1868+
/** Check that arguments of TypeApplys and AppliedTypes conform to their bounds.
19101869
*/
19111870
def postCheck(unit: tpd.Tree)(using Context): Unit =
19121871
val checker = new TreeTraverser:
@@ -1926,7 +1885,8 @@ class CheckCaptures extends Recheck, SymTransformer:
19261885
bounds.hi.isBoxedCapturing | bounds.lo.isBoxedCapturing))
19271886
CCState.withCapAsRoot: // OK? We need this since bounds use `cap` instead of `fresh`
19281887
checkBounds(normArgs, tl)
1929-
args.lazyZip(tl.paramNames).foreach(healTypeParam(_, _, fun.symbol))
1888+
if ccConfig.postCheckCapturesets then
1889+
args.lazyZip(tl.paramNames).foreach(checkTypeParam(_, _, fun.symbol))
19301890
case _ =>
19311891
case _ =>
19321892
end check

0 commit comments

Comments
 (0)