@@ -94,38 +94,54 @@ trait PatternTypeConstrainer { self: TypeComparer =>
94
94
}
95
95
96
96
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 {
98
110
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)
102
117
case scrut @ AppliedType (tycon : TypeRef , _) if tycon.symbol.isClass =>
103
118
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 ] = {
106
121
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)
119
128
}
120
129
}
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
125
144
}
126
- if (upcasted.exists)
127
- constrainSimplePatternType(pat, upcasted) || constrainUpcasted(upcasted)
128
- else true
129
145
}
130
146
131
147
scrut.dealias match {
0 commit comments