Skip to content

Commit

Permalink
Explain move errors that occur due to method calls involving self
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Aaron1011 committed Jun 24, 2020
1 parent 99dc249 commit cf4c2db
Show file tree
Hide file tree
Showing 38 changed files with 743 additions and 102 deletions.
17 changes: 14 additions & 3 deletions src/librustc_ast_lowering/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
use rustc_span::source_map::{respan, DesugaringKind, ForLoopLoc, Span, Spanned};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_target::asm;
use std::collections::hash_map::Entry;
Expand Down Expand Up @@ -1360,9 +1360,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
body: &Block,
opt_label: Option<Label>,
) -> hir::Expr<'hir> {
let orig_head_span = head.span;
// expand <head>
let mut head = self.lower_expr_mut(head);
let desugared_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
let desugared_span = self.mark_span_with_reason(
DesugaringKind::ForLoop(ForLoopLoc::Head),
orig_head_span,
None,
);
head.span = desugared_span;

let iter = Ident::with_dummy_span(sym::iter);
Expand Down Expand Up @@ -1457,10 +1462,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `mut iter => { ... }`
let iter_arm = self.arm(iter_pat, loop_expr);

let into_iter_span = self.mark_span_with_reason(
DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
orig_head_span,
None,
);

// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
let into_iter_expr = {
let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter];
self.expr_call_std_path(desugared_span, into_iter_path, arena_vec![self; head])
self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head])
};

