Emit self ty for query debug name of assoc function queries (#927)

This commit is contained in:
Lukas Wirth 2025-06-27 11:23:25 +02:00 committed by GitHub
parent d44f638408
commit f384ab538e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 133 additions and 7 deletions

View file

@ -66,6 +66,8 @@ macro_rules! setup_tracked_fn {
assert_return_type_is_update: {$($assert_return_type_is_update:tt)*},
$(self_ty: $self_ty:ty,)?
// Annoyingly macro-rules hygiene does not extend to items defined in the macro.
// We have the procedural macro generate names for those items that are
// not used elsewhere in the user's code.
@ -139,7 +141,7 @@ macro_rules! setup_tracked_fn {
file: file!(),
line: line!(),
};
const DEBUG_NAME: &'static str = concat!(stringify!($fn_name), "::interned_arguments");
const DEBUG_NAME: &'static str = concat!($(stringify!($self_ty), "::",)? stringify!($fn_name), "::interned_arguments");
type Fields<$db_lt> = ($($interned_input_ty),*);
@ -194,7 +196,7 @@ macro_rules! setup_tracked_fn {
file: file!(),
line: line!(),
};
const DEBUG_NAME: &'static str = stringify!($fn_name);
const DEBUG_NAME: &'static str = concat!($(stringify!($self_ty), "::", )? stringify!($fn_name));
type DbView = dyn $Db;

View file

@ -46,6 +46,7 @@ impl AllowedOptions for Accumulator {
const ID: bool = false;
const REVISIONS: bool = false;
const HEAP_SIZE: bool = false;
const SELF_TY: bool = false;
}
struct StructMacro {

View file

@ -66,6 +66,8 @@ impl crate::options::AllowedOptions for InputStruct {
const REVISIONS: bool = false;
const HEAP_SIZE: bool = false;
const SELF_TY: bool = false;
}
impl SalsaStructAllowedOptions for InputStruct {

View file

@ -66,6 +66,8 @@ impl crate::options::AllowedOptions for InternedStruct {
const REVISIONS: bool = true;
const HEAP_SIZE: bool = false;
const SELF_TY: bool = false;
}
impl SalsaStructAllowedOptions for InternedStruct {

View file

@ -105,6 +105,10 @@ pub(crate) struct Options<A: AllowedOptions> {
/// If this is `Some`, the value is the provided `heap_size` function.
pub heap_size_fn: Option<syn::Path>,
/// The `self_ty = <Ty>` option is used to set the the self type of the tracked impl for tracked
/// functions. This is merely used to refine the query name.
pub self_ty: Option<syn::Type>,
/// Remember the `A` parameter, which plays no role after parsing.
phantom: PhantomData<A>,
}
@ -130,6 +134,7 @@ impl<A: AllowedOptions> Default for Options<A> {
id: Default::default(),
revisions: Default::default(),
heap_size_fn: Default::default(),
self_ty: Default::default(),
}
}
}
@ -153,6 +158,7 @@ pub(crate) trait AllowedOptions {
const ID: bool;
const REVISIONS: bool;
const HEAP_SIZE: bool;
const SELF_TY: bool;
}
type Equals = syn::Token![=];
@ -416,6 +422,22 @@ impl<A: AllowedOptions> syn::parse::Parse for Options<A> {
"`heap_size` option not allowed here",
));
}
} else if ident == "self_ty" {
if A::SELF_TY {
let _eq = Equals::parse(input)?;
let ty = syn::Type::parse(input)?;
if let Some(old) = options.self_ty.replace(ty) {
return Err(syn::Error::new(
old.span(),
"option `self_ty` provided twice",
));
}
} else {
return Err(syn::Error::new(
ident.span(),
"`self_ty` option not allowed here",
));
}
} else {
return Err(syn::Error::new(
ident.span(),
@ -433,3 +455,82 @@ impl<A: AllowedOptions> syn::parse::Parse for Options<A> {
Ok(options)
}
}
impl<A: AllowedOptions> quote::ToTokens for Options<A> {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let Self {
returns,
no_eq,
debug,
no_lifetime,
singleton,
specify,
non_update_return_type,
db_path,
cycle_fn,
cycle_initial,
cycle_result,
data,
lru,
constructor_name,
id,
revisions,
heap_size_fn,
self_ty,
phantom: _,
} = self;
if let Some(returns) = returns {
tokens.extend(quote::quote! { returns(#returns), });
};
if no_eq.is_some() {
tokens.extend(quote::quote! { no_eq, });
}
if debug.is_some() {
tokens.extend(quote::quote! { debug, });
}
if no_lifetime.is_some() {
tokens.extend(quote::quote! { no_lifetime, });
}
if singleton.is_some() {
tokens.extend(quote::quote! { singleton, });
}
if specify.is_some() {
tokens.extend(quote::quote! { specify, });
}
if non_update_return_type.is_some() {
tokens.extend(quote::quote! { unsafe(non_update_return_type), });
}
if let Some(db_path) = db_path {
tokens.extend(quote::quote! { db = #db_path, });
}
if let Some(cycle_fn) = cycle_fn {
tokens.extend(quote::quote! { cycle_fn = #cycle_fn, });
}
if let Some(cycle_initial) = cycle_initial {
tokens.extend(quote::quote! { cycle_initial = #cycle_initial, });
}
if let Some(cycle_result) = cycle_result {
tokens.extend(quote::quote! { cycle_result = #cycle_result, });
}
if let Some(data) = data {
tokens.extend(quote::quote! { data = #data, });
}
if let Some(lru) = lru {
tokens.extend(quote::quote! { lru = #lru, });
}
if let Some(constructor_name) = constructor_name {
tokens.extend(quote::quote! { constructor = #constructor_name, });
}
if let Some(id) = id {
tokens.extend(quote::quote! { id = #id, });
}
if let Some(revisions) = revisions {
tokens.extend(quote::quote! { revisions = #revisions, });
}
if let Some(heap_size_fn) = heap_size_fn {
tokens.extend(quote::quote! { heap_size_fn = #heap_size_fn, });
}
if let Some(self_ty) = self_ty {
tokens.extend(quote::quote! { self_ty = #self_ty, });
}
}
}

View file

@ -59,6 +59,8 @@ impl crate::options::AllowedOptions for TrackedFn {
const REVISIONS: bool = false;
const HEAP_SIZE: bool = true;
const SELF_TY: bool = true;
}
struct Macro {
@ -199,6 +201,10 @@ impl Macro {
} else {
quote! {}
};
let self_ty = match &self.args.self_ty {
Some(ty) => quote! { self_ty: #ty, },
None => quote! {},
};
Ok(crate::debug::dump_tokens(
fn_name,
@ -224,6 +230,7 @@ impl Macro {
lru: #lru,
return_mode: #return_mode,
assert_return_type_is_update: { #assert_return_type_is_update },
#self_ty
unused_names: [
#zalsa,
#Configuration,

View file

@ -69,7 +69,7 @@ impl Macro {
return Ok(());
};
let self_ty = &impl_item.self_ty;
let self_ty = &*impl_item.self_ty;
let Some(tracked_attr_index) = fn_item.attrs.iter().position(|a| self.is_tracked_attr(a))
else {
@ -83,11 +83,20 @@ impl Macro {
let mut change = ChangeSelfPath::new(self_ty, trait_);
change.visit_impl_item_fn_mut(fn_item);
let salsa_tracked_attr = fn_item.attrs.remove(tracked_attr_index);
let args: FnArgs = match &salsa_tracked_attr.meta {
let mut salsa_tracked_attr = fn_item.attrs.remove(tracked_attr_index);
let mut args: FnArgs = match &salsa_tracked_attr.meta {
syn::Meta::Path(..) => Default::default(),
_ => salsa_tracked_attr.parse_args()?,
};
if args.self_ty.is_none() {
// If the user did not specify a self_ty, we use the impl's self_ty
args.self_ty = Some(self_ty.clone());
}
salsa_tracked_attr.meta = syn::Meta::List(syn::MetaList {
path: salsa_tracked_attr.path().clone(),
delimiter: syn::MacroDelimiter::Paren(syn::token::Paren::default()),
tokens: quote! {#args},
});
let InnerTrait = self.hygiene.ident("InnerTrait");
let inner_fn_name = self.hygiene.ident(&fn_item.sig.ident.to_string());

View file

@ -62,6 +62,8 @@ impl crate::options::AllowedOptions for TrackedStruct {
const REVISIONS: bool = false;
const HEAP_SIZE: bool = false;
const SELF_TY: bool = false;
}
impl SalsaStructAllowedOptions for TrackedStruct {

View file

@ -80,6 +80,6 @@ fn debug_name() {
assert_eq!(output.field(&db), 88);
db.assert_logs(expect![[r#"
[
"salsa_event(WillExecute { database_key: tracked_trait_fn_(Id(0)) })",
"salsa_event(WillExecute { database_key: MyOutput < 'db >::tracked_trait_fn_(Id(0)) })",
]"#]]);
}

View file

@ -54,6 +54,6 @@ fn debug_name() {
assert_eq!(object.tracked_trait_fn(&db), 88);
db.assert_logs(expect![[r#"
[
"salsa_event(WillExecute { database_key: tracked_trait_fn_(Id(0)) })",
"salsa_event(WillExecute { database_key: MyInput::tracked_trait_fn_(Id(0)) })",
]"#]]);
}