mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Sort fields in one pass, and drop 0-sized fields
This commit is contained in:
parent
487c1e3b75
commit
ae58ef914d
2 changed files with 46 additions and 29 deletions
|
@ -640,16 +640,16 @@ fn from_can<'a>(
|
||||||
} => {
|
} => {
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
|
|
||||||
let btree = crate::layout::record_fields_btree(
|
let sorted_fields = crate::layout::sort_record_fields(
|
||||||
env.arena,
|
env.arena,
|
||||||
record_var,
|
record_var,
|
||||||
env.subs,
|
env.subs,
|
||||||
env.pointer_size,
|
env.pointer_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut field_tuples = Vec::with_capacity_in(btree.len(), arena);
|
let mut field_tuples = Vec::with_capacity_in(sorted_fields.len(), arena);
|
||||||
|
|
||||||
for (label, layout) in btree {
|
for (label, layout) in sorted_fields {
|
||||||
let field = fields.remove(&label).unwrap();
|
let field = fields.remove(&label).unwrap();
|
||||||
let expr = from_can(env, field.loc_expr.value, procs, layout_cache);
|
let expr = from_can(env, field.loc_expr.value, procs, layout_cache);
|
||||||
|
|
||||||
|
@ -749,7 +749,7 @@ fn from_can<'a>(
|
||||||
} => {
|
} => {
|
||||||
let arena = env.arena;
|
let arena = env.arena;
|
||||||
|
|
||||||
let btree = crate::layout::record_fields_btree(
|
let sorted_fields = crate::layout::sort_record_fields(
|
||||||
env.arena,
|
env.arena,
|
||||||
record_var,
|
record_var,
|
||||||
env.subs,
|
env.subs,
|
||||||
|
@ -757,9 +757,9 @@ fn from_can<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut index = None;
|
let mut index = None;
|
||||||
let mut field_layouts = Vec::with_capacity_in(btree.len(), env.arena);
|
let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena);
|
||||||
|
|
||||||
for (current, (label, field_layout)) in btree.into_iter().enumerate() {
|
for (current, (label, field_layout)) in sorted_fields.into_iter().enumerate() {
|
||||||
field_layouts.push(field_layout);
|
field_layouts.push(field_layout);
|
||||||
|
|
||||||
if label == field {
|
if label == field {
|
||||||
|
@ -1675,16 +1675,16 @@ fn from_can_pattern<'a>(
|
||||||
let mut it = destructs.iter();
|
let mut it = destructs.iter();
|
||||||
let mut opt_destruct = it.next();
|
let mut opt_destruct = it.next();
|
||||||
|
|
||||||
let btree = crate::layout::record_fields_btree(
|
let sorted_fields = crate::layout::sort_record_fields(
|
||||||
env.arena,
|
env.arena,
|
||||||
*whole_var,
|
*whole_var,
|
||||||
env.subs,
|
env.subs,
|
||||||
env.pointer_size,
|
env.pointer_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut field_layouts = Vec::with_capacity_in(btree.len(), env.arena);
|
let mut field_layouts = Vec::with_capacity_in(sorted_fields.len(), env.arena);
|
||||||
|
|
||||||
for (label, field_layout) in btree.into_iter() {
|
for (label, field_layout) in sorted_fields.into_iter() {
|
||||||
if let Some(destruct) = opt_destruct {
|
if let Some(destruct) = opt_destruct {
|
||||||
if destruct.value.label == label {
|
if destruct.value.label == label {
|
||||||
opt_destruct = it.next();
|
opt_destruct = it.next();
|
||||||
|
|
|
@ -4,7 +4,6 @@ use roc_collections::all::MutMap;
|
||||||
use roc_module::ident::{Lowercase, TagName};
|
use roc_module::ident::{Lowercase, TagName};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_types::subs::{Content, FlatType, Subs, Variable};
|
use roc_types::subs::{Content, FlatType, Subs, Variable};
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::<u8>() * 8) as usize;
|
pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::<u8>() * 8) as usize;
|
||||||
|
|
||||||
|
@ -304,13 +303,19 @@ fn layout_from_flat_type<'a>(
|
||||||
Record(fields, ext_var) => {
|
Record(fields, ext_var) => {
|
||||||
debug_assert!(ext_var_is_empty_record(subs, ext_var));
|
debug_assert!(ext_var_is_empty_record(subs, ext_var));
|
||||||
|
|
||||||
let btree = fields
|
// Sort the fields by label
|
||||||
.into_iter()
|
let mut sorted_fields = Vec::with_capacity_in(fields.len(), arena);
|
||||||
.collect::<BTreeMap<Lowercase, Variable>>();
|
|
||||||
|
|
||||||
let mut layouts = Vec::with_capacity_in(btree.len(), arena);
|
for tuple in fields {
|
||||||
|
sorted_fields.push(tuple);
|
||||||
|
}
|
||||||
|
|
||||||
for (_, field_var) in btree {
|
sorted_fields.sort_by(|(label1, _), (label2, _)| label1.cmp(label2));
|
||||||
|
|
||||||
|
// Determine the layouts of the fields, maintaining sort order
|
||||||
|
let mut layouts = Vec::with_capacity_in(sorted_fields.len(), arena);
|
||||||
|
|
||||||
|
for (_, field_var) in sorted_fields {
|
||||||
let field_content = subs.get_without_compacting(field_var).content;
|
let field_content = subs.get_without_compacting(field_var).content;
|
||||||
|
|
||||||
match Layout::new(arena, field_content, subs, pointer_size) {
|
match Layout::new(arena, field_content, subs, pointer_size) {
|
||||||
|
@ -327,7 +332,13 @@ fn layout_from_flat_type<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Layout::Struct(layouts.into_bump_slice()))
|
if layouts.len() == 1 {
|
||||||
|
// If the record has only one field that isn't zero-sized,
|
||||||
|
// unwrap it.
|
||||||
|
Ok(layouts.pop().unwrap())
|
||||||
|
} else {
|
||||||
|
Ok(Layout::Struct(layouts.into_bump_slice()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TagUnion(tags, ext_var) => {
|
TagUnion(tags, ext_var) => {
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
debug_assert!(ext_var_is_empty_tag_union(subs, ext_var));
|
||||||
|
@ -348,26 +359,32 @@ fn layout_from_flat_type<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_fields_btree<'a>(
|
pub fn sort_record_fields<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
var: Variable,
|
var: Variable,
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
pointer_size: u32,
|
pointer_size: u32,
|
||||||
) -> BTreeMap<Lowercase, Layout<'a>> {
|
) -> Vec<'a, (Lowercase, Layout<'a>)> {
|
||||||
let mut fields_map = MutMap::default();
|
let mut fields_map = MutMap::default();
|
||||||
|
|
||||||
match roc_types::pretty_print::chase_ext_record(subs, var, &mut fields_map) {
|
match roc_types::pretty_print::chase_ext_record(subs, var, &mut fields_map) {
|
||||||
Ok(()) | Err((_, Content::FlexVar(_))) => {
|
Ok(()) | Err((_, Content::FlexVar(_))) => {
|
||||||
// collect into btreemap to sort
|
// Sort the fields by label
|
||||||
fields_map
|
let mut sorted_fields = Vec::with_capacity_in(fields_map.len(), arena);
|
||||||
.into_iter()
|
|
||||||
.map(|(label, var)| {
|
for (label, var) in fields_map {
|
||||||
(
|
let layout = Layout::from_var(arena, var, subs, pointer_size)
|
||||||
label,
|
.expect("invalid layout from var");
|
||||||
Layout::from_var(arena, var, subs, pointer_size)
|
|
||||||
.expect("invalid layout from var"),
|
// Drop any zero-sized fields like {}
|
||||||
)
|
if layout.stack_size(pointer_size) != 0 {
|
||||||
})
|
sorted_fields.push((label, layout));
|
||||||
.collect::<BTreeMap<Lowercase, Layout<'a>>>()
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sorted_fields.sort_by(|(label1, _), (label2, _)| label1.cmp(label2));
|
||||||
|
|
||||||
|
sorted_fields
|
||||||
}
|
}
|
||||||
Err(other) => panic!("invalid content in record variable: {:?}", other),
|
Err(other) => panic!("invalid content in record variable: {:?}", other),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue