@@ -87,6 +87,10 @@ trait ConstraintHandling[AbstractContext] {
87
87
88
88
protected def addOneBound (param : TypeParamRef , bound : Type , isUpper : Boolean )(using AbstractContext ): Boolean =
89
89
if ! constraint.contains(param) then true
90
+ else if ! isUpper && param.occursIn(bound)
91
+ // We don't allow recursive lower bounds when defining a type,
92
+ // so we shouldn't allow them as constraints either.
93
+ false
90
94
else
91
95
val oldBounds @ TypeBounds (lo, hi) = constraint.nonParamBounds(param)
92
96
val equalBounds = (if isUpper then lo else hi) eq bound
@@ -238,25 +242,20 @@ trait ConstraintHandling[AbstractContext] {
238
242
239
243
/** Solve constraint set for given type parameter `param`.
240
244
* If `fromBelow` is true the parameter is approximated by its lower bound,
241
- * otherwise it is approximated by its upper bound. However, any occurrences
242
- * of the parameter in a refinement somewhere in the bound are removed. Also
243
- * wildcard types in bounds are approximated by their upper or lower bounds.
245
+ * otherwise it is approximated by its upper bound, unless the upper bound
246
+ * contains a reference to the parameter itself (`addOneBound` ensures that
247
+ * such reference never occur in the lower bound).
248
+ * Wildcard types in bounds are approximated by their upper or lower bounds.
244
249
* (Such occurrences can arise for F-bounded types).
245
250
* The constraint is left unchanged.
246
251
* @return the instantiating type
247
252
* @pre `param` is in the constraint's domain.
248
253
*/
249
254
final def approximation (param : TypeParamRef , fromBelow : Boolean )(implicit actx : AbstractContext ): Type = {
250
- val avoidParam = new TypeMap {
255
+ val replaceWildcards = new TypeMap {
251
256
override def stopAtStatic = true
252
- def avoidInArg (arg : Type ): Type =
253
- if (param.occursIn(arg)) TypeBounds .empty else arg
254
257
def apply (tp : Type ) = mapOver {
255
258
tp match {
256
- case tp @ AppliedType (tycon, args) =>
257
- tp.derivedAppliedType(tycon, args.mapConserve(avoidInArg))
258
- case tp : RefinedType if param occursIn tp.refinedInfo =>
259
- tp.parent
260
259
case tp : WildcardType =>
261
260
val bounds = tp.optBounds.orElse(TypeBounds .empty).bounds
262
261
// Try to instantiate the wildcard to a type that is known to conform to it.
@@ -283,9 +282,10 @@ trait ConstraintHandling[AbstractContext] {
283
282
}
284
283
}
285
284
constraint.entry(param) match {
286
- case _ : TypeBounds =>
287
- val bound = if (fromBelow) fullLowerBound(param) else fullUpperBound(param)
288
- val inst = avoidParam(bound)
285
+ case entry : TypeBounds =>
286
+ val useLowerBound = fromBelow || param.occursIn(entry.hi)
287
+ val bound = if (useLowerBound) fullLowerBound(param) else fullUpperBound(param)
288
+ val inst = replaceWildcards(bound)
289
289
typr.println(s " approx ${param.show}, from below = $fromBelow, bound = ${bound.show}, inst = ${inst.show}" )
290
290
inst
291
291
case inst =>
0 commit comments