Prevent confusion between separate instances of RecursivePointer

This commit is contained in:
Brian Carroll 2022-01-04 20:00:42 +00:00
parent ad95ea4a3b
commit 456bda0895
3 changed files with 134 additions and 0 deletions

View file

@ -231,6 +231,8 @@ impl<'a> CodeGenHelp<'a> {
) -> Symbol {
use HelperOp::*;
let layout = self.replace_rec_ptr(ctx, layout);
let found = self
.specializations
.iter()
@ -329,6 +331,56 @@ impl<'a> CodeGenHelp<'a> {
let ident_id = ident_ids.add(Ident::from(debug_name));
Symbol::new(self.home, ident_id)
}
// When creating or looking up Specializations, we need to replace RecursivePointer
// with the particular Union layout it represents at this point in the tree.
// For example if a program uses `RoseTree a : [ Tree a (List (RoseTree a)) ]`
// then it could have both `RoseTree I64` and `RoseTree Str`. In this case it
// needs *two* specializations for `List(RecursivePointer)`, not just one.
fn replace_rec_ptr(&self, ctx: &Context<'a>, layout: Layout<'a>) -> Layout<'a> {
match layout {
Layout::Builtin(Builtin::Dict(k, v)) => Layout::Builtin(Builtin::Dict(
self.arena.alloc(self.replace_rec_ptr(ctx, *k)),
self.arena.alloc(self.replace_rec_ptr(ctx, *v)),
)),
Layout::Builtin(Builtin::Set(k)) => Layout::Builtin(Builtin::Set(
self.arena.alloc(self.replace_rec_ptr(ctx, *k)),
)),
Layout::Builtin(Builtin::List(v)) => Layout::Builtin(Builtin::List(
self.arena.alloc(self.replace_rec_ptr(ctx, *v)),
)),
Layout::Builtin(_) => layout,
Layout::Struct(fields) => {
let new_fields_iter = fields.iter().map(|f| self.replace_rec_ptr(ctx, *f));
Layout::Struct(self.arena.alloc_slice_fill_iter(new_fields_iter))
}
Layout::Union(UnionLayout::NonRecursive(tags)) => {
let mut new_tags = Vec::with_capacity_in(tags.len(), self.arena);
for fields in tags {
let mut new_fields = Vec::with_capacity_in(fields.len(), self.arena);
for field in fields.iter() {
new_fields.push(self.replace_rec_ptr(ctx, *field))
}
new_tags.push(new_fields.into_bump_slice());
}
Layout::Union(UnionLayout::NonRecursive(new_tags.into_bump_slice()))
}
Layout::Union(_) => layout,
Layout::LambdaSet(lambda_set) => {
self.replace_rec_ptr(ctx, lambda_set.runtime_representation())
}
// This line is the whole point of the function
Layout::RecursivePointer => Layout::Union(ctx.recursive_union.unwrap()),
}
}
}
fn let_lowlevel<'a>(