Merge remote-tracking branch 'origin/trunk' into specialize-lowlevel

This commit is contained in:
Folkert 2021-05-24 15:17:28 +02:00
commit e81087f913
14 changed files with 1156 additions and 730 deletions

View file

@ -146,6 +146,9 @@ fn jit_to_ast_help<'a>(
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), payload_vars) single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), payload_vars)
} }
Content::Structure(FlatType::FunctionOrTagUnion(tag_name, _, _)) => {
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), &[])
}
other => { other => {
unreachable!( unreachable!(
"Something had a Struct layout, but instead of a Record or TagUnion type, it had: {:?}", "Something had a Struct layout, but instead of a Record or TagUnion type, it had: {:?}",
@ -318,6 +321,9 @@ fn ptr_to_ast<'a>(
let (tag_name, payload_vars) = tags.iter().next().unwrap(); let (tag_name, payload_vars) = tags.iter().next().unwrap();
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), payload_vars) single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), payload_vars)
} }
Content::Structure(FlatType::FunctionOrTagUnion(tag_name, _, _)) => {
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), &[])
}
Content::Structure(FlatType::EmptyRecord) => { Content::Structure(FlatType::EmptyRecord) => {
struct_to_ast(env, ptr, &[], &MutMap::default()) struct_to_ast(env, ptr, &[], &MutMap::default())
} }

View file

