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