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