]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/ty/ivar.rs
Rollup merge of #31055 - steveklabnik:alt-tags, r=alexcrichton
[rust.git] / src / librustc / middle / ty / ivar.rs
1 // Copyright 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 dep_graph::DepNode;
12 use middle::ty::{Ty, TyS};
13 use middle::ty::tls;
14
15 use rustc_data_structures::ivar;
16
17 use std::fmt;
18 use std::marker::PhantomData;
19 use core::nonzero::NonZero;
20
21 /// An IVar that contains a Ty. 'lt is a (reverse-variant) upper bound
22 /// on the lifetime of the IVar. This is required because of variance
23 /// problems: the IVar needs to be variant with respect to 'tcx (so
24 /// it can be referred to from Ty) but can only be modified if its
25 /// lifetime is exactly 'tcx.
26 ///
27 /// Safety invariants:
28 ///     (A) self.0, if fulfilled, is a valid Ty<'tcx>
29 ///     (B) no aliases to this value with a 'tcx longer than this
30 ///         value's 'lt exist
31 ///
32 /// Dependency tracking: each ivar does not know what node in the
33 /// dependency graph it is associated with, so when you get/fulfill
34 /// you must supply a `DepNode` id. This should always be the same id!
35 ///
36 /// NonZero is used rather than Unique because Unique isn't Copy.
37 pub struct TyIVar<'tcx, 'lt: 'tcx>(ivar::Ivar<NonZero<*const TyS<'static>>>,
38                                    PhantomData<fn(TyS<'lt>)->TyS<'tcx>>);
39
40 impl<'tcx, 'lt> TyIVar<'tcx, 'lt> {
41     #[inline]
42     pub fn new() -> Self {
43         // Invariant (A) satisfied because the IVar is unfulfilled
44         // Invariant (B) because 'lt : 'tcx
45         TyIVar(ivar::Ivar::new(), PhantomData)
46     }
47
48     #[inline]
49     pub fn get(&self, dep_node: DepNode) -> Option<Ty<'tcx>> {
50         tls::with(|tcx| tcx.dep_graph.read(dep_node));
51         self.untracked_get()
52     }
53
54     #[inline]
55     fn untracked_get(&self) -> Option<Ty<'tcx>> {
56         match self.0.get() {
57             None => None,
58             // valid because of invariant (A)
59             Some(v) => Some(unsafe { &*(*v as *const TyS<'tcx>) })
60         }
61     }
62
63     #[inline]
64     pub fn unwrap(&self, dep_node: DepNode) -> Ty<'tcx> {
65         self.get(dep_node).unwrap()
66     }
67
68     pub fn fulfill(&self, dep_node: DepNode, value: Ty<'lt>) {
69         tls::with(|tcx| tcx.dep_graph.write(dep_node));
70
71         // Invariant (A) is fulfilled, because by (B), every alias
72         // of this has a 'tcx longer than 'lt.
73         let value: *const TyS<'lt> = value;
74         // FIXME(27214): unneeded [as *const ()]
75         let value = value as *const () as *const TyS<'static>;
76         self.0.fulfill(unsafe { NonZero::new(value) })
77     }
78 }
79
80 impl<'tcx, 'lt> fmt::Debug for TyIVar<'tcx, 'lt> {
81     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82         match self.untracked_get() {
83             Some(val) => write!(f, "TyIVar({:?})", val),
84             None => f.write_str("TyIVar(<unfulfilled>)")
85         }
86     }
87 }