Skip to content

Commit 7366752

Browse files
committed
Auto merge of rust-lang#53830 - davidtwco:issue-53228, r=nikomatsakis
Add help message for missing IndexMut impl with NLL Fixes rust-lang#53228. r? @nikomatsakis
2 parents 2ae11a9 + 08a4a37 commit 7366752

9 files changed

+137
-12
lines changed

src/librustc_mir/borrow_check/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1591,7 +1591,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
15911591
if let Some(&init_index) = first_init_index {
15921592
// And, if so, report an error.
15931593
let init = &self.move_data.inits[init_index];
1594-
self.report_illegal_reassignment(context, place_span, init.span, place_span.0);
1594+
let span = init.span(&self.mir);
1595+
self.report_illegal_reassignment(
1596+
context, place_span, span, place_span.0
1597+
);
15951598
}
15961599
}
15971600

src/librustc_mir/borrow_check/mutability_errors.rs

+63-4
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,20 @@
1010

1111
use rustc::hir;
1212
use rustc::hir::Node;
13-
use rustc::mir::{self, BindingForm, ClearCrossCrate, Local, Location, Mir};
14-
use rustc::mir::{Mutability, Place, Projection, ProjectionElem, Static};
15-
use rustc::ty::{self, TyCtxt};
13+
use rustc::mir::{self, BindingForm, Constant, ClearCrossCrate, Local, Location, Mir};
14+
use rustc::mir::{Mutability, Operand, Place, Projection, ProjectionElem, Static, Terminator};
15+
use rustc::mir::TerminatorKind;
16+
use rustc::ty::{self, Const, DefIdTree, TyS, TyKind, TyCtxt};
1617
use rustc_data_structures::indexed_vec::Idx;
1718
use syntax_pos::Span;
1819

20+
use dataflow::move_paths::InitLocation;
1921
use borrow_check::MirBorrowckCtxt;
2022
use util::borrowck_errors::{BorrowckErrors, Origin};
2123
use util::collect_writes::FindAssignments;
2224
use util::suggest_ref_mut;
2325

24-
#[derive(Copy, Clone, Debug)]
26+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2527
pub(super) enum AccessKind {
2628
MutableBorrow,
2729
Mutate,
@@ -393,6 +395,63 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
393395
);
394396
}
395397

398+
Place::Projection(box Projection {
399+
base: Place::Local(local),
400+
elem: ProjectionElem::Deref,
401+
}) if error_access == AccessKind::MutableBorrow => {
402+
err.span_label(span, format!("cannot {ACT}", ACT = act));
403+
404+
let mpi = self.move_data.rev_lookup.find_local(*local);
405+
for i in self.move_data.init_path_map[mpi].iter() {
406+
if let InitLocation::Statement(location) = self.move_data.inits[*i].location {
407+
if let Some(
408+
Terminator {
409+
kind: TerminatorKind::Call {
410+
func: Operand::Constant(box Constant {
411+
literal: Const {
412+
ty: &TyS {
413+
sty: TyKind::FnDef(id, substs),
414+
..
415+
},
416+
..
417+
},
418+
..
419+
}),
420+
..
421+
},
422+
..
423+
}
424+
) = &self.mir.basic_blocks()[location.block].terminator {
425+
if self.tcx.parent(id) == self.tcx.lang_items().index_trait() {
426+
427+
let mut found = false;
428+
self.tcx.for_each_relevant_impl(
429+
self.tcx.lang_items().index_mut_trait().unwrap(),
430+
substs.type_at(0),
431+
|_relevant_impl| {
432+
found = true;
433+
}
434+
);
435+
436+
let extra = if found {
437+
String::from("")
438+
} else {
439+
format!(", but it is not implemented for `{}`",
440+
substs.type_at(0))
441+
};
442+
443+
err.help(
444+
&format!(
445+
"trait `IndexMut` is required to modify indexed content{}",
446+
extra,
447+
),
448+
);
449+
}
450+
}
451+
}
452+
}
453+
}
454+
396455
_ => {
397456
err.span_label(span, format!("cannot {ACT}", ACT = act));
398457
}

src/librustc_mir/dataflow/move_paths/builder.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use std::mem;
2020
use super::abs_domain::Lift;
2121

2222
use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, MoveOut, MoveOutIndex};
23-
use super::{MoveError, InitIndex, Init, LookupResult, InitKind};
23+
use super::{MoveError, InitIndex, Init, InitLocation, LookupResult, InitKind};
2424
use super::IllegalMoveOriginKind::*;
2525

