mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Derive hash for tag unions with a discriminant
This commit is contained in:
parent
5eb00c4f94
commit
ff70832068
4 changed files with 366 additions and 64 deletions
|
@ -294,7 +294,8 @@ fn tag_one_label_zero_args() {
|
|||
\#Derived.bytes, #Derived.fmt ->
|
||||
Encode.appendWith
|
||||
#Derived.bytes
|
||||
(when #Derived.tag is A -> Encode.tag "A" [])
|
||||
(when #Derived.tag is
|
||||
A -> Encode.tag "A" [])
|
||||
#Derived.fmt
|
||||
"###
|
||||
)
|
||||
|
|
|
@ -200,3 +200,70 @@ fn two_field_record() {
|
|||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tag_two_labels() {
|
||||
derive_test(Hash, v!([A v!(U8) v!(STR) v!(U16), B v!(STR)]), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [A U8 Str U16, B Str]
|
||||
# a, [A a1 a2 a3, B a3] -[[hash_[A 3,B 1](0)]]-> a | a has Hasher, a1 has Hash, a2 has Hash, a3 has Hash
|
||||
# a, [A a1 a2 a3, B a3] -[[hash_[A 3,B 1](0)]]-> a | a has Hasher, a1 has Hash, a2 has Hash, a3 has Hash
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_[A 3,B 1](0)]]
|
||||
#Derived.hash_[A 3,B 1] =
|
||||
\#Derived.hasher, #Derived.union ->
|
||||
#Derived.discrHasher =
|
||||
Hash.hash #Derived.hasher (@tag_discriminant #Derived.union)
|
||||
when #Derived.union is
|
||||
A #Derived.4 #Derived.5 #Derived.6 ->
|
||||
Hash.hash
|
||||
(Hash.hash (Hash.hash #Derived.discrHasher #Derived.4) #Derived.5)
|
||||
#Derived.6
|
||||
B #Derived.7 -> Hash.hash #Derived.discrHasher #Derived.7
|
||||
"###
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tag_two_labels_no_payloads() {
|
||||
derive_test(Hash, v!([A, B]), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [A, B]
|
||||
# a, [A, B] -[[hash_[A 0,B 0](0)]]-> a | a has Hasher
|
||||
# a, [A, B] -[[hash_[A 0,B 0](0)]]-> a | a has Hasher
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_[A 0,B 0](0)]]
|
||||
#Derived.hash_[A 0,B 0] =
|
||||
\#Derived.hasher, #Derived.union ->
|
||||
#Derived.discrHasher =
|
||||
Hash.hash #Derived.hasher (@tag_discriminant #Derived.union)
|
||||
when #Derived.union is
|
||||
A -> #Derived.discrHasher
|
||||
B -> #Derived.discrHasher
|
||||
"###
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recursive_tag_union() {
|
||||
derive_test(Hash, v!([Nil, Cons v!(U8) v!(^lst) ] as lst), |golden| {
|
||||
assert_snapshot!(golden, @r###"
|
||||
# derived for [Cons U8 $rec, Nil] as $rec
|
||||
# a, [Cons a1 a2, Nil] -[[hash_[Cons 2,Nil 0](0)]]-> a | a has Hasher, a1 has Hash, a2 has Hash
|
||||
# a, [Cons a1 a2, Nil] -[[hash_[Cons 2,Nil 0](0)]]-> a | a has Hasher, a1 has Hash, a2 has Hash
|
||||
# Specialization lambda sets:
|
||||
# @<1>: [[hash_[Cons 2,Nil 0](0)]]
|
||||
#Derived.hash_[Cons 2,Nil 0] =
|
||||
\#Derived.hasher, #Derived.union ->
|
||||
#Derived.discrHasher =
|
||||
Hash.hash #Derived.hasher (@tag_discriminant #Derived.union)
|
||||
when #Derived.union is
|
||||
Cons #Derived.4 #Derived.5 ->
|
||||
Hash.hash (Hash.hash #Derived.discrHasher #Derived.4) #Derived.5
|
||||
Nil -> #Derived.discrHasher
|
||||
"###
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,7 +5,9 @@ use roc_can::expr::Expr::{self, *};
|
|||
use roc_can::expr::{ClosureData, OpaqueWrapFunctionData, WhenBranch};
|
||||
use roc_can::pattern::{Pattern, RecordDestruct};
|
||||
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::Interns;
|
||||
|
||||
use ven_pretty::{Arena, DocAllocator, DocBuilder};
|
||||
|
||||
pub struct Ctx<'a> {
|
||||
|
@ -100,8 +102,12 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
|
|||
.append(expr(c, Free, f, &loc_cond.value))
|
||||
.append(f.text(" is"))
|
||||
.append(
|
||||
f.concat(branches.iter().map(|b| f.line().append(branch(c, f, b))))
|
||||
.group(),
|
||||
f.concat(
|
||||
branches
|
||||
.iter()
|
||||
.map(|b| f.hardline().append(branch(c, f, b)))
|
||||
)
|
||||
.group(),
|
||||
)
|
||||
.nest(2)
|
||||
.group()
|
||||
|
@ -134,7 +140,10 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
|
|||
)
|
||||
.group(),
|
||||
LetRec(_, _, _) => todo!(),
|
||||
LetNonRec(_, _) => todo!(),
|
||||
LetNonRec(loc_def, body) => def(c, f, loc_def)
|
||||
.append(f.hardline())
|
||||
.append(expr(c, Free, f, &body.value))
|
||||
.group(),
|
||||
Call(fun, args, _) => {
|
||||
let (_, fun, _, _) = &**fun;
|
||||
maybe_paren!(
|
||||
|
@ -154,7 +163,27 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
|
|||
.nest(2)
|
||||
)
|
||||
}
|
||||
RunLowLevel { .. } => todo!(),
|
||||
RunLowLevel { op, args, .. } => {
|
||||
let op = match op {
|
||||
LowLevel::TagDiscriminant => "@tag_discriminant",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
maybe_paren!(
|
||||
Free,
|
||||
p,
|
||||
f.reflow(op)
|
||||
.append(
|
||||
f.concat(
|
||||
args.iter()
|
||||
.map(|le| f.line().append(expr(c, AppArg, f, &le.1)))
|
||||
)
|
||||
.group()
|
||||
)
|
||||
.group()
|
||||
.nest(2)
|
||||
)
|
||||
}
|
||||
ForeignCall { .. } => todo!(),
|
||||
Closure(ClosureData {
|
||||
arguments,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue