Skip to content

Commit aca3133

Browse files
committed
Simplify prune
1 parent c657700 commit aca3133

File tree

1 file changed

+26
-56
lines changed

1 file changed

+26
-56
lines changed

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

Lines changed: 26 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -460,66 +460,36 @@ trait ConstraintHandling[AbstractContext] {
460460
if (fromBelow) isSubType(bound, tp) else isSubType(tp, bound)
461461
}
462462

463-
/** Drop all constrained parameters that occur at the toplevel in `bound` and
464-
* handle them by `addLess` calls.
465-
* The preconditions make sure that such parameters occur only
466-
* in one of two ways:
463+
/** Normalize the bound `bnd` in the following ways:
467464
*
468-
* 1.
465+
* 1. Any toplevel occurrences of the compared parameter `param` are
466+
* replaced by `Nothing` if bound is from below or `Any` otherwise.
467+
* 2. Toplevel occurrences of TypeVars over TypeRefs in the current
468+
* constraint are dereferenced.
469+
* 3. Toplevel occurrences of TypeRefs that are instantiated in the current
470+
* constraint are also referenced.
471+
* 4. Toplevel occurrences of ExprTypes lead to a `NoType` return, which
472+
* causes the addConstraint operation to fail.
469473
*
470-
* P <: Ts1 | ... | Tsm (m > 0)
471-
* Tsi = T1 & ... Tn (n >= 0)
472-
* Some of the Ti are constrained parameters
473-
*
474-
* 2.
475-
*
476-
* Ts1 & ... & Tsm <: P (m > 0)
477-
* Tsi = T1 | ... | Tn (n >= 0)
478-
* Some of the Ti are constrained parameters
479-
*
480-
* In each case we cannot leave the parameter in place,
481-
* because that would risk making a parameter later a subtype or supertype
482-
* of a bound where the parameter occurs again at toplevel, which leads to cycles
483-
* in the subtyping test. So we intentionally narrow the constraint by
484-
* recording an isLess relationship instead (even though this is not implied
485-
* by the bound).
486-
*
487-
* Normally, narrowing a constraint is better than widening it, because
488-
* narrowing leads to incompleteness (which we face anyway, see for
489-
* instance `TypeComparer#either`) but widening leads to unsoundness,
490-
* but note the special handling in `ConstrainResult` mode below.
491-
*
492-
* A test case that demonstrates the problem is i864.scala.
493-
* Turn Config.checkConstraintsSeparated on to get an accurate diagnostic
494-
* of the cycle when it is created.
495-
*
496-
* @return The pruned type if all `addLess` calls succeed, `NoType` otherwise.
474+
* An occurrence is toplevel if it is the bound itself,
475+
* or the bound is a union or intersection, and the ocurrence is
476+
* toplevel in one of the operands of the `&` or `|`.
497477
*/
498-
def prune(bnd: Type): Type = bnd match {
499-
case bnd: AndType if !fromBelow =>
478+
def prune(bnd: Type): Type = bnd match
479+
case bnd: AndOrType =>
500480
val p1 = prune(bnd.tp1)
501481
val p2 = prune(bnd.tp2)
502-
if (p1.exists && p2.exists) bnd.derivedAndType(p1, p2)
482+
if (p1.exists && p2.exists) bnd.derivedAndOrType(p1, p2)
503483
else NoType
504-
case bnd: OrType if fromBelow =>
505-
val p1 = prune(bnd.tp1)
506-
val p2 = prune(bnd.tp2)
507-
if (p1.exists && p2.exists) bnd.derivedOrType(p1, p2)
508-
else NoType
509-
case bnd: TypeVar if constraint contains bnd.origin =>
484+
case bnd: TypeVar if constraint contains bnd.origin => // (2)
510485
prune(bnd.underlying)
511-
case bnd: TypeParamRef if bnd ne param =>
512-
constraint.entry(bnd) match {
513-
case NoType => pruneLambdaParams(bnd)
514-
case _: TypeBounds =>
515-
assertFail(i"pruning $param $bound $fromBelow $bnd")
516-
if (!addParamBound(bnd)) NoType
517-
else if (fromBelow) defn.NothingType
518-
else defn.AnyType
519-
case inst =>
520-
prune(inst)
521-
}
522-
case bnd: ExprType =>
486+
case bnd: TypeParamRef =>
487+
if bnd eq param then // (1)
488+
if fromBelow then defn.NothingType else defn.AnyType
489+
else constraint.entry(bnd) match
490+
case _: TypeBounds => bnd
491+
case inst => prune(inst) // (3)
492+
case bnd: ExprType => // (4)
523493
// ExprTypes are not value types, so type parameters should not
524494
// be instantiated to ExprTypes. A scenario where such an attempted
525495
// instantiation can happen is if we unify (=> T) => () with A => ()
@@ -531,8 +501,7 @@ trait ConstraintHandling[AbstractContext] {
531501
// the resulting types down) and is largely unknown terrain.
532502
NoType
533503
case _ =>
534-
pruneLambdaParams(bnd)
535-
}
504+
bnd
536505

537506
def kindCompatible(tp1: Type, tp2: Type): Boolean =
538507
val tparams1 = tp1.typeParams
@@ -547,7 +516,8 @@ trait ConstraintHandling[AbstractContext] {
547516
addParamBound(bound)
548517
case _ =>
549518
val savedConstraint = constraint
550-
val pbound = prune(bound)
519+
val pbound = prune(pruneLambdaParams(bound))
520+
assert(constraint eq savedConstraint)
551521
val constraintsNarrowed = constraint ne savedConstraint
552522

553523
val res =

0 commit comments

Comments
 (0)