]>
Commit | Line | Data |
---|---|---|
32a655c1 SL |
1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use util::nodemap::FxHashSet; | |
12 | use ty::context::TyCtxt; | |
13 | use ty::{AdtDef, VariantDef, FieldDef, TyS}; | |
14 | use ty::{DefId, Substs}; | |
15 | use ty::{AdtKind, Visibility}; | |
16 | use ty::TypeVariants::*; | |
17 | ||
18 | pub use self::def_id_forest::DefIdForest; | |
19 | ||
20 | mod def_id_forest; | |
21 | ||
22 | // The methods in this module calculate DefIdForests of modules in which a | |
23 | // AdtDef/VariantDef/FieldDef is visibly uninhabited. | |
24 | // | |
25 | // # Example | |
26 | // ```rust | |
27 | // enum Void {} | |
28 | // mod a { | |
29 | // pub mod b { | |
30 | // pub struct SecretlyUninhabited { | |
31 | // _priv: !, | |
32 | // } | |
33 | // } | |
34 | // } | |
35 | // | |
36 | // mod c { | |
37 | // pub struct AlsoSecretlyUninhabited { | |
38 | // _priv: Void, | |
39 | // } | |
40 | // mod d { | |
41 | // } | |
42 | // } | |
43 | // | |
44 | // struct Foo { | |
45 | // x: a::b::SecretlyUninhabited, | |
46 | // y: c::AlsoSecretlyUninhabited, | |
47 | // } | |
48 | // ``` | |
49 | // In this code, the type Foo will only be visibly uninhabited inside the | |
50 | // modules b, c and d. Calling uninhabited_from on Foo or its AdtDef will | |
51 | // return the forest of modules {b, c->d} (represented in a DefIdForest by the | |
52 | // set {b, c}) | |
53 | // | |
54 | // We need this information for pattern-matching on Foo or types that contain | |
55 | // Foo. | |
56 | // | |
57 | // # Example | |
58 | // ```rust | |
59 | // let foo_result: Result<T, Foo> = ... ; | |
60 | // let Ok(t) = foo_result; | |
61 | // ``` | |
62 | // This code should only compile in modules where the uninhabitedness of Foo is | |
63 | // visible. | |
64 | ||
65 | impl<'a, 'gcx, 'tcx> AdtDef { | |
66 | /// Calculate the forest of DefIds from which this adt is visibly uninhabited. | |
67 | pub fn uninhabited_from( | |
68 | &self, | |
69 | visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, | |
70 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
71 | substs: &'tcx Substs<'tcx>) -> DefIdForest | |
72 | { | |
73 | if !visited.insert((self.did, substs)) { | |
74 | return DefIdForest::empty(); | |
75 | } | |
76 | ||
77 | let ret = DefIdForest::intersection(tcx, self.variants.iter().map(|v| { | |
78 | v.uninhabited_from(visited, tcx, substs, self.adt_kind()) | |
79 | })); | |
80 | visited.remove(&(self.did, substs)); | |
81 | ret | |
82 | } | |
83 | } | |
84 | ||
85 | impl<'a, 'gcx, 'tcx> VariantDef { | |
86 | /// Calculate the forest of DefIds from which this variant is visibly uninhabited. | |
87 | pub fn uninhabited_from( | |
88 | &self, | |
89 | visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, | |
90 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
91 | substs: &'tcx Substs<'tcx>, | |
92 | adt_kind: AdtKind) -> DefIdForest | |
93 | { | |
94 | match adt_kind { | |
95 | AdtKind::Union => { | |
96 | DefIdForest::intersection(tcx, self.fields.iter().map(|f| { | |
97 | f.uninhabited_from(visited, tcx, substs, false) | |
98 | })) | |
99 | }, | |
100 | AdtKind::Struct => { | |
101 | DefIdForest::union(tcx, self.fields.iter().map(|f| { | |
102 | f.uninhabited_from(visited, tcx, substs, false) | |
103 | })) | |
104 | }, | |
105 | AdtKind::Enum => { | |
106 | DefIdForest::union(tcx, self.fields.iter().map(|f| { | |
107 | f.uninhabited_from(visited, tcx, substs, true) | |
108 | })) | |
109 | }, | |
110 | } | |
111 | } | |
112 | } | |
113 | ||
114 | impl<'a, 'gcx, 'tcx> FieldDef { | |
115 | /// Calculate the forest of DefIds from which this field is visibly uninhabited. | |
116 | pub fn uninhabited_from( | |
117 | &self, | |
118 | visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, | |
119 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
120 | substs: &'tcx Substs<'tcx>, | |
121 | is_enum: bool) -> DefIdForest | |
122 | { | |
123 | let mut data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(visited, tcx); | |
124 | // FIXME(canndrew): Currently enum fields are (incorrectly) stored with | |
125 | // Visibility::Invisible so we need to override self.vis if we're | |
126 | // dealing with an enum. | |
127 | if is_enum { | |
128 | data_uninhabitedness() | |
129 | } else { | |
130 | match self.vis { | |
131 | Visibility::Invisible => DefIdForest::empty(), | |
132 | Visibility::Restricted(from) => { | |
133 | let forest = DefIdForest::from_id(from); | |
134 | let iter = Some(forest).into_iter().chain(Some(data_uninhabitedness())); | |
135 | DefIdForest::intersection(tcx, iter) | |
136 | }, | |
137 | Visibility::Public => data_uninhabitedness(), | |
138 | } | |
139 | } | |
140 | } | |
141 | } | |
142 | ||
143 | impl<'a, 'gcx, 'tcx> TyS<'tcx> { | |
144 | /// Calculate the forest of DefIds from which this type is visibly uninhabited. | |
145 | pub fn uninhabited_from( | |
146 | &self, | |
147 | visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, | |
148 | tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest | |
149 | { | |
150 | match tcx.lift_to_global(&self) { | |
151 | Some(global_ty) => { | |
152 | { | |
153 | let cache = tcx.inhabitedness_cache.borrow(); | |
154 | if let Some(forest) = cache.get(&global_ty) { | |
155 | return forest.clone(); | |
156 | } | |
157 | } | |
158 | let forest = global_ty.uninhabited_from_inner(visited, tcx); | |
159 | let mut cache = tcx.inhabitedness_cache.borrow_mut(); | |
160 | cache.insert(global_ty, forest.clone()); | |
161 | forest | |
162 | }, | |
163 | None => { | |
164 | let forest = self.uninhabited_from_inner(visited, tcx); | |
165 | forest | |
166 | }, | |
167 | } | |
168 | } | |
169 | ||
170 | fn uninhabited_from_inner( | |
171 | &self, | |
172 | visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, | |
173 | tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest | |
174 | { | |
175 | match self.sty { | |
176 | TyAdt(def, substs) => { | |
177 | def.uninhabited_from(visited, tcx, substs) | |
178 | }, | |
179 | ||
180 | TyNever => DefIdForest::full(tcx), | |
181 | TyTuple(ref tys) => { | |
182 | DefIdForest::union(tcx, tys.iter().map(|ty| { | |
183 | ty.uninhabited_from(visited, tcx) | |
184 | })) | |
185 | }, | |
186 | TyArray(ty, len) => { | |
187 | if len == 0 { | |
188 | DefIdForest::empty() | |
189 | } else { | |
190 | ty.uninhabited_from(visited, tcx) | |
191 | } | |
192 | } | |
193 | TyRef(_, ref tm) => { | |
194 | tm.ty.uninhabited_from(visited, tcx) | |
195 | } | |
196 | ||
197 | _ => DefIdForest::empty(), | |
198 | } | |
199 | } | |
200 | } | |
201 |