Last active
November 9, 2017 22:57
-
-
Save nikomatsakis/90102114e8ba5792d4e28a6960942ae6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Can this lvalue be written or borrowed mutably? | |
fn is_mutable(lvalue) -> Result<(), &Lvalue> { | |
match lvalue { | |
// Shared borrowed data is never mutable. | |
deref of &T => Err(lvalue), | |
// Mutably borrowed data is mutable, but only if we have a unique path to the `&mut`. | |
deref of &mut T => can_host_mutable_ref(base), | |
// `*const` raw pointers are not mutable. | |
deref of *const T => Err(lvalue), | |
// `*mut` raw pointers are always mutable, regardless of context. | |
// User's problem. | |
deref of *mut T => Ok(()), | |
// `Box<T>` owns its contents, so mutable if its location is mutable. | |
deref of Box<T> => is_mutable(base), | |
// All other projections are owned by their base path, so mutable if base path is mutable. | |
other projection => is_mutable(base), | |
// Mutable locals/statics are mutable. Shocker. | |
mutable local or static => Ok, | |
// Non-mutable locals/statics are not (directly) mutable. | |
immutable local or static => Err(lvalue), | |
} | |
} | |
// Helper: this lvalue owns an `&mut` -- can it be used to write mutably? | |
// | |
// The basic idea is to enforce a unique path. | |
fn can_host_mutable_ref(lvalue) -> Result<(), &Lvalue> { | |
match lvalue { | |
// lvalue represents an aliased location. | |
deref of &T => Err(lvalue), | |
// `*const T` is assumed to be aliasable. | |
deref of *const T => Err(lvalue), | |
// `*mut T` can be aliased, but we leave it to user. | |
deref of *mut T => Ok(()), | |
// `&mut` is as unique as the context in which it is found. | |
// `Box<T>` referent and other "owners" are unique, *if* box is in a unique spot | |
deref of &mut T | | |
deref of Box<T> | | |
other projection => can_host_mutable_ref(base), | |
// local variables are unique | |
mutable or immutable local => Ok, | |
// statics are just not | |
mutable or immutable static => Err(lvalue), | |
} | |
} | |
// This lvalue can be moved from. | |
fn is_mobile(lvalue: &Lvalue) -> Option<&Lvalue> { | |
match lvalue { | |
// can't move from borrowed content | |
deref of &T or &mut T => Err(lvalue), | |
// cannot move from raw const pointers | |
deref of *const T => Err(lvalue), // I think? Have to check what we do now. | |
// can move from raw mut pointers. User's problem not to use it again. | |
deref of *mut T => Ok(()), | |
// can't move form a static, that would leave a gap. | |
static => Err(lvalue), | |
// can always move from a local | |
local => Ok(()), | |
// we don't permit moves from `vec[i]` because we can't track `i` precisely for dynamic drop elaboration | |
index projection => Err(lvalue), // at least the most general sort of index, not permitted | |
// in general, we can move from owned content if owner is movable | |
deref of Box<T> | | |
other projection => is_mobile(base), | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment