Merge pull request #2091 from rtfeldman/remove-empty-layouts

Remove empty layouts
This commit is contained in:
Richard Feldman 2021-11-27 23:32:15 -05:00 committed by GitHub
commit f80409800d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 280 additions and 366 deletions

View file

@ -1,6 +1,8 @@
/// Helpers for interacting with the zig that generates bitcode
use crate::debug_info_init;
use crate::llvm::build::{struct_from_fields, Env, C_CALL_CONV, FAST_CALL_CONV, TAG_DATA_INDEX};
use crate::llvm::build::{
load_roc_value, struct_from_fields, Env, C_CALL_CONV, FAST_CALL_CONV, TAG_DATA_INDEX,
};
use crate::llvm::convert::basic_type_from_layout;
use crate::llvm::refcounting::{
decrement_refcount_layout, increment_n_refcount_layout, increment_refcount_layout,
@ -506,8 +508,9 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
.build_bitcast(value_ptr2, value_type, "load_opaque")
.into_pointer_value();
let value1 = env.builder.build_load(value_cast1, "load_opaque");
let value2 = env.builder.build_load(value_cast2, "load_opaque");
// load_roc_value(env, *element_layout, elem_ptr, "get_elem")
let value1 = load_roc_value(env, *layout, value_cast1, "load_opaque");
let value2 = load_roc_value(env, *layout, value_cast2, "load_opaque");
let result =
crate::llvm::compare::generic_eq(env, layout_ids, value1, value2, layout, layout);

View file

@ -8,11 +8,11 @@ use crate::llvm::build_dict::{
};
use crate::llvm::build_hash::generic_hash;
use crate::llvm::build_list::{
self, allocate_list, empty_list, empty_polymorphic_list, list_all, list_any, list_append,
list_concat, list_contains, list_drop_at, list_find_trivial_not_found, list_find_unsafe,
list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len, list_map,
list_map2, list_map3, list_map4, list_map_with_index, list_prepend, list_range, list_repeat,
list_reverse, list_set, list_single, list_sort_with, list_sublist, list_swap,
self, allocate_list, empty_polymorphic_list, list_all, list_any, list_append, list_concat,
list_contains, list_drop_at, list_find_unsafe, list_get_unsafe, list_join, list_keep_errs,
list_keep_if, list_keep_oks, list_len, list_map, list_map2, list_map3, list_map4,
list_map_with_index, list_prepend, list_range, list_repeat, list_reverse, list_set,
list_single, list_sort_with, list_sublist, list_swap,
};
use crate::llvm::build_str::{
empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int,
@ -4726,7 +4726,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match list_layout {
Layout::Builtin(Builtin::EmptyList) => default,
Layout::Builtin(Builtin::List(element_layout)) => {
let argument_layouts = &[*default_layout, **element_layout];
@ -4765,7 +4764,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match (list_layout, return_layout) {
(Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
(
Layout::Builtin(Builtin::List(element_layout)),
Layout::Builtin(Builtin::List(result_layout)),
@ -4824,8 +4822,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
result_layout,
)
}
(Layout::Builtin(Builtin::EmptyList), _, _)
| (_, Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
_ => unreachable!("invalid list layout"),
}
}
@ -4870,9 +4866,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
result_layout,
)
}
(Layout::Builtin(Builtin::EmptyList), _, _, _)
| (_, Layout::Builtin(Builtin::EmptyList), _, _)
| (_, _, Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
_ => unreachable!("invalid list layout"),
}
}
@ -4931,10 +4924,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
result_layout,
)
}
(Layout::Builtin(Builtin::EmptyList), _, _, _, _)
| (_, Layout::Builtin(Builtin::EmptyList), _, _, _)
| (_, _, Layout::Builtin(Builtin::EmptyList), _, _)
| (_, _, _, Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
_ => unreachable!("invalid list layout"),
}
}
@ -4945,7 +4934,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match (list_layout, return_layout) {
(Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
(
Layout::Builtin(Builtin::List(element_layout)),
Layout::Builtin(Builtin::List(result_layout)),
@ -4975,7 +4963,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match list_layout {
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
Layout::Builtin(Builtin::List(element_layout)) => {
let argument_layouts = &[**element_layout];
@ -5002,8 +4989,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match (list_layout, return_layout) {
(_, Layout::Builtin(Builtin::EmptyList))
| (Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
(
Layout::Builtin(Builtin::List(before_layout)),
Layout::Builtin(Builtin::List(after_layout)),
@ -5043,8 +5028,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match (list_layout, return_layout) {
(_, Layout::Builtin(Builtin::EmptyList))
| (Layout::Builtin(Builtin::EmptyList), _) => empty_list(env),
(
Layout::Builtin(Builtin::List(before_layout)),
Layout::Builtin(Builtin::List(after_layout)),
@ -5093,7 +5076,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match list_layout {
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
Layout::Builtin(Builtin::List(element_layout)) => {
use crate::llvm::bitcode::build_compare_wrapper;
@ -5131,7 +5113,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match list_layout {
Layout::Builtin(Builtin::EmptyList) => env.context.bool_type().const_zero().into(),
Layout::Builtin(Builtin::List(element_layout)) => {
let argument_layouts = &[**element_layout];
@ -5156,9 +5137,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match list_layout {
Layout::Builtin(Builtin::EmptyList) => {
env.context.bool_type().const_int(1, false).into()
}
Layout::Builtin(Builtin::List(element_layout)) => {
let argument_layouts = &[**element_layout];
@ -5184,15 +5162,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match list_layout {
Layout::Builtin(Builtin::EmptyList) => {
// Returns { found: False, elem: \empty }, where the `elem` field is zero-sized.
// NB: currently we never hit this case, since the only caller of this
// lowlevel, namely List.find, will fail during monomorphization when there is no
// concrete list element type. This is because List.find returns a
// `Result elem [ NotFound ]*`, and we can't figure out the size of that if
// `elem` is not concrete.
list_find_trivial_not_found(env)
}
Layout::Builtin(Builtin::List(element_layout)) => {
let argument_layouts = &[**element_layout];
let roc_function_call = roc_function_call(
@ -5217,10 +5186,6 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
let (function, closure, closure_layout) = function_details!();
match dict_layout {
Layout::Builtin(Builtin::EmptyDict) => {
// no elements, so `key` is not in here
panic!("key type unknown")
}
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
let argument_layouts = &[*default_layout, **key_layout, **value_layout];
@ -5484,7 +5449,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let index_2 = load_symbol(scope, &args[2]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
Layout::Builtin(Builtin::List(element_layout)) => list_swap(
env,
original_wrapper,
@ -5510,7 +5474,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let len = load_symbol(scope, &args[2]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
Layout::Builtin(Builtin::List(element_layout)) => list_sublist(
env,
layout_ids,
@ -5532,7 +5495,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let count = load_symbol(scope, &args[1]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
Layout::Builtin(Builtin::List(element_layout)) => list_drop_at(
env,
layout_ids,
@ -5846,10 +5808,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let (element, _) = load_symbol_and_layout(scope, &args[2]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => {
// no elements, so nothing to remove
empty_list(env)
}
Layout::Builtin(Builtin::List(element_layout)) => list_set(
env,
layout_ids,
@ -5894,10 +5852,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let (key, key_layout) = load_symbol_and_layout(scope, &args[1]);
match dict_layout {
Layout::Builtin(Builtin::EmptyDict) => {
// no elements, so nothing to remove
dict
}
Layout::Builtin(Builtin::Dict(_, value_layout)) => {
dict_remove(env, layout_ids, dict, key, key_layout, value_layout)
}
@ -5911,10 +5865,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let (key, key_layout) = load_symbol_and_layout(scope, &args[1]);
match dict_layout {
Layout::Builtin(Builtin::EmptyDict) => {
// no elements, so `key` is not in here
env.context.bool_type().const_zero().into()
}
Layout::Builtin(Builtin::Dict(_, value_layout)) => {
dict_contains(env, layout_ids, dict, key, key_layout, value_layout)
}
@ -5928,10 +5878,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let (key, key_layout) = load_symbol_and_layout(scope, &args[1]);
match dict_layout {
Layout::Builtin(Builtin::EmptyDict) => {
unreachable!("we can't make up a layout for the return value");
// in other words, make sure to check whether the dict is empty first
}
Layout::Builtin(Builtin::Dict(_, value_layout)) => {
dict_get(env, layout_ids, dict, key, key_layout, value_layout)
}
@ -5944,10 +5890,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let (dict, dict_layout) = load_symbol_and_layout(scope, &args[0]);
match dict_layout {
Layout::Builtin(Builtin::EmptyDict) => {
// no elements, so `key` is not in here
empty_list(env)
}
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
dict_keys(env, layout_ids, dict, key_layout, value_layout)
}
@ -5960,10 +5902,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let (dict, dict_layout) = load_symbol_and_layout(scope, &args[0]);
match dict_layout {
Layout::Builtin(Builtin::EmptyDict) => {
// no elements, so `key` is not in here
empty_list(env)
}
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
dict_values(env, layout_ids, dict, key_layout, value_layout)
}
@ -5977,10 +5915,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let (dict2, _) = load_symbol_and_layout(scope, &args[1]);
match dict_layout {
Layout::Builtin(Builtin::EmptyDict) => {
// no elements, so `key` is not in here
panic!("key type unknown")
}
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
dict_union(env, layout_ids, dict1, dict2, key_layout, value_layout)
}
@ -5994,10 +5928,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let (dict2, _) = load_symbol_and_layout(scope, &args[1]);
match dict_layout {
Layout::Builtin(Builtin::EmptyDict) => {
// no elements, so `key` is not in here
panic!("key type unknown")
}
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
dict_difference(env, layout_ids, dict1, dict2, key_layout, value_layout)
}
@ -6011,10 +5941,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let (dict2, _) = load_symbol_and_layout(scope, &args[1]);
match dict_layout {
Layout::Builtin(Builtin::EmptyDict) => {
// no elements, so `key` is not in here
panic!("key type unknown")
}
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
dict_intersection(env, layout_ids, dict1, dict2, key_layout, value_layout)
}
@ -6027,7 +5953,6 @@ fn run_low_level<'a, 'ctx, 'env>(
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => dict_empty(env),
Layout::Builtin(Builtin::List(key_layout)) => {
set_from_list(env, layout_ids, list, key_layout)
}
@ -6123,10 +6048,8 @@ fn to_cc_type_builtin<'a, 'ctx, 'env>(
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => {
basic_type_from_builtin(env, builtin)
}
Builtin::Str | Builtin::EmptyStr | Builtin::List(_) | Builtin::EmptyList => {
env.str_list_c_abi().into()
}
Builtin::Dict(_, _) | Builtin::Set(_) | Builtin::EmptyDict | Builtin::EmptySet => {
Builtin::Str | Builtin::List(_) => env.str_list_c_abi().into(),
Builtin::Dict(_, _) | Builtin::Set(_) => {
// TODO verify this is what actually happens
basic_type_from_builtin(env, builtin)
}

View file

@ -3,7 +3,8 @@ use crate::llvm::bitcode::{
build_dec_wrapper, build_eq_wrapper, build_inc_wrapper, call_bitcode_fn, call_void_bitcode_fn,
};
use crate::llvm::build::{
complex_bitcast, load_symbol, load_symbol_and_layout, Env, RocFunctionCall, Scope,
complex_bitcast, load_roc_value, load_symbol, load_symbol_and_layout, Env, RocFunctionCall,
Scope,
};
use crate::llvm::build_list::{layout_width, pass_as_opaque};
use crate::llvm::convert::{basic_type_from_layout, zig_dict_type, zig_list_type};
@ -64,7 +65,6 @@ pub fn dict_len<'a, 'ctx, 'env>(
.build_int_cast(length_i64.into_int_value(), env.ptr_int(), "to_usize")
.into()
}
Layout::Builtin(Builtin::EmptyDict) => env.ptr_int().const_zero().into(),
_ => unreachable!("Invalid layout given to Dict.len : {:?}", dict_layout),
}
}
@ -811,7 +811,7 @@ fn build_hash_wrapper<'a, 'ctx, 'env>(
.build_bitcast(value_ptr, value_type, "load_opaque")
.into_pointer_value();
let val_arg = env.builder.build_load(value_cast, "load_opaque");
let val_arg = load_roc_value(env, *layout, value_cast, "load_opaque");
let result =
crate::llvm::build_hash::generic_hash(env, layout_ids, seed_arg, val_arg, layout);

View file

@ -136,9 +136,6 @@ fn hash_builtin<'a, 'ctx, 'env>(
)
.into_int_value()
}
Builtin::EmptyStr | Builtin::EmptyDict | Builtin::EmptyList | Builtin::EmptySet => {
hash_empty_collection(seed)
}
Builtin::Dict(_, _) => {
todo!("Implement hash for Dict")
@ -330,7 +327,6 @@ fn build_hash_tag<'a, 'ctx, 'env>(
let seed_type = env.context.i64_type();
let arg_type = basic_type_from_layout_1(env, layout);
dbg!(layout, arg_type);
let function_value = crate::llvm::refcounting::build_header_help(
env,
@ -446,9 +442,15 @@ fn hash_tag<'a, 'ctx, 'env>(
env.builder.position_at_end(entry_block);
let default = cases.pop().unwrap().1;
env.builder.build_switch(current_tag_id, default, &cases);
match cases.pop() {
Some((_, default)) => {
env.builder.build_switch(current_tag_id, default, &cases);
}
None => {
// we're hashing empty tag unions; this code is effectively unreachable
env.builder.build_unreachable();
}
}
}
Recursive(tags) => {
let current_tag_id = get_tag_id(env, parent, union_layout, tag);
@ -793,10 +795,6 @@ fn hash_null(seed: IntValue<'_>) -> IntValue<'_> {
seed
}
fn hash_empty_collection(seed: IntValue<'_>) -> IntValue<'_> {
seed
}
fn hash_ptr_to_struct<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,

View file

@ -150,12 +150,6 @@ pub fn list_join<'a, 'ctx, 'env>(
outer_list_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
match outer_list_layout {
Layout::Builtin(Builtin::EmptyList)
| Layout::Builtin(Builtin::List(Layout::Builtin(Builtin::EmptyList))) => {
// If the input list is empty, or if it is a list of empty lists
// then simply return an empty list
empty_list(env)
}
Layout::Builtin(Builtin::List(Layout::Builtin(Builtin::List(element_layout)))) => {
call_bitcode_fn_returns_list(
env,
@ -181,11 +175,6 @@ pub fn list_reverse<'a, 'ctx, 'env>(
update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> {
let element_layout = match *list_layout {
Layout::Builtin(Builtin::EmptyList) => {
// this pointer will never actually be dereferenced
Layout::i64()
}
Layout::Builtin(Builtin::List(elem_layout)) => *elem_layout,
_ => unreachable!("Invalid layout {:?} in List.reverse", list_layout),
@ -596,6 +585,14 @@ pub fn list_keep_if<'a, 'ctx, 'env>(
)
}
fn empty_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> {
let struct_type = super::convert::zig_list_type(env);
// The pointer should be null (aka zero) and the length should be zero,
// so the whole struct should be a const_zero
BasicValueEnum::StructValue(struct_type.const_zero())
}
/// List.keepOks : List before, (before -> Result after *) -> List after
pub fn list_keep_oks<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
@ -618,6 +615,10 @@ pub fn list_keep_oks<'a, 'ctx, 'env>(
let has_tag_id = match result_layout {
Layout::Union(union_layout) => build_has_tag_id(env, function, *union_layout),
Layout::Builtin(Builtin::Bool) => {
// a `Result [] whatever`, so there is nothing to keep
return empty_list(env);
}
_ => unreachable!(),
};
@ -662,6 +663,10 @@ pub fn list_keep_errs<'a, 'ctx, 'env>(
let has_tag_id = match result_layout {
Layout::Union(union_layout) => build_has_tag_id(env, function, *union_layout),
Layout::Builtin(Builtin::Bool) => {
// a `Result whatever []`, so there is nothing to keep
return empty_list(env);
}
_ => unreachable!(),
};
@ -881,11 +886,6 @@ pub fn list_concat<'a, 'ctx, 'env>(
list_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
match list_layout {
Layout::Builtin(Builtin::EmptyList) => {
// If the input list is empty, or if it is a list of empty lists
// then simply return an empty list
empty_list(env)
}
Layout::Builtin(Builtin::List(elem_layout)) => call_bitcode_fn_returns_list(
env,
&[
@ -1038,29 +1038,6 @@ pub fn list_find_unsafe<'a, 'ctx, 'env>(
.into()
}
/// Returns { value: \empty, found: False }, representing that no element was found in a call
/// to List.find when the layout of the element is also unknown.
pub fn list_find_trivial_not_found<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
) -> BasicValueEnum<'ctx> {
let empty_type = env.context.custom_width_int_type(0);
let result = env
.context
.struct_type(&[empty_type.into(), env.context.bool_type().into()], false)
.const_zero();
env.builder
.build_insert_value(
result,
env.context.bool_type().const_zero(),
1,
"insert_found",
)
.unwrap()
.into_struct_value()
.into()
}
pub fn decrementing_elem_loop<'ctx, LoopFn>(
builder: &Builder<'ctx>,
ctx: &'ctx Context,
@ -1269,15 +1246,6 @@ pub fn empty_polymorphic_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> Basi
BasicValueEnum::StructValue(struct_type.const_zero())
}
// TODO investigate: does this cause problems when the layout is known? this value is now not refcounted!
pub fn empty_list<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> {
let struct_type = super::convert::zig_list_type(env);
// The pointer should be null (aka zero) and the length should be zero,
// so the whole struct should be a const_zero
BasicValueEnum::StructValue(struct_type.const_zero())
}
pub fn load_list<'ctx>(
builder: &Builder<'ctx>,
wrapper_struct: StructValue<'ctx>,

View file

@ -14,6 +14,8 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
use super::build::load_roc_value;
#[derive(Clone, Debug)]
enum WhenRecursive<'a> {
Unreachable,
@ -135,12 +137,6 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
),
Builtin::Set(_elem) => todo!("equality on Set"),
Builtin::Dict(_key, _value) => todo!("equality on Dict"),
// empty structures are always equal to themselves
Builtin::EmptyStr => env.context.bool_type().const_int(1, false).into(),
Builtin::EmptyList => env.context.bool_type().const_int(1, false).into(),
Builtin::EmptyDict => env.context.bool_type().const_int(1, false).into(),
Builtin::EmptySet => env.context.bool_type().const_int(1, false).into(),
}
}
@ -310,12 +306,6 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
}
Builtin::Set(_elem) => todo!("equality on Set"),
Builtin::Dict(_key, _value) => todo!("equality on Dict"),
// empty structures are always equal to themselves
Builtin::EmptyStr => env.context.bool_type().const_int(0, false).into(),
Builtin::EmptyList => env.context.bool_type().const_int(0, false).into(),
Builtin::EmptyDict => env.context.bool_type().const_int(0, false).into(),
Builtin::EmptySet => env.context.bool_type().const_int(0, false).into(),
}
}
@ -533,13 +523,13 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
let elem1 = {
let elem_ptr =
unsafe { builder.build_in_bounds_gep(ptr1, &[curr_index], "load_index") };
builder.build_load(elem_ptr, "get_elem")
load_roc_value(env, *element_layout, elem_ptr, "get_elem")
};
let elem2 = {
let elem_ptr =
unsafe { builder.build_in_bounds_gep(ptr2, &[curr_index], "load_index") };
builder.build_load(elem_ptr, "get_elem")
load_roc_value(env, *element_layout, elem_ptr, "get_elem")
};
let are_equal = build_eq(
@ -882,6 +872,10 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
use UnionLayout::*;
match union_layout {
NonRecursive(&[]) => {
// we're comparing empty tag unions; this code is effectively unreachable
env.builder.build_unreachable();
}
NonRecursive(tags) => {
let ptr_equal = env.builder.build_int_compare(
IntPredicate::EQ,
@ -942,9 +936,15 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
env.builder.position_at_end(compare_tag_fields);
let default = cases.pop().unwrap().1;
env.builder.build_switch(id1, default, &cases);
match cases.pop() {
Some((_, default)) => {
env.builder.build_switch(id1, default, &cases);
}
None => {
// we're comparing empty tag unions; this code is effectively unreachable
env.builder.build_unreachable();
}
}
}
Recursive(tags) => {
let ptr_equal = env.builder.build_int_compare(

View file

@ -150,10 +150,10 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
Float(float_width) => float_type_from_float_width(env, *float_width).as_basic_type_enum(),
Bool => context.bool_type().as_basic_type_enum(),
Decimal => context.i128_type().as_basic_type_enum(),
Dict(_, _) | EmptyDict => zig_dict_type(env).into(),
Set(_) | EmptySet => zig_dict_type(env).into(),
List(_) | EmptyList => zig_list_type(env).into(),
Str | EmptyStr => zig_str_type(env).into(),
Dict(_, _) => zig_dict_type(env).into(),
Set(_) => zig_dict_type(env).into(),
List(_) => zig_list_type(env).into(),
Str => zig_str_type(env).into(),
}
}

View file

@ -593,21 +593,31 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
Union(variant) => {
use UnionLayout::*;
if let NonRecursive(tags) = variant {
let function = modify_refcount_union(env, layout_ids, mode, when_recursive, tags);
match variant {
NonRecursive(&[]) => {
// void type, nothing to refcount here
None
}
return Some(function);
NonRecursive(tags) => {
let function =
modify_refcount_union(env, layout_ids, mode, when_recursive, tags);
Some(function)
}
_ => {
let function = build_rec_union(
env,
layout_ids,
mode,
&WhenRecursive::Loop(*variant),
*variant,
);
Some(function)
}
}
let function = build_rec_union(
env,
layout_ids,
mode,
&WhenRecursive::Loop(*variant),
*variant,
);
Some(function)
}
Struct(layouts) => {