From d83a0fdf7da8b93b21de6ff2809e81a69447a9a5 Mon Sep 17 00:00:00 2001 From: Alisdair Owens Date: Sat, 8 Aug 2015 17:32:13 +0100 Subject: [PATCH 1/3] add diagnostics for E0387 --- src/librustc_borrowck/diagnostics.rs | 37 +++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 24bbd4fcb7eef..79abd08bcb1df 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -95,6 +95,42 @@ fn main(){ x = 5; } ``` +"##, + +E0387: r##" +This error occurs when an attempt is made to mutate or mutably reference data +that a closure has captured immutably. Examples of this error are shown below: + +``` +// Accepts a function or a closure that captures its environment immutably. +// Closures passed to foo will not be able to mutate their closed-over state. +fn foo(f: F) { } + +// Attempts to mutate closed-over data. Error message reads: +// `cannot assign to data in a captured outer variable...` +fn mutable() { + let mut x = 0u32; + foo(|| x = 2); +} + +// Attempts to take a mutable reference to closed-over data. Error message +// reads: `cannot borrow data mutably in a captured outer variable...` +fn mut_addr() { + let mut x = 0u32; + foo(|| { let y = &mut x; }); +} +``` + +The problem here is that foo is defined as accepting a parameter of type `Fn`. +Closures passed into foo will thus be inferred to be of type `Fn`, meaning that +they capture their context immutably. + +The solution is to capture the data mutably. This can be done by defining `foo` +to take FnMut rather than Fn: + +``` +fn foo(f: F) { } +``` "## } @@ -104,7 +140,6 @@ register_diagnostics! { E0383, // partial reinitialization of uninitialized structure E0385, // {} in an aliasable location E0386, // {} in an immutable container - E0387, // {} in a captured outer variable in an `Fn` closure E0388, // {} in a static location E0389 // {} in a `&` reference } From 78d28336feb9f46ac5929023f45acdbb3f3379e5 Mon Sep 17 00:00:00 2001 From: Alisdair Owens Date: Mon, 10 Aug 2015 16:48:01 +0100 Subject: [PATCH 2/3] add info about cell types to diagnostic message E0387 --- src/librustc_borrowck/diagnostics.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 79abd08bcb1df..b641dfd7d40e1 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -125,12 +125,28 @@ The problem here is that foo is defined as accepting a parameter of type `Fn`. Closures passed into foo will thus be inferred to be of type `Fn`, meaning that they capture their context immutably. -The solution is to capture the data mutably. This can be done by defining `foo` -to take FnMut rather than Fn: +If the definition of `foo` is under your control, the simplest solution is to +capture the data mutably. This can be done by defining `foo` to take FnMut +rather than Fn: ``` fn foo(f: F) { } ``` + +Alternatively, we can consider using the `Cell` and `RefCell` types to achieve +interior mutability through a shared reference. Our example's `mutable` function +could be redefined as below: + +``` +fn mutable() { + let x = std::cell::Cell::new(0u32); + foo(|| x.set(2)); +} +``` + +You can read more about cell types in the API documentation: + +https://doc.rust-lang.org/std/cell/ "## } From f0419661f0d27f5662f03359ebf0091a4ac7b7b2 Mon Sep 17 00:00:00 2001 From: Alisdair Owens Date: Mon, 10 Aug 2015 20:35:27 +0100 Subject: [PATCH 3/3] fix import nit for long diagnostics on E0387 --- src/librustc_borrowck/diagnostics.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index b641dfd7d40e1..78a8ab9cee0eb 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -138,8 +138,10 @@ interior mutability through a shared reference. Our example's `mutable` function could be redefined as below: ``` +use std::cell::Cell; + fn mutable() { - let x = std::cell::Cell::new(0u32); + let x = Cell::new(0u32); foo(|| x.set(2)); } ```