Change:
To the extent possible, we should try to have all interior mutability be done via , , , or (not yet landed) . If one of these patterns doesn't suffice, it'd be nice to know why!
Nominating for P-Low
Tagging as E-Mentor; I can mentor.
Related to Other types that use interior mutability I can think of off the top of my head: -
I'm definitely interested. Though---having never been a part of a project like this before---not quite sure how the mentoring works just yet :P
This is the part: .
I don't understand the reasoning behind doing this for . Using a marker type makes the intent clearer, and will perform better with optimizations disabled. The type is also supposed to be when is and this will make it always non-. The type should also be .
Marker types do not seem clearer to me than , quite the opposite, but of course thi is a matter of opinion. At first I thought you were on to something regarding , but then I realize that I was mistaken. In particular, we need to settle on precisely what makes something not : must the interior mutability be something interior, something that you own, or just something you can reach? But this question is orthogonal to whether we use markers or . If I understand it, the use of would look something like this: In this case, whether or not is will hinge directly on what we decide about owning vs mutability. At present, the definition is based on reachability. But this definition may be stronger than what we need. I guess it depends on just what is to be used for. So after considering this some more, I still think that using is the right call for is the right call, but the real discussion is what precisely ought to mean, which is most properly discussed I think under . make sense?
I don't think we have a way of enforcing deep immutability. There are many existing types doing internal writes due to I/O. I don't know of a purpose for beyond the high-level semantic meaning (perceived inherited mutability) and type-based alias analysis (which is not deep) so that's the lens I'm viewing it through.
Every type using memory allocation needs to become non- if means deep immutability. The function is mutating memory via the pointer. So it's not just a problem with I/O.
I don't believe that is an accurate summray of what was proposed, but it is a moot point, as in the latest plan there is no Freeze.
Is there a change to coming? is already using .
I think and I decided that is already using the right primitives and it was just that wasn't.
Though I didn't dig too deeply, maybe can confirm. But it looked to me like it was using the proper abstraction (is there more than one?)
Indeed, is correctly implemented as-is it appears.
I'm running into tests not compiling because something doesn't implement Freeze. Should I wait for to land before I continue?
I actually did not realized that is already on this issue. I'll let you handle this one :D
Assigning P-low as suggested.

Discussion:
*/ use cast::transmute; <ins> use cell::Cell; </ins> use clone::Clone; use cmp::{Eq, Ord}; use kinds::marker; use ops::{Deref, Drop}; use option::{Option, Some, None}; use ptr; <ins> use ptr::RawPtr; </ins> use rt::global_heap::exchange_free; struct RcBox<T> { value: T, <del> strong: uint, weak: uint </del> <ins> strong: Cell<uint>, weak: Cell<uint> </ins> } /// Immutable reference counted pointer type

// destructor never frees the allocation while the // strong destructor is running, even if the weak // pointer is stored inside the strong one. <del> ptr: transmute(~RcBox { value: value, strong: 1, weak: 1 }), </del> <ins> ptr: transmute(~RcBox { value: value, strong: Cell::new(1), weak: Cell::new(1) }), </ins> nosend: marker::NoSend, noshare: marker::NoShare }

impl<T> Rc<T> { /// Downgrade the reference-counted pointer to a weak reference pub fn downgrade(&self) -> Weak<T> { <del> unsafe { (*self.ptr).weak += 1; Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare } </del> <ins> self.inc_weak(); Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare </ins> } } }

/// Borrow the value contained in the reference-counted box #[inline(always)] fn deref<'a>(&'a self) -> &'a T { <del> unsafe { &(*self.ptr).value } </del> <ins> &self.inner().value </ins> } }

impl<T> Drop for Rc<T> { fn drop(&mut self) { unsafe { <del> if self.ptr != 0 as *mut RcBox<T> { (*self.ptr).strong -= 1; if (*self.ptr).strong == 0 { </del> <ins> if !self.ptr.is_null() { self.dec_strong(); if self.strong() == 0 { </ins> ptr::read(self.deref()); // destroy the contained object // remove the implicit "strong weak" pointer now // that we've destroyed the contents. <del> (*self.ptr).weak -= 1; </del> <ins> self.dec_weak(); </ins> <del> if (*self.ptr).weak == 0 { </del> <ins> if self.weak() == 0 { </ins> exchange_free(self.ptr as *u8) } }

impl<T> Clone for Rc<T> { #[inline] fn clone(&self) -> Rc<T> { <del> unsafe { (*self.ptr).strong += 1; Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare } } </del> <ins> self.inc_strong(); Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare } </ins> } }

impl<T> Weak<T> { /// Upgrade a weak reference to a strong reference pub fn upgrade(&self) -> Option<Rc<T>> { <del> unsafe { if (*self.ptr).strong == 0 { None } else { (*self.ptr).strong += 1; Some(Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }) } </del> <ins> if self.strong() == 0 { None } else { self.inc_strong(); Some(Rc { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare }) </ins> } } }

impl<T> Drop for Weak<T> { fn drop(&mut self) { unsafe { <del> if self.ptr != 0 as *mut RcBox<T> { (*self.ptr).weak -= 1; </del> <ins> if !self.ptr.is_null() { self.dec_weak(); </ins> // the weak count starts at 1, and will only go to // zero if all the strong pointers have disappeared. <del> if (*self.ptr).weak == 0 { </del> <ins> if self.weak() == 0 { </ins> exchange_free(self.ptr as *u8) } }

impl<T> Clone for Weak<T> { #[inline] fn clone(&self) -> Weak<T> { <del> unsafe { (*self.ptr).weak += 1; Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare } } </del> <ins> self.inc_weak(); Weak { ptr: self.ptr, nosend: marker::NoSend, noshare: marker::NoShare } </ins> } } <ins> #[allow(missing_doc)] trait RcBoxPtr<T> { fn inner<'a>(&'a self) -> &'a RcBox<T>; #[inline] fn strong(&self) -> uint { self.inner().strong.get() } #[inline] fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); } #[inline] fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); } #[inline] fn weak(&self) -> uint { self.inner().weak.get() } #[inline] fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); } #[inline] fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } } impl<T> RcBoxPtr<T> for Rc<T> { #[inline(always)] fn inner<'a>(&'a self) -> &'a RcBox<T> { unsafe { &(*self.ptr) } } } impl<T> RcBoxPtr<T> for Weak<T> { #[inline(always)] fn inner<'a>(&'a self) -> &'a RcBox<T> { unsafe { &(*self.ptr) } } } </ins> #[cfg(test)] mod tests { use prelude::*;

use codemap::*; use super::*; <del> fn is_freeze<T: Freeze>() {} // Assert that the AST remains Freeze (#10693). #[test] fn ast_is_freeze() { is_freeze::<Item>(); } </del> // are ASTs encodable? #[test] fn check_asts_encodable() {