wip: iterate towards hello_world
Some checks failed
Book / Book (push) Has been cancelled
Test / Test (false, beta) (push) Has been cancelled
Test / Test (false, stable) (push) Has been cancelled
Test / Test (true, nightly) (push) Has been cancelled
Test / Miri (push) Has been cancelled
Book / Deploy (push) Has been cancelled

This commit is contained in:
Niko Matsakis 2024-07-14 13:49:59 -04:00
parent 231dc4f713
commit 57eb0c45b4
9 changed files with 162 additions and 19 deletions

View file

@ -16,6 +16,7 @@ mod maybe_backdate;
mod maybe_clone;
mod setup_input;
mod setup_interned_fn;
mod setup_struct_fn;
mod setup_tracked_struct;
mod unexpected_cycle_recovery;

View file

@ -0,0 +1,123 @@
/// Macro for setting up a function that must intern its arguments.
#[macro_export]
macro_rules! setup_struct_fn {
(
// Attributes on the function
attrs: [$(#[$attr:meta]),*],
// Visibility of the function
vis: $vis:vis,
// Name of the function
fn_name: $fn_name:ident,
// Name of the `'db` lifetime that the user gave; if they didn't, then defaults to `'db`
db_lt: $db_lt:lifetime,
// Path to the database trait that the user's database parameter used
Db: $Db:path,
// Name of the database parameter given by the user.
db: $db:ident,
// An identifier for each function argument EXCEPT the database.
// We prefer to use the identifier the user gave, but if the user gave a pattern
// (e.g., `(a, b): (u32, u32)`) we will synthesize an identifier.
input_id: $input_id:ident,
// Types of the function arguments (may reference `$generics`).
input_ty: $input_ty:ty,
// Return type of the function (may reference `$generics`).
output_ty: $output_ty:ty,
// Function body, may reference identifiers defined in `$input_pats` and the generics from `$generics`
inner_fn: $inner_fn:item,
// Path to the cycle recovery function to use.
cycle_recovery_fn: ($($cycle_recovery_fn:tt)*),
// Name of cycle recovery strategy variant to use.
cycle_recovery_strategy: $cycle_recovery_strategy:ident,
// 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.
unused_names: [
$zalsa:ident,
$Configuration:ident,
$FN_CACHE:ident,
$inner:ident,
]
) => {
$(#[$attr])*
$vis fn $fn_name<$db_lt>(
$db: &$db_lt dyn $Db,
$input_id: $input_ty,
) -> $output_ty {
use salsa::plumbing as $zalsa;
struct $Configuration;
static $FN_CACHE: $zalsa::IngredientCache<$zalsa::function::IngredientImpl<$Configuration>> =
$zalsa::IngredientCache::new();
impl $zalsa::function::Configuration for $Configuration {
const DEBUG_NAME: &'static str = stringify!($fn_name);
type DbView = dyn $Db;
type SalsaStruct<$db_lt> = $input_ty;
type Input<$db_lt> = $input_ty;
type Output<$db_lt> = $output_ty;
const CYCLE_STRATEGY: $zalsa::CycleRecoveryStrategy = $zalsa::CycleRecoveryStrategy::$cycle_recovery_strategy;
fn should_backdate_value(
old_value: &Self::Output<'_>,
new_value: &Self::Output<'_>,
) -> bool {
old_value == new_value
}
fn execute<'db>($db: &'db Self::DbView, $input_id: $input_ty) -> Self::Output<'db> {
$inner_fn
$inner($db, $input_id)
}
fn recover_from_cycle<'db>(
db: &$db_lt dyn $Db,
cycle: &$zalsa::Cycle,
$input_id: $input_ty,
) -> Self::Output<'db> {
$($cycle_recovery_fn)*(db, cycle, $input_id)
}
fn id_to_input<'db>(db: &'db Self::DbView, key: salsa::Id) -> Self::Input<'db> {
$zalsa::LookupId::lookup_id(key, db)
}
}
impl $zalsa::Jar for $Configuration {
fn create_ingredients(
&self,
first_index: $zalsa::IngredientIndex,
) -> Vec<Box<dyn $zalsa::Ingredient>> {
vec![
Box::new(<$zalsa::function::IngredientImpl<$Configuration>>::new(
first_index,
)),
]
}
}
let fn_ingredient = $FN_CACHE.get_or_create($db.as_salsa_database(), || {
$db.add_or_lookup_jar_by_type(&$Configuration)
});
fn_ingredient.fetch($db, $input_id).clone()
}
};
}

View file

