@@ -5,16 +5,21 @@ use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed
55use rustc_hir as hir;
66use rustc_hir:: def_id:: DefId ;
77use rustc_hir:: { AsyncGeneratorKind , GeneratorKind } ;
8+ use rustc_infer:: infer:: TyCtxtInferExt ;
9+ use rustc_infer:: traits:: ObligationCause ;
810use rustc_middle:: mir:: {
911 self , AggregateKind , BindingForm , BorrowKind , ClearCrossCrate , ConstraintCategory ,
1012 FakeReadCause , LocalDecl , LocalInfo , LocalKind , Location , Operand , Place , PlaceRef ,
1113 ProjectionElem , Rvalue , Statement , StatementKind , Terminator , TerminatorKind , VarBindingForm ,
1214} ;
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+ } ;
1418use rustc_mir_dataflow:: move_paths:: { InitKind , MoveOutIndex , MovePathIndex } ;
1519use rustc_span:: symbol:: sym;
1620use rustc_span:: { BytePos , MultiSpan , Span , DUMMY_SP } ;
1721use rustc_trait_selection:: infer:: InferCtxtExt ;
22+ use rustc_trait_selection:: traits:: TraitEngineExt as _;
1823
1924use crate :: borrow_set:: TwoPhaseActivation ;
2025use crate :: borrowck_errors;
@@ -423,7 +428,63 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
423428 None ,
424429 ) ;
425430 }
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+ }
426486 }
487+
427488 let span = if let Some ( local) = place. as_local ( ) {
428489 let decl = & self . body . local_decls [ local] ;
429490 Some ( decl. source_info . span )
0 commit comments