mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-17 13:47:26 +03:00
Merge branch 'trunk' into roc_alloc
This commit is contained in:
commit
513a624d28
75
Cargo.lock
generated
75
Cargo.lock
generated
@ -210,7 +210,16 @@ dependencies = [
|
||||
"block-padding",
|
||||
"byte-tools",
|
||||
"byteorder",
|
||||
"generic-array",
|
||||
"generic-array 0.12.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||
dependencies = [
|
||||
"generic-array 0.14.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -577,6 +586,15 @@ dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dec1028182c380cc45a2e2c5ec841134f2dfd0f8f5f0a5bcd68004f81b5efdf4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.1"
|
||||
@ -840,7 +858,16 @@ version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"generic-array 0.12.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||
dependencies = [
|
||||
"generic-array 0.14.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1134,6 +1161,16 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
@ -1875,6 +1912,14 @@ dependencies = [
|
||||
"ws2_32-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "morphic_lib"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"sha2",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "0.4.1"
|
||||
@ -2116,6 +2161,12 @@ version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "2.1.1"
|
||||
@ -3212,6 +3263,7 @@ dependencies = [
|
||||
"indoc 0.3.6",
|
||||
"linked-hash-map",
|
||||
"maplit",
|
||||
"morphic_lib",
|
||||
"pretty_assertions 0.5.1",
|
||||
"quickcheck 0.8.5",
|
||||
"quickcheck_macros 0.8.0",
|
||||
@ -3557,10 +3609,23 @@ version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"block-buffer 0.7.3",
|
||||
"digest 0.8.1",
|
||||
"fake-simd",
|
||||
"opaque-debug",
|
||||
"opaque-debug 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8f6b75b17576b792bef0db1bcc4b8b8bcdf9506744cf34b974195487af6cff2"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -496,3 +496,22 @@ of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
|
||||
===========================================================
|
||||
|
||||
* morphic_lib - https://github.com/morphic-lang/morphic_lib
|
||||
|
||||
This source code can be found in vendor/morphic_lib and is licensed under the following terms:
|
||||
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
===========================================================
|
||||
|
@ -140,6 +140,9 @@ fn jit_to_ast_help<'a>(
|
||||
|
||||
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), payload_vars)
|
||||
}
|
||||
Content::Structure(FlatType::FunctionOrTagUnion(tag_name, _, _)) => {
|
||||
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), &[])
|
||||
}
|
||||
other => {
|
||||
unreachable!(
|
||||
"Something had a Struct layout, but instead of a Record or TagUnion type, it had: {:?}",
|
||||
@ -313,6 +316,9 @@ fn ptr_to_ast<'a>(
|
||||
let (tag_name, payload_vars) = tags.iter().next().unwrap();
|
||||
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), payload_vars)
|
||||
}
|
||||
Content::Structure(FlatType::FunctionOrTagUnion(tag_name, _, _)) => {
|
||||
single_tag_union_to_ast(env, ptr, field_layouts, tag_name.clone(), &[])
|
||||
}
|
||||
Content::Structure(FlatType::EmptyRecord) => {
|
||||
struct_to_ast(env, ptr, &[], &MutMap::default())
|
||||
}
|
||||
|
@ -158,6 +158,14 @@ pub enum Expr {
|
||||
arguments: Vec<(Variable, Located<Expr>)>,
|
||||
},
|
||||
|
||||
ZeroArgumentTag {
|
||||
closure_name: Symbol,
|
||||
variant_var: Variable,
|
||||
ext_var: Variable,
|
||||
name: TagName,
|
||||
arguments: Vec<(Variable, Located<Expr>)>,
|
||||
},
|
||||
|
||||
// Test
|
||||
Expect(Box<Located<Expr>>, Box<Located<Expr>>),
|
||||
|
||||
@ -392,6 +400,17 @@ pub fn canonicalize_expr<'a>(
|
||||
name,
|
||||
arguments: args,
|
||||
},
|
||||
ZeroArgumentTag {
|
||||
variant_var,
|
||||
ext_var,
|
||||
name,
|
||||
..
|
||||
} => Tag {
|
||||
variant_var,
|
||||
ext_var,
|
||||
name,
|
||||
arguments: args,
|
||||
},
|
||||
_ => {
|
||||
// This could be something like ((if True then fn1 else fn2) arg1 arg2).
|
||||
Call(
|
||||
@ -626,11 +645,14 @@ pub fn canonicalize_expr<'a>(
|
||||
let variant_var = var_store.fresh();
|
||||
let ext_var = var_store.fresh();
|
||||
|
||||
let symbol = env.gen_unique_symbol();
|
||||
|
||||
(
|
||||
Tag {
|
||||
ZeroArgumentTag {
|
||||
name: TagName::Global((*tag).into()),
|
||||
arguments: vec![],
|
||||
variant_var,
|
||||
closure_name: symbol,
|
||||
ext_var,
|
||||
},
|
||||
Output::default(),
|
||||
@ -641,13 +663,15 @@ pub fn canonicalize_expr<'a>(
|
||||
let ext_var = var_store.fresh();
|
||||
let tag_ident = env.ident_ids.get_or_insert(&(*tag).into());
|
||||
let symbol = Symbol::new(env.home, tag_ident);
|
||||
let lambda_set_symbol = env.gen_unique_symbol();
|
||||
|
||||
(
|
||||
Tag {
|
||||
ZeroArgumentTag {
|
||||
name: TagName::Private(symbol),
|
||||
arguments: vec![],
|
||||
variant_var,
|
||||
ext_var,
|
||||
closure_name: lambda_set_symbol,
|
||||
},
|
||||
Output::default(),
|
||||
)
|
||||
@ -1427,6 +1451,23 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
|
||||
);
|
||||
}
|
||||
|
||||
ZeroArgumentTag {
|
||||
closure_name,
|
||||
variant_var,
|
||||
ext_var,
|
||||
name,
|
||||
arguments,
|
||||
} => {
|
||||
todo!(
|
||||
"Inlining for ZeroArgumentTag with closure_name {:?}, variant_var {:?}, ext_var {:?}, name {:?}, arguments {:?}",
|
||||
closure_name,
|
||||
variant_var,
|
||||
ext_var,
|
||||
name,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
Call(boxed_tuple, args, called_via) => {
|
||||
let (fn_var, loc_expr, closure_var, expr_var) = *boxed_tuple;
|
||||
|
||||
|
@ -509,7 +509,7 @@ fn fix_values_captured_in_closure_expr(
|
||||
fix_values_captured_in_closure_expr(&mut loc_expr.value, no_capture_symbols);
|
||||
}
|
||||
|
||||
Tag { arguments, .. } => {
|
||||
Tag { arguments, .. } | ZeroArgumentTag { arguments, .. } => {
|
||||
for (_, loc_arg) in arguments.iter_mut() {
|
||||
fix_values_captured_in_closure_expr(&mut loc_arg.value, no_capture_symbols);
|
||||
}
|
||||
|
@ -860,6 +860,58 @@ pub fn constrain_expr(
|
||||
|
||||
exists(vars, And(arg_cons))
|
||||
}
|
||||
ZeroArgumentTag {
|
||||
variant_var,
|
||||
ext_var,
|
||||
name,
|
||||
arguments,
|
||||
closure_name,
|
||||
} => {
|
||||
let mut vars = Vec::with_capacity(arguments.len());
|
||||
let mut types = Vec::with_capacity(arguments.len());
|
||||
let mut arg_cons = Vec::with_capacity(arguments.len());
|
||||
|
||||
for (var, loc_expr) in arguments {
|
||||
let arg_con = constrain_expr(
|
||||
env,
|
||||
loc_expr.region,
|
||||
&loc_expr.value,
|
||||
Expected::NoExpectation(Type::Variable(*var)),
|
||||
);
|
||||
|
||||
arg_cons.push(arg_con);
|
||||
vars.push(*var);
|
||||
types.push(Type::Variable(*var));
|
||||
}
|
||||
|
||||
let union_con = Eq(
|
||||
Type::FunctionOrTagUnion(
|
||||
name.clone(),
|
||||
*closure_name,
|
||||
Box::new(Type::Variable(*ext_var)),
|
||||
),
|
||||
expected.clone(),
|
||||
Category::TagApply {
|
||||
tag_name: name.clone(),
|
||||
args_count: arguments.len(),
|
||||
},
|
||||
region,
|
||||
);
|
||||
let ast_con = Eq(
|
||||
Type::Variable(*variant_var),
|
||||
expected,
|
||||
Category::Storage(std::file!(), std::line!()),
|
||||
region,
|
||||
);
|
||||
|
||||
vars.push(*variant_var);
|
||||
vars.push(*ext_var);
|
||||
arg_cons.push(union_con);
|
||||
arg_cons.push(ast_con);
|
||||
|
||||
exists(vars, And(arg_cons))
|
||||
}
|
||||
|
||||
RunLowLevel { args, ret_var, op } => {
|
||||
// This is a modified version of what we do for function calls.
|
||||
|
||||
|
@ -836,7 +836,7 @@ pub fn build_exp_call<'a, 'ctx, 'env>(
|
||||
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."))
|
||||
}
|
||||
|
||||
CallType::LowLevel { op } => {
|
||||
CallType::LowLevel { op, update_mode: _ } => {
|
||||
run_low_level(env, layout_ids, scope, parent, layout, *op, arguments)
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
CallType::LowLevel { op: lowlevel } => {
|
||||
CallType::LowLevel { op: lowlevel, .. } => {
|
||||
self.build_run_low_level(sym, lowlevel, arguments, layout)
|
||||
}
|
||||
x => Err(format!("the call type, {:?}, is not yet implemented", x)),
|
||||
|
@ -2046,6 +2046,14 @@ fn update<'a>(
|
||||
&& state.dependencies.solved_all()
|
||||
&& state.goal_phase == Phase::MakeSpecializations
|
||||
{
|
||||
if false {
|
||||
let it = state.procedures.iter().map(|x| x.1);
|
||||
|
||||
if let Err(e) = roc_mono::alias_analysis::spec_program(it) {
|
||||
println!("Error in alias analysis: {:?}", e)
|
||||
}
|
||||
}
|
||||
|
||||
Proc::insert_refcount_operations(arena, &mut state.procedures);
|
||||
|
||||
Proc::optimize_refcount_operations(
|
||||
@ -3799,6 +3807,8 @@ fn make_specializations<'a>(
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
ptr_bytes,
|
||||
update_mode_counter: 0,
|
||||
call_specialization_counter: 0,
|
||||
};
|
||||
|
||||
// TODO: for now this final specialization pass is sequential,
|
||||
@ -3860,6 +3870,8 @@ fn build_pending_specializations<'a>(
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
ptr_bytes,
|
||||
update_mode_counter: 0,
|
||||
call_specialization_counter: 0,
|
||||
};
|
||||
|
||||
// Add modules' decls to Procs
|
||||
|
@ -105,6 +105,10 @@ impl Symbol {
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn to_ne_bytes(self) -> [u8; 8] {
|
||||
self.0.to_ne_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
/// Rather than displaying as this:
|
||||
|
@ -15,6 +15,7 @@ roc_unify = { path = "../unify" }
|
||||
roc_solve = { path = "../solve" }
|
||||
roc_problem = { path = "../problem" }
|
||||
ven_pretty = { path = "../../vendor/pretty" }
|
||||
morphic_lib = { path = "../../vendor/morphic_lib" }
|
||||
bumpalo = { version = "3.6.1", features = ["collections"] }
|
||||
hashbrown = { version = "0.11.2", features = [ "bumpalo" ] }
|
||||
ven_ena = { path = "../../vendor/ena" }
|
||||
|
620
compiler/mono/src/alias_analysis.rs
Normal file
620
compiler/mono/src/alias_analysis.rs
Normal file
@ -0,0 +1,620 @@
|
||||
use morphic_lib::TypeContext;
|
||||
use morphic_lib::{
|
||||
BlockExpr, BlockId, CalleeSpecVar, EntryPointName, ExprContext, FuncDef, FuncDefBuilder,
|
||||
FuncName, ModDefBuilder, ModName, ProgramBuilder, Result, TypeId, TypeName, UpdateModeVar,
|
||||
ValueId,
|
||||
};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::Symbol;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::ir::{Call, CallType, Expr, Literal, ModifyRc, Proc, Stmt};
|
||||
use crate::layout::{Builtin, Layout, ListLayout, UnionLayout};
|
||||
|
||||
// just using one module for now
|
||||
const MOD_LIST: ModName = ModName(b"UserApp");
|
||||
const MOD_APP: ModName = ModName(b"UserApp");
|
||||
|
||||
pub fn spec_program<'a, I>(procs: I) -> Result<morphic_lib::Solutions>
|
||||
where
|
||||
I: Iterator<Item = &'a Proc<'a>>,
|
||||
{
|
||||
let mut main_function = None;
|
||||
let main_module = {
|
||||
let mut m = ModDefBuilder::new();
|
||||
|
||||
for proc in procs {
|
||||
let spec = proc_spec(proc)?;
|
||||
|
||||
m.add_func(FuncName(&proc.name.to_ne_bytes()), spec)?;
|
||||
|
||||
if format!("{:?}", proc.name).contains("mainForHost") {
|
||||
main_function = Some(proc.name);
|
||||
}
|
||||
}
|
||||
|
||||
m.build()?
|
||||
};
|
||||
|
||||
let program = {
|
||||
let mut p = ProgramBuilder::new();
|
||||
p.add_mod(MOD_APP, main_module)?;
|
||||
p.add_entry_point(
|
||||
EntryPointName(b"mainForHost"),
|
||||
MOD_APP,
|
||||
FuncName(&main_function.unwrap().to_ne_bytes()),
|
||||
)?;
|
||||
|
||||
p.build()?
|
||||
};
|
||||
|
||||
morphic_lib::solve(program)
|
||||
}
|
||||
|
||||
fn proc_spec(proc: &Proc) -> Result<FuncDef> {
|
||||
let mut builder = FuncDefBuilder::new();
|
||||
let mut env = Env::default();
|
||||
|
||||
let block = builder.add_block();
|
||||
|
||||
// introduce the arguments
|
||||
let mut argument_layouts = Vec::new();
|
||||
for (i, (layout, symbol)) in proc.args.iter().enumerate() {
|
||||
let value_id = builder.add_get_tuple_field(block, builder.get_argument(), i as u32)?;
|
||||
env.symbols.insert(*symbol, value_id);
|
||||
|
||||
argument_layouts.push(*layout);
|
||||
}
|
||||
|
||||
let value_id = stmt_spec(&mut builder, &mut env, block, &proc.ret_layout, &proc.body)?;
|
||||
|
||||
let root = BlockExpr(block, value_id);
|
||||
let arg_type_id = layout_spec(&mut builder, &Layout::Struct(&argument_layouts))?;
|
||||
let ret_type_id = layout_spec(&mut builder, &proc.ret_layout)?;
|
||||
builder.build(arg_type_id, ret_type_id, root)
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Env {
|
||||
symbols: MutMap<Symbol, ValueId>,
|
||||
join_points: MutMap<crate::ir::JoinPointId, morphic_lib::JoinPointId>,
|
||||
}
|
||||
|
||||
fn stmt_spec(
|
||||
builder: &mut FuncDefBuilder,
|
||||
env: &mut Env,
|
||||
block: BlockId,
|
||||
layout: &Layout,
|
||||
stmt: &Stmt,
|
||||
) -> Result<ValueId> {
|
||||
use Stmt::*;
|
||||
|
||||
match stmt {
|
||||
Let(symbol, expr, layout, continuation) => {
|
||||
let value_id = expr_spec(builder, env, block, layout, expr)?;
|
||||
env.symbols.insert(*symbol, value_id);
|
||||
let result = stmt_spec(builder, env, block, layout, continuation)?;
|
||||
env.symbols.remove(symbol);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
Invoke {
|
||||
symbol,
|
||||
call,
|
||||
layout: call_layout,
|
||||
pass,
|
||||
fail,
|
||||
} => {
|
||||
// a call that might throw an exception
|
||||
|
||||
let value_id = call_spec(builder, env, block, call_layout, call)?;
|
||||
|
||||
let pass_block = builder.add_block();
|
||||
env.symbols.insert(*symbol, value_id);
|
||||
let pass_value_id = stmt_spec(builder, env, pass_block, layout, pass)?;
|
||||
env.symbols.remove(symbol);
|
||||
let pass_block_expr = BlockExpr(pass_block, pass_value_id);
|
||||
|
||||
let fail_block = builder.add_block();
|
||||
let fail_value_id = stmt_spec(builder, env, fail_block, layout, fail)?;
|
||||
let fail_block_expr = BlockExpr(fail_block, fail_value_id);
|
||||
|
||||
builder.add_choice(block, &[pass_block_expr, fail_block_expr])
|
||||
}
|
||||
Switch {
|
||||
cond_symbol: _,
|
||||
cond_layout: _,
|
||||
branches,
|
||||
default_branch,
|
||||
ret_layout,
|
||||
} => {
|
||||
let mut cases = Vec::with_capacity(branches.len() + 1);
|
||||
|
||||
let it = branches
|
||||
.iter()
|
||||
.map(|(_, _, body)| body)
|
||||
.chain(std::iter::once(default_branch.1));
|
||||
|
||||
for branch in it {
|
||||
let block = builder.add_block();
|
||||
let value_id = stmt_spec(builder, env, block, ret_layout, branch)?;
|
||||
cases.push(BlockExpr(block, value_id));
|
||||
}
|
||||
|
||||
builder.add_choice(block, &cases)
|
||||
}
|
||||
Ret(symbol) => Ok(env.symbols[symbol]),
|
||||
Refcounting(modify_rc, continuation) => match modify_rc {
|
||||
ModifyRc::Inc(symbol, _) | ModifyRc::Dec(symbol) | ModifyRc::DecRef(symbol) => {
|
||||
let result_type = builder.add_tuple_type(&[])?;
|
||||
let argument = env.symbols[symbol];
|
||||
|
||||
// this is how RC is modelled; it recursively touches all heap cells
|
||||
builder.add_unknown_with(block, &[argument], result_type)?;
|
||||
|
||||
stmt_spec(builder, env, block, layout, continuation)
|
||||
}
|
||||
},
|
||||
Join {
|
||||
id,
|
||||
parameters,
|
||||
continuation,
|
||||
remainder,
|
||||
} => {
|
||||
let mut type_ids = Vec::new();
|
||||
|
||||
for p in parameters.iter() {
|
||||
type_ids.push(layout_spec(builder, &p.layout)?);
|
||||
}
|
||||
|
||||
let ret_type_id = layout_spec(builder, layout)?;
|
||||
|
||||
let jp_arg_type_id = builder.add_tuple_type(&type_ids)?;
|
||||
|
||||
let (jpid, jp_argument) =
|
||||
builder.declare_join_point(block, jp_arg_type_id, ret_type_id)?;
|
||||
|
||||
let join_body_sub_block = {
|
||||
env.join_points.insert(*id, jpid);
|
||||
let jp_body_block = builder.add_block();
|
||||
|
||||
// unpack the argument
|
||||
for (i, p) in parameters.iter().enumerate() {
|
||||
let value_id =
|
||||
builder.add_get_tuple_field(jp_body_block, jp_argument, i as u32)?;
|
||||
env.symbols.insert(p.symbol, value_id);
|
||||
}
|
||||
|
||||
let jp_body_value_id = stmt_spec(builder, env, jp_body_block, layout, remainder)?;
|
||||
BlockExpr(jp_body_block, jp_body_value_id)
|
||||
};
|
||||
|
||||
// NOTE the symbols bound by the join point can shadow the argument symbols of the
|
||||
// surrounding function, so we don't remove them from the env here
|
||||
|
||||
let cont_block = builder.add_block();
|
||||
let cont_value_id = stmt_spec(builder, env, cont_block, layout, continuation)?;
|
||||
|
||||
env.join_points.remove(id);
|
||||
builder.define_join_point(jpid, join_body_sub_block)?;
|
||||
|
||||
builder.add_sub_block(block, BlockExpr(cont_block, cont_value_id))
|
||||
}
|
||||
Jump(id, symbols) => {
|
||||
let ret_type_id = layout_spec(builder, layout)?;
|
||||
let argument = build_tuple_value(builder, env, block, symbols)?;
|
||||
|
||||
let jpid = env.join_points[id];
|
||||
builder.add_jump(block, jpid, argument, ret_type_id)
|
||||
}
|
||||
Rethrow | RuntimeError(_) => {
|
||||
let type_id = layout_spec(builder, layout)?;
|
||||
|
||||
builder.add_terminate(block, type_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_tuple_value(
|
||||
builder: &mut FuncDefBuilder,
|
||||
env: &Env,
|
||||
block: BlockId,
|
||||
symbols: &[Symbol],
|
||||
) -> Result<ValueId> {
|
||||
let mut value_ids = Vec::new();
|
||||
|
||||
for field in symbols.iter() {
|
||||
let value_id = match env.symbols.get(field) {
|
||||
None => panic!(
|
||||
"Symbol {:?} is not defined in environment {:?}",
|
||||
field, &env.symbols
|
||||
),
|
||||
Some(x) => *x,
|
||||
};
|
||||
value_ids.push(value_id);
|
||||
}
|
||||
|
||||
builder.add_make_tuple(block, &value_ids)
|
||||
}
|
||||
|
||||
fn build_tuple_type(builder: &mut FuncDefBuilder, layouts: &[Layout]) -> Result<TypeId> {
|
||||
let mut field_types = Vec::new();
|
||||
|
||||
for field in layouts.iter() {
|
||||
field_types.push(layout_spec(builder, field)?);
|
||||
}
|
||||
|
||||
builder.add_tuple_type(&field_types)
|
||||
}
|
||||
|
||||
fn call_spec(
|
||||
builder: &mut FuncDefBuilder,
|
||||
env: &Env,
|
||||
block: BlockId,
|
||||
layout: &Layout,
|
||||
call: &Call,
|
||||
) -> Result<ValueId> {
|
||||
use CallType::*;
|
||||
|
||||
match &call.call_type {
|
||||
ByName {
|
||||
name: symbol,
|
||||
full_layout: _,
|
||||
ret_layout: _,
|
||||
arg_layouts: _,
|
||||
specialization_id,
|
||||
} => {
|
||||
let array = specialization_id.to_bytes();
|
||||
let spec_var = CalleeSpecVar(&array);
|
||||
|
||||
let arg_value_id = build_tuple_value(builder, env, block, call.arguments)?;
|
||||
let slice = &symbol.to_ne_bytes();
|
||||
let name = FuncName(slice);
|
||||
let module = MOD_APP;
|
||||
builder.add_call(block, spec_var, module, name, arg_value_id)
|
||||
}
|
||||
ByPointer {
|
||||
name: _,
|
||||
full_layout: _,
|
||||
ret_layout: _,
|
||||
arg_layouts: _,
|
||||
} => todo!(),
|
||||
Foreign {
|
||||
foreign_symbol: _,
|
||||
ret_layout,
|
||||
} => {
|
||||
let arguments: Vec<_> = call
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|symbol| env.symbols[symbol])
|
||||
.collect();
|
||||
|
||||
let result_type = layout_spec(builder, ret_layout)?;
|
||||
|
||||
builder.add_unknown_with(block, &arguments, result_type)
|
||||
}
|
||||
LowLevel { op, update_mode } => lowlevel_spec(
|
||||
builder,
|
||||
env,
|
||||
block,
|
||||
layout,
|
||||
op,
|
||||
*update_mode,
|
||||
call.arguments,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn lowlevel_spec(
|
||||
builder: &mut FuncDefBuilder,
|
||||
env: &Env,
|
||||
block: BlockId,
|
||||
layout: &Layout,
|
||||
op: &LowLevel,
|
||||
update_mode: crate::ir::UpdateModeId,
|
||||
arguments: &[Symbol],
|
||||
) -> Result<ValueId> {
|
||||
use LowLevel::*;
|
||||
|
||||
let type_id = layout_spec(builder, layout)?;
|
||||
let mode = update_mode.to_bytes();
|
||||
let update_mode_var = UpdateModeVar(&mode);
|
||||
|
||||
match op {
|
||||
NumAdd | NumSub => {
|
||||
// NOTE these numeric operations panic (e.g. on overflow)
|
||||
|
||||
let pass_block = {
|
||||
let block = builder.add_block();
|
||||
let value = new_num(builder, block)?;
|
||||
BlockExpr(block, value)
|
||||
};
|
||||
|
||||
let fail_block = {
|
||||
let block = builder.add_block();
|
||||
let value = builder.add_terminate(block, type_id)?;
|
||||
BlockExpr(block, value)
|
||||
};
|
||||
|
||||
let sub_block = {
|
||||
let block = builder.add_block();
|
||||
let choice = builder.add_choice(block, &[pass_block, fail_block])?;
|
||||
|
||||
BlockExpr(block, choice)
|
||||
};
|
||||
|
||||
builder.add_sub_block(block, sub_block)
|
||||
}
|
||||
Eq | NotEq => new_bool(builder, block),
|
||||
NumLte | NumLt | NumGt | NumGte => new_order(builder, block),
|
||||
ListLen => {
|
||||
let list = env.symbols[&arguments[0]];
|
||||
|
||||
builder.add_get_tuple_field(block, list, LIST_LEN_INDEX)
|
||||
}
|
||||
ListGetUnsafe => {
|
||||
// NOTE the ListGet lowlevel op is only evaluated if the index is in-bounds
|
||||
let list = env.symbols[&arguments[0]];
|
||||
|
||||
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||
let cell = builder.add_get_tuple_field(block, list, LIST_CELL_INDEX)?;
|
||||
|
||||
let _unit = builder.add_touch(block, cell)?;
|
||||
|
||||
builder.add_bag_get(block, bag)
|
||||
}
|
||||
ListSet => {
|
||||
let list = env.symbols[&arguments[0]];
|
||||
let to_insert = env.symbols[&arguments[2]];
|
||||
|
||||
let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||
let cell = builder.add_get_tuple_field(block, list, LIST_CELL_INDEX)?;
|
||||
|
||||
let _unit = builder.add_update(block, update_mode_var, cell)?;
|
||||
|
||||
builder.add_bag_insert(block, bag, to_insert)?;
|
||||
|
||||
Ok(list)
|
||||
}
|
||||
other => todo!("lowlevel op not implemented: {:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_variant_types(
|
||||
builder: &mut FuncDefBuilder,
|
||||
layout: &Layout,
|
||||
) -> Option<Result<Vec<TypeId>>> {
|
||||
match layout {
|
||||
Layout::Union(union_layout) => Some(build_variant_types_help(builder, union_layout)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_variant_types_help(
|
||||
builder: &mut FuncDefBuilder,
|
||||
union_layout: &UnionLayout,
|
||||
) -> Result<Vec<TypeId>> {
|
||||
use UnionLayout::*;
|
||||
|
||||
let mut result = Vec::new();
|
||||
|
||||
match union_layout {
|
||||
NonRecursive(tags) => {
|
||||
for tag in tags.iter() {
|
||||
result.push(build_tuple_type(builder, tag)?);
|
||||
}
|
||||
}
|
||||
Recursive(_) => todo!(),
|
||||
NonNullableUnwrapped(_) => todo!(),
|
||||
NullableWrapped {
|
||||
nullable_id: _,
|
||||
other_tags: _,
|
||||
} => todo!(),
|
||||
NullableUnwrapped {
|
||||
nullable_id: _,
|
||||
other_fields: _,
|
||||
} => todo!(),
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn expr_spec(
|
||||
builder: &mut FuncDefBuilder,
|
||||
env: &Env,
|
||||
block: BlockId,
|
||||
layout: &Layout,
|
||||
expr: &Expr,
|
||||
) -> Result<ValueId> {
|
||||
use Expr::*;
|
||||
|
||||
match expr {
|
||||
Literal(literal) => literal_spec(builder, block, literal),
|
||||
FunctionPointer(_, _) => todo!(),
|
||||
Call(call) => call_spec(builder, env, block, layout, call),
|
||||
Tag {
|
||||
tag_layout,
|
||||
tag_name: _,
|
||||
tag_id,
|
||||
union_size: _,
|
||||
arguments,
|
||||
} => {
|
||||
let value_id = build_tuple_value(builder, env, block, arguments)?;
|
||||
let variant_types = build_variant_types(builder, tag_layout).unwrap()?;
|
||||
builder.add_make_union(block, &variant_types, *tag_id as u32, value_id)
|
||||
}
|
||||
Struct(fields) => build_tuple_value(builder, env, block, fields),
|
||||
AccessAtIndex {
|
||||
index,
|
||||
field_layouts: _,
|
||||
structure,
|
||||
wrapped,
|
||||
} => {
|
||||
use crate::ir::Wrapped;
|
||||
|
||||
let value_id = env.symbols[structure];
|
||||
|
||||
match wrapped {
|
||||
Wrapped::EmptyRecord => {
|
||||
// this is a unit value
|
||||
builder.add_make_tuple(block, &[])
|
||||
}
|
||||
Wrapped::SingleElementRecord => {
|
||||
todo!("do we unwrap single-element records still?")
|
||||
}
|
||||
Wrapped::RecordOrSingleTagUnion => {
|
||||
builder.add_get_tuple_field(block, value_id, *index as u32)
|
||||
}
|
||||
Wrapped::MultiTagUnion => {
|
||||
builder.add_get_tuple_field(block, value_id, *index as u32)
|
||||
}
|
||||
}
|
||||
}
|
||||
Array { elem_layout, elems } => {
|
||||
let type_id = layout_spec(builder, elem_layout)?;
|
||||
|
||||
let list = new_list(builder, block, type_id)?;
|
||||
|
||||
let mut bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?;
|
||||
|
||||
for symbol in elems.iter() {
|
||||
let value_id = env.symbols[symbol];
|
||||
|
||||
bag = builder.add_bag_insert(block, bag, value_id)?;
|
||||
}
|
||||
|
||||
Ok(bag)
|
||||
}
|
||||
|
||||
EmptyArray => {
|
||||
use ListLayout::*;
|
||||
|
||||
match ListLayout::try_from(layout) {
|
||||
Ok(EmptyList) => {
|
||||
// just make up an element type
|
||||
let type_id = builder.add_tuple_type(&[])?;
|
||||
new_list(builder, block, type_id)
|
||||
}
|
||||
Ok(List(element_layout)) => {
|
||||
let type_id = layout_spec(builder, element_layout)?;
|
||||
new_list(builder, block, type_id)
|
||||
}
|
||||
Err(()) => unreachable!("empty array does not have a list layout"),
|
||||
}
|
||||
}
|
||||
Reuse { .. } => todo!("currently unused"),
|
||||
Reset(_) => todo!("currently unused"),
|
||||
RuntimeErrorFunction(_) => {
|
||||
let type_id = layout_spec(builder, layout)?;
|
||||
|
||||
builder.add_terminate(block, type_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn literal_spec(
|
||||
builder: &mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
literal: &Literal,
|
||||
) -> Result<ValueId> {
|
||||
use Literal::*;
|
||||
|
||||
match literal {
|
||||
Str(_) => new_static_string(builder, block),
|
||||
Int(_) | Float(_) | Bool(_) | Byte(_) => builder.add_make_tuple(block, &[]),
|
||||
}
|
||||
}
|
||||
|
||||
fn layout_spec(builder: &mut FuncDefBuilder, layout: &Layout) -> Result<TypeId> {
|
||||
use Layout::*;
|
||||
|
||||
match layout {
|
||||
Builtin(builtin) => builtin_spec(builder, builtin),
|
||||
PhantomEmptyStruct => todo!(),
|
||||
Struct(fields) => build_tuple_type(builder, fields),
|
||||
Union(union_layout) => {
|
||||
let variant_types = build_variant_types_help(builder, union_layout)?;
|
||||
builder.add_union_type(&variant_types)
|
||||
}
|
||||
RecursivePointer => todo!(),
|
||||
FunctionPointer(_, _) => todo!(),
|
||||
Closure(_, _, _) => todo!(),
|
||||
Pointer(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn builtin_spec(builder: &mut FuncDefBuilder, builtin: &Builtin) -> Result<TypeId> {
|
||||
use Builtin::*;
|
||||
|
||||
match builtin {
|
||||
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize => builder.add_tuple_type(&[]),
|
||||
Float128 => todo!(),
|
||||
Float64 => todo!(),
|
||||
Float32 => todo!(),
|
||||
Float16 => todo!(),
|
||||
Str => todo!(),
|
||||
Dict(_, _) => todo!(),
|
||||
Set(_) => todo!(),
|
||||
List(_, _) => {
|
||||
// TODO should incorporate the element type into the name
|
||||
Ok(builder.add_named_type(MOD_LIST, TypeName(b"List")))
|
||||
}
|
||||
EmptyStr => todo!(),
|
||||
EmptyList => todo!(),
|
||||
EmptyDict => todo!(),
|
||||
EmptySet => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
// const OK_TAG_ID: u8 = 1u8;
|
||||
// const ERR_TAG_ID: u8 = 0u8;
|
||||
|
||||
const LIST_CELL_INDEX: u32 = 0;
|
||||
const LIST_BAG_INDEX: u32 = 1;
|
||||
const LIST_LEN_INDEX: u32 = 2;
|
||||
|
||||
fn new_list(builder: &mut FuncDefBuilder, block: BlockId, element_type: TypeId) -> Result<ValueId> {
|
||||
let cell = builder.add_new_heap_cell(block)?;
|
||||
let bag = builder.add_empty_bag(block, element_type)?;
|
||||
let length = new_usize(builder, block)?;
|
||||
builder.add_make_tuple(block, &[cell, bag, length])
|
||||
}
|
||||
|
||||
fn new_usize(builder: &mut FuncDefBuilder, block: BlockId) -> Result<ValueId> {
|
||||
new_num(builder, block)
|
||||
}
|
||||
|
||||
fn new_static_string(builder: &mut FuncDefBuilder, block: BlockId) -> Result<ValueId> {
|
||||
let cell = builder.add_new_heap_cell(block)?;
|
||||
|
||||
// immediately mutate the cell, so any future updates on this value are invalid
|
||||
// updating a static string would cause a crash at runtime
|
||||
let _ = builder.add_update(block, UpdateModeVar(&[]), cell)?;
|
||||
|
||||
let length = new_usize(builder, block)?;
|
||||
builder.add_make_tuple(block, &[cell, length])
|
||||
}
|
||||
|
||||
fn new_order(builder: &mut FuncDefBuilder, block: BlockId) -> Result<ValueId> {
|
||||
// always generats EQ
|
||||
let tag_id = 0;
|
||||
|
||||
let unit = builder.add_tuple_type(&[])?;
|
||||
let unit_value = builder.add_make_tuple(block, &[])?;
|
||||
builder.add_make_union(block, &[unit, unit, unit], tag_id, unit_value)
|
||||
}
|
||||
|
||||
fn new_bool(builder: &mut FuncDefBuilder, block: BlockId) -> Result<ValueId> {
|
||||
// always generats False
|
||||
let tag_id = 0;
|
||||
|
||||
let unit = builder.add_tuple_type(&[])?;
|
||||
let unit_value = builder.add_make_tuple(block, &[])?;
|
||||
builder.add_make_union(block, &[unit, unit], tag_id, unit_value)
|
||||
}
|
||||
|
||||
fn new_num(builder: &mut FuncDefBuilder, block: BlockId) -> Result<ValueId> {
|
||||
// we model all our numbers as unit values
|
||||
builder.add_make_tuple(block, &[])
|
||||
}
|
@ -402,7 +402,7 @@ impl<'a> BorrowInfState<'a> {
|
||||
self.own_args(arguments);
|
||||
}
|
||||
|
||||
LowLevel { op } => {
|
||||
LowLevel { op, .. } => {
|
||||
// very unsure what demand RunLowLevel should place upon its arguments
|
||||
self.own_var(z);
|
||||
|
||||
|
@ -1404,8 +1404,12 @@ fn compile_test_help<'a>(
|
||||
default_branch,
|
||||
};
|
||||
|
||||
let op = LowLevel::Eq;
|
||||
let test = Expr::Call(crate::ir::Call {
|
||||
call_type: crate::ir::CallType::LowLevel { op: LowLevel::Eq },
|
||||
call_type: crate::ir::CallType::LowLevel {
|
||||
op,
|
||||
update_mode: env.next_update_mode_id(),
|
||||
},
|
||||
arguments: arena.alloc([lhs, rhs]),
|
||||
});
|
||||
|
||||
|
@ -442,7 +442,7 @@ impl<'a> Context<'a> {
|
||||
use crate::ir::CallType::*;
|
||||
|
||||
match &call_type {
|
||||
LowLevel { op } => {
|
||||
LowLevel { op, .. } => {
|
||||
let ps = crate::borrow::lowlevel_borrow_signature(self.arena, *op);
|
||||
let b = self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars);
|
||||
|
||||
@ -768,7 +768,7 @@ impl<'a> Context<'a> {
|
||||
|
||||
use crate::ir::CallType;
|
||||
let stmt = match &call.call_type {
|
||||
CallType::LowLevel { op } => {
|
||||
CallType::LowLevel { op, .. } => {
|
||||
let ps = crate::borrow::lowlevel_borrow_signature(self.arena, *op);
|
||||
self.add_dec_after_lowlevel(call.arguments, ps, cont, &case_live_vars)
|
||||
}
|
||||
|
@ -735,6 +735,8 @@ pub struct Env<'a, 'i> {
|
||||
pub home: ModuleId,
|
||||
pub ident_ids: &'i mut IdentIds,
|
||||
pub ptr_bytes: u32,
|
||||
pub update_mode_counter: u64,
|
||||
pub call_specialization_counter: u64,
|
||||
}
|
||||
|
||||
impl<'a, 'i> Env<'a, 'i> {
|
||||
@ -746,6 +748,26 @@ impl<'a, 'i> Env<'a, 'i> {
|
||||
Symbol::new(self.home, ident_id)
|
||||
}
|
||||
|
||||
pub fn next_update_mode_id(&mut self) -> UpdateModeId {
|
||||
let id = UpdateModeId {
|
||||
id: self.update_mode_counter,
|
||||
};
|
||||
|
||||
self.update_mode_counter += 1;
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
pub fn next_call_specialization_id(&mut self) -> CallSpecId {
|
||||
let id = CallSpecId {
|
||||
id: self.call_specialization_counter,
|
||||
};
|
||||
|
||||
self.call_specialization_counter += 1;
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
pub fn is_imported_symbol(&self, symbol: Symbol) -> bool {
|
||||
symbol.module_id() != self.home && !symbol.is_builtin()
|
||||
}
|
||||
@ -1004,7 +1026,7 @@ impl<'a> Call<'a> {
|
||||
.text("CallByPointer ")
|
||||
.append(alloc.intersperse(it, " "))
|
||||
}
|
||||
LowLevel { op: lowlevel } => {
|
||||
LowLevel { op: lowlevel, .. } => {
|
||||
let it = arguments.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
|
||||
alloc
|
||||
@ -1024,18 +1046,39 @@ impl<'a> Call<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct CallSpecId {
|
||||
id: u64,
|
||||
}
|
||||
|
||||
impl CallSpecId {
|
||||
pub fn to_bytes(self) -> [u8; 8] {
|
||||
self.id.to_ne_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct UpdateModeId {
|
||||
id: u64,
|
||||
}
|
||||
|
||||
impl UpdateModeId {
|
||||
pub fn to_bytes(self) -> [u8; 8] {
|
||||
self.id.to_ne_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum CallType<'a> {
|
||||
ByName {
|
||||
name: Symbol,
|
||||
|
||||
full_layout: Layout<'a>,
|
||||
ret_layout: Layout<'a>,
|
||||
arg_layouts: &'a [Layout<'a>],
|
||||
specialization_id: CallSpecId,
|
||||
},
|
||||
ByPointer {
|
||||
name: Symbol,
|
||||
|
||||
full_layout: Layout<'a>,
|
||||
ret_layout: Layout<'a>,
|
||||
arg_layouts: &'a [Layout<'a>],
|
||||
@ -1046,6 +1089,7 @@ pub enum CallType<'a> {
|
||||
},
|
||||
LowLevel {
|
||||
op: LowLevel,
|
||||
update_mode: UpdateModeId,
|
||||
},
|
||||
}
|
||||
|
||||
@ -2849,346 +2893,63 @@ pub fn with_hole<'a>(
|
||||
variant_var,
|
||||
name: tag_name,
|
||||
arguments: args,
|
||||
ext_var,
|
||||
..
|
||||
} => {
|
||||
let arena = env.arena;
|
||||
|
||||
debug_assert!(!matches!(
|
||||
env.subs.get_without_compacting(variant_var).content,
|
||||
Content::Structure(FlatType::Func(_, _, _))
|
||||
));
|
||||
convert_tag_union(
|
||||
env,
|
||||
variant_var,
|
||||
assigned,
|
||||
hole,
|
||||
tag_name,
|
||||
procs,
|
||||
layout_cache,
|
||||
args,
|
||||
arena,
|
||||
)
|
||||
}
|
||||
|
||||
ZeroArgumentTag {
|
||||
variant_var,
|
||||
name: tag_name,
|
||||
arguments: args,
|
||||
ext_var,
|
||||
..
|
||||
} => {
|
||||
use crate::layout::UnionVariant::*;
|
||||
let arena = env.arena;
|
||||
|
||||
let desc = env.subs.get_without_compacting(variant_var);
|
||||
|
||||
if let Content::Structure(FlatType::Func(arg_vars, _, ret_var)) = desc.content {
|
||||
let mut loc_pattern_args = vec![];
|
||||
let mut loc_expr_args = vec![];
|
||||
|
||||
let proc_symbol = env.unique_symbol();
|
||||
|
||||
for arg_var in arg_vars {
|
||||
let arg_symbol = env.unique_symbol();
|
||||
|
||||
let loc_pattern =
|
||||
Located::at_zero(roc_can::pattern::Pattern::Identifier(arg_symbol));
|
||||
|
||||
let loc_expr = Located::at_zero(roc_can::expr::Expr::Var(arg_symbol));
|
||||
|
||||
loc_pattern_args.push((arg_var, loc_pattern));
|
||||
loc_expr_args.push((arg_var, loc_expr));
|
||||
}
|
||||
|
||||
let loc_body = Located::at_zero(roc_can::expr::Expr::Tag {
|
||||
variant_var: ret_var,
|
||||
name: tag_name,
|
||||
arguments: loc_expr_args,
|
||||
ext_var,
|
||||
});
|
||||
|
||||
let inserted = procs.insert_anonymous(
|
||||
tag_union_to_function(
|
||||
env,
|
||||
proc_symbol,
|
||||
variant_var,
|
||||
loc_pattern_args,
|
||||
loc_body,
|
||||
CapturedSymbols::None,
|
||||
arg_vars,
|
||||
ret_var,
|
||||
tag_name,
|
||||
ext_var,
|
||||
procs,
|
||||
variant_var,
|
||||
layout_cache,
|
||||
);
|
||||
|
||||
match inserted {
|
||||
Ok(layout) => {
|
||||
return Stmt::Let(
|
||||
assigned,
|
||||
call_by_pointer(env, procs, proc_symbol, layout),
|
||||
layout,
|
||||
hole,
|
||||
);
|
||||
}
|
||||
Err(runtime_error) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"RuntimeError {} line {} {:?}",
|
||||
file!(),
|
||||
line!(),
|
||||
runtime_error,
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let res_variant = crate::layout::union_sorted_tags(env.arena, variant_var, env.subs);
|
||||
|
||||
let variant = match res_variant {
|
||||
Ok(cached) => cached,
|
||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"UnresolvedTypeVar {} line {}",
|
||||
file!(),
|
||||
line!()
|
||||
)));
|
||||
}
|
||||
Err(LayoutProblem::Erroneous) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"Erroneous {} line {}",
|
||||
file!(),
|
||||
line!()
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
match variant {
|
||||
Never => unreachable!(
|
||||
"The `[]` type has no constructors, source var {:?}",
|
||||
variant_var
|
||||
),
|
||||
Unit | UnitWithArguments => {
|
||||
Stmt::Let(assigned, Expr::Struct(&[]), Layout::Struct(&[]), hole)
|
||||
}
|
||||
BoolUnion { ttrue, .. } => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Bool(tag_name == ttrue)),
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
hole,
|
||||
),
|
||||
ByteUnion(tag_names) => {
|
||||
let tag_id = tag_names
|
||||
.iter()
|
||||
.position(|key| key == &tag_name)
|
||||
.expect("tag must be in its own type");
|
||||
|
||||
Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Byte(tag_id as u8)),
|
||||
Layout::Builtin(Builtin::Int8),
|
||||
hole,
|
||||
)
|
||||
}
|
||||
|
||||
Unwrapped(field_layouts) => {
|
||||
let field_symbols_temp = sorted_field_symbols(env, procs, layout_cache, args);
|
||||
|
||||
let mut field_symbols = Vec::with_capacity_in(field_layouts.len(), env.arena);
|
||||
field_symbols.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
let field_symbols = field_symbols.into_bump_slice();
|
||||
|
||||
// Layout will unpack this unwrapped tack if it only has one (non-zero-sized) field
|
||||
let layout = layout_cache
|
||||
.from_var(env.arena, variant_var, env.subs)
|
||||
.unwrap_or_else(|err| {
|
||||
panic!("TODO turn fn_var into a RuntimeError {:?}", err)
|
||||
});
|
||||
|
||||
// even though this was originally a Tag, we treat it as a Struct from now on
|
||||
let stmt = Stmt::Let(assigned, Expr::Struct(field_symbols), layout, hole);
|
||||
|
||||
let iter = field_symbols_temp.into_iter().map(|(_, _, data)| data);
|
||||
assign_to_symbols(env, procs, layout_cache, iter, stmt)
|
||||
}
|
||||
Wrapped(variant) => {
|
||||
let union_size = variant.number_of_tags() as u8;
|
||||
let (tag_id, _) = variant.tag_name_to_id(&tag_name);
|
||||
|
||||
let field_symbols_temp = sorted_field_symbols(env, procs, layout_cache, args);
|
||||
|
||||
let field_symbols;
|
||||
let opt_tag_id_symbol;
|
||||
|
||||
use WrappedVariant::*;
|
||||
let (tag, layout) = match variant {
|
||||
Recursive { sorted_tag_layouts } => {
|
||||
debug_assert!(sorted_tag_layouts.len() > 1);
|
||||
let tag_id_symbol = env.unique_symbol();
|
||||
opt_tag_id_symbol = Some(tag_id_symbol);
|
||||
|
||||
field_symbols = {
|
||||
let mut temp =
|
||||
Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
|
||||
temp.push(tag_id_symbol);
|
||||
|
||||
temp.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
|
||||
temp.into_bump_slice()
|
||||
};
|
||||
|
||||
let mut layouts: Vec<&'a [Layout<'a>]> =
|
||||
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
|
||||
|
||||
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
|
||||
layouts.push(arg_layouts);
|
||||
}
|
||||
|
||||
debug_assert!(layouts.len() > 1);
|
||||
let layout =
|
||||
Layout::Union(UnionLayout::Recursive(layouts.into_bump_slice()));
|
||||
|
||||
let tag = Expr::Tag {
|
||||
tag_layout: layout,
|
||||
tag_name,
|
||||
tag_id: tag_id as u8,
|
||||
union_size,
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
(tag, layout)
|
||||
}
|
||||
NonNullableUnwrapped {
|
||||
fields,
|
||||
tag_name: wrapped_tag_name,
|
||||
} => {
|
||||
debug_assert_eq!(tag_name, wrapped_tag_name);
|
||||
|
||||
opt_tag_id_symbol = None;
|
||||
|
||||
field_symbols = {
|
||||
let mut temp =
|
||||
Vec::with_capacity_in(field_symbols_temp.len(), arena);
|
||||
|
||||
temp.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
|
||||
temp.into_bump_slice()
|
||||
};
|
||||
|
||||
let layout = Layout::Union(UnionLayout::NonNullableUnwrapped(fields));
|
||||
|
||||
let tag = Expr::Tag {
|
||||
tag_layout: layout,
|
||||
tag_name,
|
||||
tag_id: tag_id as u8,
|
||||
union_size,
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
(tag, layout)
|
||||
}
|
||||
NonRecursive { sorted_tag_layouts } => {
|
||||
let tag_id_symbol = env.unique_symbol();
|
||||
opt_tag_id_symbol = Some(tag_id_symbol);
|
||||
|
||||
field_symbols = {
|
||||
let mut temp =
|
||||
Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
|
||||
temp.push(tag_id_symbol);
|
||||
|
||||
temp.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
|
||||
temp.into_bump_slice()
|
||||
};
|
||||
|
||||
let mut layouts: Vec<&'a [Layout<'a>]> =
|
||||
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
|
||||
|
||||
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
|
||||
layouts.push(arg_layouts);
|
||||
}
|
||||
|
||||
let layout =
|
||||
Layout::Union(UnionLayout::NonRecursive(layouts.into_bump_slice()));
|
||||
|
||||
let tag = Expr::Tag {
|
||||
tag_layout: layout,
|
||||
tag_name,
|
||||
tag_id: tag_id as u8,
|
||||
union_size,
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
(tag, layout)
|
||||
}
|
||||
NullableWrapped {
|
||||
nullable_id,
|
||||
nullable_name: _,
|
||||
sorted_tag_layouts,
|
||||
} => {
|
||||
let tag_id_symbol = env.unique_symbol();
|
||||
opt_tag_id_symbol = Some(tag_id_symbol);
|
||||
|
||||
field_symbols = {
|
||||
let mut temp =
|
||||
Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
|
||||
temp.push(tag_id_symbol);
|
||||
|
||||
temp.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
|
||||
temp.into_bump_slice()
|
||||
};
|
||||
|
||||
let mut layouts: Vec<&'a [Layout<'a>]> =
|
||||
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
|
||||
|
||||
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
|
||||
layouts.push(arg_layouts);
|
||||
}
|
||||
|
||||
let layout = Layout::Union(UnionLayout::NullableWrapped {
|
||||
nullable_id,
|
||||
other_tags: layouts.into_bump_slice(),
|
||||
});
|
||||
|
||||
let tag = Expr::Tag {
|
||||
tag_layout: layout,
|
||||
tag_name,
|
||||
tag_id: tag_id as u8,
|
||||
union_size,
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
(tag, layout)
|
||||
}
|
||||
NullableUnwrapped {
|
||||
nullable_id,
|
||||
nullable_name: _,
|
||||
other_name: _,
|
||||
other_fields,
|
||||
} => {
|
||||
// FIXME drop tag
|
||||
let tag_id_symbol = env.unique_symbol();
|
||||
opt_tag_id_symbol = Some(tag_id_symbol);
|
||||
|
||||
field_symbols = {
|
||||
let mut temp =
|
||||
Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
|
||||
// FIXME drop tag
|
||||
temp.push(tag_id_symbol);
|
||||
|
||||
temp.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
|
||||
temp.into_bump_slice()
|
||||
};
|
||||
|
||||
let layout = Layout::Union(UnionLayout::NullableUnwrapped {
|
||||
nullable_id,
|
||||
other_fields,
|
||||
});
|
||||
|
||||
let tag = Expr::Tag {
|
||||
tag_layout: layout,
|
||||
tag_name,
|
||||
tag_id: tag_id as u8,
|
||||
union_size,
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
(tag, layout)
|
||||
}
|
||||
};
|
||||
|
||||
let mut stmt = Stmt::Let(assigned, tag, layout, hole);
|
||||
let iter = field_symbols_temp
|
||||
.into_iter()
|
||||
.map(|x| x.2 .0)
|
||||
.rev()
|
||||
.zip(field_symbols.iter().rev());
|
||||
|
||||
stmt = assign_to_symbols(env, procs, layout_cache, iter, stmt);
|
||||
|
||||
if let Some(tag_id_symbol) = opt_tag_id_symbol {
|
||||
// define the tag id
|
||||
stmt = Stmt::Let(
|
||||
tag_id_symbol,
|
||||
Expr::Literal(Literal::Int(tag_id as i128)),
|
||||
Layout::Builtin(TAG_SIZE),
|
||||
arena.alloc(stmt),
|
||||
);
|
||||
}
|
||||
|
||||
stmt
|
||||
}
|
||||
)
|
||||
} else {
|
||||
convert_tag_union(
|
||||
env,
|
||||
variant_var,
|
||||
assigned,
|
||||
hole,
|
||||
tag_name,
|
||||
procs,
|
||||
layout_cache,
|
||||
args,
|
||||
arena,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -4168,7 +3929,10 @@ pub fn with_hole<'a>(
|
||||
return_on_layout_error!(env, layout_cache.from_var(env.arena, ret_var, env.subs));
|
||||
|
||||
let call = self::Call {
|
||||
call_type: CallType::LowLevel { op },
|
||||
call_type: CallType::LowLevel {
|
||||
op,
|
||||
update_mode: env.next_update_mode_id(),
|
||||
},
|
||||
arguments: arg_symbols,
|
||||
};
|
||||
|
||||
@ -4189,6 +3953,347 @@ pub fn with_hole<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn convert_tag_union<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
variant_var: Variable,
|
||||
assigned: Symbol,
|
||||
hole: &'a Stmt<'a>,
|
||||
tag_name: TagName,
|
||||
procs: &mut Procs<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
args: std::vec::Vec<(Variable, Located<roc_can::expr::Expr>)>,
|
||||
arena: &'a Bump,
|
||||
) -> Stmt<'a> {
|
||||
use crate::layout::UnionVariant::*;
|
||||
let res_variant = crate::layout::union_sorted_tags(env.arena, variant_var, env.subs);
|
||||
let variant = match res_variant {
|
||||
Ok(cached) => cached,
|
||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"UnresolvedTypeVar {} line {}",
|
||||
file!(),
|
||||
line!()
|
||||
)))
|
||||
}
|
||||
Err(LayoutProblem::Erroneous) => {
|
||||
return Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"Erroneous {} line {}",
|
||||
file!(),
|
||||
line!()
|
||||
)));
|
||||
}
|
||||
};
|
||||
match variant {
|
||||
Never => unreachable!(
|
||||
"The `[]` type has no constructors, source var {:?}",
|
||||
variant_var
|
||||
),
|
||||
Unit | UnitWithArguments => {
|
||||
Stmt::Let(assigned, Expr::Struct(&[]), Layout::Struct(&[]), hole)
|
||||
}
|
||||
BoolUnion { ttrue, .. } => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Bool(tag_name == ttrue)),
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
hole,
|
||||
),
|
||||
ByteUnion(tag_names) => {
|
||||
let tag_id = tag_names
|
||||
.iter()
|
||||
.position(|key| key == &tag_name)
|
||||
.expect("tag must be in its own type");
|
||||
|
||||
Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Byte(tag_id as u8)),
|
||||
Layout::Builtin(Builtin::Int8),
|
||||
hole,
|
||||
)
|
||||
}
|
||||
|
||||
Unwrapped(field_layouts) => {
|
||||
let field_symbols_temp = sorted_field_symbols(env, procs, layout_cache, args);
|
||||
|
||||
let mut field_symbols = Vec::with_capacity_in(field_layouts.len(), env.arena);
|
||||
field_symbols.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
let field_symbols = field_symbols.into_bump_slice();
|
||||
|
||||
// Layout will unpack this unwrapped tack if it only has one (non-zero-sized) field
|
||||
let layout = layout_cache
|
||||
.from_var(env.arena, variant_var, env.subs)
|
||||
.unwrap_or_else(|err| panic!("TODO turn fn_var into a RuntimeError {:?}", err));
|
||||
|
||||
// even though this was originally a Tag, we treat it as a Struct from now on
|
||||
let stmt = Stmt::Let(assigned, Expr::Struct(field_symbols), layout, hole);
|
||||
|
||||
let iter = field_symbols_temp.into_iter().map(|(_, _, data)| data);
|
||||
assign_to_symbols(env, procs, layout_cache, iter, stmt)
|
||||
}
|
||||
Wrapped(variant) => {
|
||||
let union_size = variant.number_of_tags() as u8;
|
||||
let (tag_id, _) = variant.tag_name_to_id(&tag_name);
|
||||
|
||||
let field_symbols_temp = sorted_field_symbols(env, procs, layout_cache, args);
|
||||
|
||||
let field_symbols;
|
||||
let opt_tag_id_symbol;
|
||||
|
||||
use WrappedVariant::*;
|
||||
let (tag, layout) = match variant {
|
||||
Recursive { sorted_tag_layouts } => {
|
||||
debug_assert!(sorted_tag_layouts.len() > 1);
|
||||
let tag_id_symbol = env.unique_symbol();
|
||||
opt_tag_id_symbol = Some(tag_id_symbol);
|
||||
|
||||
field_symbols = {
|
||||
let mut temp = Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
|
||||
temp.push(tag_id_symbol);
|
||||
|
||||
temp.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
|
||||
temp.into_bump_slice()
|
||||
};
|
||||
|
||||
let mut layouts: Vec<&'a [Layout<'a>]> =
|
||||
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
|
||||
|
||||
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
|
||||
layouts.push(arg_layouts);
|
||||
}
|
||||
|
||||
debug_assert!(layouts.len() > 1);
|
||||
let layout = Layout::Union(UnionLayout::Recursive(layouts.into_bump_slice()));
|
||||
|
||||
let tag = Expr::Tag {
|
||||
tag_layout: layout,
|
||||
tag_name,
|
||||
tag_id: tag_id as u8,
|
||||
union_size,
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
(tag, layout)
|
||||
}
|
||||
NonNullableUnwrapped {
|
||||
fields,
|
||||
tag_name: wrapped_tag_name,
|
||||
} => {
|
||||
debug_assert_eq!(tag_name, wrapped_tag_name);
|
||||
|
||||
opt_tag_id_symbol = None;
|
||||
|
||||
field_symbols = {
|
||||
let mut temp = Vec::with_capacity_in(field_symbols_temp.len(), arena);
|
||||
|
||||
temp.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
|
||||
temp.into_bump_slice()
|
||||
};
|
||||
|
||||
let layout = Layout::Union(UnionLayout::NonNullableUnwrapped(fields));
|
||||
|
||||
let tag = Expr::Tag {
|
||||
tag_layout: layout,
|
||||
tag_name,
|
||||
tag_id: tag_id as u8,
|
||||
union_size,
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
(tag, layout)
|
||||
}
|
||||
NonRecursive { sorted_tag_layouts } => {
|
||||
let tag_id_symbol = env.unique_symbol();
|
||||
opt_tag_id_symbol = Some(tag_id_symbol);
|
||||
|
||||
field_symbols = {
|
||||
let mut temp = Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
|
||||
temp.push(tag_id_symbol);
|
||||
|
||||
temp.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
|
||||
temp.into_bump_slice()
|
||||
};
|
||||
|
||||
let mut layouts: Vec<&'a [Layout<'a>]> =
|
||||
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
|
||||
|
||||
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
|
||||
layouts.push(arg_layouts);
|
||||
}
|
||||
|
||||
let layout =
|
||||
Layout::Union(UnionLayout::NonRecursive(layouts.into_bump_slice()));
|
||||
|
||||
let tag = Expr::Tag {
|
||||
tag_layout: layout,
|
||||
tag_name,
|
||||
tag_id: tag_id as u8,
|
||||
union_size,
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
(tag, layout)
|
||||
}
|
||||
NullableWrapped {
|
||||
nullable_id,
|
||||
nullable_name: _,
|
||||
sorted_tag_layouts,
|
||||
} => {
|
||||
let tag_id_symbol = env.unique_symbol();
|
||||
opt_tag_id_symbol = Some(tag_id_symbol);
|
||||
|
||||
field_symbols = {
|
||||
let mut temp = Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
|
||||
temp.push(tag_id_symbol);
|
||||
|
||||
temp.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
|
||||
temp.into_bump_slice()
|
||||
};
|
||||
|
||||
let mut layouts: Vec<&'a [Layout<'a>]> =
|
||||
Vec::with_capacity_in(sorted_tag_layouts.len(), env.arena);
|
||||
|
||||
for (_, arg_layouts) in sorted_tag_layouts.into_iter() {
|
||||
layouts.push(arg_layouts);
|
||||
}
|
||||
|
||||
let layout = Layout::Union(UnionLayout::NullableWrapped {
|
||||
nullable_id,
|
||||
other_tags: layouts.into_bump_slice(),
|
||||
});
|
||||
|
||||
let tag = Expr::Tag {
|
||||
tag_layout: layout,
|
||||
tag_name,
|
||||
tag_id: tag_id as u8,
|
||||
union_size,
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
(tag, layout)
|
||||
}
|
||||
NullableUnwrapped {
|
||||
nullable_id,
|
||||
nullable_name: _,
|
||||
other_name: _,
|
||||
other_fields,
|
||||
} => {
|
||||
// FIXME drop tag
|
||||
let tag_id_symbol = env.unique_symbol();
|
||||
opt_tag_id_symbol = Some(tag_id_symbol);
|
||||
|
||||
field_symbols = {
|
||||
let mut temp = Vec::with_capacity_in(field_symbols_temp.len() + 1, arena);
|
||||
// FIXME drop tag
|
||||
temp.push(tag_id_symbol);
|
||||
|
||||
temp.extend(field_symbols_temp.iter().map(|r| r.1));
|
||||
|
||||
temp.into_bump_slice()
|
||||
};
|
||||
|
||||
let layout = Layout::Union(UnionLayout::NullableUnwrapped {
|
||||
nullable_id,
|
||||
other_fields,
|
||||
});
|
||||
|
||||
let tag = Expr::Tag {
|
||||
tag_layout: layout,
|
||||
tag_name,
|
||||
tag_id: tag_id as u8,
|
||||
union_size,
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
||||
(tag, layout)
|
||||
}
|
||||
};
|
||||
|
||||
let mut stmt = Stmt::Let(assigned, tag, layout, hole);
|
||||
let iter = field_symbols_temp
|
||||
.into_iter()
|
||||
.map(|x| x.2 .0)
|
||||
.rev()
|
||||
.zip(field_symbols.iter().rev());
|
||||
|
||||
stmt = assign_to_symbols(env, procs, layout_cache, iter, stmt);
|
||||
|
||||
if let Some(tag_id_symbol) = opt_tag_id_symbol {
|
||||
// define the tag id
|
||||
stmt = Stmt::Let(
|
||||
tag_id_symbol,
|
||||
Expr::Literal(Literal::Int(tag_id as i128)),
|
||||
Layout::Builtin(TAG_SIZE),
|
||||
arena.alloc(stmt),
|
||||
);
|
||||
}
|
||||
|
||||
stmt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn tag_union_to_function<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
arg_vars: std::vec::Vec<Variable>,
|
||||
ret_var: Variable,
|
||||
tag_name: TagName,
|
||||
ext_var: Variable,
|
||||
procs: &mut Procs<'a>,
|
||||
variant_var: Variable,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
assigned: Symbol,
|
||||
hole: &'a Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
let mut loc_pattern_args = vec![];
|
||||
let mut loc_expr_args = vec![];
|
||||
let proc_symbol = env.unique_symbol();
|
||||
for arg_var in arg_vars {
|
||||
let arg_symbol = env.unique_symbol();
|
||||
|
||||
let loc_pattern = Located::at_zero(roc_can::pattern::Pattern::Identifier(arg_symbol));
|
||||
|
||||
let loc_expr = Located::at_zero(roc_can::expr::Expr::Var(arg_symbol));
|
||||
|
||||
loc_pattern_args.push((arg_var, loc_pattern));
|
||||
loc_expr_args.push((arg_var, loc_expr));
|
||||
}
|
||||
let loc_body = Located::at_zero(roc_can::expr::Expr::Tag {
|
||||
variant_var: ret_var,
|
||||
name: tag_name,
|
||||
arguments: loc_expr_args,
|
||||
ext_var,
|
||||
});
|
||||
let inserted = procs.insert_anonymous(
|
||||
env,
|
||||
proc_symbol,
|
||||
variant_var,
|
||||
loc_pattern_args,
|
||||
loc_body,
|
||||
CapturedSymbols::None,
|
||||
ret_var,
|
||||
layout_cache,
|
||||
);
|
||||
match inserted {
|
||||
Ok(layout) => Stmt::Let(
|
||||
assigned,
|
||||
call_by_pointer(env, procs, proc_symbol, layout),
|
||||
layout,
|
||||
hole,
|
||||
),
|
||||
Err(runtime_error) => Stmt::RuntimeError(env.arena.alloc(format!(
|
||||
"RuntimeError {} line {} {:?}",
|
||||
file!(),
|
||||
line!(),
|
||||
runtime_error,
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn sorted_field_symbols<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
@ -4316,8 +4421,10 @@ pub fn from_can<'a>(
|
||||
let bool_layout = Layout::Builtin(Builtin::Int1);
|
||||
let cond_symbol = env.unique_symbol();
|
||||
|
||||
let op = LowLevel::ExpectTrue;
|
||||
let call_type = CallType::LowLevel {
|
||||
op: LowLevel::ExpectTrue,
|
||||
op,
|
||||
update_mode: env.next_update_mode_id(),
|
||||
};
|
||||
let arguments = env.arena.alloc([cond_symbol]);
|
||||
let call = self::Call {
|
||||
@ -5054,11 +5161,13 @@ fn substitute_in_call<'a>(
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
full_layout,
|
||||
specialization_id,
|
||||
} => substitute(subs, *name).map(|new| CallType::ByName {
|
||||
name: new,
|
||||
arg_layouts,
|
||||
ret_layout: *ret_layout,
|
||||
full_layout: *full_layout,
|
||||
specialization_id: *specialization_id,
|
||||
}),
|
||||
CallType::ByPointer {
|
||||
name,
|
||||
@ -5840,6 +5949,7 @@ fn call_by_pointer<'a>(
|
||||
full_layout: layout,
|
||||
ret_layout: *ret_layout,
|
||||
arg_layouts,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
};
|
||||
let call = Call {
|
||||
call_type,
|
||||
@ -6098,6 +6208,7 @@ fn call_by_name<'a>(
|
||||
ret_layout: *ret_layout,
|
||||
full_layout,
|
||||
arg_layouts,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
arguments: field_symbols,
|
||||
};
|
||||
@ -6142,6 +6253,7 @@ fn call_by_name<'a>(
|
||||
ret_layout: *ret_layout,
|
||||
full_layout,
|
||||
arg_layouts,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
arguments: field_symbols,
|
||||
};
|
||||
@ -6248,6 +6360,7 @@ fn call_by_name<'a>(
|
||||
ret_layout: *ret_layout,
|
||||
full_layout,
|
||||
arg_layouts,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
arguments: field_symbols,
|
||||
}
|
||||
@ -6311,6 +6424,7 @@ fn call_specialized_proc<'a>(
|
||||
ret_layout: function_layout.result,
|
||||
full_layout: function_layout.full,
|
||||
arg_layouts: function_layout.arguments,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
arguments: field_symbols,
|
||||
};
|
||||
@ -6332,6 +6446,7 @@ fn call_specialized_proc<'a>(
|
||||
ret_layout: function_layout.result,
|
||||
full_layout: function_layout.full,
|
||||
arg_layouts: function_layout.arguments,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
arguments: field_symbols,
|
||||
};
|
||||
@ -6351,6 +6466,7 @@ fn call_specialized_proc<'a>(
|
||||
ret_layout: function_layout.result,
|
||||
full_layout: function_layout.full,
|
||||
arg_layouts: function_layout.arguments,
|
||||
specialization_id: env.next_call_specialization_id(),
|
||||
},
|
||||
arguments: field_symbols,
|
||||
};
|
||||
|
@ -423,6 +423,12 @@ impl<'a, 'b> Env<'a, 'b> {
|
||||
|
||||
self.seen.insert(var)
|
||||
}
|
||||
|
||||
fn remove_seen(&mut self, var: Variable) -> bool {
|
||||
let var = self.subs.get_root_key_without_compacting(var);
|
||||
|
||||
self.seen.remove(&var)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Layout<'a> {
|
||||
@ -1155,6 +1161,14 @@ fn layout_from_flat_type<'a>(
|
||||
|
||||
Ok(layout_from_tag_union(arena, tags, subs))
|
||||
}
|
||||
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||
|
||||
let mut tags = MutMap::default();
|
||||
tags.insert(tag_name, vec![]);
|
||||
|
||||
Ok(layout_from_tag_union(arena, tags, subs))
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||
|
||||
@ -1240,6 +1254,8 @@ fn layout_from_flat_type<'a>(
|
||||
UnionLayout::Recursive(tag_layouts.into_bump_slice())
|
||||
};
|
||||
|
||||
env.remove_seen(rec_var);
|
||||
|
||||
Ok(Layout::Union(union_layout))
|
||||
}
|
||||
EmptyTagUnion => {
|
||||
@ -1980,3 +1996,21 @@ impl<'a> LayoutIds<'a> {
|
||||
LayoutId(answer)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ListLayout<'a> {
|
||||
EmptyList,
|
||||
List(&'a Layout<'a>),
|
||||
}
|
||||
|
||||
impl<'a> std::convert::TryFrom<&Layout<'a>> for ListLayout<'a> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: &Layout<'a>) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Layout::Builtin(Builtin::EmptyList) => Ok(ListLayout::EmptyList),
|
||||
Layout::Builtin(Builtin::List(_, element)) => Ok(ListLayout::List(element)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
||||
#![allow(clippy::large_enum_variant, clippy::upper_case_acronyms)]
|
||||
|
||||
pub mod alias_analysis;
|
||||
pub mod borrow;
|
||||
pub mod expand_rc;
|
||||
pub mod inc_dec;
|
||||
|
@ -240,18 +240,18 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.0 ():
|
||||
let Test.9 = 0i64;
|
||||
let Test.8 = 3i64;
|
||||
let Test.2 = Just Test.9 Test.8;
|
||||
let Test.5 = 0i64;
|
||||
let Test.6 = Index 0 Test.2;
|
||||
let Test.7 = lowlevel Eq Test.5 Test.6;
|
||||
if Test.7 then
|
||||
let Test.1 = Index 1 Test.2;
|
||||
ret Test.1;
|
||||
let Test.10 = 0i64;
|
||||
let Test.9 = 3i64;
|
||||
let Test.3 = Just Test.10 Test.9;
|
||||
let Test.6 = 0i64;
|
||||
let Test.7 = Index 0 Test.3;
|
||||
let Test.8 = lowlevel Eq Test.6 Test.7;
|
||||
if Test.8 then
|
||||
let Test.2 = Index 1 Test.3;
|
||||
ret Test.2;
|
||||
else
|
||||
let Test.4 = 0i64;
|
||||
ret Test.4;
|
||||
let Test.5 = 0i64;
|
||||
ret Test.5;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -269,23 +269,23 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.0 ():
|
||||
let Test.10 = 1i64;
|
||||
let Test.8 = 1i64;
|
||||
let Test.9 = 2i64;
|
||||
let Test.4 = These Test.10 Test.8 Test.9;
|
||||
switch Test.4:
|
||||
let Test.11 = 1i64;
|
||||
let Test.9 = 1i64;
|
||||
let Test.10 = 2i64;
|
||||
let Test.5 = These Test.11 Test.9 Test.10;
|
||||
switch Test.5:
|
||||
case 2:
|
||||
let Test.1 = Index 1 Test.4;
|
||||
ret Test.1;
|
||||
|
||||
case 0:
|
||||
let Test.2 = Index 1 Test.4;
|
||||
let Test.2 = Index 1 Test.5;
|
||||
ret Test.2;
|
||||
|
||||
default:
|
||||
let Test.3 = Index 1 Test.4;
|
||||
case 0:
|
||||
let Test.3 = Index 1 Test.5;
|
||||
ret Test.3;
|
||||
|
||||
default:
|
||||
let Test.4 = Index 1 Test.5;
|
||||
ret Test.4;
|
||||
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -435,24 +435,24 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Test.5 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Test.5;
|
||||
let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Test.6;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.11 = 0i64;
|
||||
let Test.10 = 41i64;
|
||||
let Test.1 = Just Test.11 Test.10;
|
||||
let Test.7 = 0i64;
|
||||
let Test.8 = Index 0 Test.1;
|
||||
let Test.9 = lowlevel Eq Test.7 Test.8;
|
||||
if Test.9 then
|
||||
let Test.2 = Index 1 Test.1;
|
||||
let Test.4 = 1i64;
|
||||
let Test.3 = CallByName Num.24 Test.2 Test.4;
|
||||
ret Test.3;
|
||||
let Test.12 = 0i64;
|
||||
let Test.11 = 41i64;
|
||||
let Test.1 = Just Test.12 Test.11;
|
||||
let Test.8 = 0i64;
|
||||
let Test.9 = Index 0 Test.1;
|
||||
let Test.10 = lowlevel Eq Test.8 Test.9;
|
||||
if Test.10 then
|
||||
let Test.3 = Index 1 Test.1;
|
||||
let Test.5 = 1i64;
|
||||
let Test.4 = CallByName Num.24 Test.3 Test.5;
|
||||
ret Test.4;
|
||||
else
|
||||
let Test.6 = 1i64;
|
||||
ret Test.6;
|
||||
let Test.7 = 1i64;
|
||||
ret Test.7;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -470,8 +470,8 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.0 ():
|
||||
let Test.3 = 2i64;
|
||||
let Test.1 = Struct {Test.3};
|
||||
let Test.4 = 2i64;
|
||||
let Test.1 = Struct {Test.4};
|
||||
ret Test.1;
|
||||
"#
|
||||
),
|
||||
@ -491,31 +491,31 @@ mod test_mono {
|
||||
"#,
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.5 = 2i64;
|
||||
joinpoint Test.11:
|
||||
let Test.9 = 0i64;
|
||||
ret Test.9;
|
||||
procedure Test.1 (Test.3):
|
||||
let Test.6 = 2i64;
|
||||
joinpoint Test.12:
|
||||
let Test.10 = 0i64;
|
||||
ret Test.10;
|
||||
in
|
||||
let Test.10 = 2i64;
|
||||
let Test.13 = lowlevel Eq Test.10 Test.5;
|
||||
if Test.13 then
|
||||
joinpoint Test.7 Test.12:
|
||||
if Test.12 then
|
||||
let Test.6 = 42i64;
|
||||
ret Test.6;
|
||||
let Test.11 = 2i64;
|
||||
let Test.14 = lowlevel Eq Test.11 Test.6;
|
||||
if Test.14 then
|
||||
joinpoint Test.8 Test.13:
|
||||
if Test.13 then
|
||||
let Test.7 = 42i64;
|
||||
ret Test.7;
|
||||
else
|
||||
jump Test.11;
|
||||
jump Test.12;
|
||||
in
|
||||
let Test.8 = false;
|
||||
jump Test.7 Test.8;
|
||||
let Test.9 = false;
|
||||
jump Test.8 Test.9;
|
||||
else
|
||||
jump Test.11;
|
||||
jump Test.12;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 = Struct {};
|
||||
let Test.3 = CallByName Test.1 Test.4;
|
||||
ret Test.3;
|
||||
let Test.5 = Struct {};
|
||||
let Test.4 = CallByName Test.1 Test.5;
|
||||
ret Test.4;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -562,37 +562,37 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Test.6;
|
||||
let Test.8 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Test.8;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.18 = 0i64;
|
||||
let Test.20 = 0i64;
|
||||
let Test.19 = 41i64;
|
||||
let Test.17 = Just Test.20 Test.19;
|
||||
let Test.2 = Just Test.18 Test.17;
|
||||
joinpoint Test.14:
|
||||
let Test.8 = 1i64;
|
||||
ret Test.8;
|
||||
let Test.22 = 0i64;
|
||||
let Test.21 = 41i64;
|
||||
let Test.19 = Just Test.22 Test.21;
|
||||
let Test.2 = Just Test.20 Test.19;
|
||||
joinpoint Test.16:
|
||||
let Test.10 = 1i64;
|
||||
ret Test.10;
|
||||
in
|
||||
let Test.12 = 0i64;
|
||||
let Test.13 = Index 0 Test.2;
|
||||
let Test.16 = lowlevel Eq Test.12 Test.13;
|
||||
if Test.16 then
|
||||
let Test.9 = Index 1 Test.2;
|
||||
let Test.10 = 0i64;
|
||||
let Test.11 = Index 0 Test.9;
|
||||
let Test.15 = lowlevel Eq Test.10 Test.11;
|
||||
if Test.15 then
|
||||
let Test.7 = Index 1 Test.2;
|
||||
let Test.3 = Index 1 Test.7;
|
||||
let Test.5 = 1i64;
|
||||
let Test.4 = CallByName Num.24 Test.3 Test.5;
|
||||
ret Test.4;
|
||||
let Test.14 = 0i64;
|
||||
let Test.15 = Index 0 Test.2;
|
||||
let Test.18 = lowlevel Eq Test.14 Test.15;
|
||||
if Test.18 then
|
||||
let Test.11 = Index 1 Test.2;
|
||||
let Test.12 = 0i64;
|
||||
let Test.13 = Index 0 Test.11;
|
||||
let Test.17 = lowlevel Eq Test.12 Test.13;
|
||||
if Test.17 then
|
||||
let Test.9 = Index 1 Test.2;
|
||||
let Test.5 = Index 1 Test.9;
|
||||
let Test.7 = 1i64;
|
||||
let Test.6 = CallByName Num.24 Test.5 Test.7;
|
||||
ret Test.6;
|
||||
else
|
||||
jump Test.14;
|
||||
jump Test.16;
|
||||
else
|
||||
jump Test.14;
|
||||
jump Test.16;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -609,33 +609,33 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Test.6;
|
||||
let Test.7 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Test.7;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.15 = 3i64;
|
||||
let Test.14 = 2i64;
|
||||
let Test.3 = Struct {Test.14, Test.15};
|
||||
joinpoint Test.11:
|
||||
let Test.1 = Index 0 Test.3;
|
||||
let Test.2 = Index 1 Test.3;
|
||||
let Test.5 = CallByName Num.24 Test.1 Test.2;
|
||||
ret Test.5;
|
||||
let Test.16 = 3i64;
|
||||
let Test.15 = 2i64;
|
||||
let Test.4 = Struct {Test.15, Test.16};
|
||||
joinpoint Test.12:
|
||||
let Test.2 = Index 0 Test.4;
|
||||
let Test.3 = Index 1 Test.4;
|
||||
let Test.6 = CallByName Num.24 Test.2 Test.3;
|
||||
ret Test.6;
|
||||
in
|
||||
let Test.9 = Index 1 Test.3;
|
||||
let Test.10 = 3i64;
|
||||
let Test.13 = lowlevel Eq Test.10 Test.9;
|
||||
if Test.13 then
|
||||
let Test.7 = Index 0 Test.3;
|
||||
let Test.8 = 4i64;
|
||||
let Test.12 = lowlevel Eq Test.8 Test.7;
|
||||
if Test.12 then
|
||||
let Test.4 = 9i64;
|
||||
ret Test.4;
|
||||
let Test.10 = Index 1 Test.4;
|
||||
let Test.11 = 3i64;
|
||||
let Test.14 = lowlevel Eq Test.11 Test.10;
|
||||
if Test.14 then
|
||||
let Test.8 = Index 0 Test.4;
|
||||
let Test.9 = 4i64;
|
||||
let Test.13 = lowlevel Eq Test.9 Test.8;
|
||||
if Test.13 then
|
||||
let Test.5 = 9i64;
|
||||
ret Test.5;
|
||||
else
|
||||
jump Test.11;
|
||||
jump Test.12;
|
||||
else
|
||||
jump Test.11;
|
||||
jump Test.12;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -782,29 +782,29 @@ mod test_mono {
|
||||
"#,
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.1 (Test.4):
|
||||
procedure Test.1 (Test.5):
|
||||
let Test.2 = 0u8;
|
||||
joinpoint Test.8 Test.3:
|
||||
joinpoint Test.9 Test.3:
|
||||
ret Test.3;
|
||||
in
|
||||
switch Test.2:
|
||||
case 1:
|
||||
let Test.9 = 1i64;
|
||||
jump Test.8 Test.9;
|
||||
let Test.10 = 1i64;
|
||||
jump Test.9 Test.10;
|
||||
|
||||
case 2:
|
||||
let Test.10 = 2i64;
|
||||
jump Test.8 Test.10;
|
||||
let Test.11 = 2i64;
|
||||
jump Test.9 Test.11;
|
||||
|
||||
default:
|
||||
let Test.11 = 3i64;
|
||||
jump Test.8 Test.11;
|
||||
let Test.12 = 3i64;
|
||||
jump Test.9 Test.12;
|
||||
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.6 = Struct {};
|
||||
let Test.5 = CallByName Test.1 Test.6;
|
||||
ret Test.5;
|
||||
let Test.7 = Struct {};
|
||||
let Test.6 = CallByName Test.1 Test.7;
|
||||
ret Test.6;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -822,13 +822,13 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.0 ():
|
||||
let Test.2 = true;
|
||||
if Test.2 then
|
||||
let Test.3 = 1i64;
|
||||
ret Test.3;
|
||||
let Test.3 = true;
|
||||
if Test.3 then
|
||||
let Test.4 = 1i64;
|
||||
ret Test.4;
|
||||
else
|
||||
let Test.1 = 2i64;
|
||||
ret Test.1;
|
||||
let Test.2 = 2i64;
|
||||
ret Test.2;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -848,18 +848,18 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.0 ():
|
||||
let Test.4 = true;
|
||||
if Test.4 then
|
||||
let Test.5 = 1i64;
|
||||
ret Test.5;
|
||||
let Test.6 = true;
|
||||
if Test.6 then
|
||||
let Test.7 = 1i64;
|
||||
ret Test.7;
|
||||
else
|
||||
let Test.2 = false;
|
||||
if Test.2 then
|
||||
let Test.3 = 2i64;
|
||||
ret Test.3;
|
||||
let Test.4 = false;
|
||||
if Test.4 then
|
||||
let Test.5 = 2i64;
|
||||
ret Test.5;
|
||||
else
|
||||
let Test.1 = 3i64;
|
||||
ret Test.1;
|
||||
let Test.3 = 3i64;
|
||||
ret Test.3;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -884,34 +884,34 @@ mod test_mono {
|
||||
"#,
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.1 (Test.4):
|
||||
let Test.19 = 1i64;
|
||||
let Test.18 = 2i64;
|
||||
let Test.2 = Ok Test.19 Test.18;
|
||||
joinpoint Test.8 Test.3:
|
||||
procedure Test.1 (Test.5):
|
||||
let Test.20 = 1i64;
|
||||
let Test.19 = 2i64;
|
||||
let Test.2 = Ok Test.20 Test.19;
|
||||
joinpoint Test.9 Test.3:
|
||||
ret Test.3;
|
||||
in
|
||||
let Test.15 = 1i64;
|
||||
let Test.16 = Index 0 Test.2;
|
||||
let Test.17 = lowlevel Eq Test.15 Test.16;
|
||||
if Test.17 then
|
||||
let Test.12 = Index 1 Test.2;
|
||||
let Test.13 = 3i64;
|
||||
let Test.14 = lowlevel Eq Test.13 Test.12;
|
||||
if Test.14 then
|
||||
let Test.9 = 1i64;
|
||||
jump Test.8 Test.9;
|
||||
let Test.16 = 1i64;
|
||||
let Test.17 = Index 0 Test.2;
|
||||
let Test.18 = lowlevel Eq Test.16 Test.17;
|
||||
if Test.18 then
|
||||
let Test.13 = Index 1 Test.2;
|
||||
let Test.14 = 3i64;
|
||||
let Test.15 = lowlevel Eq Test.14 Test.13;
|
||||
if Test.15 then
|
||||
let Test.10 = 1i64;
|
||||
jump Test.9 Test.10;
|
||||
else
|
||||
let Test.10 = 2i64;
|
||||
jump Test.8 Test.10;
|
||||
let Test.11 = 2i64;
|
||||
jump Test.9 Test.11;
|
||||
else
|
||||
let Test.11 = 3i64;
|
||||
jump Test.8 Test.11;
|
||||
let Test.12 = 3i64;
|
||||
jump Test.9 Test.12;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.6 = Struct {};
|
||||
let Test.5 = CallByName Test.1 Test.6;
|
||||
ret Test.5;
|
||||
let Test.7 = Struct {};
|
||||
let Test.6 = CallByName Test.1 Test.7;
|
||||
ret Test.6;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -1373,70 +1373,70 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure List.3 (#Attr.2, #Attr.3):
|
||||
let Test.38 = lowlevel ListLen #Attr.2;
|
||||
let Test.34 = lowlevel NumLt #Attr.3 Test.38;
|
||||
if Test.34 then
|
||||
let Test.37 = 1i64;
|
||||
let Test.36 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
let Test.35 = Ok Test.37 Test.36;
|
||||
ret Test.35;
|
||||
let Test.39 = lowlevel ListLen #Attr.2;
|
||||
let Test.35 = lowlevel NumLt #Attr.3 Test.39;
|
||||
if Test.35 then
|
||||
let Test.38 = 1i64;
|
||||
let Test.37 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
let Test.36 = Ok Test.38 Test.37;
|
||||
ret Test.36;
|
||||
else
|
||||
let Test.33 = 0i64;
|
||||
let Test.32 = Struct {};
|
||||
let Test.31 = Err Test.33 Test.32;
|
||||
ret Test.31;
|
||||
let Test.34 = 0i64;
|
||||
let Test.33 = Struct {};
|
||||
let Test.32 = Err Test.34 Test.33;
|
||||
ret Test.32;
|
||||
|
||||
procedure List.4 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Test.14 = lowlevel ListLen #Attr.2;
|
||||
let Test.12 = lowlevel NumLt #Attr.3 Test.14;
|
||||
if Test.12 then
|
||||
let Test.13 = lowlevel ListSet #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Test.13;
|
||||
let Test.15 = lowlevel ListLen #Attr.2;
|
||||
let Test.13 = lowlevel NumLt #Attr.3 Test.15;
|
||||
if Test.13 then
|
||||
let Test.14 = lowlevel ListSet #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Test.14;
|
||||
else
|
||||
ret #Attr.2;
|
||||
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.39 = 0i64;
|
||||
let Test.29 = CallByName List.3 Test.2 Test.39;
|
||||
let Test.30 = 0i64;
|
||||
let Test.28 = CallByName List.3 Test.2 Test.30;
|
||||
let Test.7 = Struct {Test.28, Test.29};
|
||||
joinpoint Test.25:
|
||||
let Test.18 = Array [];
|
||||
ret Test.18;
|
||||
let Test.40 = 0i64;
|
||||
let Test.30 = CallByName List.3 Test.2 Test.40;
|
||||
let Test.31 = 0i64;
|
||||
let Test.29 = CallByName List.3 Test.2 Test.31;
|
||||
let Test.8 = Struct {Test.29, Test.30};
|
||||
joinpoint Test.26:
|
||||
let Test.19 = Array [];
|
||||
ret Test.19;
|
||||
in
|
||||
let Test.22 = Index 1 Test.7;
|
||||
let Test.23 = 1i64;
|
||||
let Test.24 = Index 0 Test.22;
|
||||
let Test.27 = lowlevel Eq Test.23 Test.24;
|
||||
if Test.27 then
|
||||
let Test.19 = Index 0 Test.7;
|
||||
let Test.20 = 1i64;
|
||||
let Test.21 = Index 0 Test.19;
|
||||
let Test.26 = lowlevel Eq Test.20 Test.21;
|
||||
if Test.26 then
|
||||
let Test.17 = Index 0 Test.7;
|
||||
let Test.3 = Index 1 Test.17;
|
||||
let Test.16 = Index 1 Test.7;
|
||||
let Test.4 = Index 1 Test.16;
|
||||
let Test.15 = 0i64;
|
||||
let Test.9 = CallByName List.4 Test.2 Test.15 Test.4;
|
||||
let Test.10 = 0i64;
|
||||
let Test.8 = CallByName List.4 Test.9 Test.10 Test.3;
|
||||
ret Test.8;
|
||||
let Test.23 = Index 1 Test.8;
|
||||
let Test.24 = 1i64;
|
||||
let Test.25 = Index 0 Test.23;
|
||||
let Test.28 = lowlevel Eq Test.24 Test.25;
|
||||
if Test.28 then
|
||||
let Test.20 = Index 0 Test.8;
|
||||
let Test.21 = 1i64;
|
||||
let Test.22 = Index 0 Test.20;
|
||||
let Test.27 = lowlevel Eq Test.21 Test.22;
|
||||
if Test.27 then
|
||||
let Test.18 = Index 0 Test.8;
|
||||
let Test.4 = Index 1 Test.18;
|
||||
let Test.17 = Index 1 Test.8;
|
||||
let Test.5 = Index 1 Test.17;
|
||||
let Test.16 = 0i64;
|
||||
let Test.10 = CallByName List.4 Test.2 Test.16 Test.5;
|
||||
let Test.11 = 0i64;
|
||||
let Test.9 = CallByName List.4 Test.10 Test.11 Test.4;
|
||||
ret Test.9;
|
||||
else
|
||||
dec Test.2;
|
||||
jump Test.25;
|
||||
jump Test.26;
|
||||
else
|
||||
dec Test.2;
|
||||
jump Test.25;
|
||||
jump Test.26;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.40 = 1i64;
|
||||
let Test.41 = 2i64;
|
||||
let Test.6 = Array [Test.40, Test.41];
|
||||
let Test.5 = CallByName Test.1 Test.6;
|
||||
ret Test.5;
|
||||
let Test.41 = 1i64;
|
||||
let Test.42 = 2i64;
|
||||
let Test.7 = Array [Test.41, Test.42];
|
||||
let Test.6 = CallByName Test.1 Test.7;
|
||||
ret Test.6;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -1707,16 +1707,16 @@ mod test_mono {
|
||||
r#"
|
||||
procedure Test.1 (Test.2):
|
||||
inc Test.2;
|
||||
let Test.5 = Struct {Test.2, Test.2};
|
||||
ret Test.5;
|
||||
let Test.6 = Struct {Test.2, Test.2};
|
||||
ret Test.6;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.6 = 1i64;
|
||||
let Test.7 = 2i64;
|
||||
let Test.8 = 3i64;
|
||||
let Test.4 = Array [Test.6, Test.7, Test.8];
|
||||
let Test.3 = CallByName Test.1 Test.4;
|
||||
ret Test.3;
|
||||
let Test.7 = 1i64;
|
||||
let Test.8 = 2i64;
|
||||
let Test.9 = 3i64;
|
||||
let Test.5 = Array [Test.7, Test.8, Test.9];
|
||||
let Test.4 = CallByName Test.1 Test.5;
|
||||
ret Test.4;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -1885,14 +1885,14 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.0 ():
|
||||
let Test.5 = 0i64;
|
||||
let Test.7 = 0i64;
|
||||
let Test.9 = 0i64;
|
||||
let Test.10 = 1i64;
|
||||
let Test.8 = Z Test.10;
|
||||
let Test.6 = S Test.9 Test.8;
|
||||
let Test.4 = S Test.7 Test.6;
|
||||
let Test.2 = S Test.5 Test.4;
|
||||
let Test.11 = 0i64;
|
||||
let Test.13 = 0i64;
|
||||
let Test.14 = 1i64;
|
||||
let Test.12 = Z Test.14;
|
||||
let Test.10 = S Test.13 Test.12;
|
||||
let Test.8 = S Test.11 Test.10;
|
||||
let Test.2 = S Test.9 Test.8;
|
||||
ret Test.2;
|
||||
"#
|
||||
),
|
||||
@ -1917,24 +1917,24 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.0 ():
|
||||
let Test.9 = 0i64;
|
||||
let Test.11 = 0i64;
|
||||
let Test.13 = 0i64;
|
||||
let Test.14 = 1i64;
|
||||
let Test.12 = Z Test.14;
|
||||
let Test.10 = S Test.13 Test.12;
|
||||
let Test.8 = S Test.11 Test.10;
|
||||
let Test.2 = S Test.9 Test.8;
|
||||
let Test.5 = 1i64;
|
||||
let Test.6 = Index 0 Test.2;
|
||||
let Test.15 = 0i64;
|
||||
let Test.17 = 0i64;
|
||||
let Test.18 = 1i64;
|
||||
let Test.16 = Z Test.18;
|
||||
let Test.14 = S Test.17 Test.16;
|
||||
let Test.12 = S Test.15 Test.14;
|
||||
let Test.2 = S Test.13 Test.12;
|
||||
let Test.9 = 1i64;
|
||||
let Test.10 = Index 0 Test.2;
|
||||
dec Test.2;
|
||||
let Test.7 = lowlevel Eq Test.5 Test.6;
|
||||
if Test.7 then
|
||||
let Test.3 = 0i64;
|
||||
ret Test.3;
|
||||
let Test.11 = lowlevel Eq Test.9 Test.10;
|
||||
if Test.11 then
|
||||
let Test.7 = 0i64;
|
||||
ret Test.7;
|
||||
else
|
||||
let Test.4 = 1i64;
|
||||
ret Test.4;
|
||||
let Test.8 = 1i64;
|
||||
ret Test.8;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -1959,33 +1959,33 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Test.0 ():
|
||||
let Test.15 = 0i64;
|
||||
let Test.17 = 0i64;
|
||||
let Test.19 = 0i64;
|
||||
let Test.20 = 1i64;
|
||||
let Test.18 = Z Test.20;
|
||||
let Test.16 = S Test.19 Test.18;
|
||||
let Test.14 = S Test.17 Test.16;
|
||||
let Test.2 = S Test.15 Test.14;
|
||||
let Test.11 = 0i64;
|
||||
let Test.12 = Index 0 Test.2;
|
||||
let Test.13 = lowlevel Eq Test.11 Test.12;
|
||||
if Test.13 then
|
||||
let Test.7 = Index 1 Test.2;
|
||||
let Test.8 = 0i64;
|
||||
let Test.9 = Index 0 Test.7;
|
||||
dec Test.7;
|
||||
let Test.21 = 0i64;
|
||||
let Test.23 = 0i64;
|
||||
let Test.24 = 1i64;
|
||||
let Test.22 = Z Test.24;
|
||||
let Test.20 = S Test.23 Test.22;
|
||||
let Test.18 = S Test.21 Test.20;
|
||||
let Test.2 = S Test.19 Test.18;
|
||||
let Test.15 = 0i64;
|
||||
let Test.16 = Index 0 Test.2;
|
||||
let Test.17 = lowlevel Eq Test.15 Test.16;
|
||||
if Test.17 then
|
||||
let Test.11 = Index 1 Test.2;
|
||||
let Test.12 = 0i64;
|
||||
let Test.13 = Index 0 Test.11;
|
||||
dec Test.11;
|
||||
decref Test.2;
|
||||
let Test.10 = lowlevel Eq Test.8 Test.9;
|
||||
if Test.10 then
|
||||
let Test.3 = 1i64;
|
||||
ret Test.3;
|
||||
let Test.14 = lowlevel Eq Test.12 Test.13;
|
||||
if Test.14 then
|
||||
let Test.7 = 1i64;
|
||||
ret Test.7;
|
||||
else
|
||||
let Test.5 = 0i64;
|
||||
ret Test.5;
|
||||
let Test.9 = 0i64;
|
||||
ret Test.9;
|
||||
else
|
||||
let Test.6 = 0i64;
|
||||
ret Test.6;
|
||||
let Test.10 = 0i64;
|
||||
ret Test.10;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -2012,14 +2012,14 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Num.26 (#Attr.2, #Attr.3):
|
||||
let Test.13 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||
ret Test.13;
|
||||
let Test.17 = lowlevel NumMul #Attr.2 #Attr.3;
|
||||
ret Test.17;
|
||||
|
||||
procedure Test.1 (Test.6):
|
||||
let Test.18 = Index 1 Test.6;
|
||||
let Test.19 = false;
|
||||
let Test.20 = lowlevel Eq Test.19 Test.18;
|
||||
if Test.20 then
|
||||
let Test.22 = Index 1 Test.6;
|
||||
let Test.23 = false;
|
||||
let Test.24 = lowlevel Eq Test.23 Test.22;
|
||||
if Test.24 then
|
||||
let Test.8 = Index 0 Test.6;
|
||||
ret Test.8;
|
||||
else
|
||||
@ -2027,10 +2027,10 @@ mod test_mono {
|
||||
ret Test.10;
|
||||
|
||||
procedure Test.1 (Test.6):
|
||||
let Test.29 = Index 0 Test.6;
|
||||
let Test.30 = false;
|
||||
let Test.31 = lowlevel Eq Test.30 Test.29;
|
||||
if Test.31 then
|
||||
let Test.33 = Index 0 Test.6;
|
||||
let Test.34 = false;
|
||||
let Test.35 = lowlevel Eq Test.34 Test.33;
|
||||
if Test.35 then
|
||||
let Test.8 = 3i64;
|
||||
ret Test.8;
|
||||
else
|
||||
@ -2038,24 +2038,24 @@ mod test_mono {
|
||||
ret Test.10;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.34 = true;
|
||||
let Test.33 = Struct {Test.34};
|
||||
let Test.5 = CallByName Test.1 Test.33;
|
||||
let Test.32 = false;
|
||||
let Test.26 = Struct {Test.32};
|
||||
let Test.3 = CallByName Test.1 Test.26;
|
||||
let Test.24 = 11i64;
|
||||
let Test.25 = true;
|
||||
let Test.23 = Struct {Test.24, Test.25};
|
||||
let Test.4 = CallByName Test.1 Test.23;
|
||||
let Test.21 = 7i64;
|
||||
let Test.22 = false;
|
||||
let Test.15 = Struct {Test.21, Test.22};
|
||||
let Test.2 = CallByName Test.1 Test.15;
|
||||
let Test.14 = CallByName Num.26 Test.2 Test.3;
|
||||
let Test.12 = CallByName Num.26 Test.14 Test.4;
|
||||
let Test.11 = CallByName Num.26 Test.12 Test.5;
|
||||
ret Test.11;
|
||||
let Test.38 = true;
|
||||
let Test.37 = Struct {Test.38};
|
||||
let Test.5 = CallByName Test.1 Test.37;
|
||||
let Test.36 = false;
|
||||
let Test.30 = Struct {Test.36};
|
||||
let Test.3 = CallByName Test.1 Test.30;
|
||||
let Test.28 = 11i64;
|
||||
let Test.29 = true;
|
||||
let Test.27 = Struct {Test.28, Test.29};
|
||||
let Test.4 = CallByName Test.1 Test.27;
|
||||
let Test.25 = 7i64;
|
||||
let Test.26 = false;
|
||||
let Test.19 = Struct {Test.25, Test.26};
|
||||
let Test.2 = CallByName Test.1 Test.19;
|
||||
let Test.18 = CallByName Num.26 Test.2 Test.3;
|
||||
let Test.16 = CallByName Num.26 Test.18 Test.4;
|
||||
let Test.15 = CallByName Num.26 Test.16 Test.5;
|
||||
ret Test.15;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -2079,37 +2079,37 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure Num.24 (#Attr.2, #Attr.3):
|
||||
let Test.6 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Test.6;
|
||||
let Test.8 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Test.8;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.18 = 0i64;
|
||||
let Test.20 = 0i64;
|
||||
let Test.19 = 41i64;
|
||||
let Test.17 = Just Test.20 Test.19;
|
||||
let Test.2 = Just Test.18 Test.17;
|
||||
joinpoint Test.14:
|
||||
let Test.8 = 1i64;
|
||||
ret Test.8;
|
||||
let Test.22 = 0i64;
|
||||
let Test.21 = 41i64;
|
||||
let Test.19 = Just Test.22 Test.21;
|
||||
let Test.2 = Just Test.20 Test.19;
|
||||
joinpoint Test.16:
|
||||
let Test.10 = 1i64;
|
||||
ret Test.10;
|
||||
in
|
||||
let Test.12 = 0i64;
|
||||
let Test.13 = Index 0 Test.2;
|
||||
let Test.16 = lowlevel Eq Test.12 Test.13;
|
||||
if Test.16 then
|
||||
let Test.9 = Index 1 Test.2;
|
||||
let Test.10 = 0i64;
|
||||
let Test.11 = Index 0 Test.9;
|
||||
let Test.15 = lowlevel Eq Test.10 Test.11;
|
||||
if Test.15 then
|
||||
let Test.7 = Index 1 Test.2;
|
||||
let Test.3 = Index 1 Test.7;
|
||||
let Test.5 = 1i64;
|
||||
let Test.4 = CallByName Num.24 Test.3 Test.5;
|
||||
ret Test.4;
|
||||
let Test.14 = 0i64;
|
||||
let Test.15 = Index 0 Test.2;
|
||||
let Test.18 = lowlevel Eq Test.14 Test.15;
|
||||
if Test.18 then
|
||||
let Test.11 = Index 1 Test.2;
|
||||
let Test.12 = 0i64;
|
||||
let Test.13 = Index 0 Test.11;
|
||||
let Test.17 = lowlevel Eq Test.12 Test.13;
|
||||
if Test.17 then
|
||||
let Test.9 = Index 1 Test.2;
|
||||
let Test.5 = Index 1 Test.9;
|
||||
let Test.7 = 1i64;
|
||||
let Test.6 = CallByName Num.24 Test.5 Test.7;
|
||||
ret Test.6;
|
||||
else
|
||||
jump Test.14;
|
||||
jump Test.16;
|
||||
else
|
||||
jump Test.14;
|
||||
jump Test.16;
|
||||
"#
|
||||
),
|
||||
)
|
||||
@ -2198,67 +2198,67 @@ mod test_mono {
|
||||
indoc!(
|
||||
r#"
|
||||
procedure List.3 (#Attr.2, #Attr.3):
|
||||
let Test.40 = lowlevel ListLen #Attr.2;
|
||||
let Test.36 = lowlevel NumLt #Attr.3 Test.40;
|
||||
if Test.36 then
|
||||
let Test.39 = 1i64;
|
||||
let Test.38 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
let Test.37 = Ok Test.39 Test.38;
|
||||
ret Test.37;
|
||||
let Test.41 = lowlevel ListLen #Attr.2;
|
||||
let Test.37 = lowlevel NumLt #Attr.3 Test.41;
|
||||
if Test.37 then
|
||||
let Test.40 = 1i64;
|
||||
let Test.39 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
|
||||
let Test.38 = Ok Test.40 Test.39;
|
||||
ret Test.38;
|
||||
else
|
||||
let Test.35 = 0i64;
|
||||
let Test.34 = Struct {};
|
||||
let Test.33 = Err Test.35 Test.34;
|
||||
ret Test.33;
|
||||
let Test.36 = 0i64;
|
||||
let Test.35 = Struct {};
|
||||
let Test.34 = Err Test.36 Test.35;
|
||||
ret Test.34;
|
||||
|
||||
procedure List.4 (#Attr.2, #Attr.3, #Attr.4):
|
||||
let Test.18 = lowlevel ListLen #Attr.2;
|
||||
let Test.16 = lowlevel NumLt #Attr.3 Test.18;
|
||||
if Test.16 then
|
||||
let Test.17 = lowlevel ListSet #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Test.17;
|
||||
let Test.19 = lowlevel ListLen #Attr.2;
|
||||
let Test.17 = lowlevel NumLt #Attr.3 Test.19;
|
||||
if Test.17 then
|
||||
let Test.18 = lowlevel ListSet #Attr.2 #Attr.3 #Attr.4;
|
||||
ret Test.18;
|
||||
else
|
||||
ret #Attr.2;
|
||||
|
||||
procedure Test.1 (Test.2, Test.3, Test.4):
|
||||
let Test.32 = CallByName List.3 Test.4 Test.3;
|
||||
let Test.31 = CallByName List.3 Test.4 Test.2;
|
||||
let Test.12 = Struct {Test.31, Test.32};
|
||||
joinpoint Test.28:
|
||||
let Test.21 = Array [];
|
||||
ret Test.21;
|
||||
let Test.33 = CallByName List.3 Test.4 Test.3;
|
||||
let Test.32 = CallByName List.3 Test.4 Test.2;
|
||||
let Test.13 = Struct {Test.32, Test.33};
|
||||
joinpoint Test.29:
|
||||
let Test.22 = Array [];
|
||||
ret Test.22;
|
||||
in
|
||||
let Test.25 = Index 1 Test.12;
|
||||
let Test.26 = 1i64;
|
||||
let Test.27 = Index 0 Test.25;
|
||||
let Test.30 = lowlevel Eq Test.26 Test.27;
|
||||
if Test.30 then
|
||||
let Test.22 = Index 0 Test.12;
|
||||
let Test.23 = 1i64;
|
||||
let Test.24 = Index 0 Test.22;
|
||||
let Test.29 = lowlevel Eq Test.23 Test.24;
|
||||
if Test.29 then
|
||||
let Test.20 = Index 0 Test.12;
|
||||
let Test.5 = Index 1 Test.20;
|
||||
let Test.19 = Index 1 Test.12;
|
||||
let Test.6 = Index 1 Test.19;
|
||||
let Test.14 = CallByName List.4 Test.4 Test.2 Test.6;
|
||||
let Test.13 = CallByName List.4 Test.14 Test.3 Test.5;
|
||||
ret Test.13;
|
||||
let Test.26 = Index 1 Test.13;
|
||||
let Test.27 = 1i64;
|
||||
let Test.28 = Index 0 Test.26;
|
||||
let Test.31 = lowlevel Eq Test.27 Test.28;
|
||||
if Test.31 then
|
||||
let Test.23 = Index 0 Test.13;
|
||||
let Test.24 = 1i64;
|
||||
let Test.25 = Index 0 Test.23;
|
||||
let Test.30 = lowlevel Eq Test.24 Test.25;
|
||||
if Test.30 then
|
||||
let Test.21 = Index 0 Test.13;
|
||||
let Test.6 = Index 1 Test.21;
|
||||
let Test.20 = Index 1 Test.13;
|
||||
let Test.7 = Index 1 Test.20;
|
||||
let Test.15 = CallByName List.4 Test.4 Test.2 Test.7;
|
||||
let Test.14 = CallByName List.4 Test.15 Test.3 Test.6;
|
||||
ret Test.14;
|
||||
else
|
||||
dec Test.4;
|
||||
jump Test.28;
|
||||
jump Test.29;
|
||||
else
|
||||
dec Test.4;
|
||||
jump Test.28;
|
||||
jump Test.29;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.9 = 0i64;
|
||||
let Test.10 = 0i64;
|
||||
let Test.41 = 1i64;
|
||||
let Test.11 = Array [Test.41];
|
||||
let Test.8 = CallByName Test.1 Test.9 Test.10 Test.11;
|
||||
ret Test.8;
|
||||
let Test.11 = 0i64;
|
||||
let Test.42 = 1i64;
|
||||
let Test.12 = Array [Test.42];
|
||||
let Test.9 = CallByName Test.1 Test.10 Test.11 Test.12;
|
||||
ret Test.9;
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
@ -100,6 +100,8 @@ mod test_reporting {
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
ptr_bytes: 8,
|
||||
update_mode_counter: 0,
|
||||
call_specialization_counter: 0,
|
||||
};
|
||||
let _mono_expr = Stmt::new(
|
||||
&mut mono_env,
|
||||
|
@ -728,6 +728,27 @@ fn type_to_variable(
|
||||
|
||||
register(subs, rank, pools, content)
|
||||
}
|
||||
FunctionOrTagUnion(tag_name, symbol, ext) => {
|
||||
let temp_ext_var = type_to_variable(subs, rank, pools, cached, ext);
|
||||
let mut ext_tag_vec = Vec::new();
|
||||
let new_ext_var = match roc_types::pretty_print::chase_ext_tag_union(
|
||||
subs,
|
||||
temp_ext_var,
|
||||
&mut ext_tag_vec,
|
||||
) {
|
||||
Ok(()) => Variable::EMPTY_TAG_UNION,
|
||||
Err((new, _)) => new,
|
||||
};
|
||||
debug_assert!(ext_tag_vec.is_empty());
|
||||
|
||||
let content = Content::Structure(FlatType::FunctionOrTagUnion(
|
||||
tag_name.clone(),
|
||||
*symbol,
|
||||
new_ext_var,
|
||||
));
|
||||
|
||||
register(subs, rank, pools, content)
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
let mut tag_vars = MutMap::default();
|
||||
|
||||
@ -1134,6 +1155,10 @@ fn adjust_rank_content(
|
||||
rank
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(_, _, ext_var) => {
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var)
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
|
||||
|
||||
@ -1309,6 +1334,12 @@ fn instantiate_rigids_help(
|
||||
)
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
|
||||
tag_name,
|
||||
symbol,
|
||||
instantiate_rigids_help(subs, max_rank, pools, ext_var),
|
||||
),
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let mut new_tags = MutMap::default();
|
||||
|
||||
@ -1495,6 +1526,12 @@ fn deep_copy_var_help(
|
||||
TagUnion(new_tags, deep_copy_var_help(subs, max_rank, pools, ext_var))
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
|
||||
tag_name,
|
||||
symbol,
|
||||
deep_copy_var_help(subs, max_rank, pools, ext_var),
|
||||
),
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let mut new_tags = MutMap::default();
|
||||
|
||||
|
@ -179,6 +179,9 @@ fn find_names_needed(
|
||||
|
||||
find_names_needed(ext_var, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
Structure(FunctionOrTagUnion(_, _, ext_var)) => {
|
||||
find_names_needed(ext_var, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
Structure(RecursiveTagUnion(rec_var, tags, ext_var)) => {
|
||||
let mut sorted_tags: Vec<_> = tags.iter().collect();
|
||||
sorted_tags.sort();
|
||||
@ -487,6 +490,28 @@ fn write_flat_type(env: &Env, flat_type: FlatType, subs: &Subs, buf: &mut String
|
||||
}
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
||||
let interns = &env.interns;
|
||||
let home = env.home;
|
||||
|
||||
buf.push_str("[ ");
|
||||
|
||||
buf.push_str(&tag_name.as_string(&interns, home));
|
||||
|
||||
buf.push_str(" ]");
|
||||
|
||||
let mut sorted_fields = vec![(tag_name, vec![])];
|
||||
let ext_content = chase_ext_tag_union(subs, ext_var, &mut sorted_fields);
|
||||
if let Err((_, content)) = ext_content {
|
||||
// This is an open tag union, so print the variable
|
||||
// right after the ']'
|
||||
//
|
||||
// e.g. the "*" at the end of `{ x: I64 }*`
|
||||
// or the "r" at the end of `{ x: I64 }r`
|
||||
write_content(env, content, subs, buf, parens)
|
||||
}
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let interns = &env.interns;
|
||||
let home = env.home;
|
||||
@ -570,6 +595,11 @@ pub fn chase_ext_tag_union(
|
||||
|
||||
chase_ext_tag_union(subs, ext_var, fields)
|
||||
}
|
||||
Content::Structure(FunctionOrTagUnion(tag_name, _, ext_var)) => {
|
||||
fields.push((tag_name, vec![]));
|
||||
|
||||
chase_ext_tag_union(subs, ext_var, fields)
|
||||
}
|
||||
Content::Alias(_, _, var) => chase_ext_tag_union(subs, var, fields),
|
||||
|
||||
content => Err((var, content)),
|
||||
|
@ -104,6 +104,10 @@ fn hash_solved_type_help<H: Hasher>(
|
||||
hash_solved_type_help(ext, flex_vars, state);
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
hash_solved_type_help(ext, flex_vars, state);
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec, tags, ext) => {
|
||||
var_id_hash_help(*rec, flex_vars, state);
|
||||
for (name, arguments) in tags {
|
||||
@ -172,6 +176,7 @@ pub enum SolvedType {
|
||||
},
|
||||
EmptyRecord,
|
||||
TagUnion(Vec<(TagName, Vec<SolvedType>)>, Box<SolvedType>),
|
||||
FunctionOrTagUnion(TagName, Symbol, Box<SolvedType>),
|
||||
RecursiveTagUnion(VarId, Vec<(TagName, Vec<SolvedType>)>, Box<SolvedType>),
|
||||
EmptyTagUnion,
|
||||
/// A type from an Invalid module
|
||||
@ -263,6 +268,10 @@ impl SolvedType {
|
||||
|
||||
SolvedType::TagUnion(solved_tags, Box::new(solved_ext))
|
||||
}
|
||||
FunctionOrTagUnion(tag_name, symbol, box_ext) => {
|
||||
let solved_ext = Self::from_type(solved_subs, box_ext);
|
||||
SolvedType::FunctionOrTagUnion(tag_name.clone(), *symbol, Box::new(solved_ext))
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags, box_ext) => {
|
||||
let solved_ext = Self::from_type(solved_subs, box_ext);
|
||||
let mut solved_tags = Vec::with_capacity(tags.len());
|
||||
@ -423,6 +432,11 @@ impl SolvedType {
|
||||
|
||||
SolvedType::TagUnion(new_tags, Box::new(ext))
|
||||
}
|
||||
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
|
||||
let ext = Self::from_var_help(subs, recursion_vars, ext_var);
|
||||
|
||||
SolvedType::FunctionOrTagUnion(tag_name, symbol, Box::new(ext))
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
recursion_vars.insert(subs, rec_var);
|
||||
|
||||
@ -562,6 +576,11 @@ pub fn to_type(
|
||||
|
||||
Type::TagUnion(new_tags, Box::new(to_type(ext, free_vars, var_store)))
|
||||
}
|
||||
FunctionOrTagUnion(tag_name, symbol, ext) => Type::FunctionOrTagUnion(
|
||||
tag_name.clone(),
|
||||
*symbol,
|
||||
Box::new(to_type(ext, free_vars, var_store)),
|
||||
),
|
||||
RecursiveTagUnion(rec_var_id, tags, ext) => {
|
||||
let mut new_tags = Vec::with_capacity(tags.len());
|
||||
|
||||
|
@ -606,6 +606,7 @@ pub enum FlatType {
|
||||
Func(Vec<Variable>, Variable, Variable),
|
||||
Record(MutMap<Lowercase, RecordField<Variable>>, Variable),
|
||||
TagUnion(MutMap<TagName, Vec<Variable>>, Variable),
|
||||
FunctionOrTagUnion(TagName, Symbol, Variable),
|
||||
RecursiveTagUnion(Variable, MutMap<TagName, Vec<Variable>>, Variable),
|
||||
Erroneous(Problem),
|
||||
EmptyRecord,
|
||||
@ -662,6 +663,10 @@ fn occurs(
|
||||
let it = once(&ext_var).chain(tags.values().flatten());
|
||||
short_circuit(subs, root_var, &new_seen, it)
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext_var) => {
|
||||
let it = once(&ext_var);
|
||||
short_circuit(subs, root_var, &new_seen, it)
|
||||
}
|
||||
RecursiveTagUnion(_rec_var, tags, ext_var) => {
|
||||
// TODO rec_var is excluded here, verify that this is correct
|
||||
let it = once(&ext_var).chain(tags.values().flatten());
|
||||
@ -752,6 +757,13 @@ fn explicit_substitute(
|
||||
}
|
||||
subs.set_content(in_var, Structure(TagUnion(tags, new_ext_var)));
|
||||
}
|
||||
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
|
||||
let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen);
|
||||
subs.set_content(
|
||||
in_var,
|
||||
Structure(FunctionOrTagUnion(tag_name, symbol, new_ext_var)),
|
||||
);
|
||||
}
|
||||
RecursiveTagUnion(rec_var, mut tags, ext_var) => {
|
||||
// NOTE rec_var is not substituted, verify that this is correct!
|
||||
let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen);
|
||||
@ -891,6 +903,10 @@ fn get_var_names(
|
||||
taken_names
|
||||
}
|
||||
|
||||
FlatType::FunctionOrTagUnion(_, _, ext_var) => {
|
||||
get_var_names(subs, ext_var, taken_names)
|
||||
}
|
||||
|
||||
FlatType::RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let taken_names = get_var_names(subs, ext_var, taken_names);
|
||||
let mut taken_names = get_var_names(subs, rec_var, taken_names);
|
||||
@ -1142,6 +1158,32 @@ fn flat_type_to_err_type(
|
||||
}
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_name, _, ext_var) => {
|
||||
let mut err_tags = SendMap::default();
|
||||
|
||||
err_tags.insert(tag_name, vec![]);
|
||||
|
||||
match var_to_err_type(subs, state, ext_var).unwrap_alias() {
|
||||
ErrorType::TagUnion(sub_tags, sub_ext) => {
|
||||
ErrorType::TagUnion(sub_tags.union(err_tags), sub_ext)
|
||||
}
|
||||
ErrorType::RecursiveTagUnion(_, sub_tags, sub_ext) => {
|
||||
ErrorType::TagUnion(sub_tags.union(err_tags), sub_ext)
|
||||
}
|
||||
|
||||
ErrorType::FlexVar(var) => {
|
||||
ErrorType::TagUnion(err_tags, TypeExt::FlexOpen(var))
|
||||
}
|
||||
|
||||
ErrorType::RigidVar(var) => {
|
||||
ErrorType::TagUnion(err_tags, TypeExt::RigidOpen(var))
|
||||
}
|
||||
|
||||
other =>
|
||||
panic!("Tried to convert a tag union extension to an error, but the tag union extension had the ErrorType of {:?}", other)
|
||||
}
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let mut err_tags = SendMap::default();
|
||||
|
||||
@ -1236,6 +1278,9 @@ fn restore_content(subs: &mut Subs, content: &Content) {
|
||||
|
||||
subs.restore(*ext_var);
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext_var) => {
|
||||
subs.restore(*ext_var);
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
for var in tags.values().flatten() {
|
||||
|
@ -141,6 +141,7 @@ pub enum Type {
|
||||
Function(Vec<Type>, Box<Type>, Box<Type>),
|
||||
Record(SendMap<Lowercase, RecordField<Type>>, Box<Type>),
|
||||
TagUnion(Vec<(TagName, Vec<Type>)>, Box<Type>),
|
||||
FunctionOrTagUnion(TagName, Symbol, Box<Type>),
|
||||
Alias(Symbol, Vec<(Lowercase, Type)>, Box<Type>),
|
||||
HostExposedAlias {
|
||||
name: Symbol,
|
||||
@ -308,6 +309,26 @@ impl fmt::Debug for Type {
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::FunctionOrTagUnion(tag_name, _, ext) => {
|
||||
write!(f, "[")?;
|
||||
write!(f, "{:?}", tag_name)?;
|
||||
write!(f, "]")?;
|
||||
|
||||
match *ext.clone() {
|
||||
Type::EmptyTagUnion => {
|
||||
// This is a closed variant. We're done!
|
||||
Ok(())
|
||||
}
|
||||
other => {
|
||||
// This is an open tag union, so print the variable
|
||||
// right after the ']'
|
||||
//
|
||||
// e.g. the "*" at the end of `[ Foo ]*`
|
||||
// or the "r" at the end of `[ DivByZero ]r`
|
||||
other.fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::RecursiveTagUnion(rec, tags, ext) => {
|
||||
write!(f, "[")?;
|
||||
|
||||
@ -404,6 +425,9 @@ impl Type {
|
||||
}
|
||||
ext.substitute(substitutions);
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
ext.substitute(substitutions);
|
||||
}
|
||||
RecursiveTagUnion(_, tags, ext) => {
|
||||
for (_, args) in tags {
|
||||
for x in args {
|
||||
@ -456,6 +480,9 @@ impl Type {
|
||||
closure.substitute_alias(rep_symbol, actual);
|
||||
ret.substitute_alias(rep_symbol, actual);
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
ext.substitute_alias(rep_symbol, actual);
|
||||
}
|
||||
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
|
||||
for (_, args) in tags {
|
||||
for x in args {
|
||||
@ -506,6 +533,7 @@ impl Type {
|
||||
|| closure.contains_symbol(rep_symbol)
|
||||
|| args.iter().any(|arg| arg.contains_symbol(rep_symbol))
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => ext.contains_symbol(rep_symbol),
|
||||
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
|
||||
ext.contains_symbol(rep_symbol)
|
||||
|| tags
|
||||
@ -541,6 +569,7 @@ impl Type {
|
||||
|| closure.contains_variable(rep_variable)
|
||||
|| args.iter().any(|arg| arg.contains_variable(rep_variable))
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => ext.contains_variable(rep_variable),
|
||||
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
|
||||
ext.contains_variable(rep_variable)
|
||||
|| tags
|
||||
@ -595,6 +624,9 @@ impl Type {
|
||||
closure.instantiate_aliases(region, aliases, var_store, introduced);
|
||||
ret.instantiate_aliases(region, aliases, var_store, introduced);
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
ext.instantiate_aliases(region, aliases, var_store, introduced);
|
||||
}
|
||||
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
|
||||
for (_, args) in tags {
|
||||
for x in args {
|
||||
@ -734,6 +766,9 @@ fn symbols_help(tipe: &Type, accum: &mut ImSet<Symbol>) {
|
||||
symbols_help(&closure, accum);
|
||||
args.iter().for_each(|arg| symbols_help(arg, accum));
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
symbols_help(&ext, accum);
|
||||
}
|
||||
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
|
||||
symbols_help(&ext, accum);
|
||||
tags.iter()
|
||||
@ -807,6 +842,9 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
|
||||
}
|
||||
variables_help(ext, accum);
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
variables_help(ext, accum);
|
||||
}
|
||||
RecursiveTagUnion(rec, tags, ext) => {
|
||||
for (_, args) in tags {
|
||||
for x in args {
|
||||
@ -900,6 +938,9 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
|
||||
}
|
||||
variables_help_detailed(ext, accum);
|
||||
}
|
||||
FunctionOrTagUnion(_, _, ext) => {
|
||||
variables_help_detailed(ext, accum);
|
||||
}
|
||||
RecursiveTagUnion(rec, tags, ext) => {
|
||||
for (_, args) in tags {
|
||||
for x in args {
|
||||
|
@ -237,6 +237,10 @@ fn unify_structure(
|
||||
// unify the structure with this recursive tag union
|
||||
unify_pool(subs, pool, ctx.first, *structure)
|
||||
}
|
||||
FlatType::FunctionOrTagUnion(_, _, _) => {
|
||||
// unify the structure with this unrecursive tag union
|
||||
unify_pool(subs, pool, ctx.first, *structure)
|
||||
}
|
||||
_ => todo!("rec structure {:?}", &flat_type),
|
||||
},
|
||||
|
||||
@ -978,12 +982,106 @@ fn unify_flat_type(
|
||||
problems
|
||||
}
|
||||
}
|
||||
(TagUnion(tags, ext), Func(args, closure, ret)) if tags.len() == 1 => {
|
||||
unify_tag_union_and_func(tags, args, subs, pool, ctx, ext, ret, closure, true)
|
||||
(FunctionOrTagUnion(tag_name, tag_symbol, ext), Func(args, closure, ret)) => {
|
||||
unify_function_or_tag_union_and_func(
|
||||
subs,
|
||||
pool,
|
||||
ctx,
|
||||
tag_name,
|
||||
*tag_symbol,
|
||||
*ext,
|
||||
args,
|
||||
*ret,
|
||||
*closure,
|
||||
true,
|
||||
)
|
||||
}
|
||||
(Func(args, closure, ret), TagUnion(tags, ext)) if tags.len() == 1 => {
|
||||
unify_tag_union_and_func(tags, args, subs, pool, ctx, ext, ret, closure, false)
|
||||
(Func(args, closure, ret), FunctionOrTagUnion(tag_name, tag_symbol, ext)) => {
|
||||
unify_function_or_tag_union_and_func(
|
||||
subs,
|
||||
pool,
|
||||
ctx,
|
||||
tag_name,
|
||||
*tag_symbol,
|
||||
*ext,
|
||||
args,
|
||||
*ret,
|
||||
*closure,
|
||||
false,
|
||||
)
|
||||
}
|
||||
(FunctionOrTagUnion(tag_name_1, _, ext_1), FunctionOrTagUnion(tag_name_2, _, ext_2)) => {
|
||||
if tag_name_1 == tag_name_2 {
|
||||
let problems = unify_pool(subs, pool, *ext_1, *ext_2);
|
||||
if problems.is_empty() {
|
||||
let desc = subs.get(ctx.second);
|
||||
merge(subs, ctx, desc.content)
|
||||
} else {
|
||||
problems
|
||||
}
|
||||
} else {
|
||||
let mut tags1 = MutMap::default();
|
||||
tags1.insert(tag_name_1.clone(), vec![]);
|
||||
let union1 = gather_tags(subs, tags1, *ext_1);
|
||||
|
||||
let mut tags2 = MutMap::default();
|
||||
tags2.insert(tag_name_2.clone(), vec![]);
|
||||
let union2 = gather_tags(subs, tags2, *ext_2);
|
||||
|
||||
unify_tag_union(subs, pool, ctx, union1, union2, (None, None))
|
||||
}
|
||||
}
|
||||
(TagUnion(tags1, ext1), FunctionOrTagUnion(tag_name, _, ext2)) => {
|
||||
let union1 = gather_tags(subs, tags1.clone(), *ext1);
|
||||
|
||||
let mut tags2 = MutMap::default();
|
||||
tags2.insert(tag_name.clone(), vec![]);
|
||||
let union2 = gather_tags(subs, tags2, *ext2);
|
||||
|
||||
unify_tag_union(subs, pool, ctx, union1, union2, (None, None))
|
||||
}
|
||||
(FunctionOrTagUnion(tag_name, _, ext1), TagUnion(tags2, ext2)) => {
|
||||
let mut tags1 = MutMap::default();
|
||||
tags1.insert(tag_name.clone(), vec![]);
|
||||
let union1 = gather_tags(subs, tags1, *ext1);
|
||||
|
||||
let union2 = gather_tags(subs, tags2.clone(), *ext2);
|
||||
|
||||
unify_tag_union(subs, pool, ctx, union1, union2, (None, None))
|
||||
}
|
||||
|
||||
(RecursiveTagUnion(recursion_var, tags1, ext1), FunctionOrTagUnion(tag_name, _, ext2)) => {
|
||||
// this never happens in type-correct programs, but may happen if there is a type error
|
||||
debug_assert!(is_recursion_var(subs, *recursion_var));
|
||||
|
||||
let mut tags2 = MutMap::default();
|
||||
tags2.insert(tag_name.clone(), vec![]);
|
||||
|
||||
let union1 = gather_tags(subs, tags1.clone(), *ext1);
|
||||
let union2 = gather_tags(subs, tags2, *ext2);
|
||||
|
||||
unify_tag_union(
|
||||
subs,
|
||||
pool,
|
||||
ctx,
|
||||
union1,
|
||||
union2,
|
||||
(Some(*recursion_var), None),
|
||||
)
|
||||
}
|
||||
|
||||
(FunctionOrTagUnion(tag_name, _, ext1), RecursiveTagUnion(recursion_var, tags2, ext2)) => {
|
||||
debug_assert!(is_recursion_var(subs, *recursion_var));
|
||||
|
||||
let mut tags1 = MutMap::default();
|
||||
tags1.insert(tag_name.clone(), vec![]);
|
||||
|
||||
let union1 = gather_tags(subs, tags1, *ext1);
|
||||
let union2 = gather_tags(subs, tags2.clone(), *ext2);
|
||||
|
||||
unify_tag_union_not_recursive_recursive(subs, pool, ctx, union1, union2, *recursion_var)
|
||||
}
|
||||
|
||||
(other1, other2) => mismatch!(
|
||||
"Trying to unify two flat types that are incompatible: {:?} ~ {:?}",
|
||||
other1,
|
||||
@ -1166,53 +1264,44 @@ fn is_recursion_var(subs: &Subs, var: Variable) -> bool {
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments, clippy::ptr_arg)]
|
||||
fn unify_tag_union_and_func(
|
||||
tags: &MutMap<TagName, Vec<Variable>>,
|
||||
args: &Vec<Variable>,
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn unify_function_or_tag_union_and_func(
|
||||
subs: &mut Subs,
|
||||
pool: &mut Pool,
|
||||
ctx: &Context,
|
||||
ext: &Variable,
|
||||
ret: &Variable,
|
||||
closure: &Variable,
|
||||
tag_name: &TagName,
|
||||
_tag_symbol: Symbol,
|
||||
tag_ext: Variable,
|
||||
function_arguments: &[Variable],
|
||||
function_return: Variable,
|
||||
_function_lambda_set: Variable,
|
||||
left: bool,
|
||||
) -> Outcome {
|
||||
use FlatType::*;
|
||||
|
||||
let (tag_name, payload) = tags.iter().next().unwrap();
|
||||
let mut new_tags = MutMap::with_capacity_and_hasher(1, default_hasher());
|
||||
|
||||
if payload.is_empty() {
|
||||
let mut new_tags = MutMap::with_capacity_and_hasher(1, default_hasher());
|
||||
new_tags.insert(tag_name.clone(), function_arguments.to_owned());
|
||||
|
||||
new_tags.insert(tag_name.clone(), args.to_owned());
|
||||
let content = Structure(TagUnion(new_tags, tag_ext));
|
||||
|
||||
let content = Structure(TagUnion(new_tags, *ext));
|
||||
let new_tag_union_var = fresh(subs, pool, ctx, content);
|
||||
|
||||
let new_tag_union_var = fresh(subs, pool, ctx, content);
|
||||
let problems = if left {
|
||||
unify_pool(subs, pool, new_tag_union_var, function_return)
|
||||
} else {
|
||||
unify_pool(subs, pool, function_return, new_tag_union_var)
|
||||
};
|
||||
|
||||
let problems = if left {
|
||||
unify_pool(subs, pool, new_tag_union_var, *ret)
|
||||
if problems.is_empty() {
|
||||
let desc = if left {
|
||||
subs.get(ctx.second)
|
||||
} else {
|
||||
unify_pool(subs, pool, *ret, new_tag_union_var)
|
||||
subs.get(ctx.first)
|
||||
};
|
||||
|
||||
if problems.is_empty() {
|
||||
let desc = if left {
|
||||
subs.get(ctx.second)
|
||||
} else {
|
||||
subs.get(ctx.first)
|
||||
};
|
||||
|
||||
subs.union(ctx.first, ctx.second, desc);
|
||||
}
|
||||
|
||||
problems
|
||||
} else {
|
||||
mismatch!(
|
||||
"Trying to unify two flat types that are incompatible: {:?} ~ {:?}",
|
||||
TagUnion(tags.clone(), *ext),
|
||||
Func(args.to_owned(), *closure, *ret)
|
||||
)
|
||||
subs.union(ctx.first, ctx.second, desc);
|
||||
}
|
||||
|
||||
problems
|
||||
}
|
||||
|
@ -286,9 +286,9 @@ pub fn constrain_expr<'a>(
|
||||
} => {
|
||||
// The expression that evaluates to the function being called, e.g. `foo` in
|
||||
// (foo) bar baz
|
||||
let expr = env.pool.get(*expr_node_id);
|
||||
let call_expr = env.pool.get(*expr_node_id);
|
||||
|
||||
let opt_symbol = if let Expr2::Var(symbol) = expr {
|
||||
let opt_symbol = if let Expr2::Var(symbol) = call_expr {
|
||||
Some(*symbol)
|
||||
} else {
|
||||
None
|
||||
@ -303,7 +303,7 @@ pub fn constrain_expr<'a>(
|
||||
arity: args.len() as u8,
|
||||
};
|
||||
|
||||
let fn_con = constrain_expr(arena, env, expr, fn_expected, region);
|
||||
let fn_con = constrain_expr(arena, env, call_expr, fn_expected, region);
|
||||
|
||||
// The function's return type
|
||||
// TODO: don't use expr_var?
|
||||
@ -431,6 +431,54 @@ pub fn constrain_expr<'a>(
|
||||
|
||||
exists(arena, flex_vars, And(and_constraints))
|
||||
}
|
||||
Expr2::Access {
|
||||
expr: expr_id,
|
||||
field,
|
||||
field_var,
|
||||
record_var,
|
||||
ext_var,
|
||||
} => {
|
||||
let ext_type = Type2::Variable(*ext_var);
|
||||
|
||||
let field_type = Type2::Variable(*field_var);
|
||||
|
||||
let record_field =
|
||||
types::RecordField::Demanded(env.pool.add(field_type.shallow_clone()));
|
||||
|
||||
let record_type = Type2::Record(
|
||||
PoolVec::new(vec![(*field, record_field)].into_iter(), env.pool),
|
||||
env.pool.add(ext_type),
|
||||
);
|
||||
|
||||
let record_expected = Expected::NoExpectation(record_type);
|
||||
|
||||
let category = Category::Access(field.as_str(env.pool).into());
|
||||
|
||||
let record_con = Eq(
|
||||
Type2::Variable(*record_var),
|
||||
record_expected.shallow_clone(),
|
||||
category.clone(),
|
||||
region,
|
||||
);
|
||||
|
||||
let access_expr = env.pool.get(*expr_id);
|
||||
|
||||
let constraint = constrain_expr(arena, env, access_expr, record_expected, region);
|
||||
|
||||
let mut flex_vars = BumpVec::with_capacity_in(3, arena);
|
||||
|
||||
flex_vars.push(*record_var);
|
||||
flex_vars.push(*field_var);
|
||||
flex_vars.push(*ext_var);
|
||||
|
||||
let mut and_constraints = BumpVec::with_capacity_in(3, arena);
|
||||
|
||||
and_constraints.push(constraint);
|
||||
and_constraints.push(Eq(field_type, expected, category, region));
|
||||
and_constraints.push(record_con);
|
||||
|
||||
exists(arena, flex_vars, And(and_constraints))
|
||||
}
|
||||
_ => todo!("implement constaints for {:?}", expr),
|
||||
}
|
||||
}
|
||||
|
@ -780,6 +780,10 @@ pub fn to_expr2<'a>(
|
||||
(expr, output)
|
||||
}
|
||||
|
||||
Defs(loc_defs, loc_ret) => {
|
||||
todo!("{:?} {:?}", loc_defs, loc_ret)
|
||||
}
|
||||
|
||||
PrecedenceConflict { .. } => {
|
||||
// use roc_problem::can::RuntimeError::*;
|
||||
//
|
||||
|
@ -1243,6 +1243,10 @@ fn adjust_rank_content(
|
||||
rank
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(_, _, ext_var) => {
|
||||
adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var)
|
||||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
|
||||
|
||||
@ -1418,6 +1422,12 @@ fn instantiate_rigids_help(
|
||||
)
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
|
||||
tag_name,
|
||||
symbol,
|
||||
instantiate_rigids_help(subs, max_rank, pools, ext_var),
|
||||
),
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let mut new_tags = MutMap::default();
|
||||
|
||||
@ -1604,6 +1614,12 @@ fn deep_copy_var_help(
|
||||
TagUnion(new_tags, deep_copy_var_help(subs, max_rank, pools, ext_var))
|
||||
}
|
||||
|
||||
FunctionOrTagUnion(tag_name, symbol, ext_var) => FunctionOrTagUnion(
|
||||
tag_name,
|
||||
symbol,
|
||||
deep_copy_var_help(subs, max_rank, pools, ext_var),
|
||||
),
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
let mut new_tags = MutMap::default();
|
||||
|
||||
|
@ -262,3 +262,15 @@ fn constrain_call_and_accessor() {
|
||||
"Str",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn constrain_access() {
|
||||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
{ foo: "bar" }.foo
|
||||
"#
|
||||
),
|
||||
"Str",
|
||||
)
|
||||
}
|
||||
|
@ -4,56 +4,56 @@ app "quicksort"
|
||||
provides [ quicksort ] to base
|
||||
|
||||
quicksort = \originalList ->
|
||||
|
||||
quicksortHelp : List (Num a), Nat, Nat -> List (Num a)
|
||||
quicksortHelp = \list, low, high ->
|
||||
if low < high then
|
||||
when partition low high list is
|
||||
Pair partitionIndex partitioned ->
|
||||
partitioned
|
||||
|> quicksortHelp low (partitionIndex - 1)
|
||||
|> quicksortHelp (partitionIndex + 1) high
|
||||
else
|
||||
list
|
||||
|
||||
|
||||
partition : Nat, Nat, List (Num a) -> [ Pair Nat (List (Num a)) ]
|
||||
partition = \low, high, initialList ->
|
||||
when List.get initialList high is
|
||||
Ok pivot ->
|
||||
when partitionHelp (low - 1) low initialList high pivot is
|
||||
Pair newI newList ->
|
||||
Pair (newI + 1) (swap (newI + 1) high newList)
|
||||
|
||||
Err _ ->
|
||||
Pair (low - 1) initialList
|
||||
|
||||
partitionHelp : Nat, Nat, List (Num c), Nat, (Num c) -> [ Pair Nat (List (Num c)) ]
|
||||
partitionHelp = \i, j, list, high, pivot ->
|
||||
if j < high then
|
||||
when List.get list j is
|
||||
Ok value ->
|
||||
if value <= pivot then
|
||||
partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot
|
||||
else
|
||||
partitionHelp i (j + 1) list high pivot
|
||||
|
||||
Err _ ->
|
||||
Pair i list
|
||||
else
|
||||
Pair i list
|
||||
|
||||
|
||||
swap : Nat, Nat, List a -> List a
|
||||
swap = \i, j, list ->
|
||||
when Pair (List.get list i) (List.get list j) is
|
||||
Pair (Ok atI) (Ok atJ) ->
|
||||
list
|
||||
|> List.set i atJ
|
||||
|> List.set j atI
|
||||
|
||||
_ ->
|
||||
[]
|
||||
|
||||
n = List.len originalList
|
||||
quicksortHelp originalList 0 (n - 1)
|
||||
|
||||
quicksortHelp : List (Num a), Nat, Nat -> List (Num a)
|
||||
quicksortHelp = \list, low, high ->
|
||||
if low < high then
|
||||
when partition low high list is
|
||||
Pair partitionIndex partitioned ->
|
||||
partitioned
|
||||
|> quicksortHelp low (partitionIndex - 1)
|
||||
|> quicksortHelp (partitionIndex + 1) high
|
||||
else
|
||||
list
|
||||
|
||||
|
||||
partition : Nat, Nat, List (Num a) -> [ Pair Nat (List (Num a)) ]
|
||||
partition = \low, high, initialList ->
|
||||
when List.get initialList high is
|
||||
Ok pivot ->
|
||||
when partitionHelp (low - 1) low initialList high pivot is
|
||||
Pair newI newList ->
|
||||
Pair (newI + 1) (swap (newI + 1) high newList)
|
||||
|
||||
Err _ ->
|
||||
Pair (low - 1) initialList
|
||||
|
||||
partitionHelp : Nat, Nat, List (Num c), Nat, (Num c) -> [ Pair Nat (List (Num c)) ]
|
||||
partitionHelp = \i, j, list, high, pivot ->
|
||||
if j < high then
|
||||
when List.get list j is
|
||||
Ok value ->
|
||||
if value <= pivot then
|
||||
partitionHelp (i + 1) (j + 1) (swap (i + 1) j list) high pivot
|
||||
else
|
||||
partitionHelp i (j + 1) list high pivot
|
||||
|
||||
Err _ ->
|
||||
Pair i list
|
||||
else
|
||||
Pair i list
|
||||
|
||||
|
||||
swap : Nat, Nat, List a -> List a
|
||||
swap = \i, j, list ->
|
||||
when Pair (List.get list i) (List.get list j) is
|
||||
Pair (Ok atI) (Ok atJ) ->
|
||||
list
|
||||
|> List.set i atJ
|
||||
|> List.set j atI
|
||||
|
||||
_ ->
|
||||
[]
|
||||
|
||||
|
2
vendor/morphic_lib/.gitignore
vendored
Normal file
2
vendor/morphic_lib/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
Cargo.lock
|
9
vendor/morphic_lib/Cargo.toml
vendored
Normal file
9
vendor/morphic_lib/Cargo.toml
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "morphic_lib"
|
||||
version = "0.1.0"
|
||||
authors = ["William Brandon", "Wilson Berkow", "Frank Dai", "Benjamin Driscoll"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.24"
|
||||
sha2 = "0.9.4"
|
176
vendor/morphic_lib/LICENSE-APACHE
vendored
Normal file
176
vendor/morphic_lib/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
23
vendor/morphic_lib/LICENSE-MIT
vendored
Normal file
23
vendor/morphic_lib/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
1325
vendor/morphic_lib/src/api.rs
vendored
Normal file
1325
vendor/morphic_lib/src/api.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
706
vendor/morphic_lib/src/bindings.rs
vendored
Normal file
706
vendor/morphic_lib/src/bindings.rs
vendored
Normal file
@ -0,0 +1,706 @@
|
||||
// TODO: These bindings are incomplete
|
||||
// TODO: Add test for compatibility with `include/morphic.h`
|
||||
|
||||
use crate::api::*;
|
||||
use std::{ffi::CString, os::raw::c_char, ptr, slice};
|
||||
|
||||
macro_rules! check_err {
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
::std::result::Result::Ok(val) => val,
|
||||
::std::result::Result::Err(err) => {
|
||||
return ::std::boxed::Box::into_raw(::std::boxed::Box::new(err));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RawModName {
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl RawModName {
|
||||
unsafe fn slice<'a>(&self) -> ModName<'a> {
|
||||
ModName(slice::from_raw_parts(self.data, self.len))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RawEntryPointName {
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl RawEntryPointName {
|
||||
unsafe fn slice<'a>(&self) -> EntryPointName<'a> {
|
||||
EntryPointName(slice::from_raw_parts(self.data, self.len))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RawFuncName {
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl RawFuncName {
|
||||
unsafe fn slice<'a>(&self) -> FuncName<'a> {
|
||||
FuncName(slice::from_raw_parts(self.data, self.len))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RawTypeName {
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl RawTypeName {
|
||||
unsafe fn slice<'a>(&self) -> TypeName<'a> {
|
||||
TypeName(slice::from_raw_parts(self.data, self.len))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RawCalleeSpecVar {
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl RawCalleeSpecVar {
|
||||
unsafe fn slice<'a>(&self) -> CalleeSpecVar<'a> {
|
||||
CalleeSpecVar(slice::from_raw_parts(self.data, self.len))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RawUpdateModeVar {
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl RawUpdateModeVar {
|
||||
unsafe fn slice<'a>(&self) -> UpdateModeVar<'a> {
|
||||
UpdateModeVar(slice::from_raw_parts(self.data, self.len))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RawString {
|
||||
data: *mut c_char,
|
||||
}
|
||||
|
||||
impl RawString {
|
||||
fn new<T: Into<Vec<u8>>>(t: T) -> Self {
|
||||
let c_str = CString::new(t).unwrap();
|
||||
Self {
|
||||
data: c_str.into_raw(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn raw<T>(t: T) -> *mut T {
|
||||
Box::into_raw(Box::new(t))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_String_Drop(_: Option<Box<RawString>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_Error_Clone(err: &Error) -> Box<Error> {
|
||||
Box::new(err.clone())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_Error_Drop(_: Option<Box<Error>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_Error_Display(self_: *const Error, out: *mut RawString) {
|
||||
*out = RawString::new(format!("{}", *self_));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_TypeDef_Drop(_: Option<Box<TypeDef>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_TypeDefBuilder_Drop(_: Option<Box<TypeDefBuilder>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_TypeDefBuilder_New(out: *mut *mut TypeDefBuilder) {
|
||||
*out = raw(TypeDefBuilder::new());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_TypeDefBuilder_Build(
|
||||
self_: Box<TypeDefBuilder>,
|
||||
root: TypeId,
|
||||
out: *mut *mut TypeDef,
|
||||
) -> *mut Error {
|
||||
*out = raw(check_err!(self_.build(root)));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_TypeDefBuilder_AddNamedType(
|
||||
self_: *mut TypeDefBuilder,
|
||||
mod_: RawModName,
|
||||
type_: RawTypeName,
|
||||
out: *mut TypeId,
|
||||
) {
|
||||
*out = (*self_).add_named_type(mod_.slice(), type_.slice());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_TypeDefBuilder_AddTupleType(
|
||||
self_: *mut TypeDefBuilder,
|
||||
field_types: *const TypeId,
|
||||
field_types_len: usize,
|
||||
out: *mut TypeId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_tuple_type(slice::from_raw_parts(field_types, field_types_len)));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_TypeDefBuilder_AddUnionType(
|
||||
self_: *mut TypeDefBuilder,
|
||||
variant_types: *const TypeId,
|
||||
variant_types_len: usize,
|
||||
out: *mut TypeId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!(
|
||||
(*self_).add_union_type(slice::from_raw_parts(variant_types, variant_types_len))
|
||||
);
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_TypeDefBuilder_AddHeapCellType(
|
||||
self_: *mut TypeDefBuilder,
|
||||
out: *mut TypeId,
|
||||
) {
|
||||
*out = (*self_).add_heap_cell_type();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_TypeDefBuilder_AddBagType(
|
||||
self_: *mut TypeDefBuilder,
|
||||
item_type: TypeId,
|
||||
out: *mut TypeId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_bag_type(item_type));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDef_Drop(_: Option<Box<FuncDef>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_Drop(_: Option<Box<FuncDefBuilder>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_New(out: *mut *mut FuncDefBuilder) {
|
||||
*out = raw(FuncDefBuilder::new());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_Build(
|
||||
self_: Box<FuncDefBuilder>,
|
||||
arg_type: TypeId,
|
||||
ret_type: TypeId,
|
||||
root: BlockExpr,
|
||||
out: *mut *mut FuncDef,
|
||||
) -> *mut Error {
|
||||
*out = raw(check_err!(self_.build(arg_type, ret_type, root)));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_DeclareJoinPoint(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
arg_type: TypeId,
|
||||
ret_type: TypeId,
|
||||
out0: *mut JoinPointId,
|
||||
out1: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
let (join_point, value) = check_err!((*self_).declare_join_point(block, arg_type, ret_type));
|
||||
*out0 = join_point;
|
||||
*out1 = value;
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_DefineJoinPoint(
|
||||
self_: *mut FuncDefBuilder,
|
||||
join_point: JoinPointId,
|
||||
body: BlockExpr,
|
||||
) -> *mut Error {
|
||||
check_err!((*self_).define_join_point(join_point, body));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddJump(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
join_point: JoinPointId,
|
||||
arg: ValueId,
|
||||
unreachable_result_type: TypeId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_jump(block, join_point, arg, unreachable_result_type));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddBlock(
|
||||
self_: *mut FuncDefBuilder,
|
||||
out: *mut BlockId,
|
||||
) {
|
||||
*out = (*self_).add_block();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddUnknownWith(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
args: *const ValueId,
|
||||
args_len: usize,
|
||||
result_type: TypeId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_unknown_with(
|
||||
block,
|
||||
slice::from_raw_parts(args, args_len),
|
||||
result_type
|
||||
));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddCall(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
callee_spec_var: RawCalleeSpecVar,
|
||||
callee_mod: RawModName,
|
||||
callee: RawFuncName,
|
||||
arg: ValueId,
|
||||
) -> *mut Error {
|
||||
check_err!((*self_).add_call(
|
||||
block,
|
||||
callee_spec_var.slice(),
|
||||
callee_mod.slice(),
|
||||
callee.slice(),
|
||||
arg
|
||||
));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddChoice(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
cases: *const BlockExpr,
|
||||
cases_len: usize,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_choice(block, slice::from_raw_parts(cases, cases_len)));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddTerminate(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
result_type: TypeId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_terminate(block, result_type));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddNewHeapCell(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_new_heap_cell(block));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddTouch(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
heap_cell: ValueId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_touch(block, heap_cell));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddUpdate(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
update_mode_var: RawUpdateModeVar,
|
||||
heap_cell: ValueId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_update(block, update_mode_var.slice(), heap_cell));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddUpdateWriteOnly(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
update_mode_var: RawUpdateModeVar,
|
||||
heap_cell: ValueId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_update_write_only(block, update_mode_var.slice(), heap_cell));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddEmptyBag(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
item_type: TypeId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_empty_bag(block, item_type));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddBagInsert(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
bag: ValueId,
|
||||
to_insert: ValueId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_bag_insert(block, bag, to_insert));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddBagGet(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
bag: ValueId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_bag_get(block, bag));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddBagRemove(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
bag: ValueId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_bag_remove(block, bag));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddMakeTuple(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
field_vals: *const ValueId,
|
||||
field_vals_len: usize,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!(
|
||||
(*self_).add_make_tuple(block, slice::from_raw_parts(field_vals, field_vals_len))
|
||||
);
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddGetTupleField(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
tuple: ValueId,
|
||||
field_idx: u32,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_get_tuple_field(block, tuple, field_idx));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddMakeUnion(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
variant_types: *const TypeId,
|
||||
variant_types_len: usize,
|
||||
variant_idx: u32,
|
||||
to_wrap: ValueId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_make_union(
|
||||
block,
|
||||
slice::from_raw_parts(variant_types, variant_types_len),
|
||||
variant_idx,
|
||||
to_wrap
|
||||
));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddMakeNamed(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
named_mod: RawModName,
|
||||
named: RawTypeName,
|
||||
to_wrap: ValueId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_make_named(block, named_mod.slice(), named.slice(), to_wrap));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddUnwrapNamed(
|
||||
self_: *mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
named_mod: RawModName,
|
||||
named: RawTypeName,
|
||||
to_unwrap: ValueId,
|
||||
out: *mut ValueId,
|
||||
) -> *mut Error {
|
||||
*out =
|
||||
check_err!((*self_).add_unwrap_named(block, named_mod.slice(), named.slice(), to_unwrap));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddNamedType(
|
||||
self_: *mut FuncDefBuilder,
|
||||
mod_: RawModName,
|
||||
type_: RawTypeName,
|
||||
out: *mut TypeId,
|
||||
) {
|
||||
*out = (*self_).add_named_type(mod_.slice(), type_.slice());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddTupleType(
|
||||
self_: *mut FuncDefBuilder,
|
||||
field_types: *const TypeId,
|
||||
field_types_len: usize,
|
||||
out: *mut TypeId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_tuple_type(slice::from_raw_parts(field_types, field_types_len)));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddUnionType(
|
||||
self_: *mut FuncDefBuilder,
|
||||
variant_types: *const TypeId,
|
||||
variant_types_len: usize,
|
||||
out: *mut TypeId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!(
|
||||
(*self_).add_union_type(slice::from_raw_parts(variant_types, variant_types_len))
|
||||
);
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddHeapCellType(
|
||||
self_: *mut FuncDefBuilder,
|
||||
out: *mut TypeId,
|
||||
) {
|
||||
*out = (*self_).add_heap_cell_type();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncDefBuilder_AddBagType(
|
||||
self_: *mut FuncDefBuilder,
|
||||
item_type: TypeId,
|
||||
out: *mut TypeId,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).add_bag_type(item_type));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ModDef_Drop(_: Option<Box<ModDef>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ModDefBuilder_Drop(_: Option<Box<ModDefBuilder>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ModDefBuilder_New(out: *mut *mut ModDefBuilder) {
|
||||
*out = raw(ModDefBuilder::new());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ModDefBuilder_Build(
|
||||
self_: Box<ModDefBuilder>,
|
||||
out: *mut *mut ModDef,
|
||||
) -> *mut Error {
|
||||
*out = raw(check_err!(self_.build()));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ModDefBuilder_AddNamedType(
|
||||
self_: *mut ModDefBuilder,
|
||||
name: RawTypeName,
|
||||
type_def: Box<TypeDef>,
|
||||
) -> *mut Error {
|
||||
check_err!((*self_).add_named_type(name.slice(), *type_def));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ModDefBuilder_AddFunc(
|
||||
self_: *mut ModDefBuilder,
|
||||
name: RawFuncName,
|
||||
func_def: Box<FuncDef>,
|
||||
) -> *mut Error {
|
||||
check_err!((*self_).add_func(name.slice(), *func_def));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_Program_Drop(_: Option<Box<Program>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ProgramBuilder_Drop(_: Option<Box<ProgramBuilder>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ProgramBuilder_New(out: *mut *mut ProgramBuilder) {
|
||||
*out = raw(ProgramBuilder::new());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ProgramBuilder_Build(
|
||||
self_: Box<ProgramBuilder>,
|
||||
out: *mut *mut Program,
|
||||
) -> *mut Error {
|
||||
*out = raw(check_err!(self_.build()));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ProgramBuilder_AddMod(
|
||||
self_: *mut ProgramBuilder,
|
||||
name: RawModName,
|
||||
mod_def: Box<ModDef>,
|
||||
) -> *mut Error {
|
||||
check_err!((*self_).add_mod(name.slice(), *mod_def));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ProgramBuilder_AddEntryPoint(
|
||||
self_: *mut ProgramBuilder,
|
||||
name: RawEntryPointName,
|
||||
func_mod: RawModName,
|
||||
func: RawFuncName,
|
||||
) -> *mut Error {
|
||||
check_err!((*self_).add_entry_point(name.slice(), func_mod.slice(), func.slice()));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncSpecSolutions_CalleeSpec(
|
||||
self_: *const FuncSpecSolutions,
|
||||
var: RawCalleeSpecVar,
|
||||
out: *mut FuncSpec,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).callee_spec(var.slice()));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncSpecSolutions_UpdateMode(
|
||||
self_: *const FuncSpecSolutions,
|
||||
var: RawUpdateModeVar,
|
||||
out: *mut UpdateMode,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).update_mode(var.slice()));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
pub struct FuncSpecIter<'a> {
|
||||
iter: Box<dyn Iterator<Item = &'a FuncSpec>>,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncSpecIter_Next(
|
||||
self_: *mut FuncSpecIter,
|
||||
item: *mut *const FuncSpec,
|
||||
) -> bool {
|
||||
match (*self_).iter.next() {
|
||||
Some(val) => {
|
||||
*item = val;
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncSolutions_Specs(
|
||||
_self: *const FuncSolutions,
|
||||
_out: *mut *mut FuncSpecIter,
|
||||
) {
|
||||
todo!();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_FuncSolutions_Spec(
|
||||
self_: *mut FuncSolutions,
|
||||
spec: *const FuncSpec,
|
||||
out: *mut *const FuncSpecSolutions,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).spec(&*spec));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_ModSolutions_FuncSolutions(
|
||||
self_: *mut ModSolutions,
|
||||
func: RawFuncName,
|
||||
out: *mut *const FuncSolutions,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).func_solutions(func.slice()));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_Solutions_Drop(_: Option<Box<Solutions>>) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_Solutions_ModSolutions(
|
||||
self_: *mut Solutions,
|
||||
mod_: RawModName,
|
||||
out: *mut *const ModSolutions,
|
||||
) -> *mut Error {
|
||||
*out = check_err!((*self_).mod_solutions(mod_.slice()));
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Morphic_Solve(
|
||||
program: Box<Program>,
|
||||
out: *mut *mut Solutions,
|
||||
) -> *mut Error {
|
||||
*out = raw(check_err!(solve(*program)));
|
||||
ptr::null_mut()
|
||||
}
|
9
vendor/morphic_lib/src/lib.rs
vendored
Normal file
9
vendor/morphic_lib/src/lib.rs
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[macro_use]
|
||||
mod util;
|
||||
|
||||
mod api;
|
||||
mod bindings;
|
||||
|
||||
pub use api::*;
|
27
vendor/morphic_lib/src/util/bytes_id.rs
vendored
Normal file
27
vendor/morphic_lib/src/util/bytes_id.rs
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
macro_rules! bytes_id {
|
||||
(
|
||||
// Capturing attributes allows us to capture doc comments
|
||||
$(#[$annot_borrowed:meta])* $borrowed_vis:vis $borrowed:ident;
|
||||
$(#[$annot_owned:meta])* $owned_vis:vis $owned:ident;
|
||||
) => {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
$(#[$annot_borrowed])*
|
||||
$borrowed_vis struct $borrowed<'a>($borrowed_vis &'a [u8]);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
$(#[$annot_owned])*
|
||||
$owned_vis struct $owned($owned_vis ::std::vec::Vec<u8>);
|
||||
|
||||
impl $owned {
|
||||
fn borrowed<'a>(&'a self) -> $borrowed<'a> {
|
||||
$borrowed(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ::std::convert::From<$borrowed<'a>> for $owned {
|
||||
fn from(borrowed: $borrowed<'a>) -> Self {
|
||||
$owned(<[u8]>::to_vec(&borrowed.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
91
vendor/morphic_lib/src/util/forward_trait.rs
vendored
Normal file
91
vendor/morphic_lib/src/util/forward_trait.rs
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
macro_rules! forward_trait {
|
||||
(
|
||||
$(#[$annot:meta])*
|
||||
$t_vis:vis trait $t_name:ident {
|
||||
$($methods:tt)*
|
||||
}
|
||||
|
||||
$($impls:tt)*
|
||||
) => {
|
||||
$(#[$annot])*
|
||||
$t_vis trait $t_name { $($methods)* }
|
||||
|
||||
forward_trait_impls!(trait $t_name { $($methods)* } $($impls)*);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! forward_trait_impls {
|
||||
(
|
||||
trait $t_name:ident { $($methods:tt)* }
|
||||
) => {
|
||||
// Base case: no impls left
|
||||
};
|
||||
|
||||
(
|
||||
trait $t_name:ident { $($methods:tt)* }
|
||||
|
||||
impl $wrapper:ident => .$field:ident;
|
||||
|
||||
$($impls:tt)*
|
||||
) => {
|
||||
impl $t_name for $wrapper {
|
||||
forward_trait_impl_body!( { $($methods)* } .$field );
|
||||
}
|
||||
|
||||
forward_trait_impls!(trait $t_name { $($methods)* } $($impls)*);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! forward_trait_impl_body {
|
||||
(
|
||||
{}
|
||||
.$field:ident
|
||||
) => {
|
||||
// Base case: no methods left
|
||||
};
|
||||
|
||||
(
|
||||
{
|
||||
$(#[$annot:meta])*
|
||||
fn $fn_name:ident(self $(, $arg_name:ident : $arg_ty:ty)* $(,)? ) -> $ret_ty:ty ;
|
||||
$($methods:tt)*
|
||||
}
|
||||
.$field:ident
|
||||
) => {
|
||||
fn $fn_name(self, $($arg_name: $arg_ty),*) -> $ret_ty {
|
||||
self.$field.$fn_name($($arg_name),*)
|
||||
}
|
||||
|
||||
forward_trait_impl_body!({ $($methods)* } .$field);
|
||||
};
|
||||
|
||||
(
|
||||
{
|
||||
$(#[$annot:meta])*
|
||||
fn $fn_name:ident(&self $(, $arg_name:ident : $arg_ty:ty)* $(,)? ) -> $ret_ty:ty ;
|
||||
$($methods:tt)*
|
||||
}
|
||||
.$field:ident
|
||||
) => {
|
||||
fn $fn_name(&self, $($arg_name: $arg_ty),*) -> $ret_ty {
|
||||
self.$field.$fn_name($($arg_name),*)
|
||||
}
|
||||
|
||||
forward_trait_impl_body!({ $($methods)* } .$field);
|
||||
};
|
||||
|
||||
(
|
||||
{
|
||||
$(#[$annot:meta])*
|
||||
fn $fn_name:ident(&mut self $(, $arg_name:ident : $arg_ty:ty)* $(,)? ) -> $ret_ty:ty ;
|
||||
$($methods:tt)*
|
||||
}
|
||||
.$field:ident
|
||||
) => {
|
||||
fn $fn_name(&mut self, $($arg_name: $arg_ty),*) -> $ret_ty {
|
||||
self.$field.$fn_name($($arg_name),*)
|
||||
}
|
||||
|
||||
forward_trait_impl_body!({ $($methods)* } .$field);
|
||||
};
|
||||
}
|
5
vendor/morphic_lib/src/util/mod.rs
vendored
Normal file
5
vendor/morphic_lib/src/util/mod.rs
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
#[macro_use]
|
||||
pub mod bytes_id;
|
||||
|
||||
#[macro_use]
|
||||
pub mod forward_trait;
|
Loading…
Reference in New Issue
Block a user