@@ -175,12 +175,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
175175 let mut is_loop_move = false ;
176176 let mut in_pattern = false ;
177177
178+ let mut to_clone_spans = Vec :: new ( ) ;
179+
178180 for move_site in & move_site_vec {
179181 let move_out = self . move_data . moves [ ( * move_site) . moi ] ;
180182 let moved_place = & self . move_data . move_paths [ move_out. path ] . place ;
181183
182184 let move_spans = self . move_spans ( moved_place. as_ref ( ) , move_out. source ) ;
183185 let move_span = move_spans. args_or_use ( ) ;
186+ to_clone_spans. push ( move_spans. var_or_use_path_span ( ) ) ;
184187
185188 let move_msg = if move_spans. for_closure ( ) { " into closure" } else { "" } ;
186189
@@ -293,18 +296,62 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
293296 . and_then ( |def_id| tcx. hir ( ) . get_generics ( def_id) )
294297 {
295298 let copy_did = tcx. lang_items ( ) . copy_trait ( ) . unwrap ( ) ;
296- let predicates =
299+ let copy_predicates =
297300 self . try_find_missing_generic_bounds ( ty, copy_did, generics, span) ;
298301
299- if let Ok ( predicates) = predicates {
300- suggest_constraining_type_params (
301- tcx,
302- hir_generics,
303- & mut err,
304- predicates. iter ( ) . map ( |( param, constraint) | {
305- ( param. name . as_str ( ) , & * * constraint, None )
306- } ) ,
307- ) ;
302+ let clone_did = tcx. lang_items ( ) . clone_trait ( ) . unwrap ( ) ;
303+ let clone_predicates =
304+ self . try_find_missing_generic_bounds ( ty, clone_did, generics, span) ;
305+
306+ match ( copy_predicates, clone_predicates) {
307+ // The type is already `Clone`, suggest cloning all values
308+ ( _, Ok ( clone_predicates) ) if clone_predicates. is_empty ( ) => {
309+ err. multipart_suggestion_verbose (
310+ & format ! ( "consider cloning {}" , note_msg) ,
311+ to_clone_spans
312+ . into_iter ( )
313+ . map ( |move_span| {
314+ ( move_span. shrink_to_hi ( ) , ".clone()" . to_owned ( ) )
315+ } )
316+ . collect ( ) ,
317+ Applicability :: MaybeIncorrect ,
318+ ) ;
319+ }
320+ // The type can *not* be `Copy`, but can be `Clone`, suggest adding bounds to make the type `Clone` and then cloning all values
321+ ( Err ( _) , Ok ( clone_predicates) ) => {
322+ suggest_constraining_type_params (
323+ tcx,
324+ hir_generics,
325+ & mut err,
326+ clone_predicates. iter ( ) . map ( |( param, constraint) | {
327+ ( param. name . as_str ( ) , & * * constraint, None )
328+ } ) ,
329+ ) ;
330+
331+ err. multipart_suggestion_verbose (
332+ & format ! ( "...and cloning {}" , note_msg) ,
333+ to_clone_spans
334+ . into_iter ( )
335+ . map ( |move_span| {
336+ ( move_span. shrink_to_hi ( ) , ".clone()" . to_owned ( ) )
337+ } )
338+ . collect ( ) ,
339+ Applicability :: MaybeIncorrect ,
340+ ) ;
341+ }
342+ // The type can be `Copy`, suggest adding bound to make it `Copy`
343+ ( Ok ( copy_predicates) , _) => {
344+ suggest_constraining_type_params (
345+ tcx,
346+ hir_generics,
347+ & mut err,
348+ copy_predicates. iter ( ) . map ( |( param, constraint) | {
349+ ( param. name . as_str ( ) , & * * constraint, None )
350+ } ) ,
351+ ) ;
352+ }
353+ // The type can never be `Clone` or `Copy`, there is nothing to suggest :(
354+ ( Err ( _) , Err ( _) ) => { }
308355 }
309356 }
310357
0 commit comments