Skip to content

Commit 7d417ac

Browse files
authored
Merge pull request #727 from Veykril/veykril/push-rqvpzyoqspzn
feature: add `#[salsa::supertype]`
2 parents 0177525 + 31c310f commit 7d417ac

28 files changed

+813
-189
lines changed

benches/compare.rs

+85
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,25 @@ pub struct InternedInput<'db> {
2525
pub text: String,
2626
}
2727

28+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)]
29+
enum SupertypeInput<'db> {
30+
InternedInput(InternedInput<'db>),
31+
Input(Input),
32+
}
33+
2834
#[salsa::tracked]
2935
pub fn interned_length<'db>(db: &'db dyn salsa::Database, input: InternedInput<'db>) -> usize {
3036
input.text(db).len()
3137
}
3238

39+
#[salsa::tracked]
40+
pub fn either_length<'db>(db: &'db dyn salsa::Database, input: SupertypeInput<'db>) -> usize {
41+
match input {
42+
SupertypeInput::InternedInput(input) => interned_length(db, input),
43+
SupertypeInput::Input(input) => length(db, input),
44+
}
45+
}
46+
3347
fn mutating_inputs(c: &mut Criterion) {
3448
let mut group: codspeed_criterion_compat::BenchmarkGroup<
3549
codspeed_criterion_compat::measurement::WallTime,
@@ -150,6 +164,77 @@ fn inputs(c: &mut Criterion) {
150164
)
151165
});
152166

167+
group.bench_function(BenchmarkId::new("new", "SupertypeInput"), |b| {
168+
b.iter_batched_ref(
169+
|| {
170+
let db = salsa::DatabaseImpl::default();
171+
172+
// Prepopulate ingredients.
173+
let input = SupertypeInput::Input(Input::new(
174+
black_box(&db),
175+
black_box("hello, world!".to_owned()),
176+
));
177+
let interned_input = SupertypeInput::InternedInput(InternedInput::new(
178+
black_box(&db),
179+
black_box("hello, world!".to_owned()),
180+
));
181+
let len = either_length(black_box(&db), black_box(input));
182+
assert_eq!(black_box(len), 13);
183+
let len = either_length(black_box(&db), black_box(interned_input));
184+
assert_eq!(black_box(len), 13);
185+
186+
db
187+
},
188+
|db| {
189+
let input = SupertypeInput::Input(Input::new(
190+
black_box(db),
191+
black_box("hello, world!".to_owned()),
192+
));
193+
let interned_input = SupertypeInput::InternedInput(InternedInput::new(
194+
black_box(db),
195+
black_box("hello, world!".to_owned()),
196+
));
197+
let len = either_length(black_box(db), black_box(input));
198+
assert_eq!(black_box(len), 13);
199+
let len = either_length(black_box(db), black_box(interned_input));
200+
assert_eq!(black_box(len), 13);
201+
},
202+
BatchSize::SmallInput,
203+
)
204+
});
205+
206+
group.bench_function(BenchmarkId::new("amortized", "SupertypeInput"), |b| {
207+
b.iter_batched_ref(
208+
|| {
209+
let db = salsa::DatabaseImpl::default();
210+
211+
let input = SupertypeInput::Input(Input::new(
212+
black_box(&db),
213+
black_box("hello, world!".to_owned()),
214+
));
215+
let interned_input = SupertypeInput::InternedInput(InternedInput::new(
216+
black_box(&db),
217+
black_box("hello, world!".to_owned()),
218+
));
219+
// we can't pass this along otherwise, and the lifetime is generally informational
220+
let interned_input: SupertypeInput<'static> = unsafe { transmute(interned_input) };
221+
let len = either_length(black_box(&db), black_box(input));
222+
assert_eq!(black_box(len), 13);
223+
let len = either_length(black_box(&db), black_box(interned_input));
224+
assert_eq!(black_box(len), 13);
225+
226+
(db, input, interned_input)
227+
},
228+
|&mut (ref db, input, interned_input)| {
229+
let len = either_length(black_box(db), black_box(input));
230+
assert_eq!(black_box(len), 13);
231+
let len = either_length(black_box(db), black_box(interned_input));
232+
assert_eq!(black_box(len), 13);
233+
},
234+
BatchSize::SmallInput,
235+
)
236+
});
237+
153238
group.finish();
154239
}
155240

