Use app module's to to determine platform

This commit is contained in:
Richard Feldman 2022-12-11 22:22:26 -05:00
parent fa58838f97
commit 16ce22d455
No known key found for this signature in database
GPG key ID: F1F21AA5B1D9E43B

View file

@ -915,6 +915,8 @@ struct State<'a> {
pub root_id: ModuleId,
pub root_subs: Option<Subs>,
pub cache_dir: PathBuf,
/// If the root is an app module, the shorthand specified in its header's `to` field
pub opt_platform_shorthand: Option<&'a str>,
pub platform_data: Option<PlatformData<'a>>,
pub exposed_types: ExposedByModule,
pub output_path: Option<&'a str>,
@ -976,6 +978,7 @@ impl<'a> State<'a> {
fn new(
root_id: ModuleId,
opt_platform_shorthand: Option<&'a str>,
target_info: TargetInfo,
exposed_types: ExposedByModule,
arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
@ -993,6 +996,7 @@ impl<'a> State<'a> {
Self {
root_id,
root_subs: None,
opt_platform_shorthand,
cache_dir,
target_info,
platform_data: None,
@ -1269,6 +1273,7 @@ pub struct LoadStart<'a> {
arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
ident_ids_by_module: SharedIdentIdsByModule,
root_id: ModuleId,
opt_platform_shorthand: Option<&'a str>,
root_msg: Msg<'a>,
src_dir: PathBuf,
}
@ -1287,7 +1292,7 @@ impl<'a> LoadStart<'a> {
let mut src_dir = filename.parent().unwrap().to_path_buf();
// Load the root module synchronously; we can't proceed until we have its id.
let (root_id, root_msg) = {
let header_output = {
let root_start_time = Instant::now();
let res_loaded = load_filename(
@ -1303,15 +1308,15 @@ impl<'a> LoadStart<'a> {
);
match res_loaded {
Ok((module_id, msg)) => {
Ok(header_output) => {
if let Msg::Header(ModuleHeader {
module_id: header_id,
header_type,
is_root_module,
..
}) = &msg
}) = &header_output.msg
{
debug_assert_eq!(*header_id, module_id);
debug_assert_eq!(*header_id, header_output.module_id);
debug_assert!(is_root_module);
if let HeaderType::Interface { name, .. } = header_type {
@ -1327,7 +1332,7 @@ impl<'a> LoadStart<'a> {
}
}
(module_id, msg)
header_output
}
Err(LoadingProblem::ParsingFailed(problem)) => {
@ -1401,8 +1406,9 @@ impl<'a> LoadStart<'a> {
arc_modules,
ident_ids_by_module,
src_dir,
root_id,
root_msg,
root_id: header_output.module_id,
root_msg: header_output.msg,
opt_platform_shorthand: header_output.opt_platform_shorthand,
})
}
@ -1418,7 +1424,11 @@ 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_id, root_msg) = {
let HeaderOutput {
module_id: root_id,
msg: root_msg,
opt_platform_shorthand: opt_platform_id,
} = {
let root_start_time = Instant::now();
load_from_str(
@ -1438,6 +1448,7 @@ impl<'a> LoadStart<'a> {
ident_ids_by_module,
root_id,
root_msg,
opt_platform_shorthand: opt_platform_id,
})
}
}
@ -1581,6 +1592,7 @@ pub fn load_single_threaded<'a>(
root_id,
root_msg,
src_dir,
opt_platform_shorthand,
..
} = load_start;
@ -1593,6 +1605,7 @@ pub fn load_single_threaded<'a>(
let number_of_workers = 1;
let mut state = State::new(
root_id,
opt_platform_shorthand,
target_info,
exposed_types,
arc_modules,
@ -1851,6 +1864,7 @@ fn load_multi_threaded<'a>(
root_id,
root_msg,
src_dir,
opt_platform_shorthand,
..
} = load_start;
@ -1878,6 +1892,7 @@ fn load_multi_threaded<'a>(
let mut state = State::new(
root_id,
opt_platform_shorthand,
target_info,
exposed_types,
arc_modules,
@ -2360,8 +2375,6 @@ fn update<'a>(
provides,
..
} => {
debug_assert!(matches!(state.platform_data, None));
work.extend(state.dependencies.notify_package(config_shorthand));
let is_prebuilt = if header.is_root_module {
@ -2371,7 +2384,7 @@ fn update<'a>(
));
state.platform_path = PlatformPath::RootIsPlatformModule;
// If the root module is a platform, then the platform is the very
// If the root module is this platform, then the platform is the very
// thing we're rebuilding!
false
} else {
@ -2382,11 +2395,17 @@ fn update<'a>(
)
};
state.platform_data = Some(PlatformData {
module_id: header.module_id,
provides,
is_prebuilt,
});
// If we're building an app module, and this was the platform
// specified in its header's `to` field, record it as our platform.
if state.opt_platform_shorthand == Some(config_shorthand) {
debug_assert!(matches!(state.platform_data, None));
state.platform_data = Some(PlatformData {
module_id: header.module_id,
provides,
is_prebuilt,
});
}
}
Builtin { .. } | Interface { .. } => {
if header.is_root_module {
@ -3490,7 +3509,7 @@ fn load_module<'a>(
arc_shorthands: Arc<Mutex<MutMap<&'a str, ShorthandPath>>>,
roc_cache_dir: RocCacheDir<'_>,
ident_ids_by_module: SharedIdentIdsByModule,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
) -> Result<HeaderOutput<'a>, LoadingProblem<'a>> {
let module_start_time = Instant::now();
let parse_start = Instant::now();
@ -3507,14 +3526,16 @@ fn load_module<'a>(
match module_name.as_inner().as_str() {
$(
$name => {
return Ok(load_builtin_module(
let (module_id, msg) = load_builtin_module(
arena,
module_ids,
ident_ids_by_module,
module_timing,
$module_id,
concat!($name, ".roc")
));
);
return Ok(HeaderOutput { module_id, msg, opt_platform_shorthand: None });
}
)*
_ => { /* fall through */ }
@ -3693,6 +3714,14 @@ fn verify_interface_matches_file_path<'a>(
Err(problem)
}
#[derive(Debug)]
struct HeaderOutput<'a> {
module_id: ModuleId,
msg: Msg<'a>,
/// Only comes up if we're parsing an app module
opt_platform_shorthand: Option<&'a str>,
}
fn parse_header<'a>(
arena: &'a Bump,
read_file_duration: Duration,
@ -3705,7 +3734,7 @@ fn parse_header<'a>(
src_bytes: &'a [u8],
roc_cache_dir: RocCacheDir<'_>,
start_time: Instant,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
) -> Result<HeaderOutput<'a>, LoadingProblem<'a>> {
let parse_start = Instant::now();
let parse_state = roc_parse::state::State::new(src_bytes);
let parsed = roc_parse::module::parse_header(arena, parse_state.clone());
@ -3767,7 +3796,11 @@ fn parse_header<'a>(
}
}
Ok((module_id, Msg::Header(header)))
Ok(HeaderOutput {
module_id,
msg: Msg::Header(header),
opt_platform_shorthand: None,
})
}
Ok((
ast::Module {
@ -3798,7 +3831,11 @@ fn parse_header<'a>(
module_timing,
);
Ok((module_id, Msg::Header(header)))
Ok(HeaderOutput {
module_id,
msg: Msg::Header(header),
opt_platform_shorthand: None,
})
}
Ok((
ast::Module {
@ -3857,92 +3894,81 @@ fn parse_header<'a>(
);
let app_module_header_msg = Msg::Header(resolved_header);
// Look at the app module's `to` keyword to determine which package was the platform.
match header.provides.to.value {
To::ExistingPackage(existing_package) => {
let opt_base_package = packages.iter().find_map(|loc_package_entry| {
To::ExistingPackage(shorthand) => {
let package_path = packages.iter().find_map(|loc_package_entry| {
let Loc { value, .. } = loc_package_entry;
if value.shorthand == existing_package {
Some(value)
if value.shorthand == shorthand {
Some(value.package_name.value)
} else {
None
}
}).unwrap_or_else(|| {
todo!("Gracefully handle platform shorthand after `to` that didn't map to a shorthand specified in `packages`");
});
if let Some(PackageEntry {
shorthand,
package_name:
Loc {
value: package_path,
..
},
..
}) = opt_base_package
{
let src = package_path.to_str();
let src = package_path.to_str();
// check whether we can find a `platform` module file on disk
let platform_module_path = if src.starts_with("https://") {
#[cfg(not(target_family = "wasm"))]
{
// If this is a HTTPS package, synchronously download it
// to the cache before proceeding.
// check whether we can find a `platform` module file on disk
let platform_module_path = if src.starts_with("https://") {
#[cfg(not(target_family = "wasm"))]
{
// If this is a HTTPS package, synchronously download it
// to the cache before proceeding.
// TODO we should do this async; however, with the current
// architecture of file.rs (which doesn't use async/await),
// this would be very difficult!
let (package_dir, opt_root_module) = cache::install_package(
roc_cache_dir,
src,
)
.unwrap_or_else(|err| {
// TODO we should do this async; however, with the current
// architecture of file.rs (which doesn't use async/await),
// this would be very difficult!
let (package_dir, opt_root_module) =
cache::install_package(roc_cache_dir, src).unwrap_or_else(|err| {
todo!("TODO gracefully handle package install error {:?}", err);
});
// You can optionally specify the root module using the URL fragment,
// e.g. #foo.roc
// (defaults to main.roc)
match opt_root_module {
Some(root_module) => package_dir.join(root_module),
None => package_dir.join("main.roc"),
}
// You can optionally specify the root module using the URL fragment,
// e.g. #foo.roc
// (defaults to main.roc)
match opt_root_module {
Some(root_module) => package_dir.join(root_module),
None => package_dir.join("main.roc"),
}
#[cfg(target_family = "wasm")]
{
panic!(
"Specifying packages via URLs is curently unsupported in wasm."
);
}
} else {
app_file_dir.join(src)
};
if platform_module_path.as_path().exists() {
let load_platform_module_msg = load_platform_module(
arena,
&platform_module_path,
shorthand,
module_id,
module_ids,
ident_ids_by_module,
)?;
Ok((
module_id,
Msg::Many(vec![app_module_header_msg, load_platform_module_msg]),
))
} else {
Err(LoadingProblem::FileProblem {
filename: platform_module_path,
error: io::ErrorKind::NotFound,
})
}
#[cfg(target_family = "wasm")]
{
panic!("Specifying packages via URLs is curently unsupported in wasm.");
}
} else {
panic!("could not find base")
app_file_dir.join(src)
};
if platform_module_path.as_path().exists() {
let load_platform_module_msg = load_platform_module(
arena,
&platform_module_path,
shorthand,
module_id,
module_ids,
ident_ids_by_module,
)?;
Ok(HeaderOutput {
module_id,
msg: Msg::Many(vec![app_module_header_msg, load_platform_module_msg]),
opt_platform_shorthand: Some(shorthand),
})
} else {
Err(LoadingProblem::FileProblem {
filename: platform_module_path,
error: io::ErrorKind::NotFound,
})
}
}
To::NewPackage(_package_name) => Ok((module_id, app_module_header_msg)),
To::NewPackage(_package_name) => Ok(HeaderOutput {
module_id,
msg: app_module_header_msg,
opt_platform_shorthand: None,
}),
}
}
Ok((
@ -3964,9 +3990,12 @@ fn parse_header<'a>(
module_timing,
);
Ok((module_id, Msg::Header(header)))
Ok(HeaderOutput {
module_id,
msg: Msg::Header(header),
opt_platform_shorthand: None,
})
}
Err(fail) => Err(LoadingProblem::ParsingFailed(
fail.map_problem(SyntaxError::Header)
.into_file_error(filename),
@ -3985,7 +4014,7 @@ fn load_filename<'a>(
ident_ids_by_module: SharedIdentIdsByModule,
roc_cache_dir: RocCacheDir<'_>,
module_start_time: Instant,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
) -> Result<HeaderOutput<'a>, LoadingProblem<'a>> {
let file_io_start = Instant::now();
let file = fs::read(&filename);
let file_io_duration = file_io_start.elapsed();
@ -4021,7 +4050,7 @@ fn load_from_str<'a>(
ident_ids_by_module: SharedIdentIdsByModule,
roc_cache_dir: RocCacheDir<'_>,
module_start_time: Instant,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
) -> Result<HeaderOutput<'a>, LoadingProblem<'a>> {
let file_io_start = Instant::now();
let file_io_duration = file_io_start.elapsed();
@ -5822,7 +5851,7 @@ fn run_task<'a>(
roc_cache_dir,
ident_ids_by_module,
)
.map(|(_, msg)| msg),
.map(|HeaderOutput { msg, .. }| msg),
Parse { header } => parse(arena, header),
CanonicalizeAndConstrain {
parsed,