Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit dc6c330

Browse files
committed
compute all rpitit of a trait
1 parent bfc046a commit dc6c330

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)

AltStyle によって変換されたページ (->オリジナル) /