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, DisambiguatorState};
4use rustc_hir::intravisit::{self, Visitor};
5use rustc_hir::{self as hir, ConstItemRhs, 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            // We collect RPITITs for each trait method's return type and create a corresponding
28            // associated item using the associated_types_for_impl_traits_in_trait_or_impl
29            // query.
30            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            // We collect RPITITs for each trait method's return type, on the impl side too and
40            // create a corresponding associated item using
41            // associated_types_for_impl_traits_in_trait_or_impl query.
42            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        _ => ::rustc_middle::util::bug::span_bug_fmt(item.span,
    format_args!("associated_item_def_ids: not impl or trait"))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 => ::rustc_middle::util::bug::span_bug_fmt(tcx.def_span(def_id),
    format_args!("impl item or item not found: {0:?}", node))span_bug!(tcx.def_span(def_id), "impl item or item not found: {:?}", node,),
75    };
76    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);
77    assoc_item
78}
79
80fn fn_has_self_parameter(tcx: TyCtxt<'_>, owner_id: hir::OwnerId) -> bool {
81    #[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, .. }), ..])
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(_, _, is_type_const) => {
92            ty::AssocKind::Const { name, is_type_const: is_type_const.into() }
93        }
94        hir::TraitItemKind::Fn { .. } => {
95            ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) }
96        }
97        hir::TraitItemKind::Type { .. } => {
98            ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }
99        }
100    };
101
102    ty::AssocItem { kind, def_id: owner_id.to_def_id(), container: ty::AssocContainer::Trait }
103}
104
105fn associated_item_from_impl_item(tcx: TyCtxt<'_>, impl_item: &hir::ImplItem<'_>) -> ty::AssocItem {
106    let owner_id = impl_item.owner_id;
107    let name = impl_item.ident.name;
108    let kind = match impl_item.kind {
109        hir::ImplItemKind::Const(_, rhs) => {
110            ty::AssocKind::Const { name, is_type_const: #[allow(non_exhaustive_omitted_patterns)] match rhs {
    ConstItemRhs::TypeConst(_) => true,
    _ => false,
}matches!(rhs, ConstItemRhs::TypeConst(_)) }
111        }
112        hir::ImplItemKind::Fn { .. } => {
113            ty::AssocKind::Fn { name, has_self: fn_has_self_parameter(tcx, owner_id) }
114        }
115        hir::ImplItemKind::Type { .. } => {
116            ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) }
117        }
118    };
119
120    let container = match impl_item.impl_kind {
121        ImplItemImplKind::Inherent { .. } => ty::AssocContainer::InherentImpl,
122        ImplItemImplKind::Trait { trait_item_def_id, .. } => {
123            ty::AssocContainer::TraitImpl(trait_item_def_id)
124        }
125    };
126    ty::AssocItem { kind, def_id: owner_id.to_def_id(), container }
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 !#[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) {
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(), ::alloc::vec::Vec::new()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: ::alloc::vec::Vec::new()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 !#[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) {
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 ImplItemImplKind::Trait {
194                        trait_item_def_id: Ok(trait_item_def_id), ..
195                    } = item.impl_kind
196                    else {
197                        return Some((did, ::alloc::vec::Vec::new()vec![]));
198                    };
199                    let iter = in_trait_def[&trait_item_def_id].iter().map(|&id| {
200                        associated_type_for_impl_trait_in_impl(tcx, id, item, disambiguator)
201                            .to_def_id()
202                    });
203                    Some((did, iter.collect()))
204                })
205                .collect()
206        }
207        _ => {
208            ::rustc_middle::util::bug::bug_fmt(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)))bug!(
209                "associated_types_for_impl_traits_in_trait_or_impl: {:?} should be Trait or Impl but is {:?}",
210                def_id,
211                tcx.def_kind(def_id)
212            )
213        }
214    }
215}
216
217/// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated
218/// function from a trait, synthesize an associated type for that `impl Trait`
219/// that inherits properties that we infer from the method and the opaque type.
220fn associated_type_for_impl_trait_in_trait(
221    tcx: TyCtxt<'_>,
222    opaque_ty_def_id: LocalDefId,
223    data: DefPathData,
224    disambiguator: &mut DisambiguatorState,
225) -> LocalDefId {
226    let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
227    | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
228        tcx.local_opaque_ty_origin(opaque_ty_def_id)
229    else {
230        ::rustc_middle::util::bug::bug_fmt(format_args!("expected opaque for {0:?}",
        opaque_ty_def_id));bug!("expected opaque for {opaque_ty_def_id:?}");
231    };
232    let trait_def_id = tcx.local_parent(fn_def_id);
233    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);
234
235    let span = tcx.def_span(opaque_ty_def_id);
236    // Also use the method name to create an unique def path.
237    let trait_assoc_ty = tcx.at(span).create_def(
238        trait_def_id,
239        // No name because this is an anonymous associated type.
240        None,
241        DefKind::AssocTy,
242        Some(data),
243        disambiguator,
244    );
245
246    let local_def_id = trait_assoc_ty.def_id();
247    let def_id = local_def_id.to_def_id();
248
249    trait_assoc_ty.feed_hir();
250
251    // Copy span of the opaque.
252    trait_assoc_ty.def_ident_span(Some(span));
253
254    trait_assoc_ty.associated_item(ty::AssocItem {
255        kind: ty::AssocKind::Type {
256            data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait {
257                fn_def_id: fn_def_id.to_def_id(),
258                opaque_def_id: opaque_ty_def_id.to_def_id(),
259            }),
260        },
261        def_id,
262        container: ty::AssocContainer::Trait,
263    });
264
265    // Copy visility of the containing function.
266    trait_assoc_ty.visibility(tcx.visibility(fn_def_id));
267
268    // Copy defaultness of the containing function.
269    trait_assoc_ty.defaultness(tcx.defaultness(fn_def_id));
270
271    // There are no inferred outlives for the synthesized associated type.
272    trait_assoc_ty.inferred_outlives_of(&[]);
273
274    local_def_id
275}
276
277/// Given an `trait_assoc_def_id` corresponding to an associated item synthesized
278/// from an `impl Trait` in an associated function from a trait, and an
279/// `impl_fn` that represents an implementation of the associated function
280/// that the `impl Trait` comes from, synthesize an associated type for that `impl Trait`
281/// that inherits properties that we infer from the method and the associated type.
282fn associated_type_for_impl_trait_in_impl(
283    tcx: TyCtxt<'_>,
284    trait_assoc_def_id: DefId,
285    impl_fn: &hir::ImplItem<'_>,
286    disambiguator: &mut DisambiguatorState,
287) -> LocalDefId {
288    let impl_local_def_id = tcx.local_parent(impl_fn.owner_id.def_id);
289
290    let hir::ImplItemKind::Fn(fn_sig, _) = impl_fn.kind else { ::rustc_middle::util::bug::bug_fmt(format_args!("expected decl"))bug!("expected decl") };
291    let span = match fn_sig.decl.output {
292        hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn.owner_id),
293        hir::FnRetTy::Return(ty) => ty.span,
294    };
295
296    // Use the same disambiguator and method name as the anon associated type in the trait.
297    let disambiguated_data = tcx.def_key(trait_assoc_def_id).disambiguated_data;
298    let DefPathData::AnonAssocTy(name) = disambiguated_data.data else {
299        ::rustc_middle::util::bug::bug_fmt(format_args!("expected anon associated type"))bug!("expected anon associated type")
300    };
301    let data = DefPathData::AnonAssocTy(name);
302
303    let impl_assoc_ty = tcx.at(span).create_def(
304        impl_local_def_id,
305        // No name because this is an anonymous associated type.
306        None,
307        DefKind::AssocTy,
308        Some(data),
309        disambiguator,
310    );
311
312    let local_def_id = impl_assoc_ty.def_id();
313    let def_id = local_def_id.to_def_id();
314
315    impl_assoc_ty.feed_hir();
316
317    // Copy span of the opaque.
318    impl_assoc_ty.def_ident_span(Some(span));
319
320    impl_assoc_ty.associated_item(ty::AssocItem {
321        kind: ty::AssocKind::Type {
322            data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl {
323                fn_def_id: impl_fn.owner_id.to_def_id(),
324            }),
325        },
326        def_id,
327        container: ty::AssocContainer::TraitImpl(Ok(trait_assoc_def_id)),
328    });
329
330    // Copy visility of the containing function.
331    impl_assoc_ty.visibility(tcx.visibility(impl_fn.owner_id));
332
333    // Copy defaultness of the containing function.
334    impl_assoc_ty.defaultness(tcx.defaultness(impl_fn.owner_id));
335
336    // Copy generics_of the trait's associated item but the impl as the parent.
337    // FIXME: This may be detrimental to diagnostics, as we resolve the early-bound vars
338    // here to paramswhose parent are items in the trait. We could synthesize new params
339    // here, but it seems overkill.
340    impl_assoc_ty.generics_of({
341        let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
342        let trait_assoc_parent_count = trait_assoc_generics.parent_count;
343        let mut own_params = trait_assoc_generics.own_params.clone();
344
345        let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id());
346        let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
347
348        for param in &mut own_params {
349            param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
350        }
351
352        let param_def_id_to_index =
353            own_params.iter().map(|param| (param.def_id, param.index)).collect();
354
355        ty::Generics {
356            parent: Some(impl_local_def_id.to_def_id()),
357            parent_count,
358            own_params,
359            param_def_id_to_index,
360            has_self: false,
361            has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
362        }
363    });
364
365    // There are no inferred outlives for the synthesized associated type.
366    impl_assoc_ty.inferred_outlives_of(&[]);
367
368    local_def_id
369}