Skip to content

Commit 33375a3

Browse files
committed
auto merge of #10514 : sfackler/rust/mut, r=cmr
This is based off of @blake2-ppc's work on #9429. That PR bitrotted and I haven't been able to contact the original author so I decided to take up the cause. Overview ====== `Mut` encapsulates a mutable, non-nullable slot. The `Cell` type is currently used to do this, but `Cell` is much more commonly used as a workaround for the inability to move values into non-once functions. `Mut` provides a more robust API. `Mut` duplicates the semantics of borrowed pointers with enforcement at runtime instead of compile time. ```rust let x = Mut::new(0); { // make some immutable borrows let p = x.borrow(); let y = *p.get() + 10; // multiple immutable borrows are allowed simultaneously let p2 = x.borrow(); // this would throw a runtime failure // let p_mut = x.borrow_mut(); } // now we can mutably borrow let p = x.borrow_mut(); *p.get() = 10; ``` `borrow` returns a `Ref` type and `borrow_mut` returns a `RefMut` type, both of which are simple smart pointer types with a single method, `get`, which returns a reference to the wrapped data. This also allows `RcMut<T>` to be deleted, as it can be replaced with `Rc<Mut<T>>`. Changes ====== I've done things a little bit differently than the original proposal. * I've added `try_borrow` and `try_borrow_mut` methods that return `Option<Ref<T>>` and `Option<RefMut<T>>` respectively instead of failing on a borrow check failure. I'm not totally sure when that'd be useful, but I don't see any reason to not put them in and @cmr requested them. * `ReadPtr` and `WritePtr` have been renamed to `Ref` and `RefMut` respectively, as `Ref` is to `ref foo` and `RefMut` is to `ref mut foo` as `Mut` is to `mut foo`. * `get` on `MutRef` now takes `&self` instead of `&mut self` for consistency with `&mut`. As @alexcrichton pointed, out this violates soundness by allowing aliasing `&mut` references. * `Cell` is being left as is. It solves a different problem than `Mut` is designed to solve. * There are no longer methods implemented for `Mut<Option<T>>`. Since `Cell` isn't going away, there's less of a need for these, and I didn't feel like they provided a huge benefit, especially as that kind of `impl` is very uncommon in the standard library. Open Questions ============ * `Cell` should now be used exclusively for movement into closures. Should this be enforced by reducing its API to `new` and `take`? It seems like this use case will be completely going away once the transition to `proc` and co. finishes. * Should there be `try_map` and `try_map_mut` methods along with `map` and `map_mut`?
2 parents 6cbc57c + bdfaf04 commit 33375a3

File tree

12 files changed

+437
-360
lines changed

12 files changed

+437
-360
lines changed

src/librustc/middle/typeck/infer/region_inference/mod.rs

+13-15
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use middle::graph::{Direction, NodeIndex};
2424
use util::common::indenter;
2525
use util::ppaux::{Repr};
2626

27-
use std::cell::Cell;
2827
use std::hashmap::{HashMap, HashSet};
2928
use std::uint;
3029
use std::vec;
@@ -106,16 +105,15 @@ pub struct RegionVarBindings {
106105
undo_log: ~[UndoLogEntry],
107106

108107
// This contains the results of inference. It begins as an empty
109-
// cell and only acquires a value after inference is complete.
110-
// We use a cell vs a mutable option to circumvent borrowck errors.
111-
values: Cell<~[VarValue]>,
108+
// option and only acquires a value after inference is complete.
109+
values: Option<~[VarValue]>,
112110
}
113111

114112
pub fn RegionVarBindings(tcx: ty::ctxt) -> RegionVarBindings {
115113
RegionVarBindings {
116114
tcx: tcx,
117115
var_origins: ~[],
118-
values: Cell::new_empty(),
116+
values: None,
119117
constraints: HashMap::new(),
120118
lubs: HashMap::new(),
121119
glbs: HashMap::new(),
@@ -226,7 +224,7 @@ impl RegionVarBindings {
226224
constraint: Constraint,
227225
origin: SubregionOrigin) {
228226
// cannot add constraints once regions are resolved
229-
assert!(self.values.is_empty());
227+
assert!(self.values.is_none());
230228

231229
debug!("RegionVarBindings: add_constraint({:?})", constraint);
232230

@@ -242,7 +240,7 @@ impl RegionVarBindings {
242240
sub: Region,
243241
sup: Region) {
244242
// cannot add constraints once regions are resolved
245-
assert!(self.values.is_empty());
243+
assert!(self.values.is_none());
246244

247245
debug!("RegionVarBindings: make_subregion({:?}, {:?})", sub, sup);
248246
match (sub, sup) {
@@ -277,7 +275,7 @@ impl RegionVarBindings {
277275
b: Region)
278276
-> Region {
279277
// cannot add constraints once regions are resolved
280-
assert!(self.values.is_empty());
278+
assert!(self.values.is_none());
281279

282280
debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b);
283281
match (a, b) {
@@ -300,7 +298,7 @@ impl RegionVarBindings {
300298
b: Region)
301299
-> Region {
302300
// cannot add constraints once regions are resolved
303-
assert!(self.values.is_empty());
301+
assert!(self.values.is_none());
304302

305303
debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b);
306304
match (a, b) {
@@ -319,14 +317,14 @@ impl RegionVarBindings {
319317
}
320318

321319
pub fn resolve_var(&mut self, rid: RegionVid) -> ty::Region {
322-
if self.values.is_empty() {
323-
self.tcx.sess.span_bug(
320+
let v = match self.values {
321+
None => self.tcx.sess.span_bug(
324322
self.var_origins[rid.to_uint()].span(),
325323
format!("Attempt to resolve region variable before values have \
326-
been computed!"));
327-
}
324+
been computed!")),
325+
Some(ref values) => values[rid.to_uint()]
326+
};
328327

329-
let v = self.values.with_ref(|values| values[rid.to_uint()]);
330328
debug!("RegionVarBindings: resolve_var({:?}={})={:?}",
331329
rid, rid.to_uint(), v);
332330
match v {
@@ -482,7 +480,7 @@ impl RegionVarBindings {
482480
debug!("RegionVarBindings: resolve_regions()");
483481
let mut errors = opt_vec::Empty;
484482
let v = self.infer_variable_values(&mut errors);
485-
self.values.put_back(v);
483+
self.values = Some(v);
486484
errors
487485
}
488486
}

0 commit comments

Comments
 (0)