rustc_trait_selection/traits/
util.rs1use std::collections::{BTreeMap, VecDeque};
2
3use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
4use rustc_hir::LangItem;
5use rustc_hir::def_id::DefId;
6use rustc_infer::infer::InferCtxt;
7pub use rustc_infer::traits::util::*;
8use rustc_middle::bug;
9use rustc_middle::ty::{
10 self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
11};
12use rustc_span::Span;
13use smallvec::{SmallVec, smallvec};
14use tracing::debug;
15
16pub fn expand_trait_aliases<'tcx>(
32 tcx: TyCtxt<'tcx>,
33 clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
34) -> (
35 Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>,
36 Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>,
37) {
38 let mut trait_preds = vec![];
39 let mut projection_preds = vec![];
40 let mut seen_projection_preds = FxHashSet::default();
41
42 let mut queue: VecDeque<_> = clauses.into_iter().map(|(p, s)| (p, smallvec![s])).collect();
43
44 while let Some((clause, spans)) = queue.pop_front() {
45 match clause.kind().skip_binder() {
46 ty::ClauseKind::Trait(trait_pred) => {
47 if tcx.is_trait_alias(trait_pred.def_id()) {
48 queue.extend(
49 tcx.explicit_super_predicates_of(trait_pred.def_id())
50 .iter_identity_copied()
51 .map(|(super_clause, span)| {
52 let mut spans = spans.clone();
53 spans.push(span);
54 (
55 super_clause.instantiate_supertrait(
56 tcx,
57 clause.kind().rebind(trait_pred.trait_ref),
58 ),
59 spans,
60 )
61 }),
62 );
63 } else {
64 trait_preds.push((clause.kind().rebind(trait_pred), spans));
65 }
66 }
67 ty::ClauseKind::Projection(projection_pred) => {
68 let projection_pred = clause.kind().rebind(projection_pred);
69 if !seen_projection_preds.insert(tcx.anonymize_bound_vars(projection_pred)) {
70 continue;
71 }
72 projection_preds.push((projection_pred, *spans.last().unwrap()));
73 }
74 ty::ClauseKind::RegionOutlives(..)
75 | ty::ClauseKind::TypeOutlives(..)
76 | ty::ClauseKind::ConstArgHasType(_, _)
77 | ty::ClauseKind::WellFormed(_)
78 | ty::ClauseKind::ConstEvaluatable(_)
79 | ty::ClauseKind::HostEffect(..) => {}
80 }
81 }
82
83 (trait_preds, projection_preds)
84}
85
86pub fn upcast_choices<'tcx>(
94 tcx: TyCtxt<'tcx>,
95 source_trait_ref: ty::PolyTraitRef<'tcx>,
96 target_trait_def_id: DefId,
97) -> Vec<ty::PolyTraitRef<'tcx>> {
98 if source_trait_ref.def_id() == target_trait_def_id {
99 return vec![source_trait_ref]; }
101
102 supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect()
103}
104
105pub(crate) fn closure_trait_ref_and_return_type<'tcx>(
106 tcx: TyCtxt<'tcx>,
107 fn_trait_def_id: DefId,
108 self_ty: Ty<'tcx>,
109 sig: ty::PolyFnSig<'tcx>,
110 tuple_arguments: TupleArgumentsFlag,
111) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
112 assert!(!self_ty.has_escaping_bound_vars());
113 let arguments_tuple = match tuple_arguments {
114 TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
115 TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
116 };
117 let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
118 sig.map_bound(|sig| (trait_ref, sig.output()))
119}
120
121pub(crate) fn coroutine_trait_ref_and_outputs<'tcx>(
122 tcx: TyCtxt<'tcx>,
123 fn_trait_def_id: DefId,
124 self_ty: Ty<'tcx>,
125 sig: ty::GenSig<TyCtxt<'tcx>>,
126) -> (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>) {
127 assert!(!self_ty.has_escaping_bound_vars());
128 let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.resume_ty]);
129 (trait_ref, sig.yield_ty, sig.return_ty)
130}
131
132pub(crate) fn future_trait_ref_and_outputs<'tcx>(
133 tcx: TyCtxt<'tcx>,
134 fn_trait_def_id: DefId,
135 self_ty: Ty<'tcx>,
136 sig: ty::GenSig<TyCtxt<'tcx>>,
137) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
138 assert!(!self_ty.has_escaping_bound_vars());
139 let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]);
140 (trait_ref, sig.return_ty)
141}
142
143pub(crate) fn iterator_trait_ref_and_outputs<'tcx>(
144 tcx: TyCtxt<'tcx>,
145 iterator_def_id: DefId,
146 self_ty: Ty<'tcx>,
147 sig: ty::GenSig<TyCtxt<'tcx>>,
148) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
149 assert!(!self_ty.has_escaping_bound_vars());
150 let trait_ref = ty::TraitRef::new(tcx, iterator_def_id, [self_ty]);
151 (trait_ref, sig.yield_ty)
152}
153
154pub(crate) fn async_iterator_trait_ref_and_outputs<'tcx>(
155 tcx: TyCtxt<'tcx>,
156 async_iterator_def_id: DefId,
157 self_ty: Ty<'tcx>,
158 sig: ty::GenSig<TyCtxt<'tcx>>,
159) -> (ty::TraitRef<'tcx>, Ty<'tcx>) {
160 assert!(!self_ty.has_escaping_bound_vars());
161 let trait_ref = ty::TraitRef::new(tcx, async_iterator_def_id, [self_ty]);
162 (trait_ref, sig.yield_ty)
163}
164
165pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
166 assoc_item.defaultness(tcx).is_final()
167 && tcx.defaultness(assoc_item.container_id(tcx)).is_final()
168}
169
170pub(crate) enum TupleArgumentsFlag {
171 Yes,
172 No,
173}
174
175pub fn with_replaced_escaping_bound_vars<
188 'a,
189 'tcx,
190 T: TypeFoldable<TyCtxt<'tcx>>,
191 R: TypeFoldable<TyCtxt<'tcx>>,
192>(
193 infcx: &'a InferCtxt<'tcx>,
194 universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
195 value: T,
196 f: impl FnOnce(T) -> R,
197) -> R {
198 if value.has_escaping_bound_vars() {
199 let (value, mapped_regions, mapped_types, mapped_consts) =
200 BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value);
201 let result = f(value);
202 PlaceholderReplacer::replace_placeholders(
203 infcx,
204 mapped_regions,
205 mapped_types,
206 mapped_consts,
207 universe_indices,
208 result,
209 )
210 } else {
211 f(value)
212 }
213}
214
215pub struct BoundVarReplacer<'a, 'tcx> {
216 infcx: &'a InferCtxt<'tcx>,
217 mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
221 mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
222 mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
223 current_index: ty::DebruijnIndex,
226 universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
229}
230
231impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> {
232 pub fn replace_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
235 infcx: &'a InferCtxt<'tcx>,
236 universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
237 value: T,
238 ) -> (
239 T,
240 FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
241 FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
242 BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
243 ) {
244 let mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion> =
245 FxIndexMap::default();
246 let mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy> = FxIndexMap::default();
247 let mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar> = BTreeMap::new();
248
249 let mut replacer = BoundVarReplacer {
250 infcx,
251 mapped_regions,
252 mapped_types,
253 mapped_consts,
254 current_index: ty::INNERMOST,
255 universe_indices,
256 };
257
258 let value = value.fold_with(&mut replacer);
259
260 (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
261 }
262
263 fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
264 let infcx = self.infcx;
265 let index =
266 self.universe_indices.len() + self.current_index.as_usize() - debruijn.as_usize() - 1;
267 let universe = self.universe_indices[index].unwrap_or_else(|| {
268 for i in self.universe_indices.iter_mut().take(index + 1) {
269 *i = i.or_else(|| Some(infcx.create_next_universe()))
270 }
271 self.universe_indices[index].unwrap()
272 });
273 universe
274 }
275}
276
277impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> {
278 fn cx(&self) -> TyCtxt<'tcx> {
279 self.infcx.tcx
280 }
281
282 fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
283 &mut self,
284 t: ty::Binder<'tcx, T>,
285 ) -> ty::Binder<'tcx, T> {
286 self.current_index.shift_in(1);
287 let t = t.super_fold_with(self);
288 self.current_index.shift_out(1);
289 t
290 }
291
292 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
293 match r.kind() {
294 ty::ReBound(debruijn, _)
295 if debruijn.as_usize()
296 >= self.current_index.as_usize() + self.universe_indices.len() =>
297 {
298 bug!(
299 "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}",
300 self.universe_indices
301 );
302 }
303 ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
304 let universe = self.universe_for(debruijn);
305 let p = ty::PlaceholderRegion { universe, bound: br };
306 self.mapped_regions.insert(p, br);
307 ty::Region::new_placeholder(self.infcx.tcx, p)
308 }
309 _ => r,
310 }
311 }
312
313 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
314 match *t.kind() {
315 ty::Bound(debruijn, _)
316 if debruijn.as_usize() + 1
317 > self.current_index.as_usize() + self.universe_indices.len() =>
318 {
319 bug!(
320 "Bound vars {t:#?} outside of `self.universe_indices`: {:#?}",
321 self.universe_indices
322 );
323 }
324 ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
325 let universe = self.universe_for(debruijn);
326 let p = ty::PlaceholderType { universe, bound: bound_ty };
327 self.mapped_types.insert(p, bound_ty);
328 Ty::new_placeholder(self.infcx.tcx, p)
329 }
330 _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
331 _ => t,
332 }
333 }
334
335 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
336 match ct.kind() {
337 ty::ConstKind::Bound(debruijn, _)
338 if debruijn.as_usize() + 1
339 > self.current_index.as_usize() + self.universe_indices.len() =>
340 {
341 bug!(
342 "Bound vars {ct:#?} outside of `self.universe_indices`: {:#?}",
343 self.universe_indices
344 );
345 }
346 ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
347 let universe = self.universe_for(debruijn);
348 let p = ty::PlaceholderConst { universe, bound: bound_const };
349 self.mapped_consts.insert(p, bound_const);
350 ty::Const::new_placeholder(self.infcx.tcx, p)
351 }
352 _ => ct.super_fold_with(self),
353 }
354 }
355
356 fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
357 if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
358 }
359}
360
361pub struct PlaceholderReplacer<'a, 'tcx> {
363 infcx: &'a InferCtxt<'tcx>,
364 mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
365 mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
366 mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
367 universe_indices: &'a [Option<ty::UniverseIndex>],
368 current_index: ty::DebruijnIndex,
369}
370
371impl<'a, 'tcx> PlaceholderReplacer<'a, 'tcx> {
372 pub fn replace_placeholders<T: TypeFoldable<TyCtxt<'tcx>>>(
373 infcx: &'a InferCtxt<'tcx>,
374 mapped_regions: FxIndexMap<ty::PlaceholderRegion, ty::BoundRegion>,
375 mapped_types: FxIndexMap<ty::PlaceholderType, ty::BoundTy>,
376 mapped_consts: BTreeMap<ty::PlaceholderConst, ty::BoundVar>,
377 universe_indices: &'a [Option<ty::UniverseIndex>],
378 value: T,
379 ) -> T {
380 let mut replacer = PlaceholderReplacer {
381 infcx,
382 mapped_regions,
383 mapped_types,
384 mapped_consts,
385 universe_indices,
386 current_index: ty::INNERMOST,
387 };
388 value.fold_with(&mut replacer)
389 }
390}
391
392impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
393 fn cx(&self) -> TyCtxt<'tcx> {
394 self.infcx.tcx
395 }
396
397 fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
398 &mut self,
399 t: ty::Binder<'tcx, T>,
400 ) -> ty::Binder<'tcx, T> {
401 if !t.has_placeholders() && !t.has_infer() {
402 return t;
403 }
404 self.current_index.shift_in(1);
405 let t = t.super_fold_with(self);
406 self.current_index.shift_out(1);
407 t
408 }
409
410 fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
411 let r1 = match r0.kind() {
412 ty::ReVar(vid) => self
413 .infcx
414 .inner
415 .borrow_mut()
416 .unwrap_region_constraints()
417 .opportunistic_resolve_var(self.infcx.tcx, vid),
418 _ => r0,
419 };
420
421 let r2 = match r1.kind() {
422 ty::RePlaceholder(p) => {
423 let replace_var = self.mapped_regions.get(&p);
424 match replace_var {
425 Some(replace_var) => {
426 let index = self
427 .universe_indices
428 .iter()
429 .position(|u| matches!(u, Some(pu) if *pu == p.universe))
430 .unwrap_or_else(|| bug!("Unexpected placeholder universe."));
431 let db = ty::DebruijnIndex::from_usize(
432 self.universe_indices.len() - index + self.current_index.as_usize() - 1,
433 );
434 ty::Region::new_bound(self.cx(), db, *replace_var)
435 }
436 None => r1,
437 }
438 }
439 _ => r1,
440 };
441
442 debug!(?r0, ?r1, ?r2, "fold_region");
443
444 r2
445 }
446
447 fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
448 let ty = self.infcx.shallow_resolve(ty);
449 match *ty.kind() {
450 ty::Placeholder(p) => {
451 let replace_var = self.mapped_types.get(&p);
452 match replace_var {
453 Some(replace_var) => {
454 let index = self
455 .universe_indices
456 .iter()
457 .position(|u| matches!(u, Some(pu) if *pu == p.universe))
458 .unwrap_or_else(|| bug!("Unexpected placeholder universe."));
459 let db = ty::DebruijnIndex::from_usize(
460 self.universe_indices.len() - index + self.current_index.as_usize() - 1,
461 );
462 Ty::new_bound(self.infcx.tcx, db, *replace_var)
463 }
464 None => {
465 if ty.has_infer() {
466 ty.super_fold_with(self)
467 } else {
468 ty
469 }
470 }
471 }
472 }
473
474 _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self),
475 _ => ty,
476 }
477 }
478
479 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
480 let ct = self.infcx.shallow_resolve_const(ct);
481 if let ty::ConstKind::Placeholder(p) = ct.kind() {
482 let replace_var = self.mapped_consts.get(&p);
483 match replace_var {
484 Some(replace_var) => {
485 let index = self
486 .universe_indices
487 .iter()
488 .position(|u| matches!(u, Some(pu) if *pu == p.universe))
489 .unwrap_or_else(|| bug!("Unexpected placeholder universe."));
490 let db = ty::DebruijnIndex::from_usize(
491 self.universe_indices.len() - index + self.current_index.as_usize() - 1,
492 );
493 ty::Const::new_bound(self.infcx.tcx, db, *replace_var)
494 }
495 None => {
496 if ct.has_infer() {
497 ct.super_fold_with(self)
498 } else {
499 ct
500 }
501 }
502 }
503 } else {
504 ct.super_fold_with(self)
505 }
506 }
507}
508
509pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>) -> bool {
510 if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
514 predicate.kind().skip_binder()
515 {
516 if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized)
517 && trait_ref.self_ty().is_trivially_sized(tcx)
518 {
519 debug!("fast path -- trivial sizedness");
520 return true;
521 }
522 }
523
524 false
525}