@@ -94,38 +94,54 @@ trait PatternTypeConstrainer { self: TypeComparer =>
9494 }
9595
9696 def constrainUpcasted (scrut : Type ): Boolean = trace(i " constrainUpcasted( $scrut) " , gadts) {
97- val upcasted : Type = scrut match {
97+ // Fold a list of types into an AndType
98+ def buildAndType (xs : List [Type ]): Type = {
99+ @ annotation.tailrec def recur (acc : Type , rem : List [Type ]): Type = rem match {
100+ case Nil => acc
101+ case x :: rem => recur(AndType (acc, x), rem)
102+ }
103+ xs match {
104+ case Nil => NoType
105+ case x :: xs => recur(x, xs)
106+ }
107+ }
108+
109+ scrut match {
98110 case scrut : TypeRef if scrut.symbol.isClass =>
99- // we do not infer constraints following from all parents for performance reasons
100- // in principle however, if `A extends B, C`, then `A` can be treated as `B & C`
101- scrut.firstParent
111+ // consider all parents
112+ val parents = scrut.parents
113+ val andType = trace(i " andType of scrut " , gadts) {
114+ buildAndType(parents)
115+ }
116+ constrainPatternType(pat, andType)
102117 case scrut @ AppliedType (tycon : TypeRef , _) if tycon.symbol.isClass =>
103118 val patClassSym = pat.classSymbol
104- // as above, we do not consider all parents for performance reasons
105- def firstParentSharedWithPat (tp : Type , tpClassSym : ClassSymbol ): Symbol = {
119+ // find all shared parents in the inheritance hierarchy between pat and scrut
120+ def allParentsSharedWithPat (tp : Type , tpClassSym : ClassSymbol ): List [ Symbol ] = {
106121 var parents = tpClassSym.info.parents
107- parents match {
108- case first :: rest =>
109- if (first.classSymbol == defn.ObjectClass ) parents = rest
110- case _ => ;
111- }
112- parents match {
113- case first :: _ =>
114- val firstClassSym = first.classSymbol.asClass
115- val res = if (patClassSym.derivesFrom(firstClassSym)) firstClassSym
116- else firstParentSharedWithPat(first, firstClassSym)
117- res
118- case _ => NoSymbol
122+ if parents.nonEmpty && parents.head.classSymbol == defn.ObjectClass then
123+ parents = parents.tail
124+ parents flatMap { tp =>
125+ val sym = tp.classSymbol.asClass
126+ if patClassSym.derivesFrom(sym) then List (sym)
127+ else allParentsSharedWithPat(tp, sym)
119128 }
120129 }
121- val sym = firstParentSharedWithPat(tycon, tycon.symbol.asClass)
122- if (sym.exists) scrut.baseType(sym) else NoType
123- case scrut : TypeProxy => scrut.superType
124- case _ => NoType
130+ val allSyms = allParentsSharedWithPat(tycon, tycon.symbol.asClass)
131+ val baseClasses = allSyms map scrut.baseType
132+ val andType = trace(i " andType of scrut " , gadts) {
133+ buildAndType(baseClasses)
134+ }
135+ constrainPatternType(pat, andType)
136+ case _ =>
137+ val upcasted : Type = scrut match {
138+ case scrut : TypeProxy => scrut.superType
139+ case _ => NoType
140+ }
141+ if (upcasted.exists)
142+ constrainSimplePatternType(pat, upcasted) || constrainUpcasted(upcasted)
143+ else true
125144 }
126- if (upcasted.exists)
127- constrainSimplePatternType(pat, upcasted) || constrainUpcasted(upcasted)
128- else true
129145 }
130146
131147 scrut.dealias match {
0 commit comments