Skip to content

Commit 152cd63

Browse files
committed
Report duplicate definitions in trait impls during resolution.
1 parent 8796e7a commit 152cd63

File tree

11 files changed

+137
-25
lines changed

11 files changed

+137
-25
lines changed

compiler/rustc_hir_analysis/src/impl_wf_check.rs

+3
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol
197197

198198
/// Enforce that we do not have two items in an impl with the same name.
199199
fn enforce_impl_items_are_distinct(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
200+
if tcx.impl_trait_ref(impl_def_id).is_some() {
201+
return;
202+
}
200203
let mut seen_type_items = FxHashMap::default();
201204
let mut seen_value_items = FxHashMap::default();
202205
for &impl_item_ref in tcx.associated_item_def_ids(impl_def_id) {

compiler/rustc_resolve/src/diagnostics.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,19 @@ impl<'a> Resolver<'a> {
10471047
err.span_label(trait_item_span, "item in trait");
10481048
err
10491049
}
1050+
ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => {
1051+
let mut err = struct_span_err!(
1052+
self.session,
1053+
span,
1054+
E0201,
1055+
"duplicate definitions with name `{}`:",
1056+
name,
1057+
);
1058+
err.span_label(old_span, "previous definition here");
1059+
err.span_label(trait_item_span, "item in trait");
1060+
err.span_label(span, "duplicate definition");
1061+
err
1062+
}
10501063
ResolutionError::InvalidAsmSym => {
10511064
let mut err = self.session.struct_span_err(span, "invalid `sym` operand");
10521065
err.span_label(span, "is a local variable");

compiler/rustc_resolve/src/late.rs

+30-3
Original file line numberDiff line numberDiff line change
@@ -2619,8 +2619,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
26192619
this.with_current_self_type(self_type, |this| {
26202620
this.with_self_rib_ns(ValueNS, Res::SelfCtor(item_def_id), |this| {
26212621
debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)");
2622+
let mut seen_trait_items = Default::default();
26222623
for item in impl_items {
2623-
this.resolve_impl_item(&**item);
2624+
this.resolve_impl_item(&**item, &mut seen_trait_items);
26242625
}
26252626
});
26262627
});
@@ -2634,7 +2635,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
26342635
);
26352636
}
26362637

2637-
fn resolve_impl_item(&mut self, item: &'ast AssocItem) {
2638+
fn resolve_impl_item(
2639+
&mut self,
2640+
item: &'ast AssocItem,
2641+
seen_trait_items: &mut FxHashMap<DefId, Span>,
2642+
) {
26382643
use crate::ResolutionError::*;
26392644
match &item.kind {
26402645
AssocItemKind::Const(_, ty, default) => {
@@ -2647,6 +2652,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
26472652
&item.kind,
26482653
ValueNS,
26492654
item.span,
2655+
seen_trait_items,
26502656
|i, s, c| ConstNotMemberOfTrait(i, s, c),
26512657
);
26522658

@@ -2687,6 +2693,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
26872693
&item.kind,
26882694
ValueNS,
26892695
item.span,
2696+
seen_trait_items,
26902697
|i, s, c| MethodNotMemberOfTrait(i, s, c),
26912698
);
26922699

@@ -2715,6 +2722,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
27152722
&item.kind,
27162723
TypeNS,
27172724
item.span,
2725+
seen_trait_items,
27182726
|i, s, c| TypeNotMemberOfTrait(i, s, c),
27192727
);
27202728

@@ -2736,6 +2744,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
27362744
kind: &AssocItemKind,
27372745
ns: Namespace,
27382746
span: Span,
2747+
seen_trait_items: &mut FxHashMap<DefId, Span>,
27392748
err: F,
27402749
) where
27412750
F: FnOnce(Ident, String, Option<Symbol>) -> ResolutionError<'a>,
@@ -2768,7 +2777,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
27682777
};
27692778

27702779
let res = binding.res();
2771-
let Res::Def(def_kind, _) = res else { bug!() };
2780+
let Res::Def(def_kind, id_in_trait) = res else { bug!() };
2781+
2782+
match seen_trait_items.entry(id_in_trait) {
2783+
Entry::Occupied(entry) => {
2784+
self.report_error(
2785+
span,
2786+
ResolutionError::TraitImplDuplicate {
2787+
name: ident.name,
2788+
old_span: *entry.get(),
2789+
trait_item_span: binding.span,
2790+
},
2791+
);
2792+
return;
2793+
}
2794+
Entry::Vacant(entry) => {
2795+
entry.insert(span);
2796+
}
2797+
};
2798+
27722799
match (def_kind, kind) {
27732800
(DefKind::AssocTy, AssocItemKind::TyAlias(..))
27742801
| (DefKind::AssocFn, AssocItemKind::Fn(..))

compiler/rustc_resolve/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ enum ResolutionError<'a> {
236236
trait_item_span: Span,
237237
code: rustc_errors::DiagnosticId,
238238
},
239+
/// Error E0201: multiple impl items for the same trait item.
240+
TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span },
239241
/// Inline asm `sym` operand must refer to a `fn` or `static`.
240242
InvalidAsmSym,
241243
}