@ -129,11 +129,8 @@ macro_rules! setup_tracked_struct {
}
}
impl<$db_lt, $Db> $zalsa::LookupId<&$db_lt $Db> for $Struct<$db_lt>
where
$Db: ?Sized + $zalsa::Database,
{
fn lookup_id(id: salsa::Id, db: & $db_lt $Db) -> Self {
impl<'db> $zalsa::LookupId<'db> for $Struct<$db_lt> {
fn lookup_id(id: salsa::Id, db: &'db dyn Database) -> Self {
$Configuration::ingredient(db).lookup_struct(db.runtime(), id)
}
}

View file

@ -106,7 +106,29 @@ impl Macro {
}],
)),
FunctionType::Constant => todo!(),
FunctionType::SalsaStruct => todo!(),
FunctionType::SalsaStruct => Ok(crate::debug::dump_tokens(
fn_name,
quote![salsa::plumbing::setup_struct_fn! {
attrs: [#(#attrs),*],
vis: #vis,
fn_name: #fn_name,
db_lt: #db_lt,
Db: #db_path,
db: #db_ident,
input_id: #(#input_ids,)*
input_ty: #(#input_tys,)*
output_ty: #output_ty,
inner_fn: #inner_fn,
cycle_recovery_fn: #cycle_recovery_fn,
cycle_recovery_strategy: #cycle_recovery_strategy,
unused_names: [
#zalsa,
#Configuration,
#FN_CACHE,
#inner,
]
}],
)),
}
}

View file

@ -339,9 +339,7 @@ impl TrackedStruct {
let jar_ty = self.jar_ty();
let tracked_struct_ingredient = self.tracked_struct_ingredient_index();
parse_quote_spanned! { ident.span() =>
impl<#db, #parameters> salsa::id::LookupId<& #db_lt #db> for #ident #type_generics
where
#db: ?Sized + salsa::DbWithJar<#jar_ty>,
impl<#db, #parameters> salsa::id::LookupId<#db_lt> for #ident #type_generics
#where_clause
{
fn lookup_id(id: salsa::Id, db: & #db_lt DB) -> Self {

View file

@ -2,6 +2,8 @@ use std::fmt::Debug;
use std::hash::Hash;
use std::num::NonZeroU32;
use crate::Database;
/// An Id is a newtype'd u32 ranging from `0..Id::MAX_U32`.
/// The maximum range is smaller than a standard u32 to leave
/// room for niches; currently there is only one niche, so that
@ -74,7 +76,7 @@ pub trait AsId: Sized {
/// up in the database to find it. This is different from
/// [`AsId`][] where what we have is literally a *newtype*
/// for an `Id`.
pub trait LookupId<DB>: AsId {
pub trait LookupId<'db>: AsId {
/// Lookup from an `Id` to get an instance of the type.
///
/// # Panics
@ -86,7 +88,7 @@ pub trait LookupId<DB>: AsId {
/// dependency tracking typically ensures this does not
/// occur, but it is possible for a user to violate this
/// rule.
fn lookup_id(id: Id, db: DB) -> Self;
fn lookup_id(id: Id, db: &'db dyn Database) -> Self;
}
/// Internal Salsa trait for types that are just a newtype'd [`Id`][].
@ -124,11 +126,8 @@ impl FromId for () {
}
}
impl<DB, ID> LookupId<DB> for ID
where
ID: FromId,
{
fn lookup_id(id: Id, _db: DB) -> Self {
impl<'db, ID: FromId> LookupId<'db> for ID {
fn lookup_id(id: Id, _db: &'db dyn Database) -> Self {
Self::from_id(id)
}
}

View file

@ -288,10 +288,9 @@ where
id.as_id()
}
pub fn data_with_db<'db, DB>(&'db self, id: crate::Id, db: &'db DB) -> C::Data<'db>
pub fn data_with_db<'db>(&'db self, id: crate::Id, db: &'db dyn Database) -> C::Data<'db>
where
DB: ?Sized,
C::Data<'db>: LookupId<&'db DB>,
C::Data<'db>: LookupId<'db>,
{
<C::Data<'db>>::lookup_id(id, db)
}

View file

@ -60,6 +60,7 @@ pub mod plumbing {
pub use crate::id::AsId;
pub use crate::id::FromId;
pub use crate::id::Id;
pub use crate::id::LookupId;
pub use crate::ingredient::Ingredient;
pub use crate::ingredient::Jar;
pub use crate::revision::Revision;
@ -79,6 +80,7 @@ pub mod plumbing {
pub use salsa_macro_rules::maybe_cloned_ty;
pub use salsa_macro_rules::setup_input;
pub use salsa_macro_rules::setup_interned_fn;
pub use salsa_macro_rules::setup_struct_fn;
pub use salsa_macro_rules::setup_tracked_struct;
pub use salsa_macro_rules::unexpected_cycle_recovery;

View file

@ -62,8 +62,10 @@ struct Database {
logger: Logger,
}
#[salsa::db]
impl salsa::Database for Database {}
#[salsa::db]
impl Db for Database {}
impl HasLogger for Database {