Add an AbilityResolver trait for abilities stores and views

This commit is contained in:
Ayaz Hafiz 2022-07-27 12:54:13 -04:00
parent 6a4a3e2c60
commit b72c8705e5
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
5 changed files with 150 additions and 20 deletions

View file

@ -6,7 +6,7 @@ use roc_module::symbol::Symbol;
use roc_region::all::{Loc, Region};
use roc_solve_problem::{TypeError, UnderivableReason, Unfulfilled};
use roc_types::subs::{instantiate_rigids, Content, FlatType, GetSubsSlice, Rank, Subs, Variable};
use roc_types::types::{AliasKind, Category, PatternCategory};
use roc_types::types::{AliasKind, Category, MemberImpl, PatternCategory};
use roc_unify::unify::{Env, MustImplementConstraints};
use roc_unify::unify::{MustImplementAbility, Obligated};
@ -547,7 +547,7 @@ pub fn type_implementing_specialization(
}
/// Result of trying to resolve an ability specialization.
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
pub enum Resolved {
/// A user-defined specialization should be used.
Specialization(Symbol),
@ -555,24 +555,62 @@ pub enum Resolved {
NeedsGenerated,
}
pub fn resolve_ability_specialization(
/// An [`AbilityResolver`] is a shell of an abilities store that answers questions needed for
/// [resolving ability specializations][`resolve_ability_specialization`].
///
/// The trait is provided so you can implement your own resolver at other points in the compilation
/// process, for example during monomorphization we have module-re-entrant ability stores that are
/// not available during solving.
pub trait AbilityResolver {
/// Gets the parent ability and type of an ability member.
fn member_parent_and_signature_var(&self, ability_member: Symbol)
-> Option<(Symbol, Variable)>;
/// Finds the declared implementation of an [`ImplKey`][roc_can::abilities::ImplKey].
fn get_implementation(&self, impl_key: roc_can::abilities::ImplKey) -> Option<MemberImpl>;
}
/// Trivial implementation of a resolver for a module-local abilities store, that defers all
/// queries to the module store.
impl AbilityResolver for AbilitiesStore {
#[inline(always)]
fn member_parent_and_signature_var(
&self,
ability_member: Symbol,
) -> Option<(Symbol, Variable)> {
self.member_def(ability_member)
.map(|def| (def.parent_ability, def.signature_var()))
}
#[inline(always)]
fn get_implementation(&self, impl_key: roc_can::abilities::ImplKey) -> Option<MemberImpl> {
self.get_implementation(impl_key).copied()
}
}
pub fn resolve_ability_specialization<R: AbilityResolver>(
subs: &mut Subs,
abilities_store: &AbilitiesStore,
resolver: &R,
ability_member: Symbol,
specialization_var: Variable,
) -> Option<Resolved> {
use roc_unify::unify::{unify, Mode};
let member_def = abilities_store
.member_def(ability_member)
let (parent_ability, signature_var) = resolver
.member_parent_and_signature_var(ability_member)
.expect("Not an ability member symbol");
// Figure out the ability we're resolving in a temporary subs snapshot.
let snapshot = subs.snapshot();
let signature_var = member_def.signature_var();
instantiate_rigids(subs, signature_var);
dbg!((
roc_types::subs::SubsFmtContent(
subs.get_content_without_compacting(specialization_var),
subs
),
roc_types::subs::SubsFmtContent(subs.get_content_without_compacting(signature_var), subs)
));
let (_vars, must_implement_ability, _lambda_sets_to_specialize, _meta) = unify(
&mut Env::new(subs),
specialization_var,
@ -585,8 +623,11 @@ pub fn resolve_ability_specialization(
subs.rollback_to(snapshot);
let obligated =
type_implementing_specialization(&must_implement_ability, member_def.parent_ability)?;
dbg!((&must_implement_ability, parent_ability));
let obligated = type_implementing_specialization(&must_implement_ability, parent_ability)?;
dbg!(&obligated);
let resolved = match obligated {
Obligated::Opaque(symbol) => {
@ -595,9 +636,9 @@ pub fn resolve_ability_specialization(
ability_member,
};
match abilities_store.get_implementation(impl_key)? {
match resolver.get_implementation(impl_key)? {
roc_types::types::MemberImpl::Impl(spec_symbol) => {
Resolved::Specialization(*spec_symbol)
Resolved::Specialization(spec_symbol)
}
roc_types::types::MemberImpl::Derived => Resolved::NeedsGenerated,
// TODO this is not correct. We can replace `Resolved` with `MemberImpl` entirely,
@ -611,5 +652,5 @@ pub fn resolve_ability_specialization(
}
};
Some(resolved)
dbg!(Some(resolved))
}