@@ -5,16 +5,21 @@ use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed
5
5
use rustc_hir as hir;
6
6
use rustc_hir:: def_id:: DefId ;
7
7
use rustc_hir:: { AsyncGeneratorKind , GeneratorKind } ;
8
+ use rustc_infer:: infer:: TyCtxtInferExt ;
9
+ use rustc_infer:: traits:: ObligationCause ;
8
10
use rustc_middle:: mir:: {
9
11
self , AggregateKind , BindingForm , BorrowKind , ClearCrossCrate , ConstraintCategory ,
10
12
FakeReadCause , LocalDecl , LocalInfo , LocalKind , Location , Operand , Place , PlaceRef ,
11
13
ProjectionElem , Rvalue , Statement , StatementKind , Terminator , TerminatorKind , VarBindingForm ,
12
14
} ;
13
- use rustc_middle:: ty:: { self , suggest_constraining_type_param, Ty } ;
15
+ use rustc_middle:: ty:: {
16
+ self , suggest_constraining_type_param, suggest_constraining_type_params, PredicateKind , Ty ,
17
+ } ;
14
18
use rustc_mir_dataflow:: move_paths:: { InitKind , MoveOutIndex , MovePathIndex } ;
15
19
use rustc_span:: symbol:: sym;
16
20
use rustc_span:: { BytePos , MultiSpan , Span , DUMMY_SP } ;
17
21
use rustc_trait_selection:: infer:: InferCtxtExt ;
22
+ use rustc_trait_selection:: traits:: TraitEngineExt as _;
18
23
19
24
use crate :: borrow_set:: TwoPhaseActivation ;
20
25
use crate :: borrowck_errors;
@@ -423,7 +428,63 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
423
428
None ,
424
429
) ;
425
430
}
431
+ } else {
432
+ // Try to find predicates on *generic params* that would allow copying `ty`
433
+
434
+ let tcx = self . infcx . tcx ;
435
+ let generics = tcx. generics_of ( self . mir_def_id ( ) ) ;
436
+ if let Some ( hir_generics) = tcx
437
+ . typeck_root_def_id ( self . mir_def_id ( ) . to_def_id ( ) )
438
+ . as_local ( )
439
+ . and_then ( |def_id| tcx. hir ( ) . get_generics ( def_id) )
440
+ {
441
+ let predicates: Result < Vec < _ > , _ > = tcx. infer_ctxt ( ) . enter ( |infcx| {
442
+ let mut fulfill_cx =
443
+ <dyn rustc_infer:: traits:: TraitEngine < ' _ > >:: new ( infcx. tcx ) ;
444
+
445
+ let copy_did = infcx. tcx . lang_items ( ) . copy_trait ( ) . unwrap ( ) ;
446
+ let cause = ObligationCause :: new (
447
+ span,
448
+ self . mir_hir_id ( ) ,
449
+ rustc_infer:: traits:: ObligationCauseCode :: MiscObligation ,
450
+ ) ;
451
+ fulfill_cx. register_bound ( & infcx, self . param_env , ty, copy_did, cause) ;
452
+ let errors = fulfill_cx. select_where_possible ( & infcx) ;
453
+
454
+ // Only emit suggestion if all required predicates are on generic
455
+ errors
456
+ . into_iter ( )
457
+ . map ( |err| match err. obligation . predicate . kind ( ) . skip_binder ( ) {
458
+ PredicateKind :: Trait ( predicate) => {
459
+ match predicate. self_ty ( ) . kind ( ) {
460
+ ty:: Param ( param_ty) => Ok ( (
461
+ generics. type_param ( param_ty, tcx) ,
462
+ predicate
463
+ . trait_ref
464
+ . print_only_trait_path ( )
465
+ . to_string ( ) ,
466
+ ) ) ,
467
+ _ => Err ( ( ) ) ,
468
+ }
469
+ }
470
+ _ => Err ( ( ) ) ,
471
+ } )
472
+ . collect ( )
473
+ } ) ;
474
+
475
+ if let Ok ( predicates) = predicates {
476
+ suggest_constraining_type_params (
477
+ tcx,
478
+ hir_generics,
479
+ & mut err,
480
+ predicates. iter ( ) . map ( |( param, constraint) | {
481
+ ( param. name . as_str ( ) , & * * constraint, None )
482
+ } ) ,
483
+ ) ;
484
+ }
485
+ }
426
486
}
487
+
427
488
let span = if let Some ( local) = place. as_local ( ) {
428
489
let decl = & self . body . local_decls [ local] ;
429
490
Some ( decl. source_info . span )
0 commit comments