Merge branch 'trunk' into roc_alloc

This commit is contained in:
Folkert de Vries 2021-05-24 18:22:47 +02:00 committed by GitHub
commit 513a624d28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 4487 additions and 796 deletions

75
Cargo.lock generated
View File

@ -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]]

View File

@ -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.
===========================================================

View File

@ -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())
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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.

View File

@ -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)
}

View File

@ -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)),

View File

@ -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

View File

@ -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:

View File

@ -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" }

View 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, &[])
}

View File

@ -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);

View File

@ -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]),
});

View File

@ -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)
}

View File

@ -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,
};

View File

@ -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(()),
}
}
}

View File

@ -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;

View File

@ -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;
"#
),
)

View File

@ -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,

View File

@ -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();

View File

@ -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)),

View File

@ -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());

View File

@ -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() {

View File

@ -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 {

View File

@ -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
}

View File

@ -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),
}
}

View File

@ -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::*;
//

View File

@ -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();

View File

@ -262,3 +262,15 @@ fn constrain_call_and_accessor() {
"Str",
)
}
#[test]
fn constrain_access() {
infer_eq(
indoc!(
r#"
{ foo: "bar" }.foo
"#
),
"Str",
)
}

View File

@ -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
View File

@ -0,0 +1,2 @@
/target
Cargo.lock

9
vendor/morphic_lib/Cargo.toml vendored Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

706
vendor/morphic_lib/src/bindings.rs vendored Normal file
View 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
View 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
View 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))
}
}
}
}

View 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
View File

@ -0,0 +1,5 @@
#[macro_use]
pub mod bytes_id;
#[macro_use]
pub mod forward_trait;