mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Merge remote-tracking branch 'origin/trunk' into list-str-capacity
This commit is contained in:
commit
68536e4026
31 changed files with 181 additions and 277 deletions
|
@ -4,7 +4,7 @@ use crate::lang::core::{expr::expr2::ExprId, header::AppHeader};
|
|||
pub fn parse_from_string(_header_str: &str, ast_node_id: ExprId) -> AppHeader {
|
||||
AppHeader {
|
||||
app_name: "\"untitled-app\"".to_owned(),
|
||||
packages_base: "\"platform\"".to_owned(),
|
||||
packages_base: "\"c-platform\"".to_owned(),
|
||||
imports: vec![],
|
||||
provides: vec!["main".to_owned()],
|
||||
ast_node_id,
|
||||
|
|
|
@ -243,7 +243,7 @@ fn add_header_mn_list(
|
|||
str_vec
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(indx, provide_str)| {
|
||||
.flat_map(|(indx, provide_str)| {
|
||||
let provide_str = header_val_mn(
|
||||
provide_str.to_owned(),
|
||||
ast_node_id,
|
||||
|
@ -266,7 +266,6 @@ fn add_header_mn_list(
|
|||
vec![provide_str]
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
|
@ -395,7 +395,7 @@ fn tree_as_string_helper(
|
|||
.to_owned();
|
||||
|
||||
let child = mark_node_pool.get(child_id);
|
||||
let child_str = format!("{}", mark_node_pool.get(child_id)).replace("\n", "\\n");
|
||||
let child_str = format!("{}", mark_node_pool.get(child_id)).replace('\n', "\\n");
|
||||
|
||||
full_str.push_str(&format!("{} mn_id {}\n", child_str, child_id));
|
||||
|
||||
|
|
|
@ -947,7 +947,7 @@ fn link_macos(
|
|||
Err(_) => "".to_string(),
|
||||
};
|
||||
for roc_link_flag in roc_link_flags.split_whitespace() {
|
||||
ld_command.arg(roc_link_flag.to_string());
|
||||
ld_command.arg(roc_link_flag);
|
||||
}
|
||||
|
||||
ld_command.args(&[
|
||||
|
|
|
@ -266,6 +266,7 @@ pub fn gen_from_mono_module_llvm(
|
|||
|| name.starts_with("roc_builtins.dec")
|
||||
|| name.starts_with("list.RocList")
|
||||
|| name.starts_with("dict.RocDict")
|
||||
|| name.contains("incref")
|
||||
|| name.contains("decref")
|
||||
{
|
||||
function.add_attribute(AttributeLoc::Function, enum_attr);
|
||||
|
|
|
@ -155,6 +155,7 @@ comptime {
|
|||
exportUtilsFn(utils.increfC, "incref");
|
||||
exportUtilsFn(utils.decrefC, "decref");
|
||||
exportUtilsFn(utils.decrefCheckNullC, "decref_check_null");
|
||||
exportUtilsFn(utils.allocateWithRefcountC, "allocate_with_refcount");
|
||||
exportExpectFn(expect.expectFailedC, "expect_failed");
|
||||
exportExpectFn(expect.getExpectFailuresC, "get_expect_failures");
|
||||
exportExpectFn(expect.deinitFailuresC, "deinit_failures");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const std = @import("std");
|
||||
const always_inline = std.builtin.CallOptions.Modifier.always_inline;
|
||||
const Monotonic = std.builtin.AtomicOrder.Monotonic;
|
||||
|
||||
pub fn WithOverflow(comptime T: type) type {
|
||||
return extern struct { value: T, has_overflowed: bool };
|
||||
|
@ -120,10 +121,32 @@ pub const IntWidth = enum(u8) {
|
|||
I128 = 9,
|
||||
};
|
||||
|
||||
const Refcount = enum {
|
||||
none,
|
||||
normal,
|
||||
atomic,
|
||||
};
|
||||
|
||||
const RC_TYPE = Refcount.normal;
|
||||
|
||||
pub fn increfC(ptr_to_refcount: *isize, amount: isize) callconv(.C) void {
|
||||
if (RC_TYPE == Refcount.none) return;
|
||||
var refcount = ptr_to_refcount.*;
|
||||
var masked_amount = if (refcount == REFCOUNT_MAX_ISIZE) 0 else amount;
|
||||
ptr_to_refcount.* = refcount + masked_amount;
|
||||
if (refcount < REFCOUNT_MAX_ISIZE) {
|
||||
switch (RC_TYPE) {
|
||||
Refcount.normal => {
|
||||
ptr_to_refcount.* = std.math.min(refcount + amount, REFCOUNT_MAX_ISIZE);
|
||||
},
|
||||
Refcount.atomic => {
|
||||
var next = std.math.min(refcount + amount, REFCOUNT_MAX_ISIZE);
|
||||
while (@cmpxchgWeak(isize, ptr_to_refcount, refcount, next, Monotonic, Monotonic)) |found| {
|
||||
refcount = found;
|
||||
next = std.math.min(refcount + amount, REFCOUNT_MAX_ISIZE);
|
||||
}
|
||||
},
|
||||
Refcount.none => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrefC(
|
||||
|
@ -169,71 +192,51 @@ inline fn decref_ptr_to_refcount(
|
|||
refcount_ptr: [*]isize,
|
||||
alignment: u32,
|
||||
) void {
|
||||
const refcount: isize = refcount_ptr[0];
|
||||
if (RC_TYPE == Refcount.none) return;
|
||||
const extra_bytes = std.math.max(alignment, @sizeOf(usize));
|
||||
|
||||
if (refcount == REFCOUNT_ONE_ISIZE) {
|
||||
dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment);
|
||||
} else if (refcount < 0) {
|
||||
refcount_ptr[0] = refcount - 1;
|
||||
switch (RC_TYPE) {
|
||||
Refcount.normal => {
|
||||
const refcount: isize = refcount_ptr[0];
|
||||
if (refcount == REFCOUNT_ONE_ISIZE) {
|
||||
dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment);
|
||||
} else if (refcount < REFCOUNT_MAX_ISIZE) {
|
||||
refcount_ptr[0] = refcount - 1;
|
||||
}
|
||||
},
|
||||
Refcount.atomic => {
|
||||
if (refcount_ptr[0] < REFCOUNT_MAX_ISIZE) {
|
||||
var last = @atomicRmw(isize, &refcount_ptr[0], std.builtin.AtomicRmwOp.Sub, 1, Monotonic);
|
||||
if (last == REFCOUNT_ONE_ISIZE) {
|
||||
dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment);
|
||||
}
|
||||
}
|
||||
},
|
||||
Refcount.none => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocateWithRefcountC(
|
||||
data_bytes: usize,
|
||||
element_alignment: u32,
|
||||
) callconv(.C) [*]u8 {
|
||||
return allocateWithRefcount(data_bytes, element_alignment);
|
||||
}
|
||||
|
||||
pub fn allocateWithRefcount(
|
||||
data_bytes: usize,
|
||||
element_alignment: u32,
|
||||
) [*]u8 {
|
||||
const alignment = std.math.max(@sizeOf(usize), element_alignment);
|
||||
const first_slot_offset = std.math.max(@sizeOf(usize), element_alignment);
|
||||
const ptr_width = @sizeOf(usize);
|
||||
const alignment = std.math.max(ptr_width, element_alignment);
|
||||
const length = alignment + data_bytes;
|
||||
|
||||
switch (alignment) {
|
||||
16 => {
|
||||
// TODO handle alloc failing!
|
||||
var new_bytes: [*]align(16) u8 = @alignCast(16, alloc(length, alignment) orelse unreachable);
|
||||
var new_bytes: [*]u8 = alloc(length, alignment) orelse unreachable;
|
||||
|
||||
var as_usize_array = @ptrCast([*]usize, new_bytes);
|
||||
as_usize_array[0] = 0;
|
||||
as_usize_array[1] = REFCOUNT_ONE;
|
||||
const data_ptr = new_bytes + alignment;
|
||||
const refcount_ptr = @ptrCast([*]usize, @alignCast(ptr_width, data_ptr) - ptr_width);
|
||||
refcount_ptr[0] = if (RC_TYPE == Refcount.none) REFCOUNT_MAX_ISIZE else REFCOUNT_ONE;
|
||||
|
||||
var as_u8_array = @ptrCast([*]u8, new_bytes);
|
||||
const first_slot = as_u8_array + first_slot_offset;
|
||||
|
||||
return first_slot;
|
||||
},
|
||||
8 => {
|
||||
// TODO handle alloc failing!
|
||||
var raw = alloc(length, alignment) orelse unreachable;
|
||||
var new_bytes: [*]align(8) u8 = @alignCast(8, raw);
|
||||
|
||||
var as_isize_array = @ptrCast([*]isize, new_bytes);
|
||||
as_isize_array[0] = REFCOUNT_ONE_ISIZE;
|
||||
|
||||
var as_u8_array = @ptrCast([*]u8, new_bytes);
|
||||
const first_slot = as_u8_array + first_slot_offset;
|
||||
|
||||
return first_slot;
|
||||
},
|
||||
4 => {
|
||||
// TODO handle alloc failing!
|
||||
var raw = alloc(length, alignment) orelse unreachable;
|
||||
var new_bytes: [*]align(@alignOf(isize)) u8 = @alignCast(@alignOf(isize), raw);
|
||||
|
||||
var as_isize_array = @ptrCast([*]isize, new_bytes);
|
||||
as_isize_array[0] = REFCOUNT_ONE_ISIZE;
|
||||
|
||||
var as_u8_array = @ptrCast([*]u8, new_bytes);
|
||||
const first_slot = as_u8_array + first_slot_offset;
|
||||
|
||||
return first_slot;
|
||||
},
|
||||
else => {
|
||||
// const stdout = std.io.getStdOut().writer();
|
||||
// stdout.print("alignment: {d}", .{alignment}) catch unreachable;
|
||||
// @panic("allocateWithRefcount with invalid alignment");
|
||||
unreachable;
|
||||
},
|
||||
}
|
||||
return data_ptr;
|
||||
}
|
||||
|
||||
pub const CSlice = extern struct {
|
||||
|
|
|
@ -371,6 +371,7 @@ pub const DEC_MUL_WITH_OVERFLOW: &str = "roc_builtins.dec.mul_with_overflow";
|
|||
pub const DEC_DIV: &str = "roc_builtins.dec.div";
|
||||
|
||||
pub const UTILS_TEST_PANIC: &str = "roc_builtins.utils.test_panic";
|
||||
pub const UTILS_ALLOCATE_WITH_REFCOUNT: &str = "roc_builtins.utils.allocate_with_refcount";
|
||||
pub const UTILS_INCREF: &str = "roc_builtins.utils.incref";
|
||||
pub const UTILS_DECREF: &str = "roc_builtins.utils.decref";
|
||||
pub const UTILS_DECREF_CHECK_NULL: &str = "roc_builtins.utils.decref_check_null";
|
||||
|
|
|
@ -166,8 +166,7 @@ fn sort_type_defs_before_introduction(
|
|||
Ok(result) => result
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|group_index| sccs[*group_index].iter())
|
||||
.flatten()
|
||||
.flat_map(|group_index| sccs[*group_index].iter())
|
||||
.copied()
|
||||
.collect(),
|
||||
|
||||
|
|
|
@ -281,8 +281,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
let transitive_builtins: Vec<Symbol> = referenced_values
|
||||
.iter()
|
||||
.filter(|s| s.is_builtin())
|
||||
.map(|s| crate::builtins::builtin_dependencies(*s))
|
||||
.flatten()
|
||||
.flat_map(|s| crate::builtins::builtin_dependencies(*s))
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ pub enum ParsedNumResult {
|
|||
pub fn finish_parsing_num(raw: &str) -> Result<ParsedNumResult, (&str, IntErrorKind)> {
|
||||
// Ignore underscores.
|
||||
let radix = 10;
|
||||
from_str_radix(raw.replace("_", "").as_str(), radix).map_err(|e| (raw, e))
|
||||
from_str_radix(raw.replace('_', "").as_str(), radix).map_err(|e| (raw, e))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -128,9 +128,9 @@ pub fn finish_parsing_base(
|
|||
|
||||
// Ignore underscores, insert - when negative to get correct underflow/overflow behavior
|
||||
(if is_negative {
|
||||
from_str_radix(format!("-{}", raw.replace("_", "")).as_str(), radix)
|
||||
from_str_radix(format!("-{}", raw.replace('_', "")).as_str(), radix)
|
||||
} else {
|
||||
from_str_radix(raw.replace("_", "").as_str(), radix)
|
||||
from_str_radix(raw.replace('_', "").as_str(), radix)
|
||||
})
|
||||
.and_then(|parsed| match parsed {
|
||||
ParsedNumResult::Float(..) => Err(IntErrorKind::FloatSuffix),
|
||||
|
@ -154,7 +154,7 @@ pub fn finish_parsing_float(raw: &str) -> Result<(f64, FloatBound), (&str, Float
|
|||
};
|
||||
|
||||
// Ignore underscores.
|
||||
match raw_without_suffix.replace("_", "").parse::<f64>() {
|
||||
match raw_without_suffix.replace('_', "").parse::<f64>() {
|
||||
Ok(float) if float.is_finite() => Ok((float, bound)),
|
||||
Ok(float) => {
|
||||
if float.is_sign_positive() {
|
||||
|
|
|
@ -185,8 +185,7 @@ fn is_exhaustive(matrix: &RefPatternMatrix, n: usize) -> PatternMatrix {
|
|||
alt_list
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(is_alt_exhaustive)
|
||||
.flatten()
|
||||
.flat_map(is_alt_exhaustive)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2063,8 +2063,7 @@ fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx, 'env>(
|
|||
|
||||
let alignment_bytes = fields
|
||||
.iter()
|
||||
.map(|tag| tag.iter().map(|l| l.alignment_bytes(env.target_info)))
|
||||
.flatten()
|
||||
.flat_map(|tag| tag.iter().map(|l| l.alignment_bytes(env.target_info)))
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
|
@ -2077,15 +2076,11 @@ fn reserve_with_refcount_help<'a, 'ctx, 'env>(
|
|||
stack_size: u32,
|
||||
alignment_bytes: u32,
|
||||
) -> PointerValue<'ctx> {
|
||||
let ctx = env.context;
|
||||
|
||||
let len_type = env.ptr_int();
|
||||
|
||||
let value_bytes_intvalue = len_type.const_int(stack_size as u64, false);
|
||||
|
||||
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.target_info);
|
||||
|
||||
allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue, rc1)
|
||||
allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue)
|
||||
}
|
||||
|
||||
pub fn allocate_with_refcount<'a, 'ctx, 'env>(
|
||||
|
@ -2106,74 +2101,22 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
|
|||
value_type: impl BasicType<'ctx>,
|
||||
alignment_bytes: u32,
|
||||
number_of_data_bytes: IntValue<'ctx>,
|
||||
initial_refcount: IntValue<'ctx>,
|
||||
) -> PointerValue<'ctx> {
|
||||
let builder = env.builder;
|
||||
let ptr = call_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
number_of_data_bytes.into(),
|
||||
env.alignment_const(alignment_bytes).into(),
|
||||
],
|
||||
roc_builtins::bitcode::UTILS_ALLOCATE_WITH_REFCOUNT,
|
||||
)
|
||||
.into_pointer_value();
|
||||
|
||||
let len_type = env.ptr_int();
|
||||
let ptr_width_u32 = env.target_info.ptr_width() as u32;
|
||||
let ptr_type = value_type.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let extra_bytes = alignment_bytes.max(ptr_width_u32);
|
||||
|
||||
let ptr = {
|
||||
// number of bytes we will allocated
|
||||
let number_of_bytes = builder.build_int_add(
|
||||
len_type.const_int(extra_bytes as u64, false),
|
||||
number_of_data_bytes,
|
||||
"add_extra_bytes",
|
||||
);
|
||||
|
||||
env.call_alloc(number_of_bytes, alignment_bytes)
|
||||
};
|
||||
|
||||
// We must return a pointer to the first element:
|
||||
let data_ptr = {
|
||||
let int_type = env.ptr_int();
|
||||
let as_usize_ptr = builder
|
||||
.build_bitcast(
|
||||
ptr,
|
||||
int_type.ptr_type(AddressSpace::Generic),
|
||||
"to_usize_ptr",
|
||||
)
|
||||
.into_pointer_value();
|
||||
|
||||
let index = match extra_bytes {
|
||||
n if n == ptr_width_u32 => 1,
|
||||
n if n == 2 * ptr_width_u32 => 2,
|
||||
_ => unreachable!("invalid extra_bytes, {}", extra_bytes),
|
||||
};
|
||||
|
||||
let index_intvalue = int_type.const_int(index, false);
|
||||
|
||||
let ptr_type = value_type.ptr_type(AddressSpace::Generic);
|
||||
|
||||
unsafe {
|
||||
builder.build_pointer_cast(
|
||||
env.builder
|
||||
.build_in_bounds_gep(as_usize_ptr, &[index_intvalue], "get_data_ptr"),
|
||||
ptr_type,
|
||||
"alloc_cast_to_desired",
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let refcount_ptr = match extra_bytes {
|
||||
n if n == ptr_width_u32 => {
|
||||
// the allocated pointer is the same as the refcounted pointer
|
||||
unsafe { PointerToRefcount::from_ptr(env, ptr) }
|
||||
}
|
||||
n if n == 2 * ptr_width_u32 => {
|
||||
// the refcount is stored just before the start of the actual data
|
||||
// but in this case (because of alignment) not at the start of the allocated buffer
|
||||
PointerToRefcount::from_ptr_to_data(env, data_ptr)
|
||||
}
|
||||
n => unreachable!("invalid extra_bytes {}", n),
|
||||
};
|
||||
|
||||
// let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes);
|
||||
refcount_ptr.set_refcount(env, initial_refcount);
|
||||
|
||||
data_ptr
|
||||
env.builder
|
||||
.build_bitcast(ptr, ptr_type, "alloc_cast_to_desired")
|
||||
.into_pointer_value()
|
||||
}
|
||||
|
||||
macro_rules! dict_key_value_layout {
|
||||
|
|
|
@ -1286,7 +1286,6 @@ pub fn allocate_list<'a, 'ctx, 'env>(
|
|||
number_of_elements: IntValue<'ctx>,
|
||||
) -> PointerValue<'ctx> {
|
||||
let builder = env.builder;
|
||||
let ctx = env.context;
|
||||
|
||||
let len_type = env.ptr_int();
|
||||
let elem_bytes = elem_layout.stack_size(env.target_info) as u64;
|
||||
|
@ -1294,13 +1293,9 @@ pub fn allocate_list<'a, 'ctx, 'env>(
|
|||
let number_of_data_bytes =
|
||||
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
|
||||
|
||||
// the refcount of a new list is initially 1
|
||||
// we assume that the list is indeed used (dead variables are eliminated)
|
||||
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.target_info);
|
||||
|
||||
let basic_type = basic_type_from_layout(env, elem_layout);
|
||||
let alignment_bytes = elem_layout.alignment_bytes(env.target_info);
|
||||
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes, rc1)
|
||||
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes)
|
||||
}
|
||||
|
||||
pub fn store_list<'a, 'ctx, 'env>(
|
||||
|
@ -1312,10 +1307,8 @@ pub fn store_list<'a, 'ctx, 'env>(
|
|||
|
||||
let struct_type = super::convert::zig_list_type(env);
|
||||
|
||||
let mut struct_val;
|
||||
|
||||
// Store the pointer
|
||||
struct_val = builder
|
||||
let mut struct_val = builder
|
||||
.build_insert_value(
|
||||
struct_type.get_undef(),
|
||||
pass_as_opaque(env, pointer_to_first_element),
|
||||
|
|
|
@ -8,7 +8,6 @@ use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list};
|
|||
use crate::llvm::convert::basic_type_from_layout;
|
||||
use bumpalo::collections::Vec;
|
||||
use inkwell::basic_block::BasicBlock;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::module::Linkage;
|
||||
use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum};
|
||||
use inkwell::values::{
|
||||
|
@ -18,22 +17,10 @@ use inkwell::{AddressSpace, IntPredicate};
|
|||
use roc_module::symbol::Interns;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
use super::build::load_roc_value;
|
||||
use super::convert::{argument_type_from_layout, 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;
|
||||
|
||||
pub fn refcount_1(ctx: &Context, target_info: TargetInfo) -> IntValue<'_> {
|
||||
match target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => ctx.i32_type().const_int(i32::MIN as u64, false),
|
||||
roc_target::PtrWidth::Bytes8 => ctx.i64_type().const_int(i64::MIN as u64, false),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PointerToRefcount<'ctx> {
|
||||
value: PointerValue<'ctx>,
|
||||
}
|
||||
|
@ -96,7 +83,14 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
|
||||
pub fn is_1<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>) -> IntValue<'ctx> {
|
||||
let current = self.get_refcount(env);
|
||||
let one = refcount_1(env.context, env.target_info);
|
||||
let one = match env.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => {
|
||||
env.context.i32_type().const_int(i32::MIN as u64, false)
|
||||
}
|
||||
roc_target::PtrWidth::Bytes8 => {
|
||||
env.context.i64_type().const_int(i64::MIN as u64, false)
|
||||
}
|
||||
};
|
||||
|
||||
env.builder
|
||||
.build_int_compare(IntPredicate::EQ, current, one, "is_one")
|
||||
|
@ -125,38 +119,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
}
|
||||
|
||||
fn increment<'a, 'env>(&self, amount: IntValue<'ctx>, env: &Env<'a, 'ctx, 'env>) {
|
||||
let refcount = self.get_refcount(env);
|
||||
let builder = env.builder;
|
||||
let refcount_type = env.ptr_int();
|
||||
|
||||
let is_static_allocation = builder.build_int_compare(
|
||||
IntPredicate::EQ,
|
||||
refcount,
|
||||
refcount_type.const_int(REFCOUNT_MAX as u64, false),
|
||||
"refcount_max_check",
|
||||
);
|
||||
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
let parent = block.get_parent().unwrap();
|
||||
|
||||
let modify_block = env
|
||||
.context
|
||||
.append_basic_block(parent, "inc_refcount_modify");
|
||||
let cont_block = env.context.append_basic_block(parent, "inc_refcount_cont");
|
||||
|
||||
env.builder
|
||||
.build_conditional_branch(is_static_allocation, cont_block, modify_block);
|
||||
|
||||
{
|
||||
env.builder.position_at_end(modify_block);
|
||||
|
||||
let incremented = builder.build_int_add(refcount, amount, "increment_refcount");
|
||||
self.set_refcount(env, incremented);
|
||||
|
||||
env.builder.build_unconditional_branch(cont_block);
|
||||
}
|
||||
|
||||
env.builder.position_at_end(cont_block);
|
||||
incref_pointer(env, self.value, amount);
|
||||
}
|
||||
|
||||
pub fn decrement<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) {
|
||||
|
@ -232,6 +195,25 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn incref_pointer<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
amount: IntValue<'ctx>,
|
||||
) {
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
env.builder.build_bitcast(
|
||||
pointer,
|
||||
env.ptr_int().ptr_type(AddressSpace::Generic),
|
||||
"to_isize_ptr",
|
||||
),
|
||||
amount.into(),
|
||||
],
|
||||
roc_builtins::bitcode::UTILS_INCREF,
|
||||
);
|
||||
}
|
||||
|
||||
fn decref_pointer<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
pointer: PointerValue<'ctx>,
|
||||
|
|
|
@ -121,8 +121,7 @@ fn start_phase<'a>(
|
|||
Recurse(new) => {
|
||||
return new
|
||||
.into_iter()
|
||||
.map(|(module_id, phase)| start_phase(module_id, phase, arena, state))
|
||||
.flatten()
|
||||
.flat_map(|(module_id, phase)| start_phase(module_id, phase, arena, state))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5971,7 +5971,7 @@ fn substitute_in_stmt_help<'a>(
|
|||
|
||||
if opt_remainder.is_some() || opt_continuation.is_some() {
|
||||
let remainder = opt_remainder.unwrap_or(remainder);
|
||||
let continuation = opt_continuation.unwrap_or_else(|| *continuation);
|
||||
let continuation = opt_continuation.unwrap_or(*continuation);
|
||||
|
||||
Some(arena.alloc(Join {
|
||||
id: *id,
|
||||
|
|
|
@ -1194,8 +1194,7 @@ impl<'a> Layout<'a> {
|
|||
match variant {
|
||||
NonRecursive(fields) => fields
|
||||
.iter()
|
||||
.map(|ls| ls.iter())
|
||||
.flatten()
|
||||
.flat_map(|ls| ls.iter())
|
||||
.any(|f| f.contains_refcounted()),
|
||||
Recursive(_)
|
||||
| NullableWrapped { .. }
|
||||
|
|
|
@ -117,7 +117,7 @@ fn insert_jumps<'a>(
|
|||
|
||||
if opt_remainder.is_some() || opt_continuation.is_some() {
|
||||
let remainder = opt_remainder.unwrap_or(remainder);
|
||||
let continuation = opt_continuation.unwrap_or_else(|| *continuation);
|
||||
let continuation = opt_continuation.unwrap_or(*continuation);
|
||||
|
||||
Some(arena.alloc(Join {
|
||||
id: *id,
|
||||
|
|
|
@ -966,8 +966,7 @@ impl Type {
|
|||
Self::contains_symbol_ext(ext, rep_symbol)
|
||||
|| tags
|
||||
.iter()
|
||||
.map(|v| v.1.iter())
|
||||
.flatten()
|
||||
.flat_map(|v| v.1.iter())
|
||||
.any(|arg| arg.contains_symbol(rep_symbol))
|
||||
}
|
||||
|
||||
|
@ -1026,8 +1025,7 @@ impl Type {
|
|||
Self::contains_variable_ext(ext, rep_variable)
|
||||
|| tags
|
||||
.iter()
|
||||
.map(|v| v.1.iter())
|
||||
.flatten()
|
||||
.flat_map(|v| v.1.iter())
|
||||
.any(|arg| arg.contains_variable(rep_variable))
|
||||
}
|
||||
|
||||
|
@ -1235,7 +1233,7 @@ impl Type {
|
|||
substitution.clear();
|
||||
substitution.insert(rec_var, Type::Variable(new_rec_var));
|
||||
|
||||
for typ in tags.iter_mut().map(|v| v.1.iter_mut()).flatten() {
|
||||
for typ in tags.iter_mut().flat_map(|v| v.1.iter_mut()) {
|
||||
typ.substitute(&substitution);
|
||||
}
|
||||
|
||||
|
@ -1353,7 +1351,7 @@ fn symbols_help(initial: &Type) -> Vec<Symbol> {
|
|||
}
|
||||
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
|
||||
stack.extend(ext);
|
||||
stack.extend(tags.iter().map(|v| v.1.iter()).flatten());
|
||||
stack.extend(tags.iter().flat_map(|v| v.1.iter()));
|
||||
}
|
||||
|
||||
Record(fields, ext) => {
|
||||
|
@ -2377,8 +2375,7 @@ pub fn gather_fields_unsorted_iter(
|
|||
|
||||
let it = stack
|
||||
.into_iter()
|
||||
.map(|fields| fields.iter_all())
|
||||
.flatten()
|
||||
.flat_map(|fields| fields.iter_all())
|
||||
.map(move |(i1, i2, i3)| {
|
||||
let field_name: &Lowercase = &subs[i1];
|
||||
let variable = subs[i2];
|
||||
|
@ -2462,8 +2459,7 @@ pub fn gather_tags_unsorted_iter(
|
|||
|
||||
let it = stack
|
||||
.into_iter()
|
||||
.map(|union_tags| union_tags.iter_all())
|
||||
.flatten()
|
||||
.flat_map(|union_tags| union_tags.iter_all())
|
||||
.map(move |(i1, i2)| {
|
||||
let tag_name: &TagName = &subs[i1];
|
||||
let subs_slice = subs[i2];
|
||||
|
|
|
@ -262,11 +262,7 @@ fn check_valid_range(
|
|||
range: VariableSubsSlice,
|
||||
mode: Mode,
|
||||
) -> Outcome {
|
||||
let slice = subs
|
||||
.get_subs_slice(range)
|
||||
.iter()
|
||||
.copied()
|
||||
.collect::<Vec<_>>();
|
||||
let slice = subs.get_subs_slice(range).to_vec();
|
||||
|
||||
let mut it = slice.iter().peekable();
|
||||
while let Some(&possible_var) = it.next() {
|
||||
|
@ -1432,7 +1428,7 @@ fn unify_recursion(
|
|||
} => {
|
||||
// NOTE: structure and other_structure may not be unified yet, but will be
|
||||
// we should not do that here, it would create an infinite loop!
|
||||
let name = (*opt_name).or_else(|| *other_opt_name);
|
||||
let name = (*opt_name).or(*other_opt_name);
|
||||
merge(
|
||||
subs,
|
||||
ctx,
|
||||
|
|
|
@ -83,7 +83,7 @@ pub fn generate_docs_html(filenames: Vec<PathBuf>, build_dir: &Path) {
|
|||
// Write each package's module docs html file
|
||||
for loaded_module in package.modules.iter_mut() {
|
||||
for module_docs in loaded_module.documentation.values() {
|
||||
let module_dir = build_dir.join(module_docs.name.replace(".", "/").as_str());
|
||||
let module_dir = build_dir.join(module_docs.name.replace('.', "/").as_str());
|
||||
|
||||
fs::create_dir_all(&module_dir)
|
||||
.expect("TODO gracefully handle not being able to create the module dir");
|
||||
|
|
|
@ -70,7 +70,7 @@ impl fmt::Display for CodeLines {
|
|||
.collect::<Vec<String>>()
|
||||
.join(" ");
|
||||
|
||||
let escaped_row_str = row_str.replace("\n", "\\n");
|
||||
let escaped_row_str = row_str.replace('\n', "\\n");
|
||||
|
||||
write!(f, "\n{}", escaped_row_str)?;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use super::keyboard_input;
|
||||
use super::resources::strings::PLATFORM_NAME;
|
||||
use crate::editor::mvc::ed_view;
|
||||
use crate::editor::mvc::ed_view::RenderedWgpu;
|
||||
use crate::editor::resources::strings::{HELLO_WORLD, NOTHING_OPENED};
|
||||
|
@ -17,7 +18,6 @@ use crate::graphics::{
|
|||
primitives::text::{build_glyph_brush, example_code_glyph_rect, queue_text_draw, Text},
|
||||
};
|
||||
use crate::ui::text::caret_w_select::CaretPos;
|
||||
use crate::ui::util::path_to_string;
|
||||
use bumpalo::Bump;
|
||||
use cgmath::Vector2;
|
||||
use fs_extra::dir::{copy, ls, CopyOptions, DirEntryAttr, DirEntryValue};
|
||||
|
@ -31,6 +31,7 @@ use roc_types::subs::VarStore;
|
|||
use std::collections::HashSet;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::{error::Error, io, path::Path};
|
||||
use wgpu::{CommandEncoder, LoadOp, RenderPass, TextureView};
|
||||
use wgpu_glyph::GlyphBrush;
|
||||
|
@ -125,7 +126,7 @@ fn run_event_loop(project_dir_path_opt: Option<&Path>) -> Result<(), Box<dyn Err
|
|||
let code_arena = Bump::new();
|
||||
|
||||
let (file_path_str, code_str) = read_main_roc_file(project_dir_path_opt);
|
||||
println!("Loading file {}...", file_path_str);
|
||||
println!("Loading file {:?}...", file_path_str);
|
||||
|
||||
let file_path = Path::new(&file_path_str);
|
||||
|
||||
|
@ -266,7 +267,6 @@ fn run_event_loop(project_dir_path_opt: Option<&Path>) -> Result<(), Box<dyn Err
|
|||
} => {
|
||||
keyboard_modifiers = modifiers;
|
||||
}
|
||||
Event::MainEventsCleared => window.request_redraw(),
|
||||
Event::RedrawRequested { .. } => {
|
||||
// Get a command encoder for the current frame
|
||||
let mut encoder =
|
||||
|
@ -467,9 +467,7 @@ fn begin_render_pass<'a>(
|
|||
})
|
||||
}
|
||||
|
||||
type PathStr = String;
|
||||
|
||||
fn read_main_roc_file(project_dir_path_opt: Option<&Path>) -> (PathStr, String) {
|
||||
fn read_main_roc_file(project_dir_path_opt: Option<&Path>) -> (PathBuf, String) {
|
||||
if let Some(project_dir_path) = project_dir_path_opt {
|
||||
let mut ls_config = HashSet::new();
|
||||
ls_config.insert(DirEntryAttr::FullName);
|
||||
|
@ -478,64 +476,58 @@ fn read_main_roc_file(project_dir_path_opt: Option<&Path>) -> (PathStr, String)
|
|||
.unwrap_or_else(|err| panic!("Failed to list items in project directory: {:?}", err))
|
||||
.items;
|
||||
|
||||
let file_names = dir_items
|
||||
.iter()
|
||||
.map(|info_hash_map| {
|
||||
info_hash_map
|
||||
.values()
|
||||
.map(|dir_entry_value| {
|
||||
if let DirEntryValue::String(file_name) = dir_entry_value {
|
||||
Some(file_name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.flatten() // remove None
|
||||
.collect::<Vec<&String>>()
|
||||
})
|
||||
.flatten();
|
||||
let file_names = dir_items.iter().flat_map(|info_hash_map| {
|
||||
info_hash_map
|
||||
.values()
|
||||
.filter_map(|dir_entry_value| {
|
||||
if let DirEntryValue::String(file_name) = dir_entry_value {
|
||||
Some(file_name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<&String>>()
|
||||
});
|
||||
|
||||
let roc_file_names: Vec<&String> = file_names
|
||||
.filter(|file_name| file_name.contains(".roc"))
|
||||
.collect();
|
||||
|
||||
let project_dir_path_str = path_to_string(project_dir_path);
|
||||
|
||||
if let Some(&roc_file_name) = roc_file_names.first() {
|
||||
let full_roc_file_path_str = path_to_string(&project_dir_path.join(roc_file_name));
|
||||
let file_as_str = std::fs::read_to_string(&Path::new(&full_roc_file_path_str))
|
||||
.unwrap_or_else(|err| panic!("In the provided project {:?}, I found the roc file {}, but I failed to read it: {}", &project_dir_path_str, &full_roc_file_path_str, err));
|
||||
let full_roc_file_path = project_dir_path.join(roc_file_name);
|
||||
let file_as_str = std::fs::read_to_string(&Path::new(&full_roc_file_path))
|
||||
.unwrap_or_else(|err| panic!("In the provided project {:?}, I found the roc file {:?}, but I failed to read it: {}", &project_dir_path, full_roc_file_path, err));
|
||||
|
||||
(full_roc_file_path_str, file_as_str)
|
||||
(full_roc_file_path, file_as_str)
|
||||
} else {
|
||||
init_new_roc_project(&project_dir_path_str)
|
||||
init_new_roc_project(project_dir_path)
|
||||
}
|
||||
} else {
|
||||
init_new_roc_project("new-roc-project")
|
||||
init_new_roc_project(Path::new("./new-roc-project"))
|
||||
}
|
||||
}
|
||||
|
||||
// returns path and content of app file
|
||||
fn init_new_roc_project(project_dir_path_str: &str) -> (PathStr, String) {
|
||||
let orig_platform_path = Path::new("./examples/hello-c/platform");
|
||||
fn init_new_roc_project(project_dir_path: &Path) -> (PathBuf, String) {
|
||||
let orig_platform_path = Path::new("./examples/hello-world").join(PLATFORM_NAME);
|
||||
|
||||
let project_dir_path = Path::new(project_dir_path_str);
|
||||
|
||||
let roc_file_path_str = vec![project_dir_path_str, "/UntitledApp.roc"].join("");
|
||||
let roc_file_path = Path::new("./new-roc-project/UntitledApp.roc");
|
||||
|
||||
let project_platform_path_str = vec![project_dir_path_str, "/platform"].join("");
|
||||
let project_platform_path = Path::new(&project_platform_path_str);
|
||||
let project_platform_path = project_dir_path.join(PLATFORM_NAME);
|
||||
|
||||
if !project_dir_path.exists() {
|
||||
fs::create_dir(project_dir_path).expect("Failed to create dir for roc project.");
|
||||
}
|
||||
|
||||
copy_roc_platform_if_not_exists(orig_platform_path, project_platform_path, project_dir_path);
|
||||
copy_roc_platform_if_not_exists(
|
||||
&orig_platform_path,
|
||||
&project_platform_path,
|
||||
project_dir_path,
|
||||
);
|
||||
|
||||
let code_str = create_roc_file_if_not_exists(project_dir_path, roc_file_path);
|
||||
|
||||
(roc_file_path_str, code_str)
|
||||
(roc_file_path.to_path_buf(), code_str)
|
||||
}
|
||||
|
||||
// returns contents of file
|
||||
|
|
|
@ -220,7 +220,9 @@ impl<'a> EdModule<'a> {
|
|||
pub mod test_ed_model {
|
||||
use crate::editor::ed_error::EdResult;
|
||||
use crate::editor::mvc::ed_model;
|
||||
use crate::editor::resources::strings::{nr_hello_world_lines, HELLO_WORLD, PLATFORM_STR};
|
||||
use crate::editor::resources::strings::{
|
||||
nr_hello_world_lines, HELLO_WORLD, PLATFORM_NAME, PLATFORM_STR,
|
||||
};
|
||||
use crate::ui::text::caret_w_select::test_caret_w_select::convert_dsl_to_selection;
|
||||
use crate::ui::text::caret_w_select::test_caret_w_select::convert_selection_to_dsl;
|
||||
use crate::ui::text::caret_w_select::CaretPos;
|
||||
|
@ -307,7 +309,7 @@ pub mod test_ed_model {
|
|||
|
||||
let temp_dir = tempdir().expect("Failed to create temporary directory for test.");
|
||||
|
||||
let platform_dir = temp_dir.path().join("platform");
|
||||
let platform_dir = temp_dir.path().join(PLATFORM_NAME);
|
||||
fs::create_dir(platform_dir.clone()).expect("Failed to create platform directory");
|
||||
let package_config_path = platform_dir.join("Package-Config.roc");
|
||||
let mut package_config_file =
|
||||
|
|
|
@ -137,7 +137,7 @@ fn markup_to_wgpu_helper<'a>(
|
|||
} => {
|
||||
let highlight_color = map_get(&code_style.ed_theme.syntax_high_map, syn_high_style)?;
|
||||
|
||||
let full_content = markup_node.get_full_content().replace("\n", "\\n"); // any \n left here should be escaped so that it can be shown as \n
|
||||
let full_content = markup_node.get_full_content().replace('\n', "\\n"); // any \n left here should be escaped so that it can be shown as \n
|
||||
|
||||
let glyph_text = glyph_brush::OwnedText::new(&full_content)
|
||||
.with_color(colors::to_slice(*highlight_color))
|
||||
|
|
|
@ -17,7 +17,7 @@ For convenience and consistency, there is only one way to format roc.
|
|||
|
||||
pub const HELLO_WORLD: &str = r#"
|
||||
app "test-app"
|
||||
packages { pf: "platform" }
|
||||
packages { pf: "c-platform" }
|
||||
imports []
|
||||
provides [ main ] to pf
|
||||
|
||||
|
@ -29,6 +29,8 @@ pub fn nr_hello_world_lines() -> usize {
|
|||
HELLO_WORLD.matches('\n').count() - 1
|
||||
}
|
||||
|
||||
pub const PLATFORM_NAME: &str = "c-platform";
|
||||
|
||||
pub const PLATFORM_STR: &str = r#"
|
||||
platform "test-platform"
|
||||
requires {} { main : Str }
|
||||
|
|
|
@ -187,7 +187,6 @@ fn run_event_loop(title: &str, root: RocElem) -> Result<(), Box<dyn Error>> {
|
|||
} => {
|
||||
keyboard_modifiers = modifiers;
|
||||
}
|
||||
Event::MainEventsCleared => window.request_redraw(),
|
||||
Event::RedrawRequested { .. } => {
|
||||
// Get a command cmd_encoder for the current frame
|
||||
let mut cmd_encoder =
|
||||
|
|
|
@ -416,7 +416,7 @@ fn preprocess_impl(
|
|||
})
|
||||
.map(|(_, reloc)| reloc)
|
||||
.filter(|reloc| matches!(reloc.kind(), RelocationKind::Elf(6)))
|
||||
.map(|reloc| {
|
||||
.filter_map(|reloc| {
|
||||
for symbol in app_syms.iter() {
|
||||
if reloc.target() == RelocationTarget::Symbol(symbol.index()) {
|
||||
return Some((symbol.name().unwrap().to_string(), symbol.index().0));
|
||||
|
@ -424,7 +424,6 @@ fn preprocess_impl(
|
|||
}
|
||||
None
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
for sym in app_syms.iter() {
|
||||
|
|
|
@ -1823,11 +1823,11 @@ fn to_precord_report<'a>(
|
|||
}
|
||||
|
||||
PRecord::IndentColon(_) => {
|
||||
unreachable!("because `{ foo }` is a valid field; the colon is not required")
|
||||
unreachable!("because `foo` is a valid field; the colon is not required")
|
||||
}
|
||||
|
||||
PRecord::IndentOptional(_) => {
|
||||
unreachable!("because `{ foo }` is a valid field; the question mark is not required")
|
||||
unreachable!("because `foo` is a valid field; the question mark is not required")
|
||||
}
|
||||
|
||||
PRecord::Space(error, pos) => to_space_report(alloc, lines, filename, &error, pos),
|
||||
|
@ -2288,10 +2288,10 @@ fn to_trecord_report<'a>(
|
|||
},
|
||||
|
||||
ETypeRecord::Colon(_) => {
|
||||
unreachable!("because `{ foo }` is a valid field; the colon is not required")
|
||||
unreachable!("because `foo` is a valid field; the colon is not required")
|
||||
}
|
||||
ETypeRecord::Optional(_) => {
|
||||
unreachable!("because `{ foo }` is a valid field; the question mark is not required")
|
||||
unreachable!("because `foo` is a valid field; the question mark is not required")
|
||||
}
|
||||
|
||||
ETypeRecord::Type(tipe, pos) => to_type_report(alloc, lines, filename, tipe, pos),
|
||||
|
@ -2371,11 +2371,11 @@ fn to_trecord_report<'a>(
|
|||
}
|
||||
|
||||
ETypeRecord::IndentColon(_) => {
|
||||
unreachable!("because `{ foo }` is a valid field; the colon is not required")
|
||||
unreachable!("because `foo` is a valid field; the colon is not required")
|
||||
}
|
||||
|
||||
ETypeRecord::IndentOptional(_) => {
|
||||
unreachable!("because `{ foo }` is a valid field; the question mark is not required")
|
||||
unreachable!("because `foo` is a valid field; the question mark is not required")
|
||||
}
|
||||
|
||||
ETypeRecord::Space(error, pos) => to_space_report(alloc, lines, filename, &error, pos),
|
||||
|
|
8
vendor/morphic_lib/src/preprocess.rs
vendored
8
vendor/morphic_lib/src/preprocess.rs
vendored
|
@ -774,7 +774,7 @@ fn preprocess_op(
|
|||
debug_assert_eq!(inputs.len(), 1);
|
||||
|
||||
let cont_binding = continuations_in_scope[continuation]
|
||||
.ok_or_else(|| ErrorKind::ContinuationNotInScope(*continuation))?;
|
||||
.ok_or(ErrorKind::ContinuationNotInScope(*continuation))?;
|
||||
|
||||
check_type(ctx.nc, tc, cont_binding.arg_type, input_types[0])?;
|
||||
|
||||
|
@ -1045,7 +1045,7 @@ fn preprocess_op(
|
|||
let field_types = try_get_tuple_field_types(ctx.nc, tc, tuple_type)?;
|
||||
let field_type = *field_types
|
||||
.get(*field_idx as usize)
|
||||
.ok_or_else(|| ErrorKind::TupleFieldOutOfRange(*field_idx))?;
|
||||
.ok_or(ErrorKind::TupleFieldOutOfRange(*field_idx))?;
|
||||
let value = graph_builder.add_op(
|
||||
block,
|
||||
ir::OpKind::GetTupleField {
|
||||
|
@ -1068,7 +1068,7 @@ fn preprocess_op(
|
|||
.collect();
|
||||
let this_variant_type = *tc_variant_types
|
||||
.get(*variant_idx as usize)
|
||||
.ok_or_else(|| ErrorKind::UnionVariantOutOfRange(*variant_idx))?;
|
||||
.ok_or(ErrorKind::UnionVariantOutOfRange(*variant_idx))?;
|
||||
check_type(ctx.nc, tc, this_variant_type, input_types[0])?;
|
||||
let union_type = tc.types.get_or_insert(TypeData::Union {
|
||||
variants: tc_variant_types,
|
||||
|
@ -1089,7 +1089,7 @@ fn preprocess_op(
|
|||
let variant_types = try_get_union_variant_types(ctx.nc, tc, input_types[0])?;
|
||||
let this_variant_type = *variant_types
|
||||
.get(*variant_idx as usize)
|
||||
.ok_or_else(|| ErrorKind::UnionVariantOutOfRange(*variant_idx))?;
|
||||
.ok_or(ErrorKind::UnionVariantOutOfRange(*variant_idx))?;
|
||||
let value = graph_builder.add_op(
|
||||
block,
|
||||
ir::OpKind::UnwrapUnion {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue