mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-29 20:46:07 +03:00
Merge pull request #20164 from ChayimFriedman2/fix-edition
fix: Pass the correct per-token (not global) edition when expanding macro_rules
This commit is contained in:
@@ -1475,6 +1475,7 @@ dependencies = [
|
||||
"parser",
|
||||
"ra-ap-rustc_lexer",
|
||||
"rustc-hash 2.1.1",
|
||||
"salsa",
|
||||
"smallvec",
|
||||
"span",
|
||||
"stdx",
|
||||
|
||||
@@ -1958,28 +1958,6 @@ fn f() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edition_handling_in() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:old edition:2021
|
||||
fn f() {
|
||||
old::parse_try_old!(try!{});
|
||||
}
|
||||
//- /old.rs crate:old edition:2015
|
||||
#[macro_export]
|
||||
macro_rules! parse_try_old {
|
||||
($it:expr) => {};
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn f() {
|
||||
;
|
||||
}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn semicolon_does_not_glue() {
|
||||
check(
|
||||
@@ -2051,3 +2029,33 @@ fn f() {
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn per_token_edition() {
|
||||
check(
|
||||
r#"
|
||||
//- /foo.rs crate:foo edition:2024
|
||||
#[macro_export]
|
||||
macro_rules! m {
|
||||
($e:expr) => {};
|
||||
}
|
||||
//- /bar.rs crate:bar deps:foo edition:2021
|
||||
fn gen() -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
foo::m!(gen());
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn gen() -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
;
|
||||
}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
use syntax_bridge::syntax_node_to_token_tree;
|
||||
|
||||
use crate::{
|
||||
EditionedFileId, ExpandError, ExpandResult, Lookup as _, MacroCallId,
|
||||
EditionedFileId, ExpandError, ExpandResult, MacroCallId,
|
||||
builtin::quote::{WithDelimiter, dollar_crate},
|
||||
db::ExpandDatabase,
|
||||
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt},
|
||||
@@ -230,9 +230,9 @@ fn assert_expand(
|
||||
let mut iter = tt.iter();
|
||||
|
||||
let cond = expect_fragment(
|
||||
db,
|
||||
&mut iter,
|
||||
parser::PrefixEntryPoint::Expr,
|
||||
id.lookup(db).krate.data(db).edition,
|
||||
tt.top_subtree().delimiter.delim_span(),
|
||||
);
|
||||
_ = iter.expect_char(',');
|
||||
|
||||
@@ -299,7 +299,7 @@ pub fn expand_speculative(
|
||||
}
|
||||
MacroDefKind::Declarative(it, _) => db
|
||||
.decl_macro_expander(loc.krate, it)
|
||||
.expand_unhygienic(tt, loc.kind.call_style(), span, loc.def.edition),
|
||||
.expand_unhygienic(db, tt, loc.kind.call_style(), span),
|
||||
MacroDefKind::BuiltIn(_, it) => {
|
||||
it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ pub fn expand(
|
||||
None => self
|
||||
.mac
|
||||
.expand(
|
||||
db,
|
||||
&tt,
|
||||
|s| {
|
||||
s.ctx =
|
||||
@@ -49,7 +50,6 @@ pub fn expand(
|
||||
},
|
||||
loc.kind.call_style(),
|
||||
span,
|
||||
loc.def.edition,
|
||||
)
|
||||
.map_err(Into::into),
|
||||
}
|
||||
@@ -57,10 +57,10 @@ pub fn expand(
|
||||
|
||||
pub fn expand_unhygienic(
|
||||
&self,
|
||||
db: &dyn ExpandDatabase,
|
||||
tt: tt::TopSubtree,
|
||||
call_style: MacroCallStyle,
|
||||
call_site: Span,
|
||||
def_site_edition: Edition,
|
||||
) -> ExpandResult<tt::TopSubtree> {
|
||||
match self.mac.err() {
|
||||
Some(_) => ExpandResult::new(
|
||||
@@ -69,7 +69,7 @@ pub fn expand_unhygienic(
|
||||
),
|
||||
None => self
|
||||
.mac
|
||||
.expand(&tt, |_| (), call_style, call_site, def_site_edition)
|
||||
.expand(db, &tt, |_| (), call_style, call_site)
|
||||
.map(TupleExt::head)
|
||||
.map_err(Into::into),
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ rustc-hash.workspace = true
|
||||
smallvec.workspace = true
|
||||
arrayvec.workspace = true
|
||||
ra-ap-rustc_lexer.workspace = true
|
||||
salsa.workspace = true
|
||||
bitflags.workspace = true
|
||||
|
||||
# local deps
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use intern::Symbol;
|
||||
use rustc_hash::FxHashMap;
|
||||
use span::{Edition, Span};
|
||||
use span::Span;
|
||||
use stdx::itertools::Itertools;
|
||||
use syntax::{
|
||||
AstNode,
|
||||
@@ -44,16 +44,16 @@ fn benchmark_expand_macro_rules() {
|
||||
if skip_slow_tests() {
|
||||
return;
|
||||
}
|
||||
let db = salsa::DatabaseImpl::default();
|
||||
let rules = macro_rules_fixtures();
|
||||
let invocations = invocation_fixtures(&rules);
|
||||
let invocations = invocation_fixtures(&db, &rules);
|
||||
|
||||
let hash: usize = {
|
||||
let _pt = bench("mbe expand macro rules");
|
||||
invocations
|
||||
.into_iter()
|
||||
.map(|(id, tt)| {
|
||||
let res =
|
||||
rules[&id].expand(&tt, |_| (), MacroCallStyle::FnLike, DUMMY, Edition::CURRENT);
|
||||
let res = rules[&id].expand(&db, &tt, |_| (), MacroCallStyle::FnLike, DUMMY);
|
||||
assert!(res.err.is_none());
|
||||
res.value.0.0.len()
|
||||
})
|
||||
@@ -93,6 +93,7 @@ fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::TopSubtree<Span>> {
|
||||
|
||||
/// Generate random invocation fixtures from rules
|
||||
fn invocation_fixtures(
|
||||
db: &dyn salsa::Database,
|
||||
rules: &FxHashMap<String, DeclarativeMacro>,
|
||||
) -> Vec<(String, tt::TopSubtree<Span>)> {
|
||||
let mut seed = 123456789;
|
||||
@@ -124,10 +125,7 @@ fn invocation_fixtures(
|
||||
}
|
||||
let subtree = builder.build();
|
||||
|
||||
if it
|
||||
.expand(&subtree, |_| (), MacroCallStyle::FnLike, DUMMY, Edition::CURRENT)
|
||||
.err
|
||||
.is_none()
|
||||
if it.expand(db, &subtree, |_| (), MacroCallStyle::FnLike, DUMMY).err.is_none()
|
||||
{
|
||||
res.push((name.clone(), subtree));
|
||||
break;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
use intern::Symbol;
|
||||
use rustc_hash::FxHashMap;
|
||||
use span::{Edition, Span};
|
||||
use span::Span;
|
||||
|
||||
use crate::{
|
||||
ExpandError, ExpandErrorKind, ExpandResult, MacroCallStyle, MatchedArmIndex,
|
||||
@@ -15,12 +15,12 @@
|
||||
};
|
||||
|
||||
pub(crate) fn expand_rules(
|
||||
db: &dyn salsa::Database,
|
||||
rules: &[crate::Rule],
|
||||
input: &tt::TopSubtree<Span>,
|
||||
marker: impl Fn(&mut Span) + Copy,
|
||||
call_style: MacroCallStyle,
|
||||
call_site: Span,
|
||||
def_site_edition: Edition,
|
||||
) -> ExpandResult<(tt::TopSubtree<Span>, MatchedArmIndex)> {
|
||||
let mut match_: Option<(matcher::Match<'_>, &crate::Rule, usize)> = None;
|
||||
for (idx, rule) in rules.iter().enumerate() {
|
||||
@@ -29,7 +29,7 @@ pub(crate) fn expand_rules(
|
||||
continue;
|
||||
}
|
||||
|
||||
let new_match = matcher::match_(&rule.lhs, input, def_site_edition);
|
||||
let new_match = matcher::match_(db, &rule.lhs, input);
|
||||
|
||||
if new_match.err.is_none() {
|
||||
// If we find a rule that applies without errors, we're done.
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
use intern::{Symbol, sym};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use span::{Edition, Span};
|
||||
use span::Span;
|
||||
use tt::{
|
||||
DelimSpan,
|
||||
iter::{TtElement, TtIter},
|
||||
@@ -112,11 +112,11 @@ fn add_err(&mut self, err: ExpandError) {
|
||||
|
||||
/// Matching errors are added to the `Match`.
|
||||
pub(super) fn match_<'t>(
|
||||
db: &dyn salsa::Database,
|
||||
pattern: &'t MetaTemplate,
|
||||
input: &'t tt::TopSubtree<Span>,
|
||||
edition: Edition,
|
||||
) -> Match<'t> {
|
||||
let mut res = match_loop(pattern, input, edition);
|
||||
let mut res = match_loop(db, pattern, input);
|
||||
res.bound_count = count(res.bindings.bindings());
|
||||
return res;
|
||||
|
||||
@@ -365,6 +365,7 @@ struct MatchState<'t> {
|
||||
/// - `error_items`: the set of items in errors, used for error-resilient parsing
|
||||
#[inline]
|
||||
fn match_loop_inner<'t>(
|
||||
db: &dyn salsa::Database,
|
||||
src: TtIter<'t, Span>,
|
||||
stack: &[TtIter<'t, Span>],
|
||||
res: &mut Match<'t>,
|
||||
@@ -375,7 +376,6 @@ fn match_loop_inner<'t>(
|
||||
eof_items: &mut SmallVec<[MatchState<'t>; 1]>,
|
||||
error_items: &mut SmallVec<[MatchState<'t>; 1]>,
|
||||
delim_span: tt::DelimSpan<Span>,
|
||||
edition: Edition,
|
||||
) {
|
||||
macro_rules! try_push {
|
||||
($items: expr, $it:expr) => {
|
||||
@@ -486,7 +486,7 @@ macro_rules! try_push {
|
||||
OpDelimited::Op(Op::Var { kind, name, .. }) => {
|
||||
if let &Some(kind) = kind {
|
||||
let mut fork = src.clone();
|
||||
let match_res = match_meta_var(kind, &mut fork, delim_span, edition);
|
||||
let match_res = match_meta_var(db, kind, &mut fork, delim_span);
|
||||
match match_res.err {
|
||||
None => {
|
||||
// Some meta variables are optional (e.g. vis)
|
||||
@@ -621,9 +621,9 @@ macro_rules! try_push {
|
||||
}
|
||||
|
||||
fn match_loop<'t>(
|
||||
db: &dyn salsa::Database,
|
||||
pattern: &'t MetaTemplate,
|
||||
src: &'t tt::TopSubtree<Span>,
|
||||
edition: Edition,
|
||||
) -> Match<'t> {
|
||||
let span = src.top_subtree().delimiter.delim_span();
|
||||
let mut src = src.iter();
|
||||
@@ -655,6 +655,7 @@ fn match_loop<'t>(
|
||||
stdx::always!(next_items.is_empty());
|
||||
|
||||
match_loop_inner(
|
||||
db,
|
||||
src.clone(),
|
||||
&stack,
|
||||
&mut res,
|
||||
@@ -665,7 +666,6 @@ fn match_loop<'t>(
|
||||
&mut eof_items,
|
||||
&mut error_items,
|
||||
span,
|
||||
edition,
|
||||
);
|
||||
stdx::always!(cur_items.is_empty());
|
||||
|
||||
@@ -772,14 +772,14 @@ fn match_loop<'t>(
|
||||
}
|
||||
|
||||
fn match_meta_var<'t>(
|
||||
db: &dyn salsa::Database,
|
||||
kind: MetaVarKind,
|
||||
input: &mut TtIter<'t, Span>,
|
||||
delim_span: DelimSpan<Span>,
|
||||
edition: Edition,
|
||||
) -> ExpandResult<Fragment<'t>> {
|
||||
let fragment = match kind {
|
||||
MetaVarKind::Path => {
|
||||
return expect_fragment(input, parser::PrefixEntryPoint::Path, edition, delim_span)
|
||||
return expect_fragment(db, input, parser::PrefixEntryPoint::Path, delim_span)
|
||||
.map(Fragment::Path);
|
||||
}
|
||||
MetaVarKind::Expr(expr) => {
|
||||
@@ -807,7 +807,7 @@ fn match_meta_var<'t>(
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
return expect_fragment(input, parser::PrefixEntryPoint::Expr, edition, delim_span)
|
||||
return expect_fragment(db, input, parser::PrefixEntryPoint::Expr, delim_span)
|
||||
.map(Fragment::Expr);
|
||||
}
|
||||
MetaVarKind::Ident | MetaVarKind::Tt | MetaVarKind::Lifetime | MetaVarKind::Literal => {
|
||||
@@ -853,7 +853,7 @@ fn match_meta_var<'t>(
|
||||
MetaVarKind::Item => parser::PrefixEntryPoint::Item,
|
||||
MetaVarKind::Vis => parser::PrefixEntryPoint::Vis,
|
||||
};
|
||||
expect_fragment(input, fragment, edition, delim_span).map(Fragment::Tokens)
|
||||
expect_fragment(db, input, fragment, delim_span).map(Fragment::Tokens)
|
||||
}
|
||||
|
||||
fn collect_vars(collector_fun: &mut impl FnMut(Symbol), pattern: &MetaTemplate) {
|
||||
|
||||
@@ -275,13 +275,13 @@ pub fn rule_styles(&self) -> MacroCallStyles {
|
||||
|
||||
pub fn expand(
|
||||
&self,
|
||||
db: &dyn salsa::Database,
|
||||
tt: &tt::TopSubtree<Span>,
|
||||
marker: impl Fn(&mut Span) + Copy,
|
||||
call_style: MacroCallStyle,
|
||||
call_site: Span,
|
||||
def_site_edition: Edition,
|
||||
) -> ExpandResult<(tt::TopSubtree<Span>, MatchedArmIndex)> {
|
||||
expander::expand_rules(&self.rules, tt, marker, call_style, call_site, def_site_edition)
|
||||
expander::expand_rules(db, &self.rules, tt, marker, call_style, call_site)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,15 +390,14 @@ fn from(result: Result<T, E>) -> Self {
|
||||
}
|
||||
|
||||
pub fn expect_fragment<'t>(
|
||||
db: &dyn salsa::Database,
|
||||
tt_iter: &mut TtIter<'t, Span>,
|
||||
entry_point: ::parser::PrefixEntryPoint,
|
||||
edition: ::parser::Edition,
|
||||
delim_span: DelimSpan<Span>,
|
||||
) -> ExpandResult<tt::TokenTreesView<'t, Span>> {
|
||||
use ::parser;
|
||||
let buffer = tt_iter.remaining();
|
||||
// FIXME: Pass the correct edition per token. Due to the split between mbe and hir-expand it's complicated.
|
||||
let parser_input = to_parser_input(buffer, &mut |_ctx| edition);
|
||||
let parser_input = to_parser_input(buffer, &mut |ctx| ctx.edition(db));
|
||||
let tree_traversal = entry_point.parse(&parser_input);
|
||||
let mut cursor = buffer.cursor();
|
||||
let mut error = false;
|
||||
|
||||
@@ -22,6 +22,7 @@ fn check_(
|
||||
expect: expect_test::Expect,
|
||||
parse: parser::TopEntryPoint,
|
||||
) {
|
||||
let db = salsa::DatabaseImpl::default();
|
||||
let decl_tt = &syntax_bridge::parse_to_token_tree(
|
||||
def_edition,
|
||||
SpanAnchor {
|
||||
@@ -49,6 +50,7 @@ fn check_(
|
||||
)
|
||||
.unwrap();
|
||||
let res = mac.expand(
|
||||
&db,
|
||||
&arg_tt,
|
||||
|_| (),
|
||||
crate::MacroCallStyle::FnLike,
|
||||
@@ -57,7 +59,6 @@ fn check_(
|
||||
anchor: call_anchor,
|
||||
ctx: SyntaxContext::root(Edition::CURRENT),
|
||||
},
|
||||
def_edition,
|
||||
);
|
||||
let mut expect_res = String::new();
|
||||
if let Some(err) = res.err {
|
||||
|
||||
Reference in New Issue
Block a user