1 use crate::interface::{Compiler, Result};
2 use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo};
4 use rustc_incremental::DepGraphFuture;
5 use rustc::session::config::{OutputFilenames, OutputType};
6 use rustc::util::common::{time, ErrorReported};
8 use rustc::hir::def_id::LOCAL_CRATE;
9 use rustc::ty::steal::Steal;
10 use rustc::dep_graph::DepGraph;
11 use std::cell::{Ref, RefMut, RefCell};
16 use syntax::{self, ast};
18 /// Represent the result of a query.
19 /// This result can be stolen with the `take` method and returned with the `give` method.
21 result: RefCell<Option<Result<T>>>,
25 fn compute<F: FnOnce() -> Result<T>>(&self, f: F) -> Result<&Query<T>> {
26 let mut result = self.result.borrow_mut();
30 result.as_ref().unwrap().as_ref().map(|_| self).map_err(|err| *err)
33 /// Takes ownership of the query result. Further attempts to take or peek the query
34 /// result will panic unless it is returned by calling the `give` method.
35 pub fn take(&self) -> T {
39 .expect("missing query result")
43 /// Returns a stolen query result. Panics if there's already a result.
44 pub fn give(&self, value: T) {
45 let mut result = self.result.borrow_mut();
46 assert!(result.is_none(), "a result already exists");
47 *result = Some(Ok(value));
50 /// Borrows the query result using the RefCell. Panics if the result is stolen.
51 pub fn peek(&self) -> Ref<'_, T> {
52 Ref::map(self.result.borrow(), |r| {
53 r.as_ref().unwrap().as_ref().expect("missing query result")
57 /// Mutably borrows the query result using the RefCell. Panics if the result is stolen.
58 pub fn peek_mut(&self) -> RefMut<'_, T> {
59 RefMut::map(self.result.borrow_mut(), |r| {
60 r.as_mut().unwrap().as_mut().expect("missing query result")
65 impl<T> Default for Query<T> {
66 fn default() -> Self {
68 result: RefCell::new(None),
74 pub(crate) struct Queries {
75 dep_graph_future: Query<Option<DepGraphFuture>>,
76 parse: Query<ast::Crate>,
77 crate_name: Query<String>,
78 register_plugins: Query<(ast::Crate, PluginInfo)>,
79 expansion: Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>,
80 dep_graph: Query<DepGraph>,
81 lower_to_hir: Query<(Steal<hir::map::Forest>, ExpansionResult)>,
82 prepare_outputs: Query<OutputFilenames>,
83 codegen_channel: Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
84 Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>,
85 global_ctxt: Query<BoxedGlobalCtxt>,
86 ongoing_codegen: Query<Box<dyn Any>>,
91 pub fn dep_graph_future(&self) -> Result<&Query<Option<DepGraphFuture>>> {
92 self.queries.dep_graph_future.compute(|| {
93 Ok(if self.session().opts.build_dep_graph() {
94 Some(rustc_incremental::load_dep_graph(self.session()))
101 pub fn parse(&self) -> Result<&Query<ast::Crate>> {
102 self.queries.parse.compute(|| {
103 passes::parse(self.session(), &self.input).map_err(
112 pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, PluginInfo)>> {
113 self.queries.register_plugins.compute(|| {
114 let crate_name = self.crate_name()?.peek().clone();
115 let krate = self.parse()?.take();
117 passes::register_plugins(
127 pub fn crate_name(&self) -> Result<&Query<String>> {
128 self.queries.crate_name.compute(|| {
129 let parse_result = self.parse()?;
130 let krate = parse_result.peek();
131 let result = match self.crate_name {
132 Some(ref crate_name) => crate_name.clone(),
133 None => rustc_codegen_utils::link::find_crate_name(
134 Some(self.session()),
145 ) -> Result<&Query<(ast::Crate, Rc<Option<RefCell<BoxedResolver>>>)>> {
146 self.queries.expansion.compute(|| {
147 let crate_name = self.crate_name()?.peek().clone();
148 let (krate, plugin_info) = self.register_plugins()?.take();
149 passes::configure_and_expand(
151 self.cstore().clone(),
155 ).map(|(krate, resolver)| (krate, Rc::new(Some(RefCell::new(resolver)))))
159 pub fn dep_graph(&self) -> Result<&Query<DepGraph>> {
160 self.queries.dep_graph.compute(|| {
161 Ok(match self.dep_graph_future()?.take() {
162 None => DepGraph::new_disabled(),
164 let (prev_graph, prev_work_products) =
165 time(self.session(), "blocked while dep-graph loading finishes", || {
166 future.open().unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
167 message: format!("could not decode incremental cache: {:?}", e),
168 }).open(self.session())
170 DepGraph::new(prev_graph, prev_work_products)
176 pub fn lower_to_hir(&self) -> Result<&Query<(Steal<hir::map::Forest>, ExpansionResult)>> {
177 self.queries.lower_to_hir.compute(|| {
178 let expansion_result = self.expansion()?;
179 let (krate, resolver) = expansion_result.take();
180 let resolver_ref = &*resolver;
181 let hir = Steal::new(resolver_ref.as_ref().unwrap().borrow_mut().access(|resolver| {
182 passes::lower_to_hir(
186 &*self.dep_graph()?.peek(),
190 expansion_result.give((krate, Rc::new(None)));
191 Ok((hir, BoxedResolver::to_expansion_result(resolver)))
195 pub fn prepare_outputs(&self) -> Result<&Query<OutputFilenames>> {
196 self.queries.prepare_outputs.compute(|| {
197 self.lower_to_hir()?;
198 let krate = self.expansion()?;
199 let krate = krate.peek();
200 let crate_name = self.crate_name()?;
201 let crate_name = crate_name.peek();
202 passes::prepare_outputs(self.session(), self, &krate.0, &*crate_name)
206 pub fn codegen_channel(&self) -> Result<&Query<(Steal<mpsc::Sender<Box<dyn Any + Send>>>,
207 Steal<mpsc::Receiver<Box<dyn Any + Send>>>)>> {
208 self.queries.codegen_channel.compute(|| {
209 let (tx, rx) = mpsc::channel();
210 Ok((Steal::new(tx), Steal::new(rx)))
214 pub fn global_ctxt(&self) -> Result<&Query<BoxedGlobalCtxt>> {
215 self.queries.global_ctxt.compute(|| {
216 let crate_name = self.crate_name()?.peek().clone();
217 let outputs = self.prepare_outputs()?.peek().clone();
218 let hir = self.lower_to_hir()?;
219 let hir = hir.peek();
220 let (ref hir_forest, ref expansion) = *hir;
221 let tx = self.codegen_channel()?.peek().0.steal();
222 Ok(passes::create_global_ctxt(
225 expansion.defs.steal(),
226 expansion.resolutions.steal(),
233 pub fn ongoing_codegen(&self) -> Result<&Query<Box<dyn Any>>> {
234 self.queries.ongoing_codegen.compute(|| {
235 let rx = self.codegen_channel()?.peek().1.steal();
236 let outputs = self.prepare_outputs()?;
237 self.global_ctxt()?.peek_mut().enter(|tcx| {
238 tcx.analysis(LOCAL_CRATE).ok();
240 // Don't do code generation if there were any errors
241 self.session().compile_status()?;
243 Ok(passes::start_codegen(
244 &***self.codegen_backend(),
253 pub fn link(&self) -> Result<&Query<()>> {
254 self.queries.link.compute(|| {
255 let sess = self.session();
257 let ongoing_codegen = self.ongoing_codegen()?.take();
259 self.codegen_backend().join_codegen_and_link(
262 &*self.dep_graph()?.peek(),
263 &*self.prepare_outputs()?.peek(),
264 ).map_err(|_| ErrorReported)?;
270 pub fn compile(&self) -> Result<()> {
271 self.prepare_outputs()?;
273 if self.session().opts.output_types.contains_key(&OutputType::DepInfo)
274 && self.session().opts.output_types.len() == 1
281 // Drop AST after creating GlobalCtxt to free memory
282 mem::drop(self.expansion()?.take());
284 self.ongoing_codegen()?;
286 // Drop GlobalCtxt after starting codegen to free memory
287 mem::drop(self.global_ctxt()?.take());
289 self.link().map(|_| ())