about summary refs log tree commit diff
path: root/src/librustc/middle
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-03-26 19:35:46 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-03-27 01:37:42 +0300
commit50728e52455804143e5cc601004381e395a1e2f7 (patch)
treea9169bf697cc6a472082ef1d3782586f4566e678 /src/librustc/middle
parent49c67bd632e961a57863805e5d0a400f97da9b93 (diff)
downloadrust-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.rs140
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)
             }
         }
     }