Skip to content

Commit

Permalink
Ignore capture sets in certain cases of subtyping
Browse files Browse the repository at this point in the history
  • Loading branch information
bracevac committed Dec 10, 2024
1 parent ee0dd7a commit 4c76323
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 8 deletions.
15 changes: 12 additions & 3 deletions compiler/src/dotty/tools/dotc/core/TypeComparer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
res

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

val None: Repr = 0
private val LoApprox = 1
private val HiApprox = 2
private val LoIgnoreCaptures = 4

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

object Repr:
extension (approx: Repr)
def low: Boolean = (approx & LoApprox) != 0
def high: Boolean = (approx & HiApprox) != 0
def lowIgnoreCaptures: Boolean = (approx & LoIgnoreCaptures) != 0
def addLow: Repr = approx | LoApprox
def addHigh: Repr = approx | HiApprox
def addLowIgnoreCaptures: Repr = approx | LoIgnoreCaptures
def show: String =
val lo = if low then " (left is approximated)" else ""
val hi = if high then " (right is approximated)" else ""
lo ++ hi
val locapt = if lowIgnoreCaptures then " (left captures are ignored)" else ""
lo ++ hi ++ locapt
end ApproxState
type ApproxState = ApproxState.Repr

Expand Down
6 changes: 1 addition & 5 deletions tests/pos-custom-args/captures/cc-poly-varargs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,4 @@ def either[T1, T2, Cap^](
src2: Source[T2, Cap]^{Cap^}): Source[Either[T1, T2], Cap]^{Cap^} =
val left = src1.transformValuesWith(Left(_))
val right = src2.transformValuesWith(Right(_))
race[Either[T1, T2], Cap](left, right)
// Explicit type arguments are required here because the second argument
// is inferred as `CapSet^{Cap^}` instead of `Cap`.
// Although `CapSet^{Cap^}` subsumes `Cap` in terms of capture sets,
// `Cap` is not a subtype of `CapSet^{Cap^}` in terms of subtyping.
race(left, right)

0 comments on commit 4c76323

Please sign in to comment.