@@ -130,7 +130,14 @@ enum AdjustMode {
130130 /// Peel off all immediate reference types.
131131 Peel ,
132132 /// Reset binding mode to the initial mode.
133+ /// Used for destructuring assignment, where we don't want any match ergonomics.
133134 Reset ,
135+ /// Produced by ref patterns.
136+ /// Reset the binding mode to the initial mode,
137+ /// and if the old biding mode was by-reference
138+ /// with mutability matching the pattern,
139+ /// mark the pattern as having consumed this reference.
140+ ResetAndConsumeRef ( Mutability ) ,
134141 /// Pass on the input binding mode and expected type.
135142 Pass ,
136143}
@@ -174,7 +181,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
174181 _ => None ,
175182 } ;
176183 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) ;
184+ let ( expected, def_bm, ref_pattern_already_consumed) =
185+ self . calc_default_binding_mode ( pat, expected, def_bm, adjust_mode) ;
178186 let pat_info = PatInfo {
179187 binding_mode : def_bm,
180188 top_info : ti,
@@ -211,7 +219,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
211219 }
212220 PatKind :: Box ( inner) => self . check_pat_box ( pat. span , inner, expected, pat_info) ,
213221 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) ,
222+ PatKind :: Ref ( inner, mutbl) => self . check_pat_ref (
223+ pat,
224+ inner,
225+ mutbl,
226+ expected,
227+ pat_info,
228+ ref_pattern_already_consumed,
229+ ) ,
215230 PatKind :: Slice ( before, slice, after) => {
216231 self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
217232 }
@@ -264,17 +279,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
264279
265280 /// Compute the new expected type and default binding mode from the old ones
266281 /// as well as the pattern form we are currently checking.
282+ ///
283+ /// Last entry is only relevant for ref patterns (`&` and `&mut`);
284+ /// if `true`, then the ref pattern consumed a match ergonomics inserted reference
285+ /// and so does no need to match against a reference in the scrutinee type.
267286 fn calc_default_binding_mode (
268287 & self ,
269288 pat : & ' tcx Pat < ' tcx > ,
270289 expected : Ty < ' tcx > ,
271290 def_bm : BindingAnnotation ,
272291 adjust_mode : AdjustMode ,
273- ) -> ( Ty < ' tcx > , BindingAnnotation ) {
292+ ) -> ( Ty < ' tcx > , BindingAnnotation , bool ) {
274293 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) ,
294+ AdjustMode :: Pass => ( expected, def_bm, false ) ,
295+ AdjustMode :: Reset => ( expected, INITIAL_BM , false ) ,
296+ AdjustMode :: ResetAndConsumeRef ( mutbl) => {
297+ ( expected, INITIAL_BM , def_bm. 0 == ByRef :: Yes ( mutbl) )
298+ }
299+ AdjustMode :: Peel => {
300+ let peeled = self . peel_off_references ( pat, expected, def_bm) ;
301+ ( peeled. 0 , peeled. 1 , false )
302+ }
278303 }
279304 }
280305
@@ -329,7 +354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
329354 // ```
330355 //
331356 // See issue #46688.
332- PatKind :: Ref ( .. ) => AdjustMode :: Reset ,
357+ PatKind :: Ref ( _ , mutbl ) => AdjustMode :: ResetAndConsumeRef ( * mutbl ) ,
333358 // A `_` pattern works with any expected type, so there's no need to do anything.
334359 PatKind :: Wild
335360 // A malformed pattern doesn't have an expected type, so let's just accept any type.
@@ -840,8 +865,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
840865 && let Some ( mt) = self . shallow_resolve ( expected) . builtin_deref ( true )
841866 && let ty:: Dynamic ( ..) = mt. ty . kind ( )
842867 {
843- // This is "x = SomeTrait" being reduced from
844- // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
868+ // This is "x = dyn SomeTrait" being reduced from
869+ // "let &x = &dyn SomeTrait" or "let box x = Box<dyn SomeTrait>", an error.
845870 let type_str = self . ty_to_string ( expected) ;
846871 let mut err = struct_span_code_err ! (
847872 self . dcx( ) ,
@@ -2036,6 +2061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20362061 mutbl : Mutability ,
20372062 expected : Ty < ' tcx > ,
20382063 pat_info : PatInfo < ' tcx , ' _ > ,
2064+ consumed_inherited_ref : bool ,
20392065 ) -> Ty < ' tcx > {
20402066 let tcx = self . tcx ;
20412067 let expected = self . shallow_resolve ( expected) ;
@@ -2051,26 +2077,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20512077 match * expected. kind ( ) {
20522078 ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == mutbl => ( expected, r_ty) ,
20532079 _ => {
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- ) ;
2080+ if consumed_inherited_ref && self . tcx . features ( ) . ref_pat_everywhere {
2081+ // We already matched against a match-ergonmics inserted reference,
2082+ // so we don't need to match against a reference from the original type.
2083+ // Save this infor for use in lowering later
2084+ self . typeck_results
2085+ . borrow_mut ( )
2086+ . skipped_ref_pats_mut ( )
2087+ . insert ( pat. hir_id ) ;
2088+ ( expected, expected)
2089+ } else {
2090+ let inner_ty = self . next_ty_var ( TypeVariableOrigin {
2091+ kind : TypeVariableOriginKind :: TypeInference ,
2092+ span : inner. span ,
2093+ } ) ;
2094+ let ref_ty = self . new_ref_ty ( pat. span , mutbl, inner_ty) ;
2095+ debug ! ( "check_pat_ref: demanding {:?} = {:?}" , expected, ref_ty) ;
2096+ let err = self . demand_eqtype_pat_diag (
2097+ pat. span ,
2098+ expected,
2099+ ref_ty,
2100+ pat_info. top_info ,
2101+ ) ;
20662102
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 ( ) ;
2103+ // Look for a case like `fn foo(&foo: u32)` and suggest
2104+ // `fn foo(foo: &u32)`
2105+ if let Some ( mut err) = err {
2106+ self . borrow_pat_suggestion ( & mut err, pat) ;
2107+ err. emit ( ) ;
2108+ }
2109+ ( ref_ty, inner_ty)
20722110 }
2073- ( ref_ty, inner_ty)
20742111 }
20752112 }
20762113 }
0 commit comments