@@ -163,9 +163,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
163163enum AdjustMode {
164164 /// Peel off all immediate reference types.
165165 Peel ,
166- /// Reset binding mode to the initial mode.
167- /// Used for destructuring assignment, where we don't want any match ergonomics.
168- Reset ,
169166 /// Pass on the input binding mode and expected type.
170167 Pass ,
171168}
@@ -321,77 +318,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
321318 /// Conversely, inside this module, `check_pat_top` should never be used.
322319 #[ instrument( level = "debug" , skip( self , pat_info) ) ]
323320 fn check_pat ( & self , pat : & ' tcx Pat < ' tcx > , expected : Ty < ' tcx > , pat_info : PatInfo < ' tcx > ) {
324- let PatInfo { binding_mode, max_ref_mutbl, top_info : ti, current_depth, .. } = pat_info;
325-
326- let path_res = match pat. kind {
321+ let opt_path_res = match pat. kind {
327322 PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
328323 Some ( self . resolve_ty_and_res_fully_qualified_call ( qpath, * hir_id, * span) )
329324 }
330325 _ => None ,
331326 } ;
332- let adjust_mode = self . calc_adjust_mode ( pat, path_res. map ( |( res, ..) | res) ) ;
333- let ( expected, binding_mode, max_ref_mutbl) =
334- self . calc_default_binding_mode ( pat, expected, binding_mode, adjust_mode, max_ref_mutbl) ;
335- let pat_info = PatInfo {
336- binding_mode,
337- max_ref_mutbl,
338- top_info : ti,
339- decl_origin : pat_info. decl_origin ,
340- current_depth : current_depth + 1 ,
341- } ;
342-
343- let ty = match pat. kind {
344- PatKind :: Missing | PatKind :: Wild | PatKind :: Err ( _) => expected,
345- // We allow any type here; we ensure that the type is uninhabited during match checking.
346- PatKind :: Never => expected,
347- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
348- let ty = self . check_pat_path (
349- * hir_id,
350- pat. hir_id ,
351- * span,
352- qpath,
353- path_res. unwrap ( ) ,
354- expected,
355- & pat_info. top_info ,
356- ) ;
357- self . write_ty ( * hir_id, ty) ;
358- ty
359- }
360- PatKind :: Expr ( lt) => self . check_pat_lit ( pat. span , lt, expected, & pat_info. top_info ) ,
361- PatKind :: Range ( lhs, rhs, _) => {
362- self . check_pat_range ( pat. span , lhs, rhs, expected, & pat_info. top_info )
363- }
364- PatKind :: Binding ( ba, var_id, ident, sub) => {
365- self . check_pat_ident ( pat, ba, var_id, ident, sub, expected, pat_info)
366- }
367- PatKind :: TupleStruct ( ref qpath, subpats, ddpos) => {
368- self . check_pat_tuple_struct ( pat, qpath, subpats, ddpos, expected, pat_info)
369- }
370- PatKind :: Struct ( ref qpath, fields, has_rest_pat) => {
371- self . check_pat_struct ( pat, qpath, fields, has_rest_pat, expected, pat_info)
372- }
373- PatKind :: Guard ( pat, cond) => {
374- self . check_pat ( pat, expected, pat_info) ;
375- self . check_expr_has_type_or_error ( cond, self . tcx . types . bool , |_| { } ) ;
376- expected
377- }
378- PatKind :: Or ( pats) => {
379- for pat in pats {
380- self . check_pat ( pat, expected, pat_info) ;
381- }
382- expected
383- }
384- PatKind :: Tuple ( elements, ddpos) => {
385- self . check_pat_tuple ( pat. span , elements, ddpos, expected, pat_info)
386- }
387- PatKind :: Box ( inner) => self . check_pat_box ( pat. span , inner, expected, pat_info) ,
388- PatKind :: Deref ( inner) => self . check_pat_deref ( pat. span , inner, expected, pat_info) ,
389- PatKind :: Ref ( inner, mutbl) => self . check_pat_ref ( pat, inner, mutbl, expected, pat_info) ,
390- PatKind :: Slice ( before, slice, after) => {
391- self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
392- }
393- } ;
394-
327+ let adjust_mode = self . calc_adjust_mode ( pat, opt_path_res. map ( |( res, ..) | res) ) ;
328+ let ty = self . check_pat_inner ( pat, opt_path_res, adjust_mode, expected, pat_info) ;
395329 self . write_ty ( pat. hir_id , ty) ;
396330
397331 // (note_1): In most of the cases where (note_1) is referenced
@@ -437,39 +371,133 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
437371 // `regions-relate-bound-regions-on-closures-to-inference-variables.rs`,
438372 }
439373
440- /// Compute the new expected type and default binding mode from the old ones
441- /// as well as the pattern form we are currently checking.
442- fn calc_default_binding_mode (
374+ // Helper to avoid resolving the same path pattern several times.
375+ fn check_pat_inner (
443376 & self ,
444377 pat : & ' tcx Pat < ' tcx > ,
445- expected : Ty < ' tcx > ,
446- def_br : ByRef ,
378+ opt_path_res : Option < ( Res , Option < LoweredTy < ' tcx > > , & ' tcx [ hir:: PathSegment < ' tcx > ] ) > ,
447379 adjust_mode : AdjustMode ,
448- max_ref_mutbl : MutblCap ,
449- ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
380+ expected : Ty < ' tcx > ,
381+ pat_info : PatInfo < ' tcx > ,
382+ ) -> Ty < ' tcx > {
450383 #[ cfg( debug_assertions) ]
451- if def_br == ByRef :: Yes ( Mutability :: Mut )
452- && max_ref_mutbl != MutblCap :: Mut
384+ if pat_info . binding_mode == ByRef :: Yes ( Mutability :: Mut )
385+ && pat_info . max_ref_mutbl != MutblCap :: Mut
453386 && self . downgrade_mut_inside_shared ( )
454387 {
455388 span_bug ! ( pat. span, "Pattern mutability cap violated!" ) ;
456389 }
457- match adjust_mode {
458- AdjustMode :: Pass => ( expected, def_br, max_ref_mutbl) ,
459- AdjustMode :: Reset => ( expected, ByRef :: No , MutblCap :: Mut ) ,
460- AdjustMode :: Peel => self . peel_off_references ( pat, expected, def_br, max_ref_mutbl) ,
390+
391+ // Resolve type if needed.
392+ let expected = if let AdjustMode :: Peel = adjust_mode
393+ && pat. default_binding_modes
394+ {
395+ self . try_structurally_resolve_type ( pat. span , expected)
396+ } else {
397+ expected
398+ } ;
399+ let old_pat_info = pat_info;
400+ let pat_info = PatInfo { current_depth : old_pat_info. current_depth + 1 , ..old_pat_info } ;
401+
402+ match pat. kind {
403+ // Peel off a `&` or `&mut` from the scrutinee type. See the examples in
404+ // `tests/ui/rfcs/rfc-2005-default-binding-mode`.
405+ _ if let AdjustMode :: Peel = adjust_mode
406+ && pat. default_binding_modes
407+ && let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) =>
408+ {
409+ debug ! ( "inspecting {:?}" , expected) ;
410+
411+ debug ! ( "current discriminant is Ref, inserting implicit deref" ) ;
412+ // Preserve the reference type. We'll need it later during THIR lowering.
413+ self . typeck_results
414+ . borrow_mut ( )
415+ . pat_adjustments_mut ( )
416+ . entry ( pat. hir_id )
417+ . or_default ( )
418+ . push ( expected) ;
419+
420+ let mut binding_mode = ByRef :: Yes ( match pat_info. binding_mode {
421+ // If default binding mode is by value, make it `ref` or `ref mut`
422+ // (depending on whether we observe `&` or `&mut`).
423+ ByRef :: No |
424+ // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
425+ ByRef :: Yes ( Mutability :: Mut ) => inner_mutability,
426+ // Once a `ref`, always a `ref`.
427+ // This is because a `& &mut` cannot mutate the underlying value.
428+ ByRef :: Yes ( Mutability :: Not ) => Mutability :: Not ,
429+ } ) ;
430+
431+ let mut max_ref_mutbl = pat_info. max_ref_mutbl ;
432+ if self . downgrade_mut_inside_shared ( ) {
433+ binding_mode = binding_mode. cap_ref_mutability ( max_ref_mutbl. as_mutbl ( ) ) ;
434+ }
435+ if binding_mode == ByRef :: Yes ( Mutability :: Not ) {
436+ max_ref_mutbl = MutblCap :: Not ;
437+ }
438+ debug ! ( "default binding mode is now {:?}" , binding_mode) ;
439+
440+ // Use the old pat info to keep `current_depth` to its old value.
441+ let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info } ;
442+ // Recurse with the new expected type.
443+ self . check_pat_inner ( pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
444+ }
445+ PatKind :: Missing | PatKind :: Wild | PatKind :: Err ( _) => expected,
446+ // We allow any type here; we ensure that the type is uninhabited during match checking.
447+ PatKind :: Never => expected,
448+ PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
449+ let ty = self . check_pat_path (
450+ * hir_id,
451+ pat. hir_id ,
452+ * span,
453+ qpath,
454+ opt_path_res. unwrap ( ) ,
455+ expected,
456+ & pat_info. top_info ,
457+ ) ;
458+ self . write_ty ( * hir_id, ty) ;
459+ ty
460+ }
461+ PatKind :: Expr ( lt) => self . check_pat_lit ( pat. span , lt, expected, & pat_info. top_info ) ,
462+ PatKind :: Range ( lhs, rhs, _) => {
463+ self . check_pat_range ( pat. span , lhs, rhs, expected, & pat_info. top_info )
464+ }
465+ PatKind :: Binding ( ba, var_id, ident, sub) => {
466+ self . check_pat_ident ( pat, ba, var_id, ident, sub, expected, pat_info)
467+ }
468+ PatKind :: TupleStruct ( ref qpath, subpats, ddpos) => {
469+ self . check_pat_tuple_struct ( pat, qpath, subpats, ddpos, expected, pat_info)
470+ }
471+ PatKind :: Struct ( ref qpath, fields, has_rest_pat) => {
472+ self . check_pat_struct ( pat, qpath, fields, has_rest_pat, expected, pat_info)
473+ }
474+ PatKind :: Guard ( pat, cond) => {
475+ self . check_pat ( pat, expected, pat_info) ;
476+ self . check_expr_has_type_or_error ( cond, self . tcx . types . bool , |_| { } ) ;
477+ expected
478+ }
479+ PatKind :: Or ( pats) => {
480+ for pat in pats {
481+ self . check_pat ( pat, expected, pat_info) ;
482+ }
483+ expected
484+ }
485+ PatKind :: Tuple ( elements, ddpos) => {
486+ self . check_pat_tuple ( pat. span , elements, ddpos, expected, pat_info)
487+ }
488+ PatKind :: Box ( inner) => self . check_pat_box ( pat. span , inner, expected, pat_info) ,
489+ PatKind :: Deref ( inner) => self . check_pat_deref ( pat. span , inner, expected, pat_info) ,
490+ PatKind :: Ref ( inner, mutbl) => self . check_pat_ref ( pat, inner, mutbl, expected, pat_info) ,
491+ PatKind :: Slice ( before, slice, after) => {
492+ self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
493+ }
461494 }
462495 }
463496
464497 /// How should the binding mode and expected type be adjusted?
465498 ///
466499 /// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
467500 fn calc_adjust_mode ( & self , pat : & ' tcx Pat < ' tcx > , opt_path_res : Option < Res > ) -> AdjustMode {
468- // When we perform destructuring assignment, we disable default match bindings, which are
469- // unintuitive in this context.
470- if !pat. default_binding_modes {
471- return AdjustMode :: Reset ;
472- }
473501 match & pat. kind {
474502 // Type checking these product-like types successfully always require
475503 // that the expected type be of those types and not reference types.
@@ -526,64 +554,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
526554 }
527555 }
528556
529- /// Peel off as many immediately nested `& mut?` from the expected type as possible
530- /// and return the new expected type and binding default binding mode.
531- /// The adjustments vector, if non-empty is stored in a table.
532- fn peel_off_references (
533- & self ,
534- pat : & ' tcx Pat < ' tcx > ,
535- expected : Ty < ' tcx > ,
536- mut def_br : ByRef ,
537- mut max_ref_mutbl : MutblCap ,
538- ) -> ( Ty < ' tcx > , ByRef , MutblCap ) {
539- let mut expected = self . try_structurally_resolve_type ( pat. span , expected) ;
540- // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
541- // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
542- // the `Some(5)` which is not of type Ref.
543- //
544- // For each ampersand peeled off, update the binding mode and push the original
545- // type into the adjustments vector.
546- //
547- // See the examples in `ui/match-defbm*.rs`.
548- let mut pat_adjustments = vec ! [ ] ;
549- while let ty:: Ref ( _, inner_ty, inner_mutability) = * expected. kind ( ) {
550- debug ! ( "inspecting {:?}" , expected) ;
551-
552- debug ! ( "current discriminant is Ref, inserting implicit deref" ) ;
553- // Preserve the reference type. We'll need it later during THIR lowering.
554- pat_adjustments. push ( expected) ;
555-
556- expected = self . try_structurally_resolve_type ( pat. span , inner_ty) ;
557- def_br = ByRef :: Yes ( match def_br {
558- // If default binding mode is by value, make it `ref` or `ref mut`
559- // (depending on whether we observe `&` or `&mut`).
560- ByRef :: No |
561- // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
562- ByRef :: Yes ( Mutability :: Mut ) => inner_mutability,
563- // Once a `ref`, always a `ref`.
564- // This is because a `& &mut` cannot mutate the underlying value.
565- ByRef :: Yes ( Mutability :: Not ) => Mutability :: Not ,
566- } ) ;
567- }
568-
569- if self . downgrade_mut_inside_shared ( ) {
570- def_br = def_br. cap_ref_mutability ( max_ref_mutbl. as_mutbl ( ) ) ;
571- }
572- if def_br == ByRef :: Yes ( Mutability :: Not ) {
573- max_ref_mutbl = MutblCap :: Not ;
574- }
575-
576- if !pat_adjustments. is_empty ( ) {
577- debug ! ( "default binding mode is now {:?}" , def_br) ;
578- self . typeck_results
579- . borrow_mut ( )
580- . pat_adjustments_mut ( )
581- . insert ( pat. hir_id , pat_adjustments) ;
582- }
583-
584- ( expected, def_br, max_ref_mutbl)
585- }
586-
587557 fn check_pat_expr_unadjusted ( & self , lt : & ' tcx hir:: PatExpr < ' tcx > ) -> Ty < ' tcx > {
588558 let ty = match & lt. kind {
589559 rustc_hir:: PatExprKind :: Lit { lit, negated } => {
0 commit comments