make Str + Result work

This commit is contained in:
Folkert 2022-02-26 17:52:24 +01:00
parent d1d7cfef44
commit c0d3543d5a
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
12 changed files with 401 additions and 142 deletions

View file

@ -65,6 +65,96 @@ fn validate_generate_with<'a>(
(functions, unknown)
}
#[derive(Debug)]
enum GeneratedInfo<'a> {
Hosted {
effect_symbol: Symbol,
generated_functions: HostedGeneratedFunctions,
},
Builtin {
generated_functions: &'a [Symbol],
},
NotSpecial,
}
impl<'a> GeneratedInfo<'a> {
fn from_header_for(
env: &mut Env,
scope: &mut Scope,
var_store: &mut VarStore,
header_for: &HeaderFor<'a>,
) -> Self {
match header_for {
HeaderFor::Hosted {
generates,
generates_with,
} => {
let name: &str = generates.into();
let (generated_functions, unknown_generated) =
validate_generate_with(generates_with);
for unknown in unknown_generated {
env.problem(Problem::UnknownGeneratesWith(unknown));
}
let effect_symbol = scope
.introduce(
name.into(),
&env.exposed_ident_ids,
&mut env.ident_ids,
Region::zero(),
)
.unwrap();
let effect_tag_name = TagName::Private(effect_symbol);
{
let a_var = var_store.fresh();
let actual = crate::effect_module::build_effect_actual(
effect_tag_name,
Type::Variable(a_var),
var_store,
);
scope.add_alias(
effect_symbol,
Region::zero(),
vec![Loc::at_zero(("a".into(), a_var))],
actual,
AliasKind::Structural,
);
}
GeneratedInfo::Hosted {
effect_symbol,
generated_functions,
}
}
HeaderFor::Builtin { generates_with } => GeneratedInfo::Builtin {
generated_functions: generates_with,
},
_ => GeneratedInfo::NotSpecial,
}
}
}
fn has_no_implementation(expr: &Expr) -> bool {
match expr {
Expr::RuntimeError(RuntimeError::NoImplementationNamed { .. }) => true,
Expr::Closure(closure_data)
if matches!(
closure_data.loc_body.value,
Expr::RuntimeError(RuntimeError::NoImplementationNamed { .. })
) =>
{
true
}
_ => false,
}
}
// TODO trim these down
#[allow(clippy::too_many_arguments)]
pub fn canonicalize_module_defs<'a>(
@ -95,59 +185,8 @@ pub fn canonicalize_module_defs<'a>(
);
}
struct Hosted {
effect_symbol: Symbol,
generated_functions: HostedGeneratedFunctions,
}
let hosted_info = if let HeaderFor::Hosted {
generates,
generates_with,
} = header_for
{
let name: &str = generates.into();
let (generated_functions, unknown_generated) = validate_generate_with(generates_with);
for unknown in unknown_generated {
env.problem(Problem::UnknownGeneratesWith(unknown));
}
let effect_symbol = scope
.introduce(
name.into(),
&env.exposed_ident_ids,
&mut env.ident_ids,
Region::zero(),
)
.unwrap();
let effect_tag_name = TagName::Private(effect_symbol);
{
let a_var = var_store.fresh();
let actual = crate::effect_module::build_effect_actual(
effect_tag_name,
Type::Variable(a_var),
var_store,
);
scope.add_alias(
effect_symbol,
Region::zero(),
vec![Loc::at_zero(("a".into(), a_var))],
actual,
AliasKind::Structural,
);
}
Some(Hosted {
effect_symbol,
generated_functions,
})
} else {
None
};
let generated_info =
GeneratedInfo::from_header_for(&mut env, &mut scope, var_store, header_for);
// Desugar operators (convert them to Apply calls, taking into account
// operator precedence and associativity rules), before doing other canonicalization.
@ -206,11 +245,13 @@ pub fn canonicalize_module_defs<'a>(
} else {
// This is a type alias
dbg!(scope.aliases.keys().collect::<Vec<_>>());
// the symbol should already be added to the scope when this module is canonicalized
debug_assert!(
scope.contains_alias(symbol),
"apparently, {:?} is not actually a type alias",
symbol
"The {:?} is not a type alias known in {:?}",
symbol,
home
);
// but now we know this symbol by a different identifier, so we still need to add it to
@ -291,10 +332,10 @@ pub fn canonicalize_module_defs<'a>(
(Ok(mut declarations), output) => {
use crate::def::Declaration::*;
if let Some(Hosted {
if let GeneratedInfo::Hosted {
effect_symbol,
generated_functions,
}) = hosted_info
} = generated_info
{
let mut exposed_symbols = MutSet::default();
@ -327,9 +368,23 @@ pub fn canonicalize_module_defs<'a>(
// 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 let Some(Hosted { effect_symbol, .. }) = hosted_info {
macro_rules! make_hosted_def {
() => {
if has_no_implementation(&def.loc_expr.value) {
match generated_info {
GeneratedInfo::Builtin {
generated_functions,
} => {
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")
}
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 =
@ -353,27 +408,8 @@ pub fn canonicalize_module_defs<'a>(
);
*def = hosted_def;
};
}
match &def.loc_expr.value {
Expr::RuntimeError(RuntimeError::NoImplementationNamed {
..
}) => {
make_hosted_def!();
}
Expr::Closure(closure_data)
if matches!(
closure_data.loc_body.value,
Expr::RuntimeError(
RuntimeError::NoImplementationNamed { .. }
)
) =>
{
make_hosted_def!();
}
_ => {}
_ => (),
}
}
}
@ -408,7 +444,7 @@ pub fn canonicalize_module_defs<'a>(
let mut aliases = MutMap::default();
if let Some(Hosted { effect_symbol, .. }) = hosted_info {
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