Skip to content

Commit c0f48f9

Browse files
bors[bot]matklad
andcommitted
472: Stupidly simple idea to make DefIds more stable r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 46f74e3 + d18d839 commit c0f48f9

File tree

3 files changed

+103
-93
lines changed

3 files changed

+103
-93
lines changed

crates/ra_hir/src/ids.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,17 @@ impl SourceFileItems {
253253
}
254254

255255
fn init(&mut self, source_file: &SourceFile) {
256-
source_file.syntax().descendants().for_each(|it| {
256+
// By walking the tree in bread-first order we make sure that parents
257+
// get lower ids then children. That is, addding a new child does not
258+
// change parent's id. This means that, say, adding a new function to a
259+
// trait does not chage ids of top-level items, which helps caching.
260+
bfs(source_file.syntax(), |it| {
257261
if let Some(module_item) = ast::ModuleItem::cast(it) {
258262
self.alloc(module_item.syntax().to_owned());
259263
} else if let Some(macro_call) = ast::MacroCall::cast(it) {
260264
self.alloc(macro_call.syntax().to_owned());
261265
}
262-
});
266+
})
263267
}
264268

265269
fn alloc(&mut self, item: TreePtr<SyntaxNode>) -> SourceFileItemId {
@@ -305,3 +309,16 @@ impl std::ops::Index<SourceFileItemId> for SourceFileItems {
305309
&self.arena[idx]
306310
}
307311
}
312+
313+
/// Walks the subtree in bfs order, calling `f` for each node.
314+
fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
315+
let mut curr_layer = vec![node];
316+
let mut next_layer = vec![];
317+
while !curr_layer.is_empty() {
318+
curr_layer.drain(..).for_each(|node| {
319+
next_layer.extend(node.children());
320+
f(node);
321+
});
322+
std::mem::swap(&mut curr_layer, &mut next_layer);
323+
}
324+
}

crates/ra_hir/src/nameres/tests.rs

Lines changed: 75 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -322,46 +322,17 @@ fn reexport_across_crates() {
322322
);
323323
}
324324

325-
#[test]
326-
fn typing_inside_a_function_should_not_invalidate_item_map() {
327-
let (mut db, pos) = MockDatabase::with_position(
328-
"
329-
//- /lib.rs
330-
mod foo;
331-
332-
use crate::foo::bar::Baz;
333-
334-
//- /foo/mod.rs
335-
pub mod bar;
336-
337-
//- /foo/bar.rs
338-
<|>
339-
salsa::query_group! {
340-
trait Baz {
341-
fn foo() -> i32 { 1 + 1 }
342-
}
343-
}
344-
",
345-
);
325+
fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
326+
let (mut db, pos) = MockDatabase::with_position(initial);
346327
let source_root = db.file_source_root(pos.file_id);
347328
{
348329
let events = db.log_executed(|| {
349330
db.item_map(source_root).unwrap();
350331
});
351332
assert!(format!("{:?}", events).contains("item_map"))
352333
}
353-
354-
let new_text = "
355-
salsa::query_group! {
356-
trait Baz {
357-
fn foo() -> i32 { 92 }
358-
}
359-
}
360-
"
361-
.to_string();
362-
363334
db.query_mut(ra_db::FileTextQuery)
364-
.set(pos.file_id, Arc::new(new_text));
335+
.set(pos.file_id, Arc::new(file_change.to_string()));
365336

366337
{
367338
let events = db.log_executed(|| {
@@ -376,8 +347,8 @@ fn typing_inside_a_function_should_not_invalidate_item_map() {
376347
}
377348

378349
#[test]
379-
fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
380-
let (mut db, pos) = MockDatabase::with_position(
350+
fn typing_inside_a_function_should_not_invalidate_item_map() {
351+
check_item_map_is_not_recomputed(
381352
"
382353
//- /lib.rs
383354
mod foo;<|>
@@ -392,36 +363,81 @@ fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
392363
393364
//- /foo/bar.rs
394365
pub struct Baz;
395-
",
396-
);
397-
let source_root = db.file_source_root(pos.file_id);
398-
{
399-
let events = db.log_executed(|| {
400-
db.item_map(source_root).unwrap();
401-
});
402-
assert!(format!("{:?}", events).contains("item_map"))
403-
}
404-
405-
let new_text = "
366+
",
367+
"
406368
mod foo;
407369
408370
use crate::foo::bar::Baz;
409371
410372
fn foo() -> i32 { 92 }
411-
"
412-
.to_string();
373+
",
374+
);
375+
}
413376

414-
db.query_mut(ra_db::FileTextQuery)
415-
.set(pos.file_id, Arc::new(new_text));
377+
#[test]
378+
fn adding_inner_items_should_not_invalidate_item_map() {
379+
check_item_map_is_not_recomputed(
380+
"
381+
//- /lib.rs
382+
struct S { a: i32}
383+
enum E { A }
384+
trait T {
385+
fn a() {}
386+
}
387+
mod foo;<|>
388+
impl S {
389+
fn a() {}
390+
}
391+
use crate::foo::bar::Baz;
392+
//- /foo/mod.rs
393+
pub mod bar;
416394
417-
{
418-
let events = db.log_executed(|| {
419-
db.item_map(source_root).unwrap();
420-
});
421-
assert!(
422-
!format!("{:?}", events).contains("item_map"),
423-
"{:#?}",
424-
events
425-
)
426-
}
395+
//- /foo/bar.rs
396+
pub struct Baz;
397+
",
398+
"
399+
struct S { a: i32, b: () }
400+
enum E { A, B }
401+
trait T {
402+
fn a() {}
403+
fn b() {}
404+
}
405+
mod foo;<|>
406+
impl S {
407+
fn a() {}
408+
fn b() {}
409+
}
410+
use crate::foo::bar::Baz;
411+
",
412+
);
413+
}
414+
415+
#[test]
416+
fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
417+
check_item_map_is_not_recomputed(
418+
"
419+
//- /lib.rs
420+
mod foo;
421+
422+
use crate::foo::bar::Baz;
423+
424+
//- /foo/mod.rs
425+
pub mod bar;
426+
427+
//- /foo/bar.rs
428+
<|>
429+
salsa::query_group! {
430+
trait Baz {
431+
fn foo() -> i32 { 1 + 1 }
432+
}
433+
}
434+
",
435+
"
436+
salsa::query_group! {
437+
trait Baz {
438+
fn foo() -> i32 { 92 }
439+
}
440+
}
441+
",
442+
);
427443
}

crates/ra_syntax/fuzz/Cargo.lock

Lines changed: 9 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)