Sort fields in one pass, and drop 0-sized fields

This commit is contained in:
Richard Feldman 2020-06-25 01:49:58 -04:00
parent 487c1e3b75
commit ae58ef914d
2 changed files with 46 additions and 29 deletions

View file

@ -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();

View file

@ -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,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())) 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),
} }