@@ -318,6 +318,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
318318 /// Conversely, inside this module, `check_pat_top` should never be used.
319319 #[ instrument( level = "debug" , skip( self , pat_info) ) ]
320320 fn check_pat ( & self , pat : & ' tcx Pat < ' tcx > , expected : Ty < ' tcx > , pat_info : PatInfo < ' tcx > ) {
321+ let opt_path_res = match pat. kind {
322+ PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
323+ Some ( self . resolve_ty_and_res_fully_qualified_call ( qpath, * hir_id, * span) )
324+ }
325+ _ => None ,
326+ } ;
327+ let adjust_mode = self . calc_adjust_mode ( pat, opt_path_res. map ( |( res, ..) | res) ) ;
328+ self . check_pat_inner ( pat, opt_path_res, adjust_mode, expected, pat_info) ;
329+ }
330+
331+ // Helper to avoid resolving the same path pattern several times.
332+ fn check_pat_inner (
333+ & self ,
334+ pat : & ' tcx Pat < ' tcx > ,
335+ opt_path_res : Option < ( Res , Option < LoweredTy < ' tcx > > , & ' tcx [ hir:: PathSegment < ' tcx > ] ) > ,
336+ adjust_mode : AdjustMode ,
337+ expected : Ty < ' tcx > ,
338+ pat_info : PatInfo < ' tcx > ,
339+ ) {
321340 let PatInfo { binding_mode, max_ref_mutbl, top_info : ti, current_depth, .. } = pat_info;
322341 #[ cfg( debug_assertions) ]
323342 if binding_mode == ByRef :: Yes ( Mutability :: Mut )
@@ -327,34 +346,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
327346 span_bug ! ( pat. span, "Pattern mutability cap violated!" ) ;
328347 }
329348
330- let path_res = match pat. kind {
331- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
332- Some ( self . resolve_ty_and_res_fully_qualified_call ( qpath, * hir_id, * span) )
333- }
334- _ => None ,
335- } ;
336- let adjust_mode = self . calc_adjust_mode ( pat, path_res. map ( |( res, ..) | res) ) ;
337349 let ( expected, binding_mode, max_ref_mutbl) = match adjust_mode {
338350 // When we perform destructuring assignment, we disable default match bindings, which
339351 // are unintuitive in this context.
340352 _ if !pat. default_binding_modes => ( expected, ByRef :: No , MutblCap :: Mut ) ,
341353 AdjustMode :: Pass => ( expected, binding_mode, max_ref_mutbl) ,
342- // Peel off as many immediately nested `& mut?` from the expected type as possible
343- // and return the new expected type and binding default binding mode.
344- // The adjustments vector, if non-empty is stored in a table.
354+ // Peel an immediately nested `& mut?` from the expected type if possible and return the
355+ // new expected type and binding default binding mode.
345356 AdjustMode :: Peel => {
346- let mut binding_mode = binding_mode;
347- let mut max_ref_mutbl = max_ref_mutbl;
348- let mut expected = self . try_structurally_resolve_type ( pat. span , expected) ;
349- // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
350- // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
351- // the `Some(5)` which is not of type Ref.
352- //
353- // For each ampersand peeled off, update the binding mode and push the original
354- // type into the adjustments vector.
357+ let expected = self . try_structurally_resolve_type ( pat. span , expected) ;
358+ // Peel off a `&` or `&mut` from the scrutinee type. For each ampersand peeled off,
359+ // update the binding mode and push the original type into the adjustments vector.
355360 //
356- // See the examples in `ui/match-defbm*.rs `.
357- while let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) {
361+ // See the examples in `tests/ ui/rfcs/rfc-2005-default-binding-mode `.
362+ if let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) {
358363 debug ! ( "inspecting {:?}" , expected) ;
359364
360365 debug ! ( "current discriminant is Ref, inserting implicit deref" ) ;
@@ -366,8 +371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
366371 . or_default ( )
367372 . push ( expected) ;
368373
369- expected = self . try_structurally_resolve_type ( pat. span , inner_ty) ;
370- binding_mode = ByRef :: Yes ( match binding_mode {
374+ let mut binding_mode = ByRef :: Yes ( match binding_mode {
371375 // If default binding mode is by value, make it `ref` or `ref mut`
372376 // (depending on whether we observe `&` or `&mut`).
373377 ByRef :: No |
@@ -377,18 +381,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
377381 // This is because a `& &mut` cannot mutate the underlying value.
378382 ByRef :: Yes ( Mutability :: Not ) => Mutability :: Not ,
379383 } ) ;
380- }
381384
382- if self . downgrade_mut_inside_shared ( ) {
383- binding_mode = binding_mode. cap_ref_mutability ( max_ref_mutbl. as_mutbl ( ) ) ;
384- }
385- if binding_mode == ByRef :: Yes ( Mutability :: Not ) {
386- max_ref_mutbl = MutblCap :: Not ;
385+ if self . downgrade_mut_inside_shared ( ) {
386+ binding_mode = binding_mode. cap_ref_mutability ( max_ref_mutbl. as_mutbl ( ) ) ;
387+ }
388+ let mut max_ref_mutbl = max_ref_mutbl;
389+ if binding_mode == ByRef :: Yes ( Mutability :: Not ) {
390+ max_ref_mutbl = MutblCap :: Not ;
391+ }
392+ debug ! ( "default binding mode is now {:?}" , binding_mode) ;
393+ let pat_info = PatInfo { binding_mode, max_ref_mutbl, ..pat_info } ;
394+ return self . check_pat_inner (
395+ pat,
396+ opt_path_res,
397+ adjust_mode,
398+ inner_ty,
399+ pat_info,
400+ ) ;
401+ } else {
402+ ( expected, binding_mode, max_ref_mutbl)
387403 }
388-
389- debug ! ( "default binding mode is now {:?}" , binding_mode) ;
390-
391- ( expected, binding_mode, max_ref_mutbl)
392404 }
393405 } ;
394406 let pat_info = PatInfo {
@@ -409,7 +421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
409421 pat. hir_id ,
410422 * span,
411423 qpath,
412- path_res . unwrap ( ) ,
424+ opt_path_res . unwrap ( ) ,
413425 expected,
414426 & pat_info. top_info ,
415427 ) ;
0 commit comments