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::context::TyCtxt;
51use crate::ty::{self, DefId, Ty, 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 if matches!(tcx.representability(def_id), ty::Representability::Infinite(_)) {
66 return InhabitedPredicate::True;
67 }
68 }
69 let adt = tcx.adt_def(def_id);
70 InhabitedPredicate::any(
71 tcx,
72 adt.variants().iter().map(|variant| variant.inhabited_predicate(tcx, adt)),
73 )
74}
75
76impl<'tcx> VariantDef {
77 /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited.
78 pub fn inhabited_predicate(
79 &self,
80 tcx: TyCtxt<'tcx>,
81 adt: ty::AdtDef<'_>,
82 ) -> InhabitedPredicate<'tcx> {
83 debug_assert!(!adt.is_union());
84 InhabitedPredicate::all(
85 tcx,
86 self.fields.iter().map(|field| {
87 let pred = tcx.type_of(field.did).instantiate_identity().inhabited_predicate(tcx);
88 if adt.is_enum() {
89 return pred;
90 }
91 match field.vis {
92 Visibility::Public => pred,
93 Visibility::Restricted(from) => {
94 pred.or(tcx, InhabitedPredicate::NotInModule(from))
95 }
96 }
97 }),
98 )
99 }
100}
101
102impl<'tcx> Ty<'tcx> {
103 #[instrument(level = "debug", skip(tcx), ret)]
104 pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> {
105 debug_assert!(!self.has_infer());
106 match self.kind() {
107 // For now, unions are always considered inhabited
108 Adt(adt, _) if adt.is_union() => InhabitedPredicate::True,
109 // Non-exhaustive ADTs from other crates are always considered inhabited
110 Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => {
111 InhabitedPredicate::True
112 }
113 Never => InhabitedPredicate::False,
114 Param(_) | Alias(ty::Projection | ty::Weak, _) => InhabitedPredicate::GenericType(self),
115 Alias(ty::Opaque, alias_ty) => {
116 match alias_ty.def_id.as_local() {
117 // Foreign opaque is considered inhabited.
118 None => InhabitedPredicate::True,
119 // Local opaque type may possibly be revealed.
120 Some(local_def_id) => {
121 let key = ty::OpaqueTypeKey { def_id: local_def_id, args: alias_ty.args };
122 InhabitedPredicate::OpaqueType(key)
123 }
124 }
125 }
126 // FIXME(inherent_associated_types): Most likely we can just map to `GenericType` like above.
127 // However it's unclear if the args passed to `InhabitedPredicate::instantiate` are of the correct
128 // format, i.e. don't contain parent args. If you hit this case, please verify this beforehand.
129 Alias(ty::Inherent, _) => {
130 bug!("unimplemented: inhabitedness checking for inherent projections")
131 }
132 Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
133 // use a query for more complex cases
134 Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
135 // references and other types are inhabited
136 _ => InhabitedPredicate::True,
137 }
138 }
139
140 /// Checks whether a type is visibly uninhabited from a particular module.
141 ///
142 /// # Example
143 /// ```
144 /// #![feature(never_type)]
145 /// # fn main() {}
146 /// enum Void {}
147 /// mod a {
148 /// pub mod b {
149 /// pub struct SecretlyUninhabited {
150 /// _priv: !,
151 /// }
152 /// }
153 /// }
154 ///
155 /// mod c {
156 /// use super::Void;
157 /// pub struct AlsoSecretlyUninhabited {
158 /// _priv: Void,
159 /// }
160 /// mod d {
161 /// }
162 /// }
163 ///
164 /// struct Foo {
165 /// x: a::b::SecretlyUninhabited,
166 /// y: c::AlsoSecretlyUninhabited,
167 /// }
168 /// ```
169 /// In this code, the type `Foo` will only be visibly uninhabited inside the
170 /// modules b, c and d. This effects pattern-matching on `Foo` or types that
171 /// contain `Foo`.
172 ///
173 /// # Example
174 /// ```ignore (illustrative)
175 /// let foo_result: Result<T, Foo> = ... ;
176 /// let Ok(t) = foo_result;
177 /// ```
178 /// This code should only compile in modules where the uninhabitedness of Foo is
179 /// visible.
180 pub fn is_inhabited_from(
181 self,
182 tcx: TyCtxt<'tcx>,
183 module: DefId,
184 typing_env: ty::TypingEnv<'tcx>,
185 ) -> bool {
186 self.inhabited_predicate(tcx).apply(tcx, typing_env, module)
187 }
188
189 /// Returns true if the type is uninhabited without regard to visibility
190 pub fn is_privately_uninhabited(
191 self,
192 tcx: TyCtxt<'tcx>,
193 typing_env: ty::TypingEnv<'tcx>,
194 ) -> bool {
195 !self.inhabited_predicate(tcx).apply_ignore_module(tcx, typing_env)
196 }
197}
198
199/// N.B. this query should only be called through `Ty::inhabited_predicate`
200fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedPredicate<'tcx> {
201 match *ty.kind() {
202 Adt(adt, args) => tcx.inhabited_predicate_adt(adt.did()).instantiate(tcx, args),
203
204 Tuple(tys) => {
205 InhabitedPredicate::all(tcx, tys.iter().map(|ty| ty.inhabited_predicate(tcx)))
206 }
207
208 // If we can evaluate the array length before having a `ParamEnv`, then
209 // we can simplify the predicate. This is an optimization.
210 Array(ty, len) => match len.try_to_target_usize(tcx) {
211 Some(0) => InhabitedPredicate::True,
212 Some(1..) => ty.inhabited_predicate(tcx),
213 None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
214 },
215
216 _ => bug!("unexpected TyKind, use `Ty::inhabited_predicate`"),
217 }
218}