mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 08:17:40 +03:00
Merge pull request #2771 from rtfeldman/cache-stdlib-modules
Cache stdlib modules
This commit is contained in:
commit
24b8a68503
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -3673,7 +3673,14 @@ dependencies = [
|
||||
name = "roc_load"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"roc_builtins",
|
||||
"roc_collections",
|
||||
"roc_constrain",
|
||||
"roc_load_internal",
|
||||
"roc_module",
|
||||
"roc_target",
|
||||
"roc_types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1,3 +1,7 @@
|
||||
interface Bool
|
||||
exposes [ Bool, and, or, not, isEq, isNotEq ]
|
||||
imports [ ]
|
||||
|
||||
Bool : [ True, False ]
|
||||
|
||||
and : Bool, Bool -> Bool
|
||||
|
@ -1,11 +1,15 @@
|
||||
interface Box
|
||||
exposes [ box, unbox ]
|
||||
imports [ ]
|
||||
|
||||
box : a -> Box a
|
||||
unbox : Box a -> a
|
||||
|
||||
# we'd need reset/reuse for box for this to be efficient
|
||||
# that is currently not implemented
|
||||
map : Box a, (a -> b) -> Box b
|
||||
map = \boxed, transform =
|
||||
boxed
|
||||
|> Box.unbox
|
||||
|> transform
|
||||
|> Box.box
|
||||
# # we'd need reset/reuse for box for this to be efficient
|
||||
# # that is currently not implemented
|
||||
# map : Box a, (a -> b) -> Box b
|
||||
# map = \boxed, transform =
|
||||
# boxed
|
||||
# |> Box.unbox
|
||||
# |> transform
|
||||
# |> Box.box
|
||||
|
@ -1,3 +1,22 @@
|
||||
interface Dict
|
||||
exposes
|
||||
[
|
||||
empty,
|
||||
single,
|
||||
get,
|
||||
walk,
|
||||
insert,
|
||||
len,
|
||||
remove,
|
||||
contains,
|
||||
keys,
|
||||
values,
|
||||
union,
|
||||
intersection,
|
||||
difference,
|
||||
]
|
||||
imports [ ]
|
||||
|
||||
empty : Dict k v
|
||||
single : k, v -> Dict k v
|
||||
get : Dict k v, k -> Result v [ KeyNotFound ]*
|
||||
|
@ -1,3 +1,53 @@
|
||||
isEmpty,
|
||||
get,
|
||||
set,
|
||||
replace,
|
||||
append,
|
||||
map,
|
||||
len,
|
||||
walkBackwards,
|
||||
concat,
|
||||
first,
|
||||
single,
|
||||
repeat,
|
||||
reverse,
|
||||
prepend,
|
||||
join,
|
||||
keepIf,
|
||||
contains,
|
||||
sum,
|
||||
walk,
|
||||
last,
|
||||
keepOks,
|
||||
keepErrs,
|
||||
mapWithIndex,
|
||||
map2,
|
||||
map3,
|
||||
product,
|
||||
walkUntil,
|
||||
range,
|
||||
sortWith,
|
||||
drop,
|
||||
swap,
|
||||
dropAt,
|
||||
dropLast,
|
||||
min,
|
||||
max,
|
||||
map4,
|
||||
dropFirst,
|
||||
joinMap,
|
||||
any,
|
||||
takeFirst,
|
||||
takeLast,
|
||||
find,
|
||||
sublist,
|
||||
intersperse,
|
||||
split,
|
||||
all,
|
||||
dropIf,
|
||||
sortAsc,
|
||||
sortDesc,
|
||||
|
||||
isEmpty : List a -> Bool
|
||||
isEmpty = \list ->
|
||||
List.len list == 0
|
||||
|
@ -1,3 +1,148 @@
|
||||
interface Num
|
||||
exposes
|
||||
[
|
||||
Num,
|
||||
Int,
|
||||
Float,
|
||||
|
||||
Integer,
|
||||
FloatingPoint,
|
||||
|
||||
I128,
|
||||
I64,
|
||||
I32,
|
||||
I16,
|
||||
I8,
|
||||
|
||||
U128,
|
||||
U64,
|
||||
U32,
|
||||
U16,
|
||||
U8,
|
||||
|
||||
Signed128,
|
||||
Signed64,
|
||||
Signed32,
|
||||
Signed16,
|
||||
Signed8,
|
||||
|
||||
Unsigned128,
|
||||
Unsigned64,
|
||||
Unsigned32,
|
||||
Unsigned16,
|
||||
Unsigned8,
|
||||
|
||||
Nat,
|
||||
Dec,
|
||||
|
||||
F32,
|
||||
F64,
|
||||
|
||||
Natural,
|
||||
Decimal,
|
||||
|
||||
Binary32,
|
||||
Binary64,
|
||||
|
||||
maxFloat,
|
||||
minFloat,
|
||||
abs,
|
||||
neg,
|
||||
add,
|
||||
sub,
|
||||
mul,
|
||||
isLt,
|
||||
isLte,
|
||||
isGt,
|
||||
isGte,
|
||||
sin,
|
||||
cos,
|
||||
tan,
|
||||
atan,
|
||||
acos,
|
||||
asin,
|
||||
isZero,
|
||||
isEven,
|
||||
isOdd,
|
||||
toFloat,
|
||||
isPositive,
|
||||
isNegative,
|
||||
rem,
|
||||
div,
|
||||
modInt,
|
||||
modFloat,
|
||||
sqrt,
|
||||
log,
|
||||
round,
|
||||
ceiling,
|
||||
floor,
|
||||
compare,
|
||||
pow,
|
||||
powInt,
|
||||
addWrap,
|
||||
addChecked,
|
||||
addSaturated,
|
||||
bitwiseAnd,
|
||||
bitwiseXor,
|
||||
bitwiseOr,
|
||||
shiftLeftBy,
|
||||
shiftRightBy,
|
||||
shiftRightZfBy,
|
||||
subWrap,
|
||||
subChecked,
|
||||
subSaturated,
|
||||
mulWrap,
|
||||
mulChecked,
|
||||
intCast,
|
||||
bytesToU16,
|
||||
bytesToU32,
|
||||
divCeil,
|
||||
divFloor,
|
||||
toStr,
|
||||
isMultipleOf,
|
||||
minI8,
|
||||
maxI8,
|
||||
minU8,
|
||||
maxU8,
|
||||
minI16,
|
||||
maxI16,
|
||||
minU16,
|
||||
maxU16,
|
||||
minI32,
|
||||
maxI32,
|
||||
minU32,
|
||||
maxU32,
|
||||
minI64,
|
||||
maxI64,
|
||||
minU64,
|
||||
maxU64,
|
||||
minI128,
|
||||
maxI128,
|
||||
minU128,
|
||||
maxU128,
|
||||
toI8,
|
||||
toI8Checked,
|
||||
toI16,
|
||||
toI16Checked,
|
||||
toI32,
|
||||
toI32Checked,
|
||||
toI64,
|
||||
toI64Checked,
|
||||
toI128,
|
||||
toI128Checked,
|
||||
toU8,
|
||||
toU8Checked,
|
||||
toU16,
|
||||
toU16Checked,
|
||||
toU32,
|
||||
toU32Checked,
|
||||
toU64,
|
||||
toU64Checked,
|
||||
toU128,
|
||||
toU128Checked,
|
||||
]
|
||||
imports [ ]
|
||||
|
||||
Num range : [ @Num range ]
|
||||
Int range : Num (Integer range)
|
||||
Float range : Num (FloatingPoint range)
|
||||
|
@ -1,3 +1,7 @@
|
||||
interface Result
|
||||
exposes [ Result, isOk, isErr, map, mapErr, after, withDefault ]
|
||||
imports [ ]
|
||||
|
||||
Result ok err : [ Ok ok, Err err ]
|
||||
|
||||
isOk : Result ok err -> Bool
|
||||
|
@ -1,3 +1,21 @@
|
||||
interface Dict
|
||||
exposes
|
||||
[
|
||||
empty,
|
||||
single,
|
||||
walk,
|
||||
insert,
|
||||
len,
|
||||
remove,
|
||||
contains,
|
||||
toList,
|
||||
fromList,
|
||||
union,
|
||||
intersection,
|
||||
difference,
|
||||
]
|
||||
imports [ ]
|
||||
|
||||
empty : Set k
|
||||
single : k -> Set k
|
||||
insert : Set k, k -> Set k
|
||||
|
@ -1,3 +1,43 @@
|
||||
interface Str
|
||||
exposes
|
||||
[
|
||||
concat,
|
||||
Utf8Problem,
|
||||
Utf8ByteProblem,
|
||||
isEmpty,
|
||||
joinWith,
|
||||
split,
|
||||
repeat,
|
||||
countGraphemes,
|
||||
startsWithCodePt,
|
||||
toUtf8,
|
||||
fromUtf8,
|
||||
fromUtf8Range,
|
||||
startsWith,
|
||||
endsWith,
|
||||
trim,
|
||||
trimLeft,
|
||||
trimRight,
|
||||
|
||||
toDec,
|
||||
toF64,
|
||||
toF32,
|
||||
toNat,
|
||||
toU128,
|
||||
toI128,
|
||||
toU64,
|
||||
toI64,
|
||||
toU32,
|
||||
toI32,
|
||||
toU16,
|
||||
toI16,
|
||||
toU8,
|
||||
toI8,
|
||||
]
|
||||
imports [ ]
|
||||
|
||||
|
||||
|
||||
Utf8ByteProblem :
|
||||
[
|
||||
InvalidStartByte,
|
||||
|
@ -7,6 +7,16 @@ edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
roc_load_internal = { path = "../load_internal" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
roc_target = { path = "../roc_target" }
|
||||
roc_constrain= { path = "../constrain" }
|
||||
roc_types = { path = "../types" }
|
||||
roc_module = { path = "../module" }
|
||||
roc_collections = { path = "../collections" }
|
||||
|
||||
[build-dependencies]
|
||||
roc_load_internal = { path = "../load_internal" }
|
||||
roc_builtins = { path = "../builtins" }
|
||||
roc_module = { path = "../module" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
roc_target = { path = "../roc_target" }
|
||||
|
50
compiler/load/build.rs
Normal file
50
compiler/load/build.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use roc_module::symbol::ModuleId;
|
||||
|
||||
const MODULES: &[(ModuleId, &str)] = &[
|
||||
(ModuleId::BOOL, "Bool.roc"),
|
||||
// (ModuleId::RESULT, "Result.roc"),
|
||||
// (ModuleId::LIST, "List.roc"),
|
||||
// (ModuleId::STR, "Str.roc"),
|
||||
// (ModuleId::DICT, "Dict.roc"),
|
||||
// (ModuleId::SET, "Set.roc"),
|
||||
// (ModuleId::BOX, "Box.roc"),
|
||||
// (ModuleId::NUM, "Num.roc"),
|
||||
];
|
||||
|
||||
fn main() {
|
||||
for (module_id, filename) in MODULES {
|
||||
write_subs_for_module(*module_id, filename);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_subs_for_module(module_id: ModuleId, filename: &str) {
|
||||
// Tell Cargo that if the given file changes, to rerun this build script.
|
||||
println!("cargo:rerun-if-changed=../builtins/roc/{}", filename);
|
||||
|
||||
let arena = Bump::new();
|
||||
let src_dir = PathBuf::from(".");
|
||||
let source = roc_builtins::roc::module_source(module_id);
|
||||
let target_info = roc_target::TargetInfo::default_x86_64();
|
||||
|
||||
let res_module = roc_load_internal::file::load_and_typecheck_str(
|
||||
&arena,
|
||||
PathBuf::from(filename),
|
||||
source,
|
||||
&src_dir,
|
||||
Default::default(),
|
||||
target_info,
|
||||
);
|
||||
|
||||
let module = res_module.unwrap();
|
||||
let subs = module.solved.inner();
|
||||
let exposed_vars_by_symbol: Vec<_> = module.exposed_to_host.into_iter().collect();
|
||||
|
||||
let mut output_path = PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
||||
output_path.extend(&[filename]);
|
||||
output_path.set_extension("dat");
|
||||
let mut file = std::fs::File::create(&output_path).unwrap();
|
||||
subs.serialize(&exposed_vars_by_symbol, &mut file).unwrap();
|
||||
}
|
@ -1,6 +1,136 @@
|
||||
pub use roc_load_internal::file::{
|
||||
load_and_monomorphize, load_and_monomorphize_from_str, load_and_typecheck, LoadedModule,
|
||||
LoadingProblem, MonomorphizedModule,
|
||||
};
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_constrain::module::ExposedByModule;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::subs::{Subs, Variable};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub use roc_load_internal::docs;
|
||||
pub use roc_load_internal::file::{
|
||||
LoadResult, LoadStart, LoadedModule, LoadingProblem, MonomorphizedModule, Phase,
|
||||
};
|
||||
|
||||
fn load<'a>(
|
||||
arena: &'a Bump,
|
||||
load_start: LoadStart<'a>,
|
||||
src_dir: &Path,
|
||||
exposed_types: ExposedByModule,
|
||||
goal_phase: Phase,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||
let cached_subs = read_cached_subs();
|
||||
|
||||
roc_load_internal::file::load(
|
||||
arena,
|
||||
load_start,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
goal_phase,
|
||||
target_info,
|
||||
cached_subs,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn load_and_monomorphize_from_str<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
src: &'a str,
|
||||
src_dir: &Path,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_str(arena, filename, src)?;
|
||||
|
||||
match load(
|
||||
arena,
|
||||
load_start,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
Phase::MakeSpecializations,
|
||||
target_info,
|
||||
)? {
|
||||
Monomorphized(module) => Ok(module),
|
||||
TypeChecked(_) => unreachable!(""),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_and_monomorphize<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
src_dir: &Path,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, filename)?;
|
||||
|
||||
match load(
|
||||
arena,
|
||||
load_start,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
Phase::MakeSpecializations,
|
||||
target_info,
|
||||
)? {
|
||||
Monomorphized(module) => Ok(module),
|
||||
TypeChecked(_) => unreachable!(""),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_and_typecheck<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
src_dir: &Path,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<LoadedModule, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, filename)?;
|
||||
|
||||
match load(
|
||||
arena,
|
||||
load_start,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
Phase::SolveTypes,
|
||||
target_info,
|
||||
)? {
|
||||
Monomorphized(_) => unreachable!(""),
|
||||
TypeChecked(module) => Ok(module),
|
||||
}
|
||||
}
|
||||
|
||||
const BOOL: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Bool.dat")) as &[_];
|
||||
// const RESULT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Result.dat")) as &[_];
|
||||
// const LIST: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/List.dat")) as &[_];
|
||||
// const STR: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Str.dat")) as &[_];
|
||||
// const DICT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Dict.dat")) as &[_];
|
||||
// const SET: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Set.dat")) as &[_];
|
||||
// const BOX: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Box.dat")) as &[_];
|
||||
// const NUM: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Num.dat")) as &[_];
|
||||
|
||||
fn deserialize_help(bytes: &[u8]) -> (Subs, Vec<(Symbol, Variable)>) {
|
||||
let (subs, slice) = Subs::deserialize(bytes);
|
||||
|
||||
(subs, slice.to_vec())
|
||||
}
|
||||
|
||||
fn read_cached_subs() -> MutMap<ModuleId, (Subs, Vec<(Symbol, Variable)>)> {
|
||||
let mut output = MutMap::default();
|
||||
|
||||
output.insert(ModuleId::BOOL, deserialize_help(BOOL));
|
||||
// output.insert(ModuleId::RESULT, deserialize_help(RESULT));
|
||||
// output.insert(ModuleId::LIST, deserialize_help(LIST));
|
||||
// output.insert(ModuleId::STR, deserialize_help(STR));
|
||||
// output.insert(ModuleId::DICT, deserialize_help(DICT));
|
||||
// output.insert(ModuleId::SET, deserialize_help(SET));
|
||||
// output.insert(ModuleId::BOX, deserialize_help(BOX));
|
||||
// output.insert(ModuleId::NUM, deserialize_help(NUM));
|
||||
|
||||
output
|
||||
}
|
||||
|
@ -47,7 +47,8 @@ use std::str::from_utf8_unchecked;
|
||||
use std::sync::Arc;
|
||||
use std::{env, fs};
|
||||
|
||||
use crate::work::{Dependencies, Phase};
|
||||
use crate::work::Dependencies;
|
||||
pub use crate::work::Phase;
|
||||
|
||||
#[cfg(target_family = "wasm")]
|
||||
use crate::wasm_system_time::{Duration, SystemTime};
|
||||
@ -256,6 +257,7 @@ fn start_phase<'a>(
|
||||
&mut state.exposed_types,
|
||||
dep_idents,
|
||||
declarations,
|
||||
state.cached_subs.clone(),
|
||||
)
|
||||
}
|
||||
Phase::FindSpecializations => {
|
||||
@ -602,8 +604,13 @@ struct State<'a> {
|
||||
// since the unioning process could potentially take longer than the savings.
|
||||
// (Granted, this has not been attempted or measured!)
|
||||
pub layout_caches: std::vec::Vec<LayoutCache<'a>>,
|
||||
|
||||
// cached subs (used for builtin modules, could include packages in the future too)
|
||||
cached_subs: CachedSubs,
|
||||
}
|
||||
|
||||
type CachedSubs = Arc<Mutex<MutMap<ModuleId, (Subs, Vec<(Symbol, Variable)>)>>>;
|
||||
|
||||
impl<'a> State<'a> {
|
||||
fn new(
|
||||
root_id: ModuleId,
|
||||
@ -612,6 +619,7 @@ impl<'a> State<'a> {
|
||||
exposed_types: ExposedByModule,
|
||||
arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
||||
cached_subs: MutMap<ModuleId, (Subs, Vec<(Symbol, Variable)>)>,
|
||||
) -> Self {
|
||||
let arc_shorthands = Arc::new(Mutex::new(MutMap::default()));
|
||||
|
||||
@ -635,6 +643,7 @@ impl<'a> State<'a> {
|
||||
exposed_symbols_by_module: MutMap::default(),
|
||||
timings: MutMap::default(),
|
||||
layout_caches: std::vec::Vec::with_capacity(num_cpus::get()),
|
||||
cached_subs: Arc::new(Mutex::new(cached_subs)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -738,6 +747,7 @@ enum BuildTask<'a> {
|
||||
var_store: VarStore,
|
||||
declarations: Vec<Declaration>,
|
||||
dep_idents: MutMap<ModuleId, IdentIds>,
|
||||
cached_subs: CachedSubs,
|
||||
},
|
||||
BuildPendingSpecializations {
|
||||
module_timing: ModuleTiming,
|
||||
@ -808,16 +818,21 @@ fn enqueue_task<'a>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_and_typecheck<'a>(
|
||||
pub fn load_and_typecheck_str<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
source: &'a str,
|
||||
src_dir: &Path,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<LoadedModule, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, filename)?;
|
||||
let load_start = LoadStart::from_str(arena, filename, source)?;
|
||||
|
||||
// this function is used specifically in the case
|
||||
// where we want to regenerate the cached data
|
||||
let cached_subs = MutMap::default();
|
||||
|
||||
match load(
|
||||
arena,
|
||||
@ -826,68 +841,18 @@ pub fn load_and_typecheck<'a>(
|
||||
exposed_types,
|
||||
Phase::SolveTypes,
|
||||
target_info,
|
||||
cached_subs,
|
||||
)? {
|
||||
Monomorphized(_) => unreachable!(""),
|
||||
TypeChecked(module) => Ok(module),
|
||||
}
|
||||
}
|
||||
|
||||
/// Main entry point to the compiler from the CLI and tests
|
||||
pub fn load_and_monomorphize<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
src_dir: &Path,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, filename)?;
|
||||
|
||||
match load(
|
||||
arena,
|
||||
load_start,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
Phase::MakeSpecializations,
|
||||
target_info,
|
||||
)? {
|
||||
Monomorphized(module) => Ok(module),
|
||||
TypeChecked(_) => unreachable!(""),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn load_and_monomorphize_from_str<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
src: &'a str,
|
||||
src_dir: &Path,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_str(arena, filename, src)?;
|
||||
|
||||
match load(
|
||||
arena,
|
||||
load_start,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
Phase::MakeSpecializations,
|
||||
target_info,
|
||||
)? {
|
||||
Monomorphized(module) => Ok(module),
|
||||
TypeChecked(_) => unreachable!(""),
|
||||
}
|
||||
}
|
||||
|
||||
struct LoadStart<'a> {
|
||||
pub arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
pub ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
||||
pub root_id: ModuleId,
|
||||
pub root_msg: Msg<'a>,
|
||||
pub struct LoadStart<'a> {
|
||||
arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
||||
root_id: ModuleId,
|
||||
root_msg: Msg<'a>,
|
||||
}
|
||||
|
||||
impl<'a> LoadStart<'a> {
|
||||
@ -974,7 +939,7 @@ impl<'a> LoadStart<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
enum LoadResult<'a> {
|
||||
pub enum LoadResult<'a> {
|
||||
TypeChecked(LoadedModule),
|
||||
Monomorphized(MonomorphizedModule<'a>),
|
||||
}
|
||||
@ -1023,13 +988,14 @@ enum LoadResult<'a> {
|
||||
/// specializations, so if none of their specializations changed, we don't even need
|
||||
/// to rebuild the module and can link in the cached one directly.)
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn load<'a>(
|
||||
pub fn load<'a>(
|
||||
arena: &'a Bump,
|
||||
load_start: LoadStart<'a>,
|
||||
src_dir: &Path,
|
||||
exposed_types: ExposedByModule,
|
||||
goal_phase: Phase,
|
||||
target_info: TargetInfo,
|
||||
cached_subs: MutMap<ModuleId, (Subs, Vec<(Symbol, Variable)>)>,
|
||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||
// When compiling to wasm, we cannot spawn extra threads
|
||||
// so we have a single-threaded implementation
|
||||
@ -1041,6 +1007,7 @@ fn load<'a>(
|
||||
exposed_types,
|
||||
goal_phase,
|
||||
target_info,
|
||||
cached_subs,
|
||||
)
|
||||
} else {
|
||||
load_multi_threaded(
|
||||
@ -1050,6 +1017,7 @@ fn load<'a>(
|
||||
exposed_types,
|
||||
goal_phase,
|
||||
target_info,
|
||||
cached_subs,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1063,6 +1031,7 @@ fn load_single_threaded<'a>(
|
||||
exposed_types: ExposedByModule,
|
||||
goal_phase: Phase,
|
||||
target_info: TargetInfo,
|
||||
cached_subs: MutMap<ModuleId, (Subs, Vec<(Symbol, Variable)>)>,
|
||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||
let LoadStart {
|
||||
arc_modules,
|
||||
@ -1084,6 +1053,7 @@ fn load_single_threaded<'a>(
|
||||
exposed_types,
|
||||
arc_modules,
|
||||
ident_ids_by_module,
|
||||
cached_subs,
|
||||
);
|
||||
|
||||
// We'll add tasks to this, and then worker threads will take tasks from it.
|
||||
@ -1240,6 +1210,7 @@ fn load_multi_threaded<'a>(
|
||||
exposed_types: ExposedByModule,
|
||||
goal_phase: Phase,
|
||||
target_info: TargetInfo,
|
||||
cached_subs: MutMap<ModuleId, (Subs, Vec<(Symbol, Variable)>)>,
|
||||
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||
let LoadStart {
|
||||
arc_modules,
|
||||
@ -1255,6 +1226,7 @@ fn load_multi_threaded<'a>(
|
||||
exposed_types,
|
||||
arc_modules,
|
||||
ident_ids_by_module,
|
||||
cached_subs,
|
||||
);
|
||||
|
||||
let (msg_tx, msg_rx) = bounded(1024);
|
||||
@ -3057,6 +3029,7 @@ impl<'a> BuildTask<'a> {
|
||||
exposed_types: &mut ExposedByModule,
|
||||
dep_idents: MutMap<ModuleId, IdentIds>,
|
||||
declarations: Vec<Declaration>,
|
||||
cached_subs: CachedSubs,
|
||||
) -> Self {
|
||||
let exposed_by_module = exposed_types.retain_modules(imported_modules.keys());
|
||||
let exposed_for_module =
|
||||
@ -3081,42 +3054,17 @@ impl<'a> BuildTask<'a> {
|
||||
declarations,
|
||||
dep_idents,
|
||||
module_timing,
|
||||
cached_subs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn run_solve<'a>(
|
||||
module: Module,
|
||||
ident_ids: IdentIds,
|
||||
mut module_timing: ModuleTiming,
|
||||
imported_builtins: Vec<Symbol>,
|
||||
fn add_imports(
|
||||
subs: &mut Subs,
|
||||
mut exposed_for_module: ExposedForModule,
|
||||
mut constraints: Constraints,
|
||||
constraint: ConstraintSoa,
|
||||
mut var_store: VarStore,
|
||||
decls: Vec<Declaration>,
|
||||
dep_idents: MutMap<ModuleId, IdentIds>,
|
||||
) -> Msg<'a> {
|
||||
// We have more constraining work to do now, so we'll add it to our timings.
|
||||
let constrain_start = SystemTime::now();
|
||||
|
||||
let (mut rigid_vars, mut def_types) =
|
||||
constrain_builtin_imports(borrow_stdlib(), imported_builtins, &mut var_store);
|
||||
|
||||
let constrain_end = SystemTime::now();
|
||||
|
||||
let module_id = module.module_id;
|
||||
|
||||
let Module {
|
||||
exposed_symbols,
|
||||
aliases,
|
||||
rigid_variables,
|
||||
..
|
||||
} = module;
|
||||
|
||||
let mut subs = Subs::new_from_varstore(var_store);
|
||||
|
||||
def_types: &mut Vec<(Symbol, Loc<roc_types::types::Type>)>,
|
||||
rigid_vars: &mut Vec<Variable>,
|
||||
) -> Vec<Variable> {
|
||||
let mut import_variables = Vec::new();
|
||||
|
||||
for symbol in exposed_for_module.imported_values {
|
||||
@ -3148,7 +3096,7 @@ fn run_solve<'a>(
|
||||
Some((_, x)) => *x,
|
||||
};
|
||||
|
||||
let copied_import = storage_subs.export_variable_to(&mut subs, variable);
|
||||
let copied_import = storage_subs.export_variable_to(subs, variable);
|
||||
|
||||
// not a typo; rigids are turned into flex during type inference, but when imported we must
|
||||
// consider them rigid variables
|
||||
@ -3169,6 +3117,36 @@ fn run_solve<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
import_variables
|
||||
}
|
||||
|
||||
fn run_solve_solve(
|
||||
imported_builtins: Vec<Symbol>,
|
||||
exposed_for_module: ExposedForModule,
|
||||
mut constraints: Constraints,
|
||||
constraint: ConstraintSoa,
|
||||
mut var_store: VarStore,
|
||||
module: Module,
|
||||
) -> (Solved<Subs>, Vec<(Symbol, Variable)>, Vec<solve::TypeError>) {
|
||||
let Module {
|
||||
exposed_symbols,
|
||||
aliases,
|
||||
rigid_variables,
|
||||
..
|
||||
} = module;
|
||||
|
||||
let (mut rigid_vars, mut def_types) =
|
||||
constrain_builtin_imports(borrow_stdlib(), imported_builtins, &mut var_store);
|
||||
|
||||
let mut subs = Subs::new_from_varstore(var_store);
|
||||
|
||||
let import_variables = add_imports(
|
||||
&mut subs,
|
||||
exposed_for_module,
|
||||
&mut def_types,
|
||||
&mut rigid_vars,
|
||||
);
|
||||
|
||||
let actual_constraint =
|
||||
constraints.let_import_constraint(rigid_vars, def_types, constraint, &import_variables);
|
||||
|
||||
@ -3189,11 +3167,12 @@ fn run_solve<'a>(
|
||||
let solved_subs = if true {
|
||||
solved_subs
|
||||
} else {
|
||||
let mut serialized = Vec::new();
|
||||
solved_subs.inner().serialize(&mut serialized).unwrap();
|
||||
let subs = Subs::deserialize(&serialized);
|
||||
|
||||
Solved(subs)
|
||||
panic!();
|
||||
// let mut serialized = Vec::new();
|
||||
// solved_subs.inner().serialize(&mut serialized).unwrap();
|
||||
// let subs = Subs::deserialize(&serialized);
|
||||
//
|
||||
// Solved(subs)
|
||||
};
|
||||
|
||||
let exposed_vars_by_symbol: Vec<_> = solved_env
|
||||
@ -3201,6 +3180,60 @@ fn run_solve<'a>(
|
||||
.filter(|(k, _)| exposed_symbols.contains(k))
|
||||
.collect();
|
||||
|
||||
(solved_subs, exposed_vars_by_symbol, problems)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn run_solve<'a>(
|
||||
module: Module,
|
||||
ident_ids: IdentIds,
|
||||
mut module_timing: ModuleTiming,
|
||||
imported_builtins: Vec<Symbol>,
|
||||
exposed_for_module: ExposedForModule,
|
||||
constraints: Constraints,
|
||||
constraint: ConstraintSoa,
|
||||
var_store: VarStore,
|
||||
decls: Vec<Declaration>,
|
||||
dep_idents: MutMap<ModuleId, IdentIds>,
|
||||
cached_subs: CachedSubs,
|
||||
) -> Msg<'a> {
|
||||
let solve_start = SystemTime::now();
|
||||
|
||||
let module_id = module.module_id;
|
||||
|
||||
// TODO remove when we write builtins in roc
|
||||
let aliases = module.aliases.clone();
|
||||
|
||||
let (solved_subs, exposed_vars_by_symbol, problems) = {
|
||||
if module_id.is_builtin() {
|
||||
match cached_subs.lock().remove(&module_id) {
|
||||
None => {
|
||||
// this should never happen
|
||||
run_solve_solve(
|
||||
imported_builtins,
|
||||
exposed_for_module,
|
||||
constraints,
|
||||
constraint,
|
||||
var_store,
|
||||
module,
|
||||
)
|
||||
}
|
||||
Some((subs, exposed_vars_by_symbol)) => {
|
||||
(Solved(subs), exposed_vars_by_symbol.to_vec(), vec![])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
run_solve_solve(
|
||||
imported_builtins,
|
||||
exposed_for_module,
|
||||
constraints,
|
||||
constraint,
|
||||
var_store,
|
||||
module,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let mut solved_subs = solved_subs;
|
||||
let (storage_subs, stored_vars_by_symbol) =
|
||||
roc_solve::module::exposed_types_storage_subs(&mut solved_subs, &exposed_vars_by_symbol);
|
||||
@ -3215,10 +3248,7 @@ fn run_solve<'a>(
|
||||
|
||||
// Record the final timings
|
||||
let solve_end = SystemTime::now();
|
||||
let constrain_elapsed = constrain_end.duration_since(constrain_start).unwrap();
|
||||
|
||||
module_timing.constrain += constrain_elapsed;
|
||||
module_timing.solve = solve_end.duration_since(constrain_end).unwrap();
|
||||
module_timing.solve = solve_end.duration_since(solve_start).unwrap();
|
||||
|
||||
// Send the subs to the main thread for processing,
|
||||
Msg::SolvedTypes {
|
||||
@ -3894,6 +3924,7 @@ fn run_task<'a>(
|
||||
ident_ids,
|
||||
declarations,
|
||||
dep_idents,
|
||||
cached_subs,
|
||||
} => Ok(run_solve(
|
||||
module,
|
||||
ident_ids,
|
||||
@ -3905,6 +3936,7 @@ fn run_task<'a>(
|
||||
var_store,
|
||||
declarations,
|
||||
dep_idents,
|
||||
cached_subs,
|
||||
)),
|
||||
BuildPendingSpecializations {
|
||||
module_id,
|
||||
|
@ -19,17 +19,43 @@ mod test_load {
|
||||
use roc_can::def::Declaration::*;
|
||||
use roc_can::def::Def;
|
||||
use roc_constrain::module::ExposedByModule;
|
||||
use roc_load_internal::file::{load_and_typecheck, LoadedModule};
|
||||
use roc_load_internal::file::{LoadResult, LoadStart, LoadedModule, LoadingProblem, Phase};
|
||||
use roc_module::ident::ModuleName;
|
||||
use roc_module::symbol::{Interns, ModuleId};
|
||||
use roc_problem::can::Problem;
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_reporting::report::can_problem;
|
||||
use roc_reporting::report::RocDocAllocator;
|
||||
use roc_target::TargetInfo;
|
||||
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
||||
use roc_types::subs::Subs;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
fn load_and_typecheck<'a>(
|
||||
arena: &'a Bump,
|
||||
filename: PathBuf,
|
||||
src_dir: &Path,
|
||||
exposed_types: ExposedByModule,
|
||||
target_info: TargetInfo,
|
||||
) -> Result<LoadedModule, LoadingProblem<'a>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, filename)?;
|
||||
|
||||
match roc_load_internal::file::load(
|
||||
arena,
|
||||
load_start,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
Phase::SolveTypes,
|
||||
target_info,
|
||||
Default::default(), // these tests will re-compile the builtins
|
||||
)? {
|
||||
Monomorphized(_) => unreachable!(""),
|
||||
TypeChecked(module) => Ok(module),
|
||||
}
|
||||
}
|
||||
|
||||
const TARGET_INFO: roc_target::TargetInfo = roc_target::TargetInfo::default_x86_64();
|
||||
|
||||
|
@ -63,27 +63,29 @@ struct ErrorTypeState {
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct SubsHeader {
|
||||
utable: usize,
|
||||
variables: usize,
|
||||
tag_names: usize,
|
||||
field_names: usize,
|
||||
record_fields: usize,
|
||||
variable_slices: usize,
|
||||
utable: u64,
|
||||
variables: u64,
|
||||
tag_names: u64,
|
||||
field_names: u64,
|
||||
record_fields: u64,
|
||||
variable_slices: u64,
|
||||
exposed_vars_by_symbol: u64,
|
||||
}
|
||||
|
||||
impl SubsHeader {
|
||||
fn from_subs(subs: &Subs) -> Self {
|
||||
fn from_subs(subs: &Subs, exposed_vars_by_symbol: usize) -> Self {
|
||||
// TODO what do we do with problems? they should
|
||||
// be reported and then removed from Subs I think
|
||||
debug_assert!(subs.problems.is_empty());
|
||||
|
||||
Self {
|
||||
utable: subs.utable.len(),
|
||||
variables: subs.variables.len(),
|
||||
tag_names: subs.tag_names.len(),
|
||||
field_names: subs.field_names.len(),
|
||||
record_fields: subs.record_fields.len(),
|
||||
variable_slices: subs.variable_slices.len(),
|
||||
utable: subs.utable.len() as u64,
|
||||
variables: subs.variables.len() as u64,
|
||||
tag_names: subs.tag_names.len() as u64,
|
||||
field_names: subs.field_names.len() as u64,
|
||||
record_fields: subs.record_fields.len() as u64,
|
||||
variable_slices: subs.variable_slices.len() as u64,
|
||||
exposed_vars_by_symbol: exposed_vars_by_symbol as u64,
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,10 +116,14 @@ enum SerializedTagName {
|
||||
}
|
||||
|
||||
impl Subs {
|
||||
pub fn serialize(&self, writer: &mut impl std::io::Write) -> std::io::Result<usize> {
|
||||
pub fn serialize(
|
||||
&self,
|
||||
exposed_vars_by_symbol: &[(Symbol, Variable)],
|
||||
writer: &mut impl std::io::Write,
|
||||
) -> std::io::Result<usize> {
|
||||
let mut written = 0;
|
||||
|
||||
let header = SubsHeader::from_subs(self).to_array();
|
||||
let header = SubsHeader::from_subs(self, exposed_vars_by_symbol.len()).to_array();
|
||||
written += header.len();
|
||||
writer.write_all(&header)?;
|
||||
|
||||
@ -128,6 +134,7 @@ impl Subs {
|
||||
written = Self::serialize_field_names(&self.field_names, writer, written)?;
|
||||
written = Self::serialize_slice(&self.record_fields, writer, written)?;
|
||||
written = Self::serialize_slice(&self.variable_slices, writer, written)?;
|
||||
written = Self::serialize_slice(exposed_vars_by_symbol, writer, written)?;
|
||||
|
||||
Ok(written)
|
||||
}
|
||||
@ -183,7 +190,7 @@ impl Subs {
|
||||
Self::serialize_slice(&buf, writer, written)
|
||||
}
|
||||
|
||||
/// Lowercase can be heap-allocated
|
||||
/// Global tag names can be heap-allocated
|
||||
fn serialize_tag_names(
|
||||
tag_names: &[TagName],
|
||||
writer: &mut impl std::io::Write,
|
||||
@ -231,7 +238,7 @@ impl Subs {
|
||||
Ok(written + padding_bytes + bytes_slice.len())
|
||||
}
|
||||
|
||||
pub fn deserialize(bytes: &[u8]) -> Self {
|
||||
pub fn deserialize(bytes: &[u8]) -> (Self, &[(Symbol, Variable)]) {
|
||||
use std::convert::TryInto;
|
||||
|
||||
let mut offset = 0;
|
||||
@ -239,25 +246,34 @@ impl Subs {
|
||||
offset += header_slice.len();
|
||||
let header = SubsHeader::from_array(header_slice.try_into().unwrap());
|
||||
|
||||
let (utable, offset) = Self::deserialize_unification_table(bytes, header.utable, offset);
|
||||
let (utable, offset) =
|
||||
Self::deserialize_unification_table(bytes, header.utable as usize, offset);
|
||||
|
||||
let (variables, offset) = Self::deserialize_slice(bytes, header.variables, offset);
|
||||
let (tag_names, offset) = Self::deserialize_tag_names(bytes, header.tag_names, offset);
|
||||
let (variables, offset) = Self::deserialize_slice(bytes, header.variables as usize, offset);
|
||||
let (tag_names, offset) =
|
||||
Self::deserialize_tag_names(bytes, header.tag_names as usize, offset);
|
||||
let (field_names, offset) =
|
||||
Self::deserialize_field_names(bytes, header.field_names, offset);
|
||||
let (record_fields, offset) = Self::deserialize_slice(bytes, header.record_fields, offset);
|
||||
let (variable_slices, _) = Self::deserialize_slice(bytes, header.variable_slices, offset);
|
||||
Self::deserialize_field_names(bytes, header.field_names as usize, offset);
|
||||
let (record_fields, offset) =
|
||||
Self::deserialize_slice(bytes, header.record_fields as usize, offset);
|
||||
let (variable_slices, offset) =
|
||||
Self::deserialize_slice(bytes, header.variable_slices as usize, offset);
|
||||
let (exposed_vars_by_symbol, _) =
|
||||
Self::deserialize_slice(bytes, header.exposed_vars_by_symbol as usize, offset);
|
||||
|
||||
Self {
|
||||
utable,
|
||||
variables: variables.to_vec(),
|
||||
tag_names: tag_names.to_vec(),
|
||||
field_names,
|
||||
record_fields: record_fields.to_vec(),
|
||||
variable_slices: variable_slices.to_vec(),
|
||||
tag_name_cache: Default::default(),
|
||||
problems: Default::default(),
|
||||
}
|
||||
(
|
||||
Self {
|
||||
utable,
|
||||
variables: variables.to_vec(),
|
||||
tag_names: tag_names.to_vec(),
|
||||
field_names,
|
||||
record_fields: record_fields.to_vec(),
|
||||
variable_slices: variable_slices.to_vec(),
|
||||
tag_name_cache: Default::default(),
|
||||
problems: Default::default(),
|
||||
},
|
||||
exposed_vars_by_symbol,
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_unification_table(
|
||||
|
Loading…
Reference in New Issue
Block a user