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.
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.
11 use middle::def_id::{DefId};
12 use middle::ty::{self, Ty};
13 use util::common::{memoized};
14 use util::nodemap::FnvHashMap;
21 /// Type contents is how the type checker reasons about kinds.
22 /// They track what kinds of things are found within a type. You can
23 /// think of them as kind of an "anti-kind". They track the kinds of values
24 /// and thinks that are contained in types. Having a larger contents for
25 /// a type tends to rule that type *out* from various kinds. For example,
26 /// a type that contains a reference is not sendable.
28 /// The reason we compute type contents and not kinds is that it is
29 /// easier for me (nmatsakis) to think about what is contained within
30 /// a type than to think about what is *not* contained within a type.
31 #[derive(Clone, Copy)]
32 pub struct TypeContents {
36 macro_rules! def_type_content_sets {
37 (mod $mname:ident { $($name:ident = $bits:expr),+ }) => {
38 #[allow(non_snake_case)]
40 use super::TypeContents;
42 #[allow(non_upper_case_globals)]
43 pub const $name: TypeContents = TypeContents { bits: $bits };
49 def_type_content_sets! {
51 None = 0b0000_0000__0000_0000__0000,
53 // Things that are interior to the value (first nibble):
54 InteriorUnsafe = 0b0000_0000__0000_0000__0010,
55 InteriorParam = 0b0000_0000__0000_0000__0100,
56 // InteriorAll = 0b00000000__00000000__1111,
58 // Things that are owned by the value (second and third nibbles):
59 OwnsOwned = 0b0000_0000__0000_0001__0000,
60 OwnsDtor = 0b0000_0000__0000_0010__0000,
61 OwnsAll = 0b0000_0000__1111_1111__0000,
63 // Things that mean drop glue is necessary
64 NeedsDrop = 0b0000_0000__0000_0111__0000,
67 All = 0b1111_1111__1111_1111__1111
72 pub fn when(&self, cond: bool) -> TypeContents {
73 if cond {*self} else {TC::None}
76 pub fn intersects(&self, tc: TypeContents) -> bool {
77 (self.bits & tc.bits) != 0
80 pub fn owns_owned(&self) -> bool {
81 self.intersects(TC::OwnsOwned)
84 pub fn interior_param(&self) -> bool {
85 self.intersects(TC::InteriorParam)
88 pub fn interior_unsafe(&self) -> bool {
89 self.intersects(TC::InteriorUnsafe)
92 pub fn needs_drop(&self, _: &ty::ctxt) -> bool {
93 self.intersects(TC::NeedsDrop)
96 /// Includes only those bits that still apply when indirected through a `Box` pointer
97 pub fn owned_pointer(&self) -> TypeContents {
98 TC::OwnsOwned | (*self & TC::OwnsAll)
101 pub fn union<T, F>(v: &[T], mut f: F) -> TypeContents where
102 F: FnMut(&T) -> TypeContents,
104 v.iter().fold(TC::None, |tc, ty| tc | f(ty))
107 pub fn has_dtor(&self) -> bool {
108 self.intersects(TC::OwnsDtor)
112 impl ops::BitOr for TypeContents {
113 type Output = TypeContents;
115 fn bitor(self, other: TypeContents) -> TypeContents {
116 TypeContents {bits: self.bits | other.bits}
120 impl ops::BitAnd for TypeContents {
121 type Output = TypeContents;
123 fn bitand(self, other: TypeContents) -> TypeContents {
124 TypeContents {bits: self.bits & other.bits}
128 impl ops::Sub for TypeContents {
129 type Output = TypeContents;
131 fn sub(self, other: TypeContents) -> TypeContents {
132 TypeContents {bits: self.bits & !other.bits}
136 impl fmt::Debug for TypeContents {
137 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 write!(f, "TypeContents({:b})", self.bits)
142 impl<'tcx> ty::TyS<'tcx> {
143 pub fn type_contents(&'tcx self, cx: &ty::ctxt<'tcx>) -> TypeContents {
144 return memoized(&cx.tc_cache, self, |ty| {
145 tc_ty(cx, ty, &mut FnvHashMap())
148 fn tc_ty<'tcx>(cx: &ty::ctxt<'tcx>,
150 cache: &mut FnvHashMap<Ty<'tcx>, TypeContents>) -> TypeContents
152 // Subtle: Note that we are *not* using cx.tc_cache here but rather a
153 // private cache for this walk. This is needed in the case of cyclic
156 // struct List { next: Box<Option<List>>, ... }
158 // When computing the type contents of such a type, we wind up deeply
159 // recursing as we go. So when we encounter the recursive reference
160 // to List, we temporarily use TC::None as its contents. Later we'll
161 // patch up the cache with the correct value, once we've computed it
162 // (this is basically a co-inductive process, if that helps). So in
163 // the end we'll compute TC::OwnsOwned, in this case.
165 // The problem is, as we are doing the computation, we will also
166 // compute an *intermediate* contents for, e.g., Option<List> of
167 // TC::None. This is ok during the computation of List itself, but if
168 // we stored this intermediate value into cx.tc_cache, then later
169 // requests for the contents of Option<List> would also yield TC::None
170 // which is incorrect. This value was computed based on the crutch
171 // value for the type contents of list. The correct value is
172 // TC::OwnsOwned. This manifested as issue #4821.
173 match cache.get(&ty) {
174 Some(tc) => { return *tc; }
177 match cx.tc_cache.borrow().get(&ty) { // Must check both caches!
178 Some(tc) => { return *tc; }
181 cache.insert(ty, TC::None);
183 let result = match ty.sty {
184 // usize and isize are ffi-unsafe
185 ty::TyUint(ast::TyUs) | ty::TyInt(ast::TyIs) => {
189 // Scalar and unique types are sendable, and durable
190 ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
191 ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
192 ty::TyBareFn(..) | ty::TyChar => {
197 tc_ty(cx, typ, cache).owned_pointer()
201 TC::All - TC::InteriorParam
212 ty::TyArray(ty, _) => {
219 ty::TyStr => TC::None,
221 ty::TyClosure(_, ref substs) => {
222 TypeContents::union(&substs.upvar_tys, |ty| tc_ty(cx, &ty, cache))
225 ty::TyTuple(ref tys) => {
226 TypeContents::union(&tys[..],
227 |ty| tc_ty(cx, *ty, cache))
230 ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
232 TypeContents::union(&def.variants, |v| {
233 TypeContents::union(&v.fields, |f| {
234 tc_ty(cx, f.ty(cx, substs), cache)
239 res = res | TC::OwnsDtor;
242 apply_lang_items(cx, def.did, res)
245 ty::TyProjection(..) |
252 cx.sess.bug("asked to compute contents of error type");
256 cache.insert(ty, result);
260 fn apply_lang_items(cx: &ty::ctxt, did: DefId, tc: TypeContents)
262 if Some(did) == cx.lang_items.unsafe_cell_type() {
263 tc | TC::InteriorUnsafe