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 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 let mut mapping = FxHashMap::default();
69 let generics = tcx.generics_of(def_id);
70
71 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 let remapped_wf_tys = fold_regions(
91 tcx,
92 tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(),
93 |region, _| {
94 if let Some(remapped_region) = mapping.get(®ion) {
98 *remapped_region
99 } else {
100 region
101 }
102 },
103 );
104 tcx.arena.alloc_from_iter(remapped_wf_tys)
105 }
106 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}