let match_expr = self.arena.alloc(self.expr_match(
Expand Down
78 changes: 53 additions & 25 deletions src/librustc_hir/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,26 @@ use rustc_span::Span;

use lazy_static::lazy_static;

pub enum LangItemGroup {
Op,
}

const NUM_GROUPS: usize = 1;

macro_rules! expand_group {
() => {
None
};
($group:expr) => {
Some($group)
};
}

// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! language_item_table {
(
$( $variant:ident, $name:expr, $method:ident, $target:path; )*
$( $variant:ident $($group:expr)?, $name:expr, $method:ident, $target:path;)*
) => {

enum_from_u32! {
Expand All @@ -45,6 +60,13 @@ macro_rules! language_item_table {
$( $variant => $name, )*
}
}

pub fn group(self) -> Option<LangItemGroup> {
use LangItemGroup::*;
match self {
$( $variant => expand_group!($($group)*), )*
}
}
}

#[derive(HashStable_Generic)]
Expand All @@ -54,6 +76,7 @@ macro_rules! language_item_table {
pub items: Vec<Option<DefId>>,
/// Lang items that were not found during collection.
pub missing: Vec<LangItem>,
pub groups: Vec<Vec<DefId>>
}

impl LanguageItems {
Expand All @@ -64,6 +87,7 @@ macro_rules! language_item_table {
Self {
items: vec![$(init_none($variant)),*],
missing: Vec::new(),
groups: vec![vec![]; NUM_GROUPS],
}
}

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

pub fn group(&self, group: LangItemGroup) -> &[DefId] {
self.groups[group as usize].as_ref()
}

$(
/// Returns the corresponding `DefId` for the lang item
#[doc = $name]
Expand Down Expand Up @@ -171,30 +199,30 @@ language_item_table! {
CoerceUnsizedTraitLangItem, "coerce_unsized", coerce_unsized_trait, Target::Trait;
DispatchFromDynTraitLangItem,"dispatch_from_dyn", dispatch_from_dyn_trait, Target::Trait;

AddTraitLangItem, "add", add_trait, Target::Trait;
SubTraitLangItem, "sub", sub_trait, Target::Trait;
MulTraitLangItem, "mul", mul_trait, Target::Trait;
DivTraitLangItem, "div", div_trait, Target::Trait;
RemTraitLangItem, "rem", rem_trait, Target::Trait;
NegTraitLangItem, "neg", neg_trait, Target::Trait;
NotTraitLangItem, "not", not_trait, Target::Trait;
BitXorTraitLangItem, "bitxor", bitxor_trait, Target::Trait;
BitAndTraitLangItem, "bitand", bitand_trait, Target::Trait;
BitOrTraitLangItem, "bitor", bitor_trait, Target::Trait;
ShlTraitLangItem, "shl", shl_trait, Target::Trait;
ShrTraitLangItem, "shr", shr_trait, Target::Trait;
AddAssignTraitLangItem, "add_assign", add_assign_trait, Target::Trait;
SubAssignTraitLangItem, "sub_assign", sub_assign_trait, Target::Trait;
MulAssignTraitLangItem, "mul_assign", mul_assign_trait, Target::Trait;
DivAssignTraitLangItem, "div_assign", div_assign_trait, Target::Trait;
RemAssignTraitLangItem, "rem_assign", rem_assign_trait, Target::Trait;
BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait, Target::Trait;
BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait, Target::Trait;
BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait, Target::Trait;
ShlAssignTraitLangItem, "shl_assign", shl_assign_trait, Target::Trait;
ShrAssignTraitLangItem, "shr_assign", shr_assign_trait, Target::Trait;
IndexTraitLangItem, "index", index_trait, Target::Trait;
IndexMutTraitLangItem, "index_mut", index_mut_trait, Target::Trait;
AddTraitLangItem(Op), "add", add_trait, Target::Trait;
SubTraitLangItem(Op), "sub", sub_trait, Target::Trait;
MulTraitLangItem(Op), "mul", mul_trait, Target::Trait;
DivTraitLangItem(Op), "div", div_trait, Target::Trait;
RemTraitLangItem(Op), "rem", rem_trait, Target::Trait;
NegTraitLangItem(Op), "neg", neg_trait, Target::Trait;
NotTraitLangItem(Op), "not", not_trait, Target::Trait;
BitXorTraitLangItem(Op), "bitxor", bitxor_trait, Target::Trait;
BitAndTraitLangItem(Op), "bitand", bitand_trait, Target::Trait;
BitOrTraitLangItem(Op), "bitor", bitor_trait, Target::Trait;
ShlTraitLangItem(Op), "shl", shl_trait, Target::Trait;
ShrTraitLangItem(Op), "shr", shr_trait, Target::Trait;
AddAssignTraitLangItem(Op), "add_assign", add_assign_trait, Target::Trait;
SubAssignTraitLangItem(Op), "sub_assign", sub_assign_trait, Target::Trait;
MulAssignTraitLangItem(Op), "mul_assign", mul_assign_trait, Target::Trait;
DivAssignTraitLangItem(Op), "div_assign", div_assign_trait, Target::Trait;
RemAssignTraitLangItem(Op), "rem_assign", rem_assign_trait, Target::Trait;
BitXorAssignTraitLangItem(Op),"bitxor_assign", bitxor_assign_trait, Target::Trait;
BitAndAssignTraitLangItem(Op),"bitand_assign", bitand_assign_trait, Target::Trait;
BitOrAssignTraitLangItem(Op),"bitor_assign", bitor_assign_trait, Target::Trait;
ShlAssignTraitLangItem(Op), "shl_assign", shl_assign_trait, Target::Trait;
ShrAssignTraitLangItem(Op), "shr_assign", shr_assign_trait, Target::Trait;
IndexTraitLangItem(Op), "index", index_trait, Target::Trait;
IndexMutTraitLangItem(Op), "index_mut", index_mut_trait, Target::Trait;

UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type, Target::Struct;
VaListTypeLangItem, "va_list", va_list, Target::Struct;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_infer/infer/error_reporting/need_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let msg = if let Some(simple_ident) = pattern.simple_ident() {
match pattern.span.desugaring_kind() {
None => format!("consider giving `{}` {}", simple_ident, suffix),
Some(DesugaringKind::ForLoop) => {
Some(DesugaringKind::ForLoop(_)) => {
"the element type for this iterator is not specified".to_string()
}
_ => format!("this needs {}", suffix),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_middle/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ pub fn struct_lint_level<'s, 'd>(
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
let expn_data = span.ctxt().outer_expn_data();
match expn_data.kind {
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop(_)) => false,
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
ExpnKind::Macro(MacroKind::Bang, _) => {
// Dummy span for the `def_site` means it's an external macro.
Expand Down
72 changes: 65 additions & 7 deletions src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ use crate::borrow_check::{
};

use super::{
explain_borrow::BorrowExplanation, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName,
RegionNameSource, UseSpans,
};

#[derive(Debug)]
Expand Down Expand Up @@ -150,13 +151,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
format!("value moved{} here, in previous iteration of loop", move_msg),
);
} else {
err.span_label(move_span, format!("value moved{} here", move_msg));
move_spans.var_span_label(
&mut err,
format!("variable moved due to use{}", move_spans.describe()),
);
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
move_spans
{
let place_name = self
.describe_place(moved_place.as_ref())
.map(|n| format!("`{}`", n))
.unwrap_or_else(|| "value".to_owned());
match kind {
FnSelfUseKind::FnOnceCall => {
err.span_label(
fn_call_span,
&format!("{} moved due to this call", place_name),
);
err.span_note(
var_span,
"this value implements `FnOnce`, which causes it to be moved when called",
);
}
FnSelfUseKind::Operator { self_arg } => {
err.span_label(
fn_call_span,
&format!("{} moved due to usage in operator", place_name),
);
if self.fn_self_span_reported.insert(fn_span) {
err.span_note(
self_arg.span,
"calling this operator moves the left-hand side",
);
}
}
FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
if implicit_into_iter {
err.span_label(
fn_call_span,
&format!(
"{} moved due to this implicit call to `.into_iter()`",
place_name
),
);
} else {
err.span_label(
fn_call_span,
&format!("{} moved due to this method call", place_name),
);
}
// Avoid pointing to the same function in multiple different
// error messages
if self.fn_self_span_reported.insert(self_arg.span) {
err.span_note(
self_arg.span,
&format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
);
}
}
}
} else {
err.span_label(move_span, format!("value moved{} here", move_msg));
move_spans.var_span_label(
&mut err,
format!("variable moved due to use{}", move_spans.describe()),
);
}
}
if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() {
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
let sess = self.infcx.tcx.sess;
if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
err.span_suggestion(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Used in a closure.
(LaterUseKind::ClosureCapture, var_span)
}
UseSpans::OtherUse(span) => {
UseSpans::OtherUse(span) | UseSpans::FnSelfUse { var_span: span, .. } => {
let block = &self.body.basic_blocks()[location.block];

let kind = if let Some(&Statement {
Expand Down
Loading

0 comments on commit cf4c2db

Please sign in to comment.