Skip to content

Commit

Permalink
Rollup merge of rust-lang#40841 - arielb1:immutable-blame, r=pnkfelix
Browse files Browse the repository at this point in the history
borrowck: consolidate `mut` suggestions

This converts all of borrowck's `mut` suggestions to a new
`mc::ImmutabilityBlame` API instead of the current mix of various hacks.

Fixes rust-lang#35937.
Fixes rust-lang#40823.
Fixes rust-lang#40859.

cc @estebank
r? @pnkfelix
  • Loading branch information
frewsxcv committed Mar 29, 2017
2 parents 96dd9a9 + 39011f8 commit a63b1df
Show file tree
Hide file tree
Showing 23 changed files with 427 additions and 225 deletions.
7 changes: 7 additions & 0 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,13 @@ impl<'a> LoweringContext<'a> {
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
},
variadic: decl.variadic,
has_implicit_self: decl.inputs.get(0).map_or(false, |arg| {
match arg.ty.node {
TyKind::ImplicitSelf => true,
TyKind::Rptr(_, ref mt) => mt.ty.node == TyKind::ImplicitSelf,
_ => false
}
})
})
}

Expand Down
3 changes: 3 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1383,6 +1383,9 @@ pub struct FnDecl {
pub inputs: HirVec<P<Ty>>,
pub output: FunctionRetTy,
pub variadic: bool,
/// True if this function has an `self`, `&self` or `&mut self` receiver
/// (but not a `self: Xxx` one).
pub has_implicit_self: bool,
}

#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
Expand Down
140 changes: 61 additions & 79 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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);
}
}

Loading

0 comments on commit a63b1df

Please sign in to comment.