about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2017-02-20 21:18:16 -0500
committerNiko Matsakis <niko@alum.mit.edu>2017-02-28 08:43:47 -0500
commitd79ad36cf5c8f11e37001a090abae5ff94fbab1b (patch)
tree7e60d68c0ba3a3abaa286963ca41c9b60b4aa1f7
parent3e9bddad7bcd2b1bb4e5d534c271c6005739ab9c (diff)
downloadrust-d79ad36cf5c8f11e37001a090abae5ff94fbab1b.tar.gz
rust-d79ad36cf5c8f11e37001a090abae5ff94fbab1b.zip
walk the bodies "in order" by traversing the crate
Otherwise the errors from borrowck come out in an unpredictable
order.
-rw-r--r--src/librustc/dep_graph/visit.rs28
-rw-r--r--src/librustc/hir/map/mod.rs29
-rw-r--r--src/test/ui/span/mut-arg-hint.stderr16
3 files changed, 50 insertions, 23 deletions
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
index f807437750d..0d10049bc1e 100644
--- a/src/librustc/dep_graph/visit.rs
+++ b/src/librustc/dep_graph/visit.rs
@@ -11,6 +11,7 @@
 use hir;
 use hir::def_id::DefId;
 use hir::itemlikevisit::ItemLikeVisitor;
+use hir::intravisit::{self, NestedVisitorMap, Visitor};
 use ty::TyCtxt;
 
 use super::dep_node::DepNode;
@@ -78,9 +79,30 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>
 pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C)
     where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId),
 {
+    // NB: we use a visitor here rather than walking the keys of the
+    // hashmap so as to ensure we visit the bodies "in order".
+
     let krate = tcx.hir.krate();
-    for body_id in krate.bodies.keys().cloned() {
-        let body_owner_def_id = tcx.hir.body_owner_def_id(body_id);
-        callback(body_owner_def_id, body_id);
+    intravisit::walk_crate(&mut V { tcx, callback }, krate);
+
+    struct V<'a, 'tcx: 'a, C> {
+        tcx: TyCtxt<'a, 'tcx, 'tcx>,
+        callback: C
+    }
+
+    impl<'a, 'tcx, C> Visitor<'tcx> for V<'a, 'tcx, C>
+        where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId),
+    {
+        fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+            NestedVisitorMap::All(&self.tcx.hir)
+        }
+
+        fn visit_body(&mut self, body: &'tcx hir::Body) {
+            let body_id = body.id();
+            let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id);
+            (self.callback)(body_owner_def_id, body_id);
+
+            intravisit::walk_body(self, body);
+        }
     }
 }
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 20b4d8d8a8f..5d074903b2b 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -168,43 +168,48 @@ impl<'hir> MapEntry<'hir> {
         })
     }
 
-    fn is_body_owner(self, node_id: NodeId) -> bool {
+    fn associated_body(self) -> Option<BodyId> {
         match self {
             EntryItem(_, item) => {
                 match item.node {
                     ItemConst(_, body) |
                     ItemStatic(.., body) |
-                    ItemFn(_, _, _, _, _, body) => body.node_id == node_id,
-                    _ => false
+                    ItemFn(_, _, _, _, _, body) => Some(body),
+                    _ => None,
                 }
             }
 
             EntryTraitItem(_, item) => {
                 match item.node {
                     TraitItemKind::Const(_, Some(body)) |
-                    TraitItemKind::Method(_, TraitMethod::Provided(body)) => {
-                        body.node_id == node_id
-                    }
-                    _ => false
+                    TraitItemKind::Method(_, TraitMethod::Provided(body)) => Some(body),
+                    _ => None
                 }
             }
 
             EntryImplItem(_, item) => {
                 match item.node {
                     ImplItemKind::Const(_, body) |
-                    ImplItemKind::Method(_, body) => body.node_id == node_id,
-                    _ => false
+                    ImplItemKind::Method(_, body) => Some(body),
+                    _ => None,
                 }
             }
 
             EntryExpr(_, expr) => {
                 match expr.node {
-                    ExprClosure(.., body, _) => body.node_id == node_id,
-                    _ => false
+                    ExprClosure(.., body, _) => Some(body),
+                    _ => None,
                 }
             }
 
-            _ => false
+            _ => None
+        }
+    }
+
+    fn is_body_owner(self, node_id: NodeId) -> bool {
+        match self.associated_body() {
+            Some(b) => b.node_id == node_id,
+            None => false,
         }
     }
 }
diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr
index e4ed0622147..01364c07144 100644
--- a/src/test/ui/span/mut-arg-hint.stderr
+++ b/src/test/ui/span/mut-arg-hint.stderr
@@ -1,12 +1,4 @@
 error: cannot borrow immutable borrowed content `*a` as mutable
-  --> $DIR/mut-arg-hint.rs:18:5
-   |
-17 | pub fn foo<'a>(mut a: &'a String) {
-   |                       ---------- use `&'a mut String` here to make mutable
-18 |     a.push_str("foo");
-   |     ^ cannot borrow as mutable
-
-error: cannot borrow immutable borrowed content `*a` as mutable
   --> $DIR/mut-arg-hint.rs:13:9
    |
 12 |     fn foo(mut a: &String) {
@@ -15,6 +7,14 @@ error: cannot borrow immutable borrowed content `*a` as mutable
    |         ^ cannot borrow as mutable
 
 error: cannot borrow immutable borrowed content `*a` as mutable
+  --> $DIR/mut-arg-hint.rs:18:5
+   |
+17 | pub fn foo<'a>(mut a: &'a String) {
+   |                       ---------- use `&'a mut String` here to make mutable
+18 |     a.push_str("foo");
+   |     ^ cannot borrow as mutable
+
+error: cannot borrow immutable borrowed content `*a` as mutable
   --> $DIR/mut-arg-hint.rs:25:9
    |
 24 |     pub fn foo(mut a: &String) {