Skip to content

Commit

Permalink
Preprocess query modifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
Zoxc committed Mar 18, 2019
1 parent 4f49fff commit 198dfce
Showing 1 changed file with 82 additions and 31 deletions.
113 changes: 82 additions & 31 deletions src/librustc_macros/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use syn::{
Token, Ident, Type, Attribute, ReturnType, Expr, Block, Error,
braced, parenthesized, parse_macro_input,
Expand All @@ -21,8 +20,8 @@ struct IdentOrWild(Ident);
impl Parse for IdentOrWild {
fn parse(input: ParseStream<'_>) -> Result<Self> {
Ok(if input.peek(Token![_]) {
input.parse::<Token![_]>()?;
IdentOrWild(Ident::new("_", Span::call_site()))
let underscore = input.parse::<Token![_]>()?;
IdentOrWild(Ident::new("_", underscore.span()))
} else {
IdentOrWild(input.parse()?)
})
Expand All @@ -31,7 +30,7 @@ impl Parse for IdentOrWild {

/// A modifier for a query
enum QueryModifier {
/// The description of the query
/// The description of the query.
Desc(Option<Ident>, Punctuated<Expr, Token![,]>),

/// Cache the query to disk if the `Expr` returns true.
Expand Down Expand Up @@ -107,7 +106,7 @@ fn check_attributes(attrs: Vec<Attribute>) -> Result<()> {

/// A compiler query. `query ... { ... }`
struct Query {
attrs: List<QueryModifier>,
modifiers: List<QueryModifier>,
name: Ident,
key: IdentOrWild,
arg: Type,
Expand All @@ -131,10 +130,10 @@ impl Parse for Query {
// Parse the query modifiers
let content;
braced!(content in input);
let attrs = content.parse()?;
let modifiers = content.parse()?;

Ok(Query {
attrs,
modifiers,
name,
key,
arg,
Expand Down Expand Up @@ -174,24 +173,76 @@ impl Parse for Group {
}
}

struct QueryModifiers {
/// The description of the query.
desc: Option<(Option<Ident>, Punctuated<Expr, Token![,]>)>,

/// Cache the query to disk if the `Expr` returns true.
cache: Option<(Option<Ident>, Expr)>,

/// Custom code to load the query from disk.
load_cached: Option<(Ident, Ident, Block)>,

/// A cycle error for this query aborting the compilation with a fatal error.
fatal_cycle: bool,
}

/// Process query modifiers into a struct, erroring on duplicates
fn process_modifiers(query: &mut Query) -> QueryModifiers {
let mut load_cached = None;
let mut cache = None;
let mut desc = None;
let mut fatal_cycle = false;
for modifier in query.modifiers.0.drain(..) {
match modifier {
QueryModifier::LoadCached(tcx, id, block) => {
if load_cached.is_some() {
panic!("duplicate modifier `load_cached` for query `{}`", query.name);
}
load_cached = Some((tcx, id, block));
}
QueryModifier::Cache(tcx, expr) => {
if cache.is_some() {
panic!("duplicate modifier `cache` for query `{}`", query.name);
}
cache = Some((tcx, expr));
}
QueryModifier::Desc(tcx, list) => {
if desc.is_some() {
panic!("duplicate modifier `desc` for query `{}`", query.name);
}
desc = Some((tcx, list));
}
QueryModifier::FatalCycle => {
if fatal_cycle {
panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name);
}
fatal_cycle = true;
}
}
}
QueryModifiers {
load_cached,
cache,
desc,
fatal_cycle,
}
}

/// Add the impl of QueryDescription for the query to `impls` if one is requested
fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStream) {
fn add_query_description_impl(
query: &Query,
modifiers: QueryModifiers,
impls: &mut proc_macro2::TokenStream
) {
let name = &query.name;
let arg = &query.arg;
let key = &query.key.0;

// Find custom code to load the query from disk
let load_cached = query.attrs.0.iter().find_map(|attr| match attr {
QueryModifier::LoadCached(tcx, id, block) => Some((tcx, id, block)),
_ => None,
});

// Find out if we should cache the query on disk
let cache = query.attrs.0.iter().find_map(|attr| match attr {
QueryModifier::Cache(tcx, expr) => Some((tcx, expr)),
_ => None,
}).map(|(tcx, expr)| {
let try_load_from_disk = if let Some((tcx, id, block)) = load_cached {
let cache = modifiers.cache.as_ref().map(|(tcx, expr)| {
let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() {
// Use custom code to load the query from disk
quote! {
#[inline]
fn try_load_from_disk(
Expand All @@ -202,6 +253,7 @@ fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStrea
}
}
} else {
// Use the default code to load the query from disk
quote! {
#[inline]
fn try_load_from_disk(
Expand All @@ -224,14 +276,11 @@ fn add_query_description_impl(query: &Query, impls: &mut proc_macro2::TokenStrea
}
});

if cache.is_none() && load_cached.is_some() {
if cache.is_none() && modifiers.load_cached.is_some() {
panic!("load_cached modifier on query `{}` without a cache modifier", name);
}

let desc = query.attrs.0.iter().find_map(|attr| match attr {
QueryModifier::Desc(tcx, desc) => Some((tcx, desc)),
_ => None,
}).map(|(tcx, desc)| {
let desc = modifiers.desc.as_ref().map(|(tcx, desc)| {
let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ });
quote! {
fn describe(
Expand Down Expand Up @@ -266,7 +315,8 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {

for group in groups.0 {
let mut group_stream = quote! {};
for query in &group.queries.0 {
for mut query in group.queries.0 {
let modifiers = process_modifiers(&mut query);
let name = &query.name;
let arg = &query.arg;
let result_full = &query.result;
Expand All @@ -275,18 +325,19 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
_ => quote! { #result_full },
};

// Look for a fatal_cycle modifier to pass on
let fatal_cycle = query.attrs.0.iter().find_map(|attr| match attr {
QueryModifier::FatalCycle => Some(()),
_ => None,
}).map(|_| quote! { fatal_cycle }).unwrap_or(quote! {});
// Pass on the fatal_cycle modifier
let fatal_cycle = if modifiers.fatal_cycle {
quote! { fatal_cycle }
} else {
quote! {}
};

// Add the query to the group
group_stream.extend(quote! {
[#fatal_cycle] fn #name: #name(#arg) #result,
});

add_query_description_impl(query, &mut query_description_stream);
add_query_description_impl(&query, modifiers, &mut query_description_stream);

// Create a dep node for the query
dep_node_def_stream.extend(quote! {
Expand Down

0 comments on commit 198dfce

Please sign in to comment.