Add JSON builtin, pass along solved specializations per module

This commit is contained in:
Ayaz Hafiz 2022-05-11 14:31:06 -04:00
parent 312cdd0b70
commit 0f4be93e44
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
8 changed files with 93 additions and 13 deletions

View file

@ -12,6 +12,7 @@ pub fn module_source(module_id: ModuleId) -> &'static str {
ModuleId::BOX => BOX, ModuleId::BOX => BOX,
ModuleId::BOOL => BOOL, ModuleId::BOOL => BOOL,
ModuleId::ENCODE => ENCODE, ModuleId::ENCODE => ENCODE,
ModuleId::JSON => JSON,
_ => panic!( _ => panic!(
"ModuleId {:?} is not part of the standard library", "ModuleId {:?} is not part of the standard library",
module_id module_id
@ -28,3 +29,4 @@ const SET: &str = include_str!("../roc/Set.roc");
const BOX: &str = include_str!("../roc/Box.roc"); const BOX: &str = include_str!("../roc/Box.roc");
const BOOL: &str = include_str!("../roc/Bool.roc"); const BOOL: &str = include_str!("../roc/Bool.roc");
const ENCODE: &str = include_str!("../roc/Encode.roc"); const ENCODE: &str = include_str!("../roc/Encode.roc");
const JSON: &str = include_str!("../roc/Json.roc");

View file

@ -1,4 +1,4 @@
use roc_collections::{all::MutMap, VecSet}; use roc_collections::{all::MutMap, VecMap, VecSet};
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_region::all::Region; use roc_region::all::Region;
@ -46,6 +46,8 @@ impl AbilityMemberData {
} }
} }
pub type SolvedSpecializations = VecMap<(Symbol, Symbol), MemberSpecialization>;
/// A particular specialization of an ability member. /// A particular specialization of an ability member.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MemberSpecialization { pub struct MemberSpecialization {
@ -88,7 +90,7 @@ pub struct AbilitiesStore {
/// Maps a tuple (member, type) specifying that `type` declares an implementation of an ability /// Maps a tuple (member, type) specifying that `type` declares an implementation of an ability
/// member `member`, to the exact symbol that implements the ability. /// member `member`, to the exact symbol that implements the ability.
declared_specializations: MutMap<(Symbol, Symbol), MemberSpecialization>, declared_specializations: SolvedSpecializations,
next_specialization_id: u32, next_specialization_id: u32,

View file

@ -1,6 +1,6 @@
use crate::expr::{constrain_def_make_constraint, constrain_def_pattern, Env}; use crate::expr::{constrain_def_make_constraint, constrain_def_pattern, Env};
use roc_builtins::std::StdLib; use roc_builtins::std::StdLib;
use roc_can::abilities::{AbilitiesStore, MemberTypeInfo}; use roc_can::abilities::{AbilitiesStore, MemberTypeInfo, SolvedSpecializations};
use roc_can::constraint::{Constraint, Constraints}; use roc_can::constraint::{Constraint, Constraints};
use roc_can::def::Declaration; use roc_can::def::Declaration;
use roc_can::expected::Expected; use roc_can::expected::Expected;
@ -89,6 +89,7 @@ impl ExposedForModule {
pub struct ExposedModuleTypes { pub struct ExposedModuleTypes {
pub stored_vars_by_symbol: Vec<(Symbol, Variable)>, pub stored_vars_by_symbol: Vec<(Symbol, Variable)>,
pub storage_subs: roc_types::subs::StorageSubs, pub storage_subs: roc_types::subs::StorageSubs,
pub solved_specializations: SolvedSpecializations,
} }
pub fn constrain_module( pub fn constrain_module(

View file

@ -14,6 +14,7 @@ const MODULES: &[(ModuleId, &str)] = &[
(ModuleId::SET, "Set.roc"), (ModuleId::SET, "Set.roc"),
(ModuleId::BOX, "Box.roc"), (ModuleId::BOX, "Box.roc"),
(ModuleId::ENCODE, "Encode.roc"), (ModuleId::ENCODE, "Encode.roc"),
(ModuleId::JSON, "Json.roc"),
]; ];
fn main() { fn main() {

View file

@ -6,11 +6,11 @@ use crossbeam::thread;
use parking_lot::Mutex; use parking_lot::Mutex;
use roc_builtins::roc::module_source; use roc_builtins::roc::module_source;
use roc_builtins::std::borrow_stdlib; use roc_builtins::std::borrow_stdlib;
use roc_can::abilities::AbilitiesStore; use roc_can::abilities::{AbilitiesStore, SolvedSpecializations};
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints}; use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
use roc_can::def::Declaration; use roc_can::def::Declaration;
use roc_can::module::{canonicalize_module_defs, Module}; use roc_can::module::{canonicalize_module_defs, Module};
use roc_collections::{default_hasher, BumpMap, MutMap, MutSet, VecSet}; use roc_collections::{default_hasher, BumpMap, MutMap, MutSet, VecMap, VecSet};
use roc_constrain::module::{ use roc_constrain::module::{
constrain_builtin_imports, constrain_module, ExposedByModule, ExposedForModule, constrain_builtin_imports, constrain_module, ExposedByModule, ExposedForModule,
ExposedModuleTypes, ExposedModuleTypes,
@ -166,6 +166,7 @@ impl Default for ModuleCache<'_> {
NUM, NUM,
BOX, BOX,
ENCODE, ENCODE,
JSON,
} }
Self { Self {
@ -376,7 +377,7 @@ fn start_phase<'a>(
constraint, constraint,
var_store, var_store,
imported_modules, imported_modules,
&mut state.exposed_types, &state.exposed_types,
dep_idents, dep_idents,
declarations, declarations,
state.cached_subs.clone(), state.cached_subs.clone(),
@ -2132,6 +2133,7 @@ fn update<'a>(
ExposedModuleTypes { ExposedModuleTypes {
stored_vars_by_symbol: solved_module.stored_vars_by_symbol, stored_vars_by_symbol: solved_module.stored_vars_by_symbol,
storage_subs: solved_module.storage_subs, storage_subs: solved_module.storage_subs,
solved_specializations: solved_module.solved_specializations,
}, },
); );
@ -2687,6 +2689,7 @@ fn load_module<'a>(
"Bool", ModuleId::BOOL "Bool", ModuleId::BOOL
"Box", ModuleId::BOX "Box", ModuleId::BOX
"Encode", ModuleId::ENCODE "Encode", ModuleId::ENCODE
"Json", ModuleId::JSON
} }
let (filename, opt_shorthand) = module_name_to_path(src_dir, module_name, arc_shorthands); let (filename, opt_shorthand) = module_name_to_path(src_dir, module_name, arc_shorthands);
@ -3486,19 +3489,41 @@ impl<'a> BuildTask<'a> {
// TODO trim down these arguments - possibly by moving Constraint into Module // TODO trim down these arguments - possibly by moving Constraint into Module
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn solve_module( fn solve_module(
module: Module, mut module: Module,
ident_ids: IdentIds, ident_ids: IdentIds,
module_timing: ModuleTiming, module_timing: ModuleTiming,
constraints: Constraints, constraints: Constraints,
constraint: ConstraintSoa, constraint: ConstraintSoa,
var_store: VarStore, var_store: VarStore,
imported_modules: MutMap<ModuleId, Region>, imported_modules: MutMap<ModuleId, Region>,
exposed_types: &mut ExposedByModule, exposed_types: &ExposedByModule,
dep_idents: IdentIdsByModule, dep_idents: IdentIdsByModule,
declarations: Vec<Declaration>, declarations: Vec<Declaration>,
cached_subs: CachedSubs, cached_subs: CachedSubs,
) -> Self { ) -> Self {
let exposed_by_module = exposed_types.retain_modules(imported_modules.keys()); let exposed_by_module = exposed_types.retain_modules(imported_modules.keys());
let abilities_store = &mut module.abilities_store;
for module in imported_modules.keys() {
let exposed = exposed_by_module
.get(module)
.unwrap_or_else(|| internal_error!("No exposed types for {:?}", module));
if let ExposedModuleTypes::Valid {
solved_specializations,
..
} = exposed
{
for ((member, typ), specialization) in solved_specializations.iter() {
abilities_store.register_specialization_for_type(
*member,
*typ,
*specialization,
);
}
}
}
let exposed_for_module = let exposed_for_module =
ExposedForModule::new(module.referenced_values.iter(), exposed_by_module); ExposedForModule::new(module.referenced_values.iter(), exposed_by_module);
@ -3594,6 +3619,7 @@ fn run_solve_solve(
module: Module, module: Module,
) -> ( ) -> (
Solved<Subs>, Solved<Subs>,
SolvedSpecializations,
Vec<(Symbol, Variable)>, Vec<(Symbol, Variable)>,
Vec<solve::TypeError>, Vec<solve::TypeError>,
AbilitiesStore, AbilitiesStore,
@ -3611,6 +3637,19 @@ fn run_solve_solve(
let mut subs = Subs::new_from_varstore(var_store); let mut subs = Subs::new_from_varstore(var_store);
// We don't know what types we're about to solve for in our module, so we need to include the
// solved abilities across all dependencies.
// TODO: there's got to be a better way to do this. Maybe keep a cache of module -> solved
// abilities?
// let mut exposed_for_module = exposed_for_module;
// let mut imported_modules = VecSet::with_capacity(2);
// for imported in exposed_for_module.imported_values.iter() {
// imported_modules.insert(imported.module_id());
// }
// for module in imported_modules.into_iter() {
// let typechecked =
// }
let import_variables = add_imports( let import_variables = add_imports(
&mut subs, &mut subs,
&mut abilities_store, &mut abilities_store,
@ -3628,7 +3667,7 @@ fn run_solve_solve(
solve_aliases.insert(*name, alias.clone()); solve_aliases.insert(*name, alias.clone());
} }
let (solved_subs, exposed_vars_by_symbol, problems, abilities_store) = { let (solved_subs, solved_specializations, exposed_vars_by_symbol, problems, abilities_store) = {
let (solved_subs, solved_env, problems, abilities_store) = roc_solve::module::run_solve( let (solved_subs, solved_env, problems, abilities_store) = roc_solve::module::run_solve(
&constraints, &constraints,
actual_constraint, actual_constraint,
@ -3638,13 +3677,36 @@ fn run_solve_solve(
abilities_store, abilities_store,
); );
// STORE ABILITIES
let module_id = module.module_id;
let known_specializations =
abilities_store
.get_known_specializations()
.filter(|(member, typ)| {
// This module solved this specialization if either the member or the type comes from the
// module.
member.module_id() == module_id || typ.module_id() == module_id
});
let mut solved_specializations: SolvedSpecializations = VecMap::default();
let mut specialization_symbols = VecSet::default();
for (member, typ) in known_specializations {
let specialization = abilities_store.get_specialization(member, typ).unwrap();
specialization_symbols.insert(specialization.symbol);
solved_specializations.insert((member, typ), specialization);
}
// END STORE ABILITIES
// Expose anything that is explicitly exposed by the header, or is a specialization of an
// ability.
let exposed_vars_by_symbol: Vec<_> = solved_env let exposed_vars_by_symbol: Vec<_> = solved_env
.vars_by_symbol() .vars_by_symbol()
.filter(|(k, _)| exposed_symbols.contains(k)) .filter(|(k, _)| exposed_symbols.contains(k) || specialization_symbols.contains(k))
.collect(); .collect();
( (
solved_subs, solved_subs,
solved_specializations,
exposed_vars_by_symbol, exposed_vars_by_symbol,
problems, problems,
abilities_store, abilities_store,
@ -3653,6 +3715,7 @@ fn run_solve_solve(
( (
solved_subs, solved_subs,
solved_specializations,
exposed_vars_by_symbol, exposed_vars_by_symbol,
problems, problems,
abilities_store, abilities_store,
@ -3680,7 +3743,7 @@ fn run_solve<'a>(
// TODO remove when we write builtins in roc // TODO remove when we write builtins in roc
let aliases = module.aliases.clone(); let aliases = module.aliases.clone();
let (solved_subs, exposed_vars_by_symbol, problems, abilities_store) = { let (solved_subs, solved_specializations, exposed_vars_by_symbol, problems, abilities_store) = {
if module_id.is_builtin() { if module_id.is_builtin() {
match cached_subs.lock().remove(&module_id) { match cached_subs.lock().remove(&module_id) {
None => run_solve_solve( None => run_solve_solve(
@ -3694,6 +3757,8 @@ fn run_solve<'a>(
Some((subs, exposed_vars_by_symbol)) => { Some((subs, exposed_vars_by_symbol)) => {
( (
Solved(subs), Solved(subs),
// TODO(abilities) replace when we have abilities for builtins
VecMap::default(),
exposed_vars_by_symbol.to_vec(), exposed_vars_by_symbol.to_vec(),
vec![], vec![],
// TODO(abilities) replace when we have abilities for builtins // TODO(abilities) replace when we have abilities for builtins
@ -3722,6 +3787,7 @@ fn run_solve<'a>(
problems, problems,
aliases, aliases,
stored_vars_by_symbol, stored_vars_by_symbol,
solved_specializations,
storage_subs, storage_subs,
}; };

View file

@ -90,6 +90,7 @@ impl ModuleName {
pub const RESULT: &'static str = "Result"; pub const RESULT: &'static str = "Result";
pub const BOX: &'static str = "Box"; pub const BOX: &'static str = "Box";
pub const ENCODE: &'static str = "Encode"; pub const ENCODE: &'static str = "Encode";
pub const JSON: &'static str = "Json";
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
self.0.as_str() self.0.as_str()

View file

@ -1313,6 +1313,9 @@ define_builtins! {
9 ENCODE: "Encode" => { 9 ENCODE: "Encode" => {
0 ENCODE_ENCODE: "Encode" 0 ENCODE_ENCODE: "Encode"
} }
10 JSON: "Json" => {
0 JSON_JSON: "Json"
}
num_modules: 10 // Keep this count up to date by hand! (TODO: see the mut_map! macro for how we could determine this count correctly in the macro) num_modules: 11 // Keep this count up to date by hand! (TODO: see the mut_map! macro for how we could determine this count correctly in the macro)
} }

View file

@ -1,5 +1,5 @@
use crate::solve::{self, Aliases}; use crate::solve::{self, Aliases};
use roc_can::abilities::AbilitiesStore; use roc_can::abilities::{AbilitiesStore, SolvedSpecializations};
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints}; use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
use roc_can::module::RigidVariables; use roc_can::module::RigidVariables;
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
@ -20,11 +20,15 @@ pub struct SolvedModule {
/// to create the types for HostExposed. This /// to create the types for HostExposed. This
/// has some overlap with the StorageSubs fields, /// has some overlap with the StorageSubs fields,
/// so maybe we can get rid of this at some point /// so maybe we can get rid of this at some point
///
/// Contains both variables of symbols that are explicitly exposed by the header,
/// and the variables of any solved ability specializations we have.
pub exposed_vars_by_symbol: Vec<(Symbol, Variable)>, pub exposed_vars_by_symbol: Vec<(Symbol, Variable)>,
/// Used when importing this module into another module /// Used when importing this module into another module
pub stored_vars_by_symbol: Vec<(Symbol, Variable)>, pub stored_vars_by_symbol: Vec<(Symbol, Variable)>,
pub storage_subs: StorageSubs, pub storage_subs: StorageSubs,
pub solved_specializations: SolvedSpecializations,
} }
pub fn run_solve( pub fn run_solve(