Skip to content

Commit f48ecb6

Browse files
committed
Try to support pre and post-change metavars
1 parent 8753ca5 commit f48ecb6

21 files changed

+255
-110
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ nohash-hasher = "0.2.0"
110110
rayon = "1.8.0"
111111
rust-analyzer-salsa = "0.17.0-pre.4"
112112
rustc-hash = "1.1.0"
113+
semver = "1.0.14"
113114
serde = { version = "1.0.192", features = ["derive"] }
114115
serde_json = "1.0.108"
115116
smallvec = { version = "1.10.0", features = [

crates/base-db/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ la-arena.workspace = true
1616
rust-analyzer-salsa.workspace = true
1717
rustc-hash.workspace = true
1818
triomphe.workspace = true
19+
semver.workspace = true
1920

2021
# local deps
2122
cfg.workspace = true

crates/base-db/src/input.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::{fmt, mem, ops, str::FromStr};
1111
use cfg::CfgOptions;
1212
use la_arena::{Arena, Idx};
1313
use rustc_hash::{FxHashMap, FxHashSet};
14+
use semver::Version;
1415
use syntax::SmolStr;
1516
use triomphe::Arc;
1617
use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath};
@@ -258,7 +259,7 @@ impl ReleaseChannel {
258259

259260
pub fn from_str(str: &str) -> Option<Self> {
260261
Some(match str {
261-
"" => ReleaseChannel::Stable,
262+
"" | "stable" => ReleaseChannel::Stable,
262263
"nightly" => ReleaseChannel::Nightly,
263264
_ if str.starts_with("beta") => ReleaseChannel::Beta,
264265
_ => return None,
@@ -289,7 +290,7 @@ pub struct CrateData {
289290
// things. This info does need to be somewhat present though as to prevent deduplication from
290291
// happening across different workspaces with different layouts.
291292
pub target_layout: TargetLayoutLoadResult,
292-
pub channel: Option<ReleaseChannel>,
293+
pub toolchain: Option<Version>,
293294
}
294295

295296
impl CrateData {
@@ -346,6 +347,10 @@ impl CrateData {
346347

347348
slf_deps.eq(other_deps)
348349
}
350+
351+
pub fn channel(&self) -> Option<ReleaseChannel> {
352+
self.toolchain.as_ref().and_then(|v| ReleaseChannel::from_str(&v.pre))
353+
}
349354
}
350355

351356
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -427,7 +432,7 @@ impl CrateGraph {
427432
is_proc_macro: bool,
428433
origin: CrateOrigin,
429434
target_layout: Result<Arc<str>, Arc<str>>,
430-
channel: Option<ReleaseChannel>,
435+
toolchain: Option<Version>,
431436
) -> CrateId {
432437
let data = CrateData {
433438
root_file_id,
@@ -441,7 +446,7 @@ impl CrateGraph {
441446
origin,
442447
target_layout,
443448
is_proc_macro,
444-
channel,
449+
toolchain,
445450
};
446451
self.arena.alloc(data)
447452
}

crates/base-db/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ pub use salsa::{self, Cancelled};
2323
pub use span::{FilePosition, FileRange};
2424
pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath};
2525

26+
pub use semver::{BuildMetadata, Prerelease, Version, VersionReq};
27+
2628
#[macro_export]
2729
macro_rules! impl_intern_key {
2830
($name:ident) => {

crates/hir-expand/src/db.rs

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! Defines database & queries for macro expansion.
22
3+
use std::sync::OnceLock;
4+
35
use base_db::{
46
salsa::{self, debug::DebugQueryTable},
5-
CrateId, Edition, FileId, SourceDatabase,
7+
CrateId, Edition, FileId, SourceDatabase, VersionReq,
68
};
79
use either::Either;
810
use limit::Limit;
@@ -45,32 +47,68 @@ pub struct DeclarativeMacroExpander {
4547
pub transparency: Transparency,
4648
}
4749

50+
// FIXME: Remove this once we drop support for 1.76
51+
static REQUIREMENT: OnceLock<VersionReq> = OnceLock::new();
52+
4853
impl DeclarativeMacroExpander {
4954
pub fn expand(
5055
&self,
5156
db: &dyn ExpandDatabase,
5257
tt: tt::Subtree,
5358
call_id: MacroCallId,
5459
) -> ExpandResult<tt::Subtree> {
60+
let toolchain = &db.crate_graph()[db.lookup_intern_macro_call(call_id).def.krate].toolchain;
61+
let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
62+
REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
63+
&base_db::Version {
64+
pre: base_db::Prerelease::EMPTY,
65+
build: base_db::BuildMetadata::EMPTY,
66+
major: version.major,
67+
minor: version.minor,
68+
patch: version.patch,
69+
},
70+
)
71+
});
5572
match self.mac.err() {
5673
Some(e) => ExpandResult::new(
5774
tt::Subtree::empty(tt::DelimSpan::DUMMY),
5875
ExpandError::other(format!("invalid macro definition: {e}")),
5976
),
6077
None => self
6178
.mac
62-
.expand(&tt, |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency))
79+
.expand(
80+
&tt,
81+
|s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency),
82+
new_meta_vars,
83+
)
6384
.map_err(Into::into),
6485
}
6586
}
6687

67-
pub fn expand_unhygienic(&self, tt: tt::Subtree) -> ExpandResult<tt::Subtree> {
88+
pub fn expand_unhygienic(
89+
&self,
90+
db: &dyn ExpandDatabase,
91+
tt: tt::Subtree,
92+
krate: CrateId,
93+
) -> ExpandResult<tt::Subtree> {
94+
let toolchain = &db.crate_graph()[krate].toolchain;
95+
let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
96+
REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
97+
&base_db::Version {
98+
pre: base_db::Prerelease::EMPTY,
99+
build: base_db::BuildMetadata::EMPTY,
100+
major: version.major,
101+
minor: version.minor,
102+
patch: version.patch,
103+
},
104+
)
105+
});
68106
match self.mac.err() {
69107
Some(e) => ExpandResult::new(
70108
tt::Subtree::empty(tt::DelimSpan::DUMMY),
71109
ExpandError::other(format!("invalid macro definition: {e}")),
72110
),
73-
None => self.mac.expand(&tt, |_| ()).map_err(Into::into),
111+
None => self.mac.expand(&tt, |_| (), new_meta_vars).map_err(Into::into),
74112
}
75113
}
76114
}
@@ -278,7 +316,7 @@ pub fn expand_speculative(
278316
expander.expand(db, actual_macro_call, &adt, span_map)
279317
}
280318
MacroDefKind::Declarative(it) => {
281-
db.decl_macro_expander(loc.krate, it).expand_unhygienic(tt)
319+
db.decl_macro_expander(loc.krate, it).expand_unhygienic(db, tt, loc.def.krate)
282320
}
283321
MacroDefKind::BuiltIn(it, _) => it.expand(db, actual_macro_call, &tt).map_err(Into::into),
284322
MacroDefKind::BuiltInEager(it, _) => {
@@ -525,7 +563,8 @@ fn decl_macro_expander(
525563
def_crate: CrateId,
526564
id: AstId<ast::Macro>,
527565
) -> Arc<DeclarativeMacroExpander> {
528-
let is_2021 = db.crate_graph()[def_crate].edition >= Edition::Edition2021;
566+
let crate_data = &db.crate_graph()[def_crate];
567+
let is_2021 = crate_data.edition >= Edition::Edition2021;
529568
let (root, map) = parse_with_map(db, id.file_id);
530569
let root = root.syntax_node();
531570

@@ -549,13 +588,25 @@ fn decl_macro_expander(
549588
_ => None,
550589
}
551590
};
591+
let toolchain = crate_data.toolchain.as_ref();
592+
let new_meta_vars = toolchain.as_ref().map_or(false, |version| {
593+
REQUIREMENT.get_or_init(|| VersionReq::parse(">=1.76").unwrap()).matches(
594+
&base_db::Version {
595+
pre: base_db::Prerelease::EMPTY,
596+
build: base_db::BuildMetadata::EMPTY,
597+
major: version.major,
598+
minor: version.minor,
599+
patch: version.patch,
600+
},
601+
)
602+
});
552603

553604
let (mac, transparency) = match id.to_ptr(db).to_node(&root) {
554605
ast::Macro::MacroRules(macro_rules) => (
555606
match macro_rules.token_tree() {
556607
Some(arg) => {
557608
let tt = mbe::syntax_node_to_token_tree(arg.syntax(), map.as_ref());
558-
let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021);
609+
let mac = mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021, new_meta_vars);
559610
mac
560611
}
561612
None => mbe::DeclarativeMacro::from_err(
@@ -569,7 +620,7 @@ fn decl_macro_expander(
569620
match macro_def.body() {
570621
Some(arg) => {
571622
let tt = mbe::syntax_node_to_token_tree(arg.syntax(), map.as_ref());
572-
let mac = mbe::DeclarativeMacro::parse_macro2(&tt, is_2021);
623+
let mac = mbe::DeclarativeMacro::parse_macro2(&tt, is_2021, new_meta_vars);
573624
mac
574625
}
575626
None => mbe::DeclarativeMacro::from_err(

crates/ide-completion/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ impl<'a> CompletionContext<'a> {
693693
let krate = scope.krate();
694694
let module = scope.module();
695695

696-
let toolchain = db.crate_graph()[krate.into()].channel;
696+
let toolchain = db.crate_graph()[krate.into()].channel();
697697
// `toolchain == None` means we're in some detached files. Since we have no information on
698698
// the toolchain being used, let's just allow unstable items to be listed.
699699
let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None);

crates/ide/src/doc_links.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ fn get_doc_base_urls(
492492
let Some(krate) = def.krate(db) else { return Default::default() };
493493
let Some(display_name) = krate.display_name(db) else { return Default::default() };
494494
let crate_data = &db.crate_graph()[krate.into()];
495-
let channel = crate_data.channel.map_or("nightly", ReleaseChannel::as_str);
495+
let channel = crate_data.channel().unwrap_or(ReleaseChannel::Nightly).as_str();
496496

497497
let (web_base, local_base) = match &crate_data.origin {
498498
// std and co do not specify `html_root_url` any longer so we gotta handwrite this ourself.

crates/ide/src/shuffle_crate_graph.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
4040
data.is_proc_macro,
4141
data.origin.clone(),
4242
data.target_layout.clone(),
43-
data.channel,
43+
data.toolchain.clone(),
4444
);
4545
new_proc_macros.insert(new_id, proc_macros[&old_id].clone());
4646
map.insert(old_id, new_id);

crates/mbe/src/benchmark.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ fn benchmark_parse_macro_rules() {
2020
let rules = macro_rules_fixtures_tt();
2121
let hash: usize = {
2222
let _pt = bench("mbe parse macro rules");
23-
rules.values().map(|it| DeclarativeMacro::parse_macro_rules(it, true).rules.len()).sum()
23+
rules
24+
.values()
25+
.map(|it| DeclarativeMacro::parse_macro_rules(it, true, true).rules.len())
26+
.sum()
2427
};
2528
assert_eq!(hash, 1144);
2629
}
@@ -38,7 +41,7 @@ fn benchmark_expand_macro_rules() {
3841
invocations
3942
.into_iter()
4043
.map(|(id, tt)| {
41-
let res = rules[&id].expand(&tt, |_| ());
44+
let res = rules[&id].expand(&tt, |_| (), true);
4245
assert!(res.err.is_none());
4346
res.value.token_trees.len()
4447
})
@@ -50,7 +53,7 @@ fn benchmark_expand_macro_rules() {
5053
fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro<DummyTestSpanData>> {
5154
macro_rules_fixtures_tt()
5255
.into_iter()
53-
.map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, true)))
56+
.map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, true, true)))
5457
.collect()
5558
}
5659

@@ -105,7 +108,7 @@ fn invocation_fixtures(
105108
for op in rule.lhs.iter() {
106109
collect_from_op(op, &mut subtree, &mut seed);
107110
}
108-
if it.expand(&subtree, |_| ()).err.is_none() {
111+
if it.expand(&subtree, |_| (), true).err.is_none() {
109112
res.push((name.clone(), subtree));
110113
break;
111114
}

0 commit comments

Comments
 (0)