mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
Merge branch 'trunk' into platform
This commit is contained in:
commit
db2d99f56d
12 changed files with 402 additions and 138 deletions
|
@ -674,7 +674,7 @@ mod gen_primitives {
|
||||||
Cons _ rest -> 1 + length rest
|
Cons _ rest -> 1 + length rest
|
||||||
|
|
||||||
|
|
||||||
main =
|
main =
|
||||||
length three
|
length three
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -721,7 +721,7 @@ mod gen_primitives {
|
||||||
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
LinkedList a : [ Nil, Cons a (LinkedList a) ]
|
||||||
|
|
||||||
zero : LinkedList Int
|
zero : LinkedList Int
|
||||||
zero = Nil
|
zero = Nil
|
||||||
|
|
||||||
sum : LinkedList Int -> Int
|
sum : LinkedList Int -> Int
|
||||||
sum = \list ->
|
sum = \list ->
|
||||||
|
@ -935,7 +935,7 @@ mod gen_primitives {
|
||||||
f = \{} -> x + y
|
f = \{} -> x + y
|
||||||
f
|
f
|
||||||
|
|
||||||
main =
|
main =
|
||||||
f = foo {}
|
f = foo {}
|
||||||
f {}
|
f {}
|
||||||
"#
|
"#
|
||||||
|
@ -962,7 +962,7 @@ mod gen_primitives {
|
||||||
|
|
||||||
[ f, g ]
|
[ f, g ]
|
||||||
|
|
||||||
main =
|
main =
|
||||||
items = foo {}
|
items = foo {}
|
||||||
|
|
||||||
List.len items
|
List.len items
|
||||||
|
@ -974,9 +974,7 @@ mod gen_primitives {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
fn io_poc_effect() {
|
||||||
fn io_poc() {
|
|
||||||
use roc_std::RocStr;
|
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -984,23 +982,51 @@ mod gen_primitives {
|
||||||
|
|
||||||
Effect a : [ @Effect ({} -> a) ]
|
Effect a : [ @Effect ({} -> a) ]
|
||||||
|
|
||||||
succeed : a -> Effect a
|
# succeed : a -> Effect a
|
||||||
succeed = \x -> @Effect \{} -> x
|
succeed = \x -> @Effect \{} -> x
|
||||||
|
|
||||||
foo : Effect Float
|
# runEffect : Effect a -> a
|
||||||
foo =
|
|
||||||
succeed 3.14
|
|
||||||
|
|
||||||
runEffect : Effect a -> a
|
|
||||||
runEffect = \@Effect thunk -> thunk {}
|
runEffect = \@Effect thunk -> thunk {}
|
||||||
|
|
||||||
main =
|
# foo : Effect Float
|
||||||
|
foo =
|
||||||
|
succeed 3.14
|
||||||
|
|
||||||
|
main : Float
|
||||||
|
main =
|
||||||
runEffect foo
|
runEffect foo
|
||||||
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
RocStr::from_slice(&"Foo".as_bytes()),
|
3.14,
|
||||||
RocStr
|
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]
|
#[test]
|
||||||
fn optional_field_when_use_default() {
|
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!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -425,6 +453,27 @@ mod gen_records {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn optional_field_when_no_use_default() {
|
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!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -445,11 +494,14 @@ mod gen_records {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
app Test provides [ main ] imports []
|
||||||
|
|
||||||
f = \r ->
|
f = \r ->
|
||||||
{ x ? 10, y } = r
|
{ x ? 10, y } = r
|
||||||
x + y
|
x + y
|
||||||
|
|
||||||
f { y: 9 }
|
main =
|
||||||
|
f { y: 9 }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
19,
|
19,
|
||||||
|
@ -459,6 +511,27 @@ mod gen_records {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn optional_field_let_no_use_default() {
|
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!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
@ -492,6 +565,25 @@ mod gen_records {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn optional_field_function_no_use_default() {
|
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!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
|
|
@ -413,6 +413,31 @@ mod gen_tags {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn maybe_is_just() {
|
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!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
|
|
@ -348,7 +348,7 @@ macro_rules! assert_evals_to {
|
||||||
assert_llvm_evals_to!($src, $expected, $ty, $transform, $leak);
|
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,
|
return_type: ret_var,
|
||||||
arguments: loc_args,
|
arguments: loc_args,
|
||||||
loc_body,
|
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
|
// If this is an exposed symbol, we need to
|
||||||
// register it as such. Otherwise, since it
|
// register it as such. Otherwise, since it
|
||||||
// never gets called by Roc code, it will never
|
// never gets called by Roc code, it will never
|
||||||
|
|
|
@ -51,7 +51,6 @@ pub struct Proc<'a> {
|
||||||
pub name: Symbol,
|
pub name: Symbol,
|
||||||
pub args: &'a [(Layout<'a>, Symbol)],
|
pub args: &'a [(Layout<'a>, Symbol)],
|
||||||
pub body: Stmt<'a>,
|
pub body: Stmt<'a>,
|
||||||
pub closes_over: Layout<'a>,
|
|
||||||
pub ret_layout: Layout<'a>,
|
pub ret_layout: Layout<'a>,
|
||||||
pub is_self_recursive: SelfRecursive,
|
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)?;
|
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
|
// 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,
|
name: proc_name,
|
||||||
args: proc_args,
|
args: proc_args,
|
||||||
body: specialized_body,
|
body: specialized_body,
|
||||||
closes_over,
|
|
||||||
ret_layout,
|
ret_layout,
|
||||||
is_self_recursive: recursivity,
|
is_self_recursive: recursivity,
|
||||||
};
|
};
|
||||||
|
@ -1465,85 +1463,178 @@ fn build_specialized_proc_from_var<'a>(
|
||||||
layout_cache: &mut LayoutCache<'a>,
|
layout_cache: &mut LayoutCache<'a>,
|
||||||
pattern_symbols: &[Symbol],
|
pattern_symbols: &[Symbol],
|
||||||
fn_var: Variable,
|
fn_var: Variable,
|
||||||
) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>, Layout<'a>), LayoutProblem> {
|
) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>), LayoutProblem> {
|
||||||
match env.subs.get_without_compacting(fn_var).content {
|
match layout_cache.from_var(env.arena, fn_var, env.subs) {
|
||||||
Content::Structure(FlatType::Func(pattern_vars, closure_var, ret_var)) => {
|
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(
|
build_specialized_proc(
|
||||||
env,
|
env.arena,
|
||||||
layout_cache,
|
|
||||||
pattern_symbols,
|
pattern_symbols,
|
||||||
&pattern_vars,
|
pattern_layouts_vec,
|
||||||
Some(closure_var),
|
None,
|
||||||
ret_var,
|
ret_layout.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Content::Structure(FlatType::Apply(Symbol::ATTR_ATTR, args))
|
Ok(Layout::Closure(pattern_layouts, closure_layout, ret_layout)) => {
|
||||||
if !pattern_symbols.is_empty() =>
|
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_from_var(env, layout_cache, pattern_symbols, args[1])
|
|
||||||
}
|
build_specialized_proc(
|
||||||
Content::Alias(_, _, actual) => {
|
env.arena,
|
||||||
build_specialized_proc_from_var(env, layout_cache, pattern_symbols, actual)
|
pattern_symbols,
|
||||||
|
pattern_layouts_vec,
|
||||||
|
Some(closure_layout),
|
||||||
|
ret_layout.clone(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// a top-level constant 0-argument thunk
|
match env.subs.get_without_compacting(fn_var).content {
|
||||||
build_specialized_proc(env, layout_cache, pattern_symbols, &[], None, fn_var)
|
Content::Structure(FlatType::Func(pattern_vars, closure_var, ret_var)) => {
|
||||||
|
let closure_layout = ClosureLayout::from_var(env.arena, env.subs, closure_var)?;
|
||||||
|
build_specialized_proc_adapter(
|
||||||
|
env,
|
||||||
|
layout_cache,
|
||||||
|
pattern_symbols,
|
||||||
|
&pattern_vars,
|
||||||
|
closure_layout,
|
||||||
|
ret_var,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Content::Structure(FlatType::Apply(Symbol::ATTR_ATTR, args))
|
||||||
|
if !pattern_symbols.is_empty() =>
|
||||||
|
{
|
||||||
|
build_specialized_proc_from_var(env, layout_cache, pattern_symbols, args[1])
|
||||||
|
}
|
||||||
|
Content::Alias(_, _, actual) => {
|
||||||
|
build_specialized_proc_from_var(env, layout_cache, pattern_symbols, actual)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// a top-level constant 0-argument thunk
|
||||||
|
build_specialized_proc_adapter(
|
||||||
|
env,
|
||||||
|
layout_cache,
|
||||||
|
pattern_symbols,
|
||||||
|
&[],
|
||||||
|
None,
|
||||||
|
fn_var,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn build_specialized_proc<'a>(
|
fn build_specialized_proc_adapter<'a>(
|
||||||
env: &mut Env<'a, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
layout_cache: &mut LayoutCache<'a>,
|
layout_cache: &mut LayoutCache<'a>,
|
||||||
pattern_symbols: &[Symbol],
|
pattern_symbols: &[Symbol],
|
||||||
pattern_vars: &[Variable],
|
pattern_vars: &[Variable],
|
||||||
closure_var: Option<Variable>,
|
opt_closure_layout: Option<ClosureLayout<'a>>,
|
||||||
ret_var: Variable,
|
ret_var: Variable,
|
||||||
) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>, Layout<'a>), LayoutProblem> {
|
) -> Result<(&'a [(Layout<'a>, Symbol)], Layout<'a>), LayoutProblem> {
|
||||||
let mut proc_args = Vec::with_capacity_in(pattern_vars.len(), &env.arena);
|
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)?;
|
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
|
let ret_layout = layout_cache
|
||||||
.from_var(&env.arena, ret_var, env.subs)
|
.from_var(&env.arena, ret_var, env.subs)
|
||||||
.unwrap_or_else(|err| panic!("TODO handle invalid function {:?}", err));
|
.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>(
|
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(
|
pub fn extend_function_layout(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
argument_layouts: &'a [Layout<'a>],
|
argument_layouts: &'a [Layout<'a>],
|
||||||
|
@ -567,52 +615,12 @@ fn layout_from_flat_type<'a>(
|
||||||
|
|
||||||
let ret = Layout::from_var(env, ret_var)?;
|
let ret = Layout::from_var(env, ret_var)?;
|
||||||
|
|
||||||
let mut tags = std::vec::Vec::new();
|
let fn_args = fn_args.into_bump_slice();
|
||||||
match roc_types::pretty_print::chase_ext_tag_union(env.subs, closure_var, &mut tags) {
|
let ret = arena.alloc(ret);
|
||||||
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();
|
match ClosureLayout::from_var(env.arena, env.subs, closure_var)? {
|
||||||
let ret = arena.alloc(ret);
|
Some(closure_layout) => Ok(Layout::Closure(fn_args, closure_layout, ret)),
|
||||||
|
None => Ok(Layout::FunctionPointer(fn_args, 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!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Record(fields, ext_var) => {
|
Record(fields, ext_var) => {
|
||||||
|
@ -641,7 +649,10 @@ fn layout_from_flat_type<'a>(
|
||||||
use roc_types::types::RecordField::*;
|
use roc_types::types::RecordField::*;
|
||||||
match field {
|
match field {
|
||||||
Optional(_) => {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
Required(var) => var,
|
Required(var) => var,
|
||||||
|
|
|
@ -2013,6 +2013,8 @@ mod test_mono {
|
||||||
compiles_to_ir(
|
compiles_to_ir(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
app Test provides [ main ] imports []
|
||||||
|
|
||||||
swap : Int, Int, List a -> List a
|
swap : Int, Int, List a -> List a
|
||||||
swap = \i, j, list ->
|
swap = \i, j, list ->
|
||||||
when Pair (List.get list i) (List.get list j) is
|
when Pair (List.get list i) (List.get list j) is
|
||||||
|
@ -2026,7 +2028,8 @@ mod test_mono {
|
||||||
_ ->
|
_ ->
|
||||||
[]
|
[]
|
||||||
|
|
||||||
swap 0 0 [0x1]
|
main =
|
||||||
|
swap 0 0 [0x1]
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
indoc!(
|
indoc!(
|
||||||
|
|
|
@ -1121,7 +1121,7 @@ fn adjust_rank_content(
|
||||||
rank
|
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);
|
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, ret_var);
|
||||||
|
|
||||||
// TODO investigate further.
|
// TODO investigate further.
|
||||||
|
@ -1129,13 +1129,15 @@ fn adjust_rank_content(
|
||||||
// My theory is that because the closure_var contains variables already
|
// 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
|
// contained in the signature only, it does not need to be part of the rank
|
||||||
// calculuation
|
// calculuation
|
||||||
// rank = rank.max(adjust_rank(
|
if true {
|
||||||
// subs,
|
rank = rank.max(adjust_rank(
|
||||||
// young_mark,
|
subs,
|
||||||
// visit_mark,
|
young_mark,
|
||||||
// group_rank,
|
visit_mark,
|
||||||
// closure_var,
|
group_rank,
|
||||||
// ));
|
closure_var,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
for var in arg_vars {
|
for var in arg_vars {
|
||||||
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var));
|
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();
|
let mut rank = Rank::toplevel();
|
||||||
|
|
||||||
// from elm-compiler: THEORY: anything in the real_var would be Rank::toplevel()
|
|
||||||
for (_, var) in args {
|
for (_, var) in args {
|
||||||
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var));
|
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
|
rank
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1423,6 +1423,7 @@ mod solve_uniq_expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn quicksort() {
|
fn quicksort() {
|
||||||
// theory: partition is handled before swap, so swap is not known, and therefore not taken
|
// theory: partition is handled before swap, so swap is not known, and therefore not taken
|
||||||
// out of its closure
|
// out of its closure
|
||||||
|
@ -2838,6 +2839,7 @@ mod solve_uniq_expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn astar_full_code() {
|
fn astar_full_code() {
|
||||||
// theory: things are canonicalized in an order that leaves too much captured
|
// theory: things are canonicalized in an order that leaves too much captured
|
||||||
with_larger_debug_stack(|| {
|
with_larger_debug_stack(|| {
|
||||||
|
|
|
@ -163,15 +163,14 @@ impl fmt::Debug for Type {
|
||||||
|
|
||||||
for (index, arg) in args.iter().enumerate() {
|
for (index, arg) in args.iter().enumerate() {
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
", ".fmt(f)?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg.fmt(f)?;
|
write!(f, "{:?}", arg)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, " -")?;
|
write!(f, " |{:?}|", closure)?;
|
||||||
closure.fmt(f)?;
|
write!(f, " -> ")?;
|
||||||
write!(f, "-> ")?;
|
|
||||||
|
|
||||||
ret.fmt(f)?;
|
ret.fmt(f)?;
|
||||||
|
|
||||||
|
|
|
@ -179,6 +179,10 @@ fn unify_alias(
|
||||||
|
|
||||||
problems.extend(merge(subs, &ctx, other_content.clone()));
|
problems.extend(merge(subs, &ctx, other_content.clone()));
|
||||||
|
|
||||||
|
if problems.is_empty() {
|
||||||
|
problems.extend(unify_pool(subs, pool, real_var, *other_real_var));
|
||||||
|
}
|
||||||
|
|
||||||
problems
|
problems
|
||||||
} else {
|
} else {
|
||||||
mismatch!()
|
mismatch!()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue