1use rustc_data_structures::fx::FxIndexSet;
2use rustc_hir::def::DefKind;
3use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
4use rustc_hir::definitions::{DefPathData, DisambiguatorState};
5use rustc_hir::intravisit::{self, Visitor};
6use rustc_hir::{self as hir, AmbigArg};
7use rustc_middle::query::Providers;
8use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
9use rustc_middle::{bug, span_bug};
10
11pub(crate) fn provide(providers: &mut Providers) {
12 *providers = Providers {
13 associated_item,
14 associated_item_def_ids,
15 associated_items,
16 associated_types_for_impl_traits_in_associated_fn,
17 associated_type_for_impl_trait_in_trait,
18 impl_item_implementor_ids,
19 ..*providers
20 };
21}
22
23fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] {
24 let item = tcx.hir_expect_item(def_id);
25 match item.kind {
26 hir::ItemKind::Trait(.., trait_item_refs) => {
27 tcx.arena.alloc_from_iter(
31 trait_item_refs
32 .iter()
33 .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id())
34 .chain(
35 trait_item_refs
36 .iter()
37 .filter(|trait_item_ref| {
38 matches!(trait_item_ref.kind, hir::AssocItemKind::Fn { .. })
39 })
40 .flat_map(|trait_item_ref| {
41 let trait_fn_def_id = trait_item_ref.id.owner_id.def_id.to_def_id();
42 tcx.associated_types_for_impl_traits_in_associated_fn(
43 trait_fn_def_id,
44 )
45 })
46 .copied(),
47 ),
48 )
49 }
50 hir::ItemKind::Impl(impl_) => {
51 tcx.arena.alloc_from_iter(
55 impl_
56 .items
57 .iter()
58 .map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id())
59 .chain(impl_.of_trait.iter().flat_map(|_| {
60 impl_
61 .items
62 .iter()
63 .filter(|impl_item_ref| {
64 matches!(impl_item_ref.kind, hir::AssocItemKind::Fn { .. })
65 })
66 .flat_map(|impl_item_ref| {
67 let impl_fn_def_id = impl_item_ref.id.owner_id.def_id.to_def_id();
68 tcx.associated_types_for_impl_traits_in_associated_fn(
69 impl_fn_def_id,
70 )
71 })
72 .copied()
73 })),
74 )
75 }
76 _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
77 }
78}
79
80fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems {
81 if tcx.is_trait_alias(def_id) {
82 ty::AssocItems::new(Vec::new())
83 } else {
84 let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
85 ty::AssocItems::new(items)
86 }
87}
88
89fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId> {
90 tcx.associated_items(impl_id)
91 .in_definition_order()
92 .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
93 .collect()
94}
95
96fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
97 let id = tcx.local_def_id_to_hir_id(def_id);
98 let parent_def_id = tcx.hir_get_parent_item(id);
99 let parent_item = tcx.hir_expect_item(parent_def_id.def_id);
100 match parent_item.kind {
101 hir::ItemKind::Impl(impl_) => {
102 if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.owner_id.def_id == def_id)
103 {
104 let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
105 debug_assert_eq!(assoc_item.def_id.expect_local(), def_id);
106 return assoc_item;
107 }
108 }
109
110 hir::ItemKind::Trait(.., trait_item_refs) => {
111 if let Some(trait_item_ref) =
112 trait_item_refs.iter().find(|i| i.id.owner_id.def_id == def_id)
113 {
114 let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
115 debug_assert_eq!(assoc_item.def_id.expect_local(), def_id);
116 return assoc_item;
117 }
118 }
119
120 _ => {}
121 }
122
123 span_bug!(
124 parent_item.span,
125 "unexpected parent of trait or impl item or item not found: {:?}",
126 parent_item.kind
127 )
128}
129
130fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
131 let owner_id = trait_item_ref.id.owner_id;
132 let name = trait_item_ref.ident.name;
133 let kind = match trait_item_ref.kind {
134 hir::AssocItemKind::Const => ty::AssocKind::Const { name },
135 hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
136 hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
137 };
138
139 ty::AssocItem {
140 kind,
141 def_id: owner_id.to_def_id(),
142 trait_item_def_id: Some(owner_id.to_def_id()),
143 container: ty::AssocItemContainer::Trait,
144 }
145}
146
147fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
148 let def_id = impl_item_ref.id.owner_id;
149 let name = impl_item_ref.ident.name;
150 let kind = match impl_item_ref.kind {
151 hir::AssocItemKind::Const => ty::AssocKind::Const { name },
152 hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
153 hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
154 };
155
156 ty::AssocItem {
157 kind,
158 def_id: def_id.to_def_id(),
159 trait_item_def_id: impl_item_ref.trait_item_def_id,
160 container: ty::AssocItemContainer::Impl,
161 }
162}
163struct RPITVisitor {
164 rpits: FxIndexSet<LocalDefId>,
165}
166
167impl<'tcx> Visitor<'tcx> for RPITVisitor {
168 fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
169 if let hir::TyKind::OpaqueDef(opaq) = ty.kind
170 && self.rpits.insert(opaq.def_id)
171 {
172 for bound in opaq.bounds {
173 intravisit::walk_param_bound(self, bound);
174 }
175 }
176 intravisit::walk_ty(self, ty)
177 }
178}
179
180fn associated_types_for_impl_traits_in_associated_fn(
190 tcx: TyCtxt<'_>,
191 fn_def_id: LocalDefId,
192) -> &'_ [DefId] {
193 let parent_def_id = tcx.local_parent(fn_def_id);
194
195 match tcx.def_kind(parent_def_id) {
196 DefKind::Trait => {
197 let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
198
199 if let Some(output) = tcx.hir_get_fn_output(fn_def_id) {
200 visitor.visit_fn_ret_ty(output);
201
202 tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| {
203 tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
204 }))
205 } else {
206 &[]
207 }
208 }
209
210 DefKind::Impl { .. } => {
211 let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else {
212 return &[];
213 };
214
215 tcx.arena.alloc_from_iter(
216 tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map(
217 move |&trait_assoc_def_id| {
218 associated_type_for_impl_trait_in_impl(tcx, trait_assoc_def_id, fn_def_id)
219 .to_def_id()
220 },
221 ),
222 )
223 }
224
225 def_kind => bug!(
226 "associated_types_for_impl_traits_in_associated_fn: {:?} should be Trait or Impl but is {:?}",
227 parent_def_id,
228 def_kind
229 ),
230 }
231}
232
233fn associated_type_for_impl_trait_in_trait(
237 tcx: TyCtxt<'_>,
238 opaque_ty_def_id: LocalDefId,
239) -> LocalDefId {
240 let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
241 | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
242 tcx.local_opaque_ty_origin(opaque_ty_def_id)
243 else {
244 bug!("expected opaque for {opaque_ty_def_id:?}");
245 };
246 let trait_def_id = tcx.local_parent(fn_def_id);
247 assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
248
249 let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
252 visitor.visit_fn_ret_ty(tcx.hir_get_fn_output(fn_def_id).unwrap());
253 let disambiguator = visitor.rpits.get_index_of(&opaque_ty_def_id).unwrap().try_into().unwrap();
254
255 let span = tcx.def_span(opaque_ty_def_id);
256 let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id()));
258 let trait_assoc_ty = tcx.at(span).create_def(
259 trait_def_id,
260 None,
262 DefKind::AssocTy,
263 Some(data),
264 &mut DisambiguatorState::with(trait_def_id, data, disambiguator),
265 );
266
267 let local_def_id = trait_assoc_ty.def_id();
268 let def_id = local_def_id.to_def_id();
269
270 trait_assoc_ty.feed_hir();
271
272 trait_assoc_ty.def_ident_span(Some(span));
274
275 trait_assoc_ty.associated_item(ty::AssocItem {
276 kind: ty::AssocKind::Type {
277 data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait {
278 fn_def_id: fn_def_id.to_def_id(),
279 opaque_def_id: opaque_ty_def_id.to_def_id(),
280 }),
281 },
282 def_id,
283 trait_item_def_id: None,
284 container: ty::AssocItemContainer::Trait,
285 });
286
287 trait_assoc_ty.visibility(tcx.visibility(fn_def_id));
289
290 trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
292
293 trait_assoc_ty.inferred_outlives_of(&[]);
295
296 local_def_id
297}
298
299fn associated_type_for_impl_trait_in_impl(
305 tcx: TyCtxt<'_>,
306 trait_assoc_def_id: DefId,
307 impl_fn_def_id: LocalDefId,
308) -> LocalDefId {
309 let impl_local_def_id = tcx.local_parent(impl_fn_def_id);
310
311 let decl = tcx.hir_node_by_def_id(impl_fn_def_id).fn_decl().expect("expected decl");
312 let span = match decl.output {
313 hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id),
314 hir::FnRetTy::Return(ty) => ty.span,
315 };
316
317 let disambiguated_data = tcx.def_key(trait_assoc_def_id).disambiguated_data;
319 let DefPathData::AnonAssocTy(name) = disambiguated_data.data else {
320 bug!("expected anon associated type")
321 };
322 let data = DefPathData::AnonAssocTy(name);
323
324 let impl_assoc_ty = tcx.at(span).create_def(
325 impl_local_def_id,
326 None,
328 DefKind::AssocTy,
329 Some(data),
330 &mut DisambiguatorState::with(impl_local_def_id, data, disambiguated_data.disambiguator),
331 );
332
333 let local_def_id = impl_assoc_ty.def_id();
334 let def_id = local_def_id.to_def_id();
335
336 impl_assoc_ty.feed_hir();
337
338 impl_assoc_ty.def_ident_span(Some(span));
340
341 impl_assoc_ty.associated_item(ty::AssocItem {
342 kind: ty::AssocKind::Type {
343 data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl {
344 fn_def_id: impl_fn_def_id.to_def_id(),
345 }),
346 },
347 def_id,
348 trait_item_def_id: Some(trait_assoc_def_id),
349 container: ty::AssocItemContainer::Impl,
350 });
351
352 impl_assoc_ty.visibility(tcx.visibility(impl_fn_def_id));
354
355 impl_assoc_ty.defaultness(tcx.defaultness(impl_fn_def_id));
357
358 impl_assoc_ty.generics_of({
363 let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
364 let trait_assoc_parent_count = trait_assoc_generics.parent_count;
365 let mut own_params = trait_assoc_generics.own_params.clone();
366
367 let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id());
368 let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
369
370 for param in &mut own_params {
371 param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
372 }
373
374 let param_def_id_to_index =
375 own_params.iter().map(|param| (param.def_id, param.index)).collect();
376
377 ty::Generics {
378 parent: Some(impl_local_def_id.to_def_id()),
379 parent_count,
380 own_params,
381 param_def_id_to_index,
382 has_self: false,
383 has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
384 }
385 });
386
387 impl_assoc_ty.inferred_outlives_of(&[]);
389
390 local_def_id
391}