mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-15 21:23:57 +00:00
Report duplicate implementations for ability members
This commit is contained in:
parent
7b9b855dcc
commit
e4af8af1a3
4 changed files with 74 additions and 19 deletions
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -150,6 +150,10 @@ pub enum Problem {
|
|||
AbilityImplNotIdent {
|
||||
region: Region,
|
||||
},
|
||||
DuplicateImpl {
|
||||
original: Region,
|
||||
duplicate: Region,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue