Merge remote-tracking branch 'origin/trunk' into import-builtin-mod

This commit is contained in:
Folkert 2021-03-23 15:40:27 +01:00
commit e3b65b1ce0
31 changed files with 577 additions and 728 deletions

39
Cargo.lock generated
View file

@ -889,25 +889,6 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "docs"
version = "0.1.0"
dependencies = [
"bumpalo",
"fs_extra",
"handlebars",
"maplit",
"pretty_assertions 0.5.1",
"pulldown-cmark",
"roc_builtins",
"roc_can",
"roc_collections",
"roc_load",
"serde",
"serde_derive",
"serde_json",
]
[[package]] [[package]]
name = "downcast-rs" name = "downcast-rs"
version = "1.2.0" version = "1.2.0"
@ -2961,6 +2942,7 @@ dependencies = [
"roc_can", "roc_can",
"roc_collections", "roc_collections",
"roc_constrain", "roc_constrain",
"roc_docs",
"roc_editor", "roc_editor",
"roc_fmt", "roc_fmt",
"roc_gen", "roc_gen",
@ -3012,6 +2994,25 @@ dependencies = [
"roc_types", "roc_types",
] ]
[[package]]
name = "roc_docs"
version = "0.1.0"
dependencies = [
"bumpalo",
"fs_extra",
"handlebars",
"maplit",
"pretty_assertions 0.5.1",
"pulldown-cmark",
"roc_builtins",
"roc_can",
"roc_collections",
"roc_load",
"serde",
"serde_derive",
"serde_json",
]
[[package]] [[package]]
name = "roc_editor" name = "roc_editor"
version = "0.1.0" version = "0.1.0"

View file

@ -33,6 +33,7 @@ target-all = [
[dependencies] [dependencies]
roc_collections = { path = "../compiler/collections" } roc_collections = { path = "../compiler/collections" }
roc_can = { path = "../compiler/can" } roc_can = { path = "../compiler/can" }
roc_docs = { path = "../docs" }
roc_parse = { path = "../compiler/parse" } roc_parse = { path = "../compiler/parse" }
roc_region = { path = "../compiler/region" } roc_region = { path = "../compiler/region" }
roc_module = { path = "../compiler/module" } roc_module = { path = "../compiler/module" }

View file

@ -8,7 +8,7 @@ use roc_build::link::LinkType;
use roc_gen::llvm::build::OptLevel; use roc_gen::llvm::build::OptLevel;
use roc_load::file::LoadingProblem; use roc_load::file::LoadingProblem;
use std::io; use std::io;
use std::path::Path; use std::path::{Path, PathBuf};
use std::process; use std::process;
use std::process::Command; use std::process::Command;
use target_lexicon::Triple; use target_lexicon::Triple;
@ -76,6 +76,21 @@ pub fn build_app<'a>() -> App<'a> {
.help("(optional) The directory or files to open on launch.") .help("(optional) The directory or files to open on launch.")
) )
) )
.subcommand(
App::new("docs")
.about("Generate documentation for Roc modules")
.arg(Arg::with_name(DIRECTORY_OR_FILES)
.index(1)
.multiple(true)
.required(true)
.help("The directory or files to build documentation for")
)
)
}
pub fn docs(files: Vec<PathBuf>) {
roc_docs::generate(files, roc_builtins::std::standard_stdlib(), Path::new("./"))
} }
pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io::Result<()> { pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io::Result<()> {

View file

@ -1,6 +1,6 @@
use roc_cli::{build, build_app, repl, DIRECTORY_OR_FILES}; use roc_cli::{build, build_app, docs, repl, DIRECTORY_OR_FILES};
use std::io; use std::io;
use std::path::Path; use std::path::{Path, PathBuf};
use target_lexicon::Triple; use target_lexicon::Triple;
fn main() -> io::Result<()> { fn main() -> io::Result<()> {
@ -35,6 +35,21 @@ fn main() -> io::Result<()> {
} }
} }
} }
Some("docs") => {
let values = matches
.subcommand_matches("docs")
.unwrap()
.values_of_os(DIRECTORY_OR_FILES)
.unwrap();
let paths = values
.map(|os_str| Path::new(os_str).to_path_buf())
.collect::<Vec<PathBuf>>();
docs(paths);
Ok(())
}
_ => unreachable!(), _ => unreachable!(),
} }
} }

View file

@ -148,7 +148,7 @@ fn jit_to_ast_help<'a>(
} }
}; };
let fields = [Layout::Builtin(Builtin::Int64), layout.clone()]; let fields = [Layout::Builtin(Builtin::Int64), *layout];
let layout = Layout::Struct(&fields); let layout = Layout::Struct(&fields);
let result_stack_size = layout.stack_size(env.ptr_bytes); let result_stack_size = layout.stack_size(env.ptr_bytes);

View file

