1use rustc_macros::HashStable;
2use smallvec::SmallVec;
3use tracing::instrument;
4
5use crate::ty::{self, DefId, OpaqueTypeKey, Ty, TyCtxt, TypingEnv};
6
7#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for InhabitedPredicate<'tcx> {
#[inline]
fn clone(&self) -> InhabitedPredicate<'tcx> {
let _: ::core::clone::AssertParamIsClone<ty::Const<'tcx>>;
let _: ::core::clone::AssertParamIsClone<DefId>;
let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
let _: ::core::clone::AssertParamIsClone<OpaqueTypeKey<'tcx>>;
let _:
::core::clone::AssertParamIsClone<&'tcx [InhabitedPredicate<'tcx>; 2]>;
let _:
::core::clone::AssertParamIsClone<&'tcx [InhabitedPredicate<'tcx>; 2]>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for InhabitedPredicate<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for InhabitedPredicate<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
InhabitedPredicate::True =>
::core::fmt::Formatter::write_str(f, "True"),
InhabitedPredicate::False =>
::core::fmt::Formatter::write_str(f, "False"),
InhabitedPredicate::ConstIsZero(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"ConstIsZero", &__self_0),
InhabitedPredicate::NotInModule(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"NotInModule", &__self_0),
InhabitedPredicate::GenericType(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"GenericType", &__self_0),
InhabitedPredicate::OpaqueType(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"OpaqueType", &__self_0),
InhabitedPredicate::And(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "And",
&__self_0),
InhabitedPredicate::Or(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Or",
&__self_0),
}
}
}Debug, #[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for InhabitedPredicate<'tcx> {
#[inline]
fn eq(&self, other: &InhabitedPredicate<'tcx>) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(InhabitedPredicate::ConstIsZero(__self_0),
InhabitedPredicate::ConstIsZero(__arg1_0)) =>
__self_0 == __arg1_0,
(InhabitedPredicate::NotInModule(__self_0),
InhabitedPredicate::NotInModule(__arg1_0)) =>
__self_0 == __arg1_0,
(InhabitedPredicate::GenericType(__self_0),
InhabitedPredicate::GenericType(__arg1_0)) =>
__self_0 == __arg1_0,
(InhabitedPredicate::OpaqueType(__self_0),
InhabitedPredicate::OpaqueType(__arg1_0)) =>
__self_0 == __arg1_0,
(InhabitedPredicate::And(__self_0),
InhabitedPredicate::And(__arg1_0)) => __self_0 == __arg1_0,
(InhabitedPredicate::Or(__self_0),
InhabitedPredicate::Or(__arg1_0)) => __self_0 == __arg1_0,
_ => true,
}
}
}PartialEq, const _: () =
{
impl<'tcx, '__ctx>
::rustc_data_structures::stable_hasher::HashStable<::rustc_middle::ich::StableHashingContext<'__ctx>>
for InhabitedPredicate<'tcx> {
#[inline]
fn hash_stable(&self,
__hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>,
__hasher:
&mut ::rustc_data_structures::stable_hasher::StableHasher) {
::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
match *self {
InhabitedPredicate::True => {}
InhabitedPredicate::False => {}
InhabitedPredicate::ConstIsZero(ref __binding_0) => {
{ __binding_0.hash_stable(__hcx, __hasher); }
}
InhabitedPredicate::NotInModule(ref __binding_0) => {
{ __binding_0.hash_stable(__hcx, __hasher); }
}
InhabitedPredicate::GenericType(ref __binding_0) => {
{ __binding_0.hash_stable(__hcx, __hasher); }
}
InhabitedPredicate::OpaqueType(ref __binding_0) => {
{ __binding_0.hash_stable(__hcx, __hasher); }
}
InhabitedPredicate::And(ref __binding_0) => {
{ __binding_0.hash_stable(__hcx, __hasher); }
}
InhabitedPredicate::Or(ref __binding_0) => {
{ __binding_0.hash_stable(__hcx, __hasher); }
}
}
}
}
};HashStable)]
13pub enum InhabitedPredicate<'tcx> {
14 True,
16 False,
18 ConstIsZero(ty::Const<'tcx>),
21 NotInModule(DefId),
24 GenericType(Ty<'tcx>),
27 OpaqueType(OpaqueTypeKey<'tcx>),
29 And(&'tcx [InhabitedPredicate<'tcx>; 2]),
31 Or(&'tcx [InhabitedPredicate<'tcx>; 2]),
33}
34
35impl<'tcx> InhabitedPredicate<'tcx> {
36 pub fn apply(
38 self,
39 tcx: TyCtxt<'tcx>,
40 typing_env: TypingEnv<'tcx>,
41 module_def_id: DefId,
42 ) -> bool {
43 self.apply_revealing_opaque(tcx, typing_env, module_def_id, &|_| None)
44 }
45
46 pub fn apply_revealing_opaque(
49 self,
50 tcx: TyCtxt<'tcx>,
51 typing_env: TypingEnv<'tcx>,
52 module_def_id: DefId,
53 reveal_opaque: &impl Fn(OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>>,
54 ) -> bool {
55 let Ok(result) = self.apply_inner::<!>(
56 tcx,
57 typing_env,
58 &mut Default::default(),
59 &|id| Ok(tcx.is_descendant_of(module_def_id, id)),
60 reveal_opaque,
61 );
62 result
63 }
64
65 pub fn apply_any_module(self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>) -> Option<bool> {
67 self.apply_inner(tcx, typing_env, &mut Default::default(), &|_| Err(()), &|_| None).ok()
68 }
69
70 pub fn apply_ignore_module(self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>) -> bool {
73 let Ok(result) =
74 self.apply_inner::<!>(tcx, typing_env, &mut Default::default(), &|_| Ok(true), &|_| {
75 None
76 });
77 result
78 }
79
80 x;#[instrument(level = "debug", skip(tcx, typing_env, in_module, reveal_opaque), ret)]
81 fn apply_inner<E: std::fmt::Debug>(
82 self,
83 tcx: TyCtxt<'tcx>,
84 typing_env: TypingEnv<'tcx>,
85 eval_stack: &mut SmallVec<[Ty<'tcx>; 1]>, in_module: &impl Fn(DefId) -> Result<bool, E>,
87 reveal_opaque: &impl Fn(OpaqueTypeKey<'tcx>) -> Option<Ty<'tcx>>,
88 ) -> Result<bool, E> {
89 match self {
90 Self::False => Ok(false),
91 Self::True => Ok(true),
92 Self::ConstIsZero(const_) => match const_.try_to_target_usize(tcx) {
93 None | Some(0) => Ok(true),
94 Some(1..) => Ok(false),
95 },
96 Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod),
97 Self::GenericType(t) => {
100 let normalized_pred = tcx
101 .try_normalize_erasing_regions(typing_env, t)
102 .map_or(self, |t| t.inhabited_predicate(tcx));
103 match normalized_pred {
104 Self::GenericType(_) => Ok(true),
106 pred => {
107 if eval_stack.contains(&t) {
110 return Ok(true); }
112 eval_stack.push(t);
113 let ret =
114 pred.apply_inner(tcx, typing_env, eval_stack, in_module, reveal_opaque);
115 eval_stack.pop();
116 ret
117 }
118 }
119 }
120 Self::OpaqueType(key) => match reveal_opaque(key) {
121 None => Ok(true),
123 Some(t) => {
125 if eval_stack.contains(&t) {
128 return Ok(true); }
130 eval_stack.push(t);
131 let ret = t.inhabited_predicate(tcx).apply_inner(
132 tcx,
133 typing_env,
134 eval_stack,
135 in_module,
136 reveal_opaque,
137 );
138 eval_stack.pop();
139 ret
140 }
141 },
142 Self::And([a, b]) => try_and(a, b, |x| {
143 x.apply_inner(tcx, typing_env, eval_stack, in_module, reveal_opaque)
144 }),
145 Self::Or([a, b]) => try_or(a, b, |x| {
146 x.apply_inner(tcx, typing_env, eval_stack, in_module, reveal_opaque)
147 }),
148 }
149 }
150
151 pub fn and(self, tcx: TyCtxt<'tcx>, other: Self) -> Self {
152 self.reduce_and(tcx, other).unwrap_or_else(|| Self::And(tcx.arena.alloc([self, other])))
153 }
154
155 pub fn or(self, tcx: TyCtxt<'tcx>, other: Self) -> Self {
156 self.reduce_or(tcx, other).unwrap_or_else(|| Self::Or(tcx.arena.alloc([self, other])))
157 }
158
159 pub fn all(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self {
160 let mut result = Self::True;
161 for pred in iter {
162 if pred == Self::False {
163 return Self::False;
164 }
165 result = result.and(tcx, pred);
166 }
167 result
168 }
169
170 pub fn any(tcx: TyCtxt<'tcx>, iter: impl IntoIterator<Item = Self>) -> Self {
171 let mut result = Self::False;
172 for pred in iter {
173 if pred == Self::True {
174 return Self::True;
175 }
176 result = result.or(tcx, pred);
177 }
178 result
179 }
180
181 fn reduce_and(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> {
182 match (self, other) {
183 (Self::True, a) | (a, Self::True) => Some(a),
184 (Self::False, _) | (_, Self::False) => Some(Self::False),
185 (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)),
186 (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)),
187 (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => {
188 Some(Self::NotInModule(b))
189 }
190 (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => {
191 Some(Self::NotInModule(a))
192 }
193 (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)),
194 (Self::And(&[a, b]), c) | (c, Self::And(&[a, b])) => {
195 if let Some(ac) = a.reduce_and(tcx, c) {
196 Some(ac.and(tcx, b))
197 } else if let Some(bc) = b.reduce_and(tcx, c) {
198 Some(Self::And(tcx.arena.alloc([a, bc])))
199 } else {
200 None
201 }
202 }
203 _ => None,
204 }
205 }
206
207 fn reduce_or(self, tcx: TyCtxt<'tcx>, other: Self) -> Option<Self> {
208 match (self, other) {
209 (Self::True, _) | (_, Self::True) => Some(Self::True),
210 (Self::False, a) | (a, Self::False) => Some(a),
211 (Self::ConstIsZero(a), Self::ConstIsZero(b)) if a == b => Some(Self::ConstIsZero(a)),
212 (Self::NotInModule(a), Self::NotInModule(b)) if a == b => Some(Self::NotInModule(a)),
213 (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(a, b) => {
214 Some(Self::NotInModule(a))
215 }
216 (Self::NotInModule(a), Self::NotInModule(b)) if tcx.is_descendant_of(b, a) => {
217 Some(Self::NotInModule(b))
218 }
219 (Self::GenericType(a), Self::GenericType(b)) if a == b => Some(Self::GenericType(a)),
220 (Self::Or(&[a, b]), c) | (c, Self::Or(&[a, b])) => {
221 if let Some(ac) = a.reduce_or(tcx, c) {
222 Some(ac.or(tcx, b))
223 } else if let Some(bc) = b.reduce_or(tcx, c) {
224 Some(Self::Or(tcx.arena.alloc([a, bc])))
225 } else {
226 None
227 }
228 }
229 _ => None,
230 }
231 }
232
233 pub fn instantiate(self, tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> Self {
235 self.instantiate_opt(tcx, args).unwrap_or(self)
236 }
237
238 fn instantiate_opt(self, tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> Option<Self> {
244 match self {
245 Self::ConstIsZero(c) => {
246 let c = ty::EarlyBinder::bind(c).instantiate(tcx, args);
247 let pred = match c.try_to_target_usize(tcx) {
248 Some(0) => Self::True,
249 Some(1..) => Self::False,
250 None => Self::ConstIsZero(c),
251 };
252 Some(pred)
253 }
254 Self::GenericType(t) => {
255 Some(ty::EarlyBinder::bind(t).instantiate(tcx, args).inhabited_predicate(tcx))
256 }
257 Self::And(&[a, b]) => match a.instantiate_opt(tcx, args) {
258 None => b.instantiate_opt(tcx, args).map(|b| a.and(tcx, b)),
259 Some(InhabitedPredicate::False) => Some(InhabitedPredicate::False),
260 Some(a) => Some(a.and(tcx, b.instantiate_opt(tcx, args).unwrap_or(b))),
261 },
262 Self::Or(&[a, b]) => match a.instantiate_opt(tcx, args) {
263 None => b.instantiate_opt(tcx, args).map(|b| a.or(tcx, b)),
264 Some(InhabitedPredicate::True) => Some(InhabitedPredicate::True),
265 Some(a) => Some(a.or(tcx, b.instantiate_opt(tcx, args).unwrap_or(b))),
266 },
267 Self::True | Self::False | Self::NotInModule(_) => None,
268 Self::OpaqueType(_) => {
269 crate::util::bug::bug_fmt(format_args!("unexpected OpaqueType in InhabitedPredicate"));bug!("unexpected OpaqueType in InhabitedPredicate");
270 }
271 }
272 }
273}
274
275fn try_and<T, E>(a: T, b: T, mut f: impl FnMut(T) -> Result<bool, E>) -> Result<bool, E> {
278 let a = f(a);
279 if #[allow(non_exhaustive_omitted_patterns)] match a {
Ok(false) => true,
_ => false,
}matches!(a, Ok(false)) {
280 return Ok(false);
281 }
282 match (a, f(b)) {
283 (_, Ok(false)) | (Ok(false), _) => Ok(false),
284 (Ok(true), Ok(true)) => Ok(true),
285 (Err(e), _) | (_, Err(e)) => Err(e),
286 }
287}
288
289fn try_or<T, E>(a: T, b: T, mut f: impl FnMut(T) -> Result<bool, E>) -> Result<bool, E> {
290 let a = f(a);
291 if #[allow(non_exhaustive_omitted_patterns)] match a {
Ok(true) => true,
_ => false,
}matches!(a, Ok(true)) {
292 return Ok(true);
293 }
294 match (a, f(b)) {
295 (_, Ok(true)) | (Ok(true), _) => Ok(true),
296 (Ok(false), Ok(false)) => Ok(false),
297 (Err(e), _) | (_, Err(e)) => Err(e),
298 }
299}