Report duplicate implementations for ability members

This commit is contained in:
Ayaz Hafiz 2022-07-19 12:05:54 -04:00
parent 7b9b855dcc
commit e4af8af1a3
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
4 changed files with 74 additions and 19 deletions

View file

@ -451,14 +451,7 @@ fn canonicalize_claimed_ability_impl<'a>(
};
match scope.lookup_ability_member_shadow(member_symbol) {
Some(impl_symbol) => {
// TODO: get rid of register_specializing_symbol
scope
.abilities_store
.register_specializing_symbol(impl_symbol, member_symbol);
Ok((member_symbol, impl_symbol))
}
Some(impl_symbol) => Ok((member_symbol, impl_symbol)),
None => {
env.problem(Problem::ImplementationNotFound {
member: member_symbol,
@ -514,11 +507,6 @@ fn canonicalize_claimed_ability_impl<'a>(
}
};
// TODO: get rid of register_specializing_symbol
scope
.abilities_store
.register_specializing_symbol(impl_symbol, member_symbol);
Ok((member_symbol, impl_symbol))
}
AssignedField::OptionalValue(_, _, _) => {
@ -596,20 +584,37 @@ fn canonicalize_opaque<'a>(
};
if let Some(impls) = opt_impls {
let mut impl_map: VecMap<Symbol, Symbol> = VecMap::default();
let mut impl_map: VecMap<Symbol, Loc<Symbol>> = VecMap::default();
for loc_impl in impls.extract_spaces().item.items {
match canonicalize_claimed_ability_impl(env, scope, ability, loc_impl) {
Ok((member, opaque_impl)) => {
impl_map.insert(member, opaque_impl);
let (member, impl_symbol) =
match canonicalize_claimed_ability_impl(env, scope, ability, loc_impl) {
Ok((member, impl_symbol)) => (member, impl_symbol),
Err(()) => continue,
};
match impl_map.insert(member, Loc::at(loc_impl.region, impl_symbol)) {
None => {
// TODO: get rid of register_specializing_symbol
scope
.abilities_store
.register_specializing_symbol(impl_symbol, member);
}
Some(old_impl_symbol) => {
env.problem(Problem::DuplicateImpl {
original: old_impl_symbol.region,
duplicate: loc_impl.region,
});
}
Err(()) => continue,
}
}
supported_abilities.push(OpaqueSupports::Implemented {
ability_name: ability,
impls: impl_map,
impls: impl_map
.into_iter()
.map(|(member, def)| (member, def.value))
.collect(),
});
} else if ability.is_builtin_ability() {
derived_abilities.push(Loc::at(region, ability));

View file

@ -150,6 +150,10 @@ pub enum Problem {
AbilityImplNotIdent {
region: Region,
},
DuplicateImpl {
original: Region,
duplicate: Region,
},
}
#[derive(Clone, Debug, PartialEq)]

View file

@ -53,6 +53,7 @@ const NOT_AN_ABILITY_MEMBER: &str = "NOT AN ABILITY MEMBER";
const OPTIONAL_ABILITY_IMPLEMENTATION: &str = "OPTIONAL ABILITY IMPLEMENTATION";
const QUALIFIED_ABILITY_IMPLEMENTATION: &str = "QUALIFIED ABILITY IMPLEMENTATION";
const ABILITY_IMPLEMENTATION_NOT_IDENTIFIER: &str = "ABILITY IMPLEMENTATION NOT IDENTIFIER";
const DUPLICATE_IMPLEMENTATION: &str = "DUPLICATE IMPLEMENTATION";
pub fn can_problem<'b>(
alloc: &'b RocDocAllocator<'b>,
@ -824,6 +825,21 @@ pub fn can_problem<'b>(
title = ABILITY_IMPLEMENTATION_NOT_IDENTIFIER.to_string();
severity = Severity::RuntimeError;
}
Problem::DuplicateImpl {
original,
duplicate,
} => {
doc = alloc.stack([
alloc.reflow("This ability member implementation is duplicate:"),
alloc.region(lines.convert_region(duplicate)),
alloc.reflow("The first implementation was defined here:"),
alloc.region(lines.convert_region(original)),
alloc
.reflow("Only one custom implementation can be defined for an ability member."),
]);
title = DUPLICATE_IMPLEMENTATION.to_string();
severity = Severity::RuntimeError;
}
};
Report {

View file

@ -9314,6 +9314,36 @@ All branches in an `if` must have the same type!
"###
);
test_report!(
opaque_ability_impl_duplicate,
indoc!(
r#"
app "test" provides [A] to "./platform"
Eq has eq : a, a -> Bool | a has Eq
A := U8 has [ Eq {eq: eqA, eq: eqA} ]
eqA = \@A m, @A n -> m == n
"#
),
@r###"
DUPLICATE IMPLEMENTATION /code/proj/Main.roc
This ability member implementation is duplicate:
5 A := U8 has [ Eq {eq: eqA, eq: eqA} ]
^^^^^^^
The first implementation was defined here:
5 A := U8 has [ Eq {eq: eqA, eq: eqA} ]
^^^^^^^
Only one custom implementation can be defined for an ability member.
"###
);
test_report!(
derive_non_builtin_ability,
indoc!(