Skip to content

Commit d37a605

Browse files
committed
Allow to instantiate cap in checkConformsExpr
When testing whether `A <: B`, it could be that `B` uses a local capture root, but a uses `cap`, i.e. is capture polymorphic. In this case, adaptation is allowed to instantiate `A` to match the root in `B`.
1 parent d5be8db commit d37a605

File tree

2 files changed

+25
-10
lines changed

2 files changed

+25
-10
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,20 @@ class CheckCaptures extends Recheck, SymTransformer:
757757
// accessible through those types (c.f. addOuterRefs, also #14930 for a discussion).
758758
// - Adapt box status and environment capture sets by simulating box/unbox operations.
759759

760+
override def isCompatible(actual: Type, expected: Type, tree: Tree)(using Context): Boolean =
761+
super.isCompatible(actual, expected, tree)
762+
|| {
763+
val mapr = mapRoots(defn.captureRoot.termRef, CaptureRoot.Var(ctx.owner.levelOwner))
764+
val actual1 = mapr(actual)
765+
(actual1 ne actual) && {
766+
val res = super.isCompatible(actual1, expected, tree)
767+
if !res && ctx.settings.YccDebug.value then
768+
println(i"Failure under mapped roots:")
769+
println(i"${TypeComparer.explained(_.isSubType(actual, expected))}")
770+
res
771+
}
772+
}
773+
760774
/** Massage `actual` and `expected` types using the methods below before checking conformance */
761775
override def checkConformsExpr(actual: Type, expected: Type, tree: Tree, addenda: Addenda)(using Context): Unit =
762776
val expected1 = alignDependentFunction(addOuterRefs(expected, actual), actual.stripCapturing)

compiler/src/dotty/tools/dotc/transform/Recheck.scala

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -567,18 +567,19 @@ abstract class Recheck extends Phase, SymTransformer:
567567
case _ =>
568568
checkConformsExpr(tpe.widenExpr, pt.widenExpr, tree)
569569

570+
def isCompatible(actual: Type, expected: Type)(using Context): Boolean =
571+
actual <:< expected
572+
|| expected.isRepeatedParam
573+
&& isCompatible(actual,
574+
expected.translateFromRepeated(toArray = actual.isRef(defn.ArrayClass)))
575+
|| {
576+
val widened = widenSkolems(expected)
577+
(widened ne expected) && isCompatible(actual, widened)
578+
}
579+
570580
def checkConformsExpr(actual: Type, expected: Type, tree: Tree, addenda: Addenda = NothingToAdd)(using Context): Unit =
571581
//println(i"check conforms $actual <:< $expected")
572-
573-
def isCompatible(expected: Type): Boolean =
574-
actual <:< expected
575-
|| expected.isRepeatedParam
576-
&& isCompatible(expected.translateFromRepeated(toArray = tree.tpe.isRef(defn.ArrayClass)))
577-
|| {
578-
val widened = widenSkolems(expected)
579-
(widened ne expected) && isCompatible(widened)
580-
}
581-
if !isCompatible(expected) then
582+
if !isCompatible(actual, expected) then
582583
recheckr.println(i"conforms failed for ${tree}: $actual vs $expected")
583584
err.typeMismatch(tree.withType(actual), expected, addenda)
584585
else if debugSuccesses then

0 commit comments

Comments
 (0)