Merge pull request #2771 from rtfeldman/cache-stdlib-modules

Cache stdlib modules
This commit is contained in:
Richard Feldman 2022-03-29 17:30:38 -04:00 committed by GitHub
commit 24b8a68503
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 704 additions and 149 deletions

7
Cargo.lock generated
View File

@ -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]]

View File

@ -1,3 +1,7 @@
interface Bool
exposes [ Bool, and, or, not, isEq, isNotEq ]
imports [ ]
Bool : [ True, False ]
and : Bool, Bool -> Bool

View File

@ -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

View File

@ -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 ]*

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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
View 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();
}

View File

@ -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
}

View File

@ -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,

View File

@ -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();

View File

@ -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(