@@ -74,106 +74,127 @@ trait PatternTypeConstrainer { self: TypeComparer =>
74
74
* scrutinee and pattern types. This does not apply if the pattern type is only applied to type variables,
75
75
* in which case the subtyping relationship "heals" the type.
76
76
*/
77
- def constrainPatternType (pat : Type , scrut : Type , forceInvariantRefinement : Boolean = false , typeMembersTouched : Boolean = false ): Boolean = trace(i " constrainPatternType( ${scrutRepr(scrut)}, $pat) " , gadts, res => s " $res\n gadt = ${ctx.gadt.debugBoundsDescription}" ) {
78
-
79
- def classesMayBeCompatible : Boolean = {
80
- import Flags ._
81
- val patCls = pat.classSymbol
82
- val scrCls = scrut.classSymbol
83
- ! patCls.exists || ! scrCls.exists || {
84
- if (patCls.is(Final )) patCls.derivesFrom(scrCls)
85
- else if (scrCls.is(Final )) scrCls.derivesFrom(patCls)
86
- else if (! patCls.is(Flags .Trait ) && ! scrCls.is(Flags .Trait ))
87
- patCls.derivesFrom(scrCls) || scrCls.derivesFrom(patCls)
88
- else true
77
+ def constrainPatternType (pat : Type , scrut : Type , forceInvariantRefinement : Boolean = false ): Boolean = trace(i " constrainPatternType( ${scrutRepr(scrut)}, $pat) " , gadts, res => s " $res\n gadt = ${ctx.gadt.debugBoundsDescription}" ) {
78
+ def recur (pat : Type , scrut : Type ): Boolean = {
79
+ def classesMayBeCompatible : Boolean = {
80
+ import Flags ._
81
+ val patCls = pat.classSymbol
82
+ val scrCls = scrut.classSymbol
83
+ ! patCls.exists || ! scrCls.exists || {
84
+ if (patCls.is(Final )) patCls.derivesFrom(scrCls)
85
+ else if (scrCls.is(Final )) scrCls.derivesFrom(patCls)
86
+ else if (! patCls.is(Flags .Trait ) && ! scrCls.is(Flags .Trait ))
87
+ patCls.derivesFrom(scrCls) || scrCls.derivesFrom(patCls)
88
+ else true
89
+ }
89
90
}
90
- }
91
-
92
- def stripRefinement (tp : Type ): Type = tp match {
93
- case tp : RefinedOrRecType => stripRefinement(tp.parent)
94
- case tp => tp
95
- }
96
91
97
- def tryConstrainSimplePatternType (pat : Type , scrut : Type ) = {
98
- val patCls = pat.classSymbol
99
- val scrCls = scrut.classSymbol
100
- patCls.exists && scrCls.exists
101
- && (patCls.derivesFrom(scrCls) || scrCls.derivesFrom(patCls))
102
- && constrainSimplePatternType(pat, scrut, forceInvariantRefinement)
103
- }
92
+ def stripRefinement (tp : Type ): Type = tp match {
93
+ case tp : RefinedOrRecType => stripRefinement(tp.parent)
94
+ case tp => tp
95
+ }
104
96
105
- def constrainUpcasted (scrut : Type ): Boolean = trace(i " constrainUpcasted( $scrut) " , gadts) {
106
- // Fold a list of types into an AndType
107
- def buildAndType (xs : List [Type ]): Type = {
108
- @ annotation.tailrec def recur (acc : Type , rem : List [Type ]): Type = rem match {
109
- case Nil => acc
110
- case x :: rem => recur(AndType (acc, x), rem)
111
- }
112
- xs match {
113
- case Nil => NoType
114
- case x :: xs => recur(x, xs)
115
- }
97
+ def tryConstrainSimplePatternType (pat : Type , scrut : Type ) = {
98
+ val patCls = pat.classSymbol
99
+ val scrCls = scrut.classSymbol
100
+ patCls.exists && scrCls.exists
101
+ && (patCls.derivesFrom(scrCls) || scrCls.derivesFrom(patCls))
102
+ && constrainSimplePatternType(pat, scrut, forceInvariantRefinement)
116
103
}
117
104
118
- scrut match {
119
- case scrut : TypeRef if scrut.symbol.isClass =>
120
- // consider all parents
121
- val parents = scrut.parents
122
- val andType = buildAndType(parents)
123
- ! andType.exists || constrainPatternType(pat, andType, typeMembersTouched = true )
124
- case scrut @ AppliedType (tycon : TypeRef , _) if tycon.symbol.isClass =>
125
- val patCls = pat.classSymbol
126
- // find all shared parents in the inheritance hierarchy between pat and scrut
127
- def allParentsSharedWithPat (tp : Type , tpClassSym : ClassSymbol ): List [Symbol ] = {
128
- var parents = tpClassSym.info.parents
129
- if parents.nonEmpty && parents.head.classSymbol == defn.ObjectClass then
130
- parents = parents.tail
131
- parents flatMap { tp =>
132
- val sym = tp.classSymbol.asClass
133
- if patCls.derivesFrom(sym) then List (sym)
134
- else allParentsSharedWithPat(tp, sym)
135
- }
105
+ def constrainUpcasted (scrut : Type ): Boolean = trace(i " constrainUpcasted( $scrut) " , gadts) {
106
+ // Fold a list of types into an AndType
107
+ def buildAndType (xs : List [Type ]): Type = {
108
+ @ annotation.tailrec def recur (acc : Type , rem : List [Type ]): Type = rem match {
109
+ case Nil => acc
110
+ case x :: rem => recur(AndType (acc, x), rem)
136
111
}
137
- val allSyms = allParentsSharedWithPat(tycon, tycon.symbol.asClass)
138
- val baseClasses = allSyms map scrut.baseType
139
- val andType = buildAndType(baseClasses)
140
- ! andType.exists || constrainPatternType(pat, andType, typeMembersTouched = true )
141
- case _ =>
142
- def tryGadtBounds = scrut match {
143
- case scrut : TypeRef =>
144
- ctx.gadt.bounds(scrut.symbol) match {
145
- case tb : TypeBounds =>
146
- val hi = tb.hi
147
- constrainPatternType(pat, hi, typeMembersTouched = true )
148
- case null => true
149
- }
150
- case _ => true
112
+ xs match {
113
+ case Nil => NoType
114
+ case x :: xs => recur(x, xs)
151
115
}
116
+ }
152
117
153
- def trySuperType =
154
- val upcasted : Type = scrut match {
155
- case scrut : TypeProxy =>
156
- scrut.superType
157
- case _ => NoType
118
+ scrut match {
119
+ case scrut : TypeRef if scrut.symbol.isClass =>
120
+ // consider all parents
121
+ val parents = scrut.parents
122
+ val andType = buildAndType(parents)
123
+ ! andType.exists || recur(pat, andType)
124
+ case scrut @ AppliedType (tycon : TypeRef , _) if tycon.symbol.isClass =>
125
+ val patCls = pat.classSymbol
126
+ // find all shared parents in the inheritance hierarchy between pat and scrut
127
+ def allParentsSharedWithPat (tp : Type , tpClassSym : ClassSymbol ): List [Symbol ] = {
128
+ var parents = tpClassSym.info.parents
129
+ if parents.nonEmpty && parents.head.classSymbol == defn.ObjectClass then
130
+ parents = parents.tail
131
+ parents flatMap { tp =>
132
+ val sym = tp.classSymbol.asClass
133
+ if patCls.derivesFrom(sym) then List (sym)
134
+ else allParentsSharedWithPat(tp, sym)
135
+ }
136
+ }
137
+ val allSyms = allParentsSharedWithPat(tycon, tycon.symbol.asClass)
138
+ val baseClasses = allSyms map scrut.baseType
139
+ val andType = buildAndType(baseClasses)
140
+ ! andType.exists || recur(pat, andType)
141
+ case _ =>
142
+ def tryGadtBounds = scrut match {
143
+ case scrut : TypeRef =>
144
+ ctx.gadt.bounds(scrut.symbol) match {
145
+ case tb : TypeBounds =>
146
+ val hi = tb.hi
147
+ recur(pat, hi)
148
+ case null => true
149
+ }
150
+ case _ => true
158
151
}
159
- if (upcasted.exists)
160
- tryConstrainSimplePatternType(pat, upcasted) || constrainUpcasted(upcasted)
161
- else true
162
152
163
- tryGadtBounds && trySuperType
153
+ def trySuperType =
154
+ val upcasted : Type = scrut match {
155
+ case scrut : TypeProxy =>
156
+ scrut.superType
157
+ case _ => NoType
158
+ }
159
+ if (upcasted.exists)
160
+ tryConstrainSimplePatternType(pat, upcasted) || constrainUpcasted(upcasted)
161
+ else true
162
+
163
+ tryGadtBounds && trySuperType
164
+ }
165
+ }
166
+
167
+ def dealiasDropNonmoduleRefs (tp : Type ) = tp.dealias match {
168
+ case tp : TermRef =>
169
+ // we drop TermRefs that don't have a class symbol, as they can't
170
+ // meaningfully participate in GADT reasoning and just get in the way.
171
+ // Their info could, for an example, be an AndType. One example where
172
+ // this is important is an enum case that extends its parent and an
173
+ // additional trait - argument-less enum cases desugar to vals.
174
+ // See run/enum-Tree.scala.
175
+ if tp.classSymbol.exists then tp else tp.info
176
+ case tp => tp
164
177
}
165
- }
166
178
167
- def dealiasDropNonmoduleRefs (tp : Type ) = tp.dealias match {
168
- case tp : TermRef =>
169
- // we drop TermRefs that don't have a class symbol, as they can't
170
- // meaningfully participate in GADT reasoning and just get in the way.
171
- // Their info could, for an example, be an AndType. One example where
172
- // this is important is an enum case that extends its parent and an
173
- // additional trait - argument-less enum cases desugar to vals.
174
- // See run/enum-Tree.scala.
175
- if tp.classSymbol.exists then tp else tp.info
176
- case tp => tp
179
+ dealiasDropNonmoduleRefs(scrut) match {
180
+ case OrType (scrut1, scrut2) =>
181
+ either(recur(pat, scrut1), recur(pat, scrut2))
182
+ case AndType (scrut1, scrut2) =>
183
+ recur(pat, scrut1) && recur(pat, scrut2)
184
+ case scrut : RefinedOrRecType =>
185
+ recur(pat, stripRefinement(scrut))
186
+ case scrut => dealiasDropNonmoduleRefs(pat) match {
187
+ case OrType (pat1, pat2) =>
188
+ either(recur(pat1, scrut), recur(pat2, scrut))
189
+ case AndType (pat1, pat2) =>
190
+ recur(pat1, scrut) && recur(pat2, scrut)
191
+ case pat : RefinedOrRecType =>
192
+ recur(stripRefinement(pat), scrut)
193
+ case pat =>
194
+ tryConstrainSimplePatternType(pat, scrut)
195
+ || classesMayBeCompatible && constrainUpcasted(scrut)
196
+ }
197
+ }
177
198
}
178
199
179
200
/** Reconstruct subtype constraints for type members of the scrutinee and the pattern. */
@@ -269,28 +290,7 @@ trait PatternTypeConstrainer { self: TypeComparer =>
269
290
res
270
291
}
271
292
272
- def constrainTypeParams =
273
- dealiasDropNonmoduleRefs(scrut) match {
274
- case OrType (scrut1, scrut2) =>
275
- either(constrainPatternType(pat, scrut1, typeMembersTouched = true ), constrainPatternType(pat, scrut2, typeMembersTouched = true ))
276
- case AndType (scrut1, scrut2) =>
277
- constrainPatternType(pat, scrut1, typeMembersTouched = true ) && constrainPatternType(pat, scrut2, typeMembersTouched = true )
278
- case scrut : RefinedOrRecType =>
279
- constrainPatternType(pat, stripRefinement(scrut), typeMembersTouched = true )
280
- case scrut => dealiasDropNonmoduleRefs(pat) match {
281
- case OrType (pat1, pat2) =>
282
- either(constrainPatternType(pat1, scrut, typeMembersTouched = true ), constrainPatternType(pat2, scrut, typeMembersTouched = true ))
283
- case AndType (pat1, pat2) =>
284
- constrainPatternType(pat1, scrut, typeMembersTouched = true ) && constrainPatternType(pat2, scrut, typeMembersTouched = true )
285
- case pat : RefinedOrRecType =>
286
- constrainPatternType(stripRefinement(pat), scrut, typeMembersTouched = true )
287
- case pat =>
288
- tryConstrainSimplePatternType(pat, scrut)
289
- || classesMayBeCompatible && constrainUpcasted(scrut)
290
- }
291
- }
292
-
293
- constrainTypeParams && (typeMembersTouched || constrainTypeMembers)
293
+ recur(pat, scrut) && constrainTypeMembers
294
294
}
295
295
296
296
/** Show the scrutinee. Will show the path if available. */
0 commit comments