Skip to content

Commit

Permalink
borrowck: consolidate mut suggestions
Browse files Browse the repository at this point in the history
This converts all of borrowck's `mut` suggestions to a new
`mc::ImmutabilityBlame` API instead of the current mix of various hacks.

Fixes #35937.
Fixes #40823.
  • Loading branch information
arielb1 committed Mar 26, 2017
1 parent 49c67bd commit 50728e5
Show file tree
Hide file tree
Showing 21 changed files with 304 additions and 207 deletions.
140 changes: 61 additions & 79 deletions src/librustc/middle/mem_categorization.rs
Expand Up @@ -194,76 +194,75 @@ pub struct cmt_<'tcx> {

pub type cmt<'tcx> = Rc<cmt_<'tcx>>;

pub enum ImmutabilityBlame<'tcx> {
ImmLocal(ast::NodeId),
ClosureEnv(ast::NodeId),
LocalDeref(ast::NodeId),
AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef)
}

impl<'tcx> cmt_<'tcx> {
pub fn get_def(&self) -> Option<ast::NodeId> {
match self.cat {
Categorization::Deref(ref cmt, ..) |
Categorization::Interior(ref cmt, _) |
Categorization::Downcast(ref cmt, _) => {
if let Categorization::Local(nid) = cmt.cat {
Some(nid)
} else {
None
}
fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef)
{
let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| {
bug!("interior cmt {:?} is not an ADT", self)
});
let variant_def = match self.cat {
Categorization::Downcast(_, variant_did) => {
adt_def.variant_with_id(variant_did)
}
_ => None
}
_ => {
assert!(adt_def.is_univariant());
&adt_def.variants[0]
}
};
let field_def = match field_name {
NamedField(name) => variant_def.field_named(name),
PositionalField(idx) => &variant_def.fields[idx]
};
(adt_def, field_def)
}

pub fn get_field(&self, name: ast::Name) -> Option<DefId> {
pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
match self.cat {
Categorization::Deref(ref cmt, ..) |
Categorization::Interior(ref cmt, _) |
Categorization::Downcast(ref cmt, _) => {
if let Categorization::Local(_) = cmt.cat {
if let ty::TyAdt(def, _) = self.ty.sty {
if def.is_struct() {
return def.struct_variant().find_field_named(name).map(|x| x.did);
Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) |
Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => {
// try to figure out where the immutable reference came from
match base_cmt.cat {
Categorization::Local(node_id) =>
Some(ImmutabilityBlame::LocalDeref(node_id)),
Categorization::Interior(ref base_cmt, InteriorField(field_name)) => {
let (adt_def, field_def) = base_cmt.resolve_field(field_name);
Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def))
}
Categorization::Upvar(Upvar { id, .. }) => {
if let NoteClosureEnv(..) = self.note {
Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id))
} else {
None
}
}
None
} else {
cmt.get_field(name)
_ => None
}
}
_ => None
}
}

pub fn get_field_name(&self) -> Option<ast::Name> {
match self.cat {
Categorization::Interior(_, ref ik) => {
if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik {
Some(name)
} else {
None
}
Categorization::Local(node_id) => {
Some(ImmutabilityBlame::ImmLocal(node_id))
}
Categorization::Deref(ref cmt, ..) |
Categorization::Downcast(ref cmt, _) => {
cmt.get_field_name()
Categorization::Rvalue(..) |
Categorization::Upvar(..) |
Categorization::Deref(.., UnsafePtr(..)) => {
// This should not be reachable up to inference limitations.
None
}
_ => None,
}
}

pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option<ast::NodeId> {
match self.cat {
Categorization::Deref(ref cmt, ..) |
Categorization::Interior(ref cmt, _) |
Categorization::Downcast(ref cmt, _) => {
if let Categorization::Local(nid) = cmt.cat {
if let ty::TyAdt(_, _) = self.ty.sty {
if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty {
return Some(nid);
}
}
None
} else {
cmt.get_arg_if_immutable(map)
}
Categorization::Interior(ref base_cmt, _) |
Categorization::Downcast(ref base_cmt, _) |
Categorization::Deref(ref base_cmt, _, _) => {
base_cmt.immutability_blame()
}
Categorization::StaticItem => {
// Do we want to do something here?
None
}
_ => None
}
}
}
Expand Down Expand Up @@ -1282,9 +1281,6 @@ pub enum Aliasability {
#[derive(Copy, Clone, Debug)]
pub enum AliasableReason {
AliasableBorrowed,
AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env
AliasableOther,
UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique
AliasableStatic,
AliasableStaticMut,
}
Expand Down Expand Up @@ -1324,23 +1320,13 @@ impl<'tcx> cmt_<'tcx> {
Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) |
Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
Categorization::Deref(ref b, _, Unique) |
Categorization::Downcast(ref b, _) |
Categorization::Interior(ref b, _) => {
// Aliasability depends on base cmt
b.freely_aliasable()
}

Categorization::Deref(ref b, _, Unique) => {
let sub = b.freely_aliasable();
if b.mutbl.is_mutable() {
// Aliasability depends on base cmt alone
sub
} else {
// Do not allow mutation through an immutable box.
ImmutableUnique(Box::new(sub))
}
}

Categorization::Rvalue(..) |
Categorization::Local(..) |
Categorization::Upvar(..) |
Expand All @@ -1356,13 +1342,9 @@ impl<'tcx> cmt_<'tcx> {
}
}

Categorization::Deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) |
Categorization::Deref(ref base, _, Implicit(ty::ImmBorrow, _)) => {
match base.cat {
Categorization::Upvar(Upvar{ id, .. }) =>
FreelyAliasable(AliasableClosure(id.closure_expr_id)),
_ => FreelyAliasable(AliasableBorrowed)
}
Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => {
FreelyAliasable(AliasableBorrowed)
}
}
}
Expand Down
9 changes: 0 additions & 9 deletions src/librustc_borrowck/borrowck/gather_loans/mod.rs
Expand Up @@ -188,14 +188,6 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
// user knows what they're doing in these cases.
Ok(())
}
(mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => {
bccx.report_aliasability_violation(
borrow_span,
loan_cause,
mc::AliasableReason::UnaliasableImmutable,
cmt);
Err(())
}
(mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) |
(mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => {
bccx.report_aliasability_violation(
Expand Down Expand Up @@ -510,4 +502,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
self.move_error_collector.report_potential_errors(self.bccx);
}
}

0 comments on commit 50728e5

Please sign in to comment.