1 use super::NormalizeExt;
2 use super::{ObligationCause, PredicateObligation, SelectionContext};
3 use rustc_data_structures::fx::FxHashSet;
4 use rustc_errors::Diagnostic;
5 use rustc_hir::def_id::DefId;
6 use rustc_infer::infer::InferOk;
7 use rustc_middle::ty::SubstsRef;
8 use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
9 use rustc_span::Span;
10 use smallvec::SmallVec;
11
12 pub use rustc_infer::traits::{self, util::*};
13
14 ///////////////////////////////////////////////////////////////////////////
15 // `TraitAliasExpander` iterator
16 ///////////////////////////////////////////////////////////////////////////
17
18 /// "Trait alias expansion" is the process of expanding a sequence of trait
19 /// references into another sequence by transitively following all trait
20 /// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
21 /// `trait Foo = Bar + Sync;`, and another trait alias
22 /// `trait Bar = Read + Write`, then the bounds would expand to
23 /// `Read + Write + Sync + Send`.
24 /// Expansion is done via a DFS (depth-first search), and the `visited` field
25 /// is used to avoid cycles.
26 pub struct TraitAliasExpander<'tcx> {
27 tcx: TyCtxt<'tcx>,
28 stack: Vec<TraitAliasExpansionInfo<'tcx>>,
29 }
30
31 /// Stores information about the expansion of a trait via a path of zero or more trait aliases.
32 #[derive(Debug, Clone)]
33 pub struct TraitAliasExpansionInfo<'tcx> {
34 pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
35 }
36
37 impl<'tcx> TraitAliasExpansionInfo<'tcx> {
new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self38 fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
39 Self { path: smallvec![(trait_ref, span)] }
40 }
41
42 /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate
43 /// trait aliases.
label_with_exp_info( &self, diag: &mut Diagnostic, top_label: &'static str, use_desc: &str, )44 pub fn label_with_exp_info(
45 &self,
46 diag: &mut Diagnostic,
47 top_label: &'static str,
48 use_desc: &str,
49 ) {
50 diag.span_label(self.top().1, top_label);
51 if self.path.len() > 1 {
52 for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {
53 diag.span_label(*sp, format!("referenced here ({})", use_desc));
54 }
55 }
56 if self.top().1 != self.bottom().1 {
57 // When the trait object is in a return type these two spans match, we don't want
58 // redundant labels.
59 diag.span_label(
60 self.bottom().1,
61 format!("trait alias used in trait object type ({})", use_desc),
62 );
63 }
64 }
65
trait_ref(&self) -> ty::PolyTraitRef<'tcx>66 pub fn trait_ref(&self) -> ty::PolyTraitRef<'tcx> {
67 self.top().0
68 }
69
top(&self) -> &(ty::PolyTraitRef<'tcx>, Span)70 pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
71 self.path.last().unwrap()
72 }
73
bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span)74 pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
75 self.path.first().unwrap()
76 }
77
clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self78 fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
79 let mut path = self.path.clone();
80 path.push((trait_ref, span));
81
82 Self { path }
83 }
84 }
85
expand_trait_aliases<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>, ) -> TraitAliasExpander<'tcx>86 pub fn expand_trait_aliases<'tcx>(
87 tcx: TyCtxt<'tcx>,
88 trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>,
89 ) -> TraitAliasExpander<'tcx> {
90 let items: Vec<_> =
91 trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect();
92 TraitAliasExpander { tcx, stack: items }
93 }
94
95 impl<'tcx> TraitAliasExpander<'tcx> {
96 /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
97 /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`.
98 /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a
99 /// trait alias.
100 /// The return value indicates whether `item` should be yielded to the user.
expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool101 fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
102 let tcx = self.tcx;
103 let trait_ref = item.trait_ref();
104 let pred = trait_ref.without_const().to_predicate(tcx);
105
106 debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
107
108 // Don't recurse if this bound is not a trait alias.
109 let is_alias = tcx.is_trait_alias(trait_ref.def_id());
110 if !is_alias {
111 return true;
112 }
113
114 // Don't recurse if this trait alias is already on the stack for the DFS search.
115 let anon_pred = anonymize_predicate(tcx, pred);
116 if item.path.iter().rev().skip(1).any(|&(tr, _)| {
117 anonymize_predicate(tcx, tr.without_const().to_predicate(tcx)) == anon_pred
118 }) {
119 return false;
120 }
121
122 // Get components of trait alias.
123 let predicates = tcx.implied_predicates_of(trait_ref.def_id());
124 debug!(?predicates);
125
126 let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
127 pred.subst_supertrait(tcx, &trait_ref)
128 .as_trait_clause()
129 .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
130 });
131 debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>());
132
133 self.stack.extend(items);
134
135 false
136 }
137 }
138
139 impl<'tcx> Iterator for TraitAliasExpander<'tcx> {
140 type Item = TraitAliasExpansionInfo<'tcx>;
141
size_hint(&self) -> (usize, Option<usize>)142 fn size_hint(&self) -> (usize, Option<usize>) {
143 (self.stack.len(), None)
144 }
145
next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>>146 fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {
147 while let Some(item) = self.stack.pop() {
148 if self.expand(&item) {
149 return Some(item);
150 }
151 }
152 None
153 }
154 }
155
156 ///////////////////////////////////////////////////////////////////////////
157 // Iterator over def-IDs of supertraits
158 ///////////////////////////////////////////////////////////////////////////
159
160 pub struct SupertraitDefIds<'tcx> {
161 tcx: TyCtxt<'tcx>,
162 stack: Vec<DefId>,
163 visited: FxHashSet<DefId>,
164 }
165
supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDefIds<'_>166 pub fn supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDefIds<'_> {
167 SupertraitDefIds {
168 tcx,
169 stack: vec![trait_def_id],
170 visited: Some(trait_def_id).into_iter().collect(),
171 }
172 }
173
174 impl Iterator for SupertraitDefIds<'_> {
175 type Item = DefId;
176
next(&mut self) -> Option<DefId>177 fn next(&mut self) -> Option<DefId> {
178 let def_id = self.stack.pop()?;
179 let predicates = self.tcx.super_predicates_of(def_id);
180 let visited = &mut self.visited;
181 self.stack.extend(
182 predicates
183 .predicates
184 .iter()
185 .filter_map(|(pred, _)| pred.as_trait_clause())
186 .map(|trait_ref| trait_ref.def_id())
187 .filter(|&super_def_id| visited.insert(super_def_id)),
188 );
189 Some(def_id)
190 }
191 }
192
193 ///////////////////////////////////////////////////////////////////////////
194 // Other
195 ///////////////////////////////////////////////////////////////////////////
196
197 /// Instantiate all bound parameters of the impl subject with the given substs,
198 /// returning the resulting subject and all obligations that arise.
199 /// The obligations are closed under normalization.
impl_subject_and_oblig<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, impl_def_id: DefId, impl_substs: SubstsRef<'tcx>, cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>)200 pub fn impl_subject_and_oblig<'a, 'tcx>(
201 selcx: &mut SelectionContext<'a, 'tcx>,
202 param_env: ty::ParamEnv<'tcx>,
203 impl_def_id: DefId,
204 impl_substs: SubstsRef<'tcx>,
205 cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
206 ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
207 let subject = selcx.tcx().impl_subject(impl_def_id);
208 let subject = subject.subst(selcx.tcx(), impl_substs);
209
210 let InferOk { value: subject, obligations: normalization_obligations1 } =
211 selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(subject);
212
213 let predicates = selcx.tcx().predicates_of(impl_def_id);
214 let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
215 let InferOk { value: predicates, obligations: normalization_obligations2 } =
216 selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates);
217 let impl_obligations = super::predicates_for_generics(cause, param_env, predicates);
218
219 let impl_obligations = impl_obligations
220 .chain(normalization_obligations1.into_iter())
221 .chain(normalization_obligations2.into_iter());
222
223 (subject, impl_obligations)
224 }
225
226 /// Casts a trait reference into a reference to one of its super
227 /// traits; returns `None` if `target_trait_def_id` is not a
228 /// supertrait.
upcast_choices<'tcx>( tcx: TyCtxt<'tcx>, source_trait_ref: ty::PolyTraitRef<'tcx>, target_trait_def_id: DefId, ) -> Vec<ty::PolyTraitRef<'tcx>>229 pub fn upcast_choices<'tcx>(
230 tcx: TyCtxt<'tcx>,
231 source_trait_ref: ty::PolyTraitRef<'tcx>,
232 target_trait_def_id: DefId,
233 ) -> Vec<ty::PolyTraitRef<'tcx>> {
234 if source_trait_ref.def_id() == target_trait_def_id {
235 return vec![source_trait_ref]; // Shortcut the most common case.
236 }
237
238 supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
239 }
240
241 /// Given an upcast trait object described by `object`, returns the
242 /// index of the method `method_def_id` (which should be part of
243 /// `object.upcast_trait_ref`) within the vtable for `object`.
get_vtable_index_of_object_method<'tcx, N>( tcx: TyCtxt<'tcx>, object: &super::ImplSourceObjectData<N>, method_def_id: DefId, ) -> Option<usize>244 pub fn get_vtable_index_of_object_method<'tcx, N>(
245 tcx: TyCtxt<'tcx>,
246 object: &super::ImplSourceObjectData<N>,
247 method_def_id: DefId,
248 ) -> Option<usize> {
249 // Count number of methods preceding the one we are selecting and
250 // add them to the total offset.
251 tcx.own_existential_vtable_entries(tcx.parent(method_def_id))
252 .iter()
253 .copied()
254 .position(|def_id| def_id == method_def_id)
255 .map(|index| object.vtable_base + index)
256 }
257
closure_trait_ref_and_return_type<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, sig: ty::PolyFnSig<'tcx>, tuple_arguments: TupleArgumentsFlag, ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)>258 pub fn closure_trait_ref_and_return_type<'tcx>(
259 tcx: TyCtxt<'tcx>,
260 fn_trait_def_id: DefId,
261 self_ty: Ty<'tcx>,
262 sig: ty::PolyFnSig<'tcx>,
263 tuple_arguments: TupleArgumentsFlag,
264 ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
265 assert!(!self_ty.has_escaping_bound_vars());
266 let arguments_tuple = match tuple_arguments {
267 TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
268 TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
269 };
270 let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
271 sig.map_bound(|sig| (trait_ref, sig.output()))
272 }
273
generator_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, sig: ty::PolyGenSig<'tcx>, ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)>274 pub fn generator_trait_ref_and_outputs<'tcx>(
275 tcx: TyCtxt<'tcx>,
276 fn_trait_def_id: DefId,
277 self_ty: Ty<'tcx>,
278 sig: ty::PolyGenSig<'tcx>,
279 ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
280 assert!(!self_ty.has_escaping_bound_vars());
281 let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.skip_binder().resume_ty]);
282 sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty))
283 }
284
future_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, sig: ty::PolyGenSig<'tcx>, ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)>285 pub fn future_trait_ref_and_outputs<'tcx>(
286 tcx: TyCtxt<'tcx>,
287 fn_trait_def_id: DefId,
288 self_ty: Ty<'tcx>,
289 sig: ty::PolyGenSig<'tcx>,
290 ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
291 assert!(!self_ty.has_escaping_bound_vars());
292 let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]);
293 sig.map_bound(|sig| (trait_ref, sig.return_ty))
294 }
295
impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool296 pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
297 assoc_item.defaultness(tcx).is_final()
298 && tcx.defaultness(assoc_item.container_id(tcx)).is_final()
299 }
300
301 pub enum TupleArgumentsFlag {
302 Yes,
303 No,
304 }
305
306 // Verify that the trait item and its implementation have compatible substs lists
check_substs_compatible<'tcx>( tcx: TyCtxt<'tcx>, assoc_item: ty::AssocItem, substs: ty::SubstsRef<'tcx>, ) -> bool307 pub fn check_substs_compatible<'tcx>(
308 tcx: TyCtxt<'tcx>,
309 assoc_item: ty::AssocItem,
310 substs: ty::SubstsRef<'tcx>,
311 ) -> bool {
312 fn check_substs_compatible_inner<'tcx>(
313 tcx: TyCtxt<'tcx>,
314 generics: &'tcx ty::Generics,
315 args: &'tcx [ty::GenericArg<'tcx>],
316 ) -> bool {
317 if generics.count() != args.len() {
318 return false;
319 }
320
321 let (parent_args, own_args) = args.split_at(generics.parent_count);
322
323 if let Some(parent) = generics.parent
324 && let parent_generics = tcx.generics_of(parent)
325 && !check_substs_compatible_inner(tcx, parent_generics, parent_args) {
326 return false;
327 }
328
329 for (param, arg) in std::iter::zip(&generics.params, own_args) {
330 match (¶m.kind, arg.unpack()) {
331 (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
332 | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
333 | (ty::GenericParamDefKind::Const { .. }, ty::GenericArgKind::Const(_)) => {}
334 _ => return false,
335 }
336 }
337
338 true
339 }
340
341 let generics = tcx.generics_of(assoc_item.def_id);
342 // Chop off any additional substs (RPITIT) substs
343 let substs = &substs[0..generics.count().min(substs.len())];
344 check_substs_compatible_inner(tcx, generics, substs)
345 }
346