@@ -6,6 +6,7 @@ use crate::session_diagnostics::{
66} ;
77use itertools:: Itertools ;
88use rustc_errors:: { Applicability , Diag } ;
9+ use rustc_errors:: { DiagCtxt , MultiSpan } ;
910use rustc_hir as hir;
1011use rustc_hir:: def:: { CtorKind , Namespace } ;
1112use rustc_hir:: CoroutineKind ;
@@ -30,6 +31,8 @@ use rustc_trait_selection::infer::InferCtxtExt;
3031use rustc_trait_selection:: traits:: error_reporting:: suggestions:: TypeErrCtxtExt as _;
3132use rustc_trait_selection:: traits:: type_known_to_meet_bound_modulo_regions;
3233
34+ use crate :: fluent_generated as fluent;
35+
3336use super :: borrow_set:: BorrowData ;
3437use super :: MirBorrowckCtxt ;
3538
@@ -589,7 +592,7 @@ impl UseSpans<'_> {
589592 #[ allow( rustc:: diagnostic_outside_of_impl) ]
590593 pub ( super ) fn args_subdiag (
591594 self ,
592- dcx : & rustc_errors :: DiagCtxt ,
595+ dcx : & DiagCtxt ,
593596 err : & mut Diag < ' _ > ,
594597 f : impl FnOnce ( Span ) -> CaptureArgLabel ,
595598 ) {
@@ -603,7 +606,7 @@ impl UseSpans<'_> {
603606 #[ allow( rustc:: diagnostic_outside_of_impl) ]
604607 pub ( super ) fn var_path_only_subdiag (
605608 self ,
606- dcx : & rustc_errors :: DiagCtxt ,
609+ dcx : & DiagCtxt ,
607610 err : & mut Diag < ' _ > ,
608611 action : crate :: InitializationRequiringAction ,
609612 ) {
@@ -641,7 +644,7 @@ impl UseSpans<'_> {
641644 #[ allow( rustc:: diagnostic_outside_of_impl) ]
642645 pub ( super ) fn var_subdiag (
643646 self ,
644- dcx : & rustc_errors :: DiagCtxt ,
647+ dcx : & DiagCtxt ,
645648 err : & mut Diag < ' _ > ,
646649 kind : Option < rustc_middle:: mir:: BorrowKind > ,
647650 f : impl FnOnce ( hir:: ClosureKind , Span ) -> CaptureVarCause ,
@@ -1036,7 +1039,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10361039 . map ( |n| format ! ( "`{n}`" ) )
10371040 . unwrap_or_else ( || "value" . to_owned ( ) ) ;
10381041 match kind {
1039- CallKind :: FnCall { fn_trait_id, .. }
1042+ CallKind :: FnCall { fn_trait_id, self_ty }
10401043 if Some ( fn_trait_id) == self . infcx . tcx . lang_items ( ) . fn_once_trait ( ) =>
10411044 {
10421045 err. subdiagnostic (
@@ -1048,7 +1051,58 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
10481051 is_loop_message,
10491052 } ,
10501053 ) ;
1051- err. subdiagnostic ( self . dcx ( ) , CaptureReasonNote :: FnOnceMoveInCall { var_span } ) ;
1054+ if let ty:: Param ( param_ty) = self_ty. kind ( )
1055+ && let generics = self . infcx . tcx . generics_of ( self . mir_def_id ( ) )
1056+ && let param = generics. type_param ( param_ty, self . infcx . tcx )
1057+ && let Some ( hir_generics) = self
1058+ . infcx
1059+ . tcx
1060+ . typeck_root_def_id ( self . mir_def_id ( ) . to_def_id ( ) )
1061+ . as_local ( )
1062+ . and_then ( |def_id| self . infcx . tcx . hir ( ) . get_generics ( def_id) )
1063+ && let spans = hir_generics
1064+ . predicates
1065+ . iter ( )
1066+ . filter_map ( |pred| match pred {
1067+ hir:: WherePredicate :: BoundPredicate ( pred) => Some ( pred) ,
1068+ _ => None ,
1069+ } )
1070+ . filter ( |pred| {
1071+ if let Some ( ( id, _) ) = pred. bounded_ty . as_generic_param ( ) {
1072+ id == param. def_id
1073+ } else {
1074+ false
1075+ }
1076+ } )
1077+ . flat_map ( |pred| pred. bounds )
1078+ . filter_map ( |bound| {
1079+ if let Some ( trait_ref) = bound. trait_ref ( )
1080+ && let Some ( trait_def_id) = trait_ref. trait_def_id ( )
1081+ && trait_def_id == fn_trait_id
1082+ {
1083+ Some ( bound. span ( ) )
1084+ } else {
1085+ None
1086+ }
1087+ } )
1088+ . collect :: < Vec < Span > > ( )
1089+ && !spans. is_empty ( )
1090+ {
1091+ let mut span: MultiSpan = spans. clone ( ) . into ( ) ;
1092+ for sp in spans {
1093+ span. push_span_label ( sp, fluent:: borrowck_moved_a_fn_once_in_call_def) ;
1094+ }
1095+ span. push_span_label (
1096+ fn_call_span,
1097+ fluent:: borrowck_moved_a_fn_once_in_call,
1098+ ) ;
1099+ err. span_note ( span, fluent:: borrowck_moved_a_fn_once_in_call_call) ;
1100+ } else {
1101+ err. subdiagnostic (
1102+ self . dcx ( ) ,
1103+ CaptureReasonNote :: FnOnceMoveInCall { var_span } ,
1104+ ) ;
1105+ }
10521106 }
10531107 CallKind :: Operator { self_arg, trait_id, .. } => {
10541108 let self_arg = self_arg. unwrap ( ) ;
0 commit comments