Skip to content

Commit 82fbf1a

Browse files
committed
Map capture set to read-only when comparing mutable with non-mutable
1 parent 488bf4b commit 82fbf1a

File tree

1 file changed

+18
-11
lines changed

1 file changed

+18
-11
lines changed

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
546546
case tp1 @ CapturingType(parent1, refs1) =>
547547
def compareCapturing =
548548
if tp2.isAny then true
549-
else if subCaptures(refs1, tp2.captureSet) && sameBoxed(tp1, tp2, refs1)
549+
else if compareCaptures(tp1, refs1, tp2, tp2.captureSet)
550550
|| !ctx.mode.is(Mode.CheckBoundsOrSelfType) && tp1.isAlwaysPure
551551
then
552552
val tp2a =
@@ -673,12 +673,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
673673
&& isSubInfo(info1.resultType, info2.resultType.subst(info2, info1))
674674
case (info1 @ CapturingType(parent1, refs1), info2: Type)
675675
if info2.stripCapturing.isInstanceOf[MethodOrPoly] =>
676-
subCaptures(refs1, info2.captureSet) && sameBoxed(info1, info2, refs1)
676+
compareCaptures(info1, refs1, info2, info2.captureSet)
677677
&& isSubInfo(parent1, info2)
678678
case (info1: Type, CapturingType(parent2, refs2))
679679
if info1.stripCapturing.isInstanceOf[MethodOrPoly] =>
680680
val refs1 = info1.captureSet
681-
(refs1.isAlwaysEmpty || subCaptures(refs1, refs2)) && sameBoxed(info1, info2, refs1)
681+
(refs1.isAlwaysEmpty || compareCaptures(info1, refs1, info2, refs2))
682682
&& isSubInfo(info1, parent2)
683683
case _ =>
684684
isSubType(info1, info2)
@@ -877,8 +877,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
877877
case _ =>
878878
false
879879
singletonOK
880-
|| subCaptures(refs1, refs2)
881-
&& sameBoxed(tp1, tp2, refs1)
880+
|| compareCaptures(tp1, refs1, tp2, refs2)
882881
&& (recur(tp1.widen.stripCapturing, parent2)
883882
|| tp1.isInstanceOf[SingletonType] && recur(tp1, parent2)
884883
// this alternative is needed in case the right hand side is a
@@ -2891,13 +2890,21 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
28912890
println(i"fail while subCaptures $refs1 <:< $refs2")
28922891
throw ex
28932892

2894-
/** Is the boxing status of tp1 and tp2 the same, or alternatively, is
2895-
* the capture sets `refs1` of `tp1` a subcapture of the empty set?
2896-
* In the latter case, boxing status does not matter.
2893+
/**
2894+
* - Compare capture sets using subCaptures. If the lower type derives from Mutable and the
2895+
* upper type does not, make the lower set read-only.
2896+
* - Test whether the boxing status of tp1 and tp2 the same, or alternatively,
2897+
* whether the capture set `refs1` of `tp1` is subcapture of the empty set?
2898+
* In the latter case, boxing status does not matter.
28972899
*/
2898-
protected def sameBoxed(tp1: Type, tp2: Type, refs1: CaptureSet)(using Context): Boolean =
2899-
(tp1.isBoxedCapturing == tp2.isBoxedCapturing)
2900-
|| refs1.subCaptures(CaptureSet.empty, makeVarState())
2900+
protected def compareCaptures(tp1: Type, refs1: CaptureSet, tp2: Type, refs2: CaptureSet): Boolean =
2901+
val refs1Adapted =
2902+
if tp1.derivesFromMutable && !tp2.derivesFromMutable
2903+
then refs1.readOnly
2904+
else refs1
2905+
subCaptures(refs1Adapted, refs2)
2906+
&& (tp1.isBoxedCapturing == tp2.isBoxedCapturing)
2907+
|| refs1.subCaptures(CaptureSet.empty, makeVarState())
29012908

29022909
protected def logUndoAction(action: () => Unit) =
29032910
undoLog += action

0 commit comments

Comments
 (0)