mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-20 15:27:45 +03:00
Check whether opaque implements ability using store
This commit is contained in:
parent
8659ddc684
commit
6b9c1cb690
@ -282,6 +282,25 @@ impl<Phase: ResolvePhase> IAbilitiesStore<Phase> {
|
||||
self.specialization_to_root.get(&specializing_symbol)
|
||||
}
|
||||
|
||||
/// Answers the question, "does an opaque type claim to implement a particular ability?"
|
||||
///
|
||||
/// Whether the given opaque typ faithfully implements or derives all members of the given ability
|
||||
/// without errors is not validated.
|
||||
///
|
||||
/// When the given ability is not known to the current store, this call will return `false`.
|
||||
pub fn has_declared_implementation(&self, opaque: Symbol, ability: Symbol) -> bool {
|
||||
// Idea: choose an ability member and check whether there is a declared implementation for it.
|
||||
// During canonicalization, we would have added either all members as declared
|
||||
// implementations, or none if the opaque doesn't implement the ability.
|
||||
match self.members_of_ability(ability) {
|
||||
Some(members) => self.declared_implementations.contains_key(&ImplKey {
|
||||
opaque,
|
||||
ability_member: members[0],
|
||||
}),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a store from [`self`] that closes over the abilities/members given by the
|
||||
/// imported `symbols`, and their specializations (if any).
|
||||
pub fn closure_from_imported(&self, symbols: &VecSet<Symbol>) -> PendingAbilitiesStore {
|
||||
|
@ -33,12 +33,8 @@ pub enum UnderivableReason {
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum Unfulfilled {
|
||||
/// Incomplete custom implementation for an ability by an opaque type.
|
||||
Incomplete {
|
||||
typ: Symbol,
|
||||
ability: Symbol,
|
||||
missing_members: Vec<Loc<Symbol>>,
|
||||
},
|
||||
/// No claimed implementation of an ability for an opaque type.
|
||||
OpaqueDoesNotImplement { typ: Symbol, ability: Symbol },
|
||||
/// Cannot derive implementation of an ability for a structural type.
|
||||
AdhocUnderivable {
|
||||
typ: ErrorType,
|
||||
@ -352,28 +348,14 @@ impl ObligationCache<'_> {
|
||||
}
|
||||
|
||||
let ImplKey { opaque, ability } = impl_key;
|
||||
let has_declared_impl = self
|
||||
.abilities_store
|
||||
.has_declared_implementation(opaque, ability);
|
||||
|
||||
let members_of_ability = self.abilities_store.members_of_ability(ability).unwrap();
|
||||
let mut missing_members = Vec::new();
|
||||
for &member in members_of_ability {
|
||||
if self
|
||||
.abilities_store
|
||||
.get_implementation(roc_can::abilities::ImplKey {
|
||||
opaque,
|
||||
ability_member: member,
|
||||
})
|
||||
.is_none()
|
||||
{
|
||||
let root_data = self.abilities_store.member_def(member).unwrap();
|
||||
missing_members.push(Loc::at(root_data.region, member));
|
||||
}
|
||||
}
|
||||
|
||||
let obligation_result = if !missing_members.is_empty() {
|
||||
Err(Unfulfilled::Incomplete {
|
||||
let obligation_result = if !has_declared_impl {
|
||||
Err(Unfulfilled::OpaqueDoesNotImplement {
|
||||
typ: opaque,
|
||||
ability,
|
||||
missing_members,
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
|
@ -259,30 +259,15 @@ fn report_unfulfilled_ability<'a>(
|
||||
unfulfilled: Unfulfilled,
|
||||
) -> RocDocBuilder<'a> {
|
||||
match unfulfilled {
|
||||
Unfulfilled::Incomplete {
|
||||
typ,
|
||||
ability,
|
||||
missing_members,
|
||||
} => {
|
||||
debug_assert!(!missing_members.is_empty());
|
||||
|
||||
let mut stack = vec![alloc.concat([
|
||||
Unfulfilled::OpaqueDoesNotImplement { typ, ability } => {
|
||||
let stack = vec![alloc.concat([
|
||||
alloc.reflow("The type "),
|
||||
alloc.symbol_unqualified(typ),
|
||||
alloc.reflow(" does not fully implement the ability "),
|
||||
alloc.symbol_unqualified(ability),
|
||||
alloc.reflow(". The following specializations are missing:"),
|
||||
alloc.reflow("."),
|
||||
])];
|
||||
|
||||
for member in missing_members.into_iter() {
|
||||
stack.push(alloc.concat([
|
||||
alloc.reflow("A specialization for "),
|
||||
alloc.symbol_unqualified(member.value),
|
||||
alloc.reflow(", which is defined here:"),
|
||||
]));
|
||||
stack.push(alloc.region(lines.convert_region(member.region)));
|
||||
}
|
||||
|
||||
alloc.stack(stack)
|
||||
}
|
||||
Unfulfilled::AdhocUnderivable {
|
||||
|
@ -8629,35 +8629,29 @@ All branches in an `if` must have the same type!
|
||||
}
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
@r###"
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
|
||||
15│ notYet: hash (A 1),
|
||||
^^^
|
||||
15│ notYet: hash (A 1),
|
||||
^^^
|
||||
|
||||
Roc can't generate an implementation of the `#UserApp.Hash` ability for
|
||||
Roc can't generate an implementation of the `#UserApp.Hash` ability for
|
||||
|
||||
[A (Num a)]b
|
||||
[A (Num a)]b
|
||||
|
||||
Only builtin abilities can have generated implementations!
|
||||
Only builtin abilities can have generated implementations!
|
||||
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
|
||||
14│ nope: hash (@User {}),
|
||||
^^^^^^^^
|
||||
14│ nope: hash (@User {}),
|
||||
^^^^^^^^
|
||||
|
||||
The type `User` does not fully implement the ability `Hash`. The following
|
||||
specializations are missing:
|
||||
|
||||
A specialization for `hash`, which is defined here:
|
||||
|
||||
4│ hash : a -> U64 | a has Hash
|
||||
^^^^
|
||||
"#
|
||||
The type `User` does not fully implement the ability `Hash`.
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
@ -9095,37 +9089,31 @@ All branches in an `if` must have the same type!
|
||||
// TODO: this error message is quite unfortunate. We should remove the duplication, and
|
||||
// also support regions that point to things in other modules. See also https://github.com/rtfeldman/roc/issues/3056.
|
||||
@r###"
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
This expression has a type that does not implement the abilities it's expected to:
|
||||
|
||||
4│ main = Encode.toEncoder { x: @A {} }
|
||||
^^^^^^^^^^^^
|
||||
4│ main = Encode.toEncoder { x: @A {} }
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Roc can't generate an implementation of the `Encode.Encoding` ability
|
||||
for
|
||||
Roc can't generate an implementation of the `Encode.Encoding` ability
|
||||
for
|
||||
|
||||
{ x : A }
|
||||
{ x : A }
|
||||
|
||||
In particular, an implementation for
|
||||
In particular, an implementation for
|
||||
|
||||
A
|
||||
A
|
||||
|
||||
cannot be generated.
|
||||
cannot be generated.
|
||||
|
||||
Tip: `A` does not implement `Encoding`. Consider adding a custom
|
||||
implementation or `has Encode.Encoding` to the definition of `A`.
|
||||
Tip: `A` does not implement `Encoding`. Consider adding a custom
|
||||
implementation or `has Encode.Encoding` to the definition of `A`.
|
||||
|
||||
── INCOMPLETE ABILITY IMPLEMENTATION ───────────────────── /code/proj/Main.roc ─
|
||||
── INCOMPLETE ABILITY IMPLEMENTATION ───────────────────── /code/proj/Main.roc ─
|
||||
|
||||
The type `A` does not fully implement the ability `Encoding`. The
|
||||
following specializations are missing:
|
||||
|
||||
A specialization for `toEncoder`, which is defined here:
|
||||
|
||||
5│
|
||||
^^^^^^^^^
|
||||
"###
|
||||
The type `A` does not fully implement the ability `Encoding`.
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
|
Loading…
Reference in New Issue
Block a user