1 //! This module contains the "canonicalizer" itself.
3 //! For an overview of what canonicalization is and how it fits into
4 //! rustc, check out the [chapter in the rustc dev guide][c].
6 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
8 use crate::infer::canonical::{
9 Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
11 use crate::infer::InferCtxt;
12 use rustc_middle::ty::flags::FlagComputation;
13 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
14 use rustc_middle::ty::subst::GenericArg;
15 use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags};
16 use std::sync::atomic::Ordering;
18 use rustc_data_structures::fx::FxHashMap;
19 use rustc_index::vec::Idx;
20 use smallvec::SmallVec;
22 impl<'tcx> InferCtxt<'tcx> {
23 /// Canonicalizes a query value `V`. When we canonicalize a query,
24 /// we not only canonicalize unbound inference variables, but we
25 /// *also* replace all free regions whatsoever. So for example a
26 /// query like `T: Trait<'static>` would be canonicalized to
32 /// with a mapping M that maps `'?0` to `'static`.
34 /// To get a good understanding of what is happening here, check
35 /// out the [chapter in the rustc dev guide][c].
37 /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query
38 pub fn canonicalize_query<V>(
41 query_state: &mut OriginalQueryValues<'tcx>,
42 ) -> Canonical<'tcx, V>
44 V: TypeFoldable<'tcx>,
46 self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed);
48 Canonicalizer::canonicalize(value, self, self.tcx, &CanonicalizeAllFreeRegions, query_state)
51 /// Like [Self::canonicalize_query], but preserves distinct universes. For
52 /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and
53 /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1`
56 /// This is used for Chalk integration.
57 pub fn canonicalize_query_preserving_universes<V>(
60 query_state: &mut OriginalQueryValues<'tcx>,
61 ) -> Canonical<'tcx, V>
63 V: TypeFoldable<'tcx>,
65 self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed);
67 Canonicalizer::canonicalize(
71 &CanonicalizeAllFreeRegionsPreservingUniverses,
76 /// Canonicalizes a query *response* `V`. When we canonicalize a
77 /// query response, we only canonicalize unbound inference
78 /// variables, and we leave other free regions alone. So,
79 /// continuing with the example from `canonicalize_query`, if
80 /// there was an input query `T: Trait<'static>`, it would have
81 /// been canonicalized to
87 /// with a mapping M that maps `'?0` to `'static`. But if we found that there
88 /// exists only one possible impl of `Trait`, and it looks like
89 /// ```ignore (illustrative)
90 /// impl<T> Trait<'static> for T { .. }
92 /// then we would prepare a query result R that (among other
93 /// things) includes a mapping to `'?0 := 'static`. When
94 /// canonicalizing this query result R, we would leave this
95 /// reference to `'static` alone.
97 /// To get a good understanding of what is happening here, check
98 /// out the [chapter in the rustc dev guide][c].
100 /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result
101 pub fn canonicalize_response<V>(&self, value: V) -> Canonical<'tcx, V>
103 V: TypeFoldable<'tcx>,
105 let mut query_state = OriginalQueryValues::default();
106 Canonicalizer::canonicalize(
110 &CanonicalizeQueryResponse,
115 pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonical<'tcx, V>
117 V: TypeFoldable<'tcx>,
119 let mut query_state = OriginalQueryValues::default();
120 Canonicalizer::canonicalize(
124 &CanonicalizeUserTypeAnnotation,
129 /// A variant of `canonicalize_query` that does not
130 /// canonicalize `'static`. This is useful when
131 /// the query implementation can perform more efficient
132 /// handling of `'static` regions (e.g. trait evaluation).
133 pub fn canonicalize_query_keep_static<V>(
136 query_state: &mut OriginalQueryValues<'tcx>,
137 ) -> Canonical<'tcx, V>
139 V: TypeFoldable<'tcx>,
141 self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed);
143 Canonicalizer::canonicalize(
147 &CanonicalizeFreeRegionsOtherThanStatic,
153 /// Controls how we canonicalize "free regions" that are not inference
154 /// variables. This depends on what we are canonicalizing *for* --
155 /// e.g., if we are canonicalizing to create a query, we want to
156 /// replace those with inference variables, since we want to make a
157 /// maximally general query. But if we are canonicalizing a *query
158 /// response*, then we don't typically replace free regions, as they
159 /// must have been introduced from other parts of the system.
160 trait CanonicalizeMode {
161 fn canonicalize_free_region<'tcx>(
163 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
165 ) -> ty::Region<'tcx>;
167 fn any(&self) -> bool;
169 // Do we preserve universe of variables.
170 fn preserve_universes(&self) -> bool;
173 struct CanonicalizeQueryResponse;
175 impl CanonicalizeMode for CanonicalizeQueryResponse {
176 fn canonicalize_free_region<'tcx>(
178 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
180 ) -> ty::Region<'tcx> {
182 ty::ReFree(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r,
184 ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
185 CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) },
190 let universe = canonicalizer.region_var_universe(vid);
191 canonicalizer.canonical_var_for_region(
192 CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
198 // Other than `'static` or `'empty`, the query
199 // response should be executing in a fully
200 // canonicalized environment, so there shouldn't be
201 // any other region names it can come up.
203 // rust-lang/rust#57464: `impl Trait` can leak local
204 // scopes (in manner violating typeck). Therefore, use
205 // `delay_span_bug` to allow type error over an ICE.
206 ty::tls::with(|tcx| {
207 tcx.sess.delay_span_bug(
208 rustc_span::DUMMY_SP,
209 &format!("unexpected region in query response: `{:?}`", r),
217 fn any(&self) -> bool {
221 fn preserve_universes(&self) -> bool {
226 struct CanonicalizeUserTypeAnnotation;
228 impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
229 fn canonicalize_free_region<'tcx>(
231 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
233 ) -> ty::Region<'tcx> {
235 ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic => r,
236 ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
238 // We only expect region names that the user can type.
239 bug!("unexpected region in query response: `{:?}`", r)
244 fn any(&self) -> bool {
248 fn preserve_universes(&self) -> bool {
253 struct CanonicalizeAllFreeRegions;
255 impl CanonicalizeMode for CanonicalizeAllFreeRegions {
256 fn canonicalize_free_region<'tcx>(
258 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
260 ) -> ty::Region<'tcx> {
261 canonicalizer.canonical_var_for_region_in_root_universe(r)
264 fn any(&self) -> bool {
268 fn preserve_universes(&self) -> bool {
273 struct CanonicalizeAllFreeRegionsPreservingUniverses;
275 impl CanonicalizeMode for CanonicalizeAllFreeRegionsPreservingUniverses {
276 fn canonicalize_free_region<'tcx>(
278 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
280 ) -> ty::Region<'tcx> {
281 let universe = canonicalizer.infcx.universe_of_region(r);
282 canonicalizer.canonical_var_for_region(
283 CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
288 fn any(&self) -> bool {
292 fn preserve_universes(&self) -> bool {
297 struct CanonicalizeFreeRegionsOtherThanStatic;
299 impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
300 fn canonicalize_free_region<'tcx>(
302 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
304 ) -> ty::Region<'tcx> {
305 if r.is_static() { r } else { canonicalizer.canonical_var_for_region_in_root_universe(r) }
308 fn any(&self) -> bool {
312 fn preserve_universes(&self) -> bool {
317 struct Canonicalizer<'cx, 'tcx> {
318 infcx: &'cx InferCtxt<'tcx>,
320 variables: SmallVec<[CanonicalVarInfo<'tcx>; 8]>,
321 query_state: &'cx mut OriginalQueryValues<'tcx>,
322 // Note that indices is only used once `var_values` is big enough to be
324 indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
325 canonicalize_mode: &'cx dyn CanonicalizeMode,
326 needs_canonical_flags: TypeFlags,
328 binder_index: ty::DebruijnIndex,
331 impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
332 fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
336 fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
338 T: TypeFoldable<'tcx>,
340 self.binder_index.shift_in(1);
341 let t = t.super_fold_with(self);
342 self.binder_index.shift_out(1);
346 fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
348 ty::ReLateBound(index, ..) => {
349 if index >= self.binder_index {
350 bug!("escaping late-bound region during canonicalization");
357 let resolved_vid = self
361 .unwrap_region_constraints()
362 .opportunistic_resolve_var(vid);
364 "canonical: region var found with vid {:?}, \
365 opportunistically resolved to {:?}",
368 let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
369 self.canonicalize_mode.canonicalize_free_region(self, r)
373 | ty::ReEarlyBound(..)
375 | ty::RePlaceholder(..)
376 | ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
380 fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
382 ty::Infer(ty::TyVar(vid)) => {
383 debug!("canonical: type var found with vid {:?}", vid);
384 match self.infcx.probe_ty_var(vid) {
385 // `t` could be a float / int variable; canonicalize that instead.
387 debug!("(resolved to {:?})", t);
391 // `TyVar(vid)` is unresolved, track its universe index in the canonicalized
394 if !self.canonicalize_mode.preserve_universes() {
395 // FIXME: perf problem described in #55921.
396 ui = ty::UniverseIndex::ROOT;
398 self.canonicalize_ty_var(
400 kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
408 ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var(
409 CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
413 ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var(
414 CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
418 ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
419 bug!("encountered a fresh type during canonicalization")
422 ty::Placeholder(placeholder) => self.canonicalize_ty_var(
423 CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) },
427 ty::Bound(debruijn, _) => {
428 if debruijn >= self.binder_index {
429 bug!("escaping bound type during canonicalization")
437 | ty::GeneratorWitness(..)
438 | ty::GeneratorWitnessMIR(..)
459 if t.flags().intersects(self.needs_canonical_flags) {
460 t.super_fold_with(self)
468 fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
470 ty::ConstKind::Infer(InferConst::Var(vid)) => {
471 debug!("canonical: const var found with vid {:?}", vid);
472 match self.infcx.probe_const_var(vid) {
474 debug!("(resolved to {:?})", c);
475 return self.fold_const(c);
478 // `ConstVar(vid)` is unresolved, track its universe index in the
479 // canonicalized result
481 if !self.canonicalize_mode.preserve_universes() {
482 // FIXME: perf problem described in #55921.
483 ui = ty::UniverseIndex::ROOT;
485 return self.canonicalize_const_var(
486 CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty()) },
492 ty::ConstKind::Infer(InferConst::Fresh(_)) => {
493 bug!("encountered a fresh const during canonicalization")
495 ty::ConstKind::Bound(debruijn, _) => {
496 if debruijn >= self.binder_index {
497 bug!("escaping bound const during canonicalization")
502 ty::ConstKind::Placeholder(placeholder) => {
503 return self.canonicalize_const_var(
505 kind: CanonicalVarKind::PlaceholderConst(placeholder, ct.ty()),
513 let flags = FlagComputation::for_const(ct);
514 if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct }
518 impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
519 /// The main `canonicalize` method, shared impl of
520 /// `canonicalize_query` and `canonicalize_response`.
523 infcx: &InferCtxt<'tcx>,
525 canonicalize_region_mode: &dyn CanonicalizeMode,
526 query_state: &mut OriginalQueryValues<'tcx>,
527 ) -> Canonical<'tcx, V>
529 V: TypeFoldable<'tcx>,
531 let needs_canonical_flags = if canonicalize_region_mode.any() {
532 TypeFlags::NEEDS_INFER |
533 TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
534 TypeFlags::HAS_TY_PLACEHOLDER |
535 TypeFlags::HAS_CT_PLACEHOLDER
537 TypeFlags::NEEDS_INFER
538 | TypeFlags::HAS_RE_PLACEHOLDER
539 | TypeFlags::HAS_TY_PLACEHOLDER
540 | TypeFlags::HAS_CT_PLACEHOLDER
543 // Fast path: nothing that needs to be canonicalized.
544 if !value.has_type_flags(needs_canonical_flags) {
545 let canon_value = Canonical {
546 max_universe: ty::UniverseIndex::ROOT,
547 variables: List::empty(),
553 let mut canonicalizer = Canonicalizer {
556 canonicalize_mode: canonicalize_region_mode,
557 needs_canonical_flags,
558 variables: SmallVec::new(),
560 indices: FxHashMap::default(),
561 binder_index: ty::INNERMOST,
563 let out_value = value.fold_with(&mut canonicalizer);
565 // Once we have canonicalized `out_value`, it should not
566 // contain anything that ties it to this inference context
568 debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders());
570 let canonical_variables =
571 tcx.intern_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
573 let max_universe = canonical_variables
575 .map(|cvar| cvar.universe())
577 .unwrap_or(ty::UniverseIndex::ROOT);
579 Canonical { max_universe, variables: canonical_variables, value: out_value }
582 /// Creates a canonical variable replacing `kind` from the input,
583 /// or returns an existing variable if `kind` has already been
584 /// seen. `kind` is expected to be an unbound variable (or
585 /// potentially a free region).
586 fn canonical_var(&mut self, info: CanonicalVarInfo<'tcx>, kind: GenericArg<'tcx>) -> BoundVar {
587 let Canonicalizer { variables, query_state, indices, .. } = self;
589 let var_values = &mut query_state.var_values;
591 let universe = info.universe();
592 if universe != ty::UniverseIndex::ROOT {
593 assert!(self.canonicalize_mode.preserve_universes());
595 // Insert universe into the universe map. To preserve the order of the
596 // universes in the value being canonicalized, we don't update the
597 // universe in `info` until we have finished canonicalizing.
598 match query_state.universe_map.binary_search(&universe) {
599 Err(idx) => query_state.universe_map.insert(idx, universe),
604 // This code is hot. `variables` and `var_values` are usually small
605 // (fewer than 8 elements ~95% of the time). They are SmallVec's to
606 // avoid allocations in those cases. We also don't use `indices` to
607 // determine if a kind has been seen before until the limit of 8 has
608 // been exceeded, to also avoid allocations for `indices`.
609 if !var_values.spilled() {
610 // `var_values` is stack-allocated. `indices` isn't used yet. Do a
611 // direct linear search of `var_values`.
612 if let Some(idx) = var_values.iter().position(|&k| k == kind) {
613 // `kind` is already present in `var_values`.
616 // `kind` isn't present in `var_values`. Append it. Likewise
617 // for `info` and `variables`.
618 variables.push(info);
619 var_values.push(kind);
620 assert_eq!(variables.len(), var_values.len());
622 // If `var_values` has become big enough to be heap-allocated,
623 // fill up `indices` to facilitate subsequent lookups.
624 if var_values.spilled() {
625 assert!(indices.is_empty());
626 *indices = var_values
629 .map(|(i, &kind)| (kind, BoundVar::new(i)))
632 // The cv is the index of the appended element.
633 BoundVar::new(var_values.len() - 1)
636 // `var_values` is large. Do a hashmap search via `indices`.
637 *indices.entry(kind).or_insert_with(|| {
638 variables.push(info);
639 var_values.push(kind);
640 assert_eq!(variables.len(), var_values.len());
641 BoundVar::new(variables.len() - 1)
646 /// Replaces the universe indexes used in `var_values` with their index in
647 /// `query_state.universe_map`. This minimizes the maximum universe used in
648 /// the canonicalized value.
649 fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarInfo<'tcx>; 8]> {
650 if self.query_state.universe_map.len() == 1 {
651 return self.variables;
654 let reverse_universe_map: FxHashMap<ty::UniverseIndex, ty::UniverseIndex> = self
659 .map(|(idx, universe)| (*universe, ty::UniverseIndex::from_usize(idx)))
664 .map(|v| CanonicalVarInfo {
666 CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
669 CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
670 CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
672 CanonicalVarKind::Region(u) => {
673 CanonicalVarKind::Region(reverse_universe_map[&u])
675 CanonicalVarKind::Const(u, t) => {
676 CanonicalVarKind::Const(reverse_universe_map[&u], t)
678 CanonicalVarKind::PlaceholderTy(placeholder) => {
679 CanonicalVarKind::PlaceholderTy(ty::Placeholder {
680 universe: reverse_universe_map[&placeholder.universe],
684 CanonicalVarKind::PlaceholderRegion(placeholder) => {
685 CanonicalVarKind::PlaceholderRegion(ty::Placeholder {
686 universe: reverse_universe_map[&placeholder.universe],
690 CanonicalVarKind::PlaceholderConst(placeholder, t) => {
691 CanonicalVarKind::PlaceholderConst(
693 universe: reverse_universe_map[&placeholder.universe],
704 /// Shorthand helper that creates a canonical region variable for
705 /// `r` (always in the root universe). The reason that we always
706 /// put these variables into the root universe is because this
707 /// method is used during **query construction:** in that case, we
708 /// are taking all the regions and just putting them into the most
709 /// generic context we can. This may generate solutions that don't
710 /// fit (e.g., that equate some region variable with a placeholder
711 /// it can't name) on the caller side, but that's ok, the caller
712 /// can figure that out. In the meantime, it maximizes our
715 /// (This works because unification never fails -- and hence trait
716 /// selection is never affected -- due to a universe mismatch.)
717 fn canonical_var_for_region_in_root_universe(
720 ) -> ty::Region<'tcx> {
721 self.canonical_var_for_region(
722 CanonicalVarInfo { kind: CanonicalVarKind::Region(ty::UniverseIndex::ROOT) },
727 /// Returns the universe in which `vid` is defined.
728 fn region_var_universe(&self, vid: ty::RegionVid) -> ty::UniverseIndex {
729 self.infcx.inner.borrow_mut().unwrap_region_constraints().var_universe(vid)
732 /// Creates a canonical variable (with the given `info`)
733 /// representing the region `r`; return a region referencing it.
734 fn canonical_var_for_region(
736 info: CanonicalVarInfo<'tcx>,
738 ) -> ty::Region<'tcx> {
739 let var = self.canonical_var(info, r.into());
740 let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32(), None) };
741 let region = ty::ReLateBound(self.binder_index, br);
742 self.tcx().mk_region(region)
745 /// Given a type variable `ty_var` of the given kind, first check
746 /// if `ty_var` is bound to anything; if so, canonicalize
747 /// *that*. Otherwise, create a new canonical variable for
749 fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo<'tcx>, ty_var: Ty<'tcx>) -> Ty<'tcx> {
750 let infcx = self.infcx;
751 let bound_to = infcx.shallow_resolve(ty_var);
752 if bound_to != ty_var {
753 self.fold_ty(bound_to)
755 let var = self.canonical_var(info, ty_var.into());
756 self.tcx().mk_ty(ty::Bound(self.binder_index, var.into()))
760 /// Given a type variable `const_var` of the given kind, first check
761 /// if `const_var` is bound to anything; if so, canonicalize
762 /// *that*. Otherwise, create a new canonical variable for
764 fn canonicalize_const_var(
766 info: CanonicalVarInfo<'tcx>,
767 const_var: ty::Const<'tcx>,
768 ) -> ty::Const<'tcx> {
769 let infcx = self.infcx;
770 let bound_to = infcx.shallow_resolve(const_var);
771 if bound_to != const_var {
772 self.fold_const(bound_to)
774 let var = self.canonical_var(info, const_var.into());
776 ty::ConstKind::Bound(self.binder_index, var),
777 self.fold_ty(const_var.ty()),