Skip to content

Instantly share code, notes, and snippets.

@nikomatsakis
Last active November 9, 2017 22:57
Show Gist options
  • Save nikomatsakis/90102114e8ba5792d4e28a6960942ae6 to your computer and use it in GitHub Desktop.
Save nikomatsakis/90102114e8ba5792d4e28a6960942ae6 to your computer and use it in GitHub Desktop.
// 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