mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Obligation checking Eq for floating point types may never succeed
This commit is contained in:
parent
0bae0aafb6
commit
590535a42b
2 changed files with 60 additions and 2 deletions
|
@ -488,10 +488,19 @@ struct NotDerivable {
|
|||
|
||||
struct Descend(bool);
|
||||
|
||||
enum FPDerivable {
|
||||
/// Whether the floating point type is derivable is based on its ground or unbound type.
|
||||
Descend,
|
||||
/// The FP type is never derivable.
|
||||
No(NotDerivableContext),
|
||||
}
|
||||
|
||||
trait DerivableVisitor {
|
||||
const ABILITY: Symbol;
|
||||
const ABILITY_SLICE: SubsSlice<Symbol>;
|
||||
|
||||
const IS_FLOATING_POINT_DERIVABLE: FPDerivable;
|
||||
|
||||
#[inline(always)]
|
||||
fn is_derivable_builtin_opaque(_symbol: Symbol) -> bool {
|
||||
false
|
||||
|
@ -717,14 +726,24 @@ trait DerivableVisitor {
|
|||
EmptyTagUnion => Self::visit_empty_tag_union(var)?,
|
||||
},
|
||||
Alias(
|
||||
Symbol::NUM_NUM | Symbol::NUM_INTEGER | Symbol::NUM_FLOATINGPOINT,
|
||||
Symbol::NUM_NUM | Symbol::NUM_INTEGER,
|
||||
_alias_variables,
|
||||
real_var,
|
||||
AliasKind::Opaque,
|
||||
) => {
|
||||
// Numbers: always decay until a ground is hit.
|
||||
// Unbound numbers and integers: always decay until a ground is hit,
|
||||
// since all of our builtin abilities currently support integers.
|
||||
stack.push(real_var);
|
||||
}
|
||||
Alias(Symbol::NUM_FLOATINGPOINT, _alias_variables, real_var, AliasKind::Opaque) => {
|
||||
match Self::IS_FLOATING_POINT_DERIVABLE {
|
||||
FPDerivable::Descend => {
|
||||
// Decay to a ground
|
||||
stack.push(real_var)
|
||||
}
|
||||
FPDerivable::No(context) => return Err(NotDerivable { var, context }),
|
||||
}
|
||||
}
|
||||
Alias(opaque, _alias_variables, _real_var, AliasKind::Opaque) => {
|
||||
if obligation_cache
|
||||
.check_opaque_and_read(abilities_store, opaque, Self::ABILITY)
|
||||
|
@ -769,6 +788,8 @@ impl DerivableVisitor for DeriveEncoding {
|
|||
const ABILITY: Symbol = Symbol::ENCODE_ENCODING;
|
||||
const ABILITY_SLICE: SubsSlice<Symbol> = Subs::AB_ENCODING;
|
||||
|
||||
const IS_FLOATING_POINT_DERIVABLE: FPDerivable = FPDerivable::Descend;
|
||||
|
||||
#[inline(always)]
|
||||
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
|
||||
is_builtin_number_alias(symbol)
|
||||
|
@ -848,6 +869,8 @@ impl DerivableVisitor for DeriveDecoding {
|
|||
const ABILITY: Symbol = Symbol::DECODE_DECODING;
|
||||
const ABILITY_SLICE: SubsSlice<Symbol> = Subs::AB_DECODING;
|
||||
|
||||
const IS_FLOATING_POINT_DERIVABLE: FPDerivable = FPDerivable::Descend;
|
||||
|
||||
#[inline(always)]
|
||||
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
|
||||
is_builtin_number_alias(symbol)
|
||||
|
@ -938,6 +961,8 @@ impl DerivableVisitor for DeriveHash {
|
|||
const ABILITY: Symbol = Symbol::HASH_HASH_ABILITY;
|
||||
const ABILITY_SLICE: SubsSlice<Symbol> = Subs::AB_HASH;
|
||||
|
||||
const IS_FLOATING_POINT_DERIVABLE: FPDerivable = FPDerivable::Descend;
|
||||
|
||||
#[inline(always)]
|
||||
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
|
||||
is_builtin_number_alias(symbol)
|
||||
|
@ -1028,6 +1053,9 @@ impl DerivableVisitor for DeriveEq {
|
|||
const ABILITY: Symbol = Symbol::BOOL_EQ;
|
||||
const ABILITY_SLICE: SubsSlice<Symbol> = Subs::AB_EQ;
|
||||
|
||||
const IS_FLOATING_POINT_DERIVABLE: FPDerivable =
|
||||
FPDerivable::No(NotDerivableContext::Eq(NotDerivableEq::FloatingPoint));
|
||||
|
||||
#[inline(always)]
|
||||
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
|
||||
is_builtin_int_alias(symbol) || is_builtin_dec_alias(symbol)
|
||||
|
|
|
@ -12586,6 +12586,36 @@ I recommend using camelCase. It's the standard style in Roc code!
|
|||
)
|
||||
);
|
||||
|
||||
test_report!(
|
||||
resolve_eq_for_unbound_num_float,
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
n : Num *
|
||||
|
||||
main = n == 1.
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
|
||||
5│ main = n == 1.
|
||||
^^
|
||||
|
||||
I can't generate an implementation of the `Eq` ability for
|
||||
|
||||
FloatingPoint *
|
||||
|
||||
Note: I can't derive `Bool.isEq` for floating-point types. That's
|
||||
because Roc's floating-point numbers cannot be compared for total
|
||||
equality - in Roc, `NaN` is never comparable to `NaN`. If a type
|
||||
doesn't support total equality, it cannot support the `Eq` ability!
|
||||
"###
|
||||
);
|
||||
|
||||
test_no_problem!(
|
||||
resolve_hash_for_unbound_num,
|
||||
indoc!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue