Skip to content

Commit fa6a61c

Browse files
committed
Explain move errors that occur due to method calls involving self
This is a re-attempt of rust-lang#72389 (which was reverted in rust-lang#73594) Instead of using `ExpnKind::Desugaring` to represent operators, this PR checks the lang item directly.
1 parent 36ac08e commit fa6a61c

38 files changed

+745
-102
lines changed

src/librustc_ast_lowering/expr.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_data_structures::thin_vec::ThinVec;
99
use rustc_errors::struct_span_err;
1010
use rustc_hir as hir;
1111
use rustc_hir::def::Res;
12-
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
12+
use rustc_span::source_map::{respan, DesugaringKind, ForLoopLoc, Span, Spanned};
1313
use rustc_span::symbol::{sym, Ident, Symbol};
1414
use rustc_target::asm;
1515
use std::collections::hash_map::Entry;
@@ -1361,9 +1361,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
13611361
body: &Block,
13621362
opt_label: Option<Label>,
13631363
) -> hir::Expr<'hir> {
1364+
let orig_head_span = head.span;
13641365
// expand <head>
13651366
let mut head = self.lower_expr_mut(head);
1366-
let desugared_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
1367+
let desugared_span = self.mark_span_with_reason(
1368+
DesugaringKind::ForLoop(ForLoopLoc::Head),
1369+
orig_head_span,
1370+
None,
1371+
);
13671372
head.span = desugared_span;
13681373

13691374
let iter = Ident::with_dummy_span(sym::iter);
@@ -1458,10 +1463,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
14581463
// `mut iter => { ... }`
14591464
let iter_arm = self.arm(iter_pat, loop_expr);
14601465

1466+
let into_iter_span = self.mark_span_with_reason(
1467+
DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
1468+
orig_head_span,
1469+
None,
1470+
);
1471+
14611472
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
14621473
let into_iter_expr = {
14631474
let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter];
1464-
self.expr_call_std_path(desugared_span, into_iter_path, arena_vec![self; head])
1475+
self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head])
14651476
};
14661477

