mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Simplify how glue_procs are handled
This commit is contained in:
parent
d35d268a6b
commit
8e2bbee377
5 changed files with 557 additions and 448 deletions
|
@ -3016,7 +3016,7 @@ fn finish_specialization<'a>(
|
||||||
let ret = &layout.result;
|
let ret = &layout.result;
|
||||||
|
|
||||||
for layout in layout.arguments.iter().chain([ret]) {
|
for layout in layout.arguments.iter().chain([ret]) {
|
||||||
let glue_procs = roc_mono::ir::generate_glue_procs(
|
let all_glue_procs = roc_mono::ir::generate_glue_procs(
|
||||||
module_id,
|
module_id,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
arena,
|
arena,
|
||||||
|
@ -3024,8 +3024,16 @@ fn finish_specialization<'a>(
|
||||||
*layout,
|
*layout,
|
||||||
);
|
);
|
||||||
|
|
||||||
glue_getters.extend(glue_procs.procs.iter().map(|t| t.0));
|
glue_getters.extend(all_glue_procs.iter().flat_map(|(_, glue_procs)| {
|
||||||
procedures.extend(glue_procs.procs);
|
glue_procs
|
||||||
|
.iter()
|
||||||
|
.map(|glue_proc| (glue_proc.name, glue_proc.proc_layout))
|
||||||
|
}));
|
||||||
|
procedures.extend(all_glue_procs.into_iter().flat_map(|(_, glue_procs)| {
|
||||||
|
glue_procs
|
||||||
|
.into_iter()
|
||||||
|
.map(|glue_proc| ((glue_proc.name, glue_proc.proc_layout), glue_proc.proc))
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10762,9 +10762,10 @@ pub struct GlueLayouts<'a> {
|
||||||
pub getters: std::vec::Vec<(Symbol, ProcLayout<'a>)>,
|
pub getters: std::vec::Vec<(Symbol, ProcLayout<'a>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GlueProcs<'a> {
|
pub struct GlueProc<'a> {
|
||||||
pub procs: Vec<'a, ((Symbol, ProcLayout<'a>), Proc<'a>)>,
|
pub name: Symbol,
|
||||||
pub layouts: Vec<'a, Layout<'a>>,
|
pub proc_layout: ProcLayout<'a>,
|
||||||
|
pub proc: Proc<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_glue_procs<'a, I: Interner<'a, Layout<'a>>>(
|
pub fn generate_glue_procs<'a, I: Interner<'a, Layout<'a>>>(
|
||||||
|
@ -10773,10 +10774,9 @@ pub fn generate_glue_procs<'a, I: Interner<'a, Layout<'a>>>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
layout_interner: &mut I,
|
layout_interner: &mut I,
|
||||||
layout: Layout<'a>,
|
layout: Layout<'a>,
|
||||||
) -> GlueProcs<'a> {
|
) -> Vec<'a, (Layout<'a>, Vec<'a, GlueProc<'a>>)> {
|
||||||
let mut stack = Vec::new_in(arena);
|
let mut stack = Vec::new_in(arena);
|
||||||
let mut procs = Vec::new_in(arena);
|
let mut answer = Vec::new_in(arena);
|
||||||
let mut layouts = Vec::new_in(arena);
|
|
||||||
|
|
||||||
stack.push(layout);
|
stack.push(layout);
|
||||||
|
|
||||||
|
@ -10792,17 +10792,16 @@ pub fn generate_glue_procs<'a, I: Interner<'a, Layout<'a>>>(
|
||||||
},
|
},
|
||||||
Layout::Struct { field_layouts, .. } => {
|
Layout::Struct { field_layouts, .. } => {
|
||||||
if layout.contains_function(arena) {
|
if layout.contains_function(arena) {
|
||||||
layouts.push(layout);
|
let procs = generate_glue_procs_for_fields(
|
||||||
|
|
||||||
generate_glue_procs_for_fields(
|
|
||||||
home,
|
home,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
arena,
|
arena,
|
||||||
layout,
|
layout,
|
||||||
field_layouts,
|
field_layouts,
|
||||||
&mut procs,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
answer.push((layout, procs));
|
||||||
|
|
||||||
stack.extend(field_layouts);
|
stack.extend(field_layouts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10834,7 +10833,7 @@ pub fn generate_glue_procs<'a, I: Interner<'a, Layout<'a>>>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GlueProcs { procs, layouts }
|
answer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_glue_procs_for_fields<'a>(
|
fn generate_glue_procs_for_fields<'a>(
|
||||||
|
@ -10843,24 +10842,22 @@ fn generate_glue_procs_for_fields<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
unboxed_struct_layout: Layout<'a>,
|
unboxed_struct_layout: Layout<'a>,
|
||||||
field_layouts: &'a [Layout<'a>],
|
field_layouts: &'a [Layout<'a>],
|
||||||
output: &mut Vec<'a, ((Symbol, ProcLayout<'a>), Proc<'a>)>,
|
) -> Vec<'a, GlueProc<'a>> {
|
||||||
) {
|
|
||||||
output.reserve(field_layouts.len());
|
|
||||||
|
|
||||||
let boxed_struct_layout = Layout::Boxed(arena.alloc(unboxed_struct_layout));
|
let boxed_struct_layout = Layout::Boxed(arena.alloc(unboxed_struct_layout));
|
||||||
|
let mut answer = bumpalo::collections::Vec::with_capacity_in(field_layouts.len(), arena);
|
||||||
|
|
||||||
for (index, field) in field_layouts.iter().enumerate() {
|
for (index, field) in field_layouts.iter().enumerate() {
|
||||||
let symbol = Symbol::new(home, ident_ids.gen_unique());
|
|
||||||
let argument = Symbol::new(home, ident_ids.gen_unique());
|
|
||||||
let unboxed = Symbol::new(home, ident_ids.gen_unique());
|
|
||||||
let result = Symbol::new(home, ident_ids.gen_unique());
|
|
||||||
|
|
||||||
let proc_layout = ProcLayout {
|
let proc_layout = ProcLayout {
|
||||||
arguments: arena.alloc([boxed_struct_layout]),
|
arguments: arena.alloc([boxed_struct_layout]),
|
||||||
result: *field,
|
result: *field,
|
||||||
captures_niche: CapturesNiche::no_niche(),
|
captures_niche: CapturesNiche::no_niche(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let symbol = Symbol::new(home, ident_ids.gen_unique());
|
||||||
|
let argument = Symbol::new(home, ident_ids.gen_unique());
|
||||||
|
let unboxed = Symbol::new(home, ident_ids.gen_unique());
|
||||||
|
let result = Symbol::new(home, ident_ids.gen_unique());
|
||||||
|
|
||||||
let ret_stmt = arena.alloc(Stmt::Ret(result));
|
let ret_stmt = arena.alloc(Stmt::Ret(result));
|
||||||
|
|
||||||
let field_get_expr = Expr::StructAtIndex {
|
let field_get_expr = Expr::StructAtIndex {
|
||||||
|
@ -10891,6 +10888,12 @@ fn generate_glue_procs_for_fields<'a>(
|
||||||
host_exposed_layouts: HostExposedLayouts::NotHostExposed,
|
host_exposed_layouts: HostExposedLayouts::NotHostExposed,
|
||||||
};
|
};
|
||||||
|
|
||||||
output.push(((symbol, proc_layout), proc));
|
answer.push(GlueProc {
|
||||||
|
name: symbol,
|
||||||
|
proc_layout,
|
||||||
|
proc,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
answer
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use crate::rust_glue;
|
use crate::rust_glue;
|
||||||
use crate::types::Types;
|
use crate::types::Types;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
use roc_collections::MutMap;
|
||||||
use roc_intern::GlobalInterner;
|
use roc_intern::GlobalInterner;
|
||||||
use roc_load::{ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
use roc_load::{ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
||||||
|
use roc_mono::ir::{generate_glue_procs, GlueProc};
|
||||||
use roc_mono::layout::LayoutCache;
|
use roc_mono::layout::LayoutCache;
|
||||||
use roc_reporting::report::RenderTarget;
|
use roc_reporting::report::RenderTarget;
|
||||||
use roc_target::{Architecture, TargetInfo};
|
use roc_target::{Architecture, TargetInfo};
|
||||||
|
@ -153,49 +155,53 @@ pub fn load_types(
|
||||||
operating_system,
|
operating_system,
|
||||||
};
|
};
|
||||||
let layout_cache = LayoutCache::new(layout_interner.fork(), target_info);
|
let layout_cache = LayoutCache::new(layout_interner.fork(), target_info);
|
||||||
|
let mut proc_names_by_layout = MutMap::default();
|
||||||
|
|
||||||
// Populate glue getters/setters for all relevant variables
|
// Populate glue getters/setters for all relevant variables
|
||||||
let it = variables.clone().map(|var| {
|
for var in variables.clone() {
|
||||||
use roc_mono::layout::Layout;
|
|
||||||
|
|
||||||
let mut glue_getters = bumpalo::collections::Vec::new_in(arena);
|
|
||||||
let layout = layout_cache
|
let layout = layout_cache
|
||||||
.from_var(arena, var, subs)
|
.from_var(arena, var, subs)
|
||||||
.expect("Something weird ended up in the content");
|
.expect("Something weird ended up in the content");
|
||||||
|
|
||||||
// TODO right here, we want to check the entire layout for closures;
|
if layout.contains_function(arena) {
|
||||||
// if it has any, then we want to generate getters/setters for them!
|
// Even though generate_glue_procs does more work than we need it to,
|
||||||
match layout {
|
// it's important that we use it in order to make sure we get exactly
|
||||||
Layout::Builtin(_) => todo!(),
|
// the same names that mono::ir did for code gen!
|
||||||
Layout::Struct {
|
for (layout, glue_procs) in
|
||||||
field_order_hash,
|
generate_glue_procs(home, ident_ids, arena, &mut layout_interner.fork(), layout)
|
||||||
field_layouts,
|
{
|
||||||
} => todo!(),
|
let names =
|
||||||
Layout::Boxed(_) => todo!(),
|
bumpalo::collections::Vec::with_capacity_in(glue_procs.len(), arena);
|
||||||
Layout::Union(_) => todo!(),
|
|
||||||
Layout::LambdaSet(_) => {
|
|
||||||
// TODO get function layout from LambdaSet
|
|
||||||
// let ret = &layout.result;
|
|
||||||
|
|
||||||
// for layout in layout.arguments.iter().chain([ret]) {
|
// Record all the getter/setter names associated with this layout
|
||||||
// let glue_procs = roc_mono::ir::generate_glue_procs(
|
for GlueProc { name, .. } in glue_procs {
|
||||||
// home,
|
// Store them as strings, because symbols won't be useful to glue generators!
|
||||||
// ident_ids,
|
let name_string =
|
||||||
// arena,
|
bumpalo::collections::String::from_str_in(name.as_str(&interns), arena);
|
||||||
// &mut layout_cache.interner,
|
|
||||||
// *layout,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// glue_getters.extend(glue_procs.procs.iter().map(|t| t.0));
|
// Given a struct layout (including lambda sets!) the offsets - and therefore
|
||||||
// }
|
// getters/setters - are deterministic, so we can use layout as the hash key
|
||||||
}
|
// for these getters/setters. We also only need to store the name because since
|
||||||
roc_mono::layout::Layout::RecursivePointer => todo!(),
|
// they are getters and setters, we can know their types (from a TypeId perspective)
|
||||||
|
// deterministically based on knowing the types of the structs and fields.
|
||||||
|
names.push(name_string.into_bump_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
(var, glue_getters.into_bump_slice())
|
proc_names_by_layout.insert(layout, names.into_bump_slice());
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let types = Types::new(arena, subs, it, &interns, layout_cache, target_info);
|
let types = Types::new(
|
||||||
|
arena,
|
||||||
|
subs,
|
||||||
|
variables.clone(),
|
||||||
|
&interns,
|
||||||
|
&proc_names_by_layout,
|
||||||
|
home,
|
||||||
|
layout_cache,
|
||||||
|
target_info,
|
||||||
|
);
|
||||||
|
|
||||||
types_and_targets.push((types, target_info));
|
types_and_targets.push((types, target_info));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
RocFn, RocNum, RocSingleTagPayload, RocStructFields, RocTagUnion, RocTags, RocType, TypeId,
|
Accessors, RocFn, RocNum, RocSingleTagPayload, RocStructFields, RocTagUnion, RocTags, RocType,
|
||||||
Types,
|
TypeId, Types,
|
||||||
};
|
};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use roc_target::{Architecture, TargetInfo};
|
use roc_target::{Architecture, TargetInfo};
|
||||||
|
@ -143,15 +143,8 @@ pub fn emit(types_and_targets: &[(Types, TargetInfo)]) -> String {
|
||||||
|
|
||||||
fn add_type(target_info: TargetInfo, id: TypeId, types: &Types, impls: &mut Impls) {
|
fn add_type(target_info: TargetInfo, id: TypeId, types: &Types, impls: &mut Impls) {
|
||||||
match types.get_type(id) {
|
match types.get_type(id) {
|
||||||
RocType::Struct {
|
RocType::Struct { name, fields } => {
|
||||||
name,
|
add_struct(name, target_info, fields, id, types, impls, false)
|
||||||
fields: RocStructFields::HasNoClosure { fields },
|
|
||||||
} => add_struct(name, target_info, fields, id, types, impls, false),
|
|
||||||
RocType::Struct {
|
|
||||||
name,
|
|
||||||
fields: RocStructFields::HasClosure { field_getters },
|
|
||||||
} => {
|
|
||||||
todo!();
|
|
||||||
}
|
}
|
||||||
RocType::TagUnionPayload { name, fields } => {
|
RocType::TagUnionPayload { name, fields } => {
|
||||||
add_struct(name, target_info, fields, id, types, impls, true)
|
add_struct(name, target_info, fields, id, types, impls, true)
|
||||||
|
@ -382,16 +375,18 @@ fn add_single_tag_struct(
|
||||||
buf.push_str("}\n");
|
buf.push_str("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
let field_getters = payload_getters
|
let fields = payload_getters
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(type_id, roc_fn)| (String::new(), *type_id, *roc_fn))
|
.map(|(type_id, getter)| {
|
||||||
|
(String::new(), *type_id, Accessors { getter: *getter })
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
RocType::Struct {
|
RocType::Struct {
|
||||||
// Deriving doesn't depend on the struct's name,
|
// Deriving doesn't depend on the struct's name,
|
||||||
// so no need to clone name here.
|
// so no need to clone name here.
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
fields: RocStructFields::HasClosure { field_getters },
|
fields: RocStructFields::HasClosure { fields },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,7 +432,8 @@ fn add_single_tag_struct(
|
||||||
}
|
}
|
||||||
|
|
||||||
// the impl for the single-tag union itself
|
// the impl for the single-tag union itself
|
||||||
{
|
match payload {
|
||||||
|
RocSingleTagPayload::HasNoClosures { payload_fields } => {
|
||||||
let opt_impl = Some(format!("impl {name}"));
|
let opt_impl = Some(format!("impl {name}"));
|
||||||
|
|
||||||
if payload_fields.is_empty() {
|
if payload_fields.is_empty() {
|
||||||
|
@ -587,13 +583,15 @@ fn add_single_tag_struct(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The Debug impl for the single-tag union
|
// The Debug impl for the single-tag union
|
||||||
{
|
match payload {
|
||||||
|
RocSingleTagPayload::HasNoClosures { payload_fields } => {
|
||||||
let opt_impl = Some(format!("impl core::fmt::Debug for {name}"));
|
let opt_impl = Some(format!("impl core::fmt::Debug for {name}"));
|
||||||
|
|
||||||
let mut buf =
|
let mut buf = "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {"
|
||||||
"fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {".to_string();
|
.to_string();
|
||||||
|
|
||||||
if payload_fields.is_empty() {
|
if payload_fields.is_empty() {
|
||||||
// ignore returned result, write can not fail as it is used here
|
// ignore returned result, write can not fail as it is used here
|
||||||
|
@ -618,6 +616,7 @@ fn add_single_tag_struct(
|
||||||
|
|
||||||
add_decl(impls, opt_impl, target_info, buf);
|
add_decl(impls, opt_impl, target_info, buf);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_discriminant(
|
fn add_discriminant(
|
||||||
|
@ -1044,8 +1043,7 @@ pub struct {name} {{
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
RocType::Struct { fields, name } => {
|
RocType::Struct { fields, name } => {
|
||||||
let answer =
|
let answer = tag_union_struct_help(name, fields, *payload_id, types, false);
|
||||||
tag_union_struct_help(name, fields.iter(), *payload_id, types, false);
|
|
||||||
|
|
||||||
owned_ret = answer.owned_ret;
|
owned_ret = answer.owned_ret;
|
||||||
borrowed_ret = answer.borrowed_ret;
|
borrowed_ret = answer.borrowed_ret;
|
||||||
|
@ -1055,8 +1053,7 @@ pub struct {name} {{
|
||||||
args_to_payload = answer.args_to_payload;
|
args_to_payload = answer.args_to_payload;
|
||||||
}
|
}
|
||||||
RocType::TagUnionPayload { fields, name } => {
|
RocType::TagUnionPayload { fields, name } => {
|
||||||
let answer =
|
let answer = tag_union_struct_help(name, fields, *payload_id, types, true);
|
||||||
tag_union_struct_help(name, fields.iter(), *payload_id, types, true);
|
|
||||||
|
|
||||||
owned_ret = answer.owned_ret;
|
owned_ret = answer.owned_ret;
|
||||||
borrowed_ret = answer.borrowed_ret;
|
borrowed_ret = answer.borrowed_ret;
|
||||||
|
@ -1664,12 +1661,16 @@ pub struct {name} {{
|
||||||
RocType::TagUnionPayload { fields, .. } => {
|
RocType::TagUnionPayload { fields, .. } => {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
|
|
||||||
|
match fields {
|
||||||
|
RocStructFields::HasNoClosure { fields } => {
|
||||||
for (label, _) in fields {
|
for (label, _) in fields {
|
||||||
// Needs an "f" prefix
|
// Needs an "f" prefix
|
||||||
buf.push(format!(
|
buf.push(format!(
|
||||||
".field(&({deref_str}{actual_self}.{tag_name}).f{label})"
|
".field(&({deref_str}{actual_self}.{tag_name}).f{label})"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buf.join("\n")
|
buf.join("\n")
|
||||||
}
|
}
|
||||||
|
@ -1766,10 +1767,10 @@ fn add_enumeration<I: ExactSizeIterator<Item = S>, S: AsRef<str> + Display>(
|
||||||
add_decl(impls, None, target_info, buf);
|
add_decl(impls, None, target_info, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_struct<S: Display>(
|
fn add_struct(
|
||||||
name: &str,
|
name: &str,
|
||||||
target_info: TargetInfo,
|
target_info: TargetInfo,
|
||||||
fields: &[(S, TypeId)],
|
fields: &RocStructFields,
|
||||||
struct_id: TypeId,
|
struct_id: TypeId,
|
||||||
types: &Types,
|
types: &Types,
|
||||||
impls: &mut Impls,
|
impls: &mut Impls,
|
||||||
|
@ -1778,12 +1779,17 @@ fn add_struct<S: Display>(
|
||||||
let name = escape_kw(name.to_string());
|
let name = escape_kw(name.to_string());
|
||||||
let derive = derive_str(types.get_type(struct_id), types, true);
|
let derive = derive_str(types.get_type(struct_id), types, true);
|
||||||
let pub_str = if is_tag_union_payload { "" } else { "pub " };
|
let pub_str = if is_tag_union_payload { "" } else { "pub " };
|
||||||
|
let mut buf;
|
||||||
|
|
||||||
|
match fields {
|
||||||
|
RocStructFields::HasNoClosure { fields } => {
|
||||||
let repr = if fields.len() == 1 {
|
let repr = if fields.len() == 1 {
|
||||||
"transparent"
|
"transparent"
|
||||||
} else {
|
} else {
|
||||||
"C"
|
"C"
|
||||||
};
|
};
|
||||||
let mut buf = format!("{derive}\n#[repr({repr})]\n{pub_str}struct {name} {{\n");
|
|
||||||
|
buf = format!("{derive}\n#[repr({repr})]\n{pub_str}struct {name} {{\n");
|
||||||
|
|
||||||
for (label, type_id) in fields {
|
for (label, type_id) in fields {
|
||||||
let type_str = type_name(*type_id, types);
|
let type_str = type_name(*type_id, types);
|
||||||
|
@ -1800,6 +1806,8 @@ fn add_struct<S: Display>(
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.push('}');
|
buf.push('}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
add_decl(impls, None, target_info, buf);
|
add_decl(impls, None, target_info, buf);
|
||||||
}
|
}
|
||||||
|
@ -1976,8 +1984,7 @@ pub struct {name} {{
|
||||||
borrowed_ret = format!("&{owned_ret}");
|
borrowed_ret = format!("&{owned_ret}");
|
||||||
}
|
}
|
||||||
RocType::Struct { fields, name } => {
|
RocType::Struct { fields, name } => {
|
||||||
let answer =
|
let answer = tag_union_struct_help(name, fields, non_null_payload, types, false);
|
||||||
tag_union_struct_help(name, fields.iter(), non_null_payload, types, false);
|
|
||||||
|
|
||||||
payload_args = answer.payload_args;
|
payload_args = answer.payload_args;
|
||||||
args_to_payload = answer.args_to_payload;
|
args_to_payload = answer.args_to_payload;
|
||||||
|
@ -1987,8 +1994,7 @@ pub struct {name} {{
|
||||||
borrowed_ret_type = answer.borrowed_ret_type;
|
borrowed_ret_type = answer.borrowed_ret_type;
|
||||||
}
|
}
|
||||||
RocType::TagUnionPayload { fields, name } => {
|
RocType::TagUnionPayload { fields, name } => {
|
||||||
let answer =
|
let answer = tag_union_struct_help(name, fields, non_null_payload, types, true);
|
||||||
tag_union_struct_help(name, fields.iter(), non_null_payload, types, true);
|
|
||||||
|
|
||||||
payload_args = answer.payload_args;
|
payload_args = answer.payload_args;
|
||||||
args_to_payload = answer.args_to_payload;
|
args_to_payload = answer.args_to_payload;
|
||||||
|
@ -2224,19 +2230,27 @@ pub struct {name} {{
|
||||||
RocType::Struct { fields, .. } => {
|
RocType::Struct { fields, .. } => {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
|
|
||||||
|
match fields {
|
||||||
|
RocStructFields::HasNoClosure { fields } => {
|
||||||
for (label, _) in fields {
|
for (label, _) in fields {
|
||||||
buf.push(format!(".field(&(&*{extra_deref}self.pointer).{label})"));
|
buf.push(format!(".field(&(&*{extra_deref}self.pointer).{label})"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buf.join(&format!("\n{INDENT}{INDENT}{INDENT}{INDENT}{INDENT}"))
|
buf.join(&format!("\n{INDENT}{INDENT}{INDENT}{INDENT}{INDENT}"))
|
||||||
}
|
}
|
||||||
RocType::TagUnionPayload { fields, .. } => {
|
RocType::TagUnionPayload { fields, .. } => {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
|
|
||||||
|
match fields {
|
||||||
|
RocStructFields::HasNoClosure { fields } => {
|
||||||
for (label, _) in fields {
|
for (label, _) in fields {
|
||||||
// Needs an "f" prefix
|
// Needs an "f" prefix
|
||||||
buf.push(format!(".field(&(&*{extra_deref}self.pointer).f{label})"));
|
buf.push(format!(".field(&(&*{extra_deref}self.pointer).f{label})"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buf.join(&format!("\n{INDENT}{INDENT}{INDENT}{INDENT}{INDENT}"))
|
buf.join(&format!("\n{INDENT}{INDENT}{INDENT}{INDENT}{INDENT}"))
|
||||||
}
|
}
|
||||||
|
@ -2307,17 +2321,15 @@ struct StructIngredients {
|
||||||
borrowed_ret_type: String,
|
borrowed_ret_type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tag_union_struct_help<'a, I: Iterator<Item = &'a (L, TypeId)>, L: Display + PartialOrd + 'a>(
|
fn tag_union_struct_help<'a>(
|
||||||
name: &str,
|
name: &str,
|
||||||
fields: I,
|
fields: &RocStructFields,
|
||||||
payload_id: TypeId,
|
payload_id: TypeId,
|
||||||
types: &Types,
|
types: &Types,
|
||||||
is_tag_union_payload: bool,
|
is_tag_union_payload: bool,
|
||||||
) -> StructIngredients {
|
) -> StructIngredients {
|
||||||
let mut sorted_fields = fields.collect::<Vec<&(L, TypeId)>>();
|
match fields {
|
||||||
|
RocStructFields::HasNoClosure { fields } => {
|
||||||
sorted_fields.sort_by(|(label1, _), (label2, _)| label1.partial_cmp(label2).unwrap());
|
|
||||||
|
|
||||||
let mut ret_types = if is_tag_union_payload {
|
let mut ret_types = if is_tag_union_payload {
|
||||||
// This will be a tuple we create when iterating over the fields.
|
// This will be a tuple we create when iterating over the fields.
|
||||||
Vec::new()
|
Vec::new()
|
||||||
|
@ -2327,7 +2339,7 @@ fn tag_union_struct_help<'a, I: Iterator<Item = &'a (L, TypeId)>, L: Display + P
|
||||||
|
|
||||||
let mut ret_values = Vec::new();
|
let mut ret_values = Vec::new();
|
||||||
|
|
||||||
for (label, type_id) in sorted_fields.iter() {
|
for (label, type_id) in fields.iter() {
|
||||||
let label = if is_tag_union_payload {
|
let label = if is_tag_union_payload {
|
||||||
// Tag union payload fields need "f" prefix
|
// Tag union payload fields need "f" prefix
|
||||||
// because they're numbers
|
// because they're numbers
|
||||||
|
@ -2352,7 +2364,7 @@ fn tag_union_struct_help<'a, I: Iterator<Item = &'a (L, TypeId)>, L: Display + P
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join(", ");
|
.join(", ");
|
||||||
let args_to_payload = if is_tag_union_payload {
|
let args_to_payload = if is_tag_union_payload {
|
||||||
let prefixed_fields = sorted_fields
|
let prefixed_fields = fields
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, (label, _))| {
|
.map(|(index, (label, _))| {
|
||||||
|
@ -2438,6 +2450,8 @@ fn tag_union_struct_help<'a, I: Iterator<Item = &'a (L, TypeId)>, L: Display + P
|
||||||
owned_ret_type,
|
owned_ret_type,
|
||||||
borrowed_ret_type,
|
borrowed_ret_type,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cannot_derive_default(roc_type: &RocType, types: &Types) -> bool {
|
fn cannot_derive_default(roc_type: &RocType, types: &Types) -> bool {
|
||||||
|
|
|
@ -6,17 +6,14 @@ use roc_builtins::bitcode::{
|
||||||
FloatWidth::*,
|
FloatWidth::*,
|
||||||
IntWidth::{self, *},
|
IntWidth::{self, *},
|
||||||
};
|
};
|
||||||
use roc_collections::VecMap;
|
use roc_collections::{MutMap, VecMap};
|
||||||
use roc_module::{
|
use roc_module::{
|
||||||
ident::TagName,
|
ident::TagName,
|
||||||
symbol::{Interns, Symbol},
|
symbol::{Interns, ModuleId, Symbol},
|
||||||
};
|
};
|
||||||
use roc_mono::{
|
use roc_mono::layout::{
|
||||||
ir::{Proc, ProcLayout},
|
cmp_fields, ext_var_is_empty_tag_union, round_up_to_alignment, Builtin, Discriminant, Layout,
|
||||||
layout::{
|
LayoutCache, LayoutInterner, UnionLayout,
|
||||||
cmp_fields, ext_var_is_empty_tag_union, round_up_to_alignment, Builtin, Discriminant,
|
|
||||||
Layout, LayoutCache, LayoutInterner, UnionLayout,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use roc_target::TargetInfo;
|
use roc_target::TargetInfo;
|
||||||
use roc_types::{
|
use roc_types::{
|
||||||
|
@ -70,25 +67,28 @@ impl Types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new<'a, I>(
|
pub(crate) fn new<'a, I: Iterator<Item = Variable>>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
subs: &'a Subs,
|
subs: &'a Subs,
|
||||||
variables: I,
|
variables: I,
|
||||||
interns: &'a Interns,
|
interns: &'a Interns,
|
||||||
|
glue_procs_by_layout: &'a MutMap<Layout<'a>, &'a [&'a str]>,
|
||||||
|
home: ModuleId,
|
||||||
layout_cache: LayoutCache<'a>,
|
layout_cache: LayoutCache<'a>,
|
||||||
target: TargetInfo,
|
target: TargetInfo,
|
||||||
) -> Self
|
) -> Self {
|
||||||
where
|
|
||||||
// an iterator of (variable, getter glue procs for that variable)
|
|
||||||
I: Iterator<Item = (Variable, &'a [((Symbol, ProcLayout<'a>), Proc<'a>)])>,
|
|
||||||
{
|
|
||||||
let mut types = Self::with_capacity(variables.size_hint().0, target);
|
let mut types = Self::with_capacity(variables.size_hint().0, target);
|
||||||
let mut env = Env::new(arena, subs, interns, layout_cache, target);
|
let mut env = Env::new(
|
||||||
|
arena,
|
||||||
|
subs,
|
||||||
|
interns,
|
||||||
|
layout_cache,
|
||||||
|
glue_procs_by_layout,
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
|
||||||
for (var, glue_getter_procs) in variables {
|
for var in variables {
|
||||||
env.add_type(var, &mut types);
|
env.add_type(var, &mut types);
|
||||||
|
|
||||||
// TODO incorporate glue_getter_procs!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
env.resolve_pending_recursive_types(&mut types);
|
env.resolve_pending_recursive_types(&mut types);
|
||||||
|
@ -269,11 +269,32 @@ impl Types {
|
||||||
(
|
(
|
||||||
NullableWrapped { tags: tags_a, .. },
|
NullableWrapped { tags: tags_a, .. },
|
||||||
NullableWrapped { tags: tags_b, .. },
|
NullableWrapped { tags: tags_b, .. },
|
||||||
) => {
|
) => match (tags_a, tags_b) {
|
||||||
if tags_a.len() != tags_b.len() {
|
(
|
||||||
false
|
RocTags::HasClosure {
|
||||||
} else {
|
tag_getters: getters_a,
|
||||||
tags_a.iter().zip(tags_b.iter()).all(
|
discriminant_getter: _,
|
||||||
|
},
|
||||||
|
RocTags::HasClosure {
|
||||||
|
tag_getters: getters_b,
|
||||||
|
discriminant_getter: _,
|
||||||
|
},
|
||||||
|
) if getters_a.len() == getters_b.len() => getters_a
|
||||||
|
.iter()
|
||||||
|
.zip(getters_b.iter())
|
||||||
|
.all(|((name_a, opt_getter_a), (name_b, opt_getter_b))| {
|
||||||
|
name_a == name_b && opt_getter_a == opt_getter_b
|
||||||
|
}),
|
||||||
|
(
|
||||||
|
RocTags::HasNoClosures {
|
||||||
|
tags: tags_a,
|
||||||
|
discriminant_offset: _,
|
||||||
|
},
|
||||||
|
RocTags::HasNoClosures {
|
||||||
|
tags: tags_b,
|
||||||
|
discriminant_offset: _,
|
||||||
|
},
|
||||||
|
) if tags_a.len() == tags_b.len() => tags_a.iter().zip(tags_b.iter()).all(
|
||||||
|((name_a, opt_id_a), (name_b, opt_id_b))| {
|
|((name_a, opt_id_a), (name_b, opt_id_b))| {
|
||||||
name_a == name_b
|
name_a == name_b
|
||||||
&& match (opt_id_a, opt_id_b) {
|
&& match (opt_id_a, opt_id_b) {
|
||||||
|
@ -285,9 +306,9 @@ impl Types {
|
||||||
(None, Some(_)) | (Some(_), None) => false,
|
(None, Some(_)) | (Some(_), None) => false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
}
|
(_, _) => false,
|
||||||
}
|
},
|
||||||
(
|
(
|
||||||
NullableUnwrapped {
|
NullableUnwrapped {
|
||||||
null_tag: null_tag_a,
|
null_tag: null_tag_a,
|
||||||
|
@ -574,14 +595,19 @@ enum RocTypeOrPending<'a> {
|
||||||
Pending,
|
Pending,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Accessors {
|
||||||
|
getter: String,
|
||||||
|
// TODO setter
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum RocStructFields {
|
pub enum RocStructFields {
|
||||||
HasNoClosure {
|
HasNoClosure {
|
||||||
fields: Vec<(String, TypeId)>,
|
fields: Vec<(String, TypeId)>,
|
||||||
},
|
},
|
||||||
HasClosure {
|
HasClosure {
|
||||||
field_getters: Vec<(String, TypeId, RocFn)>,
|
fields: Vec<(String, TypeId, Accessors)>,
|
||||||
// TODO field_setters
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +619,7 @@ impl RocStructFields {
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
RocStructFields::HasNoClosure { fields } => fields.len(),
|
RocStructFields::HasNoClosure { fields } => fields.len(),
|
||||||
RocStructFields::HasClosure { field_getters } => field_getters.len(),
|
RocStructFields::HasClosure { fields } => fields.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -623,7 +649,7 @@ pub enum RocType {
|
||||||
},
|
},
|
||||||
TagUnionPayload {
|
TagUnionPayload {
|
||||||
name: String,
|
name: String,
|
||||||
fields: Vec<(usize, TypeId)>,
|
fields: RocStructFields,
|
||||||
},
|
},
|
||||||
/// A recursive pointer, e.g. in StrConsList : [Nil, Cons Str StrConsList],
|
/// A recursive pointer, e.g. in StrConsList : [Nil, Cons Str StrConsList],
|
||||||
/// this would be the field of Cons containing the (recursive) StrConsList type,
|
/// this would be the field of Cons containing the (recursive) StrConsList type,
|
||||||
|
@ -701,7 +727,7 @@ pub enum RocTags {
|
||||||
/// field getters and setters because the size and order of those fields can vary based on the
|
/// field getters and setters because the size and order of those fields can vary based on the
|
||||||
/// application's implementation, so those sizes and order are not knowable at host build time.
|
/// application's implementation, so those sizes and order are not knowable at host build time.
|
||||||
HasClosure {
|
HasClosure {
|
||||||
tag_getters: Vec<(String, Option<(TypeId, RocFn)>)>,
|
tag_getters: Vec<(String, Option<(TypeId, String)>)>,
|
||||||
discriminant_getter: RocFn,
|
discriminant_getter: RocFn,
|
||||||
},
|
},
|
||||||
HasNoClosures {
|
HasNoClosures {
|
||||||
|
@ -729,7 +755,7 @@ pub enum RocSingleTagPayload {
|
||||||
/// field getters and setters because the size and order of those fields can vary based on the
|
/// field getters and setters because the size and order of those fields can vary based on the
|
||||||
/// application's implementation, so those sizes and order are not knowable at host build time.
|
/// application's implementation, so those sizes and order are not knowable at host build time.
|
||||||
HasClosure {
|
HasClosure {
|
||||||
payload_getters: Vec<(TypeId, RocFn)>,
|
payload_getters: Vec<(TypeId, String)>,
|
||||||
},
|
},
|
||||||
HasNoClosures {
|
HasNoClosures {
|
||||||
payload_fields: Vec<TypeId>,
|
payload_fields: Vec<TypeId>,
|
||||||
|
@ -810,6 +836,7 @@ struct Env<'a> {
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
subs: &'a Subs,
|
subs: &'a Subs,
|
||||||
layout_cache: LayoutCache<'a>,
|
layout_cache: LayoutCache<'a>,
|
||||||
|
glue_procs_by_layout: &'a MutMap<Layout<'a>, &'a [&'a str]>,
|
||||||
interns: &'a Interns,
|
interns: &'a Interns,
|
||||||
struct_names: Structs,
|
struct_names: Structs,
|
||||||
enum_names: Enums,
|
enum_names: Enums,
|
||||||
|
@ -819,11 +846,12 @@ struct Env<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Env<'a> {
|
impl<'a> Env<'a> {
|
||||||
pub fn new(
|
fn new(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
subs: &'a Subs,
|
subs: &'a Subs,
|
||||||
interns: &'a Interns,
|
interns: &'a Interns,
|
||||||
layout_cache: LayoutCache<'a>,
|
layout_cache: LayoutCache<'a>,
|
||||||
|
glue_procs_by_layout: &'a MutMap<Layout<'a>, &'a [&'a str]>,
|
||||||
target: TargetInfo,
|
target: TargetInfo,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Env {
|
Env {
|
||||||
|
@ -834,6 +862,7 @@ impl<'a> Env<'a> {
|
||||||
enum_names: Default::default(),
|
enum_names: Default::default(),
|
||||||
pending_recursive_types: Default::default(),
|
pending_recursive_types: Default::default(),
|
||||||
known_recursive_types: Default::default(),
|
known_recursive_types: Default::default(),
|
||||||
|
glue_procs_by_layout,
|
||||||
layout_cache,
|
layout_cache,
|
||||||
target,
|
target,
|
||||||
}
|
}
|
||||||
|
@ -1308,12 +1337,13 @@ fn add_struct<'a, I, L, F>(
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = (L, Variable)>,
|
I: IntoIterator<Item = (L, Variable)>,
|
||||||
L: Display + Ord,
|
L: Display + Ord,
|
||||||
F: FnOnce(String, Vec<(L, TypeId)>) -> RocType,
|
F: FnOnce(String, RocStructFields) -> RocType,
|
||||||
{
|
{
|
||||||
let subs = env.subs;
|
let subs = env.subs;
|
||||||
|
let arena = env.arena;
|
||||||
let fields_iter = &mut fields.into_iter();
|
let fields_iter = &mut fields.into_iter();
|
||||||
let mut sortables =
|
let mut sortables =
|
||||||
bumpalo::collections::Vec::with_capacity_in(fields_iter.size_hint().0, env.arena);
|
bumpalo::collections::Vec::with_capacity_in(fields_iter.size_hint().0, arena);
|
||||||
|
|
||||||
for (label, field_var) in fields_iter {
|
for (label, field_var) in fields_iter {
|
||||||
sortables.push((
|
sortables.push((
|
||||||
|
@ -1336,19 +1366,47 @@ where
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let fields = sortables
|
// This layout should have an entry in glue_procs_by_layout iff it
|
||||||
|
// contains closures, but we'll double-check that with a debug_assert.
|
||||||
|
let struct_fields = match env.glue_procs_by_layout.get(&layout) {
|
||||||
|
Some(&glue_procs) => {
|
||||||
|
debug_assert!(layout.contains_function(arena));
|
||||||
|
|
||||||
|
let fields: Vec<(String, TypeId, Accessors)> = sortables
|
||||||
|
.into_iter()
|
||||||
|
.zip(glue_procs.iter())
|
||||||
|
.map(|((label, field_var, field_layout), getter)| {
|
||||||
|
let type_id = add_type_help(env, field_layout, field_var, None, types);
|
||||||
|
let accessors = Accessors {
|
||||||
|
getter: getter.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(format!("{}", label), type_id, accessors)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
RocStructFields::HasClosure { fields }
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
debug_assert!(!layout.contains_function(arena));
|
||||||
|
|
||||||
|
let fields: Vec<(String, TypeId)> = sortables
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(label, field_var, field_layout)| {
|
.map(|(label, field_var, field_layout)| {
|
||||||
let type_id = add_type_help(env, field_layout, field_var, None, types);
|
let type_id = add_type_help(env, field_layout, field_var, None, types);
|
||||||
|
|
||||||
(label, type_id)
|
(format!("{}", label), type_id)
|
||||||
})
|
})
|
||||||
.collect::<Vec<(L, TypeId)>>();
|
.collect();
|
||||||
|
|
||||||
|
RocStructFields::HasNoClosure { fields }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
types.add_named(
|
types.add_named(
|
||||||
&env.layout_cache.interner,
|
&env.layout_cache.interner,
|
||||||
name.clone(),
|
name.clone(),
|
||||||
to_type(name, fields),
|
to_type(name, struct_fields),
|
||||||
layout,
|
layout,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1378,19 +1436,15 @@ fn add_tag_union<'a>(
|
||||||
Content::Structure(FlatType::TagUnion(_, _))
|
Content::Structure(FlatType::TagUnion(_, _))
|
||||||
) =>
|
) =>
|
||||||
{
|
{
|
||||||
let (tag_name, payload_vars) = single_tag_payload(union_tags, subs);
|
|
||||||
|
|
||||||
// A newtype wrapper should always have exactly one payload.
|
|
||||||
debug_assert_eq!(payload_vars.len(), 1);
|
|
||||||
|
|
||||||
// A newtype wrapper should always have the same layout as its payload.
|
// A newtype wrapper should always have the same layout as its payload.
|
||||||
let payload_layout = layout;
|
let payload_layout = layout;
|
||||||
let payload_id = add_type_help(env, payload_layout, payload_vars[0], None, types);
|
let (tag_name, payload) =
|
||||||
|
single_tag_payload_fields(union_tags, subs, layout, &[payload_layout], env, types);
|
||||||
|
|
||||||
RocTagUnion::SingleTagStruct {
|
RocTagUnion::SingleTagStruct {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
tag_name: tag_name.to_string(),
|
tag_name: tag_name.to_string(),
|
||||||
payload_fields: vec![payload_id],
|
payload,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Layout::Union(union_layout) => {
|
Layout::Union(union_layout) => {
|
||||||
|
@ -1521,16 +1575,13 @@ fn add_tag_union<'a>(
|
||||||
add_int_enumeration(union_tags, subs, &name, int_width)
|
add_int_enumeration(union_tags, subs, &name, int_width)
|
||||||
}
|
}
|
||||||
Layout::Struct { field_layouts, .. } => {
|
Layout::Struct { field_layouts, .. } => {
|
||||||
let (tag_name, payload_fields) =
|
let (tag_name, payload) =
|
||||||
single_tag_payload_fields(union_tags, subs, field_layouts, env, types);
|
single_tag_payload_fields(union_tags, subs, layout, field_layouts, env, types);
|
||||||
|
|
||||||
// A recursive tag union with just one constructor
|
|
||||||
// Optimization: No need to store a tag ID (the payload is "unwrapped")
|
|
||||||
// e.g. `RoseTree a : [Tree a (List (RoseTree a))]`
|
|
||||||
RocTagUnion::SingleTagStruct {
|
RocTagUnion::SingleTagStruct {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
tag_name: tag_name.to_string(),
|
tag_name: tag_name.to_string(),
|
||||||
payload_fields,
|
payload,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Bool) => {
|
Layout::Builtin(Builtin::Bool) => {
|
||||||
|
@ -1546,17 +1597,20 @@ fn add_tag_union<'a>(
|
||||||
RocTagUnion::SingleTagStruct {
|
RocTagUnion::SingleTagStruct {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
tag_name: tag_name.to_string(),
|
tag_name: tag_name.to_string(),
|
||||||
|
payload: RocSingleTagPayload::HasNoClosures {
|
||||||
|
// Builtins have no closures
|
||||||
payload_fields: vec![type_id],
|
payload_fields: vec![type_id],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Layout::Boxed(elem_layout) => {
|
Layout::Boxed(elem_layout) => {
|
||||||
let (tag_name, payload_fields) =
|
let (tag_name, payload) =
|
||||||
single_tag_payload_fields(union_tags, subs, &[*elem_layout], env, types);
|
single_tag_payload_fields(union_tags, subs, layout, &[*elem_layout], env, types);
|
||||||
|
|
||||||
RocTagUnion::SingleTagStruct {
|
RocTagUnion::SingleTagStruct {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
tag_name: tag_name.to_string(),
|
tag_name: tag_name.to_string(),
|
||||||
payload_fields,
|
payload,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Layout::LambdaSet(_) => {
|
Layout::LambdaSet(_) => {
|
||||||
|
@ -1647,20 +1701,44 @@ fn single_tag_payload<'a>(
|
||||||
fn single_tag_payload_fields<'a, 'b>(
|
fn single_tag_payload_fields<'a, 'b>(
|
||||||
union_tags: &'b UnionLabels<TagName>,
|
union_tags: &'b UnionLabels<TagName>,
|
||||||
subs: &'b Subs,
|
subs: &'b Subs,
|
||||||
|
layout: Layout<'a>,
|
||||||
field_layouts: &[Layout<'a>],
|
field_layouts: &[Layout<'a>],
|
||||||
env: &mut Env<'a>,
|
env: &mut Env<'a>,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
) -> (&'b str, Vec<TypeId>) {
|
) -> (&'b str, RocSingleTagPayload) {
|
||||||
todo!("TODO take closures into account and return one or the other");
|
|
||||||
let (tag_name, payload_vars) = single_tag_payload(union_tags, subs);
|
let (tag_name, payload_vars) = single_tag_payload(union_tags, subs);
|
||||||
|
let field_type_ids =
|
||||||
let payload_fields: Vec<TypeId> = payload_vars
|
payload_vars
|
||||||
.iter()
|
.iter()
|
||||||
.zip(field_layouts.iter())
|
.zip(field_layouts.iter())
|
||||||
.map(|(field_var, field_layout)| add_type_help(env, *field_layout, *field_var, None, types))
|
.map(|(field_var, field_layout)| {
|
||||||
|
add_type_help(env, *field_layout, *field_var, None, types)
|
||||||
|
});
|
||||||
|
|
||||||
|
// There should be a glue_procs_by_layout entry iff this layout has a closure in it,
|
||||||
|
// so we shouldn't need to separately check that. Howeevr, we still do a debug_assert
|
||||||
|
// anyway just so we have some warning in case that relationship somehow didn't hold!
|
||||||
|
let payload = match env.glue_procs_by_layout.get(&layout) {
|
||||||
|
Some(glue_procs) => {
|
||||||
|
debug_assert!(layout.contains_function(env.arena));
|
||||||
|
|
||||||
|
let payload_getters = field_type_ids
|
||||||
|
.zip(glue_procs.iter())
|
||||||
|
.map(|(type_id, getter_name)| (type_id, getter_name.to_string()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
(tag_name, payload_fields)
|
RocSingleTagPayload::HasClosure { payload_getters }
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
debug_assert!(!layout.contains_function(env.arena));
|
||||||
|
|
||||||
|
RocSingleTagPayload::HasNoClosures {
|
||||||
|
payload_fields: field_type_ids.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(tag_name, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tag_to_type<'a, D: Display>(
|
fn tag_to_type<'a, D: Display>(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue