Represent "able" variables with slices of abilities

This commit is contained in:
Ayaz Hafiz 2022-10-12 14:52:38 -05:00
parent 0f0678ce73
commit 229548571b
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
10 changed files with 163 additions and 85 deletions

View file

@ -105,7 +105,7 @@ impl OwnedNamedOrAble {
}
}
pub fn opt_abilities(&self) -> Option<&[Symbol]> {
pub fn opt_abilities(&self) -> Option<&VecSet<Symbol>> {
match self {
OwnedNamedOrAble::Named(_) => None,
OwnedNamedOrAble::Able(av) => Some(&av.abilities),
@ -127,6 +127,8 @@ pub struct NamedVariable {
pub struct AbleVariable {
pub variable: Variable,
pub name: Lowercase,
/// Abilities bound to this type variable.
/// INVARIANT: sorted and de-duplicated.
pub abilities: VecSet<Symbol>,
// NB: there may be multiple occurrences of a variable
pub first_seen: Region,
@ -984,6 +986,11 @@ fn canonicalize_has_clause(
let var = var_store.fresh();
let can_abilities = {
let mut vec = can_abilities.into_vec();
vec.sort();
VecSet::from_iter(vec)
};
introduced_variables.insert_able(var_name, Loc::at(region, var), can_abilities);
Ok(())

View file

@ -1044,8 +1044,8 @@ mod test {
use roc_region::all::Loc;
use roc_types::{
subs::{
self, Content, Content::*, Descriptor, FlatType, Mark, OptVariable, Rank, Subs,
SubsIndex, SubsSlice, Variable,
self, Content, Content::*, Descriptor, FlatType, GetSubsSlice, Mark, OptVariable, Rank,
Subs, SubsIndex, SubsSlice, Variable,
},
types::Uls,
};
@ -1107,7 +1107,8 @@ mod test {
let mut subs = Subs::new();
let field_name = SubsIndex::push_new(&mut subs.field_names, "a".into());
let var = new_var(&mut subs, FlexAbleVar(Some(field_name), Symbol::UNDERSCORE));
let abilities = SubsSlice::extend_new(&mut subs.symbol_names, [Symbol::UNDERSCORE]);
let var = new_var(&mut subs, FlexAbleVar(Some(field_name), abilities));
let mut copied = vec![];
@ -1116,8 +1117,9 @@ mod test {
assert_ne!(var, copy);
match subs.get_content_without_compacting(var) {
FlexAbleVar(Some(name), Symbol::UNDERSCORE) => {
FlexAbleVar(Some(name), abilities) => {
assert_eq!(subs[*name].as_str(), "a");
assert_eq!(subs.get_subs_slice(*abilities), [Symbol::UNDERSCORE]);
}
it => unreachable!("{:?}", it),
}
@ -1128,7 +1130,8 @@ mod test {
let mut subs = Subs::new();
let field_name = SubsIndex::push_new(&mut subs.field_names, "a".into());
let var = new_var(&mut subs, RigidAbleVar(field_name, Symbol::UNDERSCORE));
let abilities = SubsSlice::extend_new(&mut subs.symbol_names, [Symbol::UNDERSCORE]);
let var = new_var(&mut subs, RigidAbleVar(field_name, abilities));
let mut copied = vec![];
@ -1136,8 +1139,9 @@ mod test {
assert_ne!(var, copy);
match subs.get_content_without_compacting(var) {
RigidAbleVar(name, Symbol::UNDERSCORE) => {
RigidAbleVar(name, abilities) => {
assert_eq!(subs[*name].as_str(), "a");
assert_eq!(subs.get_subs_slice(*abilities), [Symbol::UNDERSCORE]);
}
it => internal_error!("{:?}", it),
}

View file

@ -19,7 +19,8 @@ use roc_types::{
num::int_lit_width_to_variable,
subs::{
Content, ExhaustiveMark, FlatType, GetSubsSlice, LambdaSet, OptVariable, RecordFields,
RedundantMark, SubsIndex, SubsSlice, UnionLambdas, UnionTags, Variable, VariableSubsSlice,
RedundantMark, Subs, SubsIndex, SubsSlice, UnionLambdas, UnionTags, Variable,
VariableSubsSlice,
},
types::RecordField,
};
@ -87,7 +88,7 @@ fn hash_record(env: &mut Env<'_>, fn_name: Symbol, fields: Vec<Lowercase>) -> (V
let rcd_sym = env.new_symbol("rcd");
let hasher_sym = env.new_symbol("hasher");
let hasher_var = synth_var(env.subs, Content::FlexAbleVar(None, Symbol::HASH_HASHER));
let hasher_var = synth_var(env.subs, Content::FlexAbleVar(None, Subs::AB_HASHER));
let (body_var, body) = record_fields.iter_all().fold(
(hasher_var, Expr::Var(hasher_sym, hasher_var)),
@ -165,7 +166,7 @@ fn hash_tag_union(
let union_sym = env.new_symbol("union");
let hasher_sym = env.new_symbol("hasher");
let hasher_var = synth_var(env.subs, Content::FlexAbleVar(None, Symbol::HASH_HASHER));
let hasher_var = synth_var(env.subs, Content::FlexAbleVar(None, Subs::AB_HASHER));
let (discr_width, discr_precision_var, hash_discr_member) = if union_tags.len() > u64::MAX as _
{
@ -320,7 +321,7 @@ fn hash_newtype_tag_union(
// hash_union = \hasher, A x1 .. xn ->
// Hash.hash (... (Hash.hash discrHasher x1) ...) xn
let hasher_sym = env.new_symbol("hasher");
let hasher_var = synth_var(env.subs, Content::FlexAbleVar(None, Symbol::HASH_HASHER));
let hasher_var = synth_var(env.subs, Content::FlexAbleVar(None, Subs::AB_HASHER));
// A
let tag_name = tag_name;

View file

@ -10,7 +10,8 @@ use roc_solve_problem::{
};
use roc_types::num::NumericRange;
use roc_types::subs::{
instantiate_rigids, Content, FlatType, GetSubsSlice, Rank, RecordFields, Subs, Variable,
instantiate_rigids, Content, FlatType, GetSubsSlice, Rank, RecordFields, Subs, SubsSlice,
Variable,
};
use roc_types::types::{AliasKind, Category, MemberImpl, PatternCategory};
use roc_unify::unify::{Env, MustImplementConstraints};
@ -486,6 +487,7 @@ struct Descend(bool);
trait DerivableVisitor {
const ABILITY: Symbol;
const ABILITY_SLICE: SubsSlice<Symbol>;
#[inline(always)]
fn is_derivable_builtin_opaque(_symbol: Symbol) -> bool {
@ -493,8 +495,9 @@ trait DerivableVisitor {
}
#[inline(always)]
fn visit_flex_able(var: Variable, ability: Symbol) -> Result<(), NotDerivable> {
if ability != Self::ABILITY {
fn visit_flex_able(var: Variable, abilities: &[Symbol]) -> Result<(), NotDerivable> {
// TODO(multi-abilities) flex-able can inherit other abilities
if abilities != [Self::ABILITY] {
Err(NotDerivable {
var,
context: NotDerivableContext::NoContext,
@ -505,8 +508,8 @@ trait DerivableVisitor {
}
#[inline(always)]
fn visit_rigid_able(var: Variable, ability: Symbol) -> Result<(), NotDerivable> {
if ability != Self::ABILITY {
fn visit_rigid_able(var: Variable, abilities: &[Symbol]) -> Result<(), NotDerivable> {
if abilities != [Self::ABILITY] {
Err(NotDerivable {
var,
context: NotDerivableContext::NoContext,
@ -636,7 +639,7 @@ trait DerivableVisitor {
match *content {
FlexVar(opt_name) => {
// Promote the flex var to be bound to the ability.
subs.set_content(var, Content::FlexAbleVar(opt_name, Self::ABILITY));
subs.set_content(var, Content::FlexAbleVar(opt_name, Self::ABILITY_SLICE));
}
RigidVar(_) => {
return Err(NotDerivable {
@ -644,8 +647,12 @@ trait DerivableVisitor {
context: NotDerivableContext::NoContext,
})
}
FlexAbleVar(_, ability) => Self::visit_flex_able(var, ability)?,
RigidAbleVar(_, ability) => Self::visit_rigid_able(var, ability)?,
FlexAbleVar(_, abilities) => {
Self::visit_flex_able(var, subs.get_subs_slice(abilities))?
}
RigidAbleVar(_, abilities) => {
Self::visit_rigid_able(var, subs.get_subs_slice(abilities))?
}
RecursionVar {
structure,
opt_name: _,
@ -771,6 +778,7 @@ trait DerivableVisitor {
struct DeriveEncoding;
impl DerivableVisitor for DeriveEncoding {
const ABILITY: Symbol = Symbol::ENCODE_ENCODING;
const ABILITY_SLICE: SubsSlice<Symbol> = Subs::AB_ENCODING;
#[inline(always)]
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
@ -849,6 +857,7 @@ impl DerivableVisitor for DeriveEncoding {
struct DeriveDecoding;
impl DerivableVisitor for DeriveDecoding {
const ABILITY: Symbol = Symbol::DECODE_DECODING;
const ABILITY_SLICE: SubsSlice<Symbol> = Subs::AB_DECODING;
#[inline(always)]
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
@ -938,6 +947,7 @@ impl DerivableVisitor for DeriveDecoding {
struct DeriveHash;
impl DerivableVisitor for DeriveHash {
const ABILITY: Symbol = Symbol::HASH_HASH_ABILITY;
const ABILITY_SLICE: SubsSlice<Symbol> = Subs::AB_HASH;
#[inline(always)]
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {

View file

@ -2601,17 +2601,17 @@ fn type_to_variable<'a>(
let copy_var = match opt_abilities {
None => helper!(typ),
Some(abilities) => {
// TODO(abilities)
let ability = abilities[0];
// If this type argument is marked as being bound to an ability, we must
// now correctly instantiate it as so.
match RegisterVariable::from_type(subs, rank, pools, arena, typ) {
RegisterVariable::Direct(var) => {
use Content::*;
match *subs.get_content_without_compacting(var) {
FlexVar(opt_name) => subs
.set_content(var, FlexAbleVar(opt_name, ability)),
FlexVar(opt_name) => {
// TODO(multi-abilities): check run cache
let abilities_slice = SubsSlice::extend_new(&mut subs.symbol_names, abilities.iter().copied());
subs.set_content(var, FlexAbleVar(opt_name, abilities_slice))
},
RigidVar(..) => internal_error!("Rigid var in type arg for {:?} - this is a bug in the solver, or our understanding", actual),
RigidAbleVar(..) | FlexAbleVar(..) => internal_error!("Able var in type arg for {:?} - this is a bug in the solver, or our understanding", actual),
_ => {

View file

@ -164,12 +164,14 @@ macro_rules! v {
|subs: &mut Subs| { roc_derive::synth_var(subs, Content::FlexVar(None)) }
}};
($name:ident has $ability:path) => {{
use roc_types::subs::{Subs, SubsIndex, Content};
use roc_types::subs::{Subs, SubsIndex, SubsSlice, Content};
|subs: &mut Subs| {
let name_index =
SubsIndex::push_new(&mut subs.field_names, stringify!($name).into());
roc_derive::synth_var(subs, Content::FlexAbleVar(Some(name_index), $ability))
let abilities_slice = SubsSlice::extend_new(&mut subs.symbol_names, [$ability]);
roc_derive::synth_var(subs, Content::FlexAbleVar(Some(name_index), abilities_slice))
}
}};
(^$rec_var:ident) => {{

View file

@ -621,16 +621,20 @@ fn write_content<'a>(
let name = &subs.field_names[name_index.index as usize];
buf.push_str(name.as_str())
}
FlexAbleVar(opt_name_index, ability) => {
FlexAbleVar(opt_name_index, abilities) => {
let name = opt_name_index
.map(|name_index| subs.field_names[name_index.index as usize].as_str())
.unwrap_or(WILDCARD);
ctx.able_variables.push((name, *ability));
// TODO(multi-abilities)
let abilities = subs.get_subs_slice(*abilities);
ctx.able_variables.push((name, abilities[0]));
buf.push_str(name);
}
RigidAbleVar(name_index, ability) => {
RigidAbleVar(name_index, abilities) => {
let name = subs.field_names[name_index.index as usize].as_str();
ctx.able_variables.push((name, *ability));
// TODO(multi-abilities)
let abilities = subs.get_subs_slice(*abilities);
ctx.able_variables.push((name, abilities[0]));
buf.push_str(name);
}
RecursionVar {

View file

@ -1676,6 +1676,15 @@ impl Subs {
pub const TAG_NAME_BAD_UTF_8: SubsIndex<TagName> = SubsIndex::new(3);
pub const TAG_NAME_OUT_OF_BOUNDS: SubsIndex<TagName> = SubsIndex::new(4);
#[rustfmt::skip]
pub const AB_ENCODING: SubsSlice<Symbol> = SubsSlice::new(0, 1);
#[rustfmt::skip]
pub const AB_DECODING: SubsSlice<Symbol> = SubsSlice::new(1, 1);
#[rustfmt::skip]
pub const AB_HASHER: SubsSlice<Symbol> = SubsSlice::new(2, 1);
#[rustfmt::skip]
pub const AB_HASH: SubsSlice<Symbol> = SubsSlice::new(3, 1);
pub fn new() -> Self {
Self::with_capacity(0)
}
@ -1692,11 +1701,18 @@ impl Subs {
tag_names.push(TagName("BadUtf8".into()));
tag_names.push(TagName("OutOfBounds".into()));
let mut symbol_names = Vec::with_capacity(32);
symbol_names.push(Symbol::ENCODE_ENCODING);
symbol_names.push(Symbol::DECODE_DECODING);
symbol_names.push(Symbol::HASH_HASHER);
symbol_names.push(Symbol::HASH_HASH_ABILITY);
let mut subs = Subs {
utable: UnificationTable::default(),
variables: Vec::new(),
tag_names,
symbol_names: Vec::new(),
symbol_names,
field_names: Vec::new(),
record_fields: Vec::new(),
// store an empty slice at the first position
@ -1793,7 +1809,9 @@ impl Subs {
pub fn rigid_able_var(&mut self, var: Variable, name: Lowercase, ability: Symbol) {
let name_index = SubsIndex::push_new(&mut self.field_names, name);
let content = Content::RigidAbleVar(name_index, ability);
// TODO(multi-abilities)
let abilities = SubsSlice::extend_new(&mut self.symbol_names, [ability]);
let content = Content::RigidAbleVar(name_index, abilities);
let desc = Descriptor::from(content);
self.set(var, desc);
@ -2261,12 +2279,12 @@ pub enum Content {
FlexVar(Option<SubsIndex<Lowercase>>),
/// name given in a user-written annotation
RigidVar(SubsIndex<Lowercase>),
/// Like a [Self::FlexVar], but is also bound to an ability.
/// Like a [Self::FlexVar], but is also bound to 1+ abilities.
/// This can only happen when unified with a [Self::RigidAbleVar].
FlexAbleVar(Option<SubsIndex<Lowercase>>, Symbol),
/// Like a [Self::RigidVar], but is also bound to an ability.
FlexAbleVar(Option<SubsIndex<Lowercase>>, SubsSlice<Symbol>),
/// Like a [Self::RigidVar], but is also bound to 1+ abilities.
/// For example, "a has Hash".
RigidAbleVar(SubsIndex<Lowercase>, Symbol),
RigidAbleVar(SubsIndex<Lowercase>, SubsSlice<Symbol>),
/// name given to a recursion variable
RecursionVar {
structure: Variable,
@ -3706,7 +3724,7 @@ fn content_to_err_type(
ErrorType::RigidVar(name)
}
FlexAbleVar(opt_name, ability) => {
FlexAbleVar(opt_name, abilities) => {
let name = match opt_name {
Some(name_index) => subs.field_names[name_index.index as usize].clone(),
None => {
@ -3720,12 +3738,14 @@ fn content_to_err_type(
}
};
ErrorType::FlexAbleVar(name, ability)
// TODO(multi-abilities)
ErrorType::FlexAbleVar(name, subs.get_subs_slice(abilities)[0])
}
RigidAbleVar(name_index, ability) => {
RigidAbleVar(name_index, abilities) => {
let name = subs.field_names[name_index.index as usize].clone();
ErrorType::RigidAbleVar(name, ability)
// TODO(multi-abilities)
ErrorType::RigidAbleVar(name, subs.get_subs_slice(abilities)[0])
}
RecursionVar {

View file

@ -4,6 +4,7 @@ use crate::subs::{
GetSubsSlice, RecordFields, Subs, UnionTags, VarStore, Variable, VariableSubsSlice,
};
use roc_collections::all::{HumanIndex, ImMap, ImSet, MutMap, MutSet, SendMap};
use roc_collections::VecSet;
use roc_error_macros::internal_error;
use roc_module::called_via::CalledVia;
use roc_module::ident::{ForeignSymbol, Ident, Lowercase, TagName};
@ -247,7 +248,7 @@ pub struct AliasCommon {
#[derive(Clone, Debug)]
pub struct OptAbleVar {
pub var: Variable,
pub opt_abilities: Option<Vec<Symbol>>,
pub opt_abilities: Option<VecSet<Symbol>>,
}
impl OptAbleVar {
@ -262,7 +263,7 @@ impl OptAbleVar {
#[derive(PartialEq, Eq, Debug)]
pub struct OptAbleType {
pub typ: Type,
pub opt_abilities: Option<Vec<Symbol>>,
pub opt_abilities: Option<VecSet<Symbol>>,
}
impl OptAbleType {
@ -2112,7 +2113,8 @@ pub struct AliasVar {
pub name: Lowercase,
pub var: Variable,
/// `Some` if this variable is bound to abilities; `None` otherwise.
pub opt_bound_abilities: Option<Vec<Symbol>>,
/// INVARIANT: if abilities are present, they are sorted and de-duplicated.
pub opt_bound_abilities: Option<VecSet<Symbol>>,
}
impl AliasVar {

View file

@ -68,7 +68,7 @@ macro_rules! mismatch {
..Outcome::default()
}
}};
(%not_able, $var:expr, $ability:expr, $msg:expr, $($arg:tt)*) => {{
(%not_able, $var:expr, $abilities:expr, $msg:expr, $($arg:tt)*) => {{
dbg_do!(ROC_PRINT_MISMATCHES, {
eprintln!(
"Mismatch in {} Line {} Column {}",
@ -80,8 +80,14 @@ macro_rules! mismatch {
eprintln!("");
});
let mut mismatches = Vec::with_capacity(1 + $abilities.len());
mismatches.push(Mismatch::TypeMismatch);
for ability in $abilities {
mismatches.push(Mismatch::DoesNotImplementAbiity($var, *ability));
}
Outcome {
mismatches: vec![Mismatch::TypeMismatch, Mismatch::DoesNotImplementAbiity($var, $ability)],
mismatches,
..Outcome::default()
}
}}
@ -509,8 +515,8 @@ fn unify_context<M: MetaCollector>(env: &mut Env, pool: &mut Pool, ctx: Context)
#[allow(clippy::let_and_return)]
let result = match &ctx.first_desc.content {
FlexVar(opt_name) => unify_flex(env, &ctx, opt_name, &ctx.second_desc.content),
FlexAbleVar(opt_name, ability) => {
unify_flex_able(env, &ctx, opt_name, *ability, &ctx.second_desc.content)
FlexAbleVar(opt_name, abilities) => {
unify_flex_able(env, &ctx, opt_name, *abilities, &ctx.second_desc.content)
}
RecursionVar {
opt_name,
@ -524,8 +530,8 @@ fn unify_context<M: MetaCollector>(env: &mut Env, pool: &mut Pool, ctx: Context)
&ctx.second_desc.content,
),
RigidVar(name) => unify_rigid(env, &ctx, name, &ctx.second_desc.content),
RigidAbleVar(name, ability) => {
unify_rigid_able(env, &ctx, name, *ability, &ctx.second_desc.content)
RigidAbleVar(name, abilities) => {
unify_rigid_able(env, &ctx, name, *abilities, &ctx.second_desc.content)
}
Structure(flat_type) => {
unify_structure(env, pool, &ctx, flat_type, &ctx.second_desc.content)
@ -896,13 +902,13 @@ fn unify_opaque<M: MetaCollector>(
// Alias wins
merge(env, ctx, Alias(symbol, args, real_var, kind))
}
FlexAbleVar(_, ability) => {
FlexAbleVar(_, abilities) => {
// Opaque type wins
merge_flex_able_with_concrete(
env,
ctx,
ctx.second,
*ability,
*abilities,
Alias(symbol, args, real_var, kind),
opaque_obligation(symbol, ctx.first),
)
@ -956,13 +962,13 @@ fn unify_structure<M: MetaCollector>(
// If the other is flex, Structure wins!
merge(env, ctx, Structure(*flat_type))
}
FlexAbleVar(_, ability) => {
FlexAbleVar(_, abilities) => {
// Structure wins
merge_flex_able_with_concrete(
env,
ctx,
ctx.second,
*ability,
*abilities,
Structure(*flat_type),
Obligated::Adhoc(ctx.first),
)
@ -976,9 +982,9 @@ fn unify_structure<M: MetaCollector>(
_name
)
}
RigidAbleVar(_, _ability) => {
RigidAbleVar(_, _abilities) => {
mismatch!(
%not_able, ctx.first, *_ability,
%not_able, ctx.first, env.subs.get_subs_slice(*_abilities),
"trying to unify {:?} with RigidAble {:?}",
&flat_type,
&other
@ -2826,7 +2832,7 @@ fn unify_rigid<M: MetaCollector>(
// Mismatch - Rigid can unify with FlexAble only when the Rigid has an ability
// bound as well, otherwise the user failed to correctly annotate the bound.
mismatch!(
%not_able, ctx.first, *other_ability,
%not_able, ctx.first, env.subs.get_subs_slice(*other_ability),
"Rigid {:?} with FlexAble {:?}", ctx.first, other
)
}
@ -2859,27 +2865,34 @@ fn unify_rigid_able<M: MetaCollector>(
env: &mut Env,
ctx: &Context,
name: &SubsIndex<Lowercase>,
ability: Symbol,
abilities_slice: SubsSlice<Symbol>,
other: &Content,
) -> Outcome<M> {
match other {
FlexVar(_) => {
// If the other is flex, rigid wins!
merge(env, ctx, RigidAbleVar(*name, ability))
// TODO(multi-abilities)
merge(env, ctx, RigidAbleVar(*name, abilities_slice))
}
FlexAbleVar(_, other_ability) => {
if ability == *other_ability {
FlexAbleVar(_, other_abilities_slice) => {
let (abilities, other_abilities) = (
env.subs.get_subs_slice(abilities_slice),
env.subs.get_subs_slice(*other_abilities_slice),
);
// Invariant: abilities are inserted in sorted order.
if abilities == other_abilities {
// The ability bounds are the same, so rigid wins!
merge(env, ctx, RigidAbleVar(*name, ability))
merge(env, ctx, RigidAbleVar(*name, abilities_slice))
} else {
// Mismatch for now.
// TODO check ability hierarchies.
mismatch!(
%not_able, ctx.second, ability,
"RigidAble {:?} with ability {:?} not compatible with ability {:?}",
%not_able, ctx.second, abilities,
"RigidAble {:?} with abilities {:?} not compatible with abilities {:?}",
ctx.first,
ability,
other_ability
abilities,
other_abilities,
)
}
}
@ -2946,40 +2959,52 @@ fn unify_flex_able<M: MetaCollector>(
env: &mut Env,
ctx: &Context,
opt_name: &Option<SubsIndex<Lowercase>>,
ability: Symbol,
abilities_slice: SubsSlice<Symbol>,
other: &Content,
) -> Outcome<M> {
match other {
FlexVar(opt_other_name) => {
// Prefer using right's name.
let opt_name = (opt_other_name).or(*opt_name);
merge(env, ctx, FlexAbleVar(opt_name, ability))
merge(env, ctx, FlexAbleVar(opt_name, abilities_slice))
}
FlexAbleVar(opt_other_name, other_ability) => {
FlexAbleVar(opt_other_name, other_abilities_slice) => {
// Prefer the right's name when possible.
let opt_name = (opt_other_name).or(*opt_name);
if ability == *other_ability {
merge(env, ctx, FlexAbleVar(opt_name, ability))
let (abilities, other_abilities) = (
env.subs.get_subs_slice(abilities_slice),
env.subs.get_subs_slice(*other_abilities_slice),
);
// TODO: flex vars can inherit abilities from other flex vars they see
if abilities == other_abilities {
merge(env, ctx, FlexAbleVar(opt_name, abilities_slice))
} else {
// Ability names differ; mismatch for now.
// TODO check ability hierarchies.
mismatch!(
%not_able, ctx.second, ability,
"FlexAble {:?} with ability {:?} not compatible with ability {:?}",
%not_able, ctx.second, abilities,
"FlexAble {:?} with abilities {:?} not compatible with abilities {:?}",
ctx.first,
ability,
other_ability
abilities,
other_abilities
)
}
}
RigidAbleVar(_, other_ability) => {
if ability == *other_ability {
RigidAbleVar(_, other_abilities_slice) => {
let (abilities, other_abilities) = (
env.subs.get_subs_slice(abilities_slice),
env.subs.get_subs_slice(*other_abilities_slice),
);
// Invariant: abilities are inserted in sorted order.
if abilities == other_abilities {
merge(env, ctx, *other)
} else {
mismatch!(%not_able, ctx.second, ability, "RigidAble {:?} vs {:?}", ability, other_ability)
mismatch!(%not_able, ctx.second, abilities, "RigidAble {:?} vs {:?}", abilities, other_abilities)
}
}
@ -2992,7 +3017,7 @@ fn unify_flex_able<M: MetaCollector>(
env,
ctx,
ctx.first,
ability,
abilities_slice,
*other,
opaque_obligation(*name, ctx.second),
)
@ -3007,7 +3032,7 @@ fn unify_flex_able<M: MetaCollector>(
env,
ctx,
ctx.first,
ability,
abilities_slice,
*other,
Obligated::Adhoc(ctx.second),
)
@ -3022,16 +3047,19 @@ fn merge_flex_able_with_concrete<M: MetaCollector>(
env: &mut Env,
ctx: &Context,
flex_able_var: Variable,
ability: Symbol,
abilities: SubsSlice<Symbol>,
concrete_content: Content,
concrete_obligation: Obligated,
) -> Outcome<M> {
let mut outcome = merge(env, ctx, concrete_content);
let must_implement_ability = MustImplementAbility {
typ: concrete_obligation,
ability,
};
outcome.must_implement_ability.push(must_implement_ability);
for &ability in env.subs.get_subs_slice(abilities) {
let must_implement_ability = MustImplementAbility {
typ: concrete_obligation,
ability,
};
outcome.must_implement_ability.push(must_implement_ability);
}
// Figure which, if any, lambda sets should be specialized thanks to the flex able var
// being instantiated. Now as much as I would love to do that here, we don't, because we might