14671478
let match_expr = self.arena.alloc(self.expr_match(

src/librustc_hir/lang_items.rs

+55-25
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,26 @@ use rustc_span::Span;
2121

2222
use lazy_static::lazy_static;
2323

24+
pub enum LangItemGroup {
25+
Op,
26+
}
27+
28+
const NUM_GROUPS: usize = 1;
29+
30+
macro_rules! expand_group {
31+
() => {
32+
None
33+
};
34+
($group:expr) => {
35+
Some($group)
36+
};
37+
}
38+
2439
// The actual lang items defined come at the end of this file in one handy table.
2540
// So you probably just want to nip down to the end.
2641
macro_rules! language_item_table {
2742
(
28-
$( $variant:ident, $name:expr, $method:ident, $target:expr; )*
43+
$( $variant:ident $($group:expr)?, $name:expr, $method:ident, $target:expr; )*
2944
) => {
3045

3146
enum_from_u32! {
@@ -45,6 +60,13 @@ macro_rules! language_item_table {
4560
$( $variant => $name, )*
4661
}
4762
}
63+
64+
pub fn group(self) -> Option<LangItemGroup> {
65+
use LangItemGroup::*;
66+
match self {
67+
$( $variant => expand_group!($($group)*), )*
68+
}
69+
}
4870
}
4971

5072
#[derive(HashStable_Generic)]
@@ -54,6 +76,9 @@ macro_rules! language_item_table {
5476
pub items: Vec<Option<DefId>>,
5577
/// Lang items that were not found during collection.
5678
pub missing: Vec<LangItem>,
79+
/// Mapping from `LangItemGroup` discriminants to all
80+
/// `DefId`s of lang items in that group.
81+
pub groups: [Vec<DefId>; NUM_GROUPS],
5782
}
5883

5984
impl LanguageItems {
@@ -64,6 +89,7 @@ macro_rules! language_item_table {
6489
Self {
6590
items: vec![$(init_none($variant)),*],
6691
missing: Vec::new(),
92+
groups: [vec![]; NUM_GROUPS],
6793
}
6894
}
6995

@@ -79,6 +105,10 @@ macro_rules! language_item_table {
79105
self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name()))
80106
}
81107

108+
pub fn group(&self, group: LangItemGroup) -> &[DefId] {
109+
self.groups[group as usize].as_ref()
110+
}
111+
82112
$(
83113
/// Returns the corresponding `DefId` for the lang item
84114
#[doc = $name]
@@ -171,30 +201,30 @@ language_item_table! {
171201
CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait;
172202
DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait;
173203

174-
AddTraitLangItem, "add", add_trait, Target::Trait;
175-
SubTraitLangItem, "sub", sub_trait, Target::Trait;
176-
MulTraitLangItem, "mul", mul_trait, Target::Trait;
177-
DivTraitLangItem, "div", div_trait, Target::Trait;
178-
RemTraitLangItem, "rem", rem_trait, Target::Trait;
179-
NegTraitLangItem, "neg", neg_trait, Target::Trait;
180-
NotTraitLangItem, "not", not_trait, Target::Trait;
181-
BitXorTraitLangItem, "bitxor", bitxor_trait, Target::Trait;
182-
BitAndTraitLangItem, "bitand", bitand_trait, Target::Trait;
183-
BitOrTraitLangItem, "bitor", bitor_trait, Target::Trait;
184-
ShlTraitLangItem, "shl", shl_trait, Target::Trait;
185-
ShrTraitLangItem, "shr", shr_trait, Target::Trait;
186-
AddAssignTraitLangItem, "add_assign", add_assign_trait, Target::Trait;
187-
SubAssignTraitLangItem, "sub_assign", sub_assign_trait, Target::Trait;
188-
MulAssignTraitLangItem, "mul_assign", mul_assign_trait, Target::Trait;
189-
DivAssignTraitLangItem, "div_assign", div_assign_trait, Target::Trait;
190-
RemAssignTraitLangItem, "rem_assign", rem_assign_trait, Target::Trait;
191-
BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait, Target::Trait;
192-
BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait, Target::Trait;
193-
BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait, Target::Trait;
194-
ShlAssignTraitLangItem, "shl_assign", shl_assign_trait, Target::Trait;
195-
ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait;
196-
IndexTraitLangItem, "index", index_trait, Target::Trait;
197-
IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait;
204+
AddTraitLangItem(Op), "add", add_trait, Target::Trait;
205+
SubTraitLangItem(Op), "sub", sub_trait, Target::Trait;
206+
MulTraitLangItem(Op), "mul", mul_trait, Target::Trait;
207+
DivTraitLangItem(Op), "div", div_trait, Target::Trait;
208+
RemTraitLangItem(Op), "rem", rem_trait, Target::Trait;
209+
NegTraitLangItem(Op), "neg", neg_trait, Target::Trait;
210+
NotTraitLangItem(Op), "not", not_trait, Target::Trait;
211+
BitXorTraitLangItem(Op), "bitxor", bitxor_trait, Target::Trait;
212+
BitAndTraitLangItem(Op), "bitand", bitand_trait, Target::Trait;
213+
BitOrTraitLangItem(Op), "bitor", bitor_trait, Target::Trait;
214+
ShlTraitLangItem(Op), "shl", shl_trait, Target::Trait;
215+
ShrTraitLangItem(Op), "shr", shr_trait, Target::Trait;
216+
AddAssignTraitLangItem(Op), "add_assign", add_assign_trait, Target::Trait;
217+
SubAssignTraitLangItem(Op), "sub_assign", sub_assign_trait, Target::Trait;
218+
MulAssignTraitLangItem(Op), "mul_assign", mul_assign_trait, Target::Trait;
219+
DivAssignTraitLangItem(Op), "div_assign", div_assign_trait, Target::Trait;
220+
RemAssignTraitLangItem(Op), "rem_assign", rem_assign_trait, Target::Trait;
221+
BitXorAssignTraitLangItem(Op),"bitxor_assign", bitxor_assign_trait, Target::Trait;
222+
BitAndAssignTraitLangItem(Op),"bitand_assign", bitand_assign_trait, Target::Trait;
223+
BitOrAssignTraitLangItem(Op),"bitor_assign", bitor_assign_trait, Target::Trait;
224+
ShlAssignTraitLangItem(Op), "shl_assign", shl_assign_trait, Target::Trait;
225+
ShrAssignTraitLangItem(Op), "shr_assign", shr_assign_trait, Target::Trait;
226+
IndexTraitLangItem(Op), "index", index_trait, Target::Trait;
227+
IndexMutTraitLangItem(Op), "index_mut", index_mut_trait, Target::Trait;
198228

199229
UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct;
200230
VaListTypeLangItem, "va_list", va_list, Target::Struct;

src/librustc_infer/infer/error_reporting/need_type_info.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
468468
let msg = if let Some(simple_ident) = pattern.simple_ident() {
469469
match pattern.span.desugaring_kind() {
470470
None => format!("consider giving `{}` {}", simple_ident, suffix),
471-
Some(DesugaringKind::ForLoop) => {
471+
Some(DesugaringKind::ForLoop(_)) => {
472472
"the element type for this iterator is not specified".to_string()
473473
}
474474
_ => format!("this needs {}", suffix),

src/librustc_middle/lint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ pub fn struct_lint_level<'s, 'd>(
339339
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
340340
let expn_data = span.ctxt().outer_expn_data();
341341
match expn_data.kind {
342-
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
342+
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => false,
343343
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
344344
ExpnKind::Macro(MacroKind::Bang, _) => {
345345
// Dummy span for the `def_site` means it's an external macro.

src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs

+65-7
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ use crate::borrow_check::{
2424
};
2525

2626
use super::{
27-
explain_borrow::BorrowExplanation, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
27+
explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName,
28+
RegionNameSource, UseSpans,
2829
};
2930

3031
#[derive(Debug)]
@@ -150,11 +151,68 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
150151
format!("value moved{} here, in previous iteration of loop", move_msg),
151152
);
152153
} else {
153-
err.span_label(move_span, format!("value moved{} here", move_msg));
154-
move_spans.var_span_label(
155-
&mut err,
156-
format!("variable moved due to use{}", move_spans.describe()),
157-
);
154+
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
155+
move_spans
156+
{
157+
let place_name = self
158+
.describe_place(moved_place.as_ref())
159+
.map(|n| format!("`{}`", n))
160+
.unwrap_or_else(|| "value".to_owned());
161+
match kind {
162+
FnSelfUseKind::FnOnceCall => {
163+
err.span_label(
164+
fn_call_span,
165+
&format!("{} moved due to this call", place_name),
166+
);
167+
err.span_note(
168+
var_span,
169+
"this value implements `FnOnce`, which causes it to be moved when called",
170+
);
171+
}
172+
FnSelfUseKind::Operator { self_arg } => {
173+
err.span_label(
174+
fn_call_span,
175+
&format!("{} moved due to usage in operator", place_name),
176+
);
177+
if self.fn_self_span_reported.insert(fn_span) {
178+
err.span_note(
179+
self_arg.span,
180+
"calling this operator moves the left-hand side",
181+
);
182+
}
183+
}
184+
FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
185+
if implicit_into_iter {
186+
err.span_label(
187+
fn_call_span,
188+
&format!(
189+
"{} moved due to this implicit call to `.into_iter()`",
190+
place_name
191+
),
192+
);
193+
} else {
194+
err.span_label(
195+
fn_call_span,
196+
&format!("{} moved due to this method call", place_name),
197+
);
198+
}
199+
// Avoid pointing to the same function in multiple different
200+
// error messages
201+
if self.fn_self_span_reported.insert(self_arg.span) {
202+
err.span_note(
203+
self_arg.span,
204+
&format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
205+
);
206+
}
207+
}
208+
}
209+
} else {
210+
err.span_label(move_span, format!("value moved{} here", move_msg));
211+
move_spans.var_span_label(
212+
&mut err,
213+
format!("variable moved due to use{}", move_spans.describe()),
214+
);
215+
}
158216
}
159217
if let UseSpans::PatUse(span) = move_spans {
160218
err.span_suggestion_verbose(
@@ -170,7 +228,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
170228
);
171229
}
172230

173-
if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() {
231+
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
174232
let sess = self.infcx.tcx.sess;
175233
if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
176234
err.span_suggestion(

src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
509509
// Used in a closure.
510510
(LaterUseKind::ClosureCapture, var_span)
511511
}
512-
UseSpans::PatUse(span) | UseSpans::OtherUse(span) => {
512+
UseSpans::PatUse(span)
513+
| UseSpans::OtherUse(span)
514+
| UseSpans::FnSelfUse { var_span: span, .. } => {
513515
let block = &self.body.basic_blocks()[location.block];
514516

515517
let kind = if let Some(&Statement {

0 commit comments

Comments
 (0)