Skip to content

Commit 6be5db8

Browse files
authored
Rollup merge of rust-lang#100387 - cjgillot:hygiene-trait-impl, r=petrochenkov
Check uniqueness of impl items by trait item when applicable. When checking uniqueness of item names in impl blocks, we currently use the same definition of hygiene as for toplevel items. This means that a plain item and one generated by a macro 2.0 do not collide. This hygiene rule does not match with how impl items resolve to associated trait items. As a consequence, we misdiagnose the trait impls. This PR proposes to consider that trait impl items are uses of the corresponding trait items during resolution, instead of checking for duplicates later. An error is emitted when a trait impl item is used twice. There should be no stable breakage, since macros 2.0 are still unstable. r? `@petrochenkov` cc `@RalfJung` Fixes rust-lang#71614.
2 parents bb93450 + 152cd63 commit 6be5db8

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
@@ -1050,6 +1050,19 @@ impl<'a> Resolver<'a> {
10501050
err.span_label(trait_item_span, "item in trait");
10511051
err
10521052
}
1053+
ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => {
1054+
let mut err = struct_span_err!(
1055+
self.session,
1056+
span,
1057+
E0201,
1058+
"duplicate definitions with name `{}`:",
1059+
name,
1060+
);
1061+
err.span_label(old_span, "previous definition here");
1062+
err.span_label(trait_item_span, "item in trait");
1063+
err.span_label(span, "duplicate definition");
1064+
err
1065+
}
10531066
ResolutionError::InvalidAsmSym => {
10541067
let mut err = self.session.struct_span_err(span, "invalid `sym` operand");
10551068
err.span_label(span, "is a local variable");

compiler/rustc_resolve/src/late.rs

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

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

@@ -2686,6 +2692,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
26862692
&item.kind,
26872693
ValueNS,
26882694
item.span,
2695+
seen_trait_items,
26892696
|i, s, c| MethodNotMemberOfTrait(i, s, c),
26902697
);
26912698

@@ -2714,6 +2721,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
27142721
&item.kind,
27152722
TypeNS,
27162723
item.span,
2724+
seen_trait_items,
27172725
|i, s, c| TypeNotMemberOfTrait(i, s, c),
27182726
);
27192727

@@ -2735,6 +2743,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
27352743
kind: &AssocItemKind,
27362744
ns: Namespace,
27372745
span: Span,
2746+
seen_trait_items: &mut FxHashMap<DefId, Span>,
27382747
err: F,
27392748
) where
27402749
F: FnOnce(Ident, String, Option<Symbol>) -> ResolutionError<'a>,
@@ -2767,7 +2776,25 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
27672776
};
27682777

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

compiler/rustc_resolve/src/lib.rs

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

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)