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_span::def_id::LocalModId;
47use rustc_type_ir::TyKind::*;
48use tracing::instrument;
49
50use crate::query::Providers;
51use crate::ty::{self, DefId, Ty, TyCtxt, TypeVisitableExt, VariantDef, Visibility};
52
53pub mod inhabited_predicate;
54
55pub use inhabited_predicate::InhabitedPredicate;
56
57pub(crate) fn provide(providers: &mut Providers) {
58 *providers = Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers };
59}
60
61/// Returns an `InhabitedPredicate` that is generic over type parameters and
62/// requires calling [`InhabitedPredicate::instantiate`]
63fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
64 if let Some(def_id) = def_id.as_local() {
65 tcx.ensure_ok().check_representability(def_id);
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 debug_assert!(!adt.is_union());
83 InhabitedPredicate::all(
84 tcx,
85 self.fields.iter().map(|field| {
86 let pred = tcx
87 .type_of(field.did)
88 .instantiate_identity()
89 .skip_norm_wip()
90 .inhabited_predicate(tcx);
91 if adt.is_enum() {
92 return pred;
93 }
94 match field.vis {
95 Visibility::Public => pred,
96 Visibility::Restricted(from) => {
97 InhabitedPredicate::NotInModule(from).or(tcx, pred)
98 }
99 }
100 }),
101 )
102 }
103}
104
105impl<'tcx> Ty<'tcx> {
106 #[instrument(level = "debug", skip(tcx), ret)]
107 pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> {
108 debug_assert!(!self.has_infer());
109 match self.kind() {
110 // For now, unions are always considered inhabited
111 Adt(adt, _) if adt.is_union() => InhabitedPredicate::True,
112 // Non-exhaustive ADTs from other crates are always considered inhabited
113 Adt(adt, _) if adt.variant_list_has_applicable_non_exhaustive() => {
114 InhabitedPredicate::True
115 }
116 Never => InhabitedPredicate::False,
117 // FIXME(#155345): This should only encounter rigid aliases with the new solver.
118 Param(_)
119 | Alias(
120 _,
121 ty::AliasTy {
122 kind: ty::Inherent { .. } | ty::Projection { .. } | ty::Free { .. },
123 ..
124 },
125 ) => InhabitedPredicate::GenericType(self),
126 &Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
127 match def_id.as_local() {
128 // Foreign opaque is considered inhabited.
129 None => InhabitedPredicate::True,
130 // Local opaque type may possibly be revealed.
131 Some(local_def_id) => {
132 let key = ty::OpaqueTypeKey { def_id: local_def_id, args };
133 InhabitedPredicate::OpaqueType(key)
134 }
135 }
136 }
137 Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
138 // use a query for more complex cases
139 Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
140 // references and other types are inhabited
141 _ => InhabitedPredicate::True,
142 }
143 }
144
145 /// Checks whether a type is visibly uninhabited from a particular module.
146 ///
147 /// # Example
148 /// ```
149 /// #![feature(never_type)]
150 /// # fn main() {}
151 /// enum Void {}
152 /// mod a {
153 /// pub mod b {
154 /// pub struct SecretlyUninhabited {
155 /// _priv: !,
156 /// }
157 /// }
158 /// }
159 ///
160 /// mod c {
161 /// use super::Void;
162 /// pub struct AlsoSecretlyUninhabited {
163 /// _priv: Void,
164 /// }
165 /// mod d {
166 /// }
167 /// }
168 ///
169 /// struct Foo {
170 /// x: a::b::SecretlyUninhabited,
171 /// y: c::AlsoSecretlyUninhabited,
172 /// }
173 /// ```
174 /// In this code, the type `Foo` will only be visibly uninhabited inside the
175 /// modules b, c and d. This effects pattern-matching on `Foo` or types that
176 /// contain `Foo`.
177 ///
178 /// # Example
179 /// ```ignore (illustrative)
180 /// let foo_result: Result<T, Foo> = ... ;
181 /// let Ok(t) = foo_result;
182 /// ```
183 /// This code should only compile in modules where the uninhabitedness of Foo is
184 /// visible.
185 pub fn is_inhabited_from(
186 self,
187 tcx: TyCtxt<'tcx>,
188 module: LocalModId,
189 typing_env: ty::TypingEnv<'tcx>,
190 ) -> bool {
191 self.inhabited_predicate(tcx).apply(tcx, typing_env, module)
192 }
193
194 /// Returns true if the type is uninhabited without regard to visibility
195 pub fn is_privately_uninhabited(
196 self,
197 tcx: TyCtxt<'tcx>,
198 typing_env: ty::TypingEnv<'tcx>,
199 ) -> bool {
200 !self.inhabited_predicate(tcx).apply_ignore_module(tcx, typing_env)
201 }
202}
203
204/// N.B. this query should only be called through `Ty::inhabited_predicate`
205fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedPredicate<'tcx> {
206 match *ty.kind() {
207 Adt(adt, args) => tcx.inhabited_predicate_adt(adt.did()).instantiate(tcx, args),
208
209 Tuple(tys) => {
210 InhabitedPredicate::all(tcx, tys.iter().map(|ty| ty.inhabited_predicate(tcx)))
211 }
212
213 // If we can evaluate the array length before having a `ParamEnv`, then
214 // we can simplify the predicate. This is an optimization.
215 Array(ty, len) => match len.try_to_target_usize(tcx) {
216 Some(0) => InhabitedPredicate::True,
217 Some(1..) => ty.inhabited_predicate(tcx),
218 None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
219 },
220
221 _ => bug!("unexpected TyKind, use `Ty::inhabited_predicate`"),
222 }
223}