Handle root type when loading from str

This commit is contained in:
Agus Zubiaga 2024-06-08 19:46:41 -03:00
parent 0283bd1d24
commit 4e5fdfbf52
No known key found for this signature in database
12 changed files with 127 additions and 101 deletions

View file

@ -1081,6 +1081,7 @@ pub fn load_and_typecheck_str<'a>(
filename: PathBuf,
source: &'a str,
src_dir: PathBuf,
opt_main_path: Option<PathBuf>,
exposed_types: ExposedByModule,
target: Target,
function_kind: FunctionKind,
@ -1091,7 +1092,14 @@ pub fn load_and_typecheck_str<'a>(
) -> Result<LoadedModule, LoadingProblem<'a>> {
use LoadResult::*;
let load_start = LoadStart::from_str(arena, filename, source, roc_cache_dir, src_dir)?;
let load_start = LoadStart::from_str(
arena,
filename,
opt_main_path,
source,
roc_cache_dir,
src_dir,
)?;
// this function is used specifically in the case
// where we want to regenerate the cached data
@ -1161,7 +1169,7 @@ impl<'a> LoadStart<'a> {
// Load the root module synchronously; we can't proceed until we have its id.
let root_start_time = Instant::now();
let res_loaded = load_filename(
let load_result = load_filename(
arena,
filename.clone(),
true,
@ -1173,57 +1181,22 @@ impl<'a> LoadStart<'a> {
root_start_time,
);
let (header_output, root_type) = match res_loaded {
Ok(mut header_output) => {
if let Msg::Header(ModuleHeader {
module_id: header_id,
header_type,
..
}) = &header_output.msg
{
debug_assert_eq!(*header_id, header_output.module_id);
let load_result = match load_result {
Ok(header_output) => handle_root_type(
arena,
Arc::clone(&arc_shorthands),
Arc::clone(&arc_modules),
Arc::clone(&ident_ids_by_module),
roc_cache_dir,
header_output,
opt_main_path,
&mut src_dir,
),
Err(problem) => Err(problem),
};
use HeaderType::*;
match header_type {
Module { .. } | Builtin { .. } | Hosted { .. } => {
let main_path =
opt_main_path.or_else(|| find_main_roc_recursively(&mut src_dir));
let cache_dir = roc_cache_dir.as_persistent_path();
if let (Some(main_path), Some(cache_dir)) =
(main_path.clone(), cache_dir)
{
let mut messages = Vec::with_capacity(4);
messages.push(header_output.msg);
load_packages_from_main(
arena,
src_dir.clone(),
main_path,
&mut messages,
Arc::clone(&arc_modules),
Arc::clone(&ident_ids_by_module),
Arc::clone(&arc_shorthands),
cache_dir,
)?;
header_output.msg = Msg::Many(messages);
}
let header_output = adjust_header_paths(header_output, &mut src_dir);
(header_output, RootType::Module { main_path })
}
App { .. } | Package { .. } | Platform { .. } => {
(header_output, RootType::Main)
}
}
} else {
(header_output, RootType::Main)
}
}
let (header_output, root_type) = match load_result {
Ok(header_output) => header_output,
Err(problem) => {
let module_ids = Arc::try_unwrap(arc_modules)
@ -1257,6 +1230,7 @@ impl<'a> LoadStart<'a> {
pub fn from_str(
arena: &'a Bump,
filename: PathBuf,
opt_main_path: Option<PathBuf>,
src: &'a str,
roc_cache_dir: RocCacheDir<'_>,
mut src_dir: PathBuf,
@ -1267,25 +1241,34 @@ impl<'a> LoadStart<'a> {
let ident_ids_by_module = Arc::new(Mutex::new(root_exposed_ident_ids));
// Load the root module synchronously; we can't proceed until we have its id.
let root_start_time = Instant::now();
let header_output = load_from_str(
arena,
filename.clone(),
src,
Arc::clone(&arc_modules),
Arc::clone(&ident_ids_by_module),
roc_cache_dir,
root_start_time,
)?;
let (header_output, root_type) = handle_root_type(
arena,
Arc::clone(&arc_shorthands),
Arc::clone(&arc_modules),
Arc::clone(&ident_ids_by_module),
roc_cache_dir,
header_output,
opt_main_path,
&mut src_dir,
)?;
let HeaderOutput {
module_id: root_id,
msg: root_msg,
opt_platform_shorthand: opt_platform_id,
} = {
let root_start_time = Instant::now();
let header_output = load_from_str(
arena,
filename.clone(),
src,
Arc::clone(&arc_modules),
Arc::clone(&ident_ids_by_module),
roc_cache_dir,
root_start_time,
)?;
adjust_header_paths(header_output, &mut src_dir)
};
} = header_output;
Ok(LoadStart {
arc_modules,
@ -1295,13 +1278,65 @@ impl<'a> LoadStart<'a> {
root_id,
root_path: filename,
root_msg,
// todo(agus): could be module
root_type: RootType::Main,
root_type,
opt_platform_shorthand: opt_platform_id,
})
}
}
fn handle_root_type<'a>(
arena: &'a Bump,
arc_shorthands: Arc<Mutex<MutMap<&'a str, ShorthandPath>>>,
arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
ident_ids_by_module: SharedIdentIdsByModule,
roc_cache_dir: RocCacheDir<'_>,
mut header_output: HeaderOutput<'a>,
opt_main_path: Option<PathBuf>,
src_dir: &mut PathBuf,
) -> Result<(HeaderOutput<'a>, RootType), LoadingProblem<'a>> {
if let Msg::Header(ModuleHeader {
module_id: header_id,
header_type,
..
}) = &header_output.msg
{
debug_assert_eq!(*header_id, header_output.module_id);
use HeaderType::*;
match header_type {
Module { .. } | Builtin { .. } | Hosted { .. } => {
let main_path = opt_main_path.or_else(|| find_main_roc_recursively(src_dir));
let cache_dir = roc_cache_dir.as_persistent_path();
if let (Some(main_path), Some(cache_dir)) = (main_path.clone(), cache_dir) {
let mut messages = Vec::with_capacity(4);
messages.push(header_output.msg);
load_packages_from_main(
arena,
src_dir.clone(),
main_path,
&mut messages,
Arc::clone(&arc_modules),
Arc::clone(&ident_ids_by_module),
Arc::clone(&arc_shorthands),
cache_dir,
)?;
header_output.msg = Msg::Many(messages);
}
Ok((header_output, RootType::Module { main_path }))
}
App { .. } | Package { .. } | Platform { .. } => Ok((header_output, RootType::Main)),
}
} else {
Ok((header_output, RootType::Main))
}
}
fn find_main_roc_recursively(src_dir: &mut PathBuf) -> Option<PathBuf> {
let original_src_dir = src_dir.clone();
@ -1351,7 +1386,7 @@ fn load_packages_from_main<'a>(
unspace(arena, packages.value.items)
}
Platform(PlatformHeader { packages, .. }) => unspace(arena, packages.item.items),
Module(_) | Hosted(_) => todo!("agus: report bad main"),
Module(_) | Hosted(_) => todo!("expected {} to be an app or package", filename.display()),
};
load_packages(
@ -1382,35 +1417,6 @@ fn load_packages_from_main<'a>(
)
}
fn adjust_header_paths<'a>(
header_output: HeaderOutput<'a>,
src_dir: &mut PathBuf,
) -> HeaderOutput<'a> {
if let Msg::Header(ModuleHeader {
module_id: header_id,
header_type,
..
}) = &header_output.msg
{
debug_assert_eq!(*header_id, header_output.module_id);
if let HeaderType::Module { name, .. } = header_type {
// [modules-revamp] TODO: Privacy changes
// Modules can have names like Foo.Bar.Baz,
// in which case we need to adjust the src_dir to
// remove the "Bar/Baz" directories in order to correctly
// resolve this interface module's imports!
let dirs_to_pop = name.as_str().matches('.').count();
for _ in 0..dirs_to_pop {
src_dir.pop();
}
}
}
header_output
}
pub enum LoadResult<'a> {
TypeChecked(LoadedModule),
Monomorphized(MonomorphizedModule<'a>),