diff --git a/compiler/build/src/program.rs b/compiler/build/src/program.rs index ee0d990ce5..8265dc8e74 100644 --- a/compiler/build/src/program.rs +++ b/compiler/build/src/program.rs @@ -36,7 +36,14 @@ pub fn gen_from_mono_module( let code_gen_start = SystemTime::now(); for (home, (module_path, src)) in loaded.sources { - let src_lines: Vec<&str> = src.split('\n').collect(); + let mut src_lines: Vec<&str> = Vec::new(); + + if let Some((_, header_src)) = loaded.header_sources.get(&home) { + src_lines.extend(header_src.split('\n')); + src_lines.extend(src.split('\n').skip(1)); + } else { + src_lines.extend(src.split('\n')); + } let palette = DEFAULT_PALETTE; // Report parsing and canonicalization problems diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 6b0d1e00e3..fcbdd82421 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -366,6 +366,7 @@ struct ModuleCache<'a> { mono_problems: MutMap>, sources: MutMap, + header_sources: MutMap, } fn start_phase<'a>(module_id: ModuleId, phase: Phase, state: &mut State<'a>) -> Vec> { @@ -616,6 +617,7 @@ pub struct LoadedModule { pub type_problems: MutMap>, pub declarations_by_id: MutMap>, pub exposed_to_host: MutMap, + pub header_sources: MutMap)>, pub sources: MutMap)>, pub timings: MutMap, pub documentation: MutMap, @@ -639,6 +641,7 @@ struct ModuleHeader<'a> { package_qualified_imported_modules: MutSet>, exposes: Vec, exposed_imports: MutMap, + header_src: &'a str, src: &'a [u8], module_timing: ModuleTiming, } @@ -698,6 +701,7 @@ pub struct MonomorphizedModule<'a> { pub mono_problems: MutMap>, pub procedures: MutMap<(Symbol, Layout<'a>), Proc<'a>>, pub exposed_to_host: MutMap, + pub header_sources: MutMap)>, pub sources: MutMap)>, pub timings: MutMap, } @@ -1678,6 +1682,11 @@ fn update<'a>( .exposed_symbols_by_module .insert(home, exposed_symbols); + state + .module_cache + .header_sources + .insert(home, (header.module_path.clone(), header.header_src)); + state .module_cache .imports @@ -2115,6 +2124,7 @@ fn finish_specialization( type_problems, can_problems, sources, + header_sources, .. } = module_cache; @@ -2123,6 +2133,11 @@ fn finish_specialization( .map(|(id, (path, src))| (id, (path, src.into()))) .collect(); + let header_sources: MutMap)> = header_sources + .into_iter() + .map(|(id, (path, src))| (id, (path, src.into()))) + .collect(); + let path_to_platform = { use PlatformPath::*; let package_or_path = match platform_path { @@ -2224,6 +2239,7 @@ fn finish_specialization( interns, procedures, sources, + header_sources, timings: state.timings, }) } @@ -2251,6 +2267,13 @@ fn finish( .map(|(id, (path, src))| (id, (path, src.into()))) .collect(); + let header_sources = state + .module_cache + .header_sources + .into_iter() + .map(|(id, (path, src))| (id, (path, src.into()))) + .collect(); + LoadedModule { module_id: state.root_id, interns, @@ -2259,6 +2282,7 @@ fn finish( type_problems: state.module_cache.type_problems, declarations_by_id: state.declarations_by_id, exposed_to_host: exposed_vars_by_symbol.into_iter().collect(), + header_sources, sources, timings: state.timings, documentation, @@ -2468,41 +2492,63 @@ fn parse_header<'a>( module_timing.parse_header = parse_header_duration; match parsed { - Ok((_, ast::Module::Interface { header }, parse_state)) => Ok(send_header( - Located { - region: header.name.region, - value: ModuleNameEnum::Interface(header.name.value), - }, - filename, - is_root_module, - opt_shorthand, - &[], - header.exposes.into_bump_slice(), - header.imports.into_bump_slice(), - None, - parse_state, - module_ids, - ident_ids_by_module, - module_timing, - )), + Ok((_, ast::Module::Interface { header }, parse_state)) => { + let header_src = unsafe { + let chomped = src_bytes.len() - parse_state.bytes.len(); + std::str::from_utf8_unchecked(&src_bytes[..chomped]) + }; + + let info = HeaderInfo { + loc_name: Located { + region: header.name.region, + value: ModuleNameEnum::Interface(header.name.value), + }, + filename, + is_root_module, + opt_shorthand, + header_src, + packages: &[], + exposes: header.exposes.into_bump_slice(), + imports: header.imports.into_bump_slice(), + to_platform: None, + }; + + Ok(send_header( + info, + parse_state, + module_ids, + ident_ids_by_module, + module_timing, + )) + } Ok((_, ast::Module::App { header }, parse_state)) => { let mut pkg_config_dir = filename.clone(); pkg_config_dir.pop(); + let header_src = unsafe { + let chomped = src_bytes.len() - parse_state.bytes.len(); + std::str::from_utf8_unchecked(&src_bytes[..chomped]) + }; + let packages = header.packages.into_bump_slice(); - let (module_id, app_module_header_msg) = send_header( - Located { + let info = HeaderInfo { + loc_name: Located { region: header.name.region, value: ModuleNameEnum::App(header.name.value), }, filename, is_root_module, opt_shorthand, + header_src, packages, - header.provides.into_bump_slice(), - header.imports.into_bump_slice(), - Some(header.to.value.clone()), + exposes: header.provides.into_bump_slice(), + imports: header.imports.into_bump_slice(), + to_platform: Some(header.to.value.clone()), + }; + + let (module_id, app_module_header_msg) = send_header( + info, parse_state, module_ids.clone(), ident_ids_by_module.clone(), @@ -2673,16 +2719,22 @@ enum ModuleNameEnum<'a> { PkgConfig, } -#[allow(clippy::too_many_arguments)] -fn send_header<'a>( +#[derive(Debug)] +struct HeaderInfo<'a> { loc_name: Located>, filename: PathBuf, is_root_module: bool, opt_shorthand: Option<&'a str>, + header_src: &'a str, packages: &'a [Located>], exposes: &'a [Located>], imports: &'a [Located>], to_platform: Option>, +} + +#[allow(clippy::too_many_arguments)] +fn send_header<'a>( + info: HeaderInfo<'a>, parse_state: parser::State<'a>, module_ids: Arc>>, ident_ids_by_module: Arc>>, @@ -2690,6 +2742,18 @@ fn send_header<'a>( ) -> (ModuleId, Msg<'a>) { use ModuleNameEnum::*; + let HeaderInfo { + loc_name, + filename, + is_root_module, + opt_shorthand, + packages, + exposes, + imports, + to_platform, + header_src, + } = info; + let declared_name: ModuleName = match &loc_name.value { PkgConfig => unreachable!(), App(_) => ModuleName::APP.into(), @@ -2872,6 +2936,7 @@ fn send_header<'a>( package_qualified_imported_modules, deps_by_name, exposes: exposed, + header_src, src: parse_state.bytes, exposed_imports: scope, module_timing, @@ -3091,6 +3156,7 @@ fn send_header_two<'a>( package_qualified_imported_modules, deps_by_name, exposes: exposed, + header_src: "#builtin effect header", src: parse_state.bytes, exposed_imports: scope, module_timing,