@ -161,6 +161,14 @@ pub enum Expr {
arguments: Vec<(Variable, Located<Expr>)>, arguments: Vec<(Variable, Located<Expr>)>,
}, },
ZeroArgumentTag {
closure_name: Symbol,
variant_var: Variable,
ext_var: Variable,
name: TagName,
arguments: Vec<(Variable, Located<Expr>)>,
},
// Test // Test
Expect(Box<Located<Expr>>, Box<Located<Expr>>), Expect(Box<Located<Expr>>, Box<Located<Expr>>),
@ -395,6 +403,17 @@ pub fn canonicalize_expr<'a>(
name, name,
arguments: args, arguments: args,
}, },
ZeroArgumentTag {
variant_var,
ext_var,
name,
..
} => Tag {
variant_var,
ext_var,
name,
arguments: args,
},
_ => { _ => {
// This could be something like ((if True then fn1 else fn2) arg1 arg2). // This could be something like ((if True then fn1 else fn2) arg1 arg2).
Call( Call(
@ -630,11 +649,14 @@ pub fn canonicalize_expr<'a>(
let variant_var = var_store.fresh(); let variant_var = var_store.fresh();
let ext_var = var_store.fresh(); let ext_var = var_store.fresh();
let symbol = env.gen_unique_symbol();
( (
Tag { ZeroArgumentTag {
name: TagName::Global((*tag).into()), name: TagName::Global((*tag).into()),
arguments: vec![], arguments: vec![],
variant_var, variant_var,
closure_name: symbol,
ext_var, ext_var,
}, },
Output::default(), Output::default(),
@ -645,13 +667,15 @@ pub fn canonicalize_expr<'a>(
let ext_var = var_store.fresh(); let ext_var = var_store.fresh();
let tag_ident = env.ident_ids.get_or_insert(&(*tag).into()); let tag_ident = env.ident_ids.get_or_insert(&(*tag).into());
let symbol = Symbol::new(env.home, tag_ident); let symbol = Symbol::new(env.home, tag_ident);
let lambda_set_symbol = env.gen_unique_symbol();
( (
Tag { ZeroArgumentTag {
name: TagName::Private(symbol), name: TagName::Private(symbol),
arguments: vec![], arguments: vec![],
variant_var, variant_var,
ext_var, ext_var,
closure_name: lambda_set_symbol,
}, },
Output::default(), Output::default(),
) )
@ -1431,6 +1455,23 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
); );
} }
ZeroArgumentTag {
closure_name,
variant_var,
ext_var,
name,
arguments,
} => {
todo!(
"Inlining for ZeroArgumentTag with closure_name {:?}, variant_var {:?}, ext_var {:?}, name {:?}, arguments {:?}",
closure_name,
variant_var,
ext_var,
name,
arguments
);
}
Call(boxed_tuple, args, called_via) => { Call(boxed_tuple, args, called_via) => {
let (fn_var, loc_expr, closure_var, expr_var) = *boxed_tuple; let (fn_var, loc_expr, closure_var, expr_var) = *boxed_tuple;

View file

@ -509,7 +509,7 @@ fn fix_values_captured_in_closure_expr(
fix_values_captured_in_closure_expr(&mut loc_expr.value, no_capture_symbols); fix_values_captured_in_closure_expr(&mut loc_expr.value, no_capture_symbols);
} }
Tag { arguments, .. } => { Tag { arguments, .. } | ZeroArgumentTag { arguments, .. } => {
for (_, loc_arg) in arguments.iter_mut() { for (_, loc_arg) in arguments.iter_mut() {
fix_values_captured_in_closure_expr(&mut loc_arg.value, no_capture_symbols); fix_values_captured_in_closure_expr(&mut loc_arg.value, no_capture_symbols);
} }

View file

@ -867,6 +867,58 @@ pub fn constrain_expr(
exists(vars, And(arg_cons)) exists(vars, And(arg_cons))
} }
ZeroArgumentTag {
variant_var,
ext_var,
name,
arguments,
closure_name,
} => {
let mut vars = Vec::with_capacity(arguments.len());
let mut types = Vec::with_capacity(arguments.len());
let mut arg_cons = Vec::with_capacity(arguments.len());
for (var, loc_expr) in arguments {
let arg_con = constrain_expr(
env,
loc_expr.region,
&loc_expr.value,
Expected::NoExpectation(Type::Variable(*var)),
);
arg_cons.push(arg_con);
vars.push(*var);
types.push(Type::Variable(*var));
}
let union_con = Eq(
Type::FunctionOrTagUnion(
name.clone(),
*closure_name,
Box::new(Type::Variable(*ext_var)),
),
expected.clone(),
Category::TagApply {
tag_name: name.clone(),
args_count: arguments.len(),
},
region,
);
let ast_con = Eq(
Type::Variable(*variant_var),
expected,
Category::Storage(std::file!(), std::line!()),
region,
);
vars.push(*variant_var);
vars.push(*ext_var);
arg_cons.push(union_con);
arg_cons.push(ast_con);
exists(vars, And(arg_cons))
}
RunLowLevel { args, ret_var, op } => { RunLowLevel { args, ret_var, op } => {
// This is a modified version of what we do for function calls. // This is a modified version of what we do for function calls.

View file

@ -3022,351 +3022,63 @@ pub fn with_hole<'a>(
variant_var, variant_var,
name: tag_name, name: tag_name,
arguments: args, arguments: args,
ext_var, ..
} => {
let arena = env.arena;
debug_assert!(!matches!(
env.subs.get_without_compacting(variant_var).content,
Content::Structure(FlatType::Func(_, _, _))
));
convert_tag_union(
env,
variant_var,
assigned,
hole,
tag_name,
procs,
layout_cache,
args,
arena,
)
}
ZeroArgumentTag {
variant_var,
name: tag_name,
arguments: args,
ext_var,
..
} => { } => {
use crate::layout::UnionVariant::*;
let arena = env.arena; let arena = env.arena;
let desc = env.subs.get_without_compacting(variant_var); let desc = env.subs.get_without_compacting(variant_var);
if let Content::Structure(FlatType::Func(arg_vars, _, ret_var)) = desc.content { if let Content::Structure(FlatType::Func(arg_vars, _, ret_var)) = desc.content {
let mut loc_pattern_args = vec![]; tag_union_to_function(
let mut loc_expr_args = vec![];
let proc_symbol = env.unique_symbol();
for arg_var in arg_vars {
let arg_symbol = env.unique_symbol();
let loc_pattern =
Located::at_zero(roc_can::pattern::Pattern::Identifier(arg_symbol));
let loc_expr = Located::at_zero(roc_can::expr::Expr::Var(arg_symbol));
loc_pattern_args.push((arg_var, loc_pattern));
loc_expr_args.push((arg_var, loc_expr));
}
let loc_body = Located::at_zero(roc_can::expr::Expr::Tag {
variant_var: ret_var,
name: tag_name,
arguments: loc_expr_args,
ext_var,
});
let inserted = procs.insert_anonymous(
env, env,
proc_symbol, arg_vars,
variant_var,
loc_pattern_args,
loc_body,
CapturedSymbols::None,
ret_var, ret_var,
tag_name,
ext_var,
procs,
variant_var,
layout_cache, layout_cache,
);
match inserted {
Ok(_layout) => {
todo!("depends on 0-argument tag unions having a lambda union")
// return Stmt::Let(
// assigned,
// todo!(), // call_by_pointer(env, procs, proc_symbol, layout),
// layout,
// hole,
// );
}
Err(runtime_error) => {
return Stmt::RuntimeError(env.arena.alloc(format!(
"RuntimeError {} line {} {:?}",
file!(),
line!(),
runtime_error,
)));
}
}
}
let res_variant = crate::layout::union_sorted_tags(env.arena, variant_var, env.subs);
let variant = match res_variant {
Ok(cached) => cached,
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
return Stmt::RuntimeError(env.arena.alloc(format!(
"UnresolvedTypeVar {} line {}",
file!(),
line!()
)));
}
Err(LayoutProblem::Erroneous) => {
return Stmt::RuntimeError(env.arena.alloc(format!(
"Erroneous {} line {}",
file!(),
line!()
)));
}
};
match variant {
Never => unreachable!(
"The `[]` type has no constructors, source var {:?}",
variant_var
),
Unit | UnitWithArguments => let_empty_struct(assigned, hole),
BoolUnion { ttrue, .. } => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Bool(tag_name == ttrue)),
Layout::Builtin(Builtin::Int1),
hole,
),
ByteUnion(tag_names) => {
let tag_id = tag_names
.iter()
.position(|key| key == &tag_name)
.expect("tag must be in its own type");
Stmt::Let(
assigned,
Expr::Literal(Literal::Byte(tag_id as u8)),
Layout::Builtin(Builtin::Int8),
hole, hole,
) )
}
Unwrapped(_, field_layouts) => {
let field_symbols_temp = sorted_field_symbols(env, procs, layout_cache, args);
let mut field_symbols = Vec::with_capacity_in(field_layouts.len(), env.arena);
field_symbols.extend(field_symbols_temp.iter().map(|r| r.1));
let field_symbols = field_symbols.into_bump_slice();
// Layout will unpack this unwrapped tack if it only has one (non-zero-sized) field
let layout = layout_cache
.from_var(env.arena, variant_var, env.subs)
.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
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 { } else {
Stmt::Let(assigned, Expr::Struct(field_symbols), layout, hole) convert_tag_union(
}; env,
variant_var,
let iter = field_symbols_temp.into_iter().map(|(_, _, data)| data); assigned,
assign_to_symbols(env, procs, layout_cache, iter, stmt) hole,
}
Wrapped(variant) => {
let union_size = variant.number_of_tags() as u8;
let (tag_id, _) = variant.tag_name_to_id(&tag_name);
let field_symbols_temp = sorted_field_symbols(env, procs, layout_cache, args);
let field_symbols;
let opt_tag_id_symbol;
use WrappedVariant::*;
let (tag, layout) = match variant {
Recursive { sorted_tag_layouts } => {
debug_assert!(sorted_tag_layouts.len() > 1);
let tag_id_symbol = env.unique_symbol();
opt_tag_id_symbol = Some(tag_id_symbol);
field_symbols = {
let mut temp =
Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
temp.push(tag_id_symbol);
temp.extend(field_symbols_temp.iter().map(|r| r.1));
temp.into_bump_slice()
};
let mut layouts: Vec<&'a [Layout<'a>]> =
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
layouts.push(arg_layouts);
}
debug_assert!(layouts.len() > 1);
let layout =
Layout::Union(UnionLayout::Recursive(layouts.into_bump_slice()));
let tag = Expr::Tag {
tag_layout: layout,
tag_name, tag_name,
tag_id: tag_id as u8, procs,
union_size, layout_cache,
arguments: field_symbols, args,
}; arena,
)
(tag, layout)
}
NonNullableUnwrapped {
fields,
tag_name: wrapped_tag_name,
} => {
debug_assert_eq!(tag_name, wrapped_tag_name);
opt_tag_id_symbol = None;
field_symbols = {
let mut temp =
Vec::with_capacity_in(field_symbols_temp.len(), arena);
temp.extend(field_symbols_temp.iter().map(|r| r.1));
temp.into_bump_slice()
};
let layout = Layout::Union(UnionLayout::NonNullableUnwrapped(fields));
let tag = Expr::Tag {
tag_layout: layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
}
NonRecursive { sorted_tag_layouts } => {
let tag_id_symbol = env.unique_symbol();
opt_tag_id_symbol = Some(tag_id_symbol);
field_symbols = {
let mut temp =
Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
temp.push(tag_id_symbol);
temp.extend(field_symbols_temp.iter().map(|r| r.1));
temp.into_bump_slice()
};
let mut layouts: Vec<&'a [Layout<'a>]> =
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
layouts.push(arg_layouts);
}
let layout =
Layout::Union(UnionLayout::NonRecursive(layouts.into_bump_slice()));
let tag = Expr::Tag {
tag_layout: layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
}
NullableWrapped {
nullable_id,
nullable_name: _,
sorted_tag_layouts,
} => {
let tag_id_symbol = env.unique_symbol();
opt_tag_id_symbol = Some(tag_id_symbol);
field_symbols = {
let mut temp =
Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
temp.push(tag_id_symbol);
temp.extend(field_symbols_temp.iter().map(|r| r.1));
temp.into_bump_slice()
};
let mut layouts: Vec<&'a [Layout<'a>]> =
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
layouts.push(arg_layouts);
}
let layout = Layout::Union(UnionLayout::NullableWrapped {
nullable_id,
other_tags: layouts.into_bump_slice(),
});
let tag = Expr::Tag {
tag_layout: layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
}
NullableUnwrapped {
nullable_id,
nullable_name: _,
other_name: _,
other_fields,
} => {
// FIXME drop tag
let tag_id_symbol = env.unique_symbol();
opt_tag_id_symbol = Some(tag_id_symbol);
field_symbols = {
let mut temp =
Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
// FIXME drop tag
temp.push(tag_id_symbol);
temp.extend(field_symbols_temp.iter().map(|r| r.1));
temp.into_bump_slice()
};
let layout = Layout::Union(UnionLayout::NullableUnwrapped {
nullable_id,
other_fields,
});
let tag = Expr::Tag {
tag_layout: layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
}
};
let mut stmt = Stmt::Let(assigned, tag, layout, hole);
let iter = field_symbols_temp
.into_iter()
.map(|x| x.2 .0)
.rev()
.zip(field_symbols.iter().rev());
stmt = assign_to_symbols(env, procs, layout_cache, iter, stmt);
if let Some(tag_id_symbol) = opt_tag_id_symbol {
// define the tag id
stmt = Stmt::Let(
tag_id_symbol,
Expr::Literal(Literal::Int(tag_id as i128)),
Layout::Builtin(TAG_SIZE),
arena.alloc(stmt),
);
}
stmt
}
} }
} }
@ -4468,6 +4180,347 @@ fn construct_closure_data<'a>(
} }
} }
#[allow(clippy::too_many_arguments)]
fn convert_tag_union<'a>(
env: &mut Env<'a, '_>,
variant_var: Variable,
assigned: Symbol,
hole: &'a Stmt<'a>,
tag_name: TagName,
procs: &mut Procs<'a>,
layout_cache: &mut LayoutCache<'a>,
args: std::vec::Vec<(Variable, Located<roc_can::expr::Expr>)>,
arena: &'a Bump,
) -> Stmt<'a> {
use crate::layout::UnionVariant::*;
let res_variant = crate::layout::union_sorted_tags(env.arena, variant_var, env.subs);
let variant = match res_variant {
Ok(cached) => cached,
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
return Stmt::RuntimeError(env.arena.alloc(format!(
"UnresolvedTypeVar {} line {}",
file!(),
line!()
)))
}
Err(LayoutProblem::Erroneous) => {
return Stmt::RuntimeError(env.arena.alloc(format!(
"Erroneous {} line {}",
file!(),
line!()
)));
}
};
match variant {
Never => unreachable!(
"The `[]` type has no constructors, source var {:?}",
variant_var
),
Unit | UnitWithArguments => {
Stmt::Let(assigned, Expr::Struct(&[]), Layout::Struct(&[]), hole)
}
BoolUnion { ttrue, .. } => Stmt::Let(
assigned,
Expr::Literal(Literal::Bool(tag_name == ttrue)),
Layout::Builtin(Builtin::Int1),
hole,
),
ByteUnion(tag_names) => {
let tag_id = tag_names
.iter()
.position(|key| key == &tag_name)
.expect("tag must be in its own type");
Stmt::Let(
assigned,
Expr::Literal(Literal::Byte(tag_id as u8)),
Layout::Builtin(Builtin::Int8),
hole,
)
}
Unwrapped(field_layouts) => {
let field_symbols_temp = sorted_field_symbols(env, procs, layout_cache, args);
let mut field_symbols = Vec::with_capacity_in(field_layouts.len(), env.arena);
field_symbols.extend(field_symbols_temp.iter().map(|r| r.1));
let field_symbols = field_symbols.into_bump_slice();
// Layout will unpack this unwrapped tack if it only has one (non-zero-sized) field
let layout = layout_cache
.from_var(env.arena, variant_var, env.subs)
.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
let stmt = Stmt::Let(assigned, Expr::Struct(field_symbols), layout, hole);
let iter = field_symbols_temp.into_iter().map(|(_, _, data)| data);
assign_to_symbols(env, procs, layout_cache, iter, stmt)
}
Wrapped(variant) => {
let union_size = variant.number_of_tags() as u8;
let (tag_id, _) = variant.tag_name_to_id(&tag_name);
let field_symbols_temp = sorted_field_symbols(env, procs, layout_cache, args);
let field_symbols;
let opt_tag_id_symbol;
use WrappedVariant::*;
let (tag, layout) = match variant {
Recursive { sorted_tag_layouts } => {
debug_assert!(sorted_tag_layouts.len() > 1);
let tag_id_symbol = env.unique_symbol();
opt_tag_id_symbol = Some(tag_id_symbol);
field_symbols = {
let mut temp = Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
temp.push(tag_id_symbol);
temp.extend(field_symbols_temp.iter().map(|r| r.1));
temp.into_bump_slice()
};
let mut layouts: Vec<&'a [Layout<'a>]> =
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
layouts.push(arg_layouts);
}
debug_assert!(layouts.len() > 1);
let layout = Layout::Union(UnionLayout::Recursive(layouts.into_bump_slice()));
let tag = Expr::Tag {
tag_layout: layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
}
NonNullableUnwrapped {
fields,
tag_name: wrapped_tag_name,
} => {
debug_assert_eq!(tag_name, wrapped_tag_name);
opt_tag_id_symbol = None;
field_symbols = {
let mut temp = Vec::with_capacity_in(field_symbols_temp.len(), arena);
temp.extend(field_symbols_temp.iter().map(|r| r.1));
temp.into_bump_slice()
};
let layout = Layout::Union(UnionLayout::NonNullableUnwrapped(fields));
let tag = Expr::Tag {
tag_layout: layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
}
NonRecursive { sorted_tag_layouts } => {
let tag_id_symbol = env.unique_symbol();
opt_tag_id_symbol = Some(tag_id_symbol);
field_symbols = {
let mut temp = Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
temp.push(tag_id_symbol);
temp.extend(field_symbols_temp.iter().map(|r| r.1));
temp.into_bump_slice()
};
let mut layouts: Vec<&'a [Layout<'a>]> =
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
layouts.push(arg_layouts);
}
let layout =
Layout::Union(UnionLayout::NonRecursive(layouts.into_bump_slice()));
let tag = Expr::Tag {
tag_layout: layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
}
NullableWrapped {
nullable_id,
nullable_name: _,
sorted_tag_layouts,
} => {
let tag_id_symbol = env.unique_symbol();
opt_tag_id_symbol = Some(tag_id_symbol);
field_symbols = {
let mut temp = Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
temp.push(tag_id_symbol);
temp.extend(field_symbols_temp.iter().map(|r| r.1));
temp.into_bump_slice()
};
let mut layouts: Vec<&'a [Layout<'a>]> =
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
layouts.push(arg_layouts);
}
let layout = Layout::Union(UnionLayout::NullableWrapped {
nullable_id,
other_tags: layouts.into_bump_slice(),
});
let tag = Expr::Tag {
tag_layout: layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
}
NullableUnwrapped {
nullable_id,
nullable_name: _,
other_name: _,
other_fields,
} => {
// FIXME drop tag
let tag_id_symbol = env.unique_symbol();
opt_tag_id_symbol = Some(tag_id_symbol);
field_symbols = {
let mut temp = Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
// FIXME drop tag
temp.push(tag_id_symbol);
temp.extend(field_symbols_temp.iter().map(|r| r.1));
temp.into_bump_slice()
};
let layout = Layout::Union(UnionLayout::NullableUnwrapped {
nullable_id,
other_fields,
});
let tag = Expr::Tag {
tag_layout: layout,
tag_name,
tag_id: tag_id as u8,
union_size,
arguments: field_symbols,
};
(tag, layout)
}
};
let mut stmt = Stmt::Let(assigned, tag, layout, hole);
let iter = field_symbols_temp
.into_iter()
.map(|x| x.2 .0)
.rev()
.zip(field_symbols.iter().rev());
stmt = assign_to_symbols(env, procs, layout_cache, iter, stmt);
if let Some(tag_id_symbol) = opt_tag_id_symbol {
// define the tag id
stmt = Stmt::Let(
tag_id_symbol,
Expr::Literal(Literal::Int(tag_id as i128)),
Layout::Builtin(TAG_SIZE),
arena.alloc(stmt),
);
}
stmt
}
}
}
#[allow(clippy::too_many_arguments)]
fn tag_union_to_function<'a>(
env: &mut Env<'a, '_>,
arg_vars: std::vec::Vec<Variable>,
ret_var: Variable,
tag_name: TagName,
ext_var: Variable,
procs: &mut Procs<'a>,
variant_var: Variable,
layout_cache: &mut LayoutCache<'a>,
assigned: Symbol,
hole: &'a Stmt<'a>,
) -> Stmt<'a> {
let mut loc_pattern_args = vec![];
let mut loc_expr_args = vec![];
let proc_symbol = env.unique_symbol();
for arg_var in arg_vars {
let arg_symbol = env.unique_symbol();
let loc_pattern = Located::at_zero(roc_can::pattern::Pattern::Identifier(arg_symbol));
let loc_expr = Located::at_zero(roc_can::expr::Expr::Var(arg_symbol));
loc_pattern_args.push((arg_var, loc_pattern));
loc_expr_args.push((arg_var, loc_expr));
}
let loc_body = Located::at_zero(roc_can::expr::Expr::Tag {
variant_var: ret_var,
name: tag_name,
arguments: loc_expr_args,
ext_var,
});
let inserted = procs.insert_anonymous(
env,
proc_symbol,
variant_var,
loc_pattern_args,
loc_body,
CapturedSymbols::None,
ret_var,
layout_cache,
);
match inserted {
Ok(layout) => Stmt::Let(
assigned,
call_by_pointer(env, procs, proc_symbol, layout),
layout,
hole,
),
Err(runtime_error) => Stmt::RuntimeError(env.arena.alloc(format!(
"RuntimeError {} line {} {:?}",
file!(),
line!(),
runtime_error,
))),
}
}
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn sorted_field_symbols<'a>( fn sorted_field_symbols<'a>(
env: &mut Env<'a, '_>, env: &mut Env<'a, '_>,

View file

@ -357,6 +357,12 @@ impl<'a, 'b> Env<'a, 'b> {
self.seen.insert(var) self.seen.insert(var)
} }
fn remove_seen(&mut self, var: Variable) -> bool {
let var = self.subs.get_root_key_without_compacting(var);
self.seen.remove(&var)
}
} }
impl<'a> Layout<'a> { impl<'a> Layout<'a> {
@ -1090,6 +1096,14 @@ fn layout_from_flat_type<'a>(
Ok(layout_from_tag_union(arena, tags, subs)) Ok(layout_from_tag_union(arena, tags, subs))
} }
FunctionOrTagUnion(tag_name, _, ext_var) => {
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
let mut tags = MutMap::default();
tags.insert(tag_name, vec![]);
Ok(layout_from_tag_union(arena, tags, subs))
}
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var)); debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
@ -1175,6 +1189,8 @@ fn layout_from_flat_type<'a>(
UnionLayout::Recursive(tag_layouts.into_bump_slice()) UnionLayout::Recursive(tag_layouts.into_bump_slice())
}; };
env.remove_seen(rec_var);
Ok(Layout::Union(union_layout)) Ok(Layout::Union(union_layout))
} }
EmptyTagUnion => { EmptyTagUnion => {

View file

@ -241,18 +241,18 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Test.0 (): procedure Test.0 ():
let Test.9 = 0i64; let Test.10 = 0i64;
let Test.8 = 3i64; let Test.9 = 3i64;
let Test.2 = Just Test.9 Test.8; let Test.3 = Just Test.10 Test.9;
let Test.5 = 0i64; let Test.6 = 0i64;
let Test.6 = Index 0 Test.2; let Test.7 = Index 0 Test.3;
let Test.7 = lowlevel Eq Test.5 Test.6; let Test.8 = lowlevel Eq Test.6 Test.7;
if Test.7 then if Test.8 then
let Test.1 = Index 1 Test.2; let Test.2 = Index 1 Test.3;
ret Test.1; ret Test.2;
else else
let Test.4 = 0i64; let Test.5 = 0i64;
ret Test.4; ret Test.5;
"# "#
), ),
) )
@ -270,23 +270,23 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Test.0 (): procedure Test.0 ():
let Test.10 = 1i64; let Test.11 = 1i64;
let Test.8 = 1i64; let Test.9 = 1i64;
let Test.9 = 2i64; let Test.10 = 2i64;
let Test.4 = These Test.10 Test.8 Test.9; let Test.5 = These Test.11 Test.9 Test.10;
switch Test.4: switch Test.5:
case 2: case 2:
let Test.1 = Index 1 Test.4; let Test.2 = Index 1 Test.5;
ret Test.1;
case 0:
let Test.2 = Index 1 Test.4;
ret Test.2; ret Test.2;
default: case 0:
let Test.3 = Index 1 Test.4; let Test.3 = Index 1 Test.5;
ret Test.3; ret Test.3;
default:
let Test.4 = Index 1 Test.5;
ret Test.4;
"# "#
), ),
) )
@ -436,24 +436,24 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Num.24 (#Attr.2, #Attr.3): procedure Num.24 (#Attr.2, #Attr.3):
let Test.5 = lowlevel NumAdd #Attr.2 #Attr.3; let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Test.5; ret Test.6;
procedure Test.0 (): procedure Test.0 ():
let Test.11 = 0i64; let Test.12 = 0i64;
let Test.10 = 41i64; let Test.11 = 41i64;
let Test.1 = Just Test.11 Test.10; let Test.1 = Just Test.12 Test.11;
let Test.7 = 0i64; let Test.8 = 0i64;
let Test.8 = Index 0 Test.1; let Test.9 = Index 0 Test.1;
let Test.9 = lowlevel Eq Test.7 Test.8; let Test.10 = lowlevel Eq Test.8 Test.9;
if Test.9 then if Test.10 then
let Test.2 = Index 1 Test.1; let Test.3 = Index 1 Test.1;
let Test.4 = 1i64; let Test.5 = 1i64;
let Test.3 = CallByName Num.24 Test.2 Test.4; let Test.4 = CallByName Num.24 Test.3 Test.5;
ret Test.3; ret Test.4;
else else
let Test.6 = 1i64; let Test.7 = 1i64;
ret Test.6; ret Test.7;
"# "#
), ),
) )
@ -470,9 +470,6 @@ mod test_mono {
"#, "#,
indoc!( indoc!(
r#" r#"
procedure Test.0 ():
let Test.3 = 2i64;
ret Test.3;
"# "#
), ),
) )
@ -491,31 +488,31 @@ mod test_mono {
"#, "#,
indoc!( indoc!(
r#" r#"
procedure Test.1 (Test.2): procedure Test.1 (Test.3):
let Test.5 = 2i64; let Test.6 = 2i64;
joinpoint Test.11: joinpoint Test.12:
let Test.9 = 0i64; let Test.10 = 0i64;
ret Test.9; ret Test.10;
in in
let Test.10 = 2i64; let Test.11 = 2i64;
let Test.13 = lowlevel Eq Test.10 Test.5; let Test.14 = lowlevel Eq Test.11 Test.6;
if Test.14 then
joinpoint Test.8 Test.13:
if Test.13 then if Test.13 then
joinpoint Test.7 Test.12: let Test.7 = 42i64;
if Test.12 then ret Test.7;
let Test.6 = 42i64;
ret Test.6;
else else
jump Test.11; jump Test.12;
in in
let Test.8 = false; let Test.9 = false;
jump Test.7 Test.8; jump Test.8 Test.9;
else else
jump Test.11; jump Test.12;
procedure Test.0 (): procedure Test.0 ():
let Test.4 = Struct {}; let Test.5 = Struct {};
let Test.3 = CallByName Test.1 Test.4; let Test.4 = CallByName Test.1 Test.5;
ret Test.3; ret Test.4;
"# "#
), ),
) )
@ -561,37 +558,37 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Num.24 (#Attr.2, #Attr.3): procedure Num.24 (#Attr.2, #Attr.3):
let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3; let Test.8 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Test.6; ret Test.8;
procedure Test.0 (): procedure Test.0 ():
let Test.18 = 0i64;
let Test.20 = 0i64; let Test.20 = 0i64;
let Test.19 = 41i64; let Test.22 = 0i64;
let Test.17 = Just Test.20 Test.19; let Test.21 = 41i64;
let Test.2 = Just Test.18 Test.17; let Test.19 = Just Test.22 Test.21;
joinpoint Test.14: let Test.2 = Just Test.20 Test.19;
let Test.8 = 1i64; joinpoint Test.16:
ret Test.8; let Test.10 = 1i64;
ret Test.10;
in in
let Test.14 = 0i64;
let Test.15 = Index 0 Test.2;
let Test.18 = lowlevel Eq Test.14 Test.15;
if Test.18 then
let Test.11 = Index 1 Test.2;
let Test.12 = 0i64; let Test.12 = 0i64;
let Test.13 = Index 0 Test.2; let Test.13 = Index 0 Test.11;
let Test.16 = lowlevel Eq Test.12 Test.13; let Test.17 = lowlevel Eq Test.12 Test.13;
if Test.16 then if Test.17 then
let Test.9 = Index 1 Test.2; let Test.9 = Index 1 Test.2;
let Test.10 = 0i64; let Test.5 = Index 1 Test.9;
let Test.11 = Index 0 Test.9; let Test.7 = 1i64;
let Test.15 = lowlevel Eq Test.10 Test.11; let Test.6 = CallByName Num.24 Test.5 Test.7;
if Test.15 then ret Test.6;
let Test.7 = Index 1 Test.2;
let Test.3 = Index 1 Test.7;
let Test.5 = 1i64;
let Test.4 = CallByName Num.24 Test.3 Test.5;
ret Test.4;
else else
jump Test.14; jump Test.16;
else else
jump Test.14; jump Test.16;
"# "#
), ),
) )
@ -608,33 +605,33 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Num.24 (#Attr.2, #Attr.3): procedure Num.24 (#Attr.2, #Attr.3):
let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3; let Test.7 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Test.6; ret Test.7;
procedure Test.0 (): procedure Test.0 ():
let Test.15 = 3i64; let Test.16 = 3i64;
let Test.14 = 2i64; let Test.15 = 2i64;
let Test.3 = Struct {Test.14, Test.15}; let Test.4 = Struct {Test.15, Test.16};
joinpoint Test.11: joinpoint Test.12:
let Test.1 = Index 0 Test.3; let Test.2 = Index 0 Test.4;
let Test.2 = Index 1 Test.3; let Test.3 = Index 1 Test.4;
let Test.5 = CallByName Num.24 Test.1 Test.2; let Test.6 = CallByName Num.24 Test.2 Test.3;
ret Test.5; ret Test.6;
in in
let Test.9 = Index 1 Test.3; let Test.10 = Index 1 Test.4;
let Test.10 = 3i64; let Test.11 = 3i64;
let Test.13 = lowlevel Eq Test.10 Test.9; let Test.14 = lowlevel Eq Test.11 Test.10;
if Test.14 then
let Test.8 = Index 0 Test.4;
let Test.9 = 4i64;
let Test.13 = lowlevel Eq Test.9 Test.8;
if Test.13 then if Test.13 then
let Test.7 = Index 0 Test.3; let Test.5 = 9i64;
let Test.8 = 4i64; ret Test.5;
let Test.12 = lowlevel Eq Test.8 Test.7;
if Test.12 then
let Test.4 = 9i64;
ret Test.4;
else else
jump Test.11; jump Test.12;
else else
jump Test.11; jump Test.12;
"# "#
), ),
) )
@ -781,29 +778,29 @@ mod test_mono {
"#, "#,
indoc!( indoc!(
r#" r#"
procedure Test.1 (Test.4): procedure Test.1 (Test.5):
let Test.2 = 0u8; let Test.2 = 0u8;
joinpoint Test.8 Test.3: joinpoint Test.9 Test.3:
ret Test.3; ret Test.3;
in in
switch Test.2: switch Test.2:
case 1: case 1:
let Test.9 = 1i64; let Test.10 = 1i64;
jump Test.8 Test.9; jump Test.9 Test.10;
case 2: case 2:
let Test.10 = 2i64; let Test.11 = 2i64;
jump Test.8 Test.10; jump Test.9 Test.11;
default: default:
let Test.11 = 3i64; let Test.12 = 3i64;
jump Test.8 Test.11; jump Test.9 Test.12;
procedure Test.0 (): procedure Test.0 ():
let Test.6 = Struct {}; let Test.7 = Struct {};
let Test.5 = CallByName Test.1 Test.6; let Test.6 = CallByName Test.1 Test.7;
ret Test.5; ret Test.6;
"# "#
), ),
) )
@ -821,13 +818,13 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Test.0 (): procedure Test.0 ():
let Test.2 = true; let Test.3 = true;
if Test.2 then if Test.3 then
let Test.3 = 1i64; let Test.4 = 1i64;
ret Test.3; ret Test.4;
else else
let Test.1 = 2i64; let Test.2 = 2i64;
ret Test.1; ret Test.2;
"# "#
), ),
) )
@ -847,18 +844,18 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Test.0 (): procedure Test.0 ():
let Test.4 = true; let Test.6 = true;
if Test.6 then
let Test.7 = 1i64;
ret Test.7;
else
let Test.4 = false;
if Test.4 then if Test.4 then
let Test.5 = 1i64; let Test.5 = 2i64;
ret Test.5; ret Test.5;
else else
let Test.2 = false; let Test.3 = 3i64;
if Test.2 then
let Test.3 = 2i64;
ret Test.3; ret Test.3;
else
let Test.1 = 3i64;
ret Test.1;
"# "#
), ),
) )
@ -883,34 +880,34 @@ mod test_mono {
"#, "#,
indoc!( indoc!(
r#" r#"
procedure Test.1 (Test.4): procedure Test.1 (Test.5):
let Test.19 = 1i64; let Test.20 = 1i64;
let Test.18 = 2i64; let Test.19 = 2i64;
let Test.2 = Ok Test.19 Test.18; let Test.2 = Ok Test.20 Test.19;
joinpoint Test.8 Test.3: joinpoint Test.9 Test.3:
ret Test.3; ret Test.3;
in in
let Test.15 = 1i64; let Test.16 = 1i64;
let Test.16 = Index 0 Test.2; let Test.17 = Index 0 Test.2;
let Test.17 = lowlevel Eq Test.15 Test.16; let Test.18 = lowlevel Eq Test.16 Test.17;
if Test.17 then if Test.18 then
let Test.12 = Index 1 Test.2; let Test.13 = Index 1 Test.2;
let Test.13 = 3i64; let Test.14 = 3i64;
let Test.14 = lowlevel Eq Test.13 Test.12; let Test.15 = lowlevel Eq Test.14 Test.13;
if Test.14 then if Test.15 then
let Test.9 = 1i64; let Test.10 = 1i64;
jump Test.8 Test.9; jump Test.9 Test.10;
else else
let Test.10 = 2i64; let Test.11 = 2i64;
jump Test.8 Test.10; jump Test.9 Test.11;
else else
let Test.11 = 3i64; let Test.12 = 3i64;
jump Test.8 Test.11; jump Test.9 Test.12;
procedure Test.0 (): procedure Test.0 ():
let Test.6 = Struct {}; let Test.7 = Struct {};
let Test.5 = CallByName Test.1 Test.6; let Test.6 = CallByName Test.1 Test.7;
ret Test.5; ret Test.6;
"# "#
), ),
) )
@ -1370,70 +1367,70 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure List.3 (#Attr.2, #Attr.3): procedure List.3 (#Attr.2, #Attr.3):
let Test.38 = lowlevel ListLen #Attr.2; let Test.39 = lowlevel ListLen #Attr.2;
let Test.34 = lowlevel NumLt #Attr.3 Test.38; let Test.35 = lowlevel NumLt #Attr.3 Test.39;
if Test.34 then if Test.35 then
let Test.37 = 1i64; let Test.38 = 1i64;
let Test.36 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; let Test.37 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
let Test.35 = Ok Test.37 Test.36; let Test.36 = Ok Test.38 Test.37;
ret Test.35; ret Test.36;
else else
let Test.33 = 0i64; let Test.34 = 0i64;
let Test.32 = Struct {}; let Test.33 = Struct {};
let Test.31 = Err Test.33 Test.32; let Test.32 = Err Test.34 Test.33;
ret Test.31; ret Test.32;
procedure List.4 (#Attr.2, #Attr.3, #Attr.4): procedure List.4 (#Attr.2, #Attr.3, #Attr.4):
let Test.14 = lowlevel ListLen #Attr.2; let Test.15 = lowlevel ListLen #Attr.2;
let Test.12 = lowlevel NumLt #Attr.3 Test.14; let Test.13 = lowlevel NumLt #Attr.3 Test.15;
if Test.12 then if Test.13 then
let Test.13 = lowlevel ListSet #Attr.2 #Attr.3 #Attr.4; let Test.14 = lowlevel ListSet #Attr.2 #Attr.3 #Attr.4;
ret Test.13; ret Test.14;
else else
ret #Attr.2; ret #Attr.2;
procedure Test.1 (Test.2): procedure Test.1 (Test.2):
let Test.39 = 0i64; let Test.40 = 0i64;
let Test.29 = CallByName List.3 Test.2 Test.39; let Test.30 = CallByName List.3 Test.2 Test.40;
let Test.30 = 0i64; let Test.31 = 0i64;
let Test.28 = CallByName List.3 Test.2 Test.30; let Test.29 = CallByName List.3 Test.2 Test.31;
let Test.7 = Struct {Test.28, Test.29}; let Test.8 = Struct {Test.29, Test.30};
joinpoint Test.25: joinpoint Test.26:
let Test.18 = Array []; let Test.19 = Array [];
ret Test.18; ret Test.19;
in in
let Test.22 = Index 1 Test.7; let Test.23 = Index 1 Test.8;
let Test.23 = 1i64; let Test.24 = 1i64;
let Test.24 = Index 0 Test.22; let Test.25 = Index 0 Test.23;
let Test.27 = lowlevel Eq Test.23 Test.24; let Test.28 = lowlevel Eq Test.24 Test.25;
if Test.28 then
let Test.20 = Index 0 Test.8;
let Test.21 = 1i64;
let Test.22 = Index 0 Test.20;
let Test.27 = lowlevel Eq Test.21 Test.22;
if Test.27 then if Test.27 then
let Test.19 = Index 0 Test.7; let Test.18 = Index 0 Test.8;
let Test.20 = 1i64; let Test.4 = Index 1 Test.18;
let Test.21 = Index 0 Test.19; let Test.17 = Index 1 Test.8;
let Test.26 = lowlevel Eq Test.20 Test.21; let Test.5 = Index 1 Test.17;
if Test.26 then let Test.16 = 0i64;
let Test.17 = Index 0 Test.7; let Test.10 = CallByName List.4 Test.2 Test.16 Test.5;
let Test.3 = Index 1 Test.17; let Test.11 = 0i64;
let Test.16 = Index 1 Test.7; let Test.9 = CallByName List.4 Test.10 Test.11 Test.4;
let Test.4 = Index 1 Test.16; ret Test.9;
let Test.15 = 0i64;
let Test.9 = CallByName List.4 Test.2 Test.15 Test.4;
let Test.10 = 0i64;
let Test.8 = CallByName List.4 Test.9 Test.10 Test.3;
ret Test.8;
else else
dec Test.2; dec Test.2;
jump Test.25; jump Test.26;
else else
dec Test.2; dec Test.2;
jump Test.25; jump Test.26;
procedure Test.0 (): procedure Test.0 ():
let Test.40 = 1i64; let Test.41 = 1i64;
let Test.41 = 2i64; let Test.42 = 2i64;
let Test.6 = Array [Test.40, Test.41]; let Test.7 = Array [Test.41, Test.42];
let Test.5 = CallByName Test.1 Test.6; let Test.6 = CallByName Test.1 Test.7;
ret Test.5; ret Test.6;
"# "#
), ),
) )
@ -1704,16 +1701,16 @@ mod test_mono {
r#" r#"
procedure Test.1 (Test.2): procedure Test.1 (Test.2):
inc Test.2; inc Test.2;
let Test.5 = Struct {Test.2, Test.2}; let Test.6 = Struct {Test.2, Test.2};
ret Test.5; ret Test.6;
procedure Test.0 (): procedure Test.0 ():
let Test.6 = 1i64; let Test.7 = 1i64;
let Test.7 = 2i64; let Test.8 = 2i64;
let Test.8 = 3i64; let Test.9 = 3i64;
let Test.4 = Array [Test.6, Test.7, Test.8]; let Test.5 = Array [Test.7, Test.8, Test.9];
let Test.3 = CallByName Test.1 Test.4; let Test.4 = CallByName Test.1 Test.5;
ret Test.3; ret Test.4;
"# "#
), ),
) )
@ -1882,14 +1879,14 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Test.0 (): procedure Test.0 ():
let Test.5 = 0i64;
let Test.7 = 0i64;
let Test.9 = 0i64; let Test.9 = 0i64;
let Test.10 = 1i64; let Test.11 = 0i64;
let Test.8 = Z Test.10; let Test.13 = 0i64;
let Test.6 = S Test.9 Test.8; let Test.14 = 1i64;
let Test.4 = S Test.7 Test.6; let Test.12 = Z Test.14;
let Test.2 = S Test.5 Test.4; let Test.10 = S Test.13 Test.12;
let Test.8 = S Test.11 Test.10;
let Test.2 = S Test.9 Test.8;
ret Test.2; ret Test.2;
"# "#
), ),
@ -1914,24 +1911,24 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Test.0 (): procedure Test.0 ():
let Test.9 = 0i64;
let Test.11 = 0i64;
let Test.13 = 0i64; let Test.13 = 0i64;
let Test.14 = 1i64; let Test.15 = 0i64;
let Test.12 = Z Test.14; let Test.17 = 0i64;
let Test.10 = S Test.13 Test.12; let Test.18 = 1i64;
let Test.8 = S Test.11 Test.10; let Test.16 = Z Test.18;
let Test.2 = S Test.9 Test.8; let Test.14 = S Test.17 Test.16;
let Test.5 = 1i64; let Test.12 = S Test.15 Test.14;
let Test.6 = Index 0 Test.2; let Test.2 = S Test.13 Test.12;
let Test.9 = 1i64;
let Test.10 = Index 0 Test.2;
dec Test.2; dec Test.2;
let Test.7 = lowlevel Eq Test.5 Test.6; let Test.11 = lowlevel Eq Test.9 Test.10;
if Test.7 then if Test.11 then
let Test.3 = 0i64; let Test.7 = 0i64;
ret Test.3; ret Test.7;
else else
let Test.4 = 1i64; let Test.8 = 1i64;
ret Test.4; ret Test.8;
"# "#
), ),
) )
@ -1956,33 +1953,33 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Test.0 (): procedure Test.0 ():
let Test.15 = 0i64;
let Test.17 = 0i64;
let Test.19 = 0i64; let Test.19 = 0i64;
let Test.20 = 1i64; let Test.21 = 0i64;
let Test.18 = Z Test.20; let Test.23 = 0i64;
let Test.16 = S Test.19 Test.18; let Test.24 = 1i64;
let Test.14 = S Test.17 Test.16; let Test.22 = Z Test.24;
let Test.2 = S Test.15 Test.14; let Test.20 = S Test.23 Test.22;
let Test.11 = 0i64; let Test.18 = S Test.21 Test.20;
let Test.12 = Index 0 Test.2; let Test.2 = S Test.19 Test.18;
let Test.13 = lowlevel Eq Test.11 Test.12; let Test.15 = 0i64;
if Test.13 then let Test.16 = Index 0 Test.2;
let Test.7 = Index 1 Test.2; let Test.17 = lowlevel Eq Test.15 Test.16;
let Test.8 = 0i64; if Test.17 then
let Test.9 = Index 0 Test.7; let Test.11 = Index 1 Test.2;
dec Test.7; let Test.12 = 0i64;
let Test.13 = Index 0 Test.11;
dec Test.11;
decref Test.2; decref Test.2;
let Test.10 = lowlevel Eq Test.8 Test.9; let Test.14 = lowlevel Eq Test.12 Test.13;
if Test.10 then if Test.14 then
let Test.3 = 1i64; let Test.7 = 1i64;
ret Test.3; ret Test.7;
else else
let Test.5 = 0i64; let Test.9 = 0i64;
ret Test.5; ret Test.9;
else else
let Test.6 = 0i64; let Test.10 = 0i64;
ret Test.6; ret Test.10;
"# "#
), ),
) )
@ -2009,14 +2006,14 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Num.26 (#Attr.2, #Attr.3): procedure Num.26 (#Attr.2, #Attr.3):
let Test.13 = lowlevel NumMul #Attr.2 #Attr.3; let Test.17 = lowlevel NumMul #Attr.2 #Attr.3;
ret Test.13; ret Test.17;
procedure Test.1 (Test.6): procedure Test.1 (Test.6):
let Test.18 = Index 1 Test.6; let Test.22 = Index 1 Test.6;
let Test.19 = false; let Test.23 = false;
let Test.20 = lowlevel Eq Test.19 Test.18; let Test.24 = lowlevel Eq Test.23 Test.22;
if Test.20 then if Test.24 then
let Test.8 = Index 0 Test.6; let Test.8 = Index 0 Test.6;
ret Test.8; ret Test.8;
else else
@ -2024,10 +2021,10 @@ mod test_mono {
ret Test.10; ret Test.10;
procedure Test.1 (Test.6): procedure Test.1 (Test.6):
let Test.29 = Index 0 Test.6; let Test.33 = Index 0 Test.6;
let Test.30 = false; let Test.34 = false;
let Test.31 = lowlevel Eq Test.30 Test.29; let Test.35 = lowlevel Eq Test.34 Test.33;
if Test.31 then if Test.35 then
let Test.8 = 3i64; let Test.8 = 3i64;
ret Test.8; ret Test.8;
else else
@ -2035,22 +2032,6 @@ mod test_mono {
ret Test.10; ret Test.10;
procedure Test.0 (): procedure Test.0 ():
let Test.34 = true;
let Test.5 = CallByName Test.1 Test.34;
let Test.32 = false;
let Test.3 = CallByName Test.1 Test.32;
let Test.24 = 11i64;
let Test.25 = true;
let Test.23 = Struct {Test.24, Test.25};
let Test.4 = CallByName Test.1 Test.23;
let Test.21 = 7i64;
let Test.22 = false;
let Test.15 = Struct {Test.21, Test.22};
let Test.2 = CallByName Test.1 Test.15;
let Test.14 = CallByName Num.26 Test.2 Test.3;
let Test.12 = CallByName Num.26 Test.14 Test.4;
let Test.11 = CallByName Num.26 Test.12 Test.5;
ret Test.11;
"# "#
), ),
) )
@ -2074,37 +2055,37 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure Num.24 (#Attr.2, #Attr.3): procedure Num.24 (#Attr.2, #Attr.3):
let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3; let Test.8 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Test.6; ret Test.8;
procedure Test.0 (): procedure Test.0 ():
let Test.18 = 0i64;
let Test.20 = 0i64; let Test.20 = 0i64;
let Test.19 = 41i64; let Test.22 = 0i64;
let Test.17 = Just Test.20 Test.19; let Test.21 = 41i64;
let Test.2 = Just Test.18 Test.17; let Test.19 = Just Test.22 Test.21;
joinpoint Test.14: let Test.2 = Just Test.20 Test.19;
let Test.8 = 1i64; joinpoint Test.16:
ret Test.8; let Test.10 = 1i64;
ret Test.10;
in in
let Test.14 = 0i64;
let Test.15 = Index 0 Test.2;
let Test.18 = lowlevel Eq Test.14 Test.15;
if Test.18 then
let Test.11 = Index 1 Test.2;
let Test.12 = 0i64; let Test.12 = 0i64;
let Test.13 = Index 0 Test.2; let Test.13 = Index 0 Test.11;
let Test.16 = lowlevel Eq Test.12 Test.13; let Test.17 = lowlevel Eq Test.12 Test.13;
if Test.16 then if Test.17 then
let Test.9 = Index 1 Test.2; let Test.9 = Index 1 Test.2;
let Test.10 = 0i64; let Test.5 = Index 1 Test.9;
let Test.11 = Index 0 Test.9; let Test.7 = 1i64;
let Test.15 = lowlevel Eq Test.10 Test.11; let Test.6 = CallByName Num.24 Test.5 Test.7;
if Test.15 then ret Test.6;
let Test.7 = Index 1 Test.2;
let Test.3 = Index 1 Test.7;
let Test.5 = 1i64;
let Test.4 = CallByName Num.24 Test.3 Test.5;
ret Test.4;
else else
jump Test.14; jump Test.16;
else else
jump Test.14; jump Test.16;
"# "#
), ),
) )
@ -2193,67 +2174,67 @@ mod test_mono {
indoc!( indoc!(
r#" r#"
procedure List.3 (#Attr.2, #Attr.3): procedure List.3 (#Attr.2, #Attr.3):
let Test.40 = lowlevel ListLen #Attr.2; let Test.41 = lowlevel ListLen #Attr.2;
let Test.36 = lowlevel NumLt #Attr.3 Test.40; let Test.37 = lowlevel NumLt #Attr.3 Test.41;
if Test.36 then if Test.37 then
let Test.39 = 1i64; let Test.40 = 1i64;
let Test.38 = lowlevel ListGetUnsafe #Attr.2 #Attr.3; let Test.39 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
let Test.37 = Ok Test.39 Test.38; let Test.38 = Ok Test.40 Test.39;
ret Test.37; ret Test.38;
else else
let Test.35 = 0i64; let Test.36 = 0i64;
let Test.34 = Struct {}; let Test.35 = Struct {};
let Test.33 = Err Test.35 Test.34; let Test.34 = Err Test.36 Test.35;
ret Test.33; ret Test.34;
procedure List.4 (#Attr.2, #Attr.3, #Attr.4): procedure List.4 (#Attr.2, #Attr.3, #Attr.4):
let Test.18 = lowlevel ListLen #Attr.2; let Test.19 = lowlevel ListLen #Attr.2;
let Test.16 = lowlevel NumLt #Attr.3 Test.18; let Test.17 = lowlevel NumLt #Attr.3 Test.19;
if Test.16 then if Test.17 then
let Test.17 = lowlevel ListSet #Attr.2 #Attr.3 #Attr.4; let Test.18 = lowlevel ListSet #Attr.2 #Attr.3 #Attr.4;
ret Test.17; ret Test.18;
else else
ret #Attr.2; ret #Attr.2;
procedure Test.1 (Test.2, Test.3, Test.4): procedure Test.1 (Test.2, Test.3, Test.4):
let Test.32 = CallByName List.3 Test.4 Test.3; let Test.33 = CallByName List.3 Test.4 Test.3;
let Test.31 = CallByName List.3 Test.4 Test.2; let Test.32 = CallByName List.3 Test.4 Test.2;
let Test.12 = Struct {Test.31, Test.32}; let Test.13 = Struct {Test.32, Test.33};
joinpoint Test.28: joinpoint Test.29:
let Test.21 = Array []; let Test.22 = Array [];
ret Test.21; ret Test.22;
in in
let Test.25 = Index 1 Test.12; let Test.26 = Index 1 Test.13;
let Test.26 = 1i64; let Test.27 = 1i64;
let Test.27 = Index 0 Test.25; let Test.28 = Index 0 Test.26;
let Test.30 = lowlevel Eq Test.26 Test.27; let Test.31 = lowlevel Eq Test.27 Test.28;
if Test.31 then
let Test.23 = Index 0 Test.13;
let Test.24 = 1i64;
let Test.25 = Index 0 Test.23;
let Test.30 = lowlevel Eq Test.24 Test.25;
if Test.30 then if Test.30 then
let Test.22 = Index 0 Test.12; let Test.21 = Index 0 Test.13;
let Test.23 = 1i64; let Test.6 = Index 1 Test.21;
let Test.24 = Index 0 Test.22; let Test.20 = Index 1 Test.13;
let Test.29 = lowlevel Eq Test.23 Test.24; let Test.7 = Index 1 Test.20;
if Test.29 then let Test.15 = CallByName List.4 Test.4 Test.2 Test.7;
let Test.20 = Index 0 Test.12; let Test.14 = CallByName List.4 Test.15 Test.3 Test.6;
let Test.5 = Index 1 Test.20; ret Test.14;
let Test.19 = Index 1 Test.12;
let Test.6 = Index 1 Test.19;
let Test.14 = CallByName List.4 Test.4 Test.2 Test.6;
let Test.13 = CallByName List.4 Test.14 Test.3 Test.5;
ret Test.13;
else else
dec Test.4; dec Test.4;
jump Test.28; jump Test.29;
else else
dec Test.4; dec Test.4;
jump Test.28; jump Test.29;
procedure Test.0 (): procedure Test.0 ():
let Test.9 = 0i64;
let Test.10 = 0i64; let Test.10 = 0i64;
let Test.41 = 1i64; let Test.11 = 0i64;
let Test.11 = Array [Test.41]; let Test.42 = 1i64;
let Test.8 = CallByName Test.1 Test.9 Test.10 Test.11; let Test.12 = Array [Test.42];
ret Test.8; let Test.9 = CallByName Test.1 Test.10 Test.11 Test.12;
ret Test.9;
"# "#
), ),
) )

View file

@ -728,6 +728,27 @@ fn type_to_variable(
register(subs, rank, pools, content) register(subs, rank, pools, content)
} }
FunctionOrTagUnion(tag_name, symbol, ext) => {
let temp_ext_var = type_to_variable(subs, rank, pools, cached, ext);
let mut ext_tag_vec = Vec::new();
let new_ext_var = match roc_types::pretty_print::chase_ext_tag_union(
subs,
temp_ext_var,
&mut ext_tag_vec,
) {
Ok(()) => Variable::EMPTY_TAG_UNION,
Err((new, _)) => new,
};
debug_assert!(ext_tag_vec.is_empty());
let content = Content::Structure(FlatType::FunctionOrTagUnion(
tag_name.clone(),
*symbol,
new_ext_var,
));
register(subs, rank, pools, content)
}
RecursiveTagUnion(rec_var, tags, ext) => { RecursiveTagUnion(rec_var, tags, ext) => {
let mut tag_vars = MutMap::default(); let mut tag_vars = MutMap::default();
@ -1134,6 +1155,10 @@ fn adjust_rank_content(
rank rank
} }
FunctionOrTagUnion(_, _, ext_var) => {
adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var)
}
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var); let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
@ -1309,6 +1334,12 @@ fn instantiate_rigids_help(
) )
} }
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
tag_name,
symbol,
instantiate_rigids_help(subs, max_rank, pools, ext_var),
),
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut new_tags = MutMap::default(); let mut new_tags = MutMap::default();
@ -1495,6 +1526,12 @@ fn deep_copy_var_help(
TagUnion(new_tags, deep_copy_var_help(subs, max_rank, pools, ext_var)) TagUnion(new_tags, deep_copy_var_help(subs, max_rank, pools, ext_var))
} }
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
tag_name,
symbol,
deep_copy_var_help(subs, max_rank, pools, ext_var),
),
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut new_tags = MutMap::default(); let mut new_tags = MutMap::default();

