1use rustc_data_structures::fx::FxIndexSet;
2use rustc_hir::def::DefKind;
3use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
4use rustc_hir::intravisit::{self, Visitor};
5use rustc_hir::{self as hir, AmbigArg};
6use rustc_middle::query::Providers;
7use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
8use rustc_middle::{bug, span_bug};
9use rustc_span::kw;
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 (kind, has_self) = match trait_item_ref.kind {
133 hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
134 hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
135 hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
136 };
137
138 ty::AssocItem {
139 name: trait_item_ref.ident.name,
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 fn_has_self_parameter: has_self,
145 opt_rpitit_info: None,
146 }
147}
148
149fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
150 let def_id = impl_item_ref.id.owner_id;
151 let (kind, has_self) = match impl_item_ref.kind {
152 hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
153 hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
154 hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
155 };
156
157 ty::AssocItem {
158 name: impl_item_ref.ident.name,
159 kind,
160 def_id: def_id.to_def_id(),
161 trait_item_def_id: impl_item_ref.trait_item_def_id,
162 container: ty::AssocItemContainer::Impl,
163 fn_has_self_parameter: has_self,
164 opt_rpitit_info: None,
165 }
166}
167
168fn associated_types_for_impl_traits_in_associated_fn(
178 tcx: TyCtxt<'_>,
179 fn_def_id: LocalDefId,
180) -> &'_ [DefId] {
181 let parent_def_id = tcx.local_parent(fn_def_id);
182
183 match tcx.def_kind(parent_def_id) {
184 DefKind::Trait => {
185 struct RPITVisitor {
186 rpits: FxIndexSet<LocalDefId>,
187 }
188
189 impl<'tcx> Visitor<'tcx> for RPITVisitor {
190 fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
191 if let hir::TyKind::OpaqueDef(opaq) = ty.kind
192 && self.rpits.insert(opaq.def_id)
193 {
194 for bound in opaq.bounds {
195 intravisit::walk_param_bound(self, bound);
196 }
197 }
198 intravisit::walk_ty(self, ty)
199 }
200 }
201
202 let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
203
204 if let Some(output) = tcx.hir().get_fn_output(fn_def_id) {
205 visitor.visit_fn_ret_ty(output);
206
207 tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| {
208 tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
209 }))
210 } else {
211 &[]
212 }
213 }
214
215 DefKind::Impl { .. } => {
216 let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else {
217 return &[];
218 };
219
220 tcx.arena.alloc_from_iter(
221 tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map(
222 move |&trait_assoc_def_id| {
223 associated_type_for_impl_trait_in_impl(tcx, trait_assoc_def_id, fn_def_id)
224 .to_def_id()
225 },
226 ),
227 )
228 }
229
230 def_kind => bug!(
231 "associated_types_for_impl_traits_in_associated_fn: {:?} should be Trait or Impl but is {:?}",
232 parent_def_id,
233 def_kind
234 ),
235 }
236}
237
238fn associated_type_for_impl_trait_in_trait(
242 tcx: TyCtxt<'_>,
243 opaque_ty_def_id: LocalDefId,
244) -> LocalDefId {
245 let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
246 | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
247 tcx.local_opaque_ty_origin(opaque_ty_def_id)
248 else {
249 bug!("expected opaque for {opaque_ty_def_id:?}");
250 };
251 let trait_def_id = tcx.local_parent(fn_def_id);
252 assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
253
254 let span = tcx.def_span(opaque_ty_def_id);
255 let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy);
256
257 let local_def_id = trait_assoc_ty.def_id();
258 let def_id = local_def_id.to_def_id();
259
260 trait_assoc_ty.feed_hir();
261
262 trait_assoc_ty.def_ident_span(Some(span));
264
265 trait_assoc_ty.associated_item(ty::AssocItem {
266 name: kw::Empty,
267 kind: ty::AssocKind::Type,
268 def_id,
269 trait_item_def_id: None,
270 container: ty::AssocItemContainer::Trait,
271 fn_has_self_parameter: false,
272 opt_rpitit_info: Some(ImplTraitInTraitData::Trait {
273 fn_def_id: fn_def_id.to_def_id(),
274 opaque_def_id: opaque_ty_def_id.to_def_id(),
275 }),
276 });
277
278 trait_assoc_ty.visibility(tcx.visibility(fn_def_id));
280
281 trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
283
284 trait_assoc_ty.inferred_outlives_of(&[]);
286
287 local_def_id
288}
289
290fn associated_type_for_impl_trait_in_impl(
296 tcx: TyCtxt<'_>,
297 trait_assoc_def_id: DefId,
298 impl_fn_def_id: LocalDefId,
299) -> LocalDefId {
300 let impl_local_def_id = tcx.local_parent(impl_fn_def_id);
301
302 let decl = tcx.hir_node_by_def_id(impl_fn_def_id).fn_decl().expect("expected decl");
303 let span = match decl.output {
304 hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id),
305 hir::FnRetTy::Return(ty) => ty.span,
306 };
307 let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, kw::Empty, DefKind::AssocTy);
308
309 let local_def_id = impl_assoc_ty.def_id();
310 let def_id = local_def_id.to_def_id();
311
312 impl_assoc_ty.feed_hir();
313
314 impl_assoc_ty.def_ident_span(Some(span));
316
317 impl_assoc_ty.associated_item(ty::AssocItem {
318 name: kw::Empty,
319 kind: ty::AssocKind::Type,
320 def_id,
321 trait_item_def_id: Some(trait_assoc_def_id),
322 container: ty::AssocItemContainer::Impl,
323 fn_has_self_parameter: false,
324 opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }),
325 });
326
327 impl_assoc_ty.visibility(tcx.visibility(impl_fn_def_id));
329
330 impl_assoc_ty.defaultness(tcx.defaultness(impl_fn_def_id));
332
333 impl_assoc_ty.generics_of({
338 let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
339 let trait_assoc_parent_count = trait_assoc_generics.parent_count;
340 let mut own_params = trait_assoc_generics.own_params.clone();
341
342 let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id());
343 let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
344
345 for param in &mut own_params {
346 param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
347 }
348
349 let param_def_id_to_index =
350 own_params.iter().map(|param| (param.def_id, param.index)).collect();
351
352 ty::Generics {
353 parent: Some(impl_local_def_id.to_def_id()),
354 parent_count,
355 own_params,
356 param_def_id_to_index,
357 has_self: false,
358 has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
359 }
360 });
361
362 impl_assoc_ty.inferred_outlives_of(&[]);
364
365 local_def_id
366}