Add a Newtype variant to LayoutWrapper

This commit is contained in:
Ayaz Hafiz 2023-05-11 12:12:00 -05:00
parent dd94d6ba16
commit 5274dbcd00
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
22 changed files with 348 additions and 265 deletions

View file

@ -4,7 +4,7 @@ use std::hash::Hash;
use crate::ir::{
Expr, HigherOrderLowLevel, JoinPointId, Param, PassedFunction, Proc, ProcLayout, Stmt,
};
use crate::layout::{InLayout, Layout, LayoutInterner, STLayoutInterner};
use crate::layout::{InLayout, LayoutInterner, LayoutRepr, STLayoutInterner};
use bumpalo::collections::Vec;
use bumpalo::Bump;
use roc_collections::all::{MutMap, MutSet};
@ -29,7 +29,7 @@ impl Ownership {
/// For reference-counted types (lists, (big) strings, recursive tags), owning a value
/// means incrementing its reference count. Hence, we prefer borrowing for these types
fn from_layout(layout: &Layout) -> Self {
fn from_layout(layout: &LayoutRepr) -> Self {
match layout.is_refcounted() {
true => Ownership::Borrowed,
false => Ownership::Owned,
@ -265,7 +265,7 @@ impl<'a> ParamMap<'a> {
) -> &'a [Param<'a>] {
Vec::from_iter_in(
ps.iter().map(|p| Param {
ownership: Ownership::from_layout(&interner.get(p.layout)),
ownership: Ownership::from_layout(&interner.get_repr(p.layout)),
layout: p.layout,
symbol: p.symbol,
}),
@ -281,7 +281,7 @@ impl<'a> ParamMap<'a> {
) -> &'a [Param<'a>] {
Vec::from_iter_in(
ps.iter().map(|(layout, symbol)| Param {
ownership: Ownership::from_layout(&interner.get(*layout)),
ownership: Ownership::from_layout(&interner.get_repr(*layout)),
layout: *layout,
symbol: *symbol,
}),

View file

@ -434,7 +434,8 @@ fn eq_tag_union_help<'a>(
if is_non_recursive {
compare_ptr_or_value
} else {
let union_layout = layout_interner.insert_no_semantic(LayoutRepr::Union(union_layout));
let union_layout =
layout_interner.insert_direct_no_semantic(LayoutRepr::Union(union_layout));
let loop_params_iter = operands.iter().map(|arg| Param {
symbol: *arg,
ownership: Ownership::Borrowed,
@ -657,7 +658,7 @@ fn eq_list<'a>(
let arena = root.arena;
// A "Box" layout (heap pointer to a single list element)
let box_layout = layout_interner.insert_no_semantic(LayoutRepr::Boxed(elem_layout));
let box_layout = layout_interner.insert_direct_no_semantic(LayoutRepr::Boxed(elem_layout));
// Compare lengths
@ -703,7 +704,7 @@ fn eq_list<'a>(
let size = root.create_symbol(ident_ids, "size");
let size_expr = Expr::Literal(Literal::Int(
(layout_interner
.get(elem_layout)
.get_repr(elem_layout)
.stack_size(layout_interner, root.target_info) as i128)
.to_ne_bytes(),
));

View file

@ -10,8 +10,8 @@ use crate::ir::{
Proc, ProcLayout, SelfRecursive, Stmt, UpdateModeId,
};
use crate::layout::{
Builtin, InLayout, LambdaName, Layout, LayoutInterner, LayoutRepr, Niche, STLayoutInterner,
UnionLayout,
Builtin, InLayout, LambdaName, Layout, LayoutInterner, LayoutRepr, LayoutWrapper, Niche,
STLayoutInterner, UnionLayout,
};
mod equality;
@ -290,7 +290,7 @@ impl<'a> CodeGenHelp<'a> {
LayoutRepr::RecursivePointer(_)
) {
let union_layout = ctx.recursive_union.unwrap();
layout_interner.insert_no_semantic(LayoutRepr::Union(union_layout))
layout_interner.insert_direct_no_semantic(LayoutRepr::Union(union_layout))
} else {
called_layout
};
@ -301,7 +301,7 @@ impl<'a> CodeGenHelp<'a> {
let (ret_layout, arg_layouts): (InLayout<'a>, &'a [InLayout<'a>]) = {
let arg = self.replace_rec_ptr(ctx, layout_interner, layout);
let box_arg = layout_interner.insert_no_semantic(LayoutRepr::Boxed(arg));
let box_arg = layout_interner.insert_direct_no_semantic(LayoutRepr::Boxed(arg));
match ctx.op {
Dec | DecRef(_) => (LAYOUT_UNIT, self.arena.alloc([arg])),
@ -430,12 +430,14 @@ impl<'a> CodeGenHelp<'a> {
}
Dec | DecRef(_) | Reset | ResetRef => self.arena.alloc([roc_value]),
IndirectInc => {
let box_layout = layout_interner.insert_no_semantic(LayoutRepr::Boxed(layout));
let box_layout =
layout_interner.insert_direct_no_semantic(LayoutRepr::Boxed(layout));
let inc_amount = (self.layout_isize, ARG_2);
self.arena.alloc([(box_layout, ARG_1), inc_amount])
}
IndirectDec => {
let box_layout = layout_interner.insert_no_semantic(LayoutRepr::Boxed(layout));
let box_layout =
layout_interner.insert_direct_no_semantic(LayoutRepr::Boxed(layout));
self.arena.alloc([(box_layout, ARG_1)])
}
Eq => self.arena.alloc([roc_value, (layout, ARG_2)]),
@ -483,7 +485,8 @@ impl<'a> CodeGenHelp<'a> {
niche: Niche::NONE,
},
HelperOp::IndirectInc => {
let box_layout = layout_interner.insert_no_semantic(LayoutRepr::Boxed(layout));
let box_layout =
layout_interner.insert_direct_no_semantic(LayoutRepr::Boxed(layout));
ProcLayout {
arguments: self.arena.alloc([box_layout, self.layout_isize]),
@ -492,7 +495,8 @@ impl<'a> CodeGenHelp<'a> {
}
}
HelperOp::IndirectDec => {
let box_layout = layout_interner.insert_no_semantic(LayoutRepr::Boxed(layout));
let box_layout =
layout_interner.insert_direct_no_semantic(LayoutRepr::Boxed(layout));
ProcLayout {
arguments: self.arena.alloc([box_layout]),
@ -581,7 +585,7 @@ impl<'a> CodeGenHelp<'a> {
LayoutRepr::RecursivePointer(_) => LayoutRepr::Union(ctx.recursive_union.unwrap()),
};
layout_interner.insert(Layout::new(repr, semantic))
layout_interner.insert(Layout::new(LayoutWrapper::Direct(repr), semantic))
}
fn union_tail_recursion_fields(
@ -665,16 +669,16 @@ impl<'a> CallerProc<'a> {
};
let box_capture_layout = if let Some(capture_layout) = capture_layout {
layout_interner.insert_no_semantic(LayoutRepr::Boxed(capture_layout))
layout_interner.insert_direct_no_semantic(LayoutRepr::Boxed(capture_layout))
} else {
layout_interner.insert_no_semantic(LayoutRepr::Boxed(Layout::UNIT))
layout_interner.insert_direct_no_semantic(LayoutRepr::Boxed(Layout::UNIT))
};
let box_argument_layout = layout_interner
.insert_no_semantic(LayoutRepr::Boxed(passed_function.argument_layouts[0]));
.insert_direct_no_semantic(LayoutRepr::Boxed(passed_function.argument_layouts[0]));
let box_return_layout =
layout_interner.insert_no_semantic(LayoutRepr::Boxed(passed_function.return_layout));
let box_return_layout = layout_interner
.insert_direct_no_semantic(LayoutRepr::Boxed(passed_function.return_layout));
let proc_layout = ProcLayout {
arguments: arena.alloc([box_capture_layout, box_argument_layout, box_return_layout]),

View file

@ -309,7 +309,8 @@ pub fn refcount_reset_proc_body<'a>(
// Whenever we recurse into a child layout we will want to Decrement
ctx.op = HelperOp::Dec;
ctx.recursive_union = Some(union_layout);
let recursion_ptr = layout_interner.insert_no_semantic(LayoutRepr::RecursivePointer(layout));
let recursion_ptr =
layout_interner.insert_direct_no_semantic(LayoutRepr::RecursivePointer(layout));
// Reset structure is unique. Decrement its children and return a pointer to the allocation.
let then_stmt = {
@ -491,7 +492,8 @@ pub fn refcount_resetref_proc_body<'a>(
// Whenever we recurse into a child layout we will want to Decrement
ctx.op = HelperOp::Dec;
ctx.recursive_union = Some(union_layout);
let recursion_ptr = layout_interner.insert_no_semantic(LayoutRepr::RecursivePointer(layout));
let recursion_ptr =
layout_interner.insert_direct_no_semantic(LayoutRepr::RecursivePointer(layout));
// Reset structure is unique. Return a pointer to the allocation.
let then_stmt = Stmt::Ret(addr);
@ -979,7 +981,7 @@ fn refcount_list<'a>(
let arena = root.arena;
// A "Box" layout (heap pointer to a single list element)
let box_layout = layout_interner.insert_no_semantic(LayoutRepr::Boxed(elem_layout));
let box_layout = layout_interner.insert_direct_no_semantic(LayoutRepr::Boxed(elem_layout));
//
// Check if the list is empty
@ -1106,7 +1108,7 @@ fn refcount_list<'a>(
let is_relevant_op = ctx.op.is_dec() || ctx.op.is_inc();
let modify_elems_and_list =
if is_relevant_op && layout_interner.get(elem_layout).is_refcounted() {
if is_relevant_op && layout_interner.get_repr(elem_layout).is_refcounted() {
refcount_list_elems(
root,
ident_ids,
@ -1742,7 +1744,7 @@ fn refcount_union_tailrec<'a>(
let tailrec_loop = JoinPointId(root.create_symbol(ident_ids, "tailrec_loop"));
let current = root.create_symbol(ident_ids, "current");
let next_ptr = root.create_symbol(ident_ids, "next_ptr");
let layout = layout_interner.insert_no_semantic(LayoutRepr::Union(union_layout));
let layout = layout_interner.insert_direct_no_semantic(LayoutRepr::Union(union_layout));
let tag_id_layout = union_layout.tag_id_layout();
@ -1887,7 +1889,7 @@ fn refcount_union_tailrec<'a>(
let jump_with_null_ptr = Stmt::Let(
null_pointer,
Expr::NullPointer,
layout_interner.insert_no_semantic(LayoutRepr::Union(union_layout)),
layout_interner.insert_direct_no_semantic(LayoutRepr::Union(union_layout)),
root.arena.alloc(Stmt::Jump(
jp_modify_union,
root.arena.alloc([null_pointer]),
@ -1931,7 +1933,7 @@ fn refcount_union_tailrec<'a>(
));
let loop_init = Stmt::Jump(tailrec_loop, root.arena.alloc([initial_structure]));
let union_layout = layout_interner.insert_no_semantic(LayoutRepr::Union(union_layout));
let union_layout = layout_interner.insert_direct_no_semantic(LayoutRepr::Union(union_layout));
let loop_param = Param {
symbol: current,
ownership: Ownership::Borrowed,

View file

@ -400,7 +400,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
} => {
let interned_layout = self
.interner
.insert_no_semantic(LayoutRepr::Union(tag_layout));
.insert_direct_no_semantic(LayoutRepr::Union(tag_layout));
self.check_tag_expr(interned_layout, tag_layout, tag_id, arguments);
Some(interned_layout)
}
@ -440,7 +440,9 @@ impl<'a, 'r> Ctx<'a, 'r> {
}
Some(
self.interner
.insert_no_semantic(LayoutRepr::Builtin(Builtin::List(*elem_layout))),
.insert_direct_no_semantic(LayoutRepr::Builtin(Builtin::List(
*elem_layout,
))),
)
}
Expr::EmptyArray => {
@ -449,7 +451,10 @@ impl<'a, 'r> Ctx<'a, 'r> {
}
&Expr::ExprBox { symbol } => self.with_sym_layout(symbol, |ctx, _def_line, layout| {
let inner = layout;
Some(ctx.interner.insert_no_semantic(LayoutRepr::Boxed(inner)))
Some(
ctx.interner
.insert_direct_no_semantic(LayoutRepr::Boxed(inner)),
)
}),
&Expr::ExprUnbox { symbol } => self.with_sym_layout(symbol, |ctx, def_line, layout| {
let layout = ctx.resolve(layout);
@ -471,7 +476,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
} => {
let union = self
.interner
.insert_no_semantic(LayoutRepr::Union(tag_layout));
.insert_direct_no_semantic(LayoutRepr::Union(tag_layout));
self.check_sym_layout(symbol, union, UseKind::TagReuse);
// TODO also check update arguments
Some(union)
@ -529,7 +534,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
) -> Option<InLayout<'a>> {
let union = self
.interner
.insert_no_semantic(LayoutRepr::Union(union_layout));
.insert_direct_no_semantic(LayoutRepr::Union(union_layout));
self.with_sym_layout(structure, |ctx, def_line, _layout| {
ctx.check_sym_layout(structure, union, UseKind::TagExpr);

View file

@ -3509,10 +3509,10 @@ fn specialize_proc_help<'a>(
combined.sort_by(|(_, layout1), (_, layout2)| {
let size1 = layout_cache
.get_in(**layout1)
.get_repr(**layout1)
.alignment_bytes(&layout_cache.interner, ptr_bytes);
let size2 = layout_cache
.get_in(**layout2)
.get_repr(**layout2)
.alignment_bytes(&layout_cache.interner, ptr_bytes);
size2.cmp(&size1)
@ -3557,10 +3557,10 @@ fn specialize_proc_help<'a>(
combined.sort_by(|(_, layout1), (_, layout2)| {
let size1 = layout_cache
.get_in(**layout1)
.get_repr(**layout1)
.alignment_bytes(&layout_cache.interner, ptr_bytes);
let size2 = layout_cache
.get_in(**layout2)
.get_repr(**layout2)
.alignment_bytes(&layout_cache.interner, ptr_bytes);
size2.cmp(&size1)
@ -4627,13 +4627,14 @@ pub fn with_hole<'a>(
Ok(elem_layout) => {
let expr = Expr::EmptyArray;
let list_layout = layout_cache
.put_in_no_semantic(LayoutRepr::Builtin(Builtin::List(elem_layout)));
.put_in_direct_no_semantic(LayoutRepr::Builtin(Builtin::List(elem_layout)));
Stmt::Let(assigned, expr, list_layout, hole)
}
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
let expr = Expr::EmptyArray;
let list_layout = layout_cache
.put_in_no_semantic(LayoutRepr::Builtin(Builtin::List(Layout::VOID)));
let list_layout = layout_cache.put_in_direct_no_semantic(LayoutRepr::Builtin(
Builtin::List(Layout::VOID),
));
Stmt::Let(assigned, expr, list_layout, hole)
}
Err(LayoutProblem::Erroneous) => panic!("list element is error type"),
@ -4679,8 +4680,8 @@ pub fn with_hole<'a>(
elems: elements.into_bump_slice(),
};
let list_layout =
layout_cache.put_in_no_semantic(LayoutRepr::Builtin(Builtin::List(elem_layout)));
let list_layout = layout_cache
.put_in_direct_no_semantic(LayoutRepr::Builtin(Builtin::List(elem_layout)));
let stmt = Stmt::Let(assigned, expr, list_layout, hole);
@ -5917,10 +5918,10 @@ where
combined.sort_by(|(_, layout1), (_, layout2)| {
let size1 = layout_cache
.get_in(**layout1)
.get_repr(**layout1)
.alignment_bytes(&layout_cache.interner, ptr_bytes);
let size2 = layout_cache
.get_in(**layout2)
.get_repr(**layout2)
.alignment_bytes(&layout_cache.interner, ptr_bytes);
size2.cmp(&size1)
@ -5951,10 +5952,10 @@ where
combined.sort_by(|(_, layout1), (_, layout2)| {
let size1 = layout_cache
.get_in(**layout1)
.get_repr(**layout1)
.alignment_bytes(&layout_cache.interner, ptr_bytes);
let size2 = layout_cache
.get_in(**layout2)
.get_repr(**layout2)
.alignment_bytes(&layout_cache.interner, ptr_bytes);
size2.cmp(&size1)
@ -6299,7 +6300,8 @@ fn convert_tag_union<'a>(
}
};
let union_layout = layout_cache.put_in_no_semantic(LayoutRepr::Union(union_layout));
let union_layout =
layout_cache.put_in_direct_no_semantic(LayoutRepr::Union(union_layout));
let stmt = Stmt::Let(assigned, tag, union_layout, hole);
let iter = field_symbols_temp
@ -6438,7 +6440,7 @@ fn sorted_field_symbols<'a>(
};
let alignment = layout_cache
.get_in(layout)
.get_repr(layout)
.alignment_bytes(&layout_cache.interner, env.target_info);
let symbol = possible_reuse_symbol_or_specialize(env, procs, layout_cache, &arg.value, var);
@ -7885,7 +7887,7 @@ fn specialize_symbol<'a>(
let layout = match raw {
RawFunctionLayout::ZeroArgumentThunk(layout) => layout,
RawFunctionLayout::Function(_, lambda_set, _) => layout_cache
.put_in_no_semantic(LayoutRepr::LambdaSet(lambda_set)),
.put_in_direct_no_semantic(LayoutRepr::LambdaSet(lambda_set)),
};
let raw = RawFunctionLayout::ZeroArgumentThunk(layout);
@ -9762,7 +9764,7 @@ where
($tag_id:expr, $layout:expr, $union_layout:expr, $field_layouts: expr) => {{
if $field_layouts.iter().any(|l| {
layout_interner
.get(*l)
.get_repr(*l)
.has_varying_stack_size(layout_interner, arena)
}) {
let procs = generate_glue_procs_for_tag_fields(
@ -9799,7 +9801,7 @@ where
LayoutRepr::Struct(field_layouts) => {
if field_layouts.iter().any(|l| {
layout_interner
.get(*l)
.get_repr(*l)
.has_varying_stack_size(layout_interner, arena)
}) {
let procs = generate_glue_procs_for_struct_fields(
@ -9890,7 +9892,7 @@ where
{
let interned_unboxed_struct_layout = layout_interner.insert(*unboxed_struct_layout);
let boxed_struct_layout =
Layout::no_semantic(LayoutRepr::Boxed(interned_unboxed_struct_layout));
Layout::no_semantic(LayoutRepr::Boxed(interned_unboxed_struct_layout).direct());
let boxed_struct_layout = layout_interner.insert(boxed_struct_layout);
let mut answer = bumpalo::collections::Vec::with_capacity_in(field_layouts.len(), arena);
@ -10001,7 +10003,7 @@ where
I: LayoutInterner<'a>,
{
let interned = layout_interner.insert(*unboxed_struct_layout);
let boxed_struct_layout = Layout::no_semantic(LayoutRepr::Boxed(interned));
let boxed_struct_layout = Layout::no_semantic(LayoutRepr::Boxed(interned).direct());
let boxed_struct_layout = layout_interner.insert(boxed_struct_layout);
let mut answer = bumpalo::collections::Vec::with_capacity_in(field_layouts.len(), arena);

View file

@ -1206,8 +1206,8 @@ fn store_pattern_help<'a>(
let mut fields = Vec::with_capacity_in(arguments.len(), env.arena);
fields.extend(arguments.iter().map(|x| x.1));
let layout =
layout_cache.put_in_no_semantic(LayoutRepr::struct_(fields.into_bump_slice()));
let layout = layout_cache
.put_in_direct_no_semantic(LayoutRepr::struct_(fields.into_bump_slice()));
return store_newtype_pattern(
env,
@ -1553,7 +1553,7 @@ fn store_tag_pattern<'a>(
if let LayoutRepr::RecursivePointer(_) = layout_cache.get_repr(arg_layout) {
// TODO(recursive-layouts): fix after disjoint rec ptrs
arg_layout = layout_cache.put_in_no_semantic(LayoutRepr::Union(union_layout));
arg_layout = layout_cache.put_in_direct_no_semantic(LayoutRepr::Union(union_layout));
}
let load = Expr::UnionAtIndex {

View file

@ -335,8 +335,8 @@ impl<'a> LayoutCache<'a> {
pub fn put_in(&mut self, layout: Layout<'a>) -> InLayout<'a> {
self.interner.insert(layout)
}
pub fn put_in_no_semantic(&mut self, repr: LayoutRepr<'a>) -> InLayout<'a> {
self.interner.insert_no_semantic(repr)
pub(crate) fn put_in_direct_no_semantic(&mut self, repr: LayoutRepr<'a>) -> InLayout<'a> {
self.interner.insert_direct_no_semantic(repr)
}
#[cfg(debug_assertions)]
@ -659,10 +659,17 @@ impl<'a> RawFunctionLayout<'a> {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Layout<'a> {
repr: LayoutRepr<'a>,
repr: LayoutWrapper<'a>,
semantic: SemanticRepr<'a>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub(crate) enum LayoutWrapper<'a> {
Direct(LayoutRepr<'a>),
#[allow(unused)] // for now
Newtype(InLayout<'a>),
}
/// Types for code gen must be monomorphic. No type variables allowed!
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum LayoutRepr<'a> {
@ -877,7 +884,7 @@ impl<'a> UnionLayout<'a> {
// TODO(recursive-layouts): simplify after we have disjoint recursive pointers
if let LayoutRepr::RecursivePointer(_) = interner.get_repr(result) {
interner.insert_no_semantic(LayoutRepr::Union(self))
interner.insert_direct_no_semantic(LayoutRepr::Union(self))
} else {
result
}
@ -1926,7 +1933,7 @@ impl<'a> LambdaSet<'a> {
I: LayoutInterner<'a>,
{
interner
.get(self.representation)
.get_repr(self.representation)
.stack_size(interner, target_info)
}
pub fn contains_refcounted<I>(&self, interner: &I) -> bool
@ -1934,14 +1941,16 @@ impl<'a> LambdaSet<'a> {
I: LayoutInterner<'a>,
{
interner
.get(self.representation)
.get_repr(self.representation)
.contains_refcounted(interner)
}
pub fn safe_to_memcpy<I>(&self, interner: &I) -> bool
where
I: LayoutInterner<'a>,
{
interner.get(self.representation).safe_to_memcpy(interner)
interner
.get_repr(self.representation)
.safe_to_memcpy(interner)
}
pub fn alignment_bytes<I>(&self, interner: &I, target_info: TargetInfo) -> u32
@ -1949,7 +1958,7 @@ impl<'a> LambdaSet<'a> {
I: LayoutInterner<'a>,
{
interner
.get(self.representation)
.get_repr(self.representation)
.alignment_bytes(interner, target_info)
}
}
@ -2329,22 +2338,30 @@ pub fn is_any_float_range(subs: &Subs, var: Variable) -> bool {
}
impl<'a> Layout<'a> {
pub const fn new(repr: LayoutRepr<'a>, semantic: SemanticRepr<'a>) -> Self {
pub(crate) const fn new(repr: LayoutWrapper<'a>, semantic: SemanticRepr<'a>) -> Self {
Self { repr, semantic }
}
pub const fn no_semantic(repr: LayoutRepr<'a>) -> Self {
pub(crate) const fn no_semantic(repr: LayoutWrapper<'a>) -> Self {
Self {
repr,
semantic: SemanticRepr::NONE,
}
}
pub(crate) const fn repr<I>(&self, _interner: &I) -> LayoutRepr<'a>
pub(crate) fn repr<I>(&self, interner: &I) -> LayoutRepr<'a>
where
I: LayoutInterner<'a>,
{
self.repr
let mut lay = *self;
loop {
match lay.repr {
LayoutWrapper::Direct(repr) => return repr,
LayoutWrapper::Newtype(real) => {
lay = interner.get(real);
}
}
}
}
fn new_help<'b>(
@ -2463,7 +2480,7 @@ impl<'a> Layout<'a> {
let mut total = 0;
for layout in tag.iter() {
let (stack_size, alignment) = interner
.get(*layout)
.get_repr(*layout)
.stack_size_and_alignment(interner, target_info);
total += stack_size;
data_align = data_align.max(alignment);
@ -2482,7 +2499,7 @@ impl<'a> Layout<'a> {
I: LayoutInterner<'a>,
{
use LayoutRepr::*;
match self.repr {
match self.repr(interner) {
LambdaSet(lambda_set) => interner.get(lambda_set.runtime_representation()),
_ => *self,
}
@ -2500,14 +2517,6 @@ impl<'a> Layout<'a> {
}
}
impl<'a> std::ops::Deref for Layout<'a> {
type Target = LayoutRepr<'a>;
fn deref(&self) -> &Self::Target {
&self.repr
}
}
impl<'a> LayoutRepr<'a> {
pub const UNIT: Self = LayoutRepr::struct_(&[]);
pub const BOOL: Self = LayoutRepr::Builtin(Builtin::Bool);
@ -2531,6 +2540,10 @@ impl<'a> LayoutRepr<'a> {
Self::Struct(field_layouts)
}
pub(crate) const fn direct(self) -> LayoutWrapper<'a> {
LayoutWrapper::Direct(self)
}
pub fn safe_to_memcpy<I>(&self, interner: &I) -> bool
where
I: LayoutInterner<'a>,
@ -2541,7 +2554,7 @@ impl<'a> LayoutRepr<'a> {
Builtin(builtin) => builtin.safe_to_memcpy(),
Struct(field_layouts) => field_layouts
.iter()
.all(|field_layout| interner.get(*field_layout).safe_to_memcpy(interner)),
.all(|field_layout| interner.get_repr(*field_layout).safe_to_memcpy(interner)),
Union(variant) => {
use UnionLayout::*;
@ -2549,7 +2562,7 @@ impl<'a> LayoutRepr<'a> {
NonRecursive(tags) => tags.iter().all(|tag_layout| {
tag_layout
.iter()
.all(|field| interner.get(*field).safe_to_memcpy(interner))
.all(|field| interner.get_repr(*field).safe_to_memcpy(interner))
}),
Recursive(_)
| NullableWrapped { .. }
@ -2561,7 +2574,7 @@ impl<'a> LayoutRepr<'a> {
}
}
LambdaSet(lambda_set) => interner
.get(lambda_set.runtime_representation())
.get_repr(lambda_set.runtime_representation())
.safe_to_memcpy(interner),
Boxed(_) | RecursivePointer(_) => {
// We cannot memcpy pointers, because then we would have the same pointer in multiple places!
@ -2598,7 +2611,7 @@ impl<'a> LayoutRepr<'a> {
}
LayoutRepr::Union(UnionLayout::NonRecursive(_)) => true,
LayoutRepr::LambdaSet(lambda_set) => interner
.get(lambda_set.runtime_representation())
.get_repr(lambda_set.runtime_representation())
.is_passed_by_reference(interner, target_info),
_ => false,
}
@ -2639,7 +2652,7 @@ impl<'a> LayoutRepr<'a> {
for field_layout in *field_layouts {
sum += interner
.get(*field_layout)
.get_repr(*field_layout)
.stack_size(interner, target_info);
}
@ -2647,7 +2660,7 @@ impl<'a> LayoutRepr<'a> {
}
Union(variant) => variant.stack_size_without_alignment(interner, target_info),
LambdaSet(lambda_set) => interner
.get(lambda_set.runtime_representation())
.get_repr(lambda_set.runtime_representation())
.stack_size_without_alignment(interner, target_info),
RecursivePointer(_) => target_info.ptr_width() as u32,
Boxed(_) => target_info.ptr_width() as u32,
@ -2662,7 +2675,7 @@ impl<'a> LayoutRepr<'a> {
match self {
Struct(field_layouts) => field_layouts
.iter()
.map(|x| interner.get(*x).alignment_bytes(interner, target_info))
.map(|x| interner.get_repr(*x).alignment_bytes(interner, target_info))
.max()
.unwrap_or(0),
@ -2675,7 +2688,9 @@ impl<'a> LayoutRepr<'a> {
.iter()
.flat_map(|layouts| {
layouts.iter().map(|layout| {
interner.get(*layout).alignment_bytes(interner, target_info)
interner
.get_repr(*layout)
.alignment_bytes(interner, target_info)
})
})
.max();
@ -2699,7 +2714,7 @@ impl<'a> LayoutRepr<'a> {
}
}
LambdaSet(lambda_set) => interner
.get(lambda_set.runtime_representation())
.get_repr(lambda_set.runtime_representation())
.alignment_bytes(interner, target_info),
Builtin(builtin) => builtin.alignment_bytes(target_info),
RecursivePointer(_) => target_info.ptr_width() as u32,
@ -2719,14 +2734,16 @@ impl<'a> LayoutRepr<'a> {
Struct { .. } => self.alignment_bytes(interner, target_info).max(ptr_width),
Union(union_layout) => union_layout.allocation_alignment_bytes(interner, target_info),
LambdaSet(lambda_set) => interner
.get(lambda_set.runtime_representation())
.get_repr(lambda_set.runtime_representation())
.allocation_alignment_bytes(interner, target_info),
RecursivePointer(_) => {
unreachable!("should be looked up to get an actual layout")
}
Boxed(inner) => Ord::max(
ptr_width,
interner.get(*inner).alignment_bytes(interner, target_info),
interner
.get_repr(*inner)
.alignment_bytes(interner, target_info),
),
}
}
@ -2761,7 +2778,7 @@ impl<'a> LayoutRepr<'a> {
Builtin(builtin) => builtin.is_refcounted(),
Struct(field_layouts) => field_layouts
.iter()
.any(|f| interner.get(*f).contains_refcounted(interner)),
.any(|f| interner.get_repr(*f).contains_refcounted(interner)),
Union(variant) => {
use UnionLayout::*;
@ -2769,7 +2786,7 @@ impl<'a> LayoutRepr<'a> {
NonRecursive(fields) => fields
.iter()
.flat_map(|ls| ls.iter())
.any(|f| interner.get(*f).contains_refcounted(interner)),
.any(|f| interner.get_repr(*f).contains_refcounted(interner)),
Recursive(_)
| NullableWrapped { .. }
| NullableUnwrapped { .. }
@ -2777,7 +2794,7 @@ impl<'a> LayoutRepr<'a> {
}
}
LambdaSet(lambda_set) => interner
.get(lambda_set.runtime_representation())
.get_repr(lambda_set.runtime_representation())
.contains_refcounted(interner),
RecursivePointer(_) => true,
Boxed(_) => true,
@ -2900,9 +2917,12 @@ impl<'a> Layout<'a> {
}
}
pub fn is_recursive_tag_union(self) -> bool {
pub fn is_recursive_tag_union<I>(self, interner: &I) -> bool
where
I: LayoutInterner<'a>,
{
matches!(
self.repr,
self.repr(interner),
LayoutRepr::Union(
UnionLayout::NullableUnwrapped { .. }
| UnionLayout::Recursive(_)
@ -3050,7 +3070,7 @@ impl<'a> Builtin<'a> {
let allocation = match self {
Builtin::Str => ptr_width,
Builtin::List(e) => {
let e = interner.get(*e);
let e = interner.get_repr(*e);
e.alignment_bytes(interner, target_info).max(ptr_width)
}
// The following are usually not heap-allocated, but they might be when inside a Box.
@ -3163,7 +3183,7 @@ fn layout_from_flat_type<'a>(
let inner_layout =
cached!(Layout::from_var(env, inner_var), criteria, env.subs);
let boxed_layout = env.cache.put_in(Layout {
repr: LayoutRepr::Boxed(inner_layout),
repr: LayoutRepr::Boxed(inner_layout).direct(),
semantic: SemanticRepr::NONE,
});
@ -3248,7 +3268,7 @@ fn layout_from_flat_type<'a>(
} else {
let layouts = Vec::from_iter_in(sortables.into_iter().map(|t| t.1), arena);
let struct_layout = Layout {
repr: LayoutRepr::Struct(layouts.into_bump_slice()),
repr: LayoutRepr::Struct(layouts.into_bump_slice()).direct(),
semantic: SemanticRepr::record(ordered_field_names.into_bump_slice()),
};
@ -3291,7 +3311,7 @@ fn layout_from_flat_type<'a>(
let field_layouts =
Vec::from_iter_in(sortables.into_iter().map(|t| t.1), arena).into_bump_slice();
let struct_layout = Layout {
repr: LayoutRepr::Struct(field_layouts),
repr: LayoutRepr::Struct(field_layouts).direct(),
semantic: SemanticRepr::tuple(field_layouts.len()),
};
@ -3726,11 +3746,11 @@ where
layouts.sort_by(|layout1, layout2| {
let size1 = env
.cache
.get_in(*layout1)
.get_repr(*layout1)
.alignment_bytes(&env.cache.interner, env.target_info);
let size2 = env
.cache
.get_in(*layout2)
.get_repr(*layout2)
.alignment_bytes(&env.cache.interner, env.target_info);
size2.cmp(&size1)
@ -3788,11 +3808,11 @@ where
arg_layouts.sort_by(|layout1, layout2| {
let size1 = env
.cache
.get_in(*layout1)
.get_repr(*layout1)
.alignment_bytes(&env.cache.interner, env.target_info);
let size2 = env
.cache
.get_in(*layout2)
.get_repr(*layout2)
.alignment_bytes(&env.cache.interner, env.target_info);
size2.cmp(&size1)
@ -3970,7 +3990,7 @@ where
== env
.subs
.get_root_key_without_compacting(opt_rec_var.unwrap())
&& layout.is_recursive_tag_union();
&& layout.is_recursive_tag_union(&env.cache.interner);
let arg_layout = if self_recursion {
Layout::NAKED_RECURSIVE_PTR
@ -4000,11 +4020,11 @@ where
arg_layouts.sort_by(|layout1, layout2| {
let size1 = env
.cache
.get_in(*layout1)
.get_repr(*layout1)
.alignment_bytes(&env.cache.interner, env.target_info);
let size2 = env
.cache
.get_in(*layout2)
.get_repr(*layout2)
.alignment_bytes(&env.cache.interner, env.target_info);
size2.cmp(&size1)
@ -4139,13 +4159,13 @@ where
Never => Layout::VOID,
Unit => env
.cache
.put_in(Layout::new(LayoutRepr::UNIT, compute_semantic())),
.put_in(Layout::new(LayoutRepr::UNIT.direct(), compute_semantic())),
BoolUnion { .. } => env
.cache
.put_in(Layout::new(LayoutRepr::BOOL, compute_semantic())),
.put_in(Layout::new(LayoutRepr::BOOL.direct(), compute_semantic())),
ByteUnion(_) => env
.cache
.put_in(Layout::new(LayoutRepr::U8, compute_semantic())),
.put_in(Layout::new(LayoutRepr::U8.direct(), compute_semantic())),
Newtype {
arguments: field_layouts,
..
@ -4154,7 +4174,7 @@ where
field_layouts[0]
} else {
env.cache
.put_in_no_semantic(LayoutRepr::struct_(field_layouts.into_bump_slice()))
.put_in_direct_no_semantic(LayoutRepr::struct_(field_layouts.into_bump_slice()))
};
answer1
@ -4165,8 +4185,9 @@ where
if data_tag_arguments.len() == 1 {
data_tag_arguments[0]
} else {
env.cache
.put_in_no_semantic(LayoutRepr::struct_(data_tag_arguments.into_bump_slice()))
env.cache.put_in_direct_no_semantic(LayoutRepr::struct_(
data_tag_arguments.into_bump_slice(),
))
}
}
Wrapped(variant) => {
@ -4182,7 +4203,8 @@ where
let layout = Layout {
repr: LayoutRepr::Union(UnionLayout::NonRecursive(
tag_layouts.into_bump_slice(),
)),
))
.direct(),
semantic: SemanticRepr::NONE,
};
env.cache.put_in(layout)
@ -4298,14 +4320,14 @@ where
env.cache.interner.insert_recursive(
env.arena,
Layout {
repr: LayoutRepr::Union(union_layout),
repr: LayoutRepr::Union(union_layout).direct(),
semantic: SemanticRepr::NONE,
},
)
} else {
// There are no naked recursion pointers, so we can insert the layout as-is.
env.cache.interner.insert(Layout {
repr: LayoutRepr::Union(union_layout),
repr: LayoutRepr::Union(union_layout).direct(),
semantic: SemanticRepr::NONE,
})
};
@ -4441,7 +4463,7 @@ pub(crate) fn list_layout_from_elem<'a>(
};
let list_layout = env.cache.put_in(Layout {
repr: LayoutRepr::Builtin(Builtin::List(element_layout)),
repr: LayoutRepr::Builtin(Builtin::List(element_layout)).direct(),
semantic: SemanticRepr::NONE,
});
@ -4595,8 +4617,12 @@ pub fn cmp_fields<'a, L: Ord, I>(
where
I: LayoutInterner<'a>,
{
let size1 = interner.get(layout1).alignment_bytes(interner, target_info);
let size2 = interner.get(layout2).alignment_bytes(interner, target_info);
let size1 = interner
.get_repr(layout1)
.alignment_bytes(interner, target_info);
let size2 = interner
.get_repr(layout2)
.alignment_bytes(interner, target_info);
size2.cmp(&size1).then(label1.cmp(label2))
}
@ -4619,19 +4645,16 @@ mod test {
let a = &[Layout::UNIT] as &[_];
let b = &[interner.insert(Layout {
repr: LayoutRepr::LambdaSet(lambda_set),
repr: LayoutRepr::LambdaSet(lambda_set).direct(),
semantic: SemanticRepr::NONE,
})] as &[_];
let tt = [a, b];
let layout = Layout {
repr: LayoutRepr::Union(UnionLayout::NonRecursive(&tt)),
semantic: SemanticRepr::NONE,
};
let repr = LayoutRepr::Union(UnionLayout::NonRecursive(&tt));
let target_info = TargetInfo::default_x86_64();
assert_eq!(layout.stack_size(&interner, target_info), 1);
assert_eq!(layout.alignment_bytes(&interner, target_info), 1);
assert_eq!(repr.stack_size(&interner, target_info), 1);
assert_eq!(repr.alignment_bytes(&interner, target_info), 1);
}
#[test]
@ -4639,29 +4662,28 @@ mod test {
let mut interner = STLayoutInterner::with_capacity(4, TargetInfo::default_x86_64());
let ok_tag = &[interner.insert(Layout {
repr: LayoutRepr::Builtin(Builtin::Int(IntWidth::U32)),
repr: LayoutRepr::Builtin(Builtin::Int(IntWidth::U32)).direct(),
semantic: SemanticRepr::NONE,
})];
let err_tag = &[Layout::UNIT];
let tags = [ok_tag as &[_], err_tag as &[_]];
let union_layout = UnionLayout::NonRecursive(&tags as &[_]);
let layout = Layout {
repr: LayoutRepr::Union(union_layout),
semantic: SemanticRepr::NONE,
};
let repr = LayoutRepr::Union(union_layout);
let target_info = TargetInfo::default_x86_64();
assert_eq!(
layout.stack_size_without_alignment(&interner, target_info),
8
);
assert_eq!(repr.stack_size_without_alignment(&interner, target_info), 8);
}
#[test]
fn void_stack_size() {
let interner = STLayoutInterner::with_capacity(4, TargetInfo::default_x86_64());
let target_info = TargetInfo::default_x86_64();
assert_eq!(Layout::VOID_NAKED.stack_size(&interner, target_info), 0);
assert_eq!(
Layout::VOID_NAKED
.repr(&interner)
.stack_size(&interner, target_info),
0
);
}
#[test]

View file

@ -14,7 +14,7 @@ use roc_target::TargetInfo;
use crate::layout::LayoutRepr;
use super::{LambdaSet, Layout, SeenRecPtrs, SemanticRepr, UnionLayout};
use super::{LambdaSet, Layout, LayoutWrapper, SeenRecPtrs, SemanticRepr, UnionLayout};
macro_rules! cache_interned_layouts {
($($i:literal, $name:ident, $vis:vis, $layout:expr)*; $total_constants:literal) => {
@ -50,7 +50,7 @@ macro_rules! cache_interned_layouts {
macro_rules! nosema {
($r:expr) => {
Layout {
repr: $r,
repr: $r.direct(),
semantic: SemanticRepr::NONE,
}
};
@ -119,11 +119,11 @@ impl_to_from_int_width! {
impl<'a> Layout<'a> {
pub(super) const VOID_NAKED: Self = Layout {
repr: LayoutRepr::Union(UnionLayout::NonRecursive(&[])),
repr: LayoutRepr::Union(UnionLayout::NonRecursive(&[])).direct(),
semantic: SemanticRepr::NONE,
};
pub(super) const UNIT_NAKED: Self = Layout {
repr: LayoutRepr::Struct(&[]),
repr: LayoutRepr::Struct(&[]).direct(),
semantic: SemanticRepr::EMPTY_RECORD,
};
@ -154,8 +154,8 @@ pub trait LayoutInterner<'a>: Sized {
/// Interns a value with no semantic representation, returning its interned representation.
/// If the value has been interned before, the old interned representation will be re-used.
fn insert_no_semantic(&mut self, repr: LayoutRepr<'a>) -> InLayout<'a> {
self.insert(Layout::no_semantic(repr))
fn insert_direct_no_semantic(&mut self, repr: LayoutRepr<'a>) -> InLayout<'a> {
self.insert(Layout::no_semantic(repr.direct()))
}
/// Creates a [LambdaSet], including caching the [LayoutRepr::LambdaSet] representation of the
@ -181,8 +181,13 @@ pub trait LayoutInterner<'a>: Sized {
//
// Convenience methods
fn get_repr(&self, key: InLayout<'a>) -> LayoutRepr<'a> {
self.get(key).repr
fn get_repr(&self, mut key: InLayout<'a>) -> LayoutRepr<'a> {
loop {
match self.get(key).repr {
LayoutWrapper::Direct(repr) => return repr,
LayoutWrapper::Newtype(inner) => key = inner,
}
}
}
fn get_semantic(&self, key: InLayout<'a>) -> SemanticRepr<'a> {
@ -196,38 +201,39 @@ pub trait LayoutInterner<'a>: Sized {
fn target_info(&self) -> TargetInfo;
fn alignment_bytes(&self, layout: InLayout<'a>) -> u32 {
self.get(layout).alignment_bytes(self, self.target_info())
self.get_repr(layout)
.alignment_bytes(self, self.target_info())
}
fn allocation_alignment_bytes(&self, layout: InLayout<'a>) -> u32 {
self.get(layout)
self.get_repr(layout)
.allocation_alignment_bytes(self, self.target_info())
}
fn stack_size(&self, layout: InLayout<'a>) -> u32 {
self.get(layout).stack_size(self, self.target_info())
self.get_repr(layout).stack_size(self, self.target_info())
}
fn stack_size_and_alignment(&self, layout: InLayout<'a>) -> (u32, u32) {
self.get(layout)
self.get_repr(layout)
.stack_size_and_alignment(self, self.target_info())
}
fn stack_size_without_alignment(&self, layout: InLayout<'a>) -> u32 {
self.get(layout)
self.get_repr(layout)
.stack_size_without_alignment(self, self.target_info())
}
fn contains_refcounted(&self, layout: InLayout<'a>) -> bool {
self.get(layout).contains_refcounted(self)
self.get_repr(layout).contains_refcounted(self)
}
fn is_refcounted(&self, layout: InLayout<'a>) -> bool {
self.get(layout).is_refcounted()
self.get_repr(layout).is_refcounted()
}
fn is_passed_by_reference(&self, layout: InLayout<'a>) -> bool {
self.get(layout)
self.get_repr(layout)
.is_passed_by_reference(self, self.target_info())
}
@ -239,6 +245,10 @@ pub trait LayoutInterner<'a>: Sized {
Layout::runtime_representation_in(layout, self)
}
fn has_varying_stack_size(&self, layout: InLayout<'a>, arena: &'a Bump) -> bool {
self.get_repr(layout).has_varying_stack_size(self, arena)
}
fn chase_recursive(&self, mut layout: InLayout<'a>) -> LayoutRepr<'a> {
loop {
let lay = self.get_repr(layout);
@ -251,7 +261,7 @@ pub trait LayoutInterner<'a>: Sized {
fn chase_recursive_in(&self, mut layout: InLayout<'a>) -> InLayout<'a> {
loop {
match self.get(layout).repr {
match self.get_repr(layout) {
LayoutRepr::RecursivePointer(l) => layout = l,
_ => return layout,
}
@ -259,7 +269,7 @@ pub trait LayoutInterner<'a>: Sized {
}
fn safe_to_memcpy(&self, layout: InLayout<'a>) -> bool {
self.get(layout).safe_to_memcpy(self)
self.get_repr(layout).safe_to_memcpy(self)
}
/// Checks if two layouts are equivalent up to isomorphism.
@ -306,7 +316,7 @@ pub trait LayoutInterner<'a>: Sized {
{
use LayoutRepr::*;
match self.get(layout).repr {
match self.get_repr(layout) {
Builtin(builtin) => builtin.to_doc(alloc, self, seen_rec, parens),
Struct(field_layouts) => {
let fields_doc = field_layouts
@ -673,7 +683,7 @@ impl<'a> GlobalLayoutInterner<'a> {
..normalized
};
let lambda_set_layout = Layout {
repr: LayoutRepr::LambdaSet(full_lambda_set),
repr: LayoutRepr::LambdaSet(full_lambda_set).direct(),
semantic: SemanticRepr::NONE,
};
@ -982,7 +992,7 @@ macro_rules! st_impl {
full_layout: slot,
};
let lay = Layout {
repr: LayoutRepr::LambdaSet(lambda_set),
repr: LayoutRepr::LambdaSet(lambda_set).direct(),
semantic: SemanticRepr::NONE
};
self.vec[slot.0] = lay;
@ -1054,7 +1064,8 @@ mod reify {
slot: InLayout<'a>,
normalized_layout: Layout<'a>,
) -> Layout<'a> {
let repr = match normalized_layout.repr {
// TODO: what if the layout repr is a newtype - should we preserve all the links?
let repr = match normalized_layout.repr(interner) {
LayoutRepr::Builtin(builtin) => {
LayoutRepr::Builtin(reify_builtin(arena, interner, slot, builtin))
}
@ -1073,7 +1084,7 @@ mod reify {
}
};
Layout {
repr,
repr: repr.direct(),
semantic: normalized_layout.semantic,
}
}
@ -1252,7 +1263,7 @@ mod equiv {
continue;
}
use LayoutRepr::*;
match (interner.get(l1).repr, interner.get(l2).repr) {
match (interner.get_repr(l1), interner.get_repr(l2)) {
(RecursivePointer(rec), _) => stack.push((rec, l2)),
(_, RecursivePointer(rec)) => stack.push((l1, rec)),
(Builtin(b1), Builtin(b2)) => {
@ -1348,7 +1359,7 @@ mod equiv {
pub mod dbg {
use roc_module::symbol::Symbol;
use crate::layout::{Builtin, LambdaSet, Layout, LayoutRepr, UnionLayout};
use crate::layout::{Builtin, LambdaSet, LayoutRepr, UnionLayout};
use super::{InLayout, LayoutInterner};
@ -1356,7 +1367,8 @@ pub mod dbg {
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 Layout { repr, semantic } = self.0.get(self.1);
let repr = self.0.get_repr(self.1);
let semantic = self.0.get_semantic(self.1);
f.debug_struct("Layout")
.field("repr", &DbgRepr(self.0, &repr))
@ -1552,7 +1564,7 @@ mod insert_lambda_set {
let lambda_set =
interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, TEST_SET, FIXUP, Layout::UNIT);
let lambda_set_layout_in = interner.insert(Layout {
repr: LayoutRepr::LambdaSet(lambda_set),
repr: LayoutRepr::LambdaSet(lambda_set).direct(),
semantic: SemanticRepr::NONE,
});
assert_eq!(lambda_set.full_layout, lambda_set_layout_in);
@ -1611,15 +1623,16 @@ mod insert_recursive_layout {
fn make_layout<'a>(arena: &'a Bump, interner: &mut impl LayoutInterner<'a>) -> Layout<'a> {
let list_rec = Layout {
repr: LayoutRepr::Builtin(Builtin::List(Layout::NAKED_RECURSIVE_PTR)),
repr: LayoutRepr::Builtin(Builtin::List(Layout::NAKED_RECURSIVE_PTR)).direct(),
semantic: SemanticRepr::NONE,
};
let repr = LayoutRepr::Union(UnionLayout::Recursive(&*arena.alloc([
&*arena.alloc([interner.insert(list_rec)]),
&*arena.alloc_slice_fill_iter([interner.insert_no_semantic(LayoutRepr::struct_(
&*arena.alloc([Layout::NAKED_RECURSIVE_PTR]),
))]),
])));
&*arena.alloc_slice_fill_iter([interner.insert_direct_no_semantic(
LayoutRepr::struct_(&*arena.alloc([Layout::NAKED_RECURSIVE_PTR])),
)]),
])))
.direct();
Layout {
repr,
semantic: SemanticRepr::NONE,
@ -1629,9 +1642,9 @@ mod insert_recursive_layout {
fn get_rec_ptr_index<'a>(interner: &impl LayoutInterner<'a>, layout: InLayout<'a>) -> usize {
match interner.chase_recursive(layout) {
LayoutRepr::Union(UnionLayout::Recursive(&[&[l1], &[l2]])) => {
match (interner.get(l1).repr, interner.get(l2).repr) {
match (interner.get_repr(l1), interner.get_repr(l2)) {
(LayoutRepr::Builtin(Builtin::List(l1)), LayoutRepr::Struct(&[l2])) => {
match (interner.get(l1).repr, interner.get(l2).repr) {
match (interner.get_repr(l1), interner.get_repr(l2)) {
(
LayoutRepr::RecursivePointer(i1),
LayoutRepr::RecursivePointer(i2),