2626
struct MoveDataBuilder<'a, 'gcx: 'tcx, 'tcx: 'a> {
@@ -237,10 +237,9 @@ impl<'a, 'gcx, 'tcx> MoveDataBuilder<'a, 'gcx, 'tcx> {
237237
fn gather_args(&mut self) {
238238
for arg in self.mir.args_iter() {
239239
let path = self.data.rev_lookup.locals[arg];
240-
let span = self.mir.local_decls[arg].source_info.span;
241240

242241
let init = self.data.inits.push(Init {
243-
path, span, kind: InitKind::Deep
242+
path, kind: InitKind::Deep, location: InitLocation::Argument(arg),
244243
});
245244

246245
debug!("gather_args: adding init {:?} of {:?} for argument {:?}",
@@ -428,7 +427,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
428427

429428
if let LookupResult::Exact(path) = self.builder.data.rev_lookup.find(place) {
430429
let init = self.builder.data.inits.push(Init {
431-
span: self.builder.mir.source_info(self.loc).span,
430+
location: InitLocation::Statement(self.loc),
432431
path,
433432
kind,
434433
});

src/librustc_mir/dataflow/move_paths/mod.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,21 @@ impl fmt::Debug for MoveOut {
196196
pub struct Init {
197197
/// path being initialized
198198
pub path: MovePathIndex,
199-
/// span of initialization
200-
pub span: Span,
199+
/// location of initialization
200+
pub location: InitLocation,
201201
/// Extra information about this initialization
202202
pub kind: InitKind,
203203
}
204204

205+
206+
/// Initializations can be from an argument or from a statement. Arguments
207+
/// do not have locations, in those cases the `Local` is kept..
208+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
209+
pub enum InitLocation {
210+
Argument(Local),
211+
Statement(Location),
212+
}
213+
205214
/// Additional information about the initialization.
206215
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
207216
pub enum InitKind {
@@ -215,7 +224,16 @@ pub enum InitKind {
215224

216225
impl fmt::Debug for Init {
217226
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
218-
write!(fmt, "{:?}@{:?} ({:?})", self.path, self.span, self.kind)
227+
write!(fmt, "{:?}@{:?} ({:?})", self.path, self.location, self.kind)
228+
}
229+
}
230+
231+
impl Init {
232+
crate fn span<'gcx>(&self, mir: &Mir<'gcx>) -> Span {
233+
match self.location {
234+
InitLocation::Argument(local) => mir.local_decls[local].source_info.span,
235+
InitLocation::Statement(location) => mir.source_info(location).span,
236+
}
219237
}
220238
}
221239

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0596]: cannot borrow data in a `&` reference as mutable
2+
--> $DIR/index-mut-help-with-impl.rs:19:5
3+
|
4+
LL | Index::index(&v, 1..2).make_ascii_uppercase(); //~ ERROR
5+
| ^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
6+
|
7+
= help: trait `IndexMut` is required to modify indexed content
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0596`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// When mutably indexing a type that implements `Index` and `IndexMut` but
12+
// `Index::index` is being used specifically, the normal special help message
13+
// should not mention a missing `IndexMut` impl.
14+
15+
fn main() {
16+
use std::ops::Index;
17+
18+
let v = String::from("dinosaur");
19+
Index::index(&v, 1..2).make_ascii_uppercase(); //~ ERROR
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0596]: cannot borrow immutable borrowed content as mutable
2+
--> $DIR/index-mut-help-with-impl.rs:19:5
3+
|
4+
LL | Index::index(&v, 1..2).make_ascii_uppercase(); //~ ERROR
5+
| ^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0596`.

src/test/ui/borrowck/index-mut-help.nll.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
33
|
44
LL | map["peter"].clear(); //~ ERROR
55
| ^^^^^^^^^^^^ cannot borrow as mutable
6+
|
7+
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>`
68

79
error[E0594]: cannot assign to data in a `&` reference
810
--> $DIR/index-mut-help.rs:22:5
@@ -15,6 +17,8 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
1517
|
1618
LL | let _ = &mut map["peter"]; //~ ERROR
1719
| ^^^^^^^^^^^^^^^^^ cannot borrow as mutable
20+
|
21+
= help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>`
1822

1923
error: aborting due to 3 previous errors
2024

src/test/ui/issues/issue-41726.nll.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
33
|
44
LL | things[src.as_str()].sort(); //~ ERROR cannot borrow immutable
55
| ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
6+
|
7+
= 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>>`
68

79
error: aborting due to previous error
810

0 commit comments

Comments
 (0)