Split up unify_rigid into unify_rigid, unify_rigid_able

This commit is contained in:
Ayaz Hafiz 2022-06-02 20:51:23 -05:00
parent bef83324da
commit 5f5f025e4c
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58

View file

@ -379,9 +379,9 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
*structure, *structure,
&ctx.second_desc.content, &ctx.second_desc.content,
), ),
RigidVar(name) => unify_rigid(subs, &ctx, name, None, &ctx.second_desc.content), RigidVar(name) => unify_rigid(subs, &ctx, name, &ctx.second_desc.content),
RigidAbleVar(name, ability) => { RigidAbleVar(name, ability) => {
unify_rigid(subs, &ctx, name, Some(*ability), &ctx.second_desc.content) unify_rigid_able(subs, &ctx, name, *ability, &ctx.second_desc.content)
} }
Structure(flat_type) => { Structure(flat_type) => {
unify_structure(subs, pool, &ctx, flat_type, &ctx.second_desc.content) unify_structure(subs, pool, &ctx, flat_type, &ctx.second_desc.content)
@ -1912,7 +1912,6 @@ fn unify_rigid(
subs: &mut Subs, subs: &mut Subs,
ctx: &Context, ctx: &Context,
name: &SubsIndex<Lowercase>, name: &SubsIndex<Lowercase>,
opt_able_bound: Option<Symbol>,
other: &Content, other: &Content,
) -> Outcome { ) -> Outcome {
match other { match other {
@ -1921,31 +1920,73 @@ fn unify_rigid(
merge(subs, ctx, RigidVar(*name)) merge(subs, ctx, RigidVar(*name))
} }
FlexAbleVar(_, other_ability) => { FlexAbleVar(_, other_ability) => {
match opt_able_bound { // Mismatch - Rigid can unify with FlexAble only when the Rigid has an ability
Some(ability) => { // bound as well, otherwise the user failed to correctly annotate the bound.
if ability == *other_ability { mismatch!(
// The ability bounds are the same, so rigid wins! %not_able, ctx.first, *other_ability,
merge(subs, ctx, RigidAbleVar(*name, ability)) "Rigid {:?} with FlexAble {:?}", ctx.first, other
} else { )
// Mismatch for now. }
// TODO check ability hierarchies.
mismatch!( RigidVar(_)
%not_able, ctx.second, ability, | RecursionVar { .. }
"RigidAble {:?} with ability {:?} not compatible with ability {:?}", | Structure(_)
ctx.first, | Alias(_, _, _, _)
ability, | RangedNumber(..)
other_ability | LambdaSet(..)
) if ctx.mode.contains(Mode::RIGID_AS_FLEX) =>
} {
} // Usually rigids can only unify with flex, but the mode indicates we are treating
None => { // rigid vars as flex, so admit this.
// Mismatch - Rigid can unify with FlexAble only when the Rigid has an ability merge(subs, ctx, *other)
// bound as well, otherwise the user failed to correctly annotate the bound. }
mismatch!(
%not_able, ctx.first, *other_ability, RigidVar(_)
"Rigid {:?} with FlexAble {:?}", ctx.first, other | RigidAbleVar(..)
) | RecursionVar { .. }
} | Structure(_)
| Alias(..)
| RangedNumber(..)
| LambdaSet(..) => {
// Type mismatch! Rigid can only unify with flex, even if the
// rigid names are the same.
mismatch!("Rigid {:?} with {:?}", ctx.first, &other)
}
Error => {
// Error propagates.
merge(subs, ctx, Error)
}
}
}
#[inline(always)]
fn unify_rigid_able(
subs: &mut Subs,
ctx: &Context,
name: &SubsIndex<Lowercase>,
ability: Symbol,
other: &Content,
) -> Outcome {
match other {
FlexVar(_) => {
// If the other is flex, rigid wins!
merge(subs, ctx, RigidVar(*name))
}
FlexAbleVar(_, other_ability) => {
if ability == *other_ability {
// The ability bounds are the same, so rigid wins!
merge(subs, ctx, RigidAbleVar(*name, ability))
} else {
// Mismatch for now.
// TODO check ability hierarchies.
mismatch!(
%not_able, ctx.second, ability,
"RigidAble {:?} with ability {:?} not compatible with ability {:?}",
ctx.first,
ability,
other_ability
)
} }
} }
@ -1959,11 +2000,8 @@ fn unify_rigid(
{ {
// Usually rigids can only unify with flex, but the mode indicates we are treating // Usually rigids can only unify with flex, but the mode indicates we are treating
// rigid vars as flex, so admit this. // rigid vars as flex, so admit this.
match (opt_able_bound, other) { match other {
(None, other) => merge(subs, ctx, *other), Alias(opaque_name, vars, _real_var, AliasKind::Opaque) if vars.is_empty() => {
(Some(ability), Alias(opaque_name, vars, _real_var, AliasKind::Opaque))
if vars.is_empty() =>
{
let mut output = merge(subs, ctx, *other); let mut output = merge(subs, ctx, *other);
let must_implement_ability = MustImplementAbility { let must_implement_ability = MustImplementAbility {
typ: Obligated::Opaque(*opaque_name), typ: Obligated::Opaque(*opaque_name),
@ -1974,10 +2012,10 @@ fn unify_rigid(
} }
// these have underscores because they're unused in --release builds // these have underscores because they're unused in --release builds
(Some(_ability), _other) => { _other => {
// For now, only allow opaque types with no type variables to implement abilities. // For now, only allow opaque types with no type variables to implement abilities.
mismatch!( mismatch!(
%not_able, ctx.second, _ability, %not_able, ctx.second, ability,
"RigidAble {:?} with non-opaque or opaque with type variables {:?}", "RigidAble {:?} with non-opaque or opaque with type variables {:?}",
ctx.first, ctx.first,
&_other &_other