src/test/ui/associated-item/associated-item-duplicate-names-3.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ impl Foo for Baz {
1616

1717
fn main() {
1818
let x: Baz::Bar = 5;
19+
//~^ ERROR ambiguous associated type
1920
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
error[E0201]: duplicate definitions with name `Bar`:
22
--> $DIR/associated-item-duplicate-names-3.rs:14:5
33
|
4+
LL | type Bar;
5+
| --------- item in trait
6+
...
47
LL | type Bar = i16;
5-
| -------- previous definition of `Bar` here
8+
| --------------- previous definition here
69
LL | type Bar = u16;
7-
| ^^^^^^^^ duplicate definition
10+
| ^^^^^^^^^^^^^^^ duplicate definition
811

9-
error: aborting due to previous error
12+
error[E0223]: ambiguous associated type
13+
--> $DIR/associated-item-duplicate-names-3.rs:18:12
14+
|
15+
LL | let x: Baz::Bar = 5;
16+
| ^^^^^^^^ help: use fully-qualified syntax: `<Baz as Trait>::Bar`
17+
18+
error: aborting due to 2 previous errors
1019

11-
For more information about this error, try `rustc --explain E0201`.
20+
Some errors have detailed explanations: E0201, E0223.
21+
For more information about an error, try `rustc --explain E0201`.

src/test/ui/associated-item/associated-item-duplicate-names.stderr

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
error[E0201]: duplicate definitions with name `Ty`:
22
--> $DIR/associated-item-duplicate-names.rs:11:5
33
|
4+
LL | type Ty;
5+
| -------- item in trait
6+
...
47
LL | type Ty = ();
5-
| ------- previous definition of `Ty` here
8+
| ------------- previous definition here
69
LL | type Ty = usize;
7-
| ^^^^^^^ duplicate definition
10+
| ^^^^^^^^^^^^^^^^ duplicate definition
811

912
error[E0201]: duplicate definitions with name `BAR`:
1013
--> $DIR/associated-item-duplicate-names.rs:13:5
1114
|
15+
LL | const BAR: u32;
16+
| --------------- item in trait
17+
...
1218
LL | const BAR: u32 = 7;
13-
| -------------- previous definition of `BAR` here
19+
| ------------------- previous definition here
1420
LL | const BAR: u32 = 8;
15-
| ^^^^^^^^^^^^^^ duplicate definition
21+
| ^^^^^^^^^^^^^^^^^^^ duplicate definition
1622

1723
error: aborting due to 2 previous errors
1824

src/test/ui/error-codes/E0201.stderr

+18-12
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,33 @@
1-
error[E0201]: duplicate definitions with name `bar`:
2-
--> $DIR/E0201.rs:5:5
3-
|
4-
LL | fn bar(&self) -> bool { self.0 > 5 }
5-
| --------------------- previous definition of `bar` here
6-
LL | fn bar() {}
7-
| ^^^^^^^^ duplicate definition
8-
91
error[E0201]: duplicate definitions with name `baz`:
102
--> $DIR/E0201.rs:17:5
113
|
4+
LL | fn baz(&self) -> bool;
5+
| ---------------------- item in trait
6+
...
127
LL | fn baz(&self) -> bool { true }
13-
| --------------------- previous definition of `baz` here
8+
| ------------------------------ previous definition here
149
LL | fn baz(&self) -> bool { self.0 > 5 }
15-
| ^^^^^^^^^^^^^^^^^^^^^ duplicate definition
10+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
1611

1712
error[E0201]: duplicate definitions with name `Quux`:
1813
--> $DIR/E0201.rs:18:5
1914
|
15+
LL | type Quux;
16+
| ---------- item in trait
17+
...
2018
LL | type Quux = u32;
21-
| --------- previous definition of `Quux` here
19+
| ---------------- previous definition here
2220
...
2321
LL | type Quux = u32;
24-
| ^^^^^^^^^ duplicate definition
22+
| ^^^^^^^^^^^^^^^^ duplicate definition
23+
24+
error[E0201]: duplicate definitions with name `bar`:
25+
--> $DIR/E0201.rs:5:5
26+
|
27+
LL | fn bar(&self) -> bool { self.0 > 5 }
28+
| --------------------- previous definition of `bar` here
29+
LL | fn bar() {}
30+
| ^^^^^^^^ duplicate definition
2531

2632
error: aborting due to 3 previous errors
2733

src/test/ui/hygiene/impl_items-2.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#![feature(decl_macro)]
2+
3+
trait Trait {
4+
fn foo() {}
5+
}
6+
7+
macro trait_impl() {
8+
fn foo() {}
9+
}
10+
11+
// Check that we error on multiple impl items that resolve to the same trait item.
12+
impl Trait for i32 {
13+
trait_impl!();
14+
fn foo() {}
15+
//~^ ERROR duplicate definitions with name `foo`: [E0201]
16+
}
17+
18+
struct Type;
19+
20+
// Check that we do not error with inherent impls.
21+
impl Type {
22+
trait_impl!();
23+
fn foo() {}
24+
}
25+
26+
fn main() {}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0201]: duplicate definitions with name `foo`:
2+
--> $DIR/impl_items-2.rs:14:5
3+
|
4+
LL | fn foo() {}
5+
| ----------- item in trait
6+
...
7+
LL | fn foo() {}
8+
| ----------- previous definition here
9+
...
10+
LL | fn foo() {}
11+
| ^^^^^^^^^^^ duplicate definition
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0201`.

src/test/ui/traits/issue-8153.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
error[E0201]: duplicate definitions with name `bar`:
22
--> $DIR/issue-8153.rs:11:5
33
|
4+
LL | fn bar(&self) -> isize;
5+
| ----------------------- item in trait
6+
...
47
LL | fn bar(&self) -> isize {1}
5-
| ---------------------- previous definition of `bar` here
8+
| -------------------------- previous definition here
69
LL | fn bar(&self) -> isize {2}
7-
| ^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
10+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition
811

912
error: aborting due to previous error
1013

0 commit comments

Comments
 (0)