From 152cd6322655bb5173655cdf0781ca64c2a7602f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 10 Aug 2022 21:31:26 +0200 Subject: [PATCH] Report duplicate definitions in trait impls during resolution. --- .../rustc_hir_analysis/src/impl_wf_check.rs | 3 ++ compiler/rustc_resolve/src/diagnostics.rs | 13 ++++++ compiler/rustc_resolve/src/late.rs | 33 +++++++++++++-- compiler/rustc_resolve/src/lib.rs | 2 + .../associated-item-duplicate-names-3.rs | 1 + .../associated-item-duplicate-names-3.stderr | 18 +++++++-- .../associated-item-duplicate-names.stderr | 14 +++++-- src/test/ui/error-codes/E0201.stderr | 40 +++++++++++-------- src/test/ui/hygiene/impl_items-2.rs | 26 ++++++++++++ src/test/ui/hygiene/impl_items-2.stderr | 15 +++++++ src/test/ui/traits/issue-8153.stderr | 7 +++- 11 files changed, 142 insertions(+), 30 deletions(-) create mode 100644 src/test/ui/hygiene/impl_items-2.rs create mode 100644 src/test/ui/hygiene/impl_items-2.stderr diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index c499364056f..69155a422b0 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -197,6 +197,9 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol /// Enforce that we do not have two items in an impl with the same name. fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { + if tcx.impl_trait_ref(impl_def_id).is_some() { + return; + } let mut seen_type_items = FxHashMap::default(); let mut seen_value_items = FxHashMap::default(); for &impl_item_ref in tcx.associated_item_def_ids(impl_def_id) { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 98982240af2..75c016af2f9 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1047,6 +1047,19 @@ impl<'a> Resolver<'a> { err.span_label(trait_item_span, "item in trait"); err } + ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => { + let mut err = struct_span_err!( + self.session, + span, + E0201, + "duplicate definitions with name `{}`:", + name, + ); + err.span_label(old_span, "previous definition here"); + err.span_label(trait_item_span, "item in trait"); + err.span_label(span, "duplicate definition"); + err + } ResolutionError::InvalidAsmSym => { let mut err = self.session.struct_span_err(span, "invalid `sym` operand"); err.span_label(span, "is a local variable"); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 431507e8e0f..9fc8401fa07 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2619,8 +2619,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { this.with_current_self_type(self_type, |this| { this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| { debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); + let mut seen_trait_items = Default::default(); for item in impl_items { - this.resolve_impl_item(&**item); + this.resolve_impl_item(&**item, &mut seen_trait_items); } }); }); @@ -2634,7 +2635,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ); } - fn resolve_impl_item(&mut self, item: &'ast AssocItem) { + fn resolve_impl_item( + &mut self, + item: &'ast AssocItem, + seen_trait_items: &mut FxHashMap, + ) { use crate::ResolutionError::*; match &item.kind { AssocItemKind::Const(_, ty, default) => { @@ -2647,6 +2652,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &item.kind, ValueNS, item.span, + seen_trait_items, |i, s, c| ConstNotMemberOfTrait(i, s, c), ); @@ -2687,6 +2693,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &item.kind, ValueNS, item.span, + seen_trait_items, |i, s, c| MethodNotMemberOfTrait(i, s, c), ); @@ -2715,6 +2722,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { &item.kind, TypeNS, item.span, + seen_trait_items, |i, s, c| TypeNotMemberOfTrait(i, s, c), ); @@ -2736,6 +2744,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { kind: &AssocItemKind, ns: Namespace, span: Span, + seen_trait_items: &mut FxHashMap, err: F, ) where F: FnOnce(Ident, String, Option) -> ResolutionError<'a>, @@ -2768,7 +2777,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }; let res = binding.res(); - let Res::Def(def_kind, _) = res else { bug!() }; + let Res::Def(def_kind, id_in_trait) = res else { bug!() }; + + match seen_trait_items.entry(id_in_trait) { + Entry::Occupied(entry) => { + self.report_error( + span, + ResolutionError::TraitImplDuplicate { + name: ident.name, + old_span: *entry.get(), + trait_item_span: binding.span, + }, + ); + return; + } + Entry::Vacant(entry) => { + entry.insert(span); + } + }; + match (def_kind, kind) { (DefKind::AssocTy, AssocItemKind::TyAlias(..)) | (DefKind::AssocFn, AssocItemKind::Fn(..)) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9173c3692ce..4c9e14db3c4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -236,6 +236,8 @@ enum ResolutionError<'a> { trait_item_span: Span, code: rustc_errors::DiagnosticId, }, + /// Error E0201: multiple impl items for the same trait item. + TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span }, /// Inline asm `sym` operand must refer to a `fn` or `static`. InvalidAsmSym, } diff --git a/src/test/ui/associated-item/associated-item-duplicate-names-3.rs b/src/test/ui/associated-item/associated-item-duplicate-names-3.rs index 6aa1b483eeb..3a70a2f943f 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names-3.rs +++ b/src/test/ui/associated-item/associated-item-duplicate-names-3.rs @@ -16,4 +16,5 @@ impl Foo for Baz { fn main() { let x: Baz::Bar = 5; + //~^ ERROR ambiguous associated type } diff --git a/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr b/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr index 03782f66348..bf4bd634cf1 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-names-3.stderr @@ -1,11 +1,21 @@ error[E0201]: duplicate definitions with name `Bar`: --> $DIR/associated-item-duplicate-names-3.rs:14:5 | +LL | type Bar; + | --------- item in trait +... LL | type Bar = i16; - | -------- previous definition of `Bar` here + | --------------- previous definition here LL | type Bar = u16; - | ^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^ duplicate definition -error: aborting due to previous error +error[E0223]: ambiguous associated type + --> $DIR/associated-item-duplicate-names-3.rs:18:12 + | +LL | let x: Baz::Bar = 5; + | ^^^^^^^^ help: use fully-qualified syntax: `::Bar` -For more information about this error, try `rustc --explain E0201`. +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0201, E0223. +For more information about an error, try `rustc --explain E0201`. diff --git a/src/test/ui/associated-item/associated-item-duplicate-names.stderr b/src/test/ui/associated-item/associated-item-duplicate-names.stderr index c9119c10271..f89ea6e57cc 100644 --- a/src/test/ui/associated-item/associated-item-duplicate-names.stderr +++ b/src/test/ui/associated-item/associated-item-duplicate-names.stderr @@ -1,18 +1,24 @@ error[E0201]: duplicate definitions with name `Ty`: --> $DIR/associated-item-duplicate-names.rs:11:5 | +LL | type Ty; + | -------- item in trait +... LL | type Ty = (); - | ------- previous definition of `Ty` here + | ------------- previous definition here LL | type Ty = usize; - | ^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^^ duplicate definition error[E0201]: duplicate definitions with name `BAR`: --> $DIR/associated-item-duplicate-names.rs:13:5 | +LL | const BAR: u32; + | --------------- item in trait +... LL | const BAR: u32 = 7; - | -------------- previous definition of `BAR` here + | ------------------- previous definition here LL | const BAR: u32 = 8; - | ^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^^^^^ duplicate definition error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0201.stderr b/src/test/ui/error-codes/E0201.stderr index 94e06894144..f72145a8244 100644 --- a/src/test/ui/error-codes/E0201.stderr +++ b/src/test/ui/error-codes/E0201.stderr @@ -1,3 +1,26 @@ +error[E0201]: duplicate definitions with name `baz`: + --> $DIR/E0201.rs:17:5 + | +LL | fn baz(&self) -> bool; + | ---------------------- item in trait +... +LL | fn baz(&self) -> bool { true } + | ------------------------------ previous definition here +LL | fn baz(&self) -> bool { self.0 > 5 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition + +error[E0201]: duplicate definitions with name `Quux`: + --> $DIR/E0201.rs:18:5 + | +LL | type Quux; + | ---------- item in trait +... +LL | type Quux = u32; + | ---------------- previous definition here +... +LL | type Quux = u32; + | ^^^^^^^^^^^^^^^^ duplicate definition + error[E0201]: duplicate definitions with name `bar`: --> $DIR/E0201.rs:5:5 | @@ -6,23 +29,6 @@ LL | fn bar(&self) -> bool { self.0 > 5 } LL | fn bar() {} | ^^^^^^^^ duplicate definition -error[E0201]: duplicate definitions with name `baz`: - --> $DIR/E0201.rs:17:5 - | -LL | fn baz(&self) -> bool { true } - | --------------------- previous definition of `baz` here -LL | fn baz(&self) -> bool { self.0 > 5 } - | ^^^^^^^^^^^^^^^^^^^^^ duplicate definition - -error[E0201]: duplicate definitions with name `Quux`: - --> $DIR/E0201.rs:18:5 - | -LL | type Quux = u32; - | --------- previous definition of `Quux` here -... -LL | type Quux = u32; - | ^^^^^^^^^ duplicate definition - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0201`. diff --git a/src/test/ui/hygiene/impl_items-2.rs b/src/test/ui/hygiene/impl_items-2.rs new file mode 100644 index 00000000000..465e444aedb --- /dev/null +++ b/src/test/ui/hygiene/impl_items-2.rs @@ -0,0 +1,26 @@ +#![feature(decl_macro)] + +trait Trait { + fn foo() {} +} + +macro trait_impl() { + fn foo() {} +} + +// Check that we error on multiple impl items that resolve to the same trait item. +impl Trait for i32 { + trait_impl!(); + fn foo() {} + //~^ ERROR duplicate definitions with name `foo`: [E0201] +} + +struct Type; + +// Check that we do not error with inherent impls. +impl Type { + trait_impl!(); + fn foo() {} +} + +fn main() {} diff --git a/src/test/ui/hygiene/impl_items-2.stderr b/src/test/ui/hygiene/impl_items-2.stderr new file mode 100644 index 00000000000..3c0ffeb1057 --- /dev/null +++ b/src/test/ui/hygiene/impl_items-2.stderr @@ -0,0 +1,15 @@ +error[E0201]: duplicate definitions with name `foo`: + --> $DIR/impl_items-2.rs:14:5 + | +LL | fn foo() {} + | ----------- item in trait +... +LL | fn foo() {} + | ----------- previous definition here +... +LL | fn foo() {} + | ^^^^^^^^^^^ duplicate definition + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0201`. diff --git a/src/test/ui/traits/issue-8153.stderr b/src/test/ui/traits/issue-8153.stderr index b76bbc0235f..ae214bb9e9b 100644 --- a/src/test/ui/traits/issue-8153.stderr +++ b/src/test/ui/traits/issue-8153.stderr @@ -1,10 +1,13 @@ error[E0201]: duplicate definitions with name `bar`: --> $DIR/issue-8153.rs:11:5 | +LL | fn bar(&self) -> isize; + | ----------------------- item in trait +... LL | fn bar(&self) -> isize {1} - | ---------------------- previous definition of `bar` here + | -------------------------- previous definition here LL | fn bar(&self) -> isize {2} - | ^^^^^^^^^^^^^^^^^^^^^^ duplicate definition + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition error: aborting due to previous error