enable tag unions as functions in code gen

This commit is contained in:
Folkert 2021-05-24 16:01:15 +02:00
parent 174daeb3b5
commit 5f408c42b0
3 changed files with 44 additions and 7 deletions

View file

@ -4212,6 +4212,7 @@ fn convert_tag_union<'a>(
))); )));
} }
}; };
match variant { match variant {
Never => unreachable!( Never => unreachable!(
"The `[]` type has no constructors, source var {:?}", "The `[]` type has no constructors, source var {:?}",
@ -4253,7 +4254,13 @@ fn convert_tag_union<'a>(
.unwrap_or_else(|err| panic!("TODO turn fn_var into a RuntimeError {:?}", err)); .unwrap_or_else(|err| panic!("TODO turn fn_var into a RuntimeError {:?}", err));
// even though this was originally a Tag, we treat it as a Struct from now on // even though this was originally a Tag, we treat it as a Struct from now on
let stmt = Stmt::Let(assigned, Expr::Struct(field_symbols), layout, hole); let stmt = if let [only_field] = field_symbols {
let mut hole = hole.clone();
substitute_in_exprs(env.arena, &mut hole, assigned, *only_field);
hole
} else {
Stmt::Let(assigned, Expr::Struct(field_symbols), layout, hole)
};
let iter = field_symbols_temp.into_iter().map(|(_, _, data)| data); let iter = field_symbols_temp.into_iter().map(|(_, _, data)| data);
assign_to_symbols(env, procs, layout_cache, iter, stmt) assign_to_symbols(env, procs, layout_cache, iter, stmt)
@ -4480,6 +4487,7 @@ fn tag_union_to_function<'a>(
) -> Stmt<'a> { ) -> Stmt<'a> {
let mut loc_pattern_args = vec![]; let mut loc_pattern_args = vec![];
let mut loc_expr_args = vec![]; let mut loc_expr_args = vec![];
for arg_var in argument_variables { for arg_var in argument_variables {
let arg_symbol = env.unique_symbol(); let arg_symbol = env.unique_symbol();
@ -4490,12 +4498,14 @@ fn tag_union_to_function<'a>(
loc_pattern_args.push((arg_var, loc_pattern)); loc_pattern_args.push((arg_var, loc_pattern));
loc_expr_args.push((arg_var, loc_expr)); loc_expr_args.push((arg_var, loc_expr));
} }
let loc_body = Located::at_zero(roc_can::expr::Expr::Tag { let loc_body = Located::at_zero(roc_can::expr::Expr::Tag {
variant_var: return_variable, variant_var: return_variable,
name: tag_name, name: tag_name,
arguments: loc_expr_args, arguments: loc_expr_args,
ext_var, ext_var,
}); });
let inserted = procs.insert_anonymous( let inserted = procs.insert_anonymous(
env, env,
proc_symbol, proc_symbol,
@ -4506,8 +4516,9 @@ fn tag_union_to_function<'a>(
return_variable, return_variable,
layout_cache, layout_cache,
); );
match inserted { match inserted {
Ok(layout) => { Ok(_layout) => {
// only need to construct closure data // only need to construct closure data
let full_layout = let full_layout =
return_on_layout_error!(env, layout_cache.from_var(env.arena, whole_var, env.subs)); return_on_layout_error!(env, layout_cache.from_var(env.arena, whole_var, env.subs));

View file

@ -996,7 +996,6 @@ fn applied_tag_function() {
} }
#[test] #[test]
#[ignore]
fn applied_tag_function_result() { fn applied_tag_function_result() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -1016,7 +1015,6 @@ fn applied_tag_function_result() {
} }
#[test] #[test]
#[ignore]
fn applied_tag_function_linked_list() { fn applied_tag_function_linked_list() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(

View file

@ -1270,11 +1270,11 @@ fn unify_function_or_tag_union_and_func(
pool: &mut Pool, pool: &mut Pool,
ctx: &Context, ctx: &Context,
tag_name: &TagName, tag_name: &TagName,
_tag_symbol: Symbol, tag_symbol: Symbol,
tag_ext: Variable, tag_ext: Variable,
function_arguments: &[Variable], function_arguments: &[Variable],
function_return: Variable, function_return: Variable,
_function_lambda_set: Variable, function_lambda_set: Variable,
left: bool, left: bool,
) -> Outcome { ) -> Outcome {
use FlatType::*; use FlatType::*;
@ -1287,12 +1287,40 @@ fn unify_function_or_tag_union_and_func(
let new_tag_union_var = fresh(subs, pool, ctx, content); let new_tag_union_var = fresh(subs, pool, ctx, content);
let problems = if left { let mut problems = if left {
unify_pool(subs, pool, new_tag_union_var, function_return) unify_pool(subs, pool, new_tag_union_var, function_return)
} else { } else {
unify_pool(subs, pool, function_return, new_tag_union_var) unify_pool(subs, pool, function_return, new_tag_union_var)
}; };
{
let lambda_set_ext = subs.fresh_unnamed_flex_var();
let mut closure_tags = MutMap::with_capacity_and_hasher(1, default_hasher());
closure_tags.insert(TagName::Closure(tag_symbol), vec![]);
let lambda_set_content = Structure(TagUnion(closure_tags, lambda_set_ext));
let tag_lambda_set = register(
subs,
Descriptor {
content: lambda_set_content,
rank: ctx.first_desc.rank.min(ctx.second_desc.rank),
mark: Mark::NONE,
copy: OptVariable::NONE,
},
pool,
);
let closure_problems = if left {
unify_pool(subs, pool, tag_lambda_set, function_lambda_set)
} else {
unify_pool(subs, pool, function_lambda_set, tag_lambda_set)
};
problems.extend(closure_problems);
}
if problems.is_empty() { if problems.is_empty() {
let desc = if left { let desc = if left {
subs.get(ctx.second) subs.get(ctx.second)