Add derive key generation for record hashing

This commit is contained in:
Ayaz Hafiz 2022-10-04 14:35:33 -05:00
parent fd421c005d
commit ad4d98be9c
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
3 changed files with 97 additions and 10 deletions

View file

@ -10,5 +10,7 @@ pub(crate) fn derive_hash(
key: FlatHashKey, key: FlatHashKey,
_def_symbol: Symbol, _def_symbol: Symbol,
) -> DerivedBody { ) -> DerivedBody {
match key {} match key {
FlatHashKey::Record(_) => todo!(),
}
} }

View file

@ -1,7 +1,10 @@
use roc_module::symbol::Symbol; use roc_module::{ident::Lowercase, symbol::Symbol};
use roc_types::subs::{Content, FlatType, Subs, Variable}; use roc_types::subs::{Content, FlatType, Subs, Variable};
use crate::DeriveError; use crate::{
util::{check_derivable_ext_var, debug_name_record},
DeriveError,
};
#[derive(Hash)] #[derive(Hash)]
pub enum FlatHash { pub enum FlatHash {
@ -12,11 +15,16 @@ pub enum FlatHash {
} }
#[derive(Hash, PartialEq, Eq, Debug, Clone)] #[derive(Hash, PartialEq, Eq, Debug, Clone)]
pub enum FlatHashKey {} pub enum FlatHashKey {
// Unfortunate that we must allocate here, c'est la vie
Record(Vec<Lowercase>),
}
impl FlatHashKey { impl FlatHashKey {
pub(crate) fn debug_name(&self) -> String { pub(crate) fn debug_name(&self) -> String {
unreachable!() // yet match self {
FlatHashKey::Record(fields) => debug_name_record(fields),
}
} }
} }
@ -31,8 +39,26 @@ impl FlatHash {
Symbol::STR_STR => Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_STR_BYTES)), Symbol::STR_STR => Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_STR_BYTES)),
_ => Err(Underivable), _ => Err(Underivable),
}, },
FlatType::Record(_fields, _ext) => { FlatType::Record(fields, ext) => {
Err(Underivable) // yet let (fields_iter, ext) = fields.unsorted_iterator_and_ext(subs, ext);
check_derivable_ext_var(subs, ext, |ext| {
matches!(ext, Content::Structure(FlatType::EmptyRecord))
})?;
let mut field_names = Vec::with_capacity(fields.len());
for (field_name, record_field) in fields_iter {
if record_field.is_optional() {
// Can't derive a concrete decoder for optional fields, since those are
// compile-time-polymorphic
return Err(Underivable);
}
field_names.push(field_name.clone());
}
field_names.sort();
Ok(Key(FlatHashKey::Record(field_names)))
} }
FlatType::TagUnion(_tags, _ext) | FlatType::RecursiveTagUnion(_, _tags, _ext) => { FlatType::TagUnion(_tags, _ext) | FlatType::RecursiveTagUnion(_, _tags, _ext) => {
Err(Underivable) // yet Err(Underivable) // yet
@ -40,7 +66,7 @@ impl FlatHash {
FlatType::FunctionOrTagUnion(_name_index, _, _) => { FlatType::FunctionOrTagUnion(_name_index, _, _) => {
Err(Underivable) // yet Err(Underivable) // yet
} }
FlatType::EmptyRecord => Err(Underivable), // yet FlatType::EmptyRecord => Ok(Key(FlatHashKey::Record(vec![]))),
FlatType::EmptyTagUnion => { FlatType::EmptyTagUnion => {
Err(Underivable) // yet Err(Underivable) // yet
} }

View file

@ -4,11 +4,38 @@
// For the `v!` macro we use uppercase variables when constructing tag unions. // For the `v!` macro we use uppercase variables when constructing tag unions.
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::{util::check_single_lset_immediate, v}; use crate::{
test_key_eq, test_key_neq,
util::{check_derivable, check_single_lset_immediate, check_underivable},
v,
};
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_types::subs::Variable; use roc_types::subs::Variable;
use roc_derive_key::DeriveBuiltin::Hash; use roc_derive_key::{hash::FlatHashKey, DeriveBuiltin::Hash, DeriveError, DeriveKey};
test_key_eq! {
Hash,
same_record:
v!({ a: v!(U8), }), v!({ a: v!(U8), })
same_record_fields_diff_types:
v!({ a: v!(U8), }), v!({ a: v!(STR), })
same_record_fields_any_order:
v!({ a: v!(U8), b: v!(U8), c: v!(U8), }),
v!({ c: v!(U8), a: v!(U8), b: v!(U8), })
explicit_empty_record_and_implicit_empty_record:
v!(EMPTY_RECORD), v!({})
}
test_key_neq! {
Hash,
different_record_fields:
v!({ a: v!(U8), }), v!({ b: v!(U8), })
record_empty_vs_nonempty:
v!(EMPTY_RECORD), v!({ a: v!(U8), })
}
#[test] #[test]
fn immediates() { fn immediates() {
@ -26,3 +53,35 @@ fn immediates() {
check_single_lset_immediate(Hash, v!(Symbol::LIST_LIST v!(U8)), Symbol::HASH_HASH_LIST); check_single_lset_immediate(Hash, v!(Symbol::LIST_LIST v!(U8)), Symbol::HASH_HASH_LIST);
check_single_lset_immediate(Hash, v!(Symbol::LIST_LIST v!(STR)), Symbol::HASH_HASH_LIST); check_single_lset_immediate(Hash, v!(Symbol::LIST_LIST v!(STR)), Symbol::HASH_HASH_LIST);
} }
#[test]
fn optional_record_field_derive_error() {
check_underivable(Hash, v!({ ?a: v!(U8), }), DeriveError::Underivable);
}
#[test]
fn derivable_record_ext_flex_var() {
check_derivable(
Hash,
v!({ a: v!(STR), }* ),
DeriveKey::Hash(FlatHashKey::Record(vec!["a".into()])),
);
}
#[test]
fn derivable_record_ext_flex_able_var() {
check_derivable(
Hash,
v!({ a: v!(STR), }a has Symbol::DECODE_DECODER ),
DeriveKey::Hash(FlatHashKey::Record(vec!["a".into()])),
);
}
#[test]
fn derivable_record_with_record_ext() {
check_derivable(
Hash,
v!({ b: v!(STR), }{ a: v!(STR), } ),
DeriveKey::Hash(FlatHashKey::Record(vec!["a".into(), "b".into()])),
);
}