Skip to content

Commit

Permalink
Auto merge of #54976 - davidtwco:issue-52663-special-case-closures, r…
Browse files Browse the repository at this point in the history
…=nikomatsakis

NLL lacks various special case handling of closures

Part of #52663.

Firstly, this PR extends existing handling of closures to also support generators.

Second, this PR adds the note found in the AST when a closure is invoked twice and captures a variable by-value:

```text
note: closure cannot be invoked more than once because it moves the variable `dict` out of its environment
  --> $DIR/issue-42065.rs:16:29
   |
LL |         for (key, value) in dict {
   |                             ^^^^
```

r? @nikomatsakis
cc @pnkfelix
  • Loading branch information
bors committed Oct 18, 2018
2 parents 121320d + d088edc commit e7f5d48
Show file tree
Hide file tree
Showing 10 changed files with 343 additions and 202 deletions.
4 changes: 2 additions & 2 deletions src/librustc_borrowck/borrowck/check_loans.rs
Expand Up @@ -609,12 +609,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
new_loan.span, &nl, old_loan.span, previous_end_span, Origin::Ast),
(ty::UniqueImmBorrow, _) =>
self.bccx.cannot_uniquely_borrow_by_one_closure(
new_loan.span, &nl, &new_loan_msg,
new_loan.span, "closure", &nl, &new_loan_msg,
old_loan.span, &ol_pronoun, &old_loan_msg, previous_end_span, Origin::Ast),
(_, ty::UniqueImmBorrow) => {
let new_loan_str = &new_loan.kind.to_user_str();
self.bccx.cannot_reborrow_already_uniquely_borrowed(
new_loan.span, &nl, &new_loan_msg, new_loan_str,
new_loan.span, "closure", &nl, &new_loan_msg, new_loan_str,
old_loan.span, &old_loan_msg, previous_end_span, Origin::Ast)
}
(..) =>
Expand Down
407 changes: 292 additions & 115 deletions src/librustc_mir/borrow_check/error_reporting.rs

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions src/librustc_mir/util/borrowck_errors.rs
Expand Up @@ -221,6 +221,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
fn cannot_uniquely_borrow_by_one_closure(
self,
new_loan_span: Span,
container_name: &str,
desc_new: &str,
opt_via: &str,
old_loan_span: Span,
Expand All @@ -241,7 +242,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
);
err.span_label(
new_loan_span,
format!("closure construction occurs here{}", opt_via),
format!("{} construction occurs here{}", container_name, opt_via),
);
err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via));
if let Some(previous_end_span) = previous_end_span {
Expand All @@ -253,6 +254,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
fn cannot_reborrow_already_uniquely_borrowed(
self,
new_loan_span: Span,
container_name: &str,
desc_new: &str,
opt_via: &str,
kind_new: &str,
Expand All @@ -275,7 +277,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
err.span_label(new_loan_span, format!("borrow occurs here{}", opt_via));
err.span_label(
old_loan_span,
format!("closure construction occurs here{}", old_opt_via),
format!("{} construction occurs here{}", container_name, old_opt_via),
);
if let Some(previous_end_span) = previous_end_span {
err.span_label(previous_end_span, "borrow from closure ends here");
Expand Down
11 changes: 0 additions & 11 deletions src/test/ui/closure_context/issue-42065.nll.stderr

This file was deleted.

31 changes: 16 additions & 15 deletions src/test/ui/generator/borrowing.nll.stderr
@@ -1,10 +1,11 @@
error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:18:18
--> $DIR/borrowing.rs:18:29
|
LL | unsafe { (|| yield &a).resume() }
| ^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| -----------^-
| || |
| || borrowed value does not live long enough
| |value captured here by generator
| a temporary with access to the borrow is created here ...
LL | //~^ ERROR: `a` does not live long enough
LL | };
Expand All @@ -15,18 +16,18 @@ LL | };
= note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block.

error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:24:9
--> $DIR/borrowing.rs:25:20
|
LL | let _b = {
| -- borrow later stored here
LL | let a = 3;
LL | / || {
LL | | yield &a
LL | | //~^ ERROR: `a` does not live long enough
LL | | }
| |_________^ borrowed value does not live long enough
LL | };
| - `a` dropped here while still borrowed
LL | let _b = {
| -- borrow later stored here
LL | let a = 3;
LL | || {
| -- value captured here by generator
LL | yield &a
| ^ borrowed value does not live long enough
...
LL | };
| - `a` dropped here while still borrowed

error: aborting due to 2 previous errors

Expand Down
24 changes: 11 additions & 13 deletions src/test/ui/generator/dropck.nll.stderr
Expand Up @@ -13,21 +13,19 @@ LL | }
= note: values in a scope are dropped in the opposite order they are defined

error[E0597]: `ref_` does not live long enough
--> $DIR/dropck.rs:22:11
--> $DIR/dropck.rs:24:18
|
LL | gen = || {
| ___________^
LL | | // but the generator can use it to drop a `Ref<'a, i32>`.
LL | | let _d = ref_.take(); //~ ERROR `ref_` does not live long enough
LL | | yield;
LL | | };
| |_____^ borrowed value does not live long enough
LL | gen = || {
| -- value captured here by generator
LL | // but the generator can use it to drop a `Ref<'a, i32>`.
LL | let _d = ref_.take(); //~ ERROR `ref_` does not live long enough
| ^^^^ borrowed value does not live long enough
...
LL | }
| -
| |
| `ref_` dropped here while still borrowed
| borrow might be used here, when `gen` is dropped and runs the destructor for generator
LL | }
| -
| |
| `ref_` dropped here while still borrowed
| borrow might be used here, when `gen` is dropped and runs the destructor for generator
|
= note: values in a scope are dropped in the opposite order they are defined

Expand Down
20 changes: 9 additions & 11 deletions src/test/ui/generator/yield-while-iterating.nll.stderr
Expand Up @@ -9,17 +9,15 @@ LL | yield();
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
--> $DIR/yield-while-iterating.rs:67:20
|
LL | let mut b = || {
| _________________-
LL | | for p in &mut x {
LL | | yield p;
LL | | }
LL | | };
| |_____- mutable borrow occurs here
LL | println!("{}", x[0]); //~ ERROR
| ^ immutable borrow occurs here
LL | b.resume();
| - mutable borrow later used here
LL | let mut b = || {
| -- mutable borrow occurs here
LL | for p in &mut x {
| - first borrow occurs due to use of `x` in generator
...
LL | println!("{}", x[0]); //~ ERROR
| ^ immutable borrow occurs here
LL | b.resume();
| - mutable borrow later used here

error: aborting due to 2 previous errors

Expand Down
20 changes: 9 additions & 11 deletions src/test/ui/generator/yield-while-ref-reborrowed.nll.stderr
@@ -1,17 +1,15 @@
error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access
--> $DIR/yield-while-ref-reborrowed.rs:45:20
|
LL | let mut b = || {
| _________________-
LL | | let a = &mut *x;
LL | | yield();
LL | | println!("{}", a);
LL | | };
| |_____- closure construction occurs here
LL | println!("{}", x); //~ ERROR
| ^ borrow occurs here
LL | b.resume();
| - first borrow later used here
LL | let mut b = || {
| -- generator construction occurs here
LL | let a = &mut *x;
| - first borrow occurs due to use of `x` in generator
...
LL | println!("{}", x); //~ ERROR
| ^ borrow occurs here
LL | b.resume();
| - first borrow later used here

error: aborting due to previous error

Expand Down

This file was deleted.

This file was deleted.

0 comments on commit e7f5d48

Please sign in to comment.