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;
|
||||
|
||||
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,
|
||||
ident_ids,
|
||||
arena,
|
||||
|
@ -3024,8 +3024,16 @@ fn finish_specialization<'a>(
|
|||
*layout,
|
||||
);
|
||||
|
||||
glue_getters.extend(glue_procs.procs.iter().map(|t| t.0));
|
||||
procedures.extend(glue_procs.procs);
|
||||
glue_getters.extend(all_glue_procs.iter().flat_map(|(_, glue_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 struct GlueProcs<'a> {
|
||||
pub procs: Vec<'a, ((Symbol, ProcLayout<'a>), Proc<'a>)>,
|
||||
pub layouts: Vec<'a, Layout<'a>>,
|
||||
pub struct GlueProc<'a> {
|
||||
pub name: Symbol,
|
||||
pub proc_layout: ProcLayout<'a>,
|
||||
pub proc: Proc<'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,
|
||||
layout_interner: &mut I,
|
||||
layout: Layout<'a>,
|
||||
) -> GlueProcs<'a> {
|
||||
) -> Vec<'a, (Layout<'a>, Vec<'a, GlueProc<'a>>)> {
|
||||
let mut stack = Vec::new_in(arena);
|
||||
let mut procs = Vec::new_in(arena);
|
||||
let mut layouts = Vec::new_in(arena);
|
||||
let mut answer = Vec::new_in(arena);
|
||||
|
||||
stack.push(layout);
|
||||
|
||||
|
@ -10792,17 +10792,16 @@ pub fn generate_glue_procs<'a, I: Interner<'a, Layout<'a>>>(
|
|||
},
|
||||
Layout::Struct { field_layouts, .. } => {
|
||||
if layout.contains_function(arena) {
|
||||
layouts.push(layout);
|
||||
|
||||
generate_glue_procs_for_fields(
|
||||
let procs = generate_glue_procs_for_fields(
|
||||
home,
|
||||
ident_ids,
|
||||
arena,
|
||||
layout,
|
||||
field_layouts,
|
||||
&mut procs,
|
||||
);
|
||||
|
||||
answer.push((layout, procs));
|
||||
|
||||
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>(
|
||||
|
@ -10843,24 +10842,22 @@ fn generate_glue_procs_for_fields<'a>(
|
|||
arena: &'a Bump,
|
||||
unboxed_struct_layout: Layout<'a>,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
output: &mut Vec<'a, ((Symbol, ProcLayout<'a>), Proc<'a>)>,
|
||||
) {
|
||||
output.reserve(field_layouts.len());
|
||||
|
||||
) -> Vec<'a, GlueProc<'a>> {
|
||||
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() {
|
||||
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 {
|
||||
arguments: arena.alloc([boxed_struct_layout]),
|
||||
result: *field,
|
||||
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 field_get_expr = Expr::StructAtIndex {
|
||||
|
@ -10891,6 +10888,12 @@ fn generate_glue_procs_for_fields<'a>(
|
|||
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::types::Types;
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::MutMap;
|
||||
use roc_intern::GlobalInterner;
|
||||
use roc_load::{ExecutionMode, LoadConfig, LoadedModule, LoadingProblem, Threading};
|
||||
use roc_mono::ir::{generate_glue_procs, GlueProc};
|
||||
use roc_mono::layout::LayoutCache;
|
||||
use roc_reporting::report::RenderTarget;
|
||||
use roc_target::{Architecture, TargetInfo};
|
||||
|
@ -153,49 +155,53 @@ pub fn load_types(
|
|||
operating_system,
|
||||
};
|
||||
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
|
||||
let it = variables.clone().map(|var| {
|
||||
use roc_mono::layout::Layout;
|
||||
|
||||
let mut glue_getters = bumpalo::collections::Vec::new_in(arena);
|
||||
for var in variables.clone() {
|
||||
let layout = layout_cache
|
||||
.from_var(arena, var, subs)
|
||||
.expect("Something weird ended up in the content");
|
||||
|
||||
// TODO right here, we want to check the entire layout for closures;
|
||||
// if it has any, then we want to generate getters/setters for them!
|
||||
match layout {
|
||||
Layout::Builtin(_) => todo!(),
|
||||
Layout::Struct {
|
||||
field_order_hash,
|
||||
field_layouts,
|
||||
} => todo!(),
|
||||
Layout::Boxed(_) => todo!(),
|
||||
Layout::Union(_) => todo!(),
|
||||
Layout::LambdaSet(_) => {
|
||||
// TODO get function layout from LambdaSet
|
||||
// let ret = &layout.result;
|
||||
if layout.contains_function(arena) {
|
||||
// Even though generate_glue_procs does more work than we need it to,
|
||||
// it's important that we use it in order to make sure we get exactly
|
||||
// the same names that mono::ir did for code gen!
|
||||
for (layout, glue_procs) in
|
||||
generate_glue_procs(home, ident_ids, arena, &mut layout_interner.fork(), layout)
|
||||
{
|
||||
let names =
|
||||
bumpalo::collections::Vec::with_capacity_in(glue_procs.len(), arena);
|
||||
|
||||
// for layout in layout.arguments.iter().chain([ret]) {
|
||||
// let glue_procs = roc_mono::ir::generate_glue_procs(
|
||||
// home,
|
||||
// ident_ids,
|
||||
// arena,
|
||||
// &mut layout_cache.interner,
|
||||
// *layout,
|
||||
// );
|
||||
// Record all the getter/setter names associated with this layout
|
||||
for GlueProc { name, .. } in glue_procs {
|
||||
// Store them as strings, because symbols won't be useful to glue generators!
|
||||
let name_string =
|
||||
bumpalo::collections::String::from_str_in(name.as_str(&interns), arena);
|
||||
|
||||
// glue_getters.extend(glue_procs.procs.iter().map(|t| t.0));
|
||||
// }
|
||||
}
|
||||
roc_mono::layout::Layout::RecursivePointer => todo!(),
|
||||
// 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
|
||||
// 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));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::types::{
|
||||
RocFn, RocNum, RocSingleTagPayload, RocStructFields, RocTagUnion, RocTags, RocType, TypeId,
|
||||
Types,
|
||||
Accessors, RocFn, RocNum, RocSingleTagPayload, RocStructFields, RocTagUnion, RocTags, RocType,
|
||||
TypeId, Types,
|
||||
};
|
||||
use indexmap::IndexMap;
|
||||
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) {
|
||||
match types.get_type(id) {
|
||||
RocType::Struct {
|
||||
name,
|
||||
fields: RocStructFields::HasNoClosure { fields },
|
||||
} => add_struct(name, target_info, fields, id, types, impls, false),
|
||||
RocType::Struct {
|
||||
name,
|
||||
fields: RocStructFields::HasClosure { field_getters },
|
||||
} => {
|
||||
todo!();
|
||||
RocType::Struct { name, fields } => {
|
||||
add_struct(name, target_info, fields, id, types, impls, false)
|
||||
}
|
||||
RocType::TagUnionPayload { name, fields } => {
|
||||
add_struct(name, target_info, fields, id, types, impls, true)
|
||||
|
@ -382,16 +375,18 @@ fn add_single_tag_struct(
|
|||
buf.push_str("}\n");
|
||||
}
|
||||
|
||||
let field_getters = payload_getters
|
||||
let fields = payload_getters
|
||||
.iter()
|
||||
.map(|(type_id, roc_fn)| (String::new(), *type_id, *roc_fn))
|
||||
.map(|(type_id, getter)| {
|
||||
(String::new(), *type_id, Accessors { getter: *getter })
|
||||
})
|
||||
.collect();
|
||||
|
||||
RocType::Struct {
|
||||
// Deriving doesn't depend on the struct's name,
|
||||
// so no need to clone name here.
|
||||
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
|
||||
{
|
||||
match payload {
|
||||
RocSingleTagPayload::HasNoClosures { payload_fields } => {
|
||||
let opt_impl = Some(format!("impl {name}"));
|
||||
|
||||
if payload_fields.is_empty() {
|
||||
|
@ -587,13 +583,15 @@ fn add_single_tag_struct(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 mut buf =
|
||||
"fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {".to_string();
|
||||
let mut buf = "fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {"
|
||||
.to_string();
|
||||
|
||||
if payload_fields.is_empty() {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_discriminant(
|
||||
|
@ -1044,8 +1043,7 @@ pub struct {name} {{
|
|||
};
|
||||
}
|
||||
RocType::Struct { fields, name } => {
|
||||
let answer =
|
||||
tag_union_struct_help(name, fields.iter(), *payload_id, types, false);
|
||||
let answer = tag_union_struct_help(name, fields, *payload_id, types, false);
|
||||
|
||||
owned_ret = answer.owned_ret;
|
||||
borrowed_ret = answer.borrowed_ret;
|
||||
|
@ -1055,8 +1053,7 @@ pub struct {name} {{
|
|||
args_to_payload = answer.args_to_payload;
|
||||
}
|
||||
RocType::TagUnionPayload { fields, name } => {
|
||||
let answer =
|
||||
tag_union_struct_help(name, fields.iter(), *payload_id, types, true);
|
||||
let answer = tag_union_struct_help(name, fields, *payload_id, types, true);
|
||||
|
||||
owned_ret = answer.owned_ret;
|
||||
borrowed_ret = answer.borrowed_ret;
|
||||
|
@ -1664,12 +1661,16 @@ pub struct {name} {{
|
|||
RocType::TagUnionPayload { fields, .. } => {
|
||||
let mut buf = Vec::new();
|
||||
|
||||
match fields {
|
||||
RocStructFields::HasNoClosure { fields } => {
|
||||
for (label, _) in fields {
|
||||
// Needs an "f" prefix
|
||||
buf.push(format!(
|
||||
".field(&({deref_str}{actual_self}.{tag_name}).f{label})"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
fn add_struct<S: Display>(
|
||||
fn add_struct(
|
||||
name: &str,
|
||||
target_info: TargetInfo,
|
||||
fields: &[(S, TypeId)],
|
||||
fields: &RocStructFields,
|
||||
struct_id: TypeId,
|
||||
types: &Types,
|
||||
impls: &mut Impls,
|
||||
|
@ -1778,12 +1779,17 @@ fn add_struct<S: Display>(
|
|||
let name = escape_kw(name.to_string());
|
||||
let derive = derive_str(types.get_type(struct_id), types, true);
|
||||
let pub_str = if is_tag_union_payload { "" } else { "pub " };
|
||||
let mut buf;
|
||||
|
||||
match fields {
|
||||
RocStructFields::HasNoClosure { fields } => {
|
||||
let repr = if fields.len() == 1 {
|
||||
"transparent"
|
||||
} else {
|
||||
"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 {
|
||||
let type_str = type_name(*type_id, types);
|
||||
|
@ -1800,6 +1806,8 @@ fn add_struct<S: Display>(
|
|||
}
|
||||
|
||||
buf.push('}');
|
||||
}
|
||||
}
|
||||
|
||||
add_decl(impls, None, target_info, buf);
|
||||
}
|
||||
|
@ -1976,8 +1984,7 @@ pub struct {name} {{
|
|||
borrowed_ret = format!("&{owned_ret}");
|
||||
}
|
||||
RocType::Struct { fields, name } => {
|
||||
let answer =
|
||||
tag_union_struct_help(name, fields.iter(), non_null_payload, types, false);
|
||||
let answer = tag_union_struct_help(name, fields, non_null_payload, types, false);
|
||||
|
||||
payload_args = answer.payload_args;
|
||||
args_to_payload = answer.args_to_payload;
|
||||
|
@ -1987,8 +1994,7 @@ pub struct {name} {{
|
|||
borrowed_ret_type = answer.borrowed_ret_type;
|
||||
}
|
||||
RocType::TagUnionPayload { fields, name } => {
|
||||
let answer =
|
||||
tag_union_struct_help(name, fields.iter(), non_null_payload, types, true);
|
||||
let answer = tag_union_struct_help(name, fields, non_null_payload, types, true);
|
||||
|
||||
payload_args = answer.payload_args;
|
||||
args_to_payload = answer.args_to_payload;
|
||||
|
@ -2224,19 +2230,27 @@ pub struct {name} {{
|
|||
RocType::Struct { fields, .. } => {
|
||||
let mut buf = Vec::new();
|
||||
|
||||
match fields {
|
||||
RocStructFields::HasNoClosure { fields } => {
|
||||
for (label, _) in fields {
|
||||
buf.push(format!(".field(&(&*{extra_deref}self.pointer).{label})"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf.join(&format!("\n{INDENT}{INDENT}{INDENT}{INDENT}{INDENT}"))
|
||||
}
|
||||
RocType::TagUnionPayload { fields, .. } => {
|
||||
let mut buf = Vec::new();
|
||||
|
||||
match fields {
|
||||
RocStructFields::HasNoClosure { fields } => {
|
||||
for (label, _) in fields {
|
||||
// Needs an "f" prefix
|
||||
buf.push(format!(".field(&(&*{extra_deref}self.pointer).f{label})"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf.join(&format!("\n{INDENT}{INDENT}{INDENT}{INDENT}{INDENT}"))
|
||||
}
|
||||
|
@ -2307,17 +2321,15 @@ struct StructIngredients {
|
|||
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,
|
||||
fields: I,
|
||||
fields: &RocStructFields,
|
||||
payload_id: TypeId,
|
||||
types: &Types,
|
||||
is_tag_union_payload: bool,
|
||||
) -> StructIngredients {
|
||||
let mut sorted_fields = fields.collect::<Vec<&(L, TypeId)>>();
|
||||
|
||||
sorted_fields.sort_by(|(label1, _), (label2, _)| label1.partial_cmp(label2).unwrap());
|
||||
|
||||
match fields {
|
||||
RocStructFields::HasNoClosure { fields } => {
|
||||
let mut ret_types = if is_tag_union_payload {
|
||||
// This will be a tuple we create when iterating over the fields.
|
||||
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();
|
||||
|
||||
for (label, type_id) in sorted_fields.iter() {
|
||||
for (label, type_id) in fields.iter() {
|
||||
let label = if is_tag_union_payload {
|
||||
// Tag union payload fields need "f" prefix
|
||||
// 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>>()
|
||||
.join(", ");
|
||||
let args_to_payload = if is_tag_union_payload {
|
||||
let prefixed_fields = sorted_fields
|
||||
let prefixed_fields = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.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,
|
||||
borrowed_ret_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cannot_derive_default(roc_type: &RocType, types: &Types) -> bool {
|
||||
|
|
|
@ -6,17 +6,14 @@ use roc_builtins::bitcode::{
|
|||
FloatWidth::*,
|
||||
IntWidth::{self, *},
|
||||
};
|
||||
use roc_collections::VecMap;
|
||||
use roc_collections::{MutMap, VecMap};
|
||||
use roc_module::{
|
||||
ident::TagName,
|
||||
symbol::{Interns, Symbol},
|
||||
symbol::{Interns, ModuleId, Symbol},
|
||||
};
|
||||
use roc_mono::{
|
||||
ir::{Proc, ProcLayout},
|
||||
layout::{
|
||||
cmp_fields, ext_var_is_empty_tag_union, round_up_to_alignment, Builtin, Discriminant,
|
||||
Layout, LayoutCache, LayoutInterner, UnionLayout,
|
||||
},
|
||||
use roc_mono::layout::{
|
||||
cmp_fields, ext_var_is_empty_tag_union, round_up_to_alignment, Builtin, Discriminant, Layout,
|
||||
LayoutCache, LayoutInterner, UnionLayout,
|
||||
};
|
||||
use roc_target::TargetInfo;
|
||||
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,
|
||||
subs: &'a Subs,
|
||||
variables: I,
|
||||
interns: &'a Interns,
|
||||
glue_procs_by_layout: &'a MutMap<Layout<'a>, &'a [&'a str]>,
|
||||
home: ModuleId,
|
||||
layout_cache: LayoutCache<'a>,
|
||||
target: TargetInfo,
|
||||
) -> Self
|
||||
where
|
||||
// an iterator of (variable, getter glue procs for that variable)
|
||||
I: Iterator<Item = (Variable, &'a [((Symbol, ProcLayout<'a>), Proc<'a>)])>,
|
||||
{
|
||||
) -> Self {
|
||||
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);
|
||||
|
||||
// TODO incorporate glue_getter_procs!
|
||||
}
|
||||
|
||||
env.resolve_pending_recursive_types(&mut types);
|
||||
|
@ -269,11 +269,32 @@ impl Types {
|
|||
(
|
||||
NullableWrapped { tags: tags_a, .. },
|
||||
NullableWrapped { tags: tags_b, .. },
|
||||
) => {
|
||||
if tags_a.len() != tags_b.len() {
|
||||
false
|
||||
} else {
|
||||
tags_a.iter().zip(tags_b.iter()).all(
|
||||
) => match (tags_a, tags_b) {
|
||||
(
|
||||
RocTags::HasClosure {
|
||||
tag_getters: getters_a,
|
||||
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 == name_b
|
||||
&& match (opt_id_a, opt_id_b) {
|
||||
|
@ -285,9 +306,9 @@ impl Types {
|
|||
(None, Some(_)) | (Some(_), None) => false,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
),
|
||||
(_, _) => false,
|
||||
},
|
||||
(
|
||||
NullableUnwrapped {
|
||||
null_tag: null_tag_a,
|
||||
|
@ -574,14 +595,19 @@ enum RocTypeOrPending<'a> {
|
|||
Pending,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Accessors {
|
||||
getter: String,
|
||||
// TODO setter
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum RocStructFields {
|
||||
HasNoClosure {
|
||||
fields: Vec<(String, TypeId)>,
|
||||
},
|
||||
HasClosure {
|
||||
field_getters: Vec<(String, TypeId, RocFn)>,
|
||||
// TODO field_setters
|
||||
fields: Vec<(String, TypeId, Accessors)>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -593,7 +619,7 @@ impl RocStructFields {
|
|||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
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 {
|
||||
name: String,
|
||||
fields: Vec<(usize, TypeId)>,
|
||||
fields: RocStructFields,
|
||||
},
|
||||
/// A recursive pointer, e.g. in StrConsList : [Nil, Cons Str StrConsList],
|
||||
/// 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
|
||||
/// application's implementation, so those sizes and order are not knowable at host build time.
|
||||
HasClosure {
|
||||
tag_getters: Vec<(String, Option<(TypeId, RocFn)>)>,
|
||||
tag_getters: Vec<(String, Option<(TypeId, String)>)>,
|
||||
discriminant_getter: RocFn,
|
||||
},
|
||||
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
|
||||
/// application's implementation, so those sizes and order are not knowable at host build time.
|
||||
HasClosure {
|
||||
payload_getters: Vec<(TypeId, RocFn)>,
|
||||
payload_getters: Vec<(TypeId, String)>,
|
||||
},
|
||||
HasNoClosures {
|
||||
payload_fields: Vec<TypeId>,
|
||||
|
@ -810,6 +836,7 @@ struct Env<'a> {
|
|||
arena: &'a Bump,
|
||||
subs: &'a Subs,
|
||||
layout_cache: LayoutCache<'a>,
|
||||
glue_procs_by_layout: &'a MutMap<Layout<'a>, &'a [&'a str]>,
|
||||
interns: &'a Interns,
|
||||
struct_names: Structs,
|
||||
enum_names: Enums,
|
||||
|
@ -819,11 +846,12 @@ struct Env<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Env<'a> {
|
||||
pub fn new(
|
||||
fn new(
|
||||
arena: &'a Bump,
|
||||
subs: &'a Subs,
|
||||
interns: &'a Interns,
|
||||
layout_cache: LayoutCache<'a>,
|
||||
glue_procs_by_layout: &'a MutMap<Layout<'a>, &'a [&'a str]>,
|
||||
target: TargetInfo,
|
||||
) -> Self {
|
||||
Env {
|
||||
|
@ -834,6 +862,7 @@ impl<'a> Env<'a> {
|
|||
enum_names: Default::default(),
|
||||
pending_recursive_types: Default::default(),
|
||||
known_recursive_types: Default::default(),
|
||||
glue_procs_by_layout,
|
||||
layout_cache,
|
||||
target,
|
||||
}
|
||||
|
@ -1308,12 +1337,13 @@ fn add_struct<'a, I, L, F>(
|
|||
where
|
||||
I: IntoIterator<Item = (L, Variable)>,
|
||||
L: Display + Ord,
|
||||
F: FnOnce(String, Vec<(L, TypeId)>) -> RocType,
|
||||
F: FnOnce(String, RocStructFields) -> RocType,
|
||||
{
|
||||
let subs = env.subs;
|
||||
let arena = env.arena;
|
||||
let fields_iter = &mut fields.into_iter();
|
||||
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 {
|
||||
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()
|
||||
.map(|(label, field_var, field_layout)| {
|
||||
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(
|
||||
&env.layout_cache.interner,
|
||||
name.clone(),
|
||||
to_type(name, fields),
|
||||
to_type(name, struct_fields),
|
||||
layout,
|
||||
)
|
||||
}
|
||||
|
@ -1378,19 +1436,15 @@ fn add_tag_union<'a>(
|
|||
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.
|
||||
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 {
|
||||
name: name.clone(),
|
||||
tag_name: tag_name.to_string(),
|
||||
payload_fields: vec![payload_id],
|
||||
payload,
|
||||
}
|
||||
}
|
||||
Layout::Union(union_layout) => {
|
||||
|
@ -1521,16 +1575,13 @@ fn add_tag_union<'a>(
|
|||
add_int_enumeration(union_tags, subs, &name, int_width)
|
||||
}
|
||||
Layout::Struct { field_layouts, .. } => {
|
||||
let (tag_name, payload_fields) =
|
||||
single_tag_payload_fields(union_tags, subs, field_layouts, env, types);
|
||||
let (tag_name, payload) =
|
||||
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 {
|
||||
name: name.clone(),
|
||||
tag_name: tag_name.to_string(),
|
||||
payload_fields,
|
||||
payload,
|
||||
}
|
||||
}
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
|
@ -1546,17 +1597,20 @@ fn add_tag_union<'a>(
|
|||
RocTagUnion::SingleTagStruct {
|
||||
name: name.clone(),
|
||||
tag_name: tag_name.to_string(),
|
||||
payload: RocSingleTagPayload::HasNoClosures {
|
||||
// Builtins have no closures
|
||||
payload_fields: vec![type_id],
|
||||
},
|
||||
}
|
||||
}
|
||||
Layout::Boxed(elem_layout) => {
|
||||
let (tag_name, payload_fields) =
|
||||
single_tag_payload_fields(union_tags, subs, &[*elem_layout], env, types);
|
||||
let (tag_name, payload) =
|
||||
single_tag_payload_fields(union_tags, subs, layout, &[*elem_layout], env, types);
|
||||
|
||||
RocTagUnion::SingleTagStruct {
|
||||
name: name.clone(),
|
||||
tag_name: tag_name.to_string(),
|
||||
payload_fields,
|
||||
payload,
|
||||
}
|
||||
}
|
||||
Layout::LambdaSet(_) => {
|
||||
|
@ -1647,20 +1701,44 @@ fn single_tag_payload<'a>(
|
|||
fn single_tag_payload_fields<'a, 'b>(
|
||||
union_tags: &'b UnionLabels<TagName>,
|
||||
subs: &'b Subs,
|
||||
layout: Layout<'a>,
|
||||
field_layouts: &[Layout<'a>],
|
||||
env: &mut Env<'a>,
|
||||
types: &mut Types,
|
||||
) -> (&'b str, Vec<TypeId>) {
|
||||
todo!("TODO take closures into account and return one or the other");
|
||||
) -> (&'b str, RocSingleTagPayload) {
|
||||
let (tag_name, payload_vars) = single_tag_payload(union_tags, subs);
|
||||
|
||||
let payload_fields: Vec<TypeId> = payload_vars
|
||||
let field_type_ids =
|
||||
payload_vars
|
||||
.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();
|
||||
|
||||
(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>(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue