|
| 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 std::mem; |
| 12 | +use rustc_data_structures::small_vec::SmallVec; |
| 13 | +use syntax::ast::{CRATE_NODE_ID, NodeId}; |
| 14 | +use util::nodemap::FxHashSet; |
| 15 | +use ty::context::TyCtxt; |
| 16 | +use ty::{AdtDef, VariantDef, FieldDef, TyS}; |
| 17 | +use ty::{DefId, Substs}; |
| 18 | +use ty::{AdtKind, Visibility, NodeIdTree}; |
| 19 | +use ty::TypeVariants::*; |
| 20 | + |
| 21 | +/// Represents a set of nodes closed under the ancestor relation. That is, if a |
| 22 | +/// node is in this set then so are all its descendants. |
| 23 | +#[derive(Clone)] |
| 24 | +pub struct NodeForrest { |
| 25 | + /// The minimal set of nodes required to represent the whole set. |
| 26 | + /// If A and B are nodes in the NodeForrest, and A is a desecendant |
| 27 | + /// of B, then only B will be in root_nodes. |
| 28 | + /// We use a SmallVec here because (for its use in this module) its rare |
| 29 | + /// that this will contain more than one or two nodes. |
| 30 | + root_nodes: SmallVec<[NodeId; 1]>, |
| 31 | +} |
| 32 | + |
| 33 | +impl<'a, 'gcx, 'tcx> NodeForrest { |
| 34 | + /// Create an empty set. |
| 35 | + pub fn empty() -> NodeForrest { |
| 36 | + NodeForrest { |
| 37 | + root_nodes: SmallVec::new(), |
| 38 | + } |
| 39 | + } |
| 40 | + |
| 41 | + /// Create a set containing every node. |
| 42 | + #[inline] |
| 43 | + pub fn full() -> NodeForrest { |
| 44 | + NodeForrest::from_node(CRATE_NODE_ID) |
| 45 | + } |
| 46 | + |
| 47 | + /// Create a set containing a node and all its descendants. |
| 48 | + pub fn from_node(node: NodeId) -> NodeForrest { |
| 49 | + let mut root_nodes = SmallVec::new(); |
| 50 | + root_nodes.push(node); |
| 51 | + NodeForrest { |
| 52 | + root_nodes: root_nodes, |
| 53 | + } |
| 54 | + } |
| 55 | + |
| 56 | + /// Test whether the set is empty. |
| 57 | + pub fn is_empty(&self) -> bool { |
| 58 | + self.root_nodes.is_empty() |
| 59 | + } |
| 60 | + |
| 61 | + /// Test whether the set conains a node. |
| 62 | + pub fn contains(&self, |
| 63 | + tcx: TyCtxt<'a, 'gcx, 'tcx>, |
| 64 | + node: NodeId) -> bool |
| 65 | + { |
| 66 | + for root_node in self.root_nodes.iter() { |
| 67 | + if tcx.map.is_descendant_of(node, *root_node) { |
| 68 | + return true; |
| 69 | + } |
| 70 | + } |
| 71 | + false |
| 72 | + } |
| 73 | + |
| 74 | + /// Calculate the intersection of a collection of sets. |
| 75 | + pub fn intersection<I>(tcx: TyCtxt<'a, 'gcx, 'tcx>, |
| 76 | + iter: I) -> NodeForrest |
| 77 | + where I: IntoIterator<Item=NodeForrest> |
| 78 | + { |
| 79 | + let mut ret = NodeForrest::full(); |
| 80 | + let mut next_ret = SmallVec::new(); |
| 81 | + let mut old_ret: SmallVec<[NodeId; 1]> = SmallVec::new(); |
| 82 | + for next_set in iter { |
| 83 | + for node in ret.root_nodes.drain(..) { |
| 84 | + if next_set.contains(tcx, node) { |
| 85 | + next_ret.push(node); |
| 86 | + } else { |
| 87 | + old_ret.push(node); |
| 88 | + } |
| 89 | + } |
| 90 | + ret.root_nodes.extend(old_ret.drain(..)); |
| 91 | + |
| 92 | + for node in next_set.root_nodes { |
| 93 | + if ret.contains(tcx, node) { |
| 94 | + next_ret.push(node); |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + mem::swap(&mut next_ret, &mut ret.root_nodes); |
| 99 | + next_ret.drain(..); |
| 100 | + } |
| 101 | + ret |
| 102 | + } |
| 103 | + |
| 104 | + /// Calculate the union of a collection of sets. |
| 105 | + pub fn union<I>(tcx: TyCtxt<'a, 'gcx, 'tcx>, |
| 106 | + iter: I) -> NodeForrest |
| 107 | + where I: IntoIterator<Item=NodeForrest> |
| 108 | + { |
| 109 | + let mut ret = NodeForrest::empty(); |
| 110 | + let mut next_ret = SmallVec::new(); |
| 111 | + for next_set in iter { |
| 112 | + for node in ret.root_nodes.drain(..) { |
| 113 | + if !next_set.contains(tcx, node) { |
| 114 | + next_ret.push(node); |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + for node in next_set.root_nodes { |
| 119 | + if !next_ret.contains(&node) { |
| 120 | + next_ret.push(node); |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + mem::swap(&mut next_ret, &mut ret.root_nodes); |
| 125 | + next_ret.drain(..); |
| 126 | + } |
| 127 | + ret |
| 128 | + } |
| 129 | +} |
| 130 | + |
| 131 | +impl<'a, 'gcx, 'tcx> AdtDef { |
| 132 | + /// Calculate the set of nodes from which this adt is visibly uninhabited. |
| 133 | + pub fn uninhabited_from( |
| 134 | + &self, |
| 135 | + visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, |
| 136 | + tcx: TyCtxt<'a, 'gcx, 'tcx>, |
| 137 | + substs: &'tcx Substs<'tcx>) -> NodeForrest |
| 138 | + { |
| 139 | + if !visited.insert((self.did, substs)) { |
| 140 | + return NodeForrest::empty(); |
| 141 | + } |
| 142 | + |
| 143 | + let ret = NodeForrest::intersection(tcx, self.variants.iter().map(|v| { |
| 144 | + v.uninhabited_from(visited, tcx, substs, self.adt_kind()) |
| 145 | + })); |
| 146 | + visited.remove(&(self.did, substs)); |
| 147 | + ret |
| 148 | + } |
| 149 | +} |
| 150 | + |
| 151 | +impl<'a, 'gcx, 'tcx> VariantDef { |
| 152 | + /// Calculate the set of nodes from which this variant is visibly uninhabited. |
| 153 | + pub fn uninhabited_from( |
| 154 | + &self, |
| 155 | + visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, |
| 156 | + tcx: TyCtxt<'a, 'gcx, 'tcx>, |
| 157 | + substs: &'tcx Substs<'tcx>, |
| 158 | + adt_kind: AdtKind) -> NodeForrest |
| 159 | + { |
| 160 | + match adt_kind { |
| 161 | + AdtKind::Union => { |
| 162 | + NodeForrest::intersection(tcx, self.fields.iter().map(|f| { |
| 163 | + f.uninhabited_from(visited, tcx, substs, false) |
| 164 | + })) |
| 165 | + }, |
| 166 | + AdtKind::Struct => { |
| 167 | + NodeForrest::union(tcx, self.fields.iter().map(|f| { |
| 168 | + f.uninhabited_from(visited, tcx, substs, false) |
| 169 | + })) |
| 170 | + }, |
| 171 | + AdtKind::Enum => { |
| 172 | + NodeForrest::union(tcx, self.fields.iter().map(|f| { |
| 173 | + f.uninhabited_from(visited, tcx, substs, true) |
| 174 | + })) |
| 175 | + }, |
| 176 | + } |
| 177 | + } |
| 178 | +} |
| 179 | + |
| 180 | +impl<'a, 'gcx, 'tcx> FieldDef { |
| 181 | + /// Calculate the set of nodes from which this field is visibly uninhabited. |
| 182 | + pub fn uninhabited_from( |
| 183 | + &self, |
| 184 | + visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, |
| 185 | + tcx: TyCtxt<'a, 'gcx, 'tcx>, |
| 186 | + substs: &'tcx Substs<'tcx>, |
| 187 | + is_enum: bool) -> NodeForrest |
| 188 | + { |
| 189 | + if let Visibility::PrivateExternal = self.vis { |
| 190 | + return NodeForrest::empty(); |
| 191 | + } |
| 192 | + |
| 193 | + let data_inhabitedness = self.ty(tcx, substs).uninhabited_from(visited, tcx); |
| 194 | + match self.vis { |
| 195 | + Visibility::Restricted(from) if !is_enum => { |
| 196 | + let node_set = NodeForrest::from_node(from); |
| 197 | + let iter = Some(node_set).into_iter().chain(Some(data_inhabitedness)); |
| 198 | + NodeForrest::intersection(tcx, iter) |
| 199 | + }, |
| 200 | + _ => data_inhabitedness, |
| 201 | + } |
| 202 | + } |
| 203 | +} |
| 204 | + |
| 205 | +impl<'a, 'gcx, 'tcx> TyS<'tcx> { |
| 206 | + /// Calculate the set of nodes from which this type is visibly uninhabited. |
| 207 | + pub fn uninhabited_from( |
| 208 | + &self, |
| 209 | + visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, |
| 210 | + tcx: TyCtxt<'a, 'gcx, 'tcx>) -> NodeForrest |
| 211 | + { |
| 212 | + match tcx.lift_to_global(&self) { |
| 213 | + Some(global_ty) => { |
| 214 | + { |
| 215 | + let cache = tcx.inhabitedness_cache.borrow(); |
| 216 | + if let Some(closed_node_set) = cache.get(&global_ty) { |
| 217 | + return closed_node_set.clone(); |
| 218 | + } |
| 219 | + } |
| 220 | + let node_set = global_ty.uninhabited_from_inner(visited, tcx); |
| 221 | + let mut cache = tcx.inhabitedness_cache.borrow_mut(); |
| 222 | + cache.insert(global_ty, node_set.clone()); |
| 223 | + node_set |
| 224 | + }, |
| 225 | + None => { |
| 226 | + let node_set = self.uninhabited_from_inner(visited, tcx); |
| 227 | + node_set |
| 228 | + }, |
| 229 | + } |
| 230 | + } |
| 231 | + |
| 232 | + fn uninhabited_from_inner( |
| 233 | + &self, |
| 234 | + visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>, |
| 235 | + tcx: TyCtxt<'a, 'gcx, 'tcx>) -> NodeForrest |
| 236 | + { |
| 237 | + match self.sty { |
| 238 | + TyAdt(def, substs) => { |
| 239 | + def.uninhabited_from(visited, tcx, substs) |
| 240 | + }, |
| 241 | + |
| 242 | + TyNever => NodeForrest::full(), |
| 243 | + TyTuple(ref tys) => { |
| 244 | + NodeForrest::union(tcx, tys.iter().map(|ty| { |
| 245 | + ty.uninhabited_from(visited, tcx) |
| 246 | + })) |
| 247 | + }, |
| 248 | + TyArray(ty, len) => { |
| 249 | + if len == 0 { |
| 250 | + NodeForrest::empty() |
| 251 | + } else { |
| 252 | + ty.uninhabited_from(visited, tcx) |
| 253 | + } |
| 254 | + } |
| 255 | + TyRef(_, ref tm) => tm.ty.uninhabited_from(visited, tcx), |
| 256 | + |
| 257 | + _ => NodeForrest::empty(), |
| 258 | + } |
| 259 | + } |
| 260 | +} |
| 261 | + |
0 commit comments