mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
Merge branch 'trunk' of github.com:rtfeldman/roc into list-str-capacity
This commit is contained in:
commit
456d8ff9cb
41 changed files with 790 additions and 210 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -1770,13 +1770,13 @@ dependencies = [
|
|||
name = "inkwell"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"inkwell 0.1.0 (git+https://github.com/rtfeldman/inkwell?tag=llvm13-0.release1)",
|
||||
"inkwell 0.1.0 (git+https://github.com/rtfeldman/inkwell?branch=master)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inkwell"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rtfeldman/inkwell?tag=llvm13-0.release1#e15d665227b2acad4ca949820d80048e09f3f4e5"
|
||||
source = "git+https://github.com/rtfeldman/inkwell?branch=master#b3fb82c653ffe754e078ac778d7fd9a619a26c0c"
|
||||
dependencies = [
|
||||
"either",
|
||||
"inkwell_internals",
|
||||
|
@ -1789,7 +1789,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "inkwell_internals"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/rtfeldman/inkwell?tag=llvm13-0.release1#e15d665227b2acad4ca949820d80048e09f3f4e5"
|
||||
source = "git+https://github.com/rtfeldman/inkwell?branch=master#b3fb82c653ffe754e078ac778d7fd9a619a26c0c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -1511,6 +1511,16 @@ fn expr_spec<'a>(
|
|||
|
||||
builder.add_make_named(block, MOD_APP, type_name, tag_value_id)
|
||||
}
|
||||
ExprBox { symbol } => {
|
||||
let value_id = env.symbols[symbol];
|
||||
|
||||
with_new_heap_cell(builder, block, value_id)
|
||||
}
|
||||
ExprUnbox { symbol } => {
|
||||
let tuple_id = env.symbols[symbol];
|
||||
|
||||
builder.add_get_tuple_field(block, tuple_id, BOX_VALUE_INDEX)
|
||||
}
|
||||
Struct(fields) => build_tuple_value(builder, env, block, fields),
|
||||
UnionAtIndex {
|
||||
index,
|
||||
|
@ -1705,6 +1715,13 @@ fn layout_spec_help(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Boxed(inner_layout) => {
|
||||
let inner_type = layout_spec_help(builder, inner_layout, when_recursive)?;
|
||||
let cell_type = builder.add_heap_cell_type();
|
||||
|
||||
builder.add_tuple_type(&[cell_type, inner_type])
|
||||
}
|
||||
RecursivePointer => match when_recursive {
|
||||
WhenRecursive::Unreachable => {
|
||||
unreachable!()
|
||||
|
@ -1787,6 +1804,10 @@ const LIST_BAG_INDEX: u32 = 1;
|
|||
const DICT_CELL_INDEX: u32 = LIST_CELL_INDEX;
|
||||
const DICT_BAG_INDEX: u32 = LIST_BAG_INDEX;
|
||||
|
||||
#[allow(dead_code)]
|
||||
const BOX_CELL_INDEX: u32 = LIST_CELL_INDEX;
|
||||
const BOX_VALUE_INDEX: u32 = LIST_BAG_INDEX;
|
||||
|
||||
const TAG_CELL_INDEX: u32 = 0;
|
||||
const TAG_DATA_INDEX: u32 = 1;
|
||||
|
||||
|
|
|
@ -890,14 +890,23 @@ pub fn listSublist(
|
|||
}
|
||||
|
||||
const keep_len = std.math.min(len, size - start);
|
||||
const drop_len = std.math.max(start, 0);
|
||||
const drop_start_len = start;
|
||||
const drop_end_len = size - (start + keep_len);
|
||||
|
||||
// Decrement the reference counts of elements before `start`.
|
||||
var i: usize = 0;
|
||||
while (i < drop_len) : (i += 1) {
|
||||
while (i < drop_start_len) : (i += 1) {
|
||||
const element = source_ptr + i * element_width;
|
||||
dec(element);
|
||||
}
|
||||
|
||||
// Decrement the reference counts of elements after `start + keep_len`.
|
||||
i = 0;
|
||||
while (i < drop_end_len) : (i += 1) {
|
||||
const element = source_ptr + (start + keep_len + i) * element_width;
|
||||
dec(element);
|
||||
}
|
||||
|
||||
const output = RocList.allocate(alignment, keep_len, element_width);
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@ use roc_module::ident::TagName;
|
|||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::Region;
|
||||
use roc_types::builtin_aliases::{
|
||||
bool_type, dec_type, dict_type, f32_type, f64_type, float_type, i128_type, i16_type, i32_type,
|
||||
i64_type, i8_type, int_type, list_type, nat_type, num_type, ordering_type, result_type,
|
||||
set_type, str_type, str_utf8_byte_problem_type, u128_type, u16_type, u32_type, u64_type,
|
||||
u8_type,
|
||||
bool_type, box_type, dec_type, dict_type, f32_type, f64_type, float_type, i128_type, i16_type,
|
||||
i32_type, i64_type, i8_type, int_type, list_type, nat_type, num_type, ordering_type,
|
||||
result_type, set_type, str_type, str_utf8_byte_problem_type, u128_type, u16_type, u32_type,
|
||||
u64_type, u8_type,
|
||||
};
|
||||
use roc_types::solved_types::SolvedType;
|
||||
use roc_types::subs::VarId;
|
||||
|
@ -1782,6 +1782,20 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
|||
Box::new(bool_type()),
|
||||
);
|
||||
|
||||
// Box.box : a -> Box a
|
||||
add_top_level_function_type!(
|
||||
Symbol::BOX_BOX_FUNCTION,
|
||||
vec![flex(TVAR1)],
|
||||
Box::new(box_type(flex(TVAR1))),
|
||||
);
|
||||
|
||||
// Box.unbox : Box a -> a
|
||||
add_top_level_function_type!(
|
||||
Symbol::BOX_UNBOX,
|
||||
vec![box_type(flex(TVAR1))],
|
||||
Box::new(flex(TVAR1)),
|
||||
);
|
||||
|
||||
types
|
||||
}
|
||||
|
||||
|
|
|
@ -271,6 +271,8 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
RESULT_WITH_DEFAULT => result_with_default,
|
||||
RESULT_IS_OK => result_is_ok,
|
||||
RESULT_IS_ERR => result_is_err,
|
||||
BOX_BOX_FUNCTION => box_box,
|
||||
BOX_UNBOX => box_unbox,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5326,6 +5328,16 @@ fn num_bytes_to(symbol: Symbol, var_store: &mut VarStore, offset: i64, low_level
|
|||
)
|
||||
}
|
||||
|
||||
/// Box.box : a -> Box a
|
||||
fn box_box(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_1(symbol, LowLevel::BoxExpr, var_store)
|
||||
}
|
||||
|
||||
/// Box.unbox : Box a -> a
|
||||
fn box_unbox(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
lowlevel_1(symbol, LowLevel::UnboxExpr, var_store)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn defn_help(
|
||||
fn_name: Symbol,
|
||||
|
|
|
@ -117,6 +117,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
) {
|
||||
use self::Expr::*;
|
||||
|
||||
//dbg!(self);
|
||||
let format_newlines = newlines == Newlines::Yes;
|
||||
let apply_needs_parens = parens == Parens::InApply;
|
||||
|
||||
|
@ -453,14 +454,17 @@ fn fmt_bin_ops<'a, 'buf>(
|
|||
|| (&loc_right_side.value).is_multiline()
|
||||
|| lefts.iter().any(|(expr, _)| expr.value.is_multiline());
|
||||
|
||||
let mut curr_indent = indent;
|
||||
|
||||
for (loc_left_side, loc_bin_op) in lefts {
|
||||
let bin_op = loc_bin_op.value;
|
||||
|
||||
loc_left_side.format_with_options(buf, apply_needs_parens, Newlines::No, indent);
|
||||
loc_left_side.format_with_options(buf, apply_needs_parens, Newlines::No, curr_indent);
|
||||
|
||||
if is_multiline {
|
||||
buf.newline();
|
||||
buf.indent(indent + INDENT);
|
||||
curr_indent = indent + INDENT;
|
||||
buf.indent(curr_indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
|
|
@ -2595,7 +2595,7 @@ mod test_fmt {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn pipline_apply_lambda() {
|
||||
fn pipline_apply_lambda_1() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
shout
|
||||
|
@ -2606,6 +2606,19 @@ mod test_fmt {
|
|||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pipline_apply_lambda_2() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
shout
|
||||
|> List.map
|
||||
xs
|
||||
(\i -> i)
|
||||
|> List.join
|
||||
"#
|
||||
));
|
||||
}
|
||||
|
||||
// MODULES
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -875,6 +875,12 @@ trait Backend<'a> {
|
|||
self.set_last_seen(*sym, stmt);
|
||||
}
|
||||
}
|
||||
Expr::ExprBox { symbol } => {
|
||||
self.set_last_seen(*symbol, stmt);
|
||||
}
|
||||
Expr::ExprUnbox { symbol } => {
|
||||
self.set_last_seen(*symbol, stmt);
|
||||
}
|
||||
Expr::Struct(syms) => {
|
||||
for sym in *syms {
|
||||
self.set_last_seen(*sym, stmt);
|
||||
|
|
|
@ -260,8 +260,12 @@ fn build_has_tag_id_help<'a, 'ctx, 'env>(
|
|||
tag_value.into(),
|
||||
);
|
||||
|
||||
env.builder
|
||||
.build_int_cast(tag_id_i64, env.context.i16_type(), "to_i16")
|
||||
env.builder.build_int_cast_sign_flag(
|
||||
tag_id_i64,
|
||||
env.context.i16_type(),
|
||||
true,
|
||||
"to_i16",
|
||||
)
|
||||
};
|
||||
|
||||
let answer = env.builder.build_int_compare(
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::llvm::build_str::{
|
|||
};
|
||||
use crate::llvm::compare::{generic_eq, generic_neq};
|
||||
use crate::llvm::convert::{
|
||||
self, basic_type_from_builtin, basic_type_from_layout, basic_type_from_layout_1,
|
||||
self, argument_type_from_layout, basic_type_from_builtin, basic_type_from_layout,
|
||||
block_of_memory_slices, zig_str_type,
|
||||
};
|
||||
use crate::llvm::refcounting::{
|
||||
|
@ -1100,6 +1100,30 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
..
|
||||
} => build_tag(env, scope, union_layout, *tag_id, arguments, None, parent),
|
||||
|
||||
ExprBox { symbol } => {
|
||||
let (value, layout) = load_symbol_and_layout(scope, symbol);
|
||||
let basic_type = basic_type_from_layout(env, layout);
|
||||
let allocation = reserve_with_refcount_help(
|
||||
env,
|
||||
basic_type,
|
||||
layout.stack_size(env.target_info),
|
||||
layout.alignment_bytes(env.target_info),
|
||||
);
|
||||
|
||||
env.builder.build_store(allocation, value);
|
||||
|
||||
allocation.into()
|
||||
}
|
||||
|
||||
ExprUnbox { symbol } => {
|
||||
let value = load_symbol(scope, symbol);
|
||||
|
||||
debug_assert!(value.is_pointer_value());
|
||||
|
||||
env.builder
|
||||
.build_load(value.into_pointer_value(), "load_boxed_value")
|
||||
}
|
||||
|
||||
Reset { symbol, .. } => {
|
||||
let (tag_ptr, layout) = load_symbol_and_layout(scope, symbol);
|
||||
let tag_ptr = tag_ptr.into_pointer_value();
|
||||
|
@ -1798,7 +1822,7 @@ pub fn tag_pointer_read_tag_id<'a, 'ctx, 'env>(
|
|||
let masked = env.builder.build_and(as_int, mask_intval, "mask");
|
||||
|
||||
env.builder
|
||||
.build_int_cast(masked, env.context.i8_type(), "to_u8")
|
||||
.build_int_cast_sign_flag(masked, env.context.i8_type(), false, "to_u8")
|
||||
}
|
||||
|
||||
pub fn tag_pointer_clear_tag_id<'a, 'ctx, 'env>(
|
||||
|
@ -2553,6 +2577,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
|||
let align_bytes = layout.alignment_bytes(env.target_info);
|
||||
|
||||
if align_bytes > 0 {
|
||||
debug_assert!(value.is_pointer_value(), "{:?}\n{:?}", value, layout);
|
||||
let value_ptr = value.into_pointer_value();
|
||||
|
||||
// We can only do this if the function itself writes data into this
|
||||
|
@ -4197,7 +4222,7 @@ fn build_proc_header<'a, 'ctx, 'env>(
|
|||
let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena);
|
||||
|
||||
for (layout, _) in args.iter() {
|
||||
let arg_type = basic_type_from_layout_1(env, layout);
|
||||
let arg_type = argument_type_from_layout(env, layout);
|
||||
|
||||
arg_basic_types.push(arg_type);
|
||||
}
|
||||
|
@ -5864,8 +5889,11 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
let arg = load_symbol(scope, &args[0]).into_int_value();
|
||||
|
||||
let to = basic_type_from_layout(env, layout).into_int_type();
|
||||
let to_signed = intwidth_from_layout(*layout).is_signed();
|
||||
|
||||
env.builder.build_int_cast(arg, to, "inc_cast").into()
|
||||
env.builder
|
||||
.build_int_cast_sign_flag(arg, to, to_signed, "inc_cast")
|
||||
.into()
|
||||
}
|
||||
Eq => {
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
@ -6091,6 +6119,10 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
unreachable!("these are higher order, and are handled elsewhere")
|
||||
}
|
||||
|
||||
BoxExpr | UnboxExpr => {
|
||||
unreachable!("The {:?} operation is turned into mono Expr", op)
|
||||
}
|
||||
|
||||
PtrCast | RefCountInc | RefCountDec => {
|
||||
unreachable!("Not used in LLVM backend: {:?}", op);
|
||||
}
|
||||
|
@ -6969,7 +7001,12 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
|||
let target_int_type = convert::int_type_from_int_width(env, target_int_width);
|
||||
let target_int_val: BasicValueEnum<'ctx> = env
|
||||
.builder
|
||||
.build_int_cast(arg, target_int_type, "int_cast")
|
||||
.build_int_cast_sign_flag(
|
||||
arg,
|
||||
target_int_type,
|
||||
target_int_width.is_signed(),
|
||||
"int_cast",
|
||||
)
|
||||
.into();
|
||||
|
||||
let return_type =
|
||||
|
|
|
@ -67,7 +67,12 @@ pub fn dict_len<'a, 'ctx, 'env>(
|
|||
);
|
||||
|
||||
env.builder
|
||||
.build_int_cast(length_i64.into_int_value(), env.ptr_int(), "to_usize")
|
||||
.build_int_cast_sign_flag(
|
||||
length_i64.into_int_value(),
|
||||
env.ptr_int(),
|
||||
false,
|
||||
"to_usize",
|
||||
)
|
||||
.into()
|
||||
}
|
||||
_ => unreachable!("Invalid layout given to Dict.len : {:?}", dict_layout),
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::llvm::build::tag_pointer_clear_tag_id;
|
|||
use crate::llvm::build::Env;
|
||||
use crate::llvm::build::{get_tag_id, FAST_CALL_CONV, TAG_DATA_INDEX};
|
||||
use crate::llvm::build_str;
|
||||
use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1};
|
||||
use crate::llvm::convert::basic_type_from_layout;
|
||||
use bumpalo::collections::Vec;
|
||||
use inkwell::values::{
|
||||
BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue,
|
||||
|
@ -13,6 +13,8 @@ use roc_builtins::bitcode;
|
|||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
|
||||
use super::convert::argument_type_from_union_layout;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum WhenRecursive<'a> {
|
||||
Unreachable,
|
||||
|
@ -68,8 +70,11 @@ fn build_hash_layout<'a, 'ctx, 'env>(
|
|||
when_recursive,
|
||||
),
|
||||
|
||||
Layout::Union(union_layout) => {
|
||||
build_hash_tag(env, layout_ids, layout, union_layout, seed, val)
|
||||
Layout::Union(union_layout) => build_hash_tag(env, layout_ids, union_layout, seed, val),
|
||||
|
||||
Layout::Boxed(_inner_layout) => {
|
||||
// build_hash_box(env, layout_ids, layout, inner_layout, seed, val)
|
||||
todo!()
|
||||
}
|
||||
|
||||
Layout::RecursivePointer => match when_recursive {
|
||||
|
@ -87,14 +92,7 @@ fn build_hash_layout<'a, 'ctx, 'env>(
|
|||
.build_bitcast(val, bt, "i64_to_opaque")
|
||||
.into_pointer_value();
|
||||
|
||||
build_hash_tag(
|
||||
env,
|
||||
layout_ids,
|
||||
&layout,
|
||||
&union_layout,
|
||||
seed,
|
||||
field_cast.into(),
|
||||
)
|
||||
build_hash_tag(env, layout_ids, &union_layout, seed, field_cast.into())
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -308,7 +306,6 @@ fn hash_struct<'a, 'ctx, 'env>(
|
|||
fn build_hash_tag<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
layout: &Layout<'a>,
|
||||
union_layout: &UnionLayout<'a>,
|
||||
seed: IntValue<'ctx>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
|
@ -318,7 +315,7 @@ fn build_hash_tag<'a, 'ctx, 'env>(
|
|||
|
||||
let symbol = Symbol::GENERIC_HASH;
|
||||
let fn_name = layout_ids
|
||||
.get(symbol, layout)
|
||||
.get(symbol, &Layout::Union(*union_layout))
|
||||
.to_symbol_string(symbol, &env.interns);
|
||||
|
||||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
|
@ -326,7 +323,7 @@ fn build_hash_tag<'a, 'ctx, 'env>(
|
|||
None => {
|
||||
let seed_type = env.context.i64_type();
|
||||
|
||||
let arg_type = basic_type_from_layout_1(env, layout);
|
||||
let arg_type = argument_type_from_union_layout(env, union_layout);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
|
@ -805,7 +802,7 @@ fn hash_ptr_to_struct<'a, 'ctx, 'env>(
|
|||
) -> IntValue<'ctx> {
|
||||
use inkwell::types::BasicType;
|
||||
|
||||
let wrapper_type = basic_type_from_layout_1(env, &Layout::Union(*union_layout));
|
||||
let wrapper_type = argument_type_from_union_layout(env, union_layout);
|
||||
|
||||
// cast the opaque pointer to a pointer of the correct shape
|
||||
let wrapper_ptr = env
|
||||
|
|
|
@ -82,7 +82,7 @@ fn pass_element_as_opaque<'a, 'ctx, 'env>(
|
|||
env.builder.build_bitcast(
|
||||
element_ptr,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"to_opaque",
|
||||
"pass_element_as_opaque",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ pub fn pass_as_opaque<'a, 'ctx, 'env>(
|
|||
env.builder.build_bitcast(
|
||||
ptr,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"to_opaque",
|
||||
"pass_as_opaque",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -434,10 +434,19 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
|
|||
ListWalk::WalkBackwardsUntil => todo!(),
|
||||
};
|
||||
|
||||
let default_ptr = if default_layout.is_passed_by_reference() {
|
||||
debug_assert!(default.is_pointer_value());
|
||||
default.into_pointer_value()
|
||||
} else {
|
||||
let default_ptr = builder.build_alloca(default.get_type(), "default_ptr");
|
||||
env.builder.build_store(default_ptr, default);
|
||||
default_ptr
|
||||
};
|
||||
|
||||
let result_ptr = env.builder.build_alloca(default.get_type(), "result");
|
||||
let result_ptr = {
|
||||
let basic_type = basic_type_from_layout(env, default_layout);
|
||||
env.builder.build_alloca(basic_type, "result")
|
||||
};
|
||||
|
||||
match variant {
|
||||
ListWalk::Walk | ListWalk::WalkBackwards => {
|
||||
|
@ -494,7 +503,11 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
if default_layout.is_passed_by_reference() {
|
||||
result_ptr.into()
|
||||
} else {
|
||||
env.builder.build_load(result_ptr, "load_result")
|
||||
}
|
||||
}
|
||||
|
||||
/// List.range : Int a, Int a -> List (Int a)
|
||||
|
|
|
@ -170,7 +170,7 @@ pub fn str_number_of_bytes<'a, 'ctx, 'env>(
|
|||
|
||||
// cast to the appropriate usize of the current build
|
||||
env.builder
|
||||
.build_int_cast(length, env.ptr_int(), "len_as_usize")
|
||||
.build_int_cast_sign_flag(length, env.ptr_int(), false, "len_as_usize")
|
||||
}
|
||||
|
||||
/// Str.startsWith : Str, Str -> Bool
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::llvm::bitcode::call_bitcode_fn;
|
|||
use crate::llvm::build::{get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV};
|
||||
use crate::llvm::build_list::{list_len, load_list_ptr};
|
||||
use crate::llvm::build_str::str_equal;
|
||||
use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1};
|
||||
use crate::llvm::convert::basic_type_from_layout;
|
||||
use bumpalo::collections::Vec;
|
||||
use inkwell::types::BasicType;
|
||||
use inkwell::values::{
|
||||
|
@ -15,6 +15,7 @@ use roc_module::symbol::Symbol;
|
|||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
|
||||
use super::build::load_roc_value;
|
||||
use super::convert::argument_type_from_union_layout;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum WhenRecursive<'a> {
|
||||
|
@ -176,12 +177,21 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
env,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
lhs_layout,
|
||||
union_layout,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
),
|
||||
|
||||
Layout::Boxed(inner_layout) => build_box_eq(
|
||||
env,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
lhs_layout,
|
||||
inner_layout,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
),
|
||||
|
||||
Layout::RecursivePointer => match when_recursive {
|
||||
WhenRecursive::Unreachable => {
|
||||
unreachable!("recursion pointers should never be compared directly")
|
||||
|
@ -207,7 +217,6 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
env,
|
||||
layout_ids,
|
||||
WhenRecursive::Loop(union_layout),
|
||||
&layout,
|
||||
&union_layout,
|
||||
field1_cast.into(),
|
||||
field2_cast.into(),
|
||||
|
@ -345,12 +354,12 @@ fn build_neq<'a, 'ctx, 'env>(
|
|||
|
||||
result.into()
|
||||
}
|
||||
|
||||
Layout::Union(union_layout) => {
|
||||
let is_equal = build_tag_eq(
|
||||
env,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
lhs_layout,
|
||||
union_layout,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
|
@ -362,6 +371,23 @@ fn build_neq<'a, 'ctx, 'env>(
|
|||
result.into()
|
||||
}
|
||||
|
||||
Layout::Boxed(inner_layout) => {
|
||||
let is_equal = build_box_eq(
|
||||
env,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
lhs_layout,
|
||||
inner_layout,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
)
|
||||
.into_int_value();
|
||||
|
||||
let result: IntValue = env.builder.build_not(is_equal, "negate");
|
||||
|
||||
result.into()
|
||||
}
|
||||
|
||||
Layout::RecursivePointer => {
|
||||
unreachable!("recursion pointers should never be compared directly")
|
||||
}
|
||||
|
@ -764,7 +790,6 @@ fn build_tag_eq<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
tag_layout: &Layout<'a>,
|
||||
union_layout: &UnionLayout<'a>,
|
||||
tag1: BasicValueEnum<'ctx>,
|
||||
tag2: BasicValueEnum<'ctx>,
|
||||
|
@ -772,15 +797,16 @@ fn build_tag_eq<'a, 'ctx, 'env>(
|
|||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||
|
||||
let tag_layout = Layout::Union(*union_layout);
|
||||
let symbol = Symbol::GENERIC_EQ;
|
||||
let fn_name = layout_ids
|
||||
.get(symbol, tag_layout)
|
||||
.get(symbol, &tag_layout)
|
||||
.to_symbol_string(symbol, &env.interns);
|
||||
|
||||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let arg_type = basic_type_from_layout_1(env, tag_layout);
|
||||
let arg_type = argument_type_from_union_layout(env, union_layout);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
|
@ -1101,8 +1127,10 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
let i8_type = env.context.i8_type();
|
||||
|
||||
let sum = env.builder.build_int_add(
|
||||
env.builder.build_int_cast(is_null_1, i8_type, "to_u8"),
|
||||
env.builder.build_int_cast(is_null_2, i8_type, "to_u8"),
|
||||
env.builder
|
||||
.build_int_cast_sign_flag(is_null_1, i8_type, false, "to_u8"),
|
||||
env.builder
|
||||
.build_int_cast_sign_flag(is_null_2, i8_type, false, "to_u8"),
|
||||
"sum_is_null",
|
||||
);
|
||||
|
||||
|
@ -1252,3 +1280,141 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
|||
)
|
||||
.into_int_value()
|
||||
}
|
||||
|
||||
/// ----
|
||||
|
||||
fn build_box_eq<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
box_layout: &Layout<'a>,
|
||||
inner_layout: &Layout<'a>,
|
||||
tag1: BasicValueEnum<'ctx>,
|
||||
tag2: BasicValueEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||
|
||||
let symbol = Symbol::GENERIC_EQ;
|
||||
let fn_name = layout_ids
|
||||
.get(symbol, box_layout)
|
||||
.to_symbol_string(symbol, &env.interns);
|
||||
|
||||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let arg_type = basic_type_from_layout(env, box_layout);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
&fn_name,
|
||||
env.context.bool_type().into(),
|
||||
&[arg_type, arg_type],
|
||||
);
|
||||
|
||||
build_box_eq_help(
|
||||
env,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
function_value,
|
||||
inner_layout,
|
||||
);
|
||||
|
||||
function_value
|
||||
}
|
||||
};
|
||||
|
||||
env.builder.position_at_end(block);
|
||||
env.builder
|
||||
.set_current_debug_location(env.context, di_location);
|
||||
let call = env
|
||||
.builder
|
||||
.build_call(function, &[tag1.into(), tag2.into()], "tag_eq");
|
||||
|
||||
call.set_call_convention(FAST_CALL_CONV);
|
||||
|
||||
call.try_as_basic_value().left().unwrap()
|
||||
}
|
||||
|
||||
fn build_box_eq_help<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
inner_layout: &Layout<'a>,
|
||||
) {
|
||||
let ctx = env.context;
|
||||
let builder = env.builder;
|
||||
|
||||
{
|
||||
use inkwell::debug_info::AsDIScope;
|
||||
|
||||
let func_scope = parent.get_subprogram().unwrap();
|
||||
let lexical_block = env.dibuilder.create_lexical_block(
|
||||
/* scope */ func_scope.as_debug_info_scope(),
|
||||
/* file */ env.compile_unit.get_file(),
|
||||
/* line_no */ 0,
|
||||
/* column_no */ 0,
|
||||
);
|
||||
|
||||
let loc = env.dibuilder.create_debug_location(
|
||||
ctx,
|
||||
/* line */ 0,
|
||||
/* column */ 0,
|
||||
/* current_scope */ lexical_block.as_debug_info_scope(),
|
||||
/* inlined_at */ None,
|
||||
);
|
||||
builder.set_current_debug_location(ctx, loc);
|
||||
}
|
||||
|
||||
// Add args to scope
|
||||
let mut it = parent.get_param_iter();
|
||||
let box1 = it.next().unwrap();
|
||||
let box2 = it.next().unwrap();
|
||||
|
||||
box1.set_name(Symbol::ARG_1.as_str(&env.interns));
|
||||
box2.set_name(Symbol::ARG_2.as_str(&env.interns));
|
||||
|
||||
let return_true = ctx.append_basic_block(parent, "return_true");
|
||||
env.builder.position_at_end(return_true);
|
||||
env.builder
|
||||
.build_return(Some(&env.context.bool_type().const_all_ones()));
|
||||
|
||||
let entry = ctx.append_basic_block(parent, "entry");
|
||||
env.builder.position_at_end(entry);
|
||||
|
||||
let ptr_equal = env.builder.build_int_compare(
|
||||
IntPredicate::EQ,
|
||||
env.builder
|
||||
.build_ptr_to_int(box1.into_pointer_value(), env.ptr_int(), "pti"),
|
||||
env.builder
|
||||
.build_ptr_to_int(box2.into_pointer_value(), env.ptr_int(), "pti"),
|
||||
"compare_pointers",
|
||||
);
|
||||
|
||||
let compare_inner_value = ctx.append_basic_block(parent, "compare_inner_value");
|
||||
|
||||
env.builder
|
||||
.build_conditional_branch(ptr_equal, return_true, compare_inner_value);
|
||||
|
||||
env.builder.position_at_end(compare_inner_value);
|
||||
|
||||
// clear the tag_id so we get a pointer to the actual data
|
||||
let box1 = box1.into_pointer_value();
|
||||
let box2 = box2.into_pointer_value();
|
||||
|
||||
let value1 = env.builder.build_load(box1, "load_box1");
|
||||
let value2 = env.builder.build_load(box2, "load_box2");
|
||||
|
||||
let is_equal = build_eq(
|
||||
env,
|
||||
layout_ids,
|
||||
value1,
|
||||
value2,
|
||||
inner_layout,
|
||||
inner_layout,
|
||||
when_recursive,
|
||||
);
|
||||
|
||||
env.builder.build_return(Some(&is_equal));
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::llvm::build::Env;
|
||||
use bumpalo::collections::Vec;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::types::{BasicType, BasicTypeEnum, FloatType, IntType, StructType};
|
||||
|
@ -7,7 +8,7 @@ use roc_mono::layout::{Builtin, Layout, UnionLayout};
|
|||
use roc_target::TargetInfo;
|
||||
|
||||
fn basic_type_from_record<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
fields: &[Layout<'_>],
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
let mut field_types = Vec::with_capacity_in(fields.len(), env.arena);
|
||||
|
@ -22,7 +23,7 @@ fn basic_type_from_record<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout: &Layout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use Layout::*;
|
||||
|
@ -33,7 +34,26 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
|||
..
|
||||
} => basic_type_from_record(env, sorted_fields),
|
||||
LambdaSet(lambda_set) => basic_type_from_layout(env, &lambda_set.runtime_representation()),
|
||||
Union(union_layout) => {
|
||||
Boxed(inner_layout) => {
|
||||
let inner_type = basic_type_from_layout(env, inner_layout);
|
||||
|
||||
inner_type.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
Union(union_layout) => basic_type_from_union_layout(env, union_layout),
|
||||
RecursivePointer => env
|
||||
.context
|
||||
.i64_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.as_basic_type_enum(),
|
||||
|
||||
Builtin(builtin) => basic_type_from_builtin(env, builtin),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
union_layout: &UnionLayout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use UnionLayout::*;
|
||||
|
||||
let tag_id_type = basic_type_from_layout(env, &union_layout.tag_id_layout());
|
||||
|
@ -60,8 +80,7 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
NullableUnwrapped { other_fields, .. } => {
|
||||
let block =
|
||||
block_of_memory_slices(env.context, &[other_fields], env.target_info);
|
||||
let block = block_of_memory_slices(env.context, &[other_fields], env.target_info);
|
||||
block.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
NonNullableUnwrapped(fields) => {
|
||||
|
@ -69,85 +88,10 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
|||
block.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
RecursivePointer => {
|
||||
// TODO make this dynamic
|
||||
env.context
|
||||
.i64_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.as_basic_type_enum()
|
||||
}
|
||||
|
||||
Builtin(builtin) => basic_type_from_builtin(env, builtin),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn basic_type_from_layout_1<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
layout: &Layout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use Layout::*;
|
||||
|
||||
match layout {
|
||||
Struct {
|
||||
field_layouts: sorted_fields,
|
||||
..
|
||||
} => basic_type_from_record(env, sorted_fields),
|
||||
LambdaSet(lambda_set) => {
|
||||
basic_type_from_layout_1(env, &lambda_set.runtime_representation())
|
||||
}
|
||||
Union(union_layout) => {
|
||||
use UnionLayout::*;
|
||||
|
||||
let tag_id_type = basic_type_from_layout(env, &union_layout.tag_id_layout());
|
||||
|
||||
match union_layout {
|
||||
NonRecursive(tags) => {
|
||||
let data = block_of_memory_slices(env.context, tags, env.target_info);
|
||||
let struct_type = env.context.struct_type(&[data, tag_id_type], false);
|
||||
|
||||
struct_type.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
Recursive(tags)
|
||||
| NullableWrapped {
|
||||
other_tags: tags, ..
|
||||
} => {
|
||||
let data = block_of_memory_slices(env.context, tags, env.target_info);
|
||||
|
||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
env.context
|
||||
.struct_type(&[data, tag_id_type], false)
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
} else {
|
||||
data.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
}
|
||||
NullableUnwrapped { other_fields, .. } => {
|
||||
let block =
|
||||
block_of_memory_slices(env.context, &[other_fields], env.target_info);
|
||||
block.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
NonNullableUnwrapped(fields) => {
|
||||
let block = block_of_memory_slices(env.context, &[fields], env.target_info);
|
||||
block.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
RecursivePointer => {
|
||||
// TODO make this dynamic
|
||||
env.context
|
||||
.i64_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.as_basic_type_enum()
|
||||
}
|
||||
|
||||
Builtin(builtin) => basic_type_from_builtin(env, builtin),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
builtin: &Builtin<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use Builtin::*;
|
||||
|
@ -166,8 +110,48 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Turn a layout into a BasicType that we use in LLVM function arguments.
|
||||
///
|
||||
/// This makes it possible to pass values as something different from how they are typically stored.
|
||||
/// Current differences
|
||||
///
|
||||
/// - tag unions are passed by-reference. That means that
|
||||
/// * `f : [ Some I64, None ] -> I64` is typed `{ { i64, i8 }, i64 }* -> i64`
|
||||
/// * `f : { x : [ Some I64, None ] } -> I64 is typed `{ { { i64, i8 }, i64 } } -> i64`
|
||||
///
|
||||
/// Ideas exist to have (bigger than 2 register) records also be passed by-reference, but this
|
||||
/// is not currently implemented
|
||||
pub fn argument_type_from_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout: &Layout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use Layout::*;
|
||||
|
||||
match layout {
|
||||
LambdaSet(lambda_set) => {
|
||||
argument_type_from_layout(env, &lambda_set.runtime_representation())
|
||||
}
|
||||
Union(union_layout) => argument_type_from_union_layout(env, union_layout),
|
||||
other => basic_type_from_layout(env, other),
|
||||
}
|
||||
}
|
||||
|
||||
/// Non-recursive tag unions are stored on the stack, but passed by-reference
|
||||
pub fn argument_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
union_layout: &UnionLayout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
let heap_type = basic_type_from_union_layout(env, union_layout);
|
||||
|
||||
if let UnionLayout::NonRecursive(_) = union_layout {
|
||||
heap_type.ptr_type(AddressSpace::Generic).into()
|
||||
} else {
|
||||
heap_type
|
||||
}
|
||||
}
|
||||
|
||||
pub fn int_type_from_int_width<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
int_width: IntWidth,
|
||||
) -> IntType<'ctx> {
|
||||
use IntWidth::*;
|
||||
|
@ -182,7 +166,7 @@ pub fn int_type_from_int_width<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
pub fn float_type_from_float_width<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
float_width: FloatWidth,
|
||||
) -> FloatType<'ctx> {
|
||||
use FloatWidth::*;
|
||||
|
@ -267,33 +251,23 @@ pub fn str_list_int(ctx: &Context, target_info: TargetInfo) -> IntType<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn zig_dict_type<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
) -> StructType<'ctx> {
|
||||
pub fn zig_dict_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
|
||||
env.module.get_struct_type("dict.RocDict").unwrap()
|
||||
}
|
||||
|
||||
pub fn zig_list_type<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
) -> StructType<'ctx> {
|
||||
pub fn zig_list_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
|
||||
env.module.get_struct_type("list.RocList").unwrap()
|
||||
}
|
||||
|
||||
pub fn zig_str_type<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
) -> StructType<'ctx> {
|
||||
pub fn zig_str_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
|
||||
env.module.get_struct_type("str.RocStr").unwrap()
|
||||
}
|
||||
|
||||
pub fn zig_has_tag_id_type<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
) -> StructType<'ctx> {
|
||||
pub fn zig_has_tag_id_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
|
||||
env.module.get_struct_type("list.HasTagId").unwrap()
|
||||
}
|
||||
|
||||
pub fn zig_with_overflow_roc_dec<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
) -> StructType<'ctx> {
|
||||
pub fn zig_with_overflow_roc_dec<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
|
||||
env.module
|
||||
.get_struct_type("utils.WithOverflow(dec.RocDec)")
|
||||
.unwrap()
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::llvm::build::{
|
|||
FAST_CALL_CONV, TAG_DATA_INDEX, TAG_ID_INDEX,
|
||||
};
|
||||
use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list};
|
||||
use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1};
|
||||
use crate::llvm::convert::basic_type_from_layout;
|
||||
use bumpalo::collections::Vec;
|
||||
use inkwell::basic_block::BasicBlock;
|
||||
use inkwell::context::Context;
|
||||
|
@ -20,6 +20,8 @@ use roc_module::symbol::Symbol;
|
|||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
use super::convert::argument_type_from_union_layout;
|
||||
|
||||
/// "Infinite" reference count, for static values
|
||||
/// Ref counts are encoded as negative numbers where isize::MIN represents 1
|
||||
pub const REFCOUNT_MAX: usize = 0_usize;
|
||||
|
@ -589,6 +591,12 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
|||
modify_refcount_builtin(env, layout_ids, mode, when_recursive, layout, builtin)
|
||||
}
|
||||
|
||||
Boxed(inner) => {
|
||||
let function = modify_refcount_boxed(env, layout_ids, mode, inner);
|
||||
|
||||
Some(function)
|
||||
}
|
||||
|
||||
Union(variant) => {
|
||||
use UnionLayout::*;
|
||||
|
||||
|
@ -891,6 +899,76 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
|
|||
builder.build_return(None);
|
||||
}
|
||||
|
||||
fn modify_refcount_boxed<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
mode: Mode,
|
||||
inner_layout: &'a Layout<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||
|
||||
let boxed_layout = env.arena.alloc(Layout::Boxed(inner_layout));
|
||||
|
||||
let (_, fn_name) = function_name_from_mode(
|
||||
layout_ids,
|
||||
&env.interns,
|
||||
"increment_boxed",
|
||||
"decrement_boxed",
|
||||
boxed_layout,
|
||||
mode,
|
||||
);
|
||||
|
||||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let basic_type = basic_type_from_layout(env, boxed_layout);
|
||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||
|
||||
modify_refcount_box_help(env, mode, inner_layout, function_value);
|
||||
|
||||
function_value
|
||||
}
|
||||
};
|
||||
|
||||
env.builder.position_at_end(block);
|
||||
env.builder
|
||||
.set_current_debug_location(env.context, di_location);
|
||||
|
||||
function
|
||||
}
|
||||
|
||||
fn modify_refcount_box_help<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
mode: Mode,
|
||||
inner_layout: &Layout<'a>,
|
||||
fn_val: FunctionValue<'ctx>,
|
||||
) {
|
||||
let builder = env.builder;
|
||||
let ctx = env.context;
|
||||
|
||||
// Add a basic block for the entry point
|
||||
let entry = ctx.append_basic_block(fn_val, "entry");
|
||||
|
||||
builder.position_at_end(entry);
|
||||
|
||||
debug_info_init!(env, fn_val);
|
||||
|
||||
// Add args to scope
|
||||
let arg_symbol = Symbol::ARG_1;
|
||||
let arg_val = fn_val.get_param_iter().next().unwrap();
|
||||
arg_val.set_name(arg_symbol.as_str(&env.interns));
|
||||
|
||||
let boxed = arg_val.into_pointer_value();
|
||||
let refcount_ptr = PointerToRefcount::from_ptr_to_data(env, boxed);
|
||||
let call_mode = mode_to_call_mode(fn_val, mode);
|
||||
let boxed_layout = Layout::Boxed(inner_layout);
|
||||
refcount_ptr.modify(call_mode, &boxed_layout, env);
|
||||
|
||||
// this function returns void
|
||||
builder.build_return(None);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn modify_refcount_dict<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
@ -1619,7 +1697,8 @@ fn modify_refcount_union<'a, 'ctx, 'env>(
|
|||
when_recursive: &WhenRecursive<'a>,
|
||||
fields: &'a [&'a [Layout<'a>]],
|
||||
) -> FunctionValue<'ctx> {
|
||||
let layout = Layout::Union(UnionLayout::NonRecursive(fields));
|
||||
let union_layout = UnionLayout::NonRecursive(fields);
|
||||
let layout = Layout::Union(union_layout);
|
||||
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||
|
@ -1636,7 +1715,7 @@ fn modify_refcount_union<'a, 'ctx, 'env>(
|
|||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let basic_type = basic_type_from_layout_1(env, &layout);
|
||||
let basic_type = argument_type_from_union_layout(env, &union_layout);
|
||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||
|
||||
modify_refcount_union_help(
|
||||
|
@ -1700,9 +1779,9 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
|||
.build_load(tag_id_ptr, "load_tag_id")
|
||||
.into_int_value();
|
||||
|
||||
let tag_id_u8 = env
|
||||
.builder
|
||||
.build_int_cast(tag_id, env.context.i8_type(), "tag_id_u8");
|
||||
let tag_id_u8 =
|
||||
env.builder
|
||||
.build_int_cast_sign_flag(tag_id, env.context.i8_type(), false, "tag_id_u8");
|
||||
|
||||
// next, make a jump table for all possible values of the tag_id
|
||||
let mut cases = Vec::with_capacity_in(tags.len(), env.arena);
|
||||
|
|
|
@ -594,6 +594,10 @@ impl<'a> WasmBackend<'a> {
|
|||
index,
|
||||
} => self.expr_union_at_index(*structure, *tag_id, union_layout, *index, sym),
|
||||
|
||||
Expr::ExprBox { .. } | Expr::ExprUnbox { .. } => {
|
||||
todo!("Expression `{}`", expr.to_pretty(100))
|
||||
}
|
||||
|
||||
Expr::Reuse { .. } | Expr::Reset { .. } | Expr::RuntimeErrorFunction(_) => {
|
||||
todo!("Expression `{}`", expr.to_pretty(100))
|
||||
}
|
||||
|
|
|
@ -102,6 +102,7 @@ impl WasmLayout {
|
|||
| NullableWrapped { .. }
|
||||
| NullableUnwrapped { .. },
|
||||
)
|
||||
| Layout::Boxed(_)
|
||||
| Layout::RecursivePointer => Self::Primitive(PTR_TYPE, PTR_SIZE),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -688,6 +688,10 @@ impl<'a> LowLevelCall<'a> {
|
|||
Hash => todo!("{:?}", self.lowlevel),
|
||||
|
||||
Eq | NotEq => self.eq_or_neq(backend),
|
||||
|
||||
BoxExpr | UnboxExpr => {
|
||||
unreachable!("The {:?} operation is turned into mono Expr", self.lowlevel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -748,6 +752,8 @@ impl<'a> LowLevelCall<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
Layout::Boxed(_) => todo!(),
|
||||
|
||||
Layout::RecursivePointer => {
|
||||
internal_error!(
|
||||
"Tried to apply `==` to RecursivePointer values {:?}",
|
||||
|
|
|
@ -123,6 +123,8 @@ pub enum LowLevel {
|
|||
PtrCast,
|
||||
RefCountInc,
|
||||
RefCountDec,
|
||||
BoxExpr,
|
||||
UnboxExpr,
|
||||
}
|
||||
|
||||
macro_rules! higher_order {
|
||||
|
|
|
@ -1198,6 +1198,12 @@ define_builtins! {
|
|||
13 SET_WALK_USER_FUNCTION: "#walk_user_function"
|
||||
14 SET_CONTAINS: "contains"
|
||||
}
|
||||
8 BOX: "Box" => {
|
||||
0 BOX_BOX_TYPE: "Box" imported // the Box.Box opaque type
|
||||
1 BOX_BOX_FUNCTION: "box" // Box.box
|
||||
2 BOX_UNBOX: "unbox"
|
||||
|
||||
num_modules: 8 // Keep this count up to date by hand! (TODO: see the mut_map! macro for how we could determine this count correctly in the macro)
|
||||
}
|
||||
|
||||
num_modules: 9 // Keep this count up to date by hand! (TODO: see the mut_map! macro for how we could determine this count correctly in the macro)
|
||||
}
|
||||
|
|
|
@ -724,6 +724,23 @@ impl<'a> BorrowInfState<'a> {
|
|||
// the function must take it as an owned parameter
|
||||
self.own_args_if_param(xs);
|
||||
}
|
||||
|
||||
ExprBox { symbol: x } => {
|
||||
self.own_var(z);
|
||||
|
||||
// if the used symbol is an argument to the current function,
|
||||
// the function must take it as an owned parameter
|
||||
self.own_args_if_param(&[*x]);
|
||||
}
|
||||
|
||||
ExprUnbox { symbol: x } => {
|
||||
// if the boxed value is owned, the box is
|
||||
self.if_is_owned_then_own(*x, z);
|
||||
|
||||
// if the extracted value is owned, the structure must be too
|
||||
self.if_is_owned_then_own(z, *x);
|
||||
}
|
||||
|
||||
Reset { symbol: x, .. } => {
|
||||
self.own_var(z);
|
||||
self.own_var(*x);
|
||||
|
@ -1011,6 +1028,10 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
|
||||
ExpectTrue => arena.alloc_slice_copy(&[irrelevant]),
|
||||
|
||||
BoxExpr | UnboxExpr => {
|
||||
unreachable!("These lowlevel operations are turned into mono Expr's")
|
||||
}
|
||||
|
||||
PtrCast | RefCountInc | RefCountDec => {
|
||||
unreachable!("Only inserted *after* borrow checking: {:?}", op);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ pub fn eq_generic<'a>(
|
|||
Layout::Builtin(Builtin::List(elem_layout)) => eq_list(root, ident_ids, ctx, elem_layout),
|
||||
Layout::Struct { field_layouts, .. } => eq_struct(root, ident_ids, ctx, field_layouts),
|
||||
Layout::Union(union_layout) => eq_tag_union(root, ident_ids, ctx, union_layout),
|
||||
Layout::Boxed(inner_layout) => eq_boxed(root, ident_ids, ctx, inner_layout),
|
||||
Layout::LambdaSet(_) => unreachable!("`==` is not defined on functions"),
|
||||
Layout::RecursivePointer => {
|
||||
unreachable!(
|
||||
|
@ -528,6 +529,15 @@ fn eq_tag_fields<'a>(
|
|||
stmt
|
||||
}
|
||||
|
||||
fn eq_boxed<'a>(
|
||||
_root: &mut CodeGenHelp<'a>,
|
||||
_ident_ids: &mut IdentIds,
|
||||
_ctx: &mut Context<'a>,
|
||||
_inner_layout: &'a Layout<'a>,
|
||||
) -> Stmt<'a> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// List equality
|
||||
/// We can't use `ListGetUnsafe` because it increments the refcount, and we don't want that.
|
||||
/// Another way to dereference a heap pointer is to use `Expr::UnionAtIndex`.
|
||||
|
|
|
@ -378,7 +378,13 @@ impl<'a> CodeGenHelp<'a> {
|
|||
Layout::Union(UnionLayout::NonRecursive(new_tags.into_bump_slice()))
|
||||
}
|
||||
|
||||
Layout::Union(_) => layout,
|
||||
Layout::Union(_) => {
|
||||
// we always fully unroll recursive types. That means tha when we find a
|
||||
// recursive tag union we can replace it with the layout
|
||||
layout
|
||||
}
|
||||
|
||||
Layout::Boxed(inner) => self.replace_rec_ptr(ctx, *inner),
|
||||
|
||||
Layout::LambdaSet(lambda_set) => {
|
||||
self.replace_rec_ptr(ctx, lambda_set.runtime_representation())
|
||||
|
@ -476,5 +482,7 @@ fn layout_needs_helper_proc(layout: &Layout, op: HelperOp) -> bool {
|
|||
Layout::Union(_) => true,
|
||||
|
||||
Layout::LambdaSet(_) | Layout::RecursivePointer => false,
|
||||
|
||||
Layout::Boxed(_) => true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,6 +122,7 @@ pub fn refcount_generic<'a>(
|
|||
refcount_generic(root, ident_ids, ctx, runtime_layout, structure)
|
||||
}
|
||||
Layout::RecursivePointer => rc_todo(),
|
||||
Layout::Boxed(_) => rc_todo(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,6 +156,7 @@ pub fn is_rc_implemented_yet(layout: &Layout) -> bool {
|
|||
is_rc_implemented_yet(&lambda_set.runtime_representation())
|
||||
}
|
||||
Layout::RecursivePointer => true,
|
||||
Layout::Boxed(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,6 +114,10 @@ pub fn occurring_variables_expr(expr: &Expr<'_>, result: &mut MutSet<Symbol>) {
|
|||
result.insert(*x);
|
||||
}
|
||||
|
||||
ExprBox { symbol } | ExprUnbox { symbol } => {
|
||||
result.insert(*symbol);
|
||||
}
|
||||
|
||||
EmptyArray | RuntimeErrorFunction(_) | Literal(_) => {}
|
||||
|
||||
GetTagId {
|
||||
|
@ -756,6 +760,28 @@ impl<'a> Context<'a> {
|
|||
self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
}
|
||||
|
||||
ExprBox { symbol: x } => {
|
||||
// mimics Tag
|
||||
self.add_inc_before_consume_all(
|
||||
&[x],
|
||||
self.arena.alloc(Stmt::Let(z, v, l, b)),
|
||||
b_live_vars,
|
||||
)
|
||||
}
|
||||
|
||||
ExprUnbox { symbol: x } => {
|
||||
// mimics UnionAtIndex
|
||||
let b = self.add_dec_if_needed(x, b, b_live_vars);
|
||||
let info_x = self.get_var_info(x);
|
||||
let b = if info_x.consume {
|
||||
self.add_inc(z, 1, b)
|
||||
} else {
|
||||
b
|
||||
};
|
||||
|
||||
self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
}
|
||||
|
||||
EmptyArray | Literal(_) | Reset { .. } | RuntimeErrorFunction(_) => {
|
||||
// EmptyArray is always stack-allocated
|
||||
// function pointers are persistent
|
||||
|
|
|
@ -1505,6 +1505,14 @@ pub enum Expr<'a> {
|
|||
},
|
||||
EmptyArray,
|
||||
|
||||
ExprBox {
|
||||
symbol: Symbol,
|
||||
},
|
||||
|
||||
ExprUnbox {
|
||||
symbol: Symbol,
|
||||
},
|
||||
|
||||
Reuse {
|
||||
symbol: Symbol,
|
||||
update_tag_id: bool,
|
||||
|
@ -1682,6 +1690,10 @@ impl<'a> Expr<'a> {
|
|||
.text("GetTagId ")
|
||||
.append(symbol_to_doc(alloc, *structure)),
|
||||
|
||||
ExprBox { symbol, .. } => alloc.text("Box ").append(symbol_to_doc(alloc, *symbol)),
|
||||
|
||||
ExprUnbox { symbol, .. } => alloc.text("Unbox ").append(symbol_to_doc(alloc, *symbol)),
|
||||
|
||||
UnionAtIndex {
|
||||
tag_id,
|
||||
structure,
|
||||
|
@ -4615,6 +4627,18 @@ pub fn with_hole<'a>(
|
|||
let xs = arg_symbols[0];
|
||||
match_on_closure_argument!(ListFindUnsafe, [xs])
|
||||
}
|
||||
BoxExpr => {
|
||||
debug_assert_eq!(arg_symbols.len(), 1);
|
||||
let x = arg_symbols[0];
|
||||
|
||||
Stmt::Let(assigned, Expr::ExprBox { symbol: x }, layout, hole)
|
||||
}
|
||||
UnboxExpr => {
|
||||
debug_assert_eq!(arg_symbols.len(), 1);
|
||||
let x = arg_symbols[0];
|
||||
|
||||
Stmt::Let(assigned, Expr::ExprUnbox { symbol: x }, layout, hole)
|
||||
}
|
||||
_ => {
|
||||
let call = self::Call {
|
||||
call_type: CallType::LowLevel {
|
||||
|
@ -6179,6 +6203,14 @@ fn substitute_in_expr<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
ExprBox { symbol } => {
|
||||
substitute(subs, *symbol).map(|new_symbol| ExprBox { symbol: new_symbol })
|
||||
}
|
||||
|
||||
ExprUnbox { symbol } => {
|
||||
substitute(subs, *symbol).map(|new_symbol| ExprUnbox { symbol: new_symbol })
|
||||
}
|
||||
|
||||
StructAtIndex {
|
||||
index,
|
||||
structure,
|
||||
|
|
|
@ -250,6 +250,7 @@ pub enum Layout<'a> {
|
|||
field_order_hash: FieldOrderHash,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
},
|
||||
Boxed(&'a Layout<'a>),
|
||||
Union(UnionLayout<'a>),
|
||||
LambdaSet(LambdaSet<'a>),
|
||||
RecursivePointer,
|
||||
|
@ -997,7 +998,7 @@ impl<'a> Layout<'a> {
|
|||
}
|
||||
}
|
||||
LambdaSet(lambda_set) => lambda_set.runtime_representation().safe_to_memcpy(),
|
||||
RecursivePointer => {
|
||||
Boxed(_) | RecursivePointer => {
|
||||
// We cannot memcpy pointers, because then we would have the same pointer in multiple places!
|
||||
false
|
||||
}
|
||||
|
@ -1066,6 +1067,7 @@ impl<'a> Layout<'a> {
|
|||
.runtime_representation()
|
||||
.stack_size_without_alignment(target_info),
|
||||
RecursivePointer => target_info.ptr_width() as u32,
|
||||
Boxed(_) => target_info.ptr_width() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1114,6 +1116,7 @@ impl<'a> Layout<'a> {
|
|||
.alignment_bytes(target_info),
|
||||
Layout::Builtin(builtin) => builtin.alignment_bytes(target_info),
|
||||
Layout::RecursivePointer => target_info.ptr_width() as u32,
|
||||
Layout::Boxed(_) => target_info.ptr_width() as u32,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1126,6 +1129,7 @@ impl<'a> Layout<'a> {
|
|||
.runtime_representation()
|
||||
.allocation_alignment_bytes(target_info),
|
||||
Layout::RecursivePointer => unreachable!("should be looked up to get an actual layout"),
|
||||
Layout::Boxed(inner) => inner.allocation_alignment_bytes(target_info),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1172,6 +1176,7 @@ impl<'a> Layout<'a> {
|
|||
}
|
||||
LambdaSet(lambda_set) => lambda_set.runtime_representation().contains_refcounted(),
|
||||
RecursivePointer => true,
|
||||
Boxed(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1196,6 +1201,10 @@ impl<'a> Layout<'a> {
|
|||
Union(union_layout) => union_layout.to_doc(alloc, parens),
|
||||
LambdaSet(lambda_set) => lambda_set.runtime_representation().to_doc(alloc, parens),
|
||||
RecursivePointer => alloc.text("*self"),
|
||||
Boxed(inner) => alloc
|
||||
.text("Boxed(")
|
||||
.append(inner.to_doc(alloc, parens))
|
||||
.append(")"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1615,6 +1624,15 @@ fn layout_from_flat_type<'a>(
|
|||
Symbol::LIST_LIST => list_layout_from_elem(env, args[0]),
|
||||
Symbol::DICT_DICT => dict_layout_from_key_value(env, args[0], args[1]),
|
||||
Symbol::SET_SET => dict_layout_from_key_value(env, args[0], Variable::EMPTY_RECORD),
|
||||
Symbol::BOX_BOX_TYPE => {
|
||||
// Num.Num should only ever have 1 argument, e.g. Num.Num Int.Integer
|
||||
debug_assert_eq!(args.len(), 1);
|
||||
|
||||
let inner_var = args[0];
|
||||
let inner_layout = Layout::from_var(env, inner_var)?;
|
||||
|
||||
Ok(Layout::Boxed(env.arena.alloc(inner_layout)))
|
||||
}
|
||||
_ => {
|
||||
panic!(
|
||||
"TODO layout_from_flat_type for Apply({:?}, {:?})",
|
||||
|
|
|
@ -239,6 +239,12 @@ fn insert_reset<'a>(
|
|||
stack.push((symbol, expr, expr_layout));
|
||||
stmt = rest;
|
||||
}
|
||||
|
||||
ExprBox { .. } | ExprUnbox { .. } => {
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
|
||||
Literal(_)
|
||||
| Call(_)
|
||||
| Tag { .. }
|
||||
|
@ -620,6 +626,8 @@ fn has_live_var_expr<'a>(expr: &'a Expr<'a>, needle: Symbol) -> bool {
|
|||
symbol, arguments, ..
|
||||
} => needle == *symbol || arguments.iter().any(|s| *s == needle),
|
||||
Expr::Reset { symbol, .. } => needle == *symbol,
|
||||
Expr::ExprBox { symbol, .. } => needle == *symbol,
|
||||
Expr::ExprUnbox { symbol, .. } => needle == *symbol,
|
||||
Expr::RuntimeErrorFunction(_) => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -798,6 +798,34 @@ fn list_walk_until_sum() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn list_walk_imlements_position() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
Option a : [ Some a, None ]
|
||||
|
||||
find : List a, a -> Option Nat
|
||||
find = \list, needle ->
|
||||
findHelp list needle
|
||||
|> .v
|
||||
|
||||
findHelp = \list, needle ->
|
||||
List.walkUntil list { n: 0, v: None } \{ n, v }, element ->
|
||||
if element == needle then
|
||||
Stop { n, v: Some n }
|
||||
else
|
||||
Continue { n: n + 1, v }
|
||||
|
||||
when find [ 1, 2, 3 ] 3 is
|
||||
None -> 0
|
||||
Some v -> v
|
||||
"#,
|
||||
2,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn list_walk_until_even_prefix_sum() {
|
||||
|
|
|
@ -2781,3 +2781,35 @@ fn to_float_f64() {
|
|||
f64
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
// https://github.com/rtfeldman/roc/issues/2696
|
||||
fn upcast_of_int_is_zext() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Num.toU16 0b1000_0000u8
|
||||
"#
|
||||
),
|
||||
128,
|
||||
u16
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
// https://github.com/rtfeldman/roc/issues/2696
|
||||
fn upcast_of_int_checked_is_zext() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.toU16Checked 0b1000_0000u8 is
|
||||
Ok 128u16 -> 1u8
|
||||
_ -> 0u8
|
||||
"#
|
||||
),
|
||||
1,
|
||||
u16
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3228,3 +3228,19 @@ fn issue_2322() {
|
|||
i64
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn box_and_unbox_string() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
Box.unbox (Box.box (Str.concat "Leverage " "agile frameworks to provide a robust synopsis for high level overviews"))
|
||||
"#
|
||||
),
|
||||
RocStr::from(
|
||||
"Leverage agile frameworks to provide a robust synopsis for high level overviews"
|
||||
),
|
||||
RocStr
|
||||
)
|
||||
}
|
||||
|
|
|
@ -969,6 +969,11 @@ pub fn result_type(a: SolvedType, e: SolvedType) -> SolvedType {
|
|||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn box_type(a: SolvedType) -> SolvedType {
|
||||
SolvedType::Apply(Symbol::BOX_BOX_TYPE, vec![a])
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn result_alias_content(a: SolvedType, e: SolvedType) -> SolvedType {
|
||||
SolvedType::TagUnion(
|
||||
|
|
|
@ -39,7 +39,7 @@ const QUAD_VERTS: [Vertex; 4] = [
|
|||
},
|
||||
];
|
||||
|
||||
pub const MAX_QUADS: usize = 100_000;
|
||||
pub const MAX_QUADS: usize = 1_000;
|
||||
|
||||
pub fn create_rect_buffers(
|
||||
gpu_device: &wgpu::Device,
|
||||
|
@ -59,7 +59,7 @@ pub fn create_rect_buffers(
|
|||
});
|
||||
|
||||
let quad_buffer = gpu_device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("iced_wgpu::quad instance buffer"),
|
||||
label: None,
|
||||
size: mem::size_of::<Quad>() as u64 * MAX_QUADS as u64,
|
||||
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
|
|
|
@ -178,7 +178,7 @@ fn run_event_loop(title: &str, root: RocElem) -> Result<(), Box<dyn Error>> {
|
|||
// }
|
||||
// }
|
||||
// }
|
||||
todo!("TODO handle keyboard input");
|
||||
// TODO todo!("TODO handle keyboard input");
|
||||
}
|
||||
//Modifiers Changed
|
||||
Event::WindowEvent {
|
||||
|
|
|
@ -438,6 +438,7 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
|||
unreachable!("RecursivePointers can only be inside structures")
|
||||
}
|
||||
Layout::LambdaSet(_) => Ok(OPAQUE_FUNCTION),
|
||||
Layout::Boxed(_inner) => todo!(),
|
||||
};
|
||||
result.map(|e| apply_newtypes(env, newtype_containers, e))
|
||||
}
|
||||
|
|
|
@ -426,8 +426,8 @@ mod test_reporting {
|
|||
|
||||
`Booly` is not used anywhere in your code.
|
||||
|
||||
3│ Booly : [ Yes, No, Maybe ]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
1│ Booly : [ Yes, No ]
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you didn't intend on using `Booly` then remove it so future readers
|
||||
of your code don't wonder why it is there.
|
||||
|
@ -436,8 +436,8 @@ mod test_reporting {
|
|||
|
||||
`Booly` is not used anywhere in your code.
|
||||
|
||||
1│ Booly : [ Yes, No ]
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
3│ Booly : [ Yes, No, Maybe ]
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If you didn't intend on using `Booly` then remove it so future readers
|
||||
of your code don't wonder why it is there.
|
||||
|
@ -1544,10 +1544,10 @@ mod test_reporting {
|
|||
|
||||
Did you mean one of these?
|
||||
|
||||
Box
|
||||
Bool
|
||||
U8
|
||||
F64
|
||||
Nat
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
@ -2003,8 +2003,8 @@ mod test_reporting {
|
|||
|
||||
Ok
|
||||
U8
|
||||
Box
|
||||
f
|
||||
I8
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
@ -3727,10 +3727,10 @@ mod test_reporting {
|
|||
Is there an import missing? Perhaps there is a typo. Did you mean one
|
||||
of these?
|
||||
|
||||
Box
|
||||
Bool
|
||||
Num
|
||||
Set
|
||||
Str
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
@ -7984,18 +7984,18 @@ I need all branches in an `if` to have the same type!
|
|||
r#"
|
||||
── CYCLIC ALIAS ────────────────────────────────────────────────────────────────
|
||||
|
||||
The `Bar` alias is recursive in an invalid way:
|
||||
The `Foo` alias is recursive in an invalid way:
|
||||
|
||||
2│ Bar a : [ Stuff (Foo a) ]
|
||||
^^^^^
|
||||
1│ Foo a : [ Thing (Bar a) ]
|
||||
^^^
|
||||
|
||||
The `Bar` alias depends on itself through the following chain of
|
||||
The `Foo` alias depends on itself through the following chain of
|
||||
definitions:
|
||||
|
||||
┌─────┐
|
||||
│ Bar
|
||||
│ ↓
|
||||
│ Foo
|
||||
│ ↓
|
||||
│ Bar
|
||||
└─────┘
|
||||
|
||||
Recursion in aliases is only allowed if recursion happens behind a
|
||||
|
@ -8185,7 +8185,7 @@ I need all branches in an `if` to have the same type!
|
|||
Test
|
||||
List
|
||||
Num
|
||||
Set
|
||||
Box
|
||||
"#
|
||||
),
|
||||
)
|
||||
|
|
2
vendor/inkwell/Cargo.toml
vendored
2
vendor/inkwell/Cargo.toml
vendored
|
@ -23,7 +23,7 @@ edition = "2018"
|
|||
# commit of TheDan64/inkwell, push a new tag which points to the latest commit,
|
||||
# change the tag value in this Cargo.toml to point to that tag, and `cargo update`.
|
||||
# This way, GitHub Actions works and nobody's builds get broken.
|
||||
inkwell = { git = "https://github.com/rtfeldman/inkwell", tag = "llvm13-0.release1", features = [ "llvm12-0" ] }
|
||||
inkwell = { git = "https://github.com/rtfeldman/inkwell", branch = "master", features = [ "llvm12-0" ] }
|
||||
|
||||
[features]
|
||||
target-arm = []
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue