• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use rustc_data_structures::fx::FxIndexSet;
2 use rustc_hir as hir;
3 use rustc_hir::def::DefKind;
4 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
5 use rustc_hir::definitions::DefPathData;
6 use rustc_hir::intravisit::{self, Visitor};
7 use rustc_middle::query::Providers;
8 use rustc_middle::ty::{self, ImplTraitInTraitData, InternalSubsts, Ty, TyCtxt};
9 use rustc_span::symbol::kw;
10 
provide(providers: &mut Providers)11 pub 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 
associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId]23 fn 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(.., ref trait_item_refs) => {
27             if tcx.lower_impl_trait_in_trait_to_assoc_ty() {
28                 // We collect RPITITs for each trait method's return type and create a
29                 // corresponding associated item using associated_types_for_impl_traits_in_associated_fn
30                 // query.
31                 tcx.arena.alloc_from_iter(
32                     trait_item_refs
33                         .iter()
34                         .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id())
35                         .chain(
36                             trait_item_refs
37                                 .iter()
38                                 .filter(|trait_item_ref| {
39                                     matches!(trait_item_ref.kind, hir::AssocItemKind::Fn { .. })
40                                 })
41                                 .flat_map(|trait_item_ref| {
42                                     let trait_fn_def_id =
43                                         trait_item_ref.id.owner_id.def_id.to_def_id();
44                                     tcx.associated_types_for_impl_traits_in_associated_fn(
45                                         trait_fn_def_id,
46                                     )
47                                 })
48                                 .map(|def_id| *def_id),
49                         ),
50                 )
51             } else {
52                 tcx.arena.alloc_from_iter(
53                     trait_item_refs
54                         .iter()
55                         .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()),
56                 )
57             }
58         }
59         hir::ItemKind::Impl(ref impl_) => {
60             if tcx.lower_impl_trait_in_trait_to_assoc_ty() {
61                 // We collect RPITITs for each trait method's return type, on the impl side too and
62                 // create a corresponding associated item using
63                 // associated_types_for_impl_traits_in_associated_fn query.
64                 tcx.arena.alloc_from_iter(
65                     impl_
66                         .items
67                         .iter()
68                         .map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id())
69                         .chain(impl_.of_trait.iter().flat_map(|_| {
70                             impl_
71                                 .items
72                                 .iter()
73                                 .filter(|impl_item_ref| {
74                                     matches!(impl_item_ref.kind, hir::AssocItemKind::Fn { .. })
75                                 })
76                                 .flat_map(|impl_item_ref| {
77                                     let impl_fn_def_id =
78                                         impl_item_ref.id.owner_id.def_id.to_def_id();
79                                     tcx.associated_types_for_impl_traits_in_associated_fn(
80                                         impl_fn_def_id,
81                                     )
82                                 })
83                                 .map(|def_id| *def_id)
84                         })),
85                 )
86             } else {
87                 tcx.arena.alloc_from_iter(
88                     impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()),
89                 )
90             }
91         }
92         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
93     }
94 }
95 
associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems96 fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems {
97     if tcx.is_trait_alias(def_id) {
98         ty::AssocItems::new(Vec::new())
99     } else {
100         let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
101         ty::AssocItems::new(items)
102     }
103 }
104 
impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId>105 fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId> {
106     tcx.associated_items(impl_id)
107         .in_definition_order()
108         .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
109         .collect()
110 }
111 
associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem112 fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
113     let id = tcx.hir().local_def_id_to_hir_id(def_id);
114     let parent_def_id = tcx.hir().get_parent_item(id);
115     let parent_item = tcx.hir().expect_item(parent_def_id.def_id);
116     match parent_item.kind {
117         hir::ItemKind::Impl(ref impl_) => {
118             if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.owner_id.def_id == def_id)
119             {
120                 let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
121                 debug_assert_eq!(assoc_item.def_id.expect_local(), def_id);
122                 return assoc_item;
123             }
124         }
125 
126         hir::ItemKind::Trait(.., ref trait_item_refs) => {
127             if let Some(trait_item_ref) =
128                 trait_item_refs.iter().find(|i| i.id.owner_id.def_id == def_id)
129             {
130                 let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
131                 debug_assert_eq!(assoc_item.def_id.expect_local(), def_id);
132                 return assoc_item;
133             }
134         }
135 
136         _ => {}
137     }
138 
139     span_bug!(
140         parent_item.span,
141         "unexpected parent of trait or impl item or item not found: {:?}",
142         parent_item.kind
143     )
144 }
145 
associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem146 fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
147     let owner_id = trait_item_ref.id.owner_id;
148     let (kind, has_self) = match trait_item_ref.kind {
149         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
150         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
151         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
152     };
153 
154     ty::AssocItem {
155         name: trait_item_ref.ident.name,
156         kind,
157         def_id: owner_id.to_def_id(),
158         trait_item_def_id: Some(owner_id.to_def_id()),
159         container: ty::TraitContainer,
160         fn_has_self_parameter: has_self,
161         opt_rpitit_info: None,
162     }
163 }
164 
associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem165 fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
166     let def_id = impl_item_ref.id.owner_id;
167     let (kind, has_self) = match impl_item_ref.kind {
168         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
169         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
170         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
171     };
172 
173     ty::AssocItem {
174         name: impl_item_ref.ident.name,
175         kind,
176         def_id: def_id.to_def_id(),
177         trait_item_def_id: impl_item_ref.trait_item_def_id,
178         container: ty::ImplContainer,
179         fn_has_self_parameter: has_self,
180         opt_rpitit_info: None,
181     }
182 }
183 
184 /// Given an `fn_def_id` of a trait or a trait implementation:
185 ///
186 /// if `fn_def_id` is a function defined inside a trait, then it synthesizes
187 /// a new def id corresponding to a new associated type for each return-
188 /// position `impl Trait` in the signature.
189 ///
190 /// if `fn_def_id` is a function inside of an impl, then for each synthetic
191 /// associated type generated for the corresponding trait function described
192 /// above, synthesize a corresponding associated type in the impl.
associated_types_for_impl_traits_in_associated_fn( tcx: TyCtxt<'_>, fn_def_id: LocalDefId, ) -> &'_ [DefId]193 fn associated_types_for_impl_traits_in_associated_fn(
194     tcx: TyCtxt<'_>,
195     fn_def_id: LocalDefId,
196 ) -> &'_ [DefId] {
197     let parent_def_id = tcx.local_parent(fn_def_id);
198 
199     match tcx.def_kind(parent_def_id) {
200         DefKind::Trait => {
201             struct RPITVisitor<'tcx> {
202                 rpits: FxIndexSet<LocalDefId>,
203                 tcx: TyCtxt<'tcx>,
204             }
205 
206             impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
207                 fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
208                     if let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind
209                         && self.rpits.insert(item_id.owner_id.def_id)
210                     {
211                         let opaque_item = self.tcx.hir().expect_item(item_id.owner_id.def_id).expect_opaque_ty();
212                         for bound in opaque_item.bounds {
213                             intravisit::walk_param_bound(self, bound);
214                         }
215                     }
216                     intravisit::walk_ty(self, ty)
217                 }
218             }
219 
220             let mut visitor = RPITVisitor { tcx, rpits: FxIndexSet::default() };
221 
222             if let Some(output) = tcx.hir().get_fn_output(fn_def_id) {
223                 visitor.visit_fn_ret_ty(output);
224 
225                 tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| {
226                     tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
227                 }))
228             } else {
229                 &[]
230             }
231         }
232 
233         DefKind::Impl { .. } => {
234             let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else { return &[] };
235 
236             tcx.arena.alloc_from_iter(
237                 tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map(
238                     move |&trait_assoc_def_id| {
239                         associated_type_for_impl_trait_in_impl(tcx, trait_assoc_def_id, fn_def_id)
240                             .to_def_id()
241                     },
242                 ),
243             )
244         }
245 
246         def_kind => bug!(
247             "associated_types_for_impl_traits_in_associated_fn: {:?} should be Trait or Impl but is {:?}",
248             parent_def_id,
249             def_kind
250         ),
251     }
252 }
253 
254 /// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated
255 /// function from a trait, synthesize an associated type for that `impl Trait`
256 /// that inherits properties that we infer from the method and the opaque type.
associated_type_for_impl_trait_in_trait( tcx: TyCtxt<'_>, opaque_ty_def_id: LocalDefId, ) -> LocalDefId257 fn associated_type_for_impl_trait_in_trait(
258     tcx: TyCtxt<'_>,
259     opaque_ty_def_id: LocalDefId,
260 ) -> LocalDefId {
261     let (hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id)) =
262         tcx.opaque_type_origin(opaque_ty_def_id)
263     else {
264         bug!("expected opaque for {opaque_ty_def_id:?}");
265     };
266     let trait_def_id = tcx.local_parent(fn_def_id);
267     assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
268 
269     let span = tcx.def_span(opaque_ty_def_id);
270     let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, DefPathData::ImplTraitAssocTy);
271 
272     let local_def_id = trait_assoc_ty.def_id();
273     let def_id = local_def_id.to_def_id();
274 
275     trait_assoc_ty.opt_def_kind(Some(DefKind::AssocTy));
276 
277     // There's no HIR associated with this new synthesized `def_id`, so feed
278     // `opt_local_def_id_to_hir_id` with `None`.
279     trait_assoc_ty.opt_local_def_id_to_hir_id(None);
280 
281     // Copy span of the opaque.
282     trait_assoc_ty.def_ident_span(Some(span));
283 
284     trait_assoc_ty.associated_item(ty::AssocItem {
285         name: kw::Empty,
286         kind: ty::AssocKind::Type,
287         def_id,
288         trait_item_def_id: None,
289         container: ty::TraitContainer,
290         fn_has_self_parameter: false,
291         opt_rpitit_info: Some(ImplTraitInTraitData::Trait {
292             fn_def_id: fn_def_id.to_def_id(),
293             opaque_def_id: opaque_ty_def_id.to_def_id(),
294         }),
295     });
296 
297     // Copy visility of the containing function.
298     trait_assoc_ty.visibility(tcx.visibility(fn_def_id));
299 
300     // Copy defaultness of the containing function.
301     trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
302 
303     // Copy type_of of the opaque.
304     trait_assoc_ty.type_of(ty::EarlyBinder::bind(Ty::new_opaque(
305         tcx,
306         opaque_ty_def_id.to_def_id(),
307         InternalSubsts::identity_for_item(tcx, opaque_ty_def_id),
308     )));
309 
310     trait_assoc_ty.is_type_alias_impl_trait(false);
311 
312     // Copy generics_of of the opaque type item but the trait is the parent.
313     trait_assoc_ty.generics_of({
314         let opaque_ty_generics = tcx.generics_of(opaque_ty_def_id);
315         let opaque_ty_parent_count = opaque_ty_generics.parent_count;
316         let mut params = opaque_ty_generics.params.clone();
317 
318         let parent_generics = tcx.generics_of(trait_def_id);
319         let parent_count = parent_generics.parent_count + parent_generics.params.len();
320 
321         let mut trait_fn_params = tcx.generics_of(fn_def_id).params.clone();
322 
323         for param in &mut params {
324             param.index = param.index + parent_count as u32 + trait_fn_params.len() as u32
325                 - opaque_ty_parent_count as u32;
326         }
327 
328         trait_fn_params.extend(params);
329         params = trait_fn_params;
330 
331         let param_def_id_to_index =
332             params.iter().map(|param| (param.def_id, param.index)).collect();
333 
334         ty::Generics {
335             parent: Some(trait_def_id.to_def_id()),
336             parent_count,
337             params,
338             param_def_id_to_index,
339             has_self: opaque_ty_generics.has_self,
340             has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
341             host_effect_index: parent_generics.host_effect_index,
342         }
343     });
344 
345     // There are no inferred outlives for the synthesized associated type.
346     trait_assoc_ty.inferred_outlives_of(&[]);
347 
348     local_def_id
349 }
350 
351 /// Given an `trait_assoc_def_id` corresponding to an associated item synthesized
352 /// from an `impl Trait` in an associated function from a trait, and an
353 /// `impl_fn_def_id` that represents an implementation of the associated function
354 /// that the `impl Trait` comes from, synthesize an associated type for that `impl Trait`
355 /// that inherits properties that we infer from the method and the associated type.
associated_type_for_impl_trait_in_impl( tcx: TyCtxt<'_>, trait_assoc_def_id: DefId, impl_fn_def_id: LocalDefId, ) -> LocalDefId356 fn associated_type_for_impl_trait_in_impl(
357     tcx: TyCtxt<'_>,
358     trait_assoc_def_id: DefId,
359     impl_fn_def_id: LocalDefId,
360 ) -> LocalDefId {
361     let impl_local_def_id = tcx.local_parent(impl_fn_def_id);
362 
363     // FIXME fix the span, we probably want the def_id of the return type of the function
364     let span = tcx.def_span(impl_fn_def_id);
365     let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, DefPathData::ImplTraitAssocTy);
366 
367     let local_def_id = impl_assoc_ty.def_id();
368     let def_id = local_def_id.to_def_id();
369 
370     impl_assoc_ty.opt_def_kind(Some(DefKind::AssocTy));
371 
372     // There's no HIR associated with this new synthesized `def_id`, so feed
373     // `opt_local_def_id_to_hir_id` with `None`.
374     impl_assoc_ty.opt_local_def_id_to_hir_id(None);
375 
376     // Copy span of the opaque.
377     impl_assoc_ty.def_ident_span(Some(span));
378 
379     impl_assoc_ty.associated_item(ty::AssocItem {
380         name: kw::Empty,
381         kind: ty::AssocKind::Type,
382         def_id,
383         trait_item_def_id: Some(trait_assoc_def_id),
384         container: ty::ImplContainer,
385         fn_has_self_parameter: false,
386         opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }),
387     });
388 
389     // Copy visility of the containing function.
390     impl_assoc_ty.visibility(tcx.visibility(impl_fn_def_id));
391 
392     // Copy defaultness of the containing function.
393     impl_assoc_ty.defaultness(tcx.defaultness(impl_fn_def_id));
394 
395     // Copy generics_of the trait's associated item but the impl as the parent.
396     // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) resolves to the trait instead of the impl
397     // generics.
398     impl_assoc_ty.generics_of({
399         let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
400         let trait_assoc_parent_count = trait_assoc_generics.parent_count;
401         let mut params = trait_assoc_generics.params.clone();
402 
403         let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id());
404         let parent_count = parent_generics.parent_count + parent_generics.params.len();
405 
406         for param in &mut params {
407             param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
408         }
409 
410         let param_def_id_to_index =
411             params.iter().map(|param| (param.def_id, param.index)).collect();
412 
413         ty::Generics {
414             parent: Some(impl_local_def_id.to_def_id()),
415             parent_count,
416             params,
417             param_def_id_to_index,
418             has_self: false,
419             has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
420             host_effect_index: parent_generics.host_effect_index,
421         }
422     });
423 
424     // There are no inferred outlives for the synthesized associated type.
425     impl_assoc_ty.inferred_outlives_of(&[]);
426 
427     local_def_id
428 }
429