@@ -87,55 +87,87 @@ trait ConstraintHandling[AbstractContext] {
87
87
nonParamBounds(param).derivedTypeBounds(fullLowerBound(param), fullUpperBound(param))
88
88
89
89
protected def addOneBound (param : TypeParamRef , rawBound : Type , isUpper : Boolean )(implicit actx : AbstractContext ): Boolean =
90
- ! constraint.contains(param) || {
91
- def avoidCycle (tp : Type ): Type = tp match
92
- case tp : AndOrType =>
93
- tp.derivedAndOrType(avoidCycle(tp.tp1), avoidCycle(tp.tp2))
94
- case tp : TypeParamRef =>
95
- if tp eq param then
96
- // println(i"stripping $tp from $rawBound, upper = $isUpper in $constraint")
97
- if isUpper then defn.AnyType else defn.NothingType
98
- else constraint.entry(tp) match
99
- case TypeBounds (lo, hi) => if lo eq hi then avoidCycle(lo) else tp
100
- case inst => avoidCycle(inst)
101
- case tp : TypeVar =>
102
- val underlying1 = avoidCycle(tp.underlying)
103
- if underlying1 eq tp.underlying then tp else underlying1
104
- case _ =>
105
- tp
106
- val bound = avoidCycle(rawBound)
90
+
91
+ /** Adjust the bound `tp` in the following ways:
92
+ *
93
+ * 1. Any toplevel occurrences of the compared parameter `param` are
94
+ * replaced by `Nothing` if bound is from below or `Any` otherwise.
95
+ * 2. Toplevel occurrences of TypeVars over TypeRefs in the current
96
+ * constraint are dereferenced.
97
+ * 3. Toplevel occurrences of TypeRefs that are instantiated in the current
98
+ * constraint are also dereferenced.
99
+ * 4. Toplevel occurrences of ExprTypes lead to a `NoType` return, which
100
+ * causes the addOneBound operation to fail.
101
+ *
102
+ * An occurrence is toplevel if it is the bound itself,
103
+ * or the bound is a union or intersection, and the ocurrence is
104
+ * toplevel in one of the operands of the `&` or `|`.
105
+ */
106
+ def adjust (tp : Type ): Type = tp match
107
+ case tp : AndOrType =>
108
+ val p1 = adjust(tp.tp1)
109
+ val p2 = adjust(tp.tp2)
110
+ if p1.exists && p2.exists then tp.derivedAndOrType(p1, p2) else NoType
111
+ case tp : TypeParamRef =>
112
+ if tp eq param then // (1)
113
+ // println(i"stripping $tp from $rawBound, upper = $isUpper in $constraint")
114
+ if isUpper then defn.AnyType else defn.NothingType
115
+ else constraint.entry(tp) match // (3)
116
+ case TypeBounds (lo, hi) => if lo eq hi then adjust(lo) else tp
117
+ case inst => adjust(inst)
118
+ case tp : TypeVar => // (2)
119
+ val underlying1 = adjust(tp.underlying)
120
+ if (underlying1 ne tp.underlying) || constraint.contains(tp.origin)
121
+ then underlying1
122
+ else tp
123
+ case tp : ExprType => // (4)
124
+ // ExprTypes are not value types, so type parameters should not
125
+ // be instantiated to ExprTypes. A scenario where such an attempted
126
+ // instantiation can happen is if we unify (=> T) => () with A => ()
127
+ // where A is a TypeParamRef. See the comment on EtaExpansion.etaExpand
128
+ // why types such as (=> T) => () can be constructed and i7969.scala
129
+ // as a test where this happens.
130
+ // Note that scalac by contrast allows such instantiations. But letting
131
+ // type variables be ExprTypes has its own problems (e.g. you can't write
132
+ // the resulting types down) and is largely unknown terrain.
133
+ NoType
134
+ case _ =>
135
+ tp
136
+
137
+ if ! constraint.contains(param) then true
138
+ else
139
+ val bound = adjust(rawBound)
107
140
108
141
val oldBounds @ TypeBounds (lo, hi) = constraint.nonParamBounds(param)
109
142
val equalBounds = isUpper && (lo eq bound) || ! isUpper && (bound eq hi)
110
- if (equalBounds &&
111
- ! bound.existsPart(bp => bp.isInstanceOf [WildcardType ] || (bp eq param))) {
143
+ if ! bound.exists then false
144
+ else if equalBounds
145
+ && ! bound.existsPart(bp => bp.isInstanceOf [WildcardType ] || (bp eq param))
146
+ then
112
147
// The narrowed bounds are equal and do not contain wildcards,
113
148
// so we can remove `param` from the constraint.
114
149
// (Handling wildcards requires choosing a bound, but we don't know which
115
150
// bound to choose here, this is handled in `ConstraintHandling#approximation`)
116
151
constraint = constraint.replace(param, bound)
117
152
true
118
- }
119
- else {
153
+ else
120
154
// Narrow one of the bounds of type parameter `param`
121
155
// If `isUpper` is true, ensure that `param <: `bound`, otherwise ensure
122
156
// that `param >: bound`.
123
- val narrowedBounds = {
157
+ val narrowedBounds =
124
158
val saved = homogenizeArgs
125
159
homogenizeArgs = Config .alignArgsInAnd
126
160
try
127
161
if (isUpper) oldBounds.derivedTypeBounds(lo, hi & bound)
128
162
else oldBounds.derivedTypeBounds(lo | bound, hi)
129
163
finally homogenizeArgs = saved
130
- }
131
164
val c1 = constraint.updateEntry(param, narrowedBounds)
132
165
(c1 eq constraint) || {
133
166
constraint = c1
134
167
val TypeBounds (lo, hi) = constraint.entry(param)
135
168
isSubType(lo, hi)
136
169
}
137
- }
138
- }
170
+ end addOneBound
139
171
140
172
private def location (implicit ctx : Context ) = " " // i"in ${ctx.typerState.stateChainStr}" // use for debugging
141
173
@@ -201,7 +233,6 @@ trait ConstraintHandling[AbstractContext] {
201
233
up.forall(addOneBound(_, lo, isUpper = false ))
202
234
}
203
235
204
-
205
236
protected def isSubType (tp1 : Type , tp2 : Type , whenFrozen : Boolean )(implicit actx : AbstractContext ): Boolean =
206
237
if (whenFrozen)
207
238
isSubTypeWhenFrozen(tp1, tp2)
@@ -437,7 +468,7 @@ trait ConstraintHandling[AbstractContext] {
437
468
* error in Test2 when the rest of the SI-2712 fix is applied but `pruneLambdaParams` is
438
469
* missing.
439
470
*/
440
- def pruneLambdaParams (tp : Type ) =
471
+ def avoidLambdaParams (tp : Type ) =
441
472
if (comparedTypeLambdas.nonEmpty) {
442
473
val approx = new ApproximatingTypeMap {
443
474
if (! fromBelow) variance = - 1
@@ -461,49 +492,6 @@ trait ConstraintHandling[AbstractContext] {
461
492
if (fromBelow) isSubType(bound, tp) else isSubType(tp, bound)
462
493
}
463
494
464
- /** Normalize the bound `bnd` in the following ways:
465
- *
466
- * 1. Any toplevel occurrences of the compared parameter `param` are
467
- * replaced by `Nothing` if bound is from below or `Any` otherwise.
468
- * 2. Toplevel occurrences of TypeVars over TypeRefs in the current
469
- * constraint are dereferenced.
470
- * 3. Toplevel occurrences of TypeRefs that are instantiated in the current
471
- * constraint are also referenced.
472
- * 4. Toplevel occurrences of ExprTypes lead to a `NoType` return, which
473
- * causes the addConstraint operation to fail.
474
- *
475
- * An occurrence is toplevel if it is the bound itself,
476
- * or the bound is a union or intersection, and the ocurrence is
477
- * toplevel in one of the operands of the `&` or `|`.
478
- */
479
- def prune (bnd : Type ): Type = bnd match
480
- case bnd : AndOrType =>
481
- val p1 = prune(bnd.tp1)
482
- val p2 = prune(bnd.tp2)
483
- if (p1.exists && p2.exists) bnd.derivedAndOrType(p1, p2)
484
- else NoType
485
- case bnd : TypeVar if constraint contains bnd.origin => // (2)
486
- prune(bnd.underlying)
487
- case bnd : TypeParamRef =>
488
- if bnd eq param then // (1)
489
- if fromBelow then defn.NothingType else defn.AnyType
490
- else constraint.entry(bnd) match
491
- case TypeBounds (lo, hi) => if lo eq hi then prune(lo) else bnd
492
- case inst => prune(inst) // (3)
493
- case bnd : ExprType => // (4)
494
- // ExprTypes are not value types, so type parameters should not
495
- // be instantiated to ExprTypes. A scenario where such an attempted
496
- // instantiation can happen is if we unify (=> T) => () with A => ()
497
- // where A is a TypeParamRef. See the comment on EtaExpansion.etaExpand
498
- // why types such as (=> T) => () can be constructed and i7969.scala
499
- // as a test where this happens.
500
- // Note that scalac by contrast allows such instantiations. But letting
501
- // type variables be ExprTypes has its own problems (e.g. you can't write
502
- // the resulting types down) and is largely unknown terrain.
503
- NoType
504
- case _ =>
505
- bnd
506
-
507
495
def kindCompatible (tp1 : Type , tp2 : Type ): Boolean =
508
496
val tparams1 = tp1.typeParams
509
497
val tparams2 = tp2.typeParams
@@ -521,9 +509,8 @@ trait ConstraintHandling[AbstractContext] {
521
509
case bound : TypeParamRef if constraint contains bound =>
522
510
addParamBound(bound)
523
511
case _ =>
524
- val pbound = prune(pruneLambdaParams(bound))
525
- pbound.exists
526
- && kindCompatible(param, pbound)
512
+ val pbound = avoidLambdaParams(bound)
513
+ kindCompatible(param, pbound)
527
514
&& (if fromBelow then addLowerBound(param, pbound) else addUpperBound(param, pbound))
528
515
finally addConstraintInvocations -= 1
529
516
}
0 commit comments