@@ -327,9 +327,23 @@ struct LiteralExpander;
327
327
impl < ' tcx > PatternFolder < ' tcx > for LiteralExpander {
328
328
fn fold_pattern ( & mut self , pat : & Pat < ' tcx > ) -> Pat < ' tcx > {
329
329
debug ! ( "fold_pattern {:?} {:?} {:?}" , pat, pat. ty. kind( ) , pat. kind) ;
330
- match ( pat. ty . kind ( ) , & * pat. kind ) {
331
- ( _, & PatKind :: Binding { subpattern : Some ( ref s) , .. } ) => s. fold_with ( self ) ,
332
- ( _, & PatKind :: AscribeUserType { subpattern : ref s, .. } ) => s. fold_with ( self ) ,
330
+ match ( pat. ty . kind ( ) , pat. kind . as_ref ( ) ) {
331
+ ( _, PatKind :: Binding { subpattern : Some ( s) , .. } ) => s. fold_with ( self ) ,
332
+ ( _, PatKind :: AscribeUserType { subpattern : s, .. } ) => s. fold_with ( self ) ,
333
+ ( ty:: Ref ( _, t, _) , PatKind :: Constant { .. } ) if t. is_str ( ) => {
334
+ // Treat string literal patterns as deref patterns to a `str` constant, i.e.
335
+ // `&CONST`. This expands them like other const patterns. This could have been done
336
+ // in `const_to_pat`, but that causes issues with the rest of the matching code.
337
+ let mut new_pat = pat. super_fold_with ( self ) ;
338
+ // Make a fake const pattern of type `str` (instead of `&str`). That the carried
339
+ // constant value still knows it is of type `&str`.
340
+ new_pat. ty = t;
341
+ Pat {
342
+ kind : Box :: new ( PatKind :: Deref { subpattern : new_pat } ) ,
343
+ span : pat. span ,
344
+ ty : pat. ty ,
345
+ }
346
+ }
333
347
_ => pat. super_fold_with ( self ) ,
334
348
}
335
349
}
@@ -788,7 +802,7 @@ enum Constructor<'tcx> {
788
802
/// Fake extra constructor for enums that aren't allowed to be matched exhaustively.
789
803
NonExhaustive ,
790
804
/// Fake constructor for those types for which we can't list constructors explicitly, like
791
- /// `f64` and `& str`.
805
+ /// `f64` and `str`.
792
806
Unlistable ,
793
807
/// Wildcard pattern.
794
808
Wildcard ,
@@ -931,7 +945,12 @@ impl<'tcx> Constructor<'tcx> {
931
945
// Otherwise, only a wildcard pattern can match the special extra constructor.
932
946
( Unlistable , _) => false ,
933
947
934
- _ => bug ! ( "trying to compare incompatible constructors {:?} and {:?}" , self , other) ,
948
+ _ => span_bug ! (
949
+ pcx. span,
950
+ "trying to compare incompatible constructors {:?} and {:?}" ,
951
+ self ,
952
+ other
953
+ ) ,
935
954
}
936
955
}
937
956
@@ -1009,6 +1028,10 @@ impl<'tcx> Constructor<'tcx> {
1009
1028
PatKind :: Leaf { subpatterns }
1010
1029
}
1011
1030
}
1031
+ // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
1032
+ // be careful to reconstruct the correct constant pattern here. However a string
1033
+ // literal pattern will never be reported as a non-exhaustiveness witness, so we
1034
+ // can ignore this issue.
1012
1035
ty:: Ref ( ..) => PatKind :: Deref { subpattern : subpatterns. next ( ) . unwrap ( ) } ,
1013
1036
ty:: Slice ( _) | ty:: Array ( ..) => bug ! ( "bad slice pattern {:?} {:?}" , self , pcx. ty) ,
1014
1037
_ => PatKind :: Wild ,
@@ -1303,9 +1326,13 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
1303
1326
/// [Some(0), ..] => {}
1304
1327
/// }
1305
1328
/// ```
1329
+ /// This is guaranteed to preserve the number of patterns in `self`.
1306
1330
fn replace_with_pattern_arguments ( & self , pat : & ' p Pat < ' tcx > ) -> Self {
1307
1331
match pat. kind . as_ref ( ) {
1308
- PatKind :: Deref { subpattern } => Self :: from_single_pattern ( subpattern) ,
1332
+ PatKind :: Deref { subpattern } => {
1333
+ assert_eq ! ( self . len( ) , 1 ) ;
1334
+ Fields :: from_single_pattern ( subpattern)
1335
+ }
1309
1336
PatKind :: Leaf { subpatterns } | PatKind :: Variant { subpatterns, .. } => {
1310
1337
self . replace_with_fieldpats ( subpatterns)
1311
1338
}
@@ -1596,9 +1623,8 @@ fn all_constructors<'p, 'tcx>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Vec<Constructor<'tc
1596
1623
vec ! [ make_range( 0 , max) ]
1597
1624
}
1598
1625
_ if cx. is_uninhabited ( pcx. ty ) => vec ! [ ] ,
1599
- ty:: Adt ( ..) | ty:: Tuple ( ..) => vec ! [ Single ] ,
1600
- ty:: Ref ( _, t, _) if !t. is_str ( ) => vec ! [ Single ] ,
1601
- // This type is one for which we don't know how to list constructors, like `&str` or `f64`.
1626
+ ty:: Adt ( ..) | ty:: Tuple ( ..) | ty:: Ref ( ..) => vec ! [ Single ] ,
1627
+ // This type is one for which we don't know how to list constructors, like `str` or `f64`.
1602
1628
_ => vec ! [ Unlistable ] ,
1603
1629
}
1604
1630
}
@@ -2161,28 +2187,31 @@ fn pat_constructor<'p, 'tcx>(
2161
2187
cx : & MatchCheckCtxt < ' p , ' tcx > ,
2162
2188
pat : & ' p Pat < ' tcx > ,
2163
2189
) -> Constructor < ' tcx > {
2164
- match * pat. kind {
2190
+ match pat. kind . as_ref ( ) {
2165
2191
PatKind :: AscribeUserType { .. } => bug ! ( ) , // Handled by `expand_pattern`
2166
2192
PatKind :: Binding { .. } | PatKind :: Wild => Wildcard ,
2167
2193
PatKind :: Leaf { .. } | PatKind :: Deref { .. } => Single ,
2168
- PatKind :: Variant { adt_def, variant_index, .. } => {
2194
+ & PatKind :: Variant { adt_def, variant_index, .. } => {
2169
2195
Variant ( adt_def. variants [ variant_index] . def_id )
2170
2196
}
2171
2197
PatKind :: Constant { value } => {
2172
2198
if let Some ( int_range) = IntRange :: from_const ( cx. tcx , cx. param_env , value, pat. span ) {
2173
2199
IntRange ( int_range)
2174
2200
} else {
2175
- match value . ty . kind ( ) {
2201
+ match pat . ty . kind ( ) {
2176
2202
ty:: Float ( _) => FloatRange ( value, value, RangeEnd :: Included ) ,
2177
- ty:: Ref ( _, t, _) if t. is_str ( ) => Str ( value) ,
2203
+ // In `expand_pattern`, we convert string literals to `&CONST` patterns with
2204
+ // `CONST` a pattern of type `str`. In truth this contains a constant of type
2205
+ // `&str`.
2206
+ ty:: Str => Str ( value) ,
2178
2207
// All constants that can be structurally matched have already been expanded
2179
2208
// into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
2180
2209
// opaque.
2181
2210
_ => Opaque ,
2182
2211
}
2183
2212
}
2184
2213
}
2185
- PatKind :: Range ( PatRange { lo, hi, end } ) => {
2214
+ & PatKind :: Range ( PatRange { lo, hi, end } ) => {
2186
2215
let ty = lo. ty ;
2187
2216
if let Some ( int_range) = IntRange :: from_range (
2188
2217
cx. tcx ,
@@ -2197,8 +2226,7 @@ fn pat_constructor<'p, 'tcx>(
2197
2226
FloatRange ( lo, hi, end)
2198
2227
}
2199
2228
}
2200
- PatKind :: Array { ref prefix, ref slice, ref suffix }
2201
- | PatKind :: Slice { ref prefix, ref slice, ref suffix } => {
2229
+ PatKind :: Array { prefix, slice, suffix } | PatKind :: Slice { prefix, slice, suffix } => {
2202
2230
let array_len = match pat. ty . kind ( ) {
2203
2231
ty:: Array ( _, length) => Some ( length. eval_usize ( cx. tcx , cx. param_env ) ) ,
2204
2232
ty:: Slice ( _) => None ,
0 commit comments