From 5b521dccf4b5754ea4cbb989c5dfce3f3e96a9c3 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 8 Dec 2020 21:12:36 +0100 Subject: [PATCH 01/10] make Pkg-Config into a module --- compiler/load/src/file.rs | 82 ++++++++++++++++++++++----- examples/task/platform/Pkg-Config.roc | 2 +- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 3e66211586..7e385b6250 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -1933,10 +1933,14 @@ fn load_pkg_config<'a>( let parse_header_duration = parse_start.elapsed().unwrap(); // Insert the first entries for this module's timings - let mut module_timing = ModuleTiming::new(module_start_time); + let mut pkg_module_timing = ModuleTiming::new(module_start_time); + let mut effect_module_timing = ModuleTiming::new(module_start_time); - module_timing.read_roc_file = file_io_duration; - module_timing.parse_header = parse_header_duration; + pkg_module_timing.read_roc_file = file_io_duration; + pkg_module_timing.parse_header = parse_header_duration; + + effect_module_timing.read_roc_file = file_io_duration; + effect_module_timing.parse_header = parse_header_duration; match parsed { Ok((ast::Module::Interface { header }, _parse_state)) => { @@ -1951,16 +1955,34 @@ fn load_pkg_config<'a>( header ))) } - Ok((ast::Module::Platform { header }, _parse_state)) => fabricate_effects_module( - arena, - shorthand, - module_ids, - ident_ids_by_module, - mode, - header, - module_timing, - ) - .map(|x| x.1), + Ok((ast::Module::Platform { header }, parser_state)) => { + // make a Pkg-Config module that ultimately exposes `main` to the host + let pkg_config_module_msg = fabricate_pkg_config_module( + arena, + shorthand, + filename, + parser_state, + module_ids.clone(), + ident_ids_by_module.clone(), + mode, + &header, + pkg_module_timing, + ) + .map(|x| x.1)?; + + let effects_module_msg = fabricate_effects_module( + arena, + shorthand, + module_ids, + ident_ids_by_module, + mode, + header, + effect_module_timing, + ) + .map(|x| x.1)?; + + Ok(Msg::Many(vec![effects_module_msg, pkg_config_module_msg])) + } Err((fail, _)) => Err(LoadingProblem::ParsingFailed { filename, fail }), } } @@ -2572,6 +2594,40 @@ fn run_solve<'a>( } } +#[allow(clippy::too_many_arguments)] +fn fabricate_pkg_config_module<'a>( + arena: &'a Bump, + shorthand: &'a str, + filename: PathBuf, + parse_state: parser::State<'a>, + module_ids: Arc>>, + ident_ids_by_module: Arc>>, + mode: Mode, + header: &PlatformHeader<'a>, + module_timing: ModuleTiming, +) -> Result<(ModuleId, Msg<'a>), LoadingProblem> { + let name = format!("{}.Pkg-Config", shorthand); + Ok(send_header( + Located { + region: header.name.region, + value: AppOrInterfaceName::Interface(roc_parse::header::ModuleName::new( + arena.alloc(name), + )), + }, + filename, + Some(shorthand), + &[], + // header.exposes.into_bump_slice(), + &[], + header.imports.clone().into_bump_slice(), + None, + parse_state, + module_ids, + ident_ids_by_module, + module_timing, + )) +} + #[allow(clippy::too_many_arguments)] fn fabricate_effects_module<'a>( arena: &'a Bump, diff --git a/examples/task/platform/Pkg-Config.roc b/examples/task/platform/Pkg-Config.roc index f77e395adb..3a5ed270c9 100644 --- a/examples/task/platform/Pkg-Config.roc +++ b/examples/task/platform/Pkg-Config.roc @@ -2,7 +2,7 @@ platform folkertdev/foo requires { main : Effect {} } exposes [] packages {} - imports [ File ] + imports [ ] provides [ mainForHost ] effects Effect { From 4b665639ffea3cdf7848ff8a2ce14d63f42708c8 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 8 Dec 2020 21:39:30 +0100 Subject: [PATCH 02/10] special-case the PkgConfig --- compiler/load/src/file.rs | 213 +++++++++++++++++++++++--- examples/task/platform/Pkg-Config.roc | 6 +- 2 files changed, 195 insertions(+), 24 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 7e385b6250..570341ac5d 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -551,7 +551,7 @@ pub enum BuildProblem<'a> { #[derive(Debug)] struct ModuleHeader<'a> { module_id: ModuleId, - module_name: AppOrInterfaceName<'a>, + module_name: ModuleNameEnum<'a>, module_path: PathBuf, exposed_ident_ids: IdentIds, deps_by_name: MutMap, ModuleId>, @@ -620,7 +620,7 @@ pub struct VariablySizedLayouts<'a> { #[derive(Debug)] struct ParsedModule<'a> { module_id: ModuleId, - module_name: AppOrInterfaceName<'a>, + module_name: ModuleNameEnum<'a>, module_path: PathBuf, src: &'a str, module_timing: ModuleTiming, @@ -1478,7 +1478,8 @@ fn update<'a>( // // e.g. for `app "blah"` we should generate an output file named "blah" match &parsed.module_name { - AppOrInterfaceName::App(output_str) => match output_str { + ModuleNameEnum::PkgConfig(_) => {} + ModuleNameEnum::App(output_str) => match output_str { StrLiteral::PlainLine(path) => { state.output_path = Some(path); } @@ -1486,7 +1487,7 @@ fn update<'a>( todo!("TODO gracefully handle a malformed string literal after `app` keyword."); } }, - AppOrInterfaceName::Interface(_) => {} + ModuleNameEnum::Interface(_) => {} } let module_id = parsed.module_id; @@ -2108,7 +2109,7 @@ fn parse_header<'a>( Ok((ast::Module::Interface { header }, parse_state)) => Ok(send_header( Located { region: header.name.region, - value: AppOrInterfaceName::Interface(header.name.value), + value: ModuleNameEnum::Interface(header.name.value), }, filename, opt_shorthand, @@ -2130,7 +2131,7 @@ fn parse_header<'a>( let (module_id, app_module_header_msg) = send_header( Located { region: header.name.region, - value: AppOrInterfaceName::App(header.name.value), + value: ModuleNameEnum::App(header.name.value), }, filename, opt_shorthand, @@ -2294,15 +2295,16 @@ fn load_from_str<'a>( } #[derive(Debug)] -enum AppOrInterfaceName<'a> { +enum ModuleNameEnum<'a> { /// A filename App(StrLiteral<'a>), Interface(roc_parse::header::ModuleName<'a>), + PkgConfig(&'a str), } #[allow(clippy::too_many_arguments)] fn send_header<'a>( - loc_name: Located>, + loc_name: Located>, filename: PathBuf, opt_shorthand: Option<&'a str>, packages: &'a [Located>], @@ -2314,9 +2316,10 @@ fn send_header<'a>( ident_ids_by_module: Arc>>, module_timing: ModuleTiming, ) -> (ModuleId, Msg<'a>) { - use AppOrInterfaceName::*; + use ModuleNameEnum::*; let declared_name: ModuleName = match &loc_name.value { + PkgConfig(_) => unreachable!(), App(_) => ModuleName::APP.into(), Interface(module_name) => { // TODO check to see if module_name is consistent with filename. @@ -2483,6 +2486,176 @@ fn send_header<'a>( ) } +#[allow(clippy::too_many_arguments)] +fn send_header_two<'a>( + filename: PathBuf, + shorthand: &'a str, + packages: &'a [Located>], + provides: &'a [Located>], + imports: &'a [Located>], + to_platform: Option>, + parse_state: parser::State<'a>, + module_ids: Arc>>, + ident_ids_by_module: Arc>>, + module_timing: ModuleTiming, +) -> (ModuleId, Msg<'a>) { + use inlinable_string::InlinableString; + + let declared_name: InlinableString = "Pkg-Config".into(); + + let mut imported: Vec<(QualifiedModuleName, Vec, Region)> = + Vec::with_capacity(imports.len()); + let mut imported_modules: MutSet = MutSet::default(); + + // add standard imports + // imported_modules.insert(ModuleId::APP); + // imported_modules.insert(ModuleId::EFFECT); + + let mut scope_size = 0; + + for loc_entry in imports { + let (qualified_module_name, exposed) = exposed_from_import(&loc_entry.value); + + scope_size += exposed.len(); + + imported.push((qualified_module_name, exposed, loc_entry.region)); + } + + let num_exposes = provides.len(); + let mut deps_by_name: MutMap = + HashMap::with_capacity_and_hasher(num_exposes, default_hasher()); + let mut exposed: Vec = Vec::with_capacity(num_exposes); + + // Make sure the module_ids has ModuleIds for all our deps, + // then record those ModuleIds in can_module_ids for later. + let mut scope: MutMap = + HashMap::with_capacity_and_hasher(scope_size, default_hasher()); + let home: ModuleId; + + let ident_ids = { + // Lock just long enough to perform the minimal operations necessary. + let mut module_ids = (*module_ids).lock(); + let mut ident_ids_by_module = (*ident_ids_by_module).lock(); + + let name = PQModuleName::Qualified(&shorthand, declared_name); + home = module_ids.get_or_insert(&name); + + // Ensure this module has an entry in the exposed_ident_ids map. + ident_ids_by_module + .entry(home) + .or_insert_with(IdentIds::default); + + // For each of our imports, add an entry to deps_by_name + // + // e.g. for `imports [ base.Foo.{ bar } ]`, add `Foo` to deps_by_name + // + // Also build a list of imported_values_to_expose (like `bar` above.) + for (qualified_module_name, exposed_idents, region) in imported.into_iter() { + let cloned_module_name = qualified_module_name.module.clone(); + let pq_module_name = match qualified_module_name.opt_package { + None => PQModuleName::Qualified(shorthand, qualified_module_name.module.into()), + Some(package) => { + PQModuleName::Qualified(package, cloned_module_name.clone().into()) + } + }; + + let module_id = module_ids.get_or_insert(&pq_module_name); + imported_modules.insert(module_id); + + deps_by_name.insert(pq_module_name, module_id); + + // Add the new exposed idents to the dep module's IdentIds, so + // once that module later gets loaded, its lookups will resolve + // to the same symbols as the ones we're using here. + let ident_ids = ident_ids_by_module + .entry(module_id) + .or_insert_with(IdentIds::default); + + for ident in exposed_idents { + let ident_id = ident_ids.get_or_insert(ident.as_inline_str()); + let symbol = Symbol::new(module_id, ident_id); + + // Since this value is exposed, add it to our module's default scope. + debug_assert!(!scope.contains_key(&ident.clone())); + + scope.insert(ident, (symbol, region)); + } + } + + let ident_ids = ident_ids_by_module.get_mut(&home).unwrap(); + + // Generate IdentIds entries for all values this module exposes. + // This way, when we encounter them in Defs later, they already + // have an IdentIds entry. + // + // We must *not* add them to scope yet, or else the Defs will + // incorrectly think they're shadowing them! + for loc_exposed in provides.iter() { + // Use get_or_insert here because the ident_ids may already + // created an IdentId for this, when it was imported exposed + // in a dependent module. + // + // For example, if module A has [ B.{ foo } ], then + // when we get here for B, `foo` will already have + // an IdentId. We must reuse that! + let ident_id = ident_ids.get_or_insert(&loc_exposed.value.as_str().into()); + let symbol = Symbol::new(home, ident_id); + + exposed.push(symbol); + } + + if cfg!(debug_assertions) { + home.register_debug_idents(&ident_ids); + } + + ident_ids.clone() + }; + + let mut parse_entries: Vec<_> = (&packages).iter().map(|x| &x.value).collect(); + let mut package_entries = MutMap::default(); + + while let Some(parse_entry) = parse_entries.pop() { + use PackageEntry::*; + match parse_entry { + Entry { + shorthand, + package_or_path, + .. + } => { + package_entries.insert(*shorthand, package_or_path.value.clone()); + } + SpaceBefore(inner, _) | SpaceAfter(inner, _) => { + parse_entries.push(inner); + } + } + } + + // Send the deps to the coordinator thread for processing, + // then continue on to parsing and canonicalizing defs. + // + // We always need to send these, even if deps is empty, + // because the coordinator thread needs to receive this message + // to decrement its "pending" count. + let module_name = ModuleNameEnum::PkgConfig(shorthand); + ( + home, + Msg::Header(ModuleHeader { + module_id: home, + module_path: filename, + exposed_ident_ids: ident_ids, + module_name, + packages: package_entries, + imported_modules, + deps_by_name, + exposes: exposed, + to_platform, + src: parse_state.bytes, + exposed_imports: scope, + module_timing, + }), + ) +} + impl<'a> BuildTask<'a> { // TODO trim down these arguments - possibly by moving Constraint into Module #[allow(clippy::too_many_arguments)] @@ -2607,18 +2780,15 @@ fn fabricate_pkg_config_module<'a>( module_timing: ModuleTiming, ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> { let name = format!("{}.Pkg-Config", shorthand); - Ok(send_header( - Located { - region: header.name.region, - value: AppOrInterfaceName::Interface(roc_parse::header::ModuleName::new( - arena.alloc(name), - )), - }, + + let provides: &'a [Located>] = + header.provides.clone().into_bump_slice(); + + Ok(send_header_two( filename, - Some(shorthand), - &[], - // header.exposes.into_bump_slice(), + shorthand, &[], + provides, header.imports.clone().into_bump_slice(), None, parse_state, @@ -2931,8 +3101,9 @@ fn canonicalize_and_constrain<'a>( // Generate documentation information // TODO: store timing information? let module_docs = match module_name { - AppOrInterfaceName::App(_) => None, - AppOrInterfaceName::Interface(name) => Some(crate::docs::generate_module_docs( + ModuleNameEnum::PkgConfig(_) => None, + ModuleNameEnum::App(_) => None, + ModuleNameEnum::Interface(name) => Some(crate::docs::generate_module_docs( name.as_str().into(), &exposed_ident_ids, &parsed_defs, diff --git a/examples/task/platform/Pkg-Config.roc b/examples/task/platform/Pkg-Config.roc index 3a5ed270c9..af963e5cbd 100644 --- a/examples/task/platform/Pkg-Config.roc +++ b/examples/task/platform/Pkg-Config.roc @@ -2,7 +2,7 @@ platform folkertdev/foo requires { main : Effect {} } exposes [] packages {} - imports [ ] + imports [ Effect ] provides [ mainForHost ] effects Effect { @@ -10,5 +10,5 @@ platform folkertdev/foo readAllUtf8 : Str -> Effect { errno : I64, bytes : Str } } -mainForHost : Effect {} as Fx -mainForHost = main +mainForHost : Effect.Effect {} as Fx +mainForHost = UserApp.main From 3969a7327788ca7514aa7b496cf0f600bbedf7d8 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 8 Dec 2020 22:58:30 +0100 Subject: [PATCH 03/10] make Pkg-Config work as a module --- compiler/load/src/file.rs | 88 +++++++++++++++------------ examples/task/Main.roc | 2 +- examples/task/platform/Pkg-Config.roc | 6 +- examples/task/platform/host.zig | 16 ++--- 4 files changed, 62 insertions(+), 50 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 570341ac5d..2cfe40f489 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -690,6 +690,7 @@ enum Msg<'a> { #[derive(Debug)] struct State<'a> { pub root_id: ModuleId, + pub platform_id: Option, pub goal_phase: Phase, pub stdlib: StdLib, pub exposed_types: SubsByModule, @@ -844,12 +845,6 @@ enum BuildTask<'a> { ident_ids_by_module: Arc>>, mode: Mode, }, - LoadPkgConfig { - shorthand: &'a str, - module_ids: Arc>>, - ident_ids_by_module: Arc>>, - mode: Mode, - }, Parse { header: ModuleHeader<'a>, }, @@ -1272,6 +1267,7 @@ where let mut state = State { root_id, + platform_id: None, goal_phase, stdlib, output_path: None, @@ -1426,6 +1422,10 @@ fn update<'a>( } } + if let ModuleNameEnum::PkgConfig(_shorthand) = header.module_name { + state.platform_id = Some(header.module_id); + } + state.platform_path = state.platform_path.or_else(|| header.to_platform.clone()); // store an ID to name mapping, so we know the file to read when fetching dependencies' headers @@ -1603,7 +1603,7 @@ fn update<'a>( let work = state.dependencies.notify(module_id, Phase::SolveTypes); - if module_id == state.root_id { + if Some(module_id) == state.platform_id { state .exposed_to_host .extend(solved_module.exposed_vars_by_symbol.iter().copied()); @@ -1638,15 +1638,10 @@ fn update<'a>( // the originally requested module, we're all done! return Ok(state); } else { - if module_id != state.root_id { - state.exposed_types.insert( - module_id, - ExposedModuleTypes::Valid( - solved_module.solved_types, - solved_module.aliases, - ), - ); - } + state.exposed_types.insert( + module_id, + ExposedModuleTypes::Valid(solved_module.solved_types, solved_module.aliases), + ); if state.goal_phase > Phase::SolveTypes { let layout_cache = state.layout_caches.pop().unwrap_or_default(); @@ -1914,6 +1909,7 @@ fn load_pkg_config<'a>( arena: &'a Bump, src_dir: &Path, shorthand: &'a str, + app_module_id: ModuleId, module_ids: Arc>>, ident_ids_by_module: Arc>>, mode: Mode, @@ -1961,6 +1957,7 @@ fn load_pkg_config<'a>( let pkg_config_module_msg = fabricate_pkg_config_module( arena, shorthand, + app_module_id, filename, parser_state, module_ids.clone(), @@ -2183,6 +2180,7 @@ fn parse_header<'a>( arena, &pkg_config_roc, shorthand, + module_id, module_ids, ident_ids_by_module, mode, @@ -2488,10 +2486,13 @@ fn send_header<'a>( #[allow(clippy::too_many_arguments)] fn send_header_two<'a>( + arena: &'a Bump, filename: PathBuf, shorthand: &'a str, + app_module_id: ModuleId, packages: &'a [Located>], provides: &'a [Located>], + requires: &'a [Located>], imports: &'a [Located>], to_platform: Option>, parse_state: parser::State<'a>, @@ -2501,15 +2502,23 @@ fn send_header_two<'a>( ) -> (ModuleId, Msg<'a>) { use inlinable_string::InlinableString; - let declared_name: InlinableString = "Pkg-Config".into(); + let declared_name: InlinableString = "".into(); let mut imported: Vec<(QualifiedModuleName, Vec, Region)> = Vec::with_capacity(imports.len()); let mut imported_modules: MutSet = MutSet::default(); + let num_exposes = provides.len(); + let mut deps_by_name: MutMap = + HashMap::with_capacity_and_hasher(num_exposes, default_hasher()); + // add standard imports - // imported_modules.insert(ModuleId::APP); - // imported_modules.insert(ModuleId::EFFECT); + // TODO add Effect by default + imported_modules.insert(app_module_id); + deps_by_name.insert( + PQModuleName::Unqualified(ModuleName::APP.into()), + app_module_id, + ); let mut scope_size = 0; @@ -2521,9 +2530,6 @@ fn send_header_two<'a>( imported.push((qualified_module_name, exposed, loc_entry.region)); } - let num_exposes = provides.len(); - let mut deps_by_name: MutMap = - HashMap::with_capacity_and_hasher(num_exposes, default_hasher()); let mut exposed: Vec = Vec::with_capacity(num_exposes); // Make sure the module_ids has ModuleIds for all our deps, @@ -2582,6 +2588,23 @@ fn send_header_two<'a>( } } + { + let ident_ids = ident_ids_by_module + .entry(app_module_id) + .or_insert_with(IdentIds::default); + + for (loc_ident, _) in unpack_exposes_entries(arena, requires) { + let ident: Ident = loc_ident.value.into(); + let ident_id = ident_ids.get_or_insert(ident.as_inline_str()); + let symbol = Symbol::new(app_module_id, ident_id); + + // Since this value is exposed, add it to our module's default scope. + debug_assert!(!scope.contains_key(&ident.clone())); + + scope.insert(ident, (symbol, loc_ident.region)); + } + } + let ident_ids = ident_ids_by_module.get_mut(&home).unwrap(); // Generate IdentIds entries for all values this module exposes. @@ -2771,24 +2794,26 @@ fn run_solve<'a>( fn fabricate_pkg_config_module<'a>( arena: &'a Bump, shorthand: &'a str, + app_module_id: ModuleId, filename: PathBuf, parse_state: parser::State<'a>, module_ids: Arc>>, ident_ids_by_module: Arc>>, - mode: Mode, + _mode: Mode, header: &PlatformHeader<'a>, module_timing: ModuleTiming, ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> { - let name = format!("{}.Pkg-Config", shorthand); - let provides: &'a [Located>] = header.provides.clone().into_bump_slice(); Ok(send_header_two( + arena, filename, shorthand, + app_module_id, &[], provides, + header.requires.clone().into_bump_slice(), header.imports.clone().into_bump_slice(), None, parse_state, @@ -3545,19 +3570,6 @@ fn run_task<'a>( mode, ) .map(|(_, msg)| msg), - LoadPkgConfig { - shorthand, - module_ids, - ident_ids_by_module, - mode, - } => load_pkg_config( - arena, - src_dir, - shorthand, - module_ids, - ident_ids_by_module, - mode, - ), Parse { header } => parse(arena, header), CanonicalizeAndConstrain { parsed, diff --git a/examples/task/Main.roc b/examples/task/Main.roc index f0f346d294..6ab3406342 100644 --- a/examples/task/Main.roc +++ b/examples/task/Main.roc @@ -3,6 +3,6 @@ app "effect-example" imports [ base.Task.{ Task, after } ] provides [ main ] to base -main : Task.Task {} I64 as Fx +main : Task.Task {} I64 main = Task.succeed {} diff --git a/examples/task/platform/Pkg-Config.roc b/examples/task/platform/Pkg-Config.roc index af963e5cbd..23d36a3455 100644 --- a/examples/task/platform/Pkg-Config.roc +++ b/examples/task/platform/Pkg-Config.roc @@ -2,7 +2,7 @@ platform folkertdev/foo requires { main : Effect {} } exposes [] packages {} - imports [ Effect ] + imports [ Task ] provides [ mainForHost ] effects Effect { @@ -10,5 +10,5 @@ platform folkertdev/foo readAllUtf8 : Str -> Effect { errno : I64, bytes : Str } } -mainForHost : Effect.Effect {} as Fx -mainForHost = UserApp.main +mainForHost : Task.Task {} I64 as Fx +mainForHost = main diff --git a/examples/task/platform/host.zig b/examples/task/platform/host.zig index 5de36ec6b3..682fe07296 100644 --- a/examples/task/platform/host.zig +++ b/examples/task/platform/host.zig @@ -2,15 +2,15 @@ const std = @import("std"); const str = @import("../../../compiler/builtins/bitcode/src/str.zig"); const testing = std.testing; -extern fn roc__main_1_exposed([*]u8) void; -extern fn roc__main_1_size() i64; -extern fn roc__main_1_Fx_caller(*const u8, [*]u8, [*]u8) void; -extern fn roc__main_1_Fx_size() i64; +extern fn roc__mainForHost_1_exposed([*]u8) void; +extern fn roc__mainForHost_1_size() i64; +extern fn roc__mainForHost_1_Fx_caller(*const u8, [*]u8, [*]u8) void; +extern fn roc__mainForHost_1_Fx_size() i64; pub export fn main() u8 { const stdout = std.io.getStdOut().writer(); - const size = @intCast(usize, roc__main_1_size()); + const size = @intCast(usize, roc__mainForHost_1_size()); const raw_output = std.heap.c_allocator.alloc(u8, size) catch unreachable; var output = @ptrCast([*]u8, raw_output); @@ -18,7 +18,7 @@ pub export fn main() u8 { std.heap.c_allocator.free(raw_output); } - roc__main_1_exposed(output); + roc__mainForHost_1_exposed(output); const elements = @ptrCast([*]u64, @alignCast(8, output)); @@ -38,7 +38,7 @@ pub export fn main() u8 { } fn call_the_closure(function_pointer: *const u8, closure_data_pointer: [*]u8) void { - const size = roc__main_1_Fx_size(); + const size = roc__mainForHost_1_Fx_size(); const raw_output = std.heap.c_allocator.alloc(u8, @intCast(usize, size)) catch unreachable; var output = @ptrCast([*]u8, raw_output); @@ -46,7 +46,7 @@ fn call_the_closure(function_pointer: *const u8, closure_data_pointer: [*]u8) vo std.heap.c_allocator.free(raw_output); } - roc__main_1_Fx_caller(function_pointer, closure_data_pointer, output); + roc__mainForHost_1_Fx_caller(function_pointer, closure_data_pointer, output); const elements = @ptrCast([*]u64, @alignCast(8, output)); From 89a1237b063cef7b310be109f3ed6c316257a11b Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 8 Dec 2020 23:27:25 +0100 Subject: [PATCH 04/10] refactor --- compiler/load/src/file.rs | 100 +++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 2cfe40f489..0d39c807a3 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -559,11 +559,17 @@ struct ModuleHeader<'a> { imported_modules: MutSet, exposes: Vec, exposed_imports: MutMap, - to_platform: Option>, src: &'a [u8], module_timing: ModuleTiming, } +#[derive(Debug)] +enum ModuleHeaderExtra<'a> { + HeaderForApp { to_platform: To<'a> }, + HeaderForPkgConfig, + HeaderForInterface, +} + #[derive(Debug)] struct ConstrainedModule { module: Module, @@ -634,7 +640,7 @@ struct ParsedModule<'a> { #[derive(Debug)] enum Msg<'a> { Many(Vec>), - Header(ModuleHeader<'a>), + Header(ModuleHeader<'a>, ModuleHeaderExtra<'a>), Parsed(ParsedModule<'a>), CanonicalizedAndConstrained { constrained_module: ConstrainedModule, @@ -1410,7 +1416,7 @@ fn update<'a>( Ok(state) } - Header(header) => { + Header(header, header_extra) => { log!("loaded header for {:?}", header.module_id); let home = header.module_id; @@ -1422,11 +1428,20 @@ fn update<'a>( } } - if let ModuleNameEnum::PkgConfig(_shorthand) = header.module_name { - state.platform_id = Some(header.module_id); - } + use ModuleHeaderExtra::*; + match header_extra { + HeaderForApp { to_platform } => { + debug_assert_eq!(state.platform_path, None); - state.platform_path = state.platform_path.or_else(|| header.to_platform.clone()); + state.platform_path = Some(to_platform.clone()); + } + HeaderForPkgConfig => { + debug_assert_eq!(state.platform_id, None); + + state.platform_id = Some(header.module_id); + } + HeaderForInterface => {} + } // store an ID to name mapping, so we know the file to read when fetching dependencies' headers for (name, id) in header.deps_by_name.iter() { @@ -1962,7 +1977,6 @@ fn load_pkg_config<'a>( parser_state, module_ids.clone(), ident_ids_by_module.clone(), - mode, &header, pkg_module_timing, ) @@ -2465,22 +2479,29 @@ fn send_header<'a>( // We always need to send these, even if deps is empty, // because the coordinator thread needs to receive this message // to decrement its "pending" count. + let extra = match to_platform { + Some(to_platform) => ModuleHeaderExtra::HeaderForApp { to_platform }, + None => ModuleHeaderExtra::HeaderForInterface, + }; + ( home, - Msg::Header(ModuleHeader { - module_id: home, - module_path: filename, - exposed_ident_ids: ident_ids, - module_name: loc_name.value, - packages: package_entries, - imported_modules, - deps_by_name, - exposes: exposed, - to_platform, - src: parse_state.bytes, - exposed_imports: scope, - module_timing, - }), + Msg::Header( + ModuleHeader { + module_id: home, + module_path: filename, + exposed_ident_ids: ident_ids, + module_name: loc_name.value, + packages: package_entries, + imported_modules, + deps_by_name, + exposes: exposed, + src: parse_state.bytes, + exposed_imports: scope, + module_timing, + }, + extra, + ), ) } @@ -2494,7 +2515,6 @@ fn send_header_two<'a>( provides: &'a [Located>], requires: &'a [Located>], imports: &'a [Located>], - to_platform: Option>, parse_state: parser::State<'a>, module_ids: Arc>>, ident_ids_by_module: Arc>>, @@ -2660,22 +2680,26 @@ fn send_header_two<'a>( // because the coordinator thread needs to receive this message // to decrement its "pending" count. let module_name = ModuleNameEnum::PkgConfig(shorthand); + + let extra = ModuleHeaderExtra::HeaderForPkgConfig; ( home, - Msg::Header(ModuleHeader { - module_id: home, - module_path: filename, - exposed_ident_ids: ident_ids, - module_name, - packages: package_entries, - imported_modules, - deps_by_name, - exposes: exposed, - to_platform, - src: parse_state.bytes, - exposed_imports: scope, - module_timing, - }), + Msg::Header( + ModuleHeader { + module_id: home, + module_path: filename, + exposed_ident_ids: ident_ids, + module_name, + packages: package_entries, + imported_modules, + deps_by_name, + exposes: exposed, + src: parse_state.bytes, + exposed_imports: scope, + module_timing, + }, + extra, + ), ) } @@ -2799,7 +2823,6 @@ fn fabricate_pkg_config_module<'a>( parse_state: parser::State<'a>, module_ids: Arc>>, ident_ids_by_module: Arc>>, - _mode: Mode, header: &PlatformHeader<'a>, module_timing: ModuleTiming, ) -> Result<(ModuleId, Msg<'a>), LoadingProblem> { @@ -2815,7 +2838,6 @@ fn fabricate_pkg_config_module<'a>( provides, header.requires.clone().into_bump_slice(), header.imports.clone().into_bump_slice(), - None, parse_state, module_ids, ident_ids_by_module, From f4d22634706792bd57c3ab5cf37ea73a4396f568 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 8 Dec 2020 23:32:07 +0100 Subject: [PATCH 05/10] update examples/effect --- examples/effect/Main.roc | 2 +- examples/effect/thing/platform-dir/Pkg-Config.roc | 8 ++++---- examples/effect/thing/platform-dir/src/lib.rs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/effect/Main.roc b/examples/effect/Main.roc index 04d804618a..29ed6eddd3 100644 --- a/examples/effect/Main.roc +++ b/examples/effect/Main.roc @@ -6,7 +6,7 @@ app "effect-example" # TODO `main : Task {}` does not work # it will then think that the `Task` module is unused # (if we also don't use any of the other importd symbols) -main : Task.Task {} as Fx +main : Task.Task {} main = when if 1 == 1 then True 3 else False 3.14 is True n -> Task.putLine (Str.fromInt n) diff --git a/examples/effect/thing/platform-dir/Pkg-Config.roc b/examples/effect/thing/platform-dir/Pkg-Config.roc index 78afc1799e..a1c06153f1 100644 --- a/examples/effect/thing/platform-dir/Pkg-Config.roc +++ b/examples/effect/thing/platform-dir/Pkg-Config.roc @@ -1,15 +1,15 @@ platform folkertdev/foo requires { main : Effect {} } - exposes [ Task ] + exposes [] packages {} - imports [] + imports [Effect] provides [ mainForHost ] effects Effect { - putChar : Int -> Effect {}, + putChar : I64 -> Effect {}, putLine : Str -> Effect {}, getLine : Effect Str } -mainForHost : Effect {} as Fx +mainForHost : Effect.Effect {} as Fx mainForHost = main diff --git a/examples/effect/thing/platform-dir/src/lib.rs b/examples/effect/thing/platform-dir/src/lib.rs index 216595ca4c..905bf7113e 100644 --- a/examples/effect/thing/platform-dir/src/lib.rs +++ b/examples/effect/thing/platform-dir/src/lib.rs @@ -7,16 +7,16 @@ use std::alloc::Layout; use std::time::SystemTime; extern "C" { - #[link_name = "roc__main_1_exposed"] + #[link_name = "roc__mainForHost_1_exposed"] fn roc_main(output: *mut u8) -> (); - #[link_name = "roc__main_1_size"] + #[link_name = "roc__mainForHost_1_size"] fn roc_main_size() -> i64; - #[link_name = "roc__main_1_Fx_caller"] + #[link_name = "roc__mainForHost_1_Fx_caller"] fn call_Fx(function_pointer: *const u8, closure_data: *const u8, output: *mut u8) -> (); - #[link_name = "roc__main_1_Fx_size"] + #[link_name = "roc__mainForHost_1_Fx_size"] fn size_Fx() -> i64; } From 0367a2c939ada0dac305a71bd719363174ba2608 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 8 Dec 2020 23:35:41 +0100 Subject: [PATCH 06/10] update hello-world --- examples/hello-world/Hello.roc | 5 ++++- examples/hello-world/platform/Pkg-Config.roc | 5 ++++- examples/hello-world/platform/src/lib.rs | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/hello-world/Hello.roc b/examples/hello-world/Hello.roc index d19e681b48..24a02e7823 100644 --- a/examples/hello-world/Hello.roc +++ b/examples/hello-world/Hello.roc @@ -1,4 +1,7 @@ -app "hello-world" provides [ main ] to "./platform" +app "hello-world" + packages { base: "platform" } + imports [] + provides [ main ] to base greeting = hi = "Hello" diff --git a/examples/hello-world/platform/Pkg-Config.roc b/examples/hello-world/platform/Pkg-Config.roc index 0f5b87c117..90505433fc 100644 --- a/examples/hello-world/platform/Pkg-Config.roc +++ b/examples/hello-world/platform/Pkg-Config.roc @@ -3,5 +3,8 @@ platform examples/hello-world exposes [] packages {} imports [] - provides [ main ] + provides [ mainForHost ] effects Effect {} + +mainForHost : Str +mainForHost = main diff --git a/examples/hello-world/platform/src/lib.rs b/examples/hello-world/platform/src/lib.rs index 4d390b0560..c6a68ca745 100644 --- a/examples/hello-world/platform/src/lib.rs +++ b/examples/hello-world/platform/src/lib.rs @@ -3,7 +3,7 @@ use roc_std::RocStr; use std::str; extern "C" { - #[link_name = "roc__main_1_exposed"] + #[link_name = "roc__mainForHost_1_exposed"] fn say_hello(output: &mut RocCallResult) -> (); } From b8108a4d06d317ed50749b6b3ba771f2a0bbe94f Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 9 Dec 2020 01:16:51 +0100 Subject: [PATCH 07/10] remove the multi-module example; we have other test cases for this --- examples/multi-module/.gitignore | 1 - examples/multi-module/Quicksort.roc | 47 ----------------- examples/multi-module/Utils.roc | 12 ----- examples/multi-module/platform/Cargo.lock | 23 --------- examples/multi-module/platform/Cargo.toml | 13 ----- examples/multi-module/platform/Pkg-Config.roc | 7 --- examples/multi-module/platform/README.md | 8 --- examples/multi-module/platform/build.sh | 12 ----- examples/multi-module/platform/host.c | 7 --- examples/multi-module/platform/src/lib.rs | 51 ------------------- 10 files changed, 181 deletions(-) delete mode 100644 examples/multi-module/.gitignore delete mode 100644 examples/multi-module/Quicksort.roc delete mode 100644 examples/multi-module/Utils.roc delete mode 100644 examples/multi-module/platform/Cargo.lock delete mode 100644 examples/multi-module/platform/Cargo.toml delete mode 100644 examples/multi-module/platform/Pkg-Config.roc delete mode 100644 examples/multi-module/platform/README.md delete mode 100755 examples/multi-module/platform/build.sh delete mode 100644 examples/multi-module/platform/host.c delete mode 100644 examples/multi-module/platform/src/lib.rs diff --git a/examples/multi-module/.gitignore b/examples/multi-module/.gitignore deleted file mode 100644 index 19abff6005..0000000000 --- a/examples/multi-module/.gitignore +++ /dev/null @@ -1 +0,0 @@ -quicksort diff --git a/examples/multi-module/Quicksort.roc b/examples/multi-module/Quicksort.roc deleted file mode 100644 index 5b60dae312..0000000000 --- a/examples/multi-module/Quicksort.roc +++ /dev/null @@ -1,47 +0,0 @@ -app "quicksort" imports [ Utils.{ swap } ] provides [ quicksort ] to "./platform" - - -quicksort : List I64 -> List I64 -quicksort = \originalList -> - quicksortHelp : List (Num a), I64, I64 -> List (Num a) - quicksortHelp = \list, low, high -> - if low < high then - when partition low high list is - Pair partitionIndex partitioned -> - partitioned - |> quicksortHelp low (partitionIndex - 1) - |> quicksortHelp (partitionIndex + 1) high - else - list - - partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] - partition = \low, high, initialList -> - when List.get initialList high is - Ok pivot -> - when partitionHelp (low - 1) low initialList high pivot is - Pair newI newList -> - Pair (newI + 1) (Utils.swap (newI + 1) high newList) - - Err _ -> - Pair (low - 1) initialList - - - partitionHelp : I64, I64, List (Num a), I64, (Num a) -> [ Pair I64 (List (Num a)) ] - partitionHelp = \i, j, list, high, pivot -> - if j < high then - when List.get list j is - Ok value -> - if value <= pivot then - partitionHelp (i + 1) (j + 1) (Utils.swap (i + 1) j list) high pivot - else - partitionHelp i (j + 1) list high pivot - - Err _ -> - Pair i list - else - Pair i list - - - - n = List.len originalList - quicksortHelp originalList 0 (n - 1) diff --git a/examples/multi-module/Utils.roc b/examples/multi-module/Utils.roc deleted file mode 100644 index 156a3c51c8..0000000000 --- a/examples/multi-module/Utils.roc +++ /dev/null @@ -1,12 +0,0 @@ -interface Utils exposes [ swap ] imports [] - -swap : I64, I64, List a -> List a -swap = \i, j, list -> - when Pair (List.get list i) (List.get list j) is - Pair (Ok atI) (Ok atJ) -> - list - |> List.set i atJ - |> List.set j atI - - _ -> - [] diff --git a/examples/multi-module/platform/Cargo.lock b/examples/multi-module/platform/Cargo.lock deleted file mode 100644 index c386bb6c4a..0000000000 --- a/examples/multi-module/platform/Cargo.lock +++ /dev/null @@ -1,23 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "host" -version = "0.1.0" -dependencies = [ - "roc_std 0.1.0", -] - -[[package]] -name = "libc" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "roc_std" -version = "0.1.0" -dependencies = [ - "libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum libc 0.2.79 (registry+https://github.com/rust-lang/crates.io-index)" = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" diff --git a/examples/multi-module/platform/Cargo.toml b/examples/multi-module/platform/Cargo.toml deleted file mode 100644 index 70f3c1f86c..0000000000 --- a/examples/multi-module/platform/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "host" -version = "0.1.0" -authors = ["Richard Feldman "] -edition = "2018" - -[lib] -crate-type = ["staticlib"] - -[dependencies] -roc_std = { path = "../../../roc_std" } - -[workspace] diff --git a/examples/multi-module/platform/Pkg-Config.roc b/examples/multi-module/platform/Pkg-Config.roc deleted file mode 100644 index a414c550c9..0000000000 --- a/examples/multi-module/platform/Pkg-Config.roc +++ /dev/null @@ -1,7 +0,0 @@ -platform examples/multi-module - requires { quicksort : List (Num a) -> List (Num a) } - exposes [] - packages {} - imports [] - provides [ main ] - effects Effect {} diff --git a/examples/multi-module/platform/README.md b/examples/multi-module/platform/README.md deleted file mode 100644 index eefff1996c..0000000000 --- a/examples/multi-module/platform/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Rebuilding the host from source - -Run `build.sh` to manually rebuild this platform's host. - -Note that the compiler currently has its own logic for rebuilding these hosts -(in `link.rs`). It's hardcoded for now, but the long-term goal is that -hosts will be precompiled by platform authors and distributed in packages, -at which point only package authors will need to think about rebuilding hosts. diff --git a/examples/multi-module/platform/build.sh b/examples/multi-module/platform/build.sh deleted file mode 100755 index 010c502222..0000000000 --- a/examples/multi-module/platform/build.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -# compile c_host.o and rust_host.o -clang -c host.c -o c_host.o -rustc host.rs -o rust_host.o - -# link them together into host.o -ld -r c_host.o rust_host.o -o host.o - -# clean up -rm -f c_host.o -rm -f rust_host.o diff --git a/examples/multi-module/platform/host.c b/examples/multi-module/platform/host.c deleted file mode 100644 index 0378c69589..0000000000 --- a/examples/multi-module/platform/host.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -extern int rust_main(); - -int main() { - return rust_main(); -} diff --git a/examples/multi-module/platform/src/lib.rs b/examples/multi-module/platform/src/lib.rs deleted file mode 100644 index 1166ccbb32..0000000000 --- a/examples/multi-module/platform/src/lib.rs +++ /dev/null @@ -1,51 +0,0 @@ -use roc_std::RocCallResult; -use roc_std::RocList; -use std::time::SystemTime; - -extern "C" { - #[link_name = "roc__quicksort_1_exposed"] - fn quicksort(list: RocList, output: &mut RocCallResult>) -> (); -} - -const NUM_NUMS: usize = 100; - -#[no_mangle] -pub fn rust_main() -> isize { - let nums: RocList = { - let mut nums = Vec::with_capacity(NUM_NUMS); - - for index in 0..nums.capacity() { - let num = index as i64 % 12; - - nums.push(num); - } - - RocList::from_slice(&nums) - }; - - println!("Running Roc quicksort on {} numbers...", nums.len()); - let start_time = SystemTime::now(); - let answer = unsafe { - use std::mem::MaybeUninit; - let mut output = MaybeUninit::uninit(); - - quicksort(nums, &mut *output.as_mut_ptr()); - - match output.assume_init().into() { - Ok(value) => value, - Err(msg) => panic!("roc failed with message: {}", msg), - } - }; - let end_time = SystemTime::now(); - let duration = end_time.duration_since(start_time).unwrap(); - - println!( - "Roc quicksort took {:.4} ms to compute this answer: {:?}", - duration.as_secs_f64() * 1000.0, - // truncate the answer, so stdout is not swamped - &answer.as_slice()[0..20] - ); - - // Exit code - 0 -} From 818465e8e1f03d4f32ce5561a63cdd0b869c4710 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 9 Dec 2020 01:17:29 +0100 Subject: [PATCH 08/10] update cli fixtures --- cli/tests/cli_run.rs | 24 ------------------- cli/tests/fixtures/multi-dep-str/Main.roc | 5 +++- .../multi-dep-str/platform/Pkg-Config.roc | 5 +++- .../multi-dep-str/platform/src/lib.rs | 2 +- cli/tests/fixtures/multi-dep-thunk/Main.roc | 5 +++- .../multi-dep-thunk/platform/Pkg-Config.roc | 5 +++- .../multi-dep-thunk/platform/src/lib.rs | 2 +- compiler/load/src/file.rs | 10 +++++++- examples/quicksort/Quicksort.roc | 5 +++- examples/quicksort/platform/Pkg-Config.roc | 7 ++++-- examples/quicksort/platform/src/lib.rs | 2 +- .../shared-quicksort/platform/Pkg-Config.roc | 8 +++++-- examples/shared-quicksort/platform/src/lib.rs | 2 +- 13 files changed, 44 insertions(+), 38 deletions(-) diff --git a/cli/tests/cli_run.rs b/cli/tests/cli_run.rs index 5cc55f1b52..cb4f22edfe 100644 --- a/cli/tests/cli_run.rs +++ b/cli/tests/cli_run.rs @@ -143,30 +143,6 @@ mod cli_run { ); } - #[test] - #[serial(multi_module)] - fn run_multi_module() { - check_output( - &example_file("multi-module", "Quicksort.roc"), - "quicksort", - &[], - "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n", - false, - ); - } - - #[test] - #[serial(multi_module)] - fn run_multi_module_optimized() { - check_output( - &example_file("multi-module", "Quicksort.roc"), - "quicksort", - &["--optimize"], - "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2]\n", - false, - ); - } - #[test] #[serial(multi_module)] // TODO: Stop ignoring this test once we are correctly freeing the RocList even when in dev build. diff --git a/cli/tests/fixtures/multi-dep-str/Main.roc b/cli/tests/fixtures/multi-dep-str/Main.roc index 69af7c5d9b..60d452bcc8 100644 --- a/cli/tests/fixtures/multi-dep-str/Main.roc +++ b/cli/tests/fixtures/multi-dep-str/Main.roc @@ -1,4 +1,7 @@ -app "multi-dep-str" imports [ Dep1 ] provides [ main ] to "./platform" +app "multi-dep-str" + packages { base: "platform" } + imports [ Dep1 ] + provides [ main ] to base main : Str main = Dep1.str1 diff --git a/cli/tests/fixtures/multi-dep-str/platform/Pkg-Config.roc b/cli/tests/fixtures/multi-dep-str/platform/Pkg-Config.roc index 6e7af88a5c..1ff6c7b8b8 100644 --- a/cli/tests/fixtures/multi-dep-str/platform/Pkg-Config.roc +++ b/cli/tests/fixtures/multi-dep-str/platform/Pkg-Config.roc @@ -3,5 +3,8 @@ platform examples/multi-module exposes [] packages {} imports [] - provides [ main ] + provides [ mainForHost ] effects Effect {} + +mainForHost : Str +mainForHost = main diff --git a/cli/tests/fixtures/multi-dep-str/platform/src/lib.rs b/cli/tests/fixtures/multi-dep-str/platform/src/lib.rs index 4d390b0560..c6a68ca745 100644 --- a/cli/tests/fixtures/multi-dep-str/platform/src/lib.rs +++ b/cli/tests/fixtures/multi-dep-str/platform/src/lib.rs @@ -3,7 +3,7 @@ use roc_std::RocStr; use std::str; extern "C" { - #[link_name = "roc__main_1_exposed"] + #[link_name = "roc__mainForHost_1_exposed"] fn say_hello(output: &mut RocCallResult) -> (); } diff --git a/cli/tests/fixtures/multi-dep-thunk/Main.roc b/cli/tests/fixtures/multi-dep-thunk/Main.roc index 2b2e3fc233..ae6243978b 100644 --- a/cli/tests/fixtures/multi-dep-thunk/Main.roc +++ b/cli/tests/fixtures/multi-dep-thunk/Main.roc @@ -1,4 +1,7 @@ -app "multi-dep-thunk" imports [ Dep1 ] provides [ main ] to "./platform" +app "multi-dep-thunk" + packages { base: "platform" } + imports [ Dep1 ] + provides [ main ] to base main : Str main = Dep1.value1 {} diff --git a/cli/tests/fixtures/multi-dep-thunk/platform/Pkg-Config.roc b/cli/tests/fixtures/multi-dep-thunk/platform/Pkg-Config.roc index 86d0701468..a080298820 100644 --- a/cli/tests/fixtures/multi-dep-thunk/platform/Pkg-Config.roc +++ b/cli/tests/fixtures/multi-dep-thunk/platform/Pkg-Config.roc @@ -3,5 +3,8 @@ platform examples/multi-dep-thunk exposes [] packages {} imports [] - provides [ main ] + provides [ mainForHost ] effects Effect {} + +mainForHost : Str +mainForHost = main diff --git a/cli/tests/fixtures/multi-dep-thunk/platform/src/lib.rs b/cli/tests/fixtures/multi-dep-thunk/platform/src/lib.rs index 4d390b0560..c6a68ca745 100644 --- a/cli/tests/fixtures/multi-dep-thunk/platform/src/lib.rs +++ b/cli/tests/fixtures/multi-dep-thunk/platform/src/lib.rs @@ -3,7 +3,7 @@ use roc_std::RocStr; use std::str; extern "C" { - #[link_name = "roc__main_1_exposed"] + #[link_name = "roc__mainForHost_1_exposed"] fn say_hello(output: &mut RocCallResult) -> (); } diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 0d39c807a3..7a0d80ca0e 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -1618,7 +1618,14 @@ fn update<'a>( let work = state.dependencies.notify(module_id, Phase::SolveTypes); - if Some(module_id) == state.platform_id { + // if there is a platform, the Pkg-Config module provides host-exposed, + // otherwise the App module exposes host-exposed + let is_host_exposed = match state.platform_id { + None => module_id == state.root_id, + Some(platform_id) => module_id == platform_id, + }; + + if is_host_exposed { state .exposed_to_host .extend(solved_module.exposed_vars_by_symbol.iter().copied()); @@ -2505,6 +2512,7 @@ fn send_header<'a>( ) } +// TODO refactor so more logic is shared with `send_header` #[allow(clippy::too_many_arguments)] fn send_header_two<'a>( arena: &'a Bump, diff --git a/examples/quicksort/Quicksort.roc b/examples/quicksort/Quicksort.roc index 0092b7b527..59bb6d47f0 100644 --- a/examples/quicksort/Quicksort.roc +++ b/examples/quicksort/Quicksort.roc @@ -1,4 +1,7 @@ -app "quicksort" provides [ quicksort ] to "./platform" +app "quicksort" + packages { base: "platform" } + imports [] + provides [ quicksort ] to base quicksort = \originalList -> diff --git a/examples/quicksort/platform/Pkg-Config.roc b/examples/quicksort/platform/Pkg-Config.roc index c26ae3837c..7e59c04a27 100644 --- a/examples/quicksort/platform/Pkg-Config.roc +++ b/examples/quicksort/platform/Pkg-Config.roc @@ -1,7 +1,10 @@ platform examples/quicksort - requires { quicksort : List (Num a) -> List (Num a) } + requires { quicksort : List I64 -> List I64 } exposes [] packages {} imports [] - provides [ main ] + provides [ mainForHost ] effects Effect {} + +mainForHost : List I64 -> List I64 +mainForHost = \list -> quicksort list diff --git a/examples/quicksort/platform/src/lib.rs b/examples/quicksort/platform/src/lib.rs index 53cf2f83b9..0a626cbae4 100644 --- a/examples/quicksort/platform/src/lib.rs +++ b/examples/quicksort/platform/src/lib.rs @@ -3,7 +3,7 @@ use roc_std::RocList; use std::time::SystemTime; extern "C" { - #[link_name = "roc__quicksort_1_exposed"] + #[link_name = "roc__mainForHost_1_exposed"] fn quicksort(list: RocList, output: &mut RocCallResult>) -> (); } diff --git a/examples/shared-quicksort/platform/Pkg-Config.roc b/examples/shared-quicksort/platform/Pkg-Config.roc index 18e1f25552..061e86aaa6 100644 --- a/examples/shared-quicksort/platform/Pkg-Config.roc +++ b/examples/shared-quicksort/platform/Pkg-Config.roc @@ -1,12 +1,16 @@ platform examples/shared-quicksort - requires { main : Effect {} } + requires { quicksort : List I64 -> List I64 } exposes [] packages {} imports [] provides [ mainForHost ] effects Effect { - putChar : Int -> Effect {}, + putChar : I64 -> Effect {}, putLine : Str -> Effect {}, getLine : Effect Str } + +mainForHost : List I64 -> List I64 +mainForHost = \list -> quicksort list + diff --git a/examples/shared-quicksort/platform/src/lib.rs b/examples/shared-quicksort/platform/src/lib.rs index 974dc2592c..acfbb9e263 100644 --- a/examples/shared-quicksort/platform/src/lib.rs +++ b/examples/shared-quicksort/platform/src/lib.rs @@ -5,7 +5,7 @@ use roc_std::RocList; use std::time::SystemTime; extern "C" { - #[link_name = "roc__quicksort_1_exposed"] + #[link_name = "roc__mainForHost_1_exposed"] fn quicksort(list: RocList, output: &mut RocCallResult>) -> (); } From cfe69f8467b184956e4de73f1b71ad7a4e9bc5a7 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 9 Dec 2020 01:19:28 +0100 Subject: [PATCH 09/10] add .ll to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index ee2e11b524..42a856f29f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ zig-cache .direnv *.rs.bk +# llvm human-readable output +*.ll + #valgrind vgcore.* From 7933d63573a2c50dd6b51685b876d46392c618b1 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 9 Dec 2020 03:30:07 +0100 Subject: [PATCH 10/10] clippy --- compiler/load/src/file.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 7a0d80ca0e..44977f0274 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -564,10 +564,10 @@ struct ModuleHeader<'a> { } #[derive(Debug)] -enum ModuleHeaderExtra<'a> { - HeaderForApp { to_platform: To<'a> }, - HeaderForPkgConfig, - HeaderForInterface, +enum HeaderFor<'a> { + App { to_platform: To<'a> }, + PkgConfig, + Interface, } #[derive(Debug)] @@ -640,7 +640,7 @@ struct ParsedModule<'a> { #[derive(Debug)] enum Msg<'a> { Many(Vec>), - Header(ModuleHeader<'a>, ModuleHeaderExtra<'a>), + Header(ModuleHeader<'a>, HeaderFor<'a>), Parsed(ParsedModule<'a>), CanonicalizedAndConstrained { constrained_module: ConstrainedModule, @@ -1428,19 +1428,19 @@ fn update<'a>( } } - use ModuleHeaderExtra::*; + use HeaderFor::*; match header_extra { - HeaderForApp { to_platform } => { + App { to_platform } => { debug_assert_eq!(state.platform_path, None); state.platform_path = Some(to_platform.clone()); } - HeaderForPkgConfig => { + PkgConfig => { debug_assert_eq!(state.platform_id, None); state.platform_id = Some(header.module_id); } - HeaderForInterface => {} + Interface => {} } // store an ID to name mapping, so we know the file to read when fetching dependencies' headers @@ -2487,8 +2487,8 @@ fn send_header<'a>( // because the coordinator thread needs to receive this message // to decrement its "pending" count. let extra = match to_platform { - Some(to_platform) => ModuleHeaderExtra::HeaderForApp { to_platform }, - None => ModuleHeaderExtra::HeaderForInterface, + Some(to_platform) => HeaderFor::App { to_platform }, + None => HeaderFor::Interface, }; ( @@ -2689,7 +2689,7 @@ fn send_header_two<'a>( // to decrement its "pending" count. let module_name = ModuleNameEnum::PkgConfig(shorthand); - let extra = ModuleHeaderExtra::HeaderForPkgConfig; + let extra = HeaderFor::PkgConfig; ( home, Msg::Header(