• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (&param.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