diff --git a/Cargo.lock b/Cargo.lock index 7432a82080d0..7c98a60d6324 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1236,6 +1236,7 @@ dependencies = [ "parser", "ra-ap-rustc_lexer", "rustc-hash 2.1.1", + "salsa", "smallvec", "span", "stdx", diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs index c6d901ec93bc..bd8f6214977a 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -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() { + ; +} + "#]], + ); +} diff --git a/crates/hir-expand/src/builtin/fn_macro.rs b/crates/hir-expand/src/builtin/fn_macro.rs index 800b40a9e7e5..13c3a6cbcb4e 100644 --- a/crates/hir-expand/src/builtin/fn_macro.rs +++ b/crates/hir-expand/src/builtin/fn_macro.rs @@ -18,7 +18,7 @@ use syntax::{ 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, quote}, db::ExpandDatabase, hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt}, @@ -229,9 +229,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(','); diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 888c1405a6bb..fbf073f7619c 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -298,7 +298,7 @@ pub fn expand_speculative( pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span) } MacroDefKind::Declarative(it) => { - db.decl_macro_expander(loc.krate, it).expand_unhygienic(tt, span, loc.def.edition) + db.decl_macro_expander(loc.krate, it).expand_unhygienic(db, tt, span) } MacroDefKind::BuiltIn(_, it) => { it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) diff --git a/crates/hir-expand/src/declarative.rs b/crates/hir-expand/src/declarative.rs index 0d100c1364ab..af2252d06ac8 100644 --- a/crates/hir-expand/src/declarative.rs +++ b/crates/hir-expand/src/declarative.rs @@ -32,7 +32,6 @@ impl DeclarativeMacroExpander { call_id: MacroCallId, span: Span, ) -> ExpandResult<(tt::TopSubtree, Option)> { - let loc = db.lookup_intern_macro_call(call_id); match self.mac.err() { Some(_) => ExpandResult::new( (tt::TopSubtree::empty(tt::DelimSpan { open: span, close: span }), None), @@ -41,13 +40,13 @@ impl DeclarativeMacroExpander { None => self .mac .expand( + db, &tt, |s| { s.ctx = apply_mark(db, s.ctx, call_id.into(), self.transparency, self.edition) }, span, - loc.def.edition, ) .map_err(Into::into), } @@ -55,20 +54,18 @@ impl DeclarativeMacroExpander { pub fn expand_unhygienic( &self, + db: &dyn ExpandDatabase, tt: tt::TopSubtree, call_site: Span, - def_site_edition: Edition, ) -> ExpandResult { match self.mac.err() { Some(_) => ExpandResult::new( tt::TopSubtree::empty(tt::DelimSpan { open: call_site, close: call_site }), ExpandError::new(call_site, ExpandErrorKind::MacroDefinition), ), - None => self - .mac - .expand(&tt, |_| (), call_site, def_site_edition) - .map(TupleExt::head) - .map_err(Into::into), + None => { + self.mac.expand(db, &tt, |_| (), call_site).map(TupleExt::head).map_err(Into::into) + } } } diff --git a/crates/mbe/Cargo.toml b/crates/mbe/Cargo.toml index eef718b7062a..a313c87225f0 100644 --- a/crates/mbe/Cargo.toml +++ b/crates/mbe/Cargo.toml @@ -18,6 +18,7 @@ rustc-hash.workspace = true smallvec.workspace = true arrayvec.workspace = true ra-ap-rustc_lexer.workspace = true +salsa.workspace = true # local deps parser.workspace = true diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs index 04ac85ad43dd..a8844b44e350 100644 --- a/crates/mbe/src/benchmark.rs +++ b/crates/mbe/src/benchmark.rs @@ -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,15 +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, |_| (), DUMMY, Edition::CURRENT); + let res = rules[&id].expand(&db, &tt, |_| (), DUMMY); assert!(res.err.is_none()); res.value.0.0.len() }) @@ -92,6 +93,7 @@ fn macro_rules_fixtures_tt() -> FxHashMap> { /// Generate random invocation fixtures from rules fn invocation_fixtures( + db: &dyn salsa::Database, rules: &FxHashMap, ) -> Vec<(String, tt::TopSubtree)> { let mut seed = 123456789; @@ -123,7 +125,7 @@ fn invocation_fixtures( } let subtree = builder.build(); - if it.expand(&subtree, |_| (), DUMMY, Edition::CURRENT).err.is_none() { + if it.expand(db, &subtree, |_| (), DUMMY).err.is_none() { res.push((name.clone(), subtree)); break; } diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs index f910f9f9d753..0b109b751d3e 100644 --- a/crates/mbe/src/expander.rs +++ b/crates/mbe/src/expander.rs @@ -7,20 +7,20 @@ mod transcriber; use intern::Symbol; use rustc_hash::FxHashMap; -use span::{Edition, Span}; +use span::Span; use crate::{ExpandError, ExpandErrorKind, ExpandResult, MatchedArmIndex, parser::MetaVarKind}; pub(crate) fn expand_rules( + db: &dyn salsa::Database, rules: &[crate::Rule], input: &tt::TopSubtree, marker: impl Fn(&mut Span) + Copy, call_site: Span, - def_site_edition: Edition, ) -> ExpandResult<(tt::TopSubtree, MatchedArmIndex)> { let mut match_: Option<(matcher::Match<'_>, &crate::Rule, usize)> = None; for (idx, rule) in rules.iter().enumerate() { - 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. diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index a8d5965d480c..0f8483a59f84 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -63,7 +63,7 @@ use std::{rc::Rc, sync::Arc}; 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 @@ impl Match<'_> { /// Matching errors are added to the `Match`. pub(super) fn match_<'t>( + db: &dyn salsa::Database, pattern: &'t MetaTemplate, input: &'t tt::TopSubtree, - 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, - edition: Edition, ) { macro_rules! try_push { ($items: expr, $it:expr) => { @@ -486,7 +486,7 @@ fn match_loop_inner<'t>( 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 @@ fn match_loop_inner<'t>( } fn match_loop<'t>( + db: &dyn salsa::Database, pattern: &'t MetaTemplate, src: &'t tt::TopSubtree, - 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, - edition: Edition, ) -> ExpandResult> { 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) { diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 9f9fa36abd46..558c474b2233 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs @@ -251,12 +251,12 @@ impl DeclarativeMacro { pub fn expand( &self, + db: &dyn salsa::Database, tt: &tt::TopSubtree, marker: impl Fn(&mut Span) + Copy, call_site: Span, - def_site_edition: Edition, ) -> ExpandResult<(tt::TopSubtree, MatchedArmIndex)> { - expander::expand_rules(&self.rules, tt, marker, call_site, def_site_edition) + expander::expand_rules(db, &self.rules, tt, marker, call_site) } } @@ -362,16 +362,15 @@ impl From> for ValueResult { } 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, ) -> ExpandResult> { 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 tree_traversal = entry_point.parse(&parser_input, edition); + let parser_input = to_parser_input(buffer, &mut |ctx| ctx.edition(db)); + let tree_traversal = entry_point.parse(&parser_input, Edition::CURRENT_FIXME); let mut cursor = buffer.cursor(); let mut error = false; for step in tree_traversal.iter() { diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index 56034516ef3b..c7cf7419e4b2 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs @@ -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, |_| (), Span { @@ -56,7 +58,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 {