Skip to main content

rustc_middle/ty/inhabitedness/
mod.rs

1//! This module contains logic for determining whether a type is inhabited or
2//! uninhabited. The [`InhabitedPredicate`] type captures the minimum
3//! information needed to determine whether a type is inhabited given a
4//! `ParamEnv` and module ID.
5//!
6//! # Example
7//! ```rust
8//! #![feature(never_type)]
9//! mod a {
10//!     pub mod b {
11//!         pub struct SecretlyUninhabited {
12//!             _priv: !,
13//!         }
14//!     }
15//! }
16//!
17//! mod c {
18//!     enum Void {}
19//!     pub struct AlsoSecretlyUninhabited {
20//!         _priv: Void,
21//!     }
22//!     mod d {
23//!     }
24//! }
25//!
26//! struct Foo {
27//!     x: a::b::SecretlyUninhabited,
28//!     y: c::AlsoSecretlyUninhabited,
29//! }
30//! ```
31//! In this code, the type `Foo` will only be visibly uninhabited inside the
32//! modules `b`, `c` and `d`. Calling `inhabited_predicate` on `Foo` will
33//! return `NotInModule(b) AND NotInModule(c)`.
34//!
35//! We need this information for pattern-matching on `Foo` or types that contain
36//! `Foo`.
37//!
38//! # Example
39//! ```ignore(illustrative)
40//! let foo_result: Result<T, Foo> = ... ;
41//! let Ok(t) = foo_result;
42//! ```
43//! This code should only compile in modules where the uninhabitedness of `Foo`
44//! is visible.
45
46use rustc_type_ir::TyKind::*;
47use tracing::instrument;
48
49use crate::query::Providers;
50use crate::ty::{self, DefId, Ty, TyCtxt, TypeVisitableExt, VariantDef, Visibility};
51
52pub mod inhabited_predicate;
53
54pub use inhabited_predicate::InhabitedPredicate;
55
56pub(crate) fn provide(providers: &mut Providers) {
57    *providers = Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers };
58}
59
60/// Returns an `InhabitedPredicate` that is generic over type parameters and
61/// requires calling [`InhabitedPredicate::instantiate`]
62fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
63    if let Some(def_id) = def_id.as_local() {
64        if #[allow(non_exhaustive_omitted_patterns)] match tcx.representability(def_id) {
    ty::Representability::Infinite(_) => true,
    _ => false,
}matches!(tcx.representability(def_id), ty::Representability::Infinite(_)) {
65            return InhabitedPredicate::True;
66        }
67    }
68    let adt = tcx.adt_def(def_id);
69    InhabitedPredicate::any(
70        tcx,
71        adt.variants().iter().map(|variant| variant.inhabited_predicate(tcx, adt)),
72    )
73}
74
75impl<'tcx> VariantDef {
76    /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited.
77    pub fn inhabited_predicate(
78        &self,
79        tcx: TyCtxt<'tcx>,
80        adt: ty::AdtDef<'_>,
81    ) -> InhabitedPredicate<'tcx> {
82        if true {
    if !!adt.is_union() {
        ::core::panicking::panic("assertion failed: !adt.is_union()")
    };
};debug_assert!(!adt.is_union());
83        InhabitedPredicate::all(
84            tcx,
85            self.fields.iter().map(|field| {
86                let pred = tcx.type_of(field.did).instantiate_identity().inhabited_predicate(tcx);
87                if adt.is_enum() {
88                    return pred;
89                }
90                match field.vis {
91                    Visibility::Public => pred,
92                    Visibility::Restricted(from) => {
93                        pred.or(tcx, InhabitedPredicate::NotInModule(from))
94                    }
95                }
96            }),
97        )
98    }
99}
100
101impl<'tcx> Ty<'tcx> {
102    x;#[instrument(level = "debug", skip(tcx), ret)]
103    pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> {
104        debug_assert!(!self.has_infer());
105        match self.kind() {
106            // For now, unions are always considered inhabited
107            Adt(adt, _) if adt.is_union() => InhabitedPredicate::True,
108            // Non-exhaustive ADTs from other crates are always considered inhabited
109            Adt(adt, _) if adt.variant_list_has_applicable_non_exhaustive() => {
110                InhabitedPredicate::True
111            }
112            Never => InhabitedPredicate::False,
113            Param(_) | Alias(ty::Inherent | ty::Projection | ty::Free, _) => {
114                InhabitedPredicate::GenericType(self)
115            }
116            Alias(ty::Opaque, alias_ty) => {
117                match alias_ty.def_id.as_local() {
118                    // Foreign opaque is considered inhabited.
119                    None => InhabitedPredicate::True,
120                    // Local opaque type may possibly be revealed.
121                    Some(local_def_id) => {
122                        let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
123                        InhabitedPredicate::OpaqueType(key)
124                    }
125                }
126            }
127            Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
128            // use a query for more complex cases
129            Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
130            // references and other types are inhabited
131            _ => InhabitedPredicate::True,
132        }
133    }
134
135    /// Checks whether a type is visibly uninhabited from a particular module.
136    ///
137    /// # Example
138    /// ```
139    /// #![feature(never_type)]
140    /// # fn main() {}
141    /// enum Void {}
142    /// mod a {
143    ///     pub mod b {
144    ///         pub struct SecretlyUninhabited {
145    ///             _priv: !,
146    ///         }
147    ///     }
148    /// }
149    ///
150    /// mod c {
151    ///     use super::Void;
152    ///     pub struct AlsoSecretlyUninhabited {
153    ///         _priv: Void,
154    ///     }
155    ///     mod d {
156    ///     }
157    /// }
158    ///
159    /// struct Foo {
160    ///     x: a::b::SecretlyUninhabited,
161    ///     y: c::AlsoSecretlyUninhabited,
162    /// }
163    /// ```
164    /// In this code, the type `Foo` will only be visibly uninhabited inside the
165    /// modules b, c and d. This effects pattern-matching on `Foo` or types that
166    /// contain `Foo`.
167    ///
168    /// # Example
169    /// ```ignore (illustrative)
170    /// let foo_result: Result<T, Foo> = ... ;
171    /// let Ok(t) = foo_result;
172    /// ```
173    /// This code should only compile in modules where the uninhabitedness of Foo is
174    /// visible.
175    pub fn is_inhabited_from(
176        self,
177        tcx: TyCtxt<'tcx>,
178        module: DefId,
179        typing_env: ty::TypingEnv<'tcx>,
180    ) -> bool {
181        self.inhabited_predicate(tcx).apply(tcx, typing_env, module)
182    }
183
184    /// Returns true if the type is uninhabited without regard to visibility
185    pub fn is_privately_uninhabited(
186        self,
187        tcx: TyCtxt<'tcx>,
188        typing_env: ty::TypingEnv<'tcx>,
189    ) -> bool {
190        !self.inhabited_predicate(tcx).apply_ignore_module(tcx, typing_env)
191    }
192}
193
194/// N.B. this query should only be called through `Ty::inhabited_predicate`
195fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedPredicate<'tcx> {
196    match *ty.kind() {
197        Adt(adt, args) => tcx.inhabited_predicate_adt(adt.did()).instantiate(tcx, args),
198
199        Tuple(tys) => {
200            InhabitedPredicate::all(tcx, tys.iter().map(|ty| ty.inhabited_predicate(tcx)))
201        }
202
203        // If we can evaluate the array length before having a `ParamEnv`, then
204        // we can simplify the predicate. This is an optimization.
205        Array(ty, len) => match len.try_to_target_usize(tcx) {
206            Some(0) => InhabitedPredicate::True,
207            Some(1..) => ty.inhabited_predicate(tcx),
208            None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
209        },
210
211        _ => crate::util::bug::bug_fmt(format_args!("unexpected TyKind, use `Ty::inhabited_predicate`"))bug!("unexpected TyKind, use `Ty::inhabited_predicate`"),
212    }
213}