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
, Canonicalized
,
12 use crate::infer
::InferCtxt
;
13 use rustc_middle
::ty
::flags
::FlagComputation
;
14 use rustc_middle
::ty
::fold
::{TypeFoldable, TypeFolder, TypeSuperFoldable}
;
15 use rustc_middle
::ty
::subst
::GenericArg
;
16 use rustc_middle
::ty
::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags}
;
17 use std
::sync
::atomic
::Ordering
;
19 use rustc_data_structures
::fx
::FxHashMap
;
20 use rustc_index
::vec
::Idx
;
21 use smallvec
::SmallVec
;
23 impl<'tcx
> InferCtxt
<'tcx
> {
24 /// Canonicalizes a query value `V`. When we canonicalize a query,
25 /// we not only canonicalize unbound inference variables, but we
26 /// *also* replace all free regions whatsoever. So for example a
27 /// query like `T: Trait<'static>` would be canonicalized to
33 /// with a mapping M that maps `'?0` to `'static`.
35 /// To get a good understanding of what is happening here, check
36 /// out the [chapter in the rustc dev guide][c].
38 /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query
39 pub fn canonicalize_query
<V
>(
42 query_state
: &mut OriginalQueryValues
<'tcx
>,
43 ) -> Canonicalized
<'tcx
, V
>
45 V
: TypeFoldable
<'tcx
>,
47 self.tcx
.sess
.perf_stats
.queries_canonicalized
.fetch_add(1, Ordering
::Relaxed
);
49 Canonicalizer
::canonicalize(value
, self, self.tcx
, &CanonicalizeAllFreeRegions
, query_state
)
52 /// Like [Self::canonicalize_query], but preserves distinct universes. For
53 /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and
54 /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1`
57 /// This is used for Chalk integration.
58 pub fn canonicalize_query_preserving_universes
<V
>(
61 query_state
: &mut OriginalQueryValues
<'tcx
>,
62 ) -> Canonicalized
<'tcx
, V
>
64 V
: TypeFoldable
<'tcx
>,
66 self.tcx
.sess
.perf_stats
.queries_canonicalized
.fetch_add(1, Ordering
::Relaxed
);
68 Canonicalizer
::canonicalize(
72 &CanonicalizeAllFreeRegionsPreservingUniverses
,
77 /// Canonicalizes a query *response* `V`. When we canonicalize a
78 /// query response, we only canonicalize unbound inference
79 /// variables, and we leave other free regions alone. So,
80 /// continuing with the example from `canonicalize_query`, if
81 /// there was an input query `T: Trait<'static>`, it would have
82 /// been canonicalized to
88 /// with a mapping M that maps `'?0` to `'static`. But if we found that there
89 /// exists only one possible impl of `Trait`, and it looks like
90 /// ```ignore (illustrative)
91 /// impl<T> Trait<'static> for T { .. }
93 /// then we would prepare a query result R that (among other
94 /// things) includes a mapping to `'?0 := 'static`. When
95 /// canonicalizing this query result R, we would leave this
96 /// reference to `'static` alone.
98 /// To get a good understanding of what is happening here, check
99 /// out the [chapter in the rustc dev guide][c].
101 /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result
102 pub fn canonicalize_response
<V
>(&self, value
: V
) -> Canonicalized
<'tcx
, V
>
104 V
: TypeFoldable
<'tcx
>,
106 let mut query_state
= OriginalQueryValues
::default();
107 Canonicalizer
::canonicalize(
111 &CanonicalizeQueryResponse
,
116 pub fn canonicalize_user_type_annotation
<V
>(&self, value
: V
) -> Canonicalized
<'tcx
, V
>
118 V
: TypeFoldable
<'tcx
>,
120 let mut query_state
= OriginalQueryValues
::default();
121 Canonicalizer
::canonicalize(
125 &CanonicalizeUserTypeAnnotation
,
130 /// A variant of `canonicalize_query` that does not
131 /// canonicalize `'static`. This is useful when
132 /// the query implementation can perform more efficient
133 /// handling of `'static` regions (e.g. trait evaluation).
134 pub fn canonicalize_query_keep_static
<V
>(
137 query_state
: &mut OriginalQueryValues
<'tcx
>,
138 ) -> Canonicalized
<'tcx
, V
>
140 V
: TypeFoldable
<'tcx
>,
142 self.tcx
.sess
.perf_stats
.queries_canonicalized
.fetch_add(1, Ordering
::Relaxed
);
144 Canonicalizer
::canonicalize(
148 &CanonicalizeFreeRegionsOtherThanStatic
,
154 /// Controls how we canonicalize "free regions" that are not inference
155 /// variables. This depends on what we are canonicalizing *for* --
156 /// e.g., if we are canonicalizing to create a query, we want to
157 /// replace those with inference variables, since we want to make a
158 /// maximally general query. But if we are canonicalizing a *query
159 /// response*, then we don't typically replace free regions, as they
160 /// must have been introduced from other parts of the system.
161 trait CanonicalizeMode
{
162 fn canonicalize_free_region
<'tcx
>(
164 canonicalizer
: &mut Canonicalizer
<'_
, 'tcx
>,
166 ) -> ty
::Region
<'tcx
>;
168 fn any(&self) -> bool
;
170 // Do we preserve universe of variables.
171 fn preserve_universes(&self) -> bool
;
174 struct CanonicalizeQueryResponse
;
176 impl CanonicalizeMode
for CanonicalizeQueryResponse
{
177 fn canonicalize_free_region
<'tcx
>(
179 canonicalizer
: &mut Canonicalizer
<'_
, 'tcx
>,
181 ) -> ty
::Region
<'tcx
> {
183 ty
::ReFree(_
) | ty
::ReErased
| ty
::ReStatic
| ty
::ReEarlyBound(..) => r
,
185 ty
::RePlaceholder(placeholder
) => canonicalizer
.canonical_var_for_region(
186 CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) }
,
191 let universe
= canonicalizer
.region_var_universe(vid
);
192 canonicalizer
.canonical_var_for_region(
193 CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) }
,
199 // Other than `'static` or `'empty`, the query
200 // response should be executing in a fully
201 // canonicalized environment, so there shouldn't be
202 // any other region names it can come up.
204 // rust-lang/rust#57464: `impl Trait` can leak local
205 // scopes (in manner violating typeck). Therefore, use
206 // `delay_span_bug` to allow type error over an ICE.
207 ty
::tls
::with(|tcx
| {
208 tcx
.sess
.delay_span_bug(
209 rustc_span
::DUMMY_SP
,
210 &format
!("unexpected region in query response: `{:?}`", r
),
218 fn any(&self) -> bool
{
222 fn preserve_universes(&self) -> bool
{
227 struct CanonicalizeUserTypeAnnotation
;
229 impl CanonicalizeMode
for CanonicalizeUserTypeAnnotation
{
230 fn canonicalize_free_region
<'tcx
>(
232 canonicalizer
: &mut Canonicalizer
<'_
, 'tcx
>,
234 ) -> ty
::Region
<'tcx
> {
236 ty
::ReEarlyBound(_
) | ty
::ReFree(_
) | ty
::ReErased
| ty
::ReStatic
=> r
,
237 ty
::ReVar(_
) => canonicalizer
.canonical_var_for_region_in_root_universe(r
),
239 // We only expect region names that the user can type.
240 bug
!("unexpected region in query response: `{:?}`", r
)
245 fn any(&self) -> bool
{
249 fn preserve_universes(&self) -> bool
{
254 struct CanonicalizeAllFreeRegions
;
256 impl CanonicalizeMode
for CanonicalizeAllFreeRegions
{
257 fn canonicalize_free_region
<'tcx
>(
259 canonicalizer
: &mut Canonicalizer
<'_
, 'tcx
>,
261 ) -> ty
::Region
<'tcx
> {
262 canonicalizer
.canonical_var_for_region_in_root_universe(r
)
265 fn any(&self) -> bool
{
269 fn preserve_universes(&self) -> bool
{
274 struct CanonicalizeAllFreeRegionsPreservingUniverses
;
276 impl CanonicalizeMode
for CanonicalizeAllFreeRegionsPreservingUniverses
{
277 fn canonicalize_free_region
<'tcx
>(
279 canonicalizer
: &mut Canonicalizer
<'_
, 'tcx
>,
281 ) -> ty
::Region
<'tcx
> {
282 let universe
= canonicalizer
.infcx
.universe_of_region(r
);
283 canonicalizer
.canonical_var_for_region(
284 CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) }
,
289 fn any(&self) -> bool
{
293 fn preserve_universes(&self) -> bool
{
298 struct CanonicalizeFreeRegionsOtherThanStatic
;
300 impl CanonicalizeMode
for CanonicalizeFreeRegionsOtherThanStatic
{
301 fn canonicalize_free_region
<'tcx
>(
303 canonicalizer
: &mut Canonicalizer
<'_
, 'tcx
>,
305 ) -> ty
::Region
<'tcx
> {
306 if r
.is_static() { r }
else { canonicalizer.canonical_var_for_region_in_root_universe(r) }
309 fn any(&self) -> bool
{
313 fn preserve_universes(&self) -> bool
{
318 struct Canonicalizer
<'cx
, 'tcx
> {
319 infcx
: &'cx InferCtxt
<'tcx
>,
321 variables
: SmallVec
<[CanonicalVarInfo
<'tcx
>; 8]>,
322 query_state
: &'cx
mut OriginalQueryValues
<'tcx
>,
323 // Note that indices is only used once `var_values` is big enough to be
325 indices
: FxHashMap
<GenericArg
<'tcx
>, BoundVar
>,
326 canonicalize_mode
: &'cx
dyn CanonicalizeMode
,
327 needs_canonical_flags
: TypeFlags
,
329 binder_index
: ty
::DebruijnIndex
,
332 impl<'cx
, 'tcx
> TypeFolder
<'tcx
> for Canonicalizer
<'cx
, 'tcx
> {
333 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'tcx
> {
337 fn fold_binder
<T
>(&mut self, t
: ty
::Binder
<'tcx
, T
>) -> ty
::Binder
<'tcx
, T
>
339 T
: TypeFoldable
<'tcx
>,
341 self.binder_index
.shift_in(1);
342 let t
= t
.super_fold_with(self);
343 self.binder_index
.shift_out(1);
347 fn fold_region(&mut self, r
: ty
::Region
<'tcx
>) -> ty
::Region
<'tcx
> {
349 ty
::ReLateBound(index
, ..) => {
350 if index
>= self.binder_index
{
351 bug
!("escaping late-bound region during canonicalization");
358 let resolved_vid
= self
362 .unwrap_region_constraints()
363 .opportunistic_resolve_var(vid
);
365 "canonical: region var found with vid {:?}, \
366 opportunistically resolved to {:?}",
369 let r
= self.tcx
.reuse_or_mk_region(r
, ty
::ReVar(resolved_vid
));
370 self.canonicalize_mode
.canonicalize_free_region(self, r
)
374 | ty
::ReEarlyBound(..)
376 | ty
::RePlaceholder(..)
377 | ty
::ReErased
=> self.canonicalize_mode
.canonicalize_free_region(self, r
),
381 fn fold_ty(&mut self, t
: Ty
<'tcx
>) -> Ty
<'tcx
> {
383 ty
::Infer(ty
::TyVar(vid
)) => {
384 debug
!("canonical: type var found with vid {:?}", vid
);
385 match self.infcx
.probe_ty_var(vid
) {
386 // `t` could be a float / int variable; canonicalize that instead.
388 debug
!("(resolved to {:?})", t
);
392 // `TyVar(vid)` is unresolved, track its universe index in the canonicalized
395 if !self.canonicalize_mode
.preserve_universes() {
396 // FIXME: perf problem described in #55921.
397 ui
= ty
::UniverseIndex
::ROOT
;
399 self.canonicalize_ty_var(
401 kind
: CanonicalVarKind
::Ty(CanonicalTyVarKind
::General(ui
)),
409 ty
::Infer(ty
::IntVar(_
)) => self.canonicalize_ty_var(
410 CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) }
,
414 ty
::Infer(ty
::FloatVar(_
)) => self.canonicalize_ty_var(
415 CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) }
,
419 ty
::Infer(ty
::FreshTy(_
) | ty
::FreshIntTy(_
) | ty
::FreshFloatTy(_
)) => {
420 bug
!("encountered a fresh type during canonicalization")
423 ty
::Placeholder(placeholder
) => self.canonicalize_ty_var(
424 CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) }
,
428 ty
::Bound(debruijn
, _
) => {
429 if debruijn
>= self.binder_index
{
430 bug
!("escaping bound type during canonicalization")
438 | ty
::GeneratorWitness(..)
459 | ty
::Opaque(..) => {
460 if t
.flags().intersects(self.needs_canonical_flags
) {
461 t
.super_fold_with(self)
469 fn fold_const(&mut self, ct
: ty
::Const
<'tcx
>) -> ty
::Const
<'tcx
> {
471 ty
::ConstKind
::Infer(InferConst
::Var(vid
)) => {
472 debug
!("canonical: const var found with vid {:?}", vid
);
473 match self.infcx
.probe_const_var(vid
) {
475 debug
!("(resolved to {:?})", c
);
476 return self.fold_const(c
);
479 // `ConstVar(vid)` is unresolved, track its universe index in the
480 // canonicalized result
482 if !self.canonicalize_mode
.preserve_universes() {
483 // FIXME: perf problem described in #55921.
484 ui
= ty
::UniverseIndex
::ROOT
;
486 return self.canonicalize_const_var(
487 CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty()) }
,
493 ty
::ConstKind
::Infer(InferConst
::Fresh(_
)) => {
494 bug
!("encountered a fresh const during canonicalization")
496 ty
::ConstKind
::Bound(debruijn
, _
) => {
497 if debruijn
>= self.binder_index
{
498 bug
!("escaping bound type during canonicalization")
503 ty
::ConstKind
::Placeholder(placeholder
) => {
504 return self.canonicalize_const_var(
506 kind
: CanonicalVarKind
::PlaceholderConst(placeholder
, ct
.ty()),
514 let flags
= FlagComputation
::for_const(ct
);
515 if flags
.intersects(self.needs_canonical_flags
) { ct.super_fold_with(self) }
else { ct }
519 impl<'cx
, 'tcx
> Canonicalizer
<'cx
, 'tcx
> {
520 /// The main `canonicalize` method, shared impl of
521 /// `canonicalize_query` and `canonicalize_response`.
524 infcx
: &InferCtxt
<'tcx
>,
526 canonicalize_region_mode
: &dyn CanonicalizeMode
,
527 query_state
: &mut OriginalQueryValues
<'tcx
>,
528 ) -> Canonicalized
<'tcx
, V
>
530 V
: TypeFoldable
<'tcx
>,
532 let needs_canonical_flags
= if canonicalize_region_mode
.any() {
533 TypeFlags
::NEEDS_INFER
|
534 TypeFlags
::HAS_FREE_REGIONS
| // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
535 TypeFlags
::HAS_TY_PLACEHOLDER
|
536 TypeFlags
::HAS_CT_PLACEHOLDER
538 TypeFlags
::NEEDS_INFER
539 | TypeFlags
::HAS_RE_PLACEHOLDER
540 | TypeFlags
::HAS_TY_PLACEHOLDER
541 | TypeFlags
::HAS_CT_PLACEHOLDER
544 // Fast path: nothing that needs to be canonicalized.
545 if !value
.has_type_flags(needs_canonical_flags
) {
546 let canon_value
= Canonical
{
547 max_universe
: ty
::UniverseIndex
::ROOT
,
548 variables
: List
::empty(),
554 let mut canonicalizer
= Canonicalizer
{
557 canonicalize_mode
: canonicalize_region_mode
,
558 needs_canonical_flags
,
559 variables
: SmallVec
::new(),
561 indices
: FxHashMap
::default(),
562 binder_index
: ty
::INNERMOST
,
564 let out_value
= value
.fold_with(&mut canonicalizer
);
566 // Once we have canonicalized `out_value`, it should not
567 // contain anything that ties it to this inference context
569 debug_assert
!(!out_value
.needs_infer() && !out_value
.has_placeholders());
571 let canonical_variables
=
572 tcx
.intern_canonical_var_infos(&canonicalizer
.universe_canonicalized_variables());
574 let max_universe
= canonical_variables
576 .map(|cvar
| cvar
.universe())
578 .unwrap_or(ty
::UniverseIndex
::ROOT
);
580 Canonical { max_universe, variables: canonical_variables, value: out_value }
583 /// Creates a canonical variable replacing `kind` from the input,
584 /// or returns an existing variable if `kind` has already been
585 /// seen. `kind` is expected to be an unbound variable (or
586 /// potentially a free region).
587 fn canonical_var(&mut self, info
: CanonicalVarInfo
<'tcx
>, kind
: GenericArg
<'tcx
>) -> BoundVar
{
588 let Canonicalizer { variables, query_state, indices, .. }
= self;
590 let var_values
= &mut query_state
.var_values
;
592 let universe
= info
.universe();
593 if universe
!= ty
::UniverseIndex
::ROOT
{
594 assert
!(self.canonicalize_mode
.preserve_universes());
596 // Insert universe into the universe map. To preserve the order of the
597 // universes in the value being canonicalized, we don't update the
598 // universe in `info` until we have finished canonicalizing.
599 match query_state
.universe_map
.binary_search(&universe
) {
600 Err(idx
) => query_state
.universe_map
.insert(idx
, universe
),
605 // This code is hot. `variables` and `var_values` are usually small
606 // (fewer than 8 elements ~95% of the time). They are SmallVec's to
607 // avoid allocations in those cases. We also don't use `indices` to
608 // determine if a kind has been seen before until the limit of 8 has
609 // been exceeded, to also avoid allocations for `indices`.
610 if !var_values
.spilled() {
611 // `var_values` is stack-allocated. `indices` isn't used yet. Do a
612 // direct linear search of `var_values`.
613 if let Some(idx
) = var_values
.iter().position(|&k
| k
== kind
) {
614 // `kind` is already present in `var_values`.
617 // `kind` isn't present in `var_values`. Append it. Likewise
618 // for `info` and `variables`.
619 variables
.push(info
);
620 var_values
.push(kind
);
621 assert_eq
!(variables
.len(), var_values
.len());
623 // If `var_values` has become big enough to be heap-allocated,
624 // fill up `indices` to facilitate subsequent lookups.
625 if var_values
.spilled() {
626 assert
!(indices
.is_empty());
627 *indices
= var_values
630 .map(|(i
, &kind
)| (kind
, BoundVar
::new(i
)))
633 // The cv is the index of the appended element.
634 BoundVar
::new(var_values
.len() - 1)
637 // `var_values` is large. Do a hashmap search via `indices`.
638 *indices
.entry(kind
).or_insert_with(|| {
639 variables
.push(info
);
640 var_values
.push(kind
);
641 assert_eq
!(variables
.len(), var_values
.len());
642 BoundVar
::new(variables
.len() - 1)
647 /// Replaces the universe indexes used in `var_values` with their index in
648 /// `query_state.universe_map`. This minimizes the maximum universe used in
649 /// the canonicalized value.
650 fn universe_canonicalized_variables(self) -> SmallVec
<[CanonicalVarInfo
<'tcx
>; 8]> {
651 if self.query_state
.universe_map
.len() == 1 {
652 return self.variables
;
655 let reverse_universe_map
: FxHashMap
<ty
::UniverseIndex
, ty
::UniverseIndex
> = self
660 .map(|(idx
, universe
)| (*universe
, ty
::UniverseIndex
::from_usize(idx
)))
665 .map(|v
| CanonicalVarInfo
{
667 CanonicalVarKind
::Ty(CanonicalTyVarKind
::Int
| CanonicalTyVarKind
::Float
) => {
670 CanonicalVarKind
::Ty(CanonicalTyVarKind
::General(u
)) => {
671 CanonicalVarKind
::Ty(CanonicalTyVarKind
::General(reverse_universe_map
[&u
]))
673 CanonicalVarKind
::Region(u
) => {
674 CanonicalVarKind
::Region(reverse_universe_map
[&u
])
676 CanonicalVarKind
::Const(u
, t
) => {
677 CanonicalVarKind
::Const(reverse_universe_map
[&u
], t
)
679 CanonicalVarKind
::PlaceholderTy(placeholder
) => {
680 CanonicalVarKind
::PlaceholderTy(ty
::Placeholder
{
681 universe
: reverse_universe_map
[&placeholder
.universe
],
685 CanonicalVarKind
::PlaceholderRegion(placeholder
) => {
686 CanonicalVarKind
::PlaceholderRegion(ty
::Placeholder
{
687 universe
: reverse_universe_map
[&placeholder
.universe
],
691 CanonicalVarKind
::PlaceholderConst(placeholder
, t
) => {
692 CanonicalVarKind
::PlaceholderConst(
694 universe
: reverse_universe_map
[&placeholder
.universe
],
705 /// Shorthand helper that creates a canonical region variable for
706 /// `r` (always in the root universe). The reason that we always
707 /// put these variables into the root universe is because this
708 /// method is used during **query construction:** in that case, we
709 /// are taking all the regions and just putting them into the most
710 /// generic context we can. This may generate solutions that don't
711 /// fit (e.g., that equate some region variable with a placeholder
712 /// it can't name) on the caller side, but that's ok, the caller
713 /// can figure that out. In the meantime, it maximizes our
716 /// (This works because unification never fails -- and hence trait
717 /// selection is never affected -- due to a universe mismatch.)
718 fn canonical_var_for_region_in_root_universe(
721 ) -> ty
::Region
<'tcx
> {
722 self.canonical_var_for_region(
723 CanonicalVarInfo { kind: CanonicalVarKind::Region(ty::UniverseIndex::ROOT) }
,
728 /// Returns the universe in which `vid` is defined.
729 fn region_var_universe(&self, vid
: ty
::RegionVid
) -> ty
::UniverseIndex
{
730 self.infcx
.inner
.borrow_mut().unwrap_region_constraints().var_universe(vid
)
733 /// Creates a canonical variable (with the given `info`)
734 /// representing the region `r`; return a region referencing it.
735 fn canonical_var_for_region(
737 info
: CanonicalVarInfo
<'tcx
>,
739 ) -> ty
::Region
<'tcx
> {
740 let var
= self.canonical_var(info
, r
.into());
741 let br
= ty
::BoundRegion { var, kind: ty::BrAnon(var.as_u32()) }
;
742 let region
= ty
::ReLateBound(self.binder_index
, br
);
743 self.tcx().mk_region(region
)
746 /// Given a type variable `ty_var` of the given kind, first check
747 /// if `ty_var` is bound to anything; if so, canonicalize
748 /// *that*. Otherwise, create a new canonical variable for
750 fn canonicalize_ty_var(&mut self, info
: CanonicalVarInfo
<'tcx
>, ty_var
: Ty
<'tcx
>) -> Ty
<'tcx
> {
751 let infcx
= self.infcx
;
752 let bound_to
= infcx
.shallow_resolve(ty_var
);
753 if bound_to
!= ty_var
{
754 self.fold_ty(bound_to
)
756 let var
= self.canonical_var(info
, ty_var
.into());
757 self.tcx().mk_ty(ty
::Bound(self.binder_index
, var
.into()))
761 /// Given a type variable `const_var` of the given kind, first check
762 /// if `const_var` is bound to anything; if so, canonicalize
763 /// *that*. Otherwise, create a new canonical variable for
765 fn canonicalize_const_var(
767 info
: CanonicalVarInfo
<'tcx
>,
768 const_var
: ty
::Const
<'tcx
>,
769 ) -> ty
::Const
<'tcx
> {
770 let infcx
= self.infcx
;
771 let bound_to
= infcx
.shallow_resolve(const_var
);
772 if bound_to
!= const_var
{
773 self.fold_const(bound_to
)
775 let var
= self.canonical_var(info
, const_var
.into());
776 self.tcx().mk_const(ty
::ConstS
{
777 kind
: ty
::ConstKind
::Bound(self.binder_index
, var
),
778 ty
: self.fold_ty(const_var
.ty()),