1use rustc_hir::def::DefKind;
2use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
3use rustc_hir::definitions::{DefPathData, DisambiguatorState};
4use rustc_hir::intravisit::{self, Visitor};
5use rustc_hir::{self as hir, ItemKind};
6use rustc_middle::query::Providers;
7use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
8use rustc_middle::{bug, span_bug};
9use rustc_span::Ident;
10use rustc_span::symbol::kw;
11
12pub(crate) fn provide(providers: &mut Providers) {
13 *providers = Providers {
14 associated_item,
15 associated_item_def_ids,
16 associated_items,
17 associated_types_for_impl_traits_in_trait_or_impl,
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 let rpitit_items = tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id);
31 tcx.arena.alloc_from_iter(trait_item_refs.iter().flat_map(|trait_item_ref| {
32 let item_def_id = trait_item_ref.owner_id.to_def_id();
33 [item_def_id]
34 .into_iter()
35 .chain(rpitit_items.get(&item_def_id).into_iter().flatten().copied())
36 }))
37 }
38 hir::ItemKind::Impl(impl_) => {
39 let rpitit_items = tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id);
43 tcx.arena.alloc_from_iter(impl_.items.iter().flat_map(|impl_item_ref| {
44 let item_def_id = impl_item_ref.owner_id.to_def_id();
45 [item_def_id]
46 .into_iter()
47 .chain(rpitit_items.get(&item_def_id).into_iter().flatten().copied())
48 }))
49 }
50 _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
51 }
52}
53
54fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems {
55 if tcx.is_trait_alias(def_id) {
56 ty::AssocItems::new(Vec::new())
57 } else {
58 let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
59 ty::AssocItems::new(items)
60 }
61}
62
63fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId> {
64 tcx.associated_items(impl_id)
65 .in_definition_order()
66 .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
67 .collect()
68}
69
70fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
71 let assoc_item = match tcx.hir_node_by_def_id(def_id) {
72 hir::Node::TraitItem(ti) => associated_item_from_trait_item(tcx, ti),
73 hir::Node::ImplItem(ii) => associated_item_from_impl_item(tcx, ii),
74 node => span_bug!(tcx.def_span(def_id), "impl item or item not found: {:?}", node,),
75 };
76 debug_assert_eq!(assoc_item.def_id.expect_local(), def_id);
77 assoc_item
78}
79
80fn fn_has_self_parameter(tcx: TyCtxt<'_>, owner_id: hir::OwnerId) -> bool {
81 matches!(tcx.fn_arg_idents(owner_id.def_id), [Some(Ident { name: kw::SelfLower, .. }), ..])
82}
83
84fn associated_item_from_trait_item(
85 tcx: TyCtxt<'_>,
86 trait_item: &hir::TraitItem<'_>,
87) -> ty::AssocItem {
88 let owner_id = trait_item.owner_id;
89 let name = trait_item.ident.name;
90 let kind = match trait_item.kind {
91 hir::TraitItemKind::Const { .. } => ty::AssocKind::Const { name },
92 hir::TraitItemKind::Fn { .. } => {
93 ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) }
94 }
95 hir::TraitItemKind::Type { .. } => {
96 ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }
97 }
98 };
99
100 ty::AssocItem {
101 kind,
102 def_id: owner_id.to_def_id(),
103 trait_item_def_id: Some(owner_id.to_def_id()),
104 container: ty::AssocItemContainer::Trait,
105 }
106}
107
108fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> ty::AssocItem {
109 let owner_id = impl_item.owner_id;
110 let name = impl_item.ident.name;
111 let kind = match impl_item.kind {
112 hir::ImplItemKind::Const { .. } => ty::AssocKind::Const { name },
113 hir::ImplItemKind::Fn { .. } => {
114 ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) }
115 }
116 hir::ImplItemKind::Type { .. } => {
117 ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }
118 }
119 };
120
121 ty::AssocItem {
122 kind,
123 def_id: owner_id.to_def_id(),
124 trait_item_def_id: impl_item.trait_item_def_id,
125 container: ty::AssocItemContainer::Impl,
126 }
127}
128struct RPITVisitor<'a, 'tcx> {
129 tcx: TyCtxt<'tcx>,
130 synthetics: Vec<LocalDefId>,
131 data: DefPathData,
132 disambiguator: &'a mut DisambiguatorState,
133}
134
135impl<'tcx> Visitor<'tcx> for RPITVisitor<'_, 'tcx> {
136 fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
137 self.synthetics.push(associated_type_for_impl_trait_in_trait(
138 self.tcx,
139 opaque.def_id,
140 self.data,
141 &mut self.disambiguator,
142 ));
143 intravisit::walk_opaque_ty(self, opaque)
144 }
145}
146
147fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
148 tcx: TyCtxt<'tcx>,
149 def_id: LocalDefId,
150) -> DefIdMap<Vec<DefId>> {
151 let item = tcx.hir_expect_item(def_id);
152 let disambiguator = &mut DisambiguatorState::new();
153 match item.kind {
154 ItemKind::Trait(.., trait_item_refs) => trait_item_refs
155 .iter()
156 .filter_map(move |item| {
157 if !matches!(tcx.def_kind(item.owner_id), DefKind::AssocFn) {
158 return None;
159 }
160 let fn_def_id = item.owner_id.def_id;
161 let Some(output) = tcx.hir_get_fn_output(fn_def_id) else {
162 return Some((fn_def_id.to_def_id(), vec![]));
163 };
164 let def_name = tcx.item_name(fn_def_id.to_def_id());
165 let data = DefPathData::AnonAssocTy(def_name);
166 let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, disambiguator };
167 visitor.visit_fn_ret_ty(output);
168 let defs = visitor
169 .synthetics
170 .into_iter()
171 .map(|def_id| def_id.to_def_id())
172 .collect::<Vec<_>>();
173 Some((fn_def_id.to_def_id(), defs))
174 })
175 .collect(),
176 ItemKind::Impl(impl_) => {
177 let Some(of_trait) = impl_.of_trait else {
178 return Default::default();
179 };
180 let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
181 return Default::default();
182 };
183 let in_trait_def = tcx.associated_types_for_impl_traits_in_trait_or_impl(trait_def_id);
184 impl_
185 .items
186 .iter()
187 .filter_map(|item| {
188 if !matches!(tcx.def_kind(item.owner_id), DefKind::AssocFn) {
189 return None;
190 }
191 let did = item.owner_id.def_id.to_def_id();
192 let item = tcx.hir_impl_item(*item);
193 let Some(trait_item_def_id) = item.trait_item_def_id else {
194 return Some((did, vec![]));
195 };
196 let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| {
197 associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguator)
198 .to_def_id()
199 });
200 Some((did, iter.collect()))
201 })
202 .collect()
203 }
204 _ => {
205 bug!(
206 "associated_types_for_impl_traits_in_trait_or_impl: {:?} should be Trait or Impl but is {:?}",
207 def_id,
208 tcx.def_kind(def_id)
209 )
210 }
211 }
212}
213
214fn associated_type_for_impl_trait_in_trait(
218 tcx: TyCtxt<'_>,
219 opaque_ty_def_id: LocalDefId,
220 data: DefPathData,
221 disambiguator: &mut DisambiguatorState,
222) -> LocalDefId {
223 let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
224 | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
225 tcx.local_opaque_ty_origin(opaque_ty_def_id)
226 else {
227 bug!("expected opaque for {opaque_ty_def_id:?}");
228 };
229 let trait_def_id = tcx.local_parent(fn_def_id);
230 assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
231
232 let span = tcx.def_span(opaque_ty_def_id);
233 let trait_assoc_ty = tcx.at(span).create_def(
235 trait_def_id,
236 None,
238 DefKind::AssocTy,
239 Some(data),
240 disambiguator,
241 );
242
243 let local_def_id = trait_assoc_ty.def_id();
244 let def_id = local_def_id.to_def_id();
245
246 trait_assoc_ty.feed_hir();
247
248 trait_assoc_ty.def_ident_span(Some(span));
250
251 trait_assoc_ty.associated_item(ty::AssocItem {
252 kind: ty::AssocKind::Type {
253 data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait {
254 fn_def_id: fn_def_id.to_def_id(),
255 opaque_def_id: opaque_ty_def_id.to_def_id(),
256 }),
257 },
258 def_id,
259 trait_item_def_id: None,
260 container: ty::AssocItemContainer::Trait,
261 });
262
263 trait_assoc_ty.visibility(tcx.visibility(fn_def_id));
265
266 trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
268
269 trait_assoc_ty.inferred_outlives_of(&[]);
271
272 local_def_id
273}
274
275fn associated_type_for_impl_trait_in_impl(
281 tcx: TyCtxt<'_>,
282 trait_assoc_def_id: DefId,
283 impl_fn: &hir::ImplItem<'_>,
284 disambiguator: &mut DisambiguatorState,
285) -> LocalDefId {
286 let impl_local_def_id = tcx.local_parent(impl_fn.owner_id.def_id);
287
288 let hir::ImplItemKind::Fn(fn_sig, _) = impl_fn.kind else { bug!("expected decl") };
289 let span = match fn_sig.decl.output {
290 hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn.owner_id),
291 hir::FnRetTy::Return(ty) => ty.span,
292 };
293
294 let disambiguated_data = tcx.def_key(trait_assoc_def_id).disambiguated_data;
296 let DefPathData::AnonAssocTy(name) = disambiguated_data.data else {
297 bug!("expected anon associated type")
298 };
299 let data = DefPathData::AnonAssocTy(name);
300
301 let impl_assoc_ty = tcx.at(span).create_def(
302 impl_local_def_id,
303 None,
305 DefKind::AssocTy,
306 Some(data),
307 disambiguator,
308 );
309
310 let local_def_id = impl_assoc_ty.def_id();
311 let def_id = local_def_id.to_def_id();
312
313 impl_assoc_ty.feed_hir();
314
315 impl_assoc_ty.def_ident_span(Some(span));
317
318 impl_assoc_ty.associated_item(ty::AssocItem {
319 kind: ty::AssocKind::Type {
320 data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl {
321 fn_def_id: impl_fn.owner_id.to_def_id(),
322 }),
323 },
324 def_id,
325 trait_item_def_id: Some(trait_assoc_def_id),
326 container: ty::AssocItemContainer::Impl,
327 });
328
329 impl_assoc_ty.visibility(tcx.visibility(impl_fn.owner_id));
331
332 impl_assoc_ty.defaultness(tcx.defaultness(impl_fn.owner_id));
334
335 impl_assoc_ty.generics_of({
340 let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
341 let trait_assoc_parent_count = trait_assoc_generics.parent_count;
342 let mut own_params = trait_assoc_generics.own_params.clone();
343
344 let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id());
345 let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
346
347 for param in &mut own_params {
348 param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
349 }
350
351 let param_def_id_to_index =
352 own_params.iter().map(|param| (param.def_id, param.index)).collect();
353
354 ty::Generics {
355 parent: Some(impl_local_def_id.to_def_id()),
356 parent_count,
357 own_params,
358 param_def_id_to_index,
359 has_self: false,
360 has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
361 }
362 });
363
364 impl_assoc_ty.inferred_outlives_of(&[]);
366
367 local_def_id
368}