mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 20:28:02 +00:00
Merge pull request #5539 from roc-lang/dev-gen-primitives
dev backend: de-duplicate function names based on the lambda set
This commit is contained in:
commit
b3c598fcf6
10 changed files with 433 additions and 126 deletions
|
@ -965,33 +965,32 @@ impl Assembler<AArch64GeneralReg, AArch64FloatReg> for AArch64Assembler {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn movsx_reg64_base32(buf: &mut Vec<'_, u8>, dst: AArch64GeneralReg, offset: i32, size: u8) {
|
||||
debug_assert!(size <= 8);
|
||||
if size == 8 {
|
||||
Self::mov_reg64_base32(buf, dst, offset);
|
||||
} else if size == 4 {
|
||||
todo!("sign extending 4 byte values");
|
||||
} else if size == 2 {
|
||||
todo!("sign extending 2 byte values");
|
||||
} else if size == 1 {
|
||||
todo!("sign extending 1 byte values");
|
||||
} else {
|
||||
internal_error!("Invalid size for sign extension: {}", size);
|
||||
fn movsx_reg_base32(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
register_width: RegisterWidth,
|
||||
dst: AArch64GeneralReg,
|
||||
offset: i32,
|
||||
) {
|
||||
match register_width {
|
||||
RegisterWidth::W8 => todo!("sign extend 1 byte values"),
|
||||
RegisterWidth::W16 => todo!("sign extend 2 byte values"),
|
||||
RegisterWidth::W32 => todo!("sign extend 4 byte values"),
|
||||
RegisterWidth::W64 => Self::mov_reg64_base32(buf, dst, offset),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn movzx_reg64_base32(buf: &mut Vec<'_, u8>, dst: AArch64GeneralReg, offset: i32, size: u8) {
|
||||
debug_assert!(size <= 8);
|
||||
if size == 8 {
|
||||
Self::mov_reg64_base32(buf, dst, offset);
|
||||
} else if size == 4 {
|
||||
todo!("zero extending 4 byte values");
|
||||
} else if size == 2 {
|
||||
todo!("zero extending 2 byte values");
|
||||
} else if size == 1 {
|
||||
todo!("zero extending 1 byte values");
|
||||
} else {
|
||||
internal_error!("Invalid size for zero extension: {}", size);
|
||||
fn movzx_reg_base32(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
register_width: RegisterWidth,
|
||||
dst: AArch64GeneralReg,
|
||||
offset: i32,
|
||||
) {
|
||||
match register_width {
|
||||
RegisterWidth::W8 => todo!("zero extend 1 byte values"),
|
||||
RegisterWidth::W16 => todo!("zero extend 2 byte values"),
|
||||
RegisterWidth::W32 => todo!("zero extend 4 byte values"),
|
||||
RegisterWidth::W64 => Self::mov_reg64_base32(buf, dst, offset),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ use roc_mono::ir::{
|
|||
SelfRecursive, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, InLayout, Layout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner,
|
||||
Builtin, InLayout, LambdaName, Layout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner,
|
||||
TagIdIntType, UnionLayout,
|
||||
};
|
||||
use roc_mono::low_level::HigherOrder;
|
||||
|
@ -391,10 +391,19 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
|
|||
|
||||
/// Sign extends the data at `offset` with `size` as it copies it to `dst`
|
||||
/// size must be less than or equal to 8.
|
||||
fn movsx_reg64_base32(buf: &mut Vec<'_, u8>, dst: GeneralReg, offset: i32, size: u8);
|
||||
/// Zero extends the data at `offset` with `size` as it copies it to `dst`
|
||||
/// size must be less than or equal to 8.
|
||||
fn movzx_reg64_base32(buf: &mut Vec<'_, u8>, dst: GeneralReg, offset: i32, size: u8);
|
||||
fn movsx_reg_base32(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
register_width: RegisterWidth,
|
||||
dst: GeneralReg,
|
||||
offset: i32,
|
||||
);
|
||||
|
||||
fn movzx_reg_base32(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
register_width: RegisterWidth,
|
||||
dst: GeneralReg,
|
||||
offset: i32,
|
||||
);
|
||||
|
||||
fn mov_freg64_stack32(buf: &mut Vec<'_, u8>, dst: FloatReg, offset: i32);
|
||||
fn mov_reg64_stack32(buf: &mut Vec<'_, u8>, dst: GeneralReg, offset: i32);
|
||||
|
@ -1590,8 +1599,8 @@ impl<
|
|||
HelperOp::Eq,
|
||||
);
|
||||
|
||||
let fn_name = self.function_symbol_to_string(
|
||||
eq_symbol,
|
||||
let fn_name = self.lambda_name_to_string(
|
||||
LambdaName::no_niche(eq_symbol),
|
||||
[*arg_layout, *arg_layout].into_iter(),
|
||||
None,
|
||||
Layout::U8,
|
||||
|
@ -1815,6 +1824,34 @@ impl<
|
|||
);
|
||||
}
|
||||
|
||||
fn build_num_cmp(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
arg_layout: &InLayout<'a>,
|
||||
) {
|
||||
// This implements the expression:
|
||||
// (x != y) as u8 + (x < y) as u8
|
||||
// For x==y: (false as u8) + (false as u8) = 0 = RocOrder::Eq
|
||||
// For x>y: (true as u8) + (false as u8) = 1 = RocOrder::Gt
|
||||
// For x<y: (true as u8) + (true as u8) = 2 = RocOrder::Lt
|
||||
// u8 is represented in the stack machine as i32, but written to memory as 1 byte
|
||||
let not_equal = self.debug_symbol("not_equal");
|
||||
|
||||
self.build_neq(¬_equal, src1, src2, arg_layout);
|
||||
self.build_num_lt(dst, src1, src2, arg_layout);
|
||||
|
||||
let neq_reg = self
|
||||
.storage_manager
|
||||
.load_to_general_reg(&mut self.buf, ¬_equal);
|
||||
let dst_reg = self.storage_manager.load_to_general_reg(&mut self.buf, dst);
|
||||
|
||||
ASM::add_reg64_reg64_reg64(&mut self.buf, dst_reg, dst_reg, neq_reg);
|
||||
|
||||
self.free_symbol(¬_equal);
|
||||
}
|
||||
|
||||
fn build_num_lt(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
|
@ -1947,8 +1984,8 @@ impl<
|
|||
self.load_layout_stack_size(old_element_layout, old_element_width);
|
||||
self.load_layout_stack_size(new_element_layout, new_element_width);
|
||||
|
||||
let caller_string = self.function_symbol_to_string(
|
||||
caller_proc.proc_symbol,
|
||||
let caller_string = self.lambda_name_to_string(
|
||||
LambdaName::no_niche(caller_proc.proc_symbol),
|
||||
std::iter::empty(),
|
||||
None,
|
||||
Layout::UNIT,
|
||||
|
@ -4047,10 +4084,12 @@ impl<
|
|||
}
|
||||
IntWidth::I16 | IntWidth::U16 => {
|
||||
let dst_reg = storage_manager.claim_general_reg(buf, &dst);
|
||||
ASM::xor_reg64_reg64_reg64(buf, dst_reg, dst_reg, dst_reg);
|
||||
ASM::mov_reg16_mem16_offset32(buf, dst_reg, ptr_reg, offset);
|
||||
}
|
||||
IntWidth::I8 | IntWidth::U8 => {
|
||||
let dst_reg = storage_manager.claim_general_reg(buf, &dst);
|
||||
ASM::xor_reg64_reg64_reg64(buf, dst_reg, dst_reg, dst_reg);
|
||||
ASM::mov_reg8_mem8_offset32(buf, dst_reg, ptr_reg, offset);
|
||||
}
|
||||
},
|
||||
|
@ -4065,6 +4104,8 @@ impl<
|
|||
Builtin::Bool => {
|
||||
// the same as an 8-bit integer
|
||||
let dst_reg = storage_manager.claim_general_reg(buf, &dst);
|
||||
|
||||
ASM::xor_reg64_reg64_reg64(buf, dst_reg, dst_reg, dst_reg);
|
||||
ASM::mov_reg8_mem8_offset32(buf, dst_reg, ptr_reg, offset);
|
||||
}
|
||||
Builtin::Decimal => {
|
||||
|
|
|
@ -23,6 +23,8 @@ use RegStorage::*;
|
|||
use StackStorage::*;
|
||||
use Storage::*;
|
||||
|
||||
use super::RegisterWidth;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum RegStorage<GeneralReg: RegTrait, FloatReg: RegTrait> {
|
||||
General(GeneralReg),
|
||||
|
@ -343,10 +345,19 @@ impl<
|
|||
sign_extend,
|
||||
}) => {
|
||||
let reg = self.get_general_reg(buf);
|
||||
|
||||
let register_width = match size {
|
||||
8 => RegisterWidth::W64,
|
||||
4 => RegisterWidth::W32,
|
||||
2 => RegisterWidth::W16,
|
||||
1 => RegisterWidth::W8,
|
||||
_ => internal_error!("Invalid size: {size}"),
|
||||
};
|
||||
|
||||
if sign_extend {
|
||||
ASM::movsx_reg64_base32(buf, reg, base_offset, size as u8);
|
||||
ASM::movsx_reg_base32(buf, register_width, reg, base_offset);
|
||||
} else {
|
||||
ASM::movzx_reg64_base32(buf, reg, base_offset, size as u8);
|
||||
ASM::movzx_reg_base32(buf, register_width, reg, base_offset);
|
||||
}
|
||||
self.general_used_regs.push((reg, *sym));
|
||||
self.symbol_storage_map.insert(*sym, Reg(General(reg)));
|
||||
|
@ -469,10 +480,18 @@ impl<
|
|||
}) => {
|
||||
debug_assert!(*size <= 8);
|
||||
|
||||
let register_width = match size {
|
||||
8 => RegisterWidth::W64,
|
||||
4 => RegisterWidth::W32,
|
||||
2 => RegisterWidth::W16,
|
||||
1 => RegisterWidth::W8,
|
||||
_ => internal_error!("Invalid size: {size}"),
|
||||
};
|
||||
|
||||
if *sign_extend {
|
||||
ASM::movsx_reg64_base32(buf, reg, *base_offset, *size as u8)
|
||||
ASM::movsx_reg_base32(buf, register_width, reg, *base_offset)
|
||||
} else {
|
||||
ASM::movzx_reg64_base32(buf, reg, *base_offset, *size as u8)
|
||||
ASM::movzx_reg_base32(buf, register_width, reg, *base_offset)
|
||||
}
|
||||
}
|
||||
Stack(Complex { size, .. }) => {
|
||||
|
|
|
@ -1687,29 +1687,39 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn movsx_reg64_base32(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, offset: i32, size: u8) {
|
||||
debug_assert!(size <= 8);
|
||||
match size {
|
||||
8 => Self::mov_reg64_base32(buf, dst, offset),
|
||||
4 => movsx_reg64_base32_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
2 => movsx_reg64_base16_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
1 => movsx_reg64_base8_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
_ => internal_error!("Invalid size for sign extension: {size}"),
|
||||
fn movsx_reg_base32(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
register_width: RegisterWidth,
|
||||
dst: X86_64GeneralReg,
|
||||
offset: i32,
|
||||
) {
|
||||
use RegisterWidth::*;
|
||||
|
||||
match register_width {
|
||||
W64 => Self::mov_reg64_base32(buf, dst, offset),
|
||||
W32 => movsx_reg64_base32_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
W16 => movsx_reg64_base16_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
W8 => movsx_reg64_base8_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
}
|
||||
}
|
||||
#[inline(always)]
|
||||
fn movzx_reg64_base32(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, offset: i32, size: u8) {
|
||||
debug_assert!(size <= 8);
|
||||
match size {
|
||||
8 => Self::mov_reg64_base32(buf, dst, offset),
|
||||
4 => {
|
||||
fn movzx_reg_base32(
|
||||
buf: &mut Vec<'_, u8>,
|
||||
register_width: RegisterWidth,
|
||||
dst: X86_64GeneralReg,
|
||||
offset: i32,
|
||||
) {
|
||||
use RegisterWidth::*;
|
||||
|
||||
match register_width {
|
||||
W64 => Self::mov_reg64_base32(buf, dst, offset),
|
||||
W32 => {
|
||||
// The Intel documentation (3.4.1.1 General-Purpose Registers in 64-Bit Mode in manual Basic Architecture))
|
||||
// 32-bit operands generate a 32-bit result, zero-extended to a 64-bit result in the destination general-purpose register.
|
||||
Self::mov_reg64_base32(buf, dst, offset)
|
||||
}
|
||||
2 => movzx_reg64_base16_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
1 => movzx_reg64_base8_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
_ => internal_error!("Invalid size for zero extension: {size}"),
|
||||
W16 => movzx_reg64_base16_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
W8 => movzx_reg64_base8_offset32(buf, dst, X86_64GeneralReg::RBP, offset),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ use roc_mono::ir::{
|
|||
Literal, Param, Proc, ProcLayout, SelfRecursive, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, InLayout, Layout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner,
|
||||
Builtin, InLayout, LambdaName, Layout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner,
|
||||
TagIdIntType, UnionLayout,
|
||||
};
|
||||
use roc_mono::list_element_layout;
|
||||
|
@ -317,9 +317,9 @@ trait Backend<'a> {
|
|||
&mut Vec<'a, CallerProc<'a>>,
|
||||
);
|
||||
|
||||
fn function_symbol_to_string<'b, I>(
|
||||
fn lambda_name_to_string<'b, I>(
|
||||
&self,
|
||||
symbol: Symbol,
|
||||
name: LambdaName,
|
||||
arguments: I,
|
||||
_lambda_set: Option<InLayout>,
|
||||
result: InLayout,
|
||||
|
@ -327,18 +327,27 @@ trait Backend<'a> {
|
|||
where
|
||||
I: Iterator<Item = InLayout<'b>>,
|
||||
{
|
||||
use std::fmt::Write;
|
||||
use std::hash::{BuildHasher, Hash, Hasher};
|
||||
|
||||
// NOTE: due to randomness, this will not be consistent between runs
|
||||
let mut state = roc_collections::all::BuildHasher::default().build_hasher();
|
||||
let symbol = name.name();
|
||||
|
||||
let mut buf = String::with_capacity(1024);
|
||||
|
||||
for a in arguments {
|
||||
a.hash(&mut state);
|
||||
write!(buf, "{:?}", self.interner().dbg_stable(a)).expect("capacity");
|
||||
}
|
||||
|
||||
// lambda set should not matter; it should already be added as an argument
|
||||
// lambda_set.hash(&mut state);
|
||||
// but the niche of the lambda name may be the only thing differentiating two different
|
||||
// implementations of a function with the same symbol
|
||||
write!(buf, "{:?}", name.niche().dbg_stable(self.interner())).expect("capacity");
|
||||
|
||||
result.hash(&mut state);
|
||||
write!(buf, "{:?}", self.interner().dbg_stable(result)).expect("capacity");
|
||||
|
||||
// NOTE: due to randomness, this will not be consistent between runs
|
||||
let mut state = roc_collections::all::BuildHasher::default().build_hasher();
|
||||
buf.hash(&mut state);
|
||||
|
||||
let interns = self.interns();
|
||||
let ident_string = symbol.as_str(interns);
|
||||
|
@ -389,8 +398,8 @@ trait Backend<'a> {
|
|||
let element_increment = self.debug_symbol("element_increment");
|
||||
let element_increment_symbol = self.build_indirect_inc(layout);
|
||||
|
||||
let element_increment_string = self.function_symbol_to_string(
|
||||
element_increment_symbol,
|
||||
let element_increment_string = self.lambda_name_to_string(
|
||||
LambdaName::no_niche(element_increment_symbol),
|
||||
[box_layout].into_iter(),
|
||||
None,
|
||||
Layout::UNIT,
|
||||
|
@ -409,8 +418,8 @@ trait Backend<'a> {
|
|||
let element_decrement = self.debug_symbol("element_decrement");
|
||||
let element_decrement_symbol = self.build_indirect_dec(layout);
|
||||
|
||||
let element_decrement_string = self.function_symbol_to_string(
|
||||
element_decrement_symbol,
|
||||
let element_decrement_string = self.lambda_name_to_string(
|
||||
LambdaName::no_niche(element_decrement_symbol),
|
||||
[box_layout].into_iter(),
|
||||
None,
|
||||
Layout::UNIT,
|
||||
|
@ -452,8 +461,8 @@ trait Backend<'a> {
|
|||
proc: Proc<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
) -> (Vec<u8>, Vec<Relocation>, Vec<'a, (Symbol, String)>) {
|
||||
let proc_name = self.function_symbol_to_string(
|
||||
proc.name.name(),
|
||||
let proc_name = self.lambda_name_to_string(
|
||||
proc.name,
|
||||
proc.args.iter().map(|t| t.0),
|
||||
proc.closure_data_layout,
|
||||
proc.ret_layout,
|
||||
|
@ -683,15 +692,15 @@ trait Backend<'a> {
|
|||
// implementation in `build_builtin` inlines some of the symbols.
|
||||
return self.build_builtin(
|
||||
sym,
|
||||
func_sym.name(),
|
||||
*func_sym,
|
||||
arguments,
|
||||
arg_layouts,
|
||||
ret_layout,
|
||||
);
|
||||
}
|
||||
|
||||
let fn_name = self.function_symbol_to_string(
|
||||
func_sym.name(),
|
||||
let fn_name = self.lambda_name_to_string(
|
||||
*func_sym,
|
||||
arg_layouts.iter().copied(),
|
||||
None,
|
||||
*ret_layout,
|
||||
|
@ -1807,6 +1816,10 @@ trait Backend<'a> {
|
|||
);
|
||||
}
|
||||
|
||||
LowLevel::NumCompare => {
|
||||
self.build_num_cmp(sym, &args[0], &args[1], &arg_layouts[0]);
|
||||
}
|
||||
|
||||
x => todo!("low level, {:?}", x),
|
||||
}
|
||||
}
|
||||
|
@ -1816,12 +1829,12 @@ trait Backend<'a> {
|
|||
fn build_builtin(
|
||||
&mut self,
|
||||
sym: &Symbol,
|
||||
func_sym: Symbol,
|
||||
func_name: LambdaName,
|
||||
args: &'a [Symbol],
|
||||
arg_layouts: &[InLayout<'a>],
|
||||
ret_layout: &InLayout<'a>,
|
||||
) {
|
||||
match func_sym {
|
||||
match func_name.name() {
|
||||
Symbol::NUM_IS_ZERO => {
|
||||
debug_assert_eq!(
|
||||
1,
|
||||
|
@ -1844,8 +1857,8 @@ trait Backend<'a> {
|
|||
}
|
||||
Symbol::LIST_GET | Symbol::LIST_SET | Symbol::LIST_REPLACE | Symbol::LIST_APPEND => {
|
||||
// TODO: This is probably simple enough to be worth inlining.
|
||||
let fn_name = self.function_symbol_to_string(
|
||||
func_sym,
|
||||
let fn_name = self.lambda_name_to_string(
|
||||
func_name,
|
||||
arg_layouts.iter().copied(),
|
||||
None,
|
||||
*ret_layout,
|
||||
|
@ -1876,8 +1889,8 @@ trait Backend<'a> {
|
|||
}
|
||||
Symbol::STR_IS_VALID_SCALAR => {
|
||||
// just call the function
|
||||
let fn_name = self.function_symbol_to_string(
|
||||
func_sym,
|
||||
let fn_name = self.lambda_name_to_string(
|
||||
func_name,
|
||||
arg_layouts.iter().copied(),
|
||||
None,
|
||||
*ret_layout,
|
||||
|
@ -1888,8 +1901,8 @@ trait Backend<'a> {
|
|||
}
|
||||
_other => {
|
||||
// just call the function
|
||||
let fn_name = self.function_symbol_to_string(
|
||||
func_sym,
|
||||
let fn_name = self.lambda_name_to_string(
|
||||
func_name,
|
||||
arg_layouts.iter().copied(),
|
||||
None,
|
||||
*ret_layout,
|
||||
|
@ -2057,6 +2070,14 @@ trait Backend<'a> {
|
|||
/// build_not stores the result of `!src` into dst.
|
||||
fn build_not(&mut self, dst: &Symbol, src: &Symbol, arg_layout: &InLayout<'a>);
|
||||
|
||||
fn build_num_cmp(
|
||||
&mut self,
|
||||
dst: &Symbol,
|
||||
src1: &Symbol,
|
||||
src2: &Symbol,
|
||||
arg_layout: &InLayout<'a>,
|
||||
);
|
||||
|
||||
/// build_num_lt stores the result of `src1 < src2` into dst.
|
||||
fn build_num_lt(
|
||||
&mut self,
|
||||
|
|
|
@ -343,8 +343,8 @@ fn build_object<'a, B: Backend<'a>>(
|
|||
for ((sym, layout), proc) in helper_symbols_and_layouts.into_iter().zip(helper_procs) {
|
||||
debug_assert_eq!(sym, proc.name.name());
|
||||
|
||||
let fn_name = backend.function_symbol_to_string(
|
||||
sym,
|
||||
let fn_name = backend.lambda_name_to_string(
|
||||
LambdaName::no_niche(sym),
|
||||
layout.arguments.iter().copied(),
|
||||
None,
|
||||
layout.result,
|
||||
|
@ -559,8 +559,8 @@ fn build_proc_symbol<'a, B: Backend<'a>>(
|
|||
Exposed::Exposed => layout_ids
|
||||
.get_toplevel(sym, &layout)
|
||||
.to_exposed_symbol_string(sym, backend.interns()),
|
||||
Exposed::NotExposed => backend.function_symbol_to_string(
|
||||
sym,
|
||||
Exposed::NotExposed => backend.lambda_name_to_string(
|
||||
proc.name,
|
||||
layout.arguments.iter().copied(),
|
||||
None,
|
||||
layout.result,
|
||||
|
|
|
@ -1304,10 +1304,18 @@ impl<'a> Niche<'a> {
|
|||
pub fn dbg_deep<'r, I: LayoutInterner<'a>>(
|
||||
&'r self,
|
||||
interner: &'r I,
|
||||
) -> crate::layout::intern::dbg::DbgFields<'a, 'r, I> {
|
||||
) -> crate::layout::intern::dbg_deep::DbgFields<'a, 'r, I> {
|
||||
let NichePriv::Captures(caps) = &self.0;
|
||||
interner.dbg_deep_iter(caps)
|
||||
}
|
||||
|
||||
pub fn dbg_stable<'r, I: LayoutInterner<'a>>(
|
||||
&'r self,
|
||||
interner: &'r I,
|
||||
) -> crate::layout::intern::dbg_stable::DbgFields<'a, 'r, I> {
|
||||
let NichePriv::Captures(caps) = &self.0;
|
||||
interner.dbg_stable_iter(caps)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
|
|
|
@ -405,12 +405,28 @@ pub trait LayoutInterner<'a>: Sized {
|
|||
/// return false;
|
||||
/// }
|
||||
/// ```
|
||||
fn dbg_deep<'r>(&'r self, layout: InLayout<'a>) -> dbg::Dbg<'a, 'r, Self> {
|
||||
dbg::Dbg(self, layout)
|
||||
fn dbg_deep<'r>(&'r self, layout: InLayout<'a>) -> dbg_deep::Dbg<'a, 'r, Self> {
|
||||
dbg_deep::Dbg(self, layout)
|
||||
}
|
||||
|
||||
fn dbg_deep_iter<'r>(&'r self, layouts: &'a [InLayout<'a>]) -> dbg::DbgFields<'a, 'r, Self> {
|
||||
dbg::DbgFields(self, layouts)
|
||||
fn dbg_deep_iter<'r>(
|
||||
&'r self,
|
||||
layouts: &'a [InLayout<'a>],
|
||||
) -> dbg_deep::DbgFields<'a, 'r, Self> {
|
||||
dbg_deep::DbgFields(self, layouts)
|
||||
}
|
||||
|
||||
/// Similar to `Self::dbg_deep`, but does not display the interned name of symbols. This keeps
|
||||
/// the output consistent in a multi-threaded (test) run
|
||||
fn dbg_stable<'r>(&'r self, layout: InLayout<'a>) -> dbg_stable::Dbg<'a, 'r, Self> {
|
||||
dbg_stable::Dbg(self, layout)
|
||||
}
|
||||
|
||||
fn dbg_stable_iter<'r>(
|
||||
&'r self,
|
||||
layouts: &'a [InLayout<'a>],
|
||||
) -> dbg_stable::DbgFields<'a, 'r, Self> {
|
||||
dbg_stable::DbgFields(self, layouts)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1372,7 +1388,7 @@ mod equiv {
|
|||
}
|
||||
}
|
||||
|
||||
pub mod dbg {
|
||||
pub mod dbg_deep {
|
||||
use roc_module::symbol::Symbol;
|
||||
|
||||
use crate::layout::{Builtin, LambdaSet, LayoutRepr, UnionLayout};
|
||||
|
@ -1531,6 +1547,179 @@ pub mod dbg {
|
|||
}
|
||||
}
|
||||
|
||||
/// Provides a stable debug output
|
||||
///
|
||||
/// The debug output defined in `dbg_deep` uses the `Symbol` `std::fmt::Debug` instance, which uses
|
||||
/// interned string names to make the output easier to interpret. That is useful for manual
|
||||
/// debugging, but the interned strings are not stable in a multi-threaded context (e.g. when
|
||||
/// running `cargo test`). The output of this module is always stable.
|
||||
pub mod dbg_stable {
|
||||
use roc_module::symbol::Symbol;
|
||||
|
||||
use crate::layout::{Builtin, LambdaSet, LayoutRepr, SemanticRepr, UnionLayout};
|
||||
|
||||
use super::{InLayout, LayoutInterner};
|
||||
|
||||
pub struct Dbg<'a, 'r, I: LayoutInterner<'a>>(pub &'r I, pub InLayout<'a>);
|
||||
|
||||
impl<'a, 'r, I: LayoutInterner<'a>> std::fmt::Debug for Dbg<'a, 'r, I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let repr = self.0.get_repr(self.1);
|
||||
let semantic = self.0.get_semantic(self.1);
|
||||
|
||||
struct ConsistentSemanticRepr<'a>(SemanticRepr<'a>);
|
||||
|
||||
impl std::fmt::Debug for ConsistentSemanticRepr<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt_consistent(f)
|
||||
}
|
||||
}
|
||||
|
||||
f.debug_struct("Layout")
|
||||
.field("repr", &DbgRepr(self.0, &repr))
|
||||
.field("semantic", &ConsistentSemanticRepr(semantic))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DbgFields<'a, 'r, I: LayoutInterner<'a>>(pub &'r I, pub &'a [InLayout<'a>]);
|
||||
|
||||
impl<'a, 'r, I: LayoutInterner<'a>> std::fmt::Debug for DbgFields<'a, 'r, I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_list()
|
||||
.entries(self.1.iter().map(|l| Dbg(self.0, *l)))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
struct DbgRepr<'a, 'r, I: LayoutInterner<'a>>(&'r I, &'r LayoutRepr<'a>);
|
||||
|
||||
impl<'a, 'r, I: LayoutInterner<'a>> std::fmt::Debug for DbgRepr<'a, 'r, I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.1 {
|
||||
LayoutRepr::Builtin(b) => f
|
||||
.debug_tuple("Builtin")
|
||||
.field(&DbgBuiltin(self.0, *b))
|
||||
.finish(),
|
||||
LayoutRepr::Struct(field_layouts) => f
|
||||
.debug_struct("Struct")
|
||||
.field("fields", &DbgFields(self.0, field_layouts))
|
||||
.finish(),
|
||||
LayoutRepr::Boxed(b) => f.debug_tuple("Boxed").field(&Dbg(self.0, *b)).finish(),
|
||||
LayoutRepr::Union(un) => f
|
||||
.debug_tuple("Union")
|
||||
.field(&DbgUnion(self.0, *un))
|
||||
.finish(),
|
||||
LayoutRepr::LambdaSet(ls) => f
|
||||
.debug_tuple("LambdaSet")
|
||||
.field(&DbgLambdaSet(self.0, *ls))
|
||||
.finish(),
|
||||
LayoutRepr::RecursivePointer(rp) => {
|
||||
f.debug_tuple("RecursivePointer").field(&rp.0).finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DbgTags<'a, 'r, I: LayoutInterner<'a>>(&'r I, &'a [&'a [InLayout<'a>]]);
|
||||
|
||||
impl<'a, 'r, I: LayoutInterner<'a>> std::fmt::Debug for DbgTags<'a, 'r, I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_list()
|
||||
.entries(self.1.iter().map(|l| DbgFields(self.0, l)))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
struct DbgBuiltin<'a, 'r, I: LayoutInterner<'a>>(&'r I, Builtin<'a>);
|
||||
|
||||
impl<'a, 'r, I: LayoutInterner<'a>> std::fmt::Debug for DbgBuiltin<'a, 'r, I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.1 {
|
||||
Builtin::Int(w) => f.debug_tuple("Int").field(&w).finish(),
|
||||
Builtin::Float(w) => f.debug_tuple("Float").field(&w).finish(),
|
||||
Builtin::Bool => f.debug_tuple("Bool").finish(),
|
||||
Builtin::Decimal => f.debug_tuple("Decimal").finish(),
|
||||
Builtin::Str => f.debug_tuple("Str").finish(),
|
||||
Builtin::List(e) => f.debug_tuple("List").field(&Dbg(self.0, e)).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DbgUnion<'a, 'r, I: LayoutInterner<'a>>(&'r I, UnionLayout<'a>);
|
||||
|
||||
impl<'a, 'r, I: LayoutInterner<'a>> std::fmt::Debug for DbgUnion<'a, 'r, I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.1 {
|
||||
UnionLayout::NonRecursive(payloads) => f
|
||||
.debug_tuple("NonRecursive")
|
||||
.field(&DbgTags(self.0, payloads))
|
||||
.finish(),
|
||||
UnionLayout::Recursive(payloads) => f
|
||||
.debug_tuple("Recursive")
|
||||
.field(&DbgTags(self.0, payloads))
|
||||
.finish(),
|
||||
UnionLayout::NonNullableUnwrapped(fields) => f
|
||||
.debug_tuple("NonNullableUnwrapped")
|
||||
.field(&DbgFields(self.0, fields))
|
||||
.finish(),
|
||||
UnionLayout::NullableWrapped {
|
||||
nullable_id,
|
||||
other_tags,
|
||||
} => f
|
||||
.debug_struct("NullableWrapped")
|
||||
.field("nullable_id", &nullable_id)
|
||||
.field("other_tags", &DbgTags(self.0, other_tags))
|
||||
.finish(),
|
||||
UnionLayout::NullableUnwrapped {
|
||||
nullable_id,
|
||||
other_fields,
|
||||
} => f
|
||||
.debug_struct("NullableUnwrapped")
|
||||
.field("nullable_id", &nullable_id)
|
||||
.field("other_tags", &DbgFields(self.0, other_fields))
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DbgLambdaSet<'a, 'r, I: LayoutInterner<'a>>(&'r I, LambdaSet<'a>);
|
||||
|
||||
impl<'a, 'r, I: LayoutInterner<'a>> std::fmt::Debug for DbgLambdaSet<'a, 'r, I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let LambdaSet {
|
||||
args,
|
||||
ret,
|
||||
set,
|
||||
representation,
|
||||
full_layout,
|
||||
} = self.1;
|
||||
|
||||
f.debug_struct("LambdaSet")
|
||||
.field("args", &DbgFields(self.0, args))
|
||||
.field("ret", &Dbg(self.0, ret))
|
||||
.field("set", &DbgCapturesSet(self.0, set))
|
||||
.field("representation", &Dbg(self.0, representation))
|
||||
.field("full_layout", &full_layout)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
struct DbgCapturesSet<'a, 'r, I: LayoutInterner<'a>>(&'r I, &'a [(Symbol, &'a [InLayout<'a>])]);
|
||||
|
||||
impl<'a, 'r, I: LayoutInterner<'a>> std::fmt::Debug for DbgCapturesSet<'a, 'r, I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_list()
|
||||
.entries(
|
||||
self.1
|
||||
.iter()
|
||||
.map(|(sym, captures)| (sym.as_u64(), DbgFields(self.0, captures))),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod insert_lambda_set {
|
||||
use bumpalo::Bump;
|
||||
|
|
|
@ -15,6 +15,12 @@ impl<'a> std::fmt::Debug for SemanticRepr<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> SemanticRepr<'a> {
|
||||
pub fn fmt_consistent(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt_consistent(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
enum Inner<'a> {
|
||||
None,
|
||||
|
@ -24,6 +30,19 @@ enum Inner<'a> {
|
|||
Lambdas(SemaLambdas<'a>),
|
||||
}
|
||||
|
||||
impl<'a> Inner<'a> {
|
||||
fn fmt_consistent(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// don't print the interned string name of a symbol to get consistent output
|
||||
if let Self::Lambdas(sema_lambdas) = self {
|
||||
f.debug_struct("SemaLambdas")
|
||||
.field("lambda_count", &sema_lambdas.lambdas.len())
|
||||
.finish()
|
||||
} else {
|
||||
std::fmt::Debug::fmt(&self, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SemanticRepr<'a> {
|
||||
pub(super) const NONE: Self = Self(Inner::None);
|
||||
pub(super) const EMPTY_RECORD: Self = Self::record(&[]);
|
||||
|
|
|
@ -304,7 +304,7 @@ fn apply_unnamed_identity() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn return_unnamed_fn() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -325,7 +325,7 @@ fn return_unnamed_fn() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn gen_when_fn() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -345,7 +345,7 @@ fn gen_when_fn() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn gen_basic_def() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -373,7 +373,7 @@ fn gen_basic_def() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn gen_multiple_defs() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -492,7 +492,7 @@ fn gen_multiple_defs() {
|
|||
// }
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn factorial() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -514,7 +514,7 @@ fn factorial() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn peano1() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -535,7 +535,7 @@ fn peano1() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn peano2() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -557,7 +557,7 @@ fn peano2() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn top_level_constant() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -577,7 +577,7 @@ fn top_level_constant() {
|
|||
|
||||
#[test]
|
||||
#[ignore]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn top_level_destructure() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -829,7 +829,7 @@ fn linked_list_map() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn when_nested_maybe() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -886,7 +886,7 @@ fn when_nested_maybe() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn when_peano() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1011,7 +1011,7 @@ fn annotation_without_body() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn simple_closure() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1033,7 +1033,7 @@ fn simple_closure() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn nested_closure() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1057,7 +1057,7 @@ fn nested_closure() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn closure_in_list() {
|
||||
use roc_std::RocList;
|
||||
|
||||
|
@ -1085,7 +1085,7 @@ fn closure_in_list() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn specialize_closure() {
|
||||
use roc_std::RocList;
|
||||
|
||||
|
@ -1117,7 +1117,7 @@ fn specialize_closure() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn io_poc_effect() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1148,7 +1148,7 @@ fn io_poc_effect() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn io_poc_desugared() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1176,7 +1176,7 @@ fn io_poc_desugared() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn return_wrapped_function_a() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1198,7 +1198,7 @@ fn return_wrapped_function_a() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn return_wrapped_function_b() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1219,7 +1219,7 @@ fn return_wrapped_function_b() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn return_wrapped_closure() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1367,7 +1367,7 @@ fn linked_list_singleton() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn recursive_function_with_rigid() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1394,7 +1394,7 @@ fn recursive_function_with_rigid() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn rbtree_insert() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1606,7 +1606,7 @@ fn rbtree_balance_mono_problem() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn rbtree_balance_full() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1658,7 +1658,7 @@ fn rbtree_balance_full() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn nested_pattern_match_two_ways() {
|
||||
// exposed an issue in the ordering of pattern match checks when ran with `--release` mode
|
||||
assert_evals_to!(
|
||||
|
@ -1771,6 +1771,7 @@ fn linked_list_double_pattern_match() {
|
|||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
// dev backend: this test somehow corrupts the errors vector ?!
|
||||
fn binary_tree_double_pattern_match() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1796,7 +1797,7 @@ fn binary_tree_double_pattern_match() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn unified_empty_closure_bool() {
|
||||
// none of the Closure tags will have a payload
|
||||
// this was not handled correctly in the past
|
||||
|
@ -1821,7 +1822,7 @@ fn unified_empty_closure_bool() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn unified_empty_closure_byte() {
|
||||
// none of the Closure tags will have a payload
|
||||
// this was not handled correctly in the past
|
||||
|
@ -1847,7 +1848,7 @@ fn unified_empty_closure_byte() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn task_always_twice() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1892,7 +1893,7 @@ fn task_always_twice() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn wildcard_rigid() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1921,7 +1922,7 @@ fn wildcard_rigid() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn alias_of_alias_with_type_arguments() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -1998,7 +1999,7 @@ fn todo_bad_error_message() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn hof_conditional() {
|
||||
// exposed issue with the if condition being just a symbol
|
||||
assert_evals_to!(
|
||||
|
@ -2095,7 +2096,7 @@ fn fingertree_basic() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn case_or_pattern() {
|
||||
// the `0` branch body should only be generated once in the future
|
||||
// it is currently duplicated
|
||||
|
@ -3576,7 +3577,7 @@ fn polymorphic_lambda_captures_polymorphic_value() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn lambda_capture_niche_u64_vs_u8_capture() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -3604,7 +3605,7 @@ fn lambda_capture_niche_u64_vs_u8_capture() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn lambda_capture_niches_with_other_lambda_capture() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -3637,7 +3638,7 @@ fn lambda_capture_niches_with_other_lambda_capture() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn lambda_capture_niches_with_non_capturing_function() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -3670,7 +3671,7 @@ fn lambda_capture_niches_with_non_capturing_function() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn lambda_capture_niches_have_captured_function_in_closure() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -3862,7 +3863,7 @@ fn recursive_lambda_set_issue_3444_inferred() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn compose_recursive_lambda_set_productive_toplevel() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -3930,7 +3931,7 @@ fn compose_recursive_lambda_set_productive_inferred() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn compose_recursive_lambda_set_productive_nullable_wrapped() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
@ -4216,7 +4217,7 @@ fn issue_4349() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn issue_4712() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue