Skip to content

Commit 10dccdc

Browse files
committed
Auto merge of rust-lang#94515 - estebank:tweak-move-error, r=davidtwco
Tweak move error Point at method definition that causes type to be consumed. Fix rust-lang#94056.
2 parents 6045c34 + 9875277 commit 10dccdc

21 files changed

+289
-242
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+15-140
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use either::Either;
2-
use rustc_const_eval::util::{CallDesugaringKind, CallKind};
2+
use rustc_const_eval::util::CallKind;
33
use rustc_data_structures::fx::FxHashSet;
44
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
55
use rustc_hir as hir;
@@ -17,7 +17,7 @@ use rustc_middle::ty::{
1717
};
1818
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
1919
use rustc_span::symbol::sym;
20-
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
20+
use rustc_span::{BytePos, MultiSpan, Span};
2121
use rustc_trait_selection::infer::InferCtxtExt;
2222
use rustc_trait_selection::traits::TraitEngineExt as _;
2323

@@ -195,144 +195,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
195195
is_loop_move = true;
196196
}
197197

198-
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
199-
let place_name = self
200-
.describe_place(moved_place.as_ref())
201-
.map(|n| format!("`{}`", n))
202-
.unwrap_or_else(|| "value".to_owned());
203-
match kind {
204-
CallKind::FnCall { fn_trait_id, .. }
205-
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
206-
{
207-
err.span_label(
208-
fn_call_span,
209-
&format!(
210-
"{} {}moved due to this call{}",
211-
place_name, partially_str, loop_message
212-
),
213-
);
214-
err.span_note(
215-
var_span,
216-
"this value implements `FnOnce`, which causes it to be moved when called",
217-
);
218-
}
219-
CallKind::Operator { self_arg, .. } => {
220-
let self_arg = self_arg.unwrap();
221-
err.span_label(
222-
fn_call_span,
223-
&format!(
224-
"{} {}moved due to usage in operator{}",
225-
place_name, partially_str, loop_message
226-
),
227-
);
228-
if self.fn_self_span_reported.insert(fn_span) {
229-
err.span_note(
230-
// Check whether the source is accessible
231-
if self
232-
.infcx
233-
.tcx
234-
.sess
235-
.source_map()
236-
.span_to_snippet(self_arg.span)
237-
.is_ok()
238-
{
239-
self_arg.span
240-
} else {
241-
fn_call_span
242-
},
243-
"calling this operator moves the left-hand side",
244-
);
245-
}
246-
}
247-
CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
248-
let self_arg = self_arg.unwrap();
249-
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
250-
err.span_label(
251-
fn_call_span,
252-
&format!(
253-
"{} {}moved due to this implicit call to `.into_iter()`{}",
254-
place_name, partially_str, loop_message
255-
),
256-
);
257-
let sess = self.infcx.tcx.sess;
258-
let ty = used_place.ty(self.body, self.infcx.tcx).ty;
259-
// If we have a `&mut` ref, we need to reborrow.
260-
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
261-
// If we are in a loop this will be suggested later.
262-
if !is_loop_move {
263-
err.span_suggestion_verbose(
264-
move_span.shrink_to_lo(),
265-
&format!(
266-
"consider creating a fresh reborrow of {} here",
267-
self.describe_place(moved_place.as_ref())
268-
.map(|n| format!("`{}`", n))
269-
.unwrap_or_else(
270-
|| "the mutable reference".to_string()
271-
),
272-
),
273-
"&mut *".to_string(),
274-
Applicability::MachineApplicable,
275-
);
276-
}
277-
} else if let Ok(snippet) =
278-
sess.source_map().span_to_snippet(move_span)
279-
{
280-
err.span_suggestion(
281-
move_span,
282-
"consider borrowing to avoid moving into the for loop",
283-
format!("&{}", snippet),
284-
Applicability::MaybeIncorrect,
285-
);
286-
}
287-
} else {
288-
err.span_label(
289-
fn_call_span,
290-
&format!(
291-
"{} {}moved due to this method call{}",
292-
place_name, partially_str, loop_message
293-
),
294-
);
295-
}
296-
if is_option_or_result && maybe_reinitialized_locations.is_empty() {
297-
err.span_suggestion_verbose(
298-
fn_call_span.shrink_to_lo(),
299-
"consider calling `.as_ref()` to borrow the type's contents",
300-
"as_ref().".to_string(),
301-
Applicability::MachineApplicable,
302-
);
303-
}
304-
// Avoid pointing to the same function in multiple different
305-
// error messages.
306-
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span)
307-
{
308-
err.span_note(
309-
self_arg.span,
310-
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
311-
);
312-
}
313-
}
314-
// Other desugarings takes &self, which cannot cause a move
315-
_ => unreachable!(),
316-
}
317-
} else {
318-
err.span_label(
319-
move_span,
320-
format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
321-
);
322-
// If the move error occurs due to a loop, don't show
323-
// another message for the same span
324-
if loop_message.is_empty() {
325-
move_spans.var_span_label(
326-
&mut err,
327-
format!(
328-
"variable {}moved due to use{}",
329-
partially_str,
330-
move_spans.describe()
331-
),
332-
"moved",
333-
);
334-
}
335-
}
198+
self.explain_captures(
199+
&mut err,
200+
span,
201+
move_span,
202+
move_spans,
203+
*moved_place,
204+
Some(used_place),
205+
partially_str,
206+
loop_message,
207+
move_msg,
208+
is_loop_move,
209+
maybe_reinitialized_locations.is_empty(),
210+
);
336211

337212
if let (UseSpans::PatUse(span), []) =
338213
(move_spans, &maybe_reinitialized_locations[..])

compiler/rustc_borrowck/src/diagnostics/mod.rs

+174-5
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
//! Borrow checker diagnostics.
22
3-
use rustc_const_eval::util::call_kind;
4-
use rustc_errors::Diagnostic;
3+
use rustc_const_eval::util::{call_kind, CallDesugaringKind};
4+
use rustc_errors::{Applicability, Diagnostic};
55
use rustc_hir as hir;
66
use rustc_hir::def::Namespace;
77
use rustc_hir::def_id::DefId;
88
use rustc_hir::GeneratorKind;
9+
use rustc_infer::infer::TyCtxtInferExt;
910
use rustc_middle::mir::{
1011
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
1112
Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
1213
};
1314
use rustc_middle::ty::print::Print;
1415
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
1516
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
16-
use rustc_span::{symbol::sym, Span};
17+
use rustc_span::{symbol::sym, Span, DUMMY_SP};
1718
use rustc_target::abi::VariantIdx;
19+
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
1820

1921
use super::borrow_set::BorrowData;
2022
use super::MirBorrowckCtxt;
@@ -482,9 +484,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
482484
BorrowedContentSource::DerefSharedRef
483485
}
484486
}
485-
}
486487

