Skip to content

Commit 5abc9af

Browse files
committed
Remove crate from salsa EditionedFileId
1 parent 99fa130 commit 5abc9af

37 files changed

Lines changed: 130 additions & 402 deletions

File tree

Lines changed: 21 additions & 292 deletions
Original file line numberDiff line numberDiff line change
@@ -1,317 +1,46 @@
11
//! Defines [`EditionedFileId`], an interned wrapper around [`span::EditionedFileId`] that
22
//! is interned (so queries can take it) and remembers its crate.
33
4-
use core::fmt;
5-
use std::hash::{Hash, Hasher};
4+
use std::hash::Hash;
65

6+
use salsa::Database;
77
use span::Edition;
88
use vfs::FileId;
99

10-
use crate::{Crate, RootQueryDb};
11-
12-
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
13-
pub struct EditionedFileId(
14-
salsa::Id,
15-
std::marker::PhantomData<&'static salsa::plumbing::interned::Value<EditionedFileId>>,
16-
);
17-
18-
const _: () = {
19-
use salsa::plumbing as zalsa_;
20-
use zalsa_::interned as zalsa_struct_;
21-
type Configuration_ = EditionedFileId;
22-
23-
#[derive(Debug, Clone, Eq)]
24-
pub struct EditionedFileIdData {
25-
editioned_file_id: span::EditionedFileId,
26-
krate: Crate,
27-
}
28-
29-
// FIXME: This poses an invalidation problem, if one constructs an `EditionedFileId` with a
30-
// different crate then whatever the input of a memo used, it will invalidate the memo causing
31-
// it to recompute even if the crate is not really used.
32-
/// We like to include the origin crate in an `EditionedFileId` (for use in the item tree),
33-
/// but this poses us a problem.
34-
///
35-
/// Spans contain `EditionedFileId`s, and we don't want to make them store the crate too
36-
/// because that will increase their size, which will increase memory usage significantly.
37-
/// Furthermore, things using spans do not generally need the crate: they are using the
38-
/// file id for queries like `ast_id_map` or `parse`, which do not care about the crate.
39-
///
40-
/// To solve this, we hash **only the `span::EditionedFileId`**, but on still compare
41-
/// the crate in equality check. This preserves the invariant of `Hash` and `Eq` -
42-
/// although same hashes can be used for different items, same file ids used for multiple
43-
/// crates is a rare thing, and different items always have different hashes. Then,
44-
/// when we only have a `span::EditionedFileId`, we use the `intern()` method to
45-
/// reuse existing file ids, and create new one only if needed. See [`from_span_guess_origin`].
46-
///
47-
/// See this for more info: https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/Letting.20EditionedFileId.20know.20its.20crate/near/530189401
48-
///
49-
/// [`from_span_guess_origin`]: EditionedFileId::from_span_guess_origin
50-
#[derive(Hash, PartialEq, Eq)]
51-
struct WithoutCrate {
52-
editioned_file_id: span::EditionedFileId,
53-
}
54-
55-
impl PartialEq for EditionedFileIdData {
56-
fn eq(&self, other: &Self) -> bool {
57-
let Self { editioned_file_id, krate: _ } = self;
58-
let Self { editioned_file_id: other_editioned_file_id, krate: _ } = other;
59-
editioned_file_id == other_editioned_file_id
60-
}
61-
}
62-
63-
impl Hash for EditionedFileIdData {
64-
#[inline]
65-
fn hash<H: Hasher>(&self, state: &mut H) {
66-
let EditionedFileIdData { editioned_file_id, krate: _ } = *self;
67-
editioned_file_id.hash(state);
68-
}
69-
}
70-
71-
impl zalsa_struct_::HashEqLike<WithoutCrate> for EditionedFileIdData {
72-
#[inline]
73-
fn hash<H: Hasher>(&self, state: &mut H) {
74-
Hash::hash(self, state);
75-
}
76-
77-
#[inline]
78-
fn eq(&self, data: &WithoutCrate) -> bool {
79-
let EditionedFileIdData { editioned_file_id, krate: _ } = *self;
80-
editioned_file_id == data.editioned_file_id
81-
}
82-
}
83-
84-
impl zalsa_::HasJar for EditionedFileId {
85-
type Jar = zalsa_struct_::JarImpl<EditionedFileId>;
86-
const KIND: zalsa_::JarKind = zalsa_::JarKind::Struct;
87-
}
88-
89-
zalsa_::register_jar! {
90-
zalsa_::ErasedJar::erase::<EditionedFileId>()
91-
}
92-
93-
impl zalsa_struct_::Configuration for EditionedFileId {
94-
const LOCATION: salsa::plumbing::Location =
95-
salsa::plumbing::Location { file: file!(), line: line!() };
96-
const DEBUG_NAME: &'static str = "EditionedFileId";
97-
const REVISIONS: std::num::NonZeroUsize = std::num::NonZeroUsize::MAX;
98-
const PERSIST: bool = false;
99-
100-
type Fields<'a> = EditionedFileIdData;
101-
type Struct<'db> = EditionedFileId;
102-
103-
fn serialize<S>(_: &Self::Fields<'_>, _: S) -> Result<S::Ok, S::Error>
104-
where
105-
S: zalsa_::serde::Serializer,
106-
{
107-
unimplemented!("attempted to serialize value that set `PERSIST` to false")
108-
}
109-
110-
fn deserialize<'de, D>(_: D) -> Result<Self::Fields<'static>, D::Error>
111-
where
112-
D: zalsa_::serde::Deserializer<'de>,
113-
{
114-
unimplemented!("attempted to deserialize value that cannot set `PERSIST` to false");
115-
}
116-
}
117-
118-
impl Configuration_ {
119-
pub fn ingredient(zalsa: &zalsa_::Zalsa) -> &zalsa_struct_::IngredientImpl<Self> {
120-
static CACHE: zalsa_::IngredientCache<zalsa_struct_::IngredientImpl<EditionedFileId>> =
121-
zalsa_::IngredientCache::new();
122-
123-
// SAFETY: `lookup_jar_by_type` returns a valid ingredient index, and the only
124-
// ingredient created by our jar is the struct ingredient.
125-
unsafe {
126-
CACHE.get_or_create(zalsa, || {
127-
zalsa.lookup_jar_by_type::<zalsa_struct_::JarImpl<EditionedFileId>>()
128-
})
129-
}
130-
}
131-
}
132-
133-
impl zalsa_::AsId for EditionedFileId {
134-
fn as_id(&self) -> salsa::Id {
135-
self.0.as_id()
136-
}
137-
}
138-
impl zalsa_::FromId for EditionedFileId {
139-
fn from_id(id: salsa::Id) -> Self {
140-
Self(<salsa::Id>::from_id(id), std::marker::PhantomData)
141-
}
142-
}
143-
144-
unsafe impl Send for EditionedFileId {}
145-
unsafe impl Sync for EditionedFileId {}
146-
147-
impl std::fmt::Debug for EditionedFileId {
148-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149-
Self::default_debug_fmt(*self, f)
150-
}
151-
}
152-
153-
impl zalsa_::SalsaStructInDb for EditionedFileId {
154-
type MemoIngredientMap = salsa::plumbing::MemoIngredientSingletonIndex;
155-
156-
fn lookup_ingredient_index(aux: &zalsa_::Zalsa) -> salsa::plumbing::IngredientIndices {
157-
aux.lookup_jar_by_type::<zalsa_struct_::JarImpl<EditionedFileId>>().into()
158-
}
159-
160-
fn entries(zalsa: &zalsa_::Zalsa) -> impl Iterator<Item = zalsa_::DatabaseKeyIndex> + '_ {
161-
let _ingredient_index =
162-
zalsa.lookup_jar_by_type::<zalsa_struct_::JarImpl<EditionedFileId>>();
163-
<EditionedFileId>::ingredient(zalsa).entries(zalsa).map(|entry| entry.key())
164-
}
165-
166-
#[inline]
167-
fn cast(id: salsa::Id, type_id: std::any::TypeId) -> Option<Self> {
168-
if type_id == std::any::TypeId::of::<EditionedFileId>() {
169-
Some(<Self as salsa::plumbing::FromId>::from_id(id))
170-
} else {
171-
None
172-
}
173-
}
174-
175-
#[inline]
176-
unsafe fn memo_table(
177-
zalsa: &zalsa_::Zalsa,
178-
id: zalsa_::Id,
179-
current_revision: zalsa_::Revision,
180-
) -> zalsa_::MemoTableWithTypes<'_> {
181-
// SAFETY: Guaranteed by caller.
182-
unsafe {
183-
zalsa.table().memos::<zalsa_struct_::Value<EditionedFileId>>(id, current_revision)
184-
}
185-
}
186-
}
187-
188-
unsafe impl zalsa_::Update for EditionedFileId {
189-
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
190-
if unsafe { *old_pointer } != new_value {
191-
unsafe { *old_pointer = new_value };
192-
true
193-
} else {
194-
false
195-
}
196-
}
197-
}
198-
199-
impl EditionedFileId {
200-
pub fn from_span(
201-
db: &(impl salsa::Database + ?Sized),
202-
editioned_file_id: span::EditionedFileId,
203-
krate: Crate,
204-
) -> Self {
205-
let (zalsa, zalsa_local) = db.zalsas();
206-
Configuration_::ingredient(zalsa).intern(
207-
zalsa,
208-
zalsa_local,
209-
EditionedFileIdData { editioned_file_id, krate },
210-
|_, data| data,
211-
)
212-
}
213-
214-
/// Guesses the crate for the file.
215-
///
216-
/// Only use this if you cannot precisely determine the origin. This can happen in one of two cases:
217-
///
218-
/// 1. The file is not in the module tree.
219-
/// 2. You are latency sensitive and cannot afford calling the def map to precisely compute the origin
220-
/// (e.g. on enter feature, folding, etc.).
221-
// FIXME: Remove this and all the weird crate ignoring plumbing around this
222-
// This can cause a variety of weird bugs https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/Broken.20token.20mapping/with/577739887
223-
pub fn from_span_guess_origin(
224-
db: &dyn RootQueryDb,
225-
editioned_file_id: span::EditionedFileId,
226-
) -> Self {
227-
let (zalsa, zalsa_local) = db.zalsas();
228-
Configuration_::ingredient(zalsa).intern(
229-
zalsa,
230-
zalsa_local,
231-
WithoutCrate { editioned_file_id },
232-
|_, _| {
233-
// FileId not in the database.
234-
let krate = db
235-
.relevant_crates(editioned_file_id.file_id())
236-
.first()
237-
.copied()
238-
.or_else(|| db.all_crates().first().copied())
239-
.unwrap_or_else(|| {
240-
// What we're doing here is a bit fishy. We rely on the fact that we only need
241-
// the crate in the item tree, and we should not create an `EditionedFileId`
242-
// without a crate except in cases where it does not matter. The chances that
243-
// `all_crates()` will be empty are also very slim, but it can occur during startup.
244-
// In the very unlikely case that there is a bug and we'll use this crate, Salsa
245-
// will panic.
246-
247-
// SAFETY: 0 is less than `Id::MAX_U32`.
248-
salsa::plumbing::FromId::from_id(unsafe { salsa::Id::from_index(0) })
249-
});
250-
EditionedFileIdData { editioned_file_id, krate }
251-
},
252-
)
253-
}
254-
255-
pub fn editioned_file_id(self, db: &dyn salsa::Database) -> span::EditionedFileId {
256-
let zalsa = db.zalsa();
257-
let fields = Configuration_::ingredient(zalsa).fields(zalsa, self);
258-
fields.editioned_file_id
259-
}
260-
261-
pub fn krate(self, db: &dyn salsa::Database) -> Crate {
262-
let zalsa = db.zalsa();
263-
let fields = Configuration_::ingredient(zalsa).fields(zalsa, self);
264-
fields.krate
265-
}
10+
#[salsa::interned(debug, constructor = from_span_file_id, no_lifetime)]
11+
#[derive(PartialOrd, Ord)]
12+
pub struct EditionedFileId {
13+
field: span::EditionedFileId,
14+
}
26615

267-
/// Default debug formatting for this struct (may be useful if you define your own `Debug` impl)
268-
pub fn default_debug_fmt(this: Self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269-
zalsa_::with_attached_database(|db| {
270-
let zalsa = db.zalsa();
271-
let fields = Configuration_::ingredient(zalsa).fields(zalsa, this);
272-
fmt::Debug::fmt(fields, f)
273-
})
274-
.unwrap_or_else(|| {
275-
f.debug_tuple("EditionedFileId").field(&zalsa_::AsId::as_id(&this)).finish()
276-
})
277-
}
16+
impl EditionedFileId {
17+
#[inline]
18+
pub fn new(db: &dyn Database, file_id: FileId, edition: Edition) -> Self {
19+
Self::from_span_file_id(db, span::EditionedFileId::new(file_id, edition))
27820
}
279-
};
28021

281-
impl EditionedFileId {
28222
#[inline]
283-
pub fn new(db: &dyn salsa::Database, file_id: FileId, edition: Edition, krate: Crate) -> Self {
284-
EditionedFileId::from_span(db, span::EditionedFileId::new(file_id, edition), krate)
23+
pub fn current_edition(db: &dyn Database, file_id: FileId) -> Self {
24+
Self::from_span_file_id(db, span::EditionedFileId::current_edition(file_id))
28525
}
28626

287-
/// Attaches the current edition and guesses the crate for the file.
288-
///
289-
/// Only use this if you cannot precisely determine the origin. This can happen in one of two cases:
290-
///
291-
/// 1. The file is not in the module tree.
292-
/// 2. You are latency sensitive and cannot afford calling the def map to precisely compute the origin
293-
/// (e.g. on enter feature, folding, etc.).
294-
// FIXME: Remove this and all the weird crate ignoring plumbing around this
295-
// This can cause a variety of weird bugs https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/Broken.20token.20mapping/with/577739887
29627
#[inline]
297-
pub fn current_edition_guess_origin(db: &dyn RootQueryDb, file_id: FileId) -> Self {
298-
Self::from_span_guess_origin(db, span::EditionedFileId::current_edition(file_id))
28+
pub fn file_id(self, db: &dyn Database) -> vfs::FileId {
29+
self.field(db).file_id()
29930
}
30031

30132
#[inline]
302-
pub fn file_id(self, db: &dyn salsa::Database) -> vfs::FileId {
303-
let id = self.editioned_file_id(db);
304-
id.file_id()
33+
pub fn span_file_id(self, db: &dyn Database) -> span::EditionedFileId {
34+
self.field(db)
30535
}
30636

30737
#[inline]
308-
pub fn unpack(self, db: &dyn salsa::Database) -> (vfs::FileId, span::Edition) {
309-
let id = self.editioned_file_id(db);
310-
(id.file_id(), id.edition())
38+
pub fn unpack(self, db: &dyn Database) -> (vfs::FileId, span::Edition) {
39+
self.field(db).unpack()
31140
}
31241

31342
#[inline]
314-
pub fn edition(self, db: &dyn salsa::Database) -> Edition {
315-
self.editioned_file_id(db).edition()
43+
pub fn edition(self, db: &dyn Database) -> Edition {
44+
self.field(db).edition()
31645
}
31746
}

crates/base-db/src/input.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,7 @@ impl CrateGraphBuilder {
870870
impl Crate {
871871
pub fn root_file_id(self, db: &dyn salsa::Database) -> EditionedFileId {
872872
let data = self.data(db);
873-
EditionedFileId::new(db, data.root_file_id, data.edition, self)
873+
EditionedFileId::new(db, data.root_file_id, data.edition)
874874
}
875875
}
876876

crates/hir-def/src/db.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
9696
/// Computes an [`ItemTree`] for the given file or macro expansion.
9797
#[salsa::invoke(file_item_tree_query)]
9898
#[salsa::transparent]
99-
fn file_item_tree(&self, file_id: HirFileId) -> &ItemTree;
99+
fn file_item_tree(&self, file_id: HirFileId, krate: Crate) -> &ItemTree;
100100

101101
/// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
102102
#[salsa::invoke(macro_def)]

crates/hir-def/src/expr_store/tests/body/block.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ fn f() {
196196
),
197197
block: Some(
198198
BlockId(
199-
4401,
199+
4801,
200200
),
201201
),
202202
}"#]],

0 commit comments

Comments
 (0)