Skip to main content

rustc_ty_utils/
assoc.rs

1use rustc_hir::def::DefKind;
2use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
3use rustc_hir::definitions::{DefPathData, PerParentDisambiguatorState};
4use rustc_hir::intravisit::{self, Visitor};
5use rustc_hir::{self as hir, Generics, ImplItemImplKind, ItemKind};
6use rustc_middle::query::Providers;
7use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
8use rustc_span::symbol::kw;
9use rustc_span::{Ident, bug, span_bug};
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_trait_or_impl,
17        impl_item_implementor_ids,
18        ..*providers
19    };
20}
21
22fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] {
23    let item = tcx.hir_expect_item(def_id);
24    match item.kind {
25        hir::ItemKind::Trait { items: trait_item_refs, .. } => {
26            // We collect RPITITs for each trait method's return type and create a corresponding
27            // associated item using the associated_types_for_impl_traits_in_trait_or_impl
28            // query.
29            let rpitit_items = tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id);
30            tcx.arena.alloc_from_iter(trait_item_refs.iter().flat_map(|trait_item_ref| {
31                let item_def_id = trait_item_ref.owner_id.to_def_id();
32                [item_def_id]
33                    .into_iter()
34                    .chain(rpitit_items.get(&item_def_id).into_flat_iter().copied())
35            }))
36        }
37        hir::ItemKind::Impl(impl_) => {
38            // We collect RPITITs for each trait method's return type, on the impl side too and
39            // create a corresponding associated item using
40            // associated_types_for_impl_traits_in_trait_or_impl query.
41            let rpitit_items = tcx.associated_types_for_impl_traits_in_trait_or_impl(def_id);
42            tcx.arena.alloc_from_iter(impl_.items.iter().flat_map(|impl_item_ref| {
43                let item_def_id = impl_item_ref.owner_id.to_def_id();
44                [item_def_id]
45                    .into_iter()
46                    .chain(rpitit_items.get(&item_def_id).into_flat_iter().copied())
47            }))
48        }
49        _ => ::rustc_span::macros::bug_impl(Some(item.span),
    format_args!("associated_item_def_ids: not impl or trait"),
    Location::caller())span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
50    }
51}
52
53fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems {
54    if tcx.is_trait_alias(def_id) {
55        ty::AssocItems::new(Vec::new())
56    } else {
57        let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
58        ty::AssocItems::new(items)
59    }
60}
61
62fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap<DefId> {
63    tcx.associated_items(impl_id)
64        .in_definition_order()
65        .filter_map(|item| item.trait_item_def_id().map(|trait_item| (trait_item, item.def_id)))
66        .collect()
67}
68
69fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
70    let assoc_item = match tcx.hir_node_by_def_id(def_id) {
71        hir::Node::TraitItem(ti) => associated_item_from_trait_item(tcx, ti),
72        hir::Node::ImplItem(ii) => associated_item_from_impl_item(tcx, ii),
73        node => ::rustc_span::macros::bug_impl(Some(tcx.def_span(def_id)),
    format_args!("impl item or item not found: {0:?}", node),
    Location::caller())span_bug!(tcx.def_span(def_id), "impl item or item not found: {:?}", node,),
74    };
75    if true {
    {
        match (&assoc_item.def_id.expect_local(), &def_id) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    let kind = ::core::panicking::AssertKind::Eq;
                    ::core::panicking::assert_failed(kind, &*left_val,
                        &*right_val, ::core::option::Option::None);
                }
            }
        }
    };
};debug_assert_eq!(assoc_item.def_id.expect_local(), def_id);
76    assoc_item
77}
78
79fn fn_has_self_parameter(tcx: TyCtxt<'_>, owner_id: hir::OwnerId, generics: &Generics<'_>) -> bool {
80    // With `function_arg_const_generics`, const parameters are moved into the
81    // generics. We check the original `arg_pos` to avoid treating a later `self`
82    // as a valid receiver after the const parameters are removed.
83    #[allow(non_exhaustive_omitted_patterns)] match tcx.fn_arg_idents(owner_id.def_id)
    {
    [Some(Ident { name: kw::SelfLower, .. }), ..] => true,
    _ => false,
}matches!(tcx.fn_arg_idents(owner_id.def_id), [Some(Ident { name: kw::SelfLower, .. }), ..])
84        && !generics.params.iter().any(|param| {
85            #[allow(non_exhaustive_omitted_patterns)] match param.kind {
    hir::GenericParamKind::Const { arg_pos: Some(0), .. } => true,
    _ => false,
}matches!(param.kind, hir::GenericParamKind::Const { arg_pos: Some(0), .. })
86        })
87}
88
89fn associated_item_from_trait_item(
90    tcx: TyCtxt<'_>,
91    trait_item: &hir::TraitItem<'_>,
92) -> ty::AssocItem {
93    let owner_id = trait_item.owner_id;
94    let name = trait_item.ident.name;
95    let kind = match trait_item.kind {
96        hir::TraitItemKind::Const(_, _) => ty::AssocKind::Const { name },
97        hir::TraitItemKind::Fn { .. } => ty::AssocKind::Fn {
98            name,
99            has_self: fn_has_self_parameter(tcx, owner_id, trait_item.generics),
100        },
101        hir::TraitItemKind::Type { .. } => {
102            ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }
103        }
104    };
105
106    ty::AssocItem { kind, def_id: owner_id.to_def_id(), container: ty::AssocContainer::Trait }
107}
108
109fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> ty::AssocItem {
110    let owner_id = impl_item.owner_id;
111    let name = impl_item.ident.name;
112    let kind = match impl_item.kind {
113        hir::ImplItemKind::Const(..) => ty::AssocKind::Const { name },
114        hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn {
115            name,
116            has_self: fn_has_self_parameter(tcx, owner_id, impl_item.generics),
117        },
118        hir::ImplItemKind::Type(..) => {
119            ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }
120        }
121    };
122
123    let container = match impl_item.impl_kind {
124        ImplItemImplKind::Inherent { .. } => ty::AssocContainer::InherentImpl,
125        ImplItemImplKind::Trait { trait_item_def_id, .. } => {
126            ty::AssocContainer::TraitImpl(trait_item_def_id)
127        }
128    };
129    ty::AssocItem { kind, def_id: owner_id.to_def_id(), container }
130}
131struct RPITVisitor<'a, 'tcx> {
132    tcx: TyCtxt<'tcx>,
133    synthetics: Vec<LocalDefId>,
134    data: DefPathData,
135    disambiguator: &'a mut PerParentDisambiguatorState,
136}
137
138impl<'tcx> Visitor<'tcx> for RPITVisitor<'_, 'tcx> {
139    fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
140        self.synthetics.push(associated_type_for_impl_trait_in_trait(
141            self.tcx,
142            opaque.def_id,
143            self.data,
144            &mut self.disambiguator,
145        ));
146        intravisit::walk_opaque_ty(self, opaque)
147    }
148}
149
150fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
151    tcx: TyCtxt<'tcx>,
152    def_id: LocalDefId,
153) -> DefIdMap<Vec<DefId>> {
154    let item = tcx.hir_expect_item(def_id);
155    let disambiguator = &mut PerParentDisambiguatorState::new(def_id);
156    match item.kind {
157        ItemKind::Trait { items: trait_item_refs, .. } => trait_item_refs
158            .iter()
159            .filter_map(move |item| {
160                if !#[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(item.owner_id) {
    DefKind::AssocFn => true,
    _ => false,
}matches!(tcx.def_kind(item.owner_id), DefKind::AssocFn) {
161                    return None;
162                }
163                let fn_def_id = item.owner_id.def_id;
164                let Some(output) = tcx.hir_get_fn_output(fn_def_id) else {
165                    return Some((fn_def_id.to_def_id(), ::alloc::vec::Vec::new()vec![]));
166                };
167                let def_name = tcx.item_name(fn_def_id.to_def_id());
168                let data = DefPathData::AnonAssocTy(def_name);
169                let mut visitor = RPITVisitor { tcx, synthetics: ::alloc::vec::Vec::new()vec![], data, disambiguator };
170                visitor.visit_fn_ret_ty(output);
171                let defs = visitor
172                    .synthetics
173                    .into_iter()
174                    .map(|def_id| def_id.to_def_id())
175                    .collect::<Vec<_>>();
176                Some((fn_def_id.to_def_id(), defs))
177            })
178            .collect(),
179        ItemKind::Impl(impl_) => {
180            let Some(of_trait) = impl_.of_trait else {
181                return Default::default();
182            };
183            let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
184                return Default::default();
185            };
186            let in_trait_def = tcx.associated_types_for_impl_traits_in_trait_or_impl(trait_def_id);
187            impl_
188                .items
189                .iter()
190                .filter_map(|item| {
191                    if !#[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(item.owner_id) {
    DefKind::AssocFn => true,
    _ => false,
}matches!(tcx.def_kind(item.owner_id), DefKind::AssocFn) {
192                        return None;
193                    }
194                    let did = item.owner_id.def_id.to_def_id();
195                    let item = tcx.hir_impl_item(*item);
196                    let ImplItemImplKind::Trait {
197                        trait_item_def_id: Ok(trait_item_def_id), ..
198                    } = item.impl_kind
199                    else {
200                        return Some((did, ::alloc::vec::Vec::new()vec![]));
201                    };
202                    let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| {
203                        associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguator)
204                            .to_def_id()
205                    });
206                    Some((did, iter.collect()))
207                })
208                .collect()
209        }
210        _ => {
211            ::rustc_span::macros::bug_impl(None,
    format_args!("associated_types_for_impl_traits_in_trait_or_impl: {0:?} should be Trait or Impl but is {1:?}",
        def_id, tcx.def_kind(def_id)), Location::caller())bug!(
212                "associated_types_for_impl_traits_in_trait_or_impl: {:?} should be Trait or Impl but is {:?}",
213                def_id,
214                tcx.def_kind(def_id)
215            )
216        }
217    }
218}
219
220/// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated
221/// function from a trait, synthesize an associated type for that `impl Trait`
222/// that inherits properties that we infer from the method and the opaque type.
223fn associated_type_for_impl_trait_in_trait(
224    tcx: TyCtxt<'_>,
225    opaque_ty_def_id: LocalDefId,
226    data: DefPathData,
227    disambiguator: &mut PerParentDisambiguatorState,
228) -> LocalDefId {
229    let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
230    | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
231        tcx.local_opaque_ty_origin(opaque_ty_def_id)
232    else {
233        ::rustc_span::macros::bug_impl(None,
    format_args!("expected opaque for {0:?}", opaque_ty_def_id),
    Location::caller());bug!("expected opaque for {opaque_ty_def_id:?}");
234    };
235    let trait_def_id = tcx.local_parent(fn_def_id);
236    {
    match (&tcx.def_kind(trait_def_id), &DefKind::Trait) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
237
238    let span = tcx.def_span(opaque_ty_def_id);
239    // Also use the method name to create an unique def path.
240    let trait_assoc_ty = tcx.at(span).create_def(
241        trait_def_id,
242        // No name because this is an anonymous associated type.
243        None,
244        DefKind::AssocTy,
245        Some(data),
246        disambiguator,
247    );
248
249    let local_def_id = trait_assoc_ty.def_id();
250    let def_id = local_def_id.to_def_id();
251
252    trait_assoc_ty.feed_hir();
253
254    // Copy span of the opaque.
255    trait_assoc_ty.def_ident_span(Some(span));
256
257    trait_assoc_ty.associated_item(ty::AssocItem {
258        kind: ty::AssocKind::Type {
259            data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait {
260                fn_def_id: fn_def_id.to_def_id(),
261                opaque_def_id: opaque_ty_def_id.to_def_id(),
262            }),
263        },
264        def_id,
265        container: ty::AssocContainer::Trait,
266    });
267
268    // Copy visility of the containing function.
269    trait_assoc_ty.visibility(tcx.visibility(fn_def_id));
270
271    // Copy defaultness of the containing function.
272    trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
273
274    // There are no inferred outlives for the synthesized associated type.
275    trait_assoc_ty.inferred_outlives_of(&[]);
276
277    local_def_id
278}
279
280/// Given an `trait_assoc_def_id` corresponding to an associated item synthesized
281/// from an `impl Trait` in an associated function from a trait, and an
282/// `impl_fn` that represents an implementation of the associated function
283/// that the `impl Trait` comes from, synthesize an associated type for that `impl Trait`
284/// that inherits properties that we infer from the method and the associated type.
285fn associated_type_for_impl_trait_in_impl(
286    tcx: TyCtxt<'_>,
287    trait_assoc_def_id: DefId,
288    impl_fn: &hir::ImplItem<'_>,
289    disambiguator: &mut PerParentDisambiguatorState,
290) -> LocalDefId {
291    let impl_local_def_id = tcx.local_parent(impl_fn.owner_id.def_id);
292
293    let hir::ImplItemKind::Fn(fn_sig, _) = impl_fn.kind else { ::rustc_span::macros::bug_impl(None, format_args!("expected decl"),
    Location::caller())bug!("expected decl") };
294    let span = match fn_sig.decl.output {
295        hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn.owner_id),
296        hir::FnRetTy::Return(ty) => ty.span,
297    };
298
299    // Use the same disambiguator and method name as the anon associated type in the trait.
300    let disambiguated_data = tcx.def_key(trait_assoc_def_id).disambiguated_data;
301    let DefPathData::AnonAssocTy(name) = disambiguated_data.data else {
302        ::rustc_span::macros::bug_impl(None,
    format_args!("expected anon associated type"), Location::caller())bug!("expected anon associated type")
303    };
304    let data = DefPathData::AnonAssocTy(name);
305
306    let impl_assoc_ty = tcx.at(span).create_def(
307        impl_local_def_id,
308        // No name because this is an anonymous associated type.
309        None,
310        DefKind::AssocTy,
311        Some(data),
312        disambiguator,
313    );
314
315    let local_def_id = impl_assoc_ty.def_id();
316    let def_id = local_def_id.to_def_id();
317
318    impl_assoc_ty.feed_hir();
319
320    // Copy span of the opaque.
321    impl_assoc_ty.def_ident_span(Some(span));
322
323    impl_assoc_ty.associated_item(ty::AssocItem {
324        kind: ty::AssocKind::Type {
325            data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl {
326                fn_def_id: impl_fn.owner_id.to_def_id(),
327            }),
328        },
329        def_id,
330        container: ty::AssocContainer::TraitImpl(Ok(trait_assoc_def_id)),
331    });
332
333    // Copy visility of the containing function.
334    impl_assoc_ty.visibility(tcx.visibility(impl_fn.owner_id));
335
336    // Copy defaultness of the containing function.
337    impl_assoc_ty.defaultness(tcx.defaultness(impl_fn.owner_id));
338
339    // Copy generics_of the trait's associated item but the impl as the parent.
340    // FIXME: This may be detrimental to diagnostics, as we resolve the early-bound vars
341    // here to paramswhose parent are items in the trait. We could synthesize new params
342    // here, but it seems overkill.
343    impl_assoc_ty.generics_of({
344        let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
345        let trait_assoc_parent_count = trait_assoc_generics.parent_count;
346        let mut own_params = trait_assoc_generics.own_params.clone();
347
348        let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id());
349        let parent_count = parent_generics.count();
350
351        for param in &mut own_params {
352            param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
353        }
354
355        let param_def_id_to_index =
356            own_params.iter().map(|param| (param.def_id, param.index)).collect();
357
358        ty::Generics {
359            parent: Some(impl_local_def_id.to_def_id()),
360            parent_count,
361            own_params,
362            param_def_id_to_index,
363            has_self: false,
364            has_arg_pos_consts: trait_assoc_generics.has_arg_pos_consts,
365            has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
366        }
367    });
368
369    // There are no inferred outlives for the synthesized associated type.
370    impl_assoc_ty.inferred_outlives_of(&[]);
371
372    local_def_id
373}