mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge remote-tracking branch 'origin/main' into i3696
This commit is contained in:
commit
e9f66a6385
69 changed files with 6067 additions and 793 deletions
|
@ -1,9 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
|
||||
set -euxo pipefail
|
||||
|
||||
# Test every zig
|
||||
# Execute zig tests (see build.zig)
|
||||
zig build test
|
||||
|
||||
# fmt every zig
|
||||
# check formatting of zig files
|
||||
find src/*.zig -type f -print0 | xargs -n 1 -0 zig fmt --check || (echo "zig fmt --check FAILED! Check the previous lines to see which files were improperly formatted." && exit 1)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
|
||||
set -euxo pipefail
|
||||
|
||||
# Test failures will always point at the _start function
|
||||
|
|
|
@ -857,8 +857,44 @@ isMultipleOf : Int a, Int a -> Bool
|
|||
bitwiseAnd : Int a, Int a -> Int a
|
||||
bitwiseXor : Int a, Int a -> Int a
|
||||
bitwiseOr : Int a, Int a -> Int a
|
||||
|
||||
## Bitwise left shift of a number by another
|
||||
##
|
||||
## The least significant bits always become 0. This means that shifting left is
|
||||
## like multiplying by factors of two for unsigned integers.
|
||||
##
|
||||
## >>> shiftLeftBy 0b0000_0011 2 == 0b0000_1100
|
||||
##
|
||||
## >>> 0b0000_0101 |> shiftLeftBy 2 == 0b0000_1100
|
||||
##
|
||||
## In some languages `shiftLeftBy` is implemented as a binary operator `<<`.
|
||||
shiftLeftBy : Int a, Int a -> Int a
|
||||
|
||||
## Bitwise arithmetic shift of a number by another
|
||||
##
|
||||
## The most significant bits are copied from the current.
|
||||
##
|
||||
## >>> shiftRightBy 0b0000_0011 2 == 0b0000_1100
|
||||
##
|
||||
## >>> 0b0001_0100 |> shiftRightBy 2 == 0b0000_0101
|
||||
##
|
||||
## >>> 0b1001_0000 |> shiftRightBy 2 == 0b1110_0100
|
||||
##
|
||||
## In some languages `shiftRightBy` is implemented as a binary operator `>>>`.
|
||||
shiftRightBy : Int a, Int a -> Int a
|
||||
|
||||
## Bitwise logical right shift of a number by another
|
||||
##
|
||||
## The most significant bits always become 0. This means that shifting left is
|
||||
## like dividing by factors of two for unsigned integers.
|
||||
##
|
||||
## >>> shiftRightBy 0b0010_1000 2 == 0b0000_1010
|
||||
##
|
||||
## >>> 0b0010_1000 |> shiftRightBy 2 == 0b0000_1010
|
||||
##
|
||||
## >>> 0b1001_0000 |> shiftRightBy 2 == 0b0010_0100
|
||||
##
|
||||
## In some languages `shiftRightBy` is implemented as a binary operator `>>`.
|
||||
shiftRightZfBy : Int a, Int a -> Int a
|
||||
|
||||
## Round off the given fraction to the nearest integer.
|
||||
|
|
|
@ -41,10 +41,39 @@ insert = \@Set dict, key ->
|
|||
|> Dict.insert 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"
|
||||
|
||||
expected =
|
||||
Set.empty
|
||||
|> Set.insert "foo"
|
||||
|> Set.insert "bar"
|
||||
|> Set.insert "baz"
|
||||
|
||||
expected == actual
|
||||
|
||||
len : Set k -> Nat
|
||||
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
|
||||
|
||||
actual == 3
|
||||
|
||||
## Drops the given element from the set.
|
||||
remove : Set k, k -> Set k
|
||||
remove = \@Set dict, key ->
|
||||
|
|
|
@ -1414,7 +1414,7 @@ fn canonicalize_when_branch<'a>(
|
|||
if output.references.has_value_lookup(symbol) {
|
||||
pattern_bound_symbols_body_needs.insert(symbol);
|
||||
} else {
|
||||
env.problem(Problem::UnusedDef(symbol, region));
|
||||
env.problem(Problem::UnusedBranchDef(symbol, region));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -133,6 +133,12 @@ impl DerivedModule {
|
|||
self.map.entry(key).or_insert(triple)
|
||||
}
|
||||
|
||||
pub fn is_derived_def(&self, def_symbol: Symbol) -> bool {
|
||||
self.map
|
||||
.iter()
|
||||
.any(|(_, (symbol, _, _))| *symbol == def_symbol)
|
||||
}
|
||||
|
||||
pub fn iter_all(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (&DeriveKey, &(Symbol, Def, SpecializationLambdaSets))> {
|
||||
|
|
|
@ -6411,11 +6411,11 @@ fn to_cc_type<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout: &Layout<'a>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
match layout {
|
||||
Layout::Builtin(builtin) => to_cc_type_builtin(env, builtin),
|
||||
_ => {
|
||||
match layout.runtime_representation() {
|
||||
Layout::Builtin(builtin) => to_cc_type_builtin(env, &builtin),
|
||||
layout => {
|
||||
// TODO this is almost certainly incorrect for bigger structs
|
||||
basic_type_from_layout(env, layout)
|
||||
basic_type_from_layout(env, &layout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7039,22 +7039,13 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
|||
NumBitwiseAnd => bd.build_and(lhs, rhs, "int_bitwise_and").into(),
|
||||
NumBitwiseXor => bd.build_xor(lhs, rhs, "int_bitwise_xor").into(),
|
||||
NumBitwiseOr => bd.build_or(lhs, rhs, "int_bitwise_or").into(),
|
||||
NumShiftLeftBy => {
|
||||
// NOTE arguments are flipped;
|
||||
// we write `assert_eq!(0b0000_0001 << 0, 0b0000_0001);`
|
||||
// as `Num.shiftLeftBy 0 0b0000_0001
|
||||
bd.build_left_shift(rhs, lhs, "int_shift_left").into()
|
||||
}
|
||||
NumShiftRightBy => {
|
||||
// NOTE arguments are flipped;
|
||||
bd.build_right_shift(rhs, lhs, true, "int_shift_right")
|
||||
.into()
|
||||
}
|
||||
NumShiftRightZfBy => {
|
||||
// NOTE arguments are flipped;
|
||||
bd.build_right_shift(rhs, lhs, false, "int_shift_right_zf")
|
||||
.into()
|
||||
}
|
||||
NumShiftLeftBy => bd.build_left_shift(lhs, rhs, "int_shift_left").into(),
|
||||
NumShiftRightBy => bd
|
||||
.build_right_shift(lhs, rhs, true, "int_shift_right")
|
||||
.into(),
|
||||
NumShiftRightZfBy => bd
|
||||
.build_right_shift(lhs, rhs, false, "int_shift_right_zf")
|
||||
.into(),
|
||||
|
||||
_ => {
|
||||
unreachable!("Unrecognized int binary operation: {:?}", op);
|
||||
|
|
|
@ -517,7 +517,7 @@ impl<'a> WasmBackend<'a> {
|
|||
|
||||
// Load all the arguments for the inner function
|
||||
for (i, wrapper_arg) in wrapper_arg_layouts.iter().enumerate() {
|
||||
let is_closure_data = i == 0; // Skip closure data (first for wrapper, last for inner)
|
||||
let is_closure_data = i == 0; // Skip closure data (first for wrapper, last for inner). We'll handle it below.
|
||||
let is_return_pointer = i == wrapper_arg_layouts.len() - 1; // Skip return pointer (may not be an arg for inner. And if it is, swaps from end to start)
|
||||
if is_closure_data || is_return_pointer {
|
||||
continue;
|
||||
|
@ -540,7 +540,23 @@ impl<'a> WasmBackend<'a> {
|
|||
// If the inner function has closure data, it's the last arg of the inner fn
|
||||
let closure_data_layout = wrapper_arg_layouts[0];
|
||||
if closure_data_layout.stack_size(TARGET_INFO) > 0 {
|
||||
// The closure data exists, and will have been passed in to the wrapper as a
|
||||
// one-element struct.
|
||||
let inner_closure_data_layout = match closure_data_layout {
|
||||
Layout::Struct {
|
||||
field_layouts: [inner],
|
||||
..
|
||||
} => inner,
|
||||
other => internal_error!(
|
||||
"Expected a boxed layout for wrapped closure data, got {:?}",
|
||||
other
|
||||
),
|
||||
};
|
||||
self.code_builder.get_local(LocalId(0));
|
||||
// Since the closure data is wrapped in a one-element struct, we've been passed in the
|
||||
// pointer to that struct in the stack memory. To get the closure data we just need to
|
||||
// dereference the pointer.
|
||||
self.dereference_boxed_value(inner_closure_data_layout);
|
||||
}
|
||||
|
||||
// Call the wrapped inner function
|
||||
|
|
|
@ -1599,11 +1599,11 @@ impl<'a> LowLevelCall<'a> {
|
|||
}
|
||||
}
|
||||
NumShiftLeftBy => {
|
||||
// Swap order of arguments
|
||||
backend.storage.load_symbols(
|
||||
&mut backend.code_builder,
|
||||
&[self.arguments[1], self.arguments[0]],
|
||||
);
|
||||
let num = self.arguments[0];
|
||||
let bits = self.arguments[1];
|
||||
backend
|
||||
.storage
|
||||
.load_symbols(&mut backend.code_builder, &[num, bits]);
|
||||
match CodeGenNumType::from(self.ret_layout) {
|
||||
I32 => backend.code_builder.i32_shl(),
|
||||
I64 => backend.code_builder.i64_shl(),
|
||||
|
@ -1612,8 +1612,8 @@ impl<'a> LowLevelCall<'a> {
|
|||
}
|
||||
}
|
||||
NumShiftRightBy => {
|
||||
let bits = self.arguments[0];
|
||||
let num = self.arguments[1];
|
||||
let num = self.arguments[0];
|
||||
let bits = self.arguments[1];
|
||||
match CodeGenNumType::from(self.ret_layout) {
|
||||
I32 => {
|
||||
// In most languages this operation is for signed numbers, but Roc defines it on all integers.
|
||||
|
@ -1657,41 +1657,39 @@ impl<'a> LowLevelCall<'a> {
|
|||
}
|
||||
}
|
||||
NumShiftRightZfBy => {
|
||||
let num = self.arguments[0];
|
||||
let bits = self.arguments[1];
|
||||
match CodeGenNumType::from(self.ret_layout) {
|
||||
I32 => {
|
||||
// In most languages this operation is for unsigned numbers, but Roc defines it on all integers.
|
||||
// So the argument is implicitly converted to unsigned before the shift operator.
|
||||
// We need to make that conversion explicit for i8 and i16, which use Wasm's i32 type.
|
||||
let bit_width = 8 * self.ret_layout.stack_size(TARGET_INFO);
|
||||
if bit_width < 32 && symbol_is_signed_int(backend, self.arguments[0]) {
|
||||
if bit_width < 32 && symbol_is_signed_int(backend, bits) {
|
||||
let mask = (1 << bit_width) - 1;
|
||||
|
||||
backend
|
||||
.storage
|
||||
.load_symbols(&mut backend.code_builder, &[self.arguments[1]]);
|
||||
.load_symbols(&mut backend.code_builder, &[num]);
|
||||
|
||||
backend.code_builder.i32_const(mask);
|
||||
backend.code_builder.i32_and();
|
||||
|
||||
backend
|
||||
.storage
|
||||
.load_symbols(&mut backend.code_builder, &[self.arguments[0]]);
|
||||
.load_symbols(&mut backend.code_builder, &[bits]);
|
||||
} else {
|
||||
// swap the arguments
|
||||
backend.storage.load_symbols(
|
||||
&mut backend.code_builder,
|
||||
&[self.arguments[1], self.arguments[0]],
|
||||
);
|
||||
backend
|
||||
.storage
|
||||
.load_symbols(&mut backend.code_builder, &[num, bits]);
|
||||
}
|
||||
|
||||
backend.code_builder.i32_shr_u();
|
||||
}
|
||||
I64 => {
|
||||
// swap the arguments
|
||||
backend.storage.load_symbols(
|
||||
&mut backend.code_builder,
|
||||
&[self.arguments[1], self.arguments[0]],
|
||||
);
|
||||
backend
|
||||
.storage
|
||||
.load_symbols(&mut backend.code_builder, &[num, bits]);
|
||||
backend.code_builder.i64_shr_u();
|
||||
}
|
||||
I128 => todo!("{:?} for I128", self.lowlevel),
|
||||
|
@ -1857,11 +1855,15 @@ impl<'a> LowLevelCall<'a> {
|
|||
/// Equality and inequality
|
||||
/// These can operate on any data type (except functions) so they're more complex than other operators.
|
||||
fn eq_or_neq(&self, backend: &mut WasmBackend<'a>) {
|
||||
let arg_layout = backend.storage.symbol_layouts[&self.arguments[0]];
|
||||
let other_arg_layout = backend.storage.symbol_layouts[&self.arguments[1]];
|
||||
let arg_layout =
|
||||
backend.storage.symbol_layouts[&self.arguments[0]].runtime_representation();
|
||||
let other_arg_layout =
|
||||
backend.storage.symbol_layouts[&self.arguments[1]].runtime_representation();
|
||||
debug_assert!(
|
||||
arg_layout == other_arg_layout,
|
||||
"Cannot do `==` comparison on different types"
|
||||
"Cannot do `==` comparison on different types: {:?} vs {:?}",
|
||||
arg_layout,
|
||||
other_arg_layout
|
||||
);
|
||||
|
||||
let invert_result = matches!(self.lowlevel, LowLevel::NotEq);
|
||||
|
@ -2113,6 +2115,18 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
..
|
||||
} = passed_function;
|
||||
|
||||
// The zig lowlevel builtins expect the passed functions' closure data to always
|
||||
// be sent as an opaque pointer. On the Roc side, however, we need to call the passed function
|
||||
// with the Roc representation of the closure data. There are three possible cases for that
|
||||
// representation:
|
||||
//
|
||||
// 1. The closure data is a struct
|
||||
// 2. The closure data is an unwrapped value
|
||||
// 3. There is no closure data
|
||||
//
|
||||
// To uniformly deal with the first two cases, always put the closure data, when it exists,
|
||||
// into a one-element struct. That way, we get a pointer (i32) that can be passed to the zig lowlevels.
|
||||
// The wrapper around the passed function will access the actual closure data in the struct.
|
||||
let (closure_data_layout, closure_data_exists) =
|
||||
match backend.storage.symbol_layouts[captured_environment] {
|
||||
Layout::LambdaSet(lambda_set) => {
|
||||
|
@ -2131,6 +2145,46 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
x => internal_error!("Closure data has an invalid layout\n{:?}", x),
|
||||
};
|
||||
|
||||
let (wrapped_captured_environment, wrapped_captures_layout) = if closure_data_exists {
|
||||
// If there is closure data, make sure we put in a struct it before passing it to the
|
||||
// external builtin impl. That way it's always an `i32` pointer.
|
||||
let wrapped_closure_data_sym = backend.create_symbol("wrapped_captures");
|
||||
let wrapped_captures_layout =
|
||||
Layout::struct_no_name_order(backend.env.arena.alloc([closure_data_layout]));
|
||||
|
||||
// make sure that the wrapping struct is available in stack memory, so we can hand out a
|
||||
// pointer to it.
|
||||
let wrapped_storage = backend.storage.allocate_var(
|
||||
wrapped_captures_layout,
|
||||
wrapped_closure_data_sym,
|
||||
crate::storage::StoredVarKind::Variable,
|
||||
);
|
||||
|
||||
let (wrapped_storage_local_ptr, wrapped_storage_offset) = match wrapped_storage {
|
||||
StoredValue::StackMemory { location, .. } => {
|
||||
location.local_and_offset(backend.storage.stack_frame_pointer)
|
||||
}
|
||||
other => internal_error!(
|
||||
"Struct should be allocated in stack memory, but it's in {:?}",
|
||||
other
|
||||
),
|
||||
};
|
||||
|
||||
// copy the actual closure data into the first and only element of the wrapping struct.
|
||||
backend.storage.copy_value_to_memory(
|
||||
&mut backend.code_builder,
|
||||
wrapped_storage_local_ptr,
|
||||
wrapped_storage_offset,
|
||||
*captured_environment,
|
||||
);
|
||||
|
||||
(wrapped_closure_data_sym, wrapped_captures_layout)
|
||||
} else {
|
||||
// If we don't capture anything, pass along the captured environment as-is - the wrapper
|
||||
// function will take care not to unwrap this.
|
||||
(*captured_environment, closure_data_layout)
|
||||
};
|
||||
|
||||
// We create a wrapper around the passed function, which just unboxes the arguments.
|
||||
// This allows Zig builtins to have a generic pointer-based interface.
|
||||
let helper_proc_source = {
|
||||
|
@ -2164,7 +2218,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
argument_layouts.len()
|
||||
};
|
||||
|
||||
wrapper_arg_layouts.push(closure_data_layout);
|
||||
wrapper_arg_layouts.push(wrapped_captures_layout);
|
||||
wrapper_arg_layouts.extend(
|
||||
argument_layouts
|
||||
.iter()
|
||||
|
@ -2204,7 +2258,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
.get_refcount_fn_index(Layout::Builtin(Builtin::Int(IntWidth::I32)), HelperOp::Inc);
|
||||
backend.get_fn_ptr(inc_fn)
|
||||
} else {
|
||||
let inc_fn = backend.get_refcount_fn_index(closure_data_layout, HelperOp::Inc);
|
||||
let inc_fn = backend.get_refcount_fn_index(wrapped_captures_layout, HelperOp::Inc);
|
||||
backend.get_fn_ptr(inc_fn)
|
||||
};
|
||||
|
||||
|
@ -2218,7 +2272,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
wrapper_fn_ptr,
|
||||
inc_fn_ptr,
|
||||
closure_data_exists,
|
||||
*captured_environment,
|
||||
wrapped_captured_environment,
|
||||
*owns_captured_environment,
|
||||
),
|
||||
|
||||
|
@ -2231,7 +2285,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
wrapper_fn_ptr,
|
||||
inc_fn_ptr,
|
||||
closure_data_exists,
|
||||
*captured_environment,
|
||||
wrapped_captured_environment,
|
||||
*owns_captured_environment,
|
||||
),
|
||||
|
||||
|
@ -2244,7 +2298,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
wrapper_fn_ptr,
|
||||
inc_fn_ptr,
|
||||
closure_data_exists,
|
||||
*captured_environment,
|
||||
wrapped_captured_environment,
|
||||
*owns_captured_environment,
|
||||
),
|
||||
|
||||
|
@ -2257,7 +2311,7 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
wrapper_fn_ptr,
|
||||
inc_fn_ptr,
|
||||
closure_data_exists,
|
||||
*captured_environment,
|
||||
wrapped_captured_environment,
|
||||
*owns_captured_environment,
|
||||
),
|
||||
|
||||
|
@ -2280,7 +2334,9 @@ pub fn call_higher_order_lowlevel<'a>(
|
|||
backend.storage.load_symbol_zig(cb, *xs);
|
||||
cb.i32_const(wrapper_fn_ptr);
|
||||
if closure_data_exists {
|
||||
backend.storage.load_symbols(cb, &[*captured_environment]);
|
||||
backend
|
||||
.storage
|
||||
.load_symbols(cb, &[wrapped_captured_environment]);
|
||||
} else {
|
||||
// load_symbols assumes that a zero-size arg should be eliminated in code gen,
|
||||
// but that's a specialization that our Zig code doesn't have! Pass a null pointer.
|
||||
|
|
|
@ -719,9 +719,10 @@ impl<'a> Storage<'a> {
|
|||
) => {
|
||||
debug_assert!(to_value_type == from_value_type);
|
||||
debug_assert!(to_size == from_size);
|
||||
// Note: load_symbols will not destroy the value, so we can use it again later.
|
||||
// It will leave a Popped marker in the VM stack model in CodeBuilder
|
||||
self.load_symbols(code_builder, &[from_symbol]);
|
||||
code_builder.set_local(*to_local_id);
|
||||
self.symbol_storage_map.insert(from_symbol, to.clone());
|
||||
}
|
||||
|
||||
(
|
||||
|
|
|
@ -54,6 +54,29 @@ pub fn load_single_threaded<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum LoadMonomorphizedError<'a> {
|
||||
LoadingProblem(LoadingProblem<'a>),
|
||||
/// Errors in the module that should be reported, without compiling the executable.
|
||||
/// Relevant in check-and-then-build mode.
|
||||
ErrorModule(LoadedModule),
|
||||
}
|
||||
|
||||
impl<'a> From<LoadingProblem<'a>> for LoadMonomorphizedError<'a> {
|
||||
fn from(problem: LoadingProblem<'a>) -> Self {
|
||||
Self::LoadingProblem(problem)
|
||||
}
|
||||
}
|
||||
|
||||
// HACK only relevant because of some uses of `map_err` that decay into this error, but call `todo` -
|
||||
// rustc seems to be unhappy with that.
|
||||
impl<'a> From<()> for LoadMonomorphizedError<'a> {
|
||||
fn from(_: ()) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn load_and_monomorphize_from_str<'a>(
|
||||
arena: &'a Bump,
|
||||
|
@ -78,14 +101,14 @@ pub fn load_and_monomorphize(
|
|||
filename: PathBuf,
|
||||
exposed_types: ExposedByModule,
|
||||
load_config: LoadConfig,
|
||||
) -> Result<MonomorphizedModule<'_>, LoadingProblem<'_>> {
|
||||
) -> Result<MonomorphizedModule<'_>, LoadMonomorphizedError<'_>> {
|
||||
use LoadResult::*;
|
||||
|
||||
let load_start = LoadStart::from_path(arena, filename, load_config.render)?;
|
||||
|
||||
match load(arena, load_start, exposed_types, load_config)? {
|
||||
Monomorphized(module) => Ok(module),
|
||||
TypeChecked(_) => unreachable!(""),
|
||||
TypeChecked(module) => Err(LoadMonomorphizedError::ErrorModule(module)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -130,13 +130,15 @@ pub enum ExecutionMode {
|
|||
Test,
|
||||
Check,
|
||||
Executable,
|
||||
/// Like [`ExecutionMode::Executable`], but stops in the presence of type errors.
|
||||
ExecutableIfCheck,
|
||||
}
|
||||
|
||||
impl ExecutionMode {
|
||||
fn goal_phase(&self) -> Phase {
|
||||
match self {
|
||||
ExecutionMode::Test | ExecutionMode::Executable => Phase::MakeSpecializations,
|
||||
ExecutionMode::Check => Phase::SolveTypes,
|
||||
ExecutionMode::Check | ExecutionMode::ExecutableIfCheck => Phase::SolveTypes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,6 +170,22 @@ struct ModuleCache<'a> {
|
|||
sources: MutMap<ModuleId, (PathBuf, &'a str)>,
|
||||
}
|
||||
|
||||
impl<'a> ModuleCache<'a> {
|
||||
pub fn total_problems(&self) -> usize {
|
||||
let mut total = 0;
|
||||
|
||||
for problems in self.can_problems.values() {
|
||||
total += problems.len();
|
||||
}
|
||||
|
||||
for problems in self.type_problems.values() {
|
||||
total += problems.len();
|
||||
}
|
||||
|
||||
total
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ModuleCache<'_> {
|
||||
fn default() -> Self {
|
||||
let mut module_names = MutMap::default();
|
||||
|
@ -2379,12 +2397,35 @@ fn update<'a>(
|
|||
.extend(solved_module.aliases.keys().copied());
|
||||
}
|
||||
|
||||
if is_host_exposed && state.goal_phase() == Phase::SolveTypes {
|
||||
let finish_type_checking = is_host_exposed &&
|
||||
(state.goal_phase() == Phase::SolveTypes)
|
||||
// If we're running in check-and-then-build mode, only exit now there are errors.
|
||||
&& (!matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck) || state.module_cache.total_problems() > 0);
|
||||
|
||||
if finish_type_checking {
|
||||
debug_assert!(work.is_empty());
|
||||
debug_assert!(state.dependencies.solved_all());
|
||||
|
||||
state.timings.insert(module_id, module_timing);
|
||||
|
||||
if matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck) {
|
||||
// We there may outstanding modules in the typecheked cache whose ident IDs
|
||||
// aren't registered; transfer all of their idents over to the state, since
|
||||
// we're now done and ready to report errors.
|
||||
for (
|
||||
module_id,
|
||||
TypeCheckedModule {
|
||||
ident_ids,
|
||||
module_timing,
|
||||
..
|
||||
},
|
||||
) in state.module_cache.typechecked.drain()
|
||||
{
|
||||
state.constrained_ident_ids.insert(module_id, ident_ids);
|
||||
state.timings.insert(module_id, module_timing);
|
||||
}
|
||||
}
|
||||
|
||||
let documentation = {
|
||||
let mut empty = MutMap::default();
|
||||
std::mem::swap(&mut empty, &mut state.module_cache.documentation);
|
||||
|
@ -2421,7 +2462,9 @@ fn update<'a>(
|
|||
},
|
||||
);
|
||||
|
||||
if state.goal_phase() > Phase::SolveTypes {
|
||||
if state.goal_phase() > Phase::SolveTypes
|
||||
|| matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck)
|
||||
{
|
||||
let layout_cache = state
|
||||
.layout_caches
|
||||
.pop()
|
||||
|
@ -2446,6 +2489,25 @@ fn update<'a>(
|
|||
state.timings.insert(module_id, module_timing);
|
||||
}
|
||||
|
||||
let work = if is_host_exposed
|
||||
&& matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck)
|
||||
{
|
||||
debug_assert!(
|
||||
work.is_empty(),
|
||||
"work left over after host exposed is checked"
|
||||
);
|
||||
|
||||
// Update the goal phase to target full codegen.
|
||||
state.exec_mode = ExecutionMode::Executable;
|
||||
|
||||
// Load the find + make specializations portion of the dependency graph.
|
||||
state
|
||||
.dependencies
|
||||
.load_find_and_make_specializations_after_check()
|
||||
} else {
|
||||
work
|
||||
};
|
||||
|
||||
start_tasks(arena, &mut state, work, injector, worker_listeners)?;
|
||||
}
|
||||
|
||||
|
@ -2803,7 +2865,7 @@ fn finish_specialization(
|
|||
let entry_point = {
|
||||
match exec_mode {
|
||||
ExecutionMode::Test => EntryPoint::Test,
|
||||
ExecutionMode::Executable => {
|
||||
ExecutionMode::Executable | ExecutionMode::ExecutableIfCheck => {
|
||||
let path_to_platform = {
|
||||
use PlatformPath::*;
|
||||
let package_name = match platform_path {
|
||||
|
@ -5000,7 +5062,9 @@ fn build_pending_specializations<'a>(
|
|||
// skip expectations if we're not going to run them
|
||||
match execution_mode {
|
||||
ExecutionMode::Test => { /* fall through */ }
|
||||
ExecutionMode::Check | ExecutionMode::Executable => continue,
|
||||
ExecutionMode::Check
|
||||
| ExecutionMode::Executable
|
||||
| ExecutionMode::ExecutableIfCheck => continue,
|
||||
}
|
||||
|
||||
// mark this symbol as a top-level thunk before any other work on the procs
|
||||
|
@ -5074,7 +5138,9 @@ fn build_pending_specializations<'a>(
|
|||
// skip expectations if we're not going to run them
|
||||
match execution_mode {
|
||||
ExecutionMode::Test => { /* fall through */ }
|
||||
ExecutionMode::Check | ExecutionMode::Executable => continue,
|
||||
ExecutionMode::Check
|
||||
| ExecutionMode::Executable
|
||||
| ExecutionMode::ExecutableIfCheck => continue,
|
||||
}
|
||||
|
||||
// mark this symbol as a top-level thunk before any other work on the procs
|
||||
|
|
|
@ -166,11 +166,10 @@ impl<'a> Dependencies<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if goal_phase >= MakeSpecializations {
|
||||
// Add make specialization dependents
|
||||
self.make_specializations_dependents
|
||||
.add_succ(module_id, dependencies.iter().map(|dep| *dep.as_inner()));
|
||||
}
|
||||
// Add "make specialization" dependents. Even if we're not targeting making
|
||||
// specializations right now, we may re-enter to do so later.
|
||||
self.make_specializations_dependents
|
||||
.add_succ(module_id, dependencies.iter().map(|dep| *dep.as_inner()));
|
||||
|
||||
// add dependencies for self
|
||||
// phase i + 1 of a file always depends on phase i being completed
|
||||
|
@ -374,6 +373,80 @@ impl<'a> Dependencies<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Loads the dependency graph to find and make specializations, and returns the next jobs to
|
||||
/// be run.
|
||||
///
|
||||
/// This should be used when the compiler wants to build or run a Roc executable if and only if
|
||||
/// previous stages succeed; in such cases we load the dependency graph dynamically.
|
||||
pub fn load_find_and_make_specializations_after_check(&mut self) -> MutSet<(ModuleId, Phase)> {
|
||||
let mut output = MutSet::default();
|
||||
|
||||
let mut make_specializations_dependents = MakeSpecializationsDependents::default();
|
||||
let default_make_specializations_dependents_len = make_specializations_dependents.0.len();
|
||||
std::mem::swap(
|
||||
&mut self.make_specializations_dependents,
|
||||
&mut make_specializations_dependents,
|
||||
);
|
||||
|
||||
for (&module, info) in make_specializations_dependents.0.iter_mut() {
|
||||
debug_assert!(self.status.get_mut(&Job::Step(module, Phase::FindSpecializations)).is_none(), "should only have targeted solving types, but there is already a goal to find specializations");
|
||||
debug_assert!(self.status.get_mut(&Job::Step(module, Phase::MakeSpecializations)).is_none(), "should only have targeted solving types, but there is already a goal to make specializations");
|
||||
debug_assert!(
|
||||
module == ModuleId::DERIVED_GEN || info.succ.contains(&ModuleId::DERIVED_GEN),
|
||||
"derived module not accounted for in {:?}",
|
||||
(module, info)
|
||||
);
|
||||
|
||||
let mut has_find_specialization_dep = false;
|
||||
for &module_dep in info.succ.iter() {
|
||||
// The modules in `succ` are the modules for which specializations should be made
|
||||
// after the current one. But, their specializations should be found before the
|
||||
// current one.
|
||||
if module_dep != ModuleId::DERIVED_GEN {
|
||||
// We never find specializations for DERIVED_GEN
|
||||
self.add_dependency(module, module_dep, Phase::FindSpecializations);
|
||||
has_find_specialization_dep = true;
|
||||
}
|
||||
|
||||
self.add_dependency(module_dep, module, Phase::MakeSpecializations);
|
||||
self.add_dependency(ModuleId::DERIVED_GEN, module, Phase::MakeSpecializations);
|
||||
|
||||
// `module_dep` can't make its specializations until the current module does.
|
||||
info.has_pred = true;
|
||||
}
|
||||
|
||||
if module != ModuleId::DERIVED_GEN {
|
||||
self.add_to_status_for_phase(module, Phase::FindSpecializations);
|
||||
self.add_dependency_help(
|
||||
module,
|
||||
module,
|
||||
Phase::MakeSpecializations,
|
||||
Phase::FindSpecializations,
|
||||
);
|
||||
}
|
||||
self.add_to_status_for_phase(module, Phase::MakeSpecializations);
|
||||
|
||||
if !has_find_specialization_dep && module != ModuleId::DERIVED_GEN {
|
||||
// We don't depend on any other modules having their specializations found first,
|
||||
// so start finding specializations from this module.
|
||||
output.insert((module, Phase::FindSpecializations));
|
||||
}
|
||||
}
|
||||
|
||||
std::mem::swap(
|
||||
&mut self.make_specializations_dependents,
|
||||
&mut make_specializations_dependents,
|
||||
);
|
||||
debug_assert_eq!(
|
||||
make_specializations_dependents.0.len(),
|
||||
default_make_specializations_dependents_len,
|
||||
"more modules were added to the graph: {:?}",
|
||||
make_specializations_dependents
|
||||
);
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
/// Load the entire "make specializations" dependency graph and start from the top.
|
||||
pub fn reload_make_specialization_pass(&mut self) -> MutSet<(ModuleId, Phase)> {
|
||||
let mut output = MutSet::default();
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#![allow(clippy::manual_map)]
|
||||
|
||||
use crate::layout::{
|
||||
Builtin, CapturesNiche, ClosureRepresentation, LambdaName, LambdaSet, Layout, LayoutCache,
|
||||
LayoutProblem, RawFunctionLayout, TagIdIntType, UnionLayout, WrappedVariant,
|
||||
Builtin, CapturesNiche, ClosureCallOptions, ClosureRepresentation, EnumDispatch, LambdaName,
|
||||
LambdaSet, Layout, LayoutCache, LayoutProblem, RawFunctionLayout, TagIdIntType, UnionLayout,
|
||||
WrappedVariant,
|
||||
};
|
||||
use bumpalo::collections::{CollectIn, Vec};
|
||||
use bumpalo::Bump;
|
||||
|
@ -1245,7 +1246,8 @@ impl<'a> Procs<'a> {
|
|||
}
|
||||
|
||||
// If this is an imported symbol, let its home module make this specialization
|
||||
if env.is_imported_symbol(name.name()) {
|
||||
if env.is_imported_symbol(name.name()) || env.is_unloaded_derived_symbol(name.name(), self)
|
||||
{
|
||||
add_needed_external(self, env, fn_var, name);
|
||||
return;
|
||||
}
|
||||
|
@ -1415,6 +1417,13 @@ impl<'a, 'i> Env<'a, 'i> {
|
|||
self.home == ModuleId::DERIVED_GEN
|
||||
&& symbol.module_id() == ModuleId::DERIVED_SYNTH
|
||||
&& !procs.partial_procs.contains_key(symbol)
|
||||
// TODO: locking to find the answer in the `Derived_gen` module is not great, since
|
||||
// Derived_gen also blocks other modules specializing. Improve this later.
|
||||
&& self
|
||||
.derived_module
|
||||
.lock()
|
||||
.expect("derived module is poisoned")
|
||||
.is_derived_def(symbol)
|
||||
}
|
||||
|
||||
/// Unifies two variables and performs lambda set compaction.
|
||||
|
@ -3206,6 +3215,8 @@ fn specialize_external<'a>(
|
|||
closure: opt_closure_layout,
|
||||
ret_layout,
|
||||
} => {
|
||||
let mut proc_args = Vec::from_iter_in(proc_args.iter().copied(), env.arena);
|
||||
|
||||
// unpack the closure symbols, if any
|
||||
match (opt_closure_layout, captured_symbols) {
|
||||
(Some(closure_layout), CapturedSymbols::Captured(captured)) => {
|
||||
|
@ -3325,41 +3336,35 @@ fn specialize_external<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
ClosureRepresentation::Other(layout) => match layout {
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
// just ignore this value
|
||||
// IDEA don't pass this value in the future
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
|
||||
// just ignore this value
|
||||
// IDEA don't pass this value in the future
|
||||
}
|
||||
other => {
|
||||
// NOTE other values always should be wrapped in a 1-element record
|
||||
unreachable!(
|
||||
"{:?} is not a valid closure data representation",
|
||||
other
|
||||
)
|
||||
}
|
||||
},
|
||||
ClosureRepresentation::UnwrappedCapture(_layout) => {
|
||||
debug_assert_eq!(captured.len(), 1);
|
||||
let (captured_symbol, _captured_layout) = captured[0];
|
||||
|
||||
// The capture set is unwrapped, so simply replace the closure argument
|
||||
// to the function with the unwrapped capture name.
|
||||
let captured_symbol = get_specialized_name(captured_symbol);
|
||||
let closure_arg = proc_args.last_mut().unwrap();
|
||||
debug_assert_eq!(closure_arg.1, Symbol::ARG_CLOSURE);
|
||||
closure_arg.1 = captured_symbol;
|
||||
}
|
||||
|
||||
ClosureRepresentation::EnumDispatch(_) => {
|
||||
// just ignore this value, since it's not a capture
|
||||
// IDEA don't pass this value in the future
|
||||
}
|
||||
}
|
||||
}
|
||||
(None, CapturedSymbols::None) | (None, CapturedSymbols::Captured([])) => {}
|
||||
_ => unreachable!("to closure or not to closure?"),
|
||||
}
|
||||
|
||||
let proc_args: Vec<_> = proc_args
|
||||
.iter()
|
||||
.map(|&(layout, symbol)| {
|
||||
// Grab the specialization symbol, if it exists.
|
||||
let symbol = procs
|
||||
.symbol_specializations
|
||||
.remove_single(symbol)
|
||||
.unwrap_or(symbol);
|
||||
|
||||
(layout, symbol)
|
||||
})
|
||||
.collect_in(env.arena);
|
||||
proc_args.iter_mut().for_each(|(_layout, symbol)| {
|
||||
// Grab the specialization symbol, if it exists.
|
||||
*symbol = procs
|
||||
.symbol_specializations
|
||||
.remove_single(*symbol)
|
||||
.unwrap_or(*symbol);
|
||||
});
|
||||
|
||||
// reset subs, so we don't get type errors when specializing for a different signature
|
||||
layout_cache.rollback_to(cache_snapshot);
|
||||
|
@ -5479,29 +5484,42 @@ where
|
|||
|
||||
Stmt::Let(assigned, expr, lambda_set_layout, hole)
|
||||
}
|
||||
ClosureRepresentation::Other(Layout::Builtin(Builtin::Bool)) => {
|
||||
debug_assert_eq!(symbols.len(), 0);
|
||||
ClosureRepresentation::UnwrappedCapture(_layout) => {
|
||||
debug_assert_eq!(symbols.len(), 1);
|
||||
|
||||
debug_assert_eq!(lambda_set.set.len(), 2);
|
||||
let tag_id = name.name() != lambda_set.iter_set().next().unwrap().name();
|
||||
let expr = Expr::Literal(Literal::Bool(tag_id));
|
||||
let mut symbols = symbols;
|
||||
let (captured_symbol, _) = symbols.next().unwrap();
|
||||
|
||||
Stmt::Let(assigned, expr, lambda_set_layout, hole)
|
||||
// The capture set is unwrapped, so just replaced the assigned capture symbol with the
|
||||
// only capture.
|
||||
let mut hole = hole.clone();
|
||||
substitute_in_exprs(env.arena, &mut hole, assigned, *captured_symbol);
|
||||
hole
|
||||
}
|
||||
ClosureRepresentation::Other(Layout::Builtin(Builtin::Int(IntWidth::U8))) => {
|
||||
debug_assert_eq!(symbols.len(), 0);
|
||||
ClosureRepresentation::EnumDispatch(repr) => match repr {
|
||||
EnumDispatch::Bool => {
|
||||
debug_assert_eq!(symbols.len(), 0);
|
||||
|
||||
debug_assert!(lambda_set.set.len() > 2);
|
||||
let tag_id = lambda_set
|
||||
.iter_set()
|
||||
.position(|s| s.name() == name.name())
|
||||
.unwrap() as u8;
|
||||
debug_assert_eq!(lambda_set.len(), 2);
|
||||
let tag_id = name.name() != lambda_set.iter_set().next().unwrap().name();
|
||||
let expr = Expr::Literal(Literal::Bool(tag_id));
|
||||
|
||||
let expr = Expr::Literal(Literal::Byte(tag_id));
|
||||
Stmt::Let(assigned, expr, lambda_set_layout, hole)
|
||||
}
|
||||
EnumDispatch::U8 => {
|
||||
debug_assert_eq!(symbols.len(), 0);
|
||||
|
||||
Stmt::Let(assigned, expr, lambda_set_layout, hole)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
debug_assert!(lambda_set.len() > 2);
|
||||
let tag_id = lambda_set
|
||||
.iter_set()
|
||||
.position(|s| s.name() == name.name())
|
||||
.unwrap() as u8;
|
||||
|
||||
let expr = Expr::Literal(Literal::Byte(tag_id));
|
||||
|
||||
Stmt::Let(assigned, expr, lambda_set_layout, hole)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
result
|
||||
|
@ -5940,10 +5958,7 @@ fn register_capturing_closure<'a>(
|
|||
Content::Structure(FlatType::Func(_, closure_var, _)) => {
|
||||
match LambdaSet::from_var(env.arena, env.subs, closure_var, env.target_info) {
|
||||
Ok(lambda_set) => {
|
||||
if let Layout::Struct {
|
||||
field_layouts: &[], ..
|
||||
} = lambda_set.runtime_representation()
|
||||
{
|
||||
if lambda_set.is_represented().is_none() {
|
||||
CapturedSymbols::None
|
||||
} else {
|
||||
let mut temp = Vec::from_iter_in(captured_symbols, env.arena);
|
||||
|
@ -7180,7 +7195,7 @@ fn can_reuse_symbol<'a>(
|
|||
|
||||
if arguments.contains(&symbol) {
|
||||
Value(symbol)
|
||||
} else if env.is_imported_symbol(symbol) {
|
||||
} else if env.is_imported_symbol(symbol) || env.is_unloaded_derived_symbol(symbol, procs) {
|
||||
Imported(symbol)
|
||||
} else if procs.partial_procs.contains_key(symbol) {
|
||||
LocalFunction(symbol)
|
||||
|
@ -7352,7 +7367,10 @@ fn specialize_symbol<'a>(
|
|||
match procs.get_partial_proc(original) {
|
||||
None => {
|
||||
match arg_var {
|
||||
Some(arg_var) if env.is_imported_symbol(original) => {
|
||||
Some(arg_var)
|
||||
if env.is_imported_symbol(original)
|
||||
|| env.is_unloaded_derived_symbol(original, procs) =>
|
||||
{
|
||||
let raw = match layout_cache.raw_from_var(env.arena, arg_var, env.subs) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return_on_layout_error_help!(env, e, "specialize_symbol"),
|
||||
|
@ -9195,9 +9213,9 @@ fn lowlevel_match_on_lambda_set<'a, ToLowLevelCall>(
|
|||
where
|
||||
ToLowLevelCall: Fn(ToLowLevelCallArguments<'a>) -> Call<'a> + Copy,
|
||||
{
|
||||
match lambda_set.runtime_representation() {
|
||||
Layout::VOID => empty_lambda_set_error(),
|
||||
Layout::Union(union_layout) => {
|
||||
match lambda_set.call_by_name_options() {
|
||||
ClosureCallOptions::Void => empty_lambda_set_error(),
|
||||
ClosureCallOptions::Union(union_layout) => {
|
||||
let closure_tag_id_symbol = env.unique_symbol();
|
||||
|
||||
let result = lowlevel_union_lambda_set_to_switch(
|
||||
|
@ -9226,7 +9244,7 @@ where
|
|||
env.arena.alloc(result),
|
||||
)
|
||||
}
|
||||
Layout::Struct { .. } => match lambda_set.iter_set().next() {
|
||||
ClosureCallOptions::Struct { .. } => match lambda_set.iter_set().next() {
|
||||
Some(lambda_name) => {
|
||||
let call_spec_id = env.next_call_specialization_id();
|
||||
let update_mode = env.next_update_mode_id();
|
||||
|
@ -9251,39 +9269,58 @@ where
|
|||
hole.clone()
|
||||
}
|
||||
},
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
ClosureCallOptions::UnwrappedCapture(_) => {
|
||||
let lambda_name = lambda_set
|
||||
.iter_set()
|
||||
.next()
|
||||
.expect("no function in lambda set");
|
||||
|
||||
lowlevel_enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.iter_set(),
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
let call_spec_id = env.next_call_specialization_id();
|
||||
let update_mode = env.next_update_mode_id();
|
||||
let call = to_lowlevel_call((
|
||||
lambda_name,
|
||||
closure_data_symbol,
|
||||
lambda_set.is_represented(),
|
||||
to_lowlevel_call,
|
||||
return_layout,
|
||||
assigned,
|
||||
hole,
|
||||
)
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
call_spec_id,
|
||||
update_mode,
|
||||
));
|
||||
|
||||
lowlevel_enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.iter_set(),
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)),
|
||||
closure_data_symbol,
|
||||
lambda_set.is_represented(),
|
||||
to_lowlevel_call,
|
||||
return_layout,
|
||||
assigned,
|
||||
hole,
|
||||
)
|
||||
build_call(env, call, assigned, return_layout, env.arena.alloc(hole))
|
||||
}
|
||||
other => todo!("{:?}", other),
|
||||
ClosureCallOptions::EnumDispatch(repr) => match repr {
|
||||
EnumDispatch::Bool => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
|
||||
lowlevel_enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.iter_set(),
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
closure_data_symbol,
|
||||
lambda_set.is_represented(),
|
||||
to_lowlevel_call,
|
||||
return_layout,
|
||||
assigned,
|
||||
hole,
|
||||
)
|
||||
}
|
||||
EnumDispatch::U8 => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
|
||||
lowlevel_enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.iter_set(),
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)),
|
||||
closure_data_symbol,
|
||||
lambda_set.is_represented(),
|
||||
to_lowlevel_call,
|
||||
return_layout,
|
||||
assigned,
|
||||
hole,
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9374,15 +9411,14 @@ fn match_on_lambda_set<'a>(
|
|||
assigned: Symbol,
|
||||
hole: &'a Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
match lambda_set.runtime_representation() {
|
||||
Layout::VOID => empty_lambda_set_error(),
|
||||
Layout::Union(union_layout) => {
|
||||
match lambda_set.call_by_name_options() {
|
||||
ClosureCallOptions::Void => empty_lambda_set_error(),
|
||||
ClosureCallOptions::Union(union_layout) => {
|
||||
let closure_tag_id_symbol = env.unique_symbol();
|
||||
|
||||
let result = union_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set,
|
||||
Layout::Union(union_layout),
|
||||
closure_tag_id_symbol,
|
||||
union_layout.tag_id_layout(),
|
||||
closure_data_symbol,
|
||||
|
@ -9406,9 +9442,9 @@ fn match_on_lambda_set<'a>(
|
|||
env.arena.alloc(result),
|
||||
)
|
||||
}
|
||||
Layout::Struct {
|
||||
ClosureCallOptions::Struct {
|
||||
field_layouts,
|
||||
field_order_hash,
|
||||
field_order_hash: _,
|
||||
} => {
|
||||
let function_symbol = match lambda_set.iter_set().next() {
|
||||
Some(function_symbol) => function_symbol,
|
||||
|
@ -9432,10 +9468,6 @@ fn match_on_lambda_set<'a>(
|
|||
_ => ClosureInfo::Captures {
|
||||
lambda_set,
|
||||
closure_data_symbol,
|
||||
closure_data_layout: Layout::Struct {
|
||||
field_layouts,
|
||||
field_order_hash,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -9450,15 +9482,21 @@ fn match_on_lambda_set<'a>(
|
|||
hole,
|
||||
)
|
||||
}
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
ClosureCallOptions::UnwrappedCapture(_) => {
|
||||
let function_symbol = lambda_set
|
||||
.iter_set()
|
||||
.next()
|
||||
.expect("no function in lambda set");
|
||||
|
||||
enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.iter_set(),
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
let closure_info = ClosureInfo::Captures {
|
||||
lambda_set,
|
||||
closure_data_symbol,
|
||||
};
|
||||
|
||||
union_lambda_set_branch_help(
|
||||
env,
|
||||
function_symbol,
|
||||
closure_info,
|
||||
argument_symbols,
|
||||
argument_layouts,
|
||||
return_layout,
|
||||
|
@ -9466,23 +9504,38 @@ fn match_on_lambda_set<'a>(
|
|||
hole,
|
||||
)
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
ClosureCallOptions::EnumDispatch(repr) => match repr {
|
||||
EnumDispatch::Bool => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
|
||||
enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.iter_set(),
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)),
|
||||
closure_data_symbol,
|
||||
argument_symbols,
|
||||
argument_layouts,
|
||||
return_layout,
|
||||
assigned,
|
||||
hole,
|
||||
)
|
||||
}
|
||||
other => todo!("{:?}", other),
|
||||
enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.iter_set(),
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
argument_symbols,
|
||||
argument_layouts,
|
||||
return_layout,
|
||||
assigned,
|
||||
hole,
|
||||
)
|
||||
}
|
||||
EnumDispatch::U8 => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
|
||||
enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.iter_set(),
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)),
|
||||
argument_symbols,
|
||||
argument_layouts,
|
||||
return_layout,
|
||||
assigned,
|
||||
hole,
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9490,7 +9543,6 @@ fn match_on_lambda_set<'a>(
|
|||
fn union_lambda_set_to_switch<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
lambda_set: LambdaSet<'a>,
|
||||
closure_layout: Layout<'a>,
|
||||
closure_tag_id_symbol: Symbol,
|
||||
closure_tag_id_layout: Layout<'a>,
|
||||
closure_data_symbol: Symbol,
|
||||
|
@ -9500,7 +9552,7 @@ fn union_lambda_set_to_switch<'a>(
|
|||
assigned: Symbol,
|
||||
hole: &'a Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
if lambda_set.set.is_empty() {
|
||||
if lambda_set.is_empty() {
|
||||
// NOTE this can happen if there is a type error somewhere. Since the lambda set is empty,
|
||||
// there is really nothing we can do here. We generate a runtime error here which allows
|
||||
// code gen to proceed. We then assume that we hit another (more descriptive) error before
|
||||
|
@ -9510,7 +9562,7 @@ fn union_lambda_set_to_switch<'a>(
|
|||
|
||||
let join_point_id = JoinPointId(env.unique_symbol());
|
||||
|
||||
let mut branches = Vec::with_capacity_in(lambda_set.set.len(), env.arena);
|
||||
let mut branches = Vec::with_capacity_in(lambda_set.len(), env.arena);
|
||||
|
||||
for (i, lambda_name) in lambda_set.iter_set().enumerate() {
|
||||
let closure_info = if lambda_name.no_captures() {
|
||||
|
@ -9519,7 +9571,6 @@ fn union_lambda_set_to_switch<'a>(
|
|||
ClosureInfo::Captures {
|
||||
lambda_set,
|
||||
closure_data_symbol,
|
||||
closure_data_layout: closure_layout,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -9589,11 +9640,10 @@ fn union_lambda_set_branch<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum ClosureInfo<'a> {
|
||||
Captures {
|
||||
closure_data_symbol: Symbol,
|
||||
/// The layout of this closure variant
|
||||
closure_data_layout: Layout<'a>,
|
||||
/// The whole lambda set representation this closure is a variant of
|
||||
lambda_set: LambdaSet<'a>,
|
||||
},
|
||||
|
@ -9615,34 +9665,21 @@ fn union_lambda_set_branch_help<'a>(
|
|||
ClosureInfo::Captures {
|
||||
lambda_set,
|
||||
closure_data_symbol,
|
||||
closure_data_layout,
|
||||
} => match closure_data_layout {
|
||||
Layout::Struct {
|
||||
field_layouts: &[], ..
|
||||
}
|
||||
| Layout::Builtin(Builtin::Bool)
|
||||
| Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
|
||||
(argument_layouts_slice, argument_symbols_slice)
|
||||
}
|
||||
_ => {
|
||||
// extend layouts with the layout of the closure environment
|
||||
let mut argument_layouts =
|
||||
Vec::with_capacity_in(argument_layouts_slice.len() + 1, env.arena);
|
||||
argument_layouts.extend(argument_layouts_slice);
|
||||
argument_layouts.push(Layout::LambdaSet(lambda_set));
|
||||
|
||||
} => {
|
||||
let argument_layouts =
|
||||
lambda_set.extend_argument_list(env.arena, argument_layouts_slice);
|
||||
let argument_symbols = if argument_layouts.len() > argument_layouts_slice.len() {
|
||||
// extend symbols with the symbol of the closure environment
|
||||
let mut argument_symbols =
|
||||
Vec::with_capacity_in(argument_symbols_slice.len() + 1, env.arena);
|
||||
argument_symbols.extend(argument_symbols_slice);
|
||||
argument_symbols.push(closure_data_symbol);
|
||||
|
||||
(
|
||||
argument_layouts.into_bump_slice(),
|
||||
argument_symbols.into_bump_slice(),
|
||||
)
|
||||
}
|
||||
},
|
||||
argument_symbols.into_bump_slice()
|
||||
} else {
|
||||
argument_symbols_slice
|
||||
};
|
||||
(argument_layouts, argument_symbols)
|
||||
}
|
||||
ClosureInfo::DoesNotCapture => {
|
||||
// sometimes unification causes a function that does not itself capture anything
|
||||
// to still get a lambda set that does store information. We must not pass a closure
|
||||
|
@ -9666,13 +9703,14 @@ fn union_lambda_set_branch_help<'a>(
|
|||
build_call(env, call, assigned, *return_layout, hole)
|
||||
}
|
||||
|
||||
/// Switches over a enum lambda set, which may dispatch to different functions, none of which
|
||||
/// capture.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn enum_lambda_set_to_switch<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
lambda_set: impl ExactSizeIterator<Item = LambdaName<'a>>,
|
||||
closure_tag_id_symbol: Symbol,
|
||||
closure_tag_id_layout: Layout<'a>,
|
||||
closure_data_symbol: Symbol,
|
||||
argument_symbols: &'a [Symbol],
|
||||
argument_layouts: &'a [Layout<'a>],
|
||||
return_layout: &'a Layout<'a>,
|
||||
|
@ -9685,15 +9723,11 @@ fn enum_lambda_set_to_switch<'a>(
|
|||
|
||||
let mut branches = Vec::with_capacity_in(lambda_set.len(), env.arena);
|
||||
|
||||
let closure_layout = closure_tag_id_layout;
|
||||
|
||||
for (i, lambda_name) in lambda_set.into_iter().enumerate() {
|
||||
let stmt = enum_lambda_set_branch(
|
||||
env,
|
||||
join_point_id,
|
||||
lambda_name,
|
||||
closure_data_symbol,
|
||||
closure_layout,
|
||||
argument_symbols,
|
||||
argument_layouts,
|
||||
return_layout,
|
||||
|
@ -9729,15 +9763,14 @@ fn enum_lambda_set_to_switch<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
/// A branch for an enum lambda set branch dispatch, which never capture!
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn enum_lambda_set_branch<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
join_point_id: JoinPointId,
|
||||
lambda_name: LambdaName<'a>,
|
||||
closure_data_symbol: Symbol,
|
||||
closure_data_layout: Layout<'a>,
|
||||
argument_symbols_slice: &'a [Symbol],
|
||||
argument_layouts_slice: &'a [Layout<'a>],
|
||||
argument_symbols: &'a [Symbol],
|
||||
argument_layouts: &'a [Layout<'a>],
|
||||
return_layout: &'a Layout<'a>,
|
||||
) -> Stmt<'a> {
|
||||
let result_symbol = env.unique_symbol();
|
||||
|
@ -9746,34 +9779,6 @@ fn enum_lambda_set_branch<'a>(
|
|||
|
||||
let assigned = result_symbol;
|
||||
|
||||
let (argument_layouts, argument_symbols) = match closure_data_layout {
|
||||
Layout::Struct {
|
||||
field_layouts: &[], ..
|
||||
}
|
||||
| Layout::Builtin(Builtin::Bool)
|
||||
| Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
|
||||
(argument_layouts_slice, argument_symbols_slice)
|
||||
}
|
||||
_ => {
|
||||
// extend layouts with the layout of the closure environment
|
||||
let mut argument_layouts =
|
||||
Vec::with_capacity_in(argument_layouts_slice.len() + 1, env.arena);
|
||||
argument_layouts.extend(argument_layouts_slice);
|
||||
argument_layouts.push(closure_data_layout);
|
||||
|
||||
// extend symbols with the symbol of the closure environment
|
||||
let mut argument_symbols =
|
||||
Vec::with_capacity_in(argument_symbols_slice.len() + 1, env.arena);
|
||||
argument_symbols.extend(argument_symbols_slice);
|
||||
argument_symbols.push(closure_data_symbol);
|
||||
|
||||
(
|
||||
argument_layouts.into_bump_slice(),
|
||||
argument_symbols.into_bump_slice(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let call = self::Call {
|
||||
call_type: CallType::ByName {
|
||||
name: lambda_name,
|
||||
|
|
|
@ -783,28 +783,56 @@ impl<'a> LambdaName<'a> {
|
|||
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct LambdaSet<'a> {
|
||||
/// collection of function names and their closure arguments
|
||||
pub set: &'a [(Symbol, &'a [Layout<'a>])],
|
||||
set: &'a [(Symbol, &'a [Layout<'a>])],
|
||||
/// how the closure will be represented at runtime
|
||||
representation: &'a Layout<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EnumDispatch {
|
||||
Bool,
|
||||
U8,
|
||||
}
|
||||
|
||||
/// representation of the closure *for a particular function*
|
||||
#[derive(Debug)]
|
||||
pub enum ClosureRepresentation<'a> {
|
||||
/// the closure is represented as a union. Includes the tag ID!
|
||||
/// The closure is represented as a union. Includes the tag ID!
|
||||
/// Each variant is a different function, and its payloads are the captures.
|
||||
Union {
|
||||
alphabetic_order_fields: &'a [Layout<'a>],
|
||||
closure_name: Symbol,
|
||||
tag_id: TagIdIntType,
|
||||
union_layout: UnionLayout<'a>,
|
||||
},
|
||||
/// The closure is represented as a struct. The layouts are sorted
|
||||
/// alphabetically by the identifier that is captured.
|
||||
/// The closure is one function, whose captures are represented as a struct.
|
||||
/// The layouts are sorted alphabetically by the identifier that is captured.
|
||||
///
|
||||
/// We MUST sort these according to their stack size before code gen!
|
||||
AlphabeticOrderStruct(&'a [Layout<'a>]),
|
||||
/// the representation is anything but a union
|
||||
Other(Layout<'a>),
|
||||
/// The closure is one function that captures a single identifier, whose value is unwrapped.
|
||||
UnwrappedCapture(Layout<'a>),
|
||||
/// The closure dispatches to multiple functions, but none of them capture anything, so this is
|
||||
/// a boolean or integer flag.
|
||||
EnumDispatch(EnumDispatch),
|
||||
}
|
||||
|
||||
/// How the closure should be seen when determining a call-by-name.
|
||||
#[derive(Debug)]
|
||||
pub enum ClosureCallOptions<'a> {
|
||||
/// This is an empty lambda set, dispatching is an error
|
||||
Void,
|
||||
/// One of a few capturing functions can be called to
|
||||
Union(UnionLayout<'a>),
|
||||
/// The closure is one function, whose captures are represented as a struct.
|
||||
Struct {
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
field_order_hash: FieldOrderHash,
|
||||
},
|
||||
/// The closure is one function that captures a single identifier, whose value is unwrapped.
|
||||
UnwrappedCapture(Layout<'a>),
|
||||
/// The closure dispatches to multiple possible functions, none of which capture.
|
||||
EnumDispatch(EnumDispatch),
|
||||
}
|
||||
|
||||
impl<'a> LambdaSet<'a> {
|
||||
|
@ -818,13 +846,17 @@ impl<'a> LambdaSet<'a> {
|
|||
}
|
||||
|
||||
pub fn is_represented(&self) -> Option<Layout<'a>> {
|
||||
match self.representation {
|
||||
Layout::Struct {
|
||||
field_layouts: &[], ..
|
||||
if self.has_unwrapped_capture_repr() {
|
||||
Some(*self.representation)
|
||||
} else if self.has_enum_dispatch_repr() {
|
||||
None
|
||||
} else {
|
||||
match self.representation {
|
||||
Layout::Struct {
|
||||
field_layouts: &[], ..
|
||||
} => None,
|
||||
repr => Some(*repr),
|
||||
}
|
||||
| Layout::Builtin(Builtin::Bool)
|
||||
| Layout::Builtin(Builtin::Int(..)) => None,
|
||||
repr => Some(*repr),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -835,6 +867,16 @@ impl<'a> LambdaSet<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn len(&self) -> usize {
|
||||
self.set.len()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.set.is_empty()
|
||||
}
|
||||
|
||||
pub fn layout_for_member_with_lambda_name(
|
||||
&self,
|
||||
lambda_name: LambdaName,
|
||||
|
@ -923,6 +965,11 @@ impl<'a> LambdaSet<'a> {
|
|||
where
|
||||
F: Fn(Symbol, &[Layout]) -> bool,
|
||||
{
|
||||
if self.has_unwrapped_capture_repr() {
|
||||
// Only one function, that captures one identifier.
|
||||
return ClosureRepresentation::UnwrappedCapture(*self.representation);
|
||||
}
|
||||
|
||||
match self.representation {
|
||||
Layout::Union(union) => {
|
||||
// here we rely on the fact that a union in a closure would be stored in a one-element record.
|
||||
|
@ -1004,7 +1051,58 @@ impl<'a> LambdaSet<'a> {
|
|||
|
||||
ClosureRepresentation::AlphabeticOrderStruct(fields)
|
||||
}
|
||||
_ => ClosureRepresentation::Other(*self.representation),
|
||||
layout => {
|
||||
debug_assert!(self.has_enum_dispatch_repr(),);
|
||||
let enum_repr = match layout {
|
||||
Layout::Builtin(Builtin::Bool) => EnumDispatch::Bool,
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)) => EnumDispatch::U8,
|
||||
other => internal_error!("Invalid layout for enum dispatch: {:?}", other),
|
||||
};
|
||||
ClosureRepresentation::EnumDispatch(enum_repr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_unwrapped_capture_repr(&self) -> bool {
|
||||
self.set.len() == 1 && self.set[0].1.len() == 1
|
||||
}
|
||||
|
||||
fn has_enum_dispatch_repr(&self) -> bool {
|
||||
self.set.len() > 1 && self.set.iter().all(|(_, captures)| captures.is_empty())
|
||||
}
|
||||
|
||||
pub fn call_by_name_options(&self) -> ClosureCallOptions<'a> {
|
||||
if self.has_unwrapped_capture_repr() {
|
||||
return ClosureCallOptions::UnwrappedCapture(*self.representation);
|
||||
}
|
||||
|
||||
match self.representation {
|
||||
Layout::Union(union_layout) => {
|
||||
if self.representation == &Layout::VOID {
|
||||
debug_assert!(self.set.is_empty());
|
||||
return ClosureCallOptions::Void;
|
||||
}
|
||||
ClosureCallOptions::Union(*union_layout)
|
||||
}
|
||||
Layout::Struct {
|
||||
field_layouts,
|
||||
field_order_hash,
|
||||
} => {
|
||||
debug_assert_eq!(self.set.len(), 1);
|
||||
ClosureCallOptions::Struct {
|
||||
field_layouts,
|
||||
field_order_hash: *field_order_hash,
|
||||
}
|
||||
}
|
||||
layout => {
|
||||
debug_assert!(self.has_enum_dispatch_repr());
|
||||
let enum_repr = match layout {
|
||||
Layout::Builtin(Builtin::Bool) => EnumDispatch::Bool,
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)) => EnumDispatch::U8,
|
||||
other => internal_error!("Invalid layout for enum dispatch: {:?}", other),
|
||||
};
|
||||
ClosureCallOptions::EnumDispatch(enum_repr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1013,30 +1111,27 @@ impl<'a> LambdaSet<'a> {
|
|||
arena: &'a Bump,
|
||||
argument_layouts: &'a [Layout<'a>],
|
||||
) -> &'a [Layout<'a>] {
|
||||
if let [] = self.set {
|
||||
// TERRIBLE HACK for builting functions
|
||||
argument_layouts
|
||||
} else {
|
||||
match self.representation {
|
||||
Layout::Struct {
|
||||
field_layouts: &[], ..
|
||||
} => {
|
||||
// this function does not have anything in its closure, and the lambda set is a
|
||||
// singleton, so we pass no extra argument
|
||||
argument_layouts
|
||||
}
|
||||
Layout::Builtin(Builtin::Bool)
|
||||
| Layout::Builtin(Builtin::Int(IntWidth::I8 | IntWidth::U8)) => {
|
||||
// we don't pass this along either
|
||||
argument_layouts
|
||||
}
|
||||
_ => {
|
||||
let mut arguments = Vec::with_capacity_in(argument_layouts.len() + 1, arena);
|
||||
arguments.extend(argument_layouts);
|
||||
arguments.push(Layout::LambdaSet(*self));
|
||||
match self.call_by_name_options() {
|
||||
ClosureCallOptions::Void => argument_layouts,
|
||||
ClosureCallOptions::Struct {
|
||||
field_layouts: &[], ..
|
||||
} => {
|
||||
// this function does not have anything in its closure, and the lambda set is a
|
||||
// singleton, so we pass no extra argument
|
||||
argument_layouts
|
||||
}
|
||||
ClosureCallOptions::Struct { .. }
|
||||
| ClosureCallOptions::Union(_)
|
||||
| ClosureCallOptions::UnwrappedCapture(_) => {
|
||||
let mut arguments = Vec::with_capacity_in(argument_layouts.len() + 1, arena);
|
||||
arguments.extend(argument_layouts);
|
||||
arguments.push(Layout::LambdaSet(*self));
|
||||
|
||||
arguments.into_bump_slice()
|
||||
}
|
||||
arguments.into_bump_slice()
|
||||
}
|
||||
ClosureCallOptions::EnumDispatch(_) => {
|
||||
// No captures, don't pass this along
|
||||
argument_layouts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1053,7 +1148,7 @@ impl<'a> LambdaSet<'a> {
|
|||
lambdas.sort_by_key(|(sym, _)| *sym);
|
||||
|
||||
let mut set: Vec<(Symbol, &[Layout])> = Vec::with_capacity_in(lambdas.len(), arena);
|
||||
let mut set_with_variables: std::vec::Vec<(Symbol, std::vec::Vec<Variable>)> =
|
||||
let mut set_with_variables: std::vec::Vec<(&Symbol, &[Variable])> =
|
||||
std::vec::Vec::with_capacity(lambdas.len());
|
||||
|
||||
let mut last_function_symbol = None;
|
||||
|
@ -1090,7 +1185,7 @@ impl<'a> LambdaSet<'a> {
|
|||
has_duplicate_lambda_names = has_duplicate_lambda_names || is_multimorphic;
|
||||
|
||||
set.push((*function_symbol, arguments));
|
||||
set_with_variables.push((*function_symbol, variables.to_vec()));
|
||||
set_with_variables.push((function_symbol, variables.as_slice()));
|
||||
|
||||
last_function_symbol = Some(function_symbol);
|
||||
}
|
||||
|
@ -1151,70 +1246,23 @@ impl<'a> LambdaSet<'a> {
|
|||
fn make_representation(
|
||||
arena: &'a Bump,
|
||||
subs: &Subs,
|
||||
tags: std::vec::Vec<(Symbol, std::vec::Vec<Variable>)>,
|
||||
tags: std::vec::Vec<(&Symbol, &[Variable])>,
|
||||
opt_rec_var: Option<Variable>,
|
||||
target_info: TargetInfo,
|
||||
) -> Layout<'a> {
|
||||
if let Some(rec_var) = opt_rec_var {
|
||||
let tags: std::vec::Vec<_> = tags
|
||||
.iter()
|
||||
.map(|(sym, vars)| (sym, vars.as_slice()))
|
||||
.collect();
|
||||
let tags = UnsortedUnionLabels { tags };
|
||||
let mut env = Env {
|
||||
seen: Vec::new_in(arena),
|
||||
target_info,
|
||||
arena,
|
||||
subs,
|
||||
};
|
||||
let union_labels = UnsortedUnionLabels { tags };
|
||||
let mut env = Env {
|
||||
seen: Vec::new_in(arena),
|
||||
target_info,
|
||||
arena,
|
||||
subs,
|
||||
};
|
||||
|
||||
return layout_from_recursive_union(&mut env, rec_var, &tags)
|
||||
.expect("unable to create lambda set representation");
|
||||
}
|
||||
match opt_rec_var {
|
||||
Some(rec_var) => layout_from_recursive_union(&mut env, rec_var, &union_labels)
|
||||
.expect("unable to create lambda set representation"),
|
||||
|
||||
// otherwise, this is a closure with a payload
|
||||
let variant = union_sorted_tags_help(arena, tags, opt_rec_var, subs, target_info);
|
||||
|
||||
use UnionVariant::*;
|
||||
match variant {
|
||||
Never => Layout::VOID,
|
||||
BoolUnion { .. } => Layout::bool(),
|
||||
ByteUnion { .. } => Layout::u8(),
|
||||
Unit | UnitWithArguments => {
|
||||
// no useful information to store
|
||||
Layout::UNIT
|
||||
}
|
||||
Newtype {
|
||||
arguments: layouts, ..
|
||||
} => Layout::struct_no_name_order(layouts.into_bump_slice()),
|
||||
Wrapped(variant) => {
|
||||
use WrappedVariant::*;
|
||||
|
||||
match variant {
|
||||
NonRecursive {
|
||||
sorted_tag_layouts: tags,
|
||||
} => {
|
||||
debug_assert!(tags.len() > 1);
|
||||
|
||||
// if the closed-over value is actually a layout, it should be wrapped in a 1-element record
|
||||
debug_assert!(matches!(tags[0].0, TagOrClosure::Closure(_)));
|
||||
|
||||
let mut tag_arguments = Vec::with_capacity_in(tags.len(), arena);
|
||||
|
||||
for (_, tag_args) in tags.iter() {
|
||||
tag_arguments.push(&tag_args[0..]);
|
||||
}
|
||||
Layout::Union(UnionLayout::NonRecursive(tag_arguments.into_bump_slice()))
|
||||
}
|
||||
|
||||
Recursive { .. }
|
||||
| NullableUnwrapped { .. }
|
||||
| NullableWrapped { .. }
|
||||
| NonNullableUnwrapped { .. } => {
|
||||
internal_error!("Recursive layouts should be produced in an earlier branch")
|
||||
}
|
||||
}
|
||||
}
|
||||
None => layout_from_union(&mut env, &union_labels),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1777,6 +1825,13 @@ impl<'a> Layout<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn runtime_representation(&self) -> Self {
|
||||
match self {
|
||||
Layout::LambdaSet(lambda_set) => lambda_set.runtime_representation(),
|
||||
other => *other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Avoid recomputing Layout from Variable multiple times.
|
||||
|
|
|
@ -38,6 +38,7 @@ pub enum Problem {
|
|||
/// Bool is whether the closure is anonymous
|
||||
/// Second symbol is the name of the argument that is unused
|
||||
UnusedArgument(Symbol, bool, Symbol, Region),
|
||||
UnusedBranchDef(Symbol, Region),
|
||||
PrecedenceProblem(PrecedenceProblem),
|
||||
// Example: (5 = 1 + 2) is an unsupported pattern in an assignment; Int patterns aren't allowed in assignments!
|
||||
UnsupportedPattern(BadPattern, Region),
|
||||
|
|
|
@ -182,7 +182,13 @@ mod solve_expr {
|
|||
|
||||
// Disregard UnusedDef problems, because those are unavoidable when
|
||||
// returning a function from the test expression.
|
||||
can_problems.retain(|prob| !matches!(prob, roc_problem::can::Problem::UnusedDef(_, _)));
|
||||
can_problems.retain(|prob| {
|
||||
!matches!(
|
||||
prob,
|
||||
roc_problem::can::Problem::UnusedDef(_, _)
|
||||
| roc_problem::can::Problem::UnusedBranchDef(..)
|
||||
)
|
||||
});
|
||||
|
||||
let (can_problems, type_problems) =
|
||||
format_problems(&src, home, &interns, can_problems, type_problems);
|
||||
|
|
|
@ -468,9 +468,9 @@ mod encode_immediate {
|
|||
17, u32
|
||||
17, u64
|
||||
17, u128
|
||||
// 17.23, f32 TODO https://github.com/roc-lang/roc/issues/3522
|
||||
17.25, f32
|
||||
17.23, f64
|
||||
// 17.23, dec TODO https://github.com/roc-lang/roc/issues/3522
|
||||
17.23, dec
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1009,3 +1009,25 @@ fn decode_empty_record() {
|
|||
RocStr
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
any(feature = "gen-llvm", feature = "gen-wasm"),
|
||||
not(feature = "gen-llvm-wasm") // hits a wasm3 stack overflow
|
||||
))]
|
||||
fn decode_record_of_record() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" imports [Encode, Decode, Json] provides [main] to "./platform"
|
||||
|
||||
main =
|
||||
when Str.toUtf8 "{\"outer\":{\"inner\":\"a\"},\"other\":{\"one\":\"b\",\"two\":10}}" |> Decode.fromBytes Json.fromUtf8 is
|
||||
Ok {outer: {inner: "a"}, other: {one: "b", two: 10u8}} -> "ab10"
|
||||
_ -> "something went wrong"
|
||||
"#
|
||||
),
|
||||
RocStr::from("ab10"),
|
||||
RocStr
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3369,3 +3369,23 @@ fn issue_3530_uninitialized_capacity_in_list_literal() {
|
|||
|(_, _, cap)| cap
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_let_generalization() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
empty : List a
|
||||
empty = []
|
||||
|
||||
xs : List Str
|
||||
xs = List.append empty "foo"
|
||||
|
||||
List.len xs
|
||||
"#
|
||||
),
|
||||
1,
|
||||
usize
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2091,9 +2091,9 @@ fn float_mul_checked() {
|
|||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn shift_left_by() {
|
||||
assert_evals_to!("Num.shiftLeftBy 0 0b0000_0001", 0b0000_0001, i64);
|
||||
assert_evals_to!("Num.shiftLeftBy 1 0b0000_0001", 0b0000_0010, i64);
|
||||
assert_evals_to!("Num.shiftLeftBy 2 0b0000_0011", 0b0000_1100, i64);
|
||||
assert_evals_to!("Num.shiftLeftBy 0b0000_0001 0", 0b0000_0001, i64);
|
||||
assert_evals_to!("Num.shiftLeftBy 0b0000_0001 1", 0b0000_0010, i64);
|
||||
assert_evals_to!("Num.shiftLeftBy 0b0000_0011 2", 0b0000_1100, i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2105,43 +2105,43 @@ fn shift_right_by() {
|
|||
|
||||
// FIXME (Brian) Something funny happening with 8-bit binary literals in tests
|
||||
assert_evals_to!(
|
||||
"Num.shiftRightBy 2 (Num.toI8 0b1100_0000u8)",
|
||||
"Num.shiftRightBy (Num.toI8 0b1100_0000u8) 2",
|
||||
0b1111_0000u8 as i8,
|
||||
i8
|
||||
);
|
||||
assert_evals_to!("Num.shiftRightBy 2 0b0100_0000i8", 0b0001_0000i8, i8);
|
||||
assert_evals_to!("Num.shiftRightBy 1 0b1110_0000u8", 0b1111_0000u8, u8);
|
||||
assert_evals_to!("Num.shiftRightBy 2 0b1100_0000u8", 0b1111_0000u8, u8);
|
||||
assert_evals_to!("Num.shiftRightBy 12 0b0100_0000u8", 0b0000_0000u8, u8);
|
||||
assert_evals_to!("Num.shiftRightBy 0b0100_0000i8 2", 0b0001_0000i8, i8);
|
||||
assert_evals_to!("Num.shiftRightBy 0b1110_0000u8 1", 0b1111_0000u8, u8);
|
||||
assert_evals_to!("Num.shiftRightBy 0b1100_0000u8 2", 0b1111_0000u8, u8);
|
||||
assert_evals_to!("Num.shiftRightBy 0b0100_0000u8 12", 0b0000_0000u8, u8);
|
||||
|
||||
// LLVM in release mode returns 0 instead of -1 for some reason
|
||||
if !is_llvm_release_mode {
|
||||
assert_evals_to!("Num.shiftRightBy 12 0b1000_0000u8", 0b1111_1111u8, u8);
|
||||
assert_evals_to!("Num.shiftRightBy 0b1000_0000u8 12", 0b1111_1111u8, u8);
|
||||
}
|
||||
assert_evals_to!("Num.shiftRightBy 0 12", 12, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 1 12", 6, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 1 -12", -6, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 8 12", 0, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 8 -12", -1, i64);
|
||||
assert_evals_to!("Num.shiftRightBy -1 12", 0, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 12 0", 12, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 12 1", 6, i64);
|
||||
assert_evals_to!("Num.shiftRightBy -12 1", -6, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 12 8", 0, i64);
|
||||
assert_evals_to!("Num.shiftRightBy -12 8", -1, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 12 -1", 0, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 0 0", 0, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 1 0", 0, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 0 1", 0, i64);
|
||||
|
||||
assert_evals_to!("Num.shiftRightBy 0 12i32", 12, i32);
|
||||
assert_evals_to!("Num.shiftRightBy 1 12i32", 6, i32);
|
||||
assert_evals_to!("Num.shiftRightBy 1 -12i32", -6, i32);
|
||||
assert_evals_to!("Num.shiftRightBy 8 12i32", 0, i32);
|
||||
assert_evals_to!("Num.shiftRightBy 8 -12i32", -1, i32);
|
||||
assert_evals_to!("Num.shiftRightBy 12i32 0", 12, i32);
|
||||
assert_evals_to!("Num.shiftRightBy 12i32 1", 6, i32);
|
||||
assert_evals_to!("Num.shiftRightBy -12i32 1", -6, i32);
|
||||
assert_evals_to!("Num.shiftRightBy 12i32 8", 0, i32);
|
||||
assert_evals_to!("Num.shiftRightBy -12i32 8", -1, i32);
|
||||
|
||||
assert_evals_to!("Num.shiftRightBy 0 12i8", 12, i8);
|
||||
assert_evals_to!("Num.shiftRightBy 1 12i8", 6, i8);
|
||||
assert_evals_to!("Num.shiftRightBy 1 -12i8", -6, i8);
|
||||
assert_evals_to!("Num.shiftRightBy 8 12i8", 0, i8);
|
||||
assert_evals_to!("Num.shiftRightBy 12i8 0", 12, i8);
|
||||
assert_evals_to!("Num.shiftRightBy 12i8 1", 6, i8);
|
||||
assert_evals_to!("Num.shiftRightBy -12i8 1", -6, i8);
|
||||
assert_evals_to!("Num.shiftRightBy 12i8 8", 0, i8);
|
||||
|
||||
if !is_llvm_release_mode {
|
||||
assert_evals_to!("Num.shiftRightBy -1 0", 0, i64);
|
||||
assert_evals_to!("Num.shiftRightBy -1 -12", -1, i64);
|
||||
assert_evals_to!("Num.shiftRightBy 8 -12i8", -1, i8);
|
||||
assert_evals_to!("Num.shiftRightBy 0 -1", 0, i64);
|
||||
assert_evals_to!("Num.shiftRightBy -12 -1", -1, i64);
|
||||
assert_evals_to!("Num.shiftRightBy -12i8 8", -1, i8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2150,14 +2150,14 @@ fn shift_right_by() {
|
|||
fn shift_right_zf_by() {
|
||||
// Logical Right Shift
|
||||
assert_evals_to!(
|
||||
"Num.shiftRightZfBy 2 (Num.toI8 0b1100_0000u8)",
|
||||
"Num.shiftRightZfBy (Num.toI8 0b1100_0000u8) 2",
|
||||
0b0011_0000i8,
|
||||
i8
|
||||
);
|
||||
assert_evals_to!("Num.shiftRightZfBy 2 0b1100_0000u8", 0b0011_0000u8, u8);
|
||||
assert_evals_to!("Num.shiftRightZfBy 1 0b0000_0010u8", 0b0000_0001u8, u8);
|
||||
assert_evals_to!("Num.shiftRightZfBy 2 0b0000_1100u8", 0b0000_0011u8, u8);
|
||||
assert_evals_to!("Num.shiftRightZfBy 12 0b1000_0000u8", 0b0000_0000u8, u8);
|
||||
assert_evals_to!("Num.shiftRightZfBy 0b1100_0000u8 2", 0b0011_0000u8, u8);
|
||||
assert_evals_to!("Num.shiftRightZfBy 0b0000_0010u8 1", 0b0000_0001u8, u8);
|
||||
assert_evals_to!("Num.shiftRightZfBy 0b0000_1100u8 2", 0b0000_0011u8, u8);
|
||||
assert_evals_to!("Num.shiftRightZfBy 0b1000_0000u8 12", 0b0000_0000u8, u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1234,8 +1234,8 @@ fn return_wrapped_closure() {
|
|||
main = foo
|
||||
"#
|
||||
),
|
||||
[5],
|
||||
[i64; 1]
|
||||
5,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4036,5 +4036,26 @@ fn monomorphization_sees_polymorphic_recursion() {
|
|||
),
|
||||
RocStr::from("done"),
|
||||
RocStr
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn int_let_generalization() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
manyAux : {} -> I32
|
||||
manyAux = \_ ->
|
||||
output = \_ -> 42
|
||||
|
||||
output {}
|
||||
|
||||
when manyAux {} is
|
||||
_ -> "done"
|
||||
"#
|
||||
),
|
||||
RocStr::from("done"),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1933,3 +1933,25 @@ fn issue_2165_recursive_tag_destructure() {
|
|||
RocStr
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn tag_union_let_generalization() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
manyAux : {} -> [ Loop, Done ]
|
||||
manyAux = \_ ->
|
||||
output = Done
|
||||
|
||||
output
|
||||
|
||||
when manyAux {} is
|
||||
Loop -> "loop"
|
||||
Done -> "done"
|
||||
"#
|
||||
),
|
||||
RocStr::from("done"),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,17 +4,15 @@ procedure List.6 (#Attr.2):
|
|||
|
||||
procedure Test.1 (Test.5):
|
||||
let Test.2 : I64 = 41i64;
|
||||
let Test.10 : {I64} = Struct {Test.2};
|
||||
let Test.9 : List {I64} = Array [Test.10];
|
||||
let Test.9 : List I64 = Array [Test.2];
|
||||
ret Test.9;
|
||||
|
||||
procedure Test.3 (Test.8, #Attr.12):
|
||||
let Test.2 : I64 = StructAtIndex 0 #Attr.12;
|
||||
procedure Test.3 (Test.8, Test.2):
|
||||
ret Test.2;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.7 : {} = Struct {};
|
||||
let Test.4 : List {I64} = CallByName Test.1 Test.7;
|
||||
let Test.4 : List I64 = CallByName Test.1 Test.7;
|
||||
let Test.6 : U64 = CallByName List.6 Test.4;
|
||||
dec Test.4;
|
||||
ret Test.6;
|
||||
|
|
|
@ -12,22 +12,20 @@ procedure List.71 (#Attr.2, #Attr.3):
|
|||
let List.388 : List U8 = lowlevel ListAppendUnsafe #Attr.2 #Attr.3;
|
||||
ret List.388;
|
||||
|
||||
procedure Test.23 (Test.24, Test.35, #Attr.12):
|
||||
let Test.22 : U8 = StructAtIndex 0 #Attr.12;
|
||||
procedure Test.23 (Test.24, Test.35, Test.22):
|
||||
let Test.37 : List U8 = CallByName List.4 Test.24 Test.22;
|
||||
ret Test.37;
|
||||
|
||||
procedure Test.8 (Test.22):
|
||||
let Test.34 : {U8} = Struct {Test.22};
|
||||
ret Test.34;
|
||||
ret Test.22;
|
||||
|
||||
procedure Test.9 (Test.27):
|
||||
let Test.33 : {U8} = CallByName Test.8 Test.27;
|
||||
let Test.33 : U8 = CallByName Test.8 Test.27;
|
||||
ret Test.33;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.32 : U8 = 15i64;
|
||||
let Test.28 : {U8} = CallByName Test.9 Test.32;
|
||||
let Test.28 : U8 = CallByName Test.9 Test.32;
|
||||
let Test.30 : List U8 = Array [];
|
||||
let Test.31 : {} = Struct {};
|
||||
let Test.29 : List U8 = CallByName Test.23 Test.30 Test.31 Test.28;
|
||||
|
|
|
@ -1,34 +1,26 @@
|
|||
procedure #Derived.0 (#Derived.1):
|
||||
let #Derived_gen.1 : {Str} = Struct {#Derived.1};
|
||||
let #Derived_gen.0 : {Str} = CallByName Encode.22 #Derived_gen.1;
|
||||
let #Derived_gen.0 : Str = CallByName Encode.22 #Derived.1;
|
||||
ret #Derived_gen.0;
|
||||
|
||||
procedure #Derived.2 (#Derived.3, #Derived.4, #Attr.12):
|
||||
let #Derived.1 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.1;
|
||||
dec #Attr.12;
|
||||
procedure #Derived.2 (#Derived.3, #Derived.4, #Derived.1):
|
||||
let #Derived_gen.7 : Str = "a";
|
||||
let #Derived_gen.8 : {Str} = CallByName #Derived.5 #Derived.1;
|
||||
let #Derived_gen.6 : {Str, {Str}} = Struct {#Derived_gen.7, #Derived_gen.8};
|
||||
let #Derived_gen.5 : List {Str, {Str}} = Array [#Derived_gen.6];
|
||||
let #Derived_gen.4 : {List {Str, {Str}}} = CallByName Json.20 #Derived_gen.5;
|
||||
let #Derived_gen.8 : Str = CallByName #Derived.5 #Derived.1;
|
||||
let #Derived_gen.6 : {Str, Str} = Struct {#Derived_gen.7, #Derived_gen.8};
|
||||
let #Derived_gen.5 : List {Str, Str} = Array [#Derived_gen.6];
|
||||
let #Derived_gen.4 : List {Str, Str} = CallByName Json.20 #Derived_gen.5;
|
||||
let #Derived_gen.3 : List U8 = CallByName Encode.23 #Derived.3 #Derived_gen.4 #Derived.4;
|
||||
ret #Derived_gen.3;
|
||||
|
||||
procedure #Derived.5 (#Derived.6):
|
||||
let #Derived_gen.15 : {Str} = Struct {#Derived.6};
|
||||
let #Derived_gen.14 : {Str} = CallByName Encode.22 #Derived_gen.15;
|
||||
let #Derived_gen.14 : Str = CallByName Encode.22 #Derived.6;
|
||||
ret #Derived_gen.14;
|
||||
|
||||
procedure #Derived.7 (#Derived.8, #Derived.9, #Attr.12):
|
||||
let #Derived.6 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.6;
|
||||
dec #Attr.12;
|
||||
procedure #Derived.7 (#Derived.8, #Derived.9, #Derived.6):
|
||||
let #Derived_gen.21 : Str = "b";
|
||||
let #Derived_gen.22 : {Str} = CallByName Json.18 #Derived.6;
|
||||
let #Derived_gen.20 : {Str, {Str}} = Struct {#Derived_gen.21, #Derived_gen.22};
|
||||
let #Derived_gen.19 : List {Str, {Str}} = Array [#Derived_gen.20];
|
||||
let #Derived_gen.18 : {List {Str, {Str}}} = CallByName Json.20 #Derived_gen.19;
|
||||
let #Derived_gen.22 : Str = CallByName Json.18 #Derived.6;
|
||||
let #Derived_gen.20 : {Str, Str} = Struct {#Derived_gen.21, #Derived_gen.22};
|
||||
let #Derived_gen.19 : List {Str, Str} = Array [#Derived_gen.20];
|
||||
let #Derived_gen.18 : List {Str, Str} = CallByName Json.20 #Derived_gen.19;
|
||||
let #Derived_gen.17 : List U8 = CallByName Encode.23 #Derived.8 #Derived_gen.18 #Derived.9;
|
||||
ret #Derived_gen.17;
|
||||
|
||||
|
@ -69,7 +61,7 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {Str} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.105 : Str = CallByName #Derived.0 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
|
@ -77,10 +69,7 @@ procedure Json.1 ():
|
|||
let Json.318 : {} = Struct {};
|
||||
ret Json.318;
|
||||
|
||||
procedure Json.103 (Json.104, Json.321, #Attr.12):
|
||||
let Json.102 : List {Str, {Str}} = StructAtIndex 0 #Attr.12;
|
||||
inc Json.102;
|
||||
dec #Attr.12;
|
||||
procedure Json.103 (Json.104, Json.321, Json.102):
|
||||
let Json.354 : I32 = 123i64;
|
||||
let Json.353 : U8 = CallByName Num.123 Json.354;
|
||||
let Json.106 : List U8 = CallByName List.4 Json.104 Json.353;
|
||||
|
@ -97,10 +86,7 @@ procedure Json.103 (Json.104, Json.321, #Attr.12):
|
|||
let Json.325 : List U8 = CallByName List.4 Json.108 Json.326;
|
||||
ret Json.325;
|
||||
|
||||
procedure Json.103 (Json.104, Json.321, #Attr.12):
|
||||
let Json.102 : List {Str, {Str}} = StructAtIndex 0 #Attr.12;
|
||||
inc Json.102;
|
||||
dec #Attr.12;
|
||||
procedure Json.103 (Json.104, Json.321, Json.102):
|
||||
let Json.397 : I32 = 123i64;
|
||||
let Json.396 : U8 = CallByName Num.123 Json.397;
|
||||
let Json.106 : List U8 = CallByName List.4 Json.104 Json.396;
|
||||
|
@ -120,7 +106,7 @@ procedure Json.103 (Json.104, Json.321, #Attr.12):
|
|||
procedure Json.105 (Json.323, Json.324):
|
||||
let Json.111 : Str = StructAtIndex 0 Json.324;
|
||||
inc Json.111;
|
||||
let Json.112 : {Str} = StructAtIndex 1 Json.324;
|
||||
let Json.112 : Str = StructAtIndex 1 Json.324;
|
||||
inc Json.112;
|
||||
dec Json.324;
|
||||
let Json.109 : List U8 = StructAtIndex 0 Json.323;
|
||||
|
@ -159,7 +145,7 @@ procedure Json.105 (Json.323, Json.324):
|
|||
procedure Json.105 (Json.323, Json.324):
|
||||
let Json.111 : Str = StructAtIndex 0 Json.324;
|
||||
inc Json.111;
|
||||
let Json.112 : {Str} = StructAtIndex 1 Json.324;
|
||||
let Json.112 : Str = StructAtIndex 1 Json.324;
|
||||
inc Json.112;
|
||||
dec Json.324;
|
||||
let Json.109 : List U8 = StructAtIndex 0 Json.323;
|
||||
|
@ -196,24 +182,18 @@ procedure Json.105 (Json.323, Json.324):
|
|||
jump Json.378 Json.113;
|
||||
|
||||
procedure Json.18 (Json.86):
|
||||
let Json.365 : {Str} = Struct {Json.86};
|
||||
let Json.364 : {Str} = CallByName Encode.22 Json.365;
|
||||
let Json.364 : Str = CallByName Encode.22 Json.86;
|
||||
ret Json.364;
|
||||
|
||||
procedure Json.20 (Json.102):
|
||||
let Json.320 : {List {Str, {Str}}} = Struct {Json.102};
|
||||
let Json.319 : {List {Str, {Str}}} = CallByName Encode.22 Json.320;
|
||||
let Json.319 : List {Str, Str} = CallByName Encode.22 Json.102;
|
||||
ret Json.319;
|
||||
|
||||
procedure Json.20 (Json.102):
|
||||
let Json.362 : {List {Str, {Str}}} = Struct {Json.102};
|
||||
let Json.361 : {List {Str, {Str}}} = CallByName Encode.22 Json.362;
|
||||
let Json.361 : List {Str, Str} = CallByName Encode.22 Json.102;
|
||||
ret Json.361;
|
||||
|
||||
procedure Json.87 (Json.88, Json.366, #Attr.12):
|
||||
let Json.86 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.86;
|
||||
dec #Attr.12;
|
||||
procedure Json.87 (Json.88, Json.366, Json.86):
|
||||
let Json.406 : I32 = 34i64;
|
||||
let Json.405 : U8 = CallByName Num.123 Json.406;
|
||||
let Json.403 : List U8 = CallByName List.4 Json.88 Json.405;
|
||||
|
@ -224,21 +204,18 @@ procedure Json.87 (Json.88, Json.366, #Attr.12):
|
|||
let Json.399 : List U8 = CallByName List.4 Json.400 Json.401;
|
||||
ret Json.399;
|
||||
|
||||
procedure List.133 (List.134, List.135, #Attr.12):
|
||||
let List.132 : {} = StructAtIndex 0 #Attr.12;
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.434 : {List U8, U64} = CallByName Json.105 List.134 List.135;
|
||||
let List.433 : [C [], C {List U8, U64}] = TagId(1) List.434;
|
||||
ret List.433;
|
||||
|
||||
procedure List.133 (List.134, List.135, #Attr.12):
|
||||
let List.132 : {} = StructAtIndex 0 #Attr.12;
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.515 : {List U8, U64} = CallByName Json.105 List.134 List.135;
|
||||
let List.514 : [C [], C {List U8, U64}] = TagId(1) List.515;
|
||||
ret List.514;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.411 : {{}} = Struct {List.132};
|
||||
let List.405 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.411;
|
||||
let List.405 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.132;
|
||||
let List.408 : U8 = 1i64;
|
||||
let List.409 : U8 = GetTagId List.405;
|
||||
let List.410 : Int1 = lowlevel Eq List.408 List.409;
|
||||
|
@ -254,8 +231,7 @@ procedure List.18 (List.130, List.131, List.132):
|
|||
ret List.407;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.491 : {{}} = Struct {List.132};
|
||||
let List.485 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.491;
|
||||
let List.485 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.132;
|
||||
let List.488 : U8 = 1i64;
|
||||
let List.489 : U8 = GetTagId List.485;
|
||||
let List.490 : Int1 = lowlevel Eq List.488 List.489;
|
||||
|
@ -289,11 +265,11 @@ procedure List.6 (#Attr.2):
|
|||
ret List.494;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.432 : {Str, {Str}} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
let List.432 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.432;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.513 : {Str, {Str}} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
let List.513 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.513;
|
||||
|
||||
procedure List.69 (#Attr.2):
|
||||
|
@ -328,7 +304,7 @@ procedure List.86 (List.448, List.449, List.450, List.451, List.452):
|
|||
joinpoint List.420 List.364 List.365 List.366 List.367 List.368:
|
||||
let List.422 : Int1 = CallByName Num.22 List.367 List.368;
|
||||
if List.422 then
|
||||
let List.431 : {Str, {Str}} = CallByName List.66 List.364 List.367;
|
||||
let List.431 : {Str, Str} = CallByName List.66 List.364 List.367;
|
||||
let List.423 : [C [], C {List U8, U64}] = CallByName List.133 List.365 List.431 List.366;
|
||||
let List.428 : U8 = 1i64;
|
||||
let List.429 : U8 = GetTagId List.423;
|
||||
|
@ -355,7 +331,7 @@ procedure List.86 (List.529, List.530, List.531, List.532, List.533):
|
|||
joinpoint List.501 List.364 List.365 List.366 List.367 List.368:
|
||||
let List.503 : Int1 = CallByName Num.22 List.367 List.368;
|
||||
if List.503 then
|
||||
let List.512 : {Str, {Str}} = CallByName List.66 List.364 List.367;
|
||||
let List.512 : {Str, Str} = CallByName List.66 List.364 List.367;
|
||||
let List.504 : [C [], C {List U8, U64}] = CallByName List.133 List.365 List.512 List.366;
|
||||
let List.509 : U8 = 1i64;
|
||||
let List.510 : U8 = GetTagId List.504;
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
procedure #Derived.0 (#Derived.1):
|
||||
let #Derived_gen.1 : {Str} = Struct {#Derived.1};
|
||||
let #Derived_gen.0 : {Str} = CallByName Encode.22 #Derived_gen.1;
|
||||
let #Derived_gen.0 : Str = CallByName Encode.22 #Derived.1;
|
||||
ret #Derived_gen.0;
|
||||
|
||||
procedure #Derived.2 (#Derived.3, #Derived.4, #Attr.12):
|
||||
let #Derived.1 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.1;
|
||||
dec #Attr.12;
|
||||
procedure #Derived.2 (#Derived.3, #Derived.4, #Derived.1):
|
||||
let #Derived_gen.7 : Str = "a";
|
||||
let #Derived_gen.8 : {Str} = CallByName Json.18 #Derived.1;
|
||||
let #Derived_gen.6 : {Str, {Str}} = Struct {#Derived_gen.7, #Derived_gen.8};
|
||||
let #Derived_gen.5 : List {Str, {Str}} = Array [#Derived_gen.6];
|
||||
let #Derived_gen.4 : {List {Str, {Str}}} = CallByName Json.20 #Derived_gen.5;
|
||||
let #Derived_gen.8 : Str = CallByName Json.18 #Derived.1;
|
||||
let #Derived_gen.6 : {Str, Str} = Struct {#Derived_gen.7, #Derived_gen.8};
|
||||
let #Derived_gen.5 : List {Str, Str} = Array [#Derived_gen.6];
|
||||
let #Derived_gen.4 : List {Str, Str} = CallByName Json.20 #Derived_gen.5;
|
||||
let #Derived_gen.3 : List U8 = CallByName Encode.23 #Derived.3 #Derived_gen.4 #Derived.4;
|
||||
ret #Derived_gen.3;
|
||||
|
||||
|
@ -38,7 +34,7 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {Str} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.105 : Str = CallByName #Derived.0 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
|
@ -46,10 +42,7 @@ procedure Json.1 ():
|
|||
let Json.318 : {} = Struct {};
|
||||
ret Json.318;
|
||||
|
||||
procedure Json.103 (Json.104, Json.321, #Attr.12):
|
||||
let Json.102 : List {Str, {Str}} = StructAtIndex 0 #Attr.12;
|
||||
inc Json.102;
|
||||
dec #Attr.12;
|
||||
procedure Json.103 (Json.104, Json.321, Json.102):
|
||||
let Json.357 : I32 = 123i64;
|
||||
let Json.356 : U8 = CallByName Num.123 Json.357;
|
||||
let Json.106 : List U8 = CallByName List.4 Json.104 Json.356;
|
||||
|
@ -69,7 +62,7 @@ procedure Json.103 (Json.104, Json.321, #Attr.12):
|
|||
procedure Json.105 (Json.326, Json.327):
|
||||
let Json.111 : Str = StructAtIndex 0 Json.327;
|
||||
inc Json.111;
|
||||
let Json.112 : {Str} = StructAtIndex 1 Json.327;
|
||||
let Json.112 : Str = StructAtIndex 1 Json.327;
|
||||
inc Json.112;
|
||||
dec Json.327;
|
||||
let Json.109 : List U8 = StructAtIndex 0 Json.326;
|
||||
|
@ -106,19 +99,14 @@ procedure Json.105 (Json.326, Json.327):
|
|||
jump Json.338 Json.113;
|
||||
|
||||
procedure Json.18 (Json.86):
|
||||
let Json.323 : {Str} = Struct {Json.86};
|
||||
let Json.322 : {Str} = CallByName Encode.22 Json.323;
|
||||
let Json.322 : Str = CallByName Encode.22 Json.86;
|
||||
ret Json.322;
|
||||
|
||||
procedure Json.20 (Json.102):
|
||||
let Json.320 : {List {Str, {Str}}} = Struct {Json.102};
|
||||
let Json.319 : {List {Str, {Str}}} = CallByName Encode.22 Json.320;
|
||||
let Json.319 : List {Str, Str} = CallByName Encode.22 Json.102;
|
||||
ret Json.319;
|
||||
|
||||
procedure Json.87 (Json.88, Json.324, #Attr.12):
|
||||
let Json.86 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.86;
|
||||
dec #Attr.12;
|
||||
procedure Json.87 (Json.88, Json.324, Json.86):
|
||||
let Json.366 : I32 = 34i64;
|
||||
let Json.365 : U8 = CallByName Num.123 Json.366;
|
||||
let Json.363 : List U8 = CallByName List.4 Json.88 Json.365;
|
||||
|
@ -129,15 +117,13 @@ procedure Json.87 (Json.88, Json.324, #Attr.12):
|
|||
let Json.359 : List U8 = CallByName List.4 Json.360 Json.361;
|
||||
ret Json.359;
|
||||
|
||||
procedure List.133 (List.134, List.135, #Attr.12):
|
||||
let List.132 : {} = StructAtIndex 0 #Attr.12;
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.441 : {List U8, U64} = CallByName Json.105 List.134 List.135;
|
||||
let List.440 : [C [], C {List U8, U64}] = TagId(1) List.441;
|
||||
ret List.440;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.417 : {{}} = Struct {List.132};
|
||||
let List.411 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.417;
|
||||
let List.411 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.132;
|
||||
let List.414 : U8 = 1i64;
|
||||
let List.415 : U8 = GetTagId List.411;
|
||||
let List.416 : Int1 = lowlevel Eq List.414 List.415;
|
||||
|
@ -167,7 +153,7 @@ procedure List.6 (#Attr.2):
|
|||
ret List.420;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.439 : {Str, {Str}} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
let List.439 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.439;
|
||||
|
||||
procedure List.69 (#Attr.2):
|
||||
|
@ -196,7 +182,7 @@ procedure List.86 (List.455, List.456, List.457, List.458, List.459):
|
|||
joinpoint List.427 List.364 List.365 List.366 List.367 List.368:
|
||||
let List.429 : Int1 = CallByName Num.22 List.367 List.368;
|
||||
if List.429 then
|
||||
let List.438 : {Str, {Str}} = CallByName List.66 List.364 List.367;
|
||||
let List.438 : {Str, Str} = CallByName List.66 List.364 List.367;
|
||||
let List.430 : [C [], C {List U8, U64}] = CallByName List.133 List.365 List.438 List.366;
|
||||
let List.435 : U8 = 1i64;
|
||||
let List.436 : U8 = GetTagId List.430;
|
||||
|
|
|
@ -1,25 +1,21 @@
|
|||
procedure #Derived.0 (#Derived.1):
|
||||
let #Derived_gen.1 : {{Str, Str}} = Struct {#Derived.1};
|
||||
let #Derived_gen.0 : {{Str, Str}} = CallByName Encode.22 #Derived_gen.1;
|
||||
let #Derived_gen.0 : {Str, Str} = CallByName Encode.22 #Derived.1;
|
||||
ret #Derived_gen.0;
|
||||
|
||||
procedure #Derived.2 (#Derived.3, #Derived.4, #Attr.12):
|
||||
let #Derived.1 : {Str, Str} = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.1;
|
||||
dec #Attr.12;
|
||||
procedure #Derived.2 (#Derived.3, #Derived.4, #Derived.1):
|
||||
let #Derived_gen.11 : Str = "a";
|
||||
let #Derived_gen.13 : Str = StructAtIndex 0 #Derived.1;
|
||||
inc #Derived_gen.13;
|
||||
let #Derived_gen.12 : {Str} = CallByName Json.18 #Derived_gen.13;
|
||||
let #Derived_gen.6 : {Str, {Str}} = Struct {#Derived_gen.11, #Derived_gen.12};
|
||||
let #Derived_gen.12 : Str = CallByName Json.18 #Derived_gen.13;
|
||||
let #Derived_gen.6 : {Str, Str} = Struct {#Derived_gen.11, #Derived_gen.12};
|
||||
let #Derived_gen.8 : Str = "b";
|
||||
let #Derived_gen.10 : Str = StructAtIndex 1 #Derived.1;
|
||||
inc #Derived_gen.10;
|
||||
dec #Derived.1;
|
||||
let #Derived_gen.9 : {Str} = CallByName Json.18 #Derived_gen.10;
|
||||
let #Derived_gen.7 : {Str, {Str}} = Struct {#Derived_gen.8, #Derived_gen.9};
|
||||
let #Derived_gen.5 : List {Str, {Str}} = Array [#Derived_gen.6, #Derived_gen.7];
|
||||
let #Derived_gen.4 : {List {Str, {Str}}} = CallByName Json.20 #Derived_gen.5;
|
||||
let #Derived_gen.9 : Str = CallByName Json.18 #Derived_gen.10;
|
||||
let #Derived_gen.7 : {Str, Str} = Struct {#Derived_gen.8, #Derived_gen.9};
|
||||
let #Derived_gen.5 : List {Str, Str} = Array [#Derived_gen.6, #Derived_gen.7];
|
||||
let #Derived_gen.4 : List {Str, Str} = CallByName Json.20 #Derived_gen.5;
|
||||
let #Derived_gen.3 : List U8 = CallByName Encode.23 #Derived.3 #Derived_gen.4 #Derived.4;
|
||||
ret #Derived_gen.3;
|
||||
|
||||
|
@ -46,7 +42,7 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {{Str, Str}} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.105 : {Str, Str} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
|
@ -54,10 +50,7 @@ procedure Json.1 ():
|
|||
let Json.318 : {} = Struct {};
|
||||
ret Json.318;
|
||||
|
||||
procedure Json.103 (Json.104, Json.321, #Attr.12):
|
||||
let Json.102 : List {Str, {Str}} = StructAtIndex 0 #Attr.12;
|
||||
inc Json.102;
|
||||
dec #Attr.12;
|
||||
procedure Json.103 (Json.104, Json.321, Json.102):
|
||||
let Json.360 : I32 = 123i64;
|
||||
let Json.359 : U8 = CallByName Num.123 Json.360;
|
||||
let Json.106 : List U8 = CallByName List.4 Json.104 Json.359;
|
||||
|
@ -77,7 +70,7 @@ procedure Json.103 (Json.104, Json.321, #Attr.12):
|
|||
procedure Json.105 (Json.329, Json.330):
|
||||
let Json.111 : Str = StructAtIndex 0 Json.330;
|
||||
inc Json.111;
|
||||
let Json.112 : {Str} = StructAtIndex 1 Json.330;
|
||||
let Json.112 : Str = StructAtIndex 1 Json.330;
|
||||
inc Json.112;
|
||||
dec Json.330;
|
||||
let Json.109 : List U8 = StructAtIndex 0 Json.329;
|
||||
|
@ -114,19 +107,14 @@ procedure Json.105 (Json.329, Json.330):
|
|||
jump Json.341 Json.113;
|
||||
|
||||
procedure Json.18 (Json.86):
|
||||
let Json.326 : {Str} = Struct {Json.86};
|
||||
let Json.325 : {Str} = CallByName Encode.22 Json.326;
|
||||
let Json.325 : Str = CallByName Encode.22 Json.86;
|
||||
ret Json.325;
|
||||
|
||||
procedure Json.20 (Json.102):
|
||||
let Json.320 : {List {Str, {Str}}} = Struct {Json.102};
|
||||
let Json.319 : {List {Str, {Str}}} = CallByName Encode.22 Json.320;
|
||||
let Json.319 : List {Str, Str} = CallByName Encode.22 Json.102;
|
||||
ret Json.319;
|
||||
|
||||
procedure Json.87 (Json.88, Json.324, #Attr.12):
|
||||
let Json.86 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.86;
|
||||
dec #Attr.12;
|
||||
procedure Json.87 (Json.88, Json.324, Json.86):
|
||||
let Json.369 : I32 = 34i64;
|
||||
let Json.368 : U8 = CallByName Num.123 Json.369;
|
||||
let Json.366 : List U8 = CallByName List.4 Json.88 Json.368;
|
||||
|
@ -137,15 +125,13 @@ procedure Json.87 (Json.88, Json.324, #Attr.12):
|
|||
let Json.362 : List U8 = CallByName List.4 Json.363 Json.364;
|
||||
ret Json.362;
|
||||
|
||||
procedure List.133 (List.134, List.135, #Attr.12):
|
||||
let List.132 : {} = StructAtIndex 0 #Attr.12;
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.441 : {List U8, U64} = CallByName Json.105 List.134 List.135;
|
||||
let List.440 : [C [], C {List U8, U64}] = TagId(1) List.441;
|
||||
ret List.440;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.417 : {{}} = Struct {List.132};
|
||||
let List.411 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.417;
|
||||
let List.411 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.132;
|
||||
let List.414 : U8 = 1i64;
|
||||
let List.415 : U8 = GetTagId List.411;
|
||||
let List.416 : Int1 = lowlevel Eq List.414 List.415;
|
||||
|
@ -175,7 +161,7 @@ procedure List.6 (#Attr.2):
|
|||
ret List.420;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.439 : {Str, {Str}} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
let List.439 : {Str, Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.439;
|
||||
|
||||
procedure List.69 (#Attr.2):
|
||||
|
@ -204,7 +190,7 @@ procedure List.86 (List.455, List.456, List.457, List.458, List.459):
|
|||
joinpoint List.427 List.364 List.365 List.366 List.367 List.368:
|
||||
let List.429 : Int1 = CallByName Num.22 List.367 List.368;
|
||||
if List.429 then
|
||||
let List.438 : {Str, {Str}} = CallByName List.66 List.364 List.367;
|
||||
let List.438 : {Str, Str} = CallByName List.66 List.364 List.367;
|
||||
let List.430 : [C [], C {List U8, U64}] = CallByName List.133 List.365 List.438 List.366;
|
||||
let List.435 : U8 = 1i64;
|
||||
let List.436 : U8 = GetTagId List.430;
|
||||
|
|
|
@ -7,7 +7,7 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {Str} = CallByName Json.18 Encode.100;
|
||||
let Encode.105 : Str = CallByName Json.18 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
|
@ -16,14 +16,10 @@ procedure Json.1 ():
|
|||
ret Json.318;
|
||||
|
||||
procedure Json.18 (Json.86):
|
||||
let Json.320 : {Str} = Struct {Json.86};
|
||||
let Json.319 : {Str} = CallByName Encode.22 Json.320;
|
||||
let Json.319 : Str = CallByName Encode.22 Json.86;
|
||||
ret Json.319;
|
||||
|
||||
procedure Json.87 (Json.88, Json.321, #Attr.12):
|
||||
let Json.86 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.86;
|
||||
dec #Attr.12;
|
||||
procedure Json.87 (Json.88, Json.321, Json.86):
|
||||
let Json.330 : I32 = 34i64;
|
||||
let Json.329 : U8 = CallByName Num.123 Json.330;
|
||||
let Json.327 : List U8 = CallByName List.4 Json.88 Json.329;
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
procedure #Derived.0 (#Derived.1):
|
||||
let #Derived_gen.1 : {Str} = Struct {#Derived.1};
|
||||
let #Derived_gen.0 : {Str} = CallByName Encode.22 #Derived_gen.1;
|
||||
let #Derived_gen.0 : Str = CallByName Encode.22 #Derived.1;
|
||||
ret #Derived_gen.0;
|
||||
|
||||
procedure #Derived.3 (#Derived.4, #Derived.5, #Attr.12):
|
||||
let #Derived.1 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.1;
|
||||
dec #Attr.12;
|
||||
procedure #Derived.3 (#Derived.4, #Derived.5, #Derived.1):
|
||||
joinpoint #Derived_gen.5 #Derived_gen.4:
|
||||
let #Derived_gen.3 : List U8 = CallByName Encode.23 #Derived.4 #Derived_gen.4 #Derived.5;
|
||||
ret #Derived_gen.3;
|
||||
in
|
||||
let #Derived_gen.7 : Str = "A";
|
||||
let #Derived_gen.9 : {Str} = CallByName Json.18 #Derived.1;
|
||||
let #Derived_gen.8 : List {Str} = Array [#Derived_gen.9];
|
||||
let #Derived_gen.6 : {Str, List {Str}} = CallByName Json.21 #Derived_gen.7 #Derived_gen.8;
|
||||
let #Derived_gen.9 : Str = CallByName Json.18 #Derived.1;
|
||||
let #Derived_gen.8 : List Str = Array [#Derived_gen.9];
|
||||
let #Derived_gen.6 : {Str, List Str} = CallByName Json.21 #Derived_gen.7 #Derived_gen.8;
|
||||
jump #Derived_gen.5 #Derived_gen.6;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
|
@ -40,7 +36,7 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {Str} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.105 : Str = CallByName #Derived.0 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
|
@ -49,7 +45,7 @@ procedure Json.1 ():
|
|||
ret Json.318;
|
||||
|
||||
procedure Json.117 (Json.118, Json.321, #Attr.12):
|
||||
let Json.116 : List {Str} = StructAtIndex 1 #Attr.12;
|
||||
let Json.116 : List Str = StructAtIndex 1 #Attr.12;
|
||||
inc Json.116;
|
||||
let Json.115 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.115;
|
||||
|
@ -111,19 +107,15 @@ procedure Json.119 (Json.326, Json.125):
|
|||
jump Json.340 Json.126;
|
||||
|
||||
procedure Json.18 (Json.86):
|
||||
let Json.323 : {Str} = Struct {Json.86};
|
||||
let Json.322 : {Str} = CallByName Encode.22 Json.323;
|
||||
let Json.322 : Str = CallByName Encode.22 Json.86;
|
||||
ret Json.322;
|
||||
|
||||
procedure Json.21 (Json.115, Json.116):
|
||||
let Json.320 : {Str, List {Str}} = Struct {Json.115, Json.116};
|
||||
let Json.319 : {Str, List {Str}} = CallByName Encode.22 Json.320;
|
||||
let Json.320 : {Str, List Str} = Struct {Json.115, Json.116};
|
||||
let Json.319 : {Str, List Str} = CallByName Encode.22 Json.320;
|
||||
ret Json.319;
|
||||
|
||||
procedure Json.87 (Json.88, Json.324, #Attr.12):
|
||||
let Json.86 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.86;
|
||||
dec #Attr.12;
|
||||
procedure Json.87 (Json.88, Json.324, Json.86):
|
||||
let Json.371 : I32 = 34i64;
|
||||
let Json.370 : U8 = CallByName Num.123 Json.371;
|
||||
let Json.368 : List U8 = CallByName List.4 Json.88 Json.370;
|
||||
|
@ -134,15 +126,13 @@ procedure Json.87 (Json.88, Json.324, #Attr.12):
|
|||
let Json.364 : List U8 = CallByName List.4 Json.365 Json.366;
|
||||
ret Json.364;
|
||||
|
||||
procedure List.133 (List.134, List.135, #Attr.12):
|
||||
let List.132 : {} = StructAtIndex 0 #Attr.12;
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.447 : {List U8, U64} = CallByName Json.119 List.134 List.135;
|
||||
let List.446 : [C [], C {List U8, U64}] = TagId(1) List.447;
|
||||
ret List.446;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.423 : {{}} = Struct {List.132};
|
||||
let List.417 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.423;
|
||||
let List.417 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.132;
|
||||
let List.420 : U8 = 1i64;
|
||||
let List.421 : U8 = GetTagId List.417;
|
||||
let List.422 : Int1 = lowlevel Eq List.420 List.421;
|
||||
|
@ -172,7 +162,7 @@ procedure List.6 (#Attr.2):
|
|||
ret List.424;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.445 : {Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
let List.445 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.445;
|
||||
|
||||
procedure List.69 (#Attr.2):
|
||||
|
@ -201,7 +191,7 @@ procedure List.86 (List.461, List.462, List.463, List.464, List.465):
|
|||
joinpoint List.433 List.364 List.365 List.366 List.367 List.368:
|
||||
let List.435 : Int1 = CallByName Num.22 List.367 List.368;
|
||||
if List.435 then
|
||||
let List.444 : {Str} = CallByName List.66 List.364 List.367;
|
||||
let List.444 : Str = CallByName List.66 List.364 List.367;
|
||||
let List.436 : [C [], C {List U8, U64}] = CallByName List.133 List.365 List.444 List.366;
|
||||
let List.441 : U8 = 1i64;
|
||||
let List.442 : U8 = GetTagId List.436;
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
procedure #Derived.0 (#Derived.1):
|
||||
let #Derived_gen.1 : {{Str, Str}} = Struct {#Derived.1};
|
||||
let #Derived_gen.0 : {{Str, Str}} = CallByName Encode.22 #Derived_gen.1;
|
||||
let #Derived_gen.0 : {Str, Str} = CallByName Encode.22 #Derived.1;
|
||||
ret #Derived_gen.0;
|
||||
|
||||
procedure #Derived.4 (#Derived.5, #Derived.6, #Attr.12):
|
||||
let #Derived.1 : {Str, Str} = StructAtIndex 0 #Attr.12;
|
||||
inc #Derived.1;
|
||||
dec #Attr.12;
|
||||
procedure #Derived.4 (#Derived.5, #Derived.6, #Derived.1):
|
||||
joinpoint #Derived_gen.5 #Derived_gen.4:
|
||||
let #Derived_gen.3 : List U8 = CallByName Encode.23 #Derived.5 #Derived_gen.4 #Derived.6;
|
||||
ret #Derived_gen.3;
|
||||
|
@ -17,10 +13,10 @@ procedure #Derived.4 (#Derived.5, #Derived.6, #Attr.12):
|
|||
inc #Derived.3;
|
||||
dec #Derived.1;
|
||||
let #Derived_gen.7 : Str = "A";
|
||||
let #Derived_gen.9 : {Str} = CallByName Json.18 #Derived.2;
|
||||
let #Derived_gen.10 : {Str} = CallByName Json.18 #Derived.3;
|
||||
let #Derived_gen.8 : List {Str} = Array [#Derived_gen.9, #Derived_gen.10];
|
||||
let #Derived_gen.6 : {Str, List {Str}} = CallByName Json.21 #Derived_gen.7 #Derived_gen.8;
|
||||
let #Derived_gen.9 : Str = CallByName Json.18 #Derived.2;
|
||||
let #Derived_gen.10 : Str = CallByName Json.18 #Derived.3;
|
||||
let #Derived_gen.8 : List Str = Array [#Derived_gen.9, #Derived_gen.10];
|
||||
let #Derived_gen.6 : {Str, List Str} = CallByName Json.21 #Derived_gen.7 #Derived_gen.8;
|
||||
jump #Derived_gen.5 #Derived_gen.6;
|
||||
|
||||
procedure Encode.22 (Encode.93):
|
||||
|
@ -46,7 +42,7 @@ procedure Encode.23 (Encode.94, Encode.102, Encode.96):
|
|||
|
||||
procedure Encode.25 (Encode.100, Encode.101):
|
||||
let Encode.104 : List U8 = Array [];
|
||||
let Encode.105 : {{Str, Str}} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.105 : {Str, Str} = CallByName #Derived.0 Encode.100;
|
||||
let Encode.103 : List U8 = CallByName Encode.23 Encode.104 Encode.105 Encode.101;
|
||||
ret Encode.103;
|
||||
|
||||
|
@ -55,7 +51,7 @@ procedure Json.1 ():
|
|||
ret Json.318;
|
||||
|
||||
procedure Json.117 (Json.118, Json.321, #Attr.12):
|
||||
let Json.116 : List {Str} = StructAtIndex 1 #Attr.12;
|
||||
let Json.116 : List Str = StructAtIndex 1 #Attr.12;
|
||||
inc Json.116;
|
||||
let Json.115 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.115;
|
||||
|
@ -117,19 +113,15 @@ procedure Json.119 (Json.329, Json.125):
|
|||
jump Json.343 Json.126;
|
||||
|
||||
procedure Json.18 (Json.86):
|
||||
let Json.326 : {Str} = Struct {Json.86};
|
||||
let Json.325 : {Str} = CallByName Encode.22 Json.326;
|
||||
let Json.325 : Str = CallByName Encode.22 Json.86;
|
||||
ret Json.325;
|
||||
|
||||
procedure Json.21 (Json.115, Json.116):
|
||||
let Json.320 : {Str, List {Str}} = Struct {Json.115, Json.116};
|
||||
let Json.319 : {Str, List {Str}} = CallByName Encode.22 Json.320;
|
||||
let Json.320 : {Str, List Str} = Struct {Json.115, Json.116};
|
||||
let Json.319 : {Str, List Str} = CallByName Encode.22 Json.320;
|
||||
ret Json.319;
|
||||
|
||||
procedure Json.87 (Json.88, Json.324, #Attr.12):
|
||||
let Json.86 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Json.86;
|
||||
dec #Attr.12;
|
||||
procedure Json.87 (Json.88, Json.324, Json.86):
|
||||
let Json.374 : I32 = 34i64;
|
||||
let Json.373 : U8 = CallByName Num.123 Json.374;
|
||||
let Json.371 : List U8 = CallByName List.4 Json.88 Json.373;
|
||||
|
@ -140,15 +132,13 @@ procedure Json.87 (Json.88, Json.324, #Attr.12):
|
|||
let Json.367 : List U8 = CallByName List.4 Json.368 Json.369;
|
||||
ret Json.367;
|
||||
|
||||
procedure List.133 (List.134, List.135, #Attr.12):
|
||||
let List.132 : {} = StructAtIndex 0 #Attr.12;
|
||||
procedure List.133 (List.134, List.135, List.132):
|
||||
let List.447 : {List U8, U64} = CallByName Json.119 List.134 List.135;
|
||||
let List.446 : [C [], C {List U8, U64}] = TagId(1) List.447;
|
||||
ret List.446;
|
||||
|
||||
procedure List.18 (List.130, List.131, List.132):
|
||||
let List.423 : {{}} = Struct {List.132};
|
||||
let List.417 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.423;
|
||||
let List.417 : [C [], C {List U8, U64}] = CallByName List.75 List.130 List.131 List.132;
|
||||
let List.420 : U8 = 1i64;
|
||||
let List.421 : U8 = GetTagId List.417;
|
||||
let List.422 : Int1 = lowlevel Eq List.420 List.421;
|
||||
|
@ -178,7 +168,7 @@ procedure List.6 (#Attr.2):
|
|||
ret List.424;
|
||||
|
||||
procedure List.66 (#Attr.2, #Attr.3):
|
||||
let List.445 : {Str} = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
let List.445 : Str = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
ret List.445;
|
||||
|
||||
procedure List.69 (#Attr.2):
|
||||
|
@ -207,7 +197,7 @@ procedure List.86 (List.461, List.462, List.463, List.464, List.465):
|
|||
joinpoint List.433 List.364 List.365 List.366 List.367 List.368:
|
||||
let List.435 : Int1 = CallByName Num.22 List.367 List.368;
|
||||
if List.435 then
|
||||
let List.444 : {Str} = CallByName List.66 List.364 List.367;
|
||||
let List.444 : Str = CallByName List.66 List.364 List.367;
|
||||
let List.436 : [C [], C {List U8, U64}] = CallByName List.133 List.365 List.444 List.366;
|
||||
let List.441 : U8 = 1i64;
|
||||
let List.442 : U8 = GetTagId List.436;
|
||||
|
|
|
@ -2,10 +2,7 @@ procedure Test.11 (Test.37):
|
|||
let Test.38 : Str = "";
|
||||
ret Test.38;
|
||||
|
||||
procedure Test.13 (Test.51, #Attr.12):
|
||||
let Test.12 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Test.12;
|
||||
dec #Attr.12;
|
||||
procedure Test.13 (Test.51, Test.12):
|
||||
ret Test.12;
|
||||
|
||||
procedure Test.15 (Test.39):
|
||||
|
@ -29,8 +26,8 @@ procedure Test.3 (Test.17):
|
|||
ret Test.36;
|
||||
|
||||
procedure Test.4 (Test.18):
|
||||
let Test.50 : {Str} = Struct {Test.18};
|
||||
ret Test.50;
|
||||
inc Test.18;
|
||||
ret Test.18;
|
||||
|
||||
procedure Test.9 (Test.29, #Attr.12):
|
||||
let Test.8 : {} = UnionAtIndex (Id 0) (Index 1) #Attr.12;
|
||||
|
@ -48,7 +45,8 @@ procedure Test.9 (Test.29, #Attr.12):
|
|||
let Test.7 : {} = UnionAtIndex (Id 1) (Index 0) #Attr.12;
|
||||
let Test.49 : {} = Struct {};
|
||||
let Test.48 : Str = CallByName Test.16 Test.49;
|
||||
let Test.45 : {Str} = CallByName Test.4 Test.48;
|
||||
let Test.45 : Str = CallByName Test.4 Test.48;
|
||||
dec Test.48;
|
||||
let Test.47 : {} = Struct {};
|
||||
let Test.46 : Str = CallByName Test.13 Test.47 Test.45;
|
||||
ret Test.46;
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
procedure Test.1 (Test.4):
|
||||
let Test.5 : {Str} = Struct {Test.4};
|
||||
ret Test.5;
|
||||
|
||||
procedure Test.5 (Test.12, #Attr.12):
|
||||
let Test.4 : Str = StructAtIndex 0 #Attr.12;
|
||||
inc Test.4;
|
||||
dec #Attr.12;
|
||||
ret Test.4;
|
||||
|
||||
procedure Test.5 (Test.12, Test.4):
|
||||
dec Test.4;
|
||||
let Test.14 : Str = "";
|
||||
ret Test.14;
|
||||
|
||||
|
@ -18,9 +16,11 @@ procedure Test.0 ():
|
|||
let Test.20 : Int1 = lowlevel Eq Test.19 Test.2;
|
||||
if Test.20 then
|
||||
let Test.15 : Str = "";
|
||||
let Test.10 : {Str} = CallByName Test.1 Test.15;
|
||||
let Test.10 : Str = CallByName Test.1 Test.15;
|
||||
dec Test.15;
|
||||
jump Test.9 Test.10;
|
||||
else
|
||||
let Test.18 : Str = "";
|
||||
let Test.16 : {Str} = CallByName Test.1 Test.18;
|
||||
let Test.16 : Str = CallByName Test.1 Test.18;
|
||||
dec Test.18;
|
||||
jump Test.9 Test.16;
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
procedure Test.1 (Test.5):
|
||||
let Test.2 : I64 = 42i64;
|
||||
let Test.3 : {I64} = Struct {Test.2};
|
||||
ret Test.3;
|
||||
ret Test.2;
|
||||
|
||||
procedure Test.3 (Test.9, #Attr.12):
|
||||
let Test.2 : I64 = StructAtIndex 0 #Attr.12;
|
||||
procedure Test.3 (Test.9, Test.2):
|
||||
ret Test.2;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.8 : {} = Struct {};
|
||||
let Test.4 : {I64} = CallByName Test.1 Test.8;
|
||||
let Test.4 : I64 = CallByName Test.1 Test.8;
|
||||
let Test.7 : {} = Struct {};
|
||||
let Test.6 : I64 = CallByName Test.3 Test.7 Test.4;
|
||||
ret Test.6;
|
||||
|
|
|
@ -4,20 +4,17 @@ procedure Num.19 (#Attr.2, #Attr.3):
|
|||
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.9 : U32 = 0i64;
|
||||
let Test.16 : {U32} = Struct {Test.2};
|
||||
let Test.8 : U32 = CallByName Test.3 Test.9 Test.16;
|
||||
let Test.8 : U32 = CallByName Test.3 Test.9 Test.2;
|
||||
ret Test.8;
|
||||
|
||||
procedure Test.3 (Test.18, Test.19):
|
||||
joinpoint Test.10 Test.4 #Attr.12:
|
||||
let Test.2 : U32 = StructAtIndex 0 #Attr.12;
|
||||
joinpoint Test.10 Test.4 Test.2:
|
||||
let Test.14 : Int1 = true;
|
||||
if Test.14 then
|
||||
ret Test.4;
|
||||
else
|
||||
let Test.12 : U32 = CallByName Num.19 Test.4 Test.2;
|
||||
let Test.13 : {U32} = Struct {Test.2};
|
||||
jump Test.10 Test.12 Test.13;
|
||||
jump Test.10 Test.12 Test.2;
|
||||
in
|
||||
jump Test.10 Test.18 Test.19;
|
||||
|
||||
|
|
|
@ -3018,7 +3018,7 @@ impl RecordFields {
|
|||
(it, ext)
|
||||
}
|
||||
|
||||
/// Get a sorted iterator over the fields of this record type
|
||||
/// get a sorted iterator over the fields of this record type
|
||||
///
|
||||
/// Implementation: When the record has an `ext` variable that is the empty record, then
|
||||
/// we read the (assumed sorted) fields directly from Subs. Otherwise we have to chase the
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue