@@ -830,23 +830,23 @@ object Types {
830830 * def o: Outer
831831 * <o.x.type>.widen = o.C
832832 */
833- @ tailrec final def widen (implicit ctx : Context ): Type = widenSingleton match {
833+ final def widen (implicit ctx : Context ): Type = widenSingleton match {
834834 case tp : ExprType => tp.resultType.widen
835835 case tp => tp
836836 }
837837
838838 /** Widen from singleton type to its underlying non-singleton
839839 * base type by applying one or more `underlying` dereferences.
840840 */
841- @ tailrec final def widenSingleton (implicit ctx : Context ): Type = stripTypeVar match {
841+ final def widenSingleton (implicit ctx : Context ): Type = stripTypeVar match {
842842 case tp : SingletonType if ! tp.isOverloaded => tp.underlying.widenSingleton
843843 case _ => this
844844 }
845845
846846 /** Widen from TermRef to its underlying non-termref
847847 * base type, while also skipping Expr types.
848848 */
849- @ tailrec final def widenTermRefExpr (implicit ctx : Context ): Type = stripTypeVar match {
849+ final def widenTermRefExpr (implicit ctx : Context ): Type = stripTypeVar match {
850850 case tp : TermRef if ! tp.isOverloaded => tp.underlying.widenExpr.widenTermRefExpr
851851 case _ => this
852852 }
@@ -860,7 +860,7 @@ object Types {
860860 }
861861
862862 /** Widen type if it is unstable (i.e. an ExprType, or TermRef to unstable symbol */
863- @ tailrec final def widenIfUnstable (implicit ctx : Context ): Type = stripTypeVar match {
863+ final def widenIfUnstable (implicit ctx : Context ): Type = stripTypeVar match {
864864 case tp : ExprType => tp.resultType.widenIfUnstable
865865 case tp : TermRef if ! tp.symbol.isStable => tp.underlying.widenIfUnstable
866866 case _ => this
@@ -872,6 +872,35 @@ object Types {
872872 case _ => this
873873 }
874874
875+ /** If this type contains embedded union types, replace them by their joins.
876+ * "Embedded" means: inside intersectons or recursive types, or in prefixes of refined types.
877+ * If an embedded union is found, we first try to simplify or eliminate it by
878+ * re-lubbing it while allowing type parameters to be constrained further.
879+ * Any remaining union types are replaced by their joins.
880+ *
881+ * For instance, if `A` is an unconstrained type variable, then
882+ *
883+ * ArrayBuffer[Int] | ArrayBuffer[A]
884+ *
885+ * is approximated by constraining `A` to be =:= to `Int` and returning `ArrayBuffer[Int]`
886+ * instead of `ArrayBuffer[_ >: Int | A <: Int & A]`
887+ */
888+ def widenUnion (implicit ctx : Context ): Type = this match {
889+ case OrType (tp1, tp2) =>
890+ ctx.typeComparer.lub(tp1.widenUnion, tp2.widenUnion, canConstrain = true ) match {
891+ case union : OrType => union.join
892+ case res => res
893+ }
894+ case tp @ AndType (tp1, tp2) =>
895+ tp derived_& (tp1.widenUnion, tp2.widenUnion)
896+ case tp : RefinedType =>
897+ tp.derivedRefinedType(tp.parent.widenUnion, tp.refinedName, tp.refinedInfo)
898+ case tp : RecType =>
899+ tp.rebind(tp.parent.widenUnion)
900+ case _ =>
901+ this
902+ }
903+
875904 /** Eliminate anonymous classes */
876905 final def deAnonymize (implicit ctx : Context ): Type = this match {
877906 case tp: TypeRef if tp.symbol.isAnonymousClass =>
0 commit comments