The first ability... compiles

This commit is contained in:
Ayaz Hafiz 2022-04-14 16:50:41 -04:00
parent 6b4294307f
commit b79b351136
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
7 changed files with 104 additions and 12 deletions

View file

@ -4220,10 +4220,14 @@ pub fn with_hole<'a>(
// a proc in this module, or an imported symbol // a proc in this module, or an imported symbol
procs.partial_procs.contains_key(key) procs.partial_procs.contains_key(key)
|| (env.is_imported_symbol(key) && !procs.is_imported_module_thunk(key)) || (env.is_imported_symbol(key) && !procs.is_imported_module_thunk(key))
|| env.abilities_store.is_ability_member_name(key)
}; };
match loc_expr.value { match loc_expr.value {
roc_can::expr::Expr::Var(proc_name) if is_known(proc_name) => { roc_can::expr::Expr::Var(proc_name) if is_known(proc_name) => {
// This might be an ability member - if so, use the appropriate specialization.
let proc_name = repoint_to_specialization(env, fn_var, proc_name);
// a call by a known name // a call by a known name
call_by_name( call_by_name(
env, env,
@ -4707,6 +4711,43 @@ pub fn with_hole<'a>(
} }
} }
#[inline(always)]
fn repoint_to_specialization<'a>(
env: &mut Env<'a, '_>,
symbol_var: Variable,
symbol: Symbol,
) -> Symbol {
use roc_solve::ability::type_implementing_member;
use roc_unify::unify::unify;
match env.abilities_store.member_def(symbol) {
None => {
// This is not an ability member, it doesn't need specialization.
symbol
}
Some(member) => {
let snapshot = env.subs.snapshot();
let (_, must_implement_ability) = unify(
env.subs,
symbol_var,
member.signature_var,
roc_unify::unify::Mode::EQ,
)
.expect_success("This typechecked previously");
env.subs.rollback_to(snapshot);
let specializing_type =
type_implementing_member(&must_implement_ability, member.parent_ability);
let specialization = env
.abilities_store
.get_specialization(symbol, specializing_type)
.expect("No specialization is recorded - I thought there would only be a type error here.");
specialization.symbol
}
}
}
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn construct_closure_data<'a>( fn construct_closure_data<'a>(
env: &mut Env<'a, '_>, env: &mut Env<'a, '_>,

View file

@ -1,4 +1,5 @@
use roc_can::abilities::AbilitiesStore; use roc_can::abilities::AbilitiesStore;
use roc_module::symbol::Symbol;
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
use roc_types::subs::Subs; use roc_types::subs::Subs;
use roc_types::subs::Variable; use roc_types::subs::Variable;
@ -154,3 +155,23 @@ impl DeferredMustImplementAbility {
problems problems
} }
} }
/// Determines what type implements an ability member of a specialized signature, given the
/// [MustImplementAbility] constraints of the signature.
pub fn type_implementing_member(
specialization_must_implement_constraints: &[MustImplementAbility],
ability: Symbol,
) -> Symbol {
let mut ability_implementations_for_specialization = specialization_must_implement_constraints
.iter()
.filter(|mia| mia.ability == ability)
.collect::<Vec<_>>();
ability_implementations_for_specialization.dedup();
debug_assert!(ability_implementations_for_specialization.len() == 1, "Multiple variables bound to an ability - this is ambiguous and should have been caught in canonicalization");
ability_implementations_for_specialization
.pop()
.unwrap()
.typ
}

View file

@ -2,6 +2,6 @@
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check. // See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
#![allow(clippy::large_enum_variant)] #![allow(clippy::large_enum_variant)]
mod ability; pub mod ability;
pub mod module; pub mod module;
pub mod solve; pub mod solve;

View file

@ -1,4 +1,4 @@
use crate::ability::{AbilityImplError, DeferredMustImplementAbility}; use crate::ability::{type_implementing_member, AbilityImplError, DeferredMustImplementAbility};
use bumpalo::Bump; use bumpalo::Bump;
use roc_can::abilities::{AbilitiesStore, MemberSpecialization}; use roc_can::abilities::{AbilitiesStore, MemberSpecialization};
use roc_can::constraint::Constraint::{self, *}; use roc_can::constraint::Constraint::{self, *};
@ -1346,16 +1346,8 @@ fn check_ability_specialization(
// First, figure out and register for what type does this symbol specialize // First, figure out and register for what type does this symbol specialize
// the ability member. // the ability member.
let mut ability_implementations_for_specialization = must_implement_ability let specialization_type =
.iter() type_implementing_member(&must_implement_ability, root_data.parent_ability);
.filter(|mia| mia.ability == root_data.parent_ability)
.collect::<Vec<_>>();
ability_implementations_for_specialization.dedup();
debug_assert!(ability_implementations_for_specialization.len() == 1, "Multiple variables bound to an ability - this is ambiguous and should have been caught in canonicalization");
// This is a valid specialization! Record it.
let specialization_type = ability_implementations_for_specialization[0].typ;
let specialization = MemberSpecialization { let specialization = MemberSpecialization {
symbol, symbol,
region: symbol_loc_var.region, region: symbol_loc_var.region,

View file

@ -0,0 +1,7 @@
procedure Test.5 (Test.8):
ret Test.8;
procedure Test.0 ():
let Test.10 : U64 = 1234i64;
let Test.9 : U64 = CallByName Test.5 Test.10;
ret Test.9;

View file

@ -1294,6 +1294,25 @@ fn issue_2811() {
) )
} }
#[mono_test]
fn specialize_ability_call() {
indoc!(
r#"
app "test" provides [ main ] to "./platform"
Hash has
hash : a -> U64 | a has Hash
Id := U64
hash : Id -> U64
hash = \$Id n -> n
main = hash ($Id 1234)
"#
)
}
// #[ignore] // #[ignore]
// #[mono_test] // #[mono_test]
// fn static_str_closure() { // fn static_str_closure() {

View file

@ -140,6 +140,18 @@ pub enum Unified {
BadType(Pool, roc_types::types::Problem), BadType(Pool, roc_types::types::Problem),
} }
impl Unified {
pub fn expect_success(self, err_msg: &'static str) -> (Pool, Vec<MustImplementAbility>) {
match self {
Unified::Success {
vars,
must_implement_ability,
} => (vars, must_implement_ability),
_ => panic!("{}", err_msg),
}
}
}
/// Specifies that `type` must implement the ability `ability`. /// Specifies that `type` must implement the ability `ability`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MustImplementAbility { pub struct MustImplementAbility {