Auto merge of #53830 - davidtwco:issue-53228, r=nikomatsakis
Add help message for missing IndexMut impl with NLL Fixes #53228. r? @nikomatsakis
This commit is contained in:
commit
7366752a61
|
@ -1591,7 +1591,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
if let Some(&init_index) = first_init_index {
|
||||
// And, if so, report an error.
|
||||
let init = &self.move_data.inits[init_index];
|
||||
self.report_illegal_reassignment(context, place_span, init.span, place_span.0);
|
||||
let span = init.span(&self.mir);
|
||||
self.report_illegal_reassignment(
|
||||
context, place_span, span, place_span.0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,18 +10,20 @@
|
|||
|
||||
use rustc::hir;
|
||||
use rustc::hir::Node;
|
||||
use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Mir};
|
||||
use rustc::mir::{Mutability, Place, Projection, ProjectionElem, Static};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::mir::{self, BindingForm, Constant, ClearCrossCrate, Local, Location, Mir};
|
||||
use rustc::mir::{Mutability, Operand, Place, Projection, ProjectionElem, Static, Terminator};
|
||||
use rustc::mir::TerminatorKind;
|
||||
use rustc::ty::{self, Const, DefIdTree, TyS, TyKind, TyCtxt};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use dataflow::move_paths::InitLocation;
|
||||
use borrow_check::MirBorrowckCtxt;
|
||||
use util::borrowck_errors::{BorrowckErrors, Origin};
|
||||
use util::collect_writes::FindAssignments;
|
||||
use util::suggest_ref_mut;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub(super) enum AccessKind {
|
||||
MutableBorrow,
|
||||
Mutate,
|
||||
|
@ -393,6 +395,63 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
Place::Projection(box Projection {
|
||||
base: Place::Local(local),
|
||||
elem: ProjectionElem::Deref,
|
||||
}) if error_access == AccessKind::MutableBorrow => {
|
||||
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
||||
|
||||
let mpi = self.move_data.rev_lookup.find_local(*local);
|
||||
for i in self.move_data.init_path_map[mpi].iter() {
|
||||
if let InitLocation::Statement(location) = self.move_data.inits[*i].location {
|
||||
if let Some(
|
||||
Terminator {
|
||||
kind: TerminatorKind::Call {
|
||||
func: Operand::Constant(box Constant {
|
||||
literal: Const {
|
||||
ty: &TyS {
|
||||
sty: TyKind::FnDef(id, substs),
|
||||
..
|
||||
},
|
||||
..
|
||||
},
|
||||
..
|
||||
}),
|
||||
..
|
||||
},
|
||||
..
|
||||
}
|
||||
) = &self.mir.basic_blocks()[location.block].terminator {
|
||||
if self.tcx.parent(id) == self.tcx.lang_items().index_trait() {
|
||||
|
||||
let mut found = false;
|
||||
self.tcx.for_each_relevant_impl(
|
||||
self.tcx.lang_items().index_mut_trait().unwrap(),
|
||||
substs.type_at(0),
|
||||
|_relevant_impl| {
|
||||
found = true;
|
||||
}
|
||||
);
|
||||
|
||||
let extra = if found {
|
||||
String::from("")
|
||||
} else {
|
||||
format!(", but it is not implemented for `{}`",
|
||||
substs.type_at(0))
|
||||
};
|
||||
|
||||
err.help(
|
||||
&format!(
|
||||
"trait `IndexMut` is required to modify indexed content{}",
|
||||
extra,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
err.span_label(span, format!("cannot {ACT}", ACT = act));
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ use std::mem;
|
|||
use super::abs_domain::Lift;
|
||||
|
||||
use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, MoveOut, MoveOutIndex};
|
||||
use super::{MoveError, InitIndex, Init, LookupResult, InitKind};
|
||||
use super::{MoveError, InitIndex, Init, InitLocation, LookupResult, InitKind};
|
||||
use super::IllegalMoveOriginKind::*;
|
||||
|
||||
struct MoveDataBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
|
@ -237,10 +237,9 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
|
|||
fn gather_args(&mut self) {
|
||||
for arg in self.mir.args_iter() {
|
||||
let path = self.data.rev_lookup.locals[arg];
|
||||
let span = self.mir.local_decls[arg].source_info.span;
|
||||
|
||||
let init = self.data.inits.push(Init {
|
||||
path, span, kind: InitKind::Deep
|
||||
path, kind: InitKind::Deep, location: InitLocation::Argument(arg),
|
||||
});
|
||||
|
||||
debug!("gather_args: adding init {:?} of {:?} for argument {:?}",
|
||||
|
@ -428,7 +427,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
|
||||
if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) {
|
||||
let init = self.builder.data.inits.push(Init {
|
||||
span: self.builder.mir.source_info(self.loc).span,
|
||||
location: InitLocation::Statement(self.loc),
|
||||
path,
|
||||
kind,
|
||||
});
|
||||
|
|
|
@ -196,12 +196,21 @@ impl fmt::Debug for MoveOut {
|
|||
pub struct Init {
|
||||
/// path being initialized
|
||||
pub path: MovePathIndex,
|
||||
/// span of initialization
|
||||
pub span: Span,
|
||||
/// location of initialization
|
||||
pub location: InitLocation,
|
||||
/// Extra information about this initialization
|
||||
pub kind: InitKind,
|
||||
}
|
||||
|
||||
|
||||
/// Initializations can be from an argument or from a statement. Arguments
|
||||
/// do not have locations, in those cases the `Local` is kept..
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum InitLocation {
|
||||
Argument(Local),
|
||||
Statement(Location),
|
||||
}
|
||||
|
||||
/// Additional information about the initialization.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum InitKind {
|
||||
|
@ -215,7 +224,16 @@ pub enum InitKind {
|
|||
|
||||
impl fmt::Debug for Init {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "{:?}@{:?} ({:?})", self.path, self.span, self.kind)
|
||||
write!(fmt, "{:?}@{:?} ({:?})", self.path, self.location, self.kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl Init {
|
||||
crate fn span<'gcx>(&self, mir: &Mir<'gcx>) -> Span {
|
||||
match self.location {
|
||||
InitLocation::Argument(local) => mir.local_decls[local].source_info.span,
|
||||
InitLocation::Statement(location) => mir.source_info(location).span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
error[E0596]: cannot borrow data in a `&` reference as mutable
|
||||
--> $DIR/index-mut-help-with-impl.rs:19:5
|
||||
|
|
||||
LL | Index::index(&v, 1..2).make_ascii_uppercase(); //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `IndexMut` is required to modify indexed content
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// When mutably indexing a type that implements `Index` and `IndexMut` but
|
||||
// `Index::index` is being used specifically, the normal special help message
|
||||
// should not mention a missing `IndexMut` impl.
|
||||
|
||||
fn main() {
|
||||
use std::ops::Index;
|
||||
|
||||
let v = String::from("dinosaur");
|
||||
Index::index(&v, 1..2).make_ascii_uppercase(); //~ ERROR
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
error[E0596]: cannot borrow immutable borrowed content as mutable
|
||||
--> $DIR/index-mut-help-with-impl.rs:19:5
|
||||
|
|
||||
LL | Index::index(&v, 1..2).make_ascii_uppercase(); //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
|
@ -3,6 +3,8 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
|
|||
|
|
||||
LL | map["peter"].clear(); //~ ERROR
|
||||
| ^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>`
|
||||
|
||||
error[E0594]: cannot assign to data in a `&` reference
|
||||
--> $DIR/index-mut-help.rs:22:5
|
||||
|
@ -15,6 +17,8 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
|
|||
|
|
||||
LL | let _ = &mut map["peter"]; //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
|
|||
|
|
||||
LL | things[src.as_str()].sort(); //~ ERROR cannot borrow immutable
|
||||
| ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<std::string::String, std::vec::Vec<std::string::String>>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
Loading…
Reference in New Issue