]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/inhabitedness/mod.rs
Rollup merge of #82571 - aDotInTheVoid:reexport-tests, r=CraftSpider
[rust.git] / compiler / rustc_middle / src / ty / inhabitedness / mod.rs
1 pub use self::def_id_forest::DefIdForest;
2
3 use crate::ty;
4 use crate::ty::context::TyCtxt;
5 use crate::ty::TyKind::*;
6 use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef};
7 use crate::ty::{AdtKind, Visibility};
8 use crate::ty::{DefId, SubstsRef};
9
10 mod def_id_forest;
11
12 // The methods in this module calculate `DefIdForest`s of modules in which a
13 // `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited.
14 //
15 // # Example
16 // ```rust
17 // enum Void {}
18 // mod a {
19 //     pub mod b {
20 //         pub struct SecretlyUninhabited {
21 //             _priv: !,
22 //         }
23 //     }
24 // }
25 //
26 // mod c {
27 //     pub struct AlsoSecretlyUninhabited {
28 //         _priv: Void,
29 //     }
30 //     mod d {
31 //     }
32 // }
33 //
34 // struct Foo {
35 //     x: a::b::SecretlyUninhabited,
36 //     y: c::AlsoSecretlyUninhabited,
37 // }
38 // ```
39 // In this code, the type `Foo` will only be visibly uninhabited inside the
40 // modules `b`, `c` and `d`. Calling `uninhabited_from` on `Foo` or its `AdtDef` will
41 // return the forest of modules {`b`, `c`->`d`} (represented in a `DefIdForest` by the
42 // set {`b`, `c`}).
43 //
44 // We need this information for pattern-matching on `Foo` or types that contain
45 // `Foo`.
46 //
47 // # Example
48 // ```rust
49 // let foo_result: Result<T, Foo> = ... ;
50 // let Ok(t) = foo_result;
51 // ```
52 // This code should only compile in modules where the uninhabitedness of `Foo` is
53 // visible.
54
55 impl<'tcx> TyCtxt<'tcx> {
56     /// Checks whether a type is visibly uninhabited from a particular module.
57     ///
58     /// # Example
59     /// ```rust
60     /// enum Void {}
61     /// mod a {
62     ///     pub mod b {
63     ///         pub struct SecretlyUninhabited {
64     ///             _priv: !,
65     ///         }
66     ///     }
67     /// }
68     ///
69     /// mod c {
70     ///     pub struct AlsoSecretlyUninhabited {
71     ///         _priv: Void,
72     ///     }
73     ///     mod d {
74     ///     }
75     /// }
76     ///
77     /// struct Foo {
78     ///     x: a::b::SecretlyUninhabited,
79     ///     y: c::AlsoSecretlyUninhabited,
80     /// }
81     /// ```
82     /// In this code, the type `Foo` will only be visibly uninhabited inside the
83     /// modules b, c and d. This effects pattern-matching on `Foo` or types that
84     /// contain `Foo`.
85     ///
86     /// # Example
87     /// ```rust
88     /// let foo_result: Result<T, Foo> = ... ;
89     /// let Ok(t) = foo_result;
90     /// ```
91     /// This code should only compile in modules where the uninhabitedness of Foo is
92     /// visible.
93     pub fn is_ty_uninhabited_from(
94         self,
95         module: DefId,
96         ty: Ty<'tcx>,
97         param_env: ty::ParamEnv<'tcx>,
98     ) -> bool {
99         // To check whether this type is uninhabited at all (not just from the
100         // given node), you could check whether the forest is empty.
101         // ```
102         // forest.is_empty()
103         // ```
104         ty.uninhabited_from(self, param_env).contains(self, module)
105     }
106 }
107
108 impl<'tcx> AdtDef {
109     /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited.
110     fn uninhabited_from(
111         &self,
112         tcx: TyCtxt<'tcx>,
113         substs: SubstsRef<'tcx>,
114         param_env: ty::ParamEnv<'tcx>,
115     ) -> DefIdForest {
116         // Non-exhaustive ADTs from other crates are always considered inhabited.
117         if self.is_variant_list_non_exhaustive() && !self.did.is_local() {
118             DefIdForest::empty()
119         } else {
120             DefIdForest::intersection(
121                 tcx,
122                 self.variants
123                     .iter()
124                     .map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)),
125             )
126         }
127     }
128 }
129
130 impl<'tcx> VariantDef {
131     /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited.
132     pub fn uninhabited_from(
133         &self,
134         tcx: TyCtxt<'tcx>,
135         substs: SubstsRef<'tcx>,
136         adt_kind: AdtKind,
137         param_env: ty::ParamEnv<'tcx>,
138     ) -> DefIdForest {
139         let is_enum = match adt_kind {
140             // For now, `union`s are never considered uninhabited.
141             // The precise semantics of inhabitedness with respect to unions is currently undecided.
142             AdtKind::Union => return DefIdForest::empty(),
143             AdtKind::Enum => true,
144             AdtKind::Struct => false,
145         };
146         // Non-exhaustive variants from other crates are always considered inhabited.
147         if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
148             DefIdForest::empty()
149         } else {
150             DefIdForest::union(
151                 tcx,
152                 self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)),
153             )
154         }
155     }
156 }
157
158 impl<'tcx> FieldDef {
159     /// Calculates the forest of `DefId`s from which this field is visibly uninhabited.
160     fn uninhabited_from(
161         &self,
162         tcx: TyCtxt<'tcx>,
163         substs: SubstsRef<'tcx>,
164         is_enum: bool,
165         param_env: ty::ParamEnv<'tcx>,
166     ) -> DefIdForest {
167         let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env);
168         // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
169         // `Visibility::Invisible` so we need to override `self.vis` if we're
170         // dealing with an enum.
171         if is_enum {
172             data_uninhabitedness()
173         } else {
174             match self.vis {
175                 Visibility::Invisible => DefIdForest::empty(),
176                 Visibility::Restricted(from) => {
177                     let forest = DefIdForest::from_id(from);
178                     let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness()));
179                     DefIdForest::intersection(tcx, iter)
180                 }
181                 Visibility::Public => data_uninhabitedness(),
182             }
183         }
184     }
185 }
186
187 impl<'tcx> TyS<'tcx> {
188     /// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
189     fn uninhabited_from(
190         &'tcx self,
191         tcx: TyCtxt<'tcx>,
192         param_env: ty::ParamEnv<'tcx>,
193     ) -> DefIdForest {
194         tcx.type_uninhabited_from(param_env.and(self))
195     }
196 }
197
198 // Query provider for `type_uninhabited_from`.
199 pub(crate) fn type_uninhabited_from<'tcx>(
200     tcx: TyCtxt<'tcx>,
201     key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
202 ) -> DefIdForest {
203     let ty = key.value;
204     let param_env = key.param_env;
205     match *ty.kind() {
206         Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
207
208         Never => DefIdForest::full(tcx),
209
210         Tuple(ref tys) => DefIdForest::union(
211             tcx,
212             tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
213         ),
214
215         Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
216             Some(0) | None => DefIdForest::empty(),
217             // If the array is definitely non-empty, it's uninhabited if
218             // the type of its elements is uninhabited.
219             Some(1..) => ty.uninhabited_from(tcx, param_env),
220         },
221
222         // References to uninitialised memory are valid for any type, including
223         // uninhabited types, in unsafe code, so we treat all references as
224         // inhabited.
225         // The precise semantics of inhabitedness with respect to references is currently
226         // undecided.
227         Ref(..) => DefIdForest::empty(),
228
229         _ => DefIdForest::empty(),
230     }
231 }