Skip to content

Commit

Permalink
Test item location stability
Browse files Browse the repository at this point in the history
This was the entire point of the HIR entity rewrite,
so let's ensure that we do keep stable locations of items.
  • Loading branch information
DropDemBits committed Jun 12, 2023
1 parent e43eaaa commit 3816f36
Show file tree
Hide file tree
Showing 4 changed files with 295 additions and 17 deletions.
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions compiler/toc-hir-def/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ toc-hir-expand.workspace = true

salsa = { workspace = true }
upcast = { workspace = true }

[dev-dependencies]
toc-paths.workspace = true
toc-vfs.workspace = true
insta.workspace = true
61 changes: 44 additions & 17 deletions compiler/toc-hir-def/src/item/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,21 @@ pub struct PrettyTree {
pub fn render_item_tree(db: &dyn Db, root: Package) -> PrettyTree {
fn render_sub_tree(db: &dyn Db, item: Item) -> PrettyItem {
match item {
Item::ConstVar(item) => {
PrettyItem::ConstVar(item.mutability(db), item.name(db).text(db), item.0.as_u32())
}
Item::Module(item) => PrettyItem::Module(
item.name(db).text(db),
item.items(db)
.iter()
.map(|child| render_sub_tree(db, *child))
.collect(),
item.0.as_u32(),
),
Item::ConstVar(item) => PrettyItem {
name: item.name(db).text(db),
id: item.0.as_u32(),
kind: PrettyItemKind::ConstVar(item.mutability(db)),
},
Item::Module(item) => PrettyItem {
name: item.name(db).text(db),
id: item.0.as_u32(),
kind: PrettyItemKind::Module(
item.items(db)
.iter()
.map(|child| render_sub_tree(db, *child))
.collect(),
),
},
}
}

Expand All @@ -36,26 +40,49 @@ pub fn render_item_tree(db: &dyn Db, root: Package) -> PrettyTree {
}
}

enum PrettyItem {
ConstVar(Mutability, String, u32),
Module(String, Vec<PrettyItem>, u32),
struct PrettyItem {
name: String,
id: u32,
kind: PrettyItemKind,
}

enum PrettyItemKind {
ConstVar(Mutability),
Module(Vec<PrettyItem>),
}

impl PrettyTree {
pub fn ensure_sorted(mut self) -> Self {
fn sort_child(child: &mut PrettyItem) {
match &mut child.kind {
PrettyItemKind::ConstVar(_) => {}
PrettyItemKind::Module(children) => {
children.sort_by_key(|item| item.id);
children.iter_mut().for_each(sort_child);
}
}
}

sort_child(&mut self.root);

self
}

pub fn render_as_tree(self) -> String {
fn render_item(out: &mut dyn fmt::Write, level: usize, item: PrettyItem) -> fmt::Result {
let indent = " ".repeat(level);
let PrettyItem { name, id, kind } = item;

match item {
PrettyItem::ConstVar(mutability, name, id) => {
match kind {
PrettyItemKind::ConstVar(mutability) => {
let kind = match mutability {
Mutability::Const => "const",
Mutability::Var => "var",
};
writeln!(out, "{indent}{kind} {name} /* ConstVar({id}) */")?;
writeln!(out, "")?;
}
PrettyItem::Module(name, children, id) => {
PrettyItemKind::Module(children) => {
writeln!(out, "{indent}module {name} /* Module({id}) */")?;
writeln!(out, "")?;
for child in children {
Expand Down
243 changes: 243 additions & 0 deletions compiler/toc-hir-def/src/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
use toc_paths::RawPath;
use toc_source_graph::{ArtifactKind, DependencyList, Package, RootPackages};
use toc_vfs_db::{SourceTable, VfsBridge, VfsDbExt};

#[salsa::db(
toc_paths::Jar,
toc_vfs_db::Jar,
toc_source_graph::Jar,
toc_ast_db::Jar,
toc_hir_expand::Jar,
crate::Jar
)]
#[derive(Default)]
struct TestDb {
storage: salsa::Storage<Self>,
source_table: SourceTable,
}

impl salsa::Database for TestDb {}

impl VfsBridge for TestDb {
fn source_table(&self) -> &SourceTable {
&self.source_table
}
}

impl TestDb {
pub(crate) fn from_source(source: &str) -> (Self, Package) {
let mut db = TestDb::default();
let fixture = toc_vfs::generate_vfs(source).unwrap();
db.insert_fixture(fixture);

let root_file = RawPath::new(&db, "src/main.t".into());
let package = Package::new(
&db,
"main".into(),
root_file,
ArtifactKind::Binary,
DependencyList::empty(&db),
);
RootPackages::new(&db, vec![package]);

(db, package)
}
}

#[test]
fn test_stable_item_locations_swap() {
let (mut db, package) = TestDb::from_source(
"
module a
module c1 end c1
module c2 end c2
module c3 end c3
end a
module b
module d1 end d1
end b
",
);
let start_tree = crate::item::pretty::render_item_tree(&db, package)
.ensure_sorted()
.render_as_tree();

let swapped = toc_vfs::generate_vfs(
"
module b
module d1 end d1
end b
module a
module c1 end c1
module c2 end c2
module c3 end c3
end a
",
)
.unwrap();
db.insert_fixture(swapped);

let swapped_tree = crate::item::pretty::render_item_tree(&db, package)
.ensure_sorted()
.render_as_tree();

eprintln!("{start_tree} -> {swapped_tree}");

assert_eq!(start_tree, swapped_tree);
}

#[test]
fn test_stable_item_locations_add_ws() {
let (mut db, package) = TestDb::from_source(
"
module a
module c1 end c1
module c2 end c2
module c3 end c3
end a
module b
module d1 end d1
end b
",
);
let start_tree = crate::item::pretty::render_item_tree(&db, package)
.ensure_sorted()
.render_as_tree();

let swapped = toc_vfs::generate_vfs(
"
module a
module c1 end c1
module c2 end c2
module c3 end c3
end a
% according to all known laws of aviation
% it is impossible for a bee to fly
% yet, it does so anyway because a bee does not care
% what human think is possible
module b
module d1 end d1
end b
",
)
.unwrap();
db.insert_fixture(swapped);

let new_tree = crate::item::pretty::render_item_tree(&db, package)
.ensure_sorted()
.render_as_tree();

eprintln!("{start_tree} -> {new_tree}");

assert_eq!(start_tree, new_tree);
}

#[test]
fn test_stable_item_locations_reinsert_swap() {
let (mut db, package) = TestDb::from_source(
"
module a
module c1 end c1
module c2 end c2
module c3 end c3
end a
module b
module d1 end d1
end b
module c end c
",
);
let start_tree = crate::item::pretty::render_item_tree(&db, package)
.ensure_sorted()
.render_as_tree();

// intermediate step
db.insert_fixture(
toc_vfs::generate_vfs(
"
module a
module c1 end c1
module c2 end c2
module c3 end c3
end a
module c end c
",
)
.unwrap(),
);

// reinsert
let swapped = toc_vfs::generate_vfs(
"
module b
module d1 end d1
end b
module a
module c1 end c1
module c2 end c2
module c3 end c3
end a
module c end c
",
)
.unwrap();
db.insert_fixture(swapped);

let swapped_tree = crate::item::pretty::render_item_tree(&db, package)
.ensure_sorted()
.render_as_tree();

eprintln!("{start_tree} -> {swapped_tree}");

assert_eq!(start_tree, swapped_tree);
}

#[test]
fn test_stable_constvar_locations_delete_swap() {
// constvars are a lil trickier since they also include an index
let (mut db, package) = TestDb::from_source(
"
const a, b, c := 1
",
);
let start_tree = crate::item::pretty::render_item_tree(&db, package)
.ensure_sorted()
.render_as_tree();

// intermediate step
db.insert_fixture(
toc_vfs::generate_vfs(
"
const a, c := 1
",
)
.unwrap(),
);

// reinsert
let swapped = toc_vfs::generate_vfs(
"
const a, c, b := 1
",
)
.unwrap();
db.insert_fixture(swapped);

let swapped_tree = crate::item::pretty::render_item_tree(&db, package)
.ensure_sorted()
.render_as_tree();

eprintln!("{start_tree} -> {swapped_tree}");

assert_eq!(start_tree, swapped_tree);
}

0 comments on commit 3816f36

Please sign in to comment.