mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
Use helpers in can builtins
This commit is contained in:
parent
d0da4bf926
commit
a399614824
1 changed files with 104 additions and 121 deletions
|
@ -1,11 +1,12 @@
|
||||||
use crate::def::Def;
|
use crate::def::Def;
|
||||||
|
use crate::expr::Expr;
|
||||||
use crate::expr::Recursive;
|
use crate::expr::Recursive;
|
||||||
use roc_collections::all::SendMap;
|
use roc_collections::all::SendMap;
|
||||||
use roc_module::ident::TagName;
|
use roc_module::ident::TagName;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_parse::operator::CalledVia;
|
use roc_parse::operator::CalledVia;
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
use roc_types::subs::VarStore;
|
use roc_types::subs::{VarStore, Variable};
|
||||||
|
|
||||||
/// Some builtins cannot be constructed in code gen alone, and need to be defined
|
/// Some builtins cannot be constructed in code gen alone, and need to be defined
|
||||||
/// as separate Roc defs. For example, List.get has this type:
|
/// as separate Roc defs. For example, List.get has this type:
|
||||||
|
@ -44,77 +45,63 @@ fn list_get(var_store: &VarStore) -> Def {
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Perform a bounds check. If it passes, delegate to List.getUnsafe
|
// Perform a bounds check. If it passes, delegate to List.#getUnsafe
|
||||||
let body = If {
|
let body = If {
|
||||||
cond_var: var_store.fresh(),
|
cond_var: var_store.fresh(),
|
||||||
branch_var: var_store.fresh(),
|
branch_var: var_store.fresh(),
|
||||||
branches: vec![(
|
branches: vec![(
|
||||||
// if-condition
|
// if-condition
|
||||||
Located {
|
no_region(
|
||||||
region: Region::zero(),
|
// index < List.len list
|
||||||
value: Call(
|
call(
|
||||||
Box::new((
|
Symbol::NUM_LT,
|
||||||
var_store.fresh(),
|
vec![
|
||||||
Located {
|
Var(Symbol::LIST_GET_ARG_INDEX),
|
||||||
region: Region::zero(),
|
call(
|
||||||
value: Var(Symbol::LIST_IS_EMPTY), // TODO actually check if (index < List.len list)
|
Symbol::LIST_LEN,
|
||||||
},
|
vec![Var(Symbol::LIST_GET_ARG_LIST)],
|
||||||
var_store.fresh(),
|
var_store,
|
||||||
)),
|
),
|
||||||
vec![(
|
],
|
||||||
var_store.fresh(),
|
var_store,
|
||||||
Located {
|
|
||||||
region: Region::zero(),
|
|
||||||
value: Var(Symbol::LIST_GET_ARG_LIST),
|
|
||||||
},
|
|
||||||
)],
|
|
||||||
CalledVia::Space,
|
|
||||||
),
|
),
|
||||||
},
|
),
|
||||||
// then-branch
|
// then-branch
|
||||||
Located {
|
no_region(
|
||||||
region: Region::zero(),
|
|
||||||
value:
|
|
||||||
// Ok
|
// Ok
|
||||||
Tag {
|
tag(
|
||||||
variant_var: var_store.fresh(),
|
"Ok",
|
||||||
ext_var: var_store.fresh(), // TODO Variable::EMPTY_TAG_UNION should work here
|
vec![
|
||||||
name: TagName::Global("Ok".into()),
|
// List.getUnsafe list index
|
||||||
arguments: vec![(
|
Call(
|
||||||
var_store.fresh(),
|
Box::new((
|
||||||
no_region(
|
var_store.fresh(),
|
||||||
// List.getUnsafe list index
|
no_region(Var(Symbol::LIST_GET_UNSAFE)),
|
||||||
Call(
|
var_store.fresh(),
|
||||||
Box::new((var_store.fresh(), no_region(Var(Symbol::LIST_GET_UNSAFE)), var_store.fresh())),
|
)),
|
||||||
vec![
|
vec![
|
||||||
(var_store.fresh(), no_region(Var(Symbol::LIST_GET_ARG_LIST))),
|
(var_store.fresh(), no_region(Var(Symbol::LIST_GET_ARG_LIST))),
|
||||||
(var_store.fresh(), no_region(Var(Symbol::LIST_GET_ARG_INDEX))),
|
(
|
||||||
],
|
var_store.fresh(),
|
||||||
CalledVia::Space,
|
no_region(Var(Symbol::LIST_GET_ARG_INDEX)),
|
||||||
)
|
),
|
||||||
)
|
],
|
||||||
)]
|
CalledVia::Space,
|
||||||
},
|
),
|
||||||
},
|
],
|
||||||
|
var_store,
|
||||||
|
),
|
||||||
|
),
|
||||||
)],
|
)],
|
||||||
final_else: Box::new(
|
final_else: Box::new(
|
||||||
// else-branch
|
// else-branch
|
||||||
no_region(
|
no_region(
|
||||||
// Err
|
// Err
|
||||||
Tag {
|
tag(
|
||||||
variant_var: var_store.fresh(),
|
"Err",
|
||||||
ext_var: var_store.fresh(),
|
vec![tag("OutOfBounds", Vec::new(), var_store)],
|
||||||
name: TagName::Global("Err".into()),
|
var_store,
|
||||||
arguments: vec![(
|
),
|
||||||
var_store.fresh(),
|
|
||||||
no_region(Tag {
|
|
||||||
variant_var: var_store.fresh(),
|
|
||||||
ext_var: var_store.fresh(),
|
|
||||||
name: TagName::Global("OutOfBounds".into()),
|
|
||||||
arguments: std::vec::Vec::new(),
|
|
||||||
}),
|
|
||||||
)],
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -147,79 +134,47 @@ fn list_first(var_store: &VarStore) -> Def {
|
||||||
)];
|
)];
|
||||||
|
|
||||||
// Perform a bounds check. If it passes, delegate to List.getUnsafe.
|
// Perform a bounds check. If it passes, delegate to List.getUnsafe.
|
||||||
let body =
|
let body = If {
|
||||||
// Use "when" instead of "if" so that we can have False be the first branch.
|
// TODO Use "when" instead of "if" so that we can have False be the first branch.
|
||||||
// We want that for branch prediction; usually we expect the list to be nonempty.
|
// We want that for branch prediction; usually we expect the list to be nonempty.
|
||||||
If {
|
|
||||||
cond_var: var_store.fresh(),
|
cond_var: var_store.fresh(),
|
||||||
branch_var: var_store.fresh(),
|
branch_var: var_store.fresh(),
|
||||||
branches: vec![(
|
branches: vec![(
|
||||||
// if-condition
|
// if-condition
|
||||||
Located {
|
no_region(
|
||||||
region: Region::zero(),
|
// List.isEmpty list
|
||||||
value: Call(
|
call(
|
||||||
Box::new((
|
Symbol::LIST_IS_EMPTY,
|
||||||
var_store.fresh(),
|
vec![Var(Symbol::LIST_FIRST_ARG)],
|
||||||
Located {
|
var_store,
|
||||||
region: Region::zero(),
|
|
||||||
value: Var(Symbol::LIST_IS_EMPTY),
|
|
||||||
},
|
|
||||||
var_store.fresh(),
|
|
||||||
)),
|
|
||||||
vec![(
|
|
||||||
var_store.fresh(),
|
|
||||||
Located {
|
|
||||||
region: Region::zero(),
|
|
||||||
value: Var(Symbol::LIST_GET_ARG_LIST),
|
|
||||||
},
|
|
||||||
)],
|
|
||||||
CalledVia::Space,
|
|
||||||
),
|
),
|
||||||
},
|
),
|
||||||
// then-branch
|
// then-branch
|
||||||
Located {
|
no_region(
|
||||||
region: Region::zero(),
|
// Err OutOfBounds
|
||||||
value:
|
tag(
|
||||||
// Ok
|
"Err",
|
||||||
Tag {
|
vec![tag("OutOfBounds", Vec::new(), var_store)],
|
||||||
variant_var: var_store.fresh(),
|
var_store,
|
||||||
ext_var: var_store.fresh(),
|
),
|
||||||
name: TagName::Global("Ok".into()),
|
),
|
||||||
arguments: vec![(
|
|
||||||
var_store.fresh(),
|
|
||||||
no_region(
|
|
||||||
// List.getUnsafe list index
|
|
||||||
Call(
|
|
||||||
Box::new((var_store.fresh(), no_region(Var(Symbol::LIST_GET_UNSAFE)), var_store.fresh())),
|
|
||||||
vec![
|
|
||||||
(var_store.fresh(), no_region(Var(Symbol::LIST_GET_ARG_LIST))),
|
|
||||||
(var_store.fresh(), no_region(Var(Symbol::LIST_GET_ARG_INDEX))),
|
|
||||||
],
|
|
||||||
CalledVia::Space,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)],
|
)],
|
||||||
final_else: Box::new(
|
final_else: Box::new(
|
||||||
// default branch
|
// default branch
|
||||||
no_region(
|
no_region(
|
||||||
// Err
|
// Ok (List.#getUnsafe list 0)
|
||||||
Tag {
|
tag(
|
||||||
variant_var: var_store.fresh(),
|
"Ok",
|
||||||
ext_var: var_store.fresh(),
|
vec![
|
||||||
name: TagName::Global("Err".into()),
|
// List.#getUnsafe list 0
|
||||||
arguments: vec![(
|
call(
|
||||||
var_store.fresh(),
|
Symbol::LIST_GET_UNSAFE,
|
||||||
no_region(Tag {
|
vec![(Var(Symbol::LIST_FIRST_ARG)), (Int(var_store.fresh(), 0))],
|
||||||
variant_var: var_store.fresh(),
|
var_store,
|
||||||
ext_var: var_store.fresh(),
|
),
|
||||||
name: TagName::Global("OutOfBounds".into()),
|
],
|
||||||
arguments: std::vec::Vec::new(),
|
var_store,
|
||||||
}),
|
),
|
||||||
)],
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -248,3 +203,31 @@ fn no_region<T>(value: T) -> Located<T> {
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn tag(name: &'static str, args: Vec<Expr>, var_store: &VarStore) -> Expr {
|
||||||
|
Expr::Tag {
|
||||||
|
variant_var: var_store.fresh(),
|
||||||
|
ext_var: var_store.fresh(), // TODO Variable::EMPTY_TAG_UNION should work here
|
||||||
|
name: TagName::Global(name.into()),
|
||||||
|
arguments: args
|
||||||
|
.into_iter()
|
||||||
|
.map(|expr| (var_store.fresh(), no_region(expr)))
|
||||||
|
.collect::<Vec<(Variable, Located<Expr>)>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn call(symbol: Symbol, args: Vec<Expr>, var_store: &VarStore) -> Expr {
|
||||||
|
Expr::Call(
|
||||||
|
Box::new((
|
||||||
|
var_store.fresh(),
|
||||||
|
no_region(Expr::Var(symbol)),
|
||||||
|
var_store.fresh(),
|
||||||
|
)),
|
||||||
|
args.into_iter()
|
||||||
|
.map(|expr| (var_store.fresh(), no_region(expr)))
|
||||||
|
.collect::<Vec<(Variable, Located<Expr>)>>(),
|
||||||
|
CalledVia::Space,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue