Skip to content

Commit

Permalink
Better messages for errors from Shallow borrows
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewjasper committed Sep 24, 2018
1 parent ced5c2d commit b55bb2e
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 9 deletions.
49 changes: 42 additions & 7 deletions src/librustc_mir/borrow_check/error_reporting.rs
Expand Up @@ -335,6 +335,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {

(BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _)
| (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => {
let mut err = tcx.cannot_mutate_in_match_guard(
span,
issued_span,
&desc_place,
"mutably borrow",
Origin::Mir,
);
borrow_spans.var_span_label(
&mut err,
format!(
"borrow occurs due to use of `{}` in closure",
desc_place
),
);
err.buffer(&mut self.errors_buffer);

return;
}

Expand Down Expand Up @@ -373,7 +389,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
Origin::Mir,
),

(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
(BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
| (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => {
// Shallow borrows are uses from the user's point of view.
self.report_use_while_mutably_borrowed(context, (place, span), issued_borrow);
return
}
(BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
| (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
| (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
| (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
};

if issued_spans == borrow_spans {
Expand Down Expand Up @@ -785,12 +810,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
let loan_span = loan_spans.args_or_use();

let tcx = self.infcx.tcx;
let mut err = tcx.cannot_assign_to_borrowed(
span,
loan_span,
&self.describe_place(place).unwrap_or("_".to_owned()),
Origin::Mir,
);
let mut err = if loan.kind == BorrowKind::Shallow {
tcx.cannot_mutate_in_match_guard(
span,
loan_span,
&self.describe_place(place).unwrap_or("_".to_owned()),
"assign",
Origin::Mir,
)
} else {
tcx.cannot_assign_to_borrowed(
span,
loan_span,
&self.describe_place(place).unwrap_or("_".to_owned()),
Origin::Mir,
)
};

loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");

Expand Down
13 changes: 11 additions & 2 deletions src/librustc_mir/borrow_check/mod.rs
Expand Up @@ -836,6 +836,7 @@ enum LocalMutationIsAllowed {
enum InitializationRequiringAction {
Update,
Borrow,
MatchOn,
Use,
Assignment,
}
Expand All @@ -850,6 +851,7 @@ impl InitializationRequiringAction {
match self {
InitializationRequiringAction::Update => "update",
InitializationRequiringAction::Borrow => "borrow",
InitializationRequiringAction::MatchOn => "use", // no good noun
InitializationRequiringAction::Use => "use",
InitializationRequiringAction::Assignment => "assign",
}
Expand All @@ -859,6 +861,7 @@ impl InitializationRequiringAction {
match self {
InitializationRequiringAction::Update => "updated",
InitializationRequiringAction::Borrow => "borrowed",
InitializationRequiringAction::MatchOn => "matched on",
InitializationRequiringAction::Use => "used",
InitializationRequiringAction::Assignment => "assigned",
}
Expand Down Expand Up @@ -991,7 +994,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}

match kind {
ReadKind::Copy => {
ReadKind::Copy => {
error_reported = true;
this.report_use_while_mutably_borrowed(context, place_span, borrow)
}
Expand Down Expand Up @@ -1137,9 +1140,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
flow_state,
);

let action = if bk == BorrowKind::Shallow {
InitializationRequiringAction::MatchOn
} else {
InitializationRequiringAction::Borrow
};

self.check_if_path_or_subpath_is_moved(
context,
InitializationRequiringAction::Borrow,
action,
(place, span),
flow_state,
);
Expand Down
20 changes: 20 additions & 0 deletions src/librustc_mir/diagnostics.rs
Expand Up @@ -1991,6 +1991,26 @@ fn main() {
```
"##,

E0510: r##"
Cannot mutate place in this match guard.
When matching on a variable it cannot be mutated in the match guards, as this
could cause the match to be non-exhaustive:
```compile_fail,E0510
#![feature(nll, bind_by_move_pattern_guards)]
let mut x = Some(0);
match x {
None => (),
Some(v) if { x = None; false } => (),
Some(_) => (), // No longer matches
}
```
Here executing `x = None` would modify the value being matched and require us
to go "back in time" to the `None` arm.
"##,

E0579: r##"
When matching against an exclusive range, the compiler verifies that the range
is non-empty. Exclusive range patterns include the start point but not the end
Expand Down
23 changes: 23 additions & 0 deletions src/librustc_mir/util/borrowck_errors.rs
Expand Up @@ -555,6 +555,29 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
self.cannot_borrow_path_as_mutable_because(span, path, "", o)
}

fn cannot_mutate_in_match_guard(
self,
mutate_span: Span,
match_span: Span,
match_place: &str,
action: &str,
o: Origin,
) -> DiagnosticBuilder<'cx> {
let mut err = struct_span_err!(
self,
mutate_span,
E0510,
"cannot {} `{}` in match guard{OGN}",
action,
match_place,
OGN = o
);
err.span_label(mutate_span, format!("cannot {}", action));
err.span_label(match_span, format!("value is immutable in match guard"));

self.cancel_if_wrong_origin(err, o)
}

fn cannot_borrow_across_generator_yield(
self,
span: Span,
Expand Down

0 comments on commit b55bb2e

Please sign in to comment.