diff --git a/crates/hir/src/hir_def/module_tree.rs b/crates/hir/src/hir_def/module_tree.rs index b57702220..ad7c883cc 100644 --- a/crates/hir/src/hir_def/module_tree.rs +++ b/crates/hir/src/hir_def/module_tree.rs @@ -219,10 +219,15 @@ impl<'db> ModuleTreeBuilder<'db> { continue; } - assert!(child_path - .parent() - .unwrap() - .starts_with(root_path.parent().unwrap())); + assert!( + child_path + .parent() + .unwrap() + .starts_with(root_path.parent().unwrap()), + "Parent of child path '{}' must start with the parent of the root path '{}'", + child_path, + root_path + ); if let Some(parent_mod) = self.parent_module(child) { let cur_mod = self.mod_map[&child_mod]; diff --git a/crates/language-server/src/backend/db.rs b/crates/language-server/src/backend/db.rs index 857e4c76a..49017d978 100644 --- a/crates/language-server/src/backend/db.rs +++ b/crates/language-server/src/backend/db.rs @@ -2,6 +2,8 @@ use common::{impl_db_traits, InputDb}; use hir::{HirDb, LowerHirDb, SpannedHirDb}; use hir_analysis::{diagnostics::SpannedHirAnalysisDb, HirAnalysisDb}; + +use super::get_core::init_core_ingot; // xxx use salsa::{ParallelDatabase, Snapshot}; #[salsa::db] @@ -24,11 +26,22 @@ impl LanguageServerDb for DB where } #[salsa::db] -#[derive(Default, Clone)] +#[derive(Clone)] pub struct LanguageServerDatabase { storage: salsa::Storage, } +impl Default for LanguageServerDatabase { + fn default() -> Self { + let mut db = LanguageServerDatabase { + storage: Default::default(), + }; + + init_core_ingot(&mut db); + db + } +} + impl_db_traits!( LanguageServerDatabase, InputDb, diff --git a/crates/language-server/src/backend/get_core.rs b/crates/language-server/src/backend/get_core.rs new file mode 100644 index 000000000..123d498e0 --- /dev/null +++ b/crates/language-server/src/backend/get_core.rs @@ -0,0 +1,85 @@ +use camino::Utf8PathBuf; +use common::{ + input::{IngotKind, Version}, + InputDb, InputFile, InputIngot, +}; +use tracing::info; + +#[derive(rust_embed::RustEmbed)] +#[folder = "../../library/core"] +pub struct CoreLib; + +#[salsa::tracked] +pub fn get_core_ingot(db: &dyn InputDb) -> InputIngot { + InputIngot::new( + db, + "core", // this should be handled by the driver crate default behavior + IngotKind::Core, + Version::new(0, 0, 1), + Default::default(), + ) +} + +pub fn init_core_ingot(db: &mut dyn InputDb) -> InputIngot { + info!("Loading std lib..."); + + // First collect all files and create the InputFiles + let mut std_files = Vec::new(); + let mut root_file = None; + + for path in CoreLib::iter() { + let path: Utf8PathBuf = path.as_ref().into(); + info!("Loading stdlib file: {}", path); + + if let Some(file) = CoreLib::get(path.as_str()) { + if !path.starts_with("src") { + continue; + }; + if let Ok(contents) = String::from_utf8(file.data.as_ref().to_vec()) { + // Create InputFile with paths relative to std root + let input_file = InputFile::new(db, path.clone().into(), contents); + + // Identify the root file (probably src/lib.fe or similar) + if path.as_str() == "src/lib.fe" { + root_file = Some(input_file); + } + + std_files.push(input_file); + } + } + } + + let core_ingot = get_core_ingot(db); + // Set up the ingot structure + if let Some(root) = root_file { + core_ingot.set_root_file(db, root); + } + + assert!(root_file.is_some(), "std library must have a root file"); + + // Add all files to the ingot + core_ingot.set_files(db, std_files.into_iter().collect()); + + core_ingot +} + +#[cfg(test)] +mod tests { + use crate::backend::db::LanguageServerDatabase; + + use super::*; + + #[test] + fn is_core_deduplicated() { + let mut db = LanguageServerDatabase::default(); + let core_1 = get_core_ingot(&db); + let core_2 = get_core_ingot(&db); + + let foo = InputFile::new(&db, "src/mod1/foo.fe".into(), "".into()); + + 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))); + } +} diff --git a/crates/language-server/src/backend/mod.rs b/crates/language-server/src/backend/mod.rs index 62cdc1557..37b90bec6 100644 --- a/crates/language-server/src/backend/mod.rs +++ b/crates/language-server/src/backend/mod.rs @@ -1,4 +1,5 @@ pub(crate) mod db; +pub(crate) mod get_core; pub(crate) mod workspace; use async_lsp::ClientSocket; use db::LanguageServerDatabase; diff --git a/crates/language-server/src/backend/workspace.rs b/crates/language-server/src/backend/workspace.rs index 8d1b6dd9d..f5b136e41 100644 --- a/crates/language-server/src/backend/workspace.rs +++ b/crates/language-server/src/backend/workspace.rs @@ -1,10 +1,10 @@ use std::path::{Path, PathBuf}; -use super::db::LanguageServerDatabase; +use super::{db::LanguageServerDatabase, get_core::get_core_ingot}; use anyhow::Result; use common::{ indexmap::IndexSet, - input::{IngotKind, Version}, + input::{IngotDependency, IngotKind, Version}, InputFile, InputIngot, }; @@ -12,10 +12,6 @@ use patricia_tree::StringPatriciaMap; use salsa::Setter; use tracing::info; -// #[derive(RustEmbed)] -// #[folder = "../library/std"] -// struct StdLib; - const FE_CONFIG_SUFFIX: &str = "fe.toml"; fn ingot_directory_key(path: String) -> String { @@ -82,13 +78,20 @@ pub fn get_containing_ingot<'a, T>( impl LocalIngotContext { pub fn new(db: &LanguageServerDatabase, config_path: &str) -> Option { + let mut default_dependencies = IndexSet::new(); + let core = get_core_ingot(db); + + let std_library = IngotDependency::new("core", core); + default_dependencies.insert(std_library); + let ingot = InputIngot::new( db, config_path, IngotKind::Local, Version::new(0, 0, 0), - IndexSet::new(), + default_dependencies, ); + Some(Self { ingot, files: StringPatriciaMap::new(), @@ -243,6 +246,7 @@ pub struct Workspace { impl Workspace { pub fn default() -> Self { + // let default_core_ingot = Some(get_core_ingot(db.as_input_db())); Self { ingot_contexts: StringPatriciaMap::new(), standalone_ingot_context: StandaloneIngotContext::new(), @@ -264,36 +268,6 @@ impl Workspace { ingot_files.chain(standalone_files) } - // pub fn load_std_lib( - // &mut self, - // db: &mut LanguageServerDatabase, - // root_path: &Path, - // ) -> Result<()> { - // let root_path_str = root_path.to_str().unwrap(); - // self.touch_ingot_for_file_path(db, &format!("{}/std/{}", root_path_str, FE_CONFIG_SUFFIX)) - // .unwrap(); - - // info!("Loading std lib..."); - - // // Collect paths to avoid borrowing `db` mutably during the closure - // let paths: Vec<_> = StdLib::iter().collect(); - - // for path in paths { - // let path_str = path.as_ref(); - // let std_path = format!("{}/std/{}", root_path_str, path_str); - // info!("adding std file... {:?} --- {:?}", std_path, path_str); - // if let Some(file) = StdLib::get(path_str) { - // let contents = String::from_utf8(file.data.as_ref().to_vec()); - // if let Ok(contents) = contents { - // if let Some((_ingot, file)) = self.touch_input_for_file_path(db, &std_path) { - // file.set_text(db).to(contents); - // } - // } - // } - // } - // Ok(()) - // } - pub fn set_workspace_root( &mut self, db: &mut LanguageServerDatabase, diff --git a/crates/language-server/src/functionality/handlers.rs b/crates/language-server/src/functionality/handlers.rs index 7be424a23..d6a4b7393 100644 --- a/crates/language-server/src/functionality/handlers.rs +++ b/crates/language-server/src/functionality/handlers.rs @@ -72,8 +72,6 @@ pub async fn initialize( .unwrap_or_else(|| std::env::current_dir().unwrap()); let _ = backend.workspace.set_workspace_root(&mut backend.db, &root); - // let _ = backend.workspace.load_std_lib(&mut backend.db, &root); - // let _ = backend.workspace.sync(); let capabilities = server_capabilities(); let initialize_result = InitializeResult {