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, ImplItemImplKind, 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 { kind, def_id: owner_id.to_def_id(), container: ty::AssocContainer::Trait }
101}
102
103fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> ty::AssocItem {
104 let owner_id = impl_item.owner_id;
105 let name = impl_item.ident.name;
106 let kind = match impl_item.kind {
107 hir::ImplItemKind::Const { .. } => ty::AssocKind::Const { name },
108 hir::ImplItemKind::Fn { .. } => {
109 ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) }
110 }
111 hir::ImplItemKind::Type { .. } => {
112 ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }
113 }
114 };
115
116 let container = match impl_item.impl_kind {
117 ImplItemImplKind::Inherent { .. } => ty::AssocContainer::InherentImpl,
118 ImplItemImplKind::Trait { trait_item_def_id, .. } => {
119 ty::AssocContainer::TraitImpl(trait_item_def_id)
120 }
121 };
122 ty::AssocItem { kind, def_id: owner_id.to_def_id(), container }
123}
124struct RPITVisitor<'a, 'tcx> {
125 tcx: TyCtxt<'tcx>,
126 synthetics: Vec<LocalDefId>,
127 data: DefPathData,
128 disambiguator: &'a mut DisambiguatorState,
129}
130
131impl<'tcx> Visitor<'tcx> for RPITVisitor<'_, 'tcx> {
132 fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
133 self.synthetics.push(associated_type_for_impl_trait_in_trait(
134 self.tcx,
135 opaque.def_id,
136 self.data,
137 &mut self.disambiguator,
138 ));
139 intravisit::walk_opaque_ty(self, opaque)
140 }
141}
142
143fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
144 tcx: TyCtxt<'tcx>,
145 def_id: LocalDefId,
146) -> DefIdMap<Vec<DefId>> {
147 let item = tcx.hir_expect_item(def_id);
148 let disambiguator = &mut DisambiguatorState::new();
149 match item.kind {
150 ItemKind::Trait(.., trait_item_refs) => trait_item_refs
151 .iter()
152 .filter_map(move |item| {
153 if !matches!(tcx.def_kind(item.owner_id), DefKind::AssocFn) {
154 return None;
155 }
156 let fn_def_id = item.owner_id.def_id;
157 let Some(output) = tcx.hir_get_fn_output(fn_def_id) else {
158 return Some((fn_def_id.to_def_id(), vec![]));
159 };
160 let def_name = tcx.item_name(fn_def_id.to_def_id());
161 let data = DefPathData::AnonAssocTy(def_name);
162 let mut visitor = RPITVisitor { tcx, synthetics: vec![], data, disambiguator };
163 visitor.visit_fn_ret_ty(output);
164 let defs = visitor
165 .synthetics
166 .into_iter()
167 .map(|def_id| def_id.to_def_id())
168 .collect::<Vec<_>>();
169 Some((fn_def_id.to_def_id(), defs))
170 })
171 .collect(),
172 ItemKind::Impl(impl_) => {
173 let Some(of_trait) = impl_.of_trait else {
174 return Default::default();
175 };
176 let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
177 return Default::default();
178 };
179 let in_trait_def = tcx.associated_types_for_impl_traits_in_trait_or_impl(trait_def_id);
180 impl_
181 .items
182 .iter()
183 .filter_map(|item| {
184 if !matches!(tcx.def_kind(item.owner_id), DefKind::AssocFn) {
185 return None;
186 }
187 let did = item.owner_id.def_id.to_def_id();
188 let item = tcx.hir_impl_item(*item);
189 let ImplItemImplKind::Trait {
190 trait_item_def_id: Ok(trait_item_def_id), ..
191 } = item.impl_kind
192 else {
193 return Some((did, vec![]));
194 };
195 let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| {
196 associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguator)
197 .to_def_id()
198 });
199 Some((did, iter.collect()))
200 })
201 .collect()
202 }
203 _ => {
204 bug!(
205 "associated_types_for_impl_traits_in_trait_or_impl: {:?} should be Trait or Impl but is {:?}",
206 def_id,
207 tcx.def_kind(def_id)
208 )
209 }
210 }
211}
212
213fn associated_type_for_impl_trait_in_trait(
217 tcx: TyCtxt<'_>,
218 opaque_ty_def_id: LocalDefId,
219 data: DefPathData,
220 disambiguator: &mut DisambiguatorState,
221) -> LocalDefId {
222 let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
223 | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
224 tcx.local_opaque_ty_origin(opaque_ty_def_id)
225 else {
226 bug!("expected opaque for {opaque_ty_def_id:?}");
227 };
228 let trait_def_id = tcx.local_parent(fn_def_id);
229 assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
230
231 let span = tcx.def_span(opaque_ty_def_id);
232 let trait_assoc_ty = tcx.at(span).create_def(
234 trait_def_id,
235 None,
237 DefKind::AssocTy,
238 Some(data),
239 disambiguator,
240 );
241
242 let local_def_id = trait_assoc_ty.def_id();
243 let def_id = local_def_id.to_def_id();
244
245 trait_assoc_ty.feed_hir();
246
247 trait_assoc_ty.def_ident_span(Some(span));
249
250 trait_assoc_ty.associated_item(ty::AssocItem {
251 kind: ty::AssocKind::Type {
252 data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait {
253 fn_def_id: fn_def_id.to_def_id(),
254 opaque_def_id: opaque_ty_def_id.to_def_id(),
255 }),
256 },
257 def_id,
258 container: ty::AssocContainer::Trait,
259 });
260
261 trait_assoc_ty.visibility(tcx.visibility(fn_def_id));
263
264 trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
266
267 trait_assoc_ty.inferred_outlives_of(&[]);
269
270 local_def_id
271}
272
273fn associated_type_for_impl_trait_in_impl(
279 tcx: TyCtxt<'_>,
280 trait_assoc_def_id: DefId,
281 impl_fn: &hir::ImplItem<'_>,
282 disambiguator: &mut DisambiguatorState,
283) -> LocalDefId {
284 let impl_local_def_id = tcx.local_parent(impl_fn.owner_id.def_id);
285
286 let hir::ImplItemKind::Fn(fn_sig, _) = impl_fn.kind else { bug!("expected decl") };
287 let span = match fn_sig.decl.output {
288 hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn.owner_id),
289 hir::FnRetTy::Return(ty) => ty.span,
290 };
291
292 let disambiguated_data = tcx.def_key(trait_assoc_def_id).disambiguated_data;
294 let DefPathData::AnonAssocTy(name) = disambiguated_data.data else {
295 bug!("expected anon associated type")
296 };
297 let data = DefPathData::AnonAssocTy(name);
298
299 let impl_assoc_ty = tcx.at(span).create_def(
300 impl_local_def_id,
301 None,
303 DefKind::AssocTy,
304 Some(data),
305 disambiguator,
306 );
307
308 let local_def_id = impl_assoc_ty.def_id();
309 let def_id = local_def_id.to_def_id();
310
311 impl_assoc_ty.feed_hir();
312
313 impl_assoc_ty.def_ident_span(Some(span));
315
316 impl_assoc_ty.associated_item(ty::AssocItem {
317 kind: ty::AssocKind::Type {
318 data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl {
319 fn_def_id: impl_fn.owner_id.to_def_id(),
320 }),
321 },
322 def_id,
323 container: ty::AssocContainer::TraitImpl(Ok(trait_assoc_def_id)),
324 });
325
326 impl_assoc_ty.visibility(tcx.visibility(impl_fn.owner_id));
328
329 impl_assoc_ty.defaultness(tcx.defaultness(impl_fn.owner_id));
331
332 impl_assoc_ty.generics_of({
337 let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
338 let trait_assoc_parent_count = trait_assoc_generics.parent_count;
339 let mut own_params = trait_assoc_generics.own_params.clone();
340
341 let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id());
342 let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
343
344 for param in &mut own_params {
345 param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
346 }
347
348 let param_def_id_to_index =
349 own_params.iter().map(|param| (param.def_id, param.index)).collect();
350
351 ty::Generics {
352 parent: Some(impl_local_def_id.to_def_id()),
353 parent_count,
354 own_params,
355 param_def_id_to_index,
356 has_self: false,
357 has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
358 }
359 });
360
361 impl_assoc_ty.inferred_outlives_of(&[]);
363
364 local_def_id
365}