Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore capture sets in certain cases of subtyping #22183

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Member

@noti0na1 noti0na1 Dec 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extension methods above can be tested as well. I remember they have similar issues.

// 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)
Loading