]> git.lizzy.rs Git - rust.git/blob - src/librustc_macros/src/query.rs
Run `rustfmt --file-lines ...` for changes from previous commits.
[rust.git] / src / librustc_macros / src / query.rs
1 use proc_macro::TokenStream;
2 use syn::{
3     Token, Ident, Type, Attribute, ReturnType, Expr, Block, Error,
4     braced, parenthesized, parse_macro_input,
5 };
6 use syn::spanned::Spanned;
7 use syn::parse::{Result, Parse, ParseStream};
8 use syn::punctuated::Punctuated;
9 use syn;
10 use quote::quote;
11 use itertools::Itertools;
12
13 #[allow(non_camel_case_types)]
14 mod kw {
15     syn::custom_keyword!(query);
16 }
17
18 /// Ident or a wildcard `_`.
19 struct IdentOrWild(Ident);
20
21 impl Parse for IdentOrWild {
22     fn parse(input: ParseStream<'_>) -> Result<Self> {
23         Ok(if input.peek(Token![_]) {
24             let underscore = input.parse::<Token![_]>()?;
25             IdentOrWild(Ident::new("_", underscore.span()))
26         } else {
27             IdentOrWild(input.parse()?)
28         })
29     }
30 }
31
32 /// A modifier for a query
33 enum QueryModifier {
34     /// The description of the query.
35     Desc(Option<Ident>, Punctuated<Expr, Token![,]>),
36
37     /// Cache the query to disk if the `Expr` returns true.
38     Cache(Option<Ident>, Expr),
39
40     /// Custom code to load the query from disk.
41     LoadCached(Ident, Ident, Block),
42
43     /// A cycle error for this query aborting the compilation with a fatal error.
44     FatalCycle,
45
46     /// A cycle error results in a delay_bug call
47     CycleDelayBug,
48
49     /// Don't hash the result, instead just mark a query red if it runs
50     NoHash,
51
52     /// Don't force the query
53     NoForce,
54
55     /// Generate a dep node based on the dependencies of the query
56     Anon,
57
58     /// Always evaluate the query, ignoring its depdendencies
59     EvalAlways,
60 }
61
62 impl Parse for QueryModifier {
63     fn parse(input: ParseStream<'_>) -> Result<Self> {
64         let modifier: Ident = input.parse()?;
65         if modifier == "desc" {
66             // Parse a description modifier like:
67             // `desc { |tcx| "foo {}", tcx.item_path(key) }`
68             let attr_content;
69             braced!(attr_content in input);
70             let tcx = if attr_content.peek(Token![|]) {
71                 attr_content.parse::<Token![|]>()?;
72                 let tcx = attr_content.parse()?;
73                 attr_content.parse::<Token![|]>()?;
74                 Some(tcx)
75             } else {
76                 None
77             };
78             let desc = attr_content.parse_terminated(Expr::parse)?;
79             Ok(QueryModifier::Desc(tcx, desc))
80         } else if modifier == "cache" {
81             // Parse a cache modifier like:
82             // `cache { |tcx| key.is_local() }`
83             let attr_content;
84             braced!(attr_content in input);
85             let tcx = if attr_content.peek(Token![|]) {
86                 attr_content.parse::<Token![|]>()?;
87                 let tcx = attr_content.parse()?;
88                 attr_content.parse::<Token![|]>()?;
89                 Some(tcx)
90             } else {
91                 None
92             };
93             let expr = attr_content.parse()?;
94             Ok(QueryModifier::Cache(tcx, expr))
95         } else if modifier == "load_cached" {
96             // Parse a load_cached modifier like:
97             // `load_cached(tcx, id) { tcx.queries.on_disk_cache.try_load_query_result(tcx, id) }`
98             let args;
99             parenthesized!(args in input);
100             let tcx = args.parse()?;
101             args.parse::<Token![,]>()?;
102             let id = args.parse()?;
103             let block = input.parse()?;
104             Ok(QueryModifier::LoadCached(tcx, id, block))
105         } else if modifier == "fatal_cycle" {
106             Ok(QueryModifier::FatalCycle)
107         } else if modifier == "cycle_delay_bug" {
108             Ok(QueryModifier::CycleDelayBug)
109         } else if modifier == "no_hash" {
110             Ok(QueryModifier::NoHash)
111         } else if modifier == "no_force" {
112             Ok(QueryModifier::NoForce)
113         } else if modifier == "anon" {
114             Ok(QueryModifier::Anon)
115         } else if modifier == "eval_always" {
116             Ok(QueryModifier::EvalAlways)
117         } else {
118             Err(Error::new(modifier.span(), "unknown query modifier"))
119         }
120     }
121 }
122
123 /// Ensures only doc comment attributes are used
124 fn check_attributes(attrs: Vec<Attribute>) -> Result<()> {
125     for attr in attrs {
126         if !attr.path.is_ident("doc") {
127             return Err(Error::new(attr.span(), "attributes not supported on queries"));
128         }
129     }
130     Ok(())
131 }
132
133 /// A compiler query. `query ... { ... }`
134 struct Query {
135     modifiers: List<QueryModifier>,
136     name: Ident,
137     key: IdentOrWild,
138     arg: Type,
139     result: ReturnType,
140 }
141
142 impl Parse for Query {
143     fn parse(input: ParseStream<'_>) -> Result<Self> {
144         check_attributes(input.call(Attribute::parse_outer)?)?;
145
146         // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>`
147         input.parse::<kw::query>()?;
148         let name: Ident = input.parse()?;
149         let arg_content;
150         parenthesized!(arg_content in input);
151         let key = arg_content.parse()?;
152         arg_content.parse::<Token![:]>()?;
153         let arg = arg_content.parse()?;
154         let result = input.parse()?;
155
156         // Parse the query modifiers
157         let content;
158         braced!(content in input);
159         let modifiers = content.parse()?;
160
161         Ok(Query {
162             modifiers,
163             name,
164             key,
165             arg,
166             result,
167         })
168     }
169 }
170
171 /// A type used to greedily parse another type until the input is empty.
172 struct List<T>(Vec<T>);
173
174 impl<T: Parse> Parse for List<T> {
175     fn parse(input: ParseStream<'_>) -> Result<Self> {
176         let mut list = Vec::new();
177         while !input.is_empty() {
178             list.push(input.parse()?);
179         }
180         Ok(List(list))
181     }
182 }
183
184 /// A named group containing queries.
185 struct Group {
186     name: Ident,
187     queries: List<Query>,
188 }
189
190 impl Parse for Group {
191     fn parse(input: ParseStream<'_>) -> Result<Self> {
192         let name: Ident = input.parse()?;
193         let content;
194         braced!(content in input);
195         Ok(Group {
196             name,
197             queries: content.parse()?,
198         })
199     }
200 }
201
202 struct QueryModifiers {
203     /// The description of the query.
204     desc: Option<(Option<Ident>, Punctuated<Expr, Token![,]>)>,
205
206     /// Cache the query to disk if the `Expr` returns true.
207     cache: Option<(Option<Ident>, Expr)>,
208
209     /// Custom code to load the query from disk.
210     load_cached: Option<(Ident, Ident, Block)>,
211
212     /// A cycle error for this query aborting the compilation with a fatal error.
213     fatal_cycle: bool,
214
215     /// A cycle error results in a delay_bug call
216     cycle_delay_bug: bool,
217
218     /// Don't hash the result, instead just mark a query red if it runs
219     no_hash: bool,
220
221     /// Don't force the query
222     no_force: bool,
223
224     /// Generate a dep node based on the dependencies of the query
225     anon: bool,
226
227     // Always evaluate the query, ignoring its depdendencies
228     eval_always: bool,
229 }
230
231 /// Process query modifiers into a struct, erroring on duplicates
232 fn process_modifiers(query: &mut Query) -> QueryModifiers {
233     let mut load_cached = None;
234     let mut cache = None;
235     let mut desc = None;
236     let mut fatal_cycle = false;
237     let mut cycle_delay_bug = false;
238     let mut no_hash = false;
239     let mut no_force = false;
240     let mut anon = false;
241     let mut eval_always = false;
242     for modifier in query.modifiers.0.drain(..) {
243         match modifier {
244             QueryModifier::LoadCached(tcx, id, block) => {
245                 if load_cached.is_some() {
246                     panic!("duplicate modifier `load_cached` for query `{}`", query.name);
247                 }
248                 load_cached = Some((tcx, id, block));
249             }
250             QueryModifier::Cache(tcx, expr) => {
251                 if cache.is_some() {
252                     panic!("duplicate modifier `cache` for query `{}`", query.name);
253                 }
254                 cache = Some((tcx, expr));
255             }
256             QueryModifier::Desc(tcx, list) => {
257                 if desc.is_some() {
258                     panic!("duplicate modifier `desc` for query `{}`", query.name);
259                 }
260                 desc = Some((tcx, list));
261             }
262             QueryModifier::FatalCycle => {
263                 if fatal_cycle {
264                     panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name);
265                 }
266                 fatal_cycle = true;
267             }
268             QueryModifier::CycleDelayBug => {
269                 if cycle_delay_bug {
270                     panic!("duplicate modifier `cycle_delay_bug` for query `{}`", query.name);
271                 }
272                 cycle_delay_bug = true;
273             }
274             QueryModifier::NoHash => {
275                 if no_hash {
276                     panic!("duplicate modifier `no_hash` for query `{}`", query.name);
277                 }
278                 no_hash = true;
279             }
280             QueryModifier::NoForce => {
281                 if no_force {
282                     panic!("duplicate modifier `no_force` for query `{}`", query.name);
283                 }
284                 no_force = true;
285             }
286             QueryModifier::Anon => {
287                 if anon {
288                     panic!("duplicate modifier `anon` for query `{}`", query.name);
289                 }
290                 anon = true;
291             }
292             QueryModifier::EvalAlways => {
293                 if eval_always {
294                     panic!("duplicate modifier `eval_always` for query `{}`", query.name);
295                 }
296                 eval_always = true;
297             }
298         }
299     }
300     QueryModifiers {
301         load_cached,
302         cache,
303         desc,
304         fatal_cycle,
305         cycle_delay_bug,
306         no_hash,
307         no_force,
308         anon,
309         eval_always,
310     }
311 }
312
313 /// Add the impl of QueryDescription for the query to `impls` if one is requested
314 fn add_query_description_impl(
315     query: &Query,
316     modifiers: QueryModifiers,
317     impls: &mut proc_macro2::TokenStream,
318 ) {
319     let name = &query.name;
320     let arg = &query.arg;
321     let key = &query.key.0;
322
323     // Find out if we should cache the query on disk
324     let cache = modifiers.cache.as_ref().map(|(tcx, expr)| {
325         let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() {
326             // Use custom code to load the query from disk
327             quote! {
328                 #[inline]
329                 fn try_load_from_disk(
330                     #tcx: TyCtxt<'tcx, 'tcx>,
331                     #id: SerializedDepNodeIndex
332                 ) -> Option<Self::Value> {
333                     #block
334                 }
335             }
336         } else {
337             // Use the default code to load the query from disk
338             quote! {
339                 #[inline]
340                 fn try_load_from_disk(
341                     tcx: TyCtxt<'tcx, 'tcx>,
342                     id: SerializedDepNodeIndex
343                 ) -> Option<Self::Value> {
344                     tcx.queries.on_disk_cache.try_load_query_result(tcx, id)
345                 }
346             }
347         };
348
349         let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ });
350         quote! {
351             #[inline]
352             #[allow(unused_variables)]
353             fn cache_on_disk(#tcx: TyCtxt<'tcx, 'tcx>, #key: Self::Key) -> bool {
354                 #expr
355             }
356
357             #try_load_from_disk
358         }
359     });
360
361     if cache.is_none() && modifiers.load_cached.is_some() {
362         panic!("load_cached modifier on query `{}` without a cache modifier", name);
363     }
364
365     let desc = modifiers.desc.as_ref().map(|(tcx, desc)| {
366         let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ });
367         quote! {
368             #[allow(unused_variables)]
369             fn describe(
370                 #tcx: TyCtxt<'_, '_>,
371                 #key: #arg,
372             ) -> Cow<'static, str> {
373                 format!(#desc).into()
374             }
375         }
376     });
377
378     if desc.is_some() || cache.is_some() {
379         let cache = cache.unwrap_or(quote! {});
380         let desc = desc.unwrap_or(quote! {});
381
382         impls.extend(quote! {
383             impl<'tcx> QueryDescription<'tcx> for queries::#name<'tcx> {
384                 #desc
385                 #cache
386             }
387         });
388     }
389 }
390
391 pub fn rustc_queries(input: TokenStream) -> TokenStream {
392     let groups = parse_macro_input!(input as List<Group>);
393
394     let mut query_stream = quote! {};
395     let mut query_description_stream = quote! {};
396     let mut dep_node_def_stream = quote! {};
397     let mut dep_node_force_stream = quote! {};
398     let mut no_force_queries = Vec::new();
399
400     for group in groups.0 {
401         let mut group_stream = quote! {};
402         for mut query in group.queries.0 {
403             let modifiers = process_modifiers(&mut query);
404             let name = &query.name;
405             let arg = &query.arg;
406             let result_full = &query.result;
407             let result = match query.result {
408                 ReturnType::Default => quote! { -> () },
409                 _ => quote! { #result_full },
410             };
411
412             let mut attributes = Vec::new();
413
414             // Pass on the fatal_cycle modifier
415             if modifiers.fatal_cycle {
416                 attributes.push(quote! { fatal_cycle });
417             };
418             // Pass on the cycle_delay_bug modifier
419             if modifiers.cycle_delay_bug {
420                 attributes.push(quote! { cycle_delay_bug });
421             };
422             // Pass on the no_hash modifier
423             if modifiers.no_hash {
424                 attributes.push(quote! { no_hash });
425             };
426
427             let mut attribute_stream = quote! {};
428
429             for e in attributes.into_iter().intersperse(quote! {,}) {
430                 attribute_stream.extend(e);
431             }
432
433             // Add the query to the group
434             group_stream.extend(quote! {
435                 [#attribute_stream] fn #name: #name(#arg) #result,
436             });
437
438             let mut attributes = Vec::new();
439
440             // Pass on the anon modifier
441             if modifiers.anon {
442                 attributes.push(quote! { anon });
443             };
444             // Pass on the eval_always modifier
445             if modifiers.eval_always {
446                 attributes.push(quote! { eval_always });
447             };
448
449             let mut attribute_stream = quote! {};
450             for e in attributes.into_iter().intersperse(quote! {,}) {
451                 attribute_stream.extend(e);
452             }
453             // Create a dep node for the query
454             dep_node_def_stream.extend(quote! {
455                 [#attribute_stream] #name(#arg),
456             });
457
458             if modifiers.no_force {
459                 no_force_queries.push(name.clone());
460             } else {
461                 // Add a match arm to force the query given the dep node
462                 dep_node_force_stream.extend(quote! {
463                     DepKind::#name => {
464                         if let Some(key) = RecoverKey::recover($tcx, $dep_node) {
465                             force_ex!($tcx, #name, key);
466                         } else {
467                             return false;
468                         }
469                     }
470                 });
471             }
472
473             add_query_description_impl(&query, modifiers, &mut query_description_stream);
474         }
475         let name = &group.name;
476         query_stream.extend(quote! {
477             #name { #group_stream },
478         });
479     }
480
481     // Add an arm for the no force queries to panic when trying to force them
482     for query in no_force_queries {
483         dep_node_force_stream.extend(quote! {
484             DepKind::#query |
485         });
486     }
487     dep_node_force_stream.extend(quote! {
488         DepKind::Null => {
489             bug!("Cannot force dep node: {:?}", $dep_node)
490         }
491     });
492
493     TokenStream::from(quote! {
494         macro_rules! rustc_query_append {
495             ([$($macro:tt)*][$($other:tt)*]) => {
496                 $($macro)* {
497                     $($other)*
498
499                     #query_stream
500
501                 }
502             }
503         }
504         macro_rules! rustc_dep_node_append {
505             ([$($macro:tt)*][$($other:tt)*]) => {
506                 $($macro)*(
507                     $($other)*
508
509                     #dep_node_def_stream
510                 );
511             }
512         }
513         macro_rules! rustc_dep_node_force {
514             ([$dep_node:expr, $tcx:expr] $($other:tt)*) => {
515                 match $dep_node.kind {
516                     $($other)*
517
518                     #dep_node_force_stream
519                 }
520             }
521         }
522         #query_description_stream
523     })
524 }