@@ -11,6 +11,7 @@ use rustc_hir::def::{CtorKind, Namespace};
11
11
use rustc_hir:: CoroutineKind ;
12
12
use rustc_index:: IndexSlice ;
13
13
use rustc_infer:: infer:: BoundRegionConversionTime ;
14
+ use rustc_infer:: traits:: { FulfillmentErrorCode , SelectionError , TraitEngineExt } ;
14
15
use rustc_middle:: mir:: tcx:: PlaceTy ;
15
16
use rustc_middle:: mir:: {
16
17
AggregateKind , CallSource , ConstOperand , FakeReadCause , Local , LocalInfo , LocalKind , Location ,
@@ -24,7 +25,8 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
24
25
use rustc_span:: def_id:: LocalDefId ;
25
26
use rustc_span:: { symbol:: sym, Span , Symbol , DUMMY_SP } ;
26
27
use rustc_target:: abi:: { FieldIdx , VariantIdx } ;
27
- use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
28
+ use rustc_trait_selection:: solve:: FulfillmentCtxt ;
29
+ use rustc_trait_selection:: traits:: error_reporting:: suggestions:: TypeErrCtxtExt as _;
28
30
use rustc_trait_selection:: traits:: {
29
31
type_known_to_meet_bound_modulo_regions, Obligation , ObligationCause ,
30
32
} ;
@@ -1043,7 +1045,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1043
1045
}
1044
1046
CallKind :: Normal { self_arg, desugaring, method_did, method_args } => {
1045
1047
let self_arg = self_arg. unwrap ( ) ;
1048
+ let mut has_sugg = false ;
1046
1049
let tcx = self . infcx . tcx ;
1050
+ // Avoid pointing to the same function in multiple different
1051
+ // error messages.
1052
+ if span != DUMMY_SP && self . fn_self_span_reported . insert ( self_arg. span ) {
1053
+ self . explain_iterator_advancement_in_for_loop_if_applicable (
1054
+ err,
1055
+ span,
1056
+ & move_spans,
1057
+ ) ;
1058
+
1059
+ let func = tcx. def_path_str ( method_did) ;
1060
+ err. subdiagnostic ( CaptureReasonNote :: FuncTakeSelf {
1061
+ func,
1062
+ place_name : place_name. clone ( ) ,
1063
+ span : self_arg. span ,
1064
+ } ) ;
1065
+ }
1066
+ let parent_did = tcx. parent ( method_did) ;
1067
+ let parent_self_ty =
1068
+ matches ! ( tcx. def_kind( parent_did) , rustc_hir:: def:: DefKind :: Impl { .. } )
1069
+ . then_some ( parent_did)
1070
+ . and_then ( |did| match tcx. type_of ( did) . instantiate_identity ( ) . kind ( ) {
1071
+ ty:: Adt ( def, ..) => Some ( def. did ( ) ) ,
1072
+ _ => None ,
1073
+ } ) ;
1074
+ let is_option_or_result = parent_self_ty. is_some_and ( |def_id| {
1075
+ matches ! ( tcx. get_diagnostic_name( def_id) , Some ( sym:: Option | sym:: Result ) )
1076
+ } ) ;
1077
+ if is_option_or_result && maybe_reinitialized_locations_is_empty {
1078
+ err. subdiagnostic ( CaptureReasonLabel :: BorrowContent { var_span } ) ;
1079
+ }
1047
1080
if let Some ( ( CallDesugaringKind :: ForLoopIntoIter , _) ) = desugaring {
1048
1081
let ty = moved_place. ty ( self . body , tcx) . ty ;
1049
1082
let suggest = match tcx. get_diagnostic_item ( sym:: IntoIterator ) {
@@ -1108,7 +1141,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1108
1141
// Erase and shadow everything that could be passed to the new infcx.
1109
1142
let ty = moved_place. ty ( self . body , tcx) . ty ;
1110
1143
1111
- if let ty:: Adt ( def, args) = ty. kind ( )
1144
+ if let ty:: Adt ( def, args) = ty. peel_refs ( ) . kind ( )
1112
1145
&& Some ( def. did ( ) ) == tcx. lang_items ( ) . pin_type ( )
1113
1146
&& let ty:: Ref ( _, _, hir:: Mutability :: Mut ) = args. type_at ( 0 ) . kind ( )
1114
1147
&& let self_ty = self . infcx . instantiate_binder_with_fresh_vars (
@@ -1124,17 +1157,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1124
1157
span : move_span. shrink_to_hi ( ) ,
1125
1158
} ,
1126
1159
) ;
1160
+ has_sugg = true ;
1127
1161
}
1128
- if let Some ( clone_trait) = tcx. lang_items ( ) . clone_trait ( )
1129
- && let trait_ref = ty:: TraitRef :: new ( tcx, clone_trait, [ ty] )
1130
- && let o = Obligation :: new (
1131
- tcx,
1132
- ObligationCause :: dummy ( ) ,
1133
- self . param_env ,
1134
- ty:: Binder :: dummy ( trait_ref) ,
1135
- )
1136
- && self . infcx . predicate_must_hold_modulo_regions ( & o)
1137
- {
1162
+ if let Some ( clone_trait) = tcx. lang_items ( ) . clone_trait ( ) {
1138
1163
let sugg = if moved_place
1139
1164
. iter_projections ( )
1140
1165
. any ( |( _, elem) | matches ! ( elem, ProjectionElem :: Deref ) )
@@ -1150,43 +1175,94 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1150
1175
} else {
1151
1176
vec ! [ ( move_span. shrink_to_hi( ) , ".clone()" . to_string( ) ) ]
1152
1177
} ;
1153
- err. multipart_suggestion_verbose (
1154
- "you can `clone` the value and consume it, but this might not be \
1155
- your desired behavior",
1156
- sugg,
1157
- Applicability :: MaybeIncorrect ,
1158
- ) ;
1159
- }
1160
- }
1161
- // Avoid pointing to the same function in multiple different
1162
- // error messages.
1163
- if span != DUMMY_SP && self . fn_self_span_reported . insert ( self_arg. span ) {
1164
- self . explain_iterator_advancement_in_for_loop_if_applicable (
1165
- err,
1166
- span,
1167
- & move_spans,
1168
- ) ;
1169
-
1170
- let func = tcx. def_path_str ( method_did) ;
1171
- err. subdiagnostic ( CaptureReasonNote :: FuncTakeSelf {
1172
- func,
1173
- place_name,
1174
- span : self_arg. span ,
1175
- } ) ;
1176
- }
1177
- let parent_did = tcx. parent ( method_did) ;
1178
- let parent_self_ty =
1179
- matches ! ( tcx. def_kind( parent_did) , rustc_hir:: def:: DefKind :: Impl { .. } )
1180
- . then_some ( parent_did)
1181
- . and_then ( |did| match tcx. type_of ( did) . instantiate_identity ( ) . kind ( ) {
1182
- ty:: Adt ( def, ..) => Some ( def. did ( ) ) ,
1183
- _ => None ,
1178
+ self . infcx . probe ( |_snapshot| {
1179
+ if let ty:: Adt ( def, args) = ty. kind ( )
1180
+ && !has_sugg
1181
+ && let Some ( ( def_id, _imp) ) = tcx
1182
+ . all_impls ( clone_trait)
1183
+ . filter_map ( |def_id| {
1184
+ tcx. impl_trait_ref ( def_id) . map ( |r| ( def_id, r) )
1185
+ } )
1186
+ . map ( |( def_id, imp) | ( def_id, imp. skip_binder ( ) ) )
1187
+ . filter ( |( _, imp) | match imp. self_ty ( ) . peel_refs ( ) . kind ( ) {
1188
+ ty:: Adt ( i_def, _) if i_def. did ( ) == def. did ( ) => true ,
1189
+ _ => false ,
1190
+ } )
1191
+ . next ( )
1192
+ {
1193
+ let mut fulfill_cx = FulfillmentCtxt :: new ( self . infcx ) ;
1194
+ // We get all obligations from the impl to talk about specific
1195
+ // trait bounds.
1196
+ let obligations = tcx
1197
+ . predicates_of ( def_id)
1198
+ . instantiate ( tcx, args)
1199
+ . into_iter ( )
1200
+ . map ( |( clause, span) | {
1201
+ Obligation :: new (
1202
+ tcx,
1203
+ ObligationCause :: misc (
1204
+ span,
1205
+ self . body . source . def_id ( ) . expect_local ( ) ,
1206
+ ) ,
1207
+ self . param_env ,
1208
+ clause,
1209
+ )
1210
+ } )
1211
+ . collect :: < Vec < _ > > ( ) ;
1212
+ fulfill_cx
1213
+ . register_predicate_obligations ( self . infcx , obligations) ;
1214
+ let errors = fulfill_cx. select_all_or_error ( self . infcx ) ;
1215
+ let msg = match & errors[ ..] {
1216
+ [ ] => "you can `clone` the value and consume it, but this \
1217
+ might not be your desired behavior"
1218
+ . to_string ( ) ,
1219
+ [ error] => {
1220
+ format ! (
1221
+ "you could `clone` the value and consume it, if \
1222
+ the `{}` trait bound could be satisfied",
1223
+ error. obligation. predicate,
1224
+ )
1225
+ }
1226
+ [ errors @ .., last] => {
1227
+ format ! (
1228
+ "you could `clone` the value and consume it, if \
1229
+ the following trait bounds could be satisfied: {} \
1230
+ and `{}`",
1231
+ errors
1232
+ . iter( )
1233
+ . map( |e| format!(
1234
+ "`{}`" ,
1235
+ e. obligation. predicate
1236
+ ) )
1237
+ . collect:: <Vec <_>>( )
1238
+ . join( ", " ) ,
1239
+ last. obligation. predicate,
1240
+ )
1241
+ }
1242
+ } ;
1243
+ err. multipart_suggestion_verbose (
1244
+ msg,
1245
+ sugg. clone ( ) ,
1246
+ Applicability :: MaybeIncorrect ,
1247
+ ) ;
1248
+ for error in errors {
1249
+ if let FulfillmentErrorCode :: CodeSelectionError (
1250
+ SelectionError :: Unimplemented ,
1251
+ ) = error. code
1252
+ && let ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait (
1253
+ pred,
1254
+ ) ) = error. obligation . predicate . kind ( ) . skip_binder ( )
1255
+ {
1256
+ self . infcx . err_ctxt ( ) . suggest_derive (
1257
+ & error. obligation ,
1258
+ err,
1259
+ error. obligation . predicate . kind ( ) . rebind ( pred) ,
1260
+ ) ;
1261
+ }
1262
+ }
1263
+ }
1184
1264
} ) ;
1185
- let is_option_or_result = parent_self_ty. is_some_and ( |def_id| {
1186
- matches ! ( tcx. get_diagnostic_name( def_id) , Some ( sym:: Option | sym:: Result ) )
1187
- } ) ;
1188
- if is_option_or_result && maybe_reinitialized_locations_is_empty {
1189
- err. subdiagnostic ( CaptureReasonLabel :: BorrowContent { var_span } ) ;
1265
+ }
1190
1266
}
1191
1267
}
1192
1268
// Other desugarings takes &self, which cannot cause a move
0 commit comments