487-
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
488488
/// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
489489
/// name where required.
490490
pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
@@ -995,4 +995,173 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
995995
let span = self.body.source_info(borrow.reserve_location).span;
996996
self.borrow_spans(span, borrow.reserve_location)
997997
}
998+
999+
fn explain_captures(
1000+
&mut self,
1001+
err: &mut Diagnostic,
1002+
span: Span,
1003+
move_span: Span,
1004+
move_spans: UseSpans<'tcx>,
1005+
moved_place: Place<'tcx>,
1006+
used_place: Option<PlaceRef<'tcx>>,
1007+
partially_str: &str,
1008+
loop_message: &str,
1009+
move_msg: &str,
1010+
is_loop_move: bool,
1011+
maybe_reinitialized_locations_is_empty: bool,
1012+
) {
1013+
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
1014+
let place_name = self
1015+
.describe_place(moved_place.as_ref())
1016+
.map(|n| format!("`{}`", n))
1017+
.unwrap_or_else(|| "value".to_owned());
1018+
match kind {
1019+
CallKind::FnCall { fn_trait_id, .. }
1020+
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
1021+
{
1022+
err.span_label(
1023+
fn_call_span,
1024+
&format!(
1025+
"{} {}moved due to this call{}",
1026+
place_name, partially_str, loop_message
1027+
),
1028+
);
1029+
err.span_note(
1030+
var_span,
1031+
"this value implements `FnOnce`, which causes it to be moved when called",
1032+
);
1033+
}
1034+
CallKind::Operator { self_arg, .. } => {
1035+
let self_arg = self_arg.unwrap();
1036+
err.span_label(
1037+
fn_call_span,
1038+
&format!(
1039+
"{} {}moved due to usage in operator{}",
1040+
place_name, partially_str, loop_message
1041+
),
1042+
);
1043+
if self.fn_self_span_reported.insert(fn_span) {
1044+
err.span_note(
1045+
// Check whether the source is accessible
1046+
if self
1047+
.infcx
1048+
.tcx
1049+
.sess
1050+
.source_map()
1051+
.span_to_snippet(self_arg.span)
1052+
.is_ok()
1053+
{
1054+
self_arg.span
1055+
} else {
1056+
fn_call_span
1057+
},
1058+
"calling this operator moves the left-hand side",
1059+
);
1060+
}
1061+
}
1062+
CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
1063+
let self_arg = self_arg.unwrap();
1064+
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
1065+
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
1066+
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
1067+
Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
1068+
type_known_to_meet_bound_modulo_regions(
1069+
&infcx,
1070+
self.param_env,
1071+
infcx.tcx.mk_imm_ref(
1072+
infcx.tcx.lifetimes.re_erased,
1073+
infcx.tcx.erase_regions(ty),
1074+
),
1075+
def_id,
1076+
DUMMY_SP,
1077+
)
1078+
}),
1079+
_ => false,
1080+
};
1081+
if suggest {
1082+
err.span_suggestion_verbose(
1083+
move_span.shrink_to_lo(),
1084+
&format!(
1085+
"consider iterating over a slice of the `{}`'s content to \
1086+
avoid moving into the `for` loop",
1087+
ty,
1088+
),
1089+
"&".to_string(),
1090+
Applicability::MaybeIncorrect,
1091+
);
1092+
}
1093+
1094+
err.span_label(
1095+
fn_call_span,
1096+
&format!(
1097+
"{} {}moved due to this implicit call to `.into_iter()`{}",
1098+
place_name, partially_str, loop_message
1099+
),
1100+
);
1101+
// If we have a `&mut` ref, we need to reborrow.
1102+
if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place
1103+
.map(|used_place| used_place.ty(self.body, self.infcx.tcx).ty.kind())
1104+
{
1105+
// If we are in a loop this will be suggested later.
1106+
if !is_loop_move {
1107+
err.span_suggestion_verbose(
1108+
move_span.shrink_to_lo(),
1109+
&format!(
1110+
"consider creating a fresh reborrow of {} here",
1111+
self.describe_place(moved_place.as_ref())
1112+
.map(|n| format!("`{}`", n))
1113+
.unwrap_or_else(|| "the mutable reference".to_string()),
1114+
),
1115+
"&mut *".to_string(),
1116+
Applicability::MachineApplicable,
1117+
);
1118+
}
1119+
}
1120+
} else {
1121+
err.span_label(
1122+
fn_call_span,
1123+
&format!(
1124+
"{} {}moved due to this method call{}",
1125+
place_name, partially_str, loop_message
1126+
),
1127+
);
1128+
}
1129+
if is_option_or_result && maybe_reinitialized_locations_is_empty {
1130+
err.span_suggestion_verbose(
1131+
fn_call_span.shrink_to_lo(),
1132+
"consider calling `.as_ref()` to borrow the type's contents",
1133+
"as_ref().".to_string(),
1134+
Applicability::MachineApplicable,
1135+
);
1136+
}
1137+
// Avoid pointing to the same function in multiple different
1138+
// error messages.
1139+
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
1140+
err.span_note(
1141+
self_arg.span,
1142+
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
1143+
);
1144+
}
1145+
}
1146+
// Other desugarings takes &self, which cannot cause a move
1147+
_ => {}
1148+
}
1149+
} else {
1150+
if move_span != span || !loop_message.is_empty() {
1151+
err.span_label(
1152+
move_span,
1153+
format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
1154+
);
1155+
}
1156+
// If the move error occurs due to a loop, don't show
1157+
// another message for the same span
1158+
if loop_message.is_empty() {
1159+
move_spans.var_span_label(
1160+
err,
1161+
format!("variable {}moved due to use{}", partially_str, move_spans.describe()),
1162+
"moved",
1163+
);
1164+
}
1165+
}
1166+
}
9981167
}

0 commit comments

Comments
 (0)