View file

@ -179,6 +179,9 @@ fn find_names_needed(
find_names_needed(ext_var, subs, roots, root_appearances, names_taken); find_names_needed(ext_var, subs, roots, root_appearances, names_taken);
} }
Structure(FunctionOrTagUnion(_, _, ext_var)) => {
find_names_needed(ext_var, subs, roots, root_appearances, names_taken);
}
Structure(RecursiveTagUnion(rec_var, tags, ext_var)) => { Structure(RecursiveTagUnion(rec_var, tags, ext_var)) => {
let mut sorted_tags: Vec<_> = tags.iter().collect(); let mut sorted_tags: Vec<_> = tags.iter().collect();
sorted_tags.sort(); sorted_tags.sort();
@ -487,6 +490,28 @@ fn write_flat_type(env: &Env, flat_type: FlatType, subs: &Subs, buf: &mut String
} }
} }
FunctionOrTagUnion(tag_name, _, ext_var) => {
let interns = &env.interns;
let home = env.home;
buf.push_str("[ ");
buf.push_str(&tag_name.as_string(&interns, home));
buf.push_str(" ]");
let mut sorted_fields = vec![(tag_name, vec![])];
let ext_content = chase_ext_tag_union(subs, ext_var, &mut sorted_fields);
if let Err((_, content)) = ext_content {
// This is an open tag union, so print the variable
// right after the ']'
//
// e.g. the "*" at the end of `{ x: I64 }*`
// or the "r" at the end of `{ x: I64 }r`
write_content(env, content, subs, buf, parens)
}
}
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
let interns = &env.interns; let interns = &env.interns;
let home = env.home; let home = env.home;
@ -570,6 +595,11 @@ pub fn chase_ext_tag_union(
chase_ext_tag_union(subs, ext_var, fields) chase_ext_tag_union(subs, ext_var, fields)
} }
Content::Structure(FunctionOrTagUnion(tag_name, _, ext_var)) => {
fields.push((tag_name, vec![]));
chase_ext_tag_union(subs, ext_var, fields)
}
Content::Alias(_, _, var) => chase_ext_tag_union(subs, var, fields), Content::Alias(_, _, var) => chase_ext_tag_union(subs, var, fields),
content => Err((var, content)), content => Err((var, content)),

