mirror of
https://github.com/roc-lang/roc.git
synced 2024-10-26 18:28:43 +03:00
Begin support for looping-back recursive pointers to their source layouts
This commit is contained in:
parent
a30a4e36ed
commit
8750127111
@ -1727,7 +1727,8 @@ fn layout_spec_help<'a>(
|
||||
|
||||
builder.add_tuple_type(&[cell_type, inner_type])
|
||||
}
|
||||
RecursivePointer => match when_recursive {
|
||||
// TODO(recursive-layouts): update once we have recursive pointer loops
|
||||
RecursivePointer(_) => match when_recursive {
|
||||
WhenRecursive::Unreachable => {
|
||||
unreachable!()
|
||||
}
|
||||
|
@ -1528,7 +1528,7 @@ fn build_tag_field_value<'a, 'ctx, 'env>(
|
||||
value: BasicValueEnum<'ctx>,
|
||||
tag_field_layout: InLayout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
if let Layout::RecursivePointer = layout_interner.get(tag_field_layout) {
|
||||
if let Layout::RecursivePointer(_) = layout_interner.get(tag_field_layout) {
|
||||
debug_assert!(value.is_pointer_value());
|
||||
|
||||
// we store recursive pointers as `i64*`
|
||||
@ -2020,7 +2020,7 @@ fn lookup_at_index_ptr<'a, 'ctx, 'env>(
|
||||
"load_at_index_ptr_old",
|
||||
);
|
||||
|
||||
if let Some(Layout::RecursivePointer) = field_layouts
|
||||
if let Some(Layout::RecursivePointer(_)) = field_layouts
|
||||
.get(index as usize)
|
||||
.map(|l| layout_interner.get(*l))
|
||||
{
|
||||
@ -2080,7 +2080,7 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
|
||||
"load_at_index_ptr",
|
||||
);
|
||||
|
||||
if let Some(Layout::RecursivePointer) = field_layouts
|
||||
if let Some(Layout::RecursivePointer(_)) = field_layouts
|
||||
.get(index as usize)
|
||||
.map(|l| layout_interner.get(*l))
|
||||
{
|
||||
@ -2481,7 +2481,10 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||
let mut stack = Vec::with_capacity_in(queue.len(), env.arena);
|
||||
|
||||
for (symbol, expr, layout) in queue {
|
||||
debug_assert!(layout_interner.get(*layout) != Layout::RecursivePointer);
|
||||
debug_assert!(!matches!(
|
||||
layout_interner.get(*layout),
|
||||
Layout::RecursivePointer(_)
|
||||
));
|
||||
|
||||
let val = build_exp_expr(
|
||||
env,
|
||||
@ -6107,7 +6110,7 @@ pub(crate) enum WhenRecursive<'a> {
|
||||
impl<'a> WhenRecursive<'a> {
|
||||
pub fn unwrap_recursive_pointer(&self, layout: Layout<'a>) -> Layout<'a> {
|
||||
match layout {
|
||||
Layout::RecursivePointer => match self {
|
||||
Layout::RecursivePointer(_) => match self {
|
||||
WhenRecursive::Loop(lay) => Layout::Union(*lay),
|
||||
WhenRecursive::Unreachable => {
|
||||
internal_error!("cannot compare recursive pointers outside of a structure")
|
||||
|
@ -208,7 +208,7 @@ fn build_eq<'a, 'ctx, 'env>(
|
||||
rhs_val,
|
||||
),
|
||||
|
||||
Layout::RecursivePointer => match when_recursive {
|
||||
Layout::RecursivePointer(_) => match when_recursive {
|
||||
WhenRecursive::Unreachable => {
|
||||
unreachable!("recursion pointers should never be compared directly")
|
||||
}
|
||||
@ -417,7 +417,7 @@ fn build_neq<'a, 'ctx, 'env>(
|
||||
result.into()
|
||||
}
|
||||
|
||||
Layout::RecursivePointer => {
|
||||
Layout::RecursivePointer(_) => {
|
||||
unreachable!("recursion pointers should never be compared directly")
|
||||
}
|
||||
Layout::LambdaSet(_) => unreachable!("cannot compare closure"),
|
||||
@ -761,7 +761,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
|
||||
.build_extract_value(struct2, index as u32, "eq_field")
|
||||
.unwrap();
|
||||
|
||||
let are_equal = if let Layout::RecursivePointer = layout_interner.get(*field_layout) {
|
||||
let are_equal = if let Layout::RecursivePointer(_) = layout_interner.get(*field_layout) {
|
||||
match &when_recursive {
|
||||
WhenRecursive::Unreachable => {
|
||||
unreachable!("The current layout should not be recursive, but is")
|
||||
|
@ -47,7 +47,7 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||
inner_type.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
Union(union_layout) => basic_type_from_union_layout(env, layout_interner, &union_layout),
|
||||
RecursivePointer => env
|
||||
RecursivePointer(_) => env
|
||||
.context
|
||||
.i64_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
|
@ -380,7 +380,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
||||
)
|
||||
}
|
||||
|
||||
Layout::RecursivePointer => match when_recursive {
|
||||
Layout::RecursivePointer(_) => match when_recursive {
|
||||
WhenRecursive::Unreachable => {
|
||||
unreachable!("recursion pointers should never be compared directly")
|
||||
}
|
||||
|
@ -511,7 +511,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
||||
};
|
||||
|
||||
match layout_interner.get(layout) {
|
||||
Layout::RecursivePointer => match when_recursive {
|
||||
Layout::RecursivePointer(_) => match when_recursive {
|
||||
WhenRecursive::Unreachable => {
|
||||
unreachable!("recursion pointers should never be hashed directly")
|
||||
}
|
||||
@ -640,7 +640,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
||||
Some(function)
|
||||
}
|
||||
|
||||
Layout::RecursivePointer => match when_recursive {
|
||||
Layout::RecursivePointer(_) => match when_recursive {
|
||||
WhenRecursive::Unreachable => {
|
||||
unreachable!("recursion pointers cannot be in/decremented directly")
|
||||
}
|
||||
@ -1326,7 +1326,7 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||
let mut deferred_nonrec = Vec::new_in(env.arena);
|
||||
|
||||
for (i, field_layout) in field_layouts.iter().enumerate() {
|
||||
if let Layout::RecursivePointer = layout_interner.get(*field_layout) {
|
||||
if let Layout::RecursivePointer(_) = layout_interner.get(*field_layout) {
|
||||
// this field has type `*i64`, but is really a pointer to the data we want
|
||||
let elem_pointer = env
|
||||
.builder
|
||||
@ -1810,7 +1810,7 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||
);
|
||||
|
||||
for (i, field_layout) in field_layouts.iter().enumerate() {
|
||||
if let Layout::RecursivePointer = layout_interner.get(*field_layout) {
|
||||
if let Layout::RecursivePointer(_) = layout_interner.get(*field_layout) {
|
||||
let recursive_union_layout = match when_recursive {
|
||||
WhenRecursive::Unreachable => {
|
||||
panic!("non-recursive tag unions cannot contain naked recursion pointers!");
|
||||
|
@ -98,7 +98,7 @@ impl WasmLayout {
|
||||
| NullableUnwrapped { .. },
|
||||
)
|
||||
| Layout::Boxed(_)
|
||||
| Layout::RecursivePointer => Self::Primitive(PTR_TYPE, PTR_SIZE),
|
||||
| Layout::RecursivePointer(_) => Self::Primitive(PTR_TYPE, PTR_SIZE),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1952,7 +1952,7 @@ impl<'a> LowLevelCall<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
Layout::RecursivePointer => {
|
||||
Layout::RecursivePointer(_) => {
|
||||
internal_error!(
|
||||
"Tried to apply `==` to RecursivePointer values {:?}",
|
||||
self.arguments,
|
||||
|
@ -45,7 +45,7 @@ pub fn eq_generic<'a>(
|
||||
eq_boxed(root, ident_ids, ctx, layout_interner, inner_layout)
|
||||
}
|
||||
Layout::LambdaSet(_) => unreachable!("`==` is not defined on functions"),
|
||||
Layout::RecursivePointer => {
|
||||
Layout::RecursivePointer(_) => {
|
||||
unreachable!(
|
||||
"Can't perform `==` on RecursivePointer. Should have been replaced by a tag union."
|
||||
)
|
||||
@ -451,7 +451,7 @@ fn eq_tag_fields<'a>(
|
||||
// (If there are more than one, the others will use non-tail recursion)
|
||||
let rec_ptr_index = field_layouts
|
||||
.iter()
|
||||
.position(|field| matches!(layout_interner.get(*field), Layout::RecursivePointer));
|
||||
.position(|field| matches!(layout_interner.get(*field), Layout::RecursivePointer(_)));
|
||||
|
||||
let (tailrec_index, innermost_stmt) = match rec_ptr_index {
|
||||
None => {
|
||||
|
@ -255,7 +255,10 @@ impl<'a> CodeGenHelp<'a> {
|
||||
// debug_assert!(self.debug_recursion_depth < 100);
|
||||
self.debug_recursion_depth += 1;
|
||||
|
||||
let layout = if matches!(layout_interner.get(called_layout), Layout::RecursivePointer) {
|
||||
let layout = if matches!(
|
||||
layout_interner.get(called_layout),
|
||||
Layout::RecursivePointer(_)
|
||||
) {
|
||||
let union_layout = ctx.recursive_union.unwrap();
|
||||
layout_interner.insert(Layout::Union(union_layout))
|
||||
} else {
|
||||
@ -494,7 +497,7 @@ impl<'a> CodeGenHelp<'a> {
|
||||
}
|
||||
|
||||
// This line is the whole point of the function
|
||||
Layout::RecursivePointer => Layout::Union(ctx.recursive_union.unwrap()),
|
||||
Layout::RecursivePointer(_) => Layout::Union(ctx.recursive_union.unwrap()),
|
||||
};
|
||||
layout_interner.insert(layout)
|
||||
}
|
||||
@ -535,7 +538,7 @@ impl<'a> CodeGenHelp<'a> {
|
||||
for fields in tags.iter() {
|
||||
let found_index = fields
|
||||
.iter()
|
||||
.position(|f| matches!(layout_interner.get(*f), Layout::RecursivePointer));
|
||||
.position(|f| matches!(layout_interner.get(*f), Layout::RecursivePointer(_)));
|
||||
tailrec_indices.push(found_index);
|
||||
can_use_tailrec |= found_index.is_some();
|
||||
}
|
||||
@ -586,7 +589,7 @@ fn layout_needs_helper_proc<'a>(
|
||||
Layout::Union(UnionLayout::NonRecursive(tags)) => !tags.is_empty(),
|
||||
Layout::Union(_) => true,
|
||||
Layout::LambdaSet(_) => true,
|
||||
Layout::RecursivePointer => false,
|
||||
Layout::RecursivePointer(_) => false,
|
||||
Layout::Boxed(_) => true,
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ pub fn refcount_generic<'a>(
|
||||
structure,
|
||||
)
|
||||
}
|
||||
Layout::RecursivePointer => unreachable!(
|
||||
Layout::RecursivePointer(_) => unreachable!(
|
||||
"We should never call a refcounting helper on a RecursivePointer layout directly"
|
||||
),
|
||||
Layout::Boxed(inner_layout) => refcount_boxed(
|
||||
@ -450,7 +450,7 @@ where
|
||||
.all(|l| is_rc_implemented_yet(interner, *l)),
|
||||
},
|
||||
Layout::LambdaSet(lambda_set) => is_rc_implemented_yet(interner, lambda_set.representation),
|
||||
Layout::RecursivePointer => true,
|
||||
Layout::RecursivePointer(_) => true,
|
||||
Layout::Boxed(_) => true,
|
||||
}
|
||||
}
|
||||
|
@ -657,7 +657,7 @@ fn resolve_recursive_layout<'a>(
|
||||
|
||||
// TODO check if recursive pointer not in recursive union
|
||||
let layout = match interner.get(layout) {
|
||||
Layout::RecursivePointer => Layout::Union(when_recursive),
|
||||
Layout::RecursivePointer(_) => Layout::Union(when_recursive),
|
||||
Layout::Union(union_layout) => match union_layout {
|
||||
UnionLayout::NonRecursive(payloads) => {
|
||||
let payloads = payloads.iter().map(|args| {
|
||||
|
@ -7784,7 +7784,7 @@ fn store_tag_pattern<'a>(
|
||||
for (index, (argument, arg_layout)) in arguments.iter().enumerate().rev() {
|
||||
let mut arg_layout = *arg_layout;
|
||||
|
||||
if let Layout::RecursivePointer = layout_cache.get_in(arg_layout) {
|
||||
if let Layout::RecursivePointer(_) = layout_cache.get_in(arg_layout) {
|
||||
// TODO(recursive-layouts): fix after disjoint rec ptrs
|
||||
arg_layout = layout_cache.put_in(Layout::Union(union_layout));
|
||||
}
|
||||
@ -7868,7 +7868,7 @@ fn store_newtype_pattern<'a>(
|
||||
for (index, (argument, arg_layout)) in arguments.iter().enumerate().rev() {
|
||||
let mut arg_layout = *arg_layout;
|
||||
|
||||
if let Layout::RecursivePointer = layout_cache.get_in(arg_layout) {
|
||||
if let Layout::RecursivePointer(_) = layout_cache.get_in(arg_layout) {
|
||||
arg_layout = layout;
|
||||
}
|
||||
|
||||
|
@ -675,7 +675,7 @@ pub enum Layout<'a> {
|
||||
Boxed(InLayout<'a>),
|
||||
Union(UnionLayout<'a>),
|
||||
LambdaSet(LambdaSet<'a>),
|
||||
RecursivePointer,
|
||||
RecursivePointer(InLayout<'a>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
@ -880,7 +880,7 @@ impl<'a> UnionLayout<'a> {
|
||||
};
|
||||
|
||||
// TODO(recursive-layouts): simplify after we have disjoint recursive pointers
|
||||
if let Layout::RecursivePointer = interner.get(result) {
|
||||
if let Layout::RecursivePointer(_) = interner.get(result) {
|
||||
interner.insert(Layout::Union(self))
|
||||
} else {
|
||||
result
|
||||
@ -1523,7 +1523,7 @@ impl<'a> LambdaSet<'a> {
|
||||
let left = interner.get(*left);
|
||||
let right = interner.get(*right);
|
||||
|
||||
let left = if left == Layout::RecursivePointer {
|
||||
let left = if matches!(left, Layout::RecursivePointer(_)) {
|
||||
let runtime_repr = self.runtime_representation();
|
||||
debug_assert!(matches!(
|
||||
interner.get(runtime_repr),
|
||||
@ -1534,7 +1534,7 @@ impl<'a> LambdaSet<'a> {
|
||||
left
|
||||
};
|
||||
|
||||
let right = if right == Layout::RecursivePointer {
|
||||
let right = if matches!(right, Layout::RecursivePointer(_)) {
|
||||
let runtime_repr = self.runtime_representation();
|
||||
debug_assert!(matches!(
|
||||
interner.get(runtime_repr),
|
||||
@ -2253,7 +2253,7 @@ impl<'a, 'b> Env<'a, 'b> {
|
||||
if self.is_seen(var) {
|
||||
// Always return recursion pointers directly, NEVER cache them as naked!
|
||||
// TODO(recursive-layouts): after we have disjoint recursive pointers, change this
|
||||
let rec_ptr = self.cache.put_in(Layout::RecursivePointer);
|
||||
let rec_ptr = self.cache.put_in(Layout::RecursivePointer(Layout::VOID));
|
||||
return Cacheable(Ok(rec_ptr), NAKED_RECURSION_PTR);
|
||||
}
|
||||
|
||||
@ -2443,7 +2443,7 @@ impl<'a> Layout<'a> {
|
||||
LambdaSet(lambda_set) => interner
|
||||
.get(lambda_set.runtime_representation())
|
||||
.safe_to_memcpy(interner),
|
||||
Boxed(_) | RecursivePointer => {
|
||||
Boxed(_) | RecursivePointer(_) => {
|
||||
// We cannot memcpy pointers, because then we would have the same pointer in multiple places!
|
||||
false
|
||||
}
|
||||
@ -2529,7 +2529,7 @@ impl<'a> Layout<'a> {
|
||||
LambdaSet(lambda_set) => interner
|
||||
.get(lambda_set.runtime_representation())
|
||||
.stack_size_without_alignment(interner, target_info),
|
||||
RecursivePointer => target_info.ptr_width() as u32,
|
||||
RecursivePointer(_) => target_info.ptr_width() as u32,
|
||||
Boxed(_) => target_info.ptr_width() as u32,
|
||||
}
|
||||
}
|
||||
@ -2581,7 +2581,7 @@ impl<'a> Layout<'a> {
|
||||
.get(lambda_set.runtime_representation())
|
||||
.alignment_bytes(interner, target_info),
|
||||
Layout::Builtin(builtin) => builtin.alignment_bytes(target_info),
|
||||
Layout::RecursivePointer => target_info.ptr_width() as u32,
|
||||
Layout::RecursivePointer(_) => target_info.ptr_width() as u32,
|
||||
Layout::Boxed(_) => target_info.ptr_width() as u32,
|
||||
}
|
||||
}
|
||||
@ -2601,7 +2601,9 @@ impl<'a> Layout<'a> {
|
||||
Layout::LambdaSet(lambda_set) => interner
|
||||
.get(lambda_set.runtime_representation())
|
||||
.allocation_alignment_bytes(interner, target_info),
|
||||
Layout::RecursivePointer => unreachable!("should be looked up to get an actual layout"),
|
||||
Layout::RecursivePointer(_) => {
|
||||
unreachable!("should be looked up to get an actual layout")
|
||||
}
|
||||
Layout::Boxed(inner) => interner
|
||||
.get(*inner)
|
||||
.allocation_alignment_bytes(interner, target_info),
|
||||
@ -2646,7 +2648,7 @@ impl<'a> Layout<'a> {
|
||||
|
||||
Union(_) => true,
|
||||
|
||||
RecursivePointer => true,
|
||||
RecursivePointer(_) => true,
|
||||
|
||||
Builtin(List(_)) | Builtin(Str) => true,
|
||||
|
||||
@ -2685,7 +2687,7 @@ impl<'a> Layout<'a> {
|
||||
LambdaSet(lambda_set) => interner
|
||||
.get(lambda_set.runtime_representation())
|
||||
.contains_refcounted(interner),
|
||||
RecursivePointer => true,
|
||||
RecursivePointer(_) => true,
|
||||
Boxed(_) => true,
|
||||
}
|
||||
}
|
||||
@ -2720,7 +2722,7 @@ impl<'a> Layout<'a> {
|
||||
LambdaSet(lambda_set) => interner
|
||||
.get(lambda_set.runtime_representation())
|
||||
.to_doc(alloc, interner, parens),
|
||||
RecursivePointer => alloc.text("*self"),
|
||||
RecursivePointer(_) => alloc.text("*self"),
|
||||
Boxed(inner) => alloc
|
||||
.text("Boxed(")
|
||||
.append(interner.get(inner).to_doc(alloc, interner, parens))
|
||||
@ -3104,7 +3106,7 @@ fn layout_from_flat_type<'a>(
|
||||
Func(args, closure_var, ret_var) => {
|
||||
if env.is_seen(closure_var) {
|
||||
// TODO(recursive-layouts): change after disjoint recursive layouts supported
|
||||
let rec_ptr = env.cache.put_in(Layout::RecursivePointer);
|
||||
let rec_ptr = env.cache.put_in(Layout::RecursivePointer(Layout::VOID));
|
||||
Cacheable(Ok(rec_ptr), NAKED_RECURSION_PTR)
|
||||
} else {
|
||||
let mut criteria = CACHEABLE;
|
||||
@ -3791,7 +3793,7 @@ where
|
||||
|
||||
let arg_layout = if self_recursion {
|
||||
// TODO(recursive-layouts): fix after disjoint recursive pointers supported
|
||||
env.cache.put_in(Layout::RecursivePointer)
|
||||
env.cache.put_in(Layout::RecursivePointer(Layout::VOID))
|
||||
} else {
|
||||
in_layout
|
||||
};
|
||||
@ -4056,7 +4058,8 @@ where
|
||||
for &var in variables {
|
||||
// TODO does this cause problems with mutually recursive unions?
|
||||
if rec_var == subs.get_root_key_without_compacting(var) {
|
||||
tag_layout.push(env.cache.put_in(Layout::RecursivePointer));
|
||||
// TODO(recursive-layouts): fix after disjoint recursive pointers supported
|
||||
tag_layout.push(env.cache.put_in(Layout::RecursivePointer(Layout::VOID)));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ cache_interned_layouts! {
|
||||
14, F64, Layout::Builtin(Builtin::Float(FloatWidth::F64))
|
||||
15, DEC, Layout::Builtin(Builtin::Decimal)
|
||||
16, STR, Layout::Builtin(Builtin::Str)
|
||||
17, RECURSIVE_PTR, Layout::RecursivePointer
|
||||
17, RECURSIVE_PTR, Layout::RecursivePointer(Layout::VOID)
|
||||
|
||||
; 18
|
||||
}
|
||||
|
@ -1464,7 +1464,7 @@ fn add_tag_union<'a>(
|
||||
Layout::LambdaSet(_) => {
|
||||
todo!();
|
||||
}
|
||||
Layout::RecursivePointer => {
|
||||
Layout::RecursivePointer(_) => {
|
||||
// A single-tag union which only wraps itself is erroneous and should have
|
||||
// been turned into an error earlier in the process.
|
||||
unreachable!();
|
||||
|
@ -499,7 +499,7 @@ fn jit_to_ast_help<'a, A: ReplApp<'a>>(
|
||||
},
|
||||
)
|
||||
}
|
||||
Layout::RecursivePointer => {
|
||||
Layout::RecursivePointer(_) => {
|
||||
unreachable!("RecursivePointers can only be inside structures")
|
||||
}
|
||||
Layout::LambdaSet(_) => OPAQUE_FUNCTION,
|
||||
@ -632,7 +632,7 @@ fn addr_to_ast<'a, M: ReplAppMemory>(
|
||||
);
|
||||
}
|
||||
},
|
||||
(_, Layout::RecursivePointer) => match (raw_content, when_recursive) {
|
||||
(_, Layout::RecursivePointer(_)) => match (raw_content, when_recursive) {
|
||||
(
|
||||
Content::RecursionVar {
|
||||
structure,
|
||||
|
Loading…
Reference in New Issue
Block a user