Skip to content

Commit 7d8b439

Browse files
committed
Ignore capture sets in certain cases of subtyping
1 parent d50973b commit 7d8b439

File tree

2 files changed

+13
-8
lines changed

2 files changed

+13
-8
lines changed

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
543543
res
544544

545545
case tp1 @ CapturingType(parent1, refs1) =>
546+
if (approx.lowIgnoreCaptures) then return recur(parent1, tp2)
546547
def compareCapturing =
547548
if tp2.isAny then true
548549
else if subCaptures(refs1, tp2.captureSet, frozenConstraint).isOK && sameBoxed(tp1, tp2, refs1)
@@ -936,7 +937,10 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
936937
|| tp1.widen.underlyingClassRef(refinementOK = true).exists)
937938
then
938939
def checkBase =
939-
isSubType(base, tp2, if tp1.isRef(cls2) then approx else approx.addLow)
940+
var a = approx
941+
if (!tp1.isRef(cls2)) then a = a.addLow
942+
if (cls2 eq defn.Caps_CapSet) then a = a.addLowIgnoreCaptures //TODO is this the correct place to add this?
943+
isSubType(base, tp2, a)
940944
&& recordGadtUsageIf { MatchType.thatReducesUsingGadt(tp1) }
941945
if tp1.widenDealias.isInstanceOf[AndType] || base.isInstanceOf[OrType] then
942946
// If tp1 is a intersection, it could be that one of the original
@@ -3325,30 +3329,35 @@ object TypeComparer {
33253329
* - `None` : They are still the same types
33263330
* - `LoApprox`: The left type is approximated (i.e widened)"
33273331
* - `HiApprox`: The right type is approximated (i.e narrowed)"
3332+
* - `LoIgnoreCaptures`: (Capture checking): The captures of the left type are ignored in the comparison
33283333
*/
33293334
object ApproxState:
33303335
opaque type Repr = Int
33313336

33323337
val None: Repr = 0
33333338
private val LoApprox = 1
33343339
private val HiApprox = 2
3340+
private val LoIgnoreCaptures = 4
33353341

33363342
/** A special approximation state to indicate that this is the first time we
33373343
* compare (approximations of) this pair of types. It's converted to `None`
33383344
* in `isSubType`, but also leads to `leftRoot` being set there.
33393345
*/
3340-
val Fresh: Repr = 4
3346+
val Fresh: Repr = 8
33413347

33423348
object Repr:
33433349
extension (approx: Repr)
33443350
def low: Boolean = (approx & LoApprox) != 0
33453351
def high: Boolean = (approx & HiApprox) != 0
3352+
def lowIgnoreCaptures: Boolean = (approx & LoIgnoreCaptures) != 0
33463353
def addLow: Repr = approx | LoApprox
33473354
def addHigh: Repr = approx | HiApprox
3355+
def addLowIgnoreCaptures: Repr = approx | LoIgnoreCaptures
33483356
def show: String =
33493357
val lo = if low then " (left is approximated)" else ""
33503358
val hi = if high then " (right is approximated)" else ""
3351-
lo ++ hi
3359+
val locapt = if lowIgnoreCaptures then " (left captures are ignored)" else ""
3360+
lo ++ hi ++ locapt
33523361
end ApproxState
33533362
type ApproxState = ApproxState.Repr
33543363

tests/pos-custom-args/captures/cc-poly-varargs.scala

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,4 @@ def either[T1, T2, Cap^](
1212
src2: Source[T2, Cap]^{Cap^}): Source[Either[T1, T2], Cap]^{Cap^} =
1313
val left = src1.transformValuesWith(Left(_))
1414
val right = src2.transformValuesWith(Right(_))
15-
race[Either[T1, T2], Cap](left, right)
16-
// Explicit type arguments are required here because the second argument
17-
// is inferred as `CapSet^{Cap^}` instead of `Cap`.
18-
// Although `CapSet^{Cap^}` subsumes `Cap` in terms of capture sets,
19-
// `Cap` is not a subtype of `CapSet^{Cap^}` in terms of subtyping.
15+
race(left, right)

0 commit comments

Comments
 (0)