mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge remote-tracking branch 'origin/trunk' into rust61
This commit is contained in:
commit
a1de31d99e
131 changed files with 10929 additions and 10139 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -3434,6 +3434,7 @@ name = "roc_builtins"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"dunce",
|
||||||
|
"fs_extra",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"roc_collections",
|
"roc_collections",
|
||||||
"roc_module",
|
"roc_module",
|
||||||
|
@ -3980,6 +3981,7 @@ dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"distance",
|
"distance",
|
||||||
"indoc",
|
"indoc",
|
||||||
|
"insta",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"roc_builtins",
|
"roc_builtins",
|
||||||
"roc_can",
|
"roc_can",
|
||||||
|
|
|
@ -3,7 +3,7 @@ use indexmap::IndexMap;
|
||||||
use roc_mono::layout::UnionLayout;
|
use roc_mono::layout::UnionLayout;
|
||||||
use roc_target::{Architecture, TargetInfo};
|
use roc_target::{Architecture, TargetInfo};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fmt::Display;
|
use std::fmt::{Display, Write};
|
||||||
|
|
||||||
pub static TEMPLATE: &[u8] = include_bytes!("../templates/template.rs");
|
pub static TEMPLATE: &[u8] = include_bytes!("../templates/template.rs");
|
||||||
pub static HEADER: &[u8] = include_bytes!("../templates/header.rs");
|
pub static HEADER: &[u8] = include_bytes!("../templates/header.rs");
|
||||||
|
@ -95,24 +95,32 @@ pub fn emit(types_and_targets: &[(Types, TargetInfo)]) -> String {
|
||||||
1 => {
|
1 => {
|
||||||
let arch = arch_to_str(targets.get(0).unwrap().architecture);
|
let arch = arch_to_str(targets.get(0).unwrap().architecture);
|
||||||
|
|
||||||
buf.push_str(&format!("#[cfg(target_arch = \"{arch}\")]"));
|
write!(buf, "#[cfg(target_arch = \"{arch}\")]").unwrap();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// We should never have a decl recorded with 0 targets!
|
// We should never have a decl recorded with 0 targets!
|
||||||
debug_assert_ne!(targets.len(), 0);
|
debug_assert_ne!(targets.len(), 0);
|
||||||
|
|
||||||
let alternatives = targets
|
let mut it = targets.iter().peekable();
|
||||||
.iter()
|
|
||||||
.map(|target_info| {
|
|
||||||
format!(
|
|
||||||
"{indent}{INDENT}target_arch = \"{}\"",
|
|
||||||
arch_to_str(target_info.architecture)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(",\n");
|
|
||||||
|
|
||||||
buf.push_str(&format!("#[cfg(any(\n{alternatives}\n{indent}))]"));
|
writeln!(buf, "#[cfg(any(").unwrap();
|
||||||
|
|
||||||
|
while let Some(target_info) = it.next() {
|
||||||
|
write!(
|
||||||
|
buf,
|
||||||
|
"{indent}{INDENT}target_arch = \"{}\"",
|
||||||
|
arch_to_str(target_info.architecture)
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if it.peek().is_some() {
|
||||||
|
buf.push_str(",\n");
|
||||||
|
} else {
|
||||||
|
buf.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(buf, "{indent}))]").unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,16 +373,18 @@ pub struct {name} {{
|
||||||
if let Some(payload_id) = opt_payload_id {
|
if let Some(payload_id) = opt_payload_id {
|
||||||
let payload_type = types.get_type(*payload_id);
|
let payload_type = types.get_type(*payload_id);
|
||||||
|
|
||||||
buf.push_str(&format!("{INDENT}{tag_name}: "));
|
write!(buf, "{INDENT}{tag_name}: ").unwrap();
|
||||||
|
|
||||||
if payload_type.has_pointer(types) {
|
if payload_type.has_pointer(types) {
|
||||||
// types with pointers need ManuallyDrop
|
// types with pointers need ManuallyDrop
|
||||||
// because rust unions don't (and can't)
|
// because rust unions don't (and can't)
|
||||||
// know how to drop them automatically!
|
// know how to drop them automatically!
|
||||||
buf.push_str(&format!(
|
writeln!(
|
||||||
"core::mem::ManuallyDrop<{}>,\n",
|
buf,
|
||||||
|
"core::mem::ManuallyDrop<{}>,",
|
||||||
type_name(*payload_id, types)
|
type_name(*payload_id, types)
|
||||||
));
|
)
|
||||||
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
buf.push_str(&type_name(*payload_id, types));
|
buf.push_str(&type_name(*payload_id, types));
|
||||||
buf.push_str(",\n");
|
buf.push_str(",\n");
|
||||||
|
@ -392,9 +402,7 @@ pub struct {name} {{
|
||||||
// (Do this even if theoretically shouldn't be necessary, since
|
// (Do this even if theoretically shouldn't be necessary, since
|
||||||
// there's no runtime cost and it more explicitly syncs the
|
// there's no runtime cost and it more explicitly syncs the
|
||||||
// union's size with what we think it should be.)
|
// union's size with what we think it should be.)
|
||||||
buf.push_str(&format!(
|
writeln!(buf, "{INDENT}_sizer: [u8; {size_rounded_to_alignment}],").unwrap();
|
||||||
"{INDENT}_sizer: [u8; {size_rounded_to_alignment}],\n"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.push('}');
|
buf.push('}');
|
||||||
|
@ -1154,9 +1162,7 @@ fn write_impl_tags<
|
||||||
|
|
||||||
write_indents(indentations + 1, buf);
|
write_indents(indentations + 1, buf);
|
||||||
|
|
||||||
buf.push_str(&format!(
|
writeln!(buf, "{discriminant_name}::{tag_name} => {branch_str}").unwrap();
|
||||||
"{discriminant_name}::{tag_name} => {branch_str}\n"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
write_indents(indentations, buf);
|
write_indents(indentations, buf);
|
||||||
|
@ -1192,18 +1198,18 @@ fn add_enumeration<I: ExactSizeIterator<Item = S>, S: AsRef<str> + Display>(
|
||||||
);
|
);
|
||||||
|
|
||||||
for (index, tag_name) in tags.enumerate() {
|
for (index, tag_name) in tags.enumerate() {
|
||||||
buf.push_str(&format!("{INDENT}{tag_name} = {index},\n"));
|
writeln!(buf, "{INDENT}{tag_name} = {index},").unwrap();
|
||||||
|
|
||||||
write_indents(3, &mut debug_buf);
|
write_indents(3, &mut debug_buf);
|
||||||
|
|
||||||
debug_buf.push_str(&format!(
|
writeln!(
|
||||||
"Self::{tag_name} => f.write_str(\"{name}::{tag_name}\"),\n"
|
debug_buf,
|
||||||
));
|
"Self::{tag_name} => f.write_str(\"{name}::{tag_name}\"),"
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.push_str(&format!(
|
write!(buf, "}}\n\n{debug_buf}{INDENT}{INDENT}}}\n{INDENT}}}\n}}").unwrap();
|
||||||
"}}\n\n{debug_buf}{INDENT}{INDENT}}}\n{INDENT}}}\n}}"
|
|
||||||
));
|
|
||||||
|
|
||||||
add_decl(impls, None, target_info, buf);
|
add_decl(impls, None, target_info, buf);
|
||||||
}
|
}
|
||||||
|
@ -1237,7 +1243,7 @@ fn add_struct<S: Display>(
|
||||||
format!("{label}")
|
format!("{label}")
|
||||||
};
|
};
|
||||||
|
|
||||||
buf.push_str(&format!("{INDENT}pub {label}: {type_str},\n",));
|
writeln!(buf, "{INDENT}pub {label}: {type_str},",).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.push('}');
|
buf.push('}');
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub fn load_types(
|
||||||
mut type_problems,
|
mut type_problems,
|
||||||
mut declarations_by_id,
|
mut declarations_by_id,
|
||||||
mut solved,
|
mut solved,
|
||||||
interns,
|
mut interns,
|
||||||
..
|
..
|
||||||
} = roc_load::load_and_typecheck(
|
} = roc_load::load_and_typecheck(
|
||||||
arena,
|
arena,
|
||||||
|
@ -74,7 +74,7 @@ pub fn load_types(
|
||||||
let types_and_targets = Architecture::iter()
|
let types_and_targets = Architecture::iter()
|
||||||
.map(|arch| {
|
.map(|arch| {
|
||||||
let target_info = arch.into();
|
let target_info = arch.into();
|
||||||
let mut env = Env::new(arena, subs, &interns, target_info);
|
let mut env = Env::new(arena, subs, &mut interns, target_info);
|
||||||
|
|
||||||
(env.vars_to_types(variables.clone()), target_info)
|
(env.vars_to_types(variables.clone()), target_info)
|
||||||
})
|
})
|
||||||
|
|
|
@ -419,7 +419,12 @@ pub struct Env<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Env<'a> {
|
impl<'a> Env<'a> {
|
||||||
pub fn new(arena: &'a Bump, subs: &'a Subs, interns: &'a Interns, target: TargetInfo) -> Self {
|
pub fn new(
|
||||||
|
arena: &'a Bump,
|
||||||
|
subs: &'a Subs,
|
||||||
|
interns: &'a mut Interns,
|
||||||
|
target: TargetInfo,
|
||||||
|
) -> Self {
|
||||||
Env {
|
Env {
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
|
|
|
@ -14,11 +14,15 @@ use target_lexicon::Triple;
|
||||||
use tempfile::Builder;
|
use tempfile::Builder;
|
||||||
|
|
||||||
fn report_timing(buf: &mut String, label: &str, duration: Duration) {
|
fn report_timing(buf: &mut String, label: &str, duration: Duration) {
|
||||||
buf.push_str(&format!(
|
use std::fmt::Write;
|
||||||
" {:9.3} ms {}\n",
|
|
||||||
|
writeln!(
|
||||||
|
buf,
|
||||||
|
" {:9.3} ms {}",
|
||||||
duration.as_secs_f64() * 1000.0,
|
duration.as_secs_f64() * 1000.0,
|
||||||
label,
|
label,
|
||||||
));
|
)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BuiltFile {
|
pub struct BuiltFile {
|
||||||
|
|
|
@ -19,6 +19,7 @@ use roc_ast::{
|
||||||
};
|
};
|
||||||
use roc_utils::{index_of, slice_get};
|
use roc_utils::{index_of, slice_get};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum MarkupNode {
|
pub enum MarkupNode {
|
||||||
|
@ -376,7 +377,7 @@ pub fn tree_as_string(root_node_id: MarkNodeId, mark_node_pool: &SlowPool) -> St
|
||||||
|
|
||||||
let node = mark_node_pool.get(root_node_id);
|
let node = mark_node_pool.get(root_node_id);
|
||||||
|
|
||||||
full_string.push_str(&format!("{} mn_id {}\n", node, root_node_id));
|
writeln!(full_string, "{} mn_id {}\n", node, root_node_id).unwrap();
|
||||||
|
|
||||||
tree_as_string_helper(node, 1, &mut full_string, mark_node_pool);
|
tree_as_string_helper(node, 1, &mut full_string, mark_node_pool);
|
||||||
|
|
||||||
|
@ -390,16 +391,16 @@ fn tree_as_string_helper(
|
||||||
mark_node_pool: &SlowPool,
|
mark_node_pool: &SlowPool,
|
||||||
) {
|
) {
|
||||||
for child_id in node.get_children_ids() {
|
for child_id in node.get_children_ids() {
|
||||||
|
let child = mark_node_pool.get(child_id);
|
||||||
|
let child_str = format!("{}", mark_node_pool.get(child_id)).replace('\n', "\\n");
|
||||||
|
|
||||||
let mut full_str = std::iter::repeat("|--- ")
|
let mut full_str = std::iter::repeat("|--- ")
|
||||||
.take(level)
|
.take(level)
|
||||||
.collect::<Vec<&str>>()
|
.collect::<Vec<&str>>()
|
||||||
.join("")
|
.join("")
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
let child = mark_node_pool.get(child_id);
|
writeln!(full_str, "{} mn_id {}", child_str, child_id).unwrap();
|
||||||
let child_str = format!("{}", mark_node_pool.get(child_id)).replace('\n', "\\n");
|
|
||||||
|
|
||||||
full_str.push_str(&format!("{} mn_id {}\n", child_str, child_id));
|
|
||||||
|
|
||||||
tree_string.push_str(&full_str);
|
tree_string.push_str(&full_str);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::markup::{mark_id_ast_id_map::MarkIdAstIdMap, nodes::MarkupNode};
|
use crate::markup::{mark_id_ast_id_map::MarkIdAstIdMap, nodes::MarkupNode};
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
pub type MarkNodeId = usize;
|
pub type MarkNodeId = usize;
|
||||||
|
|
||||||
|
@ -54,14 +55,16 @@ impl SlowPool {
|
||||||
child_str = format!("children: {:?}", node_children);
|
child_str = format!("children: {:?}", node_children);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret_str.push_str(&format!(
|
write!(
|
||||||
|
ret_str,
|
||||||
"{}: {} ({}) ast_id {:?} {}",
|
"{}: {} ({}) ast_id {:?} {}",
|
||||||
mark_node_id,
|
mark_node_id,
|
||||||
node.node_type_as_string(),
|
node.node_type_as_string(),
|
||||||
node.get_content(),
|
node.get_content(),
|
||||||
ast_node_id.parse::<usize>().unwrap(),
|
ast_node_id.parse::<usize>().unwrap(),
|
||||||
child_str
|
child_str
|
||||||
));
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret_str
|
ret_str
|
||||||
|
|
|
@ -12,7 +12,7 @@ use roc_mono::ir::{
|
||||||
Call, CallType, Expr, HigherOrderLowLevel, HostExposedLayouts, ListLiteralElement, Literal,
|
Call, CallType, Expr, HigherOrderLowLevel, HostExposedLayouts, ListLiteralElement, Literal,
|
||||||
ModifyRc, OptLevel, Proc, Stmt,
|
ModifyRc, OptLevel, Proc, Stmt,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Builtin, Layout, RawFunctionLayout, UnionLayout};
|
use roc_mono::layout::{Builtin, CapturesNiche, Layout, RawFunctionLayout, UnionLayout};
|
||||||
|
|
||||||
// just using one module for now
|
// just using one module for now
|
||||||
pub const MOD_APP: ModName = ModName(b"UserApp");
|
pub const MOD_APP: ModName = ModName(b"UserApp");
|
||||||
|
@ -23,7 +23,13 @@ pub const STATIC_LIST_NAME: ConstName = ConstName(b"THIS IS A STATIC LIST");
|
||||||
const ENTRY_POINT_NAME: &[u8] = b"mainForHost";
|
const ENTRY_POINT_NAME: &[u8] = b"mainForHost";
|
||||||
|
|
||||||
pub fn func_name_bytes(proc: &Proc) -> [u8; SIZE] {
|
pub fn func_name_bytes(proc: &Proc) -> [u8; SIZE] {
|
||||||
func_name_bytes_help(proc.name, proc.args.iter().map(|x| x.0), &proc.ret_layout)
|
let bytes = func_name_bytes_help(
|
||||||
|
proc.name.name(),
|
||||||
|
proc.args.iter().map(|x| x.0),
|
||||||
|
proc.name.captures_niche(),
|
||||||
|
&proc.ret_layout,
|
||||||
|
);
|
||||||
|
bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -64,6 +70,7 @@ impl TagUnionId {
|
||||||
pub fn func_name_bytes_help<'a, I>(
|
pub fn func_name_bytes_help<'a, I>(
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
argument_layouts: I,
|
argument_layouts: I,
|
||||||
|
captures_niche: CapturesNiche<'a>,
|
||||||
return_layout: &Layout<'a>,
|
return_layout: &Layout<'a>,
|
||||||
) -> [u8; SIZE]
|
) -> [u8; SIZE]
|
||||||
where
|
where
|
||||||
|
@ -82,6 +89,8 @@ where
|
||||||
layout.hash(&mut hasher);
|
layout.hash(&mut hasher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
captures_niche.hash(&mut hasher);
|
||||||
|
|
||||||
return_layout.hash(&mut hasher);
|
return_layout.hash(&mut hasher);
|
||||||
|
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
|
@ -173,13 +182,22 @@ where
|
||||||
match layout {
|
match layout {
|
||||||
RawFunctionLayout::Function(_, _, _) => {
|
RawFunctionLayout::Function(_, _, _) => {
|
||||||
let it = top_level.arguments.iter().copied();
|
let it = top_level.arguments.iter().copied();
|
||||||
let bytes = func_name_bytes_help(*symbol, it, &top_level.result);
|
let bytes = func_name_bytes_help(
|
||||||
|
*symbol,
|
||||||
|
it,
|
||||||
|
CapturesNiche::no_niche(),
|
||||||
|
&top_level.result,
|
||||||
|
);
|
||||||
|
|
||||||
host_exposed_functions.push((bytes, top_level.arguments));
|
host_exposed_functions.push((bytes, top_level.arguments));
|
||||||
}
|
}
|
||||||
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
||||||
let bytes =
|
let bytes = func_name_bytes_help(
|
||||||
func_name_bytes_help(*symbol, [Layout::UNIT], &top_level.result);
|
*symbol,
|
||||||
|
[Layout::UNIT],
|
||||||
|
CapturesNiche::no_niche(),
|
||||||
|
&top_level.result,
|
||||||
|
);
|
||||||
|
|
||||||
host_exposed_functions.push((bytes, top_level.arguments));
|
host_exposed_functions.push((bytes, top_level.arguments));
|
||||||
}
|
}
|
||||||
|
@ -207,6 +225,7 @@ where
|
||||||
let roc_main_bytes = func_name_bytes_help(
|
let roc_main_bytes = func_name_bytes_help(
|
||||||
entry_point.symbol,
|
entry_point.symbol,
|
||||||
entry_point.layout.arguments.iter().copied(),
|
entry_point.layout.arguments.iter().copied(),
|
||||||
|
CapturesNiche::no_niche(),
|
||||||
&entry_point.layout.result,
|
&entry_point.layout.result,
|
||||||
);
|
);
|
||||||
let roc_main = FuncName(&roc_main_bytes);
|
let roc_main = FuncName(&roc_main_bytes);
|
||||||
|
@ -631,7 +650,7 @@ fn call_spec(
|
||||||
|
|
||||||
match &call.call_type {
|
match &call.call_type {
|
||||||
ByName {
|
ByName {
|
||||||
name: symbol,
|
name,
|
||||||
ret_layout,
|
ret_layout,
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
specialization_id,
|
specialization_id,
|
||||||
|
@ -640,8 +659,9 @@ fn call_spec(
|
||||||
let spec_var = CalleeSpecVar(&array);
|
let spec_var = CalleeSpecVar(&array);
|
||||||
|
|
||||||
let arg_value_id = build_tuple_value(builder, env, block, call.arguments)?;
|
let arg_value_id = build_tuple_value(builder, env, block, call.arguments)?;
|
||||||
let it = arg_layouts.iter().copied();
|
let args_it = arg_layouts.iter().copied();
|
||||||
let bytes = func_name_bytes_help(*symbol, it, ret_layout);
|
let captures_niche = name.captures_niche();
|
||||||
|
let bytes = func_name_bytes_help(name.name(), args_it, captures_niche, ret_layout);
|
||||||
let name = FuncName(&bytes);
|
let name = FuncName(&bytes);
|
||||||
let module = MOD_APP;
|
let module = MOD_APP;
|
||||||
builder.add_call(block, spec_var, module, name, arg_value_id)
|
builder.add_call(block, spec_var, module, name, arg_value_id)
|
||||||
|
@ -684,9 +704,14 @@ fn call_spec(
|
||||||
let mode = update_mode.to_bytes();
|
let mode = update_mode.to_bytes();
|
||||||
let update_mode_var = UpdateModeVar(&mode);
|
let update_mode_var = UpdateModeVar(&mode);
|
||||||
|
|
||||||
let it = passed_function.argument_layouts.iter().copied();
|
let args_it = passed_function.argument_layouts.iter().copied();
|
||||||
let bytes =
|
let captures_niche = passed_function.name.captures_niche();
|
||||||
func_name_bytes_help(passed_function.name, it, &passed_function.return_layout);
|
let bytes = func_name_bytes_help(
|
||||||
|
passed_function.name.name(),
|
||||||
|
args_it,
|
||||||
|
captures_niche,
|
||||||
|
&passed_function.return_layout,
|
||||||
|
);
|
||||||
let name = FuncName(&bytes);
|
let name = FuncName(&bytes);
|
||||||
let module = MOD_APP;
|
let module = MOD_APP;
|
||||||
|
|
||||||
|
@ -733,34 +758,6 @@ fn call_spec(
|
||||||
add_loop(builder, block, state_type, init_state, loop_body)
|
add_loop(builder, block, state_type, init_state, loop_body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// List.mapWithIndex : List before, (before, Nat -> after) -> List after
|
|
||||||
ListMapWithIndex { xs } => {
|
|
||||||
let list = env.symbols[xs];
|
|
||||||
|
|
||||||
let loop_body = |builder: &mut FuncDefBuilder, block, state| {
|
|
||||||
let input_bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
|
||||||
|
|
||||||
let element = builder.add_bag_get(block, input_bag)?;
|
|
||||||
let index = builder.add_make_tuple(block, &[])?;
|
|
||||||
|
|
||||||
// before, Nat -> after
|
|
||||||
let new_element = call_function!(builder, block, [element, index]);
|
|
||||||
|
|
||||||
list_append(builder, block, update_mode_var, state, new_element)
|
|
||||||
};
|
|
||||||
|
|
||||||
let output_element_type =
|
|
||||||
layout_spec(builder, return_layout, &WhenRecursive::Unreachable)?;
|
|
||||||
|
|
||||||
let state_layout = Layout::Builtin(Builtin::List(return_layout));
|
|
||||||
let state_type =
|
|
||||||
layout_spec(builder, &state_layout, &WhenRecursive::Unreachable)?;
|
|
||||||
|
|
||||||
let init_state = new_list(builder, block, output_element_type)?;
|
|
||||||
|
|
||||||
add_loop(builder, block, state_type, init_state, loop_body)
|
|
||||||
}
|
|
||||||
|
|
||||||
ListMap { xs } => {
|
ListMap { xs } => {
|
||||||
let list = env.symbols[xs];
|
let list = env.symbols[xs];
|
||||||
|
|
||||||
|
@ -1201,14 +1198,12 @@ fn expr_spec<'a>(
|
||||||
Call(call) => call_spec(builder, env, block, layout, call),
|
Call(call) => call_spec(builder, env, block, layout, call),
|
||||||
Reuse {
|
Reuse {
|
||||||
tag_layout,
|
tag_layout,
|
||||||
tag_name: _,
|
|
||||||
tag_id,
|
tag_id,
|
||||||
arguments,
|
arguments,
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
| Tag {
|
| Tag {
|
||||||
tag_layout,
|
tag_layout,
|
||||||
tag_name: _,
|
|
||||||
tag_id,
|
tag_id,
|
||||||
arguments,
|
arguments,
|
||||||
} => {
|
} => {
|
||||||
|
|
|
@ -65,6 +65,16 @@ pub fn link(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_zig_str_path() -> PathBuf {
|
fn find_zig_str_path() -> PathBuf {
|
||||||
|
// First try using the lib path relative to the executable location.
|
||||||
|
let exe_relative_str_path = std::env::current_exe()
|
||||||
|
.ok()
|
||||||
|
.and_then(|path| Some(path.parent()?.join("lib").join("str.zig")));
|
||||||
|
if let Some(exe_relative_str_path) = exe_relative_str_path {
|
||||||
|
if std::path::Path::exists(&exe_relative_str_path) {
|
||||||
|
return exe_relative_str_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let zig_str_path = PathBuf::from("crates/compiler/builtins/bitcode/src/str.zig");
|
let zig_str_path = PathBuf::from("crates/compiler/builtins/bitcode/src/str.zig");
|
||||||
|
|
||||||
if std::path::Path::exists(&zig_str_path) {
|
if std::path::Path::exists(&zig_str_path) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ lazy_static = "1.4.0"
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
# dunce can be removed once ziglang/zig#5109 is fixed
|
# dunce can be removed once ziglang/zig#5109 is fixed
|
||||||
dunce = "1.0.2"
|
dunce = "1.0.2"
|
||||||
|
fs_extra = "1.2.0"
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.build-dependencies]
|
[target.'cfg(target_os = "macos")'.build-dependencies]
|
||||||
tempfile = "3.2.0"
|
tempfile = "3.2.0"
|
||||||
|
|
|
@ -227,38 +227,6 @@ pub fn listMap(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// List.mapWithIndex : List before, (before, Nat -> after) -> List after
|
|
||||||
pub fn listMapWithIndex(
|
|
||||||
list: RocList,
|
|
||||||
caller: Caller2,
|
|
||||||
data: Opaque,
|
|
||||||
inc_n_data: IncN,
|
|
||||||
data_is_owned: bool,
|
|
||||||
alignment: u32,
|
|
||||||
old_element_width: usize,
|
|
||||||
new_element_width: usize,
|
|
||||||
) callconv(.C) RocList {
|
|
||||||
if (list.bytes) |source_ptr| {
|
|
||||||
const size = list.len();
|
|
||||||
var i: usize = 0;
|
|
||||||
const output = RocList.allocate(alignment, size, new_element_width);
|
|
||||||
const target_ptr = output.bytes orelse unreachable;
|
|
||||||
|
|
||||||
if (data_is_owned) {
|
|
||||||
inc_n_data(data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (i < size) : (i += 1) {
|
|
||||||
// before, Nat -> after
|
|
||||||
caller(data, source_ptr + (i * old_element_width), @ptrCast(?[*]u8, &i), target_ptr + (i * new_element_width));
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
} else {
|
|
||||||
return RocList.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decrementTail(list: RocList, start_index: usize, element_width: usize, dec: Dec) void {
|
fn decrementTail(list: RocList, start_index: usize, element_width: usize, dec: Dec) void {
|
||||||
if (list.bytes) |source| {
|
if (list.bytes) |source| {
|
||||||
var i = start_index;
|
var i = start_index;
|
||||||
|
|
|
@ -40,7 +40,6 @@ comptime {
|
||||||
exportListFn(list.listMap2, "map2");
|
exportListFn(list.listMap2, "map2");
|
||||||
exportListFn(list.listMap3, "map3");
|
exportListFn(list.listMap3, "map3");
|
||||||
exportListFn(list.listMap4, "map4");
|
exportListFn(list.listMap4, "map4");
|
||||||
exportListFn(list.listMapWithIndex, "map_with_index");
|
|
||||||
exportListFn(list.listAppend, "append");
|
exportListFn(list.listAppend, "append");
|
||||||
exportListFn(list.listPrepend, "prepend");
|
exportListFn(list.listPrepend, "prepend");
|
||||||
exportListFn(list.listWithCapacity, "with_capacity");
|
exportListFn(list.listWithCapacity, "with_capacity");
|
||||||
|
@ -143,9 +142,11 @@ const str = @import("str.zig");
|
||||||
comptime {
|
comptime {
|
||||||
exportStrFn(str.init, "init");
|
exportStrFn(str.init, "init");
|
||||||
exportStrFn(str.strToScalarsC, "to_scalars");
|
exportStrFn(str.strToScalarsC, "to_scalars");
|
||||||
|
exportStrFn(str.strSplit, "str_split");
|
||||||
exportStrFn(str.strSplitInPlaceC, "str_split_in_place");
|
exportStrFn(str.strSplitInPlaceC, "str_split_in_place");
|
||||||
exportStrFn(str.countSegments, "count_segments");
|
exportStrFn(str.countSegments, "count_segments");
|
||||||
exportStrFn(str.countGraphemeClusters, "count_grapheme_clusters");
|
exportStrFn(str.countGraphemeClusters, "count_grapheme_clusters");
|
||||||
|
exportStrFn(str.countUtf8Bytes, "count_utf8_bytes");
|
||||||
exportStrFn(str.startsWith, "starts_with");
|
exportStrFn(str.startsWith, "starts_with");
|
||||||
exportStrFn(str.startsWithScalar, "starts_with_scalar");
|
exportStrFn(str.startsWithScalar, "starts_with_scalar");
|
||||||
exportStrFn(str.endsWith, "ends_with");
|
exportStrFn(str.endsWith, "ends_with");
|
||||||
|
@ -154,6 +155,11 @@ comptime {
|
||||||
exportStrFn(str.strNumberOfBytes, "number_of_bytes");
|
exportStrFn(str.strNumberOfBytes, "number_of_bytes");
|
||||||
exportStrFn(str.strFromFloatC, "from_float");
|
exportStrFn(str.strFromFloatC, "from_float");
|
||||||
exportStrFn(str.strEqual, "equal");
|
exportStrFn(str.strEqual, "equal");
|
||||||
|
exportStrFn(str.substringUnsafe, "substring_unsafe");
|
||||||
|
exportStrFn(str.getUnsafe, "get_unsafe");
|
||||||
|
exportStrFn(str.reserve, "reserve");
|
||||||
|
exportStrFn(str.getScalarUnsafe, "get_scalar_unsafe");
|
||||||
|
exportStrFn(str.appendScalar, "append_scalar");
|
||||||
exportStrFn(str.strToUtf8C, "to_utf8");
|
exportStrFn(str.strToUtf8C, "to_utf8");
|
||||||
exportStrFn(str.fromUtf8C, "from_utf8");
|
exportStrFn(str.fromUtf8C, "from_utf8");
|
||||||
exportStrFn(str.fromUtf8RangeC, "from_utf8_range");
|
exportStrFn(str.fromUtf8RangeC, "from_utf8_range");
|
||||||
|
|
|
@ -112,7 +112,7 @@ pub const RocStr = extern struct {
|
||||||
|
|
||||||
pub fn eq(self: RocStr, other: RocStr) bool {
|
pub fn eq(self: RocStr, other: RocStr) bool {
|
||||||
// If they are byte-for-byte equal, they're definitely equal!
|
// If they are byte-for-byte equal, they're definitely equal!
|
||||||
if (self.str_bytes == other.str_bytes and self.str_len == other.str_len) {
|
if (self.str_bytes == other.str_bytes and self.str_len == other.str_len and self.str_capacity == other.str_capacity) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,10 +173,10 @@ pub const RocStr = extern struct {
|
||||||
const element_width = 1;
|
const element_width = 1;
|
||||||
|
|
||||||
if (self.str_bytes) |source_ptr| {
|
if (self.str_bytes) |source_ptr| {
|
||||||
if (self.isUnique()) {
|
if (self.isUnique() and !self.isSmallStr()) {
|
||||||
const new_source = utils.unsafeReallocate(source_ptr, RocStr.alignment, self.len(), new_length, element_width);
|
const new_source = utils.unsafeReallocate(source_ptr, RocStr.alignment, self.len(), new_length, element_width);
|
||||||
|
|
||||||
return RocStr{ .str_bytes = new_source, .str_len = new_length };
|
return RocStr{ .str_bytes = new_source, .str_len = new_length, .str_capacity = new_length };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +228,11 @@ pub const RocStr = extern struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn capacity(self: RocStr) usize {
|
pub fn capacity(self: RocStr) usize {
|
||||||
return self.str_capacity ^ MASK;
|
if (self.isSmallStr()) {
|
||||||
|
return SMALL_STR_MAX_LENGTH;
|
||||||
|
} else {
|
||||||
|
return self.str_capacity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This does a small string check, but no bounds checking whatsoever!
|
// This does a small string check, but no bounds checking whatsoever!
|
||||||
|
@ -311,6 +315,10 @@ pub const RocStr = extern struct {
|
||||||
return self.asU8ptr()[0..self.len()];
|
return self.asU8ptr()[0..self.len()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn asSliceWithCapacity(self: RocStr) []u8 {
|
||||||
|
return self.asU8ptr()[0..self.capacity()];
|
||||||
|
}
|
||||||
|
|
||||||
pub fn asU8ptr(self: RocStr) [*]u8 {
|
pub fn asU8ptr(self: RocStr) [*]u8 {
|
||||||
|
|
||||||
// Since this conditional would be prone to branch misprediction,
|
// Since this conditional would be prone to branch misprediction,
|
||||||
|
@ -744,6 +752,21 @@ fn strFromFloatHelp(comptime T: type, float: T) RocStr {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Str.split
|
// Str.split
|
||||||
|
|
||||||
|
// For dev backends
|
||||||
|
pub fn strSplit(string: RocStr, delimiter: RocStr) callconv(.C) RocList {
|
||||||
|
const segment_count = countSegments(string, delimiter);
|
||||||
|
const list = RocList.allocate(@alignOf(RocStr), segment_count, @sizeOf(RocStr));
|
||||||
|
|
||||||
|
if (list.bytes) |bytes| {
|
||||||
|
const strings = @ptrCast([*]RocStr, @alignCast(@alignOf(RocStr), bytes));
|
||||||
|
strSplitInPlace(strings, string, delimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For LLVM backend
|
||||||
pub fn strSplitInPlaceC(opt_array: ?[*]RocStr, string: RocStr, delimiter: RocStr) callconv(.C) void {
|
pub fn strSplitInPlaceC(opt_array: ?[*]RocStr, string: RocStr, delimiter: RocStr) callconv(.C) void {
|
||||||
if (opt_array) |array| {
|
if (opt_array) |array| {
|
||||||
return @call(.{ .modifier = always_inline }, strSplitInPlace, .{ array, string, delimiter });
|
return @call(.{ .modifier = always_inline }, strSplitInPlace, .{ array, string, delimiter });
|
||||||
|
@ -1184,6 +1207,56 @@ test "countGraphemeClusters: emojis, ut8, and ascii characters" {
|
||||||
try expectEqual(count, 10);
|
try expectEqual(count, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn countUtf8Bytes(string: RocStr) callconv(.C) usize {
|
||||||
|
return string.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn substringUnsafe(string: RocStr, start: usize, length: usize) callconv(.C) RocStr {
|
||||||
|
const slice = string.asSlice()[start .. start + length];
|
||||||
|
|
||||||
|
return RocStr.fromSlice(slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getUnsafe(string: RocStr, index: usize) callconv(.C) u8 {
|
||||||
|
return string.getUnchecked(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "substringUnsafe: start" {
|
||||||
|
const str = RocStr.fromSlice("abcdef");
|
||||||
|
defer str.deinit();
|
||||||
|
|
||||||
|
const expected = RocStr.fromSlice("abc");
|
||||||
|
defer expected.deinit();
|
||||||
|
|
||||||
|
const actual = substringUnsafe(str, 0, 3);
|
||||||
|
|
||||||
|
try expect(RocStr.eq(actual, expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "substringUnsafe: middle" {
|
||||||
|
const str = RocStr.fromSlice("abcdef");
|
||||||
|
defer str.deinit();
|
||||||
|
|
||||||
|
const expected = RocStr.fromSlice("bcd");
|
||||||
|
defer expected.deinit();
|
||||||
|
|
||||||
|
const actual = substringUnsafe(str, 1, 3);
|
||||||
|
|
||||||
|
try expect(RocStr.eq(actual, expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "substringUnsafe: end" {
|
||||||
|
const str = RocStr.fromSlice("a string so long it is heap-allocated");
|
||||||
|
defer str.deinit();
|
||||||
|
|
||||||
|
const expected = RocStr.fromSlice("heap-allocated");
|
||||||
|
defer expected.deinit();
|
||||||
|
|
||||||
|
const actual = substringUnsafe(str, 23, 37 - 23);
|
||||||
|
|
||||||
|
try expect(RocStr.eq(actual, expected));
|
||||||
|
}
|
||||||
|
|
||||||
// Str.startsWith
|
// Str.startsWith
|
||||||
pub fn startsWith(string: RocStr, prefix: RocStr) callconv(.C) bool {
|
pub fn startsWith(string: RocStr, prefix: RocStr) callconv(.C) bool {
|
||||||
const bytes_len = string.len();
|
const bytes_len = string.len();
|
||||||
|
@ -1537,7 +1610,7 @@ const CountAndStart = extern struct {
|
||||||
start: usize,
|
start: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn fromUtf8C(arg: RocList, update_mode: UpdateMode, output: *FromUtf8Result) callconv(.C) void {
|
pub fn fromUtf8C(output: *FromUtf8Result, arg: RocList, update_mode: UpdateMode) callconv(.C) void {
|
||||||
output.* = fromUtf8(arg, update_mode);
|
output.* = fromUtf8(arg, update_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1592,7 +1665,7 @@ inline fn fromUtf8(arg: RocList, update_mode: UpdateMode) FromUtf8Result {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fromUtf8RangeC(arg: RocList, countAndStart: CountAndStart, output: *FromUtf8Result) callconv(.C) void {
|
pub fn fromUtf8RangeC(output: *FromUtf8Result, arg: RocList, countAndStart: CountAndStart) callconv(.C) void {
|
||||||
output.* = @call(.{ .modifier = always_inline }, fromUtf8Range, .{ arg, countAndStart });
|
output.* = @call(.{ .modifier = always_inline }, fromUtf8Range, .{ arg, countAndStart });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2300,3 +2373,119 @@ test "ReverseUtf8View: empty" {
|
||||||
try expect(false);
|
try expect(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "capacity: small string" {
|
||||||
|
const data_bytes = "foobar";
|
||||||
|
var data = RocStr.init(data_bytes, data_bytes.len);
|
||||||
|
defer data.deinit();
|
||||||
|
|
||||||
|
try expectEqual(data.capacity(), SMALL_STR_MAX_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "capacity: big string" {
|
||||||
|
const data_bytes = "a string so large that it must be heap-allocated";
|
||||||
|
var data = RocStr.init(data_bytes, data_bytes.len);
|
||||||
|
defer data.deinit();
|
||||||
|
|
||||||
|
try expectEqual(data.capacity(), data_bytes.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendScalar(string: RocStr, scalar_u32: u32) callconv(.C) RocStr {
|
||||||
|
const scalar = @intCast(u21, scalar_u32);
|
||||||
|
const width = std.unicode.utf8CodepointSequenceLength(scalar) catch unreachable;
|
||||||
|
|
||||||
|
var output = string.reallocate(string.len() + width);
|
||||||
|
var slice = output.asSliceWithCapacity();
|
||||||
|
|
||||||
|
_ = std.unicode.utf8Encode(scalar, slice[string.len() .. string.len() + width]) catch unreachable;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "appendScalar: small A" {
|
||||||
|
const A: []const u8 = "A";
|
||||||
|
|
||||||
|
const data_bytes = "hello";
|
||||||
|
var data = RocStr.init(data_bytes, data_bytes.len);
|
||||||
|
|
||||||
|
const actual = appendScalar(data, A[0]);
|
||||||
|
defer actual.deinit();
|
||||||
|
|
||||||
|
const expected_bytes = "helloA";
|
||||||
|
const expected = RocStr.init(expected_bytes, expected_bytes.len);
|
||||||
|
defer expected.deinit();
|
||||||
|
|
||||||
|
try expect(actual.eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "appendScalar: small 😀" {
|
||||||
|
const data_bytes = "hello";
|
||||||
|
var data = RocStr.init(data_bytes, data_bytes.len);
|
||||||
|
|
||||||
|
const actual = appendScalar(data, 0x1F600);
|
||||||
|
defer actual.deinit();
|
||||||
|
|
||||||
|
const expected_bytes = "hello😀";
|
||||||
|
const expected = RocStr.init(expected_bytes, expected_bytes.len);
|
||||||
|
defer expected.deinit();
|
||||||
|
|
||||||
|
try expect(actual.eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "appendScalar: big A" {
|
||||||
|
const A: []const u8 = "A";
|
||||||
|
|
||||||
|
const data_bytes = "a string so large that it must be heap-allocated";
|
||||||
|
var data = RocStr.init(data_bytes, data_bytes.len);
|
||||||
|
|
||||||
|
const actual = appendScalar(data, A[0]);
|
||||||
|
defer actual.deinit();
|
||||||
|
|
||||||
|
const expected_bytes = "a string so large that it must be heap-allocatedA";
|
||||||
|
const expected = RocStr.init(expected_bytes, expected_bytes.len);
|
||||||
|
defer expected.deinit();
|
||||||
|
|
||||||
|
try expect(actual.eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "appendScalar: big 😀" {
|
||||||
|
const data_bytes = "a string so large that it must be heap-allocated";
|
||||||
|
var data = RocStr.init(data_bytes, data_bytes.len);
|
||||||
|
|
||||||
|
const actual = appendScalar(data, 0x1F600);
|
||||||
|
defer actual.deinit();
|
||||||
|
|
||||||
|
const expected_bytes = "a string so large that it must be heap-allocated😀";
|
||||||
|
const expected = RocStr.init(expected_bytes, expected_bytes.len);
|
||||||
|
defer expected.deinit();
|
||||||
|
|
||||||
|
try expect(actual.eq(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reserve(string: RocStr, capacity: usize) callconv(.C) RocStr {
|
||||||
|
if (capacity > string.capacity()) {
|
||||||
|
return string.reallocate(capacity);
|
||||||
|
} else {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getScalarUnsafe(string: RocStr, index: usize) callconv(.C) extern struct { bytesParsed: usize, scalar: u32 } {
|
||||||
|
const slice = string.asSlice();
|
||||||
|
const bytesParsed = @intCast(usize, std.unicode.utf8ByteSequenceLength(slice[index]) catch unreachable);
|
||||||
|
const scalar = std.unicode.utf8Decode(slice[index .. index + bytesParsed]) catch unreachable;
|
||||||
|
|
||||||
|
return .{ .bytesParsed = bytesParsed, .scalar = @intCast(u32, scalar) };
|
||||||
|
}
|
||||||
|
|
||||||
|
test "getScalarUnsafe" {
|
||||||
|
const data_bytes = "A";
|
||||||
|
var data = RocStr.init(data_bytes, data_bytes.len);
|
||||||
|
|
||||||
|
const result = getScalarUnsafe(data, 0);
|
||||||
|
|
||||||
|
const expected = try std.unicode.utf8Decode("A");
|
||||||
|
|
||||||
|
try expectEqual(result.scalar, @intCast(u32, expected));
|
||||||
|
try expectEqual(result.bytesParsed, 1);
|
||||||
|
}
|
||||||
|
|
|
@ -256,6 +256,10 @@ pub fn unsafeReallocate(
|
||||||
const old_width = align_width + old_length * element_width;
|
const old_width = align_width + old_length * element_width;
|
||||||
const new_width = align_width + new_length * element_width;
|
const new_width = align_width + new_length * element_width;
|
||||||
|
|
||||||
|
if (old_width == new_width) {
|
||||||
|
return source_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO handle out of memory
|
// TODO handle out of memory
|
||||||
// NOTE realloc will dealloc the original allocation
|
// NOTE realloc will dealloc the original allocation
|
||||||
const old_allocation = source_ptr - align_width;
|
const old_allocation = source_ptr - align_width;
|
||||||
|
|
|
@ -67,6 +67,8 @@ fn main() {
|
||||||
"builtins-wasm32.o",
|
"builtins-wasm32.o",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
copy_zig_builtins_to_target_dir(&bitcode_path);
|
||||||
|
|
||||||
get_zig_files(bitcode_path.as_path(), &|path| {
|
get_zig_files(bitcode_path.as_path(), &|path| {
|
||||||
let path: &Path = path;
|
let path: &Path = path;
|
||||||
println!(
|
println!(
|
||||||
|
@ -144,6 +146,39 @@ fn generate_bc_file(bitcode_path: &Path, zig_object: &str, file_name: &str) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copy_zig_builtins_to_target_dir(bitcode_path: &Path) {
|
||||||
|
// To enable roc to find the zig biultins, we want them to be moved to a folder next to the roc executable.
|
||||||
|
// So if <roc_folder>/roc is the executable. The zig files will be in <roc_folder>/lib/*.zig
|
||||||
|
|
||||||
|
// Currently we have the OUT_DIR variable which points to `/target/debug/build/roc_builtins-*/out/`.
|
||||||
|
// So we just need to shed a 3 of the outer layers to get `/target/debug/` and then add `lib`.
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
let target_profile_dir = Path::new(&out_dir)
|
||||||
|
.parent()
|
||||||
|
.and_then(|path| path.parent())
|
||||||
|
.and_then(|path| path.parent())
|
||||||
|
.unwrap()
|
||||||
|
.join("lib");
|
||||||
|
|
||||||
|
let zig_src_dir = bitcode_path.join("src");
|
||||||
|
|
||||||
|
std::fs::create_dir_all(&target_profile_dir).unwrap_or_else(|err| {
|
||||||
|
panic!(
|
||||||
|
"Failed to create output library directory for zig bitcode {:?}: {:?}",
|
||||||
|
target_profile_dir, err
|
||||||
|
);
|
||||||
|
});
|
||||||
|
let mut options = fs_extra::dir::CopyOptions::new();
|
||||||
|
options.content_only = true;
|
||||||
|
options.overwrite = true;
|
||||||
|
fs_extra::dir::copy(&zig_src_dir, &target_profile_dir, &options).unwrap_or_else(|err| {
|
||||||
|
panic!(
|
||||||
|
"Failed to copy zig bitcode files {:?} to {:?}: {:?}",
|
||||||
|
zig_src_dir, target_profile_dir, err
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn run_command<S, I: Copy, P: AsRef<Path> + Copy>(path: P, command_str: &str, args: I)
|
fn run_command<S, I: Copy, P: AsRef<Path> + Copy>(path: P, command_str: &str, args: I)
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = S>,
|
I: IntoIterator<Item = S>,
|
||||||
|
|
|
@ -570,6 +570,23 @@ map4 : List a, List b, List c, List d, (a, b, c, d -> e) -> List e
|
||||||
## This works like [List.map], except it also passes the index
|
## This works like [List.map], except it also passes the index
|
||||||
## of the element to the conversion function.
|
## of the element to the conversion function.
|
||||||
mapWithIndex : List a, (a, Nat -> b) -> List b
|
mapWithIndex : List a, (a, Nat -> b) -> List b
|
||||||
|
mapWithIndex = \src, func ->
|
||||||
|
length = len src
|
||||||
|
dest = withCapacity length
|
||||||
|
|
||||||
|
mapWithIndexHelp src dest func 0 length
|
||||||
|
|
||||||
|
# Internal helper
|
||||||
|
mapWithIndexHelp : List a, List b, (a, Nat -> b), Nat, Nat -> List b
|
||||||
|
mapWithIndexHelp = \src, dest, func, index, length ->
|
||||||
|
if index < length then
|
||||||
|
elem = getUnsafe src index
|
||||||
|
mappedElem = func elem index
|
||||||
|
newDest = append dest mappedElem
|
||||||
|
|
||||||
|
mapWithIndexHelp src newDest func (index + 1) length
|
||||||
|
else
|
||||||
|
dest
|
||||||
|
|
||||||
## Returns a list of all the integers between one and another,
|
## Returns a list of all the integers between one and another,
|
||||||
## including both of the given numbers.
|
## including both of the given numbers.
|
||||||
|
|
|
@ -9,6 +9,7 @@ interface Str
|
||||||
split,
|
split,
|
||||||
repeat,
|
repeat,
|
||||||
countGraphemes,
|
countGraphemes,
|
||||||
|
countUtf8Bytes,
|
||||||
startsWithScalar,
|
startsWithScalar,
|
||||||
toUtf8,
|
toUtf8,
|
||||||
fromUtf8,
|
fromUtf8,
|
||||||
|
@ -33,6 +34,13 @@ interface Str
|
||||||
toU8,
|
toU8,
|
||||||
toI8,
|
toI8,
|
||||||
toScalars,
|
toScalars,
|
||||||
|
splitFirst,
|
||||||
|
splitLast,
|
||||||
|
walkUtf8WithIndex,
|
||||||
|
reserve,
|
||||||
|
appendScalar,
|
||||||
|
walkScalars,
|
||||||
|
walkScalarsUntil,
|
||||||
]
|
]
|
||||||
imports [Bool.{ Bool }, Result.{ Result }]
|
imports [Bool.{ Bool }, Result.{ Result }]
|
||||||
|
|
||||||
|
@ -221,3 +229,169 @@ toU16 : Str -> Result U16 [InvalidNumStr]*
|
||||||
toI16 : Str -> Result I16 [InvalidNumStr]*
|
toI16 : Str -> Result I16 [InvalidNumStr]*
|
||||||
toU8 : Str -> Result U8 [InvalidNumStr]*
|
toU8 : Str -> Result U8 [InvalidNumStr]*
|
||||||
toI8 : Str -> Result I8 [InvalidNumStr]*
|
toI8 : Str -> Result I8 [InvalidNumStr]*
|
||||||
|
|
||||||
|
## Gets the byte at the given index, without performing a bounds check
|
||||||
|
getUnsafe : Str, Nat -> U8
|
||||||
|
|
||||||
|
## gives the number of string bytes
|
||||||
|
countUtf8Bytes : Str -> Nat
|
||||||
|
|
||||||
|
## string slice that does not do bounds checking or utf-8 verification
|
||||||
|
substringUnsafe : Str, Nat, Nat -> Str
|
||||||
|
|
||||||
|
## Returns the string before the first occurrence of a delimiter, as well as the
|
||||||
|
## rest of the string after that occurrence. If the delimiter is not found, returns `Err`.
|
||||||
|
##
|
||||||
|
## Str.splitFirst "foo/bar/baz" "/" == Ok { before: "foo", after: "bar/baz" }
|
||||||
|
splitFirst : Str, Str -> Result { before : Str, after : Str } [NotFound]*
|
||||||
|
splitFirst = \haystack, needle ->
|
||||||
|
when firstMatch haystack needle is
|
||||||
|
Some index ->
|
||||||
|
remaining = Str.countUtf8Bytes haystack - Str.countUtf8Bytes needle - index
|
||||||
|
|
||||||
|
before = Str.substringUnsafe haystack 0 index
|
||||||
|
after = Str.substringUnsafe haystack (index + Str.countUtf8Bytes needle) remaining
|
||||||
|
|
||||||
|
Ok { before, after }
|
||||||
|
None ->
|
||||||
|
Err NotFound
|
||||||
|
|
||||||
|
firstMatch : Str, Str -> [Some Nat, None]
|
||||||
|
firstMatch = \haystack, needle ->
|
||||||
|
haystackLength = Str.countUtf8Bytes haystack
|
||||||
|
needleLength = Str.countUtf8Bytes needle
|
||||||
|
lastPossible = Num.subSaturated haystackLength needleLength
|
||||||
|
|
||||||
|
firstMatchHelp haystack needle 0 lastPossible
|
||||||
|
|
||||||
|
firstMatchHelp : Str, Str, Nat, Nat -> [Some Nat, None]
|
||||||
|
firstMatchHelp = \haystack, needle, index, lastPossible ->
|
||||||
|
if index < lastPossible then
|
||||||
|
if matchesAt haystack index needle then
|
||||||
|
Some index
|
||||||
|
else
|
||||||
|
firstMatchHelp haystack needle (index + 1) lastPossible
|
||||||
|
else
|
||||||
|
None
|
||||||
|
|
||||||
|
## Returns the string before the last occurrence of a delimiter, as well as the
|
||||||
|
## rest of the string after that occurrence. If the delimiter is not found, returns `Err`.
|
||||||
|
##
|
||||||
|
## Str.splitLast "foo/bar/baz" "/" == Ok { before: "foo/bar", after: "baz" }
|
||||||
|
splitLast : Str, Str -> Result { before : Str, after : Str } [NotFound]*
|
||||||
|
splitLast = \haystack, needle ->
|
||||||
|
when lastMatch haystack needle is
|
||||||
|
Some index ->
|
||||||
|
remaining = Str.countUtf8Bytes haystack - Str.countUtf8Bytes needle - index
|
||||||
|
|
||||||
|
before = Str.substringUnsafe haystack 0 index
|
||||||
|
after = Str.substringUnsafe haystack (index + Str.countUtf8Bytes needle) remaining
|
||||||
|
|
||||||
|
Ok { before, after }
|
||||||
|
None ->
|
||||||
|
Err NotFound
|
||||||
|
|
||||||
|
lastMatch : Str, Str -> [Some Nat, None]
|
||||||
|
lastMatch = \haystack, needle ->
|
||||||
|
haystackLength = Str.countUtf8Bytes haystack
|
||||||
|
needleLength = Str.countUtf8Bytes needle
|
||||||
|
lastPossibleIndex = Num.subSaturated haystackLength (needleLength + 1)
|
||||||
|
|
||||||
|
lastMatchHelp haystack needle lastPossibleIndex
|
||||||
|
|
||||||
|
lastMatchHelp : Str, Str, Nat -> [Some Nat, None]
|
||||||
|
lastMatchHelp = \haystack, needle, index ->
|
||||||
|
if matchesAt haystack index needle then
|
||||||
|
Some index
|
||||||
|
else
|
||||||
|
when Num.subChecked index 1 is
|
||||||
|
Ok nextIndex ->
|
||||||
|
lastMatchHelp haystack needle nextIndex
|
||||||
|
Err _ ->
|
||||||
|
None
|
||||||
|
|
||||||
|
min = \x, y -> if x < y then x else y
|
||||||
|
|
||||||
|
matchesAt : Str, Nat, Str -> Bool
|
||||||
|
matchesAt = \haystack, haystackIndex, needle ->
|
||||||
|
haystackLength = Str.countUtf8Bytes haystack
|
||||||
|
needleLength = Str.countUtf8Bytes needle
|
||||||
|
endIndex = min (haystackIndex + needleLength) haystackLength
|
||||||
|
|
||||||
|
matchesAtHelp haystack haystackIndex needle 0 endIndex
|
||||||
|
|
||||||
|
matchesAtHelp : Str, Nat, Str, Nat, Nat -> Bool
|
||||||
|
matchesAtHelp = \haystack, haystackIndex, needle, needleIndex, endIndex ->
|
||||||
|
if haystackIndex < endIndex then
|
||||||
|
if Str.getUnsafe haystack haystackIndex == Str.getUnsafe needle needleIndex then
|
||||||
|
matchesAtHelp haystack (haystackIndex + 1) needle (needleIndex + 1) endIndex
|
||||||
|
else
|
||||||
|
False
|
||||||
|
else
|
||||||
|
True
|
||||||
|
|
||||||
|
## Walks over the string's UTF-8 bytes, calling a function which updates a state using each
|
||||||
|
## UTF-8 `U8` byte as well as the index of that byte within the string.
|
||||||
|
walkUtf8WithIndex : Str, state, (state, U8, Nat -> state) -> state
|
||||||
|
walkUtf8WithIndex = \string, state, step ->
|
||||||
|
walkUtf8WithIndexHelp string state step 0 (Str.countUtf8Bytes string)
|
||||||
|
|
||||||
|
walkUtf8WithIndexHelp : Str, state, (state, U8, Nat -> state), Nat, Nat -> state
|
||||||
|
walkUtf8WithIndexHelp = \string, state, step, index, length ->
|
||||||
|
if index < length then
|
||||||
|
byte = Str.getUnsafe string index
|
||||||
|
newState = step state byte index
|
||||||
|
|
||||||
|
walkUtf8WithIndexHelp string newState step (index + 1) length
|
||||||
|
else
|
||||||
|
state
|
||||||
|
|
||||||
|
## Make sure at least some number of bytes fit in this string without reallocating
|
||||||
|
reserve : Str, Nat -> Str
|
||||||
|
|
||||||
|
## is UB when the scalar is invalid
|
||||||
|
appendScalarUnsafe : Str, U32 -> Str
|
||||||
|
|
||||||
|
appendScalar : Str, U32 -> Result Str [InvalidScalar]*
|
||||||
|
appendScalar = \string, scalar ->
|
||||||
|
if isValidScalar scalar then
|
||||||
|
Ok (appendScalarUnsafe string scalar)
|
||||||
|
else
|
||||||
|
Err InvalidScalar
|
||||||
|
|
||||||
|
isValidScalar : U32 -> Bool
|
||||||
|
isValidScalar = \scalar ->
|
||||||
|
scalar <= 0xD7FF || (scalar >= 0xE000 && scalar <= 0x10FFFF)
|
||||||
|
|
||||||
|
getScalarUnsafe : Str, Nat -> { scalar : U32, bytesParsed : Nat }
|
||||||
|
|
||||||
|
walkScalars : Str, state, (state, U32 -> state) -> state
|
||||||
|
walkScalars = \string, init, step ->
|
||||||
|
walkScalarsHelp string init step 0 (Str.countUtf8Bytes string)
|
||||||
|
|
||||||
|
walkScalarsHelp : Str, state, (state, U32 -> state), Nat, Nat -> state
|
||||||
|
walkScalarsHelp = \string, state, step, index, length ->
|
||||||
|
if index < length then
|
||||||
|
{ scalar, bytesParsed } = getScalarUnsafe string index
|
||||||
|
newState = step state scalar
|
||||||
|
|
||||||
|
walkScalarsHelp string newState step (index + bytesParsed) length
|
||||||
|
else
|
||||||
|
state
|
||||||
|
|
||||||
|
walkScalarsUntil : Str, state, (state, U32 -> [Break state, Continue state]) -> state
|
||||||
|
walkScalarsUntil = \string, init, step ->
|
||||||
|
walkScalarsUntilHelp string init step 0 (Str.countUtf8Bytes string)
|
||||||
|
|
||||||
|
walkScalarsUntilHelp : Str, state, (state, U32 -> [Break state, Continue state]), Nat, Nat -> state
|
||||||
|
walkScalarsUntilHelp = \string, state, step, index, length ->
|
||||||
|
if index < length then
|
||||||
|
{ scalar, bytesParsed } = getScalarUnsafe string index
|
||||||
|
|
||||||
|
when step state scalar is
|
||||||
|
Continue newState ->
|
||||||
|
walkScalarsUntilHelp string newState step (index + bytesParsed) length
|
||||||
|
Break newState ->
|
||||||
|
newState
|
||||||
|
else
|
||||||
|
state
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub enum DecWidth {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
|
||||||
pub enum FloatWidth {
|
pub enum FloatWidth {
|
||||||
F32,
|
F32,
|
||||||
F64,
|
F64,
|
||||||
|
@ -76,7 +76,7 @@ impl FloatWidth {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
|
||||||
pub enum IntWidth {
|
pub enum IntWidth {
|
||||||
U8 = 0,
|
U8 = 0,
|
||||||
U16 = 1,
|
U16 = 1,
|
||||||
|
@ -310,9 +310,11 @@ pub const STR_INIT: &str = "roc_builtins.str.init";
|
||||||
pub const STR_COUNT_SEGMENTS: &str = "roc_builtins.str.count_segments";
|
pub const STR_COUNT_SEGMENTS: &str = "roc_builtins.str.count_segments";
|
||||||
pub const STR_CONCAT: &str = "roc_builtins.str.concat";
|
pub const STR_CONCAT: &str = "roc_builtins.str.concat";
|
||||||
pub const STR_JOIN_WITH: &str = "roc_builtins.str.joinWith";
|
pub const STR_JOIN_WITH: &str = "roc_builtins.str.joinWith";
|
||||||
|
pub const STR_STR_SPLIT: &str = "roc_builtins.str.str_split";
|
||||||
pub const STR_STR_SPLIT_IN_PLACE: &str = "roc_builtins.str.str_split_in_place";
|
pub const STR_STR_SPLIT_IN_PLACE: &str = "roc_builtins.str.str_split_in_place";
|
||||||
pub const STR_TO_SCALARS: &str = "roc_builtins.str.to_scalars";
|
pub const STR_TO_SCALARS: &str = "roc_builtins.str.to_scalars";
|
||||||
pub const STR_COUNT_GRAPEHEME_CLUSTERS: &str = "roc_builtins.str.count_grapheme_clusters";
|
pub const STR_COUNT_GRAPEHEME_CLUSTERS: &str = "roc_builtins.str.count_grapheme_clusters";
|
||||||
|
pub const STR_COUNT_UTF8_BYTES: &str = "roc_builtins.str.count_utf8_bytes";
|
||||||
pub const STR_STARTS_WITH: &str = "roc_builtins.str.starts_with";
|
pub const STR_STARTS_WITH: &str = "roc_builtins.str.starts_with";
|
||||||
pub const STR_STARTS_WITH_SCALAR: &str = "roc_builtins.str.starts_with_scalar";
|
pub const STR_STARTS_WITH_SCALAR: &str = "roc_builtins.str.starts_with_scalar";
|
||||||
pub const STR_ENDS_WITH: &str = "roc_builtins.str.ends_with";
|
pub const STR_ENDS_WITH: &str = "roc_builtins.str.ends_with";
|
||||||
|
@ -323,6 +325,7 @@ pub const STR_TO_INT: IntrinsicName = int_intrinsic!("roc_builtins.str.to_int");
|
||||||
pub const STR_TO_FLOAT: IntrinsicName = float_intrinsic!("roc_builtins.str.to_float");
|
pub const STR_TO_FLOAT: IntrinsicName = float_intrinsic!("roc_builtins.str.to_float");
|
||||||
pub const STR_TO_DECIMAL: &str = "roc_builtins.str.to_decimal";
|
pub const STR_TO_DECIMAL: &str = "roc_builtins.str.to_decimal";
|
||||||
pub const STR_EQUAL: &str = "roc_builtins.str.equal";
|
pub const STR_EQUAL: &str = "roc_builtins.str.equal";
|
||||||
|
pub const STR_SUBSTRING_UNSAFE: &str = "roc_builtins.str.substring_unsafe";
|
||||||
pub const STR_TO_UTF8: &str = "roc_builtins.str.to_utf8";
|
pub const STR_TO_UTF8: &str = "roc_builtins.str.to_utf8";
|
||||||
pub const STR_FROM_UTF8: &str = "roc_builtins.str.from_utf8";
|
pub const STR_FROM_UTF8: &str = "roc_builtins.str.from_utf8";
|
||||||
pub const STR_FROM_UTF8_RANGE: &str = "roc_builtins.str.from_utf8_range";
|
pub const STR_FROM_UTF8_RANGE: &str = "roc_builtins.str.from_utf8_range";
|
||||||
|
@ -330,6 +333,10 @@ pub const STR_REPEAT: &str = "roc_builtins.str.repeat";
|
||||||
pub const STR_TRIM: &str = "roc_builtins.str.trim";
|
pub const STR_TRIM: &str = "roc_builtins.str.trim";
|
||||||
pub const STR_TRIM_LEFT: &str = "roc_builtins.str.trim_left";
|
pub const STR_TRIM_LEFT: &str = "roc_builtins.str.trim_left";
|
||||||
pub const STR_TRIM_RIGHT: &str = "roc_builtins.str.trim_right";
|
pub const STR_TRIM_RIGHT: &str = "roc_builtins.str.trim_right";
|
||||||
|
pub const STR_GET_UNSAFE: &str = "roc_builtins.str.get_unsafe";
|
||||||
|
pub const STR_RESERVE: &str = "roc_builtins.str.reserve";
|
||||||
|
pub const STR_APPEND_SCALAR: &str = "roc_builtins.str.append_scalar";
|
||||||
|
pub const STR_GET_SCALAR_UNSAFE: &str = "roc_builtins.str.get_scalar_unsafe";
|
||||||
|
|
||||||
pub const DICT_HASH: &str = "roc_builtins.dict.hash";
|
pub const DICT_HASH: &str = "roc_builtins.dict.hash";
|
||||||
pub const DICT_HASH_STR: &str = "roc_builtins.dict.hash_str";
|
pub const DICT_HASH_STR: &str = "roc_builtins.dict.hash_str";
|
||||||
|
@ -353,7 +360,6 @@ pub const LIST_MAP: &str = "roc_builtins.list.map";
|
||||||
pub const LIST_MAP2: &str = "roc_builtins.list.map2";
|
pub const LIST_MAP2: &str = "roc_builtins.list.map2";
|
||||||
pub const LIST_MAP3: &str = "roc_builtins.list.map3";
|
pub const LIST_MAP3: &str = "roc_builtins.list.map3";
|
||||||
pub const LIST_MAP4: &str = "roc_builtins.list.map4";
|
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_APPEND: &str = "roc_builtins.list.append";
|
pub const LIST_APPEND: &str = "roc_builtins.list.append";
|
||||||
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
|
pub const LIST_PREPEND: &str = "roc_builtins.list.prepend";
|
||||||
pub const LIST_SUBLIST: &str = "roc_builtins.list.sublist";
|
pub const LIST_SUBLIST: &str = "roc_builtins.list.sublist";
|
||||||
|
|
|
@ -74,12 +74,18 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
||||||
STR_CONCAT => str_concat,
|
STR_CONCAT => str_concat,
|
||||||
STR_JOIN_WITH => str_join_with,
|
STR_JOIN_WITH => str_join_with,
|
||||||
STR_TO_SCALARS => str_to_scalars,
|
STR_TO_SCALARS => str_to_scalars,
|
||||||
|
STR_GET_UNSAFE => str_get_unsafe,
|
||||||
STR_SPLIT => str_split,
|
STR_SPLIT => str_split,
|
||||||
STR_IS_EMPTY => str_is_empty,
|
STR_IS_EMPTY => str_is_empty,
|
||||||
STR_STARTS_WITH => str_starts_with,
|
STR_STARTS_WITH => str_starts_with,
|
||||||
STR_STARTS_WITH_SCALAR => str_starts_with_scalar,
|
STR_STARTS_WITH_SCALAR => str_starts_with_scalar,
|
||||||
STR_ENDS_WITH => str_ends_with,
|
STR_ENDS_WITH => str_ends_with,
|
||||||
STR_COUNT_GRAPHEMES => str_count_graphemes,
|
STR_COUNT_GRAPHEMES => str_count_graphemes,
|
||||||
|
STR_COUNT_UTF8_BYTES => str_count_bytes,
|
||||||
|
STR_SUBSTRING_UNSAFE => str_substring_unsafe,
|
||||||
|
STR_RESERVE => str_reserve,
|
||||||
|
STR_APPEND_SCALAR_UNSAFE => str_append_scalar_unsafe,
|
||||||
|
STR_GET_SCALAR_UNSAFE => str_get_scalar_unsafe,
|
||||||
STR_FROM_UTF8 => str_from_utf8,
|
STR_FROM_UTF8 => str_from_utf8,
|
||||||
STR_FROM_UTF8_RANGE => str_from_utf8_range,
|
STR_FROM_UTF8_RANGE => str_from_utf8_range,
|
||||||
STR_TO_UTF8 => str_to_utf8,
|
STR_TO_UTF8 => str_to_utf8,
|
||||||
|
@ -118,7 +124,6 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
||||||
LIST_DROP => list_drop,
|
LIST_DROP => list_drop,
|
||||||
LIST_DROP_AT => list_drop_at,
|
LIST_DROP_AT => list_drop_at,
|
||||||
LIST_SWAP => list_swap,
|
LIST_SWAP => list_swap,
|
||||||
LIST_MAP_WITH_INDEX => list_map_with_index,
|
|
||||||
LIST_SORT_WITH => list_sort_with,
|
LIST_SORT_WITH => list_sort_with,
|
||||||
LIST_IS_UNIQUE => list_is_unique,
|
LIST_IS_UNIQUE => list_is_unique,
|
||||||
DICT_LEN => dict_len,
|
DICT_LEN => dict_len,
|
||||||
|
@ -1669,67 +1674,24 @@ fn str_concat(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List.getUnsafe : Str, Nat -> U8
|
||||||
|
fn str_get_unsafe(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
lowlevel_2(symbol, LowLevel::StrGetUnsafe, var_store)
|
||||||
|
}
|
||||||
|
|
||||||
/// Str.toScalars : Str -> List U32
|
/// Str.toScalars : Str -> List U32
|
||||||
fn str_to_scalars(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn str_to_scalars(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let str_var = var_store.fresh();
|
lowlevel_1(symbol, LowLevel::StrToScalars, var_store)
|
||||||
let list_u32_var = var_store.fresh();
|
|
||||||
|
|
||||||
let body = RunLowLevel {
|
|
||||||
op: LowLevel::StrToScalars,
|
|
||||||
args: vec![(str_var, Var(Symbol::ARG_1))],
|
|
||||||
ret_var: list_u32_var,
|
|
||||||
};
|
|
||||||
|
|
||||||
defn(
|
|
||||||
symbol,
|
|
||||||
vec![(str_var, Symbol::ARG_1)],
|
|
||||||
var_store,
|
|
||||||
body,
|
|
||||||
list_u32_var,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Str.joinWith : List Str, Str -> Str
|
/// Str.joinWith : List Str, Str -> Str
|
||||||
fn str_join_with(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn str_join_with(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let list_str_var = var_store.fresh();
|
lowlevel_2(symbol, LowLevel::StrJoinWith, var_store)
|
||||||
let str_var = var_store.fresh();
|
|
||||||
|
|
||||||
let body = RunLowLevel {
|
|
||||||
op: LowLevel::StrJoinWith,
|
|
||||||
args: vec![
|
|
||||||
(list_str_var, Var(Symbol::ARG_1)),
|
|
||||||
(str_var, Var(Symbol::ARG_2)),
|
|
||||||
],
|
|
||||||
ret_var: str_var,
|
|
||||||
};
|
|
||||||
|
|
||||||
defn(
|
|
||||||
symbol,
|
|
||||||
vec![(list_str_var, Symbol::ARG_1), (str_var, Symbol::ARG_2)],
|
|
||||||
var_store,
|
|
||||||
body,
|
|
||||||
str_var,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Str.isEmpty : Str -> Bool
|
/// Str.isEmpty : Str -> Bool
|
||||||
fn str_is_empty(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn str_is_empty(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let str_var = var_store.fresh();
|
lowlevel_1(symbol, LowLevel::StrIsEmpty, var_store)
|
||||||
let bool_var = var_store.fresh();
|
|
||||||
|
|
||||||
let body = RunLowLevel {
|
|
||||||
op: LowLevel::StrIsEmpty,
|
|
||||||
args: vec![(str_var, Var(Symbol::ARG_1))],
|
|
||||||
ret_var: bool_var,
|
|
||||||
};
|
|
||||||
|
|
||||||
defn(
|
|
||||||
symbol,
|
|
||||||
vec![(str_var, Symbol::ARG_1)],
|
|
||||||
var_store,
|
|
||||||
body,
|
|
||||||
bool_var,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Str.startsWith : Str, Str -> Bool
|
/// Str.startsWith : Str, Str -> Bool
|
||||||
|
@ -1764,22 +1726,32 @@ fn str_ends_with(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
|
||||||
/// Str.countGraphemes : Str -> Int
|
/// Str.countGraphemes : Str -> Int
|
||||||
fn str_count_graphemes(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn str_count_graphemes(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let str_var = var_store.fresh();
|
lowlevel_1(symbol, LowLevel::StrCountGraphemes, var_store)
|
||||||
let int_var = var_store.fresh();
|
}
|
||||||
|
|
||||||
let body = RunLowLevel {
|
/// Str.countUtf8Bytes : Str -> Nat
|
||||||
op: LowLevel::StrCountGraphemes,
|
fn str_count_bytes(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
args: vec![(str_var, Var(Symbol::ARG_1))],
|
lowlevel_1(symbol, LowLevel::StrCountUtf8Bytes, var_store)
|
||||||
ret_var: int_var,
|
}
|
||||||
};
|
|
||||||
|
|
||||||
defn(
|
/// Str.substringUnsafe : Str, Nat, Nat -> Nat
|
||||||
symbol,
|
fn str_substring_unsafe(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
vec![(str_var, Symbol::ARG_1)],
|
lowlevel_3(symbol, LowLevel::StrSubstringUnsafe, var_store)
|
||||||
var_store,
|
}
|
||||||
body,
|
|
||||||
int_var,
|
/// Str.reserve : Str, Nat -> Str
|
||||||
)
|
fn str_reserve(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
lowlevel_2(symbol, LowLevel::StrReserve, var_store)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Str.appendScalarUnsafe : Str, U32 -> Str
|
||||||
|
fn str_append_scalar_unsafe(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
lowlevel_2(symbol, LowLevel::StrAppendScalar, var_store)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Str.getScalarUnsafe : Str, Nat -> { scalar : U32, bytesParsed : Nat }
|
||||||
|
fn str_get_scalar_unsafe(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
lowlevel_2(symbol, LowLevel::StrGetScalarUnsafe, var_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Str.fromUtf8 : List U8 -> Result Str [BadUtf8 { byteIndex : Nat, problem : Utf8Problem } }]*
|
/// Str.fromUtf8 : List U8 -> Result Str [BadUtf8 { byteIndex : Nat, problem : Utf8Problem } }]*
|
||||||
|
@ -1803,7 +1775,7 @@ fn str_from_utf8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
// Ok arg_2.str
|
// Ok arg_2.str
|
||||||
// else
|
// else
|
||||||
// # problem
|
// # problem
|
||||||
// Err (BadUtf8 { byteIndex: arg_2.byteIndex, problem : arg_2.problem })
|
// Err (BadUtf8 arg_2.problem arg_2.byteIndex)
|
||||||
|
|
||||||
let def = crate::def::Def {
|
let def = crate::def::Def {
|
||||||
loc_pattern: no_region(Pattern::Identifier(Symbol::ARG_2)),
|
loc_pattern: no_region(Pattern::Identifier(Symbol::ARG_2)),
|
||||||
|
@ -1905,7 +1877,7 @@ fn str_from_utf8_range(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
// if arg_3.a then
|
// if arg_3.a then
|
||||||
// Ok arg_3.str
|
// Ok arg_3.str
|
||||||
// else
|
// else
|
||||||
// Err (BadUtf8 { byteIndex: arg_3.byteIndex, problem : arg_3.problem })
|
// Err (BadUtf8 arg_3.problem arg_3.byteIndex)
|
||||||
|
|
||||||
let def = crate::def::Def {
|
let def = crate::def::Def {
|
||||||
loc_pattern: no_region(Pattern::Identifier(Symbol::ARG_3)),
|
loc_pattern: no_region(Pattern::Identifier(Symbol::ARG_3)),
|
||||||
|
@ -2392,11 +2364,6 @@ fn list_map(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_2(symbol, LowLevel::ListMap, var_store)
|
lowlevel_2(symbol, LowLevel::ListMap, var_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List.mapWithIndex : List before, (before, Nat -> after) -> List after
|
|
||||||
fn list_map_with_index(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
lowlevel_2(symbol, LowLevel::ListMapWithIndex, var_store)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List.map2 : List a, List b, (a, b -> c) -> List c
|
/// List.map2 : List a, List b, (a, b -> c) -> List c
|
||||||
fn list_map2(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn list_map2(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_3(symbol, LowLevel::ListMap2, var_store)
|
lowlevel_3(symbol, LowLevel::ListMap2, var_store)
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::annotation::make_apply_symbol;
|
||||||
use crate::annotation::IntroducedVariables;
|
use crate::annotation::IntroducedVariables;
|
||||||
use crate::annotation::OwnedNamedOrAble;
|
use crate::annotation::OwnedNamedOrAble;
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
|
use crate::expr::AccessorData;
|
||||||
use crate::expr::AnnotatedMark;
|
use crate::expr::AnnotatedMark;
|
||||||
use crate::expr::ClosureData;
|
use crate::expr::ClosureData;
|
||||||
use crate::expr::Declarations;
|
use crate::expr::Declarations;
|
||||||
|
@ -1554,7 +1555,10 @@ fn canonicalize_pending_value_def<'a>(
|
||||||
region: loc_ann.region,
|
region: loc_ann.region,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let symbol = scope.gen_unique_symbol();
|
let symbol = match &loc_can_pattern.value {
|
||||||
|
Pattern::Identifier(symbol) => *symbol,
|
||||||
|
_ => scope.gen_unique_symbol(),
|
||||||
|
};
|
||||||
|
|
||||||
// generate a fake pattern for each argument. this makes signatures
|
// generate a fake pattern for each argument. this makes signatures
|
||||||
// that are functions only crash when they are applied.
|
// that are functions only crash when they are applied.
|
||||||
|
@ -1725,6 +1729,36 @@ fn canonicalize_pending_body<'a>(
|
||||||
(loc_can_expr, def_references)
|
(loc_can_expr, def_references)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Turn f = .foo into f = \rcd -[f]-> rcd.foo
|
||||||
|
(
|
||||||
|
Pattern::Identifier(defined_symbol)
|
||||||
|
| Pattern::AbilityMemberSpecialization {
|
||||||
|
ident: defined_symbol,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
ast::Expr::AccessorFunction(field),
|
||||||
|
) => {
|
||||||
|
let (loc_can_expr, can_output) = (
|
||||||
|
Loc::at(
|
||||||
|
loc_expr.region,
|
||||||
|
Accessor(AccessorData {
|
||||||
|
name: *defined_symbol,
|
||||||
|
function_var: var_store.fresh(),
|
||||||
|
record_var: var_store.fresh(),
|
||||||
|
ext_var: var_store.fresh(),
|
||||||
|
closure_var: var_store.fresh(),
|
||||||
|
field_var: var_store.fresh(),
|
||||||
|
field: (*field).into(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Output::default(),
|
||||||
|
);
|
||||||
|
let def_references = DefReferences::Value(can_output.references.clone());
|
||||||
|
output.union(can_output);
|
||||||
|
|
||||||
|
(loc_can_expr, def_references)
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let (loc_can_expr, can_output) =
|
let (loc_can_expr, can_output) =
|
||||||
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
|
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
|
||||||
|
|
|
@ -29,7 +29,7 @@ impl Length {
|
||||||
} else if self.0 > 0 {
|
} else if self.0 > 0 {
|
||||||
Kind::Interned(self.0 as usize)
|
Kind::Interned(self.0 as usize)
|
||||||
} else {
|
} else {
|
||||||
Kind::Generated(self.0.abs() as usize)
|
Kind::Generated(self.0.unsigned_abs() as usize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,10 @@ impl<K: PartialEq, V> VecMap<K, V> {
|
||||||
self.keys.iter().zip(self.values.iter())
|
self.keys.iter().zip(self.values.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iter_mut(&mut self) -> impl ExactSizeIterator<Item = (&K, &mut V)> {
|
||||||
|
self.keys.iter().zip(self.values.iter_mut())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn keys(&self) -> impl ExactSizeIterator<Item = &K> {
|
pub fn keys(&self) -> impl ExactSizeIterator<Item = &K> {
|
||||||
self.keys.iter()
|
self.keys.iter()
|
||||||
}
|
}
|
||||||
|
|
|
@ -699,25 +699,44 @@ fn fmt_when<'a, 'buf>(
|
||||||
buf.push_str("is");
|
buf.push_str("is");
|
||||||
buf.newline();
|
buf.newline();
|
||||||
|
|
||||||
let mut it = branches.iter().peekable();
|
let mut it = branches.iter().enumerate().peekable();
|
||||||
while let Some(branch) = it.next() {
|
|
||||||
|
while let Some((branch_index, branch)) = it.next() {
|
||||||
let expr = &branch.value;
|
let expr = &branch.value;
|
||||||
let patterns = &branch.patterns;
|
let patterns = &branch.patterns;
|
||||||
let is_multiline_expr = expr.is_multiline();
|
let is_multiline_expr = expr.is_multiline();
|
||||||
let is_multiline_patterns = is_when_patterns_multiline(branch);
|
let is_multiline_patterns = is_when_patterns_multiline(branch);
|
||||||
|
|
||||||
for (index, pattern) in patterns.iter().enumerate() {
|
for (index, pattern) in patterns.iter().enumerate() {
|
||||||
if index != 0 {
|
if index == 0 {
|
||||||
|
match &pattern.value {
|
||||||
|
Pattern::SpaceBefore(sub_pattern, spaces) if branch_index == 0 => {
|
||||||
|
// Never include extra newlines before the first branch.
|
||||||
|
// Instead, write the comments and that's it.
|
||||||
|
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent + INDENT);
|
||||||
|
|
||||||
|
fmt_pattern(buf, sub_pattern, indent + INDENT, Parens::NotNeeded);
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
fmt_pattern(buf, other, indent + INDENT, Parens::NotNeeded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if is_multiline_patterns {
|
if is_multiline_patterns {
|
||||||
buf.newline();
|
buf.ensure_ends_in_newline();
|
||||||
buf.indent(indent + INDENT);
|
// Indent an extra level for the `|`;
|
||||||
|
// otherwise it'll be at the start of the line,
|
||||||
|
// and will be incorrectly parsed as a pattern
|
||||||
|
buf.indent(indent + INDENT + INDENT);
|
||||||
|
buf.push('|');
|
||||||
|
} else {
|
||||||
|
buf.push_str(" |");
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.push_str(" |");
|
|
||||||
buf.spaces(1);
|
buf.spaces(1);
|
||||||
}
|
|
||||||
|
|
||||||
fmt_pattern(buf, &pattern.value, indent + INDENT, Parens::NotNeeded);
|
fmt_pattern(buf, &pattern.value, indent + INDENT, Parens::NotNeeded);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(guard_expr) = &branch.guard {
|
if let Some(guard_expr) = &branch.guard {
|
||||||
|
|
|
@ -89,6 +89,14 @@ impl<'a> Buf<'a> {
|
||||||
self.beginning_of_line = true;
|
self.beginning_of_line = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensures the current buffer ends in a newline, if it didn't already.
|
||||||
|
/// Doesn't add a newline if the buffer already ends in one.
|
||||||
|
pub fn ensure_ends_in_newline(&mut self) {
|
||||||
|
if !self.text.ends_with('\n') {
|
||||||
|
self.newline()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn flush_spaces(&mut self) {
|
fn flush_spaces(&mut self) {
|
||||||
if self.spaces_to_flush > 0 {
|
if self.spaces_to_flush > 0 {
|
||||||
for _ in 0..self.spaces_to_flush {
|
for _ in 0..self.spaces_to_flush {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::annotation::{Formattable, Newlines, Parens};
|
use crate::annotation::{Formattable, Newlines, Parens};
|
||||||
use crate::spaces::{fmt_comments_only, fmt_spaces, NewlineAt};
|
use crate::spaces::{fmt_comments_only, fmt_spaces, NewlineAt};
|
||||||
use crate::Buf;
|
use crate::Buf;
|
||||||
use roc_parse::ast::{Base, Pattern};
|
use roc_parse::ast::{Base, CommentOrNewline, Pattern};
|
||||||
|
|
||||||
pub fn fmt_pattern<'a, 'buf>(
|
pub fn fmt_pattern<'a, 'buf>(
|
||||||
buf: &mut Buf<'buf>,
|
buf: &mut Buf<'buf>,
|
||||||
|
@ -167,11 +167,16 @@ impl<'a> Formattable for Pattern<'a> {
|
||||||
} else {
|
} else {
|
||||||
fmt_spaces(buf, spaces.iter(), indent);
|
fmt_spaces(buf, spaces.iter(), indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub_pattern.format_with_options(buf, parens, newlines, indent);
|
sub_pattern.format_with_options(buf, parens, newlines, indent);
|
||||||
}
|
}
|
||||||
SpaceAfter(sub_pattern, spaces) => {
|
SpaceAfter(sub_pattern, spaces) => {
|
||||||
sub_pattern.format_with_options(buf, parens, newlines, indent);
|
sub_pattern.format_with_options(buf, parens, newlines, indent);
|
||||||
// if only_comments {
|
|
||||||
|
if starts_with_inline_comment(spaces.iter()) {
|
||||||
|
buf.spaces(1);
|
||||||
|
}
|
||||||
|
|
||||||
if !sub_pattern.is_multiline() {
|
if !sub_pattern.is_multiline() {
|
||||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent)
|
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent)
|
||||||
} else {
|
} else {
|
||||||
|
@ -196,3 +201,12 @@ impl<'a> Formattable for Pattern<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn starts_with_inline_comment<'a, I: IntoIterator<Item = &'a CommentOrNewline<'a>>>(
|
||||||
|
spaces: I,
|
||||||
|
) -> bool {
|
||||||
|
matches!(
|
||||||
|
spaces.into_iter().next(),
|
||||||
|
Some(CommentOrNewline::LineComment(_))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -3373,6 +3373,18 @@ mod test_fmt {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn when_with_integer_comments() {
|
||||||
|
expr_formats_same(indoc!(
|
||||||
|
r#"
|
||||||
|
when 0 is
|
||||||
|
1 # comment
|
||||||
|
| 2 -> "a"
|
||||||
|
_ -> "b"
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nested_when() {
|
fn nested_when() {
|
||||||
expr_formats_same(indoc!(
|
expr_formats_same(indoc!(
|
||||||
|
@ -3465,18 +3477,18 @@ mod test_fmt {
|
||||||
r#"
|
r#"
|
||||||
when b is
|
when b is
|
||||||
1
|
1
|
||||||
| 2
|
| 2
|
||||||
| 3 ->
|
| 3 ->
|
||||||
4
|
4
|
||||||
5 | 6 | 7 ->
|
5 | 6 | 7 ->
|
||||||
8
|
8
|
||||||
9
|
9
|
||||||
| 10 -> 11
|
| 10 -> 11
|
||||||
12 | 13 ->
|
12 | 13 ->
|
||||||
when c is
|
when c is
|
||||||
14 | 15 -> 16
|
14 | 15 -> 16
|
||||||
17
|
17
|
||||||
| 18 -> 19
|
| 18 -> 19
|
||||||
20 -> 21
|
20 -> 21
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
@ -3498,7 +3510,7 @@ mod test_fmt {
|
||||||
when b is
|
when b is
|
||||||
3 -> 4
|
3 -> 4
|
||||||
9
|
9
|
||||||
| 8 -> 9
|
| 8 -> 9
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,9 +14,7 @@ use roc_mono::ir::{
|
||||||
BranchInfo, CallType, Expr, JoinPointId, ListLiteralElement, Literal, Param, Proc, ProcLayout,
|
BranchInfo, CallType, Expr, JoinPointId, ListLiteralElement, Literal, Param, Proc, ProcLayout,
|
||||||
SelfRecursive, Stmt,
|
SelfRecursive, Stmt,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{
|
use roc_mono::layout::{Builtin, Layout, LayoutId, LayoutIds, TagIdIntType, UnionLayout};
|
||||||
Builtin, Layout, LayoutId, LayoutIds, TagIdIntType, TagOrClosure, UnionLayout,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod generic64;
|
mod generic64;
|
||||||
mod object_builder;
|
mod object_builder;
|
||||||
|
@ -106,8 +104,8 @@ trait Backend<'a> {
|
||||||
proc: Proc<'a>,
|
proc: Proc<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
) -> (Vec<u8>, Vec<Relocation>, Vec<'a, (Symbol, String)>) {
|
) -> (Vec<u8>, Vec<Relocation>, Vec<'a, (Symbol, String)>) {
|
||||||
let layout_id = layout_ids.get(proc.name, &proc.ret_layout);
|
let layout_id = layout_ids.get(proc.name.name(), &proc.ret_layout);
|
||||||
let proc_name = self.symbol_to_string(proc.name, layout_id);
|
let proc_name = self.symbol_to_string(proc.name.name(), layout_id);
|
||||||
self.reset(proc_name, proc.is_self_recursive);
|
self.reset(proc_name, proc.is_self_recursive);
|
||||||
self.load_args(proc.args, &proc.ret_layout);
|
self.load_args(proc.args, &proc.ret_layout);
|
||||||
for (layout, sym) in proc.args {
|
for (layout, sym) in proc.args {
|
||||||
|
@ -263,7 +261,7 @@ trait Backend<'a> {
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
if let LowLevelWrapperType::CanBeReplacedBy(lowlevel) =
|
if let LowLevelWrapperType::CanBeReplacedBy(lowlevel) =
|
||||||
LowLevelWrapperType::from_symbol(*func_sym)
|
LowLevelWrapperType::from_symbol(func_sym.name())
|
||||||
{
|
{
|
||||||
self.build_run_low_level(
|
self.build_run_low_level(
|
||||||
sym,
|
sym,
|
||||||
|
@ -272,14 +270,20 @@ trait Backend<'a> {
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
ret_layout,
|
ret_layout,
|
||||||
)
|
)
|
||||||
} else if self.defined_in_app_module(*func_sym) {
|
} else if self.defined_in_app_module(func_sym.name()) {
|
||||||
let layout_id = LayoutIds::default().get(*func_sym, layout);
|
let layout_id = LayoutIds::default().get(func_sym.name(), layout);
|
||||||
let fn_name = self.symbol_to_string(*func_sym, layout_id);
|
let fn_name = self.symbol_to_string(func_sym.name(), layout_id);
|
||||||
// Now that the arguments are needed, load them if they are literals.
|
// Now that the arguments are needed, load them if they are literals.
|
||||||
self.load_literal_symbols(arguments);
|
self.load_literal_symbols(arguments);
|
||||||
self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout)
|
self.build_fn_call(sym, fn_name, arguments, arg_layouts, ret_layout)
|
||||||
} else {
|
} else {
|
||||||
self.build_builtin(sym, *func_sym, arguments, arg_layouts, ret_layout)
|
self.build_builtin(
|
||||||
|
sym,
|
||||||
|
func_sym.name(),
|
||||||
|
arguments,
|
||||||
|
arg_layouts,
|
||||||
|
ret_layout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -909,18 +913,9 @@ trait Backend<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Reuse {
|
Expr::Reuse {
|
||||||
symbol,
|
symbol, arguments, ..
|
||||||
arguments,
|
|
||||||
tag_name,
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
self.set_last_seen(*symbol, stmt);
|
self.set_last_seen(*symbol, stmt);
|
||||||
match tag_name {
|
|
||||||
TagOrClosure::Closure(sym) => {
|
|
||||||
self.set_last_seen(*sym, stmt);
|
|
||||||
}
|
|
||||||
TagOrClosure::Tag(_) => {}
|
|
||||||
}
|
|
||||||
for sym in *arguments {
|
for sym in *arguments {
|
||||||
self.set_last_seen(*sym, stmt);
|
self.set_last_seen(*sym, stmt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ use crate::llvm::build_dict::{
|
||||||
use crate::llvm::build_hash::generic_hash;
|
use crate::llvm::build_hash::generic_hash;
|
||||||
use crate::llvm::build_list::{
|
use crate::llvm::build_list::{
|
||||||
self, allocate_list, empty_polymorphic_list, list_append, list_concat, list_drop_at,
|
self, allocate_list, empty_polymorphic_list, list_append, list_concat, list_drop_at,
|
||||||
list_get_unsafe, list_len, list_map, list_map2, list_map3, list_map4, list_map_with_index,
|
list_get_unsafe, list_len, list_map, list_map2, list_map3, list_map4, list_prepend,
|
||||||
list_prepend, list_replace_unsafe, list_sort_with, list_sublist, list_swap,
|
list_replace_unsafe, list_sort_with, list_sublist, list_swap, list_symbol_to_c_abi,
|
||||||
list_symbol_to_c_abi, list_to_c_abi, list_with_capacity,
|
list_to_c_abi, list_with_capacity,
|
||||||
};
|
};
|
||||||
use crate::llvm::build_str::{
|
use crate::llvm::build_str::{
|
||||||
str_from_float, str_from_int, str_from_utf8, str_from_utf8_range, str_split,
|
str_from_float, str_from_int, str_from_utf8, str_from_utf8_range, str_split,
|
||||||
|
@ -62,7 +62,9 @@ use roc_mono::ir::{
|
||||||
BranchInfo, CallType, EntryPoint, HigherOrderLowLevel, JoinPointId, ListLiteralElement,
|
BranchInfo, CallType, EntryPoint, HigherOrderLowLevel, JoinPointId, ListLiteralElement,
|
||||||
ModifyRc, OptLevel, ProcLayout,
|
ModifyRc, OptLevel, ProcLayout,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout};
|
use roc_mono::layout::{
|
||||||
|
Builtin, CapturesNiche, LambdaName, LambdaSet, Layout, LayoutIds, TagIdIntType, UnionLayout,
|
||||||
|
};
|
||||||
use roc_std::RocDec;
|
use roc_std::RocDec;
|
||||||
use roc_target::{PtrWidth, TargetInfo};
|
use roc_target::{PtrWidth, TargetInfo};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
@ -715,7 +717,12 @@ fn promote_to_main_function<'a, 'ctx, 'env>(
|
||||||
top_level: ProcLayout<'a>,
|
top_level: ProcLayout<'a>,
|
||||||
) -> (&'static str, FunctionValue<'ctx>) {
|
) -> (&'static str, FunctionValue<'ctx>) {
|
||||||
let it = top_level.arguments.iter().copied();
|
let it = top_level.arguments.iter().copied();
|
||||||
let bytes = roc_alias_analysis::func_name_bytes_help(symbol, it, &top_level.result);
|
let bytes = roc_alias_analysis::func_name_bytes_help(
|
||||||
|
symbol,
|
||||||
|
it,
|
||||||
|
CapturesNiche::no_niche(),
|
||||||
|
&top_level.result,
|
||||||
|
);
|
||||||
let func_name = FuncName(&bytes);
|
let func_name = FuncName(&bytes);
|
||||||
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
|
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
|
||||||
|
|
||||||
|
@ -727,7 +734,14 @@ fn promote_to_main_function<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
|
|
||||||
// NOTE fake layout; it is only used for debug prints
|
// NOTE fake layout; it is only used for debug prints
|
||||||
let roc_main_fn = function_value_by_func_spec(env, *func_spec, symbol, &[], &Layout::UNIT);
|
let roc_main_fn = function_value_by_func_spec(
|
||||||
|
env,
|
||||||
|
*func_spec,
|
||||||
|
symbol,
|
||||||
|
&[],
|
||||||
|
CapturesNiche::no_niche(),
|
||||||
|
&Layout::UNIT,
|
||||||
|
);
|
||||||
|
|
||||||
let main_fn_name = "$Test.main";
|
let main_fn_name = "$Test.main";
|
||||||
|
|
||||||
|
@ -3296,6 +3310,7 @@ fn expose_function_to_host<'a, 'ctx, 'env>(
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
roc_function: FunctionValue<'ctx>,
|
roc_function: FunctionValue<'ctx>,
|
||||||
arguments: &'a [Layout<'a>],
|
arguments: &'a [Layout<'a>],
|
||||||
|
captures_niche: CapturesNiche<'a>,
|
||||||
return_layout: Layout<'a>,
|
return_layout: Layout<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
) {
|
) {
|
||||||
|
@ -3304,6 +3319,7 @@ fn expose_function_to_host<'a, 'ctx, 'env>(
|
||||||
let proc_layout = ProcLayout {
|
let proc_layout = ProcLayout {
|
||||||
arguments,
|
arguments,
|
||||||
result: return_layout,
|
result: return_layout,
|
||||||
|
captures_niche,
|
||||||
};
|
};
|
||||||
|
|
||||||
let c_function_name: String = layout_ids
|
let c_function_name: String = layout_ids
|
||||||
|
@ -4185,7 +4201,7 @@ fn build_procedures_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
// only have top-level thunks for this proc's module in scope
|
// only have top-level thunks for this proc's module in scope
|
||||||
// this retain is not needed for correctness, but will cause less confusion when debugging
|
// this retain is not needed for correctness, but will cause less confusion when debugging
|
||||||
let home = proc.name.module_id();
|
let home = proc.name.name().module_id();
|
||||||
current_scope.retain_top_level_thunks_for_module(home);
|
current_scope.retain_top_level_thunks_for_module(home);
|
||||||
|
|
||||||
build_proc(
|
build_proc(
|
||||||
|
@ -4301,6 +4317,7 @@ fn build_proc_header<'a, 'ctx, 'env>(
|
||||||
symbol,
|
symbol,
|
||||||
fn_val,
|
fn_val,
|
||||||
arguments.into_bump_slice(),
|
arguments.into_bump_slice(),
|
||||||
|
proc.name.captures_niche(),
|
||||||
proc.ret_layout,
|
proc.ret_layout,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
);
|
);
|
||||||
|
@ -4530,8 +4547,12 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||||
// * roc__mainForHost_1_Update_result_size() -> i64
|
// * roc__mainForHost_1_Update_result_size() -> i64
|
||||||
|
|
||||||
let it = top_level.arguments.iter().copied();
|
let it = top_level.arguments.iter().copied();
|
||||||
let bytes =
|
let bytes = roc_alias_analysis::func_name_bytes_help(
|
||||||
roc_alias_analysis::func_name_bytes_help(symbol, it, &top_level.result);
|
symbol,
|
||||||
|
it,
|
||||||
|
CapturesNiche::no_niche(),
|
||||||
|
&top_level.result,
|
||||||
|
);
|
||||||
let func_name = FuncName(&bytes);
|
let func_name = FuncName(&bytes);
|
||||||
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
|
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
|
||||||
|
|
||||||
|
@ -4548,6 +4569,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||||
*func_spec,
|
*func_spec,
|
||||||
symbol,
|
symbol,
|
||||||
top_level.arguments,
|
top_level.arguments,
|
||||||
|
CapturesNiche::no_niche(),
|
||||||
&top_level.result,
|
&top_level.result,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4559,7 +4581,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ident_string = proc.name.as_str(&env.interns);
|
let ident_string = proc.name.name().as_str(&env.interns);
|
||||||
let fn_name: String = format!("{}_1", ident_string);
|
let fn_name: String = format!("{}_1", ident_string);
|
||||||
|
|
||||||
build_closure_caller(
|
build_closure_caller(
|
||||||
|
@ -4624,17 +4646,19 @@ fn function_value_by_func_spec<'a, 'ctx, 'env>(
|
||||||
func_spec: FuncSpec,
|
func_spec: FuncSpec,
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
arguments: &[Layout<'a>],
|
arguments: &[Layout<'a>],
|
||||||
|
captures_niche: CapturesNiche<'a>,
|
||||||
result: &Layout<'a>,
|
result: &Layout<'a>,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
let fn_name = func_spec_name(env.arena, &env.interns, symbol, func_spec);
|
let fn_name = func_spec_name(env.arena, &env.interns, symbol, func_spec);
|
||||||
let fn_name = fn_name.as_str();
|
let fn_name = fn_name.as_str();
|
||||||
|
|
||||||
function_value_by_name_help(env, arguments, result, symbol, fn_name)
|
function_value_by_name_help(env, arguments, captures_niche, result, symbol, fn_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_value_by_name_help<'a, 'ctx, 'env>(
|
fn function_value_by_name_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
arguments: &[Layout<'a>],
|
arguments: &[Layout<'a>],
|
||||||
|
_captures_niche: CapturesNiche<'a>,
|
||||||
result: &Layout<'a>,
|
result: &Layout<'a>,
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
|
@ -4675,12 +4699,18 @@ fn roc_call_with_args<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
argument_layouts: &[Layout<'a>],
|
argument_layouts: &[Layout<'a>],
|
||||||
result_layout: &Layout<'a>,
|
result_layout: &Layout<'a>,
|
||||||
symbol: Symbol,
|
name: LambdaName<'a>,
|
||||||
func_spec: FuncSpec,
|
func_spec: FuncSpec,
|
||||||
arguments: &[BasicValueEnum<'ctx>],
|
arguments: &[BasicValueEnum<'ctx>],
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let fn_val =
|
let fn_val = function_value_by_func_spec(
|
||||||
function_value_by_func_spec(env, func_spec, symbol, argument_layouts, result_layout);
|
env,
|
||||||
|
func_spec,
|
||||||
|
name.name(),
|
||||||
|
argument_layouts,
|
||||||
|
name.captures_niche(),
|
||||||
|
result_layout,
|
||||||
|
);
|
||||||
|
|
||||||
call_roc_function(env, fn_val, result_layout, arguments)
|
call_roc_function(env, fn_val, result_layout, arguments)
|
||||||
}
|
}
|
||||||
|
@ -4869,8 +4899,9 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
let function = function_value_by_func_spec(
|
let function = function_value_by_func_spec(
|
||||||
env,
|
env,
|
||||||
func_spec,
|
func_spec,
|
||||||
function_name,
|
function_name.name(),
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
|
function_name.captures_niche(),
|
||||||
return_layout,
|
return_layout,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -5052,35 +5083,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
_ => unreachable!("invalid list layout"),
|
_ => unreachable!("invalid list layout"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListMapWithIndex { xs } => {
|
|
||||||
// List.mapWithIndex : List before, (before, Nat -> 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(element_layout)),
|
|
||||||
Layout::Builtin(Builtin::List(result_layout)),
|
|
||||||
) => {
|
|
||||||
let argument_layouts = &[**element_layout, Layout::usize(env.target_info)];
|
|
||||||
|
|
||||||
let roc_function_call = roc_function_call(
|
|
||||||
env,
|
|
||||||
layout_ids,
|
|
||||||
function,
|
|
||||||
closure,
|
|
||||||
closure_layout,
|
|
||||||
function_owns_closure_data,
|
|
||||||
argument_layouts,
|
|
||||||
**result_layout,
|
|
||||||
);
|
|
||||||
|
|
||||||
list_map_with_index(env, roc_function_call, list, element_layout, result_layout)
|
|
||||||
}
|
|
||||||
_ => unreachable!("invalid list layout"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ListSortWith { xs } => {
|
ListSortWith { xs } => {
|
||||||
// List.sortWith : List a, (a, a -> Ordering) -> List a
|
// List.sortWith : List a, (a, a -> Ordering) -> List a
|
||||||
let (list, list_layout) = load_symbol_and_layout(scope, xs);
|
let (list, list_layout) = load_symbol_and_layout(scope, xs);
|
||||||
|
@ -5334,12 +5336,52 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
BasicValueEnum::IntValue(is_zero)
|
BasicValueEnum::IntValue(is_zero)
|
||||||
}
|
}
|
||||||
StrCountGraphemes => {
|
StrCountGraphemes => {
|
||||||
// Str.countGraphemes : Str -> Int
|
// Str.countGraphemes : Str -> Nat
|
||||||
debug_assert_eq!(args.len(), 1);
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
let string = load_symbol(scope, &args[0]);
|
let string = load_symbol(scope, &args[0]);
|
||||||
call_bitcode_fn(env, &[string], bitcode::STR_COUNT_GRAPEHEME_CLUSTERS)
|
call_bitcode_fn(env, &[string], bitcode::STR_COUNT_GRAPEHEME_CLUSTERS)
|
||||||
}
|
}
|
||||||
|
StrGetScalarUnsafe => {
|
||||||
|
// Str.getScalarUnsafe : Str, Nat -> { bytesParsed : Nat, scalar : U32 }
|
||||||
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
|
let string = load_symbol(scope, &args[0]);
|
||||||
|
let index = load_symbol(scope, &args[1]);
|
||||||
|
call_bitcode_fn(env, &[string, index], bitcode::STR_GET_SCALAR_UNSAFE)
|
||||||
|
}
|
||||||
|
StrCountUtf8Bytes => {
|
||||||
|
// Str.countGraphemes : Str -> Nat
|
||||||
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let string = load_symbol(scope, &args[0]);
|
||||||
|
call_bitcode_fn(env, &[string], bitcode::STR_COUNT_UTF8_BYTES)
|
||||||
|
}
|
||||||
|
StrSubstringUnsafe => {
|
||||||
|
// Str.substringUnsafe : Str, Nat, Nat -> Str
|
||||||
|
debug_assert_eq!(args.len(), 3);
|
||||||
|
|
||||||
|
let string = load_symbol(scope, &args[0]);
|
||||||
|
let start = load_symbol(scope, &args[1]);
|
||||||
|
let length = load_symbol(scope, &args[2]);
|
||||||
|
call_str_bitcode_fn(env, &[string, start, length], bitcode::STR_SUBSTRING_UNSAFE)
|
||||||
|
}
|
||||||
|
StrReserve => {
|
||||||
|
// Str.reserve : Str, Nat -> Str
|
||||||
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
|
let string = load_symbol(scope, &args[0]);
|
||||||
|
let capacity = load_symbol(scope, &args[1]);
|
||||||
|
call_str_bitcode_fn(env, &[string, capacity], bitcode::STR_RESERVE)
|
||||||
|
}
|
||||||
|
StrAppendScalar => {
|
||||||
|
// Str.appendScalar : Str, U32 -> Str
|
||||||
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
|
let string = load_symbol(scope, &args[0]);
|
||||||
|
let capacity = load_symbol(scope, &args[1]);
|
||||||
|
call_str_bitcode_fn(env, &[string, capacity], bitcode::STR_APPEND_SCALAR)
|
||||||
|
}
|
||||||
StrTrim => {
|
StrTrim => {
|
||||||
// Str.trim : Str -> Str
|
// Str.trim : Str -> Str
|
||||||
debug_assert_eq!(args.len(), 1);
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
@ -5468,8 +5510,17 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
list_prepend(env, original_wrapper, elem, elem_layout)
|
list_prepend(env, original_wrapper, elem, elem_layout)
|
||||||
}
|
}
|
||||||
|
StrGetUnsafe => {
|
||||||
|
// List.getUnsafe : List elem, Nat -> elem
|
||||||
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
|
let wrapper_struct = load_symbol(scope, &args[0]);
|
||||||
|
let elem_index = load_symbol(scope, &args[1]);
|
||||||
|
|
||||||
|
call_bitcode_fn(env, &[wrapper_struct, elem_index], bitcode::STR_GET_UNSAFE)
|
||||||
|
}
|
||||||
ListGetUnsafe => {
|
ListGetUnsafe => {
|
||||||
// List.get : List elem, Nat -> [Ok elem, OutOfBounds]*
|
// List.getUnsafe : List elem, Nat -> elem
|
||||||
debug_assert_eq!(args.len(), 2);
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
let (wrapper_struct, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (wrapper_struct, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
@ -5945,7 +5996,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
set
|
set
|
||||||
}
|
}
|
||||||
|
|
||||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListSortWith | DictWalk => {
|
ListMap | ListMap2 | ListMap3 | ListMap4 | ListSortWith | DictWalk => {
|
||||||
unreachable!("these are higher order, and are handled elsewhere")
|
unreachable!("these are higher order, and are handled elsewhere")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -367,30 +367,6 @@ pub fn list_sort_with<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List.mapWithIndex : List before, (before, Nat -> after) -> List after
|
|
||||||
pub fn list_map_with_index<'a, 'ctx, 'env>(
|
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
|
||||||
roc_function_call: RocFunctionCall<'ctx>,
|
|
||||||
list: BasicValueEnum<'ctx>,
|
|
||||||
element_layout: &Layout<'a>,
|
|
||||||
return_layout: &Layout<'a>,
|
|
||||||
) -> BasicValueEnum<'ctx> {
|
|
||||||
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),
|
|
||||||
layout_width(env, return_layout),
|
|
||||||
],
|
|
||||||
bitcode::LIST_MAP_WITH_INDEX,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List.map : List before, (before -> after) -> List after
|
/// List.map : List before, (before -> after) -> List after
|
||||||
pub fn list_map<'a, 'ctx, 'env>(
|
pub fn list_map<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
|
|
@ -168,10 +168,10 @@ pub fn str_from_utf8_range<'a, 'ctx, 'env>(
|
||||||
call_void_bitcode_fn(
|
call_void_bitcode_fn(
|
||||||
env,
|
env,
|
||||||
&[
|
&[
|
||||||
|
result_ptr.into(),
|
||||||
list_symbol_to_c_abi(env, scope, list).into(),
|
list_symbol_to_c_abi(env, scope, list).into(),
|
||||||
count,
|
count,
|
||||||
start,
|
start,
|
||||||
result_ptr.into(),
|
|
||||||
],
|
],
|
||||||
bitcode::STR_FROM_UTF8_RANGE,
|
bitcode::STR_FROM_UTF8_RANGE,
|
||||||
);
|
);
|
||||||
|
@ -194,9 +194,9 @@ pub fn str_from_utf8<'a, 'ctx, 'env>(
|
||||||
call_void_bitcode_fn(
|
call_void_bitcode_fn(
|
||||||
env,
|
env,
|
||||||
&[
|
&[
|
||||||
|
result_ptr.into(),
|
||||||
list_symbol_to_c_abi(env, scope, list).into(),
|
list_symbol_to_c_abi(env, scope, list).into(),
|
||||||
pass_update_mode(env, update_mode),
|
pass_update_mode(env, update_mode),
|
||||||
result_ptr.into(),
|
|
||||||
],
|
],
|
||||||
bitcode::STR_FROM_UTF8,
|
bitcode::STR_FROM_UTF8,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1374,12 +1374,14 @@ fn build_box_eq_help<'a, 'ctx, 'env>(
|
||||||
box1.set_name(Symbol::ARG_1.as_str(&env.interns));
|
box1.set_name(Symbol::ARG_1.as_str(&env.interns));
|
||||||
box2.set_name(Symbol::ARG_2.as_str(&env.interns));
|
box2.set_name(Symbol::ARG_2.as_str(&env.interns));
|
||||||
|
|
||||||
|
let entry = ctx.append_basic_block(parent, "entry");
|
||||||
|
env.builder.position_at_end(entry);
|
||||||
|
|
||||||
let return_true = ctx.append_basic_block(parent, "return_true");
|
let return_true = ctx.append_basic_block(parent, "return_true");
|
||||||
env.builder.position_at_end(return_true);
|
env.builder.position_at_end(return_true);
|
||||||
env.builder
|
env.builder
|
||||||
.build_return(Some(&env.context.bool_type().const_all_ones()));
|
.build_return(Some(&env.context.bool_type().const_all_ones()));
|
||||||
|
|
||||||
let entry = ctx.append_basic_block(parent, "entry");
|
|
||||||
env.builder.position_at_end(entry);
|
env.builder.position_at_end(entry);
|
||||||
|
|
||||||
let ptr_equal = env.builder.build_int_compare(
|
let ptr_equal = env.builder.build_int_compare(
|
||||||
|
@ -1402,8 +1404,8 @@ fn build_box_eq_help<'a, 'ctx, 'env>(
|
||||||
let box1 = box1.into_pointer_value();
|
let box1 = box1.into_pointer_value();
|
||||||
let box2 = box2.into_pointer_value();
|
let box2 = box2.into_pointer_value();
|
||||||
|
|
||||||
let value1 = env.builder.build_load(box1, "load_box1");
|
let value1 = load_roc_value(env, *inner_layout, box1, "load_box1");
|
||||||
let value2 = env.builder.build_load(box2, "load_box2");
|
let value2 = load_roc_value(env, *inner_layout, box2, "load_box2");
|
||||||
|
|
||||||
let is_equal = build_eq(
|
let is_equal = build_eq(
|
||||||
env,
|
env,
|
||||||
|
|
|
@ -380,7 +380,7 @@ impl<'a> WasmBackend<'a> {
|
||||||
println!("\ngenerating procedure {:?}\n", proc.name);
|
println!("\ngenerating procedure {:?}\n", proc.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.append_proc_debug_name(proc.name);
|
self.append_proc_debug_name(proc.name.name());
|
||||||
|
|
||||||
self.start_proc(proc);
|
self.start_proc(proc);
|
||||||
|
|
||||||
|
@ -1125,9 +1125,10 @@ impl<'a> WasmBackend<'a> {
|
||||||
let proc_layout = ProcLayout {
|
let proc_layout = ProcLayout {
|
||||||
arguments: arg_layouts,
|
arguments: arg_layouts,
|
||||||
result: **result,
|
result: **result,
|
||||||
|
captures_niche: func_sym.captures_niche(),
|
||||||
};
|
};
|
||||||
self.expr_call_by_name(
|
self.expr_call_by_name(
|
||||||
*func_sym,
|
func_sym.name(),
|
||||||
&proc_layout,
|
&proc_layout,
|
||||||
arguments,
|
arguments,
|
||||||
ret_sym,
|
ret_sym,
|
||||||
|
|
|
@ -184,7 +184,8 @@ pub fn build_app_module<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let (module, called_preload_fns) = backend.finalize();
|
let (module, called_preload_fns) = backend.finalize();
|
||||||
let main_function_index = maybe_main_fn_index.unwrap();
|
let main_function_index =
|
||||||
|
maybe_main_fn_index.expect("The app must expose at least one value to the host");
|
||||||
|
|
||||||
(module, called_preload_fns, main_function_index)
|
(module, called_preload_fns, main_function_index)
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,6 +218,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
// Str
|
// Str
|
||||||
StrConcat => self.load_args_and_call_zig(backend, bitcode::STR_CONCAT),
|
StrConcat => self.load_args_and_call_zig(backend, bitcode::STR_CONCAT),
|
||||||
StrToScalars => self.load_args_and_call_zig(backend, bitcode::STR_TO_SCALARS),
|
StrToScalars => self.load_args_and_call_zig(backend, bitcode::STR_TO_SCALARS),
|
||||||
|
StrGetUnsafe => self.load_args_and_call_zig(backend, bitcode::STR_GET_UNSAFE),
|
||||||
StrJoinWith => self.load_args_and_call_zig(backend, bitcode::STR_JOIN_WITH),
|
StrJoinWith => self.load_args_and_call_zig(backend, bitcode::STR_JOIN_WITH),
|
||||||
StrIsEmpty => match backend.storage.get(&self.arguments[0]) {
|
StrIsEmpty => match backend.storage.get(&self.arguments[0]) {
|
||||||
StoredValue::StackMemory { location, .. } => {
|
StoredValue::StackMemory { location, .. } => {
|
||||||
|
@ -235,18 +236,13 @@ impl<'a> LowLevelCall<'a> {
|
||||||
self.load_args_and_call_zig(backend, bitcode::STR_STARTS_WITH_SCALAR)
|
self.load_args_and_call_zig(backend, bitcode::STR_STARTS_WITH_SCALAR)
|
||||||
}
|
}
|
||||||
StrEndsWith => self.load_args_and_call_zig(backend, bitcode::STR_ENDS_WITH),
|
StrEndsWith => self.load_args_and_call_zig(backend, bitcode::STR_ENDS_WITH),
|
||||||
StrSplit => {
|
StrSplit => self.load_args_and_call_zig(backend, bitcode::STR_STR_SPLIT),
|
||||||
// LLVM implementation (build_str.rs) does the following
|
|
||||||
// 1. Call bitcode::STR_COUNT_SEGMENTS
|
|
||||||
// 2. Allocate a `List Str`
|
|
||||||
// 3. Call bitcode::STR_STR_SPLIT_IN_PLACE
|
|
||||||
// 4. Write the elements and length of the List
|
|
||||||
// To do this here, we need full access to WasmBackend, or we could make a Zig wrapper
|
|
||||||
todo!("{:?}", self.lowlevel);
|
|
||||||
}
|
|
||||||
StrCountGraphemes => {
|
StrCountGraphemes => {
|
||||||
self.load_args_and_call_zig(backend, bitcode::STR_COUNT_GRAPEHEME_CLUSTERS)
|
self.load_args_and_call_zig(backend, bitcode::STR_COUNT_GRAPEHEME_CLUSTERS)
|
||||||
}
|
}
|
||||||
|
StrCountUtf8Bytes => {
|
||||||
|
self.load_args_and_call_zig(backend, bitcode::STR_COUNT_UTF8_BYTES)
|
||||||
|
}
|
||||||
StrToNum => {
|
StrToNum => {
|
||||||
let number_layout = match self.ret_layout {
|
let number_layout = match self.ret_layout {
|
||||||
Layout::Struct { field_layouts, .. } => field_layouts[0],
|
Layout::Struct { field_layouts, .. } => field_layouts[0],
|
||||||
|
@ -268,13 +264,41 @@ impl<'a> LowLevelCall<'a> {
|
||||||
}
|
}
|
||||||
StrFromInt => self.num_to_str(backend),
|
StrFromInt => self.num_to_str(backend),
|
||||||
StrFromFloat => self.num_to_str(backend),
|
StrFromFloat => self.num_to_str(backend),
|
||||||
StrFromUtf8 => self.load_args_and_call_zig(backend, bitcode::STR_FROM_UTF8),
|
StrFromUtf8 => {
|
||||||
|
/*
|
||||||
|
Low-level op returns a struct with all the data for both Ok and Err.
|
||||||
|
Roc AST wrapper converts this to a tag union, with app-dependent tag IDs.
|
||||||
|
|
||||||
|
fromUtf8C(output: *FromUtf8Result, arg: RocList, update_mode: UpdateMode) callconv(.C) void
|
||||||
|
output: *FromUtf8Result i32
|
||||||
|
arg: RocList i64, i32
|
||||||
|
update_mode: UpdateMode i32
|
||||||
|
*/
|
||||||
|
backend.storage.load_symbols_for_call(
|
||||||
|
backend.env.arena,
|
||||||
|
&mut backend.code_builder,
|
||||||
|
self.arguments,
|
||||||
|
self.ret_symbol,
|
||||||
|
&WasmLayout::new(&self.ret_layout),
|
||||||
|
CallConv::Zig,
|
||||||
|
);
|
||||||
|
backend.code_builder.i32_const(UPDATE_MODE_IMMUTABLE);
|
||||||
|
backend.call_host_fn_after_loading_args(bitcode::STR_FROM_UTF8, 4, false);
|
||||||
|
}
|
||||||
|
StrFromUtf8Range => self.load_args_and_call_zig(backend, bitcode::STR_FROM_UTF8_RANGE),
|
||||||
StrTrimLeft => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_LEFT),
|
StrTrimLeft => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_LEFT),
|
||||||
StrTrimRight => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_RIGHT),
|
StrTrimRight => self.load_args_and_call_zig(backend, bitcode::STR_TRIM_RIGHT),
|
||||||
StrFromUtf8Range => self.load_args_and_call_zig(backend, bitcode::STR_FROM_UTF8_RANGE),
|
|
||||||
StrToUtf8 => self.load_args_and_call_zig(backend, bitcode::STR_TO_UTF8),
|
StrToUtf8 => self.load_args_and_call_zig(backend, bitcode::STR_TO_UTF8),
|
||||||
|
StrReserve => self.load_args_and_call_zig(backend, bitcode::STR_RESERVE),
|
||||||
StrRepeat => self.load_args_and_call_zig(backend, bitcode::STR_REPEAT),
|
StrRepeat => self.load_args_and_call_zig(backend, bitcode::STR_REPEAT),
|
||||||
|
StrAppendScalar => self.load_args_and_call_zig(backend, bitcode::STR_APPEND_SCALAR),
|
||||||
StrTrim => self.load_args_and_call_zig(backend, bitcode::STR_TRIM),
|
StrTrim => self.load_args_and_call_zig(backend, bitcode::STR_TRIM),
|
||||||
|
StrGetScalarUnsafe => {
|
||||||
|
self.load_args_and_call_zig(backend, bitcode::STR_GET_SCALAR_UNSAFE)
|
||||||
|
}
|
||||||
|
StrSubstringUnsafe => {
|
||||||
|
self.load_args_and_call_zig(backend, bitcode::STR_SUBSTRING_UNSAFE)
|
||||||
|
}
|
||||||
|
|
||||||
// List
|
// List
|
||||||
ListLen => match backend.storage.get(&self.arguments[0]) {
|
ListLen => match backend.storage.get(&self.arguments[0]) {
|
||||||
|
@ -289,8 +313,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
|
|
||||||
ListIsUnique => self.load_args_and_call_zig(backend, bitcode::LIST_IS_UNIQUE),
|
ListIsUnique => self.load_args_and_call_zig(backend, bitcode::LIST_IS_UNIQUE),
|
||||||
|
|
||||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListSortWith
|
ListMap | ListMap2 | ListMap3 | ListMap4 | ListSortWith | DictWalk => {
|
||||||
| DictWalk => {
|
|
||||||
internal_error!("HigherOrder lowlevels should not be handled here")
|
internal_error!("HigherOrder lowlevels should not be handled here")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1715,7 +1738,8 @@ impl<'a> LowLevelCall<'a> {
|
||||||
Layout::Builtin(Builtin::Dict(_, _) | Builtin::Set(_) | Builtin::List(_))
|
Layout::Builtin(Builtin::Dict(_, _) | Builtin::Set(_) | Builtin::List(_))
|
||||||
| Layout::Struct { .. }
|
| Layout::Struct { .. }
|
||||||
| Layout::Union(_)
|
| Layout::Union(_)
|
||||||
| Layout::LambdaSet(_) => {
|
| Layout::LambdaSet(_)
|
||||||
|
| Layout::Boxed(_) => {
|
||||||
// Don't want Zig calling convention here, we're calling internal Roc functions
|
// Don't want Zig calling convention here, we're calling internal Roc functions
|
||||||
backend
|
backend
|
||||||
.storage
|
.storage
|
||||||
|
@ -1733,8 +1757,6 @@ impl<'a> LowLevelCall<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout::Boxed(_) => todo!(),
|
|
||||||
|
|
||||||
Layout::RecursivePointer => {
|
Layout::RecursivePointer => {
|
||||||
internal_error!(
|
internal_error!(
|
||||||
"Tried to apply `==` to RecursivePointer values {:?}",
|
"Tried to apply `==` to RecursivePointer values {:?}",
|
||||||
|
@ -1951,12 +1973,13 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||||
let passed_proc_layout = ProcLayout {
|
let passed_proc_layout = ProcLayout {
|
||||||
arguments: argument_layouts,
|
arguments: argument_layouts,
|
||||||
result: *result_layout,
|
result: *result_layout,
|
||||||
|
captures_niche: fn_name.captures_niche(),
|
||||||
};
|
};
|
||||||
let passed_proc_index = backend
|
let passed_proc_index = backend
|
||||||
.proc_lookup
|
.proc_lookup
|
||||||
.iter()
|
.iter()
|
||||||
.position(|ProcLookupData { name, layout, .. }| {
|
.position(|ProcLookupData { name, layout, .. }| {
|
||||||
name == fn_name && layout == &passed_proc_layout
|
*name == fn_name.name() && layout == &passed_proc_layout
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ProcSource::HigherOrderWrapper(passed_proc_index)
|
ProcSource::HigherOrderWrapper(passed_proc_index)
|
||||||
|
@ -1984,6 +2007,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||||
ProcLayout {
|
ProcLayout {
|
||||||
arguments: wrapper_arg_layouts.into_bump_slice(),
|
arguments: wrapper_arg_layouts.into_bump_slice(),
|
||||||
result: Layout::UNIT,
|
result: Layout::UNIT,
|
||||||
|
captures_niche: fn_name.captures_niche(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2059,7 +2083,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
||||||
*owns_captured_environment,
|
*owns_captured_environment,
|
||||||
),
|
),
|
||||||
|
|
||||||
ListMapWithIndex { .. } | ListSortWith { .. } | DictWalk { .. } => todo!("{:?}", op),
|
ListSortWith { .. } | DictWalk { .. } => todo!("{:?}", op),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ pub fn insert_wrapper_for_layout<'a>(
|
||||||
bool::insert_wrapper(arena, module, wrapper_name, main_fn_index);
|
bool::insert_wrapper(arena, module, wrapper_name, main_fn_index);
|
||||||
}
|
}
|
||||||
Layout::Union(UnionLayout::NonRecursive(_)) => stack_data_structure(),
|
Layout::Union(UnionLayout::NonRecursive(_)) => stack_data_structure(),
|
||||||
Layout::Union(_) => {
|
Layout::Union(_) | Layout::Boxed(_) => {
|
||||||
i32::insert_wrapper(arena, module, wrapper_name, main_fn_index);
|
i32::insert_wrapper(arena, module, wrapper_name, main_fn_index);
|
||||||
}
|
}
|
||||||
_ => stack_data_structure(),
|
_ => stack_data_structure(),
|
||||||
|
@ -176,6 +176,7 @@ wasm_result_primitive!(u16, i32_store16, Align::Bytes2);
|
||||||
wasm_result_primitive!(i16, i32_store16, Align::Bytes2);
|
wasm_result_primitive!(i16, i32_store16, Align::Bytes2);
|
||||||
wasm_result_primitive!(u32, i32_store, Align::Bytes4);
|
wasm_result_primitive!(u32, i32_store, Align::Bytes4);
|
||||||
wasm_result_primitive!(i32, i32_store, Align::Bytes4);
|
wasm_result_primitive!(i32, i32_store, Align::Bytes4);
|
||||||
|
wasm_result_primitive!(char, i32_store, Align::Bytes4);
|
||||||
wasm_result_primitive!(u64, i64_store, Align::Bytes8);
|
wasm_result_primitive!(u64, i64_store, Align::Bytes8);
|
||||||
wasm_result_primitive!(i64, i64_store, Align::Bytes8);
|
wasm_result_primitive!(i64, i64_store, Align::Bytes8);
|
||||||
wasm_result_primitive!(usize, i32_store, Align::Bytes4);
|
wasm_result_primitive!(usize, i32_store, Align::Bytes4);
|
||||||
|
|
|
@ -23,7 +23,7 @@ macro_rules! wasm32_sized_primitive {
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm32_sized_primitive!(
|
wasm32_sized_primitive!(
|
||||||
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f32, f64, bool, RocDec, RocOrder,
|
u8, i8, u16, i16, u32, i32, char, u64, i64, u128, i128, f32, f64, bool, RocDec, RocOrder,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl Wasm32Sized for () {
|
impl Wasm32Sized for () {
|
||||||
|
|
|
@ -33,7 +33,7 @@ use roc_mono::ir::{
|
||||||
CapturedSymbols, EntryPoint, ExternalSpecializations, PartialProc, Proc, ProcLayout, Procs,
|
CapturedSymbols, EntryPoint, ExternalSpecializations, PartialProc, Proc, ProcLayout, Procs,
|
||||||
ProcsBase, UpdateModeIds,
|
ProcsBase, UpdateModeIds,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
use roc_mono::layout::{CapturesNiche, LambdaName, Layout, LayoutCache, LayoutProblem};
|
||||||
use roc_parse::ast::{self, Defs, ExtractSpaces, Spaced, StrLiteral, TypeAnnotation};
|
use roc_parse::ast::{self, Defs, ExtractSpaces, Spaced, StrLiteral, TypeAnnotation};
|
||||||
use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
|
use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
|
||||||
use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
|
use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
|
||||||
|
@ -132,7 +132,7 @@ struct ModuleCache<'a> {
|
||||||
typechecked: MutMap<ModuleId, TypeCheckedModule<'a>>,
|
typechecked: MutMap<ModuleId, TypeCheckedModule<'a>>,
|
||||||
found_specializations: MutMap<ModuleId, FoundSpecializationsModule<'a>>,
|
found_specializations: MutMap<ModuleId, FoundSpecializationsModule<'a>>,
|
||||||
late_specializations: MutMap<ModuleId, LateSpecializationsModule<'a>>,
|
late_specializations: MutMap<ModuleId, LateSpecializationsModule<'a>>,
|
||||||
external_specializations_requested: MutMap<ModuleId, Vec<ExternalSpecializations>>,
|
external_specializations_requested: MutMap<ModuleId, Vec<ExternalSpecializations<'a>>>,
|
||||||
|
|
||||||
/// Various information
|
/// Various information
|
||||||
imports: MutMap<ModuleId, MutSet<ModuleId>>,
|
imports: MutMap<ModuleId, MutSet<ModuleId>>,
|
||||||
|
@ -715,7 +715,7 @@ enum Msg<'a> {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
ident_ids: IdentIds,
|
ident_ids: IdentIds,
|
||||||
layout_cache: LayoutCache<'a>,
|
layout_cache: LayoutCache<'a>,
|
||||||
external_specializations_requested: BumpMap<ModuleId, ExternalSpecializations>,
|
external_specializations_requested: BumpMap<ModuleId, ExternalSpecializations<'a>>,
|
||||||
procs_base: ProcsBase<'a>,
|
procs_base: ProcsBase<'a>,
|
||||||
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||||
update_mode_ids: UpdateModeIds,
|
update_mode_ids: UpdateModeIds,
|
||||||
|
@ -1007,7 +1007,7 @@ enum BuildTask<'a> {
|
||||||
subs: Subs,
|
subs: Subs,
|
||||||
procs_base: ProcsBase<'a>,
|
procs_base: ProcsBase<'a>,
|
||||||
layout_cache: LayoutCache<'a>,
|
layout_cache: LayoutCache<'a>,
|
||||||
specializations_we_must_make: Vec<ExternalSpecializations>,
|
specializations_we_must_make: Vec<ExternalSpecializations<'a>>,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
world_abilities: WorldAbilities,
|
world_abilities: WorldAbilities,
|
||||||
derived_symbols: GlobalDerivedSymbols,
|
derived_symbols: GlobalDerivedSymbols,
|
||||||
|
@ -2592,9 +2592,11 @@ fn finish_specialization(
|
||||||
.into_inner()
|
.into_inner()
|
||||||
.into_module_ids();
|
.into_module_ids();
|
||||||
|
|
||||||
|
let all_ident_ids = state.constrained_ident_ids;
|
||||||
|
|
||||||
let interns = Interns {
|
let interns = Interns {
|
||||||
module_ids,
|
module_ids,
|
||||||
all_ident_ids: state.constrained_ident_ids,
|
all_ident_ids,
|
||||||
};
|
};
|
||||||
|
|
||||||
let State {
|
let State {
|
||||||
|
@ -2660,6 +2662,7 @@ fn finish_specialization(
|
||||||
layout: roc_mono::ir::ProcLayout {
|
layout: roc_mono::ir::ProcLayout {
|
||||||
arguments: &[],
|
arguments: &[],
|
||||||
result: Layout::struct_no_name_order(&[]),
|
result: Layout::struct_no_name_order(&[]),
|
||||||
|
captures_niche: CapturesNiche::no_niche(),
|
||||||
},
|
},
|
||||||
symbol,
|
symbol,
|
||||||
}
|
}
|
||||||
|
@ -4407,7 +4410,7 @@ fn make_specializations<'a>(
|
||||||
mut subs: Subs,
|
mut subs: Subs,
|
||||||
procs_base: ProcsBase<'a>,
|
procs_base: ProcsBase<'a>,
|
||||||
mut layout_cache: LayoutCache<'a>,
|
mut layout_cache: LayoutCache<'a>,
|
||||||
specializations_we_must_make: Vec<ExternalSpecializations>,
|
specializations_we_must_make: Vec<ExternalSpecializations<'a>>,
|
||||||
mut module_timing: ModuleTiming,
|
mut module_timing: ModuleTiming,
|
||||||
target_info: TargetInfo,
|
target_info: TargetInfo,
|
||||||
world_abilities: WorldAbilities,
|
world_abilities: WorldAbilities,
|
||||||
|
@ -4571,7 +4574,7 @@ fn build_pending_specializations<'a>(
|
||||||
|
|
||||||
procs_base.host_specializations.insert_host_exposed(
|
procs_base.host_specializations.insert_host_exposed(
|
||||||
mono_env.subs,
|
mono_env.subs,
|
||||||
symbol,
|
LambdaName::no_niche(symbol),
|
||||||
annotation,
|
annotation,
|
||||||
expr_var,
|
expr_var,
|
||||||
);
|
);
|
||||||
|
@ -4631,7 +4634,7 @@ fn build_pending_specializations<'a>(
|
||||||
|
|
||||||
procs_base.host_specializations.insert_host_exposed(
|
procs_base.host_specializations.insert_host_exposed(
|
||||||
mono_env.subs,
|
mono_env.subs,
|
||||||
symbol,
|
LambdaName::no_niche(symbol),
|
||||||
annotation,
|
annotation,
|
||||||
expr_var,
|
expr_var,
|
||||||
);
|
);
|
||||||
|
@ -4709,7 +4712,7 @@ fn build_pending_specializations<'a>(
|
||||||
|
|
||||||
procs_base.host_specializations.insert_host_exposed(
|
procs_base.host_specializations.insert_host_exposed(
|
||||||
mono_env.subs,
|
mono_env.subs,
|
||||||
symbol,
|
LambdaName::no_niche(symbol),
|
||||||
annotation,
|
annotation,
|
||||||
expr_var,
|
expr_var,
|
||||||
);
|
);
|
||||||
|
@ -4769,7 +4772,7 @@ fn build_pending_specializations<'a>(
|
||||||
|
|
||||||
procs_base.host_specializations.insert_host_exposed(
|
procs_base.host_specializations.insert_host_exposed(
|
||||||
mono_env.subs,
|
mono_env.subs,
|
||||||
symbol,
|
LambdaName::no_niche(symbol),
|
||||||
annotation,
|
annotation,
|
||||||
expr_var,
|
expr_var,
|
||||||
);
|
);
|
||||||
|
|
|
@ -106,7 +106,7 @@ impl<'a> From<&'a str> for ModuleName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<IdentStr> for ModuleName {
|
impl From<IdentStr> for ModuleName {
|
||||||
fn from(string: IdentStr) -> Self {
|
fn from(string: IdentStr) -> Self {
|
||||||
Self(string.as_str().into())
|
Self(string.as_str().into())
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ impl<'a> From<&'a str> for ForeignSymbol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<String> for ForeignSymbol {
|
impl From<String> for ForeignSymbol {
|
||||||
fn from(string: String) -> Self {
|
fn from(string: String) -> Self {
|
||||||
Self(string.into())
|
Self(string.into())
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ impl<'a> From<&'a str> for Uppercase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<String> for Uppercase {
|
impl From<String> for Uppercase {
|
||||||
fn from(string: String) -> Self {
|
fn from(string: String) -> Self {
|
||||||
Self(string.into())
|
Self(string.into())
|
||||||
}
|
}
|
||||||
|
@ -198,7 +198,7 @@ impl<'a> From<&'a Lowercase> for &'a str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<String> for Lowercase {
|
impl From<String> for Lowercase {
|
||||||
fn from(string: String) -> Self {
|
fn from(string: String) -> Self {
|
||||||
Self(string.into())
|
Self(string.into())
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ pub enum LowLevel {
|
||||||
StrEndsWith,
|
StrEndsWith,
|
||||||
StrSplit,
|
StrSplit,
|
||||||
StrCountGraphemes,
|
StrCountGraphemes,
|
||||||
|
StrCountUtf8Bytes,
|
||||||
StrFromInt,
|
StrFromInt,
|
||||||
StrFromUtf8,
|
StrFromUtf8,
|
||||||
StrFromUtf8Range,
|
StrFromUtf8Range,
|
||||||
|
@ -24,6 +25,11 @@ pub enum LowLevel {
|
||||||
StrTrimRight,
|
StrTrimRight,
|
||||||
StrToNum,
|
StrToNum,
|
||||||
StrToScalars,
|
StrToScalars,
|
||||||
|
StrGetUnsafe,
|
||||||
|
StrSubstringUnsafe,
|
||||||
|
StrReserve,
|
||||||
|
StrAppendScalar,
|
||||||
|
StrGetScalarUnsafe,
|
||||||
ListLen,
|
ListLen,
|
||||||
ListWithCapacity,
|
ListWithCapacity,
|
||||||
ListGetUnsafe,
|
ListGetUnsafe,
|
||||||
|
@ -35,7 +41,6 @@ pub enum LowLevel {
|
||||||
ListMap2,
|
ListMap2,
|
||||||
ListMap3,
|
ListMap3,
|
||||||
ListMap4,
|
ListMap4,
|
||||||
ListMapWithIndex,
|
|
||||||
ListSortWith,
|
ListSortWith,
|
||||||
ListSublist,
|
ListSublist,
|
||||||
ListDropAt,
|
ListDropAt,
|
||||||
|
@ -120,7 +125,7 @@ pub enum LowLevel {
|
||||||
|
|
||||||
macro_rules! higher_order {
|
macro_rules! higher_order {
|
||||||
() => {
|
() => {
|
||||||
ListMap | ListMap2 | ListMap3 | ListMap4 | ListMapWithIndex | ListSortWith | DictWalk
|
ListMap | ListMap2 | ListMap3 | ListMap4 | ListSortWith | DictWalk
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +146,6 @@ impl LowLevel {
|
||||||
ListMap2 => 2,
|
ListMap2 => 2,
|
||||||
ListMap3 => 3,
|
ListMap3 => 3,
|
||||||
ListMap4 => 4,
|
ListMap4 => 4,
|
||||||
ListMapWithIndex => 1,
|
|
||||||
ListSortWith => 1,
|
ListSortWith => 1,
|
||||||
DictWalk => 2,
|
DictWalk => 2,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -167,6 +171,7 @@ impl LowLevelWrapperType {
|
||||||
|
|
||||||
match symbol {
|
match symbol {
|
||||||
Symbol::STR_CONCAT => CanBeReplacedBy(StrConcat),
|
Symbol::STR_CONCAT => CanBeReplacedBy(StrConcat),
|
||||||
|
Symbol::STR_GET_UNSAFE => CanBeReplacedBy(StrGetUnsafe),
|
||||||
Symbol::STR_TO_SCALARS => CanBeReplacedBy(StrToScalars),
|
Symbol::STR_TO_SCALARS => CanBeReplacedBy(StrToScalars),
|
||||||
Symbol::STR_JOIN_WITH => CanBeReplacedBy(StrJoinWith),
|
Symbol::STR_JOIN_WITH => CanBeReplacedBy(StrJoinWith),
|
||||||
Symbol::STR_IS_EMPTY => CanBeReplacedBy(StrIsEmpty),
|
Symbol::STR_IS_EMPTY => CanBeReplacedBy(StrIsEmpty),
|
||||||
|
@ -175,10 +180,13 @@ impl LowLevelWrapperType {
|
||||||
Symbol::STR_ENDS_WITH => CanBeReplacedBy(StrEndsWith),
|
Symbol::STR_ENDS_WITH => CanBeReplacedBy(StrEndsWith),
|
||||||
Symbol::STR_SPLIT => CanBeReplacedBy(StrSplit),
|
Symbol::STR_SPLIT => CanBeReplacedBy(StrSplit),
|
||||||
Symbol::STR_COUNT_GRAPHEMES => CanBeReplacedBy(StrCountGraphemes),
|
Symbol::STR_COUNT_GRAPHEMES => CanBeReplacedBy(StrCountGraphemes),
|
||||||
|
Symbol::STR_COUNT_UTF8_BYTES => CanBeReplacedBy(StrCountUtf8Bytes),
|
||||||
Symbol::STR_FROM_UTF8 => WrapperIsRequired,
|
Symbol::STR_FROM_UTF8 => WrapperIsRequired,
|
||||||
Symbol::STR_FROM_UTF8_RANGE => WrapperIsRequired,
|
Symbol::STR_FROM_UTF8_RANGE => WrapperIsRequired,
|
||||||
Symbol::STR_TO_UTF8 => CanBeReplacedBy(StrToUtf8),
|
Symbol::STR_TO_UTF8 => CanBeReplacedBy(StrToUtf8),
|
||||||
Symbol::STR_REPEAT => CanBeReplacedBy(StrRepeat),
|
Symbol::STR_REPEAT => CanBeReplacedBy(StrRepeat),
|
||||||
|
Symbol::STR_RESERVE => CanBeReplacedBy(StrReserve),
|
||||||
|
Symbol::STR_APPEND_SCALAR_UNSAFE => CanBeReplacedBy(StrAppendScalar),
|
||||||
Symbol::STR_TRIM => CanBeReplacedBy(StrTrim),
|
Symbol::STR_TRIM => CanBeReplacedBy(StrTrim),
|
||||||
Symbol::STR_TRIM_LEFT => CanBeReplacedBy(StrTrimLeft),
|
Symbol::STR_TRIM_LEFT => CanBeReplacedBy(StrTrimLeft),
|
||||||
Symbol::STR_TRIM_RIGHT => CanBeReplacedBy(StrTrimRight),
|
Symbol::STR_TRIM_RIGHT => CanBeReplacedBy(StrTrimRight),
|
||||||
|
@ -206,7 +214,6 @@ impl LowLevelWrapperType {
|
||||||
Symbol::LIST_MAP2 => WrapperIsRequired,
|
Symbol::LIST_MAP2 => WrapperIsRequired,
|
||||||
Symbol::LIST_MAP3 => WrapperIsRequired,
|
Symbol::LIST_MAP3 => WrapperIsRequired,
|
||||||
Symbol::LIST_MAP4 => WrapperIsRequired,
|
Symbol::LIST_MAP4 => WrapperIsRequired,
|
||||||
Symbol::LIST_MAP_WITH_INDEX => WrapperIsRequired,
|
|
||||||
Symbol::LIST_SORT_WITH => WrapperIsRequired,
|
Symbol::LIST_SORT_WITH => WrapperIsRequired,
|
||||||
Symbol::LIST_SUBLIST => WrapperIsRequired,
|
Symbol::LIST_SUBLIST => WrapperIsRequired,
|
||||||
Symbol::LIST_DROP_AT => CanBeReplacedBy(ListDropAt),
|
Symbol::LIST_DROP_AT => CanBeReplacedBy(ListDropAt),
|
||||||
|
|
|
@ -182,7 +182,10 @@ impl fmt::Debug for Symbol {
|
||||||
// might be used in a panic error message, and if we panick
|
// might be used in a panic error message, and if we panick
|
||||||
// while we're already panicking it'll kill the process
|
// while we're already panicking it'll kill the process
|
||||||
// without printing any of the errors!
|
// without printing any of the errors!
|
||||||
eprintln!("DEBUG INFO: Failed to acquire lock for Debug reading from DEBUG_IDENT_IDS_BY_MODULE_ID, presumably because a thread panicked: {:?}", err);
|
use std::io::Write;
|
||||||
|
|
||||||
|
let mut stderr = std::io::stderr();
|
||||||
|
writeln!(stderr, "DEBUG INFO: Failed to acquire lock for Debug reading from DEBUG_IDENT_IDS_BY_MODULE_ID, presumably because a thread panicked: {:?}", err).unwrap();
|
||||||
|
|
||||||
fallback_debug_fmt(*self, f)
|
fallback_debug_fmt(*self, f)
|
||||||
}
|
}
|
||||||
|
@ -1191,6 +1194,18 @@ define_builtins! {
|
||||||
32 STR_TO_U8: "toU8"
|
32 STR_TO_U8: "toU8"
|
||||||
33 STR_TO_I8: "toI8"
|
33 STR_TO_I8: "toI8"
|
||||||
34 STR_TO_SCALARS: "toScalars"
|
34 STR_TO_SCALARS: "toScalars"
|
||||||
|
35 STR_GET_UNSAFE: "getUnsafe"
|
||||||
|
36 STR_COUNT_UTF8_BYTES: "countUtf8Bytes"
|
||||||
|
37 STR_SUBSTRING_UNSAFE: "substringUnsafe"
|
||||||
|
38 STR_SPLIT_FIRST: "splitFirst"
|
||||||
|
39 STR_SPLIT_LAST: "splitLast"
|
||||||
|
40 STR_WALK_UTF8_WITH_INDEX: "walkUtf8WithIndex"
|
||||||
|
41 STR_RESERVE: "reserve"
|
||||||
|
42 STR_APPEND_SCALAR_UNSAFE: "appendScalarUnsafe"
|
||||||
|
43 STR_APPEND_SCALAR: "appendScalar"
|
||||||
|
44 STR_GET_SCALAR_UNSAFE: "getScalarUnsafe"
|
||||||
|
45 STR_WALK_SCALARS: "walkScalars"
|
||||||
|
46 STR_WALK_SCALARS_UNTIL: "walkScalarsUntil"
|
||||||
}
|
}
|
||||||
5 LIST: "List" => {
|
5 LIST: "List" => {
|
||||||
0 LIST_LIST: "List" imported // the List.List type alias
|
0 LIST_LIST: "List" imported // the List.List type alias
|
||||||
|
|
|
@ -163,7 +163,7 @@ impl<'a> DeclarationToIndex<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreachable!(
|
unreachable!(
|
||||||
"symbol/layout {:?} {:?} combo must be in DeclarationToIndex",
|
"symbol/layout {:?} {:#?} combo must be in DeclarationToIndex",
|
||||||
needle_symbol, needle_layout
|
needle_symbol, needle_layout
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -263,7 +263,7 @@ impl<'a> ParamMap<'a> {
|
||||||
self.declarations[index + i] = param;
|
self.declarations[index + i] = param;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_stmt(arena, proc.name, &proc.body);
|
self.visit_stmt(arena, proc.name.name(), &proc.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_proc_always_owned(
|
fn visit_proc_always_owned(
|
||||||
|
@ -282,7 +282,7 @@ impl<'a> ParamMap<'a> {
|
||||||
self.declarations[index + i] = param;
|
self.declarations[index + i] = param;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visit_stmt(arena, proc.name, &proc.body);
|
self.visit_stmt(arena, proc.name.name(), &proc.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_stmt(&mut self, arena: &'a Bump, _fnid: Symbol, stmt: &Stmt<'a>) {
|
fn visit_stmt(&mut self, arena: &'a Bump, _fnid: Symbol, stmt: &Stmt<'a>) {
|
||||||
|
@ -501,11 +501,12 @@ impl<'a> BorrowInfState<'a> {
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let top_level = ProcLayout::new(self.arena, arg_layouts, **ret_layout);
|
let top_level =
|
||||||
|
ProcLayout::new(self.arena, arg_layouts, name.captures_niche(), **ret_layout);
|
||||||
|
|
||||||
// get the borrow signature of the applied function
|
// get the borrow signature of the applied function
|
||||||
let ps = param_map
|
let ps = param_map
|
||||||
.get_symbol(*name, top_level)
|
.get_symbol(name.name(), top_level)
|
||||||
.expect("function is defined");
|
.expect("function is defined");
|
||||||
|
|
||||||
// the return value will be owned
|
// the return value will be owned
|
||||||
|
@ -544,12 +545,14 @@ impl<'a> BorrowInfState<'a> {
|
||||||
let closure_layout = ProcLayout {
|
let closure_layout = ProcLayout {
|
||||||
arguments: passed_function.argument_layouts,
|
arguments: passed_function.argument_layouts,
|
||||||
result: passed_function.return_layout,
|
result: passed_function.return_layout,
|
||||||
|
captures_niche: passed_function.name.captures_niche(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let function_ps = match param_map.get_symbol(passed_function.name, closure_layout) {
|
let function_ps =
|
||||||
Some(function_ps) => function_ps,
|
match param_map.get_symbol(passed_function.name.name(), closure_layout) {
|
||||||
None => unreachable!(),
|
Some(function_ps) => function_ps,
|
||||||
};
|
None => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
ListMap { xs } => {
|
ListMap { xs } => {
|
||||||
|
@ -558,13 +561,6 @@ impl<'a> BorrowInfState<'a> {
|
||||||
self.own_var(*xs);
|
self.own_var(*xs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListMapWithIndex { xs } => {
|
|
||||||
// List.mapWithIndex : List before, (before, Nat -> after) -> List after
|
|
||||||
// own the list if the function wants to own the element (before, index 0)
|
|
||||||
if !function_ps[0].borrow {
|
|
||||||
self.own_var(*xs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ListMap2 { xs, ys } => {
|
ListMap2 { xs, ys } => {
|
||||||
// own the lists if the function wants to own the element
|
// own the lists if the function wants to own the element
|
||||||
if !function_ps[0].borrow {
|
if !function_ps[0].borrow {
|
||||||
|
@ -743,12 +739,13 @@ impl<'a> BorrowInfState<'a> {
|
||||||
Stmt::Ret(z),
|
Stmt::Ret(z),
|
||||||
) = (v, b)
|
) = (v, b)
|
||||||
{
|
{
|
||||||
let top_level = ProcLayout::new(self.arena, arg_layouts, **ret_layout);
|
let top_level =
|
||||||
|
ProcLayout::new(self.arena, arg_layouts, g.captures_niche(), **ret_layout);
|
||||||
|
|
||||||
if self.current_proc == *g && x == *z {
|
if self.current_proc == g.name() && x == *z {
|
||||||
// anonymous functions (for which the ps may not be known)
|
// anonymous functions (for which the ps may not be known)
|
||||||
// can never be tail-recursive, so this is fine
|
// can never be tail-recursive, so this is fine
|
||||||
if let Some(ps) = param_map.get_symbol(*g, top_level) {
|
if let Some(ps) = param_map.get_symbol(g.name(), top_level) {
|
||||||
self.own_params_using_args(ys, ps)
|
self.own_params_using_args(ys, ps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -852,10 +849,10 @@ impl<'a> BorrowInfState<'a> {
|
||||||
|
|
||||||
let ys = Vec::from_iter_in(proc.args.iter().map(|t| t.1), self.arena).into_bump_slice();
|
let ys = Vec::from_iter_in(proc.args.iter().map(|t| t.1), self.arena).into_bump_slice();
|
||||||
self.update_param_set_symbols(ys);
|
self.update_param_set_symbols(ys);
|
||||||
self.current_proc = proc.name;
|
self.current_proc = proc.name.name();
|
||||||
|
|
||||||
// ensure that current_proc is in the owned map
|
// ensure that current_proc is in the owned map
|
||||||
self.owned.entry(proc.name).or_default();
|
self.owned.entry(proc.name.name()).or_default();
|
||||||
|
|
||||||
self.collect_stmt(param_map, &proc.body);
|
self.collect_stmt(param_map, &proc.body);
|
||||||
self.update_param_map_declaration(param_map, param_offset, proc.args.len());
|
self.update_param_map_declaration(param_map, param_offset, proc.args.len());
|
||||||
|
@ -887,14 +884,18 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
// - arguments that we may want to update destructively must be Owned
|
// - arguments that we may want to update destructively must be Owned
|
||||||
// - other refcounted arguments are Borrowed
|
// - other refcounted arguments are Borrowed
|
||||||
match op {
|
match op {
|
||||||
ListLen | StrIsEmpty | StrToScalars | StrCountGraphemes => {
|
ListLen | StrIsEmpty | StrToScalars | StrCountGraphemes | StrCountUtf8Bytes => {
|
||||||
arena.alloc_slice_copy(&[borrowed])
|
arena.alloc_slice_copy(&[borrowed])
|
||||||
}
|
}
|
||||||
ListWithCapacity => arena.alloc_slice_copy(&[irrelevant]),
|
ListWithCapacity => arena.alloc_slice_copy(&[irrelevant]),
|
||||||
ListReplaceUnsafe => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
ListReplaceUnsafe => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||||
ListGetUnsafe => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
StrGetUnsafe | ListGetUnsafe => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||||
ListConcat => arena.alloc_slice_copy(&[owned, owned]),
|
ListConcat => arena.alloc_slice_copy(&[owned, owned]),
|
||||||
StrConcat => arena.alloc_slice_copy(&[owned, borrowed]),
|
StrConcat => arena.alloc_slice_copy(&[owned, borrowed]),
|
||||||
|
StrSubstringUnsafe => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||||
|
StrReserve => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||||
|
StrAppendScalar => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||||
|
StrGetScalarUnsafe => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||||
StrTrim => arena.alloc_slice_copy(&[owned]),
|
StrTrim => arena.alloc_slice_copy(&[owned]),
|
||||||
StrTrimLeft => arena.alloc_slice_copy(&[owned]),
|
StrTrimLeft => arena.alloc_slice_copy(&[owned]),
|
||||||
StrTrimRight => arena.alloc_slice_copy(&[owned]),
|
StrTrimRight => arena.alloc_slice_copy(&[owned]),
|
||||||
|
@ -902,7 +903,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
StrToNum => arena.alloc_slice_copy(&[borrowed]),
|
StrToNum => arena.alloc_slice_copy(&[borrowed]),
|
||||||
ListPrepend => arena.alloc_slice_copy(&[owned, owned]),
|
ListPrepend => arena.alloc_slice_copy(&[owned, owned]),
|
||||||
StrJoinWith => arena.alloc_slice_copy(&[borrowed, borrowed]),
|
StrJoinWith => arena.alloc_slice_copy(&[borrowed, borrowed]),
|
||||||
ListMap | ListMapWithIndex => arena.alloc_slice_copy(&[owned, function, closure_data]),
|
ListMap => arena.alloc_slice_copy(&[owned, function, closure_data]),
|
||||||
ListMap2 => arena.alloc_slice_copy(&[owned, owned, function, closure_data]),
|
ListMap2 => arena.alloc_slice_copy(&[owned, owned, function, closure_data]),
|
||||||
ListMap3 => arena.alloc_slice_copy(&[owned, 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]),
|
ListMap4 => arena.alloc_slice_copy(&[owned, owned, owned, owned, function, closure_data]),
|
||||||
|
@ -975,7 +976,7 @@ fn call_info_call<'a>(call: &crate::ir::Call<'a>, info: &mut CallInfo<'a>) {
|
||||||
|
|
||||||
match call.call_type {
|
match call.call_type {
|
||||||
ByName { name, .. } => {
|
ByName { name, .. } => {
|
||||||
info.keys.push(name);
|
info.keys.push(name.name());
|
||||||
}
|
}
|
||||||
Foreign { .. } => {}
|
Foreign { .. } => {}
|
||||||
LowLevel { .. } => {}
|
LowLevel { .. } => {}
|
||||||
|
|
|
@ -530,12 +530,43 @@ fn eq_tag_fields<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eq_boxed<'a>(
|
fn eq_boxed<'a>(
|
||||||
_root: &mut CodeGenHelp<'a>,
|
root: &mut CodeGenHelp<'a>,
|
||||||
_ident_ids: &mut IdentIds,
|
ident_ids: &mut IdentIds,
|
||||||
_ctx: &mut Context<'a>,
|
ctx: &mut Context<'a>,
|
||||||
_inner_layout: &'a Layout<'a>,
|
inner_layout: &'a Layout<'a>,
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
todo!()
|
let a = root.create_symbol(ident_ids, "a");
|
||||||
|
let b = root.create_symbol(ident_ids, "b");
|
||||||
|
let result = root.create_symbol(ident_ids, "result");
|
||||||
|
|
||||||
|
let a_expr = Expr::ExprUnbox { symbol: ARG_1 };
|
||||||
|
let b_expr = Expr::ExprUnbox { symbol: ARG_2 };
|
||||||
|
let eq_call_expr = root
|
||||||
|
.call_specialized_op(ident_ids, ctx, *inner_layout, root.arena.alloc([a, b]))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Stmt::Let(
|
||||||
|
a,
|
||||||
|
a_expr,
|
||||||
|
*inner_layout,
|
||||||
|
root.arena.alloc(
|
||||||
|
//
|
||||||
|
Stmt::Let(
|
||||||
|
b,
|
||||||
|
b_expr,
|
||||||
|
*inner_layout,
|
||||||
|
root.arena.alloc(
|
||||||
|
//
|
||||||
|
Stmt::Let(
|
||||||
|
result,
|
||||||
|
eq_call_expr,
|
||||||
|
LAYOUT_BOOL,
|
||||||
|
root.arena.alloc(Stmt::Ret(result)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List equality
|
/// List equality
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::ir::{
|
||||||
Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout,
|
Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout,
|
||||||
SelfRecursive, Stmt, UpdateModeId,
|
SelfRecursive, Stmt, UpdateModeId,
|
||||||
};
|
};
|
||||||
use crate::layout::{Builtin, Layout, UnionLayout};
|
use crate::layout::{Builtin, CapturesNiche, LambdaName, Layout, UnionLayout};
|
||||||
|
|
||||||
mod equality;
|
mod equality;
|
||||||
mod refcount;
|
mod refcount;
|
||||||
|
@ -170,7 +170,7 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
let arg_layouts = self.arena.alloc([layout]);
|
let arg_layouts = self.arena.alloc([layout]);
|
||||||
let expr = Expr::Call(Call {
|
let expr = Expr::Call(Call {
|
||||||
call_type: CallType::ByName {
|
call_type: CallType::ByName {
|
||||||
name: proc_name,
|
name: LambdaName::no_niche(proc_name),
|
||||||
ret_layout,
|
ret_layout,
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
specialization_id: CallSpecId::BACKEND_DUMMY,
|
specialization_id: CallSpecId::BACKEND_DUMMY,
|
||||||
|
@ -262,7 +262,7 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
|
|
||||||
Some(Expr::Call(Call {
|
Some(Expr::Call(Call {
|
||||||
call_type: CallType::ByName {
|
call_type: CallType::ByName {
|
||||||
name: proc_name,
|
name: LambdaName::no_niche(proc_name),
|
||||||
ret_layout,
|
ret_layout,
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
specialization_id: CallSpecId::BACKEND_DUMMY,
|
specialization_id: CallSpecId::BACKEND_DUMMY,
|
||||||
|
@ -286,11 +286,11 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
ident_ids: &mut IdentIds,
|
ident_ids: &mut IdentIds,
|
||||||
ctx: &mut Context<'a>,
|
ctx: &mut Context<'a>,
|
||||||
layout: Layout<'a>,
|
orig_layout: Layout<'a>,
|
||||||
) -> Symbol {
|
) -> Symbol {
|
||||||
use HelperOp::*;
|
use HelperOp::*;
|
||||||
|
|
||||||
let layout = self.replace_rec_ptr(ctx, layout);
|
let layout = self.replace_rec_ptr(ctx, orig_layout);
|
||||||
|
|
||||||
let found = self
|
let found = self
|
||||||
.specializations
|
.specializations
|
||||||
|
@ -343,7 +343,7 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.specializations[spec_index].proc = Some(Proc {
|
self.specializations[spec_index].proc = Some(Proc {
|
||||||
name: proc_symbol,
|
name: LambdaName::no_niche(proc_symbol),
|
||||||
args,
|
args,
|
||||||
body,
|
body,
|
||||||
closure_data_layout: None,
|
closure_data_layout: None,
|
||||||
|
@ -375,19 +375,23 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
HelperOp::Inc => ProcLayout {
|
HelperOp::Inc => ProcLayout {
|
||||||
arguments: self.arena.alloc([*layout, self.layout_isize]),
|
arguments: self.arena.alloc([*layout, self.layout_isize]),
|
||||||
result: LAYOUT_UNIT,
|
result: LAYOUT_UNIT,
|
||||||
|
captures_niche: CapturesNiche::no_niche(),
|
||||||
},
|
},
|
||||||
HelperOp::Dec => ProcLayout {
|
HelperOp::Dec => ProcLayout {
|
||||||
arguments: self.arena.alloc([*layout]),
|
arguments: self.arena.alloc([*layout]),
|
||||||
result: LAYOUT_UNIT,
|
result: LAYOUT_UNIT,
|
||||||
|
captures_niche: CapturesNiche::no_niche(),
|
||||||
},
|
},
|
||||||
HelperOp::Reset => ProcLayout {
|
HelperOp::Reset => ProcLayout {
|
||||||
arguments: self.arena.alloc([*layout]),
|
arguments: self.arena.alloc([*layout]),
|
||||||
result: *layout,
|
result: *layout,
|
||||||
|
captures_niche: CapturesNiche::no_niche(),
|
||||||
},
|
},
|
||||||
HelperOp::DecRef(_) => unreachable!("No generated Proc for DecRef"),
|
HelperOp::DecRef(_) => unreachable!("No generated Proc for DecRef"),
|
||||||
HelperOp::Eq => ProcLayout {
|
HelperOp::Eq => ProcLayout {
|
||||||
arguments: self.arena.alloc([*layout, *layout]),
|
arguments: self.arena.alloc([*layout, *layout]),
|
||||||
result: LAYOUT_BOOL,
|
result: LAYOUT_BOOL,
|
||||||
|
captures_niche: CapturesNiche::no_niche(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -450,7 +454,9 @@ impl<'a> CodeGenHelp<'a> {
|
||||||
layout
|
layout
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout::Boxed(inner) => self.replace_rec_ptr(ctx, *inner),
|
Layout::Boxed(inner) => {
|
||||||
|
Layout::Boxed(self.arena.alloc(self.replace_rec_ptr(ctx, *inner)))
|
||||||
|
}
|
||||||
|
|
||||||
Layout::LambdaSet(lambda_set) => {
|
Layout::LambdaSet(lambda_set) => {
|
||||||
self.replace_rec_ptr(ctx, lambda_set.runtime_representation())
|
self.replace_rec_ptr(ctx, lambda_set.runtime_representation())
|
||||||
|
|
|
@ -129,7 +129,9 @@ pub fn refcount_generic<'a>(
|
||||||
Layout::RecursivePointer => unreachable!(
|
Layout::RecursivePointer => unreachable!(
|
||||||
"We should never call a refcounting helper on a RecursivePointer layout directly"
|
"We should never call a refcounting helper on a RecursivePointer layout directly"
|
||||||
),
|
),
|
||||||
Layout::Boxed(_) => rc_todo(),
|
Layout::Boxed(inner_layout) => {
|
||||||
|
refcount_boxed(root, ident_ids, ctx, &layout, inner_layout, structure)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +345,7 @@ pub fn is_rc_implemented_yet(layout: &Layout) -> bool {
|
||||||
is_rc_implemented_yet(&lambda_set.runtime_representation())
|
is_rc_implemented_yet(&lambda_set.runtime_representation())
|
||||||
}
|
}
|
||||||
Layout::RecursivePointer => true,
|
Layout::RecursivePointer => true,
|
||||||
Layout::Boxed(_) => false,
|
Layout::Boxed(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1465,3 +1467,66 @@ fn refcount_tag_fields<'a>(
|
||||||
|
|
||||||
stmt
|
stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn refcount_boxed<'a>(
|
||||||
|
root: &mut CodeGenHelp<'a>,
|
||||||
|
ident_ids: &mut IdentIds,
|
||||||
|
ctx: &mut Context<'a>,
|
||||||
|
layout: &Layout,
|
||||||
|
inner_layout: &'a Layout,
|
||||||
|
outer: Symbol,
|
||||||
|
) -> Stmt<'a> {
|
||||||
|
let arena = root.arena;
|
||||||
|
|
||||||
|
//
|
||||||
|
// modify refcount of the inner and outer structures
|
||||||
|
// RC on inner first, to avoid use-after-free for Dec
|
||||||
|
// We're defining statements in reverse, so define outer first
|
||||||
|
//
|
||||||
|
|
||||||
|
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
|
||||||
|
let alignment = layout.alignment_bytes(root.target_info);
|
||||||
|
let ret_stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||||
|
let modify_outer = modify_refcount(
|
||||||
|
root,
|
||||||
|
ident_ids,
|
||||||
|
ctx,
|
||||||
|
rc_ptr,
|
||||||
|
alignment,
|
||||||
|
arena.alloc(ret_stmt),
|
||||||
|
);
|
||||||
|
|
||||||
|
let get_rc_and_modify_outer = rc_ptr_from_data_ptr(
|
||||||
|
root,
|
||||||
|
ident_ids,
|
||||||
|
outer,
|
||||||
|
rc_ptr,
|
||||||
|
false,
|
||||||
|
arena.alloc(modify_outer),
|
||||||
|
);
|
||||||
|
|
||||||
|
if inner_layout.is_refcounted() && !ctx.op.is_decref() {
|
||||||
|
let inner = root.create_symbol(ident_ids, "inner");
|
||||||
|
let inner_expr = Expr::ExprUnbox { symbol: outer };
|
||||||
|
|
||||||
|
let mod_inner_unit = root.create_symbol(ident_ids, "mod_inner_unit");
|
||||||
|
let mod_inner_args = refcount_args(root, ctx, inner);
|
||||||
|
let mod_inner_expr = root
|
||||||
|
.call_specialized_op(ident_ids, ctx, *inner_layout, mod_inner_args)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Stmt::Let(
|
||||||
|
inner,
|
||||||
|
inner_expr,
|
||||||
|
*inner_layout,
|
||||||
|
arena.alloc(Stmt::Let(
|
||||||
|
mod_inner_unit,
|
||||||
|
mod_inner_expr,
|
||||||
|
LAYOUT_UNIT,
|
||||||
|
arena.alloc(get_rc_and_modify_outer),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
get_rc_and_modify_outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -564,12 +564,13 @@ impl<'a> Context<'a> {
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let top_level = ProcLayout::new(self.arena, arg_layouts, **ret_layout);
|
let top_level =
|
||||||
|
ProcLayout::new(self.arena, arg_layouts, name.captures_niche(), **ret_layout);
|
||||||
|
|
||||||
// get the borrow signature
|
// get the borrow signature
|
||||||
let ps = self
|
let ps = self
|
||||||
.param_map
|
.param_map
|
||||||
.get_symbol(*name, top_level)
|
.get_symbol(name.name(), top_level)
|
||||||
.expect("function is defined");
|
.expect("function is defined");
|
||||||
|
|
||||||
let v = Expr::Call(crate::ir::Call {
|
let v = Expr::Call(crate::ir::Call {
|
||||||
|
@ -614,11 +615,12 @@ impl<'a> Context<'a> {
|
||||||
let function_layout = ProcLayout {
|
let function_layout = ProcLayout {
|
||||||
arguments: passed_function.argument_layouts,
|
arguments: passed_function.argument_layouts,
|
||||||
result: passed_function.return_layout,
|
result: passed_function.return_layout,
|
||||||
|
captures_niche: passed_function.name.captures_niche(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let function_ps = match self
|
let function_ps = match self
|
||||||
.param_map
|
.param_map
|
||||||
.get_symbol(passed_function.name, function_layout)
|
.get_symbol(passed_function.name.name(), function_layout)
|
||||||
{
|
{
|
||||||
Some(function_ps) => function_ps,
|
Some(function_ps) => function_ps,
|
||||||
None => unreachable!(),
|
None => unreachable!(),
|
||||||
|
@ -746,17 +748,6 @@ impl<'a> Context<'a> {
|
||||||
|
|
||||||
handle_ownerships_pre!(Stmt::Let(z, v, l, b), ownerships)
|
handle_ownerships_pre!(Stmt::Let(z, v, l, b), ownerships)
|
||||||
}
|
}
|
||||||
ListMapWithIndex { xs } => {
|
|
||||||
let ownerships = [(xs, function_ps[0])];
|
|
||||||
|
|
||||||
let b = self.add_dec_after_lowlevel(after_arguments, &borrows, b, b_live_vars);
|
|
||||||
|
|
||||||
let b = handle_ownerships_post!(b, ownerships);
|
|
||||||
|
|
||||||
let v = create_call!(function_ps.get(2));
|
|
||||||
|
|
||||||
handle_ownerships_pre!(Stmt::Let(z, v, l, b), ownerships)
|
|
||||||
}
|
|
||||||
ListSortWith { xs } => {
|
ListSortWith { xs } => {
|
||||||
// NOTE: we may apply the function to the same argument multiple times.
|
// NOTE: we may apply the function to the same argument multiple times.
|
||||||
// for that to be valid, the function must borrow its argument. This is not
|
// for that to be valid, the function must borrow its argument. This is not
|
||||||
|
@ -1406,7 +1397,7 @@ fn visit_proc<'a, 'i>(
|
||||||
proc: &mut Proc<'a>,
|
proc: &mut Proc<'a>,
|
||||||
layout: ProcLayout<'a>,
|
layout: ProcLayout<'a>,
|
||||||
) {
|
) {
|
||||||
let params = match param_map.get_symbol(proc.name, layout) {
|
let params = match param_map.get_symbol(proc.name.name(), layout) {
|
||||||
Some(slice) => slice,
|
Some(slice) => slice,
|
||||||
None => Vec::from_iter_in(
|
None => Vec::from_iter_in(
|
||||||
proc.args.iter().cloned().map(|(layout, symbol)| Param {
|
proc.args.iter().cloned().map(|(layout, symbol)| Param {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,7 +8,6 @@ use roc_module::ident::{Lowercase, TagName};
|
||||||
use roc_module::symbol::{Interns, Symbol};
|
use roc_module::symbol::{Interns, Symbol};
|
||||||
use roc_problem::can::RuntimeError;
|
use roc_problem::can::RuntimeError;
|
||||||
use roc_target::{PtrWidth, TargetInfo};
|
use roc_target::{PtrWidth, TargetInfo};
|
||||||
use roc_types::pretty_print::ResolvedLambdaSet;
|
|
||||||
use roc_types::subs::{
|
use roc_types::subs::{
|
||||||
self, Content, FlatType, Label, RecordFields, Subs, UnionTags, UnsortedUnionLabels, Variable,
|
self, Content, FlatType, Label, RecordFields, Subs, UnionTags, UnsortedUnionLabels, Variable,
|
||||||
};
|
};
|
||||||
|
@ -226,7 +225,7 @@ impl<'a> RawFunctionLayout<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct FieldOrderHash(u64);
|
pub struct FieldOrderHash(u64);
|
||||||
|
|
||||||
impl FieldOrderHash {
|
impl FieldOrderHash {
|
||||||
|
@ -248,7 +247,7 @@ impl FieldOrderHash {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Types for code gen must be monomorphic. No type variables allowed!
|
/// Types for code gen must be monomorphic. No type variables allowed!
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub enum Layout<'a> {
|
pub enum Layout<'a> {
|
||||||
Builtin(Builtin<'a>),
|
Builtin(Builtin<'a>),
|
||||||
Struct {
|
Struct {
|
||||||
|
@ -270,7 +269,7 @@ pub enum Layout<'a> {
|
||||||
RecursivePointer,
|
RecursivePointer,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub enum UnionLayout<'a> {
|
pub enum UnionLayout<'a> {
|
||||||
/// A non-recursive tag union
|
/// A non-recursive tag union
|
||||||
/// e.g. `Result a e : [Ok a, Err e]`
|
/// e.g. `Result a e : [Ok a, Err e]`
|
||||||
|
@ -693,7 +692,74 @@ impl std::fmt::Debug for LambdaSet<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
/// Sometimes we can end up with lambdas of the same name and different captures in the same
|
||||||
|
/// lambda set, like `fun` having lambda set `[[thunk U64, thunk U8]]` due to the following program:
|
||||||
|
///
|
||||||
|
/// ```roc
|
||||||
|
/// capture : _ -> ({} -> Str)
|
||||||
|
/// capture = \val ->
|
||||||
|
/// thunk = \{} -> Num.toStr val
|
||||||
|
/// thunk
|
||||||
|
///
|
||||||
|
/// fun = \x ->
|
||||||
|
/// when x is
|
||||||
|
/// True -> capture 123u64
|
||||||
|
/// False -> capture 18u8
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// By recording the captures layouts this lambda expects in its identifier, we can distinguish
|
||||||
|
/// between such differences when constructing closure capture data.
|
||||||
|
///
|
||||||
|
/// See also https://github.com/rtfeldman/roc/issues/3336.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub struct CapturesNiche<'a>(&'a [Layout<'a>]);
|
||||||
|
|
||||||
|
impl CapturesNiche<'_> {
|
||||||
|
pub fn no_niche() -> Self {
|
||||||
|
Self(&[])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub struct LambdaName<'a> {
|
||||||
|
name: Symbol,
|
||||||
|
captures_niche: CapturesNiche<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LambdaName<'a> {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn name(&self) -> Symbol {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn captures_niche(&self) -> CapturesNiche<'a> {
|
||||||
|
self.captures_niche
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn no_captures(&self) -> bool {
|
||||||
|
self.captures_niche.0.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn no_niche(name: Symbol) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
captures_niche: CapturesNiche::no_niche(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn replace_name(&self, name: Symbol) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
captures_niche: self.captures_niche,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub struct LambdaSet<'a> {
|
pub struct LambdaSet<'a> {
|
||||||
/// collection of function names and their closure arguments
|
/// collection of function names and their closure arguments
|
||||||
pub set: &'a [(Symbol, &'a [Layout<'a>])],
|
pub set: &'a [(Symbol, &'a [Layout<'a>])],
|
||||||
|
@ -741,23 +807,57 @@ impl<'a> LambdaSet<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn member_does_not_need_closure_argument(&self, function_symbol: Symbol) -> bool {
|
pub fn iter_set(&self) -> impl ExactSizeIterator<Item = LambdaName<'a>> {
|
||||||
match self.layout_for_member(function_symbol) {
|
self.set.iter().map(|(name, captures_layouts)| LambdaName {
|
||||||
ClosureRepresentation::Union {
|
name: *name,
|
||||||
alphabetic_order_fields,
|
captures_niche: CapturesNiche(captures_layouts),
|
||||||
..
|
})
|
||||||
} => alphabetic_order_fields.is_empty(),
|
}
|
||||||
ClosureRepresentation::AlphabeticOrderStruct(fields) => fields.is_empty(),
|
|
||||||
ClosureRepresentation::Other(_) => false,
|
pub fn layout_for_member_with_lambda_name(
|
||||||
|
&self,
|
||||||
|
lambda_name: LambdaName,
|
||||||
|
) -> ClosureRepresentation<'a> {
|
||||||
|
debug_assert!(self.contains(lambda_name.name));
|
||||||
|
|
||||||
|
let comparator = |other_name: Symbol, other_captures_layouts: &[Layout]| {
|
||||||
|
other_name == lambda_name.name
|
||||||
|
&& other_captures_layouts
|
||||||
|
.iter()
|
||||||
|
.eq(lambda_name.captures_niche.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.layout_for_member(comparator)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finds an alias name for a possible-multimorphic lambda variant in the lambda set.
|
||||||
|
pub fn find_lambda_name(
|
||||||
|
&self,
|
||||||
|
function_symbol: Symbol,
|
||||||
|
captures_layouts: &[Layout],
|
||||||
|
) -> LambdaName<'a> {
|
||||||
|
debug_assert!(self.contains(function_symbol), "function symbol not in set");
|
||||||
|
|
||||||
|
let comparator = |other_name: Symbol, other_captures_layouts: &[Layout]| {
|
||||||
|
other_name == function_symbol && other_captures_layouts.iter().eq(captures_layouts)
|
||||||
|
};
|
||||||
|
|
||||||
|
let (name, layouts) = self
|
||||||
|
.set
|
||||||
|
.iter()
|
||||||
|
.find(|(name, layouts)| comparator(*name, layouts))
|
||||||
|
.expect("no lambda set found");
|
||||||
|
|
||||||
|
LambdaName {
|
||||||
|
name: *name,
|
||||||
|
captures_niche: CapturesNiche(layouts),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout_for_member(&self, function_symbol: Symbol) -> ClosureRepresentation<'a> {
|
fn layout_for_member<F>(&self, comparator: F) -> ClosureRepresentation<'a>
|
||||||
debug_assert!(
|
where
|
||||||
self.set.iter().any(|(s, _)| *s == function_symbol),
|
F: Fn(Symbol, &[Layout]) -> bool,
|
||||||
"function symbol not in set"
|
{
|
||||||
);
|
|
||||||
|
|
||||||
match self.representation {
|
match self.representation {
|
||||||
Layout::Union(union) => {
|
Layout::Union(union) => {
|
||||||
// here we rely on the fact that a union in a closure would be stored in a one-element record.
|
// here we rely on the fact that a union in a closure would be stored in a one-element record.
|
||||||
|
@ -766,17 +866,19 @@ impl<'a> LambdaSet<'a> {
|
||||||
UnionLayout::NonRecursive(_) => {
|
UnionLayout::NonRecursive(_) => {
|
||||||
// get the fields from the set, where they are sorted in alphabetic order
|
// get the fields from the set, where they are sorted in alphabetic order
|
||||||
// (and not yet sorted by their alignment)
|
// (and not yet sorted by their alignment)
|
||||||
let (index, (_, fields)) = self
|
let (index, (name, fields)) = self
|
||||||
.set
|
.set
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, (s, _))| *s == function_symbol)
|
.find(|(_, (s, layouts))| comparator(*s, layouts))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let closure_name = *name;
|
||||||
|
|
||||||
ClosureRepresentation::Union {
|
ClosureRepresentation::Union {
|
||||||
tag_id: index as TagIdIntType,
|
tag_id: index as TagIdIntType,
|
||||||
alphabetic_order_fields: fields,
|
alphabetic_order_fields: fields,
|
||||||
closure_name: function_symbol,
|
closure_name,
|
||||||
union_layout: *union,
|
union_layout: *union,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -793,12 +895,14 @@ impl<'a> LambdaSet<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Layout::Struct { .. } => {
|
Layout::Struct { .. } => {
|
||||||
|
debug_assert_eq!(self.set.len(), 1);
|
||||||
|
|
||||||
// get the fields from the set, where they are sorted in alphabetic order
|
// get the fields from the set, where they are sorted in alphabetic order
|
||||||
// (and not yet sorted by their alignment)
|
// (and not yet sorted by their alignment)
|
||||||
let (_, fields) = self
|
let (_, fields) = self
|
||||||
.set
|
.set
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(s, _)| *s == function_symbol)
|
.find(|(s, layouts)| comparator(*s, layouts))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
ClosureRepresentation::AlphabeticOrderStruct(fields)
|
ClosureRepresentation::AlphabeticOrderStruct(fields)
|
||||||
|
@ -846,32 +950,86 @@ impl<'a> LambdaSet<'a> {
|
||||||
closure_var: Variable,
|
closure_var: Variable,
|
||||||
target_info: TargetInfo,
|
target_info: TargetInfo,
|
||||||
) -> Result<Self, LayoutProblem> {
|
) -> Result<Self, LayoutProblem> {
|
||||||
match roc_types::pretty_print::resolve_lambda_set(subs, closure_var) {
|
match resolve_lambda_set(subs, closure_var) {
|
||||||
ResolvedLambdaSet::Set(mut lambdas) => {
|
ResolvedLambdaSet::Set(mut lambdas) => {
|
||||||
// sort the tags; make sure ordering stays intact!
|
// sort the tags; make sure ordering stays intact!
|
||||||
lambdas.sort();
|
lambdas.sort_by_key(|(sym, _)| *sym);
|
||||||
|
|
||||||
let mut set = Vec::with_capacity_in(lambdas.len(), arena);
|
let mut set: Vec<(Symbol, &[Layout])> = Vec::with_capacity_in(lambdas.len(), arena);
|
||||||
|
let mut set_with_variables: std::vec::Vec<(Symbol, std::vec::Vec<Variable>)> =
|
||||||
|
std::vec::Vec::with_capacity(lambdas.len());
|
||||||
|
|
||||||
let mut env = Env {
|
let mut last_function_symbol = None;
|
||||||
arena,
|
let mut lambdas_it = lambdas.iter().peekable();
|
||||||
subs,
|
|
||||||
seen: Vec::new_in(arena),
|
|
||||||
target_info,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (function_symbol, variables) in lambdas.iter() {
|
let mut has_duplicate_lambda_names = false;
|
||||||
|
while let Some((function_symbol, variables)) = lambdas_it.next() {
|
||||||
let mut arguments = Vec::with_capacity_in(variables.len(), arena);
|
let mut arguments = Vec::with_capacity_in(variables.len(), arena);
|
||||||
|
|
||||||
|
let mut env = Env {
|
||||||
|
arena,
|
||||||
|
subs,
|
||||||
|
seen: Vec::new_in(arena),
|
||||||
|
target_info,
|
||||||
|
};
|
||||||
|
|
||||||
for var in variables {
|
for var in variables {
|
||||||
arguments.push(Layout::from_var(&mut env, *var)?);
|
arguments.push(Layout::from_var(&mut env, *var)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
set.push((*function_symbol, arguments.into_bump_slice()));
|
let arguments = arguments.into_bump_slice();
|
||||||
|
|
||||||
|
let is_multimorphic = match (last_function_symbol, lambdas_it.peek()) {
|
||||||
|
(None, None) => false,
|
||||||
|
(Some(sym), None) | (None, Some((sym, _))) => function_symbol == sym,
|
||||||
|
(Some(sym1), Some((sym2, _))) => {
|
||||||
|
function_symbol == sym1 || function_symbol == sym2
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
has_duplicate_lambda_names = has_duplicate_lambda_names || is_multimorphic;
|
||||||
|
|
||||||
|
set.push((*function_symbol, arguments));
|
||||||
|
set_with_variables.push((*function_symbol, variables.to_vec()));
|
||||||
|
|
||||||
|
last_function_symbol = Some(function_symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
let representation =
|
let (set, set_with_variables) = if has_duplicate_lambda_names {
|
||||||
arena.alloc(Self::make_representation(arena, subs, lambdas, target_info));
|
// If we have a lambda set with duplicate names, then we sort first by name,
|
||||||
|
// and break ties by sorting on the layout. We need to do this again since the
|
||||||
|
// first sort would not have sorted on the layout.
|
||||||
|
|
||||||
|
// TODO: be more efficient, we can compute the permutation once and then apply
|
||||||
|
// it to both vectors.
|
||||||
|
let mut joined = set
|
||||||
|
.into_iter()
|
||||||
|
.zip(set_with_variables.into_iter())
|
||||||
|
.collect::<std::vec::Vec<_>>();
|
||||||
|
joined.sort_by(|(lam_and_captures1, _), (lam_and_captures2, _)| {
|
||||||
|
lam_and_captures1.cmp(lam_and_captures2)
|
||||||
|
});
|
||||||
|
// Remove duplicate lambda captures layouts unification can't see as
|
||||||
|
// duplicates, for example [[Thunk {a: Str}, Thunk [A Str]]], each of which are
|
||||||
|
// newtypes over the lambda layout `Thunk Str`.
|
||||||
|
joined.dedup_by_key(|((name, captures), _)| (*name, *captures));
|
||||||
|
|
||||||
|
let (set, set_with_variables): (std::vec::Vec<_>, std::vec::Vec<_>) =
|
||||||
|
joined.into_iter().unzip();
|
||||||
|
|
||||||
|
let set = Vec::from_iter_in(set, arena);
|
||||||
|
|
||||||
|
(set, set_with_variables)
|
||||||
|
} else {
|
||||||
|
(set, set_with_variables)
|
||||||
|
};
|
||||||
|
|
||||||
|
let representation = arena.alloc(Self::make_representation(
|
||||||
|
arena,
|
||||||
|
subs,
|
||||||
|
set_with_variables,
|
||||||
|
target_info,
|
||||||
|
));
|
||||||
|
|
||||||
Ok(LambdaSet {
|
Ok(LambdaSet {
|
||||||
set: set.into_bump_slice(),
|
set: set.into_bump_slice(),
|
||||||
|
@ -951,7 +1109,41 @@ impl<'a> LambdaSet<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
enum ResolvedLambdaSet {
|
||||||
|
Set(std::vec::Vec<(Symbol, std::vec::Vec<Variable>)>),
|
||||||
|
/// TODO: figure out if this can happen in a correct program, or is the result of a bug in our
|
||||||
|
/// compiler. See https://github.com/rtfeldman/roc/issues/3163.
|
||||||
|
Unbound,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_lambda_set(subs: &Subs, mut var: Variable) -> ResolvedLambdaSet {
|
||||||
|
let mut set = vec![];
|
||||||
|
loop {
|
||||||
|
match subs.get_content_without_compacting(var) {
|
||||||
|
Content::LambdaSet(subs::LambdaSet {
|
||||||
|
solved,
|
||||||
|
recursion_var: _,
|
||||||
|
unspecialized,
|
||||||
|
}) => {
|
||||||
|
debug_assert!(
|
||||||
|
unspecialized.is_empty(),
|
||||||
|
"unspecialized lambda sets left over during resolution: {:?}",
|
||||||
|
roc_types::subs::SubsFmtContent(subs.get_content_without_compacting(var), subs),
|
||||||
|
);
|
||||||
|
roc_types::pretty_print::push_union(subs, solved, &mut set);
|
||||||
|
return ResolvedLambdaSet::Set(set);
|
||||||
|
}
|
||||||
|
Content::RecursionVar { structure, .. } => {
|
||||||
|
var = *structure;
|
||||||
|
}
|
||||||
|
Content::FlexVar(_) => return ResolvedLambdaSet::Unbound,
|
||||||
|
|
||||||
|
c => internal_error!("called with a non-lambda set {:?}", c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
pub enum Builtin<'a> {
|
pub enum Builtin<'a> {
|
||||||
Int(IntWidth),
|
Int(IntWidth),
|
||||||
Float(FloatWidth),
|
Float(FloatWidth),
|
||||||
|
|
|
@ -20,9 +20,6 @@ pub enum HigherOrder {
|
||||||
zs: Symbol,
|
zs: Symbol,
|
||||||
ws: Symbol,
|
ws: Symbol,
|
||||||
},
|
},
|
||||||
ListMapWithIndex {
|
|
||||||
xs: Symbol,
|
|
||||||
},
|
|
||||||
ListSortWith {
|
ListSortWith {
|
||||||
xs: Symbol,
|
xs: Symbol,
|
||||||
},
|
},
|
||||||
|
@ -39,7 +36,6 @@ impl HigherOrder {
|
||||||
HigherOrder::ListMap2 { .. } => 2,
|
HigherOrder::ListMap2 { .. } => 2,
|
||||||
HigherOrder::ListMap3 { .. } => 3,
|
HigherOrder::ListMap3 { .. } => 3,
|
||||||
HigherOrder::ListMap4 { .. } => 4,
|
HigherOrder::ListMap4 { .. } => 4,
|
||||||
HigherOrder::ListMapWithIndex { .. } => 2,
|
|
||||||
HigherOrder::ListSortWith { .. } => 2,
|
HigherOrder::ListSortWith { .. } => 2,
|
||||||
HigherOrder::DictWalk { .. } => 2,
|
HigherOrder::DictWalk { .. } => 2,
|
||||||
}
|
}
|
||||||
|
@ -51,7 +47,7 @@ impl HigherOrder {
|
||||||
use HigherOrder::*;
|
use HigherOrder::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
ListMap { .. } | ListMapWithIndex { .. } | ListSortWith { .. } => 2,
|
ListMap { .. } | ListSortWith { .. } => 2,
|
||||||
ListMap2 { .. } => 3,
|
ListMap2 { .. } => 3,
|
||||||
ListMap3 { .. } => 4,
|
ListMap3 { .. } => 4,
|
||||||
ListMap4 { .. } => 5,
|
ListMap4 { .. } => 5,
|
||||||
|
|
|
@ -97,7 +97,6 @@ fn function_s<'a, 'i>(
|
||||||
Expr::Tag {
|
Expr::Tag {
|
||||||
tag_layout,
|
tag_layout,
|
||||||
tag_id,
|
tag_id,
|
||||||
tag_name,
|
|
||||||
arguments,
|
arguments,
|
||||||
} if may_reuse(*tag_layout, *tag_id, c) => {
|
} if may_reuse(*tag_layout, *tag_id, c) => {
|
||||||
// for now, always overwrite the tag ID just to be sure
|
// for now, always overwrite the tag ID just to be sure
|
||||||
|
@ -109,7 +108,6 @@ fn function_s<'a, 'i>(
|
||||||
update_tag_id,
|
update_tag_id,
|
||||||
tag_layout: *tag_layout,
|
tag_layout: *tag_layout,
|
||||||
tag_id: *tag_id,
|
tag_id: *tag_id,
|
||||||
tag_name: tag_name.clone(),
|
|
||||||
arguments,
|
arguments,
|
||||||
};
|
};
|
||||||
let new_stmt = Let(*symbol, new_expr, *layout, continuation);
|
let new_stmt = Let(*symbol, new_expr, *layout, continuation);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![allow(clippy::manual_map)]
|
#![allow(clippy::manual_map)]
|
||||||
|
|
||||||
use crate::ir::{CallType, Expr, JoinPointId, Param, Stmt};
|
use crate::ir::{CallType, Expr, JoinPointId, Param, Stmt};
|
||||||
use crate::layout::Layout;
|
use crate::layout::{LambdaName, Layout};
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
|
@ -31,7 +31,7 @@ use roc_module::symbol::Symbol;
|
||||||
pub fn make_tail_recursive<'a>(
|
pub fn make_tail_recursive<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
id: JoinPointId,
|
id: JoinPointId,
|
||||||
needle: Symbol,
|
needle: LambdaName,
|
||||||
stmt: Stmt<'a>,
|
stmt: Stmt<'a>,
|
||||||
args: &'a [(Layout<'a>, Symbol, Symbol)],
|
args: &'a [(Layout<'a>, Symbol, Symbol)],
|
||||||
ret_layout: Layout,
|
ret_layout: Layout,
|
||||||
|
@ -71,7 +71,7 @@ fn insert_jumps<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
stmt: &'a Stmt<'a>,
|
stmt: &'a Stmt<'a>,
|
||||||
goal_id: JoinPointId,
|
goal_id: JoinPointId,
|
||||||
needle: Symbol,
|
needle: LambdaName,
|
||||||
needle_arguments: &'a [(Layout<'a>, Symbol, Symbol)],
|
needle_arguments: &'a [(Layout<'a>, Symbol, Symbol)],
|
||||||
needle_result: Layout,
|
needle_result: Layout,
|
||||||
) -> Option<&'a Stmt<'a>> {
|
) -> Option<&'a Stmt<'a>> {
|
||||||
|
@ -80,7 +80,7 @@ fn insert_jumps<'a>(
|
||||||
// to insert a tail-call, it must not just be a call to the function itself, but it must also
|
// to insert a tail-call, it must not just be a call to the function itself, but it must also
|
||||||
// have the same layout. In particular when lambda sets get involved, a self-recursive call may
|
// have the same layout. In particular when lambda sets get involved, a self-recursive call may
|
||||||
// have a different type and should not be converted to a jump!
|
// have a different type and should not be converted to a jump!
|
||||||
let is_equal_function = |function_name: Symbol, arguments: &[_], result| {
|
let is_equal_function = |function_name: LambdaName, arguments: &[_], result| {
|
||||||
let it = needle_arguments.iter().map(|t| &t.0);
|
let it = needle_arguments.iter().map(|t| &t.0);
|
||||||
needle == function_name && it.eq(arguments.iter()) && needle_result == result
|
needle == function_name && it.eq(arguments.iter()) && needle_result == result
|
||||||
};
|
};
|
||||||
|
|
|
@ -1451,7 +1451,7 @@ macro_rules! word1_check_indent {
|
||||||
($word:expr, $word_problem:expr, $min_indent:expr, $indent_problem:expr) => {
|
($word:expr, $word_problem:expr, $min_indent:expr, $indent_problem:expr) => {
|
||||||
and!(
|
and!(
|
||||||
word1($word, $word_problem),
|
word1($word, $word_problem),
|
||||||
crate::parser::check_indent($min_indent, $indent_problem)
|
$crate::parser::check_indent($min_indent, $indent_problem)
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6953,6 +6953,101 @@ mod solve_expr {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Str",
|
"Str",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lambda_sets_collide_with_captured_var() {
|
||||||
|
infer_queries!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
capture : a -> ({} -> Str)
|
||||||
|
capture = \val ->
|
||||||
|
thunk =
|
||||||
|
\{} ->
|
||||||
|
when val is
|
||||||
|
_ -> ""
|
||||||
|
thunk
|
||||||
|
|
||||||
|
x : [True, False]
|
||||||
|
|
||||||
|
fun =
|
||||||
|
when x is
|
||||||
|
True -> capture ""
|
||||||
|
# ^^^^^^^
|
||||||
|
False -> capture {}
|
||||||
|
# ^^^^^^^
|
||||||
|
fun
|
||||||
|
#^^^{-1}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
&[
|
||||||
|
"capture : Str -[[capture(1)]]-> ({} -[[thunk(5) {}, thunk(5) Str]]-> Str)",
|
||||||
|
"capture : {} -[[capture(1)]]-> ({} -[[thunk(5) {}, thunk(5) Str]]-> Str)",
|
||||||
|
"fun : {} -[[thunk(5) {}, thunk(5) Str]]-> Str",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lambda_sets_collide_with_captured_function() {
|
||||||
|
infer_queries!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Lazy a : {} -> a
|
||||||
|
|
||||||
|
after : Lazy a, (a -> Lazy b) -> Lazy b
|
||||||
|
after = \effect, map ->
|
||||||
|
thunk = \{} ->
|
||||||
|
when map (effect {}) is
|
||||||
|
b -> b {}
|
||||||
|
thunk
|
||||||
|
|
||||||
|
f = \_ -> \_ -> ""
|
||||||
|
g = \{ s1 } -> \_ -> s1
|
||||||
|
|
||||||
|
x : [True, False]
|
||||||
|
|
||||||
|
fun =
|
||||||
|
when x is
|
||||||
|
True -> after (\{} -> "") f
|
||||||
|
False -> after (\{} -> {s1: "s1"}) g
|
||||||
|
fun
|
||||||
|
#^^^{-1}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
&[
|
||||||
|
"fun : {} -[[thunk(9) (({} -[[15(15)]]-> { s1 : Str })) ({ s1 : Str } -[[g(4)]]-> ({} -[[13(13) Str]]-> Str)), \
|
||||||
|
thunk(9) (({} -[[14(14)]]-> Str)) (Str -[[f(3)]]-> ({} -[[11(11)]]-> Str))]]-> Str",
|
||||||
|
],
|
||||||
|
print_only_under_alias = true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lambda_set_niche_same_layout_different_constructor() {
|
||||||
|
infer_queries!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
capture : a -> ({} -> Str)
|
||||||
|
capture = \val ->
|
||||||
|
thunk =
|
||||||
|
\{} ->
|
||||||
|
when val is
|
||||||
|
_ -> ""
|
||||||
|
thunk
|
||||||
|
|
||||||
|
x : [True, False]
|
||||||
|
|
||||||
|
fun =
|
||||||
|
when x is
|
||||||
|
True -> capture {a: ""}
|
||||||
|
False -> capture (A "")
|
||||||
|
fun
|
||||||
|
#^^^{-1}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
&["fun : {} -[[thunk(5) [A Str]*, thunk(5) { a : Str }]]-> Str",]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -672,3 +672,25 @@ fn compare_nullable_recursive_union_same_content() {
|
||||||
bool
|
bool
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn boxed_eq_int() {
|
||||||
|
assert_evals_to!("Box.box 1 == Box.box 1", true, bool);
|
||||||
|
assert_evals_to!("Box.box 2 == Box.box 1", false, bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn boxed_eq_str() {
|
||||||
|
assert_evals_to!(
|
||||||
|
"Box.box \"Hello, world\" == Box.box \"Hello, world\"",
|
||||||
|
true,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
assert_evals_to!(
|
||||||
|
"Box.box \"Hello, world\" == Box.box \"Hello, stranger\"",
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -2567,7 +2567,7 @@ fn list_keep_errs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn list_map_with_index() {
|
fn list_map_with_index() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
"List.mapWithIndex [0,0,0] (\\x, index -> Num.intCast index + x)",
|
"List.mapWithIndex [0,0,0] (\\x, index -> Num.intCast index + x)",
|
||||||
|
|
|
@ -3498,3 +3498,129 @@ fn polymorphic_lambda_captures_polymorphic_value() {
|
||||||
u64
|
u64
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn lambda_capture_niche_u64_vs_u8_capture() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
capture : _ -> ({} -> Str)
|
||||||
|
capture = \val ->
|
||||||
|
\{} ->
|
||||||
|
Num.toStr val
|
||||||
|
|
||||||
|
x : [True, False]
|
||||||
|
x = True
|
||||||
|
|
||||||
|
fun =
|
||||||
|
when x is
|
||||||
|
True -> capture 123u64
|
||||||
|
False -> capture 18u8
|
||||||
|
|
||||||
|
fun {}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
RocStr::from("123"),
|
||||||
|
RocStr
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn lambda_capture_niches_with_other_lambda_capture() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
capture : _ -> ({} -> Str)
|
||||||
|
capture = \val ->
|
||||||
|
\{} ->
|
||||||
|
Num.toStr val
|
||||||
|
|
||||||
|
capture2 = \val -> \{} -> val
|
||||||
|
|
||||||
|
f = \x ->
|
||||||
|
g =
|
||||||
|
when x is
|
||||||
|
A -> capture 11u8
|
||||||
|
B -> capture2 "lisa"
|
||||||
|
C -> capture 187128u64
|
||||||
|
g {}
|
||||||
|
|
||||||
|
{a: f A, b: f B, c: f C}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(
|
||||||
|
RocStr::from("11"),
|
||||||
|
RocStr::from("lisa"),
|
||||||
|
RocStr::from("187128")
|
||||||
|
),
|
||||||
|
(RocStr, RocStr, RocStr)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn lambda_capture_niches_with_non_capturing_function() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
capture : _ -> ({} -> Str)
|
||||||
|
capture = \val ->
|
||||||
|
\{} ->
|
||||||
|
Num.toStr val
|
||||||
|
|
||||||
|
triv = \{} -> "triv"
|
||||||
|
|
||||||
|
f = \x ->
|
||||||
|
g =
|
||||||
|
when x is
|
||||||
|
A -> capture 11u8
|
||||||
|
B -> triv
|
||||||
|
C -> capture 187128u64
|
||||||
|
g {}
|
||||||
|
|
||||||
|
{a: f A, b: f B, c: f C}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(
|
||||||
|
RocStr::from("11"),
|
||||||
|
RocStr::from("triv"),
|
||||||
|
RocStr::from("187128")
|
||||||
|
),
|
||||||
|
(RocStr, RocStr, RocStr)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn lambda_capture_niches_have_captured_function_in_closure() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Lazy a : {} -> a
|
||||||
|
|
||||||
|
after : Lazy a, (a -> Lazy b) -> Lazy b
|
||||||
|
after = \effect, map ->
|
||||||
|
thunk = \{} ->
|
||||||
|
when map (effect {}) is
|
||||||
|
b -> b {}
|
||||||
|
thunk
|
||||||
|
|
||||||
|
f = \_ -> \_ -> "fun f"
|
||||||
|
g = \{ s1 } -> \_ -> s1
|
||||||
|
|
||||||
|
fun = \x ->
|
||||||
|
h =
|
||||||
|
when x is
|
||||||
|
True -> after (\{} -> "") f
|
||||||
|
False -> after (\{} -> {s1: "s1"}) g
|
||||||
|
h {}
|
||||||
|
|
||||||
|
{a: fun False, b: fun True}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(RocStr::from("s1"), RocStr::from("fun f")),
|
||||||
|
(RocStr, RocStr)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -431,3 +431,46 @@ fn union_linked_list_long_dec() {
|
||||||
&[Deallocated; 1_000]
|
&[Deallocated; 1_000]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-wasm"))]
|
||||||
|
fn boxed_str_inc() {
|
||||||
|
assert_refcounts!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
s = Str.concat "A long enough string " "to be heap-allocated"
|
||||||
|
b = Box.box s
|
||||||
|
|
||||||
|
Tuple b b
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(Pointer, Pointer),
|
||||||
|
&[
|
||||||
|
Live(2), // s
|
||||||
|
Live(2), // b
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-wasm"))]
|
||||||
|
fn boxed_str_dec() {
|
||||||
|
assert_refcounts!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
s = Str.concat "A long enough string " "to be heap-allocated"
|
||||||
|
b = Box.box s
|
||||||
|
|
||||||
|
if False then
|
||||||
|
ReturnTheBox b
|
||||||
|
else
|
||||||
|
DeallocateEverything
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
(i32, i32),
|
||||||
|
&[
|
||||||
|
Deallocated, // s
|
||||||
|
Deallocated, // b
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ fn str_split_empty_delimiter() {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
1,
|
1,
|
||||||
i64
|
usize
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
|
@ -41,7 +41,7 @@ fn str_split_empty_delimiter() {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
3,
|
3,
|
||||||
i64
|
usize
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ fn str_split_bigger_delimiter_small_str() {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
1,
|
1,
|
||||||
i64
|
usize
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
|
@ -71,7 +71,7 @@ fn str_split_bigger_delimiter_small_str() {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
3,
|
3,
|
||||||
i64
|
usize
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ fn str_split_small_str_big_delimiter() {
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
3,
|
3,
|
||||||
i64
|
usize
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
|
@ -1700,3 +1700,75 @@ fn to_scalar_4_byte() {
|
||||||
RocList<u32>
|
RocList<u32>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn str_split_first() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Str.splitFirst "foo/bar/baz" "/"
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
// the result is a { before, after } record, and because of
|
||||||
|
// alphabetic ordering the fields here are flipped
|
||||||
|
RocResult::ok((RocStr::from("bar/baz"), RocStr::from("foo"))),
|
||||||
|
RocResult<(RocStr, RocStr), ()>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn str_split_last() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Str.splitLast"foo/bar/baz" "/"
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
RocResult::ok((RocStr::from("baz"), RocStr::from("foo/bar"))),
|
||||||
|
RocResult<(RocStr, RocStr), ()>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn str_walk_utf8_with_index() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Str.walkUtf8WithIndex "abcd" [] (\list, byte, index -> List.append list (Pair index byte))
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
RocList::from_slice(&[(0, b'a'), (1, b'b'), (2, b'c'), (3, b'd')]),
|
||||||
|
RocList<(u64, u8)>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn str_append_scalar() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Str.appendScalar "abcd" 'A'
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
RocStr::from("abcdA"),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn str_walk_scalars() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Str.walkScalars "abcd" [] List.append
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
RocList::from_slice(&['a', 'b', 'c', 'd']),
|
||||||
|
RocList<char>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ macro_rules! from_wasm_memory_primitive {
|
||||||
}
|
}
|
||||||
|
|
||||||
from_wasm_memory_primitive!(
|
from_wasm_memory_primitive!(
|
||||||
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, f32, f64, bool, RocDec, RocOrder,
|
u8, i8, u16, i16, u32, i32, char, u64, i64, u128, i128, f32, f64, bool, RocDec, RocOrder,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl FromWasmerMemory for () {
|
impl FromWasmerMemory for () {
|
||||||
|
|
|
@ -18,7 +18,7 @@ use roc_mono::ir::{
|
||||||
Call, CallType, Expr, HostExposedLayouts, Literal, Proc, ProcLayout, SelfRecursive, Stmt,
|
Call, CallType, Expr, HostExposedLayouts, Literal, Proc, ProcLayout, SelfRecursive, Stmt,
|
||||||
UpdateModeId,
|
UpdateModeId,
|
||||||
};
|
};
|
||||||
use roc_mono::layout::{Builtin, Layout};
|
use roc_mono::layout::{Builtin, CapturesNiche, LambdaName, Layout};
|
||||||
|
|
||||||
const LINKING_TEST_HOST_WASM: &str = "build/wasm_linking_test_host.wasm";
|
const LINKING_TEST_HOST_WASM: &str = "build/wasm_linking_test_host.wasm";
|
||||||
const LINKING_TEST_HOST_NATIVE: &str = "build/wasm_linking_test_host";
|
const LINKING_TEST_HOST_NATIVE: &str = "build/wasm_linking_test_host";
|
||||||
|
@ -110,7 +110,7 @@ fn build_app_mono<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
let proc = Proc {
|
let proc = Proc {
|
||||||
name: app_proc,
|
name: LambdaName::no_niche(app_proc),
|
||||||
args: &[],
|
args: &[],
|
||||||
body,
|
body,
|
||||||
closure_data_layout: None,
|
closure_data_layout: None,
|
||||||
|
@ -123,6 +123,7 @@ fn build_app_mono<'a>(
|
||||||
let proc_layout = ProcLayout {
|
let proc_layout = ProcLayout {
|
||||||
arguments: &[],
|
arguments: &[],
|
||||||
result: int_layout,
|
result: int_layout,
|
||||||
|
captures_niche: CapturesNiche::no_niche(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut app = MutMap::default();
|
let mut app = MutMap::default();
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.284 : U64 = lowlevel ListLen #Attr.2;
|
let List.279 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure Test.1 (Test.5):
|
procedure Test.1 (Test.5):
|
||||||
let Test.2 : I64 = 41i64;
|
let Test.2 : I64 = 41i64;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
procedure Dict.1 ():
|
procedure Dict.1 ():
|
||||||
let Dict.28 : Dict [] [] = lowlevel DictEmpty ;
|
let Dict.16 : Dict [] [] = lowlevel DictEmpty ;
|
||||||
ret Dict.28;
|
ret Dict.16;
|
||||||
|
|
||||||
procedure Dict.7 (#Attr.2):
|
procedure Dict.7 (#Attr.2):
|
||||||
let Dict.27 : U64 = lowlevel DictSize #Attr.2;
|
let Dict.15 : U64 = lowlevel DictSize #Attr.2;
|
||||||
dec #Attr.2;
|
dec #Attr.2;
|
||||||
ret Dict.27;
|
ret Dict.15;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.2 : Dict [] [] = CallByName Dict.1;
|
let Test.2 : Dict [] [] = CallByName Dict.1;
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
procedure List.2 (List.75, List.76):
|
procedure List.2 (List.75, List.76):
|
||||||
let List.290 : U64 = CallByName List.6 List.75;
|
let List.285 : U64 = CallByName List.6 List.75;
|
||||||
let List.286 : Int1 = CallByName Num.22 List.76 List.290;
|
let List.281 : Int1 = CallByName Num.22 List.76 List.285;
|
||||||
if List.286 then
|
if List.281 then
|
||||||
let List.288 : {} = CallByName List.60 List.75 List.76;
|
let List.283 : {} = CallByName List.60 List.75 List.76;
|
||||||
let List.287 : [C {}, C {}] = Ok List.288;
|
let List.282 : [C {}, C {}] = TagId(1) List.283;
|
||||||
ret List.287;
|
ret List.282;
|
||||||
else
|
else
|
||||||
let List.285 : {} = Struct {};
|
let List.280 : {} = Struct {};
|
||||||
let List.284 : [C {}, C {}] = Err List.285;
|
let List.279 : [C {}, C {}] = TagId(0) List.280;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.293 : U64 = lowlevel ListLen #Attr.2;
|
let List.288 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.293;
|
ret List.288;
|
||||||
|
|
||||||
procedure List.60 (#Attr.2, #Attr.3):
|
procedure List.60 (#Attr.2, #Attr.3):
|
||||||
let List.292 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
let List.287 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||||
ret List.292;
|
ret List.287;
|
||||||
|
|
||||||
procedure Num.22 (#Attr.2, #Attr.3):
|
procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.2 (Test.6):
|
procedure Test.2 (Test.6):
|
||||||
let Test.18 : Str = "bar";
|
let Test.18 : Str = "bar";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure List.4 (#Attr.2, #Attr.3):
|
procedure List.4 (#Attr.2, #Attr.3):
|
||||||
let List.284 : List U8 = lowlevel ListAppend #Attr.2 #Attr.3;
|
let List.279 : List U8 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure Test.20 (Test.22):
|
procedure Test.20 (Test.22):
|
||||||
let Test.34 : {U8} = Struct {Test.22};
|
let Test.34 : {U8} = Struct {Test.22};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
procedure Num.20 (#Attr.2, #Attr.3):
|
procedure Num.20 (#Attr.2, #Attr.3):
|
||||||
let Num.274 : I64 = lowlevel NumSub #Attr.2 #Attr.3;
|
let Num.189 : I64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||||
ret Num.274;
|
ret Num.189;
|
||||||
|
|
||||||
procedure Num.21 (#Attr.2, #Attr.3):
|
procedure Num.21 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : I64 = lowlevel NumMul #Attr.2 #Attr.3;
|
let Num.188 : I64 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.1 (Test.15, Test.16):
|
procedure Test.1 (Test.15, Test.16):
|
||||||
joinpoint Test.7 Test.2 Test.3:
|
joinpoint Test.7 Test.2 Test.3:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure Bool.7 (#Attr.2, #Attr.3):
|
procedure Bool.7 (#Attr.2, #Attr.3):
|
||||||
let Bool.14 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
let Bool.9 : Int1 = lowlevel Eq #Attr.2 #Attr.3;
|
||||||
ret Bool.14;
|
ret Bool.9;
|
||||||
|
|
||||||
procedure Test.1 (Test.3):
|
procedure Test.1 (Test.3):
|
||||||
let Test.6 : I64 = 10i64;
|
let Test.6 : I64 = 10i64;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.284 : U64 = lowlevel ListLen #Attr.2;
|
let List.279 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure Num.19 (#Attr.2, #Attr.3):
|
procedure Num.19 (#Attr.2, #Attr.3):
|
||||||
let Num.275 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
let Num.190 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||||
ret Num.275;
|
ret Num.190;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.1 : List I64 = Array [1i64, 2i64];
|
let Test.1 : List I64 = Array [1i64, 2i64];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure Num.19 (#Attr.2, #Attr.3):
|
procedure Num.19 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
let Num.188 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.2 : I64 = 1i64;
|
let Test.2 : I64 = 1i64;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure Num.45 (#Attr.2):
|
procedure Num.45 (#Attr.2):
|
||||||
let Num.273 : I64 = lowlevel NumRound #Attr.2;
|
let Num.188 : I64 = lowlevel NumRound #Attr.2;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.2 : Float64 = 3.6f64;
|
let Test.2 : Float64 = 3.6f64;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure Num.19 (#Attr.2, #Attr.3):
|
procedure Num.19 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
let Num.188 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.1 : I64 = 3i64;
|
let Test.1 : I64 = 3i64;
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
procedure Num.40 (#Attr.2, #Attr.3):
|
procedure Num.40 (#Attr.2, #Attr.3):
|
||||||
let Num.278 : I64 = 0i64;
|
let Num.193 : I64 = 0i64;
|
||||||
let Num.275 : Int1 = lowlevel NotEq #Attr.3 Num.278;
|
let Num.190 : Int1 = lowlevel NotEq #Attr.3 Num.193;
|
||||||
if Num.275 then
|
if Num.190 then
|
||||||
let Num.277 : I64 = lowlevel NumDivUnchecked #Attr.2 #Attr.3;
|
let Num.192 : I64 = lowlevel NumDivUnchecked #Attr.2 #Attr.3;
|
||||||
let Num.276 : [C {}, C I64] = Ok Num.277;
|
let Num.191 : [C {}, C I64] = TagId(1) Num.192;
|
||||||
ret Num.276;
|
ret Num.191;
|
||||||
else
|
else
|
||||||
let Num.274 : {} = Struct {};
|
let Num.189 : {} = Struct {};
|
||||||
let Num.273 : [C {}, C I64] = Err Num.274;
|
let Num.188 : [C {}, C I64] = TagId(0) Num.189;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.8 : I64 = 1000i64;
|
let Test.8 : I64 = 1000i64;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
procedure Num.19 (#Attr.2, #Attr.3):
|
procedure Num.19 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
let Num.188 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.10 : I64 = 41i64;
|
let Test.10 : I64 = 41i64;
|
||||||
let Test.1 : [C I64, C ] = Just Test.10;
|
let Test.1 : [C I64, C ] = TagId(0) Test.10;
|
||||||
let Test.7 : U8 = 0i64;
|
let Test.7 : U8 = 0i64;
|
||||||
let Test.8 : U8 = GetTagId Test.1;
|
let Test.8 : U8 = GetTagId Test.1;
|
||||||
let Test.9 : Int1 = lowlevel Eq Test.7 Test.8;
|
let Test.9 : Int1 = lowlevel Eq Test.7 Test.8;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.9 : I64 = 3i64;
|
let Test.9 : I64 = 3i64;
|
||||||
let Test.3 : [C I64, C ] = Just Test.9;
|
let Test.3 : [C I64, C ] = TagId(0) Test.9;
|
||||||
let Test.6 : U8 = 0i64;
|
let Test.6 : U8 = 0i64;
|
||||||
let Test.7 : U8 = GetTagId Test.3;
|
let Test.7 : U8 = GetTagId Test.3;
|
||||||
let Test.8 : Int1 = lowlevel Eq Test.6 Test.7;
|
let Test.8 : Int1 = lowlevel Eq Test.6 Test.7;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.10 : I64 = 1i64;
|
let Test.10 : I64 = 1i64;
|
||||||
let Test.11 : I64 = 2i64;
|
let Test.11 : I64 = 2i64;
|
||||||
let Test.5 : [C I64, C I64 I64, C I64] = These Test.10 Test.11;
|
let Test.5 : [C I64, C I64 I64, C I64] = TagId(1) Test.10 Test.11;
|
||||||
let Test.9 : U8 = GetTagId Test.5;
|
let Test.9 : U8 = GetTagId Test.5;
|
||||||
switch Test.9:
|
switch Test.9:
|
||||||
case 2:
|
case 2:
|
||||||
|
|
|
@ -11,8 +11,8 @@ procedure Test.3 (Test.4):
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.16 : I64 = 2i64;
|
let Test.16 : I64 = 2i64;
|
||||||
let Test.17 : [<rnu><null>, C I64 *self] = Nil ;
|
let Test.17 : [<rnu><null>, C I64 *self] = TagId(1) ;
|
||||||
let Test.10 : [<rnu><null>, C I64 *self] = Cons Test.16 Test.17;
|
let Test.10 : [<rnu><null>, C I64 *self] = TagId(0) Test.16 Test.17;
|
||||||
let Test.9 : Int1 = CallByName Test.3 Test.10;
|
let Test.9 : Int1 = CallByName Test.3 Test.10;
|
||||||
dec Test.10;
|
dec Test.10;
|
||||||
ret Test.9;
|
ret Test.9;
|
||||||
|
|
|
@ -1,55 +1,55 @@
|
||||||
procedure List.2 (List.75, List.76):
|
procedure List.2 (List.75, List.76):
|
||||||
let List.299 : U64 = CallByName List.6 List.75;
|
let List.294 : U64 = CallByName List.6 List.75;
|
||||||
let List.295 : Int1 = CallByName Num.22 List.76 List.299;
|
let List.290 : Int1 = CallByName Num.22 List.76 List.294;
|
||||||
if List.295 then
|
if List.290 then
|
||||||
let List.297 : I64 = CallByName List.60 List.75 List.76;
|
let List.292 : I64 = CallByName List.60 List.75 List.76;
|
||||||
let List.296 : [C {}, C I64] = Ok List.297;
|
let List.291 : [C {}, C I64] = TagId(1) List.292;
|
||||||
ret List.296;
|
ret List.291;
|
||||||
else
|
else
|
||||||
let List.294 : {} = Struct {};
|
let List.289 : {} = Struct {};
|
||||||
let List.293 : [C {}, C I64] = Err List.294;
|
let List.288 : [C {}, C I64] = TagId(0) List.289;
|
||||||
ret List.293;
|
ret List.288;
|
||||||
|
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.300 : U64 = lowlevel ListLen #Attr.2;
|
let List.295 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.300;
|
ret List.295;
|
||||||
|
|
||||||
procedure List.60 (#Attr.2, #Attr.3):
|
procedure List.60 (#Attr.2, #Attr.3):
|
||||||
let List.298 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
let List.293 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||||
ret List.298;
|
ret List.293;
|
||||||
|
|
||||||
procedure List.9 (List.202):
|
procedure List.9 (List.201):
|
||||||
let List.291 : U64 = 0i64;
|
let List.286 : U64 = 0i64;
|
||||||
let List.284 : [C {}, C I64] = CallByName List.2 List.202 List.291;
|
let List.279 : [C {}, C I64] = CallByName List.2 List.201 List.286;
|
||||||
let List.288 : U8 = 1i64;
|
let List.283 : U8 = 1i64;
|
||||||
let List.289 : U8 = GetTagId List.284;
|
let List.284 : U8 = GetTagId List.279;
|
||||||
let List.290 : Int1 = lowlevel Eq List.288 List.289;
|
let List.285 : Int1 = lowlevel Eq List.283 List.284;
|
||||||
if List.290 then
|
if List.285 then
|
||||||
let List.203 : I64 = UnionAtIndex (Id 1) (Index 0) List.284;
|
let List.202 : I64 = UnionAtIndex (Id 1) (Index 0) List.279;
|
||||||
let List.285 : [C Int1, C I64] = Ok List.203;
|
let List.280 : [C Int1, C I64] = TagId(1) List.202;
|
||||||
ret List.285;
|
ret List.280;
|
||||||
else
|
else
|
||||||
let List.287 : Int1 = true;
|
let List.282 : Int1 = true;
|
||||||
let List.286 : [C Int1, C I64] = Err List.287;
|
let List.281 : [C Int1, C I64] = TagId(0) List.282;
|
||||||
ret List.286;
|
ret List.281;
|
||||||
|
|
||||||
procedure Num.22 (#Attr.2, #Attr.3):
|
procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Str.27 (#Attr.2):
|
procedure Str.27 (#Attr.2):
|
||||||
let #Attr.3 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
let #Attr.3 : {I64, U8} = lowlevel StrToNum #Attr.2;
|
||||||
let Str.72 : U8 = StructAtIndex 1 #Attr.3;
|
let Str.159 : U8 = StructAtIndex 1 #Attr.3;
|
||||||
let Str.73 : U8 = 0i64;
|
let Str.160 : U8 = 0i64;
|
||||||
let Str.69 : Int1 = lowlevel NumGt Str.72 Str.73;
|
let Str.156 : Int1 = lowlevel NumGt Str.159 Str.160;
|
||||||
if Str.69 then
|
if Str.156 then
|
||||||
let Str.71 : Int1 = false;
|
let Str.158 : Int1 = false;
|
||||||
let Str.70 : [C Int1, C I64] = Err Str.71;
|
let Str.157 : [C Int1, C I64] = TagId(0) Str.158;
|
||||||
ret Str.70;
|
ret Str.157;
|
||||||
else
|
else
|
||||||
let Str.68 : I64 = StructAtIndex 0 #Attr.3;
|
let Str.155 : I64 = StructAtIndex 0 #Attr.3;
|
||||||
let Str.67 : [C Int1, C I64] = Ok Str.68;
|
let Str.154 : [C Int1, C I64] = TagId(1) Str.155;
|
||||||
ret Str.67;
|
ret Str.154;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.4 : Int1 = true;
|
let Test.4 : Int1 = true;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.19 : [C [<rnnu>C [C *self, C ]], C ] = SystemTool ;
|
let Test.19 : [C [<rnnu>C [C *self, C ]], C ] = TagId(1) ;
|
||||||
let Test.17 : [<rnnu>C [C *self, C ]] = Job Test.19;
|
let Test.17 : [<rnnu>C [C *self, C ]] = TagId(0) Test.19;
|
||||||
let Test.16 : [C [<rnnu>C [C *self, C ]], C ] = FromJob Test.17;
|
let Test.16 : [C [<rnnu>C [C *self, C ]], C ] = TagId(0) Test.17;
|
||||||
let Test.7 : [<rnnu>C [C *self, C ]] = Job Test.16;
|
let Test.7 : [<rnnu>C [C *self, C ]] = TagId(0) Test.16;
|
||||||
ret Test.7;
|
ret Test.7;
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
procedure Num.94 (#Attr.2):
|
||||||
|
let Num.188 : Str = lowlevel NumToStr #Attr.2;
|
||||||
|
ret Num.188;
|
||||||
|
|
||||||
|
procedure Num.94 (#Attr.2):
|
||||||
|
let Num.189 : Str = lowlevel NumToStr #Attr.2;
|
||||||
|
ret Num.189;
|
||||||
|
|
||||||
|
procedure Test.1 (Test.4):
|
||||||
|
let Test.16 : [C U8, C U64] = TagId(1) Test.4;
|
||||||
|
ret Test.16;
|
||||||
|
|
||||||
|
procedure Test.1 (Test.4):
|
||||||
|
let Test.22 : [C U8, C U64] = TagId(0) Test.4;
|
||||||
|
ret Test.22;
|
||||||
|
|
||||||
|
procedure Test.5 (Test.17, #Attr.12):
|
||||||
|
let Test.4 : U64 = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||||
|
let Test.19 : Str = CallByName Num.94 Test.4;
|
||||||
|
ret Test.19;
|
||||||
|
|
||||||
|
procedure Test.5 (Test.17, #Attr.12):
|
||||||
|
let Test.4 : U8 = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||||
|
let Test.25 : Str = CallByName Num.94 Test.4;
|
||||||
|
ret Test.25;
|
||||||
|
|
||||||
|
procedure Test.0 ():
|
||||||
|
let Test.2 : Int1 = true;
|
||||||
|
joinpoint Test.13 Test.3:
|
||||||
|
let Test.8 : {} = Struct {};
|
||||||
|
let Test.9 : U8 = GetTagId Test.3;
|
||||||
|
joinpoint Test.10 Test.7:
|
||||||
|
ret Test.7;
|
||||||
|
in
|
||||||
|
switch Test.9:
|
||||||
|
case 0:
|
||||||
|
let Test.11 : Str = CallByName Test.5 Test.8 Test.3;
|
||||||
|
jump Test.10 Test.11;
|
||||||
|
|
||||||
|
default:
|
||||||
|
let Test.12 : Str = CallByName Test.5 Test.8 Test.3;
|
||||||
|
jump Test.10 Test.12;
|
||||||
|
|
||||||
|
in
|
||||||
|
let Test.26 : Int1 = true;
|
||||||
|
let Test.27 : Int1 = lowlevel Eq Test.26 Test.2;
|
||||||
|
if Test.27 then
|
||||||
|
let Test.15 : U64 = 123i64;
|
||||||
|
let Test.14 : [C U8, C U64] = CallByName Test.1 Test.15;
|
||||||
|
jump Test.13 Test.14;
|
||||||
|
else
|
||||||
|
let Test.21 : U8 = 18i64;
|
||||||
|
let Test.20 : [C U8, C U64] = CallByName Test.1 Test.21;
|
||||||
|
jump Test.13 Test.20;
|
|
@ -0,0 +1,85 @@
|
||||||
|
procedure Test.11 (Test.37):
|
||||||
|
let Test.38 : Str = "";
|
||||||
|
ret Test.38;
|
||||||
|
|
||||||
|
procedure Test.13 (Test.51, #Attr.12):
|
||||||
|
let Test.12 : Str = StructAtIndex 0 #Attr.12;
|
||||||
|
inc Test.12;
|
||||||
|
dec #Attr.12;
|
||||||
|
ret Test.12;
|
||||||
|
|
||||||
|
procedure Test.15 (Test.39):
|
||||||
|
let Test.40 : Str = "";
|
||||||
|
ret Test.40;
|
||||||
|
|
||||||
|
procedure Test.16 (Test.54):
|
||||||
|
let Test.56 : Str = "s1";
|
||||||
|
ret Test.56;
|
||||||
|
|
||||||
|
procedure Test.2 (Test.7, Test.8):
|
||||||
|
let Test.9 : [C {} {}, C {} {}] = TagId(0) Test.7 Test.8;
|
||||||
|
ret Test.9;
|
||||||
|
|
||||||
|
procedure Test.2 (Test.7, Test.8):
|
||||||
|
let Test.9 : [C {} {}, C {} {}] = TagId(1) Test.7 Test.8;
|
||||||
|
ret Test.9;
|
||||||
|
|
||||||
|
procedure Test.3 (Test.17):
|
||||||
|
let Test.36 : {} = Struct {};
|
||||||
|
ret Test.36;
|
||||||
|
|
||||||
|
procedure Test.4 (Test.18):
|
||||||
|
let Test.50 : {Str} = Struct {Test.18};
|
||||||
|
ret Test.50;
|
||||||
|
|
||||||
|
procedure Test.9 (Test.29, #Attr.12):
|
||||||
|
let Test.8 : {} = UnionAtIndex (Id 0) (Index 1) #Attr.12;
|
||||||
|
let Test.7 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||||
|
let Test.35 : {} = Struct {};
|
||||||
|
let Test.34 : Str = CallByName Test.15 Test.35;
|
||||||
|
let Test.31 : {} = CallByName Test.3 Test.34;
|
||||||
|
dec Test.34;
|
||||||
|
let Test.33 : {} = Struct {};
|
||||||
|
let Test.32 : Str = CallByName Test.11 Test.33;
|
||||||
|
ret Test.32;
|
||||||
|
|
||||||
|
procedure Test.9 (Test.29, #Attr.12):
|
||||||
|
let Test.8 : {} = UnionAtIndex (Id 1) (Index 1) #Attr.12;
|
||||||
|
let Test.7 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||||
|
let Test.49 : {} = Struct {};
|
||||||
|
let Test.48 : Str = CallByName Test.16 Test.49;
|
||||||
|
let Test.45 : {Str} = CallByName Test.4 Test.48;
|
||||||
|
let Test.47 : {} = Struct {};
|
||||||
|
let Test.46 : Str = CallByName Test.13 Test.47 Test.45;
|
||||||
|
ret Test.46;
|
||||||
|
|
||||||
|
procedure Test.0 ():
|
||||||
|
let Test.5 : Int1 = true;
|
||||||
|
joinpoint Test.25 Test.6:
|
||||||
|
let Test.20 : {} = Struct {};
|
||||||
|
let Test.21 : U8 = GetTagId Test.6;
|
||||||
|
joinpoint Test.22 Test.19:
|
||||||
|
ret Test.19;
|
||||||
|
in
|
||||||
|
switch Test.21:
|
||||||
|
case 0:
|
||||||
|
let Test.23 : Str = CallByName Test.9 Test.20 Test.6;
|
||||||
|
jump Test.22 Test.23;
|
||||||
|
|
||||||
|
default:
|
||||||
|
let Test.24 : Str = CallByName Test.9 Test.20 Test.6;
|
||||||
|
jump Test.22 Test.24;
|
||||||
|
|
||||||
|
in
|
||||||
|
let Test.57 : Int1 = true;
|
||||||
|
let Test.58 : Int1 = lowlevel Eq Test.57 Test.5;
|
||||||
|
if Test.58 then
|
||||||
|
let Test.27 : {} = Struct {};
|
||||||
|
let Test.28 : {} = Struct {};
|
||||||
|
let Test.26 : [C {} {}, C {} {}] = CallByName Test.2 Test.27 Test.28;
|
||||||
|
jump Test.25 Test.26;
|
||||||
|
else
|
||||||
|
let Test.42 : {} = Struct {};
|
||||||
|
let Test.43 : {} = Struct {};
|
||||||
|
let Test.41 : [C {} {}, C {} {}] = CallByName Test.2 Test.42 Test.43;
|
||||||
|
jump Test.25 Test.41;
|
|
@ -0,0 +1,59 @@
|
||||||
|
procedure Test.1 (Test.5):
|
||||||
|
let Test.19 : [C , C U64, C {}] = TagId(2) Test.5;
|
||||||
|
ret Test.19;
|
||||||
|
|
||||||
|
procedure Test.1 (Test.5):
|
||||||
|
let Test.27 : [C , C U64, C {}] = TagId(1) Test.5;
|
||||||
|
ret Test.27;
|
||||||
|
|
||||||
|
procedure Test.2 (Test.8):
|
||||||
|
let Test.24 : Str = "";
|
||||||
|
ret Test.24;
|
||||||
|
|
||||||
|
procedure Test.6 (Test.20, #Attr.12):
|
||||||
|
let Test.5 : U64 = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||||
|
let Test.30 : Str = "";
|
||||||
|
ret Test.30;
|
||||||
|
|
||||||
|
procedure Test.6 (Test.20, #Attr.12):
|
||||||
|
let Test.5 : {} = UnionAtIndex (Id 2) (Index 0) #Attr.12;
|
||||||
|
let Test.22 : Str = "";
|
||||||
|
ret Test.22;
|
||||||
|
|
||||||
|
procedure Test.0 ():
|
||||||
|
let Test.3 : U8 = 0u8;
|
||||||
|
joinpoint Test.16 Test.4:
|
||||||
|
let Test.10 : {} = Struct {};
|
||||||
|
let Test.11 : U8 = GetTagId Test.4;
|
||||||
|
joinpoint Test.12 Test.9:
|
||||||
|
ret Test.9;
|
||||||
|
in
|
||||||
|
switch Test.11:
|
||||||
|
case 0:
|
||||||
|
let Test.13 : Str = CallByName Test.2 Test.10;
|
||||||
|
jump Test.12 Test.13;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
let Test.14 : Str = CallByName Test.6 Test.10 Test.4;
|
||||||
|
jump Test.12 Test.14;
|
||||||
|
|
||||||
|
default:
|
||||||
|
let Test.15 : Str = CallByName Test.6 Test.10 Test.4;
|
||||||
|
jump Test.12 Test.15;
|
||||||
|
|
||||||
|
in
|
||||||
|
switch Test.3:
|
||||||
|
case 0:
|
||||||
|
let Test.18 : {} = Struct {};
|
||||||
|
let Test.17 : [C , C U64, C {}] = CallByName Test.1 Test.18;
|
||||||
|
jump Test.16 Test.17;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
let Test.2 : [C , C U64, C {}] = TagId(0) ;
|
||||||
|
jump Test.16 Test.2;
|
||||||
|
|
||||||
|
default:
|
||||||
|
let Test.26 : U64 = 1i64;
|
||||||
|
let Test.25 : [C , C U64, C {}] = CallByName Test.1 Test.26;
|
||||||
|
jump Test.16 Test.25;
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
procedure Test.1 (Test.5):
|
||||||
|
let Test.20 : [C U64, C {}, C Str] = TagId(1) Test.5;
|
||||||
|
ret Test.20;
|
||||||
|
|
||||||
|
procedure Test.1 (Test.5):
|
||||||
|
let Test.32 : [C U64, C {}, C Str] = TagId(0) Test.5;
|
||||||
|
ret Test.32;
|
||||||
|
|
||||||
|
procedure Test.2 (Test.7):
|
||||||
|
let Test.26 : [C U64, C {}, C Str] = TagId(2) Test.7;
|
||||||
|
ret Test.26;
|
||||||
|
|
||||||
|
procedure Test.6 (Test.21, #Attr.12):
|
||||||
|
let Test.5 : U64 = UnionAtIndex (Id 0) (Index 0) #Attr.12;
|
||||||
|
dec #Attr.12;
|
||||||
|
let Test.35 : Str = "";
|
||||||
|
ret Test.35;
|
||||||
|
|
||||||
|
procedure Test.6 (Test.21, #Attr.12):
|
||||||
|
let Test.5 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||||
|
dec #Attr.12;
|
||||||
|
let Test.23 : Str = "";
|
||||||
|
ret Test.23;
|
||||||
|
|
||||||
|
procedure Test.8 (Test.27, #Attr.12):
|
||||||
|
let Test.7 : Str = UnionAtIndex (Id 2) (Index 0) #Attr.12;
|
||||||
|
inc Test.7;
|
||||||
|
dec #Attr.12;
|
||||||
|
ret Test.7;
|
||||||
|
|
||||||
|
procedure Test.0 ():
|
||||||
|
let Test.3 : U8 = 0u8;
|
||||||
|
joinpoint Test.17 Test.4:
|
||||||
|
let Test.11 : {} = Struct {};
|
||||||
|
let Test.12 : U8 = GetTagId Test.4;
|
||||||
|
joinpoint Test.13 Test.10:
|
||||||
|
ret Test.10;
|
||||||
|
in
|
||||||
|
switch Test.12:
|
||||||
|
case 0:
|
||||||
|
let Test.14 : Str = CallByName Test.6 Test.11 Test.4;
|
||||||
|
jump Test.13 Test.14;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
let Test.15 : Str = CallByName Test.6 Test.11 Test.4;
|
||||||
|
jump Test.13 Test.15;
|
||||||
|
|
||||||
|
default:
|
||||||
|
let Test.16 : Str = CallByName Test.8 Test.11 Test.4;
|
||||||
|
jump Test.13 Test.16;
|
||||||
|
|
||||||
|
in
|
||||||
|
switch Test.3:
|
||||||
|
case 0:
|
||||||
|
let Test.19 : {} = Struct {};
|
||||||
|
let Test.18 : [C U64, C {}, C Str] = CallByName Test.1 Test.19;
|
||||||
|
jump Test.17 Test.18;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
let Test.25 : Str = "foo";
|
||||||
|
let Test.24 : [C U64, C {}, C Str] = CallByName Test.2 Test.25;
|
||||||
|
jump Test.17 Test.24;
|
||||||
|
|
||||||
|
default:
|
||||||
|
let Test.31 : U64 = 1i64;
|
||||||
|
let Test.30 : [C U64, C {}, C Str] = CallByName Test.1 Test.31;
|
||||||
|
jump Test.17 Test.30;
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
procedure Test.1 (Test.4):
|
||||||
|
let Test.5 : {Str} = Struct {Test.4};
|
||||||
|
ret Test.5;
|
||||||
|
|
||||||
|
procedure Test.5 (Test.12, #Attr.12):
|
||||||
|
let Test.4 : Str = StructAtIndex 0 #Attr.12;
|
||||||
|
inc Test.4;
|
||||||
|
dec #Attr.12;
|
||||||
|
let Test.14 : Str = "";
|
||||||
|
ret Test.14;
|
||||||
|
|
||||||
|
procedure Test.0 ():
|
||||||
|
let Test.2 : Int1 = true;
|
||||||
|
joinpoint Test.9 Test.3:
|
||||||
|
ret Test.3;
|
||||||
|
in
|
||||||
|
let Test.19 : Int1 = true;
|
||||||
|
let Test.20 : Int1 = lowlevel Eq Test.19 Test.2;
|
||||||
|
if Test.20 then
|
||||||
|
let Test.15 : Str = "";
|
||||||
|
let Test.10 : {Str} = CallByName Test.1 Test.15;
|
||||||
|
jump Test.9 Test.10;
|
||||||
|
else
|
||||||
|
let Test.18 : Str = "";
|
||||||
|
let Test.16 : {Str} = CallByName Test.1 Test.18;
|
||||||
|
jump Test.9 Test.16;
|
|
@ -1,6 +1,6 @@
|
||||||
procedure List.4 (#Attr.2, #Attr.3):
|
procedure List.4 (#Attr.2, #Attr.3):
|
||||||
let List.284 : List I64 = lowlevel ListAppend #Attr.2 #Attr.3;
|
let List.279 : List I64 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.2 : List I64 = Array [1i64];
|
let Test.2 : List I64 = Array [1i64];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure List.4 (#Attr.2, #Attr.3):
|
procedure List.4 (#Attr.2, #Attr.3):
|
||||||
let List.284 : List I64 = lowlevel ListAppend #Attr.2 #Attr.3;
|
let List.279 : List I64 = lowlevel ListAppend #Attr.2 #Attr.3;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure Test.1 (Test.2):
|
procedure Test.1 (Test.2):
|
||||||
let Test.6 : I64 = 42i64;
|
let Test.6 : I64 = 42i64;
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
procedure List.3 (List.84, List.85, List.86):
|
procedure List.3 (List.83, List.84, List.85):
|
||||||
let List.287 : {List I64, I64} = CallByName List.57 List.84 List.85 List.86;
|
let List.282 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
|
||||||
let List.286 : List I64 = StructAtIndex 0 List.287;
|
let List.281 : List I64 = StructAtIndex 0 List.282;
|
||||||
inc List.286;
|
inc List.281;
|
||||||
dec List.287;
|
dec List.282;
|
||||||
ret List.286;
|
ret List.281;
|
||||||
|
|
||||||
procedure List.57 (List.81, List.82, List.83):
|
procedure List.57 (List.80, List.81, List.82):
|
||||||
let List.293 : U64 = CallByName List.6 List.81;
|
let List.288 : U64 = CallByName List.6 List.80;
|
||||||
let List.290 : Int1 = CallByName Num.22 List.82 List.293;
|
let List.285 : Int1 = CallByName Num.22 List.81 List.288;
|
||||||
if List.290 then
|
if List.285 then
|
||||||
let List.291 : {List I64, I64} = CallByName List.61 List.81 List.82 List.83;
|
let List.286 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
|
||||||
ret List.291;
|
ret List.286;
|
||||||
else
|
else
|
||||||
let List.289 : {List I64, I64} = Struct {List.81, List.83};
|
let List.284 : {List I64, I64} = Struct {List.80, List.82};
|
||||||
ret List.289;
|
ret List.284;
|
||||||
|
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.285 : U64 = lowlevel ListLen #Attr.2;
|
let List.280 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.285;
|
ret List.280;
|
||||||
|
|
||||||
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
|
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
|
||||||
let List.292 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
let List.287 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||||
ret List.292;
|
ret List.287;
|
||||||
|
|
||||||
procedure Num.19 (#Attr.2, #Attr.3):
|
procedure Num.19 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
let Num.188 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Num.22 (#Attr.2, #Attr.3):
|
procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
let Num.274 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
let Num.189 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
ret Num.274;
|
ret Num.189;
|
||||||
|
|
||||||
procedure Test.1 ():
|
procedure Test.1 ():
|
||||||
let Test.8 : List I64 = Array [1i64, 2i64, 3i64];
|
let Test.8 : List I64 = Array [1i64, 2i64, 3i64];
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
procedure List.2 (List.75, List.76):
|
procedure List.2 (List.75, List.76):
|
||||||
let List.290 : U64 = CallByName List.6 List.75;
|
let List.285 : U64 = CallByName List.6 List.75;
|
||||||
let List.286 : Int1 = CallByName Num.22 List.76 List.290;
|
let List.281 : Int1 = CallByName Num.22 List.76 List.285;
|
||||||
if List.286 then
|
if List.281 then
|
||||||
let List.288 : I64 = CallByName List.60 List.75 List.76;
|
let List.283 : I64 = CallByName List.60 List.75 List.76;
|
||||||
let List.287 : [C {}, C I64] = Ok List.288;
|
let List.282 : [C {}, C I64] = TagId(1) List.283;
|
||||||
ret List.287;
|
ret List.282;
|
||||||
else
|
else
|
||||||
let List.285 : {} = Struct {};
|
let List.280 : {} = Struct {};
|
||||||
let List.284 : [C {}, C I64] = Err List.285;
|
let List.279 : [C {}, C I64] = TagId(0) List.280;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.293 : U64 = lowlevel ListLen #Attr.2;
|
let List.288 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.293;
|
ret List.288;
|
||||||
|
|
||||||
procedure List.60 (#Attr.2, #Attr.3):
|
procedure List.60 (#Attr.2, #Attr.3):
|
||||||
let List.292 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
let List.287 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||||
ret List.292;
|
ret List.287;
|
||||||
|
|
||||||
procedure Num.22 (#Attr.2, #Attr.3):
|
procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.1 (Test.2):
|
procedure Test.1 (Test.2):
|
||||||
let Test.6 : List I64 = Array [1i64, 2i64, 3i64];
|
let Test.6 : List I64 = Array [1i64, 2i64, 3i64];
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.284 : U64 = lowlevel ListLen #Attr.2;
|
let List.279 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.285 : U64 = lowlevel ListLen #Attr.2;
|
let List.280 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.285;
|
ret List.280;
|
||||||
|
|
||||||
procedure Num.19 (#Attr.2, #Attr.3):
|
procedure Num.19 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
let Num.188 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.1 : List I64 = Array [1i64, 2i64, 3i64];
|
let Test.1 : List I64 = Array [1i64, 2i64, 3i64];
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
procedure List.2 (List.75, List.76):
|
procedure List.2 (List.75, List.76):
|
||||||
let List.290 : U64 = CallByName List.6 List.75;
|
let List.285 : U64 = CallByName List.6 List.75;
|
||||||
let List.286 : Int1 = CallByName Num.22 List.76 List.290;
|
let List.281 : Int1 = CallByName Num.22 List.76 List.285;
|
||||||
if List.286 then
|
if List.281 then
|
||||||
let List.288 : Str = CallByName List.60 List.75 List.76;
|
let List.283 : Str = CallByName List.60 List.75 List.76;
|
||||||
let List.287 : [C {}, C Str] = Ok List.288;
|
let List.282 : [C {}, C Str] = TagId(1) List.283;
|
||||||
ret List.287;
|
ret List.282;
|
||||||
else
|
else
|
||||||
let List.285 : {} = Struct {};
|
let List.280 : {} = Struct {};
|
||||||
let List.284 : [C {}, C Str] = Err List.285;
|
let List.279 : [C {}, C Str] = TagId(0) List.280;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure List.5 (#Attr.2, #Attr.3):
|
procedure List.5 (#Attr.2, #Attr.3):
|
||||||
let List.292 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
let List.287 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||||
ret List.292;
|
ret List.287;
|
||||||
|
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.294 : U64 = lowlevel ListLen #Attr.2;
|
let List.289 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.294;
|
ret List.289;
|
||||||
|
|
||||||
procedure List.60 (#Attr.2, #Attr.3):
|
procedure List.60 (#Attr.2, #Attr.3):
|
||||||
let List.293 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
let List.288 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||||
ret List.293;
|
ret List.288;
|
||||||
|
|
||||||
procedure Num.22 (#Attr.2, #Attr.3):
|
procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Str.16 (#Attr.2, #Attr.3):
|
procedure Str.16 (#Attr.2, #Attr.3):
|
||||||
let Str.67 : Str = lowlevel StrRepeat #Attr.2 #Attr.3;
|
let Str.154 : Str = lowlevel StrRepeat #Attr.2 #Attr.3;
|
||||||
ret Str.67;
|
ret Str.154;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.68 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.155 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.68;
|
ret Str.155;
|
||||||
|
|
||||||
procedure Test.1 ():
|
procedure Test.1 ():
|
||||||
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
procedure List.2 (List.75, List.76):
|
procedure List.2 (List.75, List.76):
|
||||||
let List.290 : U64 = CallByName List.6 List.75;
|
let List.285 : U64 = CallByName List.6 List.75;
|
||||||
let List.286 : Int1 = CallByName Num.22 List.76 List.290;
|
let List.281 : Int1 = CallByName Num.22 List.76 List.285;
|
||||||
if List.286 then
|
if List.281 then
|
||||||
let List.288 : Str = CallByName List.60 List.75 List.76;
|
let List.283 : Str = CallByName List.60 List.75 List.76;
|
||||||
let List.287 : [C {}, C Str] = Ok List.288;
|
let List.282 : [C {}, C Str] = TagId(1) List.283;
|
||||||
ret List.287;
|
ret List.282;
|
||||||
else
|
else
|
||||||
let List.285 : {} = Struct {};
|
let List.280 : {} = Struct {};
|
||||||
let List.284 : [C {}, C Str] = Err List.285;
|
let List.279 : [C {}, C Str] = TagId(0) List.280;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure List.5 (#Attr.2, #Attr.3):
|
procedure List.5 (#Attr.2, #Attr.3):
|
||||||
inc #Attr.2;
|
inc #Attr.2;
|
||||||
let List.292 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
let List.287 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||||
decref #Attr.2;
|
decref #Attr.2;
|
||||||
ret List.292;
|
ret List.287;
|
||||||
|
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.294 : U64 = lowlevel ListLen #Attr.2;
|
let List.289 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.294;
|
ret List.289;
|
||||||
|
|
||||||
procedure List.60 (#Attr.2, #Attr.3):
|
procedure List.60 (#Attr.2, #Attr.3):
|
||||||
let List.293 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
let List.288 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||||
ret List.293;
|
ret List.288;
|
||||||
|
|
||||||
procedure Num.22 (#Attr.2, #Attr.3):
|
procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Str.3 (#Attr.2, #Attr.3):
|
procedure Str.3 (#Attr.2, #Attr.3):
|
||||||
let Str.68 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
let Str.155 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||||
ret Str.68;
|
ret Str.155;
|
||||||
|
|
||||||
procedure Test.1 ():
|
procedure Test.1 ():
|
||||||
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
let Test.21 : Str = "lllllllllllllllllllllooooooooooong";
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
procedure List.3 (List.84, List.85, List.86):
|
procedure List.3 (List.83, List.84, List.85):
|
||||||
let List.285 : {List I64, I64} = CallByName List.57 List.84 List.85 List.86;
|
let List.280 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
|
||||||
let List.284 : List I64 = StructAtIndex 0 List.285;
|
let List.279 : List I64 = StructAtIndex 0 List.280;
|
||||||
inc List.284;
|
inc List.279;
|
||||||
dec List.285;
|
dec List.280;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure List.57 (List.81, List.82, List.83):
|
procedure List.57 (List.80, List.81, List.82):
|
||||||
let List.291 : U64 = CallByName List.6 List.81;
|
let List.286 : U64 = CallByName List.6 List.80;
|
||||||
let List.288 : Int1 = CallByName Num.22 List.82 List.291;
|
let List.283 : Int1 = CallByName Num.22 List.81 List.286;
|
||||||
if List.288 then
|
if List.283 then
|
||||||
let List.289 : {List I64, I64} = CallByName List.61 List.81 List.82 List.83;
|
let List.284 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
|
||||||
ret List.289;
|
ret List.284;
|
||||||
else
|
else
|
||||||
let List.287 : {List I64, I64} = Struct {List.81, List.83};
|
let List.282 : {List I64, I64} = Struct {List.80, List.82};
|
||||||
ret List.287;
|
ret List.282;
|
||||||
|
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.292 : U64 = lowlevel ListLen #Attr.2;
|
let List.287 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.292;
|
ret List.287;
|
||||||
|
|
||||||
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
|
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
|
||||||
let List.290 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
let List.285 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||||
ret List.290;
|
ret List.285;
|
||||||
|
|
||||||
procedure Num.22 (#Attr.2, #Attr.3):
|
procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
let Num.188 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.2 (Test.3):
|
procedure Test.2 (Test.3):
|
||||||
let Test.6 : U64 = 0i64;
|
let Test.6 : U64 = 0i64;
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
procedure List.28 (#Attr.2, #Attr.3):
|
procedure List.28 (#Attr.2, #Attr.3):
|
||||||
let List.287 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
|
let List.282 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
|
||||||
let Bool.14 : Int1 = lowlevel ListIsUnique #Attr.2;
|
let Bool.9 : Int1 = lowlevel ListIsUnique #Attr.2;
|
||||||
if Bool.14 then
|
if Bool.9 then
|
||||||
ret List.287;
|
ret List.282;
|
||||||
else
|
else
|
||||||
decref #Attr.2;
|
decref #Attr.2;
|
||||||
ret List.287;
|
ret List.282;
|
||||||
|
|
||||||
procedure List.54 (List.196):
|
procedure List.54 (List.196):
|
||||||
let List.285 : {} = Struct {};
|
let List.280 : {} = Struct {};
|
||||||
let List.284 : List I64 = CallByName List.28 List.196 List.285;
|
let List.279 : List I64 = CallByName List.28 List.196 List.280;
|
||||||
ret List.284;
|
ret List.279;
|
||||||
|
|
||||||
procedure Num.46 (#Attr.2, #Attr.3):
|
procedure Num.46 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : U8 = lowlevel NumCompare #Attr.2 #Attr.3;
|
let Num.188 : U8 = lowlevel NumCompare #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.2 : List I64 = Array [4i64, 3i64, 2i64, 1i64];
|
let Test.2 : List I64 = Array [4i64, 3i64, 2i64, 1i64];
|
||||||
|
|
|
@ -15,6 +15,6 @@ procedure Test.2 (Test.4):
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.13 : Str = "A";
|
let Test.13 : Str = "A";
|
||||||
let Test.1 : [C Str, C Str] = A Test.13;
|
let Test.1 : [C Str, C Str] = TagId(0) Test.13;
|
||||||
let Test.7 : Str = CallByName Test.2 Test.1;
|
let Test.7 : Str = CallByName Test.2 Test.1;
|
||||||
ret Test.7;
|
ret Test.7;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
procedure Num.19 (#Attr.2, #Attr.3):
|
procedure Num.19 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
let Num.188 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.19 : I64 = 41i64;
|
let Test.19 : I64 = 41i64;
|
||||||
let Test.18 : [C I64, C ] = Just Test.19;
|
let Test.18 : [C I64, C ] = TagId(0) Test.19;
|
||||||
let Test.2 : [C [C I64, C ], C ] = Just Test.18;
|
let Test.2 : [C [C I64, C ], C ] = TagId(0) Test.18;
|
||||||
joinpoint Test.15:
|
joinpoint Test.15:
|
||||||
let Test.8 : I64 = 1i64;
|
let Test.8 : I64 = 1i64;
|
||||||
ret Test.8;
|
ret Test.8;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
procedure Test.3 (Test.4):
|
procedure Test.3 (Test.4):
|
||||||
let Test.8 : [C {}, C U8] = Ok Test.4;
|
let Test.8 : [C {}, C U8] = TagId(1) Test.4;
|
||||||
ret Test.8;
|
ret Test.8;
|
||||||
|
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure Num.21 (#Attr.2, #Attr.3):
|
procedure Num.21 (#Attr.2, #Attr.3):
|
||||||
let Num.275 : I64 = lowlevel NumMul #Attr.2 #Attr.3;
|
let Num.190 : I64 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||||
ret Num.275;
|
ret Num.190;
|
||||||
|
|
||||||
procedure Test.1 (Test.6):
|
procedure Test.1 (Test.6):
|
||||||
let Test.21 : Int1 = false;
|
let Test.21 : Int1 = false;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.11 : [<rnu><null>, C *self] = Z ;
|
let Test.11 : [<rnu><null>, C *self] = TagId(1) ;
|
||||||
let Test.10 : [<rnu><null>, C *self] = S Test.11;
|
let Test.10 : [<rnu><null>, C *self] = TagId(0) Test.11;
|
||||||
let Test.9 : [<rnu><null>, C *self] = S Test.10;
|
let Test.9 : [<rnu><null>, C *self] = TagId(0) Test.10;
|
||||||
let Test.3 : [<rnu><null>, C *self] = S Test.9;
|
let Test.3 : [<rnu><null>, C *self] = TagId(0) Test.9;
|
||||||
ret Test.3;
|
ret Test.3;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.15 : [<rnu><null>, C *self] = Z ;
|
let Test.15 : [<rnu><null>, C *self] = TagId(1) ;
|
||||||
let Test.14 : [<rnu><null>, C *self] = S Test.15;
|
let Test.14 : [<rnu><null>, C *self] = TagId(0) Test.15;
|
||||||
let Test.13 : [<rnu><null>, C *self] = S Test.14;
|
let Test.13 : [<rnu><null>, C *self] = TagId(0) Test.14;
|
||||||
let Test.3 : [<rnu><null>, C *self] = S Test.13;
|
let Test.3 : [<rnu><null>, C *self] = TagId(0) Test.13;
|
||||||
let Test.10 : Int1 = 1i64;
|
let Test.10 : Int1 = 1i64;
|
||||||
let Test.11 : Int1 = GetTagId Test.3;
|
let Test.11 : Int1 = GetTagId Test.3;
|
||||||
dec Test.3;
|
dec Test.3;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
procedure Test.0 ():
|
procedure Test.0 ():
|
||||||
let Test.21 : [<rnu><null>, C *self] = Z ;
|
let Test.21 : [<rnu><null>, C *self] = TagId(1) ;
|
||||||
let Test.20 : [<rnu><null>, C *self] = S Test.21;
|
let Test.20 : [<rnu><null>, C *self] = TagId(0) Test.21;
|
||||||
let Test.19 : [<rnu><null>, C *self] = S Test.20;
|
let Test.19 : [<rnu><null>, C *self] = TagId(0) Test.20;
|
||||||
let Test.3 : [<rnu><null>, C *self] = S Test.19;
|
let Test.3 : [<rnu><null>, C *self] = TagId(0) Test.19;
|
||||||
let Test.16 : Int1 = 0i64;
|
let Test.16 : Int1 = 0i64;
|
||||||
let Test.17 : Int1 = GetTagId Test.3;
|
let Test.17 : Int1 = GetTagId Test.3;
|
||||||
let Test.18 : Int1 = lowlevel Eq Test.16 Test.17;
|
let Test.18 : Int1 = lowlevel Eq Test.16 Test.17;
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
procedure Num.19 (#Attr.2, #Attr.3):
|
procedure Num.19 (#Attr.2, #Attr.3):
|
||||||
let Num.273 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
let Num.188 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||||
ret Num.273;
|
ret Num.188;
|
||||||
|
|
||||||
procedure Num.20 (#Attr.2, #Attr.3):
|
procedure Num.20 (#Attr.2, #Attr.3):
|
||||||
let Num.274 : I64 = lowlevel NumSub #Attr.2 #Attr.3;
|
let Num.189 : I64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||||
ret Num.274;
|
ret Num.189;
|
||||||
|
|
||||||
procedure Num.22 (#Attr.2, #Attr.3):
|
procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
let Num.275 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
let Num.190 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
ret Num.275;
|
ret Num.190;
|
||||||
|
|
||||||
procedure Test.1 (Test.24, Test.25, Test.26):
|
procedure Test.1 (Test.24, Test.25, Test.26):
|
||||||
joinpoint Test.12 Test.2 Test.3 Test.4:
|
joinpoint Test.12 Test.2 Test.3 Test.4:
|
||||||
|
|
|
@ -1,47 +1,47 @@
|
||||||
procedure List.2 (List.75, List.76):
|
procedure List.2 (List.75, List.76):
|
||||||
let List.304 : U64 = CallByName List.6 List.75;
|
let List.299 : U64 = CallByName List.6 List.75;
|
||||||
let List.300 : Int1 = CallByName Num.22 List.76 List.304;
|
let List.295 : Int1 = CallByName Num.22 List.76 List.299;
|
||||||
if List.300 then
|
if List.295 then
|
||||||
let List.302 : I64 = CallByName List.60 List.75 List.76;
|
let List.297 : I64 = CallByName List.60 List.75 List.76;
|
||||||
let List.301 : [C {}, C I64] = Ok List.302;
|
let List.296 : [C {}, C I64] = TagId(1) List.297;
|
||||||
|
ret List.296;
|
||||||
|
else
|
||||||
|
let List.294 : {} = Struct {};
|
||||||
|
let List.293 : [C {}, C I64] = TagId(0) List.294;
|
||||||
|
ret List.293;
|
||||||
|
|
||||||
|
procedure List.3 (List.83, List.84, List.85):
|
||||||
|
let List.283 : {List I64, I64} = CallByName List.57 List.83 List.84 List.85;
|
||||||
|
let List.282 : List I64 = StructAtIndex 0 List.283;
|
||||||
|
inc List.282;
|
||||||
|
dec List.283;
|
||||||
|
ret List.282;
|
||||||
|
|
||||||
|
procedure List.57 (List.80, List.81, List.82):
|
||||||
|
let List.305 : U64 = CallByName List.6 List.80;
|
||||||
|
let List.302 : Int1 = CallByName Num.22 List.81 List.305;
|
||||||
|
if List.302 then
|
||||||
|
let List.303 : {List I64, I64} = CallByName List.61 List.80 List.81 List.82;
|
||||||
|
ret List.303;
|
||||||
|
else
|
||||||
|
let List.301 : {List I64, I64} = Struct {List.80, List.82};
|
||||||
ret List.301;
|
ret List.301;
|
||||||
else
|
|
||||||
let List.299 : {} = Struct {};
|
|
||||||
let List.298 : [C {}, C I64] = Err List.299;
|
|
||||||
ret List.298;
|
|
||||||
|
|
||||||
procedure List.3 (List.84, List.85, List.86):
|
|
||||||
let List.288 : {List I64, I64} = CallByName List.57 List.84 List.85 List.86;
|
|
||||||
let List.287 : List I64 = StructAtIndex 0 List.288;
|
|
||||||
inc List.287;
|
|
||||||
dec List.288;
|
|
||||||
ret List.287;
|
|
||||||
|
|
||||||
procedure List.57 (List.81, List.82, List.83):
|
|
||||||
let List.310 : U64 = CallByName List.6 List.81;
|
|
||||||
let List.307 : Int1 = CallByName Num.22 List.82 List.310;
|
|
||||||
if List.307 then
|
|
||||||
let List.308 : {List I64, I64} = CallByName List.61 List.81 List.82 List.83;
|
|
||||||
ret List.308;
|
|
||||||
else
|
|
||||||
let List.306 : {List I64, I64} = Struct {List.81, List.83};
|
|
||||||
ret List.306;
|
|
||||||
|
|
||||||
procedure List.6 (#Attr.2):
|
procedure List.6 (#Attr.2):
|
||||||
let List.311 : U64 = lowlevel ListLen #Attr.2;
|
let List.306 : U64 = lowlevel ListLen #Attr.2;
|
||||||
ret List.311;
|
ret List.306;
|
||||||
|
|
||||||
procedure List.60 (#Attr.2, #Attr.3):
|
procedure List.60 (#Attr.2, #Attr.3):
|
||||||
let List.312 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
let List.307 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||||
ret List.312;
|
ret List.307;
|
||||||
|
|
||||||
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
|
procedure List.61 (#Attr.2, #Attr.3, #Attr.4):
|
||||||
let List.309 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
let List.304 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||||
ret List.309;
|
ret List.304;
|
||||||
|
|
||||||
procedure Num.22 (#Attr.2, #Attr.3):
|
procedure Num.22 (#Attr.2, #Attr.3):
|
||||||
let Num.275 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
let Num.190 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||||
ret Num.275;
|
ret Num.190;
|
||||||
|
|
||||||
procedure Test.1 (Test.2):
|
procedure Test.1 (Test.2):
|
||||||
let Test.28 : U64 = 0i64;
|
let Test.28 : U64 = 0i64;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue