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