@@ -131,6 +131,12 @@ enum AdjustMode {
131131 Peel ,
132132 /// Reset binding mode to the initial mode.
133133 Reset ,
134+ /// Produced by ref patterns.
135+ /// Reset the binding mode to the initial mode,
136+ /// and if the old biding mode was by-reference
137+ /// with mutability matching the pattern,
138+ /// mark the pattern as having consumed this reference.
139+ RefReset ( Mutability ) ,
134140 /// Pass on the input binding mode and expected type.
135141 Pass ,
136142}
@@ -174,7 +180,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
174180 _ => None ,
175181 } ;
176182 let adjust_mode = self . calc_adjust_mode ( pat, path_res. map ( |( res, ..) | res) ) ;
177- let ( expected, def_bm) = self . calc_default_binding_mode ( pat, expected, def_bm, adjust_mode) ;
183+ let ( expected, def_bm, ref_pattern_already_consumed) =
184+ self . calc_default_binding_mode ( pat, expected, def_bm, adjust_mode) ;
178185 let pat_info = PatInfo {
179186 binding_mode : def_bm,
180187 top_info : ti,
@@ -211,7 +218,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
211218 }
212219 PatKind :: Box ( inner) => self . check_pat_box ( pat. span , inner, expected, pat_info) ,
213220 PatKind :: Deref ( inner) => self . check_pat_deref ( pat. span , inner, expected, pat_info) ,
214- PatKind :: Ref ( inner, mutbl) => self . check_pat_ref ( pat, inner, mutbl, expected, pat_info) ,
221+ PatKind :: Ref ( inner, mutbl) => self . check_pat_ref (
222+ pat,
223+ inner,
224+ mutbl,
225+ expected,
226+ pat_info,
227+ ref_pattern_already_consumed,
228+ ) ,
215229 PatKind :: Slice ( before, slice, after) => {
216230 self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
217231 }
@@ -264,17 +278,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
264278
265279 /// Compute the new expected type and default binding mode from the old ones
266280 /// as well as the pattern form we are currently checking.
281+ ///
282+ /// Last entry is only relevant for ref patterns (`&` and `&mut`);
283+ /// if `true`, then the ref pattern consumed a match ergonomics inserted reference
284+ /// and so does no need to match against a reference in the scrutinee type.
267285 fn calc_default_binding_mode (
268286 & self ,
269287 pat : & ' tcx Pat < ' tcx > ,
270288 expected : Ty < ' tcx > ,
271289 def_bm : BindingAnnotation ,
272290 adjust_mode : AdjustMode ,
273- ) -> ( Ty < ' tcx > , BindingAnnotation ) {
291+ ) -> ( Ty < ' tcx > , BindingAnnotation , bool ) {
274292 match adjust_mode {
275- AdjustMode :: Pass => ( expected, def_bm) ,
276- AdjustMode :: Reset => ( expected, INITIAL_BM ) ,
277- AdjustMode :: Peel => self . peel_off_references ( pat, expected, def_bm) ,
293+ AdjustMode :: Pass => ( expected, def_bm, false ) ,
294+ AdjustMode :: Reset => ( expected, INITIAL_BM , false ) ,
295+ AdjustMode :: RefReset ( mutbl) => ( expected, INITIAL_BM , def_bm. 0 == ByRef :: Yes ( mutbl) ) ,
296+ AdjustMode :: Peel => {
297+ let peeled = self . peel_off_references ( pat, expected, def_bm) ;
298+ ( peeled. 0 , peeled. 1 , false )
299+ }
278300 }
279301 }
280302
@@ -329,7 +351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
329351 // ```
330352 //
331353 // See issue #46688.
332- PatKind :: Ref ( .. ) => AdjustMode :: Reset ,
354+ PatKind :: Ref ( _ , mutbl ) => AdjustMode :: RefReset ( * mutbl ) ,
333355 // A `_` pattern works with any expected type, so there's no need to do anything.
334356 PatKind :: Wild
335357 // A malformed pattern doesn't have an expected type, so let's just accept any type.
@@ -840,8 +862,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
840862 && let Some ( mt) = self . shallow_resolve ( expected) . builtin_deref ( true )
841863 && let ty:: Dynamic ( ..) = mt. ty . kind ( )
842864 {
843- // This is "x = SomeTrait" being reduced from
844- // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
865+ // This is "x = dyn SomeTrait" being reduced from
866+ // "let &x = &dyn SomeTrait" or "let box x = Box<dyn SomeTrait>", an error.
845867 let type_str = self . ty_to_string ( expected) ;
846868 let mut err = struct_span_code_err ! (
847869 self . dcx( ) ,
@@ -2036,6 +2058,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20362058 mutbl : Mutability ,
20372059 expected : Ty < ' tcx > ,
20382060 pat_info : PatInfo < ' tcx , ' _ > ,
2061+ already_consumed : bool ,
20392062 ) -> Ty < ' tcx > {
20402063 let tcx = self . tcx ;
20412064 let expected = self . shallow_resolve ( expected) ;
@@ -2051,26 +2074,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20512074 match * expected. kind ( ) {
20522075 ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == mutbl => ( expected, r_ty) ,
20532076 _ => {
2054- let inner_ty = self . next_ty_var ( TypeVariableOrigin {
2055- kind : TypeVariableOriginKind :: TypeInference ,
2056- span : inner. span ,
2057- } ) ;
2058- let ref_ty = self . new_ref_ty ( pat. span , mutbl, inner_ty) ;
2059- debug ! ( "check_pat_ref: demanding {:?} = {:?}" , expected, ref_ty) ;
2060- let err = self . demand_eqtype_pat_diag (
2061- pat. span ,
2062- expected,
2063- ref_ty,
2064- pat_info. top_info ,
2065- ) ;
2077+ if already_consumed && self . tcx . features ( ) . and_pat_everywhere {
2078+ // We already matched against a match-ergonmics inserted reference,
2079+ // so we don't need to match against a reference from the original type.
2080+ // Save this infor for use in lowering later
2081+ self . typeck_results
2082+ . borrow_mut ( )
2083+ . ref_pats_that_dont_deref_mut ( )
2084+ . insert ( pat. hir_id ) ;
2085+ ( expected, expected)
2086+ } else {
2087+ let inner_ty = self . next_ty_var ( TypeVariableOrigin {
2088+ kind : TypeVariableOriginKind :: TypeInference ,
2089+ span : inner. span ,
2090+ } ) ;
2091+ let ref_ty = self . new_ref_ty ( pat. span , mutbl, inner_ty) ;
2092+ debug ! ( "check_pat_ref: demanding {:?} = {:?}" , expected, ref_ty) ;
2093+ let err = self . demand_eqtype_pat_diag (
2094+ pat. span ,
2095+ expected,
2096+ ref_ty,
2097+ pat_info. top_info ,
2098+ ) ;
20662099
2067- // Look for a case like `fn foo(&foo: u32)` and suggest
2068- // `fn foo(foo: &u32)`
2069- if let Some ( mut err) = err {
2070- self . borrow_pat_suggestion ( & mut err, pat) ;
2071- err. emit ( ) ;
2100+ // Look for a case like `fn foo(&foo: u32)` and suggest
2101+ // `fn foo(foo: &u32)`
2102+ if let Some ( mut err) = err {
2103+ self . borrow_pat_suggestion ( & mut err, pat) ;
2104+ err. emit ( ) ;
2105+ }
2106+ ( ref_ty, inner_ty)
20722107 }
2073- ( ref_ty, inner_ty)
20742108 }
20752109 }
20762110 }
0 commit comments