Repository: rust-analyzer/rust-analyzer
Pull request #472 (2019-01-08 22:59:21)

Stupidly simple idea to make DefIds more stable


Patch:
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 3db7577781..8ac49eba3e 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -253,13 +253,17 @@ impl SourceFileItems {
     }
 
     fn init(&mut self, source_file: &SourceFile) {
-        source_file.syntax().descendants().for_each(|it| {
+        // By walking the tree in bread-first order we make sure that parents
+        // get lower ids then children. That is, addding a new child does not
+        // change parent's id. This means that, say, adding a new function to a
+        // trait does not chage ids of top-level items, which helps caching.
+        bfs(source_file.syntax(), |it| {
             if let Some(module_item) = ast::ModuleItem::cast(it) {
                 self.alloc(module_item.syntax().to_owned());
             } else if let Some(macro_call) = ast::MacroCall::cast(it) {
                 self.alloc(macro_call.syntax().to_owned());
             }
-        });
+        })
     }
 
     fn alloc(&mut self, item: TreePtr<SyntaxNode>) -> SourceFileItemId {
@@ -305,3 +309,16 @@ impl std::ops::Index<SourceFileItemId> for SourceFileItems {
         &self.arena[idx]
     }
 }
+
+/// Walks the subtree in bfs order, calling `f` for each node.
+fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
+    let mut curr_layer = vec![node];
+    let mut next_layer = vec![];
+    while !curr_layer.is_empty() {
+        curr_layer.drain(..).for_each(|node| {
+            next_layer.extend(node.children());
+            f(node);
+        });
+        std::mem::swap(&mut curr_layer, &mut next_layer);
+    }
+}
diff --git a/crates/ra_syntax/fuzz/Cargo.lock b/crates/ra_syntax/fuzz/Cargo.lock
index bd634b90f8..77bddab7cf 100644
--- a/crates/ra_syntax/fuzz/Cargo.lock
+++ b/crates/ra_syntax/fuzz/Cargo.lock
@@ -135,15 +135,6 @@ dependencies = [
  "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "parking_lot"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "parking_lot"
 version = "0.7.0"
@@ -153,18 +144,6 @@ dependencies = [
  "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "parking_lot_core"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "parking_lot_core"
 version = "0.4.0"
@@ -208,8 +187,8 @@ dependencies = [
  "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "ra_text_edit 0.1.0",
- "rowan 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "text_unit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rowan 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -226,7 +205,7 @@ name = "ra_text_edit"
 version = "0.1.0"
 dependencies = [
  "proptest 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "text_unit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -337,12 +316,12 @@ dependencies = [
 
 [[package]]
 name = "rowan"
-version = "0.1.3"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "smol_str 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "text_unit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -415,7 +394,7 @@ dependencies = [
 
 [[package]]
 name = "text_unit"
-version = "0.1.5"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
@@ -491,9 +470,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
 "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
 "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
-"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
 "checksum parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9723236a9525c757d9725b993511e3fc941e33f27751942232f0058298297edf"
-"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c"
 "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
 "checksum proptest 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "926d0604475349f463fe44130aae73f2294b5309ab2ca0310b998bd334ef191f"
 "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
@@ -509,7 +486,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2"
 "checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
 "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
-"checksum rowan 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9ccca91953e9c549cac18e8f41daa5d49dad1c9a4c9bb977ac42718bb34e1bf"
+"checksum rowan 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9ae7dba5e703f423ceb8646d636c73e6d858a2f8c834808b4565e42ccda9e2"
 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
 "checksum rusty-fork 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9591f190d2852720b679c21f66ad929f9f1d7bb09d1193c26167586029d8489c"
 "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
@@ -519,7 +496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum smol_str 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "486a74e9b9fc53373808f7a17e10fc728adcb1fbe272292271d8bea61175e181"
 "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
 "checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2"
-"checksum text_unit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8009d7bdbd896a7e09b595f8f9325a19047fc708653e60d0895202b82135048f"
+"checksum text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "158bb1c22b638b1da3c95a8ad9f061ea40d4d39fd0301be3a520f92efeeb189e"
 "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
 "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
 "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"


Test patch:
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index c511c40b25..17de54b442 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -322,27 +322,8 @@ fn reexport_across_crates() {
     );
 }
 
-#[test]
-fn typing_inside_a_function_should_not_invalidate_item_map() {
-    let (mut db, pos) = MockDatabase::with_position(
-        "
-        //- /lib.rs
-        mod foo;
-
-        use crate::foo::bar::Baz;
-
-        //- /foo/mod.rs
-        pub mod bar;
-
-        //- /foo/bar.rs
-        <|>
-        salsa::query_group! {
-            trait Baz {
-                fn foo() -> i32 { 1 + 1 }
-            }
-        }
-        ",
-    );
+fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
+    let (mut db, pos) = MockDatabase::with_position(initial);
     let source_root = db.file_source_root(pos.file_id);
     {
         let events = db.log_executed(|| {
@@ -350,18 +331,8 @@ fn typing_inside_a_function_should_not_invalidate_item_map() {
         });
         assert!(format!("{:?}", events).contains("item_map"))
     }
-
-    let new_text = "
-        salsa::query_group! {
-            trait Baz {
-                fn foo() -> i32 { 92 }
-            }
-        }
-    "
-    .to_string();
-
     db.query_mut(ra_db::FileTextQuery)
-        .set(pos.file_id, Arc::new(new_text));
+        .set(pos.file_id, Arc::new(file_change.to_string()));
 
     {
         let events = db.log_executed(|| {
@@ -376,8 +347,8 @@ fn typing_inside_a_function_should_not_invalidate_item_map() {
 }
 
 #[test]
-fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
-    let (mut db, pos) = MockDatabase::with_position(
+fn typing_inside_a_function_should_not_invalidate_item_map() {
+    check_item_map_is_not_recomputed(
         "
         //- /lib.rs
         mod foo;<|>
@@ -392,36 +363,81 @@ fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
 
         //- /foo/bar.rs
         pub struct Baz;
-    ",
-    );
-    let source_root = db.file_source_root(pos.file_id);
-    {
-        let events = db.log_executed(|| {
-            db.item_map(source_root).unwrap();
-        });
-        assert!(format!("{:?}", events).contains("item_map"))
-    }
-
-    let new_text = "
+        ",
+        "
         mod foo;
 
         use crate::foo::bar::Baz;
 
         fn foo() -> i32 { 92 }
-    "
-    .to_string();
+        ",
+    );
+}
 
-    db.query_mut(ra_db::FileTextQuery)
-        .set(pos.file_id, Arc::new(new_text));
+#[test]
+fn adding_inner_items_should_not_invalidate_item_map() {
+    check_item_map_is_not_recomputed(
+        "
+        //- /lib.rs
+        struct S { a: i32}
+        enum E { A }
+        trait T {
+            fn a() {}
+        }
+        mod foo;<|>
+        impl S {
+            fn a() {}
+        }
+        use crate::foo::bar::Baz;
+        //- /foo/mod.rs
+        pub mod bar;
 
-    {
-        let events = db.log_executed(|| {
-            db.item_map(source_root).unwrap();
-        });
-        assert!(
-            !format!("{:?}", events).contains("item_map"),
-            "{:#?}",
-            events
-        )
-    }
+        //- /foo/bar.rs
+        pub struct Baz;
+        ",
+        "
+        struct S { a: i32, b: () }
+        enum E { A, B }
+        trait T {
+            fn a() {}
+            fn b() {}
+        }
+        mod foo;<|>
+        impl S {
+            fn a() {}
+            fn b() {}
+        }
+        use crate::foo::bar::Baz;
+        ",
+    );
+}
+
+#[test]
+fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
+    check_item_map_is_not_recomputed(
+        "
+        //- /lib.rs
+        mod foo;
+
+        use crate::foo::bar::Baz;
+
+        //- /foo/mod.rs
+        pub mod bar;
+
+        //- /foo/bar.rs
+        <|>
+        salsa::query_group! {
+            trait Baz {
+                fn foo() -> i32 { 1 + 1 }
+            }
+        }
+        ",
+        "
+        salsa::query_group! {
+            trait Baz {
+                fn foo() -> i32 { 92 }
+            }
+        }
+        ",
+    );
 }