rustc_ty_utils/
implied_bounds.rs

1use std::iter;
2
3use rustc_data_structures::fx::FxHashMap;
4use rustc_hir as hir;
5use rustc_hir::def::DefKind;
6use rustc_hir::def_id::LocalDefId;
7use rustc_middle::bug;
8use rustc_middle::query::Providers;
9use rustc_middle::ty::fold::fold_regions;
10use rustc_middle::ty::{self, Ty, TyCtxt};
11use rustc_span::Span;
12
13pub(crate) fn provide(providers: &mut Providers) {
14    *providers = Providers {
15        assumed_wf_types,
16        assumed_wf_types_for_rpitit: |tcx, def_id| {
17            assert!(tcx.is_impl_trait_in_trait(def_id.to_def_id()));
18            tcx.assumed_wf_types(def_id)
19        },
20        ..*providers
21    };
22}
23
24fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<'tcx>, Span)] {
25    match tcx.def_kind(def_id) {
26        DefKind::Fn => {
27            let sig = tcx.fn_sig(def_id).instantiate_identity();
28            let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
29            tcx.arena.alloc_from_iter(itertools::zip_eq(
30                liberated_sig.inputs_and_output,
31                fn_sig_spans(tcx, def_id),
32            ))
33        }
34        DefKind::AssocFn => {
35            let sig = tcx.fn_sig(def_id).instantiate_identity();
36            let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig);
37            let mut assumed_wf_types: Vec<_> =
38                tcx.assumed_wf_types(tcx.local_parent(def_id)).into();
39            assumed_wf_types.extend(itertools::zip_eq(
40                liberated_sig.inputs_and_output,
41                fn_sig_spans(tcx, def_id),
42            ));
43            tcx.arena.alloc_slice(&assumed_wf_types)
44        }
45        DefKind::Impl { .. } => {
46            // Trait arguments and the self type for trait impls or only the self type for
47            // inherent impls.
48            let tys = match tcx.impl_trait_ref(def_id) {
49                Some(trait_ref) => trait_ref.skip_binder().args.types().collect(),
50                None => vec![tcx.type_of(def_id).instantiate_identity()],
51            };
52
53            let mut impl_spans = impl_spans(tcx, def_id);
54            tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap())))
55        }
56        DefKind::AssocTy if let Some(data) = tcx.opt_rpitit_info(def_id.to_def_id()) => {
57            match data {
58                ty::ImplTraitInTraitData::Trait { fn_def_id, .. } => {
59                    // We need to remap all of the late-bound lifetimes in the assumed wf types
60                    // of the fn (which are represented as ReLateParam) to the early-bound lifetimes
61                    // of the RPITIT (which are represented by ReEarlyParam owned by the opaque).
62                    // Luckily, this is very easy to do because we already have that mapping
63                    // stored in the HIR of this RPITIT.
64                    //
65                    // Side-note: We don't really need to do this remapping for early-bound
66                    // lifetimes because they're already "linked" by the bidirectional outlives
67                    // predicates we insert in the `explicit_predicates_of` query for RPITITs.
68                    let mut mapping = FxHashMap::default();
69                    let generics = tcx.generics_of(def_id);
70
71                    // For each captured opaque lifetime, if it's late-bound (`ReLateParam` in this
72                    // case, since it has been liberated), map it back to the early-bound lifetime of
73                    // the GAT. Since RPITITs also have all of the fn's generics, we slice only
74                    // the end of the list corresponding to the opaque's generics.
75                    for param in &generics.own_params[tcx.generics_of(fn_def_id).own_params.len()..]
76                    {
77                        let orig_lt =
78                            tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local());
79                        if matches!(*orig_lt, ty::ReLateParam(..)) {
80                            mapping.insert(
81                                orig_lt,
82                                ty::Region::new_early_param(
83                                    tcx,
84                                    ty::EarlyParamRegion { index: param.index, name: param.name },
85                                ),
86                            );
87                        }
88                    }
89                    // FIXME: This could use a real folder, I guess.
90                    let remapped_wf_tys = fold_regions(
91                        tcx,
92                        tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(),
93                        |region, _| {
94                            // If `region` is a `ReLateParam` that is captured by the
95                            // opaque, remap it to its corresponding the early-
96                            // bound region.
97                            if let Some(remapped_region) = mapping.get(&region) {
98                                *remapped_region
99                            } else {
100                                region
101                            }
102                        },
103                    );
104                    tcx.arena.alloc_from_iter(remapped_wf_tys)
105                }
106                // Assumed wf types for RPITITs in an impl just inherit (and instantiate)
107                // the assumed wf types of the trait's RPITIT GAT.
108                ty::ImplTraitInTraitData::Impl { .. } => {
109                    let impl_def_id = tcx.local_parent(def_id);
110                    let rpitit_def_id = tcx.associated_item(def_id).trait_item_def_id.unwrap();
111                    let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto(
112                        tcx,
113                        impl_def_id.to_def_id(),
114                        tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity().args,
115                    );
116                    tcx.arena.alloc_from_iter(
117                        ty::EarlyBinder::bind(tcx.assumed_wf_types_for_rpitit(rpitit_def_id))
118                            .iter_instantiated_copied(tcx, args)
119                            .chain(tcx.assumed_wf_types(impl_def_id).into_iter().copied()),
120                    )
121                }
122            }
123        }
124        DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)),
125        DefKind::OpaqueTy => bug!("implied bounds are not defined for opaques"),
126        DefKind::Mod
127        | DefKind::Struct
128        | DefKind::Union
129        | DefKind::Enum
130        | DefKind::Variant
131        | DefKind::Trait
132        | DefKind::TyAlias
133        | DefKind::ForeignTy
134        | DefKind::TraitAlias
135        | DefKind::TyParam
136        | DefKind::Const
137        | DefKind::ConstParam
138        | DefKind::Static { .. }
139        | DefKind::Ctor(_, _)
140        | DefKind::Macro(_)
141        | DefKind::ExternCrate
142        | DefKind::Use
143        | DefKind::ForeignMod
144        | DefKind::AnonConst
145        | DefKind::InlineConst
146        | DefKind::Field
147        | DefKind::LifetimeParam
148        | DefKind::GlobalAsm
149        | DefKind::Closure
150        | DefKind::SyntheticCoroutineBody => ty::List::empty(),
151    }
152}
153
154fn fn_sig_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> + '_ {
155    let node = tcx.hir_node_by_def_id(def_id);
156    if let Some(decl) = node.fn_decl() {
157        decl.inputs.iter().map(|ty| ty.span).chain(iter::once(decl.output.span()))
158    } else {
159        bug!("unexpected item for fn {def_id:?}: {node:?}")
160    }
161}
162
163fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span> + '_ {
164    let item = tcx.hir().expect_item(def_id);
165    if let hir::ItemKind::Impl(impl_) = item.kind {
166        let trait_args = impl_
167            .of_trait
168            .into_iter()
169            .flat_map(|trait_ref| trait_ref.path.segments.last().unwrap().args().args)
170            .map(|arg| arg.span());
171        let dummy_spans_for_default_args =
172            impl_.of_trait.into_iter().flat_map(|trait_ref| iter::repeat(trait_ref.path.span));
173        iter::once(impl_.self_ty.span).chain(trait_args).chain(dummy_spans_for_default_args)
174    } else {
175        bug!("unexpected item for impl {def_id:?}: {item:?}")
176    }
177}