Skip to content

Commit 42a4d3f

Browse files
author
Aleksander Boruch-Gruszecki
committed
Refactor Constraint to constrain TypeRefs
1 parent e73d2e8 commit 42a4d3f

File tree

10 files changed

+243
-199
lines changed

10 files changed

+243
-199
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ object Constants {
161161
case TypeBounds(lo, hi) =>
162162
if (hi.classSymbol.isPrimitiveValueClass) hi //constrain further with high bound
163163
else classBound(lo)
164-
case NoType => classBound(param.binder.paramInfos(param.paramNum).lo)
164+
case NoType => classBound(param.binder.paramInfos(param.refNum).lo)
165165
case inst => classBound(inst)
166166
}
167167
case pt => pt

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

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ package core
55
import Types._, Contexts._
66
import printing.Showable
77

8+
object Constraint {
9+
type VarRef = TypeVarRef
10+
type Binder = TypeVarRefBinder
11+
}
12+
813
/** Constraint over undetermined type parameters. Constraints are built
914
* over values of the following types:
1015
*
@@ -14,58 +19,59 @@ import printing.Showable
1419
* that has the TypeParamRef as origin.
1520
*/
1621
abstract class Constraint extends Showable {
22+
import Constraint._
1723

1824
type This <: Constraint
1925

2026
/** Does the constraint's domain contain the type parameters of `pt`? */
21-
def contains(pt: TypeLambda): Boolean
27+
def contains(pt: Binder): Boolean
2228

2329
/** Does the constraint's domain contain the type parameter `param`? */
24-
def contains(param: TypeParamRef): Boolean
30+
def contains(param: VarRef): Boolean
2531

2632
/** Does this constraint contain the type variable `tvar` and is it uninstantiated? */
2733
def contains(tvar: TypeVar): Boolean
2834

2935
/** The constraint entry for given type parameter `param`, or NoType if `param` is not part of
3036
* the constraint domain. Note: Low level, implementation dependent.
3137
*/
32-
def entry(param: TypeParamRef): Type
38+
def entry(param: VarRef): Type
3339

3440
/** The type variable corresponding to parameter `param`, or
3541
* NoType, if `param` is not in constrained or is not paired with a type variable.
3642
*/
37-
def typeVarOfParam(param: TypeParamRef): Type
43+
def typeVarOfParam(param: VarRef): Type
3844

3945
/** Is it known that `param1 <:< param2`? */
40-
def isLess(param1: TypeParamRef, param2: TypeParamRef): Boolean
46+
def isLess(param1: VarRef, param2: VarRef): Boolean
4147

4248
/** The parameters that are known to be smaller wrt <: than `param` */
43-
def lower(param: TypeParamRef): List[TypeParamRef]
49+
def lower(param: VarRef): List[VarRef]
4450

4551
/** The parameters that are known to be greater wrt <: than `param` */
46-
def upper(param: TypeParamRef): List[TypeParamRef]
52+
def upper(param: VarRef): List[VarRef]
4753

4854
/** lower(param) \ lower(butNot) */
49-
def exclusiveLower(param: TypeParamRef, butNot: TypeParamRef): List[TypeParamRef]
55+
def exclusiveLower(param: VarRef, butNot: VarRef): List[VarRef]
5056

5157
/** upper(param) \ upper(butNot) */
52-
def exclusiveUpper(param: TypeParamRef, butNot: TypeParamRef): List[TypeParamRef]
58+
def exclusiveUpper(param: VarRef, butNot: VarRef): List[VarRef]
5359

5460
/** The constraint bounds for given type parameter `param`.
5561
* Poly params that are known to be smaller or greater than `param`
5662
* are not contained in the return bounds.
5763
* @pre `param` is not part of the constraint domain.
5864
*/
59-
def nonParamBounds(param: TypeParamRef)(implicit ctx: Context): TypeBounds
65+
def nonParamBounds(param: VarRef)(implicit ctx: Context): TypeBounds
6066

6167
/** The lower bound of `param` including all known-to-be-smaller parameters */
62-
def fullLowerBound(param: TypeParamRef)(implicit ctx: Context): Type
68+
def fullLowerBound(param: VarRef)(implicit ctx: Context): Type
6369

6470
/** The upper bound of `param` including all known-to-be-greater parameters */
65-
def fullUpperBound(param: TypeParamRef)(implicit ctx: Context): Type
71+
def fullUpperBound(param: VarRef)(implicit ctx: Context): Type
6672

6773
/** The bounds of `param` including all known-to-be-smaller and -greater parameters */
68-
def fullBounds(param: TypeParamRef)(implicit ctx: Context): TypeBounds
74+
def fullBounds(param: VarRef)(implicit ctx: Context): TypeBounds
6975

7076
/** A new constraint which is derived from this constraint by adding
7177
* entries for all type parameters of `poly`.
@@ -74,7 +80,7 @@ abstract class Constraint extends Showable {
7480
* satisfiability but will solved to give instances of
7581
* type variables.
7682
*/
77-
def add(poly: TypeLambda, tvars: List[TypeVar])(implicit ctx: Context): This
83+
def add(poly: Binder, tvars: List[TypeVar])(implicit ctx: Context): This
7884

7985
/** A new constraint which is derived from this constraint by updating
8086
* the entry for parameter `param` to `tp`.
@@ -85,44 +91,44 @@ abstract class Constraint extends Showable {
8591
*
8692
* @pre `this contains param`.
8793
*/
88-
def updateEntry(param: TypeParamRef, tp: Type)(implicit ctx: Context): This
94+
def updateEntry(param: VarRef, tp: Type)(implicit ctx: Context): This
8995

9096
/** A constraint that includes the relationship `p1 <: p2`.
9197
* `<:` relationships between parameters ("edges") are propagated, but
9298
* non-parameter bounds are left alone.
9399
*/
94-
def addLess(p1: TypeParamRef, p2: TypeParamRef)(implicit ctx: Context): This
100+
def addLess(p1: VarRef, p2: VarRef)(implicit ctx: Context): This
95101

96102
/** A constraint resulting from adding p2 = p1 to this constraint, and at the same
97103
* time transferring all bounds of p2 to p1
98104
*/
99-
def unify(p1: TypeParamRef, p2: TypeParamRef)(implicit ctx: Context): This
105+
def unify(p1: VarRef, p2: VarRef)(implicit ctx: Context): This
100106

101107
/** A new constraint which is derived from this constraint by removing
102108
* the type parameter `param` from the domain and replacing all top-level occurrences
103109
* of the parameter elsewhere in the constraint by type `tp`, or a conservative
104110
* approximation of it if that is needed to avoid cycles.
105111
* Occurrences nested inside a refinement or prefix are not affected.
106112
*/
107-
def replace(param: TypeParamRef, tp: Type)(implicit ctx: Context): This
113+
def replace(param: VarRef, tp: Type)(implicit ctx: Context): This
108114

109115
/** Is entry associated with `pt` removable? This is the case if
110116
* all type parameters of the entry are associated with type variables
111117
* which have their `inst` fields set.
112118
*/
113-
def isRemovable(pt: TypeLambda): Boolean
119+
def isRemovable(pt: Binder): Boolean
114120

115121
/** A new constraint with all entries coming from `pt` removed. */
116-
def remove(pt: TypeLambda)(implicit ctx: Context): This
122+
def remove(pt: Binder)(implicit ctx: Context): This
117123

118124
/** The type lambdas constrained by this constraint */
119-
def domainLambdas: List[TypeLambda]
125+
def domainLambdas: List[Binder]
120126

121127
/** The type lambda parameters constrained by this constraint */
122-
def domainParams: List[TypeParamRef]
128+
def domainParams: List[VarRef]
123129

124130
/** Check whether predicate holds for all parameters in constraint */
125-
def forallParams(p: TypeParamRef => Boolean): Boolean
131+
def forallParams(p: VarRef => Boolean): Boolean
126132

127133
/** Perform operation `op` on all typevars that do not have their `inst` field set. */
128134
def foreachTypeVar(op: TypeVar => Unit): Unit

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

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import config.Printers.{constr, typr}
1919
* Constraint handlers update the current constraint as a side effect.
2020
*/
2121
trait ConstraintHandling {
22+
import Constraint._
2223

2324
def constr_println(msg: => String): Unit = constr.println(msg)
2425
def typr_println(msg: => String): Unit = typr.println(msg)
@@ -60,13 +61,13 @@ trait ConstraintHandling {
6061
*/
6162
def instType(tvar: TypeVar): Type = constraint.entry(tvar.origin) match {
6263
case _: TypeBounds => NoType
63-
case tp: TypeParamRef =>
64+
case tp: VarRef =>
6465
var tvar1 = constraint.typeVarOfParam(tp)
6566
if (tvar1.exists) tvar1 else tp
6667
case tp => tp
6768
}
6869

69-
protected def addOneBound(param: TypeParamRef, bound: Type, isUpper: Boolean): Boolean =
70+
protected def addOneBound(param: VarRef, bound: Type, isUpper: Boolean): Boolean =
7071
!constraint.contains(param) || {
7172
def occursIn(bound: Type): Boolean = {
7273
val b = bound.dealias
@@ -84,7 +85,7 @@ trait ConstraintHandling {
8485
assert(!occursIn(bound), s"$param occurs in $bound")
8586

8687
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
87-
val equalBounds = isUpper && (lo eq bound) || !isUpper && (bound eq hi)
88+
val equalBounds = isUpper && (bound eq lo) || !isUpper && (bound eq hi)
8889
if (equalBounds && !bound.existsPart(_.isInstanceOf[WildcardType])) {
8990
// The narrowed bounds are equal and do not contain wildcards,
9091
// so we can remove `param` from the constraint.
@@ -116,7 +117,7 @@ trait ConstraintHandling {
116117

117118
private def location(implicit ctx: Context) = "" // i"in ${ctx.typerState.stateChainStr}" // use for debugging
118119

119-
protected def addUpperBound(param: TypeParamRef, bound: Type): Boolean = {
120+
protected def addUpperBound(param: VarRef, bound: Type): Boolean = {
120121
def description = i"constraint $param <: $bound to\n$constraint"
121122
if (bound.isRef(defn.NothingClass) && ctx.typerState.isGlobalCommittable) {
122123
def msg = s"!!! instantiated to Nothing: $param, constraint = ${constraint.show}"
@@ -132,7 +133,7 @@ trait ConstraintHandling {
132133
res
133134
}
134135

135-
protected def addLowerBound(param: TypeParamRef, bound: Type): Boolean = {
136+
protected def addLowerBound(param: VarRef, bound: Type): Boolean = {
136137
def description = i"constraint $param >: $bound to\n$constraint"
137138
constr_println(i"adding $description")
138139
val upper = constraint.upper(param)
@@ -143,7 +144,7 @@ trait ConstraintHandling {
143144
res
144145
}
145146

146-
protected def addLess(p1: TypeParamRef, p2: TypeParamRef): Boolean = {
147+
protected def addLess(p1: VarRef, p2: VarRef): Boolean = {
147148
def description = i"ordering $p1 <: $p2 to\n$constraint"
148149
val res =
149150
if (constraint.isLess(p2, p1)) unify(p2, p1)
@@ -165,7 +166,7 @@ trait ConstraintHandling {
165166
/** Make p2 = p1, transfer all bounds of p2 to p1
166167
* @pre less(p1)(p2)
167168
*/
168-
private def unify(p1: TypeParamRef, p2: TypeParamRef): Boolean = {
169+
private def unify(p1: VarRef, p2: VarRef): Boolean = {
169170
constr_println(s"unifying $p1 $p2")
170171
assert(constraint.isLess(p1, p2))
171172
val down = constraint.exclusiveLower(p2, p1)
@@ -224,7 +225,7 @@ trait ConstraintHandling {
224225
* @return the instantiating type
225226
* @pre `param` is in the constraint's domain.
226227
*/
227-
final def approximation(param: TypeParamRef, fromBelow: Boolean): Type = {
228+
final def approximation(param: VarRef, fromBelow: Boolean): Type = {
228229
val avoidParam = new TypeMap {
229230
override def stopAtStatic = true
230231
def avoidInArg(arg: Type): Type =
@@ -283,9 +284,9 @@ trait ConstraintHandling {
283284
case tp: SingletonType => true
284285
case AndType(tp1, tp2) => isMultiSingleton(tp1) | isMultiSingleton(tp2)
285286
case OrType(tp1, tp2) => isMultiSingleton(tp1) & isMultiSingleton(tp2)
286-
case tp: TypeRef => isMultiSingleton(tp.info.hiBound)
287+
case tp: TypeRef if !constraint.contains(tp : VarRef) => isMultiSingleton(tp.info.hiBound)
287288
case tp: TypeVar => isMultiSingleton(tp.underlying)
288-
case tp: TypeParamRef => isMultiSingleton(bounds(tp).hi)
289+
case tp: VarRef => isMultiSingleton(bounds(tp).hi)
289290
case _ => false
290291
}
291292
def isOrType(tp: Type): Boolean = tp.dealias match {
@@ -311,7 +312,7 @@ trait ConstraintHandling {
311312
* a lower bound instantiation can be a singleton type only if the upper bound
312313
* is also a singleton type.
313314
*/
314-
def instanceType(param: TypeParamRef, fromBelow: Boolean): Type = {
315+
def instanceType(param: VarRef, fromBelow: Boolean): Type = {
315316
val inst = approximation(param, fromBelow).simplified
316317
if (fromBelow) widenInferred(inst, constraint.fullUpperBound(param)) else inst
317318
}
@@ -340,12 +341,12 @@ trait ConstraintHandling {
340341
}
341342

342343
/** The current bounds of type parameter `param` */
343-
def bounds(param: TypeParamRef): TypeBounds = {
344+
def bounds(param: VarRef): TypeBounds = {
344345
val e = constraint.entry(param)
345346
if (e.exists) e.bounds
346347
else {
347-
val pinfos = param.binder.paramInfos
348-
if (pinfos != null) pinfos(param.paramNum) // pinfos == null happens in pos/i536.scala
348+
val pinfos = param.binder.refInfos
349+
if (pinfos != null) pinfos(param.refNum) // pinfos == null happens in pos/i536.scala
349350
else TypeBounds.empty
350351
}
351352
}
@@ -354,10 +355,10 @@ trait ConstraintHandling {
354355
* and propagate all bounds.
355356
* @param tvars See Constraint#add
356357
*/
357-
def addToConstraint(tl: TypeLambda, tvars: List[TypeVar]): Boolean =
358+
def addToConstraint(tl: Binder, tvars: List[TypeVar]): Boolean =
358359
checkPropagated(i"initialized $tl") {
359360
constraint = constraint.add(tl, tvars)
360-
tl.paramRefs.forall { param =>
361+
tl.boundRefs.forall { param =>
361362
constraint.entry(param) match {
362363
case bounds: TypeBounds =>
363364
val lower = constraint.lower(param)
@@ -375,14 +376,14 @@ trait ConstraintHandling {
375376
}
376377

377378
/** Can `param` be constrained with new bounds? */
378-
final def canConstrain(param: TypeParamRef): Boolean =
379+
final def canConstrain(param: VarRef): Boolean =
379380
(!frozenConstraint || (caseLambda `eq` param.binder)) && constraint.contains(param)
380381

381382
/** Is `param` assumed to be a sub- and super-type of any other type?
382383
* This holds if `TypeVarsMissContext` is set unless `param` is a part
383384
* of a MatchType that is currently normalized.
384385
*/
385-
final def assumedTrue(param: TypeParamRef): Boolean =
386+
final def assumedTrue(param: VarRef): Boolean =
386387
ctx.mode.is(Mode.TypevarsMissContext) && (caseLambda `ne` param.binder)
387388

388389
/** Add constraint `param <: bound` if `fromBelow` is false, `param >: bound` otherwise.
@@ -392,7 +393,7 @@ trait ConstraintHandling {
392393
* not be AndTypes and lower bounds may not be OrTypes. This is assured by the
393394
* way isSubType is organized.
394395
*/
395-
protected def addConstraint(param: TypeParamRef, bound: Type, fromBelow: Boolean): Boolean = {
396+
protected def addConstraint(param: VarRef, bound: Type, fromBelow: Boolean): Boolean = {
396397
def description = i"constr $param ${if (fromBelow) ">:" else "<:"} $bound:\n$constraint"
397398
//checkPropagated(s"adding $description")(true) // DEBUG in case following fails
398399
checkPropagated(s"added $description") {
@@ -522,7 +523,7 @@ trait ConstraintHandling {
522523
if (Config.checkConstraintsPropagated && result && addConstraintInvocations == 0) {
523524
inFrozenConstraint {
524525
for (p <- constraint.domainParams) {
525-
def check(cond: => Boolean, q: TypeParamRef, ordering: String, explanation: String): Unit =
526+
def check(cond: => Boolean, q: VarRef, ordering: String, explanation: String): Unit =
526527
assert(cond, i"propagation failure for $p $ordering $q: $explanation\n$msg")
527528
for (u <- constraint.upper(p))
528529
check(bounds(p).hi <:< bounds(u).hi, u, "<:", "upper bound not propagated")

0 commit comments

Comments
 (0)