Compile derived structural equality

This commit is contained in:
Ayaz Hafiz 2022-10-05 17:17:35 -05:00
parent 54e977be2d
commit 3674f6861e
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
7 changed files with 41 additions and 1 deletions

View file

@ -3,6 +3,7 @@ interface Eq
Eq,
isEq,
isNotEq,
structuralEq,
]
imports [
Bool,
@ -37,3 +38,7 @@ Eq has
## `a != b` is shorthand for `Eq.isNotEq a b`.
isNotEq : a, a -> Bool | a has Eq
isNotEq = \a, b -> Bool.not (isEq a b)
# INTERNAL COMPILER USE ONLY: used to lower calls to `isEq` to structural
# equality via the `Eq` low-level for derived types.
structuralEq : a, a -> Bool

View file

@ -70,6 +70,7 @@ macro_rules! map_symbol_to_lowlevel_and_arity {
// Below, we explicitly handle some exceptions to the pattern where a lowlevel maps
// directly to a symbol. If you are unsure if your lowlevel is an exception, assume
// that it isn't and just see if that works.
#[allow(unreachable_patterns)] // TODO: remove after we replace `BOOL_EQ` with `EQ_EQ` wholly
match lowlevel {
$(
LowLevel::$lowlevel => Symbol::$symbol,
@ -192,6 +193,7 @@ map_symbol_to_lowlevel_and_arity! {
NumToStr; NUM_TO_STR; 1,
Eq; BOOL_EQ; 2,
Eq; EQ_STRUCTURAL_EQ; 2,
NotEq; BOOL_NEQ; 2,
And; BOOL_AND; 2,
Or; BOOL_OR; 2,

View file

@ -374,6 +374,7 @@ pub fn canonicalize_module_defs<'a>(
if !output.references.has_type_or_value_lookup(symbol)
&& !exposed_symbols.contains(&symbol)
&& !scope.abilities_store.is_specialization_name(symbol)
&& !symbol.is_exposed_for_builtin_derivers()
{
env.problem(Problem::UnusedDef(symbol, region));
}

View file

@ -4469,7 +4469,11 @@ fn run_solve_solve(
// ability.
let exposed_vars_by_symbol: Vec<_> = solved_env
.vars_by_symbol()
.filter(|(k, _)| exposed_symbols.contains(k) || is_specialization_symbol(*k))
.filter(|(k, _)| {
exposed_symbols.contains(k)
|| is_specialization_symbol(*k)
|| k.is_exposed_for_builtin_derivers()
})
.collect();
(

View file

@ -184,6 +184,7 @@ macro_rules! map_symbol_to_lowlevel {
// Below, we explicitly handle some exceptions to the pattern where a lowlevel maps
// directly to a symbol. If you are unsure if your lowlevel is an exception, assume
// that it isn't and just see if that works.
#[allow(unreachable_patterns)] // TODO: remove after we replace `BOOL_EQ` with `EQ_EQ` wholly
match lowlevel {
$(
LowLevel::$lowlevel => Symbol::$symbol,
@ -310,6 +311,7 @@ map_symbol_to_lowlevel! {
NumShiftRightZfBy <= NUM_SHIFT_RIGHT_ZERO_FILL,
NumToStr <= NUM_TO_STR,
Eq <= BOOL_EQ,
Eq <= EQ_STRUCTURAL_EQ,
NotEq <= BOOL_NEQ,
And <= BOOL_AND,
Or <= BOOL_OR,

View file

@ -99,6 +99,17 @@ impl Symbol {
DERIVABLE_ABILITIES.iter().find(|(name, _)| *name == self)
}
/// A symbol that should never be exposed to userspace, but needs to be exposed
/// to compiled modules for deriving abilities for structural types.
pub fn is_exposed_for_builtin_derivers(&self) -> bool {
matches!(
self,
// The `structuralEq` call used deriving structural equality, which will wrap the `Eq`
// low-level implementation.
&Self::EQ_STRUCTURAL_EQ
) && false
}
pub fn module_string<'a>(&self, interns: &'a Interns) -> &'a ModuleName {
interns
.module_ids

View file

@ -1639,4 +1639,19 @@ mod eq {
RocStr
)
}
#[test]
fn derive_structural_eq() {
assert_evals_to!(
indoc!(
r#"
app "test" provides [main] to "./platform"
main = Eq.isEq 10u8 10u8
"#
),
true,
bool
)
}
}