mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34: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 btree = crate::layout::record_fields_btree(
|
||||
let sorted_fields = crate::layout::sort_record_fields(
|
||||
env.arena,
|
||||
record_var,
|
||||
env.subs,
|
||||
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 expr = from_can(env, field.loc_expr.value, procs, layout_cache);
|
||||
|
||||
|
@ -749,7 +749,7 @@ fn from_can<'a>(
|
|||
} => {
|
||||
let arena = env.arena;
|
||||
|
||||
let btree = crate::layout::record_fields_btree(
|
||||
let sorted_fields = crate::layout::sort_record_fields(
|
||||
env.arena,
|
||||
record_var,
|
||||
env.subs,
|
||||
|
@ -757,9 +757,9 @@ fn from_can<'a>(
|
|||
);
|
||||
|
||||
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);
|
||||
|
||||
if label == field {
|
||||
|
@ -1675,16 +1675,16 @@ fn from_can_pattern<'a>(
|
|||
let mut it = destructs.iter();
|
||||
let mut opt_destruct = it.next();
|
||||
|
||||
let btree = crate::layout::record_fields_btree(
|
||||
let sorted_fields = crate::layout::sort_record_fields(
|
||||
env.arena,
|
||||
*whole_var,
|
||||
env.subs,
|
||||
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 destruct.value.label == label {
|
||||
opt_destruct = it.next();
|
||||
|
|
|
@ -4,7 +4,6 @@ use roc_collections::all::MutMap;
|
|||
use roc_module::ident::{Lowercase, TagName};
|
||||
use roc_module::symbol::Symbol;
|
||||
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;
|
||||
|
||||
|
@ -304,13 +303,19 @@ fn layout_from_flat_type<'a>(
|
|||
Record(fields, ext_var) => {
|
||||
debug_assert!(ext_var_is_empty_record(subs, ext_var));
|
||||
|
||||
let btree = fields
|
||||
.into_iter()
|
||||
.collect::<BTreeMap<Lowercase, Variable>>();
|
||||
// Sort the fields by label
|
||||
let mut sorted_fields = Vec::with_capacity_in(fields.len(), arena);
|
||||
|
||||
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;
|
||||
|
||||
match Layout::new(arena, field_content, subs, pointer_size) {
|
||||
|
@ -327,8 +332,14 @@ fn layout_from_flat_type<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
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) => {
|
||||
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,
|
||||
var: Variable,
|
||||
subs: &Subs,
|
||||
pointer_size: u32,
|
||||
) -> BTreeMap<Lowercase, Layout<'a>> {
|
||||
) -> Vec<'a, (Lowercase, Layout<'a>)> {
|
||||
let mut fields_map = MutMap::default();
|
||||
|
||||
match roc_types::pretty_print::chase_ext_record(subs, var, &mut fields_map) {
|
||||
Ok(()) | Err((_, Content::FlexVar(_))) => {
|
||||
// collect into btreemap to sort
|
||||
fields_map
|
||||
.into_iter()
|
||||
.map(|(label, var)| {
|
||||
(
|
||||
label,
|
||||
Layout::from_var(arena, var, subs, pointer_size)
|
||||
.expect("invalid layout from var"),
|
||||
)
|
||||
})
|
||||
.collect::<BTreeMap<Lowercase, Layout<'a>>>()
|
||||
// Sort the fields by label
|
||||
let mut sorted_fields = Vec::with_capacity_in(fields_map.len(), arena);
|
||||
|
||||
for (label, var) in fields_map {
|
||||
let layout = 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));
|
||||
}
|
||||
}
|
||||
|
||||
sorted_fields.sort_by(|(label1, _), (label2, _)| label1.cmp(label2));
|
||||
|
||||
sorted_fields
|
||||
}
|
||||
Err(other) => panic!("invalid content in record variable: {:?}", other),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue