-
Notifications
You must be signed in to change notification settings - Fork 196
Use salsa tracking to link InputFile
to InputIngot
#1070
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
use camino::Utf8PathBuf; | ||
use rust_embed::Embed; | ||
|
||
use crate::{ | ||
indexmap::IndexSet, | ||
input::{IngotKind, Version}, | ||
InputDb, InputFile, InputIngot, | ||
}; | ||
#[derive(Embed)] | ||
#[folder = "../../library/core"] | ||
struct Core; | ||
|
||
#[salsa::tracked] | ||
pub fn core(db: &dyn InputDb) -> InputIngot { | ||
let mut files = IndexSet::new(); | ||
let mut root_file = None; | ||
let ingot_path = Utf8PathBuf::from("core"); | ||
|
||
for file in Core::iter() { | ||
if file.ends_with(".fe") { | ||
let path = ingot_path.join(Utf8PathBuf::from(&file)); | ||
if let Some(content) = Core::get(&file) { | ||
let is_root = path == "core/src/lib.fe"; | ||
let input_file = InputFile::__new_impl( | ||
db, | ||
path, | ||
String::from_utf8(content.data.into_owned()).unwrap(), | ||
); | ||
if is_root { | ||
root_file = Some(input_file); | ||
} | ||
files.insert(input_file); | ||
} | ||
} | ||
} | ||
|
||
if root_file.is_none() { | ||
panic!("root file missing from core") | ||
} | ||
|
||
InputIngot::__new_impl( | ||
db, | ||
ingot_path, | ||
IngotKind::Core, | ||
Version::new(0, 0, 0), | ||
IndexSet::default(), | ||
files, | ||
root_file, | ||
) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::impl_db_traits; | ||
|
||
use super::*; | ||
|
||
#[derive(Clone, Default)] | ||
#[salsa::db] | ||
pub(crate) struct TestDb { | ||
storage: salsa::Storage<Self>, | ||
} | ||
impl_db_traits!(TestDb, InputDb); | ||
|
||
#[test] | ||
fn is_core_deduplicated() { | ||
// this is a sanity check | ||
let mut db = TestDb::default(); | ||
let core_1 = core(&db); | ||
let core_2 = core(&db); | ||
|
||
let foo = InputFile::new(&db, "src/mod1/foo.fe".into(), core_1); | ||
|
||
core_2.set_root_file(&mut db, foo); | ||
|
||
assert!(core_1.eq(&core_2)); | ||
assert!(core_1.root_file(&db).eq(&core_2.root_file(&db))); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,8 @@ | ||
use core::panic; | ||
|
||
use camino::Utf8PathBuf; | ||
use rust_embed::Embed; | ||
use salsa::Setter; | ||
use smol_str::SmolStr; | ||
|
||
use crate::{indexmap::IndexSet, InputDb}; | ||
|
||
#[derive(Embed)] | ||
#[folder = "../../library/core"] | ||
struct Core; | ||
use crate::{core_ingot, indexmap::IndexSet, InputDb}; | ||
|
||
/// An ingot is a collection of files which are compiled together. | ||
/// Ingot can depend on other ingots. | ||
|
@@ -40,6 +33,7 @@ pub struct InputIngot { | |
#[get(__get_root_file_impl)] | ||
root_file: Option<InputFile>, | ||
} | ||
|
||
impl InputIngot { | ||
pub fn new( | ||
db: &dyn InputDb, | ||
|
@@ -62,41 +56,7 @@ impl InputIngot { | |
} | ||
|
||
pub fn core(db: &dyn InputDb) -> InputIngot { | ||
let mut files = IndexSet::new(); | ||
let mut root_file = None; | ||
let ingot_path = Utf8PathBuf::from("core"); | ||
|
||
for file in Core::iter() { | ||
if file.ends_with(".fe") { | ||
let path = ingot_path.join(Utf8PathBuf::from(&file)); | ||
if let Some(content) = Core::get(&file) { | ||
let is_root = path == "core/src/lib.fe"; | ||
let input_file = InputFile::new( | ||
db, | ||
path, | ||
String::from_utf8(content.data.into_owned()).unwrap(), | ||
); | ||
if is_root { | ||
root_file = Some(input_file); | ||
} | ||
files.insert(input_file); | ||
} | ||
} | ||
} | ||
|
||
if root_file.is_none() { | ||
panic!("root file missing from core") | ||
} | ||
|
||
Self::__new_impl( | ||
db, | ||
ingot_path, | ||
IngotKind::Core, | ||
Version::new(0, 0, 0), | ||
IndexSet::default(), | ||
files, | ||
root_file, | ||
) | ||
core_ingot::core(db) | ||
} | ||
|
||
/// Set the root file of the ingot. | ||
|
@@ -118,10 +78,22 @@ impl InputIngot { | |
} | ||
} | ||
|
||
#[salsa::input] | ||
#[salsa::interned] | ||
pub struct FilePath<'db> { | ||
path: Utf8PathBuf, | ||
} | ||
|
||
impl<'db> FilePath<'db> { | ||
pub fn from(db: &'db dyn InputDb, path: impl Into<Utf8PathBuf>) -> Self { | ||
FilePath::new(db, path.into()) | ||
} | ||
} | ||
|
||
#[salsa::input(constructor = __new_impl)] | ||
pub struct InputFile { | ||
/// A path to the file from the ingot root directory. | ||
#[return_ref] | ||
#[set(__set_path_impl)] | ||
pub path: Utf8PathBuf, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If This could be handled by some |
||
|
||
#[return_ref] | ||
|
@@ -132,6 +104,27 @@ impl InputFile { | |
pub fn abs_path(&self, db: &dyn InputDb, ingot: InputIngot) -> Utf8PathBuf { | ||
ingot.path(db).join(self.path(db)) | ||
} | ||
|
||
pub fn new(db: &dyn InputDb, path: Utf8PathBuf, ingot: InputIngot) -> Self { | ||
input_for_file_path(db, FilePath::from(db, path), ingot) | ||
} | ||
} | ||
|
||
#[salsa::tracked] | ||
pub fn input_for_file_path<'db>( | ||
db: &'db dyn InputDb, | ||
path: FilePath<'db>, | ||
ingot: InputIngot, | ||
) -> InputFile { | ||
// Check if the ingot already has a file with the same path | ||
for file in ingot.files(db).iter() { | ||
if file.path(db).as_path() == path.path(db) { | ||
return *file; | ||
} | ||
} | ||
|
||
Comment on lines
+119
to
+124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was necessary so that ingots with manually created/added There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
// If no existing file is found, create a new one | ||
InputFile::__new_impl(db, path.path(db), String::new()) | ||
} | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
|
@@ -178,3 +171,31 @@ impl Ord for IngotDependency { | |
} | ||
|
||
pub type Version = semver::Version; | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::{impl_db_traits, input::*}; | ||
|
||
#[derive(Default, Clone)] | ||
#[salsa::db] | ||
pub struct TestDatabase { | ||
storage: salsa::Storage<Self>, | ||
} | ||
|
||
impl_db_traits!(TestDatabase, InputDb); | ||
|
||
#[test] | ||
fn test_input_file_equals() { | ||
let path = Utf8PathBuf::from("test.foo"); | ||
|
||
let mut db = TestDatabase::default(); | ||
let ingot = InputIngot::core(&db); | ||
|
||
let file1 = InputFile::new(&db, path.clone(), ingot); | ||
let file2 = InputFile::new(&db, path, ingot); | ||
assert_eq!(file1, file2); | ||
|
||
file2.set_text(&mut db).to("Hello, world!".into()); | ||
assert_eq!(file1.text(&db), file2.text(&db)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
mod core_ingot; | ||
pub mod diagnostics; | ||
pub mod indexmap; | ||
pub mod input; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disabling salsa tracking on the core ingot gets rid of the errors in CI. I can't see why these particular tests should fail as a result of reusing the core ingot:
c.c. @sbillig @g-r-a-n-t this is pretty weird