1//! This module contains the "canonicalizer" itself.
2//!
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].
5//!
6//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
78use rustc_data_structures::fx::FxHashMap;
9use rustc_data_structures::sso::SsoHashMap;
10use rustc_index::Idx;
11use rustc_middle::ty::{
12self, BoundVar, Flags, GenericArg, InferConst, List, Ty, TyCtxt, TypeFlags, TypeFoldable,
13TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypingModeEqWrapper,
14};
15use rustc_span::bug;
16use rustc_type_ir::PredicateProxy;
17use smallvec::SmallVec;
18use tracing::debug;
1920use crate::infer::InferCtxt;
21use crate::infer::canonical::{
22Canonical, CanonicalQueryInput, CanonicalVarKind, OriginalQueryValues,
23};
2425impl<'tcx> InferCtxt<'tcx> {
26/// Canonicalizes a query value `V`. When we canonicalize a query,
27 /// we not only canonicalize unbound inference variables, but we
28 /// *also* replace all free regions whatsoever. So for example a
29 /// query like `T: Trait<'static>` would be canonicalized to
30 ///
31 /// ```text
32 /// T: Trait<'?0>
33 /// ```
34 ///
35 /// with a mapping M that maps `'?0` to `'static`.
36 ///
37 /// To get a good understanding of what is happening here, check
38 /// out the [chapter in the rustc dev guide][c].
39 ///
40 /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query
41pub fn canonicalize_query<V>(
42&self,
43 value: ty::ParamEnvAnd<'tcx, V>,
44 query_state: &mut OriginalQueryValues<'tcx>,
45 ) -> CanonicalQueryInput<'tcx, ty::ParamEnvAnd<'tcx, V>>
46where
47V: TypeFoldable<TyCtxt<'tcx>>,
48 {
49let ty::ParamEnvAnd { param_env, value } = value;
50let canonical_param_env = self.tcx.caches.canonical_param_env_cache.get_or_insert(
51self.tcx,
52param_env,
53query_state,
54 |tcx, param_env, query_state| {
55// FIXME(#118965): We don't canonicalize the static lifetimes that appear in the
56 // `param_env` because they are treated differently by trait selection.
57Canonicalizer::canonicalize(
58param_env,
59None,
60tcx,
61&CanonicalizeFreeRegionsOtherThanStatic,
62query_state,
63 )
64 },
65 );
6667let canonical = Canonicalizer::canonicalize_with_base(
68canonical_param_env,
69value,
70Some(self),
71self.tcx,
72&CanonicalizeAllFreeRegions,
73query_state,
74 )
75 .unchecked_map(|(param_env, value)| param_env.and(value));
76CanonicalQueryInput { canonical, typing_mode: TypingModeEqWrapper(self.typing_mode_raw()) }
77 }
7879/// Canonicalizes a query *response* `V`. When we canonicalize a
80 /// query response, we only canonicalize unbound inference
81 /// variables, and we leave other free regions alone. So,
82 /// continuing with the example from `canonicalize_query`, if
83 /// there was an input query `T: Trait<'static>`, it would have
84 /// been canonicalized to
85 ///
86 /// ```text
87 /// T: Trait<'?0>
88 /// ```
89 ///
90 /// with a mapping M that maps `'?0` to `'static`. But if we found that there
91 /// exists only one possible impl of `Trait`, and it looks like
92 /// ```ignore (illustrative)
93 /// impl<T> Trait<'static> for T { .. }
94 /// ```
95 /// then we would prepare a query result R that (among other
96 /// things) includes a mapping to `'?0 := 'static`. When
97 /// canonicalizing this query result R, we would leave this
98 /// reference to `'static` alone.
99 ///
100 /// To get a good understanding of what is happening here, check
101 /// out the [chapter in the rustc dev guide][c].
102 ///
103 /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result
104pub fn canonicalize_response<V>(&self, value: V) -> Canonical<'tcx, V>
105where
106V: TypeFoldable<TyCtxt<'tcx>>,
107 {
108let mut query_state = OriginalQueryValues::default();
109Canonicalizer::canonicalize(
110value,
111Some(self),
112self.tcx,
113&CanonicalizeQueryResponse,
114&mut query_state,
115 )
116 }
117118pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonical<'tcx, V>
119where
120V: TypeFoldable<TyCtxt<'tcx>>,
121 {
122let mut query_state = OriginalQueryValues::default();
123Canonicalizer::canonicalize(
124value,
125Some(self),
126self.tcx,
127&CanonicalizeUserTypeAnnotation,
128&mut query_state,
129 )
130 }
131}
132133/// Controls how we canonicalize "free regions" that are not inference
134/// variables. This depends on what we are canonicalizing *for* --
135/// e.g., if we are canonicalizing to create a query, we want to
136/// replace those with inference variables, since we want to make a
137/// maximally general query. But if we are canonicalizing a *query
138/// response*, then we don't typically replace free regions, as they
139/// must have been introduced from other parts of the system.
140trait CanonicalizeMode {
141fn canonicalize_free_region<'tcx>(
142&self,
143 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
144 r: ty::Region<'tcx>,
145 ) -> ty::Region<'tcx>;
146147fn any(&self) -> bool;
148149// Do we preserve universe of variables.
150fn preserve_universes(&self) -> bool;
151}
152153struct CanonicalizeQueryResponse;
154155impl CanonicalizeModefor CanonicalizeQueryResponse {
156fn canonicalize_free_region<'tcx>(
157&self,
158 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
159mut r: ty::Region<'tcx>,
160 ) -> ty::Region<'tcx> {
161let infcx = canonicalizer.infcx.unwrap();
162163if let ty::ReVar(vid) = r.kind() {
164r = infcx165 .inner
166 .borrow_mut()
167 .unwrap_region_constraints()
168 .shallow_resolve_region_var(canonicalizer.tcx, vid);
169{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/7bbda45cb1ec0a378d91959646a8fa904be3192a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs:169",
"rustc_infer::infer::canonical::canonicalizer",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/7bbda45cb1ec0a378d91959646a8fa904be3192a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs"),
::tracing_core::__macro_support::Option::Some(169u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::canonical::canonicalizer"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("canonical: region var found with vid {0:?}, opportunistically resolved to {1:?}",
vid, r) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(
170"canonical: region var found with vid {vid:?}, \
171 opportunistically resolved to {r:?}",
172 );
173 };
174175match r.kind() {
176 ty::ReLateParam(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyParam(..) => r,
177178 ty::RePlaceholder(placeholder) => canonicalizer179 .canonical_var_for_region(CanonicalVarKind::PlaceholderRegion(placeholder), r),
180181 ty::ReVar(vid) => {
182let universe = infcx183 .inner
184 .borrow_mut()
185 .unwrap_region_constraints()
186 .try_resolve_region_var(vid)
187 .unwrap_err();
188canonicalizer.canonical_var_for_region(CanonicalVarKind::Region(universe), r)
189 }
190191_ => {
192// Other than `'static` or `'empty`, the query
193 // response should be executing in a fully
194 // canonicalized environment, so there shouldn't be
195 // any other region names it can come up.
196 //
197 // rust-lang/rust#57464: `impl Trait` can leak local
198 // scopes (in manner violating typeck). Therefore, use
199 // `delayed_bug` to allow type error over an ICE.
200canonicalizer201 .tcx
202 .dcx()
203 .delayed_bug(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("unexpected region in query response: `{0:?}`",
r))
})format!("unexpected region in query response: `{r:?}`"));
204r205 }
206 }
207 }
208209fn any(&self) -> bool {
210false
211}
212213fn preserve_universes(&self) -> bool {
214true
215}
216}
217218struct CanonicalizeUserTypeAnnotation;
219220impl CanonicalizeModefor CanonicalizeUserTypeAnnotation {
221fn canonicalize_free_region<'tcx>(
222&self,
223 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
224 r: ty::Region<'tcx>,
225 ) -> ty::Region<'tcx> {
226match r.kind() {
227 ty::ReEarlyParam(_)
228 | ty::ReLateParam(_)
229 | ty::ReErased230 | ty::ReStatic231 | ty::ReError(_) => r,
232 ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
233 ty::RePlaceholder(..) | ty::ReBound(..) => {
234// We only expect region names that the user can type.
235::rustc_span::macros::bug_impl(None,
format_args!("unexpected region in query response: `{0:?}`", r),
Location::caller())bug!("unexpected region in query response: `{:?}`", r)236 }
237 }
238 }
239240fn any(&self) -> bool {
241false
242}
243244fn preserve_universes(&self) -> bool {
245false
246}
247}
248249struct CanonicalizeAllFreeRegions;
250251impl CanonicalizeModefor CanonicalizeAllFreeRegions {
252fn canonicalize_free_region<'tcx>(
253&self,
254 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
255 r: ty::Region<'tcx>,
256 ) -> ty::Region<'tcx> {
257canonicalizer.canonical_var_for_region_in_root_universe(r)
258 }
259260fn any(&self) -> bool {
261true
262}
263264fn preserve_universes(&self) -> bool {
265false
266}
267}
268269struct CanonicalizeFreeRegionsOtherThanStatic;
270271impl CanonicalizeModefor CanonicalizeFreeRegionsOtherThanStatic {
272fn canonicalize_free_region<'tcx>(
273&self,
274 canonicalizer: &mut Canonicalizer<'_, 'tcx>,
275 r: ty::Region<'tcx>,
276 ) -> ty::Region<'tcx> {
277if r.is_static() { r } else { canonicalizer.canonical_var_for_region_in_root_universe(r) }
278 }
279280fn any(&self) -> bool {
281true
282}
283284fn preserve_universes(&self) -> bool {
285false
286}
287}
288289struct Canonicalizer<'cx, 'tcx> {
290/// Set to `None` to disable the resolution of inference variables.
291infcx: Option<&'cx InferCtxt<'tcx>>,
292 tcx: TyCtxt<'tcx>,
293 var_kinds: SmallVec<[CanonicalVarKind<'tcx>; 8]>,
294 query_state: &'cx mut OriginalQueryValues<'tcx>,
295// Note that indices is only used once `var_values` is big enough to be
296 // heap-allocated.
297indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
298/// Maps each `sub_unification_table_root_var` to the index of the first
299 /// variable which used it.
300 ///
301 /// This means in case two type variables have the same sub relations root,
302 /// we set the `sub_root` of the second variable to the position of the first.
303 /// Otherwise the `sub_root` of each type variable is just its own position.
304sub_root_lookup_table: SsoHashMap<ty::TyVid, usize>,
305 canonicalize_mode: &'cx dyn CanonicalizeMode,
306 needs_canonical_flags: TypeFlags,
307}
308309impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
310fn cx(&self) -> TyCtxt<'tcx> {
311self.tcx
312 }
313314fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
315match r.kind() {
316 ty::ReBound(ty::BoundVarIndexKind::Bound(_), ..) => r,
317318 ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => {
319::rustc_span::macros::bug_impl(None,
format_args!("canonicalized bound var found during canonicalization"),
Location::caller());bug!("canonicalized bound var found during canonicalization");
320 }
321322 ty::ReStatic323 | ty::ReEarlyParam(..)
324 | ty::ReError(_)
325 | ty::ReLateParam(_)
326 | ty::RePlaceholder(..)
327 | ty::ReVar(_)
328 | ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
329 }
330 }
331332fn fold_ty(&mut self, mut t: Ty<'tcx>) -> Ty<'tcx> {
333match *t.kind() {
334 ty::Infer(ty::TyVar(mut vid)) => {
335// We need to canonicalize the *root* of our ty var.
336 // This is so that our canonical response correctly reflects
337 // any equated inference vars correctly!
338let root_vid = self.infcx.unwrap().root_var(vid);
339if root_vid != vid {
340t = Ty::new_var(self.tcx, root_vid);
341vid = root_vid;
342 }
343344{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/7bbda45cb1ec0a378d91959646a8fa904be3192a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs:344",
"rustc_infer::infer::canonical::canonicalizer",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/7bbda45cb1ec0a378d91959646a8fa904be3192a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs"),
::tracing_core::__macro_support::Option::Some(344u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::canonical::canonicalizer"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("canonical: type var found with vid {0:?}",
vid) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("canonical: type var found with vid {:?}", vid);
345match self.infcx.unwrap().try_resolve_ty_var(vid) {
346// `t` could be a float / int variable; canonicalize that instead.
347Ok(t) => {
348{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/7bbda45cb1ec0a378d91959646a8fa904be3192a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs:348",
"rustc_infer::infer::canonical::canonicalizer",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/7bbda45cb1ec0a378d91959646a8fa904be3192a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs"),
::tracing_core::__macro_support::Option::Some(348u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::canonical::canonicalizer"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("(resolved to {0:?})",
t) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("(resolved to {:?})", t);
349self.fold_ty(t)
350 }
351352// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
353 // result.
354Err(mut ui) => {
355if !self.canonicalize_mode.preserve_universes() {
356// FIXME: perf problem described in #55921.
357ui = ty::UniverseIndex::ROOT;
358 }
359let sub_root = self.get_or_insert_sub_root(vid);
360self.canonicalize_ty_var(CanonicalVarKind::Ty { ui, sub_root }, t)
361 }
362 }
363 }
364365 ty::Infer(ty::IntVar(vid)) => {
366let nt = self.infcx.unwrap().shallow_resolve_int_var(vid);
367if nt != t {
368return self.fold_ty(nt);
369 } else {
370self.canonicalize_ty_var(CanonicalVarKind::Int, t)
371 }
372 }
373 ty::Infer(ty::FloatVar(vid)) => {
374let nt = self.infcx.unwrap().shallow_resolve_float_var(vid);
375if nt != t {
376return self.fold_ty(nt);
377 } else {
378self.canonicalize_ty_var(CanonicalVarKind::Float, t)
379 }
380 }
381382 ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
383::rustc_span::macros::bug_impl(None,
format_args!("encountered a fresh type during canonicalization"),
Location::caller())bug!("encountered a fresh type during canonicalization")384 }
385386 ty::Placeholder(mut placeholder) => {
387if !self.canonicalize_mode.preserve_universes() {
388placeholder.universe = ty::UniverseIndex::ROOT;
389 }
390self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t)
391 }
392393 ty::Bound(ty::BoundVarIndexKind::Bound(_), _) => t,
394395 ty::Bound(ty::BoundVarIndexKind::Canonical, _) => {
396::rustc_span::macros::bug_impl(None,
format_args!("canonicalized bound var found during canonicalization"),
Location::caller());bug!("canonicalized bound var found during canonicalization");
397 }
398399 ty::Closure(..)
400 | ty::CoroutineClosure(..)
401 | ty::Coroutine(..)
402 | ty::CoroutineWitness(..)
403 | ty::Bool404 | ty::Char405 | ty::Int(..)
406 | ty::Uint(..)
407 | ty::Float(..)
408 | ty::Adt(..)
409 | ty::Str410 | ty::Error(_)
411 | ty::Array(..)
412 | ty::Slice(..)
413 | ty::RawPtr(..)
414 | ty::Ref(..)
415 | ty::FnDef(..)
416 | ty::FnPtr(..)
417 | ty::Dynamic(..)
418 | ty::UnsafeBinder(_)
419 | ty::Never420 | ty::Tuple(..)
421 | ty::Alias(..)
422 | ty::Foreign(..)
423 | ty::Pat(..)
424 | ty::Param(..) => {
425if t.flags().intersects(self.needs_canonical_flags) {
426t.super_fold_with(self)
427 } else {
428t429 }
430 }
431 }
432 }
433434fn fold_const(&mut self, mut ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
435match ct.kind() {
436 ty::ConstKind::Infer(InferConst::Var(mut vid)) => {
437// We need to canonicalize the *root* of our const var.
438 // This is so that our canonical response correctly reflects
439 // any equated inference vars correctly!
440let root_vid = self.infcx.unwrap().root_const_var(vid);
441if root_vid != vid {
442ct = ty::Const::new_var(self.tcx, root_vid);
443vid = root_vid;
444 }
445446{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/7bbda45cb1ec0a378d91959646a8fa904be3192a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs:446",
"rustc_infer::infer::canonical::canonicalizer",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/7bbda45cb1ec0a378d91959646a8fa904be3192a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs"),
::tracing_core::__macro_support::Option::Some(446u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::canonical::canonicalizer"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("canonical: const var found with vid {0:?}",
vid) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("canonical: const var found with vid {:?}", vid);
447match self.infcx.unwrap().try_resolve_const_var(vid) {
448Ok(c) => {
449{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/7bbda45cb1ec0a378d91959646a8fa904be3192a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs:449",
"rustc_infer::infer::canonical::canonicalizer",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/7bbda45cb1ec0a378d91959646a8fa904be3192a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs"),
::tracing_core::__macro_support::Option::Some(449u32),
::tracing_core::__macro_support::Option::Some("rustc_infer::infer::canonical::canonicalizer"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("(resolved to {0:?})",
c) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("(resolved to {:?})", c);
450return self.fold_const(c);
451 }
452453// `ConstVar(vid)` is unresolved, track its universe index in the
454 // canonicalized result
455Err(mut ui) => {
456if !self.canonicalize_mode.preserve_universes() {
457// FIXME: perf problem described in #55921.
458ui = ty::UniverseIndex::ROOT;
459 }
460return self.canonicalize_const_var(CanonicalVarKind::Const(ui), ct);
461 }
462 }
463 }
464 ty::ConstKind::Infer(InferConst::Fresh(_)) => {
465::rustc_span::macros::bug_impl(None,
format_args!("encountered a fresh const during canonicalization"),
Location::caller())bug!("encountered a fresh const during canonicalization")466 }
467 ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(_), _) => {
468return ct;
469 }
470 ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, _) => {
471::rustc_span::macros::bug_impl(None,
format_args!("canonicalized bound var found during canonicalization"),
Location::caller());bug!("canonicalized bound var found during canonicalization");
472 }
473 ty::ConstKind::Placeholder(placeholder) => {
474return self475 .canonicalize_const_var(CanonicalVarKind::PlaceholderConst(placeholder), ct);
476 }
477_ => {}
478 }
479480if ct.flags().intersects(self.needs_canonical_flags) {
481ct.super_fold_with(self)
482 } else {
483ct484 }
485 }
486487fn fold_predicate<P: PredicateProxy<TyCtxt<'tcx>>>(&mut self, p: P) -> P {
488if p.flags().intersects(self.needs_canonical_flags) { p.super_fold_with(self) } else { p }
489 }
490491fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
492if c.flags().intersects(self.needs_canonical_flags) { c.super_fold_with(self) } else { c }
493 }
494}
495496impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
497/// The main `canonicalize` method, shared impl of
498 /// `canonicalize_query` and `canonicalize_response`.
499fn canonicalize<V>(
500 value: V,
501 infcx: Option<&InferCtxt<'tcx>>,
502 tcx: TyCtxt<'tcx>,
503 canonicalize_region_mode: &dyn CanonicalizeMode,
504 query_state: &mut OriginalQueryValues<'tcx>,
505 ) -> Canonical<'tcx, V>
506where
507V: TypeFoldable<TyCtxt<'tcx>>,
508 {
509let base = Canonical {
510 max_universe: ty::UniverseIndex::ROOT,
511 var_kinds: List::empty(),
512 value: (),
513 };
514Canonicalizer::canonicalize_with_base(
515base,
516value,
517infcx,
518tcx,
519canonicalize_region_mode,
520query_state,
521 )
522 .unchecked_map(|((), val)| val)
523 }
524525fn canonicalize_with_base<U, V>(
526 base: Canonical<'tcx, U>,
527 value: V,
528 infcx: Option<&InferCtxt<'tcx>>,
529 tcx: TyCtxt<'tcx>,
530 canonicalize_region_mode: &dyn CanonicalizeMode,
531 query_state: &mut OriginalQueryValues<'tcx>,
532 ) -> Canonical<'tcx, (U, V)>
533where
534V: TypeFoldable<TyCtxt<'tcx>>,
535 {
536let needs_canonical_flags = if canonicalize_region_mode.any() {
537TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS538 } else {
539TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER540 };
541542// Fast path: nothing that needs to be canonicalized.
543if !value.has_type_flags(needs_canonical_flags) {
544return base.unchecked_map(|b| (b, value));
545 }
546547let mut canonicalizer = Canonicalizer {
548infcx,
549tcx,
550 canonicalize_mode: canonicalize_region_mode,
551needs_canonical_flags,
552 var_kinds: SmallVec::from_slice(base.var_kinds),
553query_state,
554 indices: FxHashMap::default(),
555 sub_root_lookup_table: Default::default(),
556 };
557if canonicalizer.query_state.var_values.spilled() {
558canonicalizer.indices = canonicalizer559 .query_state
560 .var_values
561 .iter()
562 .enumerate()
563 .map(|(i, &kind)| (kind, BoundVar::new(i)))
564 .collect();
565 }
566let out_value = value.fold_with(&mut canonicalizer);
567568// Once we have canonicalized `out_value`, it should not
569 // contain anything that ties it to this inference context
570 // anymore.
571if true {
if !(!out_value.has_infer() && !out_value.has_placeholders()) {
::core::panicking::panic("assertion failed: !out_value.has_infer() && !out_value.has_placeholders()")
};
};debug_assert!(!out_value.has_infer() && !out_value.has_placeholders());
572573let canonical_var_kinds =
574tcx.mk_canonical_var_kinds(&canonicalizer.universe_canonicalized_var_kinds());
575576let max_universe = canonical_var_kinds577 .iter()
578 .map(|cvar| cvar.universe())
579 .max()
580 .unwrap_or(ty::UniverseIndex::ROOT);
581582Canonical { max_universe, var_kinds: canonical_var_kinds, value: (base.value, out_value) }
583 }
584585/// Creates a canonical variable replacing `kind` from the input,
586 /// or returns an existing variable if `kind` has already been
587 /// seen. `kind` is expected to be an unbound variable (or
588 /// potentially a free region).
589fn canonical_var(
590&mut self,
591 var_kind: CanonicalVarKind<'tcx>,
592 value: GenericArg<'tcx>,
593 ) -> BoundVar {
594let Canonicalizer { var_kinds, query_state, indices, .. } = self;
595596let var_values = &mut query_state.var_values;
597598let universe = var_kind.universe();
599if universe != ty::UniverseIndex::ROOT {
600if !self.canonicalize_mode.preserve_universes() {
::core::panicking::panic("assertion failed: self.canonicalize_mode.preserve_universes()")
};assert!(self.canonicalize_mode.preserve_universes());
601602// Insert universe into the universe map. To preserve the order of the
603 // universes in the value being canonicalized, we don't update the
604 // universe in `var_kind` until we have finished canonicalizing.
605match query_state.universe_map.binary_search(&universe) {
606Err(idx) => query_state.universe_map.insert(idx, universe),
607Ok(_) => {}
608 }
609 }
610611// This code is hot. `var_kinds` and `var_values` are usually small
612 // (fewer than 8 elements ~95% of the time). They are SmallVec's to
613 // avoid allocations in those cases. We also don't use `indices` to
614 // determine if a kind has been seen before until the limit of 8 has
615 // been exceeded, to also avoid allocations for `indices`.
616if !var_values.spilled() {
617// `var_values` is stack-allocated. `indices` isn't used yet. Do a
618 // direct linear search of `var_values`.
619if let Some(idx) = var_values.iter().position(|&v| v == value) {
620// `kind` is already present in `var_values`.
621BoundVar::new(idx)
622 } else {
623// `kind` isn't present in `var_values`. Append it. Likewise
624 // for `var_kind` and `var_kinds`.
625var_kinds.push(var_kind);
626var_values.push(value);
627{
match (&var_kinds.len(), &var_values.len()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(var_kinds.len(), var_values.len());
628629// If `var_values` has become big enough to be heap-allocated,
630 // fill up `indices` to facilitate subsequent lookups.
631if var_values.spilled() {
632if !indices.is_empty() {
::core::panicking::panic("assertion failed: indices.is_empty()")
};assert!(indices.is_empty());
633*indices = var_values634 .iter()
635 .enumerate()
636 .map(|(i, &value)| (value, BoundVar::new(i)))
637 .collect();
638 }
639// The cv is the index of the appended element.
640BoundVar::new(var_values.len() - 1)
641 }
642 } else {
643// `var_values` is large. Do a hashmap search via `indices`.
644*indices.entry(value).or_insert_with(|| {
645var_kinds.push(var_kind);
646var_values.push(value);
647{
match (&var_kinds.len(), &var_values.len()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(var_kinds.len(), var_values.len());
648BoundVar::new(var_kinds.len() - 1)
649 })
650 }
651 }
652653fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar {
654let root_vid = self.infcx.unwrap().sub_unification_table_root_var(vid);
655let idx =
656*self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.var_kinds.len());
657 ty::BoundVar::from(idx)
658 }
659660/// Replaces the universe indexes used in `var_values` with their index in
661 /// `query_state.universe_map`. This minimizes the maximum universe used in
662 /// the canonicalized value.
663fn universe_canonicalized_var_kinds(self) -> SmallVec<[CanonicalVarKind<'tcx>; 8]> {
664if self.query_state.universe_map.len() == 1 {
665return self.var_kinds;
666 }
667668let reverse_universe_map: FxHashMap<ty::UniverseIndex, ty::UniverseIndex> = self669 .query_state
670 .universe_map
671 .iter()
672 .enumerate()
673 .map(|(idx, universe)| (*universe, ty::UniverseIndex::from_usize(idx)))
674 .collect();
675676self.var_kinds
677 .iter()
678 .map(|&kind| match kind {
679CanonicalVarKind::Int | CanonicalVarKind::Float => {
680return kind;
681 }
682CanonicalVarKind::Ty { ui, sub_root } => {
683CanonicalVarKind::Ty { ui: reverse_universe_map[&ui], sub_root }
684 }
685CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]),
686CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
687CanonicalVarKind::PlaceholderTy(placeholder) => {
688CanonicalVarKind::PlaceholderTy(ty::PlaceholderType::new(
689reverse_universe_map[&placeholder.universe],
690placeholder.bound,
691 ))
692 }
693CanonicalVarKind::PlaceholderRegion(placeholder) => {
694CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion::new(
695reverse_universe_map[&placeholder.universe],
696placeholder.bound,
697 ))
698 }
699CanonicalVarKind::PlaceholderConst(placeholder) => {
700CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst::new(
701reverse_universe_map[&placeholder.universe],
702placeholder.bound,
703 ))
704 }
705 })
706 .collect()
707 }
708709/// Shorthand helper that creates a canonical region variable for
710 /// `r` (always in the root universe). The reason that we always
711 /// put these variables into the root universe is because this
712 /// method is used during **query construction:** in that case, we
713 /// are taking all the regions and just putting them into the most
714 /// generic context we can. This may generate solutions that don't
715 /// fit (e.g., that equate some region variable with a placeholder
716 /// it can't name) on the caller side, but that's ok, the caller
717 /// can figure that out. In the meantime, it maximizes our
718 /// caching.
719 ///
720 /// (This works because unification never fails -- and hence trait
721 /// selection is never affected -- due to a universe mismatch.)
722fn canonical_var_for_region_in_root_universe(
723&mut self,
724 r: ty::Region<'tcx>,
725 ) -> ty::Region<'tcx> {
726self.canonical_var_for_region(CanonicalVarKind::Region(ty::UniverseIndex::ROOT), r)
727 }
728729/// Creates a canonical variable (with the given `info`)
730 /// representing the region `r`; return a region referencing it.
731fn canonical_var_for_region(
732&mut self,
733 var_kind: CanonicalVarKind<'tcx>,
734 r: ty::Region<'tcx>,
735 ) -> ty::Region<'tcx> {
736let var = self.canonical_var(var_kind, r.into());
737 ty::Region::new_canonical_bound(self.cx(), var)
738 }
739740/// Given a type variable `ty_var` of the given kind, first check
741 /// if `ty_var` is bound to anything; if so, canonicalize
742 /// *that*. Otherwise, create a new canonical variable for
743 /// `ty_var`.
744fn canonicalize_ty_var(
745&mut self,
746 var_kind: CanonicalVarKind<'tcx>,
747 ty_var: Ty<'tcx>,
748 ) -> Ty<'tcx> {
749if true {
if !!self.infcx.is_some_and(|infcx|
ty_var != infcx.shallow_resolve(ty_var)) {
::core::panicking::panic("assertion failed: !self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var))")
};
};debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var)));
750let var = self.canonical_var(var_kind, ty_var.into());
751 Ty::new_canonical_bound(self.tcx, var)
752 }
753754/// Given a type variable `const_var` of the given kind, first check
755 /// if `const_var` is bound to anything; if so, canonicalize
756 /// *that*. Otherwise, create a new canonical variable for
757 /// `const_var`.
758fn canonicalize_const_var(
759&mut self,
760 var_kind: CanonicalVarKind<'tcx>,
761 ct_var: ty::Const<'tcx>,
762 ) -> ty::Const<'tcx> {
763if true {
if !!self.infcx.is_some_and(|infcx|
ct_var != infcx.shallow_resolve_const(ct_var)) {
::core::panicking::panic("assertion failed: !self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var))")
};
};debug_assert!(
764 !self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var))
765 );
766let var = self.canonical_var(var_kind, ct_var.into());
767 ty::Const::new_canonical_bound(self.tcx, var)
768 }
769}