1use std::collections::hash_map::Entry;
25
26use rustc_data_structures::fx::FxHashMap;
27use rustc_data_structures::sync::Lock;
28use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
29pub use rustc_type_ir as ir;
30use smallvec::SmallVec;
31
32use crate::mir::ConstraintCategory;
33use crate::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
34
35pub type CanonicalQueryInput<'tcx, V> = ir::CanonicalQueryInput<TyCtxt<'tcx>, V>;
36pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>;
37pub type CanonicalVarKind<'tcx> = ir::CanonicalVarKind<TyCtxt<'tcx>>;
38pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
39pub type CanonicalVarKinds<'tcx> = &'tcx List<CanonicalVarKind<'tcx>>;
40
41#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for OriginalQueryValues<'tcx> {
#[inline]
fn clone(&self) -> OriginalQueryValues<'tcx> {
OriginalQueryValues {
universe_map: ::core::clone::Clone::clone(&self.universe_map),
var_values: ::core::clone::Clone::clone(&self.var_values),
}
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for OriginalQueryValues<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"OriginalQueryValues", "universe_map", &self.universe_map,
"var_values", &&self.var_values)
}
}Debug)]
46pub struct OriginalQueryValues<'tcx> {
47 pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
52
53 pub var_values: SmallVec<[GenericArg<'tcx>; 8]>,
56}
57
58impl<'tcx> Default for OriginalQueryValues<'tcx> {
59 fn default() -> Self {
60 let mut universe_map = SmallVec::default();
61 universe_map.push(ty::UniverseIndex::ROOT);
62
63 Self { universe_map, var_values: SmallVec::default() }
64 }
65}
66
67#[derive(#[automatically_derived]
impl<'tcx, R: ::core::clone::Clone> ::core::clone::Clone for
QueryResponse<'tcx, R> {
#[inline]
fn clone(&self) -> QueryResponse<'tcx, R> {
QueryResponse {
var_values: ::core::clone::Clone::clone(&self.var_values),
region_constraints: ::core::clone::Clone::clone(&self.region_constraints),
certainty: ::core::clone::Clone::clone(&self.certainty),
opaque_types: ::core::clone::Clone::clone(&self.opaque_types),
value: ::core::clone::Clone::clone(&self.value),
}
}
}Clone, #[automatically_derived]
impl<'tcx, R: ::core::fmt::Debug> ::core::fmt::Debug for
QueryResponse<'tcx, R> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field5_finish(f, "QueryResponse",
"var_values", &self.var_values, "region_constraints",
&self.region_constraints, "certainty", &self.certainty,
"opaque_types", &self.opaque_types, "value", &&self.value)
}
}Debug, const _: () =
{
impl<'tcx, '__ctx, R>
::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
for QueryResponse<'tcx, R> where
R: ::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
{
#[inline]
fn hash_stable(&self,
__hcx:
&mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
__hasher:
&mut ::rustc_data_structures::stable_hasher::StableHasher) {
match *self {
QueryResponse {
var_values: ref __binding_0,
region_constraints: ref __binding_1,
certainty: ref __binding_2,
opaque_types: ref __binding_3,
value: ref __binding_4 } => {
{ __binding_0.hash_stable(__hcx, __hasher); }
{ __binding_1.hash_stable(__hcx, __hasher); }
{ __binding_2.hash_stable(__hcx, __hasher); }
{ __binding_3.hash_stable(__hcx, __hasher); }
{ __binding_4.hash_stable(__hcx, __hasher); }
}
}
}
}
};HashStable, const _: () =
{
impl<'tcx, R>
::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>
for QueryResponse<'tcx, R> where
R: ::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>
{
fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
__folder: &mut __F) -> Result<Self, __F::Error> {
Ok(match self {
QueryResponse {
var_values: __binding_0,
region_constraints: __binding_1,
certainty: __binding_2,
opaque_types: __binding_3,
value: __binding_4 } => {
QueryResponse {
var_values: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
__folder)?,
region_constraints: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
__folder)?,
certainty: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_2,
__folder)?,
opaque_types: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_3,
__folder)?,
value: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_4,
__folder)?,
}
}
})
}
fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
__folder: &mut __F) -> Self {
match self {
QueryResponse {
var_values: __binding_0,
region_constraints: __binding_1,
certainty: __binding_2,
opaque_types: __binding_3,
value: __binding_4 } => {
QueryResponse {
var_values: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
__folder),
region_constraints: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
__folder),
certainty: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_2,
__folder),
opaque_types: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_3,
__folder),
value: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_4,
__folder),
}
}
}
}
}
};TypeFoldable, const _: () =
{
impl<'tcx, R>
::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>
for QueryResponse<'tcx, R> where
R: ::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>
{
fn visit_with<__V: ::rustc_middle::ty::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>(&self,
__visitor: &mut __V) -> __V::Result {
match *self {
QueryResponse {
var_values: ref __binding_0,
region_constraints: ref __binding_1,
certainty: ref __binding_2,
opaque_types: ref __binding_3,
value: ref __binding_4 } => {
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_0,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_1,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_2,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_3,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_4,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
}
}
<__V::Result as ::rustc_middle::ty::VisitorResult>::output()
}
}
};TypeVisitable)]
71pub struct QueryResponse<'tcx, R> {
72 pub var_values: CanonicalVarValues<'tcx>,
73 pub region_constraints: QueryRegionConstraints<'tcx>,
74 pub certainty: Certainty,
75 pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
76 pub value: R,
77}
78
79#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for QueryRegionConstraints<'tcx> {
#[inline]
fn clone(&self) -> QueryRegionConstraints<'tcx> {
QueryRegionConstraints {
outlives: ::core::clone::Clone::clone(&self.outlives),
assumptions: ::core::clone::Clone::clone(&self.assumptions),
}
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for QueryRegionConstraints<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"QueryRegionConstraints", "outlives", &self.outlives,
"assumptions", &&self.assumptions)
}
}Debug, #[automatically_derived]
impl<'tcx> ::core::default::Default for QueryRegionConstraints<'tcx> {
#[inline]
fn default() -> QueryRegionConstraints<'tcx> {
QueryRegionConstraints {
outlives: ::core::default::Default::default(),
assumptions: ::core::default::Default::default(),
}
}
}Default, #[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for QueryRegionConstraints<'tcx> {
#[inline]
fn eq(&self, other: &QueryRegionConstraints<'tcx>) -> bool {
self.outlives == other.outlives &&
self.assumptions == other.assumptions
}
}PartialEq, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for QueryRegionConstraints<'tcx> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _:
::core::cmp::AssertParamIsEq<Vec<QueryOutlivesConstraint<'tcx>>>;
let _:
::core::cmp::AssertParamIsEq<Vec<ty::ArgOutlivesPredicate<'tcx>>>;
}
}Eq, #[automatically_derived]
impl<'tcx> ::core::hash::Hash for QueryRegionConstraints<'tcx> {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.outlives, state);
::core::hash::Hash::hash(&self.assumptions, state)
}
}Hash)]
80#[derive(const _: () =
{
impl<'tcx, '__ctx>
::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
for QueryRegionConstraints<'tcx> {
#[inline]
fn hash_stable(&self,
__hcx:
&mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
__hasher:
&mut ::rustc_data_structures::stable_hasher::StableHasher) {
match *self {
QueryRegionConstraints {
outlives: ref __binding_0, assumptions: ref __binding_1 } =>
{
{ __binding_0.hash_stable(__hcx, __hasher); }
{ __binding_1.hash_stable(__hcx, __hasher); }
}
}
}
}
};HashStable, const _: () =
{
impl<'tcx>
::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>
for QueryRegionConstraints<'tcx> {
fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
__folder: &mut __F) -> Result<Self, __F::Error> {
Ok(match self {
QueryRegionConstraints {
outlives: __binding_0, assumptions: __binding_1 } => {
QueryRegionConstraints {
outlives: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
__folder)?,
assumptions: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
__folder)?,
}
}
})
}
fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
__folder: &mut __F) -> Self {
match self {
QueryRegionConstraints {
outlives: __binding_0, assumptions: __binding_1 } => {
QueryRegionConstraints {
outlives: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
__folder),
assumptions: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
__folder),
}
}
}
}
}
};TypeFoldable, const _: () =
{
impl<'tcx>
::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>
for QueryRegionConstraints<'tcx> {
fn visit_with<__V: ::rustc_middle::ty::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>(&self,
__visitor: &mut __V) -> __V::Result {
match *self {
QueryRegionConstraints {
outlives: ref __binding_0, assumptions: ref __binding_1 } =>
{
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_0,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
{
match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_1,
__visitor)) {
::core::ops::ControlFlow::Continue(()) => {}
::core::ops::ControlFlow::Break(r) => {
return ::rustc_middle::ty::VisitorResult::from_residual(r);
}
}
}
}
}
<__V::Result as ::rustc_middle::ty::VisitorResult>::output()
}
}
};TypeVisitable)]
81pub struct QueryRegionConstraints<'tcx> {
82 pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
83 pub assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
84}
85
86impl QueryRegionConstraints<'_> {
87 pub fn is_empty(&self) -> bool {
94 self.outlives.is_empty() && self.assumptions.is_empty()
95 }
96}
97
98pub type CanonicalQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
99
100#[derive(#[automatically_derived]
impl ::core::marker::Copy for Certainty { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Certainty {
#[inline]
fn clone(&self) -> Certainty { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for Certainty {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
Certainty::Proven => "Proven",
Certainty::Ambiguous => "Ambiguous",
})
}
}Debug, const _: () =
{
impl<'__ctx>
::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
for Certainty {
#[inline]
fn hash_stable(&self,
__hcx:
&mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
__hasher:
&mut ::rustc_data_structures::stable_hasher::StableHasher) {
::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
match *self {
Certainty::Proven => {}
Certainty::Ambiguous => {}
}
}
}
};HashStable)]
103pub enum Certainty {
104 Proven,
107
108 Ambiguous,
120}
121
122impl Certainty {
123 pub fn is_proven(&self) -> bool {
124 match self {
125 Certainty::Proven => true,
126 Certainty::Ambiguous => false,
127 }
128 }
129}
130
131impl<'tcx, R> QueryResponse<'tcx, R> {
132 pub fn is_proven(&self) -> bool {
133 self.certainty.is_proven()
134 }
135}
136
137pub type QueryOutlivesConstraint<'tcx> = (ty::ArgOutlivesPredicate<'tcx>, ConstraintCategory<'tcx>);
138
139#[derive(#[automatically_derived]
impl<'tcx> ::core::default::Default for CanonicalParamEnvCache<'tcx> {
#[inline]
fn default() -> CanonicalParamEnvCache<'tcx> {
CanonicalParamEnvCache { map: ::core::default::Default::default() }
}
}Default)]
140pub struct CanonicalParamEnvCache<'tcx> {
141 map: Lock<
142 FxHashMap<
143 ty::ParamEnv<'tcx>,
144 (Canonical<'tcx, ty::ParamEnv<'tcx>>, &'tcx [GenericArg<'tcx>]),
145 >,
146 >,
147}
148
149impl<'tcx> CanonicalParamEnvCache<'tcx> {
150 pub fn get_or_insert(
157 &self,
158 tcx: TyCtxt<'tcx>,
159 key: ty::ParamEnv<'tcx>,
160 state: &mut OriginalQueryValues<'tcx>,
161 canonicalize_op: fn(
162 TyCtxt<'tcx>,
163 ty::ParamEnv<'tcx>,
164 &mut OriginalQueryValues<'tcx>,
165 ) -> Canonical<'tcx, ty::ParamEnv<'tcx>>,
166 ) -> Canonical<'tcx, ty::ParamEnv<'tcx>> {
167 if !key.has_type_flags(
168 TypeFlags::HAS_INFER | TypeFlags::HAS_PLACEHOLDER | TypeFlags::HAS_FREE_REGIONS,
169 ) {
170 return Canonical {
171 max_universe: ty::UniverseIndex::ROOT,
172 var_kinds: List::empty(),
173 value: key,
174 };
175 }
176
177 match (&state.var_values.len(), &0) {
(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!(state.var_values.len(), 0);
178 match (&state.universe_map.len(), &1) {
(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!(state.universe_map.len(), 1);
179 if true {
match (&&*state.universe_map, &&[ty::UniverseIndex::ROOT]) {
(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);
}
}
};
};debug_assert_eq!(&*state.universe_map, &[ty::UniverseIndex::ROOT]);
180
181 match self.map.borrow().entry(key) {
182 Entry::Occupied(e) => {
183 let (canonical, var_values) = e.get();
184 if truecfg!(debug_assertions) {
185 let mut state = state.clone();
186 let rerun_canonical = canonicalize_op(tcx, key, &mut state);
187 match (&rerun_canonical, &*canonical) {
(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!(rerun_canonical, *canonical);
188 let OriginalQueryValues { var_values: rerun_var_values, universe_map } = state;
189 match (&universe_map.len(), &1) {
(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!(universe_map.len(), 1);
190 match (&**var_values, &*rerun_var_values) {
(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_values, *rerun_var_values);
191 }
192 state.var_values.extend_from_slice(var_values);
193 *canonical
194 }
195 Entry::Vacant(e) => {
196 let canonical = canonicalize_op(tcx, key, state);
197 let OriginalQueryValues { var_values, universe_map } = state;
198 match (&universe_map.len(), &1) {
(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!(universe_map.len(), 1);
199 e.insert((canonical, tcx.arena.alloc_slice(var_values)));
200 canonical
201 }
202 }
203 }
204}