@@ -300,8 +300,12 @@ trait ConstraintHandling[AbstractContext] {
300300 * (i.e. `inst.widenSingletons <:< bound` succeeds with satisfiable constraint)
301301 * 2. If `inst` is a union type, approximate the union type from above by an intersection
302302 * 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).
305309 *
306310 * Don't do these widenings if `bound` is a subtype of `scala.Singleton`.
307311 * Also, if the result of these widenings is a TypeRef to a module class,
@@ -313,21 +317,38 @@ trait ConstraintHandling[AbstractContext] {
313317 */
314318 def widenInferred (inst : Type , bound : Type )(implicit actx : AbstractContext ): Type =
315319
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
317339
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)
322344 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)
327348
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
331352
332353 def widenOr (tp : Type ) =
333354 val tpw = tp.widenUnion
@@ -343,10 +364,7 @@ trait ConstraintHandling[AbstractContext] {
343364
344365 val wideInst =
345366 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)))
350368 wideInst match
351369 case wideInst : TypeRef if wideInst.symbol.is(Module ) =>
352370 TermRef (wideInst.prefix, wideInst.symbol.sourceModule)
0 commit comments