Obligation checking for the Hash ability

This implements type-level checks that types can and cannot implement
the `Hash` ability.

Part of #4195
This commit is contained in:
Ayaz Hafiz 2022-10-04 10:51:14 -05:00
parent ca4ee908f8
commit e9efc95425
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
4 changed files with 244 additions and 4 deletions

View file

@ -272,6 +272,10 @@ impl ObligationCache {
var,
)),
Symbol::HASH_HASH_ABILITY => {
Some(DeriveHash::is_derivable(self, abilities_store, subs, var))
}
_ => None,
};
@ -893,6 +897,95 @@ impl DerivableVisitor for DeriveDecoding {
}
}
struct DeriveHash;
impl DerivableVisitor for DeriveHash {
const ABILITY: Symbol = Symbol::HASH_HASH_ABILITY;
#[inline(always)]
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
is_builtin_number_alias(symbol)
}
#[inline(always)]
fn visit_recursion(_var: Variable) -> Result<Descend, NotDerivable> {
Ok(Descend(true))
}
#[inline(always)]
fn visit_apply(var: Variable, symbol: Symbol) -> Result<Descend, NotDerivable> {
if matches!(
symbol,
Symbol::LIST_LIST | Symbol::SET_SET | Symbol::DICT_DICT | Symbol::STR_STR,
) {
Ok(Descend(true))
} else {
Err(NotDerivable {
var,
context: NotDerivableContext::NoContext,
})
}
}
#[inline(always)]
fn visit_record(
subs: &Subs,
var: Variable,
fields: RecordFields,
) -> Result<Descend, NotDerivable> {
for (field_name, _, field) in fields.iter_all() {
if subs[field].is_optional() {
return Err(NotDerivable {
var,
context: NotDerivableContext::Decode(NotDerivableDecode::OptionalRecordField(
subs[field_name].clone(),
)),
});
}
}
Ok(Descend(true))
}
#[inline(always)]
fn visit_tag_union(_var: Variable) -> Result<Descend, NotDerivable> {
Ok(Descend(true))
}
#[inline(always)]
fn visit_recursive_tag_union(_var: Variable) -> Result<Descend, NotDerivable> {
Ok(Descend(true))
}
#[inline(always)]
fn visit_function_or_tag_union(_var: Variable) -> Result<Descend, NotDerivable> {
Ok(Descend(true))
}
#[inline(always)]
fn visit_empty_record(_var: Variable) -> Result<(), NotDerivable> {
Ok(())
}
#[inline(always)]
fn visit_empty_tag_union(_var: Variable) -> Result<(), NotDerivable> {
Ok(())
}
#[inline(always)]
fn visit_alias(_var: Variable, symbol: Symbol) -> Result<Descend, NotDerivable> {
if is_builtin_number_alias(symbol) {
Ok(Descend(false))
} else {
Ok(Descend(true))
}
}
#[inline(always)]
fn visit_ranged_number(_var: Variable, _range: NumericRange) -> Result<(), NotDerivable> {
Ok(())
}
}
/// Determines what type implements an ability member of a specialized signature, given the
/// [MustImplementAbility] constraints of the signature.
pub fn type_implementing_specialization(