remove another result wrapper

This commit is contained in:
Folkert 2022-05-08 17:09:33 +02:00
parent d5b010cb13
commit 2e9477e011
No known key found for this signature in database
GPG Key ID: 1F17F6FFD112B97C
2 changed files with 296 additions and 313 deletions

View File

@ -170,7 +170,7 @@ pub fn canonicalize_module_defs<'a>(
exposed_symbols: &VecSet<Symbol>, exposed_symbols: &VecSet<Symbol>,
symbols_from_requires: &[(Loc<Symbol>, Loc<TypeAnnotation<'a>>)], symbols_from_requires: &[(Loc<Symbol>, Loc<TypeAnnotation<'a>>)],
var_store: &mut VarStore, var_store: &mut VarStore,
) -> Result<ModuleOutput, RuntimeError> { ) -> ModuleOutput {
let mut can_exposed_imports = MutMap::default(); let mut can_exposed_imports = MutMap::default();
let mut scope = Scope::new(home, exposed_ident_ids); let mut scope = Scope::new(home, exposed_ident_ids);
let mut env = Env::new(home, dep_idents, module_ids); let mut env = Env::new(home, dep_idents, module_ids);
@ -351,238 +351,231 @@ pub fn canonicalize_module_defs<'a>(
..Default::default() ..Default::default()
}; };
match sort_can_defs(&mut env, defs, new_output) { let (mut declarations, mut output) = sort_can_defs(&mut env, defs, new_output);
(mut declarations, mut output) => {
use crate::def::Declaration::*;
let symbols_from_requires = symbols_from_requires let symbols_from_requires = symbols_from_requires
.iter() .iter()
.map(|(symbol, loc_ann)| { .map(|(symbol, loc_ann)| {
let ann = canonicalize_annotation( let ann = canonicalize_annotation(
&mut env, &mut env,
&mut scope, &mut scope,
&loc_ann.value, &loc_ann.value,
loc_ann.region, loc_ann.region,
var_store, var_store,
&output.abilities_in_scope, &output.abilities_in_scope,
); );
ann.add_to( ann.add_to(
&mut output.aliases, &mut output.aliases,
&mut output.references, &mut output.references,
&mut output.introduced_variables, &mut output.introduced_variables,
); );
( (
*symbol, *symbol,
Loc { Loc {
value: ann.typ, value: ann.typ,
region: loc_ann.region, region: loc_ann.region,
}, },
) )
}) })
.collect(); .collect();
if let GeneratedInfo::Hosted { if let GeneratedInfo::Hosted {
effect_symbol, effect_symbol,
generated_functions, generated_functions,
} = generated_info } = generated_info
{ {
let mut exposed_symbols = VecSet::default(); let mut exposed_symbols = VecSet::default();
// NOTE this currently builds all functions, not just the ones that the user requested // NOTE this currently builds all functions, not just the ones that the user requested
crate::effect_module::build_effect_builtins( crate::effect_module::build_effect_builtins(
&mut scope, &mut scope,
effect_symbol, effect_symbol,
var_store, var_store,
&mut exposed_symbols, &mut exposed_symbols,
&mut declarations, &mut declarations,
generated_functions, generated_functions,
); );
}
use crate::def::Declaration::*;
for decl in declarations.iter_mut() {
match decl {
Declare(def) => {
for (symbol, _) in def.pattern_vars.iter() {
if exposed_but_not_defined.contains(symbol) {
// Remove this from exposed_symbols,
// so that at the end of the process,
// we can see if there were any
// exposed symbols which did not have
// corresponding defs.
exposed_but_not_defined.remove(symbol);
}
}
// Temporary hack: we don't know exactly what symbols are hosted symbols,
// and which are meant to be normal definitions without a body. So for now
// we just assume they are hosted functions (meant to be provided by the platform)
if has_no_implementation(&def.loc_expr.value) {
match generated_info {
GeneratedInfo::Builtin => {
let symbol = def.pattern_vars.iter().next().unwrap().0;
match crate::builtins::builtin_defs_map(*symbol, var_store) {
None => {
panic!("A builtin module contains a signature without implementation for {:?}", symbol)
}
Some(mut replacement_def) => {
replacement_def.annotation = def.annotation.take();
*def = replacement_def;
}
}
}
GeneratedInfo::Hosted { effect_symbol, .. } => {
let symbol = def.pattern_vars.iter().next().unwrap().0;
let ident_id = symbol.ident_id();
let ident = scope
.locals
.ident_ids
.get_name(ident_id)
.unwrap()
.to_string();
let def_annotation = def.annotation.clone().unwrap();
let annotation = crate::annotation::Annotation {
typ: def_annotation.signature,
introduced_variables: def_annotation.introduced_variables,
references: Default::default(),
aliases: Default::default(),
};
let hosted_def = crate::effect_module::build_host_exposed_def(
&mut scope,
*symbol,
&ident,
effect_symbol,
var_store,
annotation,
);
*def = hosted_def;
}
_ => (),
}
}
} }
DeclareRec(defs) => {
for decl in declarations.iter_mut() { for def in defs {
match decl { for (symbol, _) in def.pattern_vars.iter() {
Declare(def) => { if exposed_but_not_defined.contains(symbol) {
for (symbol, _) in def.pattern_vars.iter() { // Remove this from exposed_symbols,
if exposed_but_not_defined.contains(symbol) { // so that at the end of the process,
// Remove this from exposed_symbols, // we can see if there were any
// so that at the end of the process, // exposed symbols which did not have
// we can see if there were any // corresponding defs.
// exposed symbols which did not have exposed_but_not_defined.remove(symbol);
// corresponding defs.
exposed_but_not_defined.remove(symbol);
}
} }
// Temporary hack: we don't know exactly what symbols are hosted symbols,
// and which are meant to be normal definitions without a body. So for now
// we just assume they are hosted functions (meant to be provided by the platform)
if has_no_implementation(&def.loc_expr.value) {
match generated_info {
GeneratedInfo::Builtin => {
let symbol = def.pattern_vars.iter().next().unwrap().0;
match crate::builtins::builtin_defs_map(*symbol, var_store) {
None => {
panic!("A builtin module contains a signature without implementation for {:?}", symbol)
}
Some(mut replacement_def) => {
replacement_def.annotation = def.annotation.take();
*def = replacement_def;
}
}
}
GeneratedInfo::Hosted { effect_symbol, .. } => {
let symbol = def.pattern_vars.iter().next().unwrap().0;
let ident_id = symbol.ident_id();
let ident = scope
.locals
.ident_ids
.get_name(ident_id)
.unwrap()
.to_string();
let def_annotation = def.annotation.clone().unwrap();
let annotation = crate::annotation::Annotation {
typ: def_annotation.signature,
introduced_variables: def_annotation.introduced_variables,
references: Default::default(),
aliases: Default::default(),
};
let hosted_def = crate::effect_module::build_host_exposed_def(
&mut scope,
*symbol,
&ident,
effect_symbol,
var_store,
annotation,
);
*def = hosted_def;
}
_ => (),
}
}
}
DeclareRec(defs) => {
for def in defs {
for (symbol, _) in def.pattern_vars.iter() {
if exposed_but_not_defined.contains(symbol) {
// Remove this from exposed_symbols,
// so that at the end of the process,
// we can see if there were any
// exposed symbols which did not have
// corresponding defs.
exposed_but_not_defined.remove(symbol);
}
}
}
}
InvalidCycle(entries) => {
env.problems.push(Problem::BadRecursion(entries.to_vec()));
}
Builtin(def) => {
// Builtins cannot be exposed in module declarations.
// This should never happen!
debug_assert!(def
.pattern_vars
.iter()
.all(|(symbol, _)| !exposed_but_not_defined.contains(symbol)));
} }
} }
} }
let mut aliases = MutMap::default(); InvalidCycle(entries) => {
env.problems.push(Problem::BadRecursion(entries.to_vec()));
if let GeneratedInfo::Hosted { effect_symbol, .. } = generated_info {
// Remove this from exposed_symbols,
// so that at the end of the process,
// we can see if there were any
// exposed symbols which did not have
// corresponding defs.
exposed_but_not_defined.remove(&effect_symbol);
let hosted_alias = scope.lookup_alias(effect_symbol).unwrap().clone();
aliases.insert(effect_symbol, hosted_alias);
} }
Builtin(def) => {
for (symbol, alias) in output.aliases { // Builtins cannot be exposed in module declarations.
// Remove this from exposed_symbols, // This should never happen!
// so that at the end of the process, debug_assert!(def
// we can see if there were any .pattern_vars
// exposed symbols which did not have .iter()
// corresponding defs. .all(|(symbol, _)| !exposed_but_not_defined.contains(symbol)));
exposed_but_not_defined.remove(&symbol);
aliases.insert(symbol, alias);
} }
for member in scope.abilities_store.root_ability_members().keys() {
exposed_but_not_defined.remove(member);
}
// By this point, all exposed symbols should have been removed from
// exposed_symbols and added to exposed_vars_by_symbol. If any were
// not, that means they were declared as exposed but there was
// no actual declaration with that name!
for symbol in exposed_but_not_defined {
env.problem(Problem::ExposedButNotDefined(symbol));
// In case this exposed value is referenced by other modules,
// create a decl for it whose implementation is a runtime error.
let mut pattern_vars = SendMap::default();
pattern_vars.insert(symbol, var_store.fresh());
let runtime_error = RuntimeError::ExposedButNotDefined(symbol);
let def = Def {
loc_pattern: Loc::at(Region::zero(), Pattern::Identifier(symbol)),
loc_expr: Loc::at(Region::zero(), Expr::RuntimeError(runtime_error)),
expr_var: var_store.fresh(),
pattern_vars,
annotation: None,
};
declarations.push(Declaration::Declare(def));
}
// Incorporate any remaining output.lookups entries into references.
referenced_values.extend(output.references.value_lookups().copied());
referenced_types.extend(output.references.type_lookups().copied());
// Incorporate any remaining output.calls entries into references.
referenced_values.extend(output.references.calls().copied());
// Gather up all the symbols that were referenced from other modules.
referenced_values.extend(env.qualified_value_lookups.iter().copied());
referenced_types.extend(env.qualified_type_lookups.iter().copied());
for declaration in declarations.iter_mut() {
match declaration {
Declare(def) => fix_values_captured_in_closure_def(def, &mut VecSet::default()),
DeclareRec(defs) => {
fix_values_captured_in_closure_defs(defs, &mut VecSet::default())
}
InvalidCycle(_) | Builtin(_) => {}
}
}
let output = ModuleOutput {
scope,
aliases,
rigid_variables,
declarations,
referenced_values,
referenced_types,
exposed_imports: can_exposed_imports,
problems: env.problems,
symbols_from_requires,
lookups,
};
Ok(output)
} }
} }
let mut aliases = MutMap::default();
if let GeneratedInfo::Hosted { effect_symbol, .. } = generated_info {
// Remove this from exposed_symbols,
// so that at the end of the process,
// we can see if there were any
// exposed symbols which did not have
// corresponding defs.
exposed_but_not_defined.remove(&effect_symbol);
let hosted_alias = scope.lookup_alias(effect_symbol).unwrap().clone();
aliases.insert(effect_symbol, hosted_alias);
}
for (symbol, alias) in output.aliases {
// Remove this from exposed_symbols,
// so that at the end of the process,
// we can see if there were any
// exposed symbols which did not have
// corresponding defs.
exposed_but_not_defined.remove(&symbol);
aliases.insert(symbol, alias);
}
for member in scope.abilities_store.root_ability_members().keys() {
exposed_but_not_defined.remove(member);
}
// By this point, all exposed symbols should have been removed from
// exposed_symbols and added to exposed_vars_by_symbol. If any were
// not, that means they were declared as exposed but there was
// no actual declaration with that name!
for symbol in exposed_but_not_defined {
env.problem(Problem::ExposedButNotDefined(symbol));
// In case this exposed value is referenced by other modules,
// create a decl for it whose implementation is a runtime error.
let mut pattern_vars = SendMap::default();
pattern_vars.insert(symbol, var_store.fresh());
let runtime_error = RuntimeError::ExposedButNotDefined(symbol);
let def = Def {
loc_pattern: Loc::at(Region::zero(), Pattern::Identifier(symbol)),
loc_expr: Loc::at(Region::zero(), Expr::RuntimeError(runtime_error)),
expr_var: var_store.fresh(),
pattern_vars,
annotation: None,
};
declarations.push(Declaration::Declare(def));
}
// Incorporate any remaining output.lookups entries into references.
referenced_values.extend(output.references.value_lookups().copied());
referenced_types.extend(output.references.type_lookups().copied());
// Incorporate any remaining output.calls entries into references.
referenced_values.extend(output.references.calls().copied());
// Gather up all the symbols that were referenced from other modules.
referenced_values.extend(env.qualified_value_lookups.iter().copied());
referenced_types.extend(env.qualified_type_lookups.iter().copied());
for declaration in declarations.iter_mut() {
match declaration {
Declare(def) => fix_values_captured_in_closure_def(def, &mut VecSet::default()),
DeclareRec(defs) => fix_values_captured_in_closure_defs(defs, &mut VecSet::default()),
InvalidCycle(_) | Builtin(_) => {}
}
}
ModuleOutput {
scope,
aliases,
rigid_variables,
declarations,
referenced_values,
referenced_types,
exposed_imports: can_exposed_imports,
problems: env.problems,
symbols_from_requires,
lookups,
}
} }
fn fix_values_captured_in_closure_def( fn fix_values_captured_in_closure_def(

View File

@ -3873,7 +3873,7 @@ fn canonicalize_and_constrain<'a>(
let before = roc_types::types::get_type_clone_count(); let before = roc_types::types::get_type_clone_count();
let mut var_store = VarStore::default(); let mut var_store = VarStore::default();
let canonicalized = canonicalize_module_defs( let module_output = canonicalize_module_defs(
arena, arena,
parsed_defs, parsed_defs,
&header_for, &header_for,
@ -3902,106 +3902,96 @@ fn canonicalize_and_constrain<'a>(
module_timing.canonicalize = canonicalize_end.duration_since(canonicalize_start).unwrap(); module_timing.canonicalize = canonicalize_end.duration_since(canonicalize_start).unwrap();
match canonicalized { // Generate documentation information
Ok(module_output) => { // TODO: store timing information?
// Generate documentation information let module_docs = match module_name {
// TODO: store timing information? ModuleNameEnum::PkgConfig => None,
let module_docs = match module_name { ModuleNameEnum::App(_) => None,
ModuleNameEnum::PkgConfig => None, ModuleNameEnum::Interface(name) | ModuleNameEnum::Hosted(name) => {
ModuleNameEnum::App(_) => None, let docs = crate::docs::generate_module_docs(
ModuleNameEnum::Interface(name) | ModuleNameEnum::Hosted(name) => { module_output.scope.clone(),
let docs = crate::docs::generate_module_docs( name.as_str().into(),
module_output.scope.clone(), parsed_defs,
name.as_str().into(),
parsed_defs,
);
Some(docs)
}
};
let before = roc_types::types::get_type_clone_count();
let mut constraints = Constraints::new();
let constraint = if skip_constraint_gen {
roc_can::constraint::Constraint::True
} else {
constrain_module(
&mut constraints,
module_output.symbols_from_requires,
&module_output.scope.abilities_store,
&module_output.declarations,
module_id,
)
};
let after = roc_types::types::get_type_clone_count();
log!(
"constraint gen of {:?} cloned Type {} times ({} -> {})",
module_id,
after - before,
before,
after
); );
// scope has imported aliases, but misses aliases from inner scopes Some(docs)
// module_output.aliases does have those aliases, so we combine them }
let mut aliases: MutMap<Symbol, (bool, Alias)> = module_output };
.aliases
.into_iter() let before = roc_types::types::get_type_clone_count();
.map(|(k, v)| (k, (true, v)))
.collect(); let mut constraints = Constraints::new();
for (name, alias) in module_output.scope.aliases {
match aliases.entry(name) { let constraint = if skip_constraint_gen {
Occupied(_) => { roc_can::constraint::Constraint::True
// do nothing } else {
} constrain_module(
Vacant(vacant) => { &mut constraints,
if !name.is_builtin() { module_output.symbols_from_requires,
vacant.insert((false, alias)); &module_output.scope.abilities_store,
} &module_output.declarations,
} module_id,
)
};
let after = roc_types::types::get_type_clone_count();
log!(
"constraint gen of {:?} cloned Type {} times ({} -> {})",
module_id,
after - before,
before,
after
);
// scope has imported aliases, but misses aliases from inner scopes
// module_output.aliases does have those aliases, so we combine them
let mut aliases: MutMap<Symbol, (bool, Alias)> = module_output
.aliases
.into_iter()
.map(|(k, v)| (k, (true, v)))
.collect();
for (name, alias) in module_output.scope.aliases {
match aliases.entry(name) {
Occupied(_) => {
// do nothing
}
Vacant(vacant) => {
if !name.is_builtin() {
vacant.insert((false, alias));
} }
} }
let module = Module {
module_id,
exposed_imports: module_output.exposed_imports,
exposed_symbols,
referenced_values: module_output.referenced_values,
referenced_types: module_output.referenced_types,
aliases,
rigid_variables: module_output.rigid_variables,
abilities_store: module_output.scope.abilities_store,
};
let constrained_module = ConstrainedModule {
module,
declarations: module_output.declarations,
imported_modules,
var_store,
constraints,
constraint,
ident_ids: module_output.scope.locals.ident_ids,
dep_idents,
module_timing,
};
Ok(Msg::CanonicalizedAndConstrained {
constrained_module,
canonicalization_problems: module_output.problems,
module_docs,
})
}
Err(runtime_error) => {
panic!(
"TODO gracefully handle module canonicalization error {:?}",
runtime_error
);
} }
} }
let module = Module {
module_id,
exposed_imports: module_output.exposed_imports,
exposed_symbols,
referenced_values: module_output.referenced_values,
referenced_types: module_output.referenced_types,
aliases,
rigid_variables: module_output.rigid_variables,
abilities_store: module_output.scope.abilities_store,
};
let constrained_module = ConstrainedModule {
module,
declarations: module_output.declarations,
imported_modules,
var_store,
constraints,
constraint,
ident_ids: module_output.scope.locals.ident_ids,
dep_idents,
module_timing,
};
Ok(Msg::CanonicalizedAndConstrained {
constrained_module,
canonicalization_problems: module_output.problems,
module_docs,
})
} }
fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, LoadingProblem<'a>> { fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, LoadingProblem<'a>> {