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 std::assert_matches;
47
48use rustc_data_structures::fx::FxHashSet;
49use rustc_span::def_id::LocalModId;
50use rustc_type_ir::TyKind::*;
51use tracing::instrument;
52
53use crate::query::Providers;
54use crate::ty::{self, DefId, Ty, TyCtxt, TypeVisitableExt, VariantDef, Visibility};
55
56pub mod inhabited_predicate;
57
58pub use inhabited_predicate::InhabitedPredicate;
59
60pub(crate) fn provide(providers: &mut Providers) {
61    *providers = Providers {
62        inhabited_predicate_adt,
63        inhabited_predicate_type,
64        is_opsem_inhabited_raw,
65        ..*providers
66    };
67}
68
69/// Returns an `InhabitedPredicate` that is generic over type parameters and
70/// requires calling [`InhabitedPredicate::instantiate`]
71fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
72    if let Some(def_id) = def_id.as_local() {
73        tcx.ensure_ok().check_representability(def_id);
74    }
75
76    let adt = tcx.adt_def(def_id);
77    InhabitedPredicate::any(
78        tcx,
79        adt.variants().iter().map(|variant| variant.inhabited_predicate(tcx, adt)),
80    )
81}
82
83impl<'tcx> VariantDef {
84    /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited.
85    pub fn inhabited_predicate(
86        &self,
87        tcx: TyCtxt<'tcx>,
88        adt: ty::AdtDef<'_>,
89    ) -> InhabitedPredicate<'tcx> {
90        if true {
    if !!adt.is_union() {
        ::core::panicking::panic("assertion failed: !adt.is_union()")
    };
};debug_assert!(!adt.is_union());
91        InhabitedPredicate::all(
92            tcx,
93            self.fields.iter().map(|field| {
94                let pred = tcx
95                    .type_of(field.did)
96                    .instantiate_identity()
97                    .skip_norm_wip()
98                    .inhabited_predicate(tcx);
99                if adt.is_enum() {
100                    return pred;
101                }
102                match field.vis {
103                    Visibility::Public => pred,
104                    Visibility::Restricted(from) => {
105                        InhabitedPredicate::NotInModule(from).or(tcx, pred)
106                    }
107                }
108            }),
109        )
110    }
111}
112
113impl<'tcx> Ty<'tcx> {
114    x;#[instrument(level = "debug", skip(tcx), ret)]
115    pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> {
116        debug_assert!(!self.has_infer());
117        match self.kind() {
118            // For now, unions are always considered inhabited
119            Adt(adt, _) if adt.is_union() => InhabitedPredicate::True,
120            // Non-exhaustive ADTs from other crates are always considered inhabited
121            Adt(adt, _) if adt.variant_list_has_applicable_non_exhaustive() => {
122                InhabitedPredicate::True
123            }
124            Never => InhabitedPredicate::False,
125            // FIXME(#155345): This should only encounter rigid aliases with the new solver.
126            Param(_)
127            | Alias(
128                _,
129                ty::AliasTy {
130                    kind: ty::Inherent { .. } | ty::Projection { .. } | ty::Free { .. },
131                    ..
132                },
133            ) => InhabitedPredicate::GenericType(self),
134            &Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
135                match def_id.as_local() {
136                    // Foreign opaque is considered inhabited.
137                    None => InhabitedPredicate::True,
138                    // Local opaque type may possibly be revealed.
139                    Some(local_def_id) => {
140                        let key = ty::OpaqueTypeKey { def_id: local_def_id, args };
141                        InhabitedPredicate::OpaqueType(key)
142                    }
143                }
144            }
145            Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
146            // use a query for more complex cases
147            Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
148            // references and other types are inhabited
149            _ => InhabitedPredicate::True,
150        }
151    }
152
153    /// Checks whether a type is visibly uninhabited from a particular module.
154    ///
155    /// # Example
156    /// ```
157    /// #![feature(never_type)]
158    /// # fn main() {}
159    /// enum Void {}
160    /// mod a {
161    ///     pub mod b {
162    ///         pub struct SecretlyUninhabited {
163    ///             _priv: !,
164    ///         }
165    ///     }
166    /// }
167    ///
168    /// mod c {
169    ///     use super::Void;
170    ///     pub struct AlsoSecretlyUninhabited {
171    ///         _priv: Void,
172    ///     }
173    ///     mod d {
174    ///     }
175    /// }
176    ///
177    /// struct Foo {
178    ///     x: a::b::SecretlyUninhabited,
179    ///     y: c::AlsoSecretlyUninhabited,
180    /// }
181    /// ```
182    /// In this code, the type `Foo` will only be visibly uninhabited inside the
183    /// modules b, c and d. This effects pattern-matching on `Foo` or types that
184    /// contain `Foo`.
185    ///
186    /// # Example
187    /// ```ignore (illustrative)
188    /// let foo_result: Result<T, Foo> = ... ;
189    /// let Ok(t) = foo_result;
190    /// ```
191    /// This code should only compile in modules where the uninhabitedness of Foo is
192    /// visible.
193    pub fn is_inhabited_from(
194        self,
195        tcx: TyCtxt<'tcx>,
196        module: LocalModId,
197        typing_env: ty::TypingEnv<'tcx>,
198    ) -> bool {
199        self.inhabited_predicate(tcx).apply(tcx, typing_env, module)
200    }
201
202    /// Returns true if the type is uninhabited without regard to visibility.
203    ///
204    /// This is still conservative; for instance, a `#[non_exhaustive]` enum *in another crate*
205    /// is always considered inhabited.
206    pub fn is_privately_uninhabited(
207        self,
208        tcx: TyCtxt<'tcx>,
209        typing_env: ty::TypingEnv<'tcx>,
210    ) -> bool {
211        !self.inhabited_predicate(tcx).apply_ignore_module(tcx, typing_env)
212    }
213
214    /// Returns whether `self` is considered inhabited on the opsem level, i.e., its validity
215    /// invariant might be satisfiable. `self` is expected to be monomorphic and normalized.
216    ///
217    /// Key constraints are:
218    /// - if a type's validity invariant is satisfiable, it must be opsem-inhabited.
219    /// - if a type's layout is marked uninhabited, it must be opsem-uninhabited.
220    ///
221    /// Beyond that, the value returned by this function is not a stable guarantee.
222    pub fn is_opsem_inhabited(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
223        // Handle simple cases directly, use the query with its cache for the rest.
224        is_opsem_inhabited_recursor(self, tcx, &mut (), /* stop_at_ref */ false, &|ty, _, _| {
225            // ADT handler: stop recursing, invoke the query.
226            tcx.is_opsem_inhabited_raw(typing_env.as_query_input(ty))
227        })
228    }
229}
230
231/// N.B. this query should only be called through `Ty::inhabited_predicate`
232fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedPredicate<'tcx> {
233    match *ty.kind() {
234        Adt(adt, args) => tcx.inhabited_predicate_adt(adt.did()).instantiate(tcx, args),
235
236        Tuple(tys) => {
237            InhabitedPredicate::all(tcx, tys.iter().map(|ty| ty.inhabited_predicate(tcx)))
238        }
239
240        // If we can evaluate the array length before having a `ParamEnv`, then
241        // we can simplify the predicate. This is an optimization.
242        Array(ty, len) => match len.try_to_target_usize(tcx) {
243            Some(0) => InhabitedPredicate::True,
244            Some(1..) => ty.inhabited_predicate(tcx),
245            None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
246        },
247
248        _ => crate::util::bug::bug_fmt(format_args!("unexpected TyKind, use `Ty::inhabited_predicate`"))bug!("unexpected TyKind, use `Ty::inhabited_predicate`"),
249    }
250}
251
252/// Recurse over a type to determine whether it is inhabited on the opsem level.
253/// See `is_opsem_inhabited` above for the spec of what we compute.
254///
255/// When we encounter an ADT, we call `adt_handler`, giving it as its last argument a closure that
256/// it can invoke to continue the recursion. This lets us share the logic for "simple" cases
257/// (i.e., everything except for ADTs) between `Ty::is_opsem_inhabited` and the query.
258///
259/// `seen` is used to detect infinite recursion: the set contains all ADTs that we encountered
260/// on our path to the current type.
261/// If `stop_at_ref` is true, we stop recursing at the next reference we encounter.
262fn is_opsem_inhabited_recursor<'tcx, SEEN>(
263    ty: Ty<'tcx>,
264    tcx: TyCtxt<'tcx>,
265    seen: &mut SEEN,
266    stop_at_ref: bool,
267    adt_handler: &impl Fn(
268        Ty<'tcx>,
269        &mut SEEN,
270        &dyn Fn(Ty<'tcx>, &mut SEEN, /* stop_at_ref */ bool) -> bool,
271    ) -> bool,
272) -> bool {
273    match *ty.kind() {
274        // Trivially (un)inhabited types
275        ty::Int(_)
276        | ty::Uint(_)
277        | ty::Float(_)
278        | ty::Bool
279        | ty::Char
280        | ty::Str
281        | ty::Foreign(..)
282        | ty::RawPtr(..)
283        | ty::FnPtr(..)
284        | ty::FnDef(..) => true,
285        ty::Dynamic(..) => true, // We can't reason about traits, assume they are inhabited
286        ty::Slice(..) => true,   // Slices can always be empty
287        ty::Never => false,
288
289        // Types where we recurse
290        ty::Ref(_, pointee, _) => {
291            if stop_at_ref {
292                // Bailing out here is safe as the layout code always considers references
293                // inhabited, so the implication ("layout uninhabited => opsem uninhabited")
294                // is upheld.
295                return true;
296            }
297            is_opsem_inhabited_recursor(pointee, tcx, seen, stop_at_ref, adt_handler)
298        }
299        ty::Tuple(tys) => tys
300            .iter()
301            .all(|ty| is_opsem_inhabited_recursor(ty, tcx, seen, stop_at_ref, adt_handler)),
302        ty::Array(elem, len) => {
303            len.try_to_target_usize(tcx).unwrap() == 0
304                || is_opsem_inhabited_recursor(elem, tcx, seen, stop_at_ref, adt_handler)
305        }
306        ty::Pat(inner, _pat) => {
307            is_opsem_inhabited_recursor(inner, tcx, seen, stop_at_ref, adt_handler)
308        }
309        ty::Closure(_def, args) => {
310            let args = args.as_closure();
311            args.upvar_tys()
312                .iter()
313                .all(|ty| is_opsem_inhabited_recursor(ty, tcx, seen, stop_at_ref, adt_handler))
314        }
315        ty::Coroutine(_def, args) => {
316            let args = args.as_coroutine();
317            args.upvar_tys()
318                .iter()
319                .all(|ty| is_opsem_inhabited_recursor(ty, tcx, seen, stop_at_ref, adt_handler))
320        }
321        ty::CoroutineClosure(_def, args) => {
322            let args = args.as_coroutine_closure();
323            args.upvar_tys()
324                .iter()
325                .all(|ty| is_opsem_inhabited_recursor(ty, tcx, seen, stop_at_ref, adt_handler))
326        }
327        ty::UnsafeBinder(base) => {
328            let base = tcx.instantiate_bound_regions_with_erased((*base).into());
329            is_opsem_inhabited_recursor(base, tcx, seen, stop_at_ref, adt_handler)
330        }
331        ty::Adt(..) => {
332            // ADTs need a special handler to avoid infinite recursion. That handler is meant to
333            // call back into the recursor. Ideally it'd just call `is_opsem_inhabited_recursor` but
334            // then it would have to pass itself as the adt_handler argument which is not possible
335            // in Rust... so we provide the handler with a callback that it can use to continue the
336            // recursion with the same `adt_handler`.
337            adt_handler(ty, seen, &|ty, seen, stop_at_ref| {
338                is_opsem_inhabited_recursor(ty, tcx, seen, stop_at_ref, adt_handler)
339            })
340        }
341
342        ty::Error(_error_guaranteed) => {
343            // We have a token proving there was an error, so we can return a dummy value.
344            true
345        }
346
347        ty::Infer(..)
348        | ty::Placeholder(..)
349        | ty::Bound(..)
350        | ty::Param(..)
351        | ty::Alias(..)
352        | ty::CoroutineWitness(..) => {
353            crate::util::bug::bug_fmt(format_args!("non-normalized type in `is_opsem_uninhabited`: `{0}`",
        ty))bug!("non-normalized type in `is_opsem_uninhabited`: `{ty}`")
354        }
355    }
356}
357
358fn is_opsem_inhabited_raw<'tcx>(
359    tcx: TyCtxt<'tcx>,
360    env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
361) -> bool {
362    let (ty, typing_env) = (env.value, env.typing_env);
363    {
    match ty.kind() {
        ty::Adt(..) => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val, "ty::Adt(..)",
                ::core::option::Option::Some(format_args!("the query should only be invoked by `Ty::is_opsem_inhabited`")));
        }
    }
};assert_matches!(
364        ty.kind(),
365        ty::Adt(..),
366        "the query should only be invoked by `Ty::is_opsem_inhabited`"
367    );
368
369    is_opsem_inhabited_recursor(
370        ty,
371        tcx,
372        &mut FxHashSet::<DefId>::default(),
373        /* stop_at_ref */ false,
374        &|ty, seen, rec| {
375            let ty::Adt(adt_def, adt_args) = *ty.kind() else {
376                ::core::panicking::panic("internal error: entered unreachable code");unreachable! {}
377            };
378            if adt_def.is_union() {
379                // Unions are always inhabited.
380                return true;
381            }
382
383            let new_adt = seen.insert(adt_def.did());
384            // If we have seen this ADT before, stop at the next reference to avoid infinite
385            // recursion. We can't stop here since we have to ensure that "layout uninhabited"
386            // implies "opsem uninhabited". References are always layout-inhabited so the
387            // implication is vacuously true.
388            let stop_at_ref = !new_adt;
389
390            // We are inhabited if in some variant all fields are inhabited.
391            let inhabited = adt_def.variants().iter().any(|variant| {
392                variant.fields.iter().all(|field| {
393                    let ty = field.ty(tcx, adt_args);
394                    let ty = tcx.normalize_erasing_regions(typing_env, ty);
395                    rec(ty, seen, stop_at_ref)
396                })
397            });
398
399            // Remove the type again so that we allow it to appear on other branches.
400            if new_adt {
401                seen.remove(&adt_def.did());
402            }
403
404            inhabited
405        },
406    )
407}