Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
d36e3be
Use root hygiene for speculative resolution
ChayimFriedman2 Jul 9, 2025
7bc7abd
Include a per-token edition in the parser input
ChayimFriedman2 Jul 3, 2025
3b610a6
Use per-token edition in the parser
ChayimFriedman2 Jul 3, 2025
074b931
Fix syntax_editor duplicated changed element
A4-Tacks Nov 11, 2025
59fca5a
Fix syntax_editor duplicated changed tokens
A4-Tacks Nov 12, 2025
d2593e1
feature: Set enclosing_range field on SCIP output
Wilfred Nov 26, 2025
16a9a55
Fix complete after `extern`, add `crate` completion
A4-Tacks Nov 27, 2025
01630f3
Separate between creating an interner without crate and with crate
ChayimFriedman2 Nov 27, 2025
f2a08a2
Use one query per crate for lang items, not one per lang item
ChayimFriedman2 Nov 28, 2025
a68be9c
Merge pull request #21144 from A4-Tacks/abi-qualifier-extern-crate-comp
ChayimFriedman2 Nov 28, 2025
74e9798
Merge pull request #21141 from Wilfred/scip_enclosing_range
ChayimFriedman2 Nov 28, 2025
f7be635
Don't run cache priming when disabled in settings
ChayimFriedman2 Nov 28, 2025
450860a
Merge pull request #21151 from ChayimFriedman2/no-cache-prime
ShoyuVanilla Nov 28, 2025
83c188a
Merge pull request #20163 from ChayimFriedman2/parser-per-token-edition
Veykril Nov 28, 2025
3e42012
Merge pull request #20217 from ChayimFriedman2/spec-resolve-hygiene
Veykril Nov 28, 2025
ebda376
Pass the correct per-token (not global) edition when expanding macro_…
ChayimFriedman2 Jul 3, 2025
a63a944
Remove an incorrect test
ChayimFriedman2 Jul 3, 2025
6c80657
Merge pull request #20164 from ChayimFriedman2/fix-edition
ChayimFriedman2 Nov 28, 2025
b24f9b6
Increase MSRV to 1.91.0
ChayimFriedman2 Nov 28, 2025
e31e2b1
Merge pull request #21153 from ChayimFriedman2/msrv
ChayimFriedman2 Nov 28, 2025
8610ebb
proc-macro-srv: Fix unnecessary subtree wrapping in protocol
Veykril Nov 28, 2025
6088208
Merge pull request #21154 from Veykril/push-nvlktkknrqms
Veykril Nov 28, 2025
170d9b4
fix Display scope inlay hints after closing brace for more types of b…
asukaminato0721 Nov 20, 2025
0362682
Merge pull request #21023 from A4-Tacks/syntax-editor-duplicate-changed
ShoyuVanilla Nov 28, 2025
0b725f3
fix: rust-analyzer.imports.granularity.group should get a dropdown UI
Wilfred Nov 27, 2025
d31e27f
Merge pull request #21077 from asukaminato0721/18833
ChayimFriedman2 Nov 28, 2025
81cff93
Merge pull request #21147 from Wilfred/imports_granularity_dropdown
ChayimFriedman2 Nov 28, 2025
3d33e8f
Fix URLs and highlighting in manual
Wilfred Nov 28, 2025
e07aa92
Merge pull request #21156 from Wilfred/manual_formatting
ChayimFriedman2 Nov 28, 2025
a8d8847
Remove force-always-assert from xtask/install install_cmd as well
itsjunetime Nov 28, 2025
90d7580
Clarify generic (not just cargo) process handling
Wilfred Nov 28, 2025
3148a4a
perf: Shrink `InferenceResult` by ~40 bytes
Veykril Nov 29, 2025
da79a56
Replace incorrect `ArenaMap` use with `FxHashMap`
Veykril Nov 29, 2025
97a427c
Merge pull request #21167 from Veykril/push-xksxokxxwyqw
Veykril Nov 29, 2025
86e1529
Merge pull request #21160 from Wilfred/clarify_process_naming
lnicola Nov 29, 2025
5dbb376
Merge pull request #21161 from itsjunetime/no_default_force_always_as…
lnicola Nov 29, 2025
bc662f1
Merge pull request #21149 from ChayimFriedman2/lang-items
ChayimFriedman2 Nov 29, 2025
a10ce57
Rewrite attribute handling
ChayimFriedman2 Jul 27, 2025
bf8b351
Fix bug with attribute macro expansion
ChayimFriedman2 Oct 23, 2025
341f1df
Fix input censoring for attr macros when the input contains a `key = …
ChayimFriedman2 Oct 23, 2025
4b29847
Make `Semantics::attach_first_edition()` not return `Option`
ChayimFriedman2 Oct 23, 2025
bf75855
Fix a panic where `all_crates()` is empty
ChayimFriedman2 Oct 23, 2025
645e490
Merge pull request #20892 from ChayimFriedman2/better-attrs
ChayimFriedman2 Nov 29, 2025
70b3c35
internal: New style salsa infer query
Veykril Nov 29, 2025
e78e835
Slim down `tuple_field_access_types`
Veykril Nov 29, 2025
b35d46c
Rewrite dyn trait lowering to follow rustc
ChayimFriedman2 Nov 28, 2025
9c9c245
Merge pull request #21169 from Veykril/push-psyltyvxtpoz
Veykril Nov 29, 2025
2ecafe2
Support multiple `enable` in `#[target_feature]`
ChayimFriedman2 Nov 29, 2025
e8bb59b
minor: Option-box `crate_lang_items` query result
Veykril Nov 29, 2025
7f6f1d5
Merge pull request #21170 from ChayimFriedman2/multi-target-feature
ChayimFriedman2 Nov 30, 2025
c984395
Merge pull request #21159 from ChayimFriedman2/fix-dyn-projections
Veykril Nov 30, 2025
3924ffe
Remove the block from `DbInterner`
ChayimFriedman2 Nov 29, 2025
a58c099
Merge pull request #21172 from ChayimFriedman2/no-block
ChayimFriedman2 Nov 30, 2025
34fe0ce
internal: fix gdb pretty printer when using Repr::Static
dfaure-kdab Nov 30, 2025
b657006
Merge pull request #21177 from dfaure-kdab/fix-for-static
ChayimFriedman2 Nov 30, 2025
75d26b0
internal: Ensure proc-macro-api version check works with postcard acr…
Veykril Nov 29, 2025
b35a995
Merge pull request #21179 from Veykril/push-xnrqmltklpxs
Veykril Nov 30, 2025
c6a4a53
Prepare for merging from rust-lang/rust
invalid-email-address Dec 1, 2025
7c2523f
Merge ref 'dfe1b8c97bcd' from rust-lang/rust
invalid-email-address Dec 1, 2025
9c44cb8
Merge pull request #21171 from Veykril/push-puuqoostoysw
lnicola Dec 1, 2025
e3d314d
Merge pull request #21185 from rust-lang/rustc-pull
lnicola Dec 1, 2025
1973e38
Use Itertools::exactly_one in a couple more places
lnicola Dec 1, 2025
ad61e76
Merge pull request #21186 from lnicola/exactly-one
lnicola Dec 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/tools/rust-analyzer/Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,7 @@ dependencies = [
name = "hir-expand"
version = "0.0.0"
dependencies = [
"arrayvec",
"base-db",
"cfg",
"cov-mark",
Expand All @@ -863,6 +864,7 @@ dependencies = [
"stdx",
"syntax",
"syntax-bridge",
"thin-vec",
"tracing",
"triomphe",
"tt",
Expand Down Expand Up @@ -905,6 +907,7 @@ dependencies = [
"syntax",
"test-fixture",
"test-utils",
"thin-vec",
"tracing",
"tracing-subscriber",
"tracing-tree",
Expand Down Expand Up @@ -1475,6 +1478,7 @@ dependencies = [
"parser",
"ra-ap-rustc_lexer",
"rustc-hash 2.1.1",
"salsa",
"smallvec",
"span",
"stdx",
Expand Down Expand Up @@ -2270,9 +2274,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"

[[package]]
name = "rowan"
version = "0.15.15"
version = "0.15.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a58fa8a7ccff2aec4f39cc45bf5f985cec7125ab271cf681c279fd00192b49"
checksum = "d4f1e4a001f863f41ea8d0e6a0c34b356d5b733db50dadab3efef640bafb779b"
dependencies = [
"countme",
"hashbrown 0.14.5",
Expand Down
7 changes: 4 additions & 3 deletions src/tools/rust-analyzer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
resolver = "2"

[workspace.package]
rust-version = "1.88"
rust-version = "1.91"
edition = "2024"
license = "MIT OR Apache-2.0"
authors = ["rust-analyzer team"]
Expand Down Expand Up @@ -52,7 +52,7 @@ debug = 2
# local crates
macros = { path = "./crates/macros", version = "0.0.0" }
base-db = { path = "./crates/base-db", version = "0.0.0" }
cfg = { path = "./crates/cfg", version = "0.0.0", features = ["tt"] }
cfg = { path = "./crates/cfg", version = "0.0.0", features = ["tt", "syntax"] }
hir = { path = "./crates/hir", version = "0.0.0" }
hir-def = { path = "./crates/hir-def", version = "0.0.0" }
hir-expand = { path = "./crates/hir-expand", version = "0.0.0" }
Expand Down Expand Up @@ -132,7 +132,7 @@ process-wrap = { version = "8.2.1", features = ["std"] }
pulldown-cmark-to-cmark = "10.0.4"
pulldown-cmark = { version = "0.9.6", default-features = false }
rayon = "1.10.0"
rowan = "=0.15.15"
rowan = "=0.15.17"
# Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work
# on impls without it
salsa = { version = "0.24.0", default-features = false, features = [
Expand Down Expand Up @@ -170,6 +170,7 @@ tracing-subscriber = { version = "0.3.20", default-features = false, features =
triomphe = { version = "0.1.14", default-features = false, features = ["std"] }
url = "2.5.4"
xshell = "0.2.7"
thin-vec = "0.2.14"
petgraph = { version = "0.8.2", default-features = false }

# We need to freeze the version of the crate, as the raw-api feature is considered unstable
Expand Down
302 changes: 302 additions & 0 deletions src/tools/rust-analyzer/crates/base-db/src/editioned_file_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
//! Defines [`EditionedFileId`], an interned wrapper around [`span::EditionedFileId`] that
//! is interned (so queries can take it) and remembers its crate.

use core::fmt;
use std::hash::{Hash, Hasher};

use span::Edition;
use vfs::FileId;

use crate::{Crate, RootQueryDb};

#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct EditionedFileId(
salsa::Id,
std::marker::PhantomData<&'static salsa::plumbing::interned::Value<EditionedFileId>>,
);

const _: () = {
use salsa::plumbing as zalsa_;
use zalsa_::interned as zalsa_struct_;
type Configuration_ = EditionedFileId;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EditionedFileIdData {
editioned_file_id: span::EditionedFileId,
krate: Crate,
}

/// We like to include the origin crate in an `EditionedFileId` (for use in the item tree),
/// but this poses us a problem.
///
/// Spans contain `EditionedFileId`s, and we don't want to make them store the crate too
/// because that will increase their size, which will increase memory usage significantly.
/// Furthermore, things using spans do not generally need the crate: they are using the
/// file id for queries like `ast_id_map` or `parse`, which do not care about the crate.
///
/// To solve this, we hash **only the `span::EditionedFileId`**, but on still compare
/// the crate in equality check. This preserves the invariant of `Hash` and `Eq` -
/// although same hashes can be used for different items, same file ids used for multiple
/// crates is a rare thing, and different items always have different hashes. Then,
/// when we only have a `span::EditionedFileId`, we use the `intern()` method to
/// reuse existing file ids, and create new one only if needed. See [`from_span_guess_origin`].
///
/// 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
///
/// [`from_span_guess_origin`]: EditionedFileId::from_span_guess_origin
#[derive(Hash, PartialEq, Eq)]
struct WithoutCrate {
editioned_file_id: span::EditionedFileId,
}

impl Hash for EditionedFileIdData {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
let EditionedFileIdData { editioned_file_id, krate: _ } = *self;
editioned_file_id.hash(state);
}
}

impl zalsa_struct_::HashEqLike<WithoutCrate> for EditionedFileIdData {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(self, state);
}

#[inline]
fn eq(&self, data: &WithoutCrate) -> bool {
let EditionedFileIdData { editioned_file_id, krate: _ } = *self;
editioned_file_id == data.editioned_file_id
}
}

impl zalsa_::HasJar for EditionedFileId {
type Jar = zalsa_struct_::JarImpl<EditionedFileId>;
const KIND: zalsa_::JarKind = zalsa_::JarKind::Struct;
}

zalsa_::register_jar! {
zalsa_::ErasedJar::erase::<EditionedFileId>()
}

impl zalsa_struct_::Configuration for EditionedFileId {
const LOCATION: salsa::plumbing::Location =
salsa::plumbing::Location { file: file!(), line: line!() };
const DEBUG_NAME: &'static str = "EditionedFileId";
const REVISIONS: std::num::NonZeroUsize = std::num::NonZeroUsize::MAX;
const PERSIST: bool = false;

type Fields<'a> = EditionedFileIdData;
type Struct<'db> = EditionedFileId;

fn serialize<S>(_: &Self::Fields<'_>, _: S) -> Result<S::Ok, S::Error>
where
S: zalsa_::serde::Serializer,
{
unimplemented!("attempted to serialize value that set `PERSIST` to false")
}

fn deserialize<'de, D>(_: D) -> Result<Self::Fields<'static>, D::Error>
where
D: zalsa_::serde::Deserializer<'de>,
{
unimplemented!("attempted to deserialize value that cannot set `PERSIST` to false");
}
}

impl Configuration_ {
pub fn ingredient(zalsa: &zalsa_::Zalsa) -> &zalsa_struct_::IngredientImpl<Self> {
static CACHE: zalsa_::IngredientCache<zalsa_struct_::IngredientImpl<EditionedFileId>> =
zalsa_::IngredientCache::new();

// SAFETY: `lookup_jar_by_type` returns a valid ingredient index, and the only
// ingredient created by our jar is the struct ingredient.
unsafe {
CACHE.get_or_create(zalsa, || {
zalsa.lookup_jar_by_type::<zalsa_struct_::JarImpl<EditionedFileId>>()
})
}
}
}

impl zalsa_::AsId for EditionedFileId {
fn as_id(&self) -> salsa::Id {
self.0.as_id()
}
}
impl zalsa_::FromId for EditionedFileId {
fn from_id(id: salsa::Id) -> Self {
Self(<salsa::Id>::from_id(id), std::marker::PhantomData)
}
}

unsafe impl Send for EditionedFileId {}
unsafe impl Sync for EditionedFileId {}

impl std::fmt::Debug for EditionedFileId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Self::default_debug_fmt(*self, f)
}
}

impl zalsa_::SalsaStructInDb for EditionedFileId {
type MemoIngredientMap = salsa::plumbing::MemoIngredientSingletonIndex;

fn lookup_ingredient_index(aux: &zalsa_::Zalsa) -> salsa::plumbing::IngredientIndices {
aux.lookup_jar_by_type::<zalsa_struct_::JarImpl<EditionedFileId>>().into()
}

fn entries(zalsa: &zalsa_::Zalsa) -> impl Iterator<Item = zalsa_::DatabaseKeyIndex> + '_ {
let _ingredient_index =
zalsa.lookup_jar_by_type::<zalsa_struct_::JarImpl<EditionedFileId>>();
<EditionedFileId>::ingredient(zalsa).entries(zalsa).map(|entry| entry.key())
}

#[inline]
fn cast(id: salsa::Id, type_id: std::any::TypeId) -> Option<Self> {
if type_id == std::any::TypeId::of::<EditionedFileId>() {
Some(<Self as salsa::plumbing::FromId>::from_id(id))
} else {
None
}
}

#[inline]
unsafe fn memo_table(
zalsa: &zalsa_::Zalsa,
id: zalsa_::Id,
current_revision: zalsa_::Revision,
) -> zalsa_::MemoTableWithTypes<'_> {
// SAFETY: Guaranteed by caller.
unsafe {
zalsa.table().memos::<zalsa_struct_::Value<EditionedFileId>>(id, current_revision)
}
}
}

unsafe impl zalsa_::Update for EditionedFileId {
unsafe fn maybe_update(old_pointer: *mut Self, new_value: Self) -> bool {
if unsafe { *old_pointer } != new_value {
unsafe { *old_pointer = new_value };
true
} else {
false
}
}
}

impl EditionedFileId {
pub fn from_span(
db: &(impl salsa::Database + ?Sized),
editioned_file_id: span::EditionedFileId,
krate: Crate,
) -> Self {
let (zalsa, zalsa_local) = db.zalsas();
Configuration_::ingredient(zalsa).intern(
zalsa,
zalsa_local,
EditionedFileIdData { editioned_file_id, krate },
|_, data| data,
)
}

/// Guesses the crate for the file.
///
/// Only use this if you cannot precisely determine the origin. This can happen in one of two cases:
///
/// 1. The file is not in the module tree.
/// 2. You are latency sensitive and cannot afford calling the def map to precisely compute the origin
/// (e.g. on enter feature, folding, etc.).
pub fn from_span_guess_origin(
db: &dyn RootQueryDb,
editioned_file_id: span::EditionedFileId,
) -> Self {
let (zalsa, zalsa_local) = db.zalsas();
Configuration_::ingredient(zalsa).intern(
zalsa,
zalsa_local,
WithoutCrate { editioned_file_id },
|_, _| {
// FileId not in the database.
let krate = db
.relevant_crates(editioned_file_id.file_id())
.first()
.copied()
.or_else(|| db.all_crates().first().copied())
.unwrap_or_else(|| {
// What we're doing here is a bit fishy. We rely on the fact that we only need
// the crate in the item tree, and we should not create an `EditionedFileId`
// without a crate except in cases where it does not matter. The chances that
// `all_crates()` will be empty are also very slim, but it can occur during startup.
// In the very unlikely case that there is a bug and we'll use this crate, Salsa
// will panic.

// SAFETY: 0 is less than `Id::MAX_U32`.
salsa::plumbing::FromId::from_id(unsafe { salsa::Id::from_index(0) })
});
EditionedFileIdData { editioned_file_id, krate }
},
)
}

pub fn editioned_file_id(self, db: &dyn salsa::Database) -> span::EditionedFileId {
let zalsa = db.zalsa();
let fields = Configuration_::ingredient(zalsa).fields(zalsa, self);
fields.editioned_file_id
}

pub fn krate(self, db: &dyn salsa::Database) -> Crate {
let zalsa = db.zalsa();
let fields = Configuration_::ingredient(zalsa).fields(zalsa, self);
fields.krate
}

/// Default debug formatting for this struct (may be useful if you define your own `Debug` impl)
pub fn default_debug_fmt(this: Self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
zalsa_::with_attached_database(|db| {
let zalsa = db.zalsa();
let fields = Configuration_::ingredient(zalsa).fields(zalsa, this);
fmt::Debug::fmt(fields, f)
})
.unwrap_or_else(|| {
f.debug_tuple("EditionedFileId").field(&zalsa_::AsId::as_id(&this)).finish()
})
}
}
};

impl EditionedFileId {
#[inline]
pub fn new(db: &dyn salsa::Database, file_id: FileId, edition: Edition, krate: Crate) -> Self {
EditionedFileId::from_span(db, span::EditionedFileId::new(file_id, edition), krate)
}

/// Attaches the current edition and guesses the crate for the file.
///
/// Only use this if you cannot precisely determine the origin. This can happen in one of two cases:
///
/// 1. The file is not in the module tree.
/// 2. You are latency sensitive and cannot afford calling the def map to precisely compute the origin
/// (e.g. on enter feature, folding, etc.).
#[inline]
pub fn current_edition_guess_origin(db: &dyn RootQueryDb, file_id: FileId) -> Self {
Self::from_span_guess_origin(db, span::EditionedFileId::current_edition(file_id))
}

#[inline]
pub fn file_id(self, db: &dyn salsa::Database) -> vfs::FileId {
let id = self.editioned_file_id(db);
id.file_id()
}

#[inline]
pub fn unpack(self, db: &dyn salsa::Database) -> (vfs::FileId, span::Edition) {
let id = self.editioned_file_id(db);
(id.file_id(), id.edition())
}

#[inline]
pub fn edition(self, db: &dyn salsa::Database) -> Edition {
self.editioned_file_id(db).edition()
}
}
7 changes: 4 additions & 3 deletions src/tools/rust-analyzer/crates/base-db/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -857,9 +857,10 @@ impl CrateGraphBuilder {
}
}

impl BuiltCrateData {
pub fn root_file_id(&self, db: &dyn salsa::Database) -> EditionedFileId {
EditionedFileId::new(db, self.root_file_id, self.edition)
impl Crate {
pub fn root_file_id(self, db: &dyn salsa::Database) -> EditionedFileId {
let data = self.data(db);
EditionedFileId::new(db, data.root_file_id, data.edition, self)
}
}

Expand Down
Loading
Loading