mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
The first ability... compiles
This commit is contained in:
parent
6b4294307f
commit
b79b351136
7 changed files with 104 additions and 12 deletions
|
@ -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, '_>,
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
7
compiler/test_mono/generated/specialize_ability_call.txt
Normal file
7
compiler/test_mono/generated/specialize_ability_call.txt
Normal 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;
|
|
@ -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() {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue