diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index a65f9b347dc6d..2fb3c5ff945af 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -195,12 +195,39 @@ fn associated_types_for_impl_traits_in_associated_fn( match tcx.def_kind(parent_def_id) { DefKind::Trait => { if let Some(output) = tcx.hir_get_fn_output(fn_def_id) { - let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id())); + let def_path_id = |def_id: LocalDefId| tcx.item_name(def_id.to_def_id()); + let def_path_data = def_path_id(fn_def_id); + + let (.., trait_item_refs) = tcx.hir_expect_item(parent_def_id).expect_trait(); + // The purpose of `disambiguator_idx` is to ensure there are + // no duplicate `def_id` in certain cases, such as: + // ``` + // trait Foo { + // fn bar() -> impl Trait; + // fn bar() -> impl Trait; + // // ~~~~~~~~~~ It will generate the same ID if we don’t disambiguate it. + // } + // ``` + let disambiguator_idx = trait_item_refs + .iter() + .take_while(|item| item.id.owner_id.def_id != fn_def_id) + .fold(0, |acc, item| { + if !matches!(item.kind, hir::AssocItemKind::Fn { .. }) { + acc + } else if def_path_id(item.id.owner_id.def_id) == def_path_data { + tcx.def_key(item.id.owner_id.def_id).disambiguated_data.disambiguator + + 1 + } else { + acc + } + }); + + let data = DefPathData::AnonAssocTy(def_path_data); let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, - disambiguator: DisambiguatorState::with(parent_def_id, data, 0), + disambiguator: DisambiguatorState::with(parent_def_id, data, disambiguator_idx), }; visitor.visit_fn_ret_ty(output); tcx.arena.alloc_from_iter( diff --git a/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.rs b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.rs new file mode 100644 index 0000000000000..4fddd7c4ac8c6 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.rs @@ -0,0 +1,30 @@ +// issue#140796 + +trait Bar { + fn method() -> impl Sized; + fn method() -> impl Sized; //~ ERROR: the name `method` is defined multiple times +} + +impl Bar for () { //~ ERROR: not all trait items implemented, missing: `method` + fn method() -> impl Sized { + 42 + } + fn method() -> impl Sized { //~ ERROR: duplicate definitions with name `method` + 42 + } +} + +trait T { + fn method() -> impl Sized; +} + +impl T for () { + fn method() -> impl Sized { + 42 + } + fn method() -> impl Sized { //~ ERROR: duplicate definitions with name `method` + 42 + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.stderr b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.stderr new file mode 100644 index 0000000000000..b58e8136479c1 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn.stderr @@ -0,0 +1,53 @@ +error[E0428]: the name `method` is defined multiple times + --> $DIR/rpitit-duplicate-associated-fn.rs:5:5 + | +LL | fn method() -> impl Sized; + | -------------------------- previous definition of the value `method` here +LL | fn method() -> impl Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `method` redefined here + | + = note: `method` must be defined only once in the value namespace of this trait + +error[E0201]: duplicate definitions with name `method`: + --> $DIR/rpitit-duplicate-associated-fn.rs:12:5 + | +LL | fn method() -> impl Sized; + | -------------------------- item in trait +... +LL | / fn method() -> impl Sized { +LL | | 42 +LL | | } + | |_____- previous definition here +LL | / fn method() -> impl Sized { +LL | | 42 +LL | | } + | |_____^ duplicate definition + +error[E0201]: duplicate definitions with name `method`: + --> $DIR/rpitit-duplicate-associated-fn.rs:25:5 + | +LL | fn method() -> impl Sized; + | -------------------------- item in trait +... +LL | / fn method() -> impl Sized { +LL | | 42 +LL | | } + | |_____- previous definition here +LL | / fn method() -> impl Sized { +LL | | 42 +LL | | } + | |_____^ duplicate definition + +error[E0046]: not all trait items implemented, missing: `method` + --> $DIR/rpitit-duplicate-associated-fn.rs:8:1 + | +LL | fn method() -> impl Sized; + | -------------------------- `method` from trait +... +LL | impl Bar for () { + | ^^^^^^^^^^^^^^^ missing `method` in implementation + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0046, E0201, E0428. +For more information about an error, try `rustc --explain E0046`.