1use rustc_hir as hir;
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_middle::query::Providers;
7use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
8use rustc_middle::{bug, span_bug};
9
10pub(crate) fn provide(providers: &mut Providers) {
11 *providers = Providers {
12 associated_item,
13 associated_item_def_ids,
14 associated_items,
15 associated_types_for_impl_traits_in_associated_fn,
16 impl_item_implementor_ids,
17 ..*providers
18 };
19}
20
21fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] {
22 let item = tcx.hir_expect_item(def_id);
23 match item.kind {
24 hir::ItemKind::Trait(.., trait_item_refs) => {
25 tcx.arena.alloc_from_iter(
29 trait_item_refs
30 .iter()
31 .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id())
32 .chain(
33 trait_item_refs
34 .iter()
35 .filter(|trait_item_ref| {
36 matches!(trait_item_ref.kind, hir::AssocItemKind::Fn { .. })
37 })
38 .flat_map(|trait_item_ref| {
39 let trait_fn_def_id = trait_item_ref.id.owner_id.def_id.to_def_id();
40 tcx.associated_types_for_impl_traits_in_associated_fn(
41 trait_fn_def_id,
42 )
43 })
44 .copied(),
45 ),
46 )
47 }
48 hir::ItemKind::Impl(impl_) => {
49 tcx.arena.alloc_from_iter(
53 impl_
54 .items
55 .iter()
56 .map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id())
57 .chain(impl_.of_trait.iter().flat_map(|_| {
58 impl_
59 .items
60 .iter()
61 .filter(|impl_item_ref| {
62 matches!(impl_item_ref.kind, hir::AssocItemKind::Fn { .. })
63 })
64 .flat_map(|impl_item_ref| {
65 let impl_fn_def_id = impl_item_ref.id.owner_id.def_id.to_def_id();
66 tcx.associated_types_for_impl_traits_in_associated_fn(
67 impl_fn_def_id,
68 )
69 })
70 .copied()
71 })),
72 )
73 }
74 _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
75 }
76}
77
78fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems {
79 if tcx.is_trait_alias(def_id) {
80 ty::AssocItems::new(Vec::new())
81 } else {
82 let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
83 ty::AssocItems::new(items)
84 }
85}
86
87fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId> {
88 tcx.associated_items(impl_id)
89 .in_definition_order()
90 .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
91 .collect()
92}
93
94fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
95 let id = tcx.local_def_id_to_hir_id(def_id);
96 let parent_def_id = tcx.hir_get_parent_item(id);
97 let parent_item = tcx.hir_expect_item(parent_def_id.def_id);
98 match parent_item.kind {
99 hir::ItemKind::Impl(impl_) => {
100 if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.owner_id.def_id == def_id)
101 {
102 let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
103 debug_assert_eq!(assoc_item.def_id.expect_local(), def_id);
104 return assoc_item;
105 }
106 }
107
108 hir::ItemKind::Trait(.., trait_item_refs) => {
109 if let Some(trait_item_ref) =
110 trait_item_refs.iter().find(|i| i.id.owner_id.def_id == def_id)
111 {
112 let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
113 debug_assert_eq!(assoc_item.def_id.expect_local(), def_id);
114 return assoc_item;
115 }
116 }
117
118 _ => {}
119 }
120
121 span_bug!(
122 parent_item.span,
123 "unexpected parent of trait or impl item or item not found: {:?}",
124 parent_item.kind
125 )
126}
127
128fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
129 let owner_id = trait_item_ref.id.owner_id;
130 let name = trait_item_ref.ident.name;
131 let kind = match trait_item_ref.kind {
132 hir::AssocItemKind::Const => ty::AssocKind::Const { name },
133 hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
134 hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
135 };
136
137 ty::AssocItem {
138 kind,
139 def_id: owner_id.to_def_id(),
140 trait_item_def_id: Some(owner_id.to_def_id()),
141 container: ty::AssocItemContainer::Trait,
142 }
143}
144
145fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
146 let def_id = impl_item_ref.id.owner_id;
147 let name = impl_item_ref.ident.name;
148 let kind = match impl_item_ref.kind {
149 hir::AssocItemKind::Const => ty::AssocKind::Const { name },
150 hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
151 hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
152 };
153
154 ty::AssocItem {
155 kind,
156 def_id: def_id.to_def_id(),
157 trait_item_def_id: impl_item_ref.trait_item_def_id,
158 container: ty::AssocItemContainer::Impl,
159 }
160}
161struct RPITVisitor<'tcx> {
162 tcx: TyCtxt<'tcx>,
163 synthetics: Vec<LocalDefId>,
164 data: DefPathData,
165 disambiguator: DisambiguatorState,
166}
167
168impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
169 fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
170 self.synthetics.push(associated_type_for_impl_trait_in_trait(
171 self.tcx,
172 opaque.def_id,
173 self.data,
174 &mut self.disambiguator,
175 ));
176 intravisit::walk_opaque_ty(self, opaque)
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 if let Some(output) = tcx.hir_get_fn_output(fn_def_id) {
198 let def_path_id = |def_id: LocalDefId| tcx.item_name(def_id.to_def_id());
199 let def_path_data = def_path_id(fn_def_id);
200
201 let (.., trait_item_refs) = tcx.hir_expect_item(parent_def_id).expect_trait();
202 let disambiguator_idx = trait_item_refs
212 .iter()
213 .take_while(|item| item.id.owner_id.def_id != fn_def_id)
214 .fold(0, |acc, item| {
215 if !matches!(item.kind, hir::AssocItemKind::Fn { .. }) {
216 acc
217 } else if def_path_id(item.id.owner_id.def_id) == def_path_data {
218 tcx.def_key(item.id.owner_id.def_id).disambiguated_data.disambiguator
219 + 1
220 } else {
221 acc
222 }
223 });
224
225 let data = DefPathData::AnonAssocTy(def_path_data);
226 let mut visitor = RPITVisitor {
227 tcx,
228 synthetics: vec![],
229 data,
230 disambiguator: DisambiguatorState::with(parent_def_id, data, disambiguator_idx),
231 };
232 visitor.visit_fn_ret_ty(output);
233 tcx.arena.alloc_from_iter(
234 visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()),
235 )
236 } else {
237 &[]
238 }
239 }
240
241 DefKind::Impl { .. } => {
242 let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else {
243 return &[];
244 };
245 tcx.arena.alloc_from_iter(
246 tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map(
247 move |&trait_assoc_def_id| {
248 associated_type_for_impl_trait_in_impl(tcx, trait_assoc_def_id, fn_def_id)
249 .to_def_id()
250 },
251 ),
252 )
253 }
254
255 def_kind => bug!(
256 "associated_types_for_impl_traits_in_associated_fn: {:?} should be Trait or Impl but is {:?}",
257 parent_def_id,
258 def_kind
259 ),
260 }
261}
262
263fn associated_type_for_impl_trait_in_trait(
267 tcx: TyCtxt<'_>,
268 opaque_ty_def_id: LocalDefId,
269 data: DefPathData,
270 disambiguator: &mut DisambiguatorState,
271) -> LocalDefId {
272 let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
273 | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
274 tcx.local_opaque_ty_origin(opaque_ty_def_id)
275 else {
276 bug!("expected opaque for {opaque_ty_def_id:?}");
277 };
278 let trait_def_id = tcx.local_parent(fn_def_id);
279 assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
280
281 let span = tcx.def_span(opaque_ty_def_id);
282 let trait_assoc_ty = tcx.at(span).create_def(
284 trait_def_id,
285 None,
287 DefKind::AssocTy,
288 Some(data),
289 disambiguator,
290 );
291
292 let local_def_id = trait_assoc_ty.def_id();
293 let def_id = local_def_id.to_def_id();
294
295 trait_assoc_ty.feed_hir();
296
297 trait_assoc_ty.def_ident_span(Some(span));
299
300 trait_assoc_ty.associated_item(ty::AssocItem {
301 kind: ty::AssocKind::Type {
302 data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait {
303 fn_def_id: fn_def_id.to_def_id(),
304 opaque_def_id: opaque_ty_def_id.to_def_id(),
305 }),
306 },
307 def_id,
308 trait_item_def_id: None,
309 container: ty::AssocItemContainer::Trait,
310 });
311
312 trait_assoc_ty.visibility(tcx.visibility(fn_def_id));
314
315 trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
317
318 trait_assoc_ty.inferred_outlives_of(&[]);
320
321 local_def_id
322}
323
324fn associated_type_for_impl_trait_in_impl(
330 tcx: TyCtxt<'_>,
331 trait_assoc_def_id: DefId,
332 impl_fn_def_id: LocalDefId,
333) -> LocalDefId {
334 let impl_local_def_id = tcx.local_parent(impl_fn_def_id);
335
336 let decl = tcx.hir_node_by_def_id(impl_fn_def_id).fn_decl().expect("expected decl");
337 let span = match decl.output {
338 hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id),
339 hir::FnRetTy::Return(ty) => ty.span,
340 };
341
342 let disambiguated_data = tcx.def_key(trait_assoc_def_id).disambiguated_data;
344 let DefPathData::AnonAssocTy(name) = disambiguated_data.data else {
345 bug!("expected anon associated type")
346 };
347 let data = DefPathData::AnonAssocTy(name);
348
349 let impl_assoc_ty = tcx.at(span).create_def(
350 impl_local_def_id,
351 None,
353 DefKind::AssocTy,
354 Some(data),
355 &mut DisambiguatorState::with(impl_local_def_id, data, disambiguated_data.disambiguator),
356 );
357
358 let local_def_id = impl_assoc_ty.def_id();
359 let def_id = local_def_id.to_def_id();
360
361 impl_assoc_ty.feed_hir();
362
363 impl_assoc_ty.def_ident_span(Some(span));
365
366 impl_assoc_ty.associated_item(ty::AssocItem {
367 kind: ty::AssocKind::Type {
368 data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl {
369 fn_def_id: impl_fn_def_id.to_def_id(),
370 }),
371 },
372 def_id,
373 trait_item_def_id: Some(trait_assoc_def_id),
374 container: ty::AssocItemContainer::Impl,
375 });
376
377 impl_assoc_ty.visibility(tcx.visibility(impl_fn_def_id));
379
380 impl_assoc_ty.defaultness(tcx.defaultness(impl_fn_def_id));
382
383 impl_assoc_ty.generics_of({
388 let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
389 let trait_assoc_parent_count = trait_assoc_generics.parent_count;
390 let mut own_params = trait_assoc_generics.own_params.clone();
391
392 let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id());
393 let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
394
395 for param in &mut own_params {
396 param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
397 }
398
399 let param_def_id_to_index =
400 own_params.iter().map(|param| (param.def_id, param.index)).collect();
401
402 ty::Generics {
403 parent: Some(impl_local_def_id.to_def_id()),
404 parent_count,
405 own_params,
406 param_def_id_to_index,
407 has_self: false,
408 has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
409 }
410 });
411
412 impl_assoc_ty.inferred_outlives_of(&[]);
414
415 local_def_id
416}