Skip to content

Commit

Permalink
Improved error message when implementing duplicate impls for aliased …
Browse files Browse the repository at this point in the history
…types
  • Loading branch information
jjcnn committed Feb 24, 2025
1 parent bdfea6d commit 7e268f7
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 13 deletions.
15 changes: 8 additions & 7 deletions sway-core/src/semantic_analysis/namespace/trait_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl TraitMap {
is_extending_existing_impl: IsExtendingExistingImpl,
engines: &Engines,
) -> Result<(), ErrorEmitted> {
let type_id = engines.te().get_unaliased_type_id(type_id);
let unaliased_type_id = engines.te().get_unaliased_type_id(type_id);

handler.scope(|handler| {
let mut trait_items: TraitItems = HashMap::new();
Expand Down Expand Up @@ -267,7 +267,7 @@ impl TraitMap {
}
}

let trait_impls = self.get_impls_mut(engines, type_id);
let trait_impls = self.get_impls_mut(engines, unaliased_type_id);

// check to see if adding this trait will produce a conflicting definition
for TraitEntry {
Expand Down Expand Up @@ -295,11 +295,11 @@ impl TraitMap {

let unify_checker = UnifyCheck::non_generic_constraint_subset(engines);

// Types are subset if the `type_id` that we want to insert can unify with the
// Types are subset if the `unaliased_type_id` that we want to insert can unify with the
// existing `map_type_id`. In addition we need to additionally check for the case of
// `&mut <type>` and `&<type>`.
let types_are_subset = unify_checker.check(type_id, *map_type_id)
&& is_unified_type_subset(engines.te(), type_id, *map_type_id);
let types_are_subset = unify_checker.check(unaliased_type_id, *map_type_id)
&& is_unified_type_subset(engines.te(), unaliased_type_id, *map_type_id);

/// `left` can unify into `right`. Additionally we need to check subset condition in case of
/// [TypeInfo::Ref] types. Although `&mut <type>` can unify with `&<type>`
Expand Down Expand Up @@ -367,7 +367,8 @@ impl TraitMap {
{
handler.emit_err(CompileError::ConflictingImplsForTraitAndType {
trait_name: trait_name.to_string_with_args(engines, &trait_type_args),
type_implementing_for: engines.help_out(type_id).to_string(),
type_implementing_for: engines.help_out(unaliased_type_id).to_string(),
type_implementing_for_alias: engines.help_out(type_id).to_string(),
existing_impl_span: existing_impl_span.clone(),
second_impl_span: impl_span.clone(),
});
Expand Down Expand Up @@ -442,7 +443,7 @@ impl TraitMap {
trait_name,
impl_span.clone(),
trait_decl_span,
type_id,
unaliased_type_id,
trait_items,
engines,
);
Expand Down
23 changes: 17 additions & 6 deletions sway-error/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,10 +621,11 @@ pub enum CompileError {
},
#[error("An ABI can only be implemented for the `Contract` type, so this implementation of an ABI for type \"{ty}\" is invalid.")]
ImplAbiForNonContract { span: Span, ty: String },
#[error("Conflicting implementations of trait \"{trait_name}\" for type \"{type_implementing_for}\".")]
#[error("Conflicting implementations of trait \"{trait_name}\" for type \"{type_implementing_for_alias}\".")]
ConflictingImplsForTraitAndType {
trait_name: String,
type_implementing_for: String,
type_implementing_for_alias: String,
existing_impl_span: Span,
second_impl_span: Span,
},
Expand Down Expand Up @@ -2317,20 +2318,30 @@ impl ToDiagnostic for CompileError {
format!("{}- referencing a mutable copy of \"{decl_name}\", by returning it from a block: `&mut {{ {decl_name} }}`.", Indent::Single)
],
},
ConflictingImplsForTraitAndType { trait_name, type_implementing_for, existing_impl_span, second_impl_span } => Diagnostic {
ConflictingImplsForTraitAndType { trait_name, type_implementing_for, type_implementing_for_alias, existing_impl_span, second_impl_span } => Diagnostic {
reason: Some(Reason::new(code(1), "Trait is already implemented for type".to_string())),
issue: Issue::error(
source_engine,
second_impl_span.clone(),
format!("Trait \"{trait_name}\" is already implemented for type \"{type_implementing_for}\".")
if type_implementing_for == type_implementing_for_alias {
format!("Trait \"{trait_name}\" is already implemented for type \"{type_implementing_for}\".")
} else {
format!("Trait \"{trait_name}\" is already implemented for type \"{type_implementing_for_alias}\", possibly using an alias (the unaliased type name is \"{type_implementing_for}\").")
}
),
hints: vec![
Hint::info(
source_engine,
existing_impl_span.clone(),
format!("This is the already existing implementation of \"{}\" for \"{type_implementing_for}\".",
call_path_suffix_with_args(trait_name)
)
if type_implementing_for == type_implementing_for_alias {
format!("This is the already existing implementation of \"{}\" for \"{type_implementing_for}\".",
call_path_suffix_with_args(trait_name)
)
} else {
format!("This is the already existing implementation of \"{}\" for \"{type_implementing_for_alias}\", possibly using an alias (the unaliased type name is \"{type_implementing_for}\").",
call_path_suffix_with_args(trait_name)
)
}
),
],
help: vec![
Expand Down

0 comments on commit 7e268f7

Please sign in to comment.