components/salsa-macro-rules/src/setup_accumulator_impl.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ macro_rules! setup_accumulator_impl {
2424

2525
fn $ingredient(db: &dyn $zalsa::Database) -> &$zalsa_struct::IngredientImpl<$Struct> {
2626
$CACHE.get_or_create(db, || {
27-
db.zalsa().add_or_lookup_jar_by_type(&<$zalsa_struct::JarImpl<$Struct>>::default())
27+
db.zalsa()
28+
.add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Struct>>()
2829
})
2930
}
3031

components/salsa-macro-rules/src/setup_input_struct.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,14 @@ macro_rules! setup_input_struct {
8989
static CACHE: $zalsa::IngredientCache<$zalsa_struct::IngredientImpl<$Configuration>> =
9090
$zalsa::IngredientCache::new();
9191
CACHE.get_or_create(db, || {
92-
db.zalsa().add_or_lookup_jar_by_type(&<$zalsa_struct::JarImpl<$Configuration>>::default())
92+
db.zalsa().add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Configuration>>()
9393
})
9494
}
9595

9696
pub fn ingredient_mut(db: &mut dyn $zalsa::Database) -> (&mut $zalsa_struct::IngredientImpl<Self>, &mut $zalsa::Runtime) {
9797
let zalsa_mut = db.zalsa_mut();
9898
let current_revision = zalsa_mut.new_revision();
99-
let index = zalsa_mut.add_or_lookup_jar_by_type(&<$zalsa_struct::JarImpl<$Configuration>>::default());
99+
let index = zalsa_mut.add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Configuration>>();
100100
let (ingredient, runtime) = zalsa_mut.lookup_ingredient_mut(index);
101101
let ingredient = ingredient.assert_type_mut::<$zalsa_struct::IngredientImpl<Self>>();
102102
(ingredient, runtime)
@@ -135,8 +135,19 @@ macro_rules! setup_input_struct {
135135
}
136136

137137
impl $zalsa::SalsaStructInDb for $Struct {
138-
fn lookup_ingredient_index(aux: &dyn $zalsa::JarAux) -> core::option::Option<$zalsa::IngredientIndex> {
139-
aux.lookup_jar_by_type(&<$zalsa_struct::JarImpl<$Configuration>>::default())
138+
type MemoIngredientMap = $zalsa::MemoIngredientSingletonIndex;
139+
140+
fn lookup_or_create_ingredient_index(aux: &$zalsa::Zalsa) -> $zalsa::IngredientIndices {
141+
aux.add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Configuration>>().into()
142+
}
143+
144+
#[inline]
145+
fn cast(id: $zalsa::Id, type_id: $zalsa::TypeId) -> $zalsa::Option<Self> {
146+
if type_id == $zalsa::TypeId::of::<$Struct>() {
147+
$zalsa::Some($Struct(id))
148+
} else {
149+
$zalsa::None
150+
}
140151
}
141152
}
142153

@@ -198,7 +209,7 @@ macro_rules! setup_input_struct {
198209
// FIXME(rust-lang/rust#65991): The `db` argument *should* have the type `dyn Database`
199210
$Db: ?Sized + salsa::Database,
200211
{
201-
$Configuration::ingredient(db.as_dyn_database()).get_singleton_input()
212+
$Configuration::ingredient(db.as_dyn_database()).get_singleton_input(db)
202213
}
203214

204215
#[track_caller]

components/salsa-macro-rules/src/setup_interned_struct.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ macro_rules! setup_interned_struct {
141141
static CACHE: $zalsa::IngredientCache<$zalsa_struct::IngredientImpl<$Configuration>> =
142142
$zalsa::IngredientCache::new();
143143
CACHE.get_or_create(db.as_dyn_database(), || {
144-
db.zalsa().add_or_lookup_jar_by_type(&<$zalsa_struct::JarImpl<$Configuration>>::default())
144+
db.zalsa().add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Configuration>>()
145145
})
146146
}
147147
}
@@ -171,8 +171,19 @@ macro_rules! setup_interned_struct {
171171
}
172172

173173
impl< $($db_lt_arg)? > $zalsa::SalsaStructInDb for $Struct< $($db_lt_arg)? > {
174-
fn lookup_ingredient_index(aux: &dyn $zalsa::JarAux) -> core::option::Option<$zalsa::IngredientIndex> {
175-
aux.lookup_jar_by_type(&<$zalsa_struct::JarImpl<$Configuration>>::default())
174+
type MemoIngredientMap = $zalsa::MemoIngredientSingletonIndex;
175+
176+
fn lookup_or_create_ingredient_index(aux: &$zalsa::Zalsa) -> $zalsa::IngredientIndices {
177+
aux.add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Configuration>>().into()
178+
}
179+
180+
#[inline]
181+
fn cast(id: $zalsa::Id, type_id: $zalsa::TypeId) -> $zalsa::Option<Self> {
182+
if type_id == $zalsa::TypeId::of::<$Struct>() {
183+
$zalsa::Some(<$Struct as $zalsa::FromId>::from_id(id))
184+
} else {
185+
$zalsa::None
186+
}
176187
}
177188
}
178189

components/salsa-macro-rules/src/setup_tracked_fn.rs

+39-18
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,19 @@ macro_rules! setup_tracked_fn {
101101
$zalsa::IngredientCache::new();
102102

103103
impl $zalsa::SalsaStructInDb for $InternedData<'_> {
104-
fn lookup_ingredient_index(_aux: &dyn $zalsa::JarAux) -> core::option::Option<$zalsa::IngredientIndex> {
105-
None
104+
type MemoIngredientMap = $zalsa::MemoIngredientSingletonIndex;
105+
106+
fn lookup_or_create_ingredient_index(aux: &$zalsa::Zalsa) -> $zalsa::IngredientIndices {
107+
$zalsa::IngredientIndices::empty()
108+
}
109+
110+
#[inline]
111+
fn cast(id: $zalsa::Id, type_id: ::core::any::TypeId) -> Option<Self> {
112+
if type_id == ::core::any::TypeId::of::<$InternedData>() {
113+
Some($InternedData(id, ::core::marker::PhantomData))
114+
} else {
115+
None
116+
}
106117
}
107118
}
108119

@@ -132,13 +143,13 @@ macro_rules! setup_tracked_fn {
132143
fn fn_ingredient(db: &dyn $Db) -> &$zalsa::function::IngredientImpl<$Configuration> {
133144
$FN_CACHE.get_or_create(db.as_dyn_database(), || {
134145
<dyn $Db as $Db>::zalsa_db(db);
135-
db.zalsa().add_or_lookup_jar_by_type(&$Configuration)
146+
db.zalsa().add_or_lookup_jar_by_type::<$Configuration>()
136147
})
137148
}
138149

139150
pub fn fn_ingredient_mut(db: &mut dyn $Db) -> &mut $zalsa::function::IngredientImpl<Self> {
140151
let zalsa_mut = db.zalsa_mut();
141-
let index = zalsa_mut.add_or_lookup_jar_by_type(&$Configuration);
152+
let index = zalsa_mut.add_or_lookup_jar_by_type::<$Configuration>();
142153
let (ingredient, _) = zalsa_mut.lookup_ingredient_mut(index);
143154
ingredient.assert_type_mut::<$zalsa::function::IngredientImpl<Self>>()
144155
}
@@ -148,7 +159,7 @@ macro_rules! setup_tracked_fn {
148159
db: &dyn $Db,
149160
) -> &$zalsa::interned::IngredientImpl<$Configuration> {
150161
$INTERN_CACHE.get_or_create(db.as_dyn_database(), || {
151-
db.zalsa().add_or_lookup_jar_by_type(&$Configuration).successor(0)
162+
db.zalsa().add_or_lookup_jar_by_type::<$Configuration>().successor(0)
152163
})
153164
}
154165
}
@@ -201,33 +212,43 @@ macro_rules! setup_tracked_fn {
201212
if $needs_interner {
202213
$Configuration::intern_ingredient(db).data(db.as_dyn_database(), key).clone()
203214
} else {
204-
$zalsa::FromId::from_id(key)
215+
$zalsa::FromIdWithDb::from_id(key, db)
205216
}
206217
}
207218
}
208219
}
209220

210221
impl $zalsa::Jar for $Configuration {
222+
fn create_dependencies(zalsa: &$zalsa::Zalsa) -> $zalsa::IngredientIndices
223+
where
224+
Self: Sized
225+
{
226+
$zalsa::macro_if! {
227+
if $needs_interner {
228+
$zalsa::IngredientIndices::empty()
229+
} else {
230+
<$InternedData as $zalsa::SalsaStructInDb>::lookup_or_create_ingredient_index(zalsa)
231+
}
232+
}
233+
}
234+
211235
fn create_ingredients(
212-
&self,
213-
aux: &dyn $zalsa::JarAux,
236+
zalsa: &$zalsa::Zalsa,
214237
first_index: $zalsa::IngredientIndex,
238+
struct_index: $zalsa::IngredientIndices,
215239
) -> Vec<Box<dyn $zalsa::Ingredient>> {
216-
let struct_index = $zalsa::macro_if! {
240+
let struct_index: $zalsa::IngredientIndices = $zalsa::macro_if! {
217241
if $needs_interner {
218-
first_index.successor(0)
242+
first_index.successor(0).into()
219243
} else {
220-
<$InternedData as $zalsa::SalsaStructInDb>::lookup_ingredient_index(aux)
221-
.expect(
222-
"Salsa struct is passed as an argument of a tracked function, but its ingredient hasn't been added!"
223-
)
244+
struct_index
224245
}
225246
};
247+
let memo_ingredient_indices = From::from((zalsa, struct_index, first_index));
226248

227249
let fn_ingredient = <$zalsa::function::IngredientImpl<$Configuration>>::new(
228-
struct_index,
229250
first_index,
230-
aux,
251+
memo_ingredient_indices,
231252
$lru
232253
);
233254
$zalsa::macro_if! {
@@ -246,8 +267,8 @@ macro_rules! setup_tracked_fn {
246267
}
247268
}
248269

249-
fn salsa_struct_type_id(&self) -> Option<core::any::TypeId> {
250-
None
270+
fn id_struct_type_id() -> $zalsa::TypeId {
271+
$zalsa::TypeId::of::<$InternedData<'static>>()
251272
}
252273
}
253274

components/salsa-macro-rules/src/setup_tracked_struct.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ macro_rules! setup_tracked_struct {
180180
$zalsa::IngredientCache::new();
181181

182182
CACHE.get_or_create(db, || {
183-
db.zalsa().add_or_lookup_jar_by_type(&<$zalsa_struct::JarImpl::<$Configuration>>::default())
183+
db.zalsa().add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Configuration>>()
184184
})
185185
}
186186
}
@@ -198,8 +198,19 @@ macro_rules! setup_tracked_struct {
198198
}
199199

200200
impl $zalsa::SalsaStructInDb for $Struct<'_> {
201-
fn lookup_ingredient_index(aux: &dyn $zalsa::JarAux) -> core::option::Option<$zalsa::IngredientIndex> {
202-
aux.lookup_jar_by_type(&<$zalsa_struct::JarImpl<$Configuration>>::default())
201+
type MemoIngredientMap = $zalsa::MemoIngredientSingletonIndex;
202+
203+
fn lookup_or_create_ingredient_index(aux: &$zalsa::Zalsa) -> $zalsa::IngredientIndices {
204+
aux.add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Configuration>>().into()
205+
}
206+
207+
#[inline]
208+
fn cast(id: $zalsa::Id, type_id: $zalsa::TypeId) -> $zalsa::Option<Self> {
209+
if type_id == $zalsa::TypeId::of::<$Struct>() {
210+
$zalsa::Some(<$Struct as $zalsa::FromId>::from_id(id))
211+
} else {
212+
$zalsa::None
213+
}
203214
}
204215
}
205216

components/salsa-macros/src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ mod input;
4444
mod interned;
4545
mod options;
4646
mod salsa_struct;
47+
mod supertype;
4748
mod tracked;
4849
mod tracked_fn;
4950
mod tracked_impl;
@@ -66,6 +67,11 @@ pub fn interned(args: TokenStream, input: TokenStream) -> TokenStream {
6667
interned::interned(args, input)
6768
}
6869

70+
#[proc_macro_derive(Supertype)]
71+
pub fn supertype(input: TokenStream) -> TokenStream {
72+
supertype::supertype(input)
73+
}
74+
6975
#[proc_macro_attribute]
7076
pub fn input(args: TokenStream, input: TokenStream) -> TokenStream {
7177
input::input(args, input)

0 commit comments

Comments
 (0)