@@ -300,8 +300,12 @@ trait ConstraintHandling[AbstractContext] {
300
300
* (i.e. `inst.widenSingletons <:< bound` succeeds with satisfiable constraint)
301
301
* 2. If `inst` is a union type, approximate the union type from above by an intersection
302
302
* of all common base types, provided the result is a subtype of `bound`.
303
- * 3. (currently not enabled, see #9028) If `inst` is an intersection with some restricted base types, drop
304
- * the restricted base types from the intersection, provided the result is a subtype of `bound`.
303
+ * 3. If `inst` is an intersection such that some operands are super trait instances
304
+ * and others are not, replace as many super trait instances as possible with Any
305
+ * as long as the result is still a subtype of `bound`. But fall back to the
306
+ * original type if the resulting widened type is a supertype of all dropped
307
+ * types (since in this case the type was not a true intersection of super traits
308
+ * and other types to start with).
305
309
*
306
310
* Don't do these widenings if `bound` is a subtype of `scala.Singleton`.
307
311
* Also, if the result of these widenings is a TypeRef to a module class,
@@ -313,21 +317,38 @@ trait ConstraintHandling[AbstractContext] {
313
317
*/
314
318
def widenInferred (inst : Type , bound : Type )(implicit actx : AbstractContext ): Type =
315
319
316
- def isRestricted (tp : Type ) = tp.typeSymbol == defn.EnumValueClass // for now, to be generalized later
320
+ def dropSuperTraits (tp : Type ): Type =
321
+ var kept : Set [Type ] = Set () // types to keep since otherwise bound would not fit
322
+ var dropped : List [Type ] = List () // the types dropped so far, last one on top
323
+
324
+ def dropOneSuperTrait (tp : Type ): Type =
325
+ val tpd = tp.dealias
326
+ if tpd.typeSymbol.isSuperTrait && ! tpd.isLambdaSub && ! kept.contains(tpd) then
327
+ dropped = tpd :: dropped
328
+ defn.AnyType
329
+ else tpd match
330
+ case AndType (tp1, tp2) =>
331
+ val tp1w = dropOneSuperTrait(tp1)
332
+ if tp1w ne tp1 then tp1w & tp2
333
+ else
334
+ val tp2w = dropOneSuperTrait(tp2)
335
+ if tp2w ne tp2 then tp1 & tp2w
336
+ else tpd
337
+ case _ =>
338
+ tp
317
339
318
- def dropRestricted (tp : Type ): Type = tp.dealias match
319
- case tpd @ AndType (tp1, tp2) =>
320
- if isRestricted(tp1) then tp2
321
- else if isRestricted(tp2) then tp1
340
+ def recur (tp : Type ): Type =
341
+ val tpw = dropOneSuperTrait(tp)
342
+ if tpw eq tp then tp
343
+ else if tpw <:< bound then recur(tpw)
322
344
else
323
- val tpw = tpd.derivedAndType(dropRestricted(tp1), dropRestricted(tp2))
324
- if tpw ne tpd then tpw else tp
325
- case _ =>
326
- tp
345
+ kept += dropped.head
346
+ dropped = dropped.tail
347
+ recur(tp)
327
348
328
- def widenRestricted ( tp : Type ) =
329
- val tpw = dropRestricted( tp)
330
- if (tpw ne tp) && (tpw <:< bound) then tpw else tp
349
+ val tpw = recur(tp)
350
+ if ( tpw eq tp) || dropped.forall(_ frozen_ <:< tpw) then tp else tpw
351
+ end dropSuperTraits
331
352
332
353
def widenOr (tp : Type ) =
333
354
val tpw = tp.widenUnion
@@ -343,10 +364,7 @@ trait ConstraintHandling[AbstractContext] {
343
364
344
365
val wideInst =
345
366
if isSingleton(bound) then inst
346
- else /* widenRestricted*/ (widenOr(widenSingle(inst)))
347
- // widenRestricted is currently not called since it's special cased in `dropEnumValue`
348
- // in `Namer`. It's left in here in case we want to generalize the scheme to other
349
- // "protected inheritance" classes.
367
+ else dropSuperTraits(widenOr(widenSingle(inst)))
350
368
wideInst match
351
369
case wideInst : TypeRef if wideInst.symbol.is(Module ) =>
352
370
TermRef (wideInst.prefix, wideInst.symbol.sourceModule)
0 commit comments