View file

@ -104,6 +104,10 @@ fn hash_solved_type_help<H: Hasher>(
hash_solved_type_help(ext, flex_vars, state); hash_solved_type_help(ext, flex_vars, state);
} }
FunctionOrTagUnion(_, _, ext) => {
hash_solved_type_help(ext, flex_vars, state);
}
RecursiveTagUnion(rec, tags, ext) => { RecursiveTagUnion(rec, tags, ext) => {
var_id_hash_help(*rec, flex_vars, state); var_id_hash_help(*rec, flex_vars, state);
for (name, arguments) in tags { for (name, arguments) in tags {
@ -172,6 +176,7 @@ pub enum SolvedType {
}, },
EmptyRecord, EmptyRecord,
TagUnion(Vec<(TagName, Vec<SolvedType>)>, Box<SolvedType>), TagUnion(Vec<(TagName, Vec<SolvedType>)>, Box<SolvedType>),
FunctionOrTagUnion(TagName, Symbol, Box<SolvedType>),
RecursiveTagUnion(VarId, Vec<(TagName, Vec<SolvedType>)>, Box<SolvedType>), RecursiveTagUnion(VarId, Vec<(TagName, Vec<SolvedType>)>, Box<SolvedType>),
EmptyTagUnion, EmptyTagUnion,
/// A type from an Invalid module /// A type from an Invalid module
@ -263,6 +268,10 @@ impl SolvedType {
SolvedType::TagUnion(solved_tags, Box::new(solved_ext)) SolvedType::TagUnion(solved_tags, Box::new(solved_ext))
} }
FunctionOrTagUnion(tag_name, symbol, box_ext) => {
let solved_ext = Self::from_type(solved_subs, box_ext);
SolvedType::FunctionOrTagUnion(tag_name.clone(), *symbol, Box::new(solved_ext))
}
RecursiveTagUnion(rec_var, tags, box_ext) => { RecursiveTagUnion(rec_var, tags, box_ext) => {
let solved_ext = Self::from_type(solved_subs, box_ext); let solved_ext = Self::from_type(solved_subs, box_ext);
let mut solved_tags = Vec::with_capacity(tags.len()); let mut solved_tags = Vec::with_capacity(tags.len());
@ -423,6 +432,11 @@ impl SolvedType {
SolvedType::TagUnion(new_tags, Box::new(ext)) SolvedType::TagUnion(new_tags, Box::new(ext))
} }
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
let ext = Self::from_var_help(subs, recursion_vars, ext_var);
SolvedType::FunctionOrTagUnion(tag_name, symbol, Box::new(ext))
}
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
recursion_vars.insert(subs, rec_var); recursion_vars.insert(subs, rec_var);
@ -562,6 +576,11 @@ pub fn to_type(
Type::TagUnion(new_tags, Box::new(to_type(ext, free_vars, var_store))) Type::TagUnion(new_tags, Box::new(to_type(ext, free_vars, var_store)))
} }
FunctionOrTagUnion(tag_name, symbol, ext) => Type::FunctionOrTagUnion(
tag_name.clone(),
*symbol,
Box::new(to_type(ext, free_vars, var_store)),
),
RecursiveTagUnion(rec_var_id, tags, ext) => { RecursiveTagUnion(rec_var_id, tags, ext) => {
let mut new_tags = Vec::with_capacity(tags.len()); let mut new_tags = Vec::with_capacity(tags.len());

View file

@ -606,6 +606,7 @@ pub enum FlatType {
Func(Vec<Variable>, Variable, Variable), Func(Vec<Variable>, Variable, Variable),
Record(MutMap<Lowercase, RecordField<Variable>>, Variable), Record(MutMap<Lowercase, RecordField<Variable>>, Variable),
TagUnion(MutMap<TagName, Vec<Variable>>, Variable), TagUnion(MutMap<TagName, Vec<Variable>>, Variable),
FunctionOrTagUnion(TagName, Symbol, Variable),
RecursiveTagUnion(Variable, MutMap<TagName, Vec<Variable>>, Variable), RecursiveTagUnion(Variable, MutMap<TagName, Vec<Variable>>, Variable),
Erroneous(Problem), Erroneous(Problem),
EmptyRecord, EmptyRecord,
@ -662,6 +663,10 @@ fn occurs(
let it = once(&ext_var).chain(tags.values().flatten()); let it = once(&ext_var).chain(tags.values().flatten());
short_circuit(subs, root_var, &new_seen, it) short_circuit(subs, root_var, &new_seen, it)
} }
FunctionOrTagUnion(_, _, ext_var) => {
let it = once(&ext_var);
short_circuit(subs, root_var, &new_seen, it)
}
RecursiveTagUnion(_rec_var, tags, ext_var) => { RecursiveTagUnion(_rec_var, tags, ext_var) => {
// TODO rec_var is excluded here, verify that this is correct // TODO rec_var is excluded here, verify that this is correct
let it = once(&ext_var).chain(tags.values().flatten()); let it = once(&ext_var).chain(tags.values().flatten());
@ -752,6 +757,13 @@ fn explicit_substitute(
} }
subs.set_content(in_var, Structure(TagUnion(tags, new_ext_var))); subs.set_content(in_var, Structure(TagUnion(tags, new_ext_var)));
} }
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen);
subs.set_content(
in_var,
Structure(FunctionOrTagUnion(tag_name, symbol, new_ext_var)),
);
}
RecursiveTagUnion(rec_var, mut tags, ext_var) => { RecursiveTagUnion(rec_var, mut tags, ext_var) => {
// NOTE rec_var is not substituted, verify that this is correct! // NOTE rec_var is not substituted, verify that this is correct!
let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen); let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen);
@ -891,6 +903,10 @@ fn get_var_names(
taken_names taken_names
} }
FlatType::FunctionOrTagUnion(_, _, ext_var) => {
get_var_names(subs, ext_var, taken_names)
}
FlatType::RecursiveTagUnion(rec_var, tags, ext_var) => { FlatType::RecursiveTagUnion(rec_var, tags, ext_var) => {
let taken_names = get_var_names(subs, ext_var, taken_names); let taken_names = get_var_names(subs, ext_var, taken_names);
let mut taken_names = get_var_names(subs, rec_var, taken_names); let mut taken_names = get_var_names(subs, rec_var, taken_names);
@ -1142,6 +1158,32 @@ fn flat_type_to_err_type(
} }
} }
FunctionOrTagUnion(tag_name, _, ext_var) => {
let mut err_tags = SendMap::default();
err_tags.insert(tag_name, vec![]);
match var_to_err_type(subs, state, ext_var).unwrap_alias() {
ErrorType::TagUnion(sub_tags, sub_ext) => {
ErrorType::TagUnion(sub_tags.union(err_tags), sub_ext)
}
ErrorType::RecursiveTagUnion(_, sub_tags, sub_ext) => {
ErrorType::TagUnion(sub_tags.union(err_tags), sub_ext)
}
ErrorType::FlexVar(var) => {
ErrorType::TagUnion(err_tags, TypeExt::FlexOpen(var))
}
ErrorType::RigidVar(var) => {
ErrorType::TagUnion(err_tags, TypeExt::RigidOpen(var))
}
other =>
panic!("Tried to convert a tag union extension to an error, but the tag union extension had the ErrorType of {:?}", other)
}
}
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut err_tags = SendMap::default(); let mut err_tags = SendMap::default();
@ -1236,6 +1278,9 @@ fn restore_content(subs: &mut Subs, content: &Content) {
subs.restore(*ext_var); subs.restore(*ext_var);
} }
FunctionOrTagUnion(_, _, ext_var) => {
subs.restore(*ext_var);
}
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
for var in tags.values().flatten() { for var in tags.values().flatten() {

View file

@ -141,6 +141,7 @@ pub enum Type {
Function(Vec<Type>, Box<Type>, Box<Type>), Function(Vec<Type>, Box<Type>, Box<Type>),
Record(SendMap<Lowercase, RecordField<Type>>, Box<Type>), Record(SendMap<Lowercase, RecordField<Type>>, Box<Type>),
TagUnion(Vec<(TagName, Vec<Type>)>, Box<Type>), TagUnion(Vec<(TagName, Vec<Type>)>, Box<Type>),
FunctionOrTagUnion(TagName, Symbol, Box<Type>),
Alias(Symbol, Vec<(Lowercase, Type)>, Box<Type>), Alias(Symbol, Vec<(Lowercase, Type)>, Box<Type>),
HostExposedAlias { HostExposedAlias {
name: Symbol, name: Symbol,
@ -308,6 +309,26 @@ impl fmt::Debug for Type {
} }
} }
} }
Type::FunctionOrTagUnion(tag_name, _, ext) => {
write!(f, "[")?;
write!(f, "{:?}", tag_name)?;
write!(f, "]")?;
match *ext.clone() {
Type::EmptyTagUnion => {
// This is a closed variant. We're done!
Ok(())
}
other => {
// This is an open tag union, so print the variable
// right after the ']'
//
// e.g. the "*" at the end of `[ Foo ]*`
// or the "r" at the end of `[ DivByZero ]r`
other.fmt(f)
}
}
}
Type::RecursiveTagUnion(rec, tags, ext) => { Type::RecursiveTagUnion(rec, tags, ext) => {
write!(f, "[")?; write!(f, "[")?;
@ -404,6 +425,9 @@ impl Type {
} }
ext.substitute(substitutions); ext.substitute(substitutions);
} }
FunctionOrTagUnion(_, _, ext) => {
ext.substitute(substitutions);
}
RecursiveTagUnion(_, tags, ext) => { RecursiveTagUnion(_, tags, ext) => {
for (_, args) in tags { for (_, args) in tags {
for x in args { for x in args {
@ -456,6 +480,9 @@ impl Type {
closure.substitute_alias(rep_symbol, actual); closure.substitute_alias(rep_symbol, actual);
ret.substitute_alias(rep_symbol, actual); ret.substitute_alias(rep_symbol, actual);
} }
FunctionOrTagUnion(_, _, ext) => {
ext.substitute_alias(rep_symbol, actual);
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => { RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
for (_, args) in tags { for (_, args) in tags {
for x in args { for x in args {
@ -506,6 +533,7 @@ impl Type {
|| closure.contains_symbol(rep_symbol) || closure.contains_symbol(rep_symbol)
|| args.iter().any(|arg| arg.contains_symbol(rep_symbol)) || args.iter().any(|arg| arg.contains_symbol(rep_symbol))
} }
FunctionOrTagUnion(_, _, ext) => ext.contains_symbol(rep_symbol),
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => { RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
ext.contains_symbol(rep_symbol) ext.contains_symbol(rep_symbol)
|| tags || tags
@ -541,6 +569,7 @@ impl Type {
|| closure.contains_variable(rep_variable) || closure.contains_variable(rep_variable)
|| args.iter().any(|arg| arg.contains_variable(rep_variable)) || args.iter().any(|arg| arg.contains_variable(rep_variable))
} }
FunctionOrTagUnion(_, _, ext) => ext.contains_variable(rep_variable),
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => { RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
ext.contains_variable(rep_variable) ext.contains_variable(rep_variable)
|| tags || tags
@ -595,6 +624,9 @@ impl Type {
closure.instantiate_aliases(region, aliases, var_store, introduced); closure.instantiate_aliases(region, aliases, var_store, introduced);
ret.instantiate_aliases(region, aliases, var_store, introduced); ret.instantiate_aliases(region, aliases, var_store, introduced);
} }
FunctionOrTagUnion(_, _, ext) => {
ext.instantiate_aliases(region, aliases, var_store, introduced);
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => { RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
for (_, args) in tags { for (_, args) in tags {
for x in args { for x in args {
@ -734,6 +766,9 @@ fn symbols_help(tipe: &Type, accum: &mut ImSet<Symbol>) {
symbols_help(&closure, accum); symbols_help(&closure, accum);
args.iter().for_each(|arg| symbols_help(arg, accum)); args.iter().for_each(|arg| symbols_help(arg, accum));
} }
FunctionOrTagUnion(_, _, ext) => {
symbols_help(&ext, accum);
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => { RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
symbols_help(&ext, accum); symbols_help(&ext, accum);
tags.iter() tags.iter()
@ -807,6 +842,9 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
} }
variables_help(ext, accum); variables_help(ext, accum);
} }
FunctionOrTagUnion(_, _, ext) => {
variables_help(ext, accum);
}
RecursiveTagUnion(rec, tags, ext) => { RecursiveTagUnion(rec, tags, ext) => {
for (_, args) in tags { for (_, args) in tags {
for x in args { for x in args {
@ -900,6 +938,9 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
} }
variables_help_detailed(ext, accum); variables_help_detailed(ext, accum);
} }
FunctionOrTagUnion(_, _, ext) => {
variables_help_detailed(ext, accum);
}
RecursiveTagUnion(rec, tags, ext) => { RecursiveTagUnion(rec, tags, ext) => {
for (_, args) in tags { for (_, args) in tags {
for x in args { for x in args {

View file

@ -237,6 +237,10 @@ fn unify_structure(
// unify the structure with this recursive tag union // unify the structure with this recursive tag union
unify_pool(subs, pool, ctx.first, *structure) unify_pool(subs, pool, ctx.first, *structure)
} }
FlatType::FunctionOrTagUnion(_, _, _) => {
// unify the structure with this unrecursive tag union
unify_pool(subs, pool, ctx.first, *structure)
}
_ => todo!("rec structure {:?}", &flat_type), _ => todo!("rec structure {:?}", &flat_type),
}, },
@ -978,12 +982,106 @@ fn unify_flat_type(
problems problems
} }
} }
(TagUnion(tags, ext), Func(args, closure, ret)) if tags.len() == 1 => { (FunctionOrTagUnion(tag_name, tag_symbol, ext), Func(args, closure, ret)) => {
unify_tag_union_and_func(tags, args, subs, pool, ctx, ext, ret, closure, true) unify_function_or_tag_union_and_func(
subs,
pool,
ctx,
tag_name,
*tag_symbol,
*ext,
args,
*ret,
*closure,
true,
)
} }
(Func(args, closure, ret), TagUnion(tags, ext)) if tags.len() == 1 => { (Func(args, closure, ret), FunctionOrTagUnion(tag_name, tag_symbol, ext)) => {
unify_tag_union_and_func(tags, args, subs, pool, ctx, ext, ret, closure, false) unify_function_or_tag_union_and_func(
subs,
pool,
ctx,
tag_name,
*tag_symbol,
*ext,
args,
*ret,
*closure,
false,
)
} }
(FunctionOrTagUnion(tag_name_1, _, ext_1), FunctionOrTagUnion(tag_name_2, _, ext_2)) => {
if tag_name_1 == tag_name_2 {
let problems = unify_pool(subs, pool, *ext_1, *ext_2);
if problems.is_empty() {
let desc = subs.get(ctx.second);
merge(subs, ctx, desc.content)
} else {
problems
}
} else {
let mut tags1 = MutMap::default();
tags1.insert(tag_name_1.clone(), vec![]);
let union1 = gather_tags(subs, tags1, *ext_1);
let mut tags2 = MutMap::default();
tags2.insert(tag_name_2.clone(), vec![]);
let union2 = gather_tags(subs, tags2, *ext_2);
unify_tag_union(subs, pool, ctx, union1, union2, (None, None))
}
}
(TagUnion(tags1, ext1), FunctionOrTagUnion(tag_name, _, ext2)) => {
let union1 = gather_tags(subs, tags1.clone(), *ext1);
let mut tags2 = MutMap::default();
tags2.insert(tag_name.clone(), vec![]);
let union2 = gather_tags(subs, tags2, *ext2);
unify_tag_union(subs, pool, ctx, union1, union2, (None, None))
}
(FunctionOrTagUnion(tag_name, _, ext1), TagUnion(tags2, ext2)) => {
let mut tags1 = MutMap::default();
tags1.insert(tag_name.clone(), vec![]);
let union1 = gather_tags(subs, tags1, *ext1);
let union2 = gather_tags(subs, tags2.clone(), *ext2);
unify_tag_union(subs, pool, ctx, union1, union2, (None, None))
}
(RecursiveTagUnion(recursion_var, tags1, ext1), FunctionOrTagUnion(tag_name, _, ext2)) => {
// this never happens in type-correct programs, but may happen if there is a type error
debug_assert!(is_recursion_var(subs, *recursion_var));
let mut tags2 = MutMap::default();
tags2.insert(tag_name.clone(), vec![]);
let union1 = gather_tags(subs, tags1.clone(), *ext1);
let union2 = gather_tags(subs, tags2, *ext2);
unify_tag_union(
subs,
pool,
ctx,
union1,
union2,
(Some(*recursion_var), None),
)
}
(FunctionOrTagUnion(tag_name, _, ext1), RecursiveTagUnion(recursion_var, tags2, ext2)) => {
debug_assert!(is_recursion_var(subs, *recursion_var));
let mut tags1 = MutMap::default();
tags1.insert(tag_name.clone(), vec![]);
let union1 = gather_tags(subs, tags1, *ext1);
let union2 = gather_tags(subs, tags2.clone(), *ext2);
unify_tag_union_not_recursive_recursive(subs, pool, ctx, union1, union2, *recursion_var)
}
(other1, other2) => mismatch!( (other1, other2) => mismatch!(
"Trying to unify two flat types that are incompatible: {:?} ~ {:?}", "Trying to unify two flat types that are incompatible: {:?} ~ {:?}",
other1, other1,
@ -1166,35 +1264,33 @@ fn is_recursion_var(subs: &Subs, var: Variable) -> bool {
) )
} }
#[allow(clippy::too_many_arguments, clippy::ptr_arg)] #[allow(clippy::too_many_arguments)]
fn unify_tag_union_and_func( fn unify_function_or_tag_union_and_func(
tags: &MutMap<TagName, Vec<Variable>>,
args: &Vec<Variable>,
subs: &mut Subs, subs: &mut Subs,
pool: &mut Pool, pool: &mut Pool,
ctx: &Context, ctx: &Context,
ext: &Variable, tag_name: &TagName,
ret: &Variable, _tag_symbol: Symbol,
closure: &Variable, tag_ext: Variable,
function_arguments: &[Variable],
function_return: Variable,
_function_lambda_set: Variable,
left: bool, left: bool,
) -> Outcome { ) -> Outcome {
use FlatType::*; use FlatType::*;
let (tag_name, payload) = tags.iter().next().unwrap();
if payload.is_empty() {
let mut new_tags = MutMap::with_capacity_and_hasher(1, default_hasher()); let mut new_tags = MutMap::with_capacity_and_hasher(1, default_hasher());
new_tags.insert(tag_name.clone(), args.to_owned()); new_tags.insert(tag_name.clone(), function_arguments.to_owned());
let content = Structure(TagUnion(new_tags, *ext)); let content = Structure(TagUnion(new_tags, tag_ext));
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 problems = if left {
unify_pool(subs, pool, new_tag_union_var, *ret) unify_pool(subs, pool, new_tag_union_var, function_return)
} else { } else {
unify_pool(subs, pool, *ret, new_tag_union_var) unify_pool(subs, pool, function_return, new_tag_union_var)
}; };
if problems.is_empty() { if problems.is_empty() {
@ -1208,11 +1304,4 @@ fn unify_tag_union_and_func(
} }
problems problems
} else {
mismatch!(
"Trying to unify two flat types that are incompatible: {:?} ~ {:?}",
TagUnion(tags.clone(), *ext),
Func(args.to_owned(), *closure, *ret)
)
}
} }

View file

@ -1243,6 +1243,10 @@ fn adjust_rank_content(
rank rank
} }
FunctionOrTagUnion(_, _, ext_var) => {
adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var)
}
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var); let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
@ -1418,6 +1422,12 @@ fn instantiate_rigids_help(
) )
} }
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
tag_name,
symbol,
instantiate_rigids_help(subs, max_rank, pools, ext_var),
),
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut new_tags = MutMap::default(); let mut new_tags = MutMap::default();
@ -1604,6 +1614,12 @@ fn deep_copy_var_help(
TagUnion(new_tags, deep_copy_var_help(subs, max_rank, pools, ext_var)) TagUnion(new_tags, deep_copy_var_help(subs, max_rank, pools, ext_var))
} }
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
tag_name,
symbol,
deep_copy_var_help(subs, max_rank, pools, ext_var),
),
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut new_tags = MutMap::default(); let mut new_tags = MutMap::default();