]>
Commit | Line | Data |
---|---|---|
e1599b0c XL |
1 | pub use self::def_id_forest::DefIdForest; |
2 | ||
dfeec247 | 3 | use crate::ty; |
9fa01778 | 4 | use crate::ty::context::TyCtxt; |
9fa01778 | 5 | use crate::ty::TyKind::*; |
dfeec247 XL |
6 | use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef}; |
7 | use crate::ty::{AdtKind, Visibility}; | |
8 | use crate::ty::{DefId, SubstsRef}; | |
f9f354fc | 9 | use rustc_data_structures::stack::ensure_sufficient_stack; |
32a655c1 | 10 | |
32a655c1 SL |
11 | mod def_id_forest; |
12 | ||
e1599b0c XL |
13 | // The methods in this module calculate `DefIdForest`s of modules in which a |
14 | // `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited. | |
32a655c1 SL |
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 | // ``` | |
e1599b0c XL |
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`}). | |
32a655c1 | 44 | // |
e1599b0c XL |
45 | // We need this information for pattern-matching on `Foo` or types that contain |
46 | // `Foo`. | |
32a655c1 SL |
47 | // |
48 | // # Example | |
49 | // ```rust | |
50 | // let foo_result: Result<T, Foo> = ... ; | |
51 | // let Ok(t) = foo_result; | |
52 | // ``` | |
e1599b0c | 53 | // This code should only compile in modules where the uninhabitedness of `Foo` is |
32a655c1 SL |
54 | // visible. |
55 | ||
dc9dc135 | 56 | impl<'tcx> TyCtxt<'tcx> { |
abe05a73 | 57 | /// Checks whether a type is visibly uninhabited from a particular module. |
e1599b0c | 58 | /// |
abe05a73 XL |
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. | |
ba9703b0 XL |
94 | pub fn is_ty_uninhabited_from( |
95 | self, | |
96 | module: DefId, | |
97 | ty: Ty<'tcx>, | |
98 | param_env: ty::ParamEnv<'tcx>, | |
99 | ) -> bool { | |
abe05a73 | 100 | // To check whether this type is uninhabited at all (not just from the |
e1599b0c | 101 | // given node), you could check whether the forest is empty. |
abe05a73 XL |
102 | // ``` |
103 | // forest.is_empty() | |
104 | // ``` | |
ba9703b0 | 105 | ty.uninhabited_from(self, param_env).contains(self, module) |
abe05a73 XL |
106 | } |
107 | ||
ba9703b0 XL |
108 | pub fn is_ty_uninhabited_from_any_module( |
109 | self, | |
110 | ty: Ty<'tcx>, | |
111 | param_env: ty::ParamEnv<'tcx>, | |
112 | ) -> bool { | |
113 | !ty.uninhabited_from(self, param_env).is_empty() | |
abe05a73 | 114 | } |
abe05a73 XL |
115 | } |
116 | ||
dc9dc135 | 117 | impl<'tcx> AdtDef { |
e1599b0c | 118 | /// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited. |
ba9703b0 XL |
119 | fn uninhabited_from( |
120 | &self, | |
121 | tcx: TyCtxt<'tcx>, | |
122 | substs: SubstsRef<'tcx>, | |
123 | param_env: ty::ParamEnv<'tcx>, | |
124 | ) -> DefIdForest { | |
48663c56 XL |
125 | // Non-exhaustive ADTs from other crates are always considered inhabited. |
126 | if self.is_variant_list_non_exhaustive() && !self.did.is_local() { | |
127 | DefIdForest::empty() | |
128 | } else { | |
dfeec247 XL |
129 | DefIdForest::intersection( |
130 | tcx, | |
ba9703b0 XL |
131 | self.variants |
132 | .iter() | |
133 | .map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)), | |
dfeec247 | 134 | ) |
48663c56 | 135 | } |
32a655c1 SL |
136 | } |
137 | } | |
138 | ||
dc9dc135 | 139 | impl<'tcx> VariantDef { |
e1599b0c | 140 | /// Calculates the forest of `DefId`s from which this variant is visibly uninhabited. |
532ac7d7 | 141 | pub fn uninhabited_from( |
abe05a73 | 142 | &self, |
dc9dc135 | 143 | tcx: TyCtxt<'tcx>, |
532ac7d7 | 144 | substs: SubstsRef<'tcx>, |
dc9dc135 | 145 | adt_kind: AdtKind, |
ba9703b0 | 146 | param_env: ty::ParamEnv<'tcx>, |
dc9dc135 | 147 | ) -> DefIdForest { |
a1dfa0c6 XL |
148 | let is_enum = match adt_kind { |
149 | // For now, `union`s are never considered uninhabited. | |
150 | // The precise semantics of inhabitedness with respect to unions is currently undecided. | |
151 | AdtKind::Union => return DefIdForest::empty(), | |
152 | AdtKind::Enum => true, | |
153 | AdtKind::Struct => false, | |
154 | }; | |
48663c56 XL |
155 | // Non-exhaustive variants from other crates are always considered inhabited. |
156 | if self.is_field_list_non_exhaustive() && !self.def_id.is_local() { | |
157 | DefIdForest::empty() | |
158 | } else { | |
dfeec247 XL |
159 | DefIdForest::union( |
160 | tcx, | |
ba9703b0 | 161 | self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)), |
dfeec247 | 162 | ) |
48663c56 | 163 | } |
32a655c1 SL |
164 | } |
165 | } | |
166 | ||
dc9dc135 | 167 | impl<'tcx> FieldDef { |
e1599b0c | 168 | /// Calculates the forest of `DefId`s from which this field is visibly uninhabited. |
abe05a73 XL |
169 | fn uninhabited_from( |
170 | &self, | |
dc9dc135 | 171 | tcx: TyCtxt<'tcx>, |
532ac7d7 | 172 | substs: SubstsRef<'tcx>, |
a1dfa0c6 | 173 | is_enum: bool, |
ba9703b0 | 174 | param_env: ty::ParamEnv<'tcx>, |
a1dfa0c6 | 175 | ) -> DefIdForest { |
ba9703b0 | 176 | let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env); |
32a655c1 | 177 | // FIXME(canndrew): Currently enum fields are (incorrectly) stored with |
e1599b0c | 178 | // `Visibility::Invisible` so we need to override `self.vis` if we're |
32a655c1 SL |
179 | // dealing with an enum. |
180 | if is_enum { | |
181 | data_uninhabitedness() | |
182 | } else { | |
183 | match self.vis { | |
184 | Visibility::Invisible => DefIdForest::empty(), | |
185 | Visibility::Restricted(from) => { | |
186 | let forest = DefIdForest::from_id(from); | |
187 | let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness())); | |
188 | DefIdForest::intersection(tcx, iter) | |
dfeec247 | 189 | } |
32a655c1 SL |
190 | Visibility::Public => data_uninhabitedness(), |
191 | } | |
192 | } | |
193 | } | |
194 | } | |
195 | ||
dc9dc135 | 196 | impl<'tcx> TyS<'tcx> { |
e1599b0c | 197 | /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. |
ba9703b0 | 198 | fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest { |
e74abb32 | 199 | match self.kind { |
f9f354fc XL |
200 | Adt(def, substs) => { |
201 | ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env)) | |
202 | } | |
32a655c1 | 203 | |
b7449926 | 204 | Never => DefIdForest::full(tcx), |
a1dfa0c6 | 205 | |
ba9703b0 XL |
206 | Tuple(ref tys) => DefIdForest::union( |
207 | tcx, | |
208 | tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)), | |
209 | ), | |
a1dfa0c6 | 210 | |
ba9703b0 | 211 | Array(ty, len) => match len.try_eval_usize(tcx, param_env) { |
532ac7d7 XL |
212 | // If the array is definitely non-empty, it's uninhabited if |
213 | // the type of its elements is uninhabited. | |
ba9703b0 | 214 | Some(n) if n != 0 => ty.uninhabited_from(tcx, param_env), |
dfeec247 | 215 | _ => DefIdForest::empty(), |
532ac7d7 | 216 | }, |
a1dfa0c6 XL |
217 | |
218 | // References to uninitialised memory is valid for any type, including | |
219 | // uninhabited types, in unsafe code, so we treat all references as | |
220 | // inhabited. | |
221 | // The precise semantics of inhabitedness with respect to references is currently | |
222 | // undecided. | |
223 | Ref(..) => DefIdForest::empty(), | |
32a655c1 SL |
224 | |
225 | _ => DefIdForest::empty(), | |
226 | } | |
227 | } | |
228 | } |