mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
Make sure unit structs are always units
This commit is contained in:
parent
148dbb4efe
commit
395e0a33e0
2 changed files with 35 additions and 20 deletions
|
@ -4701,9 +4701,7 @@ fn construct_closure_data<'a>(
|
||||||
Vec::from_iter_in(combined.iter().map(|(_, b)| **b), env.arena).into_bump_slice();
|
Vec::from_iter_in(combined.iter().map(|(_, b)| **b), env.arena).into_bump_slice();
|
||||||
|
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
// NB: this may be wrong! If it comes up, we may need to hash the closure
|
Layout::struct_no_name_order(field_layouts),
|
||||||
// argument name order.
|
|
||||||
Layout::struct_no_name_order(field_layouts,),
|
|
||||||
lambda_set.runtime_representation()
|
lambda_set.runtime_representation()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ static_assertions::assert_eq_size!([usize; 3], LambdaSet);
|
||||||
pub type TagIdIntType = u16;
|
pub type TagIdIntType = u16;
|
||||||
pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::<TagIdIntType>() * 8) as usize;
|
pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::<TagIdIntType>() * 8) as usize;
|
||||||
const GENERATE_NULLABLE: bool = true;
|
const GENERATE_NULLABLE: bool = true;
|
||||||
const IRRELEVANT_FIELD_HASH: u64 = 0;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LayoutProblem {
|
pub enum LayoutProblem {
|
||||||
|
@ -203,6 +202,27 @@ impl<'a> RawFunctionLayout<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct FieldOrderHash(u64);
|
||||||
|
|
||||||
|
impl FieldOrderHash {
|
||||||
|
// NB: This should really be a proper "zero" hash via `DefaultHasher::new().finish()`, but Rust
|
||||||
|
// stdlib hashers are not (yet) compile-time-computable.
|
||||||
|
const ZERO_FIELD_HASH: Self = Self(0);
|
||||||
|
const IRRELEVANT_NON_ZERO_FIELD_HASH: Self = Self(1);
|
||||||
|
|
||||||
|
pub fn from_ordered_fields(fields: &[&Lowercase]) -> Self {
|
||||||
|
if fields.is_empty() {
|
||||||
|
// HACK: we must make sure this is always equivalent to a `ZERO_FIELD_HASH`.
|
||||||
|
return Self::ZERO_FIELD_HASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
fields.iter().for_each(|field| field.hash(&mut hasher));
|
||||||
|
Self(hasher.finish())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Types for code gen must be monomorphic. No type variables allowed!
|
/// Types for code gen must be monomorphic. No type variables allowed!
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum Layout<'a> {
|
pub enum Layout<'a> {
|
||||||
|
@ -217,7 +237,7 @@ pub enum Layout<'a> {
|
||||||
/// in collisions, but it's unlikely.
|
/// in collisions, but it's unlikely.
|
||||||
///
|
///
|
||||||
/// See also https://github.com/rtfeldman/roc/issues/2535.
|
/// See also https://github.com/rtfeldman/roc/issues/2535.
|
||||||
field_order_hash: u64,
|
field_order_hash: FieldOrderHash,
|
||||||
field_layouts: &'a [Layout<'a>],
|
field_layouts: &'a [Layout<'a>],
|
||||||
},
|
},
|
||||||
Union(UnionLayout<'a>),
|
Union(UnionLayout<'a>),
|
||||||
|
@ -885,7 +905,7 @@ impl<'a> Layout<'a> {
|
||||||
pub const VOID: Self = Layout::Union(UnionLayout::NonRecursive(&[]));
|
pub const VOID: Self = Layout::Union(UnionLayout::NonRecursive(&[]));
|
||||||
pub const UNIT: Self = Layout::Struct {
|
pub const UNIT: Self = Layout::Struct {
|
||||||
field_layouts: &[],
|
field_layouts: &[],
|
||||||
field_order_hash: IRRELEVANT_FIELD_HASH,
|
field_order_hash: FieldOrderHash::ZERO_FIELD_HASH,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn new_help<'b>(
|
fn new_help<'b>(
|
||||||
|
@ -1171,9 +1191,13 @@ impl<'a> Layout<'a> {
|
||||||
|
|
||||||
/// Used to build a `Layout::Struct` where the field name order is irrelevant.
|
/// Used to build a `Layout::Struct` where the field name order is irrelevant.
|
||||||
pub fn struct_no_name_order(field_layouts: &'a [Layout]) -> Self {
|
pub fn struct_no_name_order(field_layouts: &'a [Layout]) -> Self {
|
||||||
Self::Struct {
|
if field_layouts.is_empty() {
|
||||||
field_layouts,
|
Self::UNIT
|
||||||
field_order_hash: IRRELEVANT_FIELD_HASH,
|
} else {
|
||||||
|
Self::Struct {
|
||||||
|
field_layouts,
|
||||||
|
field_order_hash: FieldOrderHash::IRRELEVANT_NON_ZERO_FIELD_HASH,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1619,13 +1643,10 @@ fn layout_from_flat_type<'a>(
|
||||||
size2.cmp(&size1).then(label1.cmp(label2))
|
size2.cmp(&size1).then(label1.cmp(label2))
|
||||||
});
|
});
|
||||||
|
|
||||||
let field_order_hash = {
|
let ordered_field_names =
|
||||||
let mut field_order_hasher = DefaultHasher::new();
|
Vec::from_iter_in(pairs.iter().map(|(label, _)| *label), arena);
|
||||||
pairs
|
let field_order_hash =
|
||||||
.iter()
|
FieldOrderHash::from_ordered_fields(ordered_field_names.as_slice());
|
||||||
.for_each(|(label, _)| label.hash(&mut field_order_hasher));
|
|
||||||
field_order_hasher.finish()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut layouts = Vec::from_iter_in(pairs.into_iter().map(|t| t.1), arena);
|
let mut layouts = Vec::from_iter_in(pairs.into_iter().map(|t| t.1), arena);
|
||||||
|
|
||||||
|
@ -2264,9 +2285,6 @@ pub fn union_sorted_tags_help<'a>(
|
||||||
} else {
|
} else {
|
||||||
UnionVariant::Newtype {
|
UnionVariant::Newtype {
|
||||||
tag_name,
|
tag_name,
|
||||||
// NB: It may be the case that the order of the layouts chosen here must be
|
|
||||||
// hashed, in case they differ for two specializations of the same type. If
|
|
||||||
// there is a problem with newtypes not specializing correctly, this might be why!
|
|
||||||
arguments: layouts,
|
arguments: layouts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2473,7 +2491,6 @@ fn layout_from_tag_union<'a>(
|
||||||
let answer1 = if field_layouts.len() == 1 {
|
let answer1 = if field_layouts.len() == 1 {
|
||||||
field_layouts[0]
|
field_layouts[0]
|
||||||
} else {
|
} else {
|
||||||
// NB: does the field name order here matter, when it comes from the tag payload order?
|
|
||||||
Layout::struct_no_name_order(field_layouts.into_bump_slice())
|
Layout::struct_no_name_order(field_layouts.into_bump_slice())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue