Skip to main content

rustc_middle/ty/inhabitedness/
inhabited_predicate.rs

1use rustc_macros::HashStable;
2use smallvec::SmallVec;
3use tracing::instrument;
4
5use crate::ty::{self, DefId, OpaqueTypeKey, Ty, TyCtxt, TypingEnv};
6
7/// Represents whether some type is inhabited in a given context.
8/// Examples of uninhabited types are `!`, `enum Void {}`, or a struct
9/// containing either of those types.
10/// A type's inhabitedness may depend on the `ParamEnv` as well as what types
11/// are visible in the current module.
12#[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    /// Inhabited
15    True,
16    /// Uninhabited
17    False,
18    /// Uninhabited when a const value is non-zero. This occurs when there is an
19    /// array of uninhabited items, but the array is inhabited if it is empty.
20    ConstIsZero(ty::Const<'tcx>),
21    /// Uninhabited if within a certain module. This occurs when an uninhabited
22    /// type has restricted visibility.
23    NotInModule(DefId),
24    /// Inhabited if some generic type is inhabited.
25    /// These are replaced by calling [`Self::instantiate`].
26    GenericType(Ty<'tcx>),
27    /// Inhabited if either we don't know the hidden type or we know it and it is inhabited.
28    OpaqueType(OpaqueTypeKey<'tcx>),
29    /// A AND B
30    And(&'tcx [InhabitedPredicate<'tcx>; 2]),
31    /// A OR B
32    Or(&'tcx [InhabitedPredicate<'tcx>; 2]),
33}
34
35impl<'tcx> InhabitedPredicate<'tcx> {
36    /// Returns true if the corresponding type is inhabited in the given `ParamEnv` and module.
37    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    /// Returns true if the corresponding type is inhabited in the given `ParamEnv` and module,
47    /// revealing opaques when possible.
48    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    /// Same as `apply`, but returns `None` if self contains a module predicate
66    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    /// Same as `apply`, but `NotInModule(_)` predicates yield `false`. That is,
71    /// privately uninhabited types are considered always uninhabited.
72    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]>, // for cycle detection
86        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            // `t` may be a projection, for which `inhabited_predicate` returns a `GenericType`. As
98            // we have a param_env available, we can do better.
99            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                    // We don't have more information than we started with, so consider inhabited.
105                    Self::GenericType(_) => Ok(true),
106                    pred => {
107                        // A type which is cyclic when monomorphized can happen here since the
108                        // layout error would only trigger later. See e.g. `tests/ui/sized/recursive-type-2.rs`.
109                        if eval_stack.contains(&t) {
110                            return Ok(true); // Recover; this will error later.
111                        }
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                // Unknown opaque is assumed inhabited.
122                None => Ok(true),
123                // Known opaque type is inspected recursively.
124                Some(t) => {
125                    // A cyclic opaque type can happen in corner cases that would only error later.
126                    // See e.g. `tests/ui/type-alias-impl-trait/recursive-tait-conflicting-defn.rs`.
127                    if eval_stack.contains(&t) {
128                        return Ok(true); // Recover; this will error later.
129                    }
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    /// Replaces generic types with its corresponding predicate
234    pub fn instantiate(self, tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> Self {
235        self.instantiate_opt(tcx, args).unwrap_or(self)
236    }
237
238    /// Same as [`Self::instantiate`], but if there is no generics to
239    /// instantiate, returns `None`. This is useful because it lets us avoid
240    /// allocating a recursive copy of everything when the result is unchanged.
241    ///
242    /// Only used to implement `instantiate` itself.
243    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
275// this is basically like `f(a)? && f(b)?` but different in the case of
276// `Ok(false) && Err(_) -> Ok(false)`
277fn 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}