mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Merge branch 'trunk' into platform
This commit is contained in:
commit
db2d99f56d
12 changed files with 402 additions and 138 deletions
|
@ -974,9 +974,7 @@ mod gen_primitives {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn io_poc() {
|
||||
use roc_std::RocStr;
|
||||
fn io_poc_effect() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -984,23 +982,51 @@ mod gen_primitives {
|
|||
|
||||
Effect a : [ @Effect ({} -> a) ]
|
||||
|
||||
succeed : a -> Effect a
|
||||
# succeed : a -> Effect a
|
||||
succeed = \x -> @Effect \{} -> x
|
||||
|
||||
foo : Effect Float
|
||||
# runEffect : Effect a -> a
|
||||
runEffect = \@Effect thunk -> thunk {}
|
||||
|
||||
# foo : Effect Float
|
||||
foo =
|
||||
succeed 3.14
|
||||
|
||||
runEffect : Effect a -> a
|
||||
runEffect = \@Effect thunk -> thunk {}
|
||||
|
||||
main : Float
|
||||
main =
|
||||
runEffect foo
|
||||
|
||||
"#
|
||||
),
|
||||
RocStr::from_slice(&"Foo".as_bytes()),
|
||||
RocStr
|
||||
3.14,
|
||||
f64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn io_poc_desugared() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app Test provides [ main ] imports []
|
||||
|
||||
# succeed : a -> ({} -> a)
|
||||
succeed = \x -> \{} -> x
|
||||
|
||||
foo : {} -> Float
|
||||
foo =
|
||||
succeed 3.14
|
||||
|
||||
# runEffect : ({} -> a) -> a
|
||||
runEffect = \thunk -> thunk {}
|
||||
|
||||
main : Float
|
||||
main =
|
||||
runEffect foo
|
||||
"#
|
||||
),
|
||||
3.14,
|
||||
f64
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -402,6 +402,34 @@ mod gen_records {
|
|||
|
||||
#[test]
|
||||
fn optional_field_when_use_default() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app Test provides [ main ] imports []
|
||||
|
||||
f = \r ->
|
||||
when r is
|
||||
{ x: Blue, y ? 3 } -> y
|
||||
{ x: Red, y ? 5 } -> y
|
||||
|
||||
|
||||
main =
|
||||
a = f { x: Blue, y: 7 }
|
||||
b = f { x: Blue }
|
||||
c = f { x: Red, y: 11 }
|
||||
d = f { x: Red }
|
||||
|
||||
a * b * c * d
|
||||
"#
|
||||
),
|
||||
3 * 5 * 7 * 11,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn optional_field_when_use_default_nested() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -425,6 +453,27 @@ mod gen_records {
|
|||
|
||||
#[test]
|
||||
fn optional_field_when_no_use_default() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app Test provides [ main ] imports []
|
||||
|
||||
f = \r ->
|
||||
{ x ? 10, y } = r
|
||||
x + y
|
||||
|
||||
main =
|
||||
f { x: 4, y: 9 }
|
||||
"#
|
||||
),
|
||||
13,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn optional_field_when_no_use_default_nested() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -445,10 +494,13 @@ mod gen_records {
|
|||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app Test provides [ main ] imports []
|
||||
|
||||
f = \r ->
|
||||
{ x ? 10, y } = r
|
||||
x + y
|
||||
|
||||
main =
|
||||
f { y: 9 }
|
||||
"#
|
||||
),
|
||||
|
@ -459,6 +511,27 @@ mod gen_records {
|
|||
|
||||
#[test]
|
||||
fn optional_field_let_no_use_default() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app Test provides [ main ] imports []
|
||||
|
||||
f = \r ->
|
||||
{ x ? 10, y } = r
|
||||
x + y
|
||||
|
||||
main =
|
||||
f { x: 4, y: 9 }
|
||||
"#
|
||||
),
|
||||
13,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn optional_field_let_no_use_default_nested() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -492,6 +565,25 @@ mod gen_records {
|
|||
|
||||
#[test]
|
||||
fn optional_field_function_no_use_default() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app Test provides [ main ] imports []
|
||||
|
||||
f = \{ x ? 10, y } -> x + y
|
||||
|
||||
main =
|
||||
f { x: 4, y: 9 }
|
||||
"#
|
||||
),
|
||||
13,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn optional_field_function_no_use_default_nested() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
|
|
@ -413,6 +413,31 @@ mod gen_tags {
|
|||
|
||||
#[test]
|
||||
fn maybe_is_just() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app Test provides [ main ] imports []
|
||||
|
||||
Maybe a : [ Just a, Nothing ]
|
||||
|
||||
isJust : Maybe a -> Bool
|
||||
isJust = \list ->
|
||||
when list is
|
||||
Nothing -> False
|
||||
Just _ -> True
|
||||
|
||||
main =
|
||||
isJust (Just 42)
|
||||
"#
|
||||
),
|
||||
true,
|
||||
bool
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn maybe_is_just_nested() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
|
|
@ -348,7 +348,7 @@ macro_rules! assert_evals_to {
|
|||
assert_llvm_evals_to!($src, $expected, $ty, $transform, $leak);
|
||||
}
|
||||
{
|
||||
// assert_opt_evals_to!($src, $expected, $ty, $transform, $leak);
|
||||
assert_opt_evals_to!($src, $expected, $ty, $transform, $leak);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2244,8 +2244,12 @@ fn add_def_to_module<'a>(
|
|||
return_type: ret_var,
|
||||
arguments: loc_args,
|
||||
loc_body,
|
||||
captured_symbols,
|
||||
..
|
||||
} => {
|
||||
// this is a top-level definition, it should not capture anything
|
||||
debug_assert!(captured_symbols.is_empty());
|
||||
|
||||
// If this is an exposed symbol, we need to
|
||||
// register it as such. Otherwise, since it
|
||||
// never gets called by Roc code, it will never
|
||||
|
|
|
@ -51,7 +51,6 @@ pub struct Proc<'a> {
|
|||
pub name: Symbol,
|
||||
pub args: &'a [(Layout<'a>, Symbol)],
|
||||
pub body: Stmt<'a>,
|
||||
pub closes_over: Layout<'a>,
|
||||
pub ret_layout: Layout<'a>,
|
||||
pub is_self_recursive: SelfRecursive,
|
||||
}
|
||||
|
@ -1434,7 +1433,7 @@ fn specialize_external<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
let (proc_args, closes_over, ret_layout) =
|
||||
let (proc_args, ret_layout) =
|
||||
build_specialized_proc_from_var(env, layout_cache, pattern_symbols, fn_var)?;
|
||||
|
||||
// reset subs, so we don't get type errors when specializing for a different signature
|
||||
|
@ -1451,7 +1450,6 @@ fn specialize_external<'a>(
|
|||
name: proc_name,
|
||||
args: proc_args,
|
||||
body: specialized_body,
|
||||
closes_over,
|
||||
ret_layout,
|
||||
is_self_recursive: recursivity,
|
||||
};
|
||||
|
@ -1465,15 +1463,42 @@ fn build_specialized_proc_from_var<'a>(
|
|||
layout_cache: &mut LayoutCache<'a>,
|
||||
pattern_symbols: &[Symbol],
|
||||
fn_var: Variable,
|
||||
) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>, Layout<'a>), LayoutProblem> {
|
||||
) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>), LayoutProblem> {
|
||||
match layout_cache.from_var(env.arena, fn_var, env.subs) {
|
||||
Ok(Layout::FunctionPointer(pattern_layouts, ret_layout)) => {
|
||||
let mut pattern_layouts_vec = Vec::with_capacity_in(pattern_layouts.len(), env.arena);
|
||||
pattern_layouts_vec.extend_from_slice(pattern_layouts);
|
||||
|
||||
build_specialized_proc(
|
||||
env.arena,
|
||||
pattern_symbols,
|
||||
pattern_layouts_vec,
|
||||
None,
|
||||
ret_layout.clone(),
|
||||
)
|
||||
}
|
||||
Ok(Layout::Closure(pattern_layouts, closure_layout, ret_layout)) => {
|
||||
let mut pattern_layouts_vec = Vec::with_capacity_in(pattern_layouts.len(), env.arena);
|
||||
pattern_layouts_vec.extend_from_slice(pattern_layouts);
|
||||
|
||||
build_specialized_proc(
|
||||
env.arena,
|
||||
pattern_symbols,
|
||||
pattern_layouts_vec,
|
||||
Some(closure_layout),
|
||||
ret_layout.clone(),
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
match env.subs.get_without_compacting(fn_var).content {
|
||||
Content::Structure(FlatType::Func(pattern_vars, closure_var, ret_var)) => {
|
||||
build_specialized_proc(
|
||||
let closure_layout = ClosureLayout::from_var(env.arena, env.subs, closure_var)?;
|
||||
build_specialized_proc_adapter(
|
||||
env,
|
||||
layout_cache,
|
||||
pattern_symbols,
|
||||
&pattern_vars,
|
||||
Some(closure_var),
|
||||
closure_layout,
|
||||
ret_var,
|
||||
)
|
||||
}
|
||||
|
@ -1487,63 +1512,129 @@ fn build_specialized_proc_from_var<'a>(
|
|||
}
|
||||
_ => {
|
||||
// a top-level constant 0-argument thunk
|
||||
build_specialized_proc(env, layout_cache, pattern_symbols, &[], None, fn_var)
|
||||
build_specialized_proc_adapter(
|
||||
env,
|
||||
layout_cache,
|
||||
pattern_symbols,
|
||||
&[],
|
||||
None,
|
||||
fn_var,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn build_specialized_proc<'a>(
|
||||
fn build_specialized_proc_adapter<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
pattern_symbols: &[Symbol],
|
||||
pattern_vars: &[Variable],
|
||||
closure_var: Option<Variable>,
|
||||
opt_closure_layout: Option<ClosureLayout<'a>>,
|
||||
ret_var: Variable,
|
||||
) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>, Layout<'a>), LayoutProblem> {
|
||||
let mut proc_args = Vec::with_capacity_in(pattern_vars.len(), &env.arena);
|
||||
) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>), LayoutProblem> {
|
||||
let mut arg_layouts = Vec::with_capacity_in(pattern_vars.len(), &env.arena);
|
||||
|
||||
for (arg_var, arg_name) in pattern_vars.iter().zip(pattern_symbols.iter()) {
|
||||
for arg_var in pattern_vars {
|
||||
let layout = layout_cache.from_var(&env.arena, *arg_var, env.subs)?;
|
||||
|
||||
proc_args.push((layout, *arg_name));
|
||||
arg_layouts.push(layout);
|
||||
}
|
||||
|
||||
// is the final argument symbol the closure symbol? then add the closure variable to the
|
||||
// pattern variables
|
||||
if pattern_symbols.last() == Some(&Symbol::ARG_CLOSURE) {
|
||||
let layout = layout_cache.from_var(&env.arena, closure_var.unwrap(), env.subs)?;
|
||||
proc_args.push((layout, Symbol::ARG_CLOSURE));
|
||||
|
||||
debug_assert_eq!(
|
||||
pattern_vars.len() + 1,
|
||||
pattern_symbols.len(),
|
||||
"Tried to zip two vecs with different lengths!"
|
||||
);
|
||||
} else {
|
||||
debug_assert_eq!(
|
||||
pattern_vars.len(),
|
||||
pattern_symbols.len(),
|
||||
"Tried to zip two vecs with different lengths!"
|
||||
);
|
||||
}
|
||||
|
||||
let proc_args = proc_args.into_bump_slice();
|
||||
|
||||
let closes_over = match closure_var {
|
||||
Some(cvar) => match layout_cache.from_var(&env.arena, cvar, env.subs) {
|
||||
Ok(layout) => layout,
|
||||
Err(LayoutProblem::UnresolvedTypeVar) => Layout::Struct(&[]),
|
||||
Err(err) => panic!("TODO handle invalid function {:?}", err),
|
||||
},
|
||||
None => Layout::Struct(&[]),
|
||||
};
|
||||
|
||||
let ret_layout = layout_cache
|
||||
.from_var(&env.arena, ret_var, env.subs)
|
||||
.unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err));
|
||||
|
||||
Ok((proc_args, closes_over, ret_layout))
|
||||
build_specialized_proc(
|
||||
env.arena,
|
||||
pattern_symbols,
|
||||
arg_layouts,
|
||||
opt_closure_layout,
|
||||
ret_layout,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn build_specialized_proc<'a>(
|
||||
arena: &'a Bump,
|
||||
pattern_symbols: &[Symbol],
|
||||
pattern_layouts: Vec<Layout<'a>>,
|
||||
opt_closure_layout: Option<ClosureLayout<'a>>,
|
||||
ret_layout: Layout<'a>,
|
||||
) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>), LayoutProblem> {
|
||||
let mut proc_args = Vec::with_capacity_in(pattern_layouts.len(), arena);
|
||||
|
||||
let pattern_layouts_len = pattern_layouts.len();
|
||||
|
||||
for (arg_layout, arg_name) in pattern_layouts.into_iter().zip(pattern_symbols.iter()) {
|
||||
proc_args.push((arg_layout, *arg_name));
|
||||
}
|
||||
|
||||
// Given
|
||||
//
|
||||
// foo =
|
||||
// x = 42
|
||||
//
|
||||
// f = \{} -> x
|
||||
//
|
||||
// We desugar that into
|
||||
//
|
||||
// f = \{}, x -> x
|
||||
//
|
||||
// foo =
|
||||
// x = 42
|
||||
//
|
||||
// f_closure = { ptr: f, closure: x }
|
||||
//
|
||||
// then
|
||||
match opt_closure_layout {
|
||||
Some(layout) if pattern_symbols.last() == Some(&Symbol::ARG_CLOSURE) => {
|
||||
// here we define the lifted (now top-level) f function. Its final argument is `Symbol::ARG_CLOSURE`,
|
||||
// it stores the closure structure (just an integer in this case)
|
||||
proc_args.push((layout.as_layout(), Symbol::ARG_CLOSURE));
|
||||
|
||||
debug_assert_eq!(
|
||||
pattern_layouts_len + 1,
|
||||
pattern_symbols.len(),
|
||||
"Tried to zip two vecs with different lengths!"
|
||||
);
|
||||
}
|
||||
Some(layout) => {
|
||||
// else if there is a closure layout, we're building the `f_closure` value
|
||||
// that means we're really creating a ( function_ptr, closure_data ) pair
|
||||
|
||||
let closure_data_layout = layout.as_layout();
|
||||
let function_ptr_layout = Layout::FunctionPointer(
|
||||
arena.alloc([Layout::Struct(&[]), closure_data_layout.clone()]),
|
||||
arena.alloc(ret_layout),
|
||||
);
|
||||
|
||||
let closure_layout =
|
||||
Layout::Struct(arena.alloc([function_ptr_layout, closure_data_layout]));
|
||||
|
||||
return Ok((&[], closure_layout));
|
||||
}
|
||||
None => {
|
||||
// else we're making a normal function, no closure problems to worry about
|
||||
// we'll just assert some things
|
||||
|
||||
// make sure there is not arg_closure argument without a closure layout
|
||||
debug_assert!(pattern_symbols.last() != Some(&Symbol::ARG_CLOSURE));
|
||||
|
||||
// since this is not a closure, the number of arguments should match between symbols
|
||||
// and layout
|
||||
debug_assert_eq!(
|
||||
pattern_layouts_len,
|
||||
pattern_symbols.len(),
|
||||
"Tried to zip two vecs with different lengths!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let proc_args = proc_args.into_bump_slice();
|
||||
|
||||
Ok((proc_args, ret_layout))
|
||||
}
|
||||
|
||||
fn specialize<'a>(
|
||||
|
|
|
@ -64,6 +64,54 @@ impl<'a> ClosureLayout<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_var(
|
||||
arena: &'a Bump,
|
||||
subs: &Subs,
|
||||
closure_var: Variable,
|
||||
) -> Result<Option<Self>, LayoutProblem> {
|
||||
let mut tags = std::vec::Vec::new();
|
||||
match roc_types::pretty_print::chase_ext_tag_union(subs, closure_var, &mut tags) {
|
||||
Ok(()) | Err((_, Content::FlexVar(_))) if !tags.is_empty() => {
|
||||
// this is a closure
|
||||
let variant = union_sorted_tags_help(arena, tags, None, subs);
|
||||
|
||||
use UnionVariant::*;
|
||||
match variant {
|
||||
Never | Unit => {
|
||||
// a max closure size of 0 means this is a standart top-level function
|
||||
Ok(None)
|
||||
}
|
||||
BoolUnion { .. } => {
|
||||
let closure_layout = ClosureLayout::from_bool(arena);
|
||||
|
||||
Ok(Some(closure_layout))
|
||||
}
|
||||
ByteUnion(_) => {
|
||||
let closure_layout = ClosureLayout::from_byte(arena);
|
||||
|
||||
Ok(Some(closure_layout))
|
||||
}
|
||||
Unwrapped(layouts) => {
|
||||
let closure_layout =
|
||||
ClosureLayout::from_unwrapped(layouts.into_bump_slice());
|
||||
|
||||
Ok(Some(closure_layout))
|
||||
}
|
||||
Wrapped(_tags) => {
|
||||
// Wrapped(Vec<'a, (TagName, &'a [Layout<'a>])>),
|
||||
todo!("can't specialize multi-size closures yet")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(()) | Err((_, Content::FlexVar(_))) => {
|
||||
// a max closure size of 0 means this is a standart top-level function
|
||||
Ok(None)
|
||||
}
|
||||
_ => panic!("called ClosureLayout.from_var on invalid input"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extend_function_layout(
|
||||
arena: &'a Bump,
|
||||
argument_layouts: &'a [Layout<'a>],
|
||||
|
@ -567,52 +615,12 @@ fn layout_from_flat_type<'a>(
|
|||
|
||||
let ret = Layout::from_var(env, ret_var)?;
|
||||
|
||||
let mut tags = std::vec::Vec::new();
|
||||
match roc_types::pretty_print::chase_ext_tag_union(env.subs, closure_var, &mut tags) {
|
||||
Ok(()) | Err((_, Content::FlexVar(_))) if !tags.is_empty() => {
|
||||
// this is a closure
|
||||
let variant = union_sorted_tags_help(env.arena, tags, None, env.subs);
|
||||
|
||||
let fn_args = fn_args.into_bump_slice();
|
||||
let ret = arena.alloc(ret);
|
||||
|
||||
use UnionVariant::*;
|
||||
match variant {
|
||||
Never | Unit => {
|
||||
// a max closure size of 0 means this is a standart top-level function
|
||||
Ok(Layout::FunctionPointer(fn_args, ret))
|
||||
}
|
||||
BoolUnion { .. } => {
|
||||
let closure_layout = ClosureLayout::from_bool(env.arena);
|
||||
|
||||
Ok(Layout::Closure(fn_args, closure_layout, ret))
|
||||
}
|
||||
ByteUnion(_) => {
|
||||
let closure_layout = ClosureLayout::from_byte(env.arena);
|
||||
|
||||
Ok(Layout::Closure(fn_args, closure_layout, ret))
|
||||
}
|
||||
Unwrapped(layouts) => {
|
||||
let closure_layout =
|
||||
ClosureLayout::from_unwrapped(layouts.into_bump_slice());
|
||||
|
||||
Ok(Layout::Closure(fn_args, closure_layout, ret))
|
||||
}
|
||||
Wrapped(_tags) => {
|
||||
// Wrapped(Vec<'a, (TagName, &'a [Layout<'a>])>),
|
||||
todo!("can't specialize multi-size closures yet")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(()) | Err((_, Content::FlexVar(_))) => {
|
||||
// a max closure size of 0 means this is a standart top-level function
|
||||
Ok(Layout::FunctionPointer(
|
||||
fn_args.into_bump_slice(),
|
||||
arena.alloc(ret),
|
||||
))
|
||||
}
|
||||
Err(_) => todo!(),
|
||||
match ClosureLayout::from_var(env.arena, env.subs, closure_var)? {
|
||||
Some(closure_layout) => Ok(Layout::Closure(fn_args, closure_layout, ret)),
|
||||
None => Ok(Layout::FunctionPointer(fn_args, ret)),
|
||||
}
|
||||
}
|
||||
Record(fields, ext_var) => {
|
||||
|
@ -641,7 +649,10 @@ fn layout_from_flat_type<'a>(
|
|||
use roc_types::types::RecordField::*;
|
||||
match field {
|
||||
Optional(_) => {
|
||||
// optional values are not available at this point
|
||||
// when an optional field reaches this stage, the field was truly
|
||||
// optional, and not unified to be demanded or required
|
||||
// therefore, there is no such field on the record, and we ignore this
|
||||
// field from now on.
|
||||
continue;
|
||||
}
|
||||
Required(var) => var,
|
||||
|
|
|
@ -2013,6 +2013,8 @@ mod test_mono {
|
|||
compiles_to_ir(
|
||||
indoc!(
|
||||
r#"
|
||||
app Test provides [ main ] imports []
|
||||
|
||||
swap : Int, Int, List a -> List a
|
||||
swap = \i, j, list ->
|
||||
when Pair (List.get list i) (List.get list j) is
|
||||
|
@ -2026,6 +2028,7 @@ mod test_mono {
|
|||
_ ->
|
||||
[]
|
||||
|
||||
main =
|
||||
swap 0 0 [0x1]
|
||||
"#
|
||||
),
|
||||
|
|
|
@ -1121,7 +1121,7 @@ fn adjust_rank_content(
|
|||
rank
|
||||
}
|
||||
|
||||
Func(arg_vars, _closure_var, ret_var) => {
|
||||
Func(arg_vars, closure_var, ret_var) => {
|
||||
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, ret_var);
|
||||
|
||||
// TODO investigate further.
|
||||
|
@ -1129,13 +1129,15 @@ fn adjust_rank_content(
|
|||
// My theory is that because the closure_var contains variables already
|
||||
// contained in the signature only, it does not need to be part of the rank
|
||||
// calculuation
|
||||
// rank = rank.max(adjust_rank(
|
||||
// subs,
|
||||
// young_mark,
|
||||
// visit_mark,
|
||||
// group_rank,
|
||||
// closure_var,
|
||||
// ));
|
||||
if true {
|
||||
rank = rank.max(adjust_rank(
|
||||
subs,
|
||||
young_mark,
|
||||
visit_mark,
|
||||
group_rank,
|
||||
closure_var,
|
||||
));
|
||||
}
|
||||
|
||||
for var in arg_vars {
|
||||
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var));
|
||||
|
@ -1207,14 +1209,19 @@ fn adjust_rank_content(
|
|||
}
|
||||
}
|
||||
|
||||
Alias(_, args, _) => {
|
||||
Alias(_, args, real_var) => {
|
||||
let mut rank = Rank::toplevel();
|
||||
|
||||
// from elm-compiler: THEORY: anything in the real_var would be Rank::toplevel()
|
||||
for (_, var) in args {
|
||||
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var));
|
||||
}
|
||||
|
||||
// from elm-compiler: THEORY: anything in the real_var would be Rank::toplevel()
|
||||
// this theory is not true in Roc! aliases of function types capture the closure var
|
||||
rank = rank.max(adjust_rank(
|
||||
subs, young_mark, visit_mark, group_rank, real_var,
|
||||
));
|
||||
|
||||
rank
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1423,6 +1423,7 @@ mod solve_uniq_expr {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn quicksort() {
|
||||
// theory: partition is handled before swap, so swap is not known, and therefore not taken
|
||||
// out of its closure
|
||||
|
@ -2838,6 +2839,7 @@ mod solve_uniq_expr {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn astar_full_code() {
|
||||
// theory: things are canonicalized in an order that leaves too much captured
|
||||
with_larger_debug_stack(|| {
|
||||
|
|
|
@ -163,15 +163,14 @@ impl fmt::Debug for Type {
|
|||
|
||||
for (index, arg) in args.iter().enumerate() {
|
||||
if index > 0 {
|
||||
", ".fmt(f)?;
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
|
||||
arg.fmt(f)?;
|
||||
write!(f, "{:?}", arg)?;
|
||||
}
|
||||
|
||||
write!(f, " -")?;
|
||||
closure.fmt(f)?;
|
||||
write!(f, "-> ")?;
|
||||
write!(f, " |{:?}|", closure)?;
|
||||
write!(f, " -> ")?;
|
||||
|
||||
ret.fmt(f)?;
|
||||
|
||||
|
|
|
@ -179,6 +179,10 @@ fn unify_alias(
|
|||
|
||||
problems.extend(merge(subs, &ctx, other_content.clone()));
|
||||
|
||||
if problems.is_empty() {
|
||||
problems.extend(unify_pool(subs, pool, real_var, *other_real_var));
|
||||
}
|
||||
|
||||
problems
|
||||
} else {
|
||||
mismatch!()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue