@@ -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
130131fn lower_pattern_range_endpoint (
131132& mut self ,
133+ pat : & ' tcx hir:: Pat < ' tcx > , // Range pattern containing the endpoint
132134expr : Option < & ' tcx hir:: PatExpr < ' tcx > > ,
133135// Out-parameter collecting extra data to be reapplied by the caller
134136ascriptions : & 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.
136142let 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.
143149loop {
@@ -214,20 +220,23 @@ impl<'tcx> PatCtxt<'tcx> {
214220
215221fn lower_pattern_range (
216222& mut self ,
223+ pat : & ' tcx hir:: Pat < ' tcx > ,
217224lo_expr : Option < & ' tcx hir:: PatExpr < ' tcx > > ,
218225hi_expr : Option < & ' tcx hir:: PatExpr < ' tcx > > ,
219226end : 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+
223231if lo_expr. is_none ( ) && hi_expr. is_none ( ) {
224232let msg = "found twice-open range pattern (`..`) outside of error recovery" ;
225233self . tcx . dcx ( ) . span_bug ( span, msg) ;
226234}
227235
228236// Collect extra data while lowering the endpoints, to be reapplied later.
229237let 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
232241let lo = lower_endpoint ( lo_expr) ?. unwrap_or ( PatRangeBoundary :: NegInfinity ) ;
233242let 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} ;
390397let variant_def = adt_def. variant_of_res ( res) ;
391398let 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
446453fn slice_or_array_pattern (
447454& mut self ,
448- span : Span ,
449- ty : Ty < ' tcx > ,
455+ pat : & ' tcx hir:: Pat < ' tcx > ,
450456prefix : & ' tcx [ hir:: Pat < ' tcx > ] ,
451457slice : Option < & ' tcx hir:: Pat < ' tcx > > ,
452458suffix : & ' tcx [ hir:: Pat < ' tcx > ] ,
453459) -> PatKind < ' tcx > {
460+ let ty = self . typeck_results . node_type ( pat. hir_id ) ;
461+
454462let prefix = self . lower_patterns ( prefix) ;
455463let slice = self . lower_opt_pattern ( slice) ;
456464let suffix = self . lower_patterns ( suffix) ;
@@ -465,18 +473,32 @@ impl<'tcx> PatCtxt<'tcx> {
465473assert ! ( len >= prefix. len( ) as u64 + suffix. len( ) as u64 ) ;
466474PatKind :: 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
472480fn lower_variant_or_leaf (
473481& mut self ,
482+ pat : & ' tcx hir:: Pat < ' tcx > ,
483+ expr : Option < & ' tcx hir:: PatExpr < ' tcx > > ,
474484res : Res ,
475- hir_id : hir:: HirId ,
476- span : Span ,
477- ty : Ty < ' tcx > ,
478485subpatterns : 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+
480502let res = match res {
481503Res :: Def ( DefKind :: Ctor ( CtorOf :: Variant , ..) , variant_ctor_id) => {
482504let 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 ;
567598let ty = self . typeck_results . node_type ( id) ;
568599let 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 ! [ ] ) ;
579610return Box :: new ( Pat { span, ty, kind } ) ;
580611}
581612} ;
@@ -615,24 +646,26 @@ impl<'tcx> PatCtxt<'tcx> {
615646/// - Literals, possibly negated (e.g. `-128u8`, `"hello"`)
616647fn lower_pat_expr (
617648& mut self ,
649+ pat : & ' tcx hir:: Pat < ' tcx > , // Pattern that directly contains `expr`
618650expr : & ' tcx hir:: PatExpr < ' tcx > ,
619- pat_ty : Option < Ty < ' tcx > > ,
620651) -> PatKind < ' tcx > {
652+ assert_matches ! ( pat. kind, hir:: PatKind :: Expr ( ..) | hir:: PatKind :: Range ( ..) ) ;
621653match & 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 } ;
634667let 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