]> git.lizzy.rs Git - rust.git/commitdiff
When building an item-tree, keep fewer nodes in memory
authorAleksey Kladov <aleksey.kladov@gmail.com>
Sat, 16 Jan 2021 19:38:22 +0000 (22:38 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Sat, 16 Jan 2021 20:07:28 +0000 (23:07 +0300)
Cargo.lock
crates/hir_expand/src/ast_id_map.rs
crates/syntax/Cargo.toml

index 7ba7aea155383e5e70f9e67b73417affd06919d4..0c6e9ff61e28a0ec2c2be20cbc160e967337845e 100644 (file)
@@ -1325,9 +1325,9 @@ checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
 
 [[package]]
 name = "rowan"
-version = "0.10.2"
+version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5093b337dccf58ace6c6d1fe7e28a0b8229c1e72579ae66bae258fbe53df3e0e"
+checksum = "d55d358c5fda3d5c4484f71a4808f5eeb39a0aff93bf3acebc680a6d15376f3c"
 dependencies = [
  "rustc-hash",
  "smol_str",
index f4f6e11fdbe377ec8d3b3079d5ce354e52e9d2b2..2401b0cc59dd34871238d8521c7d290a6c71b45d 100644 (file)
@@ -72,10 +72,12 @@ pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap {
         // get lower ids then children. That is, adding a new child does not
         // change parent's id. This means that, say, adding a new function to a
         // trait does not change ids of top-level items, which helps caching.
-        bfs(node, |it| {
-            if let Some(module_item) = ast::Item::cast(it) {
+        bdfs(node, |it| match ast::Item::cast(it) {
+            Some(module_item) => {
                 res.alloc(module_item.syntax());
+                true
             }
+            None => false,
         });
         res
     }
@@ -105,14 +107,30 @@ fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId {
     }
 }
 
-/// Walks the subtree in bfs order, calling `f` for each node.
-fn bfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode)) {
+/// Walks the subtree in bdfs order, calling `f` for each node. What is bdfs
+/// order? It is a mix of breadth-first and depth first orders. Nodes for which
+/// `f` returns true are visited breadth-first, all the other nodes are explored
+/// depth-first.
+///
+/// In other words, the size of the bfs queue is bound by the number of "true"
+/// nodes.
+fn bdfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode) -> bool) {
     let mut curr_layer = vec![node.clone()];
     let mut next_layer = vec![];
     while !curr_layer.is_empty() {
         curr_layer.drain(..).for_each(|node| {
-            next_layer.extend(node.children());
-            f(node);
+            let mut preorder = node.preorder();
+            while let Some(event) = preorder.next() {
+                match event {
+                    syntax::WalkEvent::Enter(node) => {
+                        if f(node.clone()) {
+                            next_layer.extend(node.children());
+                            preorder.skip_subtree();
+                        }
+                    }
+                    syntax::WalkEvent::Leave(_) => {}
+                }
+            }
         });
         std::mem::swap(&mut curr_layer, &mut next_layer);
     }
index ad8b797fec862497409851782d055a9c6daad1b2..52394b3373cbd7a94ad4255ce2b63278cfc371cc 100644 (file)
@@ -12,7 +12,7 @@ doctest = false
 
 [dependencies]
 itertools = "0.10.0"
-rowan = "0.10.1"
+rowan = "0.10.3"
 rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" }
 rustc-hash = "1.1.0"
 arrayvec = "0.5.1"