@ -153,7 +153,7 @@ pub fn gen_and_eval<'a>(
let expr_type_str = content_to_string(content.clone(), &subs, home, &interns); let expr_type_str = content_to_string(content.clone(), &subs, home, &interns);
let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) { let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) {
Some(layout) => layout.clone(), Some(layout) => *layout,
None => { None => {
return Ok(ReplOutput::NoProblems { return Ok(ReplOutput::NoProblems {
expr: "<function>".to_string(), expr: "<function>".to_string(),

View file

@ -17,6 +17,6 @@ isEmpty : Dict * * -> Bool
## See for example #Result.map, #List.map, and #Set.map. ## See for example #Result.map, #List.map, and #Set.map.
map : map :
Dict beforeKey beforeValue, Dict beforeKey beforeValue,
(\{ key: beforeKey, value: beforeValue } -> ({ key: beforeKey, value: beforeValue } ->
{ key: afterKey, value: afterValue } { key: afterKey, value: afterValue }
) -> Dict afterKey afterValue ) -> Dict afterKey afterValue

View file

@ -1,5 +1,54 @@
interface List2 interface List2
exposes [ List, single, empty, repeat, range, reverse, sort, map, mapWithIndex, mapOrCancel, mapOks, update, updater, allOks, append, prepend, concat, join, joinMap, oks, zip, zipMap, keepIf, dropIf, first, last, get, max, min, put, drop, append, prepend, dropLast, dropFirst, takeFirst, takeLast, split, sublist, walk, walkBackwards, walkUntil, walkBackwardsUntil, len, isEmpty, contains, all, any ] exposes
[ List
, single
, empty
, repeat
, range
, reverse
, sort
, map
, mapWithIndex
, mapOrCancel
, mapOks
, update
, updater
, allOks
, append
, prepend
, concat
, join
, joinMap
, oks
, zip
, zipMap
, keepIf
, dropIf
, first
, last
, get
, max
, min
, put
, drop
, append
, prepend
, dropLast
, dropFirst
, takeFirst
, takeLast
, split
, sublist
, walk
, walkBackwards
, walkUntil
, walkBackwardsUntil
, len
, isEmpty
, contains
, all
, any
]
imports [] imports []
## Types ## Types
@ -298,7 +347,7 @@ oks : List (Result elem *) -> List elem
## ##
## > For a generalized version that returns whatever you like, instead of a `Pair`, ## > For a generalized version that returns whatever you like, instead of a `Pair`,
## > see `zipMap`. ## > see `zipMap`.
zip : List a, List b, -> List [ Pair a b ]* zip : List a, List b -> List [ Pair a b ]*
## Like `zip` but you can specify what to do with each element. ## Like `zip` but you can specify what to do with each element.
## ##
@ -307,7 +356,7 @@ zip : List a, List b, -> List [ Pair a b ]*
## >>> List.zipMap [ 1, 2, 3 ] [ 0, 5, 4 ] [ 2, 1 ] \num1 num2 num3 -> num1 + num2 - num3 ## >>> List.zipMap [ 1, 2, 3 ] [ 0, 5, 4 ] [ 2, 1 ] \num1 num2 num3 -> num1 + num2 - num3
## ##
## Accepts up to 8 lists. ## Accepts up to 8 lists.
zipMap : List a, List b, (a, b) -> List c zipMap : List a, List b, (a, b -> c) -> List c
## Filter ## Filter

View file

@ -2030,7 +2030,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
// access itself! // access itself!
// scope = scope.clone(); // scope = scope.clone();
scope.insert(*symbol, (layout.clone(), val)); scope.insert(*symbol, (*layout, val));
stack.push(*symbol); stack.push(*symbol);
} }
@ -2063,8 +2063,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
} => { } => {
// when the fail case is just Rethrow, there is no cleanup work to do // when the fail case is just Rethrow, there is no cleanup work to do
// so we can just treat this invoke as a normal call // so we can just treat this invoke as a normal call
let stmt = let stmt = roc_mono::ir::Stmt::Let(*symbol, Expr::Call(call.clone()), *layout, pass);
roc_mono::ir::Stmt::Let(*symbol, Expr::Call(call.clone()), layout.clone(), pass);
build_exp_stmt(env, layout_ids, scope, parent, &stmt) build_exp_stmt(env, layout_ids, scope, parent, &stmt)
} }
@ -2088,7 +2087,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
scope, scope,
parent, parent,
*symbol, *symbol,
layout.clone(), *layout,
function_value.into(), function_value.into(),
call.arguments, call.arguments,
None, None,
@ -2108,7 +2107,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
scope, scope,
parent, parent,
*symbol, *symbol,
layout.clone(), *layout,
function_ptr.into(), function_ptr.into(),
call.arguments, call.arguments,
None, None,
@ -2135,7 +2134,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
scope, scope,
parent, parent,
*symbol, *symbol,
layout.clone(), *layout,
function_ptr.into(), function_ptr.into(),
call.arguments, call.arguments,
Some(closure_data), Some(closure_data),
@ -2194,7 +2193,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
basic_type_from_layout(env.arena, env.context, &ret_layout, env.ptr_bytes); basic_type_from_layout(env.arena, env.context, &ret_layout, env.ptr_bytes);
let switch_args = SwitchArgsIr { let switch_args = SwitchArgsIr {
cond_layout: cond_layout.clone(), cond_layout: *cond_layout,
cond_symbol: *cond_symbol, cond_symbol: *cond_symbol,
branches, branches,
default_branch: default_branch.1, default_branch: default_branch.1,
@ -2242,7 +2241,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
for (ptr, param) in joinpoint_args.iter().zip(parameters.iter()) { for (ptr, param) in joinpoint_args.iter().zip(parameters.iter()) {
let value = env.builder.build_load(*ptr, "load_jp_argument"); let value = env.builder.build_load(*ptr, "load_jp_argument");
scope.insert(param.symbol, (param.layout.clone(), value)); scope.insert(param.symbol, (param.layout, value));
} }
// put the continuation in // put the continuation in
@ -2277,7 +2276,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
match modify { match modify {
Inc(symbol, inc_amount) => { Inc(symbol, inc_amount) => {
let (value, layout) = load_symbol_and_layout(scope, symbol); let (value, layout) = load_symbol_and_layout(scope, symbol);
let layout = layout.clone(); let layout = *layout;
if layout.contains_refcounted() { if layout.contains_refcounted() {
increment_refcount_layout( increment_refcount_layout(
@ -3177,7 +3176,7 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
let function_pointer_type = { let function_pointer_type = {
let function_layout = let function_layout =
ClosureLayout::extend_function_layout(arena, arguments, closure.clone(), result); ClosureLayout::extend_function_layout(arena, arguments, *closure, result);
// this is already a (function) pointer type // this is already a (function) pointer type
basic_type_from_layout(arena, context, &function_layout, env.ptr_bytes) basic_type_from_layout(arena, context, &function_layout, env.ptr_bytes)
@ -3252,7 +3251,7 @@ pub fn build_closure_caller<'a, 'ctx, 'env>(
); );
// STEP 4: build a {} -> u64 function that gives the size of the closure // STEP 4: build a {} -> u64 function that gives the size of the closure
let layout = Layout::Closure(arguments, closure.clone(), result); let layout = Layout::Closure(arguments, *closure, result);
build_host_exposed_alias_size(env, def_name, alias_symbol, &layout); build_host_exposed_alias_size(env, def_name, alias_symbol, &layout);
} }
@ -3455,7 +3454,7 @@ pub fn build_proc<'a, 'ctx, 'env>(
// Add args to scope // Add args to scope
for (arg_val, (layout, arg_symbol)) in fn_val.get_param_iter().zip(args) { for (arg_val, (layout, arg_symbol)) in fn_val.get_param_iter().zip(args) {
set_name(arg_val, arg_symbol.ident_string(&env.interns)); set_name(arg_val, arg_symbol.ident_string(&env.interns));
scope.insert(*arg_symbol, (layout.clone(), arg_val)); scope.insert(*arg_symbol, (*layout, arg_val));
} }
let body = build_exp_stmt(env, layout_ids, &mut scope, fn_val, &proc.body); let body = build_exp_stmt(env, layout_ids, &mut scope, fn_val, &proc.body);
@ -4559,7 +4558,7 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
{ {
env.builder.position_at_end(pass_block); env.builder.position_at_end(pass_block);
scope.insert(symbol, (ret_layout.clone(), call_result)); scope.insert(symbol, (*ret_layout, call_result));
build_exp_stmt(env, layout_ids, scope, parent, pass); build_exp_stmt(env, layout_ids, scope, parent, pass);

View file

@ -717,11 +717,7 @@ pub fn dict_walk<'a, 'ctx, 'env>(
env, env,
layout_ids, layout_ids,
stepper_layout, stepper_layout,
&[ &[*key_layout, *value_layout, *accum_layout],
key_layout.clone(),
value_layout.clone(),
accum_layout.clone(),
],
) )
.as_global_value() .as_global_value()
.as_pointer_value(); .as_pointer_value();

View file

@ -70,7 +70,7 @@ fn build_hash_layout<'a, 'ctx, 'env>(
unreachable!("recursion pointers should never be hashed directly") unreachable!("recursion pointers should never be hashed directly")
} }
WhenRecursive::Loop(union_layout) => { WhenRecursive::Loop(union_layout) => {
let layout = Layout::Union(union_layout.clone()); let layout = Layout::Union(union_layout);
let bt = basic_type_from_layout(env.arena, env.context, &layout, env.ptr_bytes); let bt = basic_type_from_layout(env.arena, env.context, &layout, env.ptr_bytes);
@ -287,7 +287,7 @@ fn hash_struct<'a, 'ctx, 'env>(
unreachable!("The current layout should not be recursive, but is") unreachable!("The current layout should not be recursive, but is")
} }
WhenRecursive::Loop(union_layout) => { WhenRecursive::Loop(union_layout) => {
let field_layout = Layout::Union(union_layout.clone()); let field_layout = Layout::Union(*union_layout);
let bt = basic_type_from_layout( let bt = basic_type_from_layout(
env.arena, env.arena,
@ -811,7 +811,7 @@ fn hash_ptr_to_struct<'a, 'ctx, 'env>(
env, env,
layout_ids, layout_ids,
field_layouts, field_layouts,
WhenRecursive::Loop(union_layout.clone()), WhenRecursive::Loop(*union_layout),
seed, seed,
struct_value, struct_value,
) )

View file

@ -423,7 +423,7 @@ pub fn list_reverse<'a, 'ctx, 'env>(
let ctx = env.context; let ctx = env.context;
let wrapper_struct = list.into_struct_value(); let wrapper_struct = list.into_struct_value();
let (input_inplace, element_layout) = match list_layout.clone() { let (input_inplace, element_layout) = match *list_layout {
Layout::Builtin(Builtin::EmptyList) => ( Layout::Builtin(Builtin::EmptyList) => (
InPlace::InPlace, InPlace::InPlace,
// this pointer will never actually be dereferenced // this pointer will never actually be dereferenced
@ -434,7 +434,7 @@ pub fn list_reverse<'a, 'ctx, 'env>(
MemoryMode::Unique => InPlace::InPlace, MemoryMode::Unique => InPlace::InPlace,
MemoryMode::Refcounted => InPlace::Clone, MemoryMode::Refcounted => InPlace::Clone,
}, },
elem_layout.clone(), *elem_layout,
), ),
_ => unreachable!("Invalid layout {:?} in List.reverse", list_layout), _ => unreachable!("Invalid layout {:?} in List.reverse", list_layout),
@ -868,7 +868,7 @@ fn list_walk_generic<'a, 'ctx, 'env>(
env, env,
layout_ids, layout_ids,
func_layout, func_layout,
&[element_layout.clone(), default_layout.clone()], &[*element_layout, *default_layout],
) )
.as_global_value() .as_global_value()
.as_pointer_value(); .as_pointer_value();
@ -959,7 +959,7 @@ pub fn list_keep_if<'a, 'ctx, 'env>(
env.builder.build_store(transform_ptr, transform); env.builder.build_store(transform_ptr, transform);
let stepper_caller = let stepper_caller =
build_transform_caller(env, layout_ids, transform_layout, &[element_layout.clone()]) build_transform_caller(env, layout_ids, transform_layout, &[*element_layout])
.as_global_value() .as_global_value()
.as_pointer_value(); .as_pointer_value();
@ -1066,7 +1066,7 @@ pub fn list_keep_result<'a, 'ctx, 'env>(
env.builder.build_store(transform_ptr, transform); env.builder.build_store(transform_ptr, transform);
let stepper_caller = let stepper_caller =
build_transform_caller(env, layout_ids, transform_layout, &[before_layout.clone()]) build_transform_caller(env, layout_ids, transform_layout, &[*before_layout])
.as_global_value() .as_global_value()
.as_pointer_value(); .as_pointer_value();
@ -1130,7 +1130,7 @@ pub fn list_map<'a, 'ctx, 'env>(
list, list,
element_layout, element_layout,
bitcode::LIST_MAP, bitcode::LIST_MAP,
&[element_layout.clone()], &[*element_layout],
) )
} }
@ -1151,7 +1151,7 @@ pub fn list_map_with_index<'a, 'ctx, 'env>(
list, list,
element_layout, element_layout,
bitcode::LIST_MAP_WITH_INDEX, bitcode::LIST_MAP_WITH_INDEX,
&[Layout::Builtin(Builtin::Usize), element_layout.clone()], &[Layout::Builtin(Builtin::Usize), *element_layout],
) )
} }
@ -1255,7 +1255,7 @@ pub fn list_map2<'a, 'ctx, 'env>(
let transform_ptr = builder.build_alloca(transform.get_type(), "transform_ptr"); let transform_ptr = builder.build_alloca(transform.get_type(), "transform_ptr");
env.builder.build_store(transform_ptr, transform); env.builder.build_store(transform_ptr, transform);
let argument_layouts = [element1_layout.clone(), element2_layout.clone()]; let argument_layouts = [*element1_layout, *element2_layout];
let stepper_caller = let stepper_caller =
build_transform_caller(env, layout_ids, transform_layout, &argument_layouts) build_transform_caller(env, layout_ids, transform_layout, &argument_layouts)
.as_global_value() .as_global_value()
@ -1351,11 +1351,7 @@ pub fn list_map3<'a, 'ctx, 'env>(
let transform_ptr = builder.build_alloca(transform.get_type(), "transform_ptr"); let transform_ptr = builder.build_alloca(transform.get_type(), "transform_ptr");
env.builder.build_store(transform_ptr, transform); env.builder.build_store(transform_ptr, transform);
let argument_layouts = [ let argument_layouts = [*element1_layout, *element2_layout, *element3_layout];
element1_layout.clone(),
element2_layout.clone(),
element3_layout.clone(),
];
let stepper_caller = let stepper_caller =
build_transform_caller(env, layout_ids, transform_layout, &argument_layouts) build_transform_caller(env, layout_ids, transform_layout, &argument_layouts)
.as_global_value() .as_global_value()

View file

@ -102,7 +102,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
Builtin::List(_, elem) => build_list_eq( Builtin::List(_, elem) => build_list_eq(
env, env,
layout_ids, layout_ids,
&Layout::Builtin(builtin.clone()), &Layout::Builtin(*builtin),
elem, elem,
lhs_val.into_struct_value(), lhs_val.into_struct_value(),
rhs_val.into_struct_value(), rhs_val.into_struct_value(),
@ -170,7 +170,7 @@ fn build_eq<'a, 'ctx, 'env>(
} }
WhenRecursive::Loop(union_layout) => { WhenRecursive::Loop(union_layout) => {
let layout = Layout::Union(union_layout.clone()); let layout = Layout::Union(union_layout);
let bt = basic_type_from_layout(env.arena, env.context, &layout, env.ptr_bytes); let bt = basic_type_from_layout(env.arena, env.context, &layout, env.ptr_bytes);
@ -188,7 +188,7 @@ fn build_eq<'a, 'ctx, 'env>(
build_tag_eq( build_tag_eq(
env, env,
layout_ids, layout_ids,
WhenRecursive::Loop(union_layout.clone()), WhenRecursive::Loop(union_layout),
&layout, &layout,
&union_layout, &union_layout,
field1_cast.into(), field1_cast.into(),
@ -262,7 +262,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
let is_equal = build_list_eq( let is_equal = build_list_eq(
env, env,
layout_ids, layout_ids,
&Layout::Builtin(builtin.clone()), &Layout::Builtin(*builtin),
elem, elem,
lhs_val.into_struct_value(), lhs_val.into_struct_value(),
rhs_val.into_struct_value(), rhs_val.into_struct_value(),
@ -690,7 +690,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
unreachable!("The current layout should not be recursive, but is") unreachable!("The current layout should not be recursive, but is")
} }
WhenRecursive::Loop(union_layout) => { WhenRecursive::Loop(union_layout) => {
let field_layout = Layout::Union(union_layout.clone()); let field_layout = Layout::Union(*union_layout);
let bt = basic_type_from_layout( let bt = basic_type_from_layout(
env.arena, env.arena,
@ -717,7 +717,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
field2_cast.into(), field2_cast.into(),
&field_layout, &field_layout,
&field_layout, &field_layout,
WhenRecursive::Loop(union_layout.clone()), WhenRecursive::Loop(*union_layout),
) )
.into_int_value() .into_int_value()
} }
@ -1234,7 +1234,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
env, env,
layout_ids, layout_ids,
field_layouts, field_layouts,
WhenRecursive::Loop(union_layout.clone()), WhenRecursive::Loop(*union_layout),
struct1, struct1,
struct2, struct2,
) )

View file

@ -454,7 +454,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
env, env,
layout_ids, layout_ids,
mode, mode,
&WhenRecursive::Loop(variant.clone()), &WhenRecursive::Loop(*variant),
tags, tags,
value.into_pointer_value(), value.into_pointer_value(),
true, true,
@ -470,7 +470,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
env, env,
layout_ids, layout_ids,
mode, mode,
&WhenRecursive::Loop(variant.clone()), &WhenRecursive::Loop(*variant),
&*env.arena.alloc([other_fields]), &*env.arena.alloc([other_fields]),
value.into_pointer_value(), value.into_pointer_value(),
true, true,
@ -484,7 +484,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
env, env,
layout_ids, layout_ids,
mode, mode,
&WhenRecursive::Loop(variant.clone()), &WhenRecursive::Loop(*variant),
&*env.arena.alloc([*fields]), &*env.arena.alloc([*fields]),
value.into_pointer_value(), value.into_pointer_value(),
true, true,
@ -497,7 +497,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
env, env,
layout_ids, layout_ids,
mode, mode,
&WhenRecursive::Loop(variant.clone()), &WhenRecursive::Loop(*variant),
tags, tags,
value.into_pointer_value(), value.into_pointer_value(),
false, false,
@ -549,7 +549,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
unreachable!("recursion pointers should never be hashed directly") unreachable!("recursion pointers should never be hashed directly")
} }
WhenRecursive::Loop(union_layout) => { WhenRecursive::Loop(union_layout) => {
let layout = Layout::Union(union_layout.clone()); let layout = Layout::Union(*union_layout);
let bt = basic_type_from_layout(env.arena, env.context, &layout, env.ptr_bytes); let bt = basic_type_from_layout(env.arena, env.context, &layout, env.ptr_bytes);

View file

@ -105,7 +105,7 @@ where
} => { } => {
// for now, treat invoke as a normal call // for now, treat invoke as a normal call
let stmt = Stmt::Let(*symbol, Expr::Call(call.clone()), layout.clone(), pass); let stmt = Stmt::Let(*symbol, Expr::Call(call.clone()), *layout, pass);
self.build_stmt(&stmt) self.build_stmt(&stmt)
} }
Stmt::Switch { Stmt::Switch {
@ -252,32 +252,20 @@ where
x => Err(format!("layout, {:?}, not implemented yet", x)), x => Err(format!("layout, {:?}, not implemented yet", x)),
} }
} }
LowLevel::NumAcos => self.build_fn_call( LowLevel::NumAcos => {
sym, self.build_fn_call(sym, bitcode::NUM_ACOS.to_string(), args, &[*layout], layout)
bitcode::NUM_ACOS.to_string(), }
args, LowLevel::NumAsin => {
&[layout.clone()], self.build_fn_call(sym, bitcode::NUM_ASIN.to_string(), args, &[*layout], layout)
layout, }
), LowLevel::NumAtan => {
LowLevel::NumAsin => self.build_fn_call( self.build_fn_call(sym, bitcode::NUM_ATAN.to_string(), args, &[*layout], layout)
sym, }
bitcode::NUM_ASIN.to_string(),
args,
&[layout.clone()],
layout,
),
LowLevel::NumAtan => self.build_fn_call(
sym,
bitcode::NUM_ATAN.to_string(),
args,
&[layout.clone()],
layout,
),
LowLevel::NumPowInt => self.build_fn_call( LowLevel::NumPowInt => self.build_fn_call(
sym, sym,
bitcode::NUM_POW_INT.to_string(), bitcode::NUM_POW_INT.to_string(),
args, args,
&[layout.clone(), layout.clone()], &[*layout, *layout],
layout, layout,
), ),
LowLevel::NumSub => { LowLevel::NumSub => {
@ -472,7 +460,7 @@ where
} => { } => {
// for now, treat invoke as a normal call // for now, treat invoke as a normal call
let stmt = Stmt::Let(*symbol, Expr::Call(call.clone()), layout.clone(), pass); let stmt = Stmt::Let(*symbol, Expr::Call(call.clone()), *layout, pass);
self.scan_ast(&stmt); self.scan_ast(&stmt);
} }

