diff options
| author | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2017-03-26 19:35:46 +0300 |
|---|---|---|
| committer | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2017-03-27 01:37:42 +0300 |
| commit | 50728e52455804143e5cc601004381e395a1e2f7 (patch) | |
| tree | a9169bf697cc6a472082ef1d3782586f4566e678 /src/librustc/middle | |
| parent | 49c67bd632e961a57863805e5d0a400f97da9b93 (diff) | |
| download | rust-50728e52455804143e5cc601004381e395a1e2f7.tar.gz rust-50728e52455804143e5cc601004381e395a1e2f7.zip | |
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 #35937. Fixes #40823.
Diffstat (limited to 'src/librustc/middle')
| -rw-r--r-- | src/librustc/middle/mem_categorization.rs | 140 |
1 files changed, 61 insertions, 79 deletions
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0cf53826dd4..3b52e85e08e 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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 } } } @@ -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, } @@ -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(..) | @@ -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) } } } |
