Skip to content

Commit 6908bfc

Browse files
committed
refactor subsumes
1 parent 3edd4a0 commit 6908bfc

File tree

1 file changed

+37
-79
lines changed

1 file changed

+37
-79
lines changed

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

Lines changed: 37 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -155,95 +155,53 @@ final class ProperGadtConstraint private(
155155
* In `subsumes`, we have to recognize the fact that both T(param)$1 and T(param)$2
156156
* represents the same path-dependent type, to give the correct result.
157157
*/
158-
def subsumes(left: GadtConstraint, right: GadtConstraint, pre: GadtConstraint)(using Context): Boolean = {
159-
def checkSubsumes(c1: Constraint, c2: Constraint, pre: Constraint): Boolean = {
160-
if (c2 eq pre) true
161-
else if (c1 eq pre) false
162-
else {
163-
val saved = constraint
164-
165-
def computeNewParams =
166-
val params1 = c1.domainParams.toSet
167-
val params2 = c2.domainParams.toSet
168-
val preParams = pre.domainParams.toSet
169-
/** Type parameter registered after branching */
170-
(params1.diff(preParams), params2.diff(preParams))
171-
172-
val (newParams1, newParams2) = computeNewParams
173-
174-
// When new types are registered after pre, for left to subsume right, it should contain all types
175-
// newly registered in right.
176-
def checkNewParams: Boolean = (left, right) match {
177-
case (left: ProperGadtConstraint, right: ProperGadtConstraint) =>
178-
newParams2 forall { p2 =>
179-
val tp2 = right.externalize(p2)
180-
left.tvarOf(tp2) != null
158+
def subsumes(left: GadtConstraint, right: GadtConstraint, pre: GadtConstraint)(using Context): Boolean =
159+
def checkSubsumes(left: ProperGadtConstraint, right: ProperGadtConstraint, pre: ProperGadtConstraint): Boolean = {
160+
def rightToLeft: TypeParamRef => TypeParamRef = {
161+
val preParams = pre.constraint.domainParams.toSet
162+
val mapping = {
163+
var res: SimpleIdentityMap[TypeParamRef, TypeParamRef] = SimpleIdentityMap.empty
164+
165+
right.constraint.domainParams.foreach { p2 =>
166+
left.tvarOf(right.externalize(p2)) match {
167+
case null =>
168+
case tv: TypeVar =>
169+
res = res.updated(p2, tv.origin)
181170
}
182-
case _ => true
183-
}
184-
185-
checkNewParams && {
186-
// Computes mappings between the newly-registered type params in
187-
// the two branches.
188-
def createMappings = {
189-
var mapping1: SimpleIdentityMap[TypeParamRef, TypeParamRef] = SimpleIdentityMap.empty
190-
var mapping2: SimpleIdentityMap[TypeParamRef, TypeParamRef] = SimpleIdentityMap.empty
191-
192-
(left, right) match {
193-
case (left: ProperGadtConstraint, right: ProperGadtConstraint) =>
194-
newParams1 foreach { p1 =>
195-
val tp1 = left.externalize(p1)
196-
right.tvarOf(tp1) match {
197-
case null =>
198-
case tvar2: TypeVar =>
199-
mapping1 = mapping1.updated(p1, tvar2.origin)
200-
mapping2 = mapping2.updated(tvar2.origin, p1)
201-
}
202-
}
203-
case _ =>
204-
}
205-
206-
def mapTypeParam(m: SimpleIdentityMap[TypeParamRef, TypeParamRef])(tpr: TypeParamRef) =
207-
m(tpr) match
208-
case null => tpr
209-
case tpr1: TypeParamRef => tpr1
210-
211-
(mapTypeParam(mapping1), mapTypeParam(mapping2))
212171
}
213172

214-
// Bridge between the newly-registered types in c2 and c1
215-
val (mapping1, mapping2) = createMappings
173+
res
174+
}
216175

217-
try {
218-
// checks existing type parameters in `pre`
219-
def existing: Boolean = pre.forallParams { p =>
220-
c1.contains(p) &&
221-
c2.upper(p).forall { q =>
222-
c1.isLess(p, mapping1(q))
223-
} && isSubTypeWhenFrozen(c1.nonParamBounds(p), c2.nonParamBounds(p))
224-
}
176+
def func(p2: TypeParamRef) =
177+
if pre.constraint.domainParams contains p2 then p2
178+
else mapping(p2)
225179

226-
// checks new type parameters in `c1`
227-
def added: Boolean = newParams1 forall { p1 =>
228-
val p2 = mapping1(p1)
229-
c2.upper(p2).forall { q =>
230-
c1.isLess(p1, mapping2(q))
231-
} && isSubTypeWhenFrozen(c1.nonParamBounds(p1), c2.nonParamBounds(p2))
232-
}
180+
func
181+
}
233182

234-
existing && checkNewParams && added
235-
} finally constraint = saved
183+
def checkParam(p2: TypeParamRef) =
184+
rightToLeft(p2).match {
185+
case null => false
186+
case p1: TypeParamRef =>
187+
left.constraint.entry(p1).exists
188+
&& right.constraint.upper(p1).map(rightToLeft).forall(left.constraint.isLess(p1, _))
189+
&& isSubTypeWhenFrozen(left.constraint.nonParamBounds(p1), right.constraint.nonParamBounds(p2))
236190
}
237-
}
238-
}
239191

240-
def extractConstraint(g: GadtConstraint) = g match {
241-
case s: ProperGadtConstraint => s.constraint
242-
case EmptyGadtConstraint => OrderingConstraint.empty
192+
def todos: Set[TypeParamRef] =
193+
right.constraint.domainParams.toSet ++ pre.constraint.domainParams
194+
195+
todos.forall(checkParam)
243196
}
244197

245-
checkSubsumes(extractConstraint(left), extractConstraint(right), extractConstraint(pre))
246-
}
198+
(left, right, pre) match {
199+
case (left: ProperGadtConstraint, right: ProperGadtConstraint, pre: ProperGadtConstraint) =>
200+
checkSubsumes(left, right, pre)
201+
case (_, EmptyGadtConstraint, _) => true
202+
case (EmptyGadtConstraint, _, _) => false
203+
case (_, _, EmptyGadtConstraint) => false
204+
}
247205

248206
override protected def legalBound(param: TypeParamRef, rawBound: Type, isUpper: Boolean)(using Context): Type =
249207
// GADT constraints never involve wildcards and are not propagated outside

0 commit comments

Comments
 (0)