mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 15:03:46 +00:00
remove zig implementation of keepIf/keepErrs/keepOks
This commit is contained in:
parent
addb27164e
commit
e29a89d33c
13 changed files with 21 additions and 721 deletions
|
@ -594,69 +594,6 @@ fn build_tuple_type(
|
|||
builder.add_tuple_type(&field_types)
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy)]
|
||||
enum KeepResult {
|
||||
Errs = ERR_TAG_ID,
|
||||
Oks = OK_TAG_ID,
|
||||
}
|
||||
|
||||
impl KeepResult {
|
||||
fn invert(&self) -> Self {
|
||||
match self {
|
||||
KeepResult::Errs => KeepResult::Oks,
|
||||
KeepResult::Oks => KeepResult::Errs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum ResultRepr<'a> {
|
||||
/// This is basically a `Result * whatever` or `Result [] whatever` (in keepOks, arguments flipped for keepErrs).
|
||||
/// Such a `Result` gets a `Bool` layout at currently. We model the `*` or `[]` as a unit
|
||||
/// (empty tuple) in morphic, otherwise we run into trouble when we need to crate a value of
|
||||
/// type void
|
||||
ResultStarStar,
|
||||
ResultConcrete {
|
||||
err: Layout<'a>,
|
||||
ok: Layout<'a>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> ResultRepr<'a> {
|
||||
fn from_layout(layout: &Layout<'a>) -> Self {
|
||||
match layout {
|
||||
Layout::Union(UnionLayout::NonRecursive(tags)) => ResultRepr::ResultConcrete {
|
||||
err: tags[ERR_TAG_ID as usize][0],
|
||||
ok: tags[OK_TAG_ID as usize][0],
|
||||
},
|
||||
Layout::Builtin(Builtin::Bool) => ResultRepr::ResultStarStar,
|
||||
other => unreachable!("unexpected layout: {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap(
|
||||
&self,
|
||||
builder: &mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
err_or_ok: ValueId,
|
||||
keep_tag_id: u32,
|
||||
) -> Result<ValueId> {
|
||||
match self {
|
||||
ResultRepr::ResultConcrete { .. } => {
|
||||
let unwrapped = builder.add_unwrap_union(block, err_or_ok, keep_tag_id)?;
|
||||
|
||||
builder.add_get_tuple_field(block, unwrapped, 0)
|
||||
}
|
||||
ResultRepr::ResultStarStar => {
|
||||
// Void/EmptyTagUnion is represented as a unit value in morphic
|
||||
// using `union {}` runs into trouble where we have to crate a value of that type
|
||||
builder.add_make_tuple(block, &[])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_loop(
|
||||
builder: &mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
|
@ -1026,120 +963,6 @@ fn call_spec(
|
|||
|
||||
add_loop(builder, block, state_type, init_state, loop_body)
|
||||
}
|
||||
ListKeepIf { xs } => {
|
||||
let list = env.symbols[xs];
|
||||
|
||||
let loop_body = |builder: &mut FuncDefBuilder, block, state| {
|
||||
let bag = builder.add_get_tuple_field(block, state, LIST_BAG_INDEX)?;
|
||||
let cell = builder.add_get_tuple_field(block, state, LIST_CELL_INDEX)?;
|
||||
|
||||
let element = builder.add_bag_get(block, bag)?;
|
||||
|
||||
let _ = call_function!(builder, block, [element]);
|
||||
|
||||
// NOTE: we assume the element is not kept
|
||||
builder.add_update(block, update_mode_var, cell)?;
|
||||
|
||||
let removed = builder.add_bag_remove(block, bag)?;
|
||||
|
||||
// decrement the removed element
|
||||
let removed_element = builder.add_get_tuple_field(block, removed, 1)?;
|
||||
builder.add_recursive_touch(block, removed_element)?;
|
||||
|
||||
let new_bag = builder.add_get_tuple_field(block, removed, 0)?;
|
||||
|
||||
with_new_heap_cell(builder, block, new_bag)
|
||||
};
|
||||
|
||||
let state_layout = Layout::Builtin(Builtin::List(&argument_layouts[0]));
|
||||
let state_type =
|
||||
layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?;
|
||||
let init_state = list;
|
||||
|
||||
add_loop(builder, block, state_type, init_state, loop_body)
|
||||
}
|
||||
ListKeepOks { xs } | ListKeepErrs { xs } => {
|
||||
let list = env.symbols[xs];
|
||||
|
||||
let keep_result = match op {
|
||||
ListKeepOks { .. } => KeepResult::Oks,
|
||||
ListKeepErrs { .. } => KeepResult::Errs,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let result_repr = ResultRepr::from_layout(return_layout);
|
||||
|
||||
let output_element_layout = match (keep_result, result_repr) {
|
||||
(KeepResult::Errs, ResultRepr::ResultConcrete { err, .. }) => err,
|
||||
(KeepResult::Oks, ResultRepr::ResultConcrete { ok, .. }) => ok,
|
||||
(_, ResultRepr::ResultStarStar) => {
|
||||
// we represent this case as Unit, while Void is maybe more natural
|
||||
// but using Void we'd need to crate values of type Void, which is not
|
||||
// possible
|
||||
Layout::UNIT
|
||||
}
|
||||
};
|
||||
|
||||
let loop_body = |builder: &mut FuncDefBuilder, block, state| {
|
||||
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||
|
||||
let element = builder.add_bag_get(block, bag)?;
|
||||
|
||||
let err_or_ok = call_function!(builder, block, [element]);
|
||||
|
||||
let kept_branch = builder.add_block();
|
||||
let not_kept_branch = builder.add_block();
|
||||
|
||||
let element_kept = {
|
||||
let block = kept_branch;
|
||||
|
||||
// a Result can be represented as a Int1
|
||||
let new_element = result_repr.unwrap(
|
||||
builder,
|
||||
block,
|
||||
err_or_ok,
|
||||
keep_result as u32,
|
||||
)?;
|
||||
|
||||
list_append(builder, block, update_mode_var, state, new_element)?
|
||||
};
|
||||
|
||||
let element_not_kept = {
|
||||
let block = not_kept_branch;
|
||||
|
||||
// a Result can be represented as a Int1
|
||||
let dropped_element = result_repr.unwrap(
|
||||
builder,
|
||||
block,
|
||||
err_or_ok,
|
||||
keep_result.invert() as u32,
|
||||
)?;
|
||||
|
||||
// decrement the element we will not keep
|
||||
builder.add_recursive_touch(block, dropped_element)?;
|
||||
|
||||
state
|
||||
};
|
||||
|
||||
builder.add_choice(
|
||||
block,
|
||||
&[
|
||||
BlockExpr(not_kept_branch, element_not_kept),
|
||||
BlockExpr(kept_branch, element_kept),
|
||||
],
|
||||
)
|
||||
};
|
||||
|
||||
let output_element_type =
|
||||
layout_spec(builder, &output_element_layout, &WhenRecursive::Unreachable)?;
|
||||
let init_state = new_list(builder, block, output_element_type)?;
|
||||
|
||||
let state_layout = Layout::Builtin(Builtin::List(&output_element_layout));
|
||||
let state_type =
|
||||
layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?;
|
||||
|
||||
add_loop(builder, block, state_type, init_state, loop_body)
|
||||
}
|
||||
ListAny { xs } => {
|
||||
let list = env.symbols[xs];
|
||||
|
||||
|
@ -1831,9 +1654,6 @@ fn static_list_type<TC: TypeContext>(builder: &mut TC) -> Result<TypeId> {
|
|||
builder.add_tuple_type(&[cell, bag])
|
||||
}
|
||||
|
||||
const OK_TAG_ID: u32 = 1;
|
||||
const ERR_TAG_ID: u32 = 0;
|
||||
|
||||
const LIST_CELL_INDEX: u32 = 0;
|
||||
const LIST_BAG_INDEX: u32 = 1;
|
||||
|
||||
|
|
|
@ -422,179 +422,6 @@ pub fn listMap4(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn listKeepIf(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
alignment: u32,
|
||||
element_width: usize,
|
||||
inc: Inc,
|
||||
dec: Dec,
|
||||
) callconv(.C) RocList {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
var i: usize = 0;
|
||||
var output = RocList.allocate(alignment, list.len(), list.len() * element_width);
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
}
|
||||
|
||||
var kept: usize = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
var keep = false;
|
||||
const element = source_ptr + (i * element_width);
|
||||
inc(element);
|
||||
caller(data, element, @ptrCast(?[*]u8, &keep));
|
||||
|
||||
if (keep) {
|
||||
@memcpy(target_ptr + (kept * element_width), element, element_width);
|
||||
|
||||
kept += 1;
|
||||
} else {
|
||||
dec(element);
|
||||
}
|
||||
}
|
||||
|
||||
if (kept == 0) {
|
||||
// if the output is empty, deallocate the space we made for the result
|
||||
utils.decref(output.bytes, size * element_width, alignment);
|
||||
return RocList.empty();
|
||||
} else {
|
||||
output.length = kept;
|
||||
|
||||
return output;
|
||||
}
|
||||
} else {
|
||||
return RocList.empty();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listKeepOks(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
alignment: u32,
|
||||
before_width: usize,
|
||||
result_width: usize,
|
||||
after_width: usize,
|
||||
has_tag_id: HasTagId,
|
||||
dec_result: Dec,
|
||||
) callconv(.C) RocList {
|
||||
const good_constructor: u16 = 1;
|
||||
|
||||
return listKeepResult(
|
||||
list,
|
||||
good_constructor,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
data_is_owned,
|
||||
alignment,
|
||||
before_width,
|
||||
result_width,
|
||||
after_width,
|
||||
has_tag_id,
|
||||
dec_result,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn listKeepErrs(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
alignment: u32,
|
||||
before_width: usize,
|
||||
result_width: usize,
|
||||
after_width: usize,
|
||||
has_tag_id: HasTagId,
|
||||
dec_result: Dec,
|
||||
) callconv(.C) RocList {
|
||||
const good_constructor: u16 = 0;
|
||||
|
||||
return listKeepResult(
|
||||
list,
|
||||
good_constructor,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
data_is_owned,
|
||||
alignment,
|
||||
before_width,
|
||||
result_width,
|
||||
after_width,
|
||||
has_tag_id,
|
||||
dec_result,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn listKeepResult(
|
||||
list: RocList,
|
||||
good_constructor: u16,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
alignment: u32,
|
||||
before_width: usize,
|
||||
result_width: usize,
|
||||
after_width: usize,
|
||||
has_tag_id: HasTagId,
|
||||
dec_result: Dec,
|
||||
) RocList {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
var i: usize = 0;
|
||||
var output = RocList.allocate(alignment, list.len(), list.len() * after_width);
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
|
||||
// TODO handle alloc failing!
|
||||
var temporary = utils.alloc(result_width, alignment) orelse unreachable;
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
}
|
||||
|
||||
var kept: usize = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
const before_element = source_ptr + (i * before_width);
|
||||
caller(data, before_element, temporary);
|
||||
|
||||
// a record { matched: bool, data: ?[*]u8 }
|
||||
// for now, that data pointer is just the input `temporary` pointer
|
||||
// this will change in the future to only return a pointer to the
|
||||
// payload of the tag
|
||||
const answer = has_tag_id(good_constructor, temporary);
|
||||
if (answer.matched) {
|
||||
const contents = (answer.data orelse unreachable);
|
||||
@memcpy(target_ptr + (kept * after_width), contents, after_width);
|
||||
kept += 1;
|
||||
} else {
|
||||
dec_result(temporary);
|
||||
}
|
||||
}
|
||||
|
||||
utils.dealloc(temporary, alignment);
|
||||
|
||||
if (kept == 0) {
|
||||
utils.decref(output.bytes, size * after_width, alignment);
|
||||
return RocList.empty();
|
||||
} else {
|
||||
output.length = kept;
|
||||
return output;
|
||||
}
|
||||
} else {
|
||||
return RocList.empty();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listWalk(
|
||||
list: RocList,
|
||||
caller: Caller2,
|
||||
|
@ -891,6 +718,7 @@ pub fn listSublist(
|
|||
if (len == 0) {
|
||||
return RocList.empty();
|
||||
}
|
||||
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
|
||||
|
@ -916,14 +744,20 @@ pub fn listSublist(
|
|||
dec(element);
|
||||
}
|
||||
|
||||
const output = RocList.allocate(alignment, keep_len, element_width);
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
if (start == 0 and list.isUnique()) {
|
||||
var output = list;
|
||||
output.length = keep_len;
|
||||
return output;
|
||||
} else {
|
||||
const output = RocList.allocate(alignment, keep_len, element_width);
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
|
||||
@memcpy(target_ptr, source_ptr + start * element_width, keep_len * element_width);
|
||||
@memcpy(target_ptr, source_ptr + start * element_width, keep_len * element_width);
|
||||
|
||||
utils.decref(list.bytes, size * element_width, alignment);
|
||||
utils.decref(list.bytes, size * element_width, alignment);
|
||||
|
||||
return output;
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
return RocList.empty();
|
||||
|
|
|
@ -41,12 +41,9 @@ comptime {
|
|||
exportListFn(list.listMap3, "map3");
|
||||
exportListFn(list.listMap4, "map4");
|
||||
exportListFn(list.listMapWithIndex, "map_with_index");
|
||||
exportListFn(list.listKeepIf, "keep_if");
|
||||
exportListFn(list.listWalk, "walk");
|
||||
exportListFn(list.listWalkUntil, "walkUntil");
|
||||
exportListFn(list.listWalkBackwards, "walk_backwards");
|
||||
exportListFn(list.listKeepOks, "keep_oks");
|
||||
exportListFn(list.listKeepErrs, "keep_errs");
|
||||
exportListFn(list.listContains, "contains");
|
||||
exportListFn(list.listRepeat, "repeat");
|
||||
exportListFn(list.listAppend, "append");
|
||||
|
|
|
@ -353,9 +353,6 @@ pub const LIST_MAP2: &str = "roc_builtins.list.map2";
|
|||
pub const LIST_MAP3: &str = "roc_builtins.list.map3";
|
||||
pub const LIST_MAP4: &str = "roc_builtins.list.map4";
|
||||
pub const LIST_MAP_WITH_INDEX: &str = "roc_builtins.list.map_with_index";
|
||||
pub const LIST_KEEP_IF: &str = "roc_builtins.list.keep_if";
|
||||
pub const LIST_KEEP_OKS: &str = "roc_builtins.list.keep_oks";
|
||||
pub const LIST_KEEP_ERRS: &str = "roc_builtins.list.keep_errs";
|
||||
pub const LIST_WALK: &str = "roc_builtins.list.walk";
|
||||
pub const LIST_WALK_UNTIL: &str = "roc_builtins.list.walkUntil";
|
||||
pub const LIST_WALK_BACKWARDS: &str = "roc_builtins.list.walk_backwards";
|
||||
|
|
|
@ -119,9 +119,6 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
LIST_DROP_AT => list_drop_at,
|
||||
LIST_SWAP => list_swap,
|
||||
LIST_MAP_WITH_INDEX => list_map_with_index,
|
||||
LIST_KEEP_IF => list_keep_if,
|
||||
LIST_KEEP_OKS => list_keep_oks,
|
||||
LIST_KEEP_ERRS=> list_keep_errs,
|
||||
LIST_WALK => list_walk,
|
||||
LIST_WALK_BACKWARDS => list_walk_backwards,
|
||||
LIST_WALK_UNTIL => list_walk_until,
|
||||
|
@ -2478,39 +2475,6 @@ fn list_walk_until(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||
lowlevel_3(symbol, LowLevel::ListWalkUntil, var_store)
|
||||
}
|
||||
|
||||
/// List.keepIf : List elem, (elem -> Bool) -> List elem
|
||||
fn list_keep_if(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
let list_var = var_store.fresh();
|
||||
let func_var = var_store.fresh();
|
||||
|
||||
let body = RunLowLevel {
|
||||
op: LowLevel::ListKeepIf,
|
||||
args: vec![
|
||||
(list_var, Var(Symbol::ARG_1)),
|
||||
(func_var, Var(Symbol::ARG_2)),
|
||||
],
|
||||
ret_var: list_var,
|
||||
};
|
||||
|
||||
defn(
|
||||
symbol,
|
||||
vec![(list_var, Symbol::ARG_1), (func_var, Symbol::ARG_2)],
|
||||
var_store,
|
||||
body,
|
||||
list_var,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.keepOks : List before, (before -> Result after *) -> List after
|
||||
fn list_keep_oks(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_2(symbol, LowLevel::ListKeepOks, var_store)
|
||||
}
|
||||
|
||||
/// List.keepErrs: List before, (before -> Result * after) -> List after
|
||||
fn list_keep_errs(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_2(symbol, LowLevel::ListKeepErrs, var_store)
|
||||
}
|
||||
|
||||
/// List.map : List before, (before -> after) -> List after
|
||||
fn list_map(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_2(symbol, LowLevel::ListMap, var_store)
|
||||
|
|
|
@ -9,10 +9,9 @@ use crate::llvm::build_dict::{
|
|||
use crate::llvm::build_hash::generic_hash;
|
||||
use crate::llvm::build_list::{
|
||||
self, allocate_list, empty_polymorphic_list, list_all, list_any, list_append, list_concat,
|
||||
list_drop_at, list_find_unsafe, list_get_unsafe, list_keep_errs, list_keep_if, list_keep_oks,
|
||||
list_len, list_map, list_map2, list_map3, list_map4, list_map_with_index, list_prepend,
|
||||
list_replace_unsafe, list_sort_with, list_sublist, list_swap, list_symbol_to_c_abi,
|
||||
list_to_c_abi, list_with_capacity,
|
||||
list_drop_at, list_find_unsafe, list_get_unsafe, list_len, list_map, list_map2, list_map3,
|
||||
list_map4, list_map_with_index, list_prepend, list_replace_unsafe, list_sort_with,
|
||||
list_sublist, list_swap, list_symbol_to_c_abi, list_to_c_abi, list_with_capacity,
|
||||
};
|
||||
use crate::llvm::build_str::{
|
||||
str_from_float, str_from_int, str_from_utf8, str_from_utf8_range, str_split,
|
||||
|
@ -5120,110 +5119,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}
|
||||
ListKeepIf { xs } => {
|
||||
// List.keepIf : List elem, (elem -> Bool) -> List elem
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, xs);
|
||||
|
||||
let (function, closure, closure_layout) = function_details!();
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||
let argument_layouts = &[**element_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
result_layout,
|
||||
);
|
||||
|
||||
list_keep_if(env, layout_ids, roc_function_call, list, element_layout)
|
||||
}
|
||||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}
|
||||
ListKeepOks { xs } => {
|
||||
// List.keepOks : List before, (before -> Result after *) -> List after
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, xs);
|
||||
|
||||
let (function, closure, closure_layout) = function_details!();
|
||||
|
||||
match (list_layout, return_layout) {
|
||||
(
|
||||
Layout::Builtin(Builtin::List(before_layout)),
|
||||
Layout::Builtin(Builtin::List(after_layout)),
|
||||
) => {
|
||||
let argument_layouts = &[**before_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
result_layout,
|
||||
);
|
||||
|
||||
list_keep_oks(
|
||||
env,
|
||||
layout_ids,
|
||||
roc_function_call,
|
||||
&result_layout,
|
||||
list,
|
||||
before_layout,
|
||||
after_layout,
|
||||
)
|
||||
}
|
||||
(other1, other2) => {
|
||||
unreachable!("invalid list layouts:\n{:?}\n{:?}", other1, other2)
|
||||
}
|
||||
}
|
||||
}
|
||||
ListKeepErrs { xs } => {
|
||||
// List.keepErrs : List before, (before -> Result * after) -> List after
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, xs);
|
||||
|
||||
let (function, closure, closure_layout) = function_details!();
|
||||
|
||||
match (list_layout, return_layout) {
|
||||
(
|
||||
Layout::Builtin(Builtin::List(before_layout)),
|
||||
Layout::Builtin(Builtin::List(after_layout)),
|
||||
) => {
|
||||
let argument_layouts = &[**before_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
result_layout,
|
||||
);
|
||||
|
||||
list_keep_errs(
|
||||
env,
|
||||
layout_ids,
|
||||
roc_function_call,
|
||||
&result_layout,
|
||||
list,
|
||||
before_layout,
|
||||
after_layout,
|
||||
)
|
||||
}
|
||||
(other1, other2) => {
|
||||
unreachable!("invalid list layouts:\n{:?}\n{:?}", other1, other2)
|
||||
}
|
||||
}
|
||||
}
|
||||
ListWalk { xs, state } => {
|
||||
list_walk!(crate::llvm::build_list::ListWalk::Walk, xs, state)
|
||||
}
|
||||
|
@ -6161,9 +6056,8 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
set
|
||||
}
|
||||
|
||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk
|
||||
| ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith
|
||||
| ListFindUnsafe | DictWalk => {
|
||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListWalk | ListWalkUntil
|
||||
| ListWalkBackwards | ListSortWith | ListFindUnsafe | DictWalk => {
|
||||
unreachable!("these are higher order, and are handled elsewhere")
|
||||
}
|
||||
|
||||
|
|
|
@ -473,42 +473,6 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
/// List.keepIf : List elem, (elem -> Bool) -> List elem
|
||||
pub fn list_keep_if<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let inc_element_fn = build_inc_wrapper(env, layout_ids, element_layout);
|
||||
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
|
||||
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
list_to_c_abi(env, list).into(),
|
||||
roc_function_call.caller.into(),
|
||||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
inc_element_fn.as_global_value().as_pointer_value().into(),
|
||||
dec_element_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::LIST_KEEP_IF,
|
||||
)
|
||||
}
|
||||
|
||||
fn empty_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> {
|
||||
let struct_type = super::convert::zig_list_type(env);
|
||||
|
||||
// The pointer should be null (aka zero) and the length should be zero,
|
||||
// so the whole struct should be a const_zero
|
||||
BasicValueEnum::StructValue(struct_type.const_zero())
|
||||
}
|
||||
|
||||
fn has_tag_id_helper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
has_tag_id: FunctionValue<'ctx>,
|
||||
|
@ -533,102 +497,6 @@ fn has_tag_id_helper<'a, 'ctx, 'env>(
|
|||
)
|
||||
}
|
||||
|
||||
/// List.keepOks : List before, (before -> Result after *) -> List after
|
||||
pub fn list_keep_oks<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
// Layout of the `Result after *`
|
||||
result_layout: &Layout<'a>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
before_layout: &Layout<'a>,
|
||||
after_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
|
||||
|
||||
let function = env
|
||||
.builder
|
||||
.get_insert_block()
|
||||
.unwrap()
|
||||
.get_parent()
|
||||
.unwrap();
|
||||
|
||||
let has_tag_id = match result_layout {
|
||||
Layout::Union(union_layout) => build_has_tag_id(env, function, *union_layout),
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
// a `Result whatever []`, so there is nothing to keep
|
||||
return empty_list(env);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
list_to_c_abi(env, list).into(),
|
||||
roc_function_call.caller.into(),
|
||||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
env.alignment_intvalue(before_layout),
|
||||
layout_width(env, before_layout),
|
||||
layout_width(env, result_layout),
|
||||
layout_width(env, after_layout),
|
||||
has_tag_id_helper(env, has_tag_id).into(),
|
||||
dec_result_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::LIST_KEEP_OKS,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.keepErrs : List before, (before -> Result * after) -> List after
|
||||
pub fn list_keep_errs<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
// Layout of the `Result * err`
|
||||
result_layout: &Layout<'a>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
before_layout: &Layout<'a>,
|
||||
after_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
|
||||
|
||||
let function = env
|
||||
.builder
|
||||
.get_insert_block()
|
||||
.unwrap()
|
||||
.get_parent()
|
||||
.unwrap();
|
||||
|
||||
let has_tag_id = match result_layout {
|
||||
Layout::Union(union_layout) => build_has_tag_id(env, function, *union_layout),
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
// a `Result whatever []`, so there is nothing to keep
|
||||
return empty_list(env);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
list_to_c_abi(env, list).into(),
|
||||
roc_function_call.caller.into(),
|
||||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
env.alignment_intvalue(before_layout),
|
||||
layout_width(env, before_layout),
|
||||
layout_width(env, result_layout),
|
||||
layout_width(env, after_layout),
|
||||
has_tag_id_helper(env, has_tag_id).into(),
|
||||
dec_result_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::LIST_KEEP_ERRS,
|
||||
)
|
||||
}
|
||||
|
||||
/// List.sortWith : List a, (a, a -> Ordering) -> List a
|
||||
pub fn list_sort_with<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
|
|
@ -288,9 +288,8 @@ impl<'a> LowLevelCall<'a> {
|
|||
|
||||
ListIsUnique => self.load_args_and_call_zig(backend, bitcode::LIST_IS_UNIQUE),
|
||||
|
||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListKeepIf | ListWalk
|
||||
| ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith
|
||||
| ListFindUnsafe | DictWalk => {
|
||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListWalk
|
||||
| ListWalkUntil | ListWalkBackwards | ListSortWith | ListFindUnsafe | DictWalk => {
|
||||
internal_error!("HigherOrder lowlevels should not be handled here")
|
||||
}
|
||||
|
||||
|
@ -2019,12 +2018,9 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
),
|
||||
|
||||
ListMapWithIndex { .. }
|
||||
| ListKeepIf { .. }
|
||||
| ListWalk { .. }
|
||||
| ListWalkUntil { .. }
|
||||
| ListWalkBackwards { .. }
|
||||
| ListKeepOks { .. }
|
||||
| ListKeepErrs { .. }
|
||||
| ListSortWith { .. }
|
||||
| ListAny { .. }
|
||||
| ListAll { .. }
|
||||
|
|
|
@ -35,12 +35,9 @@ pub enum LowLevel {
|
|||
ListMap3,
|
||||
ListMap4,
|
||||
ListMapWithIndex,
|
||||
ListKeepIf,
|
||||
ListWalk,
|
||||
ListWalkUntil,
|
||||
ListWalkBackwards,
|
||||
ListKeepOks,
|
||||
ListKeepErrs,
|
||||
ListSortWith,
|
||||
ListSublist,
|
||||
ListDropAt,
|
||||
|
@ -131,12 +128,9 @@ macro_rules! higher_order {
|
|||
| ListMap3
|
||||
| ListMap4
|
||||
| ListMapWithIndex
|
||||
| ListKeepIf
|
||||
| ListWalk
|
||||
| ListWalkUntil
|
||||
| ListWalkBackwards
|
||||
| ListKeepOks
|
||||
| ListKeepErrs
|
||||
| ListSortWith
|
||||
| ListFindUnsafe
|
||||
| DictWalk
|
||||
|
@ -161,12 +155,9 @@ impl LowLevel {
|
|||
ListMap3 => 3,
|
||||
ListMap4 => 4,
|
||||
ListMapWithIndex => 1,
|
||||
ListKeepIf => 1,
|
||||
ListWalk => 2,
|
||||
ListWalkUntil => 2,
|
||||
ListWalkBackwards => 2,
|
||||
ListKeepOks => 1,
|
||||
ListKeepErrs => 1,
|
||||
ListSortWith => 1,
|
||||
ListFindUnsafe => 1,
|
||||
DictWalk => 2,
|
||||
|
@ -232,12 +223,9 @@ impl LowLevelWrapperType {
|
|||
Symbol::LIST_MAP3 => WrapperIsRequired,
|
||||
Symbol::LIST_MAP4 => WrapperIsRequired,
|
||||
Symbol::LIST_MAP_WITH_INDEX => WrapperIsRequired,
|
||||
Symbol::LIST_KEEP_IF => WrapperIsRequired,
|
||||
Symbol::LIST_WALK => WrapperIsRequired,
|
||||
Symbol::LIST_WALK_UNTIL => WrapperIsRequired,
|
||||
Symbol::LIST_WALK_BACKWARDS => WrapperIsRequired,
|
||||
Symbol::LIST_KEEP_OKS => WrapperIsRequired,
|
||||
Symbol::LIST_KEEP_ERRS => WrapperIsRequired,
|
||||
Symbol::LIST_SORT_WITH => WrapperIsRequired,
|
||||
Symbol::LIST_SUBLIST => WrapperIsRequired,
|
||||
Symbol::LIST_DROP_AT => CanBeReplacedBy(ListDropAt),
|
||||
|
|
|
@ -552,13 +552,7 @@ impl<'a> BorrowInfState<'a> {
|
|||
};
|
||||
|
||||
match op {
|
||||
ListMap { xs }
|
||||
| ListKeepIf { xs }
|
||||
| ListKeepOks { xs }
|
||||
| ListKeepErrs { xs }
|
||||
| ListAny { xs }
|
||||
| ListAll { xs }
|
||||
| ListFindUnsafe { xs } => {
|
||||
ListMap { xs } | ListAny { xs } | ListAll { xs } | ListFindUnsafe { xs } => {
|
||||
// own the list if the function wants to own the element
|
||||
if !function_ps[0].borrow {
|
||||
self.own_var(*xs);
|
||||
|
@ -913,9 +907,6 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
ListMap2 => arena.alloc_slice_copy(&[owned, owned, function, closure_data]),
|
||||
ListMap3 => arena.alloc_slice_copy(&[owned, owned, owned, function, closure_data]),
|
||||
ListMap4 => arena.alloc_slice_copy(&[owned, owned, owned, owned, function, closure_data]),
|
||||
ListKeepIf | ListKeepOks | ListKeepErrs => {
|
||||
arena.alloc_slice_copy(&[owned, function, closure_data])
|
||||
}
|
||||
ListWalk | ListWalkUntil | ListWalkBackwards => {
|
||||
arena.alloc_slice_copy(&[owned, owned, function, closure_data])
|
||||
}
|
||||
|
|
|
@ -693,13 +693,7 @@ impl<'a> Context<'a> {
|
|||
let after_arguments = &arguments[op.function_index()..];
|
||||
|
||||
match *op {
|
||||
ListMap { xs }
|
||||
| ListKeepIf { xs }
|
||||
| ListKeepOks { xs }
|
||||
| ListKeepErrs { xs }
|
||||
| ListAny { xs }
|
||||
| ListAll { xs }
|
||||
| ListFindUnsafe { xs } => {
|
||||
ListMap { xs } | ListAny { xs } | ListAll { xs } | ListFindUnsafe { xs } => {
|
||||
let ownerships = [(xs, function_ps[0])];
|
||||
|
||||
let b = self.add_dec_after_lowlevel(after_arguments, &borrows, b, b_live_vars);
|
||||
|
|
|
@ -5043,34 +5043,6 @@ pub fn with_hole<'a>(
|
|||
let xs = arg_symbols[0];
|
||||
match_on_closure_argument!(ListMapWithIndex, [xs])
|
||||
}
|
||||
ListKeepIf => {
|
||||
debug_assert_eq!(arg_symbols.len(), 2);
|
||||
let xs = arg_symbols[0];
|
||||
let stmt = match_on_closure_argument!(ListKeepIf, [xs]);
|
||||
|
||||
// See the comment in `walk!`. We use List.keepIf to implement
|
||||
// other builtins, where the closure can be an actual closure rather
|
||||
// than a symbol.
|
||||
assign_to_symbol(
|
||||
env,
|
||||
procs,
|
||||
layout_cache,
|
||||
args[1].0, // the closure
|
||||
Loc::at_zero(args[1].1.clone()),
|
||||
arg_symbols[1],
|
||||
stmt,
|
||||
)
|
||||
}
|
||||
ListKeepOks => {
|
||||
debug_assert_eq!(arg_symbols.len(), 2);
|
||||
let xs = arg_symbols[0];
|
||||
match_on_closure_argument!(ListKeepOks, [xs])
|
||||
}
|
||||
ListKeepErrs => {
|
||||
debug_assert_eq!(arg_symbols.len(), 2);
|
||||
let xs = arg_symbols[0];
|
||||
match_on_closure_argument!(ListKeepErrs, [xs])
|
||||
}
|
||||
ListSortWith => {
|
||||
debug_assert_eq!(arg_symbols.len(), 2);
|
||||
let xs = arg_symbols[0];
|
||||
|
|
|
@ -23,9 +23,6 @@ pub enum HigherOrder {
|
|||
ListMapWithIndex {
|
||||
xs: Symbol,
|
||||
},
|
||||
ListKeepIf {
|
||||
xs: Symbol,
|
||||
},
|
||||
ListWalk {
|
||||
xs: Symbol,
|
||||
state: Symbol,
|
||||
|
@ -38,12 +35,6 @@ pub enum HigherOrder {
|
|||
xs: Symbol,
|
||||
state: Symbol,
|
||||
},
|
||||
ListKeepOks {
|
||||
xs: Symbol,
|
||||
},
|
||||
ListKeepErrs {
|
||||
xs: Symbol,
|
||||
},
|
||||
ListSortWith {
|
||||
xs: Symbol,
|
||||
},
|
||||
|
@ -70,12 +61,9 @@ impl HigherOrder {
|
|||
HigherOrder::ListMap3 { .. } => 3,
|
||||
HigherOrder::ListMap4 { .. } => 4,
|
||||
HigherOrder::ListMapWithIndex { .. } => 2,
|
||||
HigherOrder::ListKeepIf { .. } => 1,
|
||||
HigherOrder::ListWalk { .. } => 2,
|
||||
HigherOrder::ListWalkUntil { .. } => 2,
|
||||
HigherOrder::ListWalkBackwards { .. } => 2,
|
||||
HigherOrder::ListKeepOks { .. } => 1,
|
||||
HigherOrder::ListKeepErrs { .. } => 1,
|
||||
HigherOrder::ListSortWith { .. } => 2,
|
||||
HigherOrder::ListFindUnsafe { .. } => 1,
|
||||
HigherOrder::DictWalk { .. } => 2,
|
||||
|
@ -93,9 +81,6 @@ impl HigherOrder {
|
|||
ListMap { .. }
|
||||
| ListMapWithIndex { .. }
|
||||
| ListSortWith { .. }
|
||||
| ListKeepIf { .. }
|
||||
| ListKeepOks { .. }
|
||||
| ListKeepErrs { .. }
|
||||
| ListAny { .. }
|
||||
| ListAll { .. }
|
||||
| ListFindUnsafe { .. } => 2,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue