@@ -192,146 +192,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
192192 is_loop_move = true ;
193193 }
194194
195- struct ExpressionFinder < ' hir > {
196- expr_span : Span ,
197- expr : Option < & ' hir hir:: Expr < ' hir > > ,
198- pat : Option < & ' hir hir:: Pat < ' hir > > ,
199- }
200- impl < ' hir > Visitor < ' hir > for ExpressionFinder < ' hir > {
201- fn visit_expr ( & mut self , e : & ' hir hir:: Expr < ' hir > ) {
202- if e. span == self . expr_span {
203- self . expr = Some ( e) ;
204- }
205- hir:: intravisit:: walk_expr ( self , e) ;
206- }
207- fn visit_pat ( & mut self , p : & ' hir hir:: Pat < ' hir > ) {
208- if p. span == self . expr_span {
209- self . pat = Some ( p) ;
210- }
211- if let hir:: PatKind :: Binding ( hir:: BindingAnnotation :: NONE , _, i, _) = p. kind
212- && i. span == self . expr_span
213- {
214- self . pat = Some ( p) ;
215- }
216- hir:: intravisit:: walk_pat ( self , p) ;
217- }
218- }
219-
220- let hir = self . infcx . tcx . hir ( ) ;
221- if let Some ( hir:: Node :: Item ( hir:: Item {
222- kind : hir:: ItemKind :: Fn ( _, _, body_id) ,
223- ..
224- } ) ) = hir. find ( hir. local_def_id_to_hir_id ( self . mir_def_id ( ) ) )
225- && let Some ( hir:: Node :: Expr ( expr) ) = hir. find ( body_id. hir_id )
226- {
227- let place = & self . move_data . move_paths [ mpi] . place ;
228- let span = place. as_local ( )
229- . map ( |local| self . body . local_decls [ local] . source_info . span ) ;
230- let mut finder = ExpressionFinder {
231- expr_span : move_span,
232- expr : None ,
233- pat : None ,
234- } ;
235- finder. visit_expr ( expr) ;
236- if let Some ( span) = span && let Some ( expr) = finder. expr {
237- for ( _, expr) in hir. parent_iter ( expr. hir_id ) {
238- if let hir:: Node :: Expr ( expr) = expr {
239- if expr. span . contains ( span) {
240- // If the let binding occurs within the same loop, then that
241- // loop isn't relevant, like in the following, the outermost `loop`
242- // doesn't play into `x` being moved.
243- // ```
244- // loop {
245- // let x = String::new();
246- // loop {
247- // foo(x);
248- // }
249- // }
250- // ```
251- break ;
252- }
253- if let hir:: ExprKind :: Loop ( .., loop_span) = expr. kind {
254- err. span_label ( loop_span, "inside of this loop" ) ;
255- }
256- }
257- }
258- let typeck = self . infcx . tcx . typeck ( self . mir_def_id ( ) ) ;
259- let hir_id = hir. get_parent_node ( expr. hir_id ) ;
260- if let Some ( parent) = hir. find ( hir_id) {
261- if let hir:: Node :: Expr ( parent_expr) = parent
262- && let hir:: ExprKind :: MethodCall ( _, _, args, _) = parent_expr. kind
263- && let Some ( def_id) = typeck. type_dependent_def_id ( parent_expr. hir_id )
264- && let Some ( def_id) = def_id. as_local ( )
265- && let Some ( node) = hir. find ( hir. local_def_id_to_hir_id ( def_id) )
266- && let Some ( fn_sig) = node. fn_sig ( )
267- && let Some ( ident) = node. ident ( )
268- && let Some ( pos) = args. iter ( )
269- . position ( |arg| arg. hir_id == expr. hir_id )
270- && let Some ( arg) = fn_sig. decl . inputs . get ( pos + 1 )
271- {
272- let mut span: MultiSpan = arg. span . into ( ) ;
273- span. push_span_label (
274- arg. span ,
275- "this type parameter takes ownership of the value" . to_string ( ) ,
276- ) ;
277- span. push_span_label (
278- ident. span ,
279- "in this method" . to_string ( ) ,
280- ) ;
281- err. span_note (
282- span,
283- format ! (
284- "consider changing this parameter type in `{}` to borrow \
285- instead if ownering the value isn't necessary",
286- ident,
287- ) ,
288- ) ;
289- }
290- if let hir:: Node :: Expr ( parent_expr) = parent
291- && let hir:: ExprKind :: Call ( call, args) = parent_expr. kind
292- && let ty:: FnDef ( def_id, _) = typeck. node_type ( call. hir_id ) . kind ( )
293- && let Some ( def_id) = def_id. as_local ( )
294- && let Some ( node) = hir. find ( hir. local_def_id_to_hir_id ( def_id) )
295- && let Some ( fn_sig) = node. fn_sig ( )
296- && let Some ( ident) = node. ident ( )
297- && let Some ( pos) = args. iter ( )
298- . position ( |arg| arg. hir_id == expr. hir_id )
299- && let Some ( arg) = fn_sig. decl . inputs . get ( pos)
300- {
301- let mut span: MultiSpan = arg. span . into ( ) ;
302- span. push_span_label (
303- arg. span ,
304- "this type parameter takes ownership of the value" . to_string ( ) ,
305- ) ;
306- span. push_span_label (
307- ident. span ,
308- "in this function" . to_string ( ) ,
309- ) ;
310- err. span_note (
311- span,
312- format ! (
313- "consider changing this parameter type in `{}` to borrow \
314- instead if ownering the value isn't necessary",
315- ident,
316- ) ,
317- ) ;
318- }
319- let place = & self . move_data . move_paths [ mpi] . place ;
320- let ty = place. ty ( self . body , self . infcx . tcx ) . ty ;
321- self . suggest_cloning ( & mut err, ty, move_span) ;
322- }
323- }
324- if let Some ( pat) = finder. pat && !seen_spans. contains ( & pat. span ) {
325- in_pattern = true ;
326- err. span_suggestion_verbose (
327- pat. span . shrink_to_lo ( ) ,
328- "borrow this binding in the pattern to avoid moving the value" ,
329- "ref " . to_string ( ) ,
330- Applicability :: MachineApplicable ,
331- ) ;
332- seen_spans. insert ( pat. span ) ;
333- }
334- }
195+ self . suggest_ref_or_clone (
196+ mpi,
197+ move_span,
198+ & mut err,
199+ & mut seen_spans,
200+ & mut in_pattern,
201+ ) ;
335202
336203 self . explain_captures (
337204 & mut err,
@@ -440,6 +307,155 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
440307 }
441308 }
442309
310+ fn suggest_ref_or_clone (
311+ & mut self ,
312+ mpi : MovePathIndex ,
313+ move_span : Span ,
314+ err : & mut DiagnosticBuilder < ' _ , ErrorGuaranteed > ,
315+ seen_spans : & mut FxHashSet < Span > ,
316+ in_pattern : & mut bool ,
317+ ) {
318+ struct ExpressionFinder < ' hir > {
319+ expr_span : Span ,
320+ expr : Option < & ' hir hir:: Expr < ' hir > > ,
321+ pat : Option < & ' hir hir:: Pat < ' hir > > ,
322+ }
323+ impl < ' hir > Visitor < ' hir > for ExpressionFinder < ' hir > {
324+ fn visit_expr ( & mut self , e : & ' hir hir:: Expr < ' hir > ) {
325+ if e. span == self . expr_span {
326+ self . expr = Some ( e) ;
327+ }
328+ hir:: intravisit:: walk_expr ( self , e) ;
329+ }
330+ fn visit_pat ( & mut self , p : & ' hir hir:: Pat < ' hir > ) {
331+ if p. span == self . expr_span {
332+ self . pat = Some ( p) ;
333+ }
334+ if let hir:: PatKind :: Binding ( hir:: BindingAnnotation :: NONE , _, i, _) = p. kind
335+ && i. span == self . expr_span
336+ {
337+ self . pat = Some ( p) ;
338+ }
339+ hir:: intravisit:: walk_pat ( self , p) ;
340+ }
341+ }
342+ let hir = self . infcx . tcx . hir ( ) ;
343+ if let Some ( hir:: Node :: Item ( hir:: Item {
344+ kind : hir:: ItemKind :: Fn ( _, _, body_id) ,
345+ ..
346+ } ) ) = hir. find ( hir. local_def_id_to_hir_id ( self . mir_def_id ( ) ) )
347+ && let Some ( hir:: Node :: Expr ( expr) ) = hir. find ( body_id. hir_id )
348+ {
349+ let place = & self . move_data . move_paths [ mpi] . place ;
350+ let span = place. as_local ( )
351+ . map ( |local| self . body . local_decls [ local] . source_info . span ) ;
352+ let mut finder = ExpressionFinder {
353+ expr_span : move_span,
354+ expr : None ,
355+ pat : None ,
356+ } ;
357+ finder. visit_expr ( expr) ;
358+ if let Some ( span) = span && let Some ( expr) = finder. expr {
359+ for ( _, expr) in hir. parent_iter ( expr. hir_id ) {
360+ if let hir:: Node :: Expr ( expr) = expr {
361+ if expr. span . contains ( span) {
362+ // If the let binding occurs within the same loop, then that
363+ // loop isn't relevant, like in the following, the outermost `loop`
364+ // doesn't play into `x` being moved.
365+ // ```
366+ // loop {
367+ // let x = String::new();
368+ // loop {
369+ // foo(x);
370+ // }
371+ // }
372+ // ```
373+ break ;
374+ }
375+ if let hir:: ExprKind :: Loop ( .., loop_span) = expr. kind {
376+ err. span_label ( loop_span, "inside of this loop" ) ;
377+ }
378+ }
379+ }
380+ let typeck = self . infcx . tcx . typeck ( self . mir_def_id ( ) ) ;
381+ let hir_id = hir. get_parent_node ( expr. hir_id ) ;
382+ if let Some ( parent) = hir. find ( hir_id) {
383+ if let hir:: Node :: Expr ( parent_expr) = parent
384+ && let hir:: ExprKind :: MethodCall ( _, _, args, _) = parent_expr. kind
385+ && let Some ( def_id) = typeck. type_dependent_def_id ( parent_expr. hir_id )
386+ && let Some ( def_id) = def_id. as_local ( )
387+ && let Some ( node) = hir. find ( hir. local_def_id_to_hir_id ( def_id) )
388+ && let Some ( fn_sig) = node. fn_sig ( )
389+ && let Some ( ident) = node. ident ( )
390+ && let Some ( pos) = args. iter ( )
391+ . position ( |arg| arg. hir_id == expr. hir_id )
392+ && let Some ( arg) = fn_sig. decl . inputs . get ( pos + 1 )
393+ {
394+ let mut span: MultiSpan = arg. span . into ( ) ;
395+ span. push_span_label (
396+ arg. span ,
397+ "this type parameter takes ownership of the value" . to_string ( ) ,
398+ ) ;
399+ span. push_span_label (
400+ ident. span ,
401+ "in this method" . to_string ( ) ,
402+ ) ;
403+ err. span_note (
404+ span,
405+ format ! (
406+ "consider changing this parameter type in `{}` to borrow instead \
407+ if ownering the value isn't necessary",
408+ ident,
409+ ) ,
410+ ) ;
411+ }
412+ if let hir:: Node :: Expr ( parent_expr) = parent
413+ && let hir:: ExprKind :: Call ( call, args) = parent_expr. kind
414+ && let ty:: FnDef ( def_id, _) = typeck. node_type ( call. hir_id ) . kind ( )
415+ && let Some ( def_id) = def_id. as_local ( )
416+ && let Some ( node) = hir. find ( hir. local_def_id_to_hir_id ( def_id) )
417+ && let Some ( fn_sig) = node. fn_sig ( )
418+ && let Some ( ident) = node. ident ( )
419+ && let Some ( pos) = args. iter ( )
420+ . position ( |arg| arg. hir_id == expr. hir_id )
421+ && let Some ( arg) = fn_sig. decl . inputs . get ( pos)
422+ {
423+ let mut span: MultiSpan = arg. span . into ( ) ;
424+ span. push_span_label (
425+ arg. span ,
426+ "this type parameter takes ownership of the value" . to_string ( ) ,
427+ ) ;
428+ span. push_span_label (
429+ ident. span ,
430+ "in this function" . to_string ( ) ,
431+ ) ;
432+ err. span_note (
433+ span,
434+ format ! (
435+ "consider changing this parameter type in `{}` to borrow instead \
436+ if ownering the value isn't necessary",
437+ ident,
438+ ) ,
439+ ) ;
440+ }
441+ let place = & self . move_data . move_paths [ mpi] . place ;
442+ let ty = place. ty ( self . body , self . infcx . tcx ) . ty ;
443+ self . suggest_cloning ( err, ty, move_span) ;
444+ }
445+ }
446+ if let Some ( pat) = finder. pat && !seen_spans. contains ( & pat. span ) {
447+ * in_pattern = true ;
448+ err. span_suggestion_verbose (
449+ pat. span . shrink_to_lo ( ) ,
450+ "borrow this binding in the pattern to avoid moving the value" ,
451+ "ref " . to_string ( ) ,
452+ Applicability :: MachineApplicable ,
453+ ) ;
454+ seen_spans. insert ( pat. span ) ;
455+ }
456+ }
457+ }
458+
443459 fn report_use_of_uninitialized (
444460 & self ,
445461 mpi : MovePathIndex ,
0 commit comments