Merge pull request #4644 from roc-lang/i4594

Unify ranged numbers with flex able, modulo obligation checking
This commit is contained in:
Ayaz 2022-12-01 16:52:32 -06:00 committed by GitHub
commit 9b4552608f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 167 additions and 10 deletions

View file

@ -593,6 +593,18 @@ trait DerivableVisitor {
})
}
#[inline(always)]
fn visit_floating_point_content(
var: Variable,
_subs: &mut Subs,
_content_var: Variable,
) -> Result<Descend, NotDerivable> {
Err(NotDerivable {
var,
context: NotDerivableContext::NoContext,
})
}
#[inline(always)]
fn visit_ranged_number(var: Variable, _range: NumericRange) -> Result<(), NotDerivable> {
Err(NotDerivable {
@ -717,14 +729,22 @@ 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) => {
let descend = Self::visit_floating_point_content(var, subs, real_var)?;
if descend.0 {
// Decay to a ground
stack.push(real_var)
}
}
Alias(opaque, _alias_variables, _real_var, AliasKind::Opaque) => {
if obligation_cache
.check_opaque_and_read(abilities_store, opaque, Self::ABILITY)
@ -841,6 +861,15 @@ impl DerivableVisitor for DeriveEncoding {
fn visit_ranged_number(_var: Variable, _range: NumericRange) -> Result<(), NotDerivable> {
Ok(())
}
#[inline(always)]
fn visit_floating_point_content(
_var: Variable,
_subs: &mut Subs,
_content_var: Variable,
) -> Result<Descend, NotDerivable> {
Ok(Descend(false))
}
}
struct DeriveDecoding;
@ -931,6 +960,15 @@ impl DerivableVisitor for DeriveDecoding {
fn visit_ranged_number(_var: Variable, _range: NumericRange) -> Result<(), NotDerivable> {
Ok(())
}
#[inline(always)]
fn visit_floating_point_content(
_var: Variable,
_subs: &mut Subs,
_content_var: Variable,
) -> Result<Descend, NotDerivable> {
Ok(Descend(false))
}
}
struct DeriveHash;
@ -1021,6 +1059,15 @@ impl DerivableVisitor for DeriveHash {
fn visit_ranged_number(_var: Variable, _range: NumericRange) -> Result<(), NotDerivable> {
Ok(())
}
#[inline(always)]
fn visit_floating_point_content(
_var: Variable,
_subs: &mut Subs,
_content_var: Variable,
) -> Result<Descend, NotDerivable> {
Ok(Descend(false))
}
}
struct DeriveEq;
@ -1116,6 +1163,32 @@ impl DerivableVisitor for DeriveEq {
}
}
fn visit_floating_point_content(
var: Variable,
subs: &mut Subs,
content_var: Variable,
) -> Result<Descend, NotDerivable> {
use roc_unify::unify::{unify, Mode};
// Of the floating-point types,
// only Dec implements Eq.
let mut env = Env::new(subs);
let unified = unify(
&mut env,
content_var,
Variable::DECIMAL,
Mode::EQ,
Polarity::Pos,
);
match unified {
roc_unify::unify::Unified::Success { .. } => Ok(Descend(false)),
roc_unify::unify::Unified::Failure(..) => Err(NotDerivable {
var,
context: NotDerivableContext::Eq(NotDerivableEq::FloatingPoint),
}),
}
}
#[inline(always)]
fn visit_ranged_number(_var: Variable, _range: NumericRange) -> Result<(), NotDerivable> {
// Ranged numbers are allowed, because they are always possibly ints - floats can not have

View file

@ -8414,4 +8414,21 @@ mod solve_expr {
"[Ok a]* -> a",
);
}
#[test]
fn resolve_eq_for_float_forces_dec() {
infer_queries!(
indoc!(
r#"
app "test" provides [main] to "./platform"
n : Num *
main = n == 1.
# ^
"#
),
@"n : Dec"
);
}
}

View file

@ -1588,7 +1588,7 @@ fn float_type(
num_binary64,
AliasVariables::default(),
Variable::EMPTY_TAG_UNION,
AliasKind::Structural,
AliasKind::Opaque,
)
});
}

View file

@ -650,7 +650,18 @@ fn unify_ranged_number<M: MetaCollector>(
// Int a vs Int <range>, the rigid wins
merge(env, ctx, RigidVar(*name))
}
RecursionVar { .. } | Alias(..) | Structure(..) | RigidAbleVar(..) | FlexAbleVar(..) => {
FlexAbleVar(_, abilities) => {
// Range wins, modulo obligation checking.
merge_flex_able_with_concrete(
env,
ctx,
ctx.second,
*abilities,
RangedNumber(range_vars),
Obligated::Adhoc(ctx.first),
)
}
RecursionVar { .. } | Alias(..) | Structure(..) | RigidAbleVar(..) => {
check_and_merge_valid_range(env, pool, ctx, ctx.first, range_vars, ctx.second)
}
&RangedNumber(other_range_vars) => match range_vars.intersection(&other_range_vars) {