Skip to content

Commit 5dacf52

Browse files
committed
Fix subCapture in frozen state
Previously, we still OKed two empty variables to be compared with subcapture in the frozen state. This should give an error.
1 parent f6ff1fc commit 5dacf52

File tree

2 files changed

+45
-24
lines changed

2 files changed

+45
-24
lines changed

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

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Types.*, Symbols.*, Flags.*, Contexts.*, Decorators.*
77
import config.Printers.capt
88
import Annotations.Annotation
99
import annotation.threadUnsafe
10+
import annotation.constructorOnly
1011
import annotation.internal.sharable
1112
import reporting.trace
1213
import printing.{Showable, Printer}
@@ -58,11 +59,11 @@ sealed abstract class CaptureSet extends Showable:
5859
protected def addNewElems(newElems: Refs, origin: CaptureSet)(using Context, VarState): CompareResult
5960

6061
/** If this is a variable, add `cs` as a super set */
61-
protected def addSuper(cs: CaptureSet): this.type
62+
protected def addSuper(cs: CaptureSet)(using Context, VarState): CompareResult
6263

6364
/** If `cs` is a variable, add this capture set as one of its super sets */
64-
protected def addSub(cs: CaptureSet): this.type =
65-
cs.addSuper(this)
65+
protected def addSub(cs: CaptureSet)(using Context): this.type =
66+
cs.addSuper(this)(using ctx, UnrecordedState)
6667
this
6768

6869
/** Try to include all references of `elems` that are not yet accounted by this
@@ -81,18 +82,20 @@ sealed abstract class CaptureSet extends Showable:
8182
def accountsFor(x: CaptureRef)(using Context): Boolean =
8283
reporting.trace(i"$this accountsFor $x, ${x.captureSetOfInfo}?", show = true) {
8384
elems.contains(x)
84-
|| !x.isRootCapability
85-
&& x.captureSetOfInfo.subCaptures(this, frozen = true) == CompareResult.OK
85+
|| !x.isRootCapability && x.captureSetOfInfo.elems.forall(accountsFor)
8686
}
8787

8888
/** The subcapturing test */
89-
def subCaptures(that: CaptureSet, frozen: Boolean)(using Context): CompareResult =
89+
final def subCaptures(that: CaptureSet, frozen: Boolean)(using Context): CompareResult =
9090
subCaptures(that)(using ctx, if frozen then FrozenState else VarState())
9191

9292
private def subCaptures(that: CaptureSet)(using Context, VarState): CompareResult =
9393
val result = that.tryInclude(elems, this)
94-
if result == CompareResult.OK then addSuper(that) else varState.abort()
95-
result
94+
if result == CompareResult.OK then
95+
addSuper(that)
96+
else
97+
varState.abort()
98+
result
9699

97100
def =:= (that: CaptureSet)(using Context): Boolean =
98101
this.subCaptures(that, frozen = true) == CompareResult.OK
@@ -201,7 +204,7 @@ object CaptureSet:
201204
def addNewElems(elems: Refs, origin: CaptureSet)(using Context, VarState): CompareResult =
202205
CompareResult.fail(this)
203206

204-
def addSuper(cs: CaptureSet) = this
207+
def addSuper(cs: CaptureSet)(using Context, VarState) = CompareResult.OK
205208

206209
override def toString = elems.toString
207210
end Const
@@ -244,7 +247,14 @@ object CaptureSet:
244247
else
245248
CompareResult.fail(this)
246249

247-
def addSuper(cs: CaptureSet) = { deps += cs; this }
250+
def addSuper(cs: CaptureSet)(using Context, VarState): CompareResult =
251+
if (cs eq this) || cs.elems.contains(defn.captureRoot.termRef) then
252+
CompareResult.OK
253+
else if recordDepsState() then
254+
deps += cs
255+
CompareResult.OK
256+
else
257+
CompareResult.fail(this)
248258

249259
override def toString = s"Var$id$elems"
250260
end Var
@@ -254,7 +264,7 @@ object CaptureSet:
254264
*/
255265
class Mapped private[CaptureSet] (
256266
cv: Var, tm: TypeMap, variance: Int, initial: CaptureSet
257-
) extends Var(initial.elems):
267+
)(using @constructorOnly ctx: Context) extends Var(initial.elems):
258268
addSub(cv)
259269
addSub(initial)
260270
val stack = if debugSets then (new Throwable).getStackTrace().take(20) else null
@@ -271,21 +281,21 @@ object CaptureSet:
271281
mapRefs(newElems, tm, variance)
272282
else
273283
if variance <= 0 && !origin.isConst && (origin ne initial) then
274-
report.error(i"trying to add elems $newElems to $this from unrecognized source of mapped set $this$whereCreated")
284+
report.warning(i"trying to add elems $newElems to $this from unrecognized source of mapped set $this$whereCreated")
275285
Const(newElems)
276286
val result = super.addNewElems(added.elems, origin)
277287
if result == CompareResult.OK then
278288
added match
279289
case added: Var =>
280-
added.recordDepsState()
281-
addSub(added)
290+
if added.recordDepsState() then addSub(added)
291+
else CompareResult.fail(this)
282292
case _ =>
283293
result
284294

285295
override def toString = s"Mapped$id($cv, elems = $elems)"
286296
end Mapped
287297

288-
class BiMapped private[CaptureSet] (cv: Var, bimap: BiTypeMap, initialElems: Refs) extends Var(initialElems):
298+
class BiMapped private[CaptureSet] (cv: Var, bimap: BiTypeMap, initialElems: Refs)(using @constructorOnly ctx: Context) extends Var(initialElems):
289299
addSub(cv)
290300

291301
override def addNewElems(newElems: Refs, origin: CaptureSet)(using Context, VarState): CompareResult =
@@ -302,7 +312,7 @@ object CaptureSet:
302312
end BiMapped
303313

304314
/** A variable with elements given at any time as { x <- cv.elems | p(x) } */
305-
class Filtered private[CaptureSet] (cv: Var, p: CaptureRef => Boolean)
315+
class Filtered private[CaptureSet] (cv: Var, p: CaptureRef => Boolean)(using @constructorOnly ctx: Context)
306316
extends Var(cv.elems.filter(p)):
307317
addSub(cv)
308318

@@ -370,6 +380,12 @@ object CaptureSet:
370380
override def putDeps(v: Var, deps: Deps) = false
371381
override def abort(): Unit = ()
372382

383+
@sharable
384+
object UnrecordedState extends VarState:
385+
override def putElems(v: Var, refs: Refs) = true
386+
override def putDeps(v: Var, deps: Deps) = true
387+
override def abort(): Unit = ()
388+
373389
def varState(using state: VarState): VarState = state
374390

375391
def ofClass(cinfo: ClassInfo, argTypes: List[Type])(using Context): CaptureSet =

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -615,14 +615,19 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
615615
case _ =>
616616
isSubType(info1, info2)
617617

618-
tp1 match
619-
case tp1: RefinedType
620-
if ctx.phase == Phases.checkCapturesPhase
621-
&& defn.isFunctionOrPolyType(tp1)
622-
&& defn.isFunctionOrPolyType(tp2) =>
623-
isSubInfo(tp1.refinedInfo, tp2.refinedInfo)
624-
case _ =>
625-
compareRefined
618+
if ctx.phase == Phases.checkCapturesPhase then
619+
if defn.isFunctionType(tp2) then
620+
tp1.widenDealias match
621+
case tp1: RefinedType =>
622+
return isSubInfo(tp1.refinedInfo, tp2.refinedInfo)
623+
case _ =>
624+
else if tp2.parent.typeSymbol == defn.PolyFunctionClass then
625+
tp1.member(nme.apply).info match
626+
case info1: PolyType =>
627+
return isSubInfo(info1, tp2.refinedInfo)
628+
case _ =>
629+
630+
compareRefined
626631
case tp2: RecType =>
627632
def compareRec = tp1.safeDealias match {
628633
case tp1: RecType =>

0 commit comments

Comments
 (0)