@@ -131,6 +131,12 @@ enum AdjustMode {
131
131
Peel ,
132
132
/// Reset binding mode to the initial mode.
133
133
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 ) ,
134
140
/// Pass on the input binding mode and expected type.
135
141
Pass ,
136
142
}
@@ -174,7 +180,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
174
180
_ => None ,
175
181
} ;
176
182
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) ;
178
185
let pat_info = PatInfo {
179
186
binding_mode : def_bm,
180
187
top_info : ti,
@@ -211,7 +218,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
211
218
}
212
219
PatKind :: Box ( inner) => self . check_pat_box ( pat. span , inner, expected, pat_info) ,
213
220
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
+ ) ,
215
229
PatKind :: Slice ( before, slice, after) => {
216
230
self . check_pat_slice ( pat. span , before, slice, after, expected, pat_info)
217
231
}
@@ -264,17 +278,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
264
278
265
279
/// Compute the new expected type and default binding mode from the old ones
266
280
/// 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.
267
285
fn calc_default_binding_mode (
268
286
& self ,
269
287
pat : & ' tcx Pat < ' tcx > ,
270
288
expected : Ty < ' tcx > ,
271
289
def_bm : BindingAnnotation ,
272
290
adjust_mode : AdjustMode ,
273
- ) -> ( Ty < ' tcx > , BindingAnnotation ) {
291
+ ) -> ( Ty < ' tcx > , BindingAnnotation , bool ) {
274
292
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
+ }
278
300
}
279
301
}
280
302
@@ -329,7 +351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
329
351
// ```
330
352
//
331
353
// See issue #46688.
332
- PatKind :: Ref ( .. ) => AdjustMode :: Reset ,
354
+ PatKind :: Ref ( _ , mutbl ) => AdjustMode :: RefReset ( * mutbl ) ,
333
355
// A `_` pattern works with any expected type, so there's no need to do anything.
334
356
PatKind :: Wild
335
357
// 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> {
840
862
&& let Some ( mt) = self . shallow_resolve ( expected) . builtin_deref ( true )
841
863
&& let ty:: Dynamic ( ..) = mt. ty . kind ( )
842
864
{
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.
845
867
let type_str = self . ty_to_string ( expected) ;
846
868
let mut err = struct_span_code_err ! (
847
869
self . dcx( ) ,
@@ -2036,6 +2058,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2036
2058
mutbl : Mutability ,
2037
2059
expected : Ty < ' tcx > ,
2038
2060
pat_info : PatInfo < ' tcx , ' _ > ,
2061
+ already_consumed : bool ,
2039
2062
) -> Ty < ' tcx > {
2040
2063
let tcx = self . tcx ;
2041
2064
let expected = self . shallow_resolve ( expected) ;
@@ -2051,26 +2074,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2051
2074
match * expected. kind ( ) {
2052
2075
ty:: Ref ( _, r_ty, r_mutbl) if r_mutbl == mutbl => ( expected, r_ty) ,
2053
2076
_ => {
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
+ ) ;
2066
2099
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)
2072
2107
}
2073
- ( ref_ty, inner_ty)
2074
2108
}
2075
2109
}
2076
2110
}
0 commit comments