Skip to content

Commit 247cc86

Browse files
committed
Rearrange parts of ConstraintHandling for legibility
1 parent 94f3f0c commit 247cc86

File tree

1 file changed

+88
-87
lines changed

1 file changed

+88
-87
lines changed

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

Lines changed: 88 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -418,98 +418,99 @@ trait ConstraintHandling[AbstractContext] {
418418
* not be AndTypes and lower bounds may not be OrTypes. This is assured by the
419419
* way isSubType is organized.
420420
*/
421-
protected def addConstraint(param: TypeParamRef, bound: Type, fromBelow: Boolean)(implicit actx: AbstractContext): Boolean = {
422-
def description = i"constr $param ${if (fromBelow) ">:" else "<:"} $bound:\n$constraint"
423-
//checkPropagated(s"adding $description")(true) // DEBUG in case following fails
424-
checkPropagated(s"added $description") {
425-
426-
/** When comparing lambdas we might get constraints such as
427-
* `A <: X0` or `A = List[X0]` where `A` is a constrained parameter
428-
* and `X0` is a lambda parameter. The constraint for `A` is not allowed
429-
* to refer to such a lambda parameter because the lambda parameter is
430-
* not visible where `A` is defined. Consequently, we need to
431-
* approximate the bound so that the lambda parameter does not appear in it.
432-
* If `tp` is an upper bound, we need to approximate with something smaller,
433-
* otherwise something larger.
434-
* Test case in pos/i94-nada.scala. This test crashes with an illegal instance
435-
* error in Test2 when the rest of the SI-2712 fix is applied but `pruneLambdaParams` is
436-
* missing.
437-
*/
438-
def pruneLambdaParams(tp: Type) =
439-
if (comparedTypeLambdas.nonEmpty) {
440-
val approx = new ApproximatingTypeMap {
441-
if (!fromBelow) variance = -1
442-
def apply(t: Type): Type = t match {
443-
case t @ TypeParamRef(tl: TypeLambda, n) if comparedTypeLambdas contains tl =>
444-
val bounds = tl.paramInfos(n)
445-
range(bounds.lo, bounds.hi)
446-
case _ =>
447-
mapOver(t)
448-
}
421+
protected def addConstraint(param: TypeParamRef, bound: Type, fromBelow: Boolean)(implicit actx: AbstractContext): Boolean =
422+
423+
/** When comparing lambdas we might get constraints such as
424+
* `A <: X0` or `A = List[X0]` where `A` is a constrained parameter
425+
* and `X0` is a lambda parameter. The constraint for `A` is not allowed
426+
* to refer to such a lambda parameter because the lambda parameter is
427+
* not visible where `A` is defined. Consequently, we need to
428+
* approximate the bound so that the lambda parameter does not appear in it.
429+
* If `tp` is an upper bound, we need to approximate with something smaller,
430+
* otherwise something larger.
431+
* Test case in pos/i94-nada.scala. This test crashes with an illegal instance
432+
* error in Test2 when the rest of the SI-2712 fix is applied but `pruneLambdaParams` is
433+
* missing.
434+
*/
435+
def pruneLambdaParams(tp: Type) =
436+
if (comparedTypeLambdas.nonEmpty) {
437+
val approx = new ApproximatingTypeMap {
438+
if (!fromBelow) variance = -1
439+
def apply(t: Type): Type = t match {
440+
case t @ TypeParamRef(tl: TypeLambda, n) if comparedTypeLambdas contains tl =>
441+
val bounds = tl.paramInfos(n)
442+
range(bounds.lo, bounds.hi)
443+
case _ =>
444+
mapOver(t)
449445
}
450-
approx(tp)
451446
}
452-
else tp
447+
approx(tp)
448+
}
449+
else tp
450+
451+
def addParamBound(bound: TypeParamRef) =
452+
constraint.entry(param) match {
453+
case _: TypeBounds =>
454+
if (fromBelow) addLess(bound, param) else addLess(param, bound)
455+
case tp =>
456+
if (fromBelow) isSubType(bound, tp) else isSubType(tp, bound)
457+
}
453458

454-
def addParamBound(bound: TypeParamRef) =
455-
constraint.entry(param) match {
456-
case _: TypeBounds =>
457-
if (fromBelow) addLess(bound, param) else addLess(param, bound)
458-
case tp =>
459-
if (fromBelow) isSubType(bound, tp) else isSubType(tp, bound)
460-
}
459+
/** Normalize the bound `bnd` in the following ways:
460+
*
461+
* 1. Any toplevel occurrences of the compared parameter `param` are
462+
* replaced by `Nothing` if bound is from below or `Any` otherwise.
463+
* 2. Toplevel occurrences of TypeVars over TypeRefs in the current
464+
* constraint are dereferenced.
465+
* 3. Toplevel occurrences of TypeRefs that are instantiated in the current
466+
* constraint are also referenced.
467+
* 4. Toplevel occurrences of ExprTypes lead to a `NoType` return, which
468+
* causes the addConstraint operation to fail.
469+
*
470+
* An occurrence is toplevel if it is the bound itself,
471+
* or the bound is a union or intersection, and the ocurrence is
472+
* toplevel in one of the operands of the `&` or `|`.
473+
*/
474+
def prune(bnd: Type): Type = bnd match
475+
case bnd: AndOrType =>
476+
val p1 = prune(bnd.tp1)
477+
val p2 = prune(bnd.tp2)
478+
if (p1.exists && p2.exists) bnd.derivedAndOrType(p1, p2)
479+
else NoType
480+
case bnd: TypeVar if constraint contains bnd.origin => // (2)
481+
prune(bnd.underlying)
482+
case bnd: TypeParamRef =>
483+
if bnd eq param then // (1)
484+
if fromBelow then defn.NothingType else defn.AnyType
485+
else constraint.entry(bnd) match
486+
case _: TypeBounds => bnd
487+
case inst => prune(inst) // (3)
488+
case bnd: ExprType => // (4)
489+
// ExprTypes are not value types, so type parameters should not
490+
// be instantiated to ExprTypes. A scenario where such an attempted
491+
// instantiation can happen is if we unify (=> T) => () with A => ()
492+
// where A is a TypeParamRef. See the comment on EtaExpansion.etaExpand
493+
// why types such as (=> T) => () can be constructed and i7969.scala
494+
// as a test where this happens.
495+
// Note that scalac by contrast allows such instantiations. But letting
496+
// type variables be ExprTypes has its own problems (e.g. you can't write
497+
// the resulting types down) and is largely unknown terrain.
498+
NoType
499+
case _ =>
500+
bnd
461501

462-
/** Normalize the bound `bnd` in the following ways:
463-
*
464-
* 1. Any toplevel occurrences of the compared parameter `param` are
465-
* replaced by `Nothing` if bound is from below or `Any` otherwise.
466-
* 2. Toplevel occurrences of TypeVars over TypeRefs in the current
467-
* constraint are dereferenced.
468-
* 3. Toplevel occurrences of TypeRefs that are instantiated in the current
469-
* constraint are also referenced.
470-
* 4. Toplevel occurrences of ExprTypes lead to a `NoType` return, which
471-
* causes the addConstraint operation to fail.
472-
*
473-
* An occurrence is toplevel if it is the bound itself,
474-
* or the bound is a union or intersection, and the ocurrence is
475-
* toplevel in one of the operands of the `&` or `|`.
476-
*/
477-
def prune(bnd: Type): Type = bnd match
478-
case bnd: AndOrType =>
479-
val p1 = prune(bnd.tp1)
480-
val p2 = prune(bnd.tp2)
481-
if (p1.exists && p2.exists) bnd.derivedAndOrType(p1, p2)
482-
else NoType
483-
case bnd: TypeVar if constraint contains bnd.origin => // (2)
484-
prune(bnd.underlying)
485-
case bnd: TypeParamRef =>
486-
if bnd eq param then // (1)
487-
if fromBelow then defn.NothingType else defn.AnyType
488-
else constraint.entry(bnd) match
489-
case _: TypeBounds => bnd
490-
case inst => prune(inst) // (3)
491-
case bnd: ExprType => // (4)
492-
// ExprTypes are not value types, so type parameters should not
493-
// be instantiated to ExprTypes. A scenario where such an attempted
494-
// instantiation can happen is if we unify (=> T) => () with A => ()
495-
// where A is a TypeParamRef. See the comment on EtaExpansion.etaExpand
496-
// why types such as (=> T) => () can be constructed and i7969.scala
497-
// as a test where this happens.
498-
// Note that scalac by contrast allows such instantiations. But letting
499-
// type variables be ExprTypes has its own problems (e.g. you can't write
500-
// the resulting types down) and is largely unknown terrain.
501-
NoType
502-
case _ =>
503-
bnd
502+
def kindCompatible(tp1: Type, tp2: Type): Boolean =
503+
val tparams1 = tp1.typeParams
504+
val tparams2 = tp2.typeParams
505+
tparams1.corresponds(tparams2)((p1, p2) => kindCompatible(p1.paramInfo, p2.paramInfo))
506+
&& (tparams1.isEmpty || kindCompatible(tp1.hkResult, tp2.hkResult))
507+
|| tp1.hasAnyKind
508+
|| tp2.hasAnyKind
504509

505-
def kindCompatible(tp1: Type, tp2: Type): Boolean =
506-
val tparams1 = tp1.typeParams
507-
val tparams2 = tp2.typeParams
508-
tparams1.corresponds(tparams2)((p1, p2) => kindCompatible(p1.paramInfo, p2.paramInfo))
509-
&& (tparams1.isEmpty || kindCompatible(tp1.hkResult, tp2.hkResult))
510-
|| tp1.hasAnyKind
511-
|| tp2.hasAnyKind
510+
def description = i"constr $param ${if (fromBelow) ">:" else "<:"} $bound:\n$constraint"
512511

512+
//checkPropagated(s"adding $description")(true) // DEBUG in case following fails
513+
checkPropagated(s"added $description") {
513514
addConstraintInvocations += 1
514515
try bound match
515516
case bound: TypeParamRef if constraint contains bound =>
@@ -521,7 +522,7 @@ trait ConstraintHandling[AbstractContext] {
521522
&& (if fromBelow then addLowerBound(param, pbound) else addUpperBound(param, pbound))
522523
finally addConstraintInvocations -= 1
523524
}
524-
}
525+
end addConstraint
525526

526527
/** Check that constraint is fully propagated. See comment in Config.checkConstraintsPropagated */
527528
def checkPropagated(msg: => String)(result: Boolean)(implicit actx: AbstractContext): Boolean = {

0 commit comments

Comments
 (0)