mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge branch 'refactor-platform-info' into packages
This commit is contained in:
commit
3227f95d45
137 changed files with 6178 additions and 2855 deletions
|
@ -10,11 +10,12 @@ use roc_module::low_level::LowLevel;
|
|||
use roc_module::symbol::Symbol;
|
||||
|
||||
use roc_mono::ir::{
|
||||
Call, CallType, Expr, HigherOrderLowLevel, HostExposedLayouts, ListLiteralElement, Literal,
|
||||
ModifyRc, OptLevel, Proc, Stmt,
|
||||
Call, CallType, EntryPoint, Expr, HigherOrderLowLevel, HostExposedLayouts, ListLiteralElement,
|
||||
Literal, ModifyRc, OptLevel, Proc, ProcLayout, SingleEntryPoint, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, CapturesNiche, Layout, RawFunctionLayout, STLayoutInterner, UnionLayout,
|
||||
Builtin, CapturesNiche, FieldOrderHash, Layout, RawFunctionLayout, STLayoutInterner,
|
||||
UnionLayout,
|
||||
};
|
||||
|
||||
// just using one module for now
|
||||
|
@ -136,7 +137,7 @@ pub fn spec_program<'a, I>(
|
|||
arena: &'a Bump,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
opt_level: OptLevel,
|
||||
opt_entry_point: Option<roc_mono::ir::EntryPoint<'a>>,
|
||||
entry_point: roc_mono::ir::EntryPoint<'a>,
|
||||
procs: I,
|
||||
) -> Result<morphic_lib::Solutions>
|
||||
where
|
||||
|
@ -226,30 +227,70 @@ where
|
|||
m.add_func(func_name, spec)?;
|
||||
}
|
||||
|
||||
if let Some(entry_point) = opt_entry_point {
|
||||
// the entry point wrapper
|
||||
let roc_main_bytes = func_name_bytes_help(
|
||||
entry_point.symbol,
|
||||
entry_point.layout.arguments.iter().copied(),
|
||||
CapturesNiche::no_niche(),
|
||||
&entry_point.layout.result,
|
||||
);
|
||||
let roc_main = FuncName(&roc_main_bytes);
|
||||
match entry_point {
|
||||
EntryPoint::Single(SingleEntryPoint {
|
||||
symbol: entry_point_symbol,
|
||||
layout: entry_point_layout,
|
||||
}) => {
|
||||
// the entry point wrapper
|
||||
let roc_main_bytes = func_name_bytes_help(
|
||||
entry_point_symbol,
|
||||
entry_point_layout.arguments.iter().copied(),
|
||||
CapturesNiche::no_niche(),
|
||||
&entry_point_layout.result,
|
||||
);
|
||||
let roc_main = FuncName(&roc_main_bytes);
|
||||
|
||||
let mut env = Env::new(arena);
|
||||
let mut env = Env::new(arena);
|
||||
|
||||
let entry_point_function = build_entry_point(
|
||||
&mut env,
|
||||
interner,
|
||||
entry_point.layout,
|
||||
roc_main,
|
||||
&host_exposed_functions,
|
||||
)?;
|
||||
let entry_point_function = build_entry_point(
|
||||
&mut env,
|
||||
interner,
|
||||
entry_point_layout,
|
||||
Some(roc_main),
|
||||
&host_exposed_functions,
|
||||
)?;
|
||||
|
||||
type_definitions.extend(env.type_names);
|
||||
type_definitions.extend(env.type_names);
|
||||
|
||||
let entry_point_name = FuncName(ENTRY_POINT_NAME);
|
||||
m.add_func(entry_point_name, entry_point_function)?;
|
||||
let entry_point_name = FuncName(ENTRY_POINT_NAME);
|
||||
m.add_func(entry_point_name, entry_point_function)?;
|
||||
}
|
||||
EntryPoint::Expects { symbols } => {
|
||||
// construct a big pattern match picking one of the expects at random
|
||||
let layout: ProcLayout<'a> = ProcLayout {
|
||||
arguments: &[],
|
||||
result: Layout::Struct {
|
||||
field_order_hash: FieldOrderHash::from_ordered_fields(&[]),
|
||||
field_layouts: &[],
|
||||
},
|
||||
captures_niche: CapturesNiche::no_niche(),
|
||||
};
|
||||
|
||||
let host_exposed: Vec<_> = symbols
|
||||
.iter()
|
||||
.map(|symbol| {
|
||||
(
|
||||
func_name_bytes_help(
|
||||
*symbol,
|
||||
[],
|
||||
CapturesNiche::no_niche(),
|
||||
&layout.result,
|
||||
),
|
||||
[].as_slice(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut env = Env::new(arena);
|
||||
let entry_point_function =
|
||||
build_entry_point(&mut env, interner, layout, None, &host_exposed)?;
|
||||
|
||||
type_definitions.extend(env.type_names);
|
||||
|
||||
let entry_point_name = FuncName(ENTRY_POINT_NAME);
|
||||
m.add_func(entry_point_name, entry_point_function)?;
|
||||
}
|
||||
}
|
||||
|
||||
for union_layout in type_definitions {
|
||||
|
@ -286,10 +327,11 @@ where
|
|||
let mut p = ProgramBuilder::new();
|
||||
p.add_mod(MOD_APP, main_module)?;
|
||||
|
||||
if opt_entry_point.is_some() {
|
||||
let entry_point_name = FuncName(ENTRY_POINT_NAME);
|
||||
p.add_entry_point(EntryPointName(ENTRY_POINT_NAME), MOD_APP, entry_point_name)?;
|
||||
}
|
||||
p.add_entry_point(
|
||||
EntryPointName(ENTRY_POINT_NAME),
|
||||
MOD_APP,
|
||||
FuncName(ENTRY_POINT_NAME),
|
||||
)?;
|
||||
|
||||
p.build()?
|
||||
};
|
||||
|
@ -324,7 +366,7 @@ fn build_entry_point<'a>(
|
|||
env: &mut Env<'a>,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
layout: roc_mono::ir::ProcLayout<'a>,
|
||||
func_name: FuncName,
|
||||
entry_point_function: Option<FuncName>,
|
||||
host_exposed_functions: &[([u8; SIZE], &'a [Layout<'a>])],
|
||||
) -> Result<FuncDef> {
|
||||
let mut builder = FuncDefBuilder::new();
|
||||
|
@ -332,7 +374,7 @@ fn build_entry_point<'a>(
|
|||
|
||||
let mut cases = Vec::new();
|
||||
|
||||
{
|
||||
if let Some(entry_point_function) = entry_point_function {
|
||||
let block = builder.add_block();
|
||||
|
||||
// to the modelling language, the arguments appear out of thin air
|
||||
|
@ -352,7 +394,7 @@ fn build_entry_point<'a>(
|
|||
|
||||
let name_bytes = [0; 16];
|
||||
let spec_var = CalleeSpecVar(&name_bytes);
|
||||
let result = builder.add_call(block, spec_var, MOD_APP, func_name, argument)?;
|
||||
let result = builder.add_call(block, spec_var, MOD_APP, entry_point_function, argument)?;
|
||||
|
||||
// to the modelling language, the result disappears into the void
|
||||
let unit_type = builder.add_tuple_type(&[])?;
|
||||
|
@ -365,7 +407,7 @@ fn build_entry_point<'a>(
|
|||
for (name_bytes, layouts) in host_exposed_functions {
|
||||
let host_exposed_func_name = FuncName(name_bytes);
|
||||
|
||||
if host_exposed_func_name == func_name {
|
||||
if Some(host_exposed_func_name) == entry_point_function {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -392,7 +434,11 @@ fn build_entry_point<'a>(
|
|||
}
|
||||
|
||||
let unit_type = builder.add_tuple_type(&[])?;
|
||||
let unit_value = builder.add_choice(outer_block, &cases)?;
|
||||
let unit_value = if cases.is_empty() {
|
||||
builder.add_make_tuple(outer_block, &[])?
|
||||
} else {
|
||||
builder.add_choice(outer_block, &cases)?
|
||||
};
|
||||
|
||||
let root = BlockExpr(outer_block, unit_value);
|
||||
let spec = builder.build(unit_type, unit_type, root)?;
|
||||
|
|
|
@ -3,7 +3,7 @@ use roc_error_macros::internal_error;
|
|||
use roc_gen_llvm::llvm::build::{module_from_builtins, LlvmBackendMode};
|
||||
use roc_gen_llvm::llvm::externs::add_default_roc_externs;
|
||||
use roc_load::{EntryPoint, ExpectMetadata, LoadedModule, MonomorphizedModule};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_mono::ir::{OptLevel, SingleEntryPoint};
|
||||
use roc_reporting::cli::{report_problems, Problems};
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -188,18 +188,25 @@ fn gen_from_mono_module_llvm<'a>(
|
|||
// expects that would confuse the surgical linker
|
||||
add_default_roc_externs(&env);
|
||||
|
||||
let opt_entry_point = match loaded.entry_point {
|
||||
EntryPoint::Executable { symbol, layout, .. } => {
|
||||
Some(roc_mono::ir::EntryPoint { symbol, layout })
|
||||
let entry_point = match loaded.entry_point {
|
||||
EntryPoint::Executable {
|
||||
exposed_to_host,
|
||||
platform_path: _,
|
||||
} => {
|
||||
// TODO support multiple of these!
|
||||
debug_assert_eq!(exposed_to_host.len(), 1);
|
||||
let (symbol, layout) = exposed_to_host[0];
|
||||
|
||||
roc_mono::ir::EntryPoint::Single(SingleEntryPoint { symbol, layout })
|
||||
}
|
||||
EntryPoint::Test => None,
|
||||
EntryPoint::Test => roc_mono::ir::EntryPoint::Expects { symbols: &[] },
|
||||
};
|
||||
|
||||
roc_gen_llvm::llvm::build::build_procedures(
|
||||
&env,
|
||||
opt_level,
|
||||
loaded.procedures,
|
||||
opt_entry_point,
|
||||
entry_point,
|
||||
Some(&app_ll_file),
|
||||
);
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const SIGUSR1: c_int = if (builtin.os.tag.isDarwin()) 30 else 10;
|
||||
const SIGUSR2: c_int = if (builtin.os.tag.isDarwin()) 31 else 12;
|
||||
const Atomic = std.atomic.Atomic;
|
||||
|
||||
const O_RDWR: c_int = 2;
|
||||
const O_CREAT: c_int = 64;
|
||||
|
@ -51,7 +50,6 @@ pub fn expectFailedStartSharedFile() callconv(.C) [*]u8 {
|
|||
}
|
||||
}
|
||||
|
||||
extern fn roc_send_signal(pid: c_int, sig: c_int) c_int;
|
||||
extern fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn roc_getppid() c_int;
|
||||
|
@ -81,18 +79,24 @@ pub fn readSharedBufferEnv() callconv(.C) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expectFailedFinalize() callconv(.C) void {
|
||||
pub fn notifyParent(shared_buffer: [*]u8, tag: u32) callconv(.C) void {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
const parent_pid = roc_getppid();
|
||||
const usize_ptr = @ptrCast([*]u32, @alignCast(@alignOf(usize), shared_buffer));
|
||||
const atomic_ptr = @ptrCast(*Atomic(u32), &usize_ptr[5]);
|
||||
atomic_ptr.storeUnchecked(tag);
|
||||
|
||||
_ = roc_send_signal(parent_pid, SIGUSR1);
|
||||
// wait till the parent is done before proceeding
|
||||
const Ordering = std.atomic.Ordering;
|
||||
while (atomic_ptr.load(Ordering.Acquire) != 0) {
|
||||
std.atomic.spinLoopHint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sendDbg() callconv(.C) void {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
const parent_pid = roc_getppid();
|
||||
|
||||
_ = roc_send_signal(parent_pid, SIGUSR2);
|
||||
}
|
||||
pub fn notifyParentExpect(shared_buffer: [*]u8) callconv(.C) void {
|
||||
notifyParent(shared_buffer, 1);
|
||||
}
|
||||
|
||||
pub fn notifyParentDbg(shared_buffer: [*]u8) callconv(.C) void {
|
||||
notifyParent(shared_buffer, 2);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ const UpdateMode = utils.UpdateMode;
|
|||
const mem = std.mem;
|
||||
const math = std.math;
|
||||
|
||||
const expect = std.testing.expect;
|
||||
|
||||
const EqFn = fn (?[*]u8, ?[*]u8) callconv(.C) bool;
|
||||
const CompareFn = fn (?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) u8;
|
||||
const Opaque = ?[*]u8;
|
||||
|
@ -770,7 +772,7 @@ pub fn listConcat(list_a: RocList, list_b: RocList, alignment: u32, element_widt
|
|||
// This first call must use mem.copy because the slices might overlap.
|
||||
const byte_count_a = list_a.len() * element_width;
|
||||
const byte_count_b = list_b.len() * element_width;
|
||||
mem.copy(u8, source_b[byte_count_a .. byte_count_a + byte_count_b], source_b[0..byte_count_b]);
|
||||
mem.copyBackwards(u8, source_b[byte_count_a .. byte_count_a + byte_count_b], source_b[0..byte_count_b]);
|
||||
@memcpy(source_b, source_a, byte_count_a);
|
||||
|
||||
// decrement list a.
|
||||
|
@ -854,3 +856,21 @@ pub fn listIsUnique(
|
|||
) callconv(.C) bool {
|
||||
return list.isEmpty() or list.isUnique();
|
||||
}
|
||||
|
||||
test "listConcat: non-unique with unique overlapping" {
|
||||
var nonUnique = RocList.fromSlice(u8, ([_]u8{1})[0..]);
|
||||
var bytes: [*]u8 = @ptrCast([*]u8, nonUnique.bytes);
|
||||
const ptr_width = @sizeOf(usize);
|
||||
const refcount_ptr = @ptrCast([*]isize, @alignCast(ptr_width, bytes) - ptr_width);
|
||||
utils.increfC(&refcount_ptr[0], 1);
|
||||
defer nonUnique.deinit(u8); // listConcat will dec the other refcount
|
||||
|
||||
var unique = RocList.fromSlice(u8, ([_]u8{ 2, 3, 4 })[0..]);
|
||||
defer unique.deinit(u8);
|
||||
|
||||
var concatted = listConcat(nonUnique, unique, 1, 1);
|
||||
var wanted = RocList.fromSlice(u8, ([_]u8{ 1, 2, 3, 4 })[0..]);
|
||||
defer wanted.deinit(u8);
|
||||
|
||||
try expect(concatted.eql(wanted));
|
||||
}
|
||||
|
|
|
@ -172,8 +172,8 @@ comptime {
|
|||
if (builtin.target.cpu.arch != .wasm32) {
|
||||
exportUtilsFn(expect.expectFailedStartSharedBuffer, "expect_failed_start_shared_buffer");
|
||||
exportUtilsFn(expect.expectFailedStartSharedFile, "expect_failed_start_shared_file");
|
||||
exportUtilsFn(expect.expectFailedFinalize, "expect_failed_finalize");
|
||||
exportUtilsFn(expect.sendDbg, "send_dbg");
|
||||
exportUtilsFn(expect.notifyParentExpect, "notify_parent_expect");
|
||||
exportUtilsFn(expect.notifyParentDbg, "notify_parent_dbg");
|
||||
|
||||
// sets the buffer used for expect failures
|
||||
@export(expect.setSharedBuffer, .{ .name = "set_shared_buffer", .linkage = .Weak });
|
||||
|
|
|
@ -32,9 +32,6 @@ fn roc_getppid_windows_stub() callconv(.C) c_int {
|
|||
return 0;
|
||||
}
|
||||
|
||||
fn testing_roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn testing_roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
|
@ -55,7 +52,6 @@ comptime {
|
|||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(testing_roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(testing_roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(testing_roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(testing_roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,18 @@ interface Dict
|
|||
empty,
|
||||
withCapacity,
|
||||
single,
|
||||
get,
|
||||
walk,
|
||||
insert,
|
||||
clear,
|
||||
capacity,
|
||||
len,
|
||||
get,
|
||||
contains,
|
||||
insert,
|
||||
remove,
|
||||
update,
|
||||
contains,
|
||||
walk,
|
||||
walkUntil,
|
||||
toList,
|
||||
fromList,
|
||||
keys,
|
||||
values,
|
||||
insertAll,
|
||||
|
@ -22,8 +27,8 @@ interface Dict
|
|||
Result.{ Result },
|
||||
List,
|
||||
Str,
|
||||
Num.{ Nat, U64, U8 },
|
||||
Hash.{ Hasher },
|
||||
Num.{ Nat, U64, U8, I8 },
|
||||
Hash.{ Hasher, Hash },
|
||||
]
|
||||
|
||||
## A [dictionary](https://en.wikipedia.org/wiki/Associative_array) that lets you
|
||||
|
@ -74,45 +79,103 @@ interface Dict
|
|||
## does. It removes an element and moves the most recent insertion into the
|
||||
## vacated spot.
|
||||
##
|
||||
## This move is done as a performance optimization, and it lets [Dict.remove]
|
||||
## have [constant time complexity](https://en.wikipedia.org/wiki/Time_complexity#Constant_time).
|
||||
## This move is done as a performance optimization, and it lets [remove] have
|
||||
## [constant time complexity](https://en.wikipedia.org/wiki/Time_complexity#Constant_time). ##
|
||||
##
|
||||
## ### Equality
|
||||
##
|
||||
## Two dictionaries are equal when their contents and orderings match. This
|
||||
## means that when `dict1 == dict2`, the expression `fn dict1 == fn dict2` will
|
||||
## also evaluate to `Bool.true`. The function `fn` can count on the ordering of
|
||||
## values in the dictionary to also match.
|
||||
Dict k v := List [Pair k v] has [Eq]
|
||||
## Dict is inspired by [IndexMap](https://docs.rs/indexmap/latest/indexmap/map/struct.IndexMap.html).
|
||||
## The internal implementation of a dictionary is similar to [absl::flat_hash_map](https://abseil.io/docs/cpp/guides/container).
|
||||
## It has a list of keys value pairs that is ordered based on insertion.
|
||||
## It uses a list of indices into the data as the backing of a hash map.
|
||||
Dict k v := {
|
||||
# TODO: Add hashflooding ordered map fall back.
|
||||
# TODO: Add Groups and SIMD h1 key comparison (initial tests where slower, but with proper SIMD should be fast).
|
||||
# TODO: As an optimization, we can make all of these lists in one allocation
|
||||
# TODO: Grow data with the rest of the hashmap. This will require creating a list of garbage data.
|
||||
# TODO: Change remove to use tombstones. Store the tombstones in a bitmap.
|
||||
# TODO: define Eq and Hash that are unordered. Only if value has hash/eq?
|
||||
metadata : List I8,
|
||||
dataIndices : List Nat,
|
||||
data : List (T k v),
|
||||
size : Nat,
|
||||
} | k has Hash & Eq
|
||||
|
||||
## Return an empty dictionary.
|
||||
empty : Dict k v
|
||||
empty = @Dict []
|
||||
empty : Dict k v | k has Hash & Eq
|
||||
empty =
|
||||
@Dict {
|
||||
metadata: List.repeat emptySlot 8,
|
||||
dataIndices: List.repeat 0 8,
|
||||
data: [],
|
||||
size: 0,
|
||||
}
|
||||
|
||||
## Returns the max number of elements the dictionary can hold before requiring a rehash.
|
||||
capacity : Dict k v -> Nat | k has Hash & Eq
|
||||
capacity = \@Dict { dataIndices } ->
|
||||
cap = List.len dataIndices
|
||||
|
||||
cap - Num.shiftRightZfBy cap 3
|
||||
|
||||
## Return a dictionary with space allocated for a number of entries. This
|
||||
## may provide a performance optimisation if you know how many entries will be
|
||||
## inserted.
|
||||
withCapacity : Nat -> Dict k v
|
||||
withCapacity = \n -> @Dict (List.withCapacity n)
|
||||
withCapacity : Nat -> Dict k v | k has Hash & Eq
|
||||
withCapacity = \_ ->
|
||||
# TODO: power of 2 * 8 and actual implementation
|
||||
empty
|
||||
|
||||
## Get the value for a given key. If there is a value for the specified key it
|
||||
## will return [Ok value], otherwise return [Err KeyNotFound].
|
||||
## Returns a dictionary containing the key and value provided as input.
|
||||
##
|
||||
## dictionary =
|
||||
## expect
|
||||
## Dict.single "A" "B"
|
||||
## |> Bool.isEq (Dict.insert Dict.empty "A" "B")
|
||||
single : k, v -> Dict k v | k has Hash & Eq
|
||||
single = \k, v ->
|
||||
insert empty k v
|
||||
|
||||
## Returns dictionary with the keys and values specified by the input [List].
|
||||
##
|
||||
## expect
|
||||
## Dict.single 1 "One"
|
||||
## |> Dict.insert 2 "Two"
|
||||
## |> Dict.insert 3 "Three"
|
||||
## |> Dict.insert 4 "Four"
|
||||
## |> Bool.isEq (Dict.fromList [T 1 "One", T 2 "Two", T 3 "Three", T 4 "Four"])
|
||||
fromList : List (T k v) -> Dict k v | k has Hash & Eq
|
||||
fromList = \data ->
|
||||
# TODO: make this efficient. Should just set data and then set all indicies in the hashmap.
|
||||
List.walk data empty (\dict, T k v -> insert dict k v)
|
||||
|
||||
## Returns the number of values in the dictionary.
|
||||
##
|
||||
## expect
|
||||
## Dict.empty
|
||||
## |> Dict.insert 1 "Apple"
|
||||
## |> Dict.insert 2 "Orange"
|
||||
##
|
||||
## expect Dict.get dictionary 1 == Ok "Apple"
|
||||
## expect Dict.get dictionary 2000 == Err KeyNotFound
|
||||
get : Dict k v, k -> Result v [KeyNotFound] | k has Eq
|
||||
get = \@Dict list, needle ->
|
||||
when List.findFirst list (\Pair key _ -> key == needle) is
|
||||
Ok (Pair _ v) ->
|
||||
Ok v
|
||||
## |> Dict.insert "One" "A Song"
|
||||
## |> Dict.insert "Two" "Candy Canes"
|
||||
## |> Dict.insert "Three" "Boughs of Holly"
|
||||
## |> Dict.len
|
||||
## |> Bool.isEq 3
|
||||
len : Dict k v -> Nat | k has Hash & Eq
|
||||
len = \@Dict { size } ->
|
||||
size
|
||||
|
||||
Err NotFound ->
|
||||
Err KeyNotFound
|
||||
## Clears all elements from a dictionary keeping around the allocation if it isn't huge.
|
||||
clear : Dict k v -> Dict k v | k has Hash & Eq
|
||||
clear = \@Dict { metadata, dataIndices, data } ->
|
||||
cap = List.len dataIndices
|
||||
|
||||
# Only clear large allocations.
|
||||
if cap > 128 * 8 then
|
||||
empty
|
||||
else
|
||||
@Dict {
|
||||
metadata: List.map metadata (\_ -> emptySlot),
|
||||
# just leave data indicies as garbage, no need to clear.
|
||||
dataIndices,
|
||||
# use takeFirst to keep around the capacity.
|
||||
data: List.takeFirst data 0,
|
||||
size: 0,
|
||||
}
|
||||
|
||||
## Iterate through the keys and values in the dictionary and call the provided
|
||||
## function with signature `state, k, v -> state` for each value, with an
|
||||
|
@ -124,9 +187,78 @@ get = \@Dict list, needle ->
|
|||
## |> Dict.insert "Orange" 24
|
||||
## |> Dict.walk 0 (\count, _, qty -> count + qty)
|
||||
## |> Bool.isEq 36
|
||||
walk : Dict k v, state, (state, k, v -> state) -> state
|
||||
walk = \@Dict list, initialState, transform ->
|
||||
List.walk list initialState (\state, Pair k v -> transform state k v)
|
||||
walk : Dict k v, state, (state, k, v -> state) -> state | k has Hash & Eq
|
||||
walk = \@Dict { data }, initialState, transform ->
|
||||
List.walk data initialState (\state, T k v -> transform state k v)
|
||||
|
||||
## Same as [Dict.walk], except you can stop walking early.
|
||||
##
|
||||
## ## Performance Details
|
||||
##
|
||||
## Compared to [Dict.walk], this can potentially visit fewer elements (which can
|
||||
## improve performance) at the cost of making each step take longer.
|
||||
## However, the added cost to each step is extremely small, and can easily
|
||||
## be outweighed if it results in skipping even a small number of elements.
|
||||
##
|
||||
## As such, it is typically better for performance to use this over [Dict.walk]
|
||||
## if returning `Break` earlier than the last element is expected to be common.
|
||||
walkUntil : Dict k v, state, (state, k, v -> [Continue state, Break state]) -> state | k has Hash & Eq
|
||||
walkUntil = \@Dict { data }, initialState, transform ->
|
||||
List.walkUntil data initialState (\state, T k v -> transform state k v)
|
||||
|
||||
## Get the value for a given key. If there is a value for the specified key it
|
||||
## will return [Ok value], otherwise return [Err KeyNotFound].
|
||||
##
|
||||
## dictionary =
|
||||
## Dict.empty
|
||||
## |> Dict.insert 1 "Apple"
|
||||
## |> Dict.insert 2 "Orange"
|
||||
##
|
||||
## expect Dict.get dictionary 1 == Ok "Apple"
|
||||
## expect Dict.get dictionary 2000 == Err KeyNotFound
|
||||
get : Dict k v, k -> Result v [KeyNotFound] | k has Hash & Eq
|
||||
get = \@Dict { metadata, dataIndices, data }, key ->
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
|
||||
when findIndexHelper metadata dataIndices data h2Key key probe 0 is
|
||||
Ok index ->
|
||||
dataIndex = listGetUnsafe dataIndices index
|
||||
(T _ v) = listGetUnsafe data dataIndex
|
||||
|
||||
Ok v
|
||||
|
||||
Err NotFound ->
|
||||
Err KeyNotFound
|
||||
|
||||
## Check if the dictionary has a value for a specified key.
|
||||
##
|
||||
## expect
|
||||
## Dict.empty
|
||||
## |> Dict.insert 1234 "5678"
|
||||
## |> Dict.contains 1234
|
||||
## |> Bool.isEq Bool.true
|
||||
contains : Dict k v, k -> Bool | k has Hash & Eq
|
||||
contains = \@Dict { metadata, dataIndices, data }, key ->
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
|
||||
when findIndexHelper metadata dataIndices data h2Key key probe 0 is
|
||||
Ok _ ->
|
||||
Bool.true
|
||||
|
||||
Err NotFound ->
|
||||
Bool.false
|
||||
|
||||
## Insert a value into the dictionary at a specified key.
|
||||
##
|
||||
|
@ -135,29 +267,42 @@ walk = \@Dict list, initialState, transform ->
|
|||
## |> Dict.insert "Apples" 12
|
||||
## |> Dict.get "Apples"
|
||||
## |> Bool.isEq (Ok 12)
|
||||
insert : Dict k v, k, v -> Dict k v | k has Eq
|
||||
insert = \@Dict list, k, v ->
|
||||
when List.findFirstIndex list (\Pair key _ -> key == k) is
|
||||
Err NotFound ->
|
||||
insertFresh (@Dict list) k v
|
||||
insert : Dict k v, k, v -> Dict k v | k has Hash & Eq
|
||||
insert = \@Dict { metadata, dataIndices, data, size }, key, value ->
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
|
||||
when findIndexHelper metadata dataIndices data h2Key key probe 0 is
|
||||
Ok index ->
|
||||
list
|
||||
|> List.set index (Pair k v)
|
||||
|> @Dict
|
||||
dataIndex = listGetUnsafe dataIndices index
|
||||
|
||||
## Returns the number of values in the dictionary.
|
||||
##
|
||||
## expect
|
||||
## Dict.empty
|
||||
## |> Dict.insert "One" "A Song"
|
||||
## |> Dict.insert "Two" "Candy Canes"
|
||||
## |> Dict.insert "Three" "Boughs of Holly"
|
||||
## |> Dict.len
|
||||
## |> Bool.isEq 3
|
||||
len : Dict k v -> Nat
|
||||
len = \@Dict list ->
|
||||
List.len list
|
||||
@Dict {
|
||||
metadata,
|
||||
dataIndices,
|
||||
data: List.set data dataIndex (T key value),
|
||||
size,
|
||||
}
|
||||
|
||||
Err NotFound ->
|
||||
# The dictionary has grown, it might need to rehash.
|
||||
rehashedDict =
|
||||
maybeRehash
|
||||
(
|
||||
@Dict {
|
||||
metadata,
|
||||
dataIndices,
|
||||
data,
|
||||
size: size + 1,
|
||||
}
|
||||
)
|
||||
|
||||
# Need to rescan searching for the first empty or deleted cell.
|
||||
insertNotFoundHelper rehashedDict key value h1Key h2Key
|
||||
|
||||
## Remove a value from the dictionary for a specified key.
|
||||
##
|
||||
|
@ -167,19 +312,34 @@ len = \@Dict list ->
|
|||
## |> Dict.remove "Some"
|
||||
## |> Dict.len
|
||||
## |> Bool.isEq 0
|
||||
remove : Dict k v, k -> Dict k v | k has Eq
|
||||
remove = \@Dict list, key ->
|
||||
when List.findFirstIndex list (\Pair k _ -> k == key) is
|
||||
Err NotFound ->
|
||||
@Dict list
|
||||
remove : Dict k v, k -> Dict k v | k has Hash & Eq
|
||||
remove = \@Dict { metadata, dataIndices, data, size }, key ->
|
||||
# TODO: change this from swap remove to tombstone and test is performance is still good.
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
|
||||
when findIndexHelper metadata dataIndices data h2Key key probe 0 is
|
||||
Ok index ->
|
||||
lastIndex = List.len list - 1
|
||||
last = List.len data - 1
|
||||
dataIndex = listGetUnsafe dataIndices index
|
||||
|
||||
list
|
||||
|> List.swap index lastIndex
|
||||
|> List.dropLast
|
||||
|> @Dict
|
||||
if dataIndex == last then
|
||||
@Dict {
|
||||
metadata: List.set metadata index deletedSlot,
|
||||
dataIndices,
|
||||
data: List.dropLast data,
|
||||
size: size - 1,
|
||||
}
|
||||
else
|
||||
swapAndUpdateDataIndex (@Dict { metadata, dataIndices, data, size }) index last
|
||||
|
||||
Err NotFound ->
|
||||
@Dict { metadata, dataIndices, data, size }
|
||||
|
||||
## Insert or remove a value for a specified key. This function enables a
|
||||
## performance optimisation for the use case of providing a default when a value
|
||||
|
@ -195,8 +355,9 @@ remove = \@Dict list, key ->
|
|||
## expect Dict.update Dict.empty "a" alterValue == Dict.single "a" Bool.false
|
||||
## expect Dict.update (Dict.single "a" Bool.false) "a" alterValue == Dict.single "a" Bool.true
|
||||
## expect Dict.update (Dict.single "a" Bool.true) "a" alterValue == Dict.empty
|
||||
update : Dict k v, k, ([Present v, Missing] -> [Present v, Missing]) -> Dict k v | k has Eq
|
||||
update : Dict k v, k, ([Present v, Missing] -> [Present v, Missing]) -> Dict k v | k has Hash & Eq
|
||||
update = \dict, key, alter ->
|
||||
# TODO: look into optimizing by merging substeps and reducing lookups.
|
||||
possibleValue =
|
||||
get dict key
|
||||
|> Result.map Present
|
||||
|
@ -206,46 +367,22 @@ update = \dict, key, alter ->
|
|||
Present value -> insert dict key value
|
||||
Missing -> remove dict key
|
||||
|
||||
# Internal for testing only
|
||||
alterValue : [Present Bool, Missing] -> [Present Bool, Missing]
|
||||
alterValue = \possibleValue ->
|
||||
when possibleValue is
|
||||
Missing -> Present Bool.false
|
||||
Present value -> if value then Missing else Present Bool.true
|
||||
|
||||
expect update empty "a" alterValue == single "a" Bool.false
|
||||
expect update (single "a" Bool.false) "a" alterValue == single "a" Bool.true
|
||||
expect update (single "a" Bool.true) "a" alterValue == empty
|
||||
|
||||
## Check if the dictionary has a value for a specified key.
|
||||
## Returns the keys and values of a dictionary as a [List].
|
||||
## This requires allocating a temporary list, prefer using [Dict.toList] or [Dict.walk] instead.
|
||||
##
|
||||
## expect
|
||||
## Dict.empty
|
||||
## |> Dict.insert 1234 "5678"
|
||||
## |> Dict.contains 1234
|
||||
contains : Dict k v, k -> Bool | k has Eq
|
||||
contains = \@Dict list, needle ->
|
||||
List.any list \Pair key _val -> key == needle
|
||||
|
||||
expect contains empty "a" == Bool.false
|
||||
expect contains (single "a" {}) "a" == Bool.true
|
||||
expect contains (single "b" {}) "a" == Bool.false
|
||||
expect
|
||||
Dict.empty
|
||||
|> Dict.insert 1234 "5678"
|
||||
|> Dict.contains 1234
|
||||
|> Bool.isEq Bool.true
|
||||
|
||||
## Returns a dictionary containing the key and value provided as input.
|
||||
##
|
||||
## expect
|
||||
## Dict.single "A" "B"
|
||||
## |> Bool.isEq (Dict.insert Dict.empty "A" "B")
|
||||
single : k, v -> Dict k v
|
||||
single = \key, value ->
|
||||
@Dict [Pair key value]
|
||||
## Dict.single 1 "One"
|
||||
## |> Dict.insert 2 "Two"
|
||||
## |> Dict.insert 3 "Three"
|
||||
## |> Dict.insert 4 "Four"
|
||||
## |> Dict.toList
|
||||
## |> Bool.isEq [T 1 "One", T 2 "Two", T 3 "Three", T 4 "Four"]
|
||||
toList : Dict k v -> List (T k v) | k has Hash & Eq
|
||||
toList = \@Dict { data } ->
|
||||
data
|
||||
|
||||
## Returns the keys of a dictionary as a [List].
|
||||
## This requires allocating a temporary [List], prefer using [Dict.toList] or [Dict.walk] instead.
|
||||
##
|
||||
## expect
|
||||
## Dict.single 1 "One"
|
||||
|
@ -254,11 +391,12 @@ single = \key, value ->
|
|||
## |> Dict.insert 4 "Four"
|
||||
## |> Dict.keys
|
||||
## |> Bool.isEq [1,2,3,4]
|
||||
keys : Dict k v -> List k
|
||||
keys = \@Dict list ->
|
||||
List.map list (\Pair k _ -> k)
|
||||
keys : Dict k v -> List k | k has Hash & Eq
|
||||
keys = \@Dict { data } ->
|
||||
List.map data (\T k _ -> k)
|
||||
|
||||
## Returns the values of a dictionary as a [List].
|
||||
## This requires allocating a temporary [List], prefer using [Dict.toList] or [Dict.walk] instead.
|
||||
##
|
||||
## expect
|
||||
## Dict.single 1 "One"
|
||||
|
@ -267,22 +405,22 @@ keys = \@Dict list ->
|
|||
## |> Dict.insert 4 "Four"
|
||||
## |> Dict.values
|
||||
## |> Bool.isEq ["One","Two","Three","Four"]
|
||||
values : Dict k v -> List v
|
||||
values = \@Dict list ->
|
||||
List.map list (\Pair _ v -> v)
|
||||
values : Dict k v -> List v | k has Hash & Eq
|
||||
values = \@Dict { data } ->
|
||||
List.map data (\T _ v -> v)
|
||||
|
||||
## Combine two dictionaries by keeping the [union](https://en.wikipedia.org/wiki/Union_(set_theory))
|
||||
## of all the key-value pairs. This means that all the key-value pairs in
|
||||
## both dictionaries will be combined. Note that where there are pairs
|
||||
## with the same key, the value contained in the first input will be
|
||||
## retained, and the value in the second input will be removed.
|
||||
## with the same key, the value contained in the second input will be
|
||||
## retained, and the value in the first input will be removed.
|
||||
##
|
||||
## first =
|
||||
## Dict.single 1 "Keep Me"
|
||||
## Dict.single 1 "Not Me"
|
||||
## |> Dict.insert 2 "And Me"
|
||||
##
|
||||
## second =
|
||||
## Dict.single 1 "Not Me"
|
||||
## Dict.single 1 "Keep Me"
|
||||
## |> Dict.insert 3 "Me Too"
|
||||
## |> Dict.insert 4 "And Also Me"
|
||||
##
|
||||
|
@ -294,9 +432,9 @@ values = \@Dict list ->
|
|||
##
|
||||
## expect
|
||||
## Dict.insertAll first second == expected
|
||||
insertAll : Dict k v, Dict k v -> Dict k v | k has Eq
|
||||
insertAll = \xs, @Dict ys ->
|
||||
List.walk ys xs (\state, Pair k v -> Dict.insertIfVacant state k v)
|
||||
insertAll : Dict k v, Dict k v -> Dict k v | k has Hash & Eq
|
||||
insertAll = \xs, ys ->
|
||||
walk ys xs insert
|
||||
|
||||
## Combine two dictionaries by keeping the [intersection](https://en.wikipedia.org/wiki/Intersection_(set_theory))
|
||||
## of all the key-value pairs. This means that we keep only those pairs
|
||||
|
@ -315,10 +453,17 @@ insertAll = \xs, @Dict ys ->
|
|||
## |> Dict.insert 4 "Or Me"
|
||||
##
|
||||
## expect Dict.keepShared first second == first
|
||||
keepShared : Dict k v, Dict k v -> Dict k v | k has Eq
|
||||
keepShared = \@Dict xs, ys ->
|
||||
List.keepIf xs (\Pair k _ -> Dict.contains ys k)
|
||||
|> @Dict
|
||||
keepShared : Dict k v, Dict k v -> Dict k v | k has Hash & Eq
|
||||
keepShared = \xs, ys ->
|
||||
walk
|
||||
xs
|
||||
empty
|
||||
(\state, k, v ->
|
||||
if contains ys k then
|
||||
insert state k v
|
||||
else
|
||||
state
|
||||
)
|
||||
|
||||
## Remove the key-value pairs in the first input that are also in the second
|
||||
## using the [set difference](https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement)
|
||||
|
@ -339,25 +484,349 @@ keepShared = \@Dict xs, ys ->
|
|||
## |> Dict.insert 2 "And Me"
|
||||
##
|
||||
## expect Dict.removeAll first second == expected
|
||||
removeAll : Dict k v, Dict k v -> Dict k v | k has Eq
|
||||
removeAll = \xs, @Dict ys ->
|
||||
List.walk ys xs (\state, Pair k _ -> Dict.remove state k)
|
||||
removeAll : Dict k v, Dict k v -> Dict k v | k has Hash & Eq
|
||||
removeAll = \xs, ys ->
|
||||
walk ys xs (\state, k, _ -> remove state k)
|
||||
|
||||
## Internal helper function to insert a new association
|
||||
##
|
||||
## Precondition: `k` should not exist in the Dict yet.
|
||||
insertFresh : Dict k v, k, v -> Dict k v
|
||||
insertFresh = \@Dict list, k, v ->
|
||||
list
|
||||
|> List.append (Pair k v)
|
||||
|> @Dict
|
||||
swapAndUpdateDataIndex : Dict k v, Nat, Nat -> Dict k v | k has Hash & Eq
|
||||
swapAndUpdateDataIndex = \@Dict { metadata, dataIndices, data, size }, removedIndex, lastIndex ->
|
||||
(T key _) = listGetUnsafe data lastIndex
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
|
||||
insertIfVacant : Dict k v, k, v -> Dict k v | k has Eq
|
||||
insertIfVacant = \dict, key, value ->
|
||||
if Dict.contains dict key then
|
||||
dict
|
||||
when findIndexHelper metadata dataIndices data h2Key key probe 0 is
|
||||
Ok index ->
|
||||
dataIndex = listGetUnsafe dataIndices removedIndex
|
||||
# Swap and remove data.
|
||||
nextData =
|
||||
data
|
||||
|> List.swap dataIndex lastIndex
|
||||
|> List.dropLast
|
||||
|
||||
@Dict {
|
||||
# Set old metadata as deleted.
|
||||
metadata: List.set metadata removedIndex deletedSlot,
|
||||
# Update index of swaped element.
|
||||
dataIndices: List.set dataIndices index dataIndex,
|
||||
data: nextData,
|
||||
size: size - 1,
|
||||
}
|
||||
|
||||
Err NotFound ->
|
||||
# This should be impossible.
|
||||
crash "unreachable state in dict swapAndUpdateDataIndex hit. Definitely a standard library bug."
|
||||
|
||||
insertNotFoundHelper : Dict k v, k, v, U64, I8 -> Dict k v
|
||||
insertNotFoundHelper = \@Dict { metadata, dataIndices, data, size }, key, value, h1Key, h2Key ->
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
index = nextEmptyOrDeletedHelper metadata probe 0
|
||||
dataIndex = List.len data
|
||||
nextData = List.append data (T key value)
|
||||
|
||||
@Dict {
|
||||
metadata: List.set metadata index h2Key,
|
||||
dataIndices: List.set dataIndices index dataIndex,
|
||||
data: nextData,
|
||||
size,
|
||||
}
|
||||
|
||||
nextEmptyOrDeletedHelper : List I8, Probe, Nat -> Nat
|
||||
nextEmptyOrDeletedHelper = \metadata, probe, offset ->
|
||||
# For inserting, we can use deleted indices.
|
||||
index = Num.addWrap (mul8 probe.slotIndex) offset
|
||||
|
||||
md = listGetUnsafe metadata index
|
||||
|
||||
if md < 0 then
|
||||
# Empty or deleted slot, no possibility of the element.
|
||||
index
|
||||
else if offset == 7 then
|
||||
nextEmptyOrDeletedHelper metadata (nextProbe probe) 0
|
||||
else
|
||||
Dict.insert dict key value
|
||||
nextEmptyOrDeletedHelper metadata probe (Num.addWrap offset 1)
|
||||
|
||||
# TODO: investigate if this needs to be split into more specific helper functions.
|
||||
# There is a chance that returning specific sub-info like the value would be faster.
|
||||
findIndexHelper : List I8, List Nat, List (T k v), I8, k, Probe, Nat -> Result Nat [NotFound] | k has Hash & Eq
|
||||
findIndexHelper = \metadata, dataIndices, data, h2Key, key, probe, offset ->
|
||||
# For finding a value, we must search past all deleted element tombstones.
|
||||
index = Num.addWrap (mul8 probe.slotIndex) offset
|
||||
|
||||
md = listGetUnsafe metadata index
|
||||
|
||||
if md == emptySlot then
|
||||
# Empty slot, no possibility of the element.
|
||||
Err NotFound
|
||||
else if md == h2Key then
|
||||
# Potentially matching slot, check if the key is a match.
|
||||
dataIndex = listGetUnsafe dataIndices index
|
||||
(T k _) = listGetUnsafe data dataIndex
|
||||
|
||||
if k == key then
|
||||
# We have a match, return its index.
|
||||
Ok index
|
||||
else if offset == 7 then
|
||||
# No match, keep checking.
|
||||
findIndexHelper metadata dataIndices data h2Key key (nextProbe probe) 0
|
||||
else
|
||||
findIndexHelper metadata dataIndices data h2Key key probe (Num.addWrap offset 1)
|
||||
else if offset == 7 then
|
||||
# Used slot, check next slot.
|
||||
findIndexHelper metadata dataIndices data h2Key key (nextProbe probe) 0
|
||||
else
|
||||
findIndexHelper metadata dataIndices data h2Key key probe (Num.addWrap offset 1)
|
||||
|
||||
# This is how we grow the container.
|
||||
# If we aren't to the load factor yet, just ignore this.
|
||||
# The container must have an updated size including any elements about to be inserted.
|
||||
maybeRehash : Dict k v -> Dict k v | k has Hash & Eq
|
||||
maybeRehash = \@Dict { metadata, dataIndices, data, size } ->
|
||||
cap = List.len dataIndices
|
||||
maxLoadCap =
|
||||
# This is 7/8 * capacity, which is the max load factor.
|
||||
cap - Num.shiftRightZfBy cap 3
|
||||
|
||||
if size > maxLoadCap then
|
||||
rehash (@Dict { metadata, dataIndices, data, size })
|
||||
else
|
||||
@Dict { metadata, dataIndices, data, size }
|
||||
|
||||
# TODO: switch rehash to iterate data and eventually clear out tombstones as well.
|
||||
rehash : Dict k v -> Dict k v | k has Hash & Eq
|
||||
rehash = \@Dict { metadata, dataIndices, data, size } ->
|
||||
newLen = 2 * List.len dataIndices
|
||||
newDict =
|
||||
@Dict {
|
||||
metadata: List.repeat emptySlot newLen,
|
||||
dataIndices: List.repeat 0 newLen,
|
||||
data,
|
||||
size,
|
||||
}
|
||||
|
||||
rehashHelper newDict metadata dataIndices data 0
|
||||
|
||||
rehashHelper : Dict k v, List I8, List Nat, List (T k v), Nat -> Dict k v | k has Hash & Eq
|
||||
rehashHelper = \dict, oldMetadata, oldDataIndices, oldData, index ->
|
||||
when List.get oldMetadata index is
|
||||
Ok md ->
|
||||
nextDict =
|
||||
if md >= 0 then
|
||||
# We have an actual element here
|
||||
dataIndex = listGetUnsafe oldDataIndices index
|
||||
(T k _) = listGetUnsafe oldData dataIndex
|
||||
|
||||
insertForRehash dict k dataIndex
|
||||
else
|
||||
# Empty or deleted data
|
||||
dict
|
||||
|
||||
rehashHelper nextDict oldMetadata oldDataIndices oldData (index + 1)
|
||||
|
||||
Err OutOfBounds ->
|
||||
# Walked entire list, complete now.
|
||||
dict
|
||||
|
||||
insertForRehash : Dict k v, k, Nat -> Dict k v | k has Hash & Eq
|
||||
insertForRehash = \@Dict { metadata, dataIndices, data, size }, key, dataIndex ->
|
||||
hashKey =
|
||||
createLowLevelHasher {}
|
||||
|> Hash.hash key
|
||||
|> complete
|
||||
h1Key = h1 hashKey
|
||||
h2Key = h2 hashKey
|
||||
probe = newProbe h1Key (div8 (List.len metadata))
|
||||
index = nextEmptyOrDeletedHelper metadata probe 0
|
||||
|
||||
@Dict {
|
||||
metadata: List.set metadata index h2Key,
|
||||
dataIndices: List.set dataIndices index dataIndex,
|
||||
data,
|
||||
size,
|
||||
}
|
||||
|
||||
emptySlot : I8
|
||||
emptySlot = -128
|
||||
deletedSlot : I8
|
||||
deletedSlot = -2
|
||||
|
||||
T k v : [T k v]
|
||||
|
||||
# Capacity must be a power of 2.
|
||||
# We still will use slots of 8 even though this version has no true slots.
|
||||
# We just move an element at a time.
|
||||
# Thus, the true index is slotIndex * 8 + offset.
|
||||
Probe : { slotIndex : Nat, probeI : Nat, mask : Nat }
|
||||
|
||||
newProbe : U64, Nat -> Probe
|
||||
newProbe = \h1Key, slots ->
|
||||
mask = Num.subSaturated slots 1
|
||||
slotIndex = Num.bitwiseAnd (Num.toNat h1Key) mask
|
||||
|
||||
{ slotIndex, probeI: 1, mask }
|
||||
|
||||
nextProbe : Probe -> Probe
|
||||
nextProbe = \{ slotIndex, probeI, mask } ->
|
||||
nextSlotIndex = Num.bitwiseAnd (Num.addWrap slotIndex probeI) mask
|
||||
|
||||
{ slotIndex: nextSlotIndex, probeI: Num.addWrap probeI 1, mask }
|
||||
|
||||
mul8 = \val -> Num.shiftLeftBy val 3
|
||||
div8 = \val -> Num.shiftRightZfBy val 3
|
||||
|
||||
h1 : U64 -> U64
|
||||
h1 = \hashKey ->
|
||||
Num.shiftRightZfBy hashKey 7
|
||||
|
||||
h2 : U64 -> I8
|
||||
h2 = \hashKey ->
|
||||
Num.toI8 (Num.bitwiseAnd hashKey 0b0111_1111)
|
||||
|
||||
expect
|
||||
val =
|
||||
empty
|
||||
|> insert "foo" "bar"
|
||||
|> get "foo"
|
||||
|
||||
val == Ok "bar"
|
||||
|
||||
expect
|
||||
val =
|
||||
empty
|
||||
|> insert "foo" "bar"
|
||||
|> insert "foo" "baz"
|
||||
|> get "foo"
|
||||
|
||||
val == Ok "baz"
|
||||
|
||||
expect
|
||||
val =
|
||||
empty
|
||||
|> insert "foo" "bar"
|
||||
|> get "bar"
|
||||
|
||||
val == Err KeyNotFound
|
||||
|
||||
expect
|
||||
empty
|
||||
|> insert "foo" {}
|
||||
|> contains "foo"
|
||||
|
||||
expect
|
||||
dict =
|
||||
empty
|
||||
|> insert "foo" {}
|
||||
|> insert "bar" {}
|
||||
|> insert "baz" {}
|
||||
|
||||
contains dict "baz" && Bool.not (contains dict "other")
|
||||
|
||||
expect
|
||||
dict =
|
||||
fromList [T 1u8 1u8, T 2 2, T 3 3]
|
||||
|> remove 1
|
||||
|> remove 3
|
||||
|
||||
keys dict == [2]
|
||||
|
||||
expect
|
||||
list =
|
||||
fromList [T 1u8 1u8, T 2u8 2u8, T 3 3]
|
||||
|> remove 1
|
||||
|> insert 0 0
|
||||
|> remove 3
|
||||
|> keys
|
||||
|
||||
list == [0, 2]
|
||||
|
||||
# Reach capacity, no rehash.
|
||||
expect
|
||||
val =
|
||||
empty
|
||||
|> insert "a" 0
|
||||
|> insert "b" 1
|
||||
|> insert "c" 2
|
||||
|> insert "d" 3
|
||||
|> insert "e" 4
|
||||
|> insert "f" 5
|
||||
|> insert "g" 6
|
||||
|> capacity
|
||||
|
||||
val == 7
|
||||
|
||||
expect
|
||||
dict =
|
||||
empty
|
||||
|> insert "a" 0
|
||||
|> insert "b" 1
|
||||
|> insert "c" 2
|
||||
|> insert "d" 3
|
||||
|> insert "e" 4
|
||||
|> insert "f" 5
|
||||
|> insert "g" 6
|
||||
|
||||
(get dict "a" == Ok 0)
|
||||
&& (get dict "b" == Ok 1)
|
||||
&& (get dict "c" == Ok 2)
|
||||
&& (get dict "d" == Ok 3)
|
||||
&& (get dict "e" == Ok 4)
|
||||
&& (get dict "f" == Ok 5)
|
||||
&& (get dict "g" == Ok 6)
|
||||
|
||||
# Force rehash.
|
||||
expect
|
||||
val =
|
||||
empty
|
||||
|> insert "a" 0
|
||||
|> insert "b" 1
|
||||
|> insert "c" 2
|
||||
|> insert "d" 3
|
||||
|> insert "e" 4
|
||||
|> insert "f" 5
|
||||
|> insert "g" 6
|
||||
|> insert "h" 7
|
||||
|> capacity
|
||||
|
||||
val == 14
|
||||
|
||||
expect
|
||||
dict =
|
||||
empty
|
||||
|> insert "a" 0
|
||||
|> insert "b" 1
|
||||
|> insert "c" 2
|
||||
|> insert "d" 3
|
||||
|> insert "e" 4
|
||||
|> insert "f" 5
|
||||
|> insert "g" 6
|
||||
|> insert "h" 7
|
||||
|
||||
(get dict "a" == Ok 0)
|
||||
&& (get dict "b" == Ok 1)
|
||||
&& (get dict "c" == Ok 2)
|
||||
&& (get dict "d" == Ok 3)
|
||||
&& (get dict "e" == Ok 4)
|
||||
&& (get dict "f" == Ok 5)
|
||||
&& (get dict "g" == Ok 6)
|
||||
&& (get dict "h" == Ok 7)
|
||||
|
||||
expect
|
||||
empty
|
||||
|> insert "Some" "Value"
|
||||
|> remove "Some"
|
||||
|> len
|
||||
|> Bool.isEq 0
|
||||
|
||||
# Makes sure a Dict with Nat keys works
|
||||
expect
|
||||
empty
|
||||
|> insert 7nat "Testing"
|
||||
|> get 7
|
||||
|> Bool.isEq (Ok "Testing")
|
||||
|
||||
# We have decided not to expose the standard roc hashing algorithm.
|
||||
# This is to avoid external dependence and the need for versioning.
|
||||
|
@ -524,10 +993,32 @@ wymix = \a, b ->
|
|||
|
||||
wymum : U64, U64 -> { lower : U64, upper : U64 }
|
||||
wymum = \a, b ->
|
||||
r = Num.toU128 a * Num.toU128 b
|
||||
lower = Num.toU64 r
|
||||
upper = Num.shiftRightZfBy r 64 |> Num.toU64
|
||||
# uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo;
|
||||
# uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl;
|
||||
# lo=t+(rm1<<32); c+=lo<t; hi=rh+(rm0>>32)+(rm1>>32)+c;
|
||||
ha = Num.shiftRightZfBy a 32
|
||||
hb = Num.shiftRightZfBy b 32
|
||||
la = Num.bitwiseAnd a 0x0000_0000_FFFF_FFFF
|
||||
lb = Num.bitwiseAnd b 0x0000_0000_FFFF_FFFF
|
||||
rh = ha * hb
|
||||
rm0 = ha * lb
|
||||
rm1 = hb * la
|
||||
rl = la * lb
|
||||
t = Num.addWrap rl (Num.shiftLeftBy rm0 32)
|
||||
c = if t < rl then 1 else 0
|
||||
lower = Num.addWrap t (Num.shiftLeftBy rm1 32)
|
||||
c2 = c + (if lower < t then 1 else 0)
|
||||
upper =
|
||||
rh
|
||||
|> Num.addWrap (Num.shiftRightZfBy rm0 32)
|
||||
|> Num.addWrap (Num.shiftRightZfBy rm1 32)
|
||||
|> Num.addWrap c2
|
||||
|
||||
# TODO: switch back to this once wasm supports bit shifting a U128.
|
||||
# The above code is manually doing the 128bit multiplication.
|
||||
# r = Num.toU128 a * Num.toU128 b
|
||||
# lower = Num.toU64 r
|
||||
# upper = Num.shiftRightZfBy r 64 |> Num.toU64
|
||||
# This is the more robust form.
|
||||
# { lower: Num.bitwiseXor a lower, upper: Num.bitwiseXor b upper }
|
||||
{ lower, upper }
|
||||
|
|
|
@ -14,14 +14,16 @@ interface Hash
|
|||
hashI32,
|
||||
hashI64,
|
||||
hashI128,
|
||||
hashNat,
|
||||
complete,
|
||||
hashStrBytes,
|
||||
hashList,
|
||||
hashUnordered,
|
||||
] imports [
|
||||
Bool.{ isEq },
|
||||
List,
|
||||
Str,
|
||||
Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128 },
|
||||
Num.{ U8, U16, U32, U64, U128, I8, I16, I32, I64, I128, Nat },
|
||||
]
|
||||
|
||||
## A value that can hashed.
|
||||
|
@ -88,6 +90,21 @@ hashI64 = \hasher, n -> addU64 hasher (Num.toU64 n)
|
|||
hashI128 : a, I128 -> a | a has Hasher
|
||||
hashI128 = \hasher, n -> addU128 hasher (Num.toU128 n)
|
||||
|
||||
## Adds a single Nat to a hasher.
|
||||
hashNat : a, Nat -> a | a has Hasher
|
||||
hashNat = \hasher, n ->
|
||||
isPlatform32bit =
|
||||
x : Nat
|
||||
x = 0xffff_ffff
|
||||
y = Num.addWrap x 1
|
||||
|
||||
y == 0
|
||||
|
||||
if isPlatform32bit then
|
||||
addU32 hasher (Num.toU32 n)
|
||||
else
|
||||
addU64 hasher (Num.toU64 n)
|
||||
|
||||
## Adds a container of [Hash]able elements to a [Hasher] by hashing each element.
|
||||
## The container is iterated using the walk method passed in.
|
||||
## The order of the elements does not affect the final hash.
|
||||
|
|
|
@ -205,7 +205,7 @@ takeWhile = \list, predicate ->
|
|||
helper { taken: [], rest: list }
|
||||
|
||||
digits : List U8
|
||||
digits = List.range '0' ('9' + 1)
|
||||
digits = List.range { start: At '0', end: At '9' }
|
||||
|
||||
takeDigits = \bytes ->
|
||||
takeWhile bytes \n -> List.contains digits n
|
||||
|
|
|
@ -637,26 +637,122 @@ mapWithIndexHelp = \src, dest, func, index, length ->
|
|||
else
|
||||
dest
|
||||
|
||||
## Returns a list of all the integers between one and another,
|
||||
## including both of the given numbers.
|
||||
## Returns a list of all the integers between `start` and `end`.
|
||||
##
|
||||
## >>> List.range 2 8
|
||||
range : Int a, Int a -> List (Int a)
|
||||
range = \start, end ->
|
||||
when Num.compare start end is
|
||||
GT -> []
|
||||
EQ -> [start]
|
||||
LT ->
|
||||
length = Num.intCast (end - start)
|
||||
## To include the `start` and `end` integers themselves, use `At` like so:
|
||||
##
|
||||
## List.range { start: At 2, end: At 5 } # returns [2, 3, 4, 5]
|
||||
##
|
||||
## To exclude them, use `After` and `Before`, like so:
|
||||
##
|
||||
## List.range { start: After 2, end: Before 5 } # returns [3, 4]
|
||||
##
|
||||
## You can have the list end at a certain length rather than a certain integer:
|
||||
##
|
||||
## List.range { start: At 6, end: Length 4 } # returns [6, 7, 8, 9]
|
||||
##
|
||||
## If `step` is specified, each integer increases by that much. (`step: 1` is the default.)
|
||||
##
|
||||
## List.range { start: After 0, end: Before 9, step: 3 } # returns [3, 6]
|
||||
##
|
||||
## All of these options are compatible with the others. For example, you can use `At` or `After`
|
||||
## with `start` regardless of what `end` and `step` are set to.
|
||||
range : _
|
||||
range = \{ start, end, step ? 0 } ->
|
||||
{ incByStep, stepIsPositive } =
|
||||
if step == 0 then
|
||||
when T start end is
|
||||
T (At x) (At y) | T (At x) (Before y) | T (After x) (At y) | T (After x) (Before y) ->
|
||||
if x < y then
|
||||
{
|
||||
incByStep: \i -> i + 1,
|
||||
stepIsPositive: Bool.true,
|
||||
}
|
||||
else
|
||||
{
|
||||
incByStep: \i -> i - 1,
|
||||
stepIsPositive: Bool.false,
|
||||
}
|
||||
|
||||
rangeHelp (List.withCapacity length) start end
|
||||
T (At _) (Length _) | T (After _) (Length _) ->
|
||||
{
|
||||
incByStep: \i -> i + 1,
|
||||
stepIsPositive: Bool.true,
|
||||
}
|
||||
else
|
||||
{
|
||||
incByStep: \i -> i + step,
|
||||
stepIsPositive: step > 0,
|
||||
}
|
||||
|
||||
rangeHelp : List (Int a), Int a, Int a -> List (Int a)
|
||||
rangeHelp = \accum, start, end ->
|
||||
if end <= start then
|
||||
inclusiveStart =
|
||||
when start is
|
||||
At x -> x
|
||||
After x -> incByStep x
|
||||
|
||||
when end is
|
||||
At at ->
|
||||
isComplete =
|
||||
if stepIsPositive then
|
||||
\i -> i > at
|
||||
else
|
||||
\i -> i < at
|
||||
|
||||
# TODO: switch to List.withCapacity
|
||||
rangeHelp [] inclusiveStart incByStep isComplete
|
||||
|
||||
Before before ->
|
||||
isComplete =
|
||||
if stepIsPositive then
|
||||
\i -> i >= before
|
||||
else
|
||||
\i -> i <= before
|
||||
|
||||
# TODO: switch to List.withCapacity
|
||||
rangeHelp [] inclusiveStart incByStep isComplete
|
||||
|
||||
Length l ->
|
||||
rangeLengthHelp (List.withCapacity l) inclusiveStart l incByStep
|
||||
|
||||
rangeHelp = \accum, i, incByStep, isComplete ->
|
||||
if isComplete i then
|
||||
accum
|
||||
else
|
||||
rangeHelp (List.appendUnsafe accum start) (start + 1) end
|
||||
# TODO: change this to List.appendUnsafe once capacity is set correctly
|
||||
rangeHelp (List.append accum i) (incByStep i) incByStep isComplete
|
||||
|
||||
rangeLengthHelp = \accum, i, remaining, incByStep ->
|
||||
if remaining == 0 then
|
||||
accum
|
||||
else
|
||||
rangeLengthHelp (List.appendUnsafe accum i) (incByStep i) (remaining - 1) incByStep
|
||||
|
||||
expect
|
||||
List.range { start: At 0, end: At 4 } == [0, 1, 2, 3, 4]
|
||||
|
||||
expect
|
||||
List.range { start: After 0, end: At 4 } == [1, 2, 3, 4]
|
||||
|
||||
expect
|
||||
List.range { start: At 0, end: At 4, step: 2 } == [0, 2, 4]
|
||||
|
||||
expect
|
||||
List.range { start: At 0, end: Before 4 } == [0, 1, 2, 3]
|
||||
|
||||
expect
|
||||
List.range { start: After 0, end: Before 4 } == [1, 2, 3]
|
||||
|
||||
expect
|
||||
List.range { start: At 0, end: Before 4, step: 2 } == [0, 2]
|
||||
|
||||
expect
|
||||
List.range { start: At 4, end: Length 5 } == [4, 5, 6, 7, 8]
|
||||
|
||||
expect
|
||||
List.range { start: At 4, end: Length 5, step: 10 } == [4, 14, 24, 34, 44]
|
||||
|
||||
expect
|
||||
List.range { start: At 4, end: Length 5, step: -3 } == [4, 1, -2, -5, -8]
|
||||
|
||||
## Sort with a custom comparison function
|
||||
sortWith : List a, (a, a -> [LT, EQ, GT]) -> List a
|
||||
|
|
|
@ -14,99 +14,192 @@ interface Set
|
|||
intersection,
|
||||
difference,
|
||||
]
|
||||
imports [List, Bool.{ Bool, Eq }, Dict.{ Dict }, Num.{ Nat }]
|
||||
imports [
|
||||
List,
|
||||
Bool.{ Bool, Eq },
|
||||
Dict.{ Dict },
|
||||
Num.{ Nat },
|
||||
Hash.{ Hash },
|
||||
]
|
||||
|
||||
Set k := Dict.Dict k {} has [Eq]
|
||||
# We should have this line above the next has.
|
||||
# It causes the formatter to fail currently.
|
||||
# | k has Hash & Eq
|
||||
Set k := Dict.Dict k {}
|
||||
has [
|
||||
Eq {
|
||||
isEq,
|
||||
},
|
||||
]
|
||||
|
||||
fromDict : Dict k {} -> Set k
|
||||
fromDict = \dict -> @Set dict
|
||||
|
||||
toDict : Set k -> Dict k {}
|
||||
toDict = \@Set dict -> dict
|
||||
isEq : Set k, Set k -> Bool | k has Hash & Eq
|
||||
isEq = \xs, ys ->
|
||||
if len xs != len ys then
|
||||
Bool.false
|
||||
else
|
||||
walkUntil xs Bool.true \_, elem ->
|
||||
if contains ys elem then
|
||||
Continue Bool.true
|
||||
else
|
||||
Break Bool.false
|
||||
|
||||
## An empty set.
|
||||
empty : Set k
|
||||
empty = fromDict Dict.empty
|
||||
empty : Set k | k has Hash & Eq
|
||||
empty = @Set Dict.empty
|
||||
|
||||
single : k -> Set k
|
||||
single : k -> Set k | k has Hash & Eq
|
||||
single = \key ->
|
||||
@Set (Dict.single key {})
|
||||
Dict.single key {} |> @Set
|
||||
|
||||
## Make sure never to insert a *NaN* to a [Set]! Because *NaN* is defined to be
|
||||
## unequal to *NaN*, adding a *NaN* results in an entry that can never be
|
||||
## retrieved or removed from the [Set].
|
||||
insert : Set k, k -> Set k | k has Eq
|
||||
insert : Set k, k -> Set k | k has Hash & Eq
|
||||
insert = \@Set dict, key ->
|
||||
dict
|
||||
|> Dict.insert key {}
|
||||
|> @Set
|
||||
Dict.insert dict key {} |> @Set
|
||||
|
||||
# Inserting a duplicate key has no effect.
|
||||
expect
|
||||
actual =
|
||||
Set.empty
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "bar"
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "baz"
|
||||
empty
|
||||
|> insert "foo"
|
||||
|> insert "bar"
|
||||
|> insert "foo"
|
||||
|> insert "baz"
|
||||
|
||||
expected =
|
||||
Set.empty
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "bar"
|
||||
|> Set.insert "baz"
|
||||
empty
|
||||
|> insert "foo"
|
||||
|> insert "bar"
|
||||
|> insert "baz"
|
||||
|
||||
expected == actual
|
||||
|
||||
len : Set k -> Nat
|
||||
len : Set k -> Nat | k has Hash & Eq
|
||||
len = \@Set dict ->
|
||||
Dict.len dict
|
||||
|
||||
# Inserting a duplicate key has no effect on length.
|
||||
expect
|
||||
actual =
|
||||
Set.empty
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "bar"
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "baz"
|
||||
|> Set.len
|
||||
empty
|
||||
|> insert "foo"
|
||||
|> insert "bar"
|
||||
|> insert "foo"
|
||||
|> insert "baz"
|
||||
|> len
|
||||
|
||||
actual == 3
|
||||
|
||||
## Drops the given element from the set.
|
||||
remove : Set k, k -> Set k | k has Eq
|
||||
remove : Set k, k -> Set k | k has Hash & Eq
|
||||
remove = \@Set dict, key ->
|
||||
@Set (Dict.remove dict key)
|
||||
Dict.remove dict key |> @Set
|
||||
|
||||
contains : Set k, k -> Bool | k has Eq
|
||||
contains = \set, key ->
|
||||
set
|
||||
|> Set.toDict
|
||||
|> Dict.contains key
|
||||
contains : Set k, k -> Bool | k has Hash & Eq
|
||||
contains = \@Set dict, key ->
|
||||
Dict.contains dict key
|
||||
|
||||
toList : Set k -> List k
|
||||
toList : Set k -> List k | k has Hash & Eq
|
||||
toList = \@Set dict ->
|
||||
Dict.keys dict
|
||||
|
||||
fromList : List k -> Set k | k has Eq
|
||||
fromList : List k -> Set k | k has Hash & Eq
|
||||
fromList = \list ->
|
||||
initial = @Set (Dict.withCapacity (List.len list))
|
||||
|
||||
List.walk list initial \set, key -> Set.insert set key
|
||||
List.walk list initial insert
|
||||
|
||||
union : Set k, Set k -> Set k | k has Eq
|
||||
union : Set k, Set k -> Set k | k has Hash & Eq
|
||||
union = \@Set dict1, @Set dict2 ->
|
||||
@Set (Dict.insertAll dict1 dict2)
|
||||
Dict.insertAll dict1 dict2 |> @Set
|
||||
|
||||
intersection : Set k, Set k -> Set k | k has Eq
|
||||
intersection : Set k, Set k -> Set k | k has Hash & Eq
|
||||
intersection = \@Set dict1, @Set dict2 ->
|
||||
@Set (Dict.keepShared dict1 dict2)
|
||||
Dict.keepShared dict1 dict2 |> @Set
|
||||
|
||||
difference : Set k, Set k -> Set k | k has Eq
|
||||
difference : Set k, Set k -> Set k | k has Hash & Eq
|
||||
difference = \@Set dict1, @Set dict2 ->
|
||||
@Set (Dict.removeAll dict1 dict2)
|
||||
Dict.removeAll dict1 dict2 |> @Set
|
||||
|
||||
walk : Set k, state, (state, k -> state) -> state
|
||||
walk = \set, state, step ->
|
||||
Dict.walk (Set.toDict set) state (\s, k, _ -> step s k)
|
||||
walk : Set k, state, (state, k -> state) -> state | k has Hash & Eq
|
||||
walk = \@Set dict, state, step ->
|
||||
Dict.walk dict state (\s, k, _ -> step s k)
|
||||
|
||||
walkUntil : Set k, state, (state, k -> [Continue state, Break state]) -> state | k has Hash & Eq
|
||||
walkUntil = \@Set dict, state, step ->
|
||||
Dict.walkUntil dict state (\s, k, _ -> step s k)
|
||||
|
||||
expect
|
||||
first =
|
||||
single "Keep Me"
|
||||
|> insert "And Me"
|
||||
|> insert "Remove Me"
|
||||
|
||||
second =
|
||||
single "Remove Me"
|
||||
|> insert "I do nothing..."
|
||||
|
||||
expected =
|
||||
single "Keep Me"
|
||||
|> insert "And Me"
|
||||
|
||||
difference first second == expected
|
||||
|
||||
expect
|
||||
first =
|
||||
single "Keep Me"
|
||||
|> insert "And Me"
|
||||
|> insert "Remove Me"
|
||||
|
||||
second =
|
||||
single "Remove Me"
|
||||
|> insert "I do nothing..."
|
||||
|
||||
expected =
|
||||
single "Keep Me"
|
||||
|> insert "And Me"
|
||||
|
||||
difference first second == expected
|
||||
|
||||
expect
|
||||
first =
|
||||
single 1
|
||||
|> insert 2
|
||||
|
||||
second =
|
||||
single 1
|
||||
|> insert 3
|
||||
|> insert 4
|
||||
|
||||
expected =
|
||||
single 1
|
||||
|> insert 2
|
||||
|> insert 3
|
||||
|> insert 4
|
||||
|
||||
union first second == expected
|
||||
|
||||
expect
|
||||
base =
|
||||
single "Remove Me"
|
||||
|> insert "Keep Me"
|
||||
|> insert "And Me"
|
||||
|
||||
expected =
|
||||
single "Keep Me"
|
||||
|> insert "And Me"
|
||||
|
||||
remove base "Remove Me" == expected
|
||||
|
||||
expect
|
||||
x =
|
||||
single 0
|
||||
|> insert 1
|
||||
|> insert 2
|
||||
|> insert 3
|
||||
|> insert 4
|
||||
|> insert 5
|
||||
|> insert 6
|
||||
|> insert 7
|
||||
|> insert 8
|
||||
|> insert 9
|
||||
|
||||
x == fromList (toList x)
|
||||
|
|
|
@ -424,9 +424,9 @@ pub const UTILS_EXPECT_FAILED_START_SHARED_BUFFER: &str =
|
|||
"roc_builtins.utils.expect_failed_start_shared_buffer";
|
||||
pub const UTILS_EXPECT_FAILED_START_SHARED_FILE: &str =
|
||||
"roc_builtins.utils.expect_failed_start_shared_file";
|
||||
pub const UTILS_EXPECT_FAILED_FINALIZE: &str = "roc_builtins.utils.expect_failed_finalize";
|
||||
pub const UTILS_EXPECT_READ_ENV_SHARED_BUFFER: &str = "roc_builtins.utils.read_env_shared_buffer";
|
||||
pub const UTILS_SEND_DBG: &str = "roc_builtins.utils.send_dbg";
|
||||
pub const NOTIFY_PARENT_EXPECT: &str = "roc_builtins.utils.notify_parent_expect";
|
||||
pub const NOTIFY_PARENT_DBG: &str = "roc_builtins.utils.notify_parent_dbg";
|
||||
|
||||
pub const UTILS_LONGJMP: &str = "longjmp";
|
||||
pub const UTILS_SETJMP: &str = "setjmp";
|
||||
|
|
|
@ -488,17 +488,19 @@ impl Constraints {
|
|||
/// then need to find their way to the pool, and a convenient approach turned out to be to
|
||||
/// tag them onto the `Let` that we used to add the imported values.
|
||||
#[inline(always)]
|
||||
pub fn let_import_constraint<I1, I2>(
|
||||
pub fn let_import_constraint<I1, I2, I3>(
|
||||
&mut self,
|
||||
rigid_vars: I1,
|
||||
def_types: I2,
|
||||
flex_vars: I2,
|
||||
def_types: I3,
|
||||
module_constraint: Constraint,
|
||||
pool_variables: &[Variable],
|
||||
) -> Constraint
|
||||
where
|
||||
I1: IntoIterator<Item = Variable>,
|
||||
I2: IntoIterator<Item = (Symbol, Loc<TypeOrVar>)>,
|
||||
I2::IntoIter: ExactSizeIterator,
|
||||
I2: IntoIterator<Item = Variable>,
|
||||
I3: IntoIterator<Item = (Symbol, Loc<TypeOrVar>)>,
|
||||
I3::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
// defs and ret constraint are stored consequtively, so we only need to store one index
|
||||
let defs_and_ret_constraint = Index::new(self.constraints.len() as _);
|
||||
|
@ -508,7 +510,7 @@ impl Constraints {
|
|||
|
||||
let let_contraint = LetConstraint {
|
||||
rigid_vars: self.variable_slice(rigid_vars),
|
||||
flex_vars: Slice::default(),
|
||||
flex_vars: self.variable_slice(flex_vars),
|
||||
def_types: self.def_types_slice(def_types),
|
||||
defs_and_ret_constraint,
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::annotation::IntroducedVariables;
|
|||
use crate::annotation::OwnedNamedOrAble;
|
||||
use crate::derive;
|
||||
use crate::env::Env;
|
||||
use crate::expr::get_lookup_symbols;
|
||||
use crate::expr::AnnotatedMark;
|
||||
use crate::expr::ClosureData;
|
||||
use crate::expr::Declarations;
|
||||
|
@ -2414,10 +2415,12 @@ fn decl_to_let(decl: Declaration, loc_ret: Loc<Expr>) -> Loc<Expr> {
|
|||
|
||||
for ((expect_region, condition_region), condition) in it {
|
||||
let region = Region::span_across(&expect_region, &loc_ret.region);
|
||||
let lookups_in_cond = get_lookup_symbols(&condition);
|
||||
|
||||
let expr = Expr::Expect {
|
||||
loc_condition: Box::new(Loc::at(condition_region, condition)),
|
||||
loc_continuation: Box::new(loc_ret),
|
||||
lookups_in_cond: vec![],
|
||||
lookups_in_cond,
|
||||
};
|
||||
|
||||
loc_ret = Loc::at(region, expr);
|
||||
|
|
|
@ -2778,7 +2778,7 @@ pub struct DestructureDef {
|
|||
pub pattern_vars: VecMap<Symbol, Variable>,
|
||||
}
|
||||
|
||||
fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
||||
pub(crate) fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
||||
let mut stack: Vec<&Expr> = vec![expr];
|
||||
let mut lookups: Vec<ExpectLookup> = Vec::new();
|
||||
|
||||
|
@ -2840,8 +2840,16 @@ fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
|||
|
||||
stack.push(&final_else.value);
|
||||
}
|
||||
Expr::LetRec(_, _, _) => todo!(),
|
||||
Expr::LetNonRec { .. } => todo!(),
|
||||
Expr::LetRec(defs, expr, _illegal_cycle_mark) => {
|
||||
for def in defs {
|
||||
stack.push(&def.loc_expr.value);
|
||||
}
|
||||
stack.push(&expr.value);
|
||||
}
|
||||
Expr::LetNonRec(def, expr) => {
|
||||
stack.push(&def.loc_expr.value);
|
||||
stack.push(&expr.value);
|
||||
}
|
||||
Expr::Call(boxed_expr, args, _called_via) => {
|
||||
stack.reserve(1 + args.len());
|
||||
|
||||
|
@ -2995,7 +3003,7 @@ fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: b
|
|||
|
||||
let mut loc_expr = Loc::at(expect_region, expect);
|
||||
|
||||
for stored in stack {
|
||||
for stored in stack.into_iter().rev() {
|
||||
match stored {
|
||||
StoredDef::NonRecursive(region, boxed_def) => {
|
||||
loc_expr = Loc::at(region, Expr::LetNonRec(boxed_def, Box::new(loc_expr)));
|
||||
|
|
|
@ -15,7 +15,7 @@ use roc_module::ident::Ident;
|
|||
use roc_module::ident::Lowercase;
|
||||
use roc_module::symbol::{IdentIds, IdentIdsByModule, ModuleId, ModuleIds, Symbol};
|
||||
use roc_parse::ast::{Defs, TypeAnnotation};
|
||||
use roc_parse::header::HeaderFor;
|
||||
use roc_parse::header::HeaderType;
|
||||
use roc_parse::pattern::PatternType;
|
||||
use roc_problem::can::{Problem, RuntimeError};
|
||||
use roc_region::all::{Loc, Region};
|
||||
|
@ -194,16 +194,17 @@ enum GeneratedInfo {
|
|||
}
|
||||
|
||||
impl GeneratedInfo {
|
||||
fn from_header_for<'a>(
|
||||
fn from_header_type<'a>(
|
||||
env: &mut Env,
|
||||
scope: &mut Scope,
|
||||
var_store: &mut VarStore,
|
||||
header_for: &HeaderFor<'a>,
|
||||
header_type: &HeaderType<'a>,
|
||||
) -> Self {
|
||||
match header_for {
|
||||
HeaderFor::Hosted {
|
||||
match header_type {
|
||||
HeaderType::Hosted {
|
||||
generates,
|
||||
generates_with,
|
||||
name: _,
|
||||
} => {
|
||||
let name: &str = generates.into();
|
||||
let (generated_functions, unknown_generated) =
|
||||
|
@ -236,7 +237,10 @@ impl GeneratedInfo {
|
|||
generated_functions,
|
||||
}
|
||||
}
|
||||
HeaderFor::Builtin { generates_with } => {
|
||||
HeaderType::Builtin {
|
||||
generates_with,
|
||||
name: _,
|
||||
} => {
|
||||
debug_assert!(generates_with.is_empty());
|
||||
GeneratedInfo::Builtin
|
||||
}
|
||||
|
@ -266,7 +270,7 @@ fn has_no_implementation(expr: &Expr) -> bool {
|
|||
pub fn canonicalize_module_defs<'a>(
|
||||
arena: &'a Bump,
|
||||
loc_defs: &'a mut Defs<'a>,
|
||||
header_for: &roc_parse::header::HeaderFor,
|
||||
header_type: &roc_parse::header::HeaderType,
|
||||
home: ModuleId,
|
||||
module_ids: &'a ModuleIds,
|
||||
exposed_ident_ids: IdentIds,
|
||||
|
@ -294,7 +298,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
}
|
||||
|
||||
let generated_info =
|
||||
GeneratedInfo::from_header_for(&mut env, &mut scope, var_store, header_for);
|
||||
GeneratedInfo::from_header_type(&mut env, &mut scope, var_store, header_type);
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
// operator precedence and associativity rules), before doing other canonicalization.
|
||||
|
|
|
@ -79,6 +79,9 @@ flags! {
|
|||
/// Only use this in single-threaded mode!
|
||||
ROC_PRINT_UNIFICATIONS
|
||||
|
||||
/// Prints types whose ability impls failed to be derived.
|
||||
ROC_PRINT_UNDERIVABLE
|
||||
|
||||
/// Prints traces of unspecialized lambda set compaction
|
||||
ROC_TRACE_COMPACTION
|
||||
|
||||
|
@ -116,6 +119,9 @@ flags! {
|
|||
|
||||
// ===Mono===
|
||||
|
||||
/// Type-checks the mono IR after specialization.
|
||||
ROC_CHECK_MONO_IR
|
||||
|
||||
/// Writes a pretty-printed mono IR to stderr after function specialization.
|
||||
ROC_PRINT_IR_AFTER_SPECIALIZATION
|
||||
|
||||
|
|
|
@ -174,6 +174,9 @@ const fn num_symbol_to_hash_lambda(symbol: Symbol) -> Option<FlatHash> {
|
|||
Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => {
|
||||
Some(SingleLambdaSetImmediate(Symbol::HASH_HASH_I128))
|
||||
}
|
||||
Symbol::NUM_NAT | Symbol::NUM_NATURAL => {
|
||||
Some(SingleLambdaSetImmediate(Symbol::HASH_HASH_NAT))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -298,17 +298,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
}
|
||||
SingleQuote(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push('\'');
|
||||
for c in string.chars() {
|
||||
if c == '"' {
|
||||
buf.push_char_literal('"')
|
||||
} else {
|
||||
for escaped in c.escape_default() {
|
||||
buf.push_char_literal(escaped);
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.push('\'');
|
||||
format_sq_literal(buf, string);
|
||||
}
|
||||
&NonBase10Int {
|
||||
base,
|
||||
|
@ -438,6 +428,20 @@ impl<'a> Formattable for Expr<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn format_sq_literal(buf: &mut Buf, s: &str) {
|
||||
buf.push('\'');
|
||||
for c in s.chars() {
|
||||
if c == '"' {
|
||||
buf.push_char_literal('"')
|
||||
} else {
|
||||
for escaped in c.escape_default() {
|
||||
buf.push_char_literal(escaped);
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.push('\'');
|
||||
}
|
||||
|
||||
fn starts_with_newline(expr: &Expr) -> bool {
|
||||
use roc_parse::ast::Expr::*;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::annotation::{Formattable, Newlines, Parens};
|
||||
use crate::expr::fmt_str_literal;
|
||||
use crate::expr::{fmt_str_literal, format_sq_literal};
|
||||
use crate::spaces::{fmt_comments_only, fmt_spaces, NewlineAt};
|
||||
use crate::Buf;
|
||||
use roc_parse::ast::{Base, CommentOrNewline, Pattern};
|
||||
|
@ -155,9 +155,7 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
StrLiteral(literal) => fmt_str_literal(buf, *literal, indent),
|
||||
SingleQuote(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push('\'');
|
||||
buf.push_str(string);
|
||||
buf.push('\'');
|
||||
format_sq_literal(buf, string);
|
||||
}
|
||||
Underscore(name) => {
|
||||
buf.indent(indent);
|
||||
|
|
|
@ -5673,6 +5673,18 @@ mod test_fmt {
|
|||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_char_pattern() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
when x is
|
||||
' ' -> x
|
||||
'\n' -> x
|
||||
'\t' -> x
|
||||
"#
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_nested_pipeline() {
|
||||
expr_formats_same(indoc!(
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::llvm::build_list::{self, allocate_list, empty_polymorphic_list};
|
|||
use crate::llvm::convert::{
|
||||
argument_type_from_layout, basic_type_from_builtin, basic_type_from_layout, zig_str_type,
|
||||
};
|
||||
use crate::llvm::expect::clone_to_shared_memory;
|
||||
use crate::llvm::expect::{clone_to_shared_memory, SharedMemoryPointer};
|
||||
use crate::llvm::refcounting::{
|
||||
build_reset, decrement_refcount_layout, increment_refcount_layout, PointerToRefcount,
|
||||
};
|
||||
|
@ -41,7 +41,7 @@ use roc_error_macros::internal_error;
|
|||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::ir::{
|
||||
BranchInfo, CallType, CrashTag, EntryPoint, JoinPointId, ListLiteralElement, ModifyRc,
|
||||
OptLevel, ProcLayout,
|
||||
OptLevel, ProcLayout, SingleEntryPoint,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, CapturesNiche, LambdaName, LambdaSet, Layout, LayoutIds, RawFunctionLayout,
|
||||
|
@ -2611,17 +2611,20 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
|
||||
match env.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes8 => {
|
||||
let shared_memory = SharedMemoryPointer::get(env);
|
||||
|
||||
clone_to_shared_memory(
|
||||
env,
|
||||
scope,
|
||||
layout_ids,
|
||||
&shared_memory,
|
||||
*cond_symbol,
|
||||
*region,
|
||||
lookups,
|
||||
);
|
||||
|
||||
if let LlvmBackendMode::BinaryDev = env.mode {
|
||||
crate::llvm::expect::finalize(env);
|
||||
crate::llvm::expect::notify_parent_expect(env, &shared_memory);
|
||||
}
|
||||
|
||||
bd.build_unconditional_branch(then_block);
|
||||
|
@ -2677,10 +2680,13 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
|
||||
match env.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes8 => {
|
||||
let shared_memory = SharedMemoryPointer::get(env);
|
||||
|
||||
clone_to_shared_memory(
|
||||
env,
|
||||
scope,
|
||||
layout_ids,
|
||||
&shared_memory,
|
||||
*cond_symbol,
|
||||
*region,
|
||||
lookups,
|
||||
|
@ -4164,29 +4170,23 @@ pub fn build_procedures<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
opt_level: OptLevel,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
|
||||
opt_entry_point: Option<EntryPoint<'a>>,
|
||||
entry_point: EntryPoint<'a>,
|
||||
debug_output_file: Option<&Path>,
|
||||
) {
|
||||
build_procedures_help(
|
||||
env,
|
||||
opt_level,
|
||||
procedures,
|
||||
opt_entry_point,
|
||||
debug_output_file,
|
||||
);
|
||||
build_procedures_help(env, opt_level, procedures, entry_point, debug_output_file);
|
||||
}
|
||||
|
||||
pub fn build_wasm_test_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
opt_level: OptLevel,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
|
||||
entry_point: EntryPoint<'a>,
|
||||
entry_point: SingleEntryPoint<'a>,
|
||||
) -> (&'static str, FunctionValue<'ctx>) {
|
||||
let mod_solutions = build_procedures_help(
|
||||
env,
|
||||
opt_level,
|
||||
procedures,
|
||||
Some(entry_point),
|
||||
EntryPoint::Single(entry_point),
|
||||
Some(&std::env::temp_dir().join("test.ll")),
|
||||
);
|
||||
|
||||
|
@ -4197,13 +4197,13 @@ pub fn build_procedures_return_main<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
opt_level: OptLevel,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
|
||||
entry_point: EntryPoint<'a>,
|
||||
entry_point: SingleEntryPoint<'a>,
|
||||
) -> (&'static str, FunctionValue<'ctx>) {
|
||||
let mod_solutions = build_procedures_help(
|
||||
env,
|
||||
opt_level,
|
||||
procedures,
|
||||
Some(entry_point),
|
||||
EntryPoint::Single(entry_point),
|
||||
Some(&std::env::temp_dir().join("test.ll")),
|
||||
);
|
||||
|
||||
|
@ -4215,13 +4215,14 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>(
|
|||
opt_level: OptLevel,
|
||||
expects: &[Symbol],
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
|
||||
opt_entry_point: Option<EntryPoint<'a>>,
|
||||
) -> Vec<'a, &'a str> {
|
||||
let entry_point = EntryPoint::Expects { symbols: expects };
|
||||
|
||||
let mod_solutions = build_procedures_help(
|
||||
env,
|
||||
opt_level,
|
||||
procedures,
|
||||
opt_entry_point,
|
||||
entry_point,
|
||||
Some(&std::env::temp_dir().join("test.ll")),
|
||||
);
|
||||
|
||||
|
@ -4243,7 +4244,11 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>(
|
|||
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
|
||||
|
||||
let mut it = func_solutions.specs();
|
||||
let func_spec = it.next().unwrap();
|
||||
let func_spec = match it.next() {
|
||||
Some(spec) => spec,
|
||||
None => panic!("no specialization for expect {}", symbol),
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
it.next().is_none(),
|
||||
"we expect only one specialization of this symbol"
|
||||
|
@ -4283,7 +4288,7 @@ fn build_procedures_help<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
opt_level: OptLevel,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
|
||||
opt_entry_point: Option<EntryPoint<'a>>,
|
||||
entry_point: EntryPoint<'a>,
|
||||
debug_output_file: Option<&Path>,
|
||||
) -> &'a ModSolutions {
|
||||
let mut layout_ids = roc_mono::layout::LayoutIds::default();
|
||||
|
@ -4295,7 +4300,7 @@ fn build_procedures_help<'a, 'ctx, 'env>(
|
|||
env.arena,
|
||||
env.layout_interner,
|
||||
opt_level,
|
||||
opt_entry_point,
|
||||
entry_point,
|
||||
it,
|
||||
) {
|
||||
Err(e) => panic!("Error in alias analysis: {}", e),
|
||||
|
|
|
@ -18,6 +18,32 @@ use super::build::{
|
|||
Scope,
|
||||
};
|
||||
|
||||
pub(crate) struct SharedMemoryPointer<'ctx>(PointerValue<'ctx>);
|
||||
|
||||
impl<'ctx> SharedMemoryPointer<'ctx> {
|
||||
pub(crate) fn get<'a, 'env>(env: &Env<'a, 'ctx, 'env>) -> Self {
|
||||
let start_function = if let LlvmBackendMode::BinaryDev = env.mode {
|
||||
bitcode::UTILS_EXPECT_FAILED_START_SHARED_FILE
|
||||
} else {
|
||||
bitcode::UTILS_EXPECT_FAILED_START_SHARED_BUFFER
|
||||
};
|
||||
|
||||
let func = env.module.get_function(start_function).unwrap();
|
||||
|
||||
let call_result = env
|
||||
.builder
|
||||
.build_call(func, &[], "call_expect_start_failed");
|
||||
|
||||
let ptr = call_result
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap()
|
||||
.into_pointer_value();
|
||||
|
||||
Self(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct Cursors<'ctx> {
|
||||
offset: IntValue<'ctx>,
|
||||
|
@ -94,48 +120,39 @@ fn write_state<'a, 'ctx, 'env>(
|
|||
env.builder.build_store(offset_ptr, offset);
|
||||
}
|
||||
|
||||
pub(crate) fn finalize(env: &Env) {
|
||||
pub(crate) fn notify_parent_expect(env: &Env, shared_memory: &SharedMemoryPointer) {
|
||||
let func = env
|
||||
.module
|
||||
.get_function(bitcode::UTILS_EXPECT_FAILED_FINALIZE)
|
||||
.get_function(bitcode::NOTIFY_PARENT_EXPECT)
|
||||
.unwrap();
|
||||
|
||||
env.builder
|
||||
.build_call(func, &[], "call_expect_failed_finalize");
|
||||
env.builder.build_call(
|
||||
func,
|
||||
&[shared_memory.0.into()],
|
||||
"call_expect_failed_finalize",
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn send_dbg(env: &Env) {
|
||||
let func = env.module.get_function(bitcode::UTILS_SEND_DBG).unwrap();
|
||||
pub(crate) fn notify_parent_dbg(env: &Env, shared_memory: &SharedMemoryPointer) {
|
||||
let func = env.module.get_function(bitcode::NOTIFY_PARENT_DBG).unwrap();
|
||||
|
||||
env.builder
|
||||
.build_call(func, &[], "call_expect_failed_finalize");
|
||||
env.builder.build_call(
|
||||
func,
|
||||
&[shared_memory.0.into()],
|
||||
"call_expect_failed_finalize",
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
shared_memory: &SharedMemoryPointer<'ctx>,
|
||||
condition: Symbol,
|
||||
region: Region,
|
||||
lookups: &[Symbol],
|
||||
) {
|
||||
let start_function = if let LlvmBackendMode::BinaryDev = env.mode {
|
||||
bitcode::UTILS_EXPECT_FAILED_START_SHARED_FILE
|
||||
} else {
|
||||
bitcode::UTILS_EXPECT_FAILED_START_SHARED_BUFFER
|
||||
};
|
||||
|
||||
let func = env.module.get_function(start_function).unwrap();
|
||||
|
||||
let call_result = env
|
||||
.builder
|
||||
.build_call(func, &[], "call_expect_start_failed");
|
||||
|
||||
let original_ptr = call_result
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap()
|
||||
.into_pointer_value();
|
||||
let original_ptr = shared_memory.0;
|
||||
|
||||
let (count, mut offset) = read_state(env, original_ptr);
|
||||
|
||||
|
|
|
@ -158,7 +158,6 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
|
|||
|
||||
unreachable_function(env, "roc_getppid");
|
||||
unreachable_function(env, "roc_mmap");
|
||||
unreachable_function(env, "roc_send_signal");
|
||||
unreachable_function(env, "roc_shm_open");
|
||||
|
||||
add_sjlj_roc_panic(env)
|
||||
|
@ -168,7 +167,10 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
|
|||
fn unreachable_function(env: &Env, name: &str) {
|
||||
// The type of this function (but not the implementation) should have
|
||||
// already been defined by the builtins, which rely on it.
|
||||
let fn_val = env.module.get_function(name).unwrap();
|
||||
let fn_val = match env.module.get_function(name) {
|
||||
Some(f) => f,
|
||||
None => panic!("extern function {name} is not defined by the builtins"),
|
||||
};
|
||||
|
||||
// Add a basic block for the entry point
|
||||
let entry = env.context.append_basic_block(fn_val, "entry");
|
||||
|
|
|
@ -1126,16 +1126,19 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
if env.mode.runs_expects() {
|
||||
let region = unsafe { std::mem::transmute::<_, roc_region::all::Region>(args[0]) };
|
||||
|
||||
let shared_memory = crate::llvm::expect::SharedMemoryPointer::get(env);
|
||||
|
||||
crate::llvm::expect::clone_to_shared_memory(
|
||||
env,
|
||||
scope,
|
||||
layout_ids,
|
||||
&shared_memory,
|
||||
args[0],
|
||||
region,
|
||||
&[args[0]],
|
||||
);
|
||||
|
||||
crate::llvm::expect::send_dbg(env);
|
||||
crate::llvm::expect::notify_parent_dbg(env, &shared_memory);
|
||||
}
|
||||
|
||||
condition
|
||||
|
|
|
@ -744,7 +744,7 @@ impl<'a> WasmBackend<'a> {
|
|||
let mut current_stmt = stmt;
|
||||
while let Stmt::Let(sym, expr, layout, following) = current_stmt {
|
||||
if DEBUG_SETTINGS.let_stmt_ir {
|
||||
print!("\nlet {:?} = {}", sym, expr.to_pretty(200));
|
||||
print!("\nlet {:?} = {}", sym, expr.to_pretty(200, true));
|
||||
}
|
||||
|
||||
let kind = match following {
|
||||
|
@ -974,7 +974,7 @@ impl<'a> WasmBackend<'a> {
|
|||
self.register_symbol_debug_names();
|
||||
println!(
|
||||
"## rc_stmt:\n{}\n{:?}",
|
||||
rc_stmt.to_pretty(self.env.layout_interner, 200),
|
||||
rc_stmt.to_pretty(self.env.layout_interner, 200, true),
|
||||
rc_stmt
|
||||
);
|
||||
}
|
||||
|
@ -1078,7 +1078,7 @@ impl<'a> WasmBackend<'a> {
|
|||
Expr::Reset { symbol: arg, .. } => self.expr_reset(*arg, sym, storage),
|
||||
|
||||
Expr::RuntimeErrorFunction(_) => {
|
||||
todo!("Expression `{}`", expr.to_pretty(100))
|
||||
todo!("Expression `{}`", expr.to_pretty(100, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,7 +143,7 @@ pub fn build_app_module<'a>(
|
|||
if DEBUG_SETTINGS.user_procs_ir {
|
||||
println!("## procs");
|
||||
for proc in procs.iter() {
|
||||
println!("{}", proc.to_pretty(env.layout_interner, 200));
|
||||
println!("{}", proc.to_pretty(env.layout_interner, 200, true));
|
||||
// println!("{:?}", proc);
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ pub fn build_app_module<'a>(
|
|||
if DEBUG_SETTINGS.helper_procs_ir {
|
||||
println!("## helper_procs");
|
||||
for proc in helper_procs.iter() {
|
||||
println!("{}", proc.to_pretty(env.layout_interner, 200));
|
||||
println!("{}", proc.to_pretty(env.layout_interner, 200, true));
|
||||
// println!("{:#?}", proc);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,7 @@ Model position :
|
|||
}
|
||||
|
||||
|
||||
initialModel : position -> Model position
|
||||
initialModel : position -> Model position | position has Hash & Eq
|
||||
initialModel = \start ->
|
||||
{ evaluated : Set.empty
|
||||
, openSet : Set.single start
|
||||
|
@ -22,7 +22,7 @@ initialModel = \start ->
|
|||
}
|
||||
|
||||
|
||||
cheapestOpen : (position -> F64), Model position -> Result position [KeyNotFound] | position has Eq
|
||||
cheapestOpen : (position -> F64), Model position -> Result position [KeyNotFound] | position has Hash & Eq
|
||||
cheapestOpen = \costFunction, model ->
|
||||
|
||||
folder = \resSmallestSoFar, position ->
|
||||
|
@ -47,7 +47,7 @@ cheapestOpen = \costFunction, model ->
|
|||
|
||||
|
||||
|
||||
reconstructPath : Dict position position, position -> List position | position has Eq
|
||||
reconstructPath : Dict position position, position -> List position | position has Hash & Eq
|
||||
reconstructPath = \cameFrom, goal ->
|
||||
when Dict.get cameFrom goal is
|
||||
Err KeyNotFound ->
|
||||
|
@ -56,7 +56,7 @@ reconstructPath = \cameFrom, goal ->
|
|||
Ok next ->
|
||||
List.append (reconstructPath cameFrom next) goal
|
||||
|
||||
updateCost : position, position, Model position -> Model position | position has Eq
|
||||
updateCost : position, position, Model position -> Model position | position has Hash & Eq
|
||||
updateCost = \current, neighbour, model ->
|
||||
newCameFrom = Dict.insert model.cameFrom neighbour current
|
||||
|
||||
|
@ -80,12 +80,12 @@ updateCost = \current, neighbour, model ->
|
|||
model
|
||||
|
||||
|
||||
findPath : { costFunction: (position, position -> F64), moveFunction: (position -> Set position), start : position, end : position } -> Result (List position) [KeyNotFound] | position has Eq
|
||||
findPath : { costFunction: (position, position -> F64), moveFunction: (position -> Set position), start : position, end : position } -> Result (List position) [KeyNotFound] | position has Hash & Eq
|
||||
findPath = \{ costFunction, moveFunction, start, end } ->
|
||||
astar costFunction moveFunction end (initialModel start)
|
||||
|
||||
|
||||
astar : (position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] | position has Eq
|
||||
astar : (position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] | position has Hash & Eq
|
||||
astar = \costFn, moveFn, goal, model ->
|
||||
when cheapestOpen (\position -> costFn goal position) model is
|
||||
Err _ ->
|
||||
|
|
|
@ -491,12 +491,12 @@ fn load_astar() {
|
|||
expect_types(
|
||||
loaded_module,
|
||||
hashmap! {
|
||||
"findPath" => "{ costFunction : position, position -> F64, end : position, moveFunction : position -> Set position, start : position } -> Result (List position) [KeyNotFound] | position has Eq",
|
||||
"initialModel" => "position -> Model position",
|
||||
"reconstructPath" => "Dict position position, position -> List position | position has Eq",
|
||||
"updateCost" => "position, position, Model position -> Model position | position has Eq",
|
||||
"cheapestOpen" => "(position -> F64), Model position -> Result position [KeyNotFound] | position has Eq",
|
||||
"astar" => "(position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] | position has Eq",
|
||||
"findPath" => "{ costFunction : position, position -> F64, end : position, moveFunction : position -> Set position, start : position } -> Result (List position) [KeyNotFound] | position has Hash & Eq",
|
||||
"initialModel" => "position -> Model position | position has Hash & Eq",
|
||||
"reconstructPath" => "Dict position position, position -> List position | position has Hash & Eq",
|
||||
"updateCost" => "position, position, Model position -> Model position | position has Hash & Eq",
|
||||
"cheapestOpen" => "(position -> F64), Model position -> Result position [KeyNotFound] | position has Hash & Eq",
|
||||
"astar" => "(position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound], Ok (List position)] | position has Hash & Eq",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1400,26 +1400,30 @@ define_builtins! {
|
|||
0 DICT_DICT: "Dict" exposed_type=true // the Dict.Dict type alias
|
||||
1 DICT_EMPTY: "empty"
|
||||
2 DICT_SINGLE: "single"
|
||||
3 DICT_GET: "get"
|
||||
4 DICT_GET_RESULT: "#get_result" // symbol used in the definition of Dict.get
|
||||
5 DICT_WALK: "walk"
|
||||
6 DICT_INSERT: "insert"
|
||||
7 DICT_LEN: "len"
|
||||
3 DICT_CLEAR: "clear"
|
||||
4 DICT_LEN: "len"
|
||||
5 DICT_GET: "get"
|
||||
6 DICT_GET_RESULT: "#get_result" // symbol used in the definition of Dict.get
|
||||
7 DICT_CONTAINS: "contains"
|
||||
8 DICT_INSERT: "insert"
|
||||
9 DICT_REMOVE: "remove"
|
||||
|
||||
8 DICT_REMOVE: "remove"
|
||||
9 DICT_CONTAINS: "contains"
|
||||
10 DICT_KEYS: "keys"
|
||||
11 DICT_VALUES: "values"
|
||||
10 DICT_WALK: "walk"
|
||||
11 DICT_WALK_UNTIL: "walkUntil"
|
||||
12 DICT_FROM_LIST: "fromList"
|
||||
13 DICT_TO_LIST: "toList"
|
||||
14 DICT_KEYS: "keys"
|
||||
15 DICT_VALUES: "values"
|
||||
|
||||
12 DICT_INSERT_ALL: "insertAll" // union
|
||||
13 DICT_KEEP_SHARED: "keepShared" // intersection
|
||||
14 DICT_REMOVE_ALL: "removeAll" // difference
|
||||
16 DICT_INSERT_ALL: "insertAll" // union
|
||||
17 DICT_KEEP_SHARED: "keepShared" // intersection
|
||||
18 DICT_REMOVE_ALL: "removeAll" // difference
|
||||
|
||||
15 DICT_WITH_CAPACITY: "withCapacity"
|
||||
16 DICT_CAPACITY: "capacity"
|
||||
17 DICT_UPDATE: "update"
|
||||
19 DICT_WITH_CAPACITY: "withCapacity"
|
||||
20 DICT_CAPACITY: "capacity"
|
||||
21 DICT_UPDATE: "update"
|
||||
|
||||
18 DICT_LIST_GET_UNSAFE: "listGetUnsafe"
|
||||
22 DICT_LIST_GET_UNSAFE: "listGetUnsafe"
|
||||
}
|
||||
9 SET: "Set" => {
|
||||
0 SET_SET: "Set" exposed_type=true // the Set.Set type alias
|
||||
|
@ -1434,10 +1438,11 @@ define_builtins! {
|
|||
9 SET_TO_LIST: "toList"
|
||||
10 SET_FROM_LIST: "fromList"
|
||||
11 SET_WALK: "walk"
|
||||
12 SET_WALK_USER_FUNCTION: "#walk_user_function"
|
||||
13 SET_CONTAINS: "contains"
|
||||
14 SET_TO_DICT: "toDict"
|
||||
15 SET_CAPACITY: "capacity"
|
||||
12 SET_WALK_UNTIL: "walkUntil"
|
||||
13 SET_WALK_USER_FUNCTION: "#walk_user_function"
|
||||
14 SET_CONTAINS: "contains"
|
||||
15 SET_TO_DICT: "toDict"
|
||||
16 SET_CAPACITY: "capacity"
|
||||
}
|
||||
10 BOX: "Box" => {
|
||||
0 BOX_BOX_TYPE: "Box" exposed_apply_type=true // the Box.Box opaque type
|
||||
|
@ -1517,10 +1522,11 @@ define_builtins! {
|
|||
11 HASH_HASH_I32: "hashI32"
|
||||
12 HASH_HASH_I64: "hashI64"
|
||||
13 HASH_HASH_I128: "hashI128"
|
||||
14 HASH_COMPLETE: "complete"
|
||||
15 HASH_HASH_STR_BYTES: "hashStrBytes"
|
||||
16 HASH_HASH_LIST: "hashList"
|
||||
17 HASH_HASH_UNORDERED: "hashUnordered"
|
||||
14 HASH_HASH_NAT: "hashNat"
|
||||
15 HASH_COMPLETE: "complete"
|
||||
16 HASH_HASH_STR_BYTES: "hashStrBytes"
|
||||
17 HASH_HASH_LIST: "hashList"
|
||||
18 HASH_HASH_UNORDERED: "hashUnordered"
|
||||
}
|
||||
14 JSON: "Json" => {
|
||||
0 JSON_JSON: "Json"
|
||||
|
|
5
crates/compiler/mono/src/debug.rs
Normal file
5
crates/compiler/mono/src/debug.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod checker;
|
||||
mod report;
|
||||
|
||||
pub use checker::{check_procs, Problem, Problems};
|
||||
pub use report::format_problems;
|
690
crates/compiler/mono/src/debug/checker.rs
Normal file
690
crates/compiler/mono/src/debug/checker.rs
Normal file
|
@ -0,0 +1,690 @@
|
|||
//! Type-checking of the generated [ir][crate::ir::Proc].
|
||||
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::{MutMap, VecMap, VecSet};
|
||||
use roc_module::symbol::Symbol;
|
||||
|
||||
use crate::{
|
||||
ir::{
|
||||
Call, CallSpecId, CallType, Expr, HigherOrderLowLevel, JoinPointId, ListLiteralElement,
|
||||
ModifyRc, Param, Proc, ProcLayout, Stmt,
|
||||
},
|
||||
layout::{Builtin, Layout, STLayoutInterner, TagIdIntType, UnionLayout},
|
||||
};
|
||||
|
||||
pub enum UseKind {
|
||||
Ret,
|
||||
TagExpr,
|
||||
TagReuse,
|
||||
TagPayloadArg,
|
||||
ListElemExpr,
|
||||
CallArg,
|
||||
JumpArg,
|
||||
CrashArg,
|
||||
SwitchCond,
|
||||
ExpectCond,
|
||||
ExpectLookup,
|
||||
}
|
||||
|
||||
pub enum ProblemKind<'a> {
|
||||
RedefinedSymbol {
|
||||
symbol: Symbol,
|
||||
old_line: usize,
|
||||
},
|
||||
NoSymbolInScope {
|
||||
symbol: Symbol,
|
||||
},
|
||||
SymbolUseMismatch {
|
||||
symbol: Symbol,
|
||||
def_layout: Layout<'a>,
|
||||
def_line: usize,
|
||||
use_layout: Layout<'a>,
|
||||
use_kind: UseKind,
|
||||
},
|
||||
SymbolDefMismatch {
|
||||
symbol: Symbol,
|
||||
def_layout: Layout<'a>,
|
||||
expr_layout: Layout<'a>,
|
||||
},
|
||||
BadSwitchConditionLayout {
|
||||
found_layout: Layout<'a>,
|
||||
},
|
||||
DuplicateSwitchBranch {},
|
||||
RedefinedJoinPoint {
|
||||
id: JoinPointId,
|
||||
old_line: usize,
|
||||
},
|
||||
NoJoinPoint {
|
||||
id: JoinPointId,
|
||||
},
|
||||
JumpArityMismatch {
|
||||
def_line: usize,
|
||||
num_needed: usize,
|
||||
num_given: usize,
|
||||
},
|
||||
CallingUndefinedProc {
|
||||
symbol: Symbol,
|
||||
proc_layout: ProcLayout<'a>,
|
||||
similar: Vec<ProcLayout<'a>>,
|
||||
},
|
||||
DuplicateCallSpecId {
|
||||
old_call_line: usize,
|
||||
},
|
||||
StructIndexOOB {
|
||||
structure: Symbol,
|
||||
def_line: usize,
|
||||
index: u64,
|
||||
size: usize,
|
||||
},
|
||||
NotAStruct {
|
||||
structure: Symbol,
|
||||
def_line: usize,
|
||||
},
|
||||
IndexingTagIdNotInUnion {
|
||||
structure: Symbol,
|
||||
def_line: usize,
|
||||
tag_id: u16,
|
||||
union_layout: UnionLayout<'a>,
|
||||
},
|
||||
TagUnionStructIndexOOB {
|
||||
structure: Symbol,
|
||||
def_line: usize,
|
||||
tag_id: u16,
|
||||
index: u64,
|
||||
size: usize,
|
||||
},
|
||||
IndexIntoNullableTag {
|
||||
structure: Symbol,
|
||||
def_line: usize,
|
||||
tag_id: u16,
|
||||
union_layout: UnionLayout<'a>,
|
||||
},
|
||||
UnboxNotABox {
|
||||
symbol: Symbol,
|
||||
def_line: usize,
|
||||
},
|
||||
CreatingTagIdNotInUnion {
|
||||
tag_id: u16,
|
||||
union_layout: UnionLayout<'a>,
|
||||
},
|
||||
CreateTagPayloadMismatch {
|
||||
num_needed: usize,
|
||||
num_given: usize,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Problem<'a> {
|
||||
pub proc: &'a Proc<'a>,
|
||||
pub proc_layout: ProcLayout<'a>,
|
||||
pub line: usize,
|
||||
pub kind: ProblemKind<'a>,
|
||||
}
|
||||
|
||||
type Procs<'a> = MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>;
|
||||
pub struct Problems<'a>(pub(crate) Vec<Problem<'a>>);
|
||||
|
||||
impl<'a> Problems<'a> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_procs<'a>(
|
||||
arena: &'a Bump,
|
||||
interner: &'a STLayoutInterner<'a>,
|
||||
procs: &'a Procs<'a>,
|
||||
) -> Problems<'a> {
|
||||
let mut problems = Default::default();
|
||||
|
||||
for ((_, proc_layout), proc) in procs.iter() {
|
||||
let mut ctx = Ctx {
|
||||
arena,
|
||||
interner,
|
||||
proc,
|
||||
proc_layout: *proc_layout,
|
||||
ret_layout: proc.ret_layout,
|
||||
problems: &mut problems,
|
||||
call_spec_ids: Default::default(),
|
||||
procs,
|
||||
venv: Default::default(),
|
||||
joinpoints: Default::default(),
|
||||
line: 0,
|
||||
};
|
||||
ctx.check_proc(proc);
|
||||
}
|
||||
|
||||
Problems(problems)
|
||||
}
|
||||
|
||||
type VEnv<'a> = VecMap<Symbol, (usize, Layout<'a>)>;
|
||||
type JoinPoints<'a> = VecMap<JoinPointId, (usize, &'a [Param<'a>])>;
|
||||
type CallSpecIds = VecMap<CallSpecId, usize>;
|
||||
struct Ctx<'a, 'r> {
|
||||
arena: &'a Bump,
|
||||
interner: &'a STLayoutInterner<'a>,
|
||||
problems: &'r mut Vec<Problem<'a>>,
|
||||
proc: &'a Proc<'a>,
|
||||
proc_layout: ProcLayout<'a>,
|
||||
procs: &'r Procs<'a>,
|
||||
call_spec_ids: CallSpecIds,
|
||||
ret_layout: Layout<'a>,
|
||||
venv: VEnv<'a>,
|
||||
joinpoints: JoinPoints<'a>,
|
||||
line: usize,
|
||||
}
|
||||
|
||||
impl<'a, 'r> Ctx<'a, 'r> {
|
||||
fn alloc<T>(&self, v: T) -> &'a T {
|
||||
self.arena.alloc(v)
|
||||
}
|
||||
|
||||
fn problem(&mut self, problem_kind: ProblemKind<'a>) {
|
||||
self.problems.push(Problem {
|
||||
proc: self.proc,
|
||||
proc_layout: self.proc_layout,
|
||||
line: self.line,
|
||||
kind: problem_kind,
|
||||
})
|
||||
}
|
||||
|
||||
fn in_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let old_venv = self.venv.clone();
|
||||
let r = f(self);
|
||||
self.venv = old_venv;
|
||||
r
|
||||
}
|
||||
|
||||
fn resolve(&mut self, mut layout: Layout<'a>) -> Layout<'a> {
|
||||
// Note that we are more aggressive than the usual `runtime_representation`
|
||||
// here because we need strict equality, and so cannot unwrap lambda sets
|
||||
// lazily.
|
||||
loop {
|
||||
match layout {
|
||||
Layout::LambdaSet(ls) => layout = ls.runtime_representation(self.interner),
|
||||
layout => return layout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, symbol: Symbol, layout: Layout<'a>) {
|
||||
if let Some((old_line, _)) = self.venv.insert(symbol, (self.line, layout)) {
|
||||
self.problem(ProblemKind::RedefinedSymbol { symbol, old_line })
|
||||
}
|
||||
}
|
||||
|
||||
fn check_sym_exists(&mut self, symbol: Symbol) {
|
||||
if !self.venv.contains_key(&symbol) {
|
||||
self.problem(ProblemKind::NoSymbolInScope { symbol })
|
||||
}
|
||||
}
|
||||
|
||||
fn with_sym_layout<T>(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
f: impl FnOnce(&mut Self, usize, Layout<'a>) -> Option<T>,
|
||||
) -> Option<T> {
|
||||
if let Some(&(def_line, layout)) = self.venv.get(&symbol) {
|
||||
f(self, def_line, layout)
|
||||
} else {
|
||||
self.problem(ProblemKind::NoSymbolInScope { symbol });
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn check_sym_layout(&mut self, symbol: Symbol, expected_layout: Layout<'a>, use_kind: UseKind) {
|
||||
if let Some(&(def_line, layout)) = self.venv.get(&symbol) {
|
||||
if self.resolve(layout) != self.resolve(expected_layout) {
|
||||
self.problem(ProblemKind::SymbolUseMismatch {
|
||||
symbol,
|
||||
def_layout: layout,
|
||||
def_line,
|
||||
use_layout: expected_layout,
|
||||
use_kind,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
self.problem(ProblemKind::NoSymbolInScope { symbol })
|
||||
}
|
||||
}
|
||||
|
||||
fn check_proc(&mut self, proc: &Proc<'a>) {
|
||||
for (lay, arg) in proc.args.iter() {
|
||||
self.insert(*arg, *lay);
|
||||
}
|
||||
|
||||
self.check_stmt(&proc.body)
|
||||
}
|
||||
|
||||
fn check_stmt(&mut self, body: &Stmt<'a>) {
|
||||
self.line += 1;
|
||||
|
||||
match body {
|
||||
Stmt::Let(x, e, x_layout, rest) => {
|
||||
if let Some(e_layout) = self.check_expr(e) {
|
||||
if self.resolve(e_layout) != self.resolve(*x_layout) {
|
||||
self.problem(ProblemKind::SymbolDefMismatch {
|
||||
symbol: *x,
|
||||
def_layout: *x_layout,
|
||||
expr_layout: e_layout,
|
||||
})
|
||||
}
|
||||
}
|
||||
self.insert(*x, *x_layout);
|
||||
self.check_stmt(rest);
|
||||
}
|
||||
Stmt::Switch {
|
||||
cond_symbol,
|
||||
cond_layout,
|
||||
branches,
|
||||
default_branch,
|
||||
ret_layout: _,
|
||||
} => {
|
||||
self.check_sym_layout(*cond_symbol, *cond_layout, UseKind::SwitchCond);
|
||||
match self.resolve(*cond_layout) {
|
||||
Layout::Builtin(Builtin::Int(int_width)) if !int_width.is_signed() => {}
|
||||
Layout::Builtin(Builtin::Bool) => {}
|
||||
_ => self.problem(ProblemKind::BadSwitchConditionLayout {
|
||||
found_layout: *cond_layout,
|
||||
}),
|
||||
}
|
||||
|
||||
// TODO: need to adjust line numbers as we step through, and depending on whether
|
||||
// the switch is printed as true/false or a proper switch.
|
||||
let mut seen_branches = VecSet::with_capacity(branches.len());
|
||||
for (match_no, _branch_info, branch) in branches.iter() {
|
||||
if seen_branches.insert(match_no) {
|
||||
self.problem(ProblemKind::DuplicateSwitchBranch {});
|
||||
}
|
||||
self.in_scope(|ctx| ctx.check_stmt(branch));
|
||||
}
|
||||
let (_branch_info, default_branch) = default_branch;
|
||||
self.in_scope(|ctx| ctx.check_stmt(default_branch));
|
||||
}
|
||||
&Stmt::Ret(sym) => self.check_sym_layout(sym, self.ret_layout, UseKind::Ret),
|
||||
&Stmt::Refcounting(rc, rest) => {
|
||||
self.check_modify_rc(rc);
|
||||
self.check_stmt(rest);
|
||||
}
|
||||
&Stmt::Expect {
|
||||
condition,
|
||||
region: _,
|
||||
lookups,
|
||||
layouts,
|
||||
remainder,
|
||||
}
|
||||
| &Stmt::ExpectFx {
|
||||
condition,
|
||||
region: _,
|
||||
lookups,
|
||||
layouts,
|
||||
remainder,
|
||||
} => {
|
||||
self.check_sym_layout(
|
||||
condition,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
UseKind::ExpectCond,
|
||||
);
|
||||
for (sym, lay) in lookups.iter().zip(layouts) {
|
||||
self.check_sym_layout(*sym, *lay, UseKind::ExpectLookup);
|
||||
}
|
||||
self.check_stmt(remainder);
|
||||
}
|
||||
&Stmt::Join {
|
||||
id,
|
||||
parameters,
|
||||
body,
|
||||
remainder,
|
||||
} => {
|
||||
if let Some((old_line, _)) = self.joinpoints.insert(id, (self.line, parameters)) {
|
||||
self.problem(ProblemKind::RedefinedJoinPoint { id, old_line })
|
||||
}
|
||||
self.in_scope(|ctx| {
|
||||
for Param {
|
||||
symbol,
|
||||
layout,
|
||||
borrow: _,
|
||||
} in parameters
|
||||
{
|
||||
ctx.insert(*symbol, *layout);
|
||||
}
|
||||
ctx.check_stmt(body)
|
||||
});
|
||||
self.line += 1; // `in` line
|
||||
self.check_stmt(remainder);
|
||||
}
|
||||
&Stmt::Jump(id, symbols) => {
|
||||
if let Some(&(def_line, parameters)) = self.joinpoints.get(&id) {
|
||||
if symbols.len() != parameters.len() {
|
||||
self.problem(ProblemKind::JumpArityMismatch {
|
||||
def_line,
|
||||
num_needed: parameters.len(),
|
||||
num_given: symbols.len(),
|
||||
});
|
||||
}
|
||||
for (arg, param) in symbols.iter().zip(parameters.iter()) {
|
||||
let Param {
|
||||
symbol: _,
|
||||
borrow: _,
|
||||
layout,
|
||||
} = param;
|
||||
self.check_sym_layout(*arg, *layout, UseKind::JumpArg);
|
||||
}
|
||||
} else {
|
||||
self.problem(ProblemKind::NoJoinPoint { id });
|
||||
}
|
||||
}
|
||||
&Stmt::Crash(sym, _) => {
|
||||
self.check_sym_layout(sym, Layout::Builtin(Builtin::Str), UseKind::CrashArg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, e: &Expr<'a>) -> Option<Layout<'a>> {
|
||||
match e {
|
||||
Expr::Literal(_) => None,
|
||||
Expr::Call(call) => self.check_call(call),
|
||||
&Expr::Tag {
|
||||
tag_layout,
|
||||
tag_id,
|
||||
arguments,
|
||||
} => {
|
||||
self.check_tag_expr(tag_layout, tag_id, arguments);
|
||||
Some(Layout::Union(tag_layout))
|
||||
}
|
||||
Expr::Struct(syms) => {
|
||||
for sym in syms.iter() {
|
||||
self.check_sym_exists(*sym);
|
||||
}
|
||||
// TODO: pass the field order hash down, so we can check this
|
||||
None
|
||||
}
|
||||
&Expr::StructAtIndex {
|
||||
index,
|
||||
// TODO: pass the field order hash down, so we can check this
|
||||
field_layouts: _,
|
||||
structure,
|
||||
} => self.check_struct_at_index(structure, index),
|
||||
Expr::GetTagId {
|
||||
structure: _,
|
||||
union_layout,
|
||||
} => Some(union_layout.tag_id_layout()),
|
||||
&Expr::UnionAtIndex {
|
||||
structure,
|
||||
tag_id,
|
||||
union_layout,
|
||||
index,
|
||||
} => self.check_union_at_index(structure, union_layout, tag_id, index),
|
||||
Expr::Array { elem_layout, elems } => {
|
||||
for elem in elems.iter() {
|
||||
match elem {
|
||||
ListLiteralElement::Literal(_) => {}
|
||||
ListLiteralElement::Symbol(sym) => {
|
||||
self.check_sym_layout(*sym, *elem_layout, UseKind::ListElemExpr)
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Layout::Builtin(Builtin::List(self.alloc(*elem_layout))))
|
||||
}
|
||||
Expr::EmptyArray => {
|
||||
// TODO don't know what the element layout is
|
||||
None
|
||||
}
|
||||
&Expr::ExprBox { symbol } => self.with_sym_layout(symbol, |ctx, _def_line, layout| {
|
||||
Some(Layout::Boxed(ctx.alloc(layout)))
|
||||
}),
|
||||
&Expr::ExprUnbox { symbol } => {
|
||||
self.with_sym_layout(symbol, |ctx, def_line, layout| match ctx.resolve(layout) {
|
||||
Layout::Boxed(inner) => Some(*inner),
|
||||
_ => {
|
||||
ctx.problem(ProblemKind::UnboxNotABox { symbol, def_line });
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
&Expr::Reuse {
|
||||
symbol,
|
||||
update_tag_id: _,
|
||||
update_mode: _,
|
||||
tag_layout,
|
||||
tag_id: _,
|
||||
arguments: _,
|
||||
} => {
|
||||
self.check_sym_layout(symbol, Layout::Union(tag_layout), UseKind::TagReuse);
|
||||
// TODO also check update arguments
|
||||
Some(Layout::Union(tag_layout))
|
||||
}
|
||||
&Expr::Reset {
|
||||
symbol,
|
||||
update_mode: _,
|
||||
} => {
|
||||
self.check_sym_exists(symbol);
|
||||
None
|
||||
}
|
||||
Expr::RuntimeErrorFunction(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_struct_at_index(&mut self, structure: Symbol, index: u64) -> Option<Layout<'a>> {
|
||||
self.with_sym_layout(structure, |ctx, def_line, layout| {
|
||||
match ctx.resolve(layout) {
|
||||
Layout::Struct { field_layouts, .. } => {
|
||||
if index as usize >= field_layouts.len() {
|
||||
ctx.problem(ProblemKind::StructIndexOOB {
|
||||
structure,
|
||||
def_line,
|
||||
index,
|
||||
size: field_layouts.len(),
|
||||
});
|
||||
None
|
||||
} else {
|
||||
Some(field_layouts[index as usize])
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
ctx.problem(ProblemKind::NotAStruct {
|
||||
structure,
|
||||
def_line,
|
||||
});
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn check_union_at_index(
|
||||
&mut self,
|
||||
structure: Symbol,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_id: u16,
|
||||
index: u64,
|
||||
) -> Option<Layout<'a>> {
|
||||
self.with_sym_layout(structure, |ctx, def_line, _layout| {
|
||||
ctx.check_sym_layout(structure, Layout::Union(union_layout), UseKind::TagExpr);
|
||||
|
||||
match get_tag_id_payloads(union_layout, tag_id) {
|
||||
TagPayloads::IdNotInUnion => {
|
||||
ctx.problem(ProblemKind::IndexingTagIdNotInUnion {
|
||||
structure,
|
||||
def_line,
|
||||
tag_id,
|
||||
union_layout,
|
||||
});
|
||||
None
|
||||
}
|
||||
TagPayloads::Payloads(payloads) => {
|
||||
if index as usize >= payloads.len() {
|
||||
ctx.problem(ProblemKind::TagUnionStructIndexOOB {
|
||||
structure,
|
||||
def_line,
|
||||
tag_id,
|
||||
index,
|
||||
size: payloads.len(),
|
||||
});
|
||||
return None;
|
||||
}
|
||||
let layout = resolve_recursive_layout(payloads[index as usize], union_layout);
|
||||
Some(layout)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn check_call(&mut self, call: &Call<'a>) -> Option<Layout<'a>> {
|
||||
let Call {
|
||||
call_type,
|
||||
arguments,
|
||||
} = call;
|
||||
|
||||
match call_type {
|
||||
CallType::ByName {
|
||||
name,
|
||||
ret_layout,
|
||||
arg_layouts,
|
||||
specialization_id,
|
||||
} => {
|
||||
let proc_layout = ProcLayout {
|
||||
arguments: arg_layouts,
|
||||
result: **ret_layout,
|
||||
captures_niche: name.captures_niche(),
|
||||
};
|
||||
if !self.procs.contains_key(&(name.name(), proc_layout)) {
|
||||
let similar = self
|
||||
.procs
|
||||
.keys()
|
||||
.filter(|(sym, _)| *sym == name.name())
|
||||
.map(|(_, lay)| *lay)
|
||||
.collect();
|
||||
self.problem(ProblemKind::CallingUndefinedProc {
|
||||
symbol: name.name(),
|
||||
proc_layout,
|
||||
similar,
|
||||
});
|
||||
}
|
||||
for (arg, wanted_layout) in arguments.iter().zip(arg_layouts.iter()) {
|
||||
self.check_sym_layout(*arg, *wanted_layout, UseKind::CallArg);
|
||||
}
|
||||
if let Some(old_call_line) =
|
||||
self.call_spec_ids.insert(*specialization_id, self.line)
|
||||
{
|
||||
self.problem(ProblemKind::DuplicateCallSpecId { old_call_line });
|
||||
}
|
||||
Some(**ret_layout)
|
||||
}
|
||||
CallType::HigherOrder(HigherOrderLowLevel {
|
||||
op: _,
|
||||
closure_env_layout: _,
|
||||
update_mode: _,
|
||||
passed_function: _,
|
||||
}) => {
|
||||
// TODO
|
||||
None
|
||||
}
|
||||
CallType::Foreign {
|
||||
foreign_symbol: _,
|
||||
ret_layout,
|
||||
} => Some(**ret_layout),
|
||||
CallType::LowLevel {
|
||||
op: _,
|
||||
update_mode: _,
|
||||
} => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_tag_expr(&mut self, union_layout: UnionLayout<'a>, tag_id: u16, arguments: &[Symbol]) {
|
||||
match get_tag_id_payloads(union_layout, tag_id) {
|
||||
TagPayloads::IdNotInUnion => {
|
||||
self.problem(ProblemKind::CreatingTagIdNotInUnion {
|
||||
tag_id,
|
||||
union_layout,
|
||||
});
|
||||
}
|
||||
TagPayloads::Payloads(payloads) => {
|
||||
if arguments.len() != payloads.len() {
|
||||
self.problem(ProblemKind::CreateTagPayloadMismatch {
|
||||
num_needed: payloads.len(),
|
||||
num_given: arguments.len(),
|
||||
});
|
||||
}
|
||||
for (arg, wanted_layout) in arguments.iter().zip(payloads.iter()) {
|
||||
let wanted_layout = resolve_recursive_layout(*wanted_layout, union_layout);
|
||||
self.check_sym_layout(*arg, wanted_layout, UseKind::TagPayloadArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_modify_rc(&mut self, rc: ModifyRc) {
|
||||
match rc {
|
||||
ModifyRc::Inc(sym, _) | ModifyRc::Dec(sym) | ModifyRc::DecRef(sym) => {
|
||||
// TODO: also check that sym layout needs refcounting
|
||||
self.check_sym_exists(sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_recursive_layout<'a>(layout: Layout<'a>, when_recursive: UnionLayout<'a>) -> Layout<'a> {
|
||||
// TODO check if recursive pointer not in recursive union
|
||||
match layout {
|
||||
Layout::RecursivePointer => Layout::Union(when_recursive),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
enum TagPayloads<'a> {
|
||||
IdNotInUnion,
|
||||
Payloads(&'a [Layout<'a>]),
|
||||
}
|
||||
|
||||
fn get_tag_id_payloads(union_layout: UnionLayout, tag_id: TagIdIntType) -> TagPayloads {
|
||||
macro_rules! check_tag_id_oob {
|
||||
($len:expr) => {
|
||||
if tag_id as usize >= $len {
|
||||
return TagPayloads::IdNotInUnion;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
match union_layout {
|
||||
UnionLayout::NonRecursive(union) => {
|
||||
check_tag_id_oob!(union.len());
|
||||
let payloads = union[tag_id as usize];
|
||||
TagPayloads::Payloads(payloads)
|
||||
}
|
||||
UnionLayout::Recursive(union) => {
|
||||
check_tag_id_oob!(union.len());
|
||||
let payloads = union[tag_id as usize];
|
||||
TagPayloads::Payloads(payloads)
|
||||
}
|
||||
UnionLayout::NonNullableUnwrapped(payloads) => {
|
||||
if tag_id != 0 {
|
||||
TagPayloads::Payloads(&[])
|
||||
} else {
|
||||
TagPayloads::Payloads(payloads)
|
||||
}
|
||||
}
|
||||
UnionLayout::NullableWrapped {
|
||||
nullable_id,
|
||||
other_tags,
|
||||
} => {
|
||||
if tag_id == nullable_id {
|
||||
TagPayloads::Payloads(&[])
|
||||
} else {
|
||||
check_tag_id_oob!(other_tags.len());
|
||||
let payloads = other_tags[tag_id as usize];
|
||||
TagPayloads::Payloads(payloads)
|
||||
}
|
||||
}
|
||||
UnionLayout::NullableUnwrapped {
|
||||
nullable_id,
|
||||
other_fields,
|
||||
} => {
|
||||
if tag_id == nullable_id as _ {
|
||||
TagPayloads::Payloads(&[])
|
||||
} else {
|
||||
check_tag_id_oob!(2);
|
||||
TagPayloads::Payloads(other_fields)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
499
crates/compiler/mono/src/debug/report.rs
Normal file
499
crates/compiler/mono/src/debug/report.rs
Normal file
|
@ -0,0 +1,499 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use roc_intern::Interner;
|
||||
use roc_module::symbol::{Interns, Symbol};
|
||||
use ven_pretty::{Arena, DocAllocator, DocBuilder};
|
||||
|
||||
use crate::{
|
||||
ir::{Parens, ProcLayout},
|
||||
layout::{CapturesNiche, Layout},
|
||||
};
|
||||
|
||||
use super::{
|
||||
checker::{ProblemKind, UseKind},
|
||||
Problem, Problems,
|
||||
};
|
||||
|
||||
pub fn format_problems<'a, I>(
|
||||
interns: &Interns,
|
||||
interner: &I,
|
||||
problems: Problems<'a>,
|
||||
) -> impl Display
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let Problems(problems) = problems;
|
||||
let f = Arena::new();
|
||||
let problem_docs = problems
|
||||
.into_iter()
|
||||
.map(|p| format_problem(&f, interns, interner, p));
|
||||
let all = f.intersperse(problem_docs, f.hardline());
|
||||
all.1.pretty(80).to_string()
|
||||
}
|
||||
|
||||
type Doc<'d> = DocBuilder<'d, Arena<'d>>;
|
||||
|
||||
const GUTTER_BAR: &str = "│";
|
||||
const HEADER_WIDTH: usize = 80;
|
||||
|
||||
fn format_problem<'a, 'd, I>(
|
||||
f: &'d Arena<'d>,
|
||||
interns: &'d Interns,
|
||||
interner: &'d I,
|
||||
problem: Problem<'a>,
|
||||
) -> Doc<'d>
|
||||
where
|
||||
'a: 'd,
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let Problem {
|
||||
proc,
|
||||
proc_layout,
|
||||
line,
|
||||
kind,
|
||||
} = problem;
|
||||
|
||||
let (title, mut docs, last_doc) = format_kind(f, interns, interner, kind);
|
||||
docs.push((line, last_doc));
|
||||
docs.sort_by_key(|(line, _)| *line);
|
||||
|
||||
let src = proc
|
||||
.to_doc(f, interner, true, Parens::NotNeeded)
|
||||
.1
|
||||
.pretty(80)
|
||||
.to_string();
|
||||
|
||||
let interpolated_docs = stack(
|
||||
f,
|
||||
docs.into_iter()
|
||||
.map(|(line, doc)| format_sourced_doc(f, line, &src, doc)),
|
||||
);
|
||||
|
||||
let header = format_header(f, title);
|
||||
let proc_loc = format_proc_spec(f, interns, interner, proc.name.name(), proc_layout);
|
||||
|
||||
stack(
|
||||
f,
|
||||
[
|
||||
header,
|
||||
f.concat([f.reflow("in "), proc_loc]),
|
||||
interpolated_docs,
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
fn format_sourced_doc<'d>(f: &'d Arena<'d>, line: usize, source: &str, doc: Doc<'d>) -> Doc<'d> {
|
||||
let start_at = line.saturating_sub(1);
|
||||
let source_lines = source.lines().skip(start_at).take(3);
|
||||
let max_line_no_width = (start_at.to_string().len()).max((start_at + 3).to_string().len());
|
||||
let pretty_lines = source_lines.enumerate().map(|(i, line_src)| {
|
||||
let line_no = start_at + i;
|
||||
let line_no_s = line_no.to_string();
|
||||
let line_no_len = line_no_s.len();
|
||||
f.text(line_no_s)
|
||||
.append(f.text(" ".repeat(max_line_no_width - line_no_len)))
|
||||
.append(f.text(GUTTER_BAR))
|
||||
.append(f.text(if line_no == line { "> " } else { " " }))
|
||||
.append(f.text(line_src.to_string()))
|
||||
});
|
||||
let pretty_lines = f.intersperse(pretty_lines, f.hardline());
|
||||
stack(f, [pretty_lines, doc])
|
||||
}
|
||||
|
||||
fn format_header<'d>(f: &'d Arena<'d>, title: &str) -> Doc<'d> {
|
||||
let title_width = title.len() + 4;
|
||||
f.text(format!(
|
||||
"── {} {}",
|
||||
title,
|
||||
"─".repeat(HEADER_WIDTH - title_width)
|
||||
))
|
||||
}
|
||||
|
||||
fn format_kind<'a, 'd, I>(
|
||||
f: &'d Arena<'d>,
|
||||
interns: &'d Interns,
|
||||
interner: &I,
|
||||
kind: ProblemKind<'a>,
|
||||
) -> (&'static str, Vec<(usize, Doc<'d>)>, Doc<'d>)
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let title;
|
||||
let docs_before;
|
||||
let doc = match kind {
|
||||
ProblemKind::RedefinedSymbol { symbol, old_line } => {
|
||||
title = "REDEFINED SYMBOL";
|
||||
docs_before = vec![(
|
||||
old_line,
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" first defined here"),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" re-defined here"),
|
||||
])
|
||||
}
|
||||
ProblemKind::NoSymbolInScope { symbol } => {
|
||||
title = "SYMBOL NOT DEFINED";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" not found in the present scope"),
|
||||
])
|
||||
}
|
||||
ProblemKind::SymbolUseMismatch {
|
||||
symbol,
|
||||
def_layout,
|
||||
def_line,
|
||||
use_layout,
|
||||
use_kind,
|
||||
} => {
|
||||
title = "SYMBOL LAYOUT DOESN'T MATCH ITS USE";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" defined here with layout "),
|
||||
def_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" used as a "),
|
||||
f.reflow(format_use_kind(use_kind)),
|
||||
f.reflow(" here with layout "),
|
||||
use_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::SymbolDefMismatch {
|
||||
symbol,
|
||||
def_layout,
|
||||
expr_layout,
|
||||
} => {
|
||||
title = "SYMBOL INITIALIZER HAS THE WRONG LAYOUT";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" is defined as "),
|
||||
def_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
f.reflow(" but its initializer is "),
|
||||
expr_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::BadSwitchConditionLayout { found_layout } => {
|
||||
title = "BAD SWITCH CONDITION LAYOUT";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
f.reflow("This switch condition is a "),
|
||||
found_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::DuplicateSwitchBranch {} => {
|
||||
title = "DUPLICATE SWITCH BRANCH";
|
||||
docs_before = vec![];
|
||||
f.reflow("The match of switch branch is reached earlier")
|
||||
}
|
||||
ProblemKind::RedefinedJoinPoint { id, old_line } => {
|
||||
title = "DUPLICATE JOIN POINT";
|
||||
docs_before = vec![(
|
||||
old_line,
|
||||
f.concat([
|
||||
f.reflow("The join point "),
|
||||
f.as_string(id.0),
|
||||
f.reflow(" was previously defined here"),
|
||||
]),
|
||||
)];
|
||||
f.reflow("and is redefined here")
|
||||
}
|
||||
ProblemKind::NoJoinPoint { id } => {
|
||||
title = "JOIN POINT NOT DEFINED";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
f.reflow("The join point "),
|
||||
f.as_string(id.0),
|
||||
f.reflow(" was not found in the present scope"),
|
||||
])
|
||||
}
|
||||
ProblemKind::JumpArityMismatch {
|
||||
def_line,
|
||||
num_needed,
|
||||
num_given,
|
||||
} => {
|
||||
title = "WRONG NUMBER OF ARGUMENTS IN JUMP";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("This join pont needs "),
|
||||
f.as_string(num_needed),
|
||||
f.reflow(" arguments"),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
f.reflow("but this jump only gives it "),
|
||||
f.as_string(num_given),
|
||||
])
|
||||
}
|
||||
ProblemKind::CallingUndefinedProc {
|
||||
symbol,
|
||||
proc_layout,
|
||||
similar,
|
||||
} => {
|
||||
title = "PROC SPECIALIZATION NOT DEFINED";
|
||||
docs_before = vec![];
|
||||
let no_spec_doc = stack(
|
||||
f,
|
||||
[
|
||||
f.reflow("No specialization"),
|
||||
format_proc_spec(f, interns, interner, symbol, proc_layout),
|
||||
f.reflow("was found"),
|
||||
],
|
||||
);
|
||||
let similar_doc = if similar.is_empty() {
|
||||
f.nil()
|
||||
} else {
|
||||
let similars = similar
|
||||
.into_iter()
|
||||
.map(|other| format_proc_spec(f, interns, interner, symbol, other));
|
||||
stack(
|
||||
f,
|
||||
[f.concat([
|
||||
f.reflow("The following specializations of "),
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" were built:"),
|
||||
stack(f, similars),
|
||||
])],
|
||||
)
|
||||
};
|
||||
stack(f, [no_spec_doc, similar_doc])
|
||||
}
|
||||
ProblemKind::DuplicateCallSpecId { old_call_line } => {
|
||||
title = "DUPLICATE CALL SPEC ID";
|
||||
docs_before = vec![(old_call_line, f.reflow("This call has a specialization ID"))];
|
||||
f.reflow("...that is the same as the specialization ID of the call here")
|
||||
}
|
||||
ProblemKind::StructIndexOOB {
|
||||
structure,
|
||||
def_line,
|
||||
index,
|
||||
size,
|
||||
} => {
|
||||
title = "STRUCT INDEX IS OUT-OF-BOUNDS";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("The struct "),
|
||||
format_symbol(f, interns, structure),
|
||||
f.reflow(" defined here has "),
|
||||
f.as_string(size),
|
||||
f.reflow(" fields"),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
f.reflow("but is being indexed into field "),
|
||||
f.as_string(index),
|
||||
])
|
||||
}
|
||||
ProblemKind::NotAStruct {
|
||||
structure,
|
||||
def_line,
|
||||
} => {
|
||||
title = "SYMBOL IS NOT A STRUCT";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("The value "),
|
||||
format_symbol(f, interns, structure),
|
||||
f.reflow(" defined here"),
|
||||
]),
|
||||
)];
|
||||
f.reflow("cannot be used as a structure here")
|
||||
}
|
||||
ProblemKind::IndexingTagIdNotInUnion {
|
||||
structure,
|
||||
def_line,
|
||||
tag_id,
|
||||
union_layout,
|
||||
} => {
|
||||
title = "TAG ID NOT IN UNION";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("The union "),
|
||||
format_symbol(f, interns, structure),
|
||||
f.reflow(" defined here has layout "),
|
||||
Layout::Union(union_layout).to_doc(f, interner, Parens::NotNeeded),
|
||||
]),
|
||||
)];
|
||||
f.concat([f.reflow("which has no tag of id "), f.as_string(tag_id)])
|
||||
}
|
||||
ProblemKind::TagUnionStructIndexOOB {
|
||||
structure,
|
||||
def_line,
|
||||
tag_id,
|
||||
index,
|
||||
size,
|
||||
} => {
|
||||
title = "UNION ID AND PAYLOAD INDEX IS OUT-OF-BOUNDS";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("The union "),
|
||||
format_symbol(f, interns, structure),
|
||||
f.reflow(" defined here has "),
|
||||
f.as_string(size),
|
||||
f.reflow(" payloads at ID "),
|
||||
f.as_string(tag_id),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
f.reflow("but is being indexed into field "),
|
||||
f.as_string(index),
|
||||
f.reflow(" here"),
|
||||
])
|
||||
}
|
||||
ProblemKind::IndexIntoNullableTag {
|
||||
structure,
|
||||
def_line,
|
||||
tag_id,
|
||||
union_layout,
|
||||
} => {
|
||||
title = "INDEX INTO NULLABLE TAG";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([
|
||||
f.reflow("The union "),
|
||||
format_symbol(f, interns, structure),
|
||||
f.reflow(" defined here has layout "),
|
||||
Layout::Union(union_layout).to_doc(f, interner, Parens::NotNeeded),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
f.reflow("but is being indexed into the nullable variant "),
|
||||
f.as_string(tag_id),
|
||||
f.reflow(" here"),
|
||||
])
|
||||
}
|
||||
ProblemKind::UnboxNotABox { symbol, def_line } => {
|
||||
title = "ATTEMPTING TO UNBOX A NON-BOX";
|
||||
docs_before = vec![(
|
||||
def_line,
|
||||
f.concat([format_symbol(f, interns, symbol), f.reflow(" is not a box")]),
|
||||
)];
|
||||
f.reflow("but is being unboxed here")
|
||||
}
|
||||
ProblemKind::CreatingTagIdNotInUnion {
|
||||
tag_id,
|
||||
union_layout,
|
||||
} => {
|
||||
title = "NO SUCH ID FOR TAG UNION";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
f.reflow("The variant "),
|
||||
f.as_string(tag_id),
|
||||
f.reflow(" is outside the target union layout "),
|
||||
Layout::Union(union_layout).to_doc(f, interner, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::CreateTagPayloadMismatch {
|
||||
num_needed,
|
||||
num_given,
|
||||
} => {
|
||||
title = "WRONG NUMBER OF ARGUMENTS IN TAG UNION";
|
||||
docs_before = vec![];
|
||||
f.concat([
|
||||
f.reflow("This tag union payload needs "),
|
||||
f.as_string(num_needed),
|
||||
f.reflow(" values, but is only given "),
|
||||
f.as_string(num_given),
|
||||
])
|
||||
}
|
||||
};
|
||||
(title, docs_before, doc)
|
||||
}
|
||||
|
||||
fn format_symbol<'d>(f: &'d Arena<'d>, interns: &'d Interns, symbol: Symbol) -> Doc<'d> {
|
||||
f.text(symbol.module_string(interns).to_string())
|
||||
.append(f.text("."))
|
||||
.append(f.text(symbol.as_str(interns)))
|
||||
}
|
||||
|
||||
fn format_use_kind(use_kind: UseKind) -> &'static str {
|
||||
match use_kind {
|
||||
UseKind::Ret => "return value",
|
||||
UseKind::TagExpr => "tag constructor",
|
||||
UseKind::TagReuse => "tag reuse",
|
||||
UseKind::TagPayloadArg => "tag's payload",
|
||||
UseKind::ListElemExpr => "list element",
|
||||
UseKind::CallArg => "call argument",
|
||||
UseKind::JumpArg => "jump argument",
|
||||
UseKind::CrashArg => "crash message",
|
||||
UseKind::SwitchCond => "switch condition",
|
||||
UseKind::ExpectCond => "expect condition",
|
||||
UseKind::ExpectLookup => "lookup for an expect",
|
||||
}
|
||||
}
|
||||
|
||||
fn format_proc_spec<'a, 'd, I>(
|
||||
f: &'d Arena<'d>,
|
||||
interns: &'d Interns,
|
||||
interner: &I,
|
||||
symbol: Symbol,
|
||||
proc_layout: ProcLayout<'a>,
|
||||
) -> Doc<'d>
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
f.concat([
|
||||
f.as_string(symbol.as_str(interns)),
|
||||
f.reflow(" : "),
|
||||
format_proc_layout(f, interner, proc_layout),
|
||||
])
|
||||
}
|
||||
|
||||
fn format_proc_layout<'a, 'd, I>(
|
||||
f: &'d Arena<'d>,
|
||||
interner: &I,
|
||||
proc_layout: ProcLayout<'a>,
|
||||
) -> Doc<'d>
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let ProcLayout {
|
||||
arguments,
|
||||
result,
|
||||
captures_niche,
|
||||
} = proc_layout;
|
||||
let args = f.intersperse(
|
||||
arguments
|
||||
.iter()
|
||||
.map(|a| a.to_doc(f, interner, Parens::InFunction)),
|
||||
f.reflow(", "),
|
||||
);
|
||||
let fun = f.concat([
|
||||
f.concat([f.reflow("("), args, f.reflow(")")]),
|
||||
f.reflow(" -> "),
|
||||
result.to_doc(f, interner, Parens::NotNeeded),
|
||||
]);
|
||||
let niche = if captures_niche == CapturesNiche::no_niche() {
|
||||
f.reflow("(no niche)")
|
||||
} else {
|
||||
f.concat([
|
||||
f.reflow("(niche {"),
|
||||
f.intersperse(
|
||||
captures_niche
|
||||
.0
|
||||
.iter()
|
||||
.map(|c| c.to_doc(f, interner, Parens::NotNeeded)),
|
||||
f.reflow(", "),
|
||||
),
|
||||
f.reflow("})"),
|
||||
])
|
||||
};
|
||||
f.concat([fun, f.space(), niche])
|
||||
}
|
||||
|
||||
fn stack<'d>(f: &'d Arena<'d>, docs: impl IntoIterator<Item = Doc<'d>>) -> Doc<'d> {
|
||||
f.intersperse(docs, f.line().append(f.line()))
|
||||
}
|
|
@ -425,6 +425,7 @@ fn flatten<'a>(
|
|||
/// variables to "how to get their value". So a pattern like (Just (x,_)) will give
|
||||
/// us something like ("x" => value.0.0)
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Match {
|
||||
Exact(Label),
|
||||
GuardOnly,
|
||||
|
@ -795,7 +796,22 @@ fn to_relevant_branch_help<'a>(
|
|||
elements,
|
||||
element_layout: _,
|
||||
} => match test {
|
||||
IsListLen { bound: _, len } if my_arity.covers_length(*len as _) => {
|
||||
IsListLen {
|
||||
bound: test_bound,
|
||||
len,
|
||||
} if my_arity.covers_length(*len as _)
|
||||
// Spread tests [_, ..] can only match spread tests, not exact-sized bounds [_].
|
||||
//
|
||||
// On the other hand, exact-sized tests [_] can match spread bounds [_, ..],
|
||||
// because each spread bound generates 0 or more exact-sized tests.
|
||||
//
|
||||
// See exhaustiveness checking of lists for more details on the tests generated
|
||||
// for spread bounds.
|
||||
&& !matches!(
|
||||
(test_bound, my_arity),
|
||||
(ListLenBound::AtLeast, ListArity::Exact(..))
|
||||
) =>
|
||||
{
|
||||
let sub_positions = elements.into_iter().enumerate().map(|(index, elem_pat)| {
|
||||
let mut new_path = path.to_vec();
|
||||
|
||||
|
|
|
@ -119,11 +119,17 @@ pub enum OptLevel {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct EntryPoint<'a> {
|
||||
pub struct SingleEntryPoint<'a> {
|
||||
pub symbol: Symbol,
|
||||
pub layout: ProcLayout<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EntryPoint<'a> {
|
||||
Single(SingleEntryPoint<'a>),
|
||||
Expects { symbols: &'a [Symbol] },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct PartialProcId(usize);
|
||||
|
||||
|
@ -326,6 +332,7 @@ impl<'a> Proc<'a> {
|
|||
&'b self,
|
||||
alloc: &'b D,
|
||||
interner: &'b I,
|
||||
pretty: bool,
|
||||
_parens: Parens,
|
||||
) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
|
@ -335,7 +342,7 @@ impl<'a> Proc<'a> {
|
|||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let args_doc = self.args.iter().map(|(layout, symbol)| {
|
||||
let arg_doc = symbol_to_doc(alloc, *symbol);
|
||||
let arg_doc = symbol_to_doc(alloc, *symbol, pretty);
|
||||
if pretty_print_ir_symbols() {
|
||||
arg_doc.append(alloc.reflow(": ")).append(layout.to_doc(
|
||||
alloc,
|
||||
|
@ -350,36 +357,36 @@ impl<'a> Proc<'a> {
|
|||
if pretty_print_ir_symbols() {
|
||||
alloc
|
||||
.text("procedure : ")
|
||||
.append(symbol_to_doc(alloc, self.name.name()))
|
||||
.append(symbol_to_doc(alloc, self.name.name(), pretty))
|
||||
.append(" ")
|
||||
.append(self.ret_layout.to_doc(alloc, interner, Parens::NotNeeded))
|
||||
.append(alloc.hardline())
|
||||
.append(alloc.text("procedure = "))
|
||||
.append(symbol_to_doc(alloc, self.name.name()))
|
||||
.append(symbol_to_doc(alloc, self.name.name(), pretty))
|
||||
.append(" (")
|
||||
.append(alloc.intersperse(args_doc, ", "))
|
||||
.append("):")
|
||||
.append(alloc.hardline())
|
||||
.append(self.body.to_doc(alloc, interner).indent(4))
|
||||
.append(self.body.to_doc(alloc, interner, pretty).indent(4))
|
||||
} else {
|
||||
alloc
|
||||
.text("procedure ")
|
||||
.append(symbol_to_doc(alloc, self.name.name()))
|
||||
.append(symbol_to_doc(alloc, self.name.name(), pretty))
|
||||
.append(" (")
|
||||
.append(alloc.intersperse(args_doc, ", "))
|
||||
.append("):")
|
||||
.append(alloc.hardline())
|
||||
.append(self.body.to_doc(alloc, interner).indent(4))
|
||||
.append(self.body.to_doc(alloc, interner, pretty).indent(4))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_pretty<I>(&self, interner: &I, width: usize) -> String
|
||||
pub fn to_pretty<I>(&self, interner: &I, width: usize, pretty: bool) -> String
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let allocator = BoxAllocator;
|
||||
let mut w = std::vec::Vec::new();
|
||||
self.to_doc::<_, (), _>(&allocator, interner, Parens::NotNeeded)
|
||||
self.to_doc::<_, (), _>(&allocator, interner, pretty, Parens::NotNeeded)
|
||||
.1
|
||||
.render(width, &mut w)
|
||||
.unwrap();
|
||||
|
@ -1675,35 +1682,13 @@ pub enum BranchInfo<'a> {
|
|||
}
|
||||
|
||||
impl<'a> BranchInfo<'a> {
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D) -> DocBuilder<'b, D, A>
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, _pretty: bool) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
A: Clone,
|
||||
{
|
||||
use BranchInfo::*;
|
||||
|
||||
match self {
|
||||
Constructor {
|
||||
tag_id,
|
||||
scrutinee,
|
||||
layout: _,
|
||||
} if pretty_print_ir_symbols() => alloc
|
||||
.hardline()
|
||||
.append(" BranchInfo: { scrutinee: ")
|
||||
.append(symbol_to_doc(alloc, *scrutinee))
|
||||
.append(", tag_id: ")
|
||||
.append(format!("{}", tag_id))
|
||||
.append("} "),
|
||||
|
||||
_ => {
|
||||
if pretty_print_ir_symbols() {
|
||||
alloc.text(" <no branch info>")
|
||||
} else {
|
||||
alloc.text("")
|
||||
}
|
||||
}
|
||||
}
|
||||
alloc.text("")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1724,7 +1709,7 @@ pub enum ModifyRc {
|
|||
}
|
||||
|
||||
impl ModifyRc {
|
||||
pub fn to_doc<'a, D, A>(self, alloc: &'a D) -> DocBuilder<'a, D, A>
|
||||
pub fn to_doc<'a, D, A>(self, alloc: &'a D, pretty: bool) -> DocBuilder<'a, D, A>
|
||||
where
|
||||
D: DocAllocator<'a, A>,
|
||||
D::Doc: Clone,
|
||||
|
@ -1735,20 +1720,20 @@ impl ModifyRc {
|
|||
match self {
|
||||
Inc(symbol, 1) => alloc
|
||||
.text("inc ")
|
||||
.append(symbol_to_doc(alloc, symbol))
|
||||
.append(symbol_to_doc(alloc, symbol, pretty))
|
||||
.append(";"),
|
||||
Inc(symbol, n) => alloc
|
||||
.text("inc ")
|
||||
.append(alloc.text(format!("{} ", n)))
|
||||
.append(symbol_to_doc(alloc, symbol))
|
||||
.append(symbol_to_doc(alloc, symbol, pretty))
|
||||
.append(";"),
|
||||
Dec(symbol) => alloc
|
||||
.text("dec ")
|
||||
.append(symbol_to_doc(alloc, symbol))
|
||||
.append(symbol_to_doc(alloc, symbol, pretty))
|
||||
.append(";"),
|
||||
DecRef(symbol) => alloc
|
||||
.text("decref ")
|
||||
.append(symbol_to_doc(alloc, symbol))
|
||||
.append(symbol_to_doc(alloc, symbol, pretty))
|
||||
.append(";"),
|
||||
}
|
||||
}
|
||||
|
@ -1808,7 +1793,7 @@ pub struct Call<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Call<'a> {
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D) -> DocBuilder<'b, D, A>
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, pretty: bool) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
|
@ -1822,19 +1807,19 @@ impl<'a> Call<'a> {
|
|||
CallType::ByName { name, .. } => {
|
||||
let it = std::iter::once(name.name())
|
||||
.chain(arguments.iter().copied())
|
||||
.map(|s| symbol_to_doc(alloc, s));
|
||||
.map(|s| symbol_to_doc(alloc, s, pretty));
|
||||
|
||||
alloc.text("CallByName ").append(alloc.intersperse(it, " "))
|
||||
}
|
||||
LowLevel { op: lowlevel, .. } => {
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text(format!("lowlevel {:?} ", lowlevel))
|
||||
.append(alloc.intersperse(it, " "))
|
||||
}
|
||||
HigherOrder(higher_order) => {
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text(format!("lowlevel {:?} ", higher_order.op))
|
||||
|
@ -1843,7 +1828,7 @@ impl<'a> Call<'a> {
|
|||
Foreign {
|
||||
ref foreign_symbol, ..
|
||||
} => {
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text(format!("foreign {:?} ", foreign_symbol.as_str()))
|
||||
|
@ -2034,10 +2019,10 @@ impl<'a> Literal<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn symbol_to_doc_string(symbol: Symbol) -> String {
|
||||
pub(crate) fn symbol_to_doc_string(symbol: Symbol, force_pretty: bool) -> String {
|
||||
use roc_module::ident::ModuleName;
|
||||
|
||||
if pretty_print_ir_symbols() {
|
||||
if pretty_print_ir_symbols() || force_pretty {
|
||||
format!("{:?}", symbol)
|
||||
} else {
|
||||
let text = format!("{}", symbol);
|
||||
|
@ -2051,26 +2036,30 @@ pub(crate) fn symbol_to_doc_string(symbol: Symbol) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn symbol_to_doc<'b, D, A>(alloc: &'b D, symbol: Symbol) -> DocBuilder<'b, D, A>
|
||||
fn symbol_to_doc<'b, D, A>(alloc: &'b D, symbol: Symbol, force_pretty: bool) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
A: Clone,
|
||||
{
|
||||
alloc.text(symbol_to_doc_string(symbol))
|
||||
alloc.text(symbol_to_doc_string(symbol, force_pretty))
|
||||
}
|
||||
|
||||
fn join_point_to_doc<'b, D, A>(alloc: &'b D, symbol: JoinPointId) -> DocBuilder<'b, D, A>
|
||||
fn join_point_to_doc<'b, D, A>(
|
||||
alloc: &'b D,
|
||||
symbol: JoinPointId,
|
||||
pretty: bool,
|
||||
) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
A: Clone,
|
||||
{
|
||||
symbol_to_doc(alloc, symbol.0)
|
||||
symbol_to_doc(alloc, symbol.0, pretty)
|
||||
}
|
||||
|
||||
impl<'a> Expr<'a> {
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D) -> DocBuilder<'b, D, A>
|
||||
pub fn to_doc<'b, D, A>(&'b self, alloc: &'b D, pretty: bool) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
|
@ -2081,7 +2070,7 @@ impl<'a> Expr<'a> {
|
|||
match self {
|
||||
Literal(lit) => lit.to_doc(alloc),
|
||||
|
||||
Call(call) => call.to_doc(alloc),
|
||||
Call(call) => call.to_doc(alloc, pretty),
|
||||
|
||||
Tag {
|
||||
tag_id, arguments, ..
|
||||
|
@ -2091,7 +2080,7 @@ impl<'a> Expr<'a> {
|
|||
.append(alloc.text(tag_id.to_string()))
|
||||
.append(")");
|
||||
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
doc_tag
|
||||
.append(alloc.space())
|
||||
|
@ -2109,11 +2098,11 @@ impl<'a> Expr<'a> {
|
|||
.append(alloc.text(tag_id.to_string()))
|
||||
.append(")");
|
||||
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text("Reuse ")
|
||||
.append(symbol_to_doc(alloc, *symbol))
|
||||
.append(symbol_to_doc(alloc, *symbol, pretty))
|
||||
.append(alloc.space())
|
||||
.append(format!("{:?}", update_mode))
|
||||
.append(alloc.space())
|
||||
|
@ -2130,7 +2119,7 @@ impl<'a> Expr<'a> {
|
|||
)),
|
||||
|
||||
Struct(args) => {
|
||||
let it = args.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = args.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text("Struct {")
|
||||
|
@ -2140,7 +2129,7 @@ impl<'a> Expr<'a> {
|
|||
Array { elems, .. } => {
|
||||
let it = elems.iter().map(|e| match e {
|
||||
ListLiteralElement::Literal(l) => l.to_doc(alloc),
|
||||
ListLiteralElement::Symbol(s) => symbol_to_doc(alloc, *s),
|
||||
ListLiteralElement::Symbol(s) => symbol_to_doc(alloc, *s, pretty),
|
||||
});
|
||||
|
||||
alloc
|
||||
|
@ -2154,17 +2143,21 @@ impl<'a> Expr<'a> {
|
|||
index, structure, ..
|
||||
} => alloc
|
||||
.text(format!("StructAtIndex {} ", index))
|
||||
.append(symbol_to_doc(alloc, *structure)),
|
||||
.append(symbol_to_doc(alloc, *structure, pretty)),
|
||||
|
||||
RuntimeErrorFunction(s) => alloc.text(format!("ErrorFunction {}", s)),
|
||||
|
||||
GetTagId { structure, .. } => alloc
|
||||
.text("GetTagId ")
|
||||
.append(symbol_to_doc(alloc, *structure)),
|
||||
.append(symbol_to_doc(alloc, *structure, pretty)),
|
||||
|
||||
ExprBox { symbol, .. } => alloc.text("Box ").append(symbol_to_doc(alloc, *symbol)),
|
||||
ExprBox { symbol, .. } => alloc
|
||||
.text("Box ")
|
||||
.append(symbol_to_doc(alloc, *symbol, pretty)),
|
||||
|
||||
ExprUnbox { symbol, .. } => alloc.text("Unbox ").append(symbol_to_doc(alloc, *symbol)),
|
||||
ExprUnbox { symbol, .. } => alloc
|
||||
.text("Unbox ")
|
||||
.append(symbol_to_doc(alloc, *symbol, pretty)),
|
||||
|
||||
UnionAtIndex {
|
||||
tag_id,
|
||||
|
@ -2173,14 +2166,14 @@ impl<'a> Expr<'a> {
|
|||
..
|
||||
} => alloc
|
||||
.text(format!("UnionAtIndex (Id {}) (Index {}) ", tag_id, index))
|
||||
.append(symbol_to_doc(alloc, *structure)),
|
||||
.append(symbol_to_doc(alloc, *structure, pretty)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_pretty(&self, width: usize) -> String {
|
||||
pub fn to_pretty(&self, width: usize, pretty: bool) -> String {
|
||||
let allocator = BoxAllocator;
|
||||
let mut w = std::vec::Vec::new();
|
||||
self.to_doc::<_, ()>(&allocator)
|
||||
self.to_doc::<_, ()>(&allocator, pretty)
|
||||
.1
|
||||
.render(width, &mut w)
|
||||
.unwrap();
|
||||
|
@ -2200,7 +2193,12 @@ impl<'a> Stmt<'a> {
|
|||
from_can(env, var, can_expr, procs, layout_cache)
|
||||
}
|
||||
|
||||
pub fn to_doc<'b, D, A, I>(&'b self, alloc: &'b D, interner: &I) -> DocBuilder<'b, D, A>
|
||||
pub fn to_doc<'b, D, A, I>(
|
||||
&'b self,
|
||||
alloc: &'b D,
|
||||
interner: &I,
|
||||
pretty: bool,
|
||||
) -> DocBuilder<'b, D, A>
|
||||
where
|
||||
D: DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
|
@ -2212,19 +2210,19 @@ impl<'a> Stmt<'a> {
|
|||
match self {
|
||||
Let(symbol, expr, layout, cont) => alloc
|
||||
.text("let ")
|
||||
.append(symbol_to_doc(alloc, *symbol))
|
||||
.append(symbol_to_doc(alloc, *symbol, pretty))
|
||||
.append(" : ")
|
||||
.append(layout.to_doc(alloc, interner, Parens::NotNeeded))
|
||||
.append(" = ")
|
||||
.append(expr.to_doc(alloc))
|
||||
.append(expr.to_doc(alloc, pretty))
|
||||
.append(";")
|
||||
.append(alloc.hardline())
|
||||
.append(cont.to_doc(alloc, interner)),
|
||||
.append(cont.to_doc(alloc, interner, pretty)),
|
||||
|
||||
Refcounting(modify, cont) => modify
|
||||
.to_doc(alloc)
|
||||
.to_doc(alloc, pretty)
|
||||
.append(alloc.hardline())
|
||||
.append(cont.to_doc(alloc, interner)),
|
||||
.append(cont.to_doc(alloc, interner, pretty)),
|
||||
|
||||
Expect {
|
||||
condition,
|
||||
|
@ -2232,10 +2230,10 @@ impl<'a> Stmt<'a> {
|
|||
..
|
||||
} => alloc
|
||||
.text("expect ")
|
||||
.append(symbol_to_doc(alloc, *condition))
|
||||
.append(symbol_to_doc(alloc, *condition, pretty))
|
||||
.append(";")
|
||||
.append(alloc.hardline())
|
||||
.append(remainder.to_doc(alloc, interner)),
|
||||
.append(remainder.to_doc(alloc, interner, pretty)),
|
||||
|
||||
ExpectFx {
|
||||
condition,
|
||||
|
@ -2243,14 +2241,14 @@ impl<'a> Stmt<'a> {
|
|||
..
|
||||
} => alloc
|
||||
.text("expect-fx ")
|
||||
.append(symbol_to_doc(alloc, *condition))
|
||||
.append(symbol_to_doc(alloc, *condition, pretty))
|
||||
.append(";")
|
||||
.append(alloc.hardline())
|
||||
.append(remainder.to_doc(alloc, interner)),
|
||||
.append(remainder.to_doc(alloc, interner, pretty)),
|
||||
|
||||
Ret(symbol) => alloc
|
||||
.text("ret ")
|
||||
.append(symbol_to_doc(alloc, *symbol))
|
||||
.append(symbol_to_doc(alloc, *symbol, pretty))
|
||||
.append(";"),
|
||||
|
||||
Switch {
|
||||
|
@ -2264,23 +2262,23 @@ impl<'a> Stmt<'a> {
|
|||
let fail = default_branch.1;
|
||||
alloc
|
||||
.text("if ")
|
||||
.append(symbol_to_doc(alloc, *cond_symbol))
|
||||
.append(symbol_to_doc(alloc, *cond_symbol, pretty))
|
||||
.append(" then")
|
||||
.append(info.to_doc(alloc))
|
||||
.append(info.to_doc(alloc, pretty))
|
||||
.append(alloc.hardline())
|
||||
.append(pass.to_doc(alloc, interner).indent(4))
|
||||
.append(pass.to_doc(alloc, interner, pretty).indent(4))
|
||||
.append(alloc.hardline())
|
||||
.append(alloc.text("else"))
|
||||
.append(default_branch.0.to_doc(alloc))
|
||||
.append(default_branch.0.to_doc(alloc, pretty))
|
||||
.append(alloc.hardline())
|
||||
.append(fail.to_doc(alloc, interner).indent(4))
|
||||
.append(fail.to_doc(alloc, interner, pretty).indent(4))
|
||||
}
|
||||
|
||||
_ => {
|
||||
let default_doc = alloc
|
||||
.text("default:")
|
||||
.append(alloc.hardline())
|
||||
.append(default_branch.1.to_doc(alloc, interner).indent(4))
|
||||
.append(default_branch.1.to_doc(alloc, interner, pretty).indent(4))
|
||||
.indent(4);
|
||||
|
||||
let branches_docs = branches
|
||||
|
@ -2289,14 +2287,14 @@ impl<'a> Stmt<'a> {
|
|||
alloc
|
||||
.text(format!("case {}:", tag))
|
||||
.append(alloc.hardline())
|
||||
.append(expr.to_doc(alloc, interner).indent(4))
|
||||
.append(expr.to_doc(alloc, interner, pretty).indent(4))
|
||||
.indent(4)
|
||||
})
|
||||
.chain(std::iter::once(default_doc));
|
||||
//
|
||||
alloc
|
||||
.text("switch ")
|
||||
.append(symbol_to_doc(alloc, *cond_symbol))
|
||||
.append(symbol_to_doc(alloc, *cond_symbol, pretty))
|
||||
.append(":")
|
||||
.append(alloc.hardline())
|
||||
.append(alloc.intersperse(
|
||||
|
@ -2308,7 +2306,9 @@ impl<'a> Stmt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
Crash(s, _src) => alloc.text("Crash ").append(symbol_to_doc(alloc, *s)),
|
||||
Crash(s, _src) => alloc
|
||||
.text("Crash ")
|
||||
.append(symbol_to_doc(alloc, *s, pretty)),
|
||||
|
||||
Join {
|
||||
id,
|
||||
|
@ -2316,29 +2316,31 @@ impl<'a> Stmt<'a> {
|
|||
body: continuation,
|
||||
remainder,
|
||||
} => {
|
||||
let it = parameters.iter().map(|p| symbol_to_doc(alloc, p.symbol));
|
||||
let it = parameters
|
||||
.iter()
|
||||
.map(|p| symbol_to_doc(alloc, p.symbol, pretty));
|
||||
|
||||
alloc.intersperse(
|
||||
vec![
|
||||
alloc
|
||||
.text("joinpoint ")
|
||||
.append(join_point_to_doc(alloc, *id))
|
||||
.append(join_point_to_doc(alloc, *id, pretty))
|
||||
.append(" ".repeat(parameters.len().min(1)))
|
||||
.append(alloc.intersperse(it, alloc.space()))
|
||||
.append(":"),
|
||||
continuation.to_doc(alloc, interner).indent(4),
|
||||
continuation.to_doc(alloc, interner, pretty).indent(4),
|
||||
alloc.text("in"),
|
||||
remainder.to_doc(alloc, interner),
|
||||
remainder.to_doc(alloc, interner, pretty),
|
||||
],
|
||||
alloc.hardline(),
|
||||
)
|
||||
}
|
||||
Jump(id, arguments) => {
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s, pretty));
|
||||
|
||||
alloc
|
||||
.text("jump ")
|
||||
.append(join_point_to_doc(alloc, *id))
|
||||
.append(join_point_to_doc(alloc, *id, pretty))
|
||||
.append(" ".repeat(arguments.len().min(1)))
|
||||
.append(alloc.intersperse(it, alloc.space()))
|
||||
.append(";")
|
||||
|
@ -2346,13 +2348,13 @@ impl<'a> Stmt<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_pretty<I>(&self, interner: &I, width: usize) -> String
|
||||
pub fn to_pretty<I>(&self, interner: &I, width: usize, pretty: bool) -> String
|
||||
where
|
||||
I: Interner<'a, Layout<'a>>,
|
||||
{
|
||||
let allocator = BoxAllocator;
|
||||
let mut w = std::vec::Vec::new();
|
||||
self.to_doc::<_, (), _>(&allocator, interner)
|
||||
self.to_doc::<_, (), _>(&allocator, interner, pretty)
|
||||
.1
|
||||
.render(width, &mut w)
|
||||
.unwrap();
|
||||
|
|
|
@ -1154,7 +1154,7 @@ struct SetElement<'a> {
|
|||
|
||||
impl std::fmt::Debug for SetElement<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let symbol_string = crate::ir::symbol_to_doc_string(self.symbol);
|
||||
let symbol_string = crate::ir::symbol_to_doc_string(self.symbol, false);
|
||||
|
||||
write!(f, "( {}, {:?})", symbol_string, self.layout)
|
||||
}
|
||||
|
@ -1204,7 +1204,7 @@ impl std::fmt::Debug for LambdaSet<'_> {
|
|||
///
|
||||
/// See also https://github.com/roc-lang/roc/issues/3336.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct CapturesNiche<'a>(&'a [Layout<'a>]);
|
||||
pub struct CapturesNiche<'a>(pub(crate) &'a [Layout<'a>]);
|
||||
|
||||
impl CapturesNiche<'_> {
|
||||
pub fn no_niche() -> Self {
|
||||
|
|
|
@ -21,3 +21,5 @@ pub mod tail_recursion;
|
|||
// For now, following this warning's advice will lead to nasty type inference errors.
|
||||
//#[allow(clippy::ptr_arg)]
|
||||
pub mod decision_tree;
|
||||
|
||||
pub mod debug;
|
||||
|
|
|
@ -1,22 +1,43 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use roc_parse::{module, module::module_defs, parser::Parser, state::State};
|
||||
|
||||
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||
let mut path = std::env::current_dir()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.parent()
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
path.push("examples");
|
||||
path.push("false-interpreter");
|
||||
path.push("False.roc");
|
||||
|
||||
let src = std::fs::read_to_string(&path).unwrap();
|
||||
|
||||
pub fn parse_benchmark(c: &mut Criterion) {
|
||||
c.bench_function("parse false-interpreter", |b| {
|
||||
let mut path = PathBuf::from(std::env!("ROC_WORKSPACE_DIR"));
|
||||
path.push("examples");
|
||||
path.push("cli");
|
||||
path.push("false-interpreter");
|
||||
path.push("False.roc");
|
||||
let src = std::fs::read_to_string(&path).unwrap();
|
||||
|
||||
b.iter(|| {
|
||||
let arena = Bump::new();
|
||||
|
||||
let (_actual, state) =
|
||||
module::parse_header(&arena, State::new(src.as_bytes())).unwrap();
|
||||
|
||||
let min_indent = 0;
|
||||
let res = module_defs()
|
||||
.parse(&arena, state, min_indent)
|
||||
.map(|tuple| tuple.1)
|
||||
.unwrap();
|
||||
|
||||
black_box(res.len());
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function("parse Num builtin", |b| {
|
||||
let mut path = PathBuf::from(std::env!("ROC_WORKSPACE_DIR"));
|
||||
path.push("crates");
|
||||
path.push("compiler");
|
||||
path.push("builtins");
|
||||
path.push("roc");
|
||||
path.push("Num.roc");
|
||||
let src = std::fs::read_to_string(&path).unwrap();
|
||||
|
||||
b.iter(|| {
|
||||
let arena = Bump::new();
|
||||
|
||||
|
@ -34,5 +55,5 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
criterion_group!(benches, parse_benchmark);
|
||||
criterion_main!(benches);
|
||||
|
|
|
@ -4,34 +4,40 @@ use crate::ident::{lowercase_ident, UppercaseIdent};
|
|||
use crate::parser::{optional, then};
|
||||
use crate::parser::{specialize, word1, EPackageEntry, EPackageName, Parser};
|
||||
use crate::string_literal;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_region::all::Loc;
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum HeaderFor<'a> {
|
||||
pub enum HeaderType<'a> {
|
||||
App {
|
||||
output_name: StrLiteral<'a>,
|
||||
to_platform: To<'a>,
|
||||
},
|
||||
Hosted {
|
||||
name: ModuleName<'a>,
|
||||
generates: UppercaseIdent<'a>,
|
||||
generates_with: &'a [Loc<ExposedName<'a>>],
|
||||
},
|
||||
/// Only created during canonicalization, never actually parsed from source
|
||||
Builtin {
|
||||
name: ModuleName<'a>,
|
||||
generates_with: &'a [Symbol],
|
||||
},
|
||||
Platform {
|
||||
opt_app_module_id: Option<ModuleId>,
|
||||
/// the name and type scheme of the main function (required by the platform)
|
||||
/// (type scheme is currently unused)
|
||||
provides: &'a [(Loc<ExposedName<'a>>, Loc<TypedIdent<'a>>)],
|
||||
requires: &'a [Loc<TypedIdent<'a>>],
|
||||
requires_types: &'a [Loc<UppercaseIdent<'a>>],
|
||||
|
||||
/// usually `pf`
|
||||
config_shorthand: &'a str,
|
||||
/// the type scheme of the main function (required by the platform)
|
||||
/// (currently unused)
|
||||
#[allow(dead_code)]
|
||||
platform_main_type: TypedIdent<'a>,
|
||||
/// provided symbol to host (commonly `mainForHost`)
|
||||
main_for_host: roc_module::symbol::Symbol,
|
||||
},
|
||||
Interface,
|
||||
Interface {
|
||||
name: ModuleName<'a>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
|
@ -95,15 +101,6 @@ impl<'a> ModuleName<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ModuleNameEnum<'a> {
|
||||
/// A filename
|
||||
App(StrLiteral<'a>),
|
||||
Interface(ModuleName<'a>),
|
||||
Hosted(ModuleName<'a>),
|
||||
Platform,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct ExposedName<'a>(&'a str);
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use roc_can::abilities::AbilitiesStore;
|
||||
use roc_can::expr::PendingDerives;
|
||||
use roc_collections::{VecMap, VecSet};
|
||||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
use roc_debug_flags::ROC_PRINT_UNDERIVABLE;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Loc, Region};
|
||||
|
@ -309,12 +312,18 @@ impl ObligationCache {
|
|||
Some(Err(NotDerivable {
|
||||
var: failure_var,
|
||||
context,
|
||||
})) => Some(if failure_var == var {
|
||||
UnderivableReason::SurfaceNotDerivable(context)
|
||||
} else {
|
||||
let error_type = subs.var_to_error_type(failure_var, Polarity::OF_VALUE);
|
||||
UnderivableReason::NestedNotDerivable(error_type, context)
|
||||
}),
|
||||
})) => {
|
||||
dbg_do!(ROC_PRINT_UNDERIVABLE, {
|
||||
eprintln!("❌ derived {:?} of {:?}", ability, subs.dbg(failure_var));
|
||||
});
|
||||
|
||||
Some(if failure_var == var {
|
||||
UnderivableReason::SurfaceNotDerivable(context)
|
||||
} else {
|
||||
let error_type = subs.var_to_error_type(failure_var, Polarity::OF_VALUE);
|
||||
UnderivableReason::NestedNotDerivable(error_type, context)
|
||||
})
|
||||
}
|
||||
None => Some(UnderivableReason::NotABuiltin),
|
||||
};
|
||||
|
||||
|
@ -497,18 +506,6 @@ trait DerivableVisitor {
|
|||
false
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn visit_rigid_able(var: Variable, abilities: &[Symbol]) -> Result<(), NotDerivable> {
|
||||
if abilities != [Self::ABILITY] {
|
||||
Err(NotDerivable {
|
||||
var,
|
||||
context: NotDerivableContext::UnboundVar,
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn visit_recursion(var: Variable) -> Result<Descend, NotDerivable> {
|
||||
Err(NotDerivable {
|
||||
|
@ -659,7 +656,12 @@ trait DerivableVisitor {
|
|||
subs.set_content(var, Content::FlexAbleVar(opt_name, merged_abilites));
|
||||
}
|
||||
RigidAbleVar(_, abilities) => {
|
||||
Self::visit_rigid_able(var, subs.get_subs_slice(abilities))?
|
||||
if !subs.get_subs_slice(abilities).contains(&Self::ABILITY) {
|
||||
return Err(NotDerivable {
|
||||
var,
|
||||
context: NotDerivableContext::NoContext,
|
||||
});
|
||||
}
|
||||
}
|
||||
RecursionVar {
|
||||
structure,
|
||||
|
|
|
@ -3473,7 +3473,7 @@ mod solve_expr {
|
|||
Dict.insert
|
||||
"#
|
||||
),
|
||||
"Dict k v, k, v -> Dict k v | k has Eq",
|
||||
"Dict k v, k, v -> Dict k v | k has Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3734,7 +3734,7 @@ mod solve_expr {
|
|||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
reconstructPath : Dict position position, position -> List position | position has Eq
|
||||
reconstructPath : Dict position position, position -> List position | position has Hash & Eq
|
||||
reconstructPath = \cameFrom, goal ->
|
||||
when Dict.get cameFrom goal is
|
||||
Err KeyNotFound ->
|
||||
|
@ -3746,7 +3746,7 @@ mod solve_expr {
|
|||
reconstructPath
|
||||
"#
|
||||
),
|
||||
"Dict position position, position -> List position | position has Eq",
|
||||
"Dict position position, position -> List position | position has Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3781,7 +3781,7 @@ mod solve_expr {
|
|||
|
||||
Model position : { openSet : Set position }
|
||||
|
||||
cheapestOpen : Model position -> Result position [KeyNotFound] | position has Eq
|
||||
cheapestOpen : Model position -> Result position [KeyNotFound] | position has Hash & Eq
|
||||
cheapestOpen = \model ->
|
||||
|
||||
folder = \resSmallestSoFar, position ->
|
||||
|
@ -3796,14 +3796,14 @@ mod solve_expr {
|
|||
Set.walk model.openSet (Ok { position: boom {}, cost: 0.0 }) folder
|
||||
|> Result.map (\x -> x.position)
|
||||
|
||||
astar : Model position -> Result position [KeyNotFound] | position has Eq
|
||||
astar : Model position -> Result position [KeyNotFound] | position has Hash & Eq
|
||||
astar = \model -> cheapestOpen model
|
||||
|
||||
main =
|
||||
astar
|
||||
"#
|
||||
),
|
||||
"Model position -> Result position [KeyNotFound] | position has Eq",
|
||||
"Model position -> Result position [KeyNotFound] | position has Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4445,7 +4445,7 @@ mod solve_expr {
|
|||
|
||||
Key k : Num k
|
||||
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Eq
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Hash & Eq
|
||||
removeHelpEQGT = \targetKey, dict ->
|
||||
when dict is
|
||||
Node color key value left right ->
|
||||
|
@ -4559,7 +4559,7 @@ mod solve_expr {
|
|||
_ ->
|
||||
Empty
|
||||
|
||||
removeHelp : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Eq
|
||||
removeHelp : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Hash & Eq
|
||||
removeHelp = \targetKey, dict ->
|
||||
when dict is
|
||||
Empty ->
|
||||
|
@ -4647,7 +4647,7 @@ mod solve_expr {
|
|||
|
||||
RBTree k v : [Node NodeColor k v (RBTree k v) (RBTree k v), Empty]
|
||||
|
||||
removeHelp : Num k, RBTree (Num k) v -> RBTree (Num k) v | k has Eq
|
||||
removeHelp : Num k, RBTree (Num k) v -> RBTree (Num k) v | k has Hash & Eq
|
||||
removeHelp = \targetKey, dict ->
|
||||
when dict is
|
||||
Empty ->
|
||||
|
@ -4682,7 +4682,7 @@ mod solve_expr {
|
|||
|
||||
removeHelpPrepEQGT : Key k, RBTree (Key k) v, NodeColor, (Key k), v, RBTree (Key k) v, RBTree (Key k) v -> RBTree (Key k) v
|
||||
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Eq
|
||||
removeHelpEQGT : Key k, RBTree (Key k) v -> RBTree (Key k) v | k has Hash & Eq
|
||||
removeHelpEQGT = \targetKey, dict ->
|
||||
when dict is
|
||||
Node color key value left right ->
|
||||
|
@ -8270,7 +8270,7 @@ mod solve_expr {
|
|||
r#"
|
||||
app "test" provides [top] to "./platform"
|
||||
|
||||
MDict u := (List u) | u has Eq
|
||||
MDict u := (List u) | u has Hash & Eq
|
||||
|
||||
bot : MDict k -> MDict k
|
||||
bot = \@MDict data ->
|
||||
|
@ -8281,7 +8281,7 @@ mod solve_expr {
|
|||
top = \x -> bot x
|
||||
"#
|
||||
),
|
||||
"MDict v -> MDict v | v has Eq",
|
||||
"MDict v -> MDict v | v has Hash & Eq",
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -8431,4 +8431,29 @@ mod solve_expr {
|
|||
@"n : Dec"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_set_eq_issue_4671() {
|
||||
infer_queries!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
s1 : Set U8
|
||||
s1 = Set.empty
|
||||
|
||||
s2 : Set Str
|
||||
s2 = Set.empty
|
||||
|
||||
Bool.isEq s1 s1 && Bool.isEq s2 s2
|
||||
# ^^^^^^^^^ ^^^^^^^^^
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
Set#Bool.isEq(17) : Set U8, Set U8 -[[Set.isEq(17)]]-> Bool
|
||||
Set#Bool.isEq(17) : Set Str, Set Str -[[Set.isEq(17)]]-> Bool
|
||||
"###
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -378,6 +378,7 @@ fn check_derived_typechecks_and_golden(
|
|||
);
|
||||
let mut def_types = Default::default();
|
||||
let mut rigid_vars = Default::default();
|
||||
let mut flex_vars = Default::default();
|
||||
let (import_variables, abilities_store) = add_imports(
|
||||
test_module,
|
||||
&mut constraints,
|
||||
|
@ -386,9 +387,15 @@ fn check_derived_typechecks_and_golden(
|
|||
&exposed_for_module,
|
||||
&mut def_types,
|
||||
&mut rigid_vars,
|
||||
&mut flex_vars,
|
||||
);
|
||||
let constr = constraints.let_import_constraint(
|
||||
rigid_vars,
|
||||
flex_vars,
|
||||
def_types,
|
||||
constr,
|
||||
&import_variables,
|
||||
);
|
||||
let constr =
|
||||
constraints.let_import_constraint(rigid_vars, def_types, constr, &import_variables);
|
||||
|
||||
// run the solver, print and fail if we have errors
|
||||
dbg_do!(
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#![cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#![cfg(all(
|
||||
any(feature = "gen-llvm", feature = "gen-wasm"),
|
||||
not(debug_assertions) // https://github.com/roc-lang/roc/issues/3898
|
||||
))]
|
||||
|
||||
#[cfg(feature = "gen-llvm")]
|
||||
use crate::helpers::llvm::assert_evals_to;
|
||||
|
@ -77,6 +80,7 @@ fn dict_nonempty_contains() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "TODO figure out why this is broken with llvm wasm tests"]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn dict_empty_remove() {
|
||||
assert_evals_to!(
|
||||
|
@ -252,7 +256,11 @@ fn from_list_with_fold_reallocates() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// TODO: Re-enable this test for wasm.
|
||||
// Currently it causes "[trap] out of bounds memory access" due to the small strings.
|
||||
// I was unable to find the root cause and with llvm and valgrind it passes with no issues.
|
||||
// #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn small_str_keys() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -384,7 +392,7 @@ fn insert_all() {
|
|||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn insert_all_prefer_first() {
|
||||
fn insert_all_prefer_second() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -396,7 +404,7 @@ fn insert_all_prefer_first() {
|
|||
Dict.values myDict
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[100]),
|
||||
RocList::from_slice(&[200]),
|
||||
RocList<i64>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2808,22 +2808,6 @@ fn cleanup_because_exception() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_range() {
|
||||
assert_evals_to!(
|
||||
"List.range 0 -1",
|
||||
RocList::<i64>::from_slice(&[]),
|
||||
RocList<i64>
|
||||
);
|
||||
assert_evals_to!("List.range 0 0", RocList::from_slice(&[0]), RocList<i64>);
|
||||
assert_evals_to!(
|
||||
"List.range 0 5",
|
||||
RocList::from_slice(&[0, 1, 2, 3, 4]),
|
||||
RocList<i64>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_sort_with() {
|
||||
|
@ -3561,6 +3545,27 @@ fn list_walk_from_until_sum() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn concat_unique_to_nonunique_overlapping_issue_4697() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
# originalList is shared, but others is unique.
|
||||
# When we concat originalList with others, others should be re-used.
|
||||
|
||||
originalList = [1u8]
|
||||
others = [2u8, 3u8, 4u8]
|
||||
new = List.concat originalList others
|
||||
{a: originalList, b: new}
|
||||
"#,
|
||||
(
|
||||
RocList::from_slice(&[1u8]),
|
||||
RocList::from_slice(&[1u8, 2, 3, 4]),
|
||||
),
|
||||
(RocList<u8>, RocList<u8>)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_from_even_prefix_sum() {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#![cfg(feature = "gen-llvm")]
|
||||
#![cfg(all(
|
||||
any(feature = "gen-llvm"),
|
||||
not(debug_assertions) // https://github.com/roc-lang/roc/issues/3898
|
||||
))]
|
||||
|
||||
#[cfg(feature = "gen-llvm")]
|
||||
use crate::helpers::llvm::assert_evals_to;
|
||||
|
@ -62,16 +65,6 @@ fn single_to_list() {
|
|||
RocList::from_slice(&[1]),
|
||||
RocList<i64>
|
||||
);
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Set.toList (Set.single 1.0)
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&[1.0]),
|
||||
RocList<f64>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -260,6 +253,20 @@ fn from_list_void() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn to_list_empty() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Set.toList Set.empty
|
||||
"#
|
||||
),
|
||||
RocList::<std::convert::Infallible>::default(),
|
||||
RocList<std::convert::Infallible>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn from_list_result() {
|
||||
|
@ -280,3 +287,26 @@ fn from_list_result() {
|
|||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn resolve_set_eq_issue_4671() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
s1 : Set U8
|
||||
s1 = Set.fromList [1, 2, 3]
|
||||
|
||||
s2 : Set U8
|
||||
s2 = Set.fromList [3, 2, 1]
|
||||
|
||||
s1 == s2
|
||||
"#
|
||||
),
|
||||
true,
|
||||
bool
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use libloading::Library;
|
|||
use roc_build::link::{link, LinkType};
|
||||
use roc_builtins::bitcode;
|
||||
use roc_load::{EntryPoint, ExecutionMode, LoadConfig, Threading};
|
||||
use roc_mono::ir::SingleEntryPoint;
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_region::all::LineInfo;
|
||||
use tempfile::tempdir;
|
||||
|
@ -105,8 +106,15 @@ pub fn helper(
|
|||
|
||||
debug_assert_eq!(exposed_to_host.values.len(), 1);
|
||||
let entry_point = match loaded.entry_point {
|
||||
EntryPoint::Executable { symbol, layout, .. } => {
|
||||
roc_mono::ir::EntryPoint { symbol, layout }
|
||||
EntryPoint::Executable {
|
||||
exposed_to_host,
|
||||
platform_path: _,
|
||||
} => {
|
||||
// TODO support multiple of these!
|
||||
debug_assert_eq!(exposed_to_host.len(), 1);
|
||||
let (symbol, layout) = exposed_to_host[0];
|
||||
|
||||
SingleEntryPoint { symbol, layout }
|
||||
}
|
||||
EntryPoint::Test => {
|
||||
unreachable!()
|
||||
|
|
|
@ -8,7 +8,7 @@ use roc_collections::all::MutSet;
|
|||
use roc_gen_llvm::llvm::externs::add_default_roc_externs;
|
||||
use roc_gen_llvm::{llvm::build::LlvmBackendMode, run_roc::RocCallResult};
|
||||
use roc_load::{EntryPoint, ExecutionMode, LoadConfig, LoadMonomorphizedError, Threading};
|
||||
use roc_mono::ir::{CrashTag, OptLevel};
|
||||
use roc_mono::ir::{CrashTag, OptLevel, SingleEntryPoint};
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use roc_region::all::LineInfo;
|
||||
use roc_reporting::report::{RenderTarget, DEFAULT_PALETTE};
|
||||
|
@ -99,7 +99,6 @@ fn create_llvm_module<'a>(
|
|||
use roc_load::MonomorphizedModule;
|
||||
let MonomorphizedModule {
|
||||
procedures,
|
||||
entry_point,
|
||||
interns,
|
||||
layout_interner,
|
||||
..
|
||||
|
@ -238,9 +237,16 @@ fn create_llvm_module<'a>(
|
|||
// platform to provide them.
|
||||
add_default_roc_externs(&env);
|
||||
|
||||
let entry_point = match entry_point {
|
||||
EntryPoint::Executable { symbol, layout, .. } => {
|
||||
roc_mono::ir::EntryPoint { symbol, layout }
|
||||
let entry_point = match loaded.entry_point {
|
||||
EntryPoint::Executable {
|
||||
exposed_to_host,
|
||||
platform_path: _,
|
||||
} => {
|
||||
// TODO support multiple of these!
|
||||
debug_assert_eq!(exposed_to_host.len(), 1);
|
||||
let (symbol, layout) = exposed_to_host[0];
|
||||
|
||||
SingleEntryPoint { symbol, layout }
|
||||
}
|
||||
EntryPoint::Test => {
|
||||
unreachable!()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.409 : List {} = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
let List.478 : List {} = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
decref #Attr.2;
|
||||
ret List.409;
|
||||
ret List.478;
|
||||
|
||||
procedure Test.2 (Test.3):
|
||||
let Test.7 : {} = Struct {};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.409 : List [] = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
let List.478 : List [] = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.2 #Attr.3;
|
||||
decref #Attr.2;
|
||||
ret List.409;
|
||||
ret List.478;
|
||||
|
||||
procedure Test.2 (Test.3):
|
||||
let Test.7 : {} = Struct {};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure Test.1 (Test.5):
|
||||
let Test.2 : I64 = 41i64;
|
||||
|
|
|
@ -1,17 +1,87 @@
|
|||
procedure Dict.1 ():
|
||||
let Dict.318 : List {[], []} = Array [];
|
||||
ret Dict.318;
|
||||
let Dict.520 : List {[], []} = Array [];
|
||||
let Dict.527 : U64 = 0i64;
|
||||
let Dict.528 : U64 = 8i64;
|
||||
let Dict.521 : List U64 = CallByName List.11 Dict.527 Dict.528;
|
||||
let Dict.524 : I8 = CallByName Dict.34;
|
||||
let Dict.525 : U64 = 8i64;
|
||||
let Dict.522 : List I8 = CallByName List.11 Dict.524 Dict.525;
|
||||
let Dict.523 : U64 = 0i64;
|
||||
let Dict.519 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.520, Dict.521, Dict.522, Dict.523};
|
||||
ret Dict.519;
|
||||
|
||||
procedure Dict.7 (Dict.312):
|
||||
let Dict.317 : U64 = CallByName List.6 Dict.312;
|
||||
ret Dict.317;
|
||||
procedure Dict.34 ():
|
||||
let Dict.526 : I8 = -128i64;
|
||||
ret Dict.526;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
procedure Dict.4 (Dict.507):
|
||||
let Dict.85 : U64 = StructAtIndex 3 Dict.507;
|
||||
dec Dict.507;
|
||||
ret Dict.85;
|
||||
|
||||
procedure List.11 (List.114, List.115):
|
||||
let List.479 : List I8 = CallByName List.68 List.115;
|
||||
let List.478 : List I8 = CallByName List.80 List.114 List.115 List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.11 (List.114, List.115):
|
||||
let List.491 : List U64 = CallByName List.68 List.115;
|
||||
let List.490 : List U64 = CallByName List.80 List.114 List.115 List.491;
|
||||
ret List.490;
|
||||
|
||||
procedure List.68 (#Attr.2):
|
||||
let List.489 : List I8 = lowlevel ListWithCapacity #Attr.2;
|
||||
ret List.489;
|
||||
|
||||
procedure List.68 (#Attr.2):
|
||||
let List.501 : List U64 = lowlevel ListWithCapacity #Attr.2;
|
||||
ret List.501;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.486 : List I8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.486;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.498 : List U64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.498;
|
||||
|
||||
procedure List.80 (List.502, List.503, List.504):
|
||||
joinpoint List.480 List.116 List.117 List.118:
|
||||
let List.488 : U64 = 0i64;
|
||||
let List.482 : Int1 = CallByName Num.24 List.117 List.488;
|
||||
if List.482 then
|
||||
let List.487 : U64 = 1i64;
|
||||
let List.484 : U64 = CallByName Num.20 List.117 List.487;
|
||||
let List.485 : List I8 = CallByName List.71 List.118 List.116;
|
||||
jump List.480 List.116 List.484 List.485;
|
||||
else
|
||||
ret List.118;
|
||||
in
|
||||
jump List.480 List.502 List.503 List.504;
|
||||
|
||||
procedure List.80 (List.510, List.511, List.512):
|
||||
joinpoint List.492 List.116 List.117 List.118:
|
||||
let List.500 : U64 = 0i64;
|
||||
let List.494 : Int1 = CallByName Num.24 List.117 List.500;
|
||||
if List.494 then
|
||||
let List.499 : U64 = 1i64;
|
||||
let List.496 : U64 = CallByName Num.20 List.117 List.499;
|
||||
let List.497 : List U64 = CallByName List.71 List.118 List.116;
|
||||
jump List.492 List.116 List.496 List.497;
|
||||
else
|
||||
ret List.118;
|
||||
in
|
||||
jump List.492 List.510 List.511 List.512;
|
||||
|
||||
procedure Num.20 (#Attr.2, #Attr.3):
|
||||
let Num.257 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
|
||||
ret Num.257;
|
||||
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Num.259 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
|
||||
ret Num.259;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : List {[], []} = CallByName Dict.1;
|
||||
let Test.1 : U64 = CallByName Dict.7 Test.2;
|
||||
dec Test.2;
|
||||
let Test.2 : {List {[], []}, List U64, List I8, U64} = CallByName Dict.1;
|
||||
let Test.1 : U64 = CallByName Dict.4 Test.2;
|
||||
ret Test.1;
|
||||
|
|
|
@ -2,25 +2,25 @@ procedure Bool.1 ():
|
|||
let Bool.23 : Int1 = false;
|
||||
ret Bool.23;
|
||||
|
||||
procedure List.2 (List.94, List.95):
|
||||
let List.415 : U64 = CallByName List.6 List.94;
|
||||
let List.411 : Int1 = CallByName Num.22 List.95 List.415;
|
||||
if List.411 then
|
||||
let List.413 : {} = CallByName List.66 List.94 List.95;
|
||||
let List.412 : [C {}, C {}] = TagId(1) List.413;
|
||||
ret List.412;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.484 : U64 = CallByName List.6 List.95;
|
||||
let List.480 : Int1 = CallByName Num.22 List.96 List.484;
|
||||
if List.480 then
|
||||
let List.482 : {} = CallByName List.66 List.95 List.96;
|
||||
let List.481 : [C {}, C {}] = TagId(1) List.482;
|
||||
ret List.481;
|
||||
else
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : [C {}, C {}] = TagId(0) List.410;
|
||||
ret List.409;
|
||||
let List.479 : {} = Struct {};
|
||||
let List.478 : [C {}, C {}] = TagId(0) List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.414 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.414;
|
||||
let List.483 : {} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
procedure List.4 (List.105, List.106):
|
||||
let List.412 : U64 = 1i64;
|
||||
let List.410 : List U8 = CallByName List.70 List.105 List.412;
|
||||
let List.409 : List U8 = CallByName List.71 List.410 List.106;
|
||||
ret List.409;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.481 : U64 = 1i64;
|
||||
let List.479 : List U8 = CallByName List.70 List.106 List.481;
|
||||
let List.478 : List U8 = CallByName List.71 List.479 List.107;
|
||||
ret List.478;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.411 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.411;
|
||||
let List.480 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.480;
|
||||
|
||||
procedure Test.23 (Test.24, Test.35, Test.22):
|
||||
let Test.37 : List U8 = CallByName List.4 Test.24 Test.22;
|
||||
|
|
|
@ -66,237 +66,237 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.430 : I64 = 123i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.429;
|
||||
let Json.428 : U64 = CallByName List.6 Json.111;
|
||||
let Json.405 : {List U8, U64} = Struct {Json.115, Json.428};
|
||||
let Json.406 : {} = Struct {};
|
||||
let Json.404 : {List U8, U64} = CallByName List.18 Json.111 Json.405 Json.406;
|
||||
procedure Json.112 (Json.113, Json.399, Json.111):
|
||||
let Json.432 : I64 = 123i64;
|
||||
let Json.431 : U8 = CallByName Num.125 Json.432;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.431;
|
||||
let Json.430 : U64 = CallByName List.6 Json.111;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.115, Json.430};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.111 Json.407 Json.408;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.404;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.117;
|
||||
dec Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.117 Json.402;
|
||||
ret Json.401;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.117 Json.404;
|
||||
ret Json.403;
|
||||
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.470 : I64 = 123i64;
|
||||
let Json.469 : U8 = CallByName Num.125 Json.470;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.469;
|
||||
let Json.468 : U64 = CallByName List.6 Json.111;
|
||||
let Json.445 : {List U8, U64} = Struct {Json.115, Json.468};
|
||||
let Json.446 : {} = Struct {};
|
||||
let Json.444 : {List U8, U64} = CallByName List.18 Json.111 Json.445 Json.446;
|
||||
procedure Json.112 (Json.113, Json.399, Json.111):
|
||||
let Json.472 : I64 = 123i64;
|
||||
let Json.471 : U8 = CallByName Num.125 Json.472;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.471;
|
||||
let Json.470 : U64 = CallByName List.6 Json.111;
|
||||
let Json.447 : {List U8, U64} = Struct {Json.115, Json.470};
|
||||
let Json.448 : {} = Struct {};
|
||||
let Json.446 : {List U8, U64} = CallByName List.18 Json.111 Json.447 Json.448;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.444;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.446;
|
||||
inc Json.117;
|
||||
dec Json.444;
|
||||
let Json.443 : I64 = 125i64;
|
||||
let Json.442 : U8 = CallByName Num.125 Json.443;
|
||||
let Json.441 : List U8 = CallByName List.4 Json.117 Json.442;
|
||||
ret Json.441;
|
||||
dec Json.446;
|
||||
let Json.445 : I64 = 125i64;
|
||||
let Json.444 : U8 = CallByName Num.125 Json.445;
|
||||
let Json.443 : List U8 = CallByName List.4 Json.117 Json.444;
|
||||
ret Json.443;
|
||||
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
procedure Json.114 (Json.401, Json.402):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.402;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.121;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
dec Json.402;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.427 : I64 = 34i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.424 : List U8 = CallByName List.4 Json.118 Json.426;
|
||||
let Json.425 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.421 : List U8 = CallByName List.8 Json.424 Json.425;
|
||||
let Json.423 : I64 = 34i64;
|
||||
let Json.422 : U8 = CallByName Num.125 Json.423;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.421 Json.422;
|
||||
let Json.420 : I64 = 58i64;
|
||||
let Json.419 : U8 = CallByName Num.125 Json.420;
|
||||
let Json.416 : List U8 = CallByName List.4 Json.418 Json.419;
|
||||
let Json.417 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.416 Json.121 Json.417;
|
||||
joinpoint Json.411 Json.123:
|
||||
let Json.409 : U64 = 1i64;
|
||||
let Json.408 : U64 = CallByName Num.20 Json.119 Json.409;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.123, Json.408};
|
||||
ret Json.407;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.429 : I64 = 34i64;
|
||||
let Json.428 : U8 = CallByName Num.125 Json.429;
|
||||
let Json.426 : List U8 = CallByName List.4 Json.118 Json.428;
|
||||
let Json.427 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.423 : List U8 = CallByName List.8 Json.426 Json.427;
|
||||
let Json.425 : I64 = 34i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 58i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.418 Json.121 Json.419;
|
||||
joinpoint Json.413 Json.123:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.119 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.123, Json.410};
|
||||
ret Json.409;
|
||||
in
|
||||
let Json.415 : U64 = 1i64;
|
||||
let Json.412 : Int1 = CallByName Num.24 Json.119 Json.415;
|
||||
if Json.412 then
|
||||
let Json.414 : I64 = 44i64;
|
||||
let Json.413 : U8 = CallByName Num.125 Json.414;
|
||||
let Json.410 : List U8 = CallByName List.4 Json.122 Json.413;
|
||||
jump Json.411 Json.410;
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.119 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.122 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
else
|
||||
jump Json.411 Json.122;
|
||||
jump Json.413 Json.122;
|
||||
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
procedure Json.114 (Json.401, Json.402):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.402;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.121;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
dec Json.402;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.467 : I64 = 34i64;
|
||||
let Json.466 : U8 = CallByName Num.125 Json.467;
|
||||
let Json.464 : List U8 = CallByName List.4 Json.118 Json.466;
|
||||
let Json.465 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.461 : List U8 = CallByName List.8 Json.464 Json.465;
|
||||
let Json.463 : I64 = 34i64;
|
||||
let Json.462 : U8 = CallByName Num.125 Json.463;
|
||||
let Json.458 : List U8 = CallByName List.4 Json.461 Json.462;
|
||||
let Json.460 : I64 = 58i64;
|
||||
let Json.459 : U8 = CallByName Num.125 Json.460;
|
||||
let Json.456 : List U8 = CallByName List.4 Json.458 Json.459;
|
||||
let Json.457 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.456 Json.121 Json.457;
|
||||
joinpoint Json.451 Json.123:
|
||||
let Json.449 : U64 = 1i64;
|
||||
let Json.448 : U64 = CallByName Num.20 Json.119 Json.449;
|
||||
let Json.447 : {List U8, U64} = Struct {Json.123, Json.448};
|
||||
ret Json.447;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.469 : I64 = 34i64;
|
||||
let Json.468 : U8 = CallByName Num.125 Json.469;
|
||||
let Json.466 : List U8 = CallByName List.4 Json.118 Json.468;
|
||||
let Json.467 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.463 : List U8 = CallByName List.8 Json.466 Json.467;
|
||||
let Json.465 : I64 = 34i64;
|
||||
let Json.464 : U8 = CallByName Num.125 Json.465;
|
||||
let Json.460 : List U8 = CallByName List.4 Json.463 Json.464;
|
||||
let Json.462 : I64 = 58i64;
|
||||
let Json.461 : U8 = CallByName Num.125 Json.462;
|
||||
let Json.458 : List U8 = CallByName List.4 Json.460 Json.461;
|
||||
let Json.459 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.458 Json.121 Json.459;
|
||||
joinpoint Json.453 Json.123:
|
||||
let Json.451 : U64 = 1i64;
|
||||
let Json.450 : U64 = CallByName Num.20 Json.119 Json.451;
|
||||
let Json.449 : {List U8, U64} = Struct {Json.123, Json.450};
|
||||
ret Json.449;
|
||||
in
|
||||
let Json.455 : U64 = 1i64;
|
||||
let Json.452 : Int1 = CallByName Num.24 Json.119 Json.455;
|
||||
if Json.452 then
|
||||
let Json.454 : I64 = 44i64;
|
||||
let Json.453 : U8 = CallByName Num.125 Json.454;
|
||||
let Json.450 : List U8 = CallByName List.4 Json.122 Json.453;
|
||||
jump Json.451 Json.450;
|
||||
let Json.457 : U64 = 1i64;
|
||||
let Json.454 : Int1 = CallByName Num.24 Json.119 Json.457;
|
||||
if Json.454 then
|
||||
let Json.456 : I64 = 44i64;
|
||||
let Json.455 : U8 = CallByName Num.125 Json.456;
|
||||
let Json.452 : List U8 = CallByName List.4 Json.122 Json.455;
|
||||
jump Json.453 Json.452;
|
||||
else
|
||||
jump Json.451 Json.122;
|
||||
jump Json.453 Json.122;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.471 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.471;
|
||||
let Json.473 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.473;
|
||||
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.395 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.395;
|
||||
let Json.397 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.437 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.437;
|
||||
let Json.439 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.439;
|
||||
|
||||
procedure Json.96 (Json.97, Json.473, Json.95):
|
||||
let Json.482 : I64 = 34i64;
|
||||
let Json.481 : U8 = CallByName Num.125 Json.482;
|
||||
let Json.479 : List U8 = CallByName List.4 Json.97 Json.481;
|
||||
let Json.480 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.476 : List U8 = CallByName List.8 Json.479 Json.480;
|
||||
let Json.478 : I64 = 34i64;
|
||||
let Json.477 : U8 = CallByName Num.125 Json.478;
|
||||
let Json.475 : List U8 = CallByName List.4 Json.476 Json.477;
|
||||
ret Json.475;
|
||||
procedure Json.96 (Json.97, Json.475, Json.95):
|
||||
let Json.484 : I64 = 34i64;
|
||||
let Json.483 : U8 = CallByName Num.125 Json.484;
|
||||
let Json.481 : List U8 = CallByName List.4 Json.97 Json.483;
|
||||
let Json.482 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.478 : List U8 = CallByName List.8 Json.481 Json.482;
|
||||
let Json.480 : I64 = 34i64;
|
||||
let Json.479 : U8 = CallByName Num.125 Json.480;
|
||||
let Json.477 : List U8 = CallByName List.4 Json.478 Json.479;
|
||||
ret Json.477;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.450 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.450;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.519 : {List U8, U64} = CallByName Json.114 List.139 List.140;
|
||||
ret List.519;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.523 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.523;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.592 : {List U8, U64} = CallByName Json.114 List.139 List.140;
|
||||
ret List.592;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.431 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.431;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.500 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.500;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.504 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.504;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.573 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.573;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.503 : U64 = 1i64;
|
||||
let List.502 : List U8 = CallByName List.70 List.105 List.503;
|
||||
let List.501 : List U8 = CallByName List.71 List.502 List.106;
|
||||
ret List.501;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.572 : U64 = 1i64;
|
||||
let List.571 : List U8 = CallByName List.70 List.106 List.572;
|
||||
let List.570 : List U8 = CallByName List.71 List.571 List.107;
|
||||
ret List.570;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.452 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.452;
|
||||
let List.521 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.521;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.526 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.526;
|
||||
let List.595 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.595;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.447 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.447;
|
||||
let List.516 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.516;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.520 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.520;
|
||||
let List.589 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.589;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.482 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
let List.551 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.551;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.480 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.480;
|
||||
let List.549 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.549;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.525 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.525;
|
||||
let List.594 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.594;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.435 : U64 = 0i64;
|
||||
let List.436 : U64 = CallByName List.6 List.385;
|
||||
let List.434 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.435 List.436;
|
||||
ret List.434;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.504 : U64 = 0i64;
|
||||
let List.505 : U64 = CallByName List.6 List.426;
|
||||
let List.503 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.504 List.505;
|
||||
ret List.503;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.508 : U64 = 0i64;
|
||||
let List.509 : U64 = CallByName List.6 List.385;
|
||||
let List.507 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.508 List.509;
|
||||
ret List.507;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.577 : U64 = 0i64;
|
||||
let List.578 : U64 = CallByName List.6 List.426;
|
||||
let List.576 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.577 List.578;
|
||||
ret List.576;
|
||||
|
||||
procedure List.90 (List.462, List.463, List.464, List.465, List.466):
|
||||
joinpoint List.437 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.439 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.439 then
|
||||
let List.446 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.440 : {List U8, U64} = CallByName List.137 List.389 List.446 List.390;
|
||||
let List.443 : U64 = 1i64;
|
||||
let List.442 : U64 = CallByName Num.19 List.391 List.443;
|
||||
jump List.437 List.388 List.440 List.390 List.442 List.392;
|
||||
procedure List.91 (List.531, List.532, List.533, List.534, List.535):
|
||||
joinpoint List.506 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.508 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.508 then
|
||||
let List.515 : {Str, Str} = CallByName List.66 List.429 List.432;
|
||||
let List.509 : {List U8, U64} = CallByName List.138 List.430 List.515 List.431;
|
||||
let List.512 : U64 = 1i64;
|
||||
let List.511 : U64 = CallByName Num.19 List.432 List.512;
|
||||
jump List.506 List.429 List.509 List.431 List.511 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.437 List.462 List.463 List.464 List.465 List.466;
|
||||
jump List.506 List.531 List.532 List.533 List.534 List.535;
|
||||
|
||||
procedure List.90 (List.536, List.537, List.538, List.539, List.540):
|
||||
joinpoint List.510 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.512 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.512 then
|
||||
let List.519 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.513 : {List U8, U64} = CallByName List.137 List.389 List.519 List.390;
|
||||
let List.516 : U64 = 1i64;
|
||||
let List.515 : U64 = CallByName Num.19 List.391 List.516;
|
||||
jump List.510 List.388 List.513 List.390 List.515 List.392;
|
||||
procedure List.91 (List.605, List.606, List.607, List.608, List.609):
|
||||
joinpoint List.579 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.581 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.581 then
|
||||
let List.588 : {Str, Str} = CallByName List.66 List.429 List.432;
|
||||
let List.582 : {List U8, U64} = CallByName List.138 List.430 List.588 List.431;
|
||||
let List.585 : U64 = 1i64;
|
||||
let List.584 : U64 = CallByName Num.19 List.432 List.585;
|
||||
jump List.579 List.429 List.582 List.431 List.584 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.510 List.536 List.537 List.538 List.539 List.540;
|
||||
jump List.579 List.605 List.606 List.607 List.608 List.609;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.282 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -39,141 +39,141 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.430 : I64 = 123i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.429;
|
||||
let Json.428 : U64 = CallByName List.6 Json.111;
|
||||
let Json.405 : {List U8, U64} = Struct {Json.115, Json.428};
|
||||
let Json.406 : {} = Struct {};
|
||||
let Json.404 : {List U8, U64} = CallByName List.18 Json.111 Json.405 Json.406;
|
||||
procedure Json.112 (Json.113, Json.399, Json.111):
|
||||
let Json.432 : I64 = 123i64;
|
||||
let Json.431 : U8 = CallByName Num.125 Json.432;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.431;
|
||||
let Json.430 : U64 = CallByName List.6 Json.111;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.115, Json.430};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.111 Json.407 Json.408;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.404;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.117;
|
||||
dec Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.117 Json.402;
|
||||
ret Json.401;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.117 Json.404;
|
||||
ret Json.403;
|
||||
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
procedure Json.114 (Json.401, Json.402):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.402;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.121;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
dec Json.402;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.427 : I64 = 34i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.424 : List U8 = CallByName List.4 Json.118 Json.426;
|
||||
let Json.425 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.421 : List U8 = CallByName List.8 Json.424 Json.425;
|
||||
let Json.423 : I64 = 34i64;
|
||||
let Json.422 : U8 = CallByName Num.125 Json.423;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.421 Json.422;
|
||||
let Json.420 : I64 = 58i64;
|
||||
let Json.419 : U8 = CallByName Num.125 Json.420;
|
||||
let Json.416 : List U8 = CallByName List.4 Json.418 Json.419;
|
||||
let Json.417 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.416 Json.121 Json.417;
|
||||
joinpoint Json.411 Json.123:
|
||||
let Json.409 : U64 = 1i64;
|
||||
let Json.408 : U64 = CallByName Num.20 Json.119 Json.409;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.123, Json.408};
|
||||
ret Json.407;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.429 : I64 = 34i64;
|
||||
let Json.428 : U8 = CallByName Num.125 Json.429;
|
||||
let Json.426 : List U8 = CallByName List.4 Json.118 Json.428;
|
||||
let Json.427 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.423 : List U8 = CallByName List.8 Json.426 Json.427;
|
||||
let Json.425 : I64 = 34i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 58i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.418 Json.121 Json.419;
|
||||
joinpoint Json.413 Json.123:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.119 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.123, Json.410};
|
||||
ret Json.409;
|
||||
in
|
||||
let Json.415 : U64 = 1i64;
|
||||
let Json.412 : Int1 = CallByName Num.24 Json.119 Json.415;
|
||||
if Json.412 then
|
||||
let Json.414 : I64 = 44i64;
|
||||
let Json.413 : U8 = CallByName Num.125 Json.414;
|
||||
let Json.410 : List U8 = CallByName List.4 Json.122 Json.413;
|
||||
jump Json.411 Json.410;
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.119 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.122 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
else
|
||||
jump Json.411 Json.122;
|
||||
jump Json.413 Json.122;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.431 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.431;
|
||||
let Json.433 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.433;
|
||||
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.395 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.395;
|
||||
let Json.397 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.96 (Json.97, Json.433, Json.95):
|
||||
let Json.442 : I64 = 34i64;
|
||||
let Json.441 : U8 = CallByName Num.125 Json.442;
|
||||
let Json.439 : List U8 = CallByName List.4 Json.97 Json.441;
|
||||
let Json.440 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.436 : List U8 = CallByName List.8 Json.439 Json.440;
|
||||
let Json.438 : I64 = 34i64;
|
||||
let Json.437 : U8 = CallByName Num.125 Json.438;
|
||||
let Json.435 : List U8 = CallByName List.4 Json.436 Json.437;
|
||||
ret Json.435;
|
||||
procedure Json.96 (Json.97, Json.435, Json.95):
|
||||
let Json.444 : I64 = 34i64;
|
||||
let Json.443 : U8 = CallByName Num.125 Json.444;
|
||||
let Json.441 : List U8 = CallByName List.4 Json.97 Json.443;
|
||||
let Json.442 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.438 : List U8 = CallByName List.8 Json.441 Json.442;
|
||||
let Json.440 : I64 = 34i64;
|
||||
let Json.439 : U8 = CallByName Num.125 Json.440;
|
||||
let Json.437 : List U8 = CallByName List.4 Json.438 Json.439;
|
||||
ret Json.437;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.456 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.456;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.525 : {List U8, U64} = CallByName Json.114 List.139 List.140;
|
||||
ret List.525;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.437 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.437;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.506 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.506;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.436 : U64 = 1i64;
|
||||
let List.435 : List U8 = CallByName List.70 List.105 List.436;
|
||||
let List.434 : List U8 = CallByName List.71 List.435 List.106;
|
||||
ret List.434;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.505 : U64 = 1i64;
|
||||
let List.504 : List U8 = CallByName List.70 List.106 List.505;
|
||||
let List.503 : List U8 = CallByName List.71 List.504 List.107;
|
||||
ret List.503;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.459 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.459;
|
||||
let List.528 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.528;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.453 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.453;
|
||||
let List.522 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.522;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
let List.484 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.484;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.458 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.458;
|
||||
let List.527 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.527;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.441 : U64 = 0i64;
|
||||
let List.442 : U64 = CallByName List.6 List.385;
|
||||
let List.440 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.441 List.442;
|
||||
ret List.440;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.510 : U64 = 0i64;
|
||||
let List.511 : U64 = CallByName List.6 List.426;
|
||||
let List.509 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.510 List.511;
|
||||
ret List.509;
|
||||
|
||||
procedure List.90 (List.469, List.470, List.471, List.472, List.473):
|
||||
joinpoint List.443 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.445 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.445 then
|
||||
let List.452 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.446 : {List U8, U64} = CallByName List.137 List.389 List.452 List.390;
|
||||
let List.449 : U64 = 1i64;
|
||||
let List.448 : U64 = CallByName Num.19 List.391 List.449;
|
||||
jump List.443 List.388 List.446 List.390 List.448 List.392;
|
||||
procedure List.91 (List.538, List.539, List.540, List.541, List.542):
|
||||
joinpoint List.512 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.514 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.514 then
|
||||
let List.521 : {Str, Str} = CallByName List.66 List.429 List.432;
|
||||
let List.515 : {List U8, U64} = CallByName List.138 List.430 List.521 List.431;
|
||||
let List.518 : U64 = 1i64;
|
||||
let List.517 : U64 = CallByName Num.19 List.432 List.518;
|
||||
jump List.512 List.429 List.515 List.431 List.517 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.443 List.469 List.470 List.471 List.472 List.473;
|
||||
jump List.512 List.538 List.539 List.540 List.541 List.542;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.263 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -47,141 +47,141 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.112 (Json.113, Json.397, Json.111):
|
||||
let Json.430 : I64 = 123i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.429;
|
||||
let Json.428 : U64 = CallByName List.6 Json.111;
|
||||
let Json.405 : {List U8, U64} = Struct {Json.115, Json.428};
|
||||
let Json.406 : {} = Struct {};
|
||||
let Json.404 : {List U8, U64} = CallByName List.18 Json.111 Json.405 Json.406;
|
||||
procedure Json.112 (Json.113, Json.399, Json.111):
|
||||
let Json.432 : I64 = 123i64;
|
||||
let Json.431 : U8 = CallByName Num.125 Json.432;
|
||||
let Json.115 : List U8 = CallByName List.4 Json.113 Json.431;
|
||||
let Json.430 : U64 = CallByName List.6 Json.111;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.115, Json.430};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.111 Json.407 Json.408;
|
||||
dec Json.111;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.404;
|
||||
let Json.117 : List U8 = StructAtIndex 0 Json.406;
|
||||
inc Json.117;
|
||||
dec Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.117 Json.402;
|
||||
ret Json.401;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.117 Json.404;
|
||||
ret Json.403;
|
||||
|
||||
procedure Json.114 (Json.399, Json.400):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.400;
|
||||
procedure Json.114 (Json.401, Json.402):
|
||||
let Json.120 : Str = StructAtIndex 0 Json.402;
|
||||
inc Json.120;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.400;
|
||||
let Json.121 : Str = StructAtIndex 1 Json.402;
|
||||
inc Json.121;
|
||||
dec Json.400;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.399;
|
||||
dec Json.402;
|
||||
let Json.118 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.118;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.427 : I64 = 34i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.424 : List U8 = CallByName List.4 Json.118 Json.426;
|
||||
let Json.425 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.421 : List U8 = CallByName List.8 Json.424 Json.425;
|
||||
let Json.423 : I64 = 34i64;
|
||||
let Json.422 : U8 = CallByName Num.125 Json.423;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.421 Json.422;
|
||||
let Json.420 : I64 = 58i64;
|
||||
let Json.419 : U8 = CallByName Num.125 Json.420;
|
||||
let Json.416 : List U8 = CallByName List.4 Json.418 Json.419;
|
||||
let Json.417 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.416 Json.121 Json.417;
|
||||
joinpoint Json.411 Json.123:
|
||||
let Json.409 : U64 = 1i64;
|
||||
let Json.408 : U64 = CallByName Num.20 Json.119 Json.409;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.123, Json.408};
|
||||
ret Json.407;
|
||||
let Json.119 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.429 : I64 = 34i64;
|
||||
let Json.428 : U8 = CallByName Num.125 Json.429;
|
||||
let Json.426 : List U8 = CallByName List.4 Json.118 Json.428;
|
||||
let Json.427 : List U8 = CallByName Str.12 Json.120;
|
||||
let Json.423 : List U8 = CallByName List.8 Json.426 Json.427;
|
||||
let Json.425 : I64 = 34i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 58i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.418 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : {} = Struct {};
|
||||
let Json.122 : List U8 = CallByName Encode.23 Json.418 Json.121 Json.419;
|
||||
joinpoint Json.413 Json.123:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.119 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.123, Json.410};
|
||||
ret Json.409;
|
||||
in
|
||||
let Json.415 : U64 = 1i64;
|
||||
let Json.412 : Int1 = CallByName Num.24 Json.119 Json.415;
|
||||
if Json.412 then
|
||||
let Json.414 : I64 = 44i64;
|
||||
let Json.413 : U8 = CallByName Num.125 Json.414;
|
||||
let Json.410 : List U8 = CallByName List.4 Json.122 Json.413;
|
||||
jump Json.411 Json.410;
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.119 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.122 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
else
|
||||
jump Json.411 Json.122;
|
||||
jump Json.413 Json.122;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.443 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.443;
|
||||
let Json.445 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.445;
|
||||
|
||||
procedure Json.20 (Json.111):
|
||||
let Json.395 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.395;
|
||||
let Json.397 : List {Str, Str} = CallByName Encode.22 Json.111;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.96 (Json.97, Json.433, Json.95):
|
||||
let Json.442 : I64 = 34i64;
|
||||
let Json.441 : U8 = CallByName Num.125 Json.442;
|
||||
let Json.439 : List U8 = CallByName List.4 Json.97 Json.441;
|
||||
let Json.440 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.436 : List U8 = CallByName List.8 Json.439 Json.440;
|
||||
let Json.438 : I64 = 34i64;
|
||||
let Json.437 : U8 = CallByName Num.125 Json.438;
|
||||
let Json.435 : List U8 = CallByName List.4 Json.436 Json.437;
|
||||
ret Json.435;
|
||||
procedure Json.96 (Json.97, Json.435, Json.95):
|
||||
let Json.444 : I64 = 34i64;
|
||||
let Json.443 : U8 = CallByName Num.125 Json.444;
|
||||
let Json.441 : List U8 = CallByName List.4 Json.97 Json.443;
|
||||
let Json.442 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.438 : List U8 = CallByName List.8 Json.441 Json.442;
|
||||
let Json.440 : I64 = 34i64;
|
||||
let Json.439 : U8 = CallByName Num.125 Json.440;
|
||||
let Json.437 : List U8 = CallByName List.4 Json.438 Json.439;
|
||||
ret Json.437;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.456 : {List U8, U64} = CallByName Json.114 List.138 List.139;
|
||||
ret List.456;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.525 : {List U8, U64} = CallByName Json.114 List.139 List.140;
|
||||
ret List.525;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.437 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.437;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.506 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.506;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.436 : U64 = 1i64;
|
||||
let List.435 : List U8 = CallByName List.70 List.105 List.436;
|
||||
let List.434 : List U8 = CallByName List.71 List.435 List.106;
|
||||
ret List.434;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.505 : U64 = 1i64;
|
||||
let List.504 : List U8 = CallByName List.70 List.106 List.505;
|
||||
let List.503 : List U8 = CallByName List.71 List.504 List.107;
|
||||
ret List.503;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.459 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.459;
|
||||
let List.528 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.528;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.453 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.453;
|
||||
let List.522 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.522;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
let List.484 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.484;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.458 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.458;
|
||||
let List.527 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.527;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.441 : U64 = 0i64;
|
||||
let List.442 : U64 = CallByName List.6 List.385;
|
||||
let List.440 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.441 List.442;
|
||||
ret List.440;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.510 : U64 = 0i64;
|
||||
let List.511 : U64 = CallByName List.6 List.426;
|
||||
let List.509 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.510 List.511;
|
||||
ret List.509;
|
||||
|
||||
procedure List.90 (List.469, List.470, List.471, List.472, List.473):
|
||||
joinpoint List.443 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.445 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.445 then
|
||||
let List.452 : {Str, Str} = CallByName List.66 List.388 List.391;
|
||||
let List.446 : {List U8, U64} = CallByName List.137 List.389 List.452 List.390;
|
||||
let List.449 : U64 = 1i64;
|
||||
let List.448 : U64 = CallByName Num.19 List.391 List.449;
|
||||
jump List.443 List.388 List.446 List.390 List.448 List.392;
|
||||
procedure List.91 (List.538, List.539, List.540, List.541, List.542):
|
||||
joinpoint List.512 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.514 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.514 then
|
||||
let List.521 : {Str, Str} = CallByName List.66 List.429 List.432;
|
||||
let List.515 : {List U8, U64} = CallByName List.138 List.430 List.521 List.431;
|
||||
let List.518 : U64 = 1i64;
|
||||
let List.517 : U64 = CallByName Num.19 List.432 List.518;
|
||||
jump List.512 List.429 List.515 List.431 List.517 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.443 List.469 List.470 List.471 List.472 List.473;
|
||||
jump List.512 List.538 List.539 List.540 List.541 List.542;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.263 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -12,45 +12,45 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.395 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.395;
|
||||
let Json.397 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.96 (Json.97, Json.397, Json.95):
|
||||
let Json.406 : I64 = 34i64;
|
||||
let Json.405 : U8 = CallByName Num.125 Json.406;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.97 Json.405;
|
||||
let Json.404 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.400 : List U8 = CallByName List.8 Json.403 Json.404;
|
||||
let Json.402 : I64 = 34i64;
|
||||
let Json.401 : U8 = CallByName Num.125 Json.402;
|
||||
let Json.399 : List U8 = CallByName List.4 Json.400 Json.401;
|
||||
ret Json.399;
|
||||
procedure Json.96 (Json.97, Json.399, Json.95):
|
||||
let Json.408 : I64 = 34i64;
|
||||
let Json.407 : U8 = CallByName Num.125 Json.408;
|
||||
let Json.405 : List U8 = CallByName List.4 Json.97 Json.407;
|
||||
let Json.406 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.402 : List U8 = CallByName List.8 Json.405 Json.406;
|
||||
let Json.404 : I64 = 34i64;
|
||||
let Json.403 : U8 = CallByName Num.125 Json.404;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.402 Json.403;
|
||||
ret Json.401;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.418 : U64 = 1i64;
|
||||
let List.417 : List U8 = CallByName List.70 List.105 List.418;
|
||||
let List.416 : List U8 = CallByName List.71 List.417 List.106;
|
||||
ret List.416;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.487 : U64 = 1i64;
|
||||
let List.486 : List U8 = CallByName List.70 List.106 List.487;
|
||||
let List.485 : List U8 = CallByName List.71 List.486 List.107;
|
||||
ret List.485;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
let List.484 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.484;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.419 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.419;
|
||||
let List.488 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.488;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.257 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -41,148 +41,148 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.126 (Json.127, Json.397, #Attr.12):
|
||||
procedure Json.126 (Json.127, Json.399, #Attr.12):
|
||||
let Json.125 : List Str = StructAtIndex 1 #Attr.12;
|
||||
inc Json.125;
|
||||
let Json.124 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.124;
|
||||
dec #Attr.12;
|
||||
let Json.435 : I64 = 123i64;
|
||||
let Json.437 : I64 = 123i64;
|
||||
let Json.436 : U8 = CallByName Num.125 Json.437;
|
||||
let Json.433 : List U8 = CallByName List.4 Json.127 Json.436;
|
||||
let Json.435 : I64 = 34i64;
|
||||
let Json.434 : U8 = CallByName Num.125 Json.435;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.127 Json.434;
|
||||
let Json.433 : I64 = 34i64;
|
||||
let Json.432 : U8 = CallByName Num.125 Json.433;
|
||||
let Json.429 : List U8 = CallByName List.4 Json.431 Json.432;
|
||||
let Json.430 : List U8 = CallByName Str.12 Json.124;
|
||||
let Json.426 : List U8 = CallByName List.8 Json.429 Json.430;
|
||||
let Json.428 : I64 = 34i64;
|
||||
let Json.427 : U8 = CallByName Num.125 Json.428;
|
||||
let Json.423 : List U8 = CallByName List.4 Json.426 Json.427;
|
||||
let Json.425 : I64 = 58i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 91i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.129 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : U64 = CallByName List.6 Json.125;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.129, Json.419};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.125 Json.407 Json.408;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.433 Json.434;
|
||||
let Json.432 : List U8 = CallByName Str.12 Json.124;
|
||||
let Json.428 : List U8 = CallByName List.8 Json.431 Json.432;
|
||||
let Json.430 : I64 = 34i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.425 : List U8 = CallByName List.4 Json.428 Json.429;
|
||||
let Json.427 : I64 = 58i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.422 : List U8 = CallByName List.4 Json.425 Json.426;
|
||||
let Json.424 : I64 = 91i64;
|
||||
let Json.423 : U8 = CallByName Num.125 Json.424;
|
||||
let Json.129 : List U8 = CallByName List.4 Json.422 Json.423;
|
||||
let Json.421 : U64 = CallByName List.6 Json.125;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.129, Json.421};
|
||||
let Json.410 : {} = Struct {};
|
||||
let Json.408 : {List U8, U64} = CallByName List.18 Json.125 Json.409 Json.410;
|
||||
dec Json.125;
|
||||
let Json.131 : List U8 = StructAtIndex 0 Json.406;
|
||||
let Json.131 : List U8 = StructAtIndex 0 Json.408;
|
||||
inc Json.131;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 93i64;
|
||||
dec Json.408;
|
||||
let Json.407 : I64 = 93i64;
|
||||
let Json.406 : U8 = CallByName Num.125 Json.407;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.131 Json.406;
|
||||
let Json.405 : I64 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.131 Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.400 : List U8 = CallByName List.4 Json.401 Json.402;
|
||||
ret Json.400;
|
||||
let Json.402 : List U8 = CallByName List.4 Json.403 Json.404;
|
||||
ret Json.402;
|
||||
|
||||
procedure Json.128 (Json.399, Json.134):
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.399;
|
||||
procedure Json.128 (Json.401, Json.134):
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.132;
|
||||
let Json.133 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.418 : {} = Struct {};
|
||||
let Json.135 : List U8 = CallByName Encode.23 Json.132 Json.134 Json.418;
|
||||
joinpoint Json.413 Json.136:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.133 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.136, Json.410};
|
||||
ret Json.409;
|
||||
let Json.133 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.420 : {} = Struct {};
|
||||
let Json.135 : List U8 = CallByName Encode.23 Json.132 Json.134 Json.420;
|
||||
joinpoint Json.415 Json.136:
|
||||
let Json.413 : U64 = 1i64;
|
||||
let Json.412 : U64 = CallByName Num.20 Json.133 Json.413;
|
||||
let Json.411 : {List U8, U64} = Struct {Json.136, Json.412};
|
||||
ret Json.411;
|
||||
in
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.133 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.135 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
let Json.419 : U64 = 1i64;
|
||||
let Json.416 : Int1 = CallByName Num.24 Json.133 Json.419;
|
||||
if Json.416 then
|
||||
let Json.418 : I64 = 44i64;
|
||||
let Json.417 : U8 = CallByName Num.125 Json.418;
|
||||
let Json.414 : List U8 = CallByName List.4 Json.135 Json.417;
|
||||
jump Json.415 Json.414;
|
||||
else
|
||||
jump Json.413 Json.135;
|
||||
jump Json.415 Json.135;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.436 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.436;
|
||||
let Json.438 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.438;
|
||||
|
||||
procedure Json.21 (Json.124, Json.125):
|
||||
let Json.396 : {Str, List Str} = Struct {Json.124, Json.125};
|
||||
let Json.395 : {Str, List Str} = CallByName Encode.22 Json.396;
|
||||
ret Json.395;
|
||||
let Json.398 : {Str, List Str} = Struct {Json.124, Json.125};
|
||||
let Json.397 : {Str, List Str} = CallByName Encode.22 Json.398;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.96 (Json.97, Json.438, Json.95):
|
||||
let Json.447 : I64 = 34i64;
|
||||
let Json.446 : U8 = CallByName Num.125 Json.447;
|
||||
let Json.444 : List U8 = CallByName List.4 Json.97 Json.446;
|
||||
let Json.445 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.441 : List U8 = CallByName List.8 Json.444 Json.445;
|
||||
let Json.443 : I64 = 34i64;
|
||||
let Json.442 : U8 = CallByName Num.125 Json.443;
|
||||
let Json.440 : List U8 = CallByName List.4 Json.441 Json.442;
|
||||
ret Json.440;
|
||||
procedure Json.96 (Json.97, Json.440, Json.95):
|
||||
let Json.449 : I64 = 34i64;
|
||||
let Json.448 : U8 = CallByName Num.125 Json.449;
|
||||
let Json.446 : List U8 = CallByName List.4 Json.97 Json.448;
|
||||
let Json.447 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.443 : List U8 = CallByName List.8 Json.446 Json.447;
|
||||
let Json.445 : I64 = 34i64;
|
||||
let Json.444 : U8 = CallByName Num.125 Json.445;
|
||||
let Json.442 : List U8 = CallByName List.4 Json.443 Json.444;
|
||||
ret Json.442;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.462 : {List U8, U64} = CallByName Json.128 List.138 List.139;
|
||||
ret List.462;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.531 : {List U8, U64} = CallByName Json.128 List.139 List.140;
|
||||
ret List.531;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.443 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.443;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.512 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.512;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.442 : U64 = 1i64;
|
||||
let List.441 : List U8 = CallByName List.70 List.105 List.442;
|
||||
let List.440 : List U8 = CallByName List.71 List.441 List.106;
|
||||
ret List.440;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.511 : U64 = 1i64;
|
||||
let List.510 : List U8 = CallByName List.70 List.106 List.511;
|
||||
let List.509 : List U8 = CallByName List.71 List.510 List.107;
|
||||
ret List.509;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.463 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.463;
|
||||
let List.532 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.532;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.459 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.459;
|
||||
let List.528 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.528;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
let List.484 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.484;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.465 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.465;
|
||||
let List.534 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.534;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.447 : U64 = 0i64;
|
||||
let List.448 : U64 = CallByName List.6 List.385;
|
||||
let List.446 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.447 List.448;
|
||||
ret List.446;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.516 : U64 = 0i64;
|
||||
let List.517 : U64 = CallByName List.6 List.426;
|
||||
let List.515 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.516 List.517;
|
||||
ret List.515;
|
||||
|
||||
procedure List.90 (List.475, List.476, List.477, List.478, List.479):
|
||||
joinpoint List.449 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.451 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.451 then
|
||||
let List.458 : Str = CallByName List.66 List.388 List.391;
|
||||
let List.452 : {List U8, U64} = CallByName List.137 List.389 List.458 List.390;
|
||||
let List.455 : U64 = 1i64;
|
||||
let List.454 : U64 = CallByName Num.19 List.391 List.455;
|
||||
jump List.449 List.388 List.452 List.390 List.454 List.392;
|
||||
procedure List.91 (List.544, List.545, List.546, List.547, List.548):
|
||||
joinpoint List.518 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.520 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.520 then
|
||||
let List.527 : Str = CallByName List.66 List.429 List.432;
|
||||
let List.521 : {List U8, U64} = CallByName List.138 List.430 List.527 List.431;
|
||||
let List.524 : U64 = 1i64;
|
||||
let List.523 : U64 = CallByName Num.19 List.432 List.524;
|
||||
jump List.518 List.429 List.521 List.431 List.523 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.449 List.475 List.476 List.477 List.478 List.479;
|
||||
jump List.518 List.544 List.545 List.546 List.547 List.548;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.265 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -47,148 +47,148 @@ procedure Encode.25 (Encode.100, Encode.101):
|
|||
ret Encode.103;
|
||||
|
||||
procedure Json.1 ():
|
||||
let Json.394 : {} = Struct {};
|
||||
ret Json.394;
|
||||
let Json.396 : {} = Struct {};
|
||||
ret Json.396;
|
||||
|
||||
procedure Json.126 (Json.127, Json.397, #Attr.12):
|
||||
procedure Json.126 (Json.127, Json.399, #Attr.12):
|
||||
let Json.125 : List Str = StructAtIndex 1 #Attr.12;
|
||||
inc Json.125;
|
||||
let Json.124 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.124;
|
||||
dec #Attr.12;
|
||||
let Json.435 : I64 = 123i64;
|
||||
let Json.437 : I64 = 123i64;
|
||||
let Json.436 : U8 = CallByName Num.125 Json.437;
|
||||
let Json.433 : List U8 = CallByName List.4 Json.127 Json.436;
|
||||
let Json.435 : I64 = 34i64;
|
||||
let Json.434 : U8 = CallByName Num.125 Json.435;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.127 Json.434;
|
||||
let Json.433 : I64 = 34i64;
|
||||
let Json.432 : U8 = CallByName Num.125 Json.433;
|
||||
let Json.429 : List U8 = CallByName List.4 Json.431 Json.432;
|
||||
let Json.430 : List U8 = CallByName Str.12 Json.124;
|
||||
let Json.426 : List U8 = CallByName List.8 Json.429 Json.430;
|
||||
let Json.428 : I64 = 34i64;
|
||||
let Json.427 : U8 = CallByName Num.125 Json.428;
|
||||
let Json.423 : List U8 = CallByName List.4 Json.426 Json.427;
|
||||
let Json.425 : I64 = 58i64;
|
||||
let Json.424 : U8 = CallByName Num.125 Json.425;
|
||||
let Json.420 : List U8 = CallByName List.4 Json.423 Json.424;
|
||||
let Json.422 : I64 = 91i64;
|
||||
let Json.421 : U8 = CallByName Num.125 Json.422;
|
||||
let Json.129 : List U8 = CallByName List.4 Json.420 Json.421;
|
||||
let Json.419 : U64 = CallByName List.6 Json.125;
|
||||
let Json.407 : {List U8, U64} = Struct {Json.129, Json.419};
|
||||
let Json.408 : {} = Struct {};
|
||||
let Json.406 : {List U8, U64} = CallByName List.18 Json.125 Json.407 Json.408;
|
||||
let Json.431 : List U8 = CallByName List.4 Json.433 Json.434;
|
||||
let Json.432 : List U8 = CallByName Str.12 Json.124;
|
||||
let Json.428 : List U8 = CallByName List.8 Json.431 Json.432;
|
||||
let Json.430 : I64 = 34i64;
|
||||
let Json.429 : U8 = CallByName Num.125 Json.430;
|
||||
let Json.425 : List U8 = CallByName List.4 Json.428 Json.429;
|
||||
let Json.427 : I64 = 58i64;
|
||||
let Json.426 : U8 = CallByName Num.125 Json.427;
|
||||
let Json.422 : List U8 = CallByName List.4 Json.425 Json.426;
|
||||
let Json.424 : I64 = 91i64;
|
||||
let Json.423 : U8 = CallByName Num.125 Json.424;
|
||||
let Json.129 : List U8 = CallByName List.4 Json.422 Json.423;
|
||||
let Json.421 : U64 = CallByName List.6 Json.125;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.129, Json.421};
|
||||
let Json.410 : {} = Struct {};
|
||||
let Json.408 : {List U8, U64} = CallByName List.18 Json.125 Json.409 Json.410;
|
||||
dec Json.125;
|
||||
let Json.131 : List U8 = StructAtIndex 0 Json.406;
|
||||
let Json.131 : List U8 = StructAtIndex 0 Json.408;
|
||||
inc Json.131;
|
||||
dec Json.406;
|
||||
let Json.405 : I64 = 93i64;
|
||||
dec Json.408;
|
||||
let Json.407 : I64 = 93i64;
|
||||
let Json.406 : U8 = CallByName Num.125 Json.407;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.131 Json.406;
|
||||
let Json.405 : I64 = 125i64;
|
||||
let Json.404 : U8 = CallByName Num.125 Json.405;
|
||||
let Json.401 : List U8 = CallByName List.4 Json.131 Json.404;
|
||||
let Json.403 : I64 = 125i64;
|
||||
let Json.402 : U8 = CallByName Num.125 Json.403;
|
||||
let Json.400 : List U8 = CallByName List.4 Json.401 Json.402;
|
||||
ret Json.400;
|
||||
let Json.402 : List U8 = CallByName List.4 Json.403 Json.404;
|
||||
ret Json.402;
|
||||
|
||||
procedure Json.128 (Json.399, Json.134):
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.399;
|
||||
procedure Json.128 (Json.401, Json.134):
|
||||
let Json.132 : List U8 = StructAtIndex 0 Json.401;
|
||||
inc Json.132;
|
||||
let Json.133 : U64 = StructAtIndex 1 Json.399;
|
||||
dec Json.399;
|
||||
let Json.418 : {} = Struct {};
|
||||
let Json.135 : List U8 = CallByName Encode.23 Json.132 Json.134 Json.418;
|
||||
joinpoint Json.413 Json.136:
|
||||
let Json.411 : U64 = 1i64;
|
||||
let Json.410 : U64 = CallByName Num.20 Json.133 Json.411;
|
||||
let Json.409 : {List U8, U64} = Struct {Json.136, Json.410};
|
||||
ret Json.409;
|
||||
let Json.133 : U64 = StructAtIndex 1 Json.401;
|
||||
dec Json.401;
|
||||
let Json.420 : {} = Struct {};
|
||||
let Json.135 : List U8 = CallByName Encode.23 Json.132 Json.134 Json.420;
|
||||
joinpoint Json.415 Json.136:
|
||||
let Json.413 : U64 = 1i64;
|
||||
let Json.412 : U64 = CallByName Num.20 Json.133 Json.413;
|
||||
let Json.411 : {List U8, U64} = Struct {Json.136, Json.412};
|
||||
ret Json.411;
|
||||
in
|
||||
let Json.417 : U64 = 1i64;
|
||||
let Json.414 : Int1 = CallByName Num.24 Json.133 Json.417;
|
||||
if Json.414 then
|
||||
let Json.416 : I64 = 44i64;
|
||||
let Json.415 : U8 = CallByName Num.125 Json.416;
|
||||
let Json.412 : List U8 = CallByName List.4 Json.135 Json.415;
|
||||
jump Json.413 Json.412;
|
||||
let Json.419 : U64 = 1i64;
|
||||
let Json.416 : Int1 = CallByName Num.24 Json.133 Json.419;
|
||||
if Json.416 then
|
||||
let Json.418 : I64 = 44i64;
|
||||
let Json.417 : U8 = CallByName Num.125 Json.418;
|
||||
let Json.414 : List U8 = CallByName List.4 Json.135 Json.417;
|
||||
jump Json.415 Json.414;
|
||||
else
|
||||
jump Json.413 Json.135;
|
||||
jump Json.415 Json.135;
|
||||
|
||||
procedure Json.18 (Json.95):
|
||||
let Json.448 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.448;
|
||||
let Json.450 : Str = CallByName Encode.22 Json.95;
|
||||
ret Json.450;
|
||||
|
||||
procedure Json.21 (Json.124, Json.125):
|
||||
let Json.396 : {Str, List Str} = Struct {Json.124, Json.125};
|
||||
let Json.395 : {Str, List Str} = CallByName Encode.22 Json.396;
|
||||
ret Json.395;
|
||||
let Json.398 : {Str, List Str} = Struct {Json.124, Json.125};
|
||||
let Json.397 : {Str, List Str} = CallByName Encode.22 Json.398;
|
||||
ret Json.397;
|
||||
|
||||
procedure Json.96 (Json.97, Json.438, Json.95):
|
||||
let Json.447 : I64 = 34i64;
|
||||
let Json.446 : U8 = CallByName Num.125 Json.447;
|
||||
let Json.444 : List U8 = CallByName List.4 Json.97 Json.446;
|
||||
let Json.445 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.441 : List U8 = CallByName List.8 Json.444 Json.445;
|
||||
let Json.443 : I64 = 34i64;
|
||||
let Json.442 : U8 = CallByName Num.125 Json.443;
|
||||
let Json.440 : List U8 = CallByName List.4 Json.441 Json.442;
|
||||
ret Json.440;
|
||||
procedure Json.96 (Json.97, Json.440, Json.95):
|
||||
let Json.449 : I64 = 34i64;
|
||||
let Json.448 : U8 = CallByName Num.125 Json.449;
|
||||
let Json.446 : List U8 = CallByName List.4 Json.97 Json.448;
|
||||
let Json.447 : List U8 = CallByName Str.12 Json.95;
|
||||
let Json.443 : List U8 = CallByName List.8 Json.446 Json.447;
|
||||
let Json.445 : I64 = 34i64;
|
||||
let Json.444 : U8 = CallByName Num.125 Json.445;
|
||||
let Json.442 : List U8 = CallByName List.4 Json.443 Json.444;
|
||||
ret Json.442;
|
||||
|
||||
procedure List.137 (List.138, List.139, List.136):
|
||||
let List.462 : {List U8, U64} = CallByName Json.128 List.138 List.139;
|
||||
ret List.462;
|
||||
procedure List.138 (List.139, List.140, List.137):
|
||||
let List.531 : {List U8, U64} = CallByName Json.128 List.139 List.140;
|
||||
ret List.531;
|
||||
|
||||
procedure List.18 (List.134, List.135, List.136):
|
||||
let List.443 : {List U8, U64} = CallByName List.89 List.134 List.135 List.136;
|
||||
ret List.443;
|
||||
procedure List.18 (List.135, List.136, List.137):
|
||||
let List.512 : {List U8, U64} = CallByName List.90 List.135 List.136 List.137;
|
||||
ret List.512;
|
||||
|
||||
procedure List.4 (List.105, List.106):
|
||||
let List.442 : U64 = 1i64;
|
||||
let List.441 : List U8 = CallByName List.70 List.105 List.442;
|
||||
let List.440 : List U8 = CallByName List.71 List.441 List.106;
|
||||
ret List.440;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.511 : U64 = 1i64;
|
||||
let List.510 : List U8 = CallByName List.70 List.106 List.511;
|
||||
let List.509 : List U8 = CallByName List.71 List.510 List.107;
|
||||
ret List.509;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.463 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.463;
|
||||
let List.532 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.532;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.459 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.459;
|
||||
let List.528 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.528;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.415 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.415;
|
||||
let List.484 : List U8 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.484;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.413 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.8 (#Attr.2, #Attr.3):
|
||||
let List.465 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.465;
|
||||
let List.534 : List U8 = lowlevel ListConcat #Attr.2 #Attr.3;
|
||||
ret List.534;
|
||||
|
||||
procedure List.89 (List.385, List.386, List.387):
|
||||
let List.447 : U64 = 0i64;
|
||||
let List.448 : U64 = CallByName List.6 List.385;
|
||||
let List.446 : {List U8, U64} = CallByName List.90 List.385 List.386 List.387 List.447 List.448;
|
||||
ret List.446;
|
||||
procedure List.90 (List.426, List.427, List.428):
|
||||
let List.516 : U64 = 0i64;
|
||||
let List.517 : U64 = CallByName List.6 List.426;
|
||||
let List.515 : {List U8, U64} = CallByName List.91 List.426 List.427 List.428 List.516 List.517;
|
||||
ret List.515;
|
||||
|
||||
procedure List.90 (List.475, List.476, List.477, List.478, List.479):
|
||||
joinpoint List.449 List.388 List.389 List.390 List.391 List.392:
|
||||
let List.451 : Int1 = CallByName Num.22 List.391 List.392;
|
||||
if List.451 then
|
||||
let List.458 : Str = CallByName List.66 List.388 List.391;
|
||||
let List.452 : {List U8, U64} = CallByName List.137 List.389 List.458 List.390;
|
||||
let List.455 : U64 = 1i64;
|
||||
let List.454 : U64 = CallByName Num.19 List.391 List.455;
|
||||
jump List.449 List.388 List.452 List.390 List.454 List.392;
|
||||
procedure List.91 (List.544, List.545, List.546, List.547, List.548):
|
||||
joinpoint List.518 List.429 List.430 List.431 List.432 List.433:
|
||||
let List.520 : Int1 = CallByName Num.22 List.432 List.433;
|
||||
if List.520 then
|
||||
let List.527 : Str = CallByName List.66 List.429 List.432;
|
||||
let List.521 : {List U8, U64} = CallByName List.138 List.430 List.527 List.431;
|
||||
let List.524 : U64 = 1i64;
|
||||
let List.523 : U64 = CallByName Num.19 List.432 List.524;
|
||||
jump List.518 List.429 List.521 List.431 List.523 List.433;
|
||||
else
|
||||
ret List.389;
|
||||
ret List.430;
|
||||
in
|
||||
jump List.449 List.475 List.476 List.477 List.478 List.479;
|
||||
jump List.518 List.544 List.545 List.546 List.547 List.548;
|
||||
|
||||
procedure Num.125 (#Attr.2):
|
||||
let Num.265 : U8 = lowlevel NumIntCast #Attr.2;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.258 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
|
|
@ -6,40 +6,40 @@ procedure Bool.2 ():
|
|||
let Bool.23 : Int1 = true;
|
||||
ret Bool.23;
|
||||
|
||||
procedure List.2 (List.94, List.95):
|
||||
let List.423 : U64 = CallByName List.6 List.94;
|
||||
let List.419 : Int1 = CallByName Num.22 List.95 List.423;
|
||||
if List.419 then
|
||||
let List.421 : I64 = CallByName List.66 List.94 List.95;
|
||||
let List.420 : [C {}, C I64] = TagId(1) List.421;
|
||||
ret List.420;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.492 : U64 = CallByName List.6 List.95;
|
||||
let List.488 : Int1 = CallByName Num.22 List.96 List.492;
|
||||
if List.488 then
|
||||
let List.490 : I64 = CallByName List.66 List.95 List.96;
|
||||
let List.489 : [C {}, C I64] = TagId(1) List.490;
|
||||
ret List.489;
|
||||
else
|
||||
let List.418 : {} = Struct {};
|
||||
let List.417 : [C {}, C I64] = TagId(0) List.418;
|
||||
ret List.417;
|
||||
let List.487 : {} = Struct {};
|
||||
let List.486 : [C {}, C I64] = TagId(0) List.487;
|
||||
ret List.486;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.424 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.424;
|
||||
let List.493 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.493;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.422 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.422;
|
||||
let List.491 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.491;
|
||||
|
||||
procedure List.9 (List.242):
|
||||
let List.416 : U64 = 0i64;
|
||||
let List.409 : [C {}, C I64] = CallByName List.2 List.242 List.416;
|
||||
let List.413 : U8 = 1i64;
|
||||
let List.414 : U8 = GetTagId List.409;
|
||||
let List.415 : Int1 = lowlevel Eq List.413 List.414;
|
||||
if List.415 then
|
||||
let List.243 : I64 = UnionAtIndex (Id 1) (Index 0) List.409;
|
||||
let List.410 : [C Int1, C I64] = TagId(1) List.243;
|
||||
ret List.410;
|
||||
procedure List.9 (List.283):
|
||||
let List.485 : U64 = 0i64;
|
||||
let List.478 : [C {}, C I64] = CallByName List.2 List.283 List.485;
|
||||
let List.482 : U8 = 1i64;
|
||||
let List.483 : U8 = GetTagId List.478;
|
||||
let List.484 : Int1 = lowlevel Eq List.482 List.483;
|
||||
if List.484 then
|
||||
let List.284 : I64 = UnionAtIndex (Id 1) (Index 0) List.478;
|
||||
let List.479 : [C Int1, C I64] = TagId(1) List.284;
|
||||
ret List.479;
|
||||
else
|
||||
let List.412 : Int1 = true;
|
||||
let List.411 : [C Int1, C I64] = TagId(0) List.412;
|
||||
ret List.411;
|
||||
let List.481 : Int1 = true;
|
||||
let List.480 : [C Int1, C I64] = TagId(0) List.481;
|
||||
ret List.480;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
14
crates/compiler/test_mono/generated/issue_4705.txt
Normal file
14
crates/compiler/test_mono/generated/issue_4705.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
procedure Bool.2 ():
|
||||
let Bool.23 : Int1 = true;
|
||||
ret Bool.23;
|
||||
|
||||
procedure Test.0 (Test.4):
|
||||
let Test.7 : Int1 = CallByName Bool.2;
|
||||
ret Test.7;
|
||||
|
||||
procedure Test.3 ():
|
||||
let Test.1 : {} = Struct {};
|
||||
let Test.2 : Int1 = CallByName Test.0 Test.1;
|
||||
expect Test.2;
|
||||
let Test.5 : {} = Struct {};
|
||||
ret Test.5;
|
|
@ -1,16 +1,16 @@
|
|||
procedure List.4 (List.105, List.106):
|
||||
let List.412 : U64 = 1i64;
|
||||
let List.410 : List I64 = CallByName List.70 List.105 List.412;
|
||||
let List.409 : List I64 = CallByName List.71 List.410 List.106;
|
||||
ret List.409;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.481 : U64 = 1i64;
|
||||
let List.479 : List I64 = CallByName List.70 List.106 List.481;
|
||||
let List.478 : List I64 = CallByName List.71 List.479 List.107;
|
||||
ret List.478;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.413 : List I64 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List I64 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.411 : List I64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.411;
|
||||
let List.480 : List I64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.480;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.2 : List I64 = Array [1i64];
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
procedure List.4 (List.105, List.106):
|
||||
let List.412 : U64 = 1i64;
|
||||
let List.410 : List I64 = CallByName List.70 List.105 List.412;
|
||||
let List.409 : List I64 = CallByName List.71 List.410 List.106;
|
||||
ret List.409;
|
||||
procedure List.4 (List.106, List.107):
|
||||
let List.481 : U64 = 1i64;
|
||||
let List.479 : List I64 = CallByName List.70 List.106 List.481;
|
||||
let List.478 : List I64 = CallByName List.71 List.479 List.107;
|
||||
ret List.478;
|
||||
|
||||
procedure List.70 (#Attr.2, #Attr.3):
|
||||
let List.413 : List I64 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.413;
|
||||
let List.482 : List I64 = lowlevel ListReserve #Attr.2 #Attr.3;
|
||||
ret List.482;
|
||||
|
||||
procedure List.71 (#Attr.2, #Attr.3):
|
||||
let List.411 : List I64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.411;
|
||||
let List.480 : List I64 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.480;
|
||||
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.6 : I64 = 42i64;
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
procedure List.3 (List.102, List.103, List.104):
|
||||
let List.412 : {List I64, I64} = CallByName List.64 List.102 List.103 List.104;
|
||||
let List.411 : List I64 = StructAtIndex 0 List.412;
|
||||
inc List.411;
|
||||
dec List.412;
|
||||
ret List.411;
|
||||
procedure List.3 (List.103, List.104, List.105):
|
||||
let List.481 : {List I64, I64} = CallByName List.64 List.103 List.104 List.105;
|
||||
let List.480 : List I64 = StructAtIndex 0 List.481;
|
||||
inc List.480;
|
||||
dec List.481;
|
||||
ret List.480;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.410 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.410;
|
||||
let List.479 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.479;
|
||||
|
||||
procedure List.64 (List.99, List.100, List.101):
|
||||
let List.417 : U64 = CallByName List.6 List.99;
|
||||
let List.414 : Int1 = CallByName Num.22 List.100 List.417;
|
||||
if List.414 then
|
||||
let List.415 : {List I64, I64} = CallByName List.67 List.99 List.100 List.101;
|
||||
ret List.415;
|
||||
procedure List.64 (List.100, List.101, List.102):
|
||||
let List.486 : U64 = CallByName List.6 List.100;
|
||||
let List.483 : Int1 = CallByName Num.22 List.101 List.486;
|
||||
if List.483 then
|
||||
let List.484 : {List I64, I64} = CallByName List.67 List.100 List.101 List.102;
|
||||
ret List.484;
|
||||
else
|
||||
let List.413 : {List I64, I64} = Struct {List.99, List.101};
|
||||
ret List.413;
|
||||
let List.482 : {List I64, I64} = Struct {List.100, List.102};
|
||||
ret List.482;
|
||||
|
||||
procedure List.67 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.416 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.416;
|
||||
let List.485 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.485;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.256 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
procedure List.2 (List.94, List.95):
|
||||
let List.415 : U64 = CallByName List.6 List.94;
|
||||
let List.411 : Int1 = CallByName Num.22 List.95 List.415;
|
||||
if List.411 then
|
||||
let List.413 : I64 = CallByName List.66 List.94 List.95;
|
||||
let List.412 : [C {}, C I64] = TagId(1) List.413;
|
||||
ret List.412;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.484 : U64 = CallByName List.6 List.95;
|
||||
let List.480 : Int1 = CallByName Num.22 List.96 List.484;
|
||||
if List.480 then
|
||||
let List.482 : I64 = CallByName List.66 List.95 List.96;
|
||||
let List.481 : [C {}, C I64] = TagId(1) List.482;
|
||||
ret List.481;
|
||||
else
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : [C {}, C I64] = TagId(0) List.410;
|
||||
ret List.409;
|
||||
let List.479 : {} = Struct {};
|
||||
let List.478 : [C {}, C I64] = TagId(0) List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.414 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.414;
|
||||
let List.483 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
procedure List.6 (#Attr.2):
|
||||
let List.409 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.409;
|
||||
let List.478 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.410 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.410;
|
||||
let List.479 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.479;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.256 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
procedure List.2 (List.94, List.95):
|
||||
let List.415 : U64 = CallByName List.6 List.94;
|
||||
let List.411 : Int1 = CallByName Num.22 List.95 List.415;
|
||||
if List.411 then
|
||||
let List.413 : Str = CallByName List.66 List.94 List.95;
|
||||
let List.412 : [C {}, C Str] = TagId(1) List.413;
|
||||
ret List.412;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.484 : U64 = CallByName List.6 List.95;
|
||||
let List.480 : Int1 = CallByName Num.22 List.96 List.484;
|
||||
if List.480 then
|
||||
let List.482 : Str = CallByName List.66 List.95 List.96;
|
||||
let List.481 : [C {}, C Str] = TagId(1) List.482;
|
||||
ret List.481;
|
||||
else
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : [C {}, C Str] = TagId(0) List.410;
|
||||
ret List.409;
|
||||
let List.479 : {} = Struct {};
|
||||
let List.478 : [C {}, C Str] = TagId(0) List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.417 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
ret List.417;
|
||||
let List.486 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
ret List.486;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.414 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.414;
|
||||
let List.483 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
procedure List.2 (List.94, List.95):
|
||||
let List.415 : U64 = CallByName List.6 List.94;
|
||||
let List.411 : Int1 = CallByName Num.22 List.95 List.415;
|
||||
if List.411 then
|
||||
let List.413 : Str = CallByName List.66 List.94 List.95;
|
||||
let List.412 : [C {}, C Str] = TagId(1) List.413;
|
||||
ret List.412;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.484 : U64 = CallByName List.6 List.95;
|
||||
let List.480 : Int1 = CallByName Num.22 List.96 List.484;
|
||||
if List.480 then
|
||||
let List.482 : Str = CallByName List.66 List.95 List.96;
|
||||
let List.481 : [C {}, C Str] = TagId(1) List.482;
|
||||
ret List.481;
|
||||
else
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : [C {}, C Str] = TagId(0) List.410;
|
||||
ret List.409;
|
||||
let List.479 : {} = Struct {};
|
||||
let List.478 : [C {}, C Str] = TagId(0) List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.5 (#Attr.2, #Attr.3):
|
||||
let List.417 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
let List.486 : List Str = lowlevel ListMap { xs: `#Attr.#arg1` } #Attr.2 Test.3 #Attr.3;
|
||||
decref #Attr.2;
|
||||
ret List.417;
|
||||
ret List.486;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.414 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.414;
|
||||
let List.483 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
procedure Test.0 ():
|
||||
let Test.6 : Str = "";
|
||||
let Test.1 : List Str = Array [Test.6];
|
||||
let Test.5 : U64 = lowlevel ListLen Test.1;
|
||||
dec Test.1;
|
||||
switch Test.5:
|
||||
case 0:
|
||||
let Test.2 : Str = "A";
|
||||
ret Test.2;
|
||||
|
||||
case 1:
|
||||
let Test.3 : Str = "B";
|
||||
ret Test.3;
|
||||
|
||||
default:
|
||||
let Test.4 : Str = "C";
|
||||
ret Test.4;
|
||||
|
|
@ -1,27 +1,27 @@
|
|||
procedure List.3 (List.102, List.103, List.104):
|
||||
let List.410 : {List I64, I64} = CallByName List.64 List.102 List.103 List.104;
|
||||
let List.409 : List I64 = StructAtIndex 0 List.410;
|
||||
inc List.409;
|
||||
dec List.410;
|
||||
ret List.409;
|
||||
procedure List.3 (List.103, List.104, List.105):
|
||||
let List.479 : {List I64, I64} = CallByName List.64 List.103 List.104 List.105;
|
||||
let List.478 : List I64 = StructAtIndex 0 List.479;
|
||||
inc List.478;
|
||||
dec List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.64 (List.99, List.100, List.101):
|
||||
let List.415 : U64 = CallByName List.6 List.99;
|
||||
let List.412 : Int1 = CallByName Num.22 List.100 List.415;
|
||||
if List.412 then
|
||||
let List.413 : {List I64, I64} = CallByName List.67 List.99 List.100 List.101;
|
||||
ret List.413;
|
||||
procedure List.64 (List.100, List.101, List.102):
|
||||
let List.484 : U64 = CallByName List.6 List.100;
|
||||
let List.481 : Int1 = CallByName Num.22 List.101 List.484;
|
||||
if List.481 then
|
||||
let List.482 : {List I64, I64} = CallByName List.67 List.100 List.101 List.102;
|
||||
ret List.482;
|
||||
else
|
||||
let List.411 : {List I64, I64} = Struct {List.99, List.101};
|
||||
ret List.411;
|
||||
let List.480 : {List I64, I64} = Struct {List.100, List.102};
|
||||
ret List.480;
|
||||
|
||||
procedure List.67 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.414 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.414;
|
||||
let List.483 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.256 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
procedure List.28 (#Attr.2, #Attr.3):
|
||||
let List.411 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
|
||||
let List.480 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
|
||||
let #Derived_gen.0 : Int1 = lowlevel ListIsUnique #Attr.2;
|
||||
if #Derived_gen.0 then
|
||||
ret List.411;
|
||||
ret List.480;
|
||||
else
|
||||
decref #Attr.2;
|
||||
ret List.411;
|
||||
ret List.480;
|
||||
|
||||
procedure List.59 (List.237):
|
||||
let List.410 : {} = Struct {};
|
||||
let List.409 : List I64 = CallByName List.28 List.237 List.410;
|
||||
ret List.409;
|
||||
procedure List.59 (List.278):
|
||||
let List.479 : {} = Struct {};
|
||||
let List.478 : List I64 = CallByName List.28 List.278 List.479;
|
||||
ret List.478;
|
||||
|
||||
procedure Num.46 (#Attr.2, #Attr.3):
|
||||
let Num.256 : U8 = lowlevel NumCompare #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,52 +1,49 @@
|
|||
procedure Test.0 ():
|
||||
let Test.36 : Int1 = false;
|
||||
let Test.37 : Int1 = true;
|
||||
let Test.1 : List Int1 = Array [Test.36, Test.37];
|
||||
joinpoint Test.10:
|
||||
let Test.31 : Int1 = false;
|
||||
let Test.32 : Int1 = true;
|
||||
let Test.1 : List Int1 = Array [Test.31, Test.32];
|
||||
joinpoint Test.9:
|
||||
let Test.8 : Str = "E";
|
||||
ret Test.8;
|
||||
in
|
||||
joinpoint Test.9:
|
||||
let Test.5 : Str = "B";
|
||||
ret Test.5;
|
||||
in
|
||||
let Test.33 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.34 : U64 = 0i64;
|
||||
let Test.35 : Int1 = lowlevel Eq Test.33 Test.34;
|
||||
if Test.35 then
|
||||
let Test.28 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.29 : U64 = 0i64;
|
||||
let Test.30 : Int1 = lowlevel Eq Test.28 Test.29;
|
||||
if Test.30 then
|
||||
dec Test.1;
|
||||
let Test.4 : Str = "A";
|
||||
ret Test.4;
|
||||
else
|
||||
let Test.30 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.31 : U64 = 1i64;
|
||||
let Test.32 : Int1 = lowlevel Eq Test.30 Test.31;
|
||||
if Test.32 then
|
||||
let Test.11 : U64 = 0i64;
|
||||
let Test.12 : Int1 = lowlevel ListGetUnsafe Test.1 Test.11;
|
||||
let Test.25 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.26 : U64 = 1i64;
|
||||
let Test.27 : Int1 = lowlevel Eq Test.25 Test.26;
|
||||
if Test.27 then
|
||||
let Test.10 : U64 = 0i64;
|
||||
let Test.11 : Int1 = lowlevel ListGetUnsafe Test.1 Test.10;
|
||||
dec Test.1;
|
||||
let Test.13 : Int1 = false;
|
||||
let Test.14 : Int1 = lowlevel Eq Test.13 Test.12;
|
||||
if Test.14 then
|
||||
jump Test.9;
|
||||
let Test.12 : Int1 = false;
|
||||
let Test.13 : Int1 = lowlevel Eq Test.12 Test.11;
|
||||
if Test.13 then
|
||||
let Test.5 : Str = "B";
|
||||
ret Test.5;
|
||||
else
|
||||
jump Test.10;
|
||||
jump Test.9;
|
||||
else
|
||||
let Test.27 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.28 : U64 = 2i64;
|
||||
let Test.29 : Int1 = lowlevel NumGte Test.27 Test.28;
|
||||
if Test.29 then
|
||||
let Test.19 : U64 = 0i64;
|
||||
let Test.20 : Int1 = lowlevel ListGetUnsafe Test.1 Test.19;
|
||||
let Test.21 : Int1 = false;
|
||||
let Test.22 : Int1 = lowlevel Eq Test.21 Test.20;
|
||||
if Test.22 then
|
||||
let Test.15 : U64 = 1i64;
|
||||
let Test.16 : Int1 = lowlevel ListGetUnsafe Test.1 Test.15;
|
||||
let Test.22 : U64 = lowlevel ListLen Test.1;
|
||||
let Test.23 : U64 = 2i64;
|
||||
let Test.24 : Int1 = lowlevel NumGte Test.22 Test.23;
|
||||
if Test.24 then
|
||||
let Test.18 : U64 = 0i64;
|
||||
let Test.19 : Int1 = lowlevel ListGetUnsafe Test.1 Test.18;
|
||||
let Test.20 : Int1 = false;
|
||||
let Test.21 : Int1 = lowlevel Eq Test.20 Test.19;
|
||||
if Test.21 then
|
||||
let Test.14 : U64 = 1i64;
|
||||
let Test.15 : Int1 = lowlevel ListGetUnsafe Test.1 Test.14;
|
||||
dec Test.1;
|
||||
let Test.17 : Int1 = false;
|
||||
let Test.18 : Int1 = lowlevel Eq Test.17 Test.16;
|
||||
if Test.18 then
|
||||
let Test.16 : Int1 = false;
|
||||
let Test.17 : Int1 = lowlevel Eq Test.16 Test.15;
|
||||
if Test.17 then
|
||||
let Test.6 : Str = "C";
|
||||
ret Test.6;
|
||||
else
|
||||
|
@ -54,14 +51,7 @@ procedure Test.0 ():
|
|||
ret Test.7;
|
||||
else
|
||||
dec Test.1;
|
||||
jump Test.10;
|
||||
else
|
||||
let Test.23 : U64 = 0i64;
|
||||
let Test.24 : Int1 = lowlevel ListGetUnsafe Test.1 Test.23;
|
||||
dec Test.1;
|
||||
let Test.25 : Int1 = false;
|
||||
let Test.26 : Int1 = lowlevel Eq Test.25 Test.24;
|
||||
if Test.26 then
|
||||
jump Test.9;
|
||||
else
|
||||
jump Test.10;
|
||||
else
|
||||
dec Test.1;
|
||||
jump Test.9;
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
procedure List.2 (List.94, List.95):
|
||||
let List.431 : U64 = CallByName List.6 List.94;
|
||||
let List.428 : Int1 = CallByName Num.22 List.95 List.431;
|
||||
if List.428 then
|
||||
let List.430 : I64 = CallByName List.66 List.94 List.95;
|
||||
let List.429 : [C {}, C I64] = TagId(1) List.430;
|
||||
ret List.429;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.500 : U64 = CallByName List.6 List.95;
|
||||
let List.497 : Int1 = CallByName Num.22 List.96 List.500;
|
||||
if List.497 then
|
||||
let List.499 : I64 = CallByName List.66 List.95 List.96;
|
||||
let List.498 : [C {}, C I64] = TagId(1) List.499;
|
||||
ret List.498;
|
||||
else
|
||||
let List.427 : {} = Struct {};
|
||||
let List.426 : [C {}, C I64] = TagId(0) List.427;
|
||||
ret List.426;
|
||||
let List.496 : {} = Struct {};
|
||||
let List.495 : [C {}, C I64] = TagId(0) List.496;
|
||||
ret List.495;
|
||||
|
||||
procedure List.3 (List.102, List.103, List.104):
|
||||
let List.418 : {List I64, I64} = CallByName List.64 List.102 List.103 List.104;
|
||||
let List.417 : List I64 = StructAtIndex 0 List.418;
|
||||
inc List.417;
|
||||
dec List.418;
|
||||
ret List.417;
|
||||
procedure List.3 (List.103, List.104, List.105):
|
||||
let List.487 : {List I64, I64} = CallByName List.64 List.103 List.104 List.105;
|
||||
let List.486 : List I64 = StructAtIndex 0 List.487;
|
||||
inc List.486;
|
||||
dec List.487;
|
||||
ret List.486;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.64 (List.99, List.100, List.101):
|
||||
let List.415 : U64 = CallByName List.6 List.99;
|
||||
let List.412 : Int1 = CallByName Num.22 List.100 List.415;
|
||||
if List.412 then
|
||||
let List.413 : {List I64, I64} = CallByName List.67 List.99 List.100 List.101;
|
||||
ret List.413;
|
||||
procedure List.64 (List.100, List.101, List.102):
|
||||
let List.484 : U64 = CallByName List.6 List.100;
|
||||
let List.481 : Int1 = CallByName Num.22 List.101 List.484;
|
||||
if List.481 then
|
||||
let List.482 : {List I64, I64} = CallByName List.67 List.100 List.101 List.102;
|
||||
ret List.482;
|
||||
else
|
||||
let List.411 : {List I64, I64} = Struct {List.99, List.101};
|
||||
ret List.411;
|
||||
let List.480 : {List I64, I64} = Struct {List.100, List.102};
|
||||
ret List.480;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.424 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.424;
|
||||
let List.493 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.493;
|
||||
|
||||
procedure List.67 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.414 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.414;
|
||||
let List.483 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.258 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
procedure List.2 (List.94, List.95):
|
||||
let List.431 : U64 = CallByName List.6 List.94;
|
||||
let List.428 : Int1 = CallByName Num.22 List.95 List.431;
|
||||
if List.428 then
|
||||
let List.430 : I64 = CallByName List.66 List.94 List.95;
|
||||
let List.429 : [C {}, C I64] = TagId(1) List.430;
|
||||
ret List.429;
|
||||
procedure List.2 (List.95, List.96):
|
||||
let List.500 : U64 = CallByName List.6 List.95;
|
||||
let List.497 : Int1 = CallByName Num.22 List.96 List.500;
|
||||
if List.497 then
|
||||
let List.499 : I64 = CallByName List.66 List.95 List.96;
|
||||
let List.498 : [C {}, C I64] = TagId(1) List.499;
|
||||
ret List.498;
|
||||
else
|
||||
let List.427 : {} = Struct {};
|
||||
let List.426 : [C {}, C I64] = TagId(0) List.427;
|
||||
ret List.426;
|
||||
let List.496 : {} = Struct {};
|
||||
let List.495 : [C {}, C I64] = TagId(0) List.496;
|
||||
ret List.495;
|
||||
|
||||
procedure List.3 (List.102, List.103, List.104):
|
||||
let List.418 : {List I64, I64} = CallByName List.64 List.102 List.103 List.104;
|
||||
let List.417 : List I64 = StructAtIndex 0 List.418;
|
||||
inc List.417;
|
||||
dec List.418;
|
||||
ret List.417;
|
||||
procedure List.3 (List.103, List.104, List.105):
|
||||
let List.487 : {List I64, I64} = CallByName List.64 List.103 List.104 List.105;
|
||||
let List.486 : List I64 = StructAtIndex 0 List.487;
|
||||
inc List.486;
|
||||
dec List.487;
|
||||
ret List.486;
|
||||
|
||||
procedure List.6 (#Attr.2):
|
||||
let List.416 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.416;
|
||||
let List.485 : U64 = lowlevel ListLen #Attr.2;
|
||||
ret List.485;
|
||||
|
||||
procedure List.64 (List.99, List.100, List.101):
|
||||
let List.415 : U64 = CallByName List.6 List.99;
|
||||
let List.412 : Int1 = CallByName Num.22 List.100 List.415;
|
||||
if List.412 then
|
||||
let List.413 : {List I64, I64} = CallByName List.67 List.99 List.100 List.101;
|
||||
ret List.413;
|
||||
procedure List.64 (List.100, List.101, List.102):
|
||||
let List.484 : U64 = CallByName List.6 List.100;
|
||||
let List.481 : Int1 = CallByName Num.22 List.101 List.484;
|
||||
if List.481 then
|
||||
let List.482 : {List I64, I64} = CallByName List.67 List.100 List.101 List.102;
|
||||
ret List.482;
|
||||
else
|
||||
let List.411 : {List I64, I64} = Struct {List.99, List.101};
|
||||
ret List.411;
|
||||
let List.480 : {List I64, I64} = Struct {List.100, List.102};
|
||||
ret List.480;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.424 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.424;
|
||||
let List.493 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.493;
|
||||
|
||||
procedure List.67 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let List.414 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.414;
|
||||
let List.483 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
|
||||
ret List.483;
|
||||
|
||||
procedure Num.22 (#Attr.2, #Attr.3):
|
||||
let Num.258 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
|
||||
|
|
|
@ -13,11 +13,13 @@ extern crate indoc;
|
|||
#[allow(dead_code)]
|
||||
const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_load::ExecutionMode;
|
||||
use roc_load::LoadConfig;
|
||||
use roc_load::LoadMonomorphizedError;
|
||||
use roc_load::Threading;
|
||||
use roc_module::symbol::Interns;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::ir::Proc;
|
||||
use roc_mono::ir::ProcLayout;
|
||||
|
@ -74,11 +76,16 @@ fn promote_expr_to_module(src: &str) -> String {
|
|||
buffer
|
||||
}
|
||||
|
||||
fn compiles_to_ir(test_name: &str, src: &str) {
|
||||
use bumpalo::Bump;
|
||||
fn compiles_to_ir(test_name: &str, src: &str, mode: &str, no_check: bool) {
|
||||
use roc_packaging::cache::RocCacheDir;
|
||||
use std::path::PathBuf;
|
||||
|
||||
let exec_mode = match mode {
|
||||
"exec" => ExecutionMode::Executable,
|
||||
"test" => ExecutionMode::Test,
|
||||
_ => panic!("Invalid test_mono exec mode {mode}"),
|
||||
};
|
||||
|
||||
let arena = &Bump::new();
|
||||
|
||||
let filename = PathBuf::from("Test.roc");
|
||||
|
@ -86,7 +93,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
|||
|
||||
let module_src;
|
||||
let temp;
|
||||
if src.starts_with("app") {
|
||||
if src.starts_with("app") || src.starts_with("interface") {
|
||||
// this is already a module
|
||||
module_src = src;
|
||||
} else {
|
||||
|
@ -100,7 +107,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
|||
threading: Threading::Single,
|
||||
render: roc_reporting::report::RenderTarget::Generic,
|
||||
palette: roc_reporting::report::DEFAULT_PALETTE,
|
||||
exec_mode: ExecutionMode::Executable,
|
||||
exec_mode,
|
||||
};
|
||||
let loaded = roc_load::load_and_monomorphize_from_str(
|
||||
arena,
|
||||
|
@ -129,6 +136,7 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
|||
procedures,
|
||||
exposed_to_host,
|
||||
layout_interner,
|
||||
interns,
|
||||
..
|
||||
} = loaded;
|
||||
|
||||
|
@ -141,33 +149,54 @@ fn compiles_to_ir(test_name: &str, src: &str) {
|
|||
|
||||
assert!(type_problems.is_empty());
|
||||
|
||||
debug_assert_eq!(exposed_to_host.values.len(), 1);
|
||||
let main_fn_symbol = exposed_to_host.values.keys().copied().next();
|
||||
|
||||
let main_fn_symbol = exposed_to_host.values.keys().copied().next().unwrap();
|
||||
if !no_check {
|
||||
check_procedures(arena, &interns, &layout_interner, &procedures);
|
||||
}
|
||||
|
||||
verify_procedures(test_name, layout_interner, procedures, main_fn_symbol);
|
||||
}
|
||||
|
||||
fn check_procedures<'a>(
|
||||
arena: &'a Bump,
|
||||
interns: &Interns,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
procedures: &MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
) {
|
||||
use roc_mono::debug::{check_procs, format_problems};
|
||||
let problems = check_procs(arena, interner, procedures);
|
||||
if problems.is_empty() {
|
||||
return;
|
||||
}
|
||||
let formatted = format_problems(interns, interner, problems);
|
||||
panic!("IR problems found:\n{formatted}");
|
||||
}
|
||||
|
||||
fn verify_procedures<'a>(
|
||||
test_name: &str,
|
||||
interner: STLayoutInterner<'a>,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
main_fn_symbol: Symbol,
|
||||
opt_main_fn_symbol: Option<Symbol>,
|
||||
) {
|
||||
let index = procedures
|
||||
.keys()
|
||||
.position(|(s, _)| *s == main_fn_symbol)
|
||||
.unwrap();
|
||||
|
||||
let mut procs_string = procedures
|
||||
.values()
|
||||
.map(|proc| proc.to_pretty(&interner, 200))
|
||||
.map(|proc| proc.to_pretty(&interner, 200, false))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let main_fn = procs_string.swap_remove(index);
|
||||
let opt_main_fn = opt_main_fn_symbol.map(|main_fn_symbol| {
|
||||
let index = procedures
|
||||
.keys()
|
||||
.position(|(s, _)| *s == main_fn_symbol)
|
||||
.unwrap();
|
||||
procs_string.swap_remove(index)
|
||||
});
|
||||
|
||||
procs_string.sort();
|
||||
procs_string.push(main_fn);
|
||||
|
||||
if let Some(main_fn) = opt_main_fn {
|
||||
procs_string.push(main_fn);
|
||||
}
|
||||
|
||||
let result = procs_string.join("\n");
|
||||
|
||||
|
@ -564,7 +593,7 @@ fn record_optional_field_function_use_default() {
|
|||
"#
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
#[mono_test(no_check)]
|
||||
fn quicksort_help() {
|
||||
// do we still need with_larger_debug_stack?
|
||||
r#"
|
||||
|
@ -1282,7 +1311,7 @@ fn issue_2583_specialize_errors_behind_unified_branches() {
|
|||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
#[mono_test(no_check)]
|
||||
fn issue_2810() {
|
||||
indoc!(
|
||||
r#"
|
||||
|
@ -2099,3 +2128,34 @@ fn toplevel_accessor_fn_thunk() {
|
|||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn list_one_vs_one_spread_issue_4685() {
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
main = when [""] is
|
||||
[] -> "A"
|
||||
[_] -> "B"
|
||||
[_, ..] -> "C"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test(mode = "test")]
|
||||
fn issue_4705() {
|
||||
indoc!(
|
||||
r###"
|
||||
interface Test exposes [] imports []
|
||||
|
||||
go : {} -> Bool
|
||||
go = \{} -> Bool.true
|
||||
|
||||
expect
|
||||
input = {}
|
||||
x = go input
|
||||
x
|
||||
"###
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,26 @@ use proc_macro::TokenStream;
|
|||
use quote::quote;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn mono_test(_args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
pub fn mono_test(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let mut no_check = false;
|
||||
let mut mode = "exec".to_owned();
|
||||
for arg in syn::parse_macro_input!(args as syn::AttributeArgs) {
|
||||
use syn::{Lit, Meta, MetaNameValue, NestedMeta};
|
||||
if matches!(&arg, NestedMeta::Meta(Meta::Path(p)) if p.is_ident("no_check")) {
|
||||
no_check = true;
|
||||
}
|
||||
if let NestedMeta::Meta(Meta::NameValue(MetaNameValue {
|
||||
path,
|
||||
eq_token: _,
|
||||
lit: Lit::Str(s),
|
||||
})) = arg
|
||||
{
|
||||
if path.is_ident("mode") {
|
||||
mode = s.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let task_fn = syn::parse_macro_input!(item as syn::ItemFn);
|
||||
|
||||
let args = task_fn.sig.inputs.clone();
|
||||
|
@ -21,7 +40,7 @@ pub fn mono_test(_args: TokenStream, item: TokenStream) -> TokenStream {
|
|||
#[test]
|
||||
#(#attributes)*
|
||||
#visibility fn #name(#args) {
|
||||
compiles_to_ir(#name_str, #body);
|
||||
compiles_to_ir(#name_str, #body, &#mode, #no_check);
|
||||
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4339,8 +4339,12 @@ impl StorageSubs {
|
|||
match content {
|
||||
FlexVar(opt_name) => FlexVar(*opt_name),
|
||||
RigidVar(name) => RigidVar(*name),
|
||||
FlexAbleVar(opt_name, ability) => FlexAbleVar(*opt_name, *ability),
|
||||
RigidAbleVar(name, ability) => RigidAbleVar(*name, *ability),
|
||||
FlexAbleVar(opt_name, abilities) => {
|
||||
FlexAbleVar(*opt_name, Self::offset_ability_slice(offsets, *abilities))
|
||||
}
|
||||
RigidAbleVar(name, abilities) => {
|
||||
RigidAbleVar(*name, Self::offset_ability_slice(offsets, *abilities))
|
||||
}
|
||||
RecursionVar {
|
||||
structure,
|
||||
opt_name,
|
||||
|
@ -4387,6 +4391,15 @@ impl StorageSubs {
|
|||
union_tags
|
||||
}
|
||||
|
||||
fn offset_ability_slice(
|
||||
offsets: &StorageSubsOffsets,
|
||||
mut ability_names: SubsSlice<Symbol>,
|
||||
) -> SubsSlice<Symbol> {
|
||||
ability_names.start += offsets.symbol_names;
|
||||
|
||||
ability_names
|
||||
}
|
||||
|
||||
fn offset_lambda_set(
|
||||
offsets: &StorageSubsOffsets,
|
||||
mut union_lambdas: UnionLambdas,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue