Skip to main content

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