]> git.lizzy.rs Git - rust.git/blob - src/librustc_interface/queries.rs
Rollup merge of #59026 - GuillaumeGomez:search-tabs-header, r=QuietMisdreavus
[rust.git] / src / librustc_interface / queries.rs
1 use interface::{Compiler, Result};
2 use passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo};
3 use rustc_incremental::DepGraphFuture;
4 use rustc_data_structures::sync::Lrc;
5 use rustc::session::config::{Input, OutputFilenames, OutputType};
6 use rustc::session::Session;
7 use rustc::util::common::{time, ErrorReported};
8 use rustc::util::profiling::ProfileCategory;
9 use rustc::lint;
10 use rustc::hir;
11 use rustc::hir::def_id::LOCAL_CRATE;
12 use rustc::ty;
13 use rustc::ty::steal::Steal;
14 use rustc::dep_graph::DepGraph;
15 use rustc_passes::hir_stats;
16 use rustc_plugin::registry::Registry;
17 use serialize::json;
18 use std::cell::{Ref, RefMut, RefCell};
19 use std::ops::Deref;
20 use std::rc::Rc;
21 use std::sync::mpsc;
22 use std::any::Any;
23 use std::mem;
24 use syntax::parse::{self, PResult};
25 use syntax::util::node_count::NodeCounter;
26 use syntax::{self, ast, attr, diagnostics, visit};
27 use syntax_pos::hygiene;
28
29 /// Represent the result of a query.
30 /// This result can be stolen with the `take` method and returned with the `give` method.
31 pub struct Query<T> {
32     result: RefCell<Option<Result<T>>>,
33 }
34
35 impl<T> Query<T> {
36     fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
37         let mut result = self.result.borrow_mut();
38         if result.is_none() {
39             *result = Some(f());
40         }
41         result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err)
42     }
43
44     /// Takes ownership of the query result. Further attempts to take or peek the query
45     /// result will panic unless it is returned by calling the `give` method.
46     pub fn take(&self) -> T {
47         self.result
48             .borrow_mut()
49             .take()
50             .expect("missing query result")
51             .unwrap()
52     }
53
54     /// Returns a stolen query result. Panics if there's already a result.
55     pub fn give(&self, value: T) {
56         let mut result = self.result.borrow_mut();
57         assert!(result.is_none(), "a result already exists");
58         *result = Some(Ok(value));
59     }
60
61     /// Borrows the query result using the RefCell. Panics if the result is stolen.
62     pub fn peek(&self) -> Ref<'_, T> {
63         Ref::map(self.result.borrow(), |r| {
64             r.as_ref().unwrap().as_ref().expect("missing query result")
65         })
66     }
67
68     /// Mutably borrows the query result using the RefCell. Panics if the result is stolen.
69     pub fn peek_mut(&self) -> RefMut<'_, T> {
70         RefMut::map(self.result.borrow_mut(), |r| {
71             r.as_mut().unwrap().as_mut().expect("missing query result")
72         })
73     }
74 }
75
76 impl<T> Default for Query<T> {
77     fn default() -> Self {
78         Query {
79             result: RefCell::new(None),
80         }
81     }
82 }
83
84 #[derive(Default)]
85 pub(crate) struct Queries {
86     dep_graph_future: Query<Option<DepGraphFuture>>,
87     parse: Query<ast::Crate>,
88     crate_name: Query<String>,
89     register_plugins: Query<(ast::Crate, PluginInfo)>,
90     expansion: Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>,
91     dep_graph: Query<DepGraph>,
92     lower_to_hir: Query<(Steal<hir::map::Forest>, ExpansionResult)>,
93     prepare_outputs: Query<OutputFilenames>,
94     codegen_channel: Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
95                             Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>,
96     global_ctxt: Query<BoxedGlobalCtxt>,
97     ongoing_codegen: Query<Box<dyn Any>>,
98     link: Query<()>,
99 }
100
101 impl Compiler {
102     pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
103         self.queries.dep_graph_future.compute(|| {
104             Ok(if self.session().opts.build_dep_graph() {
105                 Some(rustc_incremental::load_dep_graph(self.session()))
106             } else {
107                 None
108             })
109         })
110     }
111
112     pub fn parse(&self) -> Result<&Query<ast::Crate>> {
113         self.queries.parse.compute(|| {
114             passes::parse(self.session(), &self.input).map_err(
115                 |mut parse_error| {
116                     parse_error.emit();
117                     ErrorReported
118                 },
119             )
120         })
121     }
122
123     pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> {
124         self.queries.register_plugins.compute(|| {
125             let crate_name = self.crate_name()?.peek().clone();
126             let krate = self.parse()?.take();
127
128             passes::register_plugins(
129                 self,
130                 self.session(),
131                 self.cstore(),
132                 krate,
133                 &crate_name,
134             )
135         })
136     }
137
138     pub fn crate_name(&self) -> Result<&Query<String>> {
139         self.queries.crate_name.compute(|| {
140             let parse_result = self.parse()?;
141             let krate = parse_result.peek();
142             let result = match self.crate_name {
143                 Some(ref crate_name) => crate_name.clone(),
144                 None => rustc_codegen_utils::link::find_crate_name(
145                     Some(self.session()),
146                     &krate.attrs,
147                     &self.input
148                 ),
149             };
150             Ok(result)
151         })
152     }
153
154     pub fn expansion(
155         &self
156     ) -> Result<&Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>> {
157         self.queries.expansion.compute(|| {
158             let crate_name = self.crate_name()?.peek().clone();
159             let (krate, plugin_info) = self.register_plugins()?.take();
160             passes::configure_and_expand(
161                 self.sess.clone(),
162                 self.cstore().clone(),
163                 krate,
164                 &crate_name,
165                 plugin_info,
166             ).map(|(krate, resolver)| (krate, Rc::new(Some(RefCell::new(resolver)))))
167         })
168     }
169
170     pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
171         self.queries.dep_graph.compute(|| {
172             Ok(match self.dep_graph_future()?.take() {
173                 None => DepGraph::new_disabled(),
174                 Some(future) => {
175                     let (prev_graph, prev_work_products) =
176                         time(self.session(), "blocked while dep-graph loading finishes", || {
177                             future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
178                                 message: format!("could not decode incremental cache: {:?}", e),
179                             }).open(self.session())
180                         });
181                     DepGraph::new(prev_graph, prev_work_products)
182                 }
183             })
184         })
185     }
186
187     pub fn lower_to_hir(&self) -> Result<&Query<(Steal<hir::map::Forest>, ExpansionResult)>> {
188         self.queries.lower_to_hir.compute(|| {
189             let expansion_result = self.expansion()?;
190             let (krate, resolver) = expansion_result.take();
191             let resolver_ref = &*resolver;
192             let hir = Steal::new(resolver_ref.as_ref().unwrap().borrow_mut().access(|resolver| {
193                 passes::lower_to_hir(
194                     self.session(),
195                     self.cstore(),
196                     resolver,
197                     &*self.dep_graph()?.peek(),
198                     &krate
199                 )
200             })?);
201             expansion_result.give((krate, Rc::new(None)));
202             Ok((hir, BoxedResolver::to_expansion_result(resolver)))
203         })
204     }
205
206     pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
207         self.queries.prepare_outputs.compute(|| {
208             self.lower_to_hir()?;
209             let krate = self.expansion()?;
210             let krate = krate.peek();
211             let crate_name = self.crate_name()?;
212             let crate_name = crate_name.peek();
213             passes::prepare_outputs(self.session(), self, &krate.0, &*crate_name)
214         })
215     }
216
217     pub fn codegen_channel(&self) -> Result<&Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
218                                                     Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>> {
219         self.queries.codegen_channel.compute(|| {
220             let (tx, rx) = mpsc::channel();
221             Ok((Steal::new(tx), Steal::new(rx)))
222         })
223     }
224
225     pub fn global_ctxt(&self) -> Result<&Query<BoxedGlobalCtxt>> {
226         self.queries.global_ctxt.compute(|| {
227             let crate_name = self.crate_name()?.peek().clone();
228             let outputs = self.prepare_outputs()?.peek().clone();
229             let hir = self.lower_to_hir()?;
230             let hir = hir.peek();
231             let (ref hir_forest, ref expansion) = *hir;
232             let tx = self.codegen_channel()?.peek().0.steal();
233             Ok(passes::create_global_ctxt(
234                 self,
235                 hir_forest.steal(),
236                 expansion.defs.steal(),
237                 expansion.resolutions.steal(),
238                 outputs,
239                 tx,
240                 &crate_name))
241         })
242     }
243
244     pub fn ongoing_codegen(&self) -> Result<&Query<Box<dyn Any>>> {
245         self.queries.ongoing_codegen.compute(|| {
246             let rx = self.codegen_channel()?.peek().1.steal();
247             let outputs = self.prepare_outputs()?;
248             self.global_ctxt()?.peek_mut().enter(|tcx| {
249                 tcx.analysis(LOCAL_CRATE).ok();
250
251                 // Don't do code generation if there were any errors
252                 self.session().compile_status()?;
253
254                 Ok(passes::start_codegen(
255                     &***self.codegen_backend(),
256                     tcx,
257                     rx,
258                     &*outputs.peek()
259                 ))
260             })
261         })
262     }
263
264     pub fn link(&self) -> Result<&Query<()>> {
265         self.queries.link.compute(|| {
266             let sess = self.session();
267
268             let ongoing_codegen = self.ongoing_codegen()?.take();
269
270             self.codegen_backend().join_codegen_and_link(
271                 ongoing_codegen,
272                 sess,
273                 &*self.dep_graph()?.peek(),
274                 &*self.prepare_outputs()?.peek(),
275             ).map_err(|_| ErrorReported)?;
276
277             Ok(())
278         })
279     }
280
281     pub fn compile(&self) -> Result<()> {
282         self.prepare_outputs()?;
283
284         if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
285             && self.session().opts.output_types.len() == 1
286         {
287             return Ok(())
288         }
289
290         self.global_ctxt()?;
291
292         // Drop AST after creating GlobalCtxt to free memory
293         mem::drop(self.expansion()?.take());
294
295         self.ongoing_codegen()?;
296
297         // Drop GlobalCtxt after starting codegen to free memory
298         mem::drop(self.global_ctxt()?.take());
299
300         self.link().map(|_| ())
301     }
302 }