Skip to content

Commit 9304f8a

Browse files
Auto merge of #143783 - bvanjoi:issue-143697-2, r=<try>
compute all rpitit of a trait Fixes #143697 r? `@compiler-errors`
2 parents 855e0fe + 58cefcb commit 9304f8a

File tree

4 files changed

+97
-57
lines changed

4 files changed

+97
-57
lines changed

compiler/rustc_middle/src/query/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,12 @@ rustc_queries! {
10911091
separate_provide_extern
10921092
}
10931093

1094+
query associated_types_for_impl_traits_in_trait(trait_id: DefId) -> &'tcx DefIdMap<&'tcx [DefId]> {
1095+
arena_cache
1096+
desc { |tcx| "creating associated items for trait `{}`", tcx.def_path_str(trait_id) }
1097+
separate_provide_extern
1098+
}
1099+
10941100
/// Given an `impl_id`, return the trait it implements along with some header information.
10951101
/// Return `None` if this is an inherent impl.
10961102
query impl_trait_header(impl_id: DefId) -> Option<ty::ImplTraitHeader<'tcx>> {

compiler/rustc_ty_utils/src/assoc.rs

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use std::collections::hash_map::Entry;
2+
3+
use rustc_data_structures::fx::FxHashMap;
14
use rustc_hir as hir;
25
use rustc_hir::def::DefKind;
36
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
@@ -6,12 +9,14 @@ use rustc_hir::intravisit::{self, Visitor};
69
use rustc_middle::query::Providers;
710
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
811
use rustc_middle::{bug, span_bug};
12+
use rustc_span::Symbol;
913

1014
pub(crate) fn provide(providers: &mut Providers) {
1115
*providers = Providers {
1216
associated_item,
1317
associated_item_def_ids,
1418
associated_items,
19+
associated_types_for_impl_traits_in_trait,
1520
associated_types_for_impl_traits_in_associated_fn,
1621
impl_item_implementor_ids,
1722
..*providers
@@ -163,10 +168,12 @@ struct RPITVisitor<'tcx> {
163168
synthetics: Vec<LocalDefId>,
164169
data: DefPathData,
165170
disambiguator: DisambiguatorState,
171+
depth: u32,
166172
}
167173

168174
impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
169175
fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
176+
self.depth += 1;
170177
self.synthetics.push(associated_type_for_impl_trait_in_trait(
171178
self.tcx,
172179
opaque.def_id,
@@ -177,17 +184,6 @@ impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
177184
}
178185
}
179186

180-
struct DisambiguatorIdxVisitor {
181-
depth: u32,
182-
}
183-
184-
impl<'tcx> Visitor<'tcx> for DisambiguatorIdxVisitor {
185-
fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
186-
self.depth += 1;
187-
intravisit::walk_opaque_ty(self, opaque)
188-
}
189-
}
190-
191187
/// Given an `fn_def_id` of a trait or a trait implementation:
192188
///
193189
/// if `fn_def_id` is a function defined inside a trait, then it synthesizes
@@ -205,51 +201,7 @@ fn associated_types_for_impl_traits_in_associated_fn(
205201

206202
match tcx.def_kind(parent_def_id) {
207203
DefKind::Trait => {
208-
if let Some(output) = tcx.hir_get_fn_output(fn_def_id) {
209-
let def_path_id = |def_id: LocalDefId| tcx.item_name(def_id.to_def_id());
210-
let def_path_data = def_path_id(fn_def_id);
211-
212-
let (.., trait_item_refs) = tcx.hir_expect_item(parent_def_id).expect_trait();
213-
// The purpose of `disambiguator_idx` is to ensure there are
214-
// no duplicate `def_id` in certain cases, such as:
215-
// ```
216-
// trait Foo {
217-
// fn bar() -> impl Trait;
218-
// fn bar() -> impl Trait;
219-
// // ~~~~~~~~~~ It will generate the same ID if we don’t disambiguate it.
220-
// }
221-
// ```
222-
let disambiguator_idx = trait_item_refs
223-
.iter()
224-
.take_while(|item| item.id.owner_id.def_id != fn_def_id)
225-
.filter(|item| {
226-
matches!(item.kind, hir::AssocItemKind::Fn { .. })
227-
&& def_path_id(item.id.owner_id.def_id) == def_path_data
228-
})
229-
.last()
230-
.map(|item| {
231-
let output = tcx.hir_get_fn_output(item.id.owner_id.def_id).unwrap();
232-
let mut visitor = DisambiguatorIdxVisitor { depth: 0 };
233-
visitor.visit_fn_ret_ty(output);
234-
tcx.def_key(item.id.owner_id.def_id).disambiguated_data.disambiguator
235-
+ visitor.depth
236-
})
237-
.unwrap_or_default();
238-
239-
let data = DefPathData::AnonAssocTy(def_path_data);
240-
let mut visitor = RPITVisitor {
241-
tcx,
242-
synthetics: vec![],
243-
data,
244-
disambiguator: DisambiguatorState::with(parent_def_id, data, disambiguator_idx),
245-
};
246-
visitor.visit_fn_ret_ty(output);
247-
tcx.arena.alloc_from_iter(
248-
visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()),
249-
)
250-
} else {
251-
&[]
252-
}
204+
tcx.associated_types_for_impl_traits_in_trait(parent_def_id)[&fn_def_id.to_def_id()]
253205
}
254206

255207
DefKind::Impl { .. } => {
@@ -274,6 +226,54 @@ fn associated_types_for_impl_traits_in_associated_fn(
274226
}
275227
}
276228

229+
fn associated_types_for_impl_traits_in_trait<'tcx>(
230+
tcx: TyCtxt<'tcx>,
231+
trait_id: LocalDefId,
232+
) -> DefIdMap<&'tcx [DefId]> {
233+
let (.., trait_item_refs) = tcx.hir_expect_item(trait_id).expect_trait();
234+
235+
let mut disambiguator_idx_map = FxHashMap::default();
236+
let find_disambiguator_idx = |map: &mut FxHashMap<Symbol, u32>, name| match map.entry(name) {
237+
Entry::Occupied(occ) => *occ.get() + 1,
238+
Entry::Vacant(vac) => {
239+
vac.insert(0);
240+
0
241+
}
242+
};
243+
let update_disambiguator_idx = |map: &mut FxHashMap<Symbol, u32>, name, offset: u32| {
244+
*map.get_mut(&name).unwrap() += offset
245+
};
246+
247+
trait_item_refs
248+
.iter()
249+
.filter_map(move |item| {
250+
if !matches!(item.kind, hir::AssocItemKind::Fn { .. }) {
251+
return None;
252+
}
253+
let fn_def_id = item.id.owner_id.def_id;
254+
let Some(output) = tcx.hir_get_fn_output(fn_def_id) else {
255+
return Some((fn_def_id.to_def_id(), &[] as &[DefId]));
256+
};
257+
let def_name = tcx.item_name(fn_def_id.to_def_id());
258+
let disambiguator_idx = find_disambiguator_idx(&mut disambiguator_idx_map, def_name);
259+
let data = DefPathData::AnonAssocTy(def_name);
260+
let mut visitor = RPITVisitor {
261+
tcx,
262+
synthetics: vec![],
263+
data,
264+
depth: 0,
265+
disambiguator: DisambiguatorState::with(trait_id, data, disambiguator_idx),
266+
};
267+
visitor.visit_fn_ret_ty(output);
268+
update_disambiguator_idx(&mut disambiguator_idx_map, def_name, visitor.depth);
269+
let defs = tcx
270+
.arena
271+
.alloc_from_iter(visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()));
272+
Some((fn_def_id.to_def_id(), defs))
273+
})
274+
.collect()
275+
}
276+
277277
/// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated
278278
/// function from a trait, synthesize an associated type for that `impl Trait`
279279
/// that inherits properties that we infer from the method and the opaque type.

tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn-with-nested.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,17 @@ trait Qux {
4343
//~^^^^ ERROR: the name `foo` is defined multiple times
4444
}
4545

46+
trait T0<T> {
47+
type Target;
48+
}
49+
trait T1<T> {}
50+
51+
trait X {
52+
fn a() -> impl T0<(), Target = impl T1<()>>;
53+
fn a() -> impl T0<(), Target = impl T1<()>>;
54+
//~^ ERROR the name `a` is defined multiple times
55+
fn a() -> impl T0<(), Target = impl T1<()>>;
56+
//~^ ERROR the name `a` is defined multiple times
57+
}
58+
4659
fn main() {}

tests/ui/impl-trait/in-trait/rpitit-duplicate-associated-fn-with-nested.stderr

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,27 @@ LL | | >;
4444
|
4545
= note: `foo` must be defined only once in the value namespace of this trait
4646

47-
error: aborting due to 4 previous errors
47+
error[E0428]: the name `a` is defined multiple times
48+
--> $DIR/rpitit-duplicate-associated-fn-with-nested.rs:53:5
49+
|
50+
LL | fn a() -> impl T0<(), Target = impl T1<()>>;
51+
| -------------------------------------------- previous definition of the value `a` here
52+
LL | fn a() -> impl T0<(), Target = impl T1<()>>;
53+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `a` redefined here
54+
|
55+
= note: `a` must be defined only once in the value namespace of this trait
56+
57+
error[E0428]: the name `a` is defined multiple times
58+
--> $DIR/rpitit-duplicate-associated-fn-with-nested.rs:55:5
59+
|
60+
LL | fn a() -> impl T0<(), Target = impl T1<()>>;
61+
| -------------------------------------------- previous definition of the value `a` here
62+
...
63+
LL | fn a() -> impl T0<(), Target = impl T1<()>>;
64+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `a` redefined here
65+
|
66+
= note: `a` must be defined only once in the value namespace of this trait
67+
68+
error: aborting due to 6 previous errors
4869

4970
For more information about this error, try `rustc --explain E0428`.

0 commit comments

Comments
 (0)