View file

@ -1944,7 +1944,7 @@ fn update<'a>(
}; };
for (layout, pend) in specs { for (layout, pend) in specs {
existing.insert(layout.clone(), pend.clone()); existing.insert(*layout, pend.clone());
} }
} }
} }

View file

@ -22,7 +22,7 @@ pub fn infer_borrow<'a>(
}; };
for (key, proc) in procs { for (key, proc) in procs {
param_map.visit_proc(arena, proc, key.clone()); param_map.visit_proc(arena, proc, *key);
} }
let mut env = BorrowInfState { let mut env = BorrowInfState {
@ -47,7 +47,7 @@ pub fn infer_borrow<'a>(
// mutually recursive functions (or just make all their arguments owned) // mutually recursive functions (or just make all their arguments owned)
for (key, proc) in procs { for (key, proc) in procs {
env.collect_proc(proc, key.1.clone()); env.collect_proc(proc, key.1);
} }
if !env.modified { if !env.modified {
@ -113,7 +113,7 @@ impl<'a> ParamMap<'a> {
Vec::from_iter_in( Vec::from_iter_in(
ps.iter().map(|p| Param { ps.iter().map(|p| Param {
borrow: p.layout.is_refcounted(), borrow: p.layout.is_refcounted(),
layout: p.layout.clone(), layout: p.layout,
symbol: p.symbol, symbol: p.symbol,
}), }),
arena, arena,
@ -125,7 +125,7 @@ impl<'a> ParamMap<'a> {
Vec::from_iter_in( Vec::from_iter_in(
ps.iter().map(|(layout, symbol)| Param { ps.iter().map(|(layout, symbol)| Param {
borrow: should_borrow_layout(layout), borrow: should_borrow_layout(layout),
layout: layout.clone(), layout: *layout,
symbol: *symbol, symbol: *symbol,
}), }),
arena, arena,
@ -140,7 +140,7 @@ impl<'a> ParamMap<'a> {
Vec::from_iter_in( Vec::from_iter_in(
ps.iter().map(|(layout, symbol)| Param { ps.iter().map(|(layout, symbol)| Param {
borrow: false, borrow: false,
layout: layout.clone(), layout: *layout,
symbol: *symbol, symbol: *symbol,
}), }),
arena, arena,
@ -367,7 +367,7 @@ impl<'a> BorrowInfState<'a> {
name, full_layout, .. name, full_layout, ..
} => { } => {
// get the borrow signature of the applied function // get the borrow signature of the applied function
match self.param_map.get_symbol(*name, full_layout.clone()) { match self.param_map.get_symbol(*name, *full_layout) {
Some(ps) => { Some(ps) => {
// the return value will be owned // the return value will be owned
self.own_var(z); self.own_var(z);
@ -499,7 +499,7 @@ impl<'a> BorrowInfState<'a> {
if self.current_proc == *g && x == *z { if self.current_proc == *g && x == *z {
// anonymous functions (for which the ps may not be known) // anonymous functions (for which the ps may not be known)
// can never be tail-recursive, so this is fine // can never be tail-recursive, so this is fine
if let Some(ps) = self.param_map.get_symbol(*g, full_layout.clone()) { if let Some(ps) = self.param_map.get_symbol(*g, *full_layout) {
self.own_params_using_args(ys, ps) self.own_params_using_args(ys, ps)
} }
} }
@ -541,14 +541,14 @@ impl<'a> BorrowInfState<'a> {
Let(x, Expr::FunctionPointer(fsymbol, layout), _, b) => { Let(x, Expr::FunctionPointer(fsymbol, layout), _, b) => {
// ensure that the function pointed to is in the param map // ensure that the function pointed to is in the param map
if let Some(params) = self.param_map.get_symbol(*fsymbol, layout.clone()) { if let Some(params) = self.param_map.get_symbol(*fsymbol, *layout) {
self.param_map self.param_map
.items .items
.insert(Key::Declaration(*x, layout.clone()), params); .insert(Key::Declaration(*x, *layout), params);
} }
self.collect_stmt(b); self.collect_stmt(b);
self.preserve_tail_call(*x, &Expr::FunctionPointer(*fsymbol, layout.clone()), b); self.preserve_tail_call(*x, &Expr::FunctionPointer(*fsymbol, *layout), b);
} }
Let(x, v, _, b) => { Let(x, v, _, b) => {

View file

@ -22,7 +22,7 @@ pub fn compile<'a>(raw_branches: Vec<(Guard<'a>, Pattern<'a>, u64)>) -> Decision
.into_iter() .into_iter()
.map(|(guard, pattern, index)| Branch { .map(|(guard, pattern, index)| Branch {
goal: index, goal: index,
patterns: vec![(Path::Empty, guard, pattern)], patterns: vec![(Vec::new(), guard, pattern)],
}) })
.collect(); .collect();
@ -52,7 +52,7 @@ impl<'a> Guard<'a> {
pub enum DecisionTree<'a> { pub enum DecisionTree<'a> {
Match(Label), Match(Label),
Decision { Decision {
path: Path, path: Vec<PathInstruction>,
edges: Vec<(Test<'a>, DecisionTree<'a>)>, edges: Vec<(Test<'a>, DecisionTree<'a>)>,
default: Option<Box<DecisionTree<'a>>>, default: Option<Box<DecisionTree<'a>>>,
}, },
@ -132,23 +132,12 @@ impl<'a> Hash for Test<'a> {
} }
} }
#[derive(Clone, Debug, PartialEq)]
pub enum Path {
Index {
index: u64,
tag_id: u8,
path: Box<Path>,
},
Unbox(Box<Path>),
Empty,
}
// ACTUALLY BUILD DECISION TREES // ACTUALLY BUILD DECISION TREES
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
struct Branch<'a> { struct Branch<'a> {
goal: Label, goal: Label,
patterns: Vec<(Path, Guard<'a>, Pattern<'a>)>, patterns: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
} }
fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree { fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree {
@ -172,13 +161,13 @@ fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree {
decision_tree.clone() decision_tree.clone()
} }
(_, None) => DecisionTree::Decision { (_, None) => DecisionTree::Decision {
path, path: path.clone(),
edges: decision_edges, edges: decision_edges,
default: None, default: None,
}, },
(None, Some(_)) => to_decision_tree(fallback), (None, Some(_)) => to_decision_tree(fallback),
_ => DecisionTree::Decision { _ => DecisionTree::Decision {
path, path: path.clone(),
edges: decision_edges, edges: decision_edges,
default: Some(Box::new(to_decision_tree(fallback))), default: Some(Box::new(to_decision_tree(fallback))),
}, },
@ -218,8 +207,8 @@ fn flatten_patterns(branch: Branch) -> Branch {
} }
fn flatten<'a>( fn flatten<'a>(
path_pattern: (Path, Guard<'a>, Pattern<'a>), path_pattern: (Vec<PathInstruction>, Guard<'a>, Pattern<'a>),
path_patterns: &mut Vec<(Path, Guard<'a>, Pattern<'a>)>, path_patterns: &mut Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
) { ) {
match path_pattern.2 { match path_pattern.2 {
Pattern::AppliedTag { Pattern::AppliedTag {
@ -241,8 +230,9 @@ fn flatten<'a>(
// Theory: unbox doesn't have any value for us, because one-element tag unions // Theory: unbox doesn't have any value for us, because one-element tag unions
// don't store the tag anyway. // don't store the tag anyway.
if arguments.len() == 1 { if arguments.len() == 1 {
// NOTE here elm will unbox, but we don't use that
path_patterns.push(( path_patterns.push((
Path::Unbox(Box::new(path)), path,
path_pattern.1.clone(), path_pattern.1.clone(),
Pattern::AppliedTag { Pattern::AppliedTag {
union, union,
@ -254,13 +244,15 @@ fn flatten<'a>(
)); ));
} else { } else {
for (index, (arg_pattern, _)) in arguments.iter().enumerate() { for (index, (arg_pattern, _)) in arguments.iter().enumerate() {
let mut new_path = path.clone();
new_path.push(PathInstruction {
index: index as u64,
tag_id,
});
flatten( flatten(
( (
Path::Index { new_path,
index: index as u64,
tag_id,
path: Box::new(path.clone()),
},
// same guard here? // same guard here?
path_pattern.1.clone(), path_pattern.1.clone(),
arg_pattern.clone(), arg_pattern.clone(),
@ -283,7 +275,7 @@ fn flatten<'a>(
/// path. If that is the case we give the resulting label and a mapping from free /// path. If that is the case we give the resulting label and a mapping from free
/// variables to "how to get their value". So a pattern like (Just (x,_)) will give /// variables to "how to get their value". So a pattern like (Just (x,_)) will give
/// us something like ("x" => value.0.0) /// us something like ("x" => value.0.0)
fn check_for_match(branches: &Vec<Branch>) -> Option<Label> { fn check_for_match(branches: &[Branch]) -> Option<Label> {
match branches.get(0) { match branches.get(0) {
Some(Branch { goal, patterns }) Some(Branch { goal, patterns })
if patterns if patterns
@ -300,7 +292,7 @@ fn check_for_match(branches: &Vec<Branch>) -> Option<Label> {
fn gather_edges<'a>( fn gather_edges<'a>(
branches: Vec<Branch<'a>>, branches: Vec<Branch<'a>>,
path: &Path, path: &[PathInstruction],
) -> (Vec<(Test<'a>, Vec<Branch<'a>>)>, Vec<Branch<'a>>) { ) -> (Vec<(Test<'a>, Vec<Branch<'a>>)>, Vec<Branch<'a>>) {
let relevant_tests = tests_at_path(path, &branches); let relevant_tests = tests_at_path(path, &branches);
@ -326,7 +318,7 @@ fn gather_edges<'a>(
/// FIND RELEVANT TESTS /// FIND RELEVANT TESTS
fn tests_at_path<'a>(selected_path: &Path, branches: &[Branch<'a>]) -> Vec<Test<'a>> { fn tests_at_path<'a>(selected_path: &[PathInstruction], branches: &[Branch<'a>]) -> Vec<Test<'a>> {
// NOTE the ordering of the result is important! // NOTE the ordering of the result is important!
let mut all_tests = Vec::new(); let mut all_tests = Vec::new();
@ -360,7 +352,11 @@ fn tests_at_path<'a>(selected_path: &Path, branches: &[Branch<'a>]) -> Vec<Test<
unique unique
} }
fn test_at_path<'a>(selected_path: &Path, branch: &Branch<'a>, all_tests: &mut Vec<Test<'a>>) { fn test_at_path<'a>(
selected_path: &[PathInstruction],
branch: &Branch<'a>,
all_tests: &mut Vec<Test<'a>>,
) {
use Pattern::*; use Pattern::*;
use Test::*; use Test::*;
@ -413,10 +409,10 @@ fn test_at_path<'a>(selected_path: &Path, branch: &Branch<'a>, all_tests: &mut V
for destruct in destructs { for destruct in destructs {
match &destruct.typ { match &destruct.typ {
DestructType::Guard(guard) => { DestructType::Guard(guard) => {
arguments.push((guard.clone(), destruct.layout.clone())); arguments.push((guard.clone(), destruct.layout));
} }
DestructType::Required(_) => { DestructType::Required(_) => {
arguments.push((Pattern::Underscore, destruct.layout.clone())); arguments.push((Pattern::Underscore, destruct.layout));
} }
} }
} }
@ -469,7 +465,7 @@ fn test_at_path<'a>(selected_path: &Path, branch: &Branch<'a>, all_tests: &mut V
/// BUILD EDGES /// BUILD EDGES
fn edges_for<'a>( fn edges_for<'a>(
path: &Path, path: &[PathInstruction],
branches: Vec<Branch<'a>>, branches: Vec<Branch<'a>>,
test: Test<'a>, test: Test<'a>,
) -> (Test<'a>, Vec<Branch<'a>>) { ) -> (Test<'a>, Vec<Branch<'a>>) {
@ -484,7 +480,7 @@ fn edges_for<'a>(
fn to_relevant_branch<'a>( fn to_relevant_branch<'a>(
test: &Test<'a>, test: &Test<'a>,
path: &Path, path: &[PathInstruction],
branch: &Branch<'a>, branch: &Branch<'a>,
new_branches: &mut Vec<Branch<'a>>, new_branches: &mut Vec<Branch<'a>>,
) { ) {
@ -524,9 +520,9 @@ fn to_relevant_branch<'a>(
fn to_relevant_branch_help<'a>( fn to_relevant_branch_help<'a>(
test: &Test<'a>, test: &Test<'a>,
path: &Path, path: &[PathInstruction],
mut start: Vec<(Path, Guard<'a>, Pattern<'a>)>, mut start: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
end: Vec<(Path, Guard<'a>, Pattern<'a>)>, end: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
branch: &Branch<'a>, branch: &Branch<'a>,
guard: Guard<'a>, guard: Guard<'a>,
pattern: Pattern<'a>, pattern: Pattern<'a>,
@ -550,15 +546,13 @@ fn to_relevant_branch_help<'a>(
DestructType::Required(_) => Pattern::Underscore, DestructType::Required(_) => Pattern::Underscore,
}; };
( let mut new_path = path.to_vec();
Path::Index { new_path.push(PathInstruction {
index: index as u64, index: index as u64,
tag_id: *tag_id, tag_id: *tag_id,
path: Box::new(path.clone()), });
},
Guard::NoGuard, (new_path, Guard::NoGuard, pattern)
pattern,
)
}); });
start.extend(sub_positions); start.extend(sub_positions);
start.extend(end); start.extend(end);
@ -597,26 +591,21 @@ fn to_relevant_branch_help<'a>(
debug_assert_eq!(arguments.len(), 1); debug_assert_eq!(arguments.len(), 1);
let arg = arguments[0].clone(); let arg = arguments[0].clone();
{ {
start.push(( // NOTE here elm unboxes, but we ignore that
Path::Unbox(Box::new(path.clone())), // Path::Unbox(Box::new(path.clone()))
guard, start.push((path.to_vec(), guard, arg.0));
arg.0,
));
start.extend(end); start.extend(end);
} }
} }
Wrapped::RecordOrSingleTagUnion => { Wrapped::RecordOrSingleTagUnion => {
let sub_positions = arguments.into_iter().enumerate().map( let sub_positions = arguments.into_iter().enumerate().map(
|(index, (pattern, _))| { |(index, (pattern, _))| {
( let mut new_path = path.to_vec();
Path::Index { new_path.push(PathInstruction {
index: index as u64, index: index as u64,
tag_id, tag_id,
path: Box::new(path.clone()), });
}, (new_path, Guard::NoGuard, pattern)
Guard::NoGuard,
pattern,
)
}, },
); );
start.extend(sub_positions); start.extend(sub_positions);
@ -625,15 +614,12 @@ fn to_relevant_branch_help<'a>(
Wrapped::MultiTagUnion => { Wrapped::MultiTagUnion => {
let sub_positions = arguments.into_iter().enumerate().map( let sub_positions = arguments.into_iter().enumerate().map(
|(index, (pattern, _))| { |(index, (pattern, _))| {
( let mut new_path = path.to_vec();
Path::Index { new_path.push(PathInstruction {
index: 1 + index as u64, index: 1 + index as u64,
tag_id, tag_id,
path: Box::new(path.clone()), });
}, (new_path, Guard::NoGuard, pattern)
Guard::NoGuard,
pattern,
)
}, },
); );
start.extend(sub_positions); start.extend(sub_positions);
@ -715,22 +701,22 @@ fn to_relevant_branch_help<'a>(
enum Extract<'a> { enum Extract<'a> {
NotFound, NotFound,
Found { Found {
start: Vec<(Path, Guard<'a>, Pattern<'a>)>, start: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
found_pattern: (Guard<'a>, Pattern<'a>), found_pattern: (Guard<'a>, Pattern<'a>),
end: Vec<(Path, Guard<'a>, Pattern<'a>)>, end: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
}, },
} }
fn extract<'a>( fn extract<'a>(
selected_path: &Path, selected_path: &[PathInstruction],
path_patterns: Vec<(Path, Guard<'a>, Pattern<'a>)>, path_patterns: Vec<(Vec<PathInstruction>, Guard<'a>, Pattern<'a>)>,
) -> Extract<'a> { ) -> Extract<'a> {
let mut start = Vec::new(); let mut start = Vec::new();
// TODO potential ordering problem // TODO potential ordering problem
let mut it = path_patterns.into_iter(); let mut it = path_patterns.into_iter();
while let Some(current) = it.next() { while let Some(current) = it.next() {
if &current.0 == selected_path { if current.0 == selected_path {
return Extract::Found { return Extract::Found {
start, start,
found_pattern: (current.1, current.2), found_pattern: (current.1, current.2),
@ -746,7 +732,7 @@ fn extract<'a>(
/// FIND IRRELEVANT BRANCHES /// FIND IRRELEVANT BRANCHES
fn is_irrelevant_to<'a>(selected_path: &Path, branch: &Branch<'a>) -> bool { fn is_irrelevant_to<'a>(selected_path: &[PathInstruction], branch: &Branch<'a>) -> bool {
match branch match branch
.patterns .patterns
.iter() .iter()
@ -775,7 +761,7 @@ fn needs_tests(pattern: &Pattern) -> bool {
/// PICK A PATH /// PICK A PATH
fn pick_path<'a>(branches: &'a [Branch]) -> &'a Path { fn pick_path<'a>(branches: &'a [Branch]) -> &'a Vec<PathInstruction> {
let mut all_paths = Vec::with_capacity(branches.len()); let mut all_paths = Vec::with_capacity(branches.len());
// is choice path // is choice path
@ -804,9 +790,12 @@ fn pick_path<'a>(branches: &'a [Branch]) -> &'a Path {
} }
} }
fn bests_by_small_branching_factor<'a, I>(branches: &[Branch], mut all_paths: I) -> Vec<&'a Path> fn bests_by_small_branching_factor<'a, I>(
branches: &[Branch],
mut all_paths: I,
) -> Vec<&'a Vec<PathInstruction>>
where where
I: Iterator<Item = &'a Path>, I: Iterator<Item = &'a Vec<PathInstruction>>,
{ {
match all_paths.next() { match all_paths.next() {
None => panic!("Cannot choose the best of zero paths. This should never happen."), None => panic!("Cannot choose the best of zero paths. This should never happen."),
@ -836,9 +825,12 @@ where
} }
} }
fn bests_by_small_defaults<'a, I>(branches: &[Branch], mut all_paths: I) -> Vec<&'a Path> fn bests_by_small_defaults<'a, I>(
branches: &[Branch],
mut all_paths: I,
) -> Vec<&'a Vec<PathInstruction>>
where where
I: Iterator<Item = &'a Path>, I: Iterator<Item = &'a Vec<PathInstruction>>,
{ {
match all_paths.next() { match all_paths.next() {
None => panic!("Cannot choose the best of zero paths. This should never happen."), None => panic!("Cannot choose the best of zero paths. This should never happen."),
@ -870,7 +862,7 @@ where
/// PATH PICKING HEURISTICS /// PATH PICKING HEURISTICS
fn small_defaults(branches: &[Branch], path: &Path) -> usize { fn small_defaults(branches: &[Branch], path: &[PathInstruction]) -> usize {
branches branches
.iter() .iter()
.filter(|b| is_irrelevant_to(path, b)) .filter(|b| is_irrelevant_to(path, b))
@ -878,8 +870,7 @@ fn small_defaults(branches: &[Branch], path: &Path) -> usize {
.sum() .sum()
} }
fn small_branching_factor(branches: &[Branch], path: &Path) -> usize { fn small_branching_factor(branches: &[Branch], path: &[PathInstruction]) -> usize {
// TODO remove clone
let (edges, fallback) = gather_edges(branches.to_vec(), path); let (edges, fallback) = gather_edges(branches.to_vec(), path);
edges.len() + (if fallback.is_empty() { 0 } else { 1 }) edges.len() + (if fallback.is_empty() { 0 } else { 1 })
@ -889,12 +880,12 @@ fn small_branching_factor(branches: &[Branch], path: &Path) -> usize {
enum Decider<'a, T> { enum Decider<'a, T> {
Leaf(T), Leaf(T),
Chain { Chain {
test_chain: Vec<(Path, Test<'a>)>, test_chain: Vec<(Vec<PathInstruction>, Test<'a>)>,
success: Box<Decider<'a, T>>, success: Box<Decider<'a, T>>,
failure: Box<Decider<'a, T>>, failure: Box<Decider<'a, T>>,
}, },
FanOut { FanOut {
path: Path, path: Vec<PathInstruction>,
tests: Vec<(Test<'a>, Decider<'a, T>)>, tests: Vec<(Test<'a>, Decider<'a, T>)>,
fallback: Box<Decider<'a, T>>, fallback: Box<Decider<'a, T>>,
}, },
@ -973,49 +964,22 @@ pub fn optimize_when<'a>(
stmt stmt
} }
#[derive(Debug)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct PathInstruction { pub struct PathInstruction {
index: u64, index: u64,
tag_id: u8, tag_id: u8,
} }
fn reverse_path(mut path: &Path) -> Vec<PathInstruction> {
let mut result = Vec::new();
loop {
match path {
Path::Unbox(nested) => {
path = nested;
}
Path::Empty => break,
Path::Index {
index,
tag_id,
path: nested,
} => {
result.push(PathInstruction {
index: *index,
tag_id: *tag_id,
});
path = nested;
}
}
}
result.reverse();
result
}
fn path_to_expr_help<'a>( fn path_to_expr_help<'a>(
env: &mut Env<'a, '_>, env: &mut Env<'a, '_>,
mut symbol: Symbol, mut symbol: Symbol,
path: &Path, path: &[PathInstruction],
mut layout: Layout<'a>, mut layout: Layout<'a>,
) -> (Symbol, StoresVec<'a>, Layout<'a>) { ) -> (Symbol, StoresVec<'a>, Layout<'a>) {
let mut stores = bumpalo::collections::Vec::new_in(env.arena); let mut stores = bumpalo::collections::Vec::new_in(env.arena);
let instructions = reverse_path(path); // let instructions = reverse_path(path);
let instructions = path;
let mut it = instructions.iter().peekable(); let mut it = instructions.iter().peekable();
while let Some(PathInstruction { index, tag_id }) = it.next() { while let Some(PathInstruction { index, tag_id }) = it.next() {
@ -1027,13 +991,12 @@ fn path_to_expr_help<'a>(
debug_assert_eq!(*tag_id, 0); debug_assert_eq!(*tag_id, 0);
debug_assert!(it.peek().is_none()); debug_assert!(it.peek().is_none());
let field_layouts = vec![layout.clone()]; let field_layouts = vec![layout];
debug_assert!(*index < field_layouts.len() as u64); debug_assert!(*index < field_layouts.len() as u64);
debug_assert_eq!(field_layouts.len(), 1); debug_assert_eq!(field_layouts.len(), 1);
let inner_layout = field_layouts[*index as usize].clone();
let inner_expr = Expr::AccessAtIndex { let inner_expr = Expr::AccessAtIndex {
index: *index, index: *index,
field_layouts: env.arena.alloc(field_layouts), field_layouts: env.arena.alloc(field_layouts),
@ -1042,7 +1005,8 @@ fn path_to_expr_help<'a>(
}; };
symbol = env.unique_symbol(); symbol = env.unique_symbol();
stores.push((symbol, inner_layout.clone(), inner_expr)); let inner_layout = layout;
stores.push((symbol, inner_layout, inner_expr));
break; break;
} }
@ -1096,7 +1060,7 @@ fn path_to_expr_help<'a>(
} }
Layout::Struct(layouts) => layouts, Layout::Struct(layouts) => layouts,
other => env.arena.alloc([other.clone()]), other => env.arena.alloc([*other]),
}; };
debug_assert!( debug_assert!(
@ -1109,8 +1073,8 @@ fn path_to_expr_help<'a>(
); );
let inner_layout = match &field_layouts[index as usize] { let inner_layout = match &field_layouts[index as usize] {
Layout::RecursivePointer => layout.clone(), Layout::RecursivePointer => layout,
other => other.clone(), other => *other,
}; };
let inner_expr = Expr::AccessAtIndex { let inner_expr = Expr::AccessAtIndex {
@ -1121,7 +1085,7 @@ fn path_to_expr_help<'a>(
}; };
symbol = env.unique_symbol(); symbol = env.unique_symbol();
stores.push((symbol, inner_layout.clone(), inner_expr)); stores.push((symbol, inner_layout, inner_expr));
layout = inner_layout; layout = inner_layout;
} }
@ -1135,11 +1099,11 @@ fn test_to_equality<'a>(
env: &mut Env<'a, '_>, env: &mut Env<'a, '_>,
cond_symbol: Symbol, cond_symbol: Symbol,
cond_layout: &Layout<'a>, cond_layout: &Layout<'a>,
path: &Path, path: &[PathInstruction],
test: Test<'a>, test: Test<'a>,
) -> (StoresVec<'a>, Symbol, Symbol, Layout<'a>) { ) -> (StoresVec<'a>, Symbol, Symbol, Layout<'a>) {
let (rhs_symbol, mut stores, _layout) = let (rhs_symbol, mut stores, _layout) =
path_to_expr_help(env, cond_symbol, &path, cond_layout.clone()); path_to_expr_help(env, cond_symbol, &path, *cond_layout);
match test { match test {
Test::IsCtor { Test::IsCtor {
@ -1273,7 +1237,7 @@ fn stores_and_condition<'a>(
env: &mut Env<'a, '_>, env: &mut Env<'a, '_>,
cond_symbol: Symbol, cond_symbol: Symbol,
cond_layout: &Layout<'a>, cond_layout: &Layout<'a>,
test_chain: Vec<(Path, Test<'a>)>, test_chain: Vec<(Vec<PathInstruction>, Test<'a>)>,
) -> (Tests<'a>, Option<(Symbol, JoinPointId, Stmt<'a>)>) { ) -> (Tests<'a>, Option<(Symbol, JoinPointId, Stmt<'a>)>) {
let mut tests = Vec::with_capacity(test_chain.len()); let mut tests = Vec::with_capacity(test_chain.len());
@ -1399,12 +1363,12 @@ fn compile_test_help<'a>(
} => { } => {
let pass_info = BranchInfo::Constructor { let pass_info = BranchInfo::Constructor {
scrutinee, scrutinee,
layout: layout.clone(), layout,
tag_id: pass, tag_id: pass,
}; };
let fail_info = BranchInfo::Constructor { let fail_info = BranchInfo::Constructor {
scrutinee, scrutinee,
layout: layout.clone(), layout,
tag_id: fail, tag_id: fail,
}; };
@ -1418,7 +1382,7 @@ fn compile_test_help<'a>(
} => { } => {
let pass_info = BranchInfo::Constructor { let pass_info = BranchInfo::Constructor {
scrutinee, scrutinee,
layout: layout.clone(), layout,
tag_id, tag_id,
}; };
@ -1473,11 +1437,11 @@ fn compile_tests<'a>(
// the guard is the final thing that we check, so needs to be layered on first! // the guard is the final thing that we check, so needs to be layered on first!
if let Some((_, id, stmt)) = opt_guard { if let Some((_, id, stmt)) = opt_guard {
cond = compile_guard(env, ret_layout.clone(), id, arena.alloc(stmt), fail, cond); cond = compile_guard(env, ret_layout, id, arena.alloc(stmt), fail, cond);
} }
for (new_stores, lhs, rhs, _layout) in tests.into_iter() { for (new_stores, lhs, rhs, _layout) in tests.into_iter() {
cond = compile_test(env, ret_layout.clone(), new_stores, lhs, rhs, fail, cond); cond = compile_test(env, ret_layout, new_stores, lhs, rhs, fail, cond);
} }
cond cond
} }
@ -1501,22 +1465,22 @@ impl<'a> ConstructorKnown<'a> {
fn from_test_chain( fn from_test_chain(
cond_symbol: Symbol, cond_symbol: Symbol,
cond_layout: &Layout<'a>, cond_layout: &Layout<'a>,
test_chain: &[(Path, Test)], test_chain: &[(Vec<PathInstruction>, Test)],
) -> Self { ) -> Self {
match test_chain { match test_chain {
[(path, test)] => match (path, test) { [(path, test)] => match test {
(Path::Empty, Test::IsCtor { tag_id, union, .. }) => { Test::IsCtor { tag_id, union, .. } if path.is_empty() => {
if union.alternatives.len() == 2 { if union.alternatives.len() == 2 {
// excluded middle: we also know the tag_id in the fail branch // excluded middle: we also know the tag_id in the fail branch
ConstructorKnown::Both { ConstructorKnown::Both {
layout: cond_layout.clone(), layout: *cond_layout,
scrutinee: cond_symbol, scrutinee: cond_symbol,
pass: *tag_id, pass: *tag_id,
fail: (*tag_id == 0) as u8, fail: (*tag_id == 0) as u8,
} }
} else { } else {
ConstructorKnown::OnlyPass { ConstructorKnown::OnlyPass {
layout: cond_layout.clone(), layout: *cond_layout,
scrutinee: cond_symbol, scrutinee: cond_symbol,
tag_id: *tag_id, tag_id: *tag_id,
} }
@ -1541,7 +1505,7 @@ fn decide_to_branching<'a>(
cond_layout: Layout<'a>, cond_layout: Layout<'a>,
ret_layout: Layout<'a>, ret_layout: Layout<'a>,
decider: Decider<'a, Choice<'a>>, decider: Decider<'a, Choice<'a>>,
jumps: &Vec<(u64, JoinPointId, Stmt<'a>)>, jumps: &[(u64, JoinPointId, Stmt<'a>)],
) -> Stmt<'a> { ) -> Stmt<'a> {
use Choice::*; use Choice::*;
use Decider::*; use Decider::*;
@ -1569,8 +1533,8 @@ fn decide_to_branching<'a>(
procs, procs,
layout_cache, layout_cache,
cond_symbol, cond_symbol,
cond_layout.clone(), cond_layout,
ret_layout.clone(), ret_layout,
*success, *success,
jumps, jumps,
); );
@ -1580,8 +1544,8 @@ fn decide_to_branching<'a>(
procs, procs,
layout_cache, layout_cache,
cond_symbol, cond_symbol,
cond_layout.clone(), cond_layout,
ret_layout.clone(), ret_layout,
*failure, *failure,
jumps, jumps,
); );
@ -1608,7 +1572,7 @@ fn decide_to_branching<'a>(
compile_test_help( compile_test_help(
env, env,
chain_branch_info, chain_branch_info,
ret_layout.clone(), ret_layout,
new_stores, new_stores,
lhs, lhs,
rhs, rhs,
@ -1643,15 +1607,15 @@ fn decide_to_branching<'a>(
// switch on the tag discriminant (currently an i64 value) // switch on the tag discriminant (currently an i64 value)
// NOTE the tag discriminant is not actually loaded, `cond` can point to a tag // NOTE the tag discriminant is not actually loaded, `cond` can point to a tag
let (inner_cond_symbol, cond_stores_vec, inner_cond_layout) = let (inner_cond_symbol, cond_stores_vec, inner_cond_layout) =
path_to_expr_help(env, cond_symbol, &path, cond_layout.clone()); path_to_expr_help(env, cond_symbol, &path, cond_layout);
let default_branch = decide_to_branching( let default_branch = decide_to_branching(
env, env,
procs, procs,
layout_cache, layout_cache,
cond_symbol, cond_symbol,
cond_layout.clone(), cond_layout,
ret_layout.clone(), ret_layout,
*fallback, *fallback,
jumps, jumps,
); );
@ -1667,8 +1631,8 @@ fn decide_to_branching<'a>(
procs, procs,
layout_cache, layout_cache,
cond_symbol, cond_symbol,
cond_layout.clone(), cond_layout,
ret_layout.clone(), ret_layout,
decider, decider,
jumps, jumps,
); );
@ -1689,7 +1653,7 @@ fn decide_to_branching<'a>(
BranchInfo::Constructor { BranchInfo::Constructor {
scrutinee: inner_cond_symbol, scrutinee: inner_cond_symbol,
layout: inner_cond_layout.clone(), layout: inner_cond_layout,
tag_id, tag_id,
} }
} else { } else {
@ -1704,7 +1668,7 @@ fn decide_to_branching<'a>(
let default_branch_info = if tag_id_sum > 0 && union_size > 0 { let default_branch_info = if tag_id_sum > 0 && union_size > 0 {
BranchInfo::Constructor { BranchInfo::Constructor {
scrutinee: inner_cond_symbol, scrutinee: inner_cond_symbol,
layout: inner_cond_layout.clone(), layout: inner_cond_layout,
tag_id: tag_id_sum as u8, tag_id: tag_id_sum as u8,
} }
} else { } else {
@ -1847,7 +1811,7 @@ fn tree_to_decider(tree: DecisionTree) -> Decider<u64> {
} }
fn to_chain<'a>( fn to_chain<'a>(
path: Path, path: Vec<PathInstruction>,
test: Test<'a>, test: Test<'a>,
success_tree: DecisionTree<'a>, success_tree: DecisionTree<'a>,
failure_tree: DecisionTree<'a>, failure_tree: DecisionTree<'a>,

View file

@ -141,7 +141,7 @@ impl<'a, 'i> Env<'a, 'i> {
tag_id, tag_id,
} => { } => {
self.constructor_map.insert(*scrutinee, *tag_id as u64); self.constructor_map.insert(*scrutinee, *tag_id as u64);
self.layout_map.insert(*scrutinee, layout.clone()); self.layout_map.insert(*scrutinee, *layout);
} }
BranchInfo::None => (), BranchInfo::None => (),
} }
@ -167,7 +167,7 @@ impl<'a, 'i> Env<'a, 'i> {
} }
Closure(arguments, closure_layout, result) => { Closure(arguments, closure_layout, result) => {
let fpointer = Layout::FunctionPointer(arguments, result); let fpointer = Layout::FunctionPointer(arguments, result);
let fields = self.arena.alloc([fpointer, closure_layout.layout.clone()]); let fields = self.arena.alloc([fpointer, *closure_layout.layout]);
self.constructor_map.insert(symbol, 0); self.constructor_map.insert(symbol, 0);
self.layout_map.insert(symbol, Layout::Struct(fields)); self.layout_map.insert(symbol, Layout::Struct(fields));
} }
@ -247,7 +247,7 @@ fn layout_for_constructor<'a>(
} }
Closure(arguments, closure_layout, result) => { Closure(arguments, closure_layout, result) => {
let fpointer = Layout::FunctionPointer(arguments, result); let fpointer = Layout::FunctionPointer(arguments, result);
let fields = arena.alloc([fpointer, closure_layout.layout.clone()]); let fields = arena.alloc([fpointer, *closure_layout.layout]);
HasFields(fields) HasFields(fields)
} }
other => unreachable!("weird layout {:?}", other), other => unreachable!("weird layout {:?}", other),
@ -315,9 +315,9 @@ fn work_for_constructor<'a>(
let alias_symbol = Env::manual_unique_symbol(env.home, env.ident_ids); let alias_symbol = Env::manual_unique_symbol(env.home, env.ident_ids);
let layout = if let Layout::RecursivePointer = field_layout { let layout = if let Layout::RecursivePointer = field_layout {
full_layout.clone() *full_layout
} else { } else {
field_layout.clone() *field_layout
}; };
env.deferred.assignments.push((alias_symbol, expr, layout)); env.deferred.assignments.push((alias_symbol, expr, layout));
@ -375,7 +375,7 @@ pub fn expand_and_cancel_proc<'a>(
} }
Layout::Closure(arguments, closure_layout, result) => { Layout::Closure(arguments, closure_layout, result) => {
let fpointer = Layout::FunctionPointer(arguments, result); let fpointer = Layout::FunctionPointer(arguments, result);
let fields = env.arena.alloc([fpointer, closure_layout.layout.clone()]); let fields = env.arena.alloc([fpointer, *closure_layout.layout]);
env.insert_struct_info(*symbol, fields); env.insert_struct_info(*symbol, fields);
introduced.push(*symbol); introduced.push(*symbol);
} }
@ -412,7 +412,7 @@ fn expand_and_cancel<'a>(env: &mut Env<'a, '_>, stmt: &'a Stmt<'a>) -> &'a Stmt<
let mut result = { let mut result = {
match stmt { match stmt {
Let(mut symbol, expr, layout, cont) => { Let(mut symbol, expr, layout, cont) => {
env.layout_map.insert(symbol, layout.clone()); env.layout_map.insert(symbol, *layout);
let mut expr = expr; let mut expr = expr;
let mut layout = layout; let mut layout = layout;
@ -423,7 +423,7 @@ fn expand_and_cancel<'a>(env: &mut Env<'a, '_>, stmt: &'a Stmt<'a>) -> &'a Stmt<
while !matches!(&expr, Expr::AccessAtIndex { .. } | Expr::Struct(_)) { while !matches!(&expr, Expr::AccessAtIndex { .. } | Expr::Struct(_)) {
if let Stmt::Let(symbol1, expr1, layout1, cont1) = cont { if let Stmt::Let(symbol1, expr1, layout1, cont1) = cont {
literal_stack.push((symbol, expr.clone(), layout.clone())); literal_stack.push((symbol, expr.clone(), *layout));
symbol = *symbol1; symbol = *symbol1;
expr = expr1; expr = expr1;
@ -479,7 +479,7 @@ fn expand_and_cancel<'a>(env: &mut Env<'a, '_>, stmt: &'a Stmt<'a>) -> &'a Stmt<
} }
} }
let stmt = Let(symbol, expr.clone(), layout.clone(), new_cont); let stmt = Let(symbol, expr.clone(), *layout, new_cont);
let mut stmt = &*env.arena.alloc(stmt); let mut stmt = &*env.arena.alloc(stmt);
for (symbol, expr, layout) in literal_stack.into_iter().rev() { for (symbol, expr, layout) in literal_stack.into_iter().rev() {
@ -519,8 +519,8 @@ fn expand_and_cancel<'a>(env: &mut Env<'a, '_>, stmt: &'a Stmt<'a>) -> &'a Stmt<
let stmt = Switch { let stmt = Switch {
cond_symbol: *cond_symbol, cond_symbol: *cond_symbol,
cond_layout: cond_layout.clone(), cond_layout: *cond_layout,
ret_layout: ret_layout.clone(), ret_layout: *ret_layout,
branches: new_branches.into_bump_slice(), branches: new_branches.into_bump_slice(),
default_branch: new_default, default_branch: new_default,
}; };
@ -579,7 +579,7 @@ fn expand_and_cancel<'a>(env: &mut Env<'a, '_>, stmt: &'a Stmt<'a>) -> &'a Stmt<
let stmt = Invoke { let stmt = Invoke {
symbol: *symbol, symbol: *symbol,
call: call.clone(), call: call.clone(),
layout: layout.clone(), layout: *layout,
pass, pass,
fail, fail,
}; };

View file

@ -470,7 +470,7 @@ impl<'a> Context<'a> {
name, full_layout, .. name, full_layout, ..
} => { } => {
// get the borrow signature // get the borrow signature
match self.param_map.get_symbol(*name, full_layout.clone()) { match self.param_map.get_symbol(*name, *full_layout) {
Some(ps) => { Some(ps) => {
let v = Expr::Call(crate::ir::Call { let v = Expr::Call(crate::ir::Call {
call_type, call_type,
@ -695,7 +695,7 @@ impl<'a> Context<'a> {
let pair = ctx.visit_variable_declaration( let pair = ctx.visit_variable_declaration(
*symbol, *symbol,
(*expr).clone(), (*expr).clone(),
(*layout).clone(), *layout,
b, b,
&b_live_vars, &b_live_vars,
); );
@ -712,13 +712,7 @@ impl<'a> Context<'a> {
Let(symbol, expr, layout, cont) => { Let(symbol, expr, layout, cont) => {
let ctx = self.update_var_info(*symbol, layout, expr); let ctx = self.update_var_info(*symbol, layout, expr);
let (b, b_live_vars) = ctx.visit_stmt(cont); let (b, b_live_vars) = ctx.visit_stmt(cont);
ctx.visit_variable_declaration( ctx.visit_variable_declaration(*symbol, expr.clone(), *layout, b, &b_live_vars)
*symbol,
expr.clone(),
layout.clone(),
b,
&b_live_vars,
)
} }
Invoke { Invoke {
@ -759,7 +753,7 @@ impl<'a> Context<'a> {
call: call.clone(), call: call.clone(),
pass, pass,
fail, fail,
layout: layout.clone(), layout: *layout,
}; };
let cont = self.arena.alloc(invoke); let cont = self.arena.alloc(invoke);
@ -783,7 +777,7 @@ impl<'a> Context<'a> {
name, full_layout, .. name, full_layout, ..
} => { } => {
// get the borrow signature // get the borrow signature
match self.param_map.get_symbol(*name, full_layout.clone()) { match self.param_map.get_symbol(*name, *full_layout) {
Some(ps) => self.add_dec_after_application( Some(ps) => self.add_dec_after_application(
call.arguments, call.arguments,
ps, ps,
@ -908,8 +902,8 @@ impl<'a> Context<'a> {
cond_symbol: *cond_symbol, cond_symbol: *cond_symbol,
branches, branches,
default_branch, default_branch,
cond_layout: cond_layout.clone(), cond_layout: *cond_layout,
ret_layout: ret_layout.clone(), ret_layout: *ret_layout,
}); });
(switch, case_live_vars) (switch, case_live_vars)

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,7 @@ pub enum LayoutProblem {
} }
/// Types for code gen must be monomorphic. No type variables allowed! /// Types for code gen must be monomorphic. No type variables allowed!
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Layout<'a> { pub enum Layout<'a> {
Builtin(Builtin<'a>), Builtin(Builtin<'a>),
/// A layout that is empty (turns into the empty struct in LLVM IR /// A layout that is empty (turns into the empty struct in LLVM IR
@ -39,7 +39,7 @@ pub enum Layout<'a> {
Pointer(&'a Layout<'a>), Pointer(&'a Layout<'a>),
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum UnionLayout<'a> { pub enum UnionLayout<'a> {
/// A non-recursive tag union /// A non-recursive tag union
/// e.g. `Result a e : [ Ok a, Err e ]` /// e.g. `Result a e : [ Ok a, Err e ]`
@ -93,7 +93,7 @@ impl<'a> UnionLayout<'a> {
} }
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ClosureLayout<'a> { pub struct ClosureLayout<'a> {
/// the layout that this specific closure captures /// the layout that this specific closure captures
/// uses a Vec instead of a MutMap because it's Hash /// uses a Vec instead of a MutMap because it's Hash
@ -258,7 +258,7 @@ impl<'a> ClosureLayout<'a> {
// define the function pointer // define the function pointer
let function_ptr_layout = { let function_ptr_layout = {
let mut temp = Vec::from_iter_in(argument_layouts.iter().cloned(), arena); let mut temp = Vec::from_iter_in(argument_layouts.iter().cloned(), arena);
temp.push(closure_data_layout.clone()); temp.push(*closure_data_layout);
Layout::FunctionPointer(temp.into_bump_slice(), ret_layout) Layout::FunctionPointer(temp.into_bump_slice(), ret_layout)
}; };
@ -278,8 +278,8 @@ impl<'a> ClosureLayout<'a> {
pub fn as_named_layout(&self, symbol: Symbol) -> Layout<'a> { pub fn as_named_layout(&self, symbol: Symbol) -> Layout<'a> {
let layouts = if self.captured.is_empty() { let layouts = if self.captured.is_empty() {
match self.layout { match self.layout {
Layout::Struct(fields) if fields.len() == 1 => fields[0].clone(), Layout::Struct(fields) if fields.len() == 1 => fields[0],
other => other.clone(), other => *other,
} }
} else if let Some((_, tag_args)) = self } else if let Some((_, tag_args)) = self
.captured .captured
@ -287,7 +287,7 @@ impl<'a> ClosureLayout<'a> {
.find(|(tn, _)| *tn == TagName::Closure(symbol)) .find(|(tn, _)| *tn == TagName::Closure(symbol))
{ {
if tag_args.len() == 1 { if tag_args.len() == 1 {
tag_args[0].clone() tag_args[0]
} else { } else {
Layout::Struct(tag_args) Layout::Struct(tag_args)
} }
@ -303,13 +303,13 @@ impl<'a> ClosureLayout<'a> {
pub fn as_block_of_memory_layout(&self) -> Layout<'a> { pub fn as_block_of_memory_layout(&self) -> Layout<'a> {
match self.layout { match self.layout {
Layout::Struct(fields) if fields.len() == 1 => fields[0].clone(), Layout::Struct(fields) if fields.len() == 1 => fields[0],
other => other.clone(), other => *other,
} }
} }
pub fn internal_layout(&self) -> Layout<'a> { pub fn internal_layout(&self) -> Layout<'a> {
self.layout.clone() *self.layout
} }
pub fn build_closure_data( pub fn build_closure_data(
@ -382,7 +382,7 @@ pub enum MemoryMode {
Refcounted, Refcounted,
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Builtin<'a> { pub enum Builtin<'a> {
Int128, Int128,
Int64, Int64,
@ -825,7 +825,7 @@ impl<'a> LayoutCache<'a> {
// of a problem // of a problem
if false { if false {
let cached_layout = match &result { let cached_layout = match &result {
Ok(layout) => Cached(layout.clone()), Ok(layout) => Cached(*layout),
Err(problem) => Problem(problem.clone()), Err(problem) => Problem(problem.clone()),
}; };
@ -2057,7 +2057,7 @@ impl<'a> LayoutIds<'a> {
// If we had to default to next_id, it must not have been found; // If we had to default to next_id, it must not have been found;
// store the ID we're going to return and increment next_id. // store the ID we're going to return and increment next_id.
if answer == ids.next_id { if answer == ids.next_id {
ids.by_id.insert(layout.clone(), ids.next_id); ids.by_id.insert(*layout, ids.next_id);
ids.next_id += 1; ids.next_id += 1;
} }

View file

@ -13,7 +13,6 @@ pub mod tail_recursion;
// For now, following this warning's advice will lead to nasty type inference errors. // For now, following this warning's advice will lead to nasty type inference errors.
//#[allow(clippy::ptr_arg)] //#[allow(clippy::ptr_arg)]
//pub mod decision_tree; //pub mod decision_tree;
#[allow(clippy::ptr_arg)]
pub mod decision_tree; pub mod decision_tree;
#[allow(clippy::ptr_arg)] #[allow(clippy::ptr_arg)]
pub mod exhaustive; pub mod exhaustive;

View file

@ -42,7 +42,7 @@ pub fn make_tail_recursive<'a>(
let params = Vec::from_iter_in( let params = Vec::from_iter_in(
args.iter().map(|(layout, symbol)| Param { args.iter().map(|(layout, symbol)| Param {
symbol: *symbol, symbol: *symbol,
layout: layout.clone(), layout: *layout,
borrow: true, borrow: true,
}), }),
arena, arena,
@ -117,7 +117,7 @@ fn insert_jumps<'a>(
if opt_cont.is_some() { if opt_cont.is_some() {
let cont = opt_cont.unwrap_or(cont); let cont = opt_cont.unwrap_or(cont);
Some(arena.alloc(Let(*symbol, expr.clone(), layout.clone(), cont))) Some(arena.alloc(Let(*symbol, expr.clone(), *layout, cont)))
} else { } else {
None None
} }
@ -140,7 +140,7 @@ fn insert_jumps<'a>(
let stmt = Invoke { let stmt = Invoke {
symbol: *symbol, symbol: *symbol,
call: call.clone(), call: call.clone(),
layout: layout.clone(), layout: *layout,
pass, pass,
fail, fail,
}; };
@ -222,10 +222,10 @@ fn insert_jumps<'a>(
Some(arena.alloc(Switch { Some(arena.alloc(Switch {
cond_symbol: *cond_symbol, cond_symbol: *cond_symbol,
cond_layout: cond_layout.clone(), cond_layout: *cond_layout,
default_branch, default_branch,
branches, branches,
ret_layout: ret_layout.clone(), ret_layout: *ret_layout,
})) }))
} else { } else {
None None

View file

@ -880,7 +880,7 @@ fn check_for_infinite_type(
let var = loc_var.value; let var = loc_var.value;
let is_uniq_infer = matches!( let is_uniq_infer = matches!(
subs.get(var).content, subs.get_ref(var).content,
Content::Alias(Symbol::ATTR_ATTR, _, _) Content::Alias(Symbol::ATTR_ATTR, _, _)
); );
@ -1088,7 +1088,7 @@ fn generalize(
for vars in all_but_last_pool { for vars in all_but_last_pool {
for &var in vars { for &var in vars {
if !subs.redundant(var) { if !subs.redundant(var) {
let rank = subs.get(var).rank; let rank = subs.get_rank(var);
pools.get_mut(rank).push(var); pools.get_mut(rank).push(var);
} }
@ -1099,13 +1099,12 @@ fn generalize(
// otherwise generalize // otherwise generalize
for &var in last_pool { for &var in last_pool {
if !subs.redundant(var) { if !subs.redundant(var) {
let mut desc = subs.get(var); let desc_rank = subs.get_rank(var);
if desc.rank < young_rank { if desc_rank < young_rank {
pools.get_mut(desc.rank).push(var); pools.get_mut(desc_rank).push(var);
} else { } else {
desc.rank = Rank::NONE; subs.set_rank(var, Rank::NONE);
subs.set(var, desc);
} }
} }
} }
@ -1121,18 +1120,8 @@ fn pool_to_rank_table(
// Sort the variables into buckets by rank. // Sort the variables into buckets by rank.
for &var in young_vars.iter() { for &var in young_vars.iter() {
let desc = subs.get(var); let rank = subs.get_rank(var);
let rank = desc.rank; subs.set_mark(var, young_mark);
subs.set(
var,
Descriptor {
rank,
mark: young_mark,
content: desc.content,
copy: desc.copy,
},
);
debug_assert!(rank.into_usize() < young_rank.into_usize() + 1); debug_assert!(rank.into_usize() < young_rank.into_usize() + 1);
pools.get_mut(rank).push(var); pools.get_mut(rank).push(var);
@ -1155,24 +1144,15 @@ fn adjust_rank(
if desc.mark == young_mark { if desc.mark == young_mark {
let Descriptor { let Descriptor {
content, content,
rank, rank: _,
mark: _, mark: _,
copy, copy,
} = desc; } = desc;
// Mark the variable as visited before adjusting content, as it may be cyclic. // Mark the variable as visited before adjusting content, as it may be cyclic.
subs.set( subs.set_mark(var, visit_mark);
var,
Descriptor {
content: content.clone(),
rank,
mark: visit_mark,
copy,
},
);
let max_rank = let max_rank = adjust_rank_content(subs, young_mark, visit_mark, group_rank, &content);
adjust_rank_content(subs, young_mark, visit_mark, group_rank, content.clone());
subs.set( subs.set(
var, var,
@ -1208,7 +1188,7 @@ fn adjust_rank_content(
young_mark: Mark, young_mark: Mark,
visit_mark: Mark, visit_mark: Mark,
group_rank: Rank, group_rank: Rank,
content: Content, content: &Content,
) -> Rank { ) -> Rank {
use roc_types::subs::Content::*; use roc_types::subs::Content::*;
use roc_types::subs::FlatType::*; use roc_types::subs::FlatType::*;
@ -1224,14 +1204,15 @@ fn adjust_rank_content(
let mut rank = Rank::toplevel(); let mut rank = Rank::toplevel();
for var in args { for var in args {
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); rank =
rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, *var));
} }
rank rank
} }
Func(arg_vars, closure_var, ret_var) => { Func(arg_vars, closure_var, ret_var) => {
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, ret_var); let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ret_var);
// TODO investigate further. // TODO investigate further.
// //
@ -1244,12 +1225,13 @@ fn adjust_rank_content(
young_mark, young_mark,
visit_mark, visit_mark,
group_rank, group_rank,
closure_var, *closure_var,
)); ));
} }
for var in arg_vars { for var in arg_vars {
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); rank =
rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, *var));
} }
rank rank
@ -1263,9 +1245,9 @@ fn adjust_rank_content(
EmptyTagUnion => Rank::toplevel(), EmptyTagUnion => Rank::toplevel(),
Record(fields, ext_var) => { Record(fields, ext_var) => {
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var); let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
for (_, var) in fields { for var in fields.values() {
rank = rank.max(adjust_rank( rank = rank.max(adjust_rank(
subs, subs,
young_mark, young_mark,
@ -1279,7 +1261,7 @@ fn adjust_rank_content(
} }
TagUnion(tags, ext_var) => { TagUnion(tags, ext_var) => {
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, ext_var); let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *ext_var);
for var in tags.values().flatten() { for var in tags.values().flatten() {
rank = rank =
@ -1290,9 +1272,9 @@ fn adjust_rank_content(
} }
RecursiveTagUnion(rec_var, tags, ext_var) => { RecursiveTagUnion(rec_var, tags, ext_var) => {
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, rec_var); let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *rec_var);
rank = rank.max(adjust_rank( rank = rank.max(adjust_rank(
subs, young_mark, visit_mark, group_rank, ext_var, subs, young_mark, visit_mark, group_rank, *ext_var,
)); ));
for var in tags.values().flatten() { for var in tags.values().flatten() {
@ -1305,10 +1287,11 @@ fn adjust_rank_content(
Boolean(Bool::Shared) => Rank::toplevel(), Boolean(Bool::Shared) => Rank::toplevel(),
Boolean(Bool::Container(cvar, mvars)) => { Boolean(Bool::Container(cvar, mvars)) => {
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, cvar); let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, *cvar);
for var in mvars { for var in mvars {
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); rank =
rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, *var));
} }
rank rank
@ -1322,13 +1305,13 @@ fn adjust_rank_content(
let mut rank = Rank::toplevel(); let mut rank = Rank::toplevel();
for (_, var) in args { for (_, var) in args {
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var)); rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, *var));
} }
// from elm-compiler: THEORY: anything in the real_var would be Rank::toplevel() // from elm-compiler: THEORY: anything in the real_var would be Rank::toplevel()
// this theory is not true in Roc! aliases of function types capture the closure var // this theory is not true in Roc! aliases of function types capture the closure var
rank = rank.max(adjust_rank( rank = rank.max(adjust_rank(
subs, young_mark, visit_mark, group_rank, real_var, subs, young_mark, visit_mark, group_rank, *real_var,
)); ));
rank rank

View file

@ -176,7 +176,7 @@ pub fn helper<'a>(
} }
let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) { let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) {
Some(found) => found.clone(), Some(found) => *found,
None => panic!( None => panic!(
"The main function symbol {:?} does not have a procedure in {:?}", "The main function symbol {:?} does not have a procedure in {:?}",
main_fn_symbol, main_fn_symbol,

View file

@ -306,6 +306,18 @@ impl Subs {
self.utable.probe_value(key) self.utable.probe_value(key)
} }
pub fn get_ref(&self, key: Variable) -> &Descriptor {
&self.utable.probe_value_ref(key).value
}
pub fn get_rank(&mut self, key: Variable) -> Rank {
self.utable.probe_value_ref(key).value.rank
}
pub fn get_mark(&mut self, key: Variable) -> Mark {
self.utable.probe_value_ref(key).value.mark
}
pub fn get_without_compacting(&self, key: Variable) -> Descriptor { pub fn get_without_compacting(&self, key: Variable) -> Descriptor {
self.utable.probe_value_without_compacting(key) self.utable.probe_value_without_compacting(key)
} }

View file

@ -1,5 +1,5 @@
[package] [package]
name = "docs" name = "roc_docs"
version = "0.1.0" version = "0.1.0"
authors = ["Pablo Hirafuji <pablohirafuji@gmail.com>"] authors = ["Pablo Hirafuji <pablohirafuji@gmail.com>"]
edition = "2018" edition = "2018"

View file

@ -1,5 +1,4 @@
extern crate fs_extra; extern crate fs_extra;
extern crate handlebars;
extern crate serde; extern crate serde;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
@ -19,26 +18,26 @@ use std::path::{Path, PathBuf};
#[derive(Serialize)] #[derive(Serialize)]
pub struct Template { pub struct Template {
package_name: String, pub package_name: String,
package_version: String, pub package_version: String,
module_name: String, pub module_name: String,
module_docs: String, pub module_docs: String,
module_entries: Vec<ModuleEntry>, pub module_entries: Vec<ModuleEntry>,
module_links: Vec<TemplateLink>, pub module_links: Vec<TemplateLink>,
} }
#[derive(Serialize, Clone, Debug, PartialEq)] #[derive(Serialize, Clone, Debug, PartialEq)]
pub struct ModuleEntry { pub struct ModuleEntry {
name: String, pub name: String,
docs: String, pub docs: String,
} }
#[derive(Serialize)] #[derive(Serialize)]
pub struct TemplateLink { pub struct TemplateLink {
name: String, pub name: String,
href: String, pub href: String,
classes: String, pub classes: String,
entries: Vec<TemplateLinkEntry>, pub entries: Vec<TemplateLinkEntry>,
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -46,27 +45,9 @@ pub struct TemplateLinkEntry {
name: String, name: String,
} }
fn main() { pub fn generate(filenames: Vec<PathBuf>, std_lib: StdLib, build_dir: &Path) {
generate( let files_docs = files_to_documentations(filenames, std_lib);
vec![ //
PathBuf::from(r"../compiler/builtins/docs/Bool.roc"),
PathBuf::from(r"../compiler/builtins/docs/Dict.roc"),
// Not working
// PathBuf::from(r"../compiler/builtins/docs/List.roc"),
// Not working
// PathBuf::from(r"../compiler/builtins/docs/Num.roc"),
PathBuf::from(r"../compiler/builtins/docs/Set.roc"),
PathBuf::from(r"../compiler/builtins/docs/Str.roc"),
],
roc_builtins::std::standard_stdlib(),
Path::new("../compiler/builtins/docs"),
Path::new("./build"),
)
}
pub fn generate(filenames: Vec<PathBuf>, std_lib: StdLib, src_dir: &Path, build_dir: &Path) {
let files_docs = files_to_documentations(filenames, std_lib, src_dir);
// TODO: get info from a file like "elm.json" // TODO: get info from a file like "elm.json"
let package = roc_load::docs::Documentation { let package = roc_load::docs::Documentation {
name: "roc/builtins".to_string(), name: "roc/builtins".to_string(),
@ -75,21 +56,10 @@ pub fn generate(filenames: Vec<PathBuf>, std_lib: StdLib, src_dir: &Path, build_
modules: files_docs, modules: files_docs,
}; };
// Remove old build folder, if exists
let _ = fs::remove_dir_all(build_dir);
let version_folder = build_dir
.join(package.name.clone())
.join(package.version.clone());
// Make sure the output directories exists
fs::create_dir_all(&version_folder)
.expect("TODO gracefully handle creating directories failing");
// Register handlebars template // Register handlebars template
let mut handlebars = handlebars::Handlebars::new(); let mut handlebars = handlebars::Handlebars::new();
handlebars handlebars
.register_template_file("page", "./src/templates/page.hbs") .register_template_file("page", "./docs/src/templates/page.hbs")
.expect("TODO gracefully handle registering template failing"); .expect("TODO gracefully handle registering template failing");
// Write each package's module docs html file // Write each package's module docs html file
@ -97,7 +67,7 @@ pub fn generate(filenames: Vec<PathBuf>, std_lib: StdLib, src_dir: &Path, build_
let template = documentation_to_template_data(&package, module); let template = documentation_to_template_data(&package, module);
let handlebars_data = handlebars::to_json(&template); let handlebars_data = handlebars::to_json(&template);
let filepath = version_folder.join(format!("{}.html", module.name)); let filepath = build_dir.join(format!("{}.html", module.name));
let mut output_file = let mut output_file =
fs::File::create(filepath).expect("TODO gracefully handle creating file failing"); fs::File::create(filepath).expect("TODO gracefully handle creating file failing");
handlebars handlebars
@ -105,34 +75,25 @@ pub fn generate(filenames: Vec<PathBuf>, std_lib: StdLib, src_dir: &Path, build_
.expect("TODO gracefully handle writing file failing"); .expect("TODO gracefully handle writing file failing");
} }
// Copy /static folder content to /build
let copy_options = fs_extra::dir::CopyOptions {
overwrite: true,
skip_exist: false,
buffer_size: 64000, //64kb
copy_inside: false,
content_only: true,
depth: 0,
};
fs_extra::dir::copy("./src/static/", &build_dir, &copy_options)
.expect("TODO gracefully handle copying static content failing");
println!("Docs generated at {}", build_dir.display()); println!("Docs generated at {}", build_dir.display());
} }
fn files_to_documentations( pub fn files_to_documentations(
filenames: Vec<PathBuf>, filenames: Vec<PathBuf>,
std_lib: StdLib, std_lib: StdLib,
src_dir: &Path,
) -> Vec<ModuleDocumentation> { ) -> Vec<ModuleDocumentation> {
let arena = Bump::new(); let arena = Bump::new();
let mut files_docs = vec![]; let mut files_docs = vec![];
for filename in filenames { for filename in filenames {
let mut src_dir = filename.clone();
src_dir.pop();
match roc_load::file::load_and_typecheck( match roc_load::file::load_and_typecheck(
&arena, &arena,
filename, filename,
&std_lib, &std_lib,
src_dir, src_dir.as_path(),
MutMap::default(), MutMap::default(),
8, // TODO: Is it okay to hardcode ptr_bytes here? I think it should be fine since we'er only type checking (also, 8 => 32bit system) 8, // TODO: Is it okay to hardcode ptr_bytes here? I think it should be fine since we'er only type checking (also, 8 => 32bit system)
builtin_defs_map, builtin_defs_map,
@ -148,7 +109,10 @@ fn files_to_documentations(
files_docs files_docs
} }
fn documentation_to_template_data(doc: &Documentation, module: &ModuleDocumentation) -> Template { pub fn documentation_to_template_data(
doc: &Documentation,
module: &ModuleDocumentation,
) -> Template {
Template { Template {
package_name: doc.name.clone(), package_name: doc.name.clone(),
package_version: doc.version.clone(), package_version: doc.version.clone(),
@ -248,51 +212,3 @@ fn markdown_to_html(markdown: String) -> String {
pulldown_cmark::html::push_html(&mut docs_html, docs_parser.into_iter()); pulldown_cmark::html::push_html(&mut docs_html, docs_parser.into_iter());
docs_html docs_html
} }
#[cfg(test)]
mod test_docs {
use super::*;
#[test]
fn internal() {
let files_docs = files_to_documentations(
vec![PathBuf::from(r"tests/fixtures/Interface.roc")],
roc_builtins::std::standard_stdlib(),
Path::new("tests/fixtures"),
);
let package = roc_load::docs::Documentation {
name: "roc/builtins".to_string(),
version: "1.0.0".to_string(),
docs: "Package introduction or README.".to_string(),
modules: files_docs,
};
let expected_entries = vec![
ModuleEntry {
name: "singleline".to_string(),
docs: "<p>Single line documentation.</p>\n".to_string(),
},
ModuleEntry {
name: "multiline".to_string(),
docs: "<p>Multiline documentation.\nWithout any complex syntax yet!</p>\n".to_string(),
}, ModuleEntry {
name: "multiparagraph".to_string(),
docs: "<p>Multiparagraph documentation.</p>\n<p>Without any complex syntax yet!</p>\n".to_string(),
}, ModuleEntry {
name: "codeblock".to_string(),
docs: "<p>Turns &gt;&gt;&gt; into code block for now.</p>\n<pre><code class=\"language-roc\">codeblock</code></pre>\n".to_string(),
},
];
for module in &package.modules {
let template = documentation_to_template_data(&package, module);
assert_eq!(template.module_name, "Test");
template
.module_entries
.iter()
.zip(expected_entries.iter())
.for_each(|(x, y)| assert_eq!(x, y));
}
}
}

49
docs/tests/test_docs.rs Normal file
View file

@ -0,0 +1,49 @@
use roc_docs::{documentation_to_template_data, files_to_documentations, ModuleEntry};
use std::path::{Path, PathBuf};
#[cfg(test)]
mod test_docs {
use super::*;
#[test]
fn internal() {
let files_docs = files_to_documentations(
vec![PathBuf::from(r"tests/fixtures/Interface.roc")],
roc_builtins::std::standard_stdlib(),
);
let package = roc_load::docs::Documentation {
name: "roc/builtins".to_string(),
version: "1.0.0".to_string(),
docs: "Package introduction or README.".to_string(),
modules: files_docs,
};
let expected_entries = vec![
ModuleEntry {
name: "singleline".to_string(),
docs: "<p>Single line documentation.</p>\n".to_string(),
},
ModuleEntry {
name: "multiline".to_string(),
docs: "<p>Multiline documentation.\nWithout any complex syntax yet!</p>\n".to_string(),
}, ModuleEntry {
name: "multiparagraph".to_string(),
docs: "<p>Multiparagraph documentation.</p>\n<p>Without any complex syntax yet!</p>\n".to_string(),
}, ModuleEntry {
name: "codeblock".to_string(),
docs: "<p>Turns &gt;&gt;&gt; into code block for now.</p>\n<pre><code class=\"language-roc\">codeblock</code></pre>\n".to_string(),
},
];
for module in &package.modules {
let template = documentation_to_template_data(&package, module);
assert_eq!(template.module_name, "Test");
template
.module_entries
.iter()
.zip(expected_entries.iter())
.for_each(|(x, y)| assert_eq!(x, y));
}
}
}

View file

@ -433,6 +433,17 @@ where
self.value(id).value.clone() self.value(id).value.clone()
} }
/// Returns the current value for the given key. If the key has
/// been union'd, this will give the value from the current root.
pub fn probe_value_ref<K1>(&self, id: K1) -> &VarValue<K>
where
K1: Into<K>,
{
let id = id.into();
let id = self.get_root_key_without_compacting(id);
self.value(id)
}
/// This is for a debug_assert! in solve() only. Do not use it elsewhere! /// This is for a debug_assert! in solve() only. Do not use it elsewhere!
pub fn probe_value_without_compacting<K1>(&self, id: K1) -> V pub fn probe_value_without_compacting<K1>(&self, id: K1) -> V
where where