Detect ability specializations that overload different opaque types

This commit is contained in:
Ayaz Hafiz 2022-07-25 11:35:20 -04:00
parent 51bce825fb
commit 10db3f8574
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
5 changed files with 70 additions and 2 deletions

View file

@ -279,6 +279,13 @@ impl<Phase: ResolvePhase> IAbilitiesStore<Phase> {
id
}
/// Finds the implementation key for a symbol specializing the ability member, if it specializes any.
/// For example, suppose `hashId : Id -> U64` specializes `hash : a -> U64 | a has Hash`.
/// Calling this with `hashId` would retrieve (hash, hashId).
pub fn impl_key(&self, specializing_symbol: Symbol) -> Option<&ImplKey> {
self.specialization_to_root.get(&specializing_symbol)
}
/// 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 {
@ -373,7 +380,7 @@ impl IAbilitiesStore<Resolved> {
&self,
specializing_symbol: Symbol,
) -> Option<(ImplKey, &AbilityMemberData<Resolved>)> {
let impl_key = self.specialization_to_root.get(&specializing_symbol)?;
let impl_key = self.impl_key(specializing_symbol)?;
debug_assert!(self.ability_members.contains_key(&impl_key.ability_member));
let root_data = self
.ability_members

View file

@ -1,4 +1,5 @@
use crate::abilities::AbilityMemberData;
use crate::abilities::ImplKey;
use crate::abilities::MemberVariables;
use crate::abilities::PendingMemberType;
use crate::annotation::canonicalize_annotation;
@ -671,8 +672,30 @@ fn canonicalize_opaque<'a>(
Err(()) => continue,
};
let member_impl = MemberImpl::Impl(impl_symbol);
// Did the user claim this implementation for a specialization of a different
// type? e.g.
//
// A has [Hash {hash: myHash}]
// B has [Hash {hash: myHash}]
//
// If so, that's an error and we drop the impl for this opaque type.
let member_impl = match scope.abilities_store.impl_key(impl_symbol) {
Some(ImplKey {
opaque,
ability_member,
}) => {
env.problem(Problem::OverloadedSpecialization {
overload: loc_impl.region,
original_opaque: *opaque,
ability_member: *ability_member,
});
MemberImpl::Error
}
None => MemberImpl::Impl(impl_symbol),
};
// Did the user already claim an implementation for the ability member for this
// type previously? (e.g. Hash {hash: hash1, hash: hash2})
let opt_old_impl_symbol =
impl_map.insert(member, Loc::at(loc_impl.region, member_impl));