@@ -4,6 +4,7 @@ mod check_match;
44mod const_to_pat;
55mod migration;
66
7+ use std:: assert_matches:: assert_matches;
78use std:: cmp:: Ordering ;
89use std:: sync:: Arc ;
910
@@ -21,7 +22,7 @@ use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment};
2122use rustc_middle:: ty:: layout:: IntegerExt ;
2223use rustc_middle:: ty:: { self , CanonicalUserTypeAnnotation , Ty , TyCtxt } ;
2324use rustc_middle:: { bug, span_bug} ;
24- use rustc_span:: { ErrorGuaranteed , Span } ;
25+ use rustc_span:: ErrorGuaranteed ;
2526use tracing:: { debug, instrument} ;
2627
2728pub ( crate ) use self :: check_match:: check_match;
@@ -129,15 +130,20 @@ impl<'tcx> PatCtxt<'tcx> {
129130
130131 fn lower_pattern_range_endpoint (
131132 & mut self ,
133+ pat : & ' tcx hir:: Pat < ' tcx > , // Range pattern containing the endpoint
132134 expr : Option < & ' tcx hir:: PatExpr < ' tcx > > ,
133135 // Out-parameter collecting extra data to be reapplied by the caller
134136 ascriptions : & mut Vec < Ascription < ' tcx > > ,
135137 ) -> Result < Option < PatRangeBoundary < ' tcx > > , ErrorGuaranteed > {
138+ assert_matches ! ( pat. kind, hir:: PatKind :: Range ( ..) ) ;
139+
140+ // For partly-bounded ranges like `X..` or `..X`, an endpoint will be absent.
141+ // Return None in that case; the caller will use NegInfinity or PosInfinity instead.
136142 let Some ( expr) = expr else { return Ok ( None ) } ;
137143
138144 // Lower the endpoint into a temporary `PatKind` that will then be
139145 // deconstructed to obtain the constant value and other data.
140- let mut kind: PatKind < ' tcx > = self . lower_pat_expr ( expr , None ) ;
146+ let mut kind: PatKind < ' tcx > = self . lower_pat_expr ( pat , expr ) ;
141147
142148 // Unpeel any ascription or inline-const wrapper nodes.
143149 loop {
@@ -214,20 +220,23 @@ impl<'tcx> PatCtxt<'tcx> {
214220
215221 fn lower_pattern_range (
216222 & mut self ,
223+ pat : & ' tcx hir:: Pat < ' tcx > ,
217224 lo_expr : Option < & ' tcx hir:: PatExpr < ' tcx > > ,
218225 hi_expr : Option < & ' tcx hir:: PatExpr < ' tcx > > ,
219226 end : RangeEnd ,
220- ty : Ty < ' tcx > ,
221- span : Span ,
222227 ) -> Result < PatKind < ' tcx > , ErrorGuaranteed > {
228+ let ty = self . typeck_results . node_type ( pat. hir_id ) ;
229+ let span = pat. span ;
230+
223231 if lo_expr. is_none ( ) && hi_expr. is_none ( ) {
224232 let msg = "found twice-open range pattern (`..`) outside of error recovery" ;
225233 self . tcx . dcx ( ) . span_bug ( span, msg) ;
226234 }
227235
228236 // Collect extra data while lowering the endpoints, to be reapplied later.
229237 let mut ascriptions = vec ! [ ] ;
230- let mut lower_endpoint = |expr| self . lower_pattern_range_endpoint ( expr, & mut ascriptions) ;
238+ let mut lower_endpoint =
239+ |expr| self . lower_pattern_range_endpoint ( pat, expr, & mut ascriptions) ;
231240
232241 let lo = lower_endpoint ( lo_expr) ?. unwrap_or ( PatRangeBoundary :: NegInfinity ) ;
233242 let hi = lower_endpoint ( hi_expr) ?. unwrap_or ( PatRangeBoundary :: PosInfinity ) ;
@@ -299,12 +308,10 @@ impl<'tcx> PatCtxt<'tcx> {
299308
300309 hir:: PatKind :: Never => PatKind :: Never ,
301310
302- hir:: PatKind :: Expr ( value) => self . lower_pat_expr ( value , Some ( ty ) ) ,
311+ hir:: PatKind :: Expr ( value) => self . lower_pat_expr ( pat , value ) ,
303312
304- hir:: PatKind :: Range ( ref lo_expr, ref hi_expr, end) => {
305- let ( lo_expr, hi_expr) = ( lo_expr. as_deref ( ) , hi_expr. as_deref ( ) ) ;
306- self . lower_pattern_range ( lo_expr, hi_expr, end, ty, span)
307- . unwrap_or_else ( PatKind :: Error )
313+ hir:: PatKind :: Range ( lo_expr, hi_expr, end) => {
314+ self . lower_pattern_range ( pat, lo_expr, hi_expr, end) . unwrap_or_else ( PatKind :: Error )
308315 }
309316
310317 hir:: PatKind :: Deref ( subpattern) => {
@@ -327,7 +334,7 @@ impl<'tcx> PatCtxt<'tcx> {
327334 } ,
328335
329336 hir:: PatKind :: Slice ( prefix, slice, suffix) => {
330- self . slice_or_array_pattern ( pat. span , ty , prefix, slice, suffix)
337+ self . slice_or_array_pattern ( pat, prefix, slice, suffix)
331338 }
332339
333340 hir:: PatKind :: Tuple ( pats, ddpos) => {
@@ -389,7 +396,7 @@ impl<'tcx> PatCtxt<'tcx> {
389396 } ;
390397 let variant_def = adt_def. variant_of_res ( res) ;
391398 let subpatterns = self . lower_tuple_subpats ( pats, variant_def. fields . len ( ) , ddpos) ;
392- self . lower_variant_or_leaf ( res , pat. hir_id , pat . span , ty , subpatterns)
399+ self . lower_variant_or_leaf ( pat, None , res , subpatterns)
393400 }
394401
395402 hir:: PatKind :: Struct ( ref qpath, fields, _) => {
@@ -406,7 +413,7 @@ impl<'tcx> PatCtxt<'tcx> {
406413 } )
407414 . collect ( ) ;
408415
409- self . lower_variant_or_leaf ( res , pat. hir_id , pat . span , ty , subpatterns)
416+ self . lower_variant_or_leaf ( pat, None , res , subpatterns)
410417 }
411418
412419 hir:: PatKind :: Or ( pats) => PatKind :: Or { pats : self . lower_patterns ( pats) } ,
@@ -445,12 +452,13 @@ impl<'tcx> PatCtxt<'tcx> {
445452
446453 fn slice_or_array_pattern (
447454 & mut self ,
448- span : Span ,
449- ty : Ty < ' tcx > ,
455+ pat : & ' tcx hir:: Pat < ' tcx > ,
450456 prefix : & ' tcx [ hir:: Pat < ' tcx > ] ,
451457 slice : Option < & ' tcx hir:: Pat < ' tcx > > ,
452458 suffix : & ' tcx [ hir:: Pat < ' tcx > ] ,
453459 ) -> PatKind < ' tcx > {
460+ let ty = self . typeck_results . node_type ( pat. hir_id ) ;
461+
454462 let prefix = self . lower_patterns ( prefix) ;
455463 let slice = self . lower_opt_pattern ( slice) ;
456464 let suffix = self . lower_patterns ( suffix) ;
@@ -465,18 +473,32 @@ impl<'tcx> PatCtxt<'tcx> {
465473 assert ! ( len >= prefix. len( ) as u64 + suffix. len( ) as u64 ) ;
466474 PatKind :: Array { prefix, slice, suffix }
467475 }
468- _ => span_bug ! ( span, "bad slice pattern type {:?}" , ty ) ,
476+ _ => span_bug ! ( pat . span, "bad slice pattern type {ty :?}" ) ,
469477 }
470478 }
471479
472480 fn lower_variant_or_leaf (
473481 & mut self ,
482+ pat : & ' tcx hir:: Pat < ' tcx > ,
483+ expr : Option < & ' tcx hir:: PatExpr < ' tcx > > ,
474484 res : Res ,
475- hir_id : hir:: HirId ,
476- span : Span ,
477- ty : Ty < ' tcx > ,
478485 subpatterns : Vec < FieldPat < ' tcx > > ,
479486 ) -> PatKind < ' tcx > {
487+ // Check whether the caller should have provided an `expr` for this pattern kind.
488+ assert_matches ! (
489+ ( pat. kind, expr) ,
490+ ( hir:: PatKind :: Expr ( ..) | hir:: PatKind :: Range ( ..) , Some ( _) )
491+ | ( hir:: PatKind :: Struct ( ..) | hir:: PatKind :: TupleStruct ( ..) , None )
492+ ) ;
493+
494+ // Use the id/span of the `hir::PatExpr`, if provided.
495+ // Otherwise, use the id/span of the `hir::Pat`.
496+ let ( hir_id, span) = match expr {
497+ Some ( expr) => ( expr. hir_id , expr. span ) ,
498+ None => ( pat. hir_id , pat. span ) ,
499+ } ;
500+ let ty = self . typeck_results . node_type ( hir_id) ;
501+
480502 let res = match res {
481503 Res :: Def ( DefKind :: Ctor ( CtorOf :: Variant , ..) , variant_ctor_id) => {
482504 let variant_id = self . tcx . parent ( variant_ctor_id) ;
@@ -563,7 +585,16 @@ impl<'tcx> PatCtxt<'tcx> {
563585 /// it to `const_to_pat`. Any other path (like enum variants without fields)
564586 /// is converted to the corresponding pattern via `lower_variant_or_leaf`.
565587 #[ instrument( skip( self ) , level = "debug" ) ]
566- fn lower_path ( & mut self , qpath : & hir:: QPath < ' _ > , id : hir:: HirId , span : Span ) -> Box < Pat < ' tcx > > {
588+ fn lower_path (
589+ & mut self ,
590+ pat : & ' tcx hir:: Pat < ' tcx > , // Pattern that directly contains `expr`
591+ expr : & ' tcx hir:: PatExpr < ' tcx > ,
592+ qpath : & hir:: QPath < ' _ > ,
593+ ) -> Box < Pat < ' tcx > > {
594+ assert_matches ! ( pat. kind, hir:: PatKind :: Expr ( ..) | hir:: PatKind :: Range ( ..) ) ;
595+
596+ let id = expr. hir_id ;
597+ let span = expr. span ;
567598 let ty = self . typeck_results . node_type ( id) ;
568599 let res = self . typeck_results . qpath_res ( qpath, id) ;
569600
@@ -575,7 +606,7 @@ impl<'tcx> PatCtxt<'tcx> {
575606 _ => {
576607 // The path isn't the name of a constant, so it must actually
577608 // be a unit struct or unit variant (e.g. `Option::None`).
578- let kind = self . lower_variant_or_leaf ( res , id , span , ty , vec ! [ ] ) ;
609+ let kind = self . lower_variant_or_leaf ( pat , Some ( expr ) , res , vec ! [ ] ) ;
579610 return Box :: new ( Pat { span, ty, kind } ) ;
580611 }
581612 } ;
@@ -615,24 +646,26 @@ impl<'tcx> PatCtxt<'tcx> {
615646 /// - Literals, possibly negated (e.g. `-128u8`, `"hello"`)
616647 fn lower_pat_expr (
617648 & mut self ,
649+ pat : & ' tcx hir:: Pat < ' tcx > , // Pattern that directly contains `expr`
618650 expr : & ' tcx hir:: PatExpr < ' tcx > ,
619- pat_ty : Option < Ty < ' tcx > > ,
620651 ) -> PatKind < ' tcx > {
652+ assert_matches ! ( pat. kind, hir:: PatKind :: Expr ( ..) | hir:: PatKind :: Range ( ..) ) ;
621653 match & expr. kind {
622- hir:: PatExprKind :: Path ( qpath) => self . lower_path ( qpath , expr. hir_id , expr . span ) . kind ,
654+ hir:: PatExprKind :: Path ( qpath) => self . lower_path ( pat , expr, qpath ) . kind ,
623655 hir:: PatExprKind :: Lit { lit, negated } => {
624656 // We handle byte string literal patterns by using the pattern's type instead of the
625657 // literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference,
626658 // the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the
627659 // pattern's type means we'll properly translate it to a slice reference pattern. This works
628660 // because slices and arrays have the same valtree representation.
629- let ct_ty = match pat_ty {
630- Some ( pat_ty) => pat_ty,
631- None => self . typeck_results . node_type ( expr. hir_id ) ,
632- } ;
633- let lit_input = LitToConstInput { lit : lit. node , ty : ct_ty, neg : * negated } ;
661+ //
662+ // Under `feature(deref_patterns)`, this adjustment can also convert string literal
663+ // patterns to `str`, and byte-string literal patterns to `[u8; N]` or `[u8]`.
664+
665+ let pat_ty = self . typeck_results . node_type ( pat. hir_id ) ;
666+ let lit_input = LitToConstInput { lit : lit. node , ty : pat_ty, neg : * negated } ;
634667 let constant = self . tcx . at ( expr. span ) . lit_to_const ( lit_input) ;
635- self . const_to_pat ( constant, ct_ty , expr. hir_id , lit. span ) . kind
668+ self . const_to_pat ( constant, pat_ty , expr. hir_id , lit. span ) . kind
636669 }
637670 }
638671 }
0 commit comments