@@ -150,41 +150,22 @@ object Inferencing {
150
150
tree
151
151
}
152
152
153
- /** Derive information about a pattern type by comparing it with some variant of the
154
- * static scrutinee type. We have the following situation in case of a (dynamic) pattern match:
153
+ /** Infer constraints that should be in scope for a case body with given pattern and scrutinee types.
155
154
*
156
- * StaticScrutineeType PatternType
157
- * \ /
158
- * DynamicScrutineeType
155
+ * If `termPattern`, infer constraints from knowing that there exists a value which of both scrutinee
156
+ * and pattern types (which is the case for normal pattern matching). If not `termPattern`, instead
157
+ * infer constraints from knowing that `tp <: pt`.
159
158
*
160
- * If `PatternType` is not a subtype of `StaticScrutineeType, there's no information to be gained.
161
- * Now let's say we can prove that `PatternType <: StaticScrutineeType`.
159
+ * If a pattern matches during normal pattern matching, we can be certain that there exists a value
160
+ * which is of both scrutinee and pattern types (the value we're matching on). If this value
161
+ * was in a variable, say `x`, then we could simply infer constraints from `x.type <: pt`. Since we might
162
+ * be matching on an expression as well, we take a skolem of the scrutinee, which is essentially an existential
163
+ * singleton type (see [[dotty.tools.dotc.core.Types.SkolemType ]]).
162
164
*
163
- * StaticScrutineeType
164
- * | \
165
- * | \
166
- * | \
167
- * | PatternType
168
- * | /
169
- * DynamicScrutineeType
170
- *
171
- * What can we say about the relationship of parameter types between `PatternType` and
172
- * `DynamicScrutineeType`?
173
- *
174
- * - If `DynamicScrutineeType` refines the type parameters of `StaticScrutineeType`
175
- * in the same way as `PatternType` ("invariant refinement"), the subtype test
176
- * `PatternType <:< StaticScrutineeType` tells us all we need to know.
177
- * - Otherwise, if variant refinement is a possibility we can only make predictions
178
- * about invariant parameters of `StaticScrutineeType`. Hence we do a subtype test
179
- * where `PatternType <: widenVariantParams(StaticScrutineeType)`, where `widenVariantParams`
180
- * replaces all type argument of variant parameters with empty bounds.
181
- *
182
- * Invariant refinement can be assumed if `PatternType`'s class(es) are final or
183
- * case classes (because of `RefChecks#checkCaseClassInheritanceInvariant`).
184
- *
185
- * TODO: Update so that GADT symbols can be variant, and we special case final class types in patterns
165
+ * Note that we need to sometimes widen type parameters of the scrutinee type to avoid unsoundness -
166
+ * see i3989c.scala and related issue discussion on Github.
186
167
*/
187
- def constrainPatternType (tp : Type , pt : Type )(implicit ctx : Context ): Boolean = {
168
+ def constrainPatternType (tp : Type , pt : Type , termPattern : Boolean )(implicit ctx : Context ): Boolean = {
188
169
def refinementIsInvariant (tp : Type ): Boolean = tp match {
189
170
case tp : ClassInfo => tp.cls.is(Final ) || tp.cls.is(Case )
190
171
case tp : TypeProxy => refinementIsInvariant(tp.underlying)
@@ -206,8 +187,9 @@ object Inferencing {
206
187
}
207
188
208
189
val widePt = if (ctx.scala2Mode || refinementIsInvariant(tp)) pt else widenVariantParams(pt)
209
- trace(i " constraining pattern type $tp <:< $widePt" , gadts, res => s " $res\n ${ctx.gadt.debugBoundsDescription}" ) {
210
- tp <:< widePt
190
+ val narrowTp = if (termPattern) SkolemType (tp) else tp
191
+ trace(i " constraining pattern type $narrowTp <:< $widePt" , gadts, res => s " $res\n ${ctx.gadt.debugBoundsDescription}" ) {
192
+ narrowTp <:< widePt
211
193
}
212
194
}
213
195
0 commit comments