From 255a8aef92137195b803b5b5df22a4ebe49c2168 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 19 Mar 2024 16:53:34 +0100 Subject: [PATCH 1/3] Move Edition into span crate --- Cargo.lock | 3 + crates/base-db/src/input.rs | 73 +------------------ crates/base-db/src/lib.rs | 6 +- crates/hir-def/src/lib.rs | 4 +- crates/hir-def/src/nameres.rs | 4 +- crates/hir-def/src/nameres/collector.rs | 4 +- crates/hir-def/src/nameres/path_resolution.rs | 2 +- crates/hir-expand/src/builtin_fn_macro.rs | 4 +- crates/hir-expand/src/declarative.rs | 4 +- crates/hir-expand/src/lib.rs | 5 +- crates/hir-ty/Cargo.toml | 1 + crates/hir-ty/src/method_resolution.rs | 3 +- crates/hir/src/lib.rs | 3 +- crates/ide/Cargo.toml | 1 + crates/ide/src/lib.rs | 5 +- crates/project-model/Cargo.toml | 1 + crates/project-model/src/cargo_workspace.rs | 2 +- crates/project-model/src/project_json.rs | 3 +- crates/project-model/src/workspace.rs | 5 +- crates/span/src/lib.rs | 50 +++++++++++++ crates/test-fixture/src/lib.rs | 21 ++++-- 21 files changed, 103 insertions(+), 101 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 733e119b04c0..7ab4e24f08f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -594,6 +594,7 @@ dependencies = [ "rustc-hash", "scoped-tls", "smallvec", + "span", "stdx", "syntax", "test-fixture", @@ -637,6 +638,7 @@ dependencies = [ "pulldown-cmark", "pulldown-cmark-to-cmark", "smallvec", + "span", "stdx", "syntax", "test-fixture", @@ -1380,6 +1382,7 @@ dependencies = [ "semver", "serde", "serde_json", + "span", "stdx", "toolchain", "tracing", diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index b243b37b77b9..f59c4e50168e 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -6,11 +6,12 @@ //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how //! actual IO is done and lowered to input. -use std::{fmt, mem, ops, str::FromStr}; +use std::{fmt, mem, ops}; use cfg::CfgOptions; use la_arena::{Arena, Idx, RawIdx}; use rustc_hash::{FxHashMap, FxHashSet}; +use span::Edition; use syntax::SmolStr; use triomphe::Arc; use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath}; @@ -293,42 +294,11 @@ pub struct CrateData { pub is_proc_macro: bool, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Edition { - Edition2015, - Edition2018, - Edition2021, - Edition2024, -} - -impl Edition { - pub const CURRENT: Edition = Edition::Edition2021; - pub const DEFAULT: Edition = Edition::Edition2015; -} - #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Env { entries: FxHashMap, } -impl Env { - pub fn new_for_test_fixture() -> Self { - Env { - entries: FxHashMap::from_iter([( - String::from("__ra_is_test_fixture"), - String::from("__ra_is_test_fixture"), - )]), - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum DependencyKind { - Normal, - Dev, - Build, -} - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Dependency { pub crate_id: CrateId, @@ -670,32 +640,6 @@ impl CrateData { } } -impl FromStr for Edition { - type Err = ParseEditionError; - - fn from_str(s: &str) -> Result { - let res = match s { - "2015" => Edition::Edition2015, - "2018" => Edition::Edition2018, - "2021" => Edition::Edition2021, - "2024" => Edition::Edition2024, - _ => return Err(ParseEditionError { invalid_input: s.to_owned() }), - }; - Ok(res) - } -} - -impl fmt::Display for Edition { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Edition::Edition2015 => "2015", - Edition::Edition2018 => "2018", - Edition::Edition2021 => "2021", - Edition::Edition2024 => "2024", - }) - } -} - impl Extend<(String, String)> for Env { fn extend>(&mut self, iter: T) { self.entries.extend(iter); @@ -722,19 +666,6 @@ impl Env { } } -#[derive(Debug)] -pub struct ParseEditionError { - invalid_input: String, -} - -impl fmt::Display for ParseEditionError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "invalid edition: {:?}", self.invalid_input) - } -} - -impl std::error::Error for ParseEditionError {} - #[derive(Debug)] pub struct CyclicDependenciesError { path: Vec<(CrateId, Option)>, diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 5dcb580723fa..785ff9ceffad 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -14,9 +14,9 @@ use triomphe::Arc; pub use crate::{ change::FileChange, input::{ - CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, - DependencyKind, Edition, Env, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, SourceRoot, - SourceRootId, TargetLayoutLoadResult, + CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, + LangCrateOrigin, ProcMacroPaths, ReleaseChannel, SourceRoot, SourceRootId, + TargetLayoutLoadResult, }, }; pub use salsa::{self, Cancelled}; diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 828842de7e8a..46898ce542d6 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -73,7 +73,7 @@ use std::{ use base_db::{ impl_intern_key, salsa::{self, impl_intern_value_trivial}, - CrateId, Edition, + CrateId, }; use hir_expand::{ builtin_attr_macro::BuiltinAttrExpander, @@ -90,7 +90,7 @@ use hir_expand::{ use item_tree::ExternBlock; use la_arena::Idx; use nameres::DefMap; -use span::{AstIdNode, FileAstId, FileId, SyntaxContextId}; +use span::{AstIdNode, Edition, FileAstId, FileId, SyntaxContextId}; use stdx::impl_from; use syntax::{ast, AstNode}; diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index b56dee3efb55..2d1e92c1afe8 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -59,14 +59,14 @@ mod tests; use std::ops::Deref; -use base_db::{CrateId, Edition, FileId}; +use base_db::{CrateId, FileId}; use hir_expand::{ name::Name, proc_macro::ProcMacroKind, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, }; use itertools::Itertools; use la_arena::Arena; use rustc_hash::{FxHashMap, FxHashSet}; -use span::{FileAstId, ROOT_ERASED_FILE_AST_ID}; +use span::{Edition, FileAstId, ROOT_ERASED_FILE_AST_ID}; use stdx::format_to; use syntax::{ast, SmolStr}; use triomphe::Arc; diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 3d026447fb74..312938e2c17f 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -5,7 +5,7 @@ use std::{cmp::Ordering, iter, mem, ops::Not}; -use base_db::{CrateId, Dependency, Edition, FileId}; +use base_db::{CrateId, Dependency, FileId}; use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ @@ -22,7 +22,7 @@ use itertools::{izip, Itertools}; use la_arena::Idx; use limit::Limit; use rustc_hash::{FxHashMap, FxHashSet}; -use span::{ErasedFileAstId, FileAstId, Span, SyntaxContextId}; +use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId}; use stdx::always; use syntax::{ast, SmolStr}; use triomphe::Arc; diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs index 9e53b0372830..ee29b89f3d3b 100644 --- a/crates/hir-def/src/nameres/path_resolution.rs +++ b/crates/hir-def/src/nameres/path_resolution.rs @@ -10,8 +10,8 @@ //! //! `ReachedFixedPoint` signals about this. -use base_db::Edition; use hir_expand::{name::Name, Lookup}; +use span::Edition; use triomphe::Arc; use crate::{ diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index 9fb6a0b2346b..fd3e4e7a4dba 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -1,11 +1,11 @@ //! Builtin macro -use base_db::{AnchoredPath, Edition, FileId}; +use base_db::{AnchoredPath, FileId}; use cfg::CfgExpr; use either::Either; use itertools::Itertools; use mbe::{parse_exprs_with_sep, parse_to_token_tree}; -use span::{Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; +use span::{Edition, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; use syntax::ast::{self, AstToken}; use crate::{ diff --git a/crates/hir-expand/src/declarative.rs b/crates/hir-expand/src/declarative.rs index 33643c02724f..7272ea5c35f9 100644 --- a/crates/hir-expand/src/declarative.rs +++ b/crates/hir-expand/src/declarative.rs @@ -1,8 +1,8 @@ //! Compiled declarative macro expanders (`macro_rules!`` and `macro`) use std::sync::OnceLock; -use base_db::{CrateId, Edition, VersionReq}; -use span::{MacroCallId, Span}; +use base_db::{CrateId, VersionReq}; +use span::{Edition, MacroCallId, Span}; use syntax::{ast, AstNode}; use triomphe::Arc; diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 5d4f7dc1462a..80b851871128 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -30,10 +30,11 @@ use triomphe::Arc; use std::{fmt, hash::Hash}; -use base_db::{salsa::impl_intern_value_trivial, CrateId, Edition, FileId}; +use base_db::{salsa::impl_intern_value_trivial, CrateId, FileId}; use either::Either; use span::{ - ErasedFileAstId, FileRange, HirFileIdRepr, Span, SpanAnchor, SyntaxContextData, SyntaxContextId, + Edition, ErasedFileAstId, FileRange, HirFileIdRepr, Span, SpanAnchor, SyntaxContextData, + SyntaxContextId, }; use syntax::{ ast::{self, AstNode}, diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index a2711f8cbe34..bf473740166c 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -47,6 +47,7 @@ hir-expand.workspace = true base-db.workspace = true syntax.workspace = true limit.workspace = true +span.workspace = true [dev-dependencies] expect-test = "1.4.0" diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 0885d92ae8a5..064d317835fd 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -4,7 +4,7 @@ //! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs. use std::ops::ControlFlow; -use base_db::{CrateId, Edition}; +use base_db::CrateId; use chalk_ir::{cast::Cast, Mutability, TyKind, UniverseIndex, WhereClause}; use hir_def::{ data::{adt::StructFlags, ImplData}, @@ -15,6 +15,7 @@ use hir_def::{ use hir_expand::name::Name; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; +use span::Edition; use stdx::never; use triomphe::Arc; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 9d7be9a4219e..15a0967b3d7f 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -38,7 +38,7 @@ mod display; use std::{iter, mem::discriminant, ops::ControlFlow}; use arrayvec::ArrayVec; -use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId}; +use base_db::{CrateDisplayName, CrateId, CrateOrigin, FileId}; use either::Either; use hir_def::{ body::{BodyDiagnostic, SyntheticSyntax}, @@ -79,6 +79,7 @@ use hir_ty::{ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; +use span::Edition; use stdx::{impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasName}, diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index aca7d613e11f..a535015a27f0 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml @@ -36,6 +36,7 @@ ide-ssr.workspace = true profile.workspace = true stdx.workspace = true syntax.workspace = true +span.workspace = true text-edit.workspace = true # ide should depend only on the top-level `hir` package. if you need # something from some `hir-xxx` subpackage, reexport the API via `hir`. diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 11eaa88c5c43..7a6c6ec41d0e 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -119,8 +119,8 @@ pub use ide_completion::{ }; pub use ide_db::{ base_db::{ - Cancelled, CrateGraph, CrateId, Edition, FileChange, FileId, FilePosition, FileRange, - SourceRoot, SourceRootId, + Cancelled, CrateGraph, CrateId, FileChange, FileId, FilePosition, FileRange, SourceRoot, + SourceRootId, }, documentation::Documentation, label::Label, @@ -135,6 +135,7 @@ pub use ide_diagnostics::{ Diagnostic, DiagnosticCode, DiagnosticsConfig, ExprFillDefaultMode, Severity, }; pub use ide_ssr::SsrError; +pub use span::Edition; pub use syntax::{TextRange, TextSize}; pub use text_edit::{Indel, TextEdit}; diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml index 139689975d72..097ee1f75cd7 100644 --- a/crates/project-model/Cargo.toml +++ b/crates/project-model/Cargo.toml @@ -25,6 +25,7 @@ itertools.workspace = true # local deps base-db.workspace = true +span.workspace = true cfg.workspace = true paths = { workspace = true, features = ["serde1"] } stdx.workspace = true diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs index 4f6bac08f69e..957366b61045 100644 --- a/crates/project-model/src/cargo_workspace.rs +++ b/crates/project-model/src/cargo_workspace.rs @@ -4,13 +4,13 @@ use std::ops; use std::str::from_utf8; use anyhow::Context; -use base_db::Edition; use cargo_metadata::{CargoOpt, MetadataCommand}; use la_arena::{Arena, Idx}; use paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use serde::Deserialize; use serde_json::from_value; +use span::Edition; use toolchain::Tool; use crate::{utf8_stdout, InvocationLocation, ManifestPath, Sysroot}; diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs index 0b6e8caf5ddb..512588cc8f8f 100644 --- a/crates/project-model/src/project_json.rs +++ b/crates/project-model/src/project_json.rs @@ -49,11 +49,12 @@ //! user explores them belongs to that extension (it's totally valid to change //! rust-project.json over time via configuration request!) -use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition}; +use base_db::{CrateDisplayName, CrateId, CrateName, Dependency}; use la_arena::RawIdx; use paths::{AbsPath, AbsPathBuf, Utf8PathBuf}; use rustc_hash::FxHashMap; use serde::{de, Deserialize}; +use span::Edition; use crate::cfg_flag::CfgFlag; diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index c6642efca247..1556e9b54908 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -6,13 +6,14 @@ use std::{collections::VecDeque, fmt, fs, iter, str::FromStr, sync}; use anyhow::{format_err, Context}; use base_db::{ - CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult, + CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, FileId, + LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult, }; use cfg::{CfgAtom, CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; +use span::Edition; use stdx::always; use toolchain::Tool; use triomphe::Arc; diff --git a/crates/span/src/lib.rs b/crates/span/src/lib.rs index 6b849ce37381..c9109c72d0d2 100644 --- a/crates/span/src/lib.rs +++ b/crates/span/src/lib.rs @@ -16,6 +16,56 @@ pub use self::{ pub use syntax::{TextRange, TextSize}; pub use vfs::FileId; +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Edition { + Edition2015, + Edition2018, + Edition2021, + Edition2024, +} + +impl Edition { + pub const CURRENT: Edition = Edition::Edition2021; + pub const DEFAULT: Edition = Edition::Edition2015; +} + +#[derive(Debug)] +pub struct ParseEditionError { + invalid_input: String, +} + +impl std::error::Error for ParseEditionError {} +impl fmt::Display for ParseEditionError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "invalid edition: {:?}", self.invalid_input) + } +} + +impl std::str::FromStr for Edition { + type Err = ParseEditionError; + + fn from_str(s: &str) -> Result { + let res = match s { + "2015" => Edition::Edition2015, + "2018" => Edition::Edition2018, + "2021" => Edition::Edition2021, + "2024" => Edition::Edition2024, + _ => return Err(ParseEditionError { invalid_input: s.to_owned() }), + }; + Ok(res) + } +} + +impl fmt::Display for Edition { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Edition::Edition2015 => "2015", + Edition::Edition2018 => "2018", + Edition::Edition2021 => "2021", + Edition::Edition2024 => "2024", + }) + } +} #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct FilePosition { pub file_id: FileId, diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs index 8cf65d11c6c0..b20315eefc87 100644 --- a/crates/test-fixture/src/lib.rs +++ b/crates/test-fixture/src/lib.rs @@ -2,8 +2,8 @@ use std::{iter, mem, ops::Not, str::FromStr, sync}; use base_db::{ - CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileChange, FileSet, LangCrateOrigin, SourceDatabaseExt, SourceRoot, Version, VfsPath, + CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, FileChange, + FileSet, LangCrateOrigin, SourceDatabaseExt, SourceRoot, Version, VfsPath, }; use cfg::CfgOptions; use hir_expand::{ @@ -14,7 +14,7 @@ use hir_expand::{ }, }; use rustc_hash::FxHashMap; -use span::{FileId, FilePosition, FileRange, Span}; +use span::{Edition, FileId, FilePosition, FileRange, Span}; use test_utils::{ extract_range_or_offset, Fixture, FixtureWithProjectMeta, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER, @@ -137,7 +137,10 @@ impl ChangeFixture { let mut crate_deps = Vec::new(); let mut default_crate_root: Option = None; let mut default_cfg = CfgOptions::default(); - let mut default_env = Env::new_for_test_fixture(); + let mut default_env = Env::from_iter([( + String::from("__ra_is_test_fixture"), + String::from("__ra_is_test_fixture"), + )]); let mut file_set = FileSet::default(); let mut current_source_root_kind = SourceRootKind::Local; @@ -262,7 +265,10 @@ impl ChangeFixture { None, Default::default(), Default::default(), - Env::new_for_test_fixture(), + Env::from_iter([( + String::from("__ra_is_test_fixture"), + String::from("__ra_is_test_fixture"), + )]), false, CrateOrigin::Lang(LangCrateOrigin::Core), ); @@ -298,7 +304,10 @@ impl ChangeFixture { None, Default::default(), Default::default(), - Env::new_for_test_fixture(), + Env::from_iter([( + String::from("__ra_is_test_fixture"), + String::from("__ra_is_test_fixture"), + )]), true, CrateOrigin::Local { repo: None, name: None }, ); From 7e88fa5d3a6914ae95b2c846f2ddb63a334576cd Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 19 Mar 2024 17:06:50 +0100 Subject: [PATCH 2/3] Remove span generics from most of the mbe crate --- crates/hir-expand/src/declarative.rs | 2 +- crates/hir-expand/src/lib.rs | 4 +- crates/mbe/src/benchmark.rs | 10 +- crates/mbe/src/expander.rs | 42 +++---- crates/mbe/src/expander/matcher.rs | 150 +++++++++++-------------- crates/mbe/src/expander/transcriber.rs | 99 ++++++++-------- crates/mbe/src/lib.rs | 38 +++---- crates/mbe/src/parser.rs | 70 ++++++------ 8 files changed, 187 insertions(+), 228 deletions(-) diff --git a/crates/hir-expand/src/declarative.rs b/crates/hir-expand/src/declarative.rs index 7272ea5c35f9..eceb20df5f84 100644 --- a/crates/hir-expand/src/declarative.rs +++ b/crates/hir-expand/src/declarative.rs @@ -16,7 +16,7 @@ use crate::{ /// Old-style `macro_rules` or the new macros 2.0 #[derive(Debug, Clone, Eq, PartialEq)] pub struct DeclarativeMacroExpander { - pub mac: mbe::DeclarativeMacro, + pub mac: mbe::DeclarativeMacro, pub transparency: Transparency, } diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 80b851871128..2233ae51fa84 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -54,11 +54,9 @@ use crate::{ pub use crate::files::{AstId, ErasedAstId, InFile, InMacroFile, InRealFile}; -pub use mbe::ValueResult; +pub use mbe::{DeclarativeMacro, ValueResult}; pub use span::{HirFileId, MacroCallId, MacroFileId}; -pub type DeclarativeMacro = ::mbe::DeclarativeMacro; - pub mod tt { pub use span::Span; pub use tt::{DelimiterKind, Spacing}; diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs index ac7f07117845..cacd5ed81a52 100644 --- a/crates/mbe/src/benchmark.rs +++ b/crates/mbe/src/benchmark.rs @@ -51,7 +51,7 @@ fn benchmark_expand_macro_rules() { assert_eq!(hash, 69413); } -fn macro_rules_fixtures() -> FxHashMap> { +fn macro_rules_fixtures() -> FxHashMap { macro_rules_fixtures_tt() .into_iter() .map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, true, true))) @@ -80,7 +80,7 @@ fn macro_rules_fixtures_tt() -> FxHashMap> { /// Generate random invocation fixtures from rules fn invocation_fixtures( - rules: &FxHashMap>, + rules: &FxHashMap, ) -> Vec<(String, tt::Subtree)> { let mut seed = 123456789; let mut res = Vec::new(); @@ -128,11 +128,7 @@ fn invocation_fixtures( } return res; - fn collect_from_op( - op: &Op, - token_trees: &mut Vec>, - seed: &mut usize, - ) { + fn collect_from_op(op: &Op, token_trees: &mut Vec>, seed: &mut usize) { return match op { Op::Var { kind, .. } => match kind.as_ref() { Some(MetaVarKind::Ident) => token_trees.push(make_ident("foo")), diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs index 9366048fd955..9e365232656d 100644 --- a/crates/mbe/src/expander.rs +++ b/crates/mbe/src/expander.rs @@ -6,20 +6,20 @@ mod matcher; mod transcriber; use rustc_hash::FxHashMap; +use span::Span; use syntax::SmolStr; -use tt::Span; use crate::{parser::MetaVarKind, ExpandError, ExpandResult}; -pub(crate) fn expand_rules( - rules: &[crate::Rule], - input: &tt::Subtree, - marker: impl Fn(&mut S) + Copy, +pub(crate) fn expand_rules( + rules: &[crate::Rule], + input: &tt::Subtree, + marker: impl Fn(&mut Span) + Copy, is_2021: bool, new_meta_vars: bool, - call_site: S, -) -> ExpandResult> { - let mut match_: Option<(matcher::Match, &crate::Rule)> = None; + call_site: Span, +) -> ExpandResult> { + let mut match_: Option<(matcher::Match, &crate::Rule)> = None; for rule in rules { let new_match = matcher::match_(&rule.lhs, input, is_2021); @@ -110,30 +110,24 @@ pub(crate) fn expand_rules( /// In other words, `Bindings` is a *multi* mapping from `SmolStr` to /// `tt::TokenTree`, where the index to select a particular `TokenTree` among /// many is not a plain `usize`, but a `&[usize]`. -#[derive(Debug, Clone, PartialEq, Eq)] -struct Bindings { - inner: FxHashMap>, -} - -impl Default for Bindings { - fn default() -> Self { - Self { inner: Default::default() } - } +#[derive(Debug, Default, Clone, PartialEq, Eq)] +struct Bindings { + inner: FxHashMap, } #[derive(Debug, Clone, PartialEq, Eq)] -enum Binding { - Fragment(Fragment), - Nested(Vec>), +enum Binding { + Fragment(Fragment), + Nested(Vec), Empty, Missing(MetaVarKind), } #[derive(Debug, Clone, PartialEq, Eq)] -enum Fragment { +enum Fragment { Empty, /// token fragments are just copy-pasted into the output - Tokens(tt::TokenTree), + Tokens(tt::TokenTree), /// Expr ast fragments are surrounded with `()` on insertion to preserve /// precedence. Note that this impl is different from the one currently in /// `rustc` -- `rustc` doesn't translate fragments into token trees at all. @@ -141,7 +135,7 @@ enum Fragment { /// At one point in time, we tried to use "fake" delimiters here à la /// proc-macro delimiter=none. As we later discovered, "none" delimiters are /// tricky to handle in the parser, and rustc doesn't handle those either. - Expr(tt::Subtree), + Expr(tt::Subtree), /// There are roughly two types of paths: paths in expression context, where a /// separator `::` between an identifier and its following generic argument list /// is mandatory, and paths in type context, where `::` can be omitted. @@ -151,5 +145,5 @@ enum Fragment { /// and is trasncribed as an expression-context path, verbatim transcription /// would cause a syntax error. We need to fix it up just before transcribing; /// see `transcriber::fix_up_and_push_path_tt()`. - Path(tt::Subtree), + Path(tt::Subtree), } diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index eea92cfba4c2..e14e13856fd2 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -62,8 +62,9 @@ use std::rc::Rc; use smallvec::{smallvec, SmallVec}; +use span::Span; use syntax::SmolStr; -use tt::{DelimSpan, Span}; +use tt::DelimSpan; use crate::{ expander::{Binding, Bindings, ExpandResult, Fragment}, @@ -72,7 +73,7 @@ use crate::{ ExpandError, MetaTemplate, ValueResult, }; -impl Bindings { +impl Bindings { fn push_optional(&mut self, name: &SmolStr) { self.inner.insert(name.clone(), Binding::Fragment(Fragment::Empty)); } @@ -81,14 +82,14 @@ impl Bindings { self.inner.insert(name.clone(), Binding::Empty); } - fn bindings(&self) -> impl Iterator> { + fn bindings(&self) -> impl Iterator { self.inner.values() } } -#[derive(Clone, Debug, PartialEq, Eq)] -pub(super) struct Match { - pub(super) bindings: Bindings, +#[derive(Clone, Default, Debug, PartialEq, Eq)] +pub(super) struct Match { + pub(super) bindings: Bindings, /// We currently just keep the first error and count the rest to compare matches. pub(super) err: Option, pub(super) err_count: usize, @@ -98,19 +99,7 @@ pub(super) struct Match { pub(super) bound_count: usize, } -impl Default for Match { - fn default() -> Self { - Self { - bindings: Default::default(), - err: Default::default(), - err_count: Default::default(), - unmatched_tts: Default::default(), - bound_count: Default::default(), - } - } -} - -impl Match { +impl Match { fn add_err(&mut self, err: ExpandError) { let prev_err = self.err.take(); self.err = prev_err.or(Some(err)); @@ -119,16 +108,12 @@ impl Match { } /// Matching errors are added to the `Match`. -pub(super) fn match_( - pattern: &MetaTemplate, - input: &tt::Subtree, - is_2021: bool, -) -> Match { +pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree, is_2021: bool) -> Match { let mut res = match_loop(pattern, input, is_2021); res.bound_count = count(res.bindings.bindings()); return res; - fn count<'a, S: 'a>(bindings: impl Iterator>) -> usize { + fn count<'a>(bindings: impl Iterator) -> usize { bindings .map(|it| match it { Binding::Fragment(_) => 1, @@ -141,10 +126,10 @@ pub(super) fn match_( } #[derive(Debug, Clone)] -enum BindingKind { +enum BindingKind { Empty(SmolStr), Optional(SmolStr), - Fragment(SmolStr, Fragment), + Fragment(SmolStr, Fragment), Missing(SmolStr, MetaVarKind), Nested(usize, usize), } @@ -158,18 +143,13 @@ enum LinkNode { Parent { idx: usize, len: usize }, } -struct BindingsBuilder { - nodes: Vec>>>>, +#[derive(Default)] +struct BindingsBuilder { + nodes: Vec>>>, nested: Vec>>, } -impl Default for BindingsBuilder { - fn default() -> Self { - Self { nodes: Default::default(), nested: Default::default() } - } -} - -impl BindingsBuilder { +impl BindingsBuilder { fn alloc(&mut self) -> BindingsIdx { let idx = self.nodes.len(); self.nodes.push(Vec::new()); @@ -206,7 +186,7 @@ impl BindingsBuilder { self.nodes[idx.0].push(LinkNode::Node(Rc::new(BindingKind::Optional(var.clone())))); } - fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &SmolStr, fragment: Fragment) { + fn push_fragment(&mut self, idx: &mut BindingsIdx, var: &SmolStr, fragment: Fragment) { self.nodes[idx.0] .push(LinkNode::Node(Rc::new(BindingKind::Fragment(var.clone(), fragment)))); } @@ -227,11 +207,11 @@ impl BindingsBuilder { idx.0 = new_idx; } - fn build(self, idx: &BindingsIdx) -> Bindings { + fn build(self, idx: &BindingsIdx) -> Bindings { self.build_inner(&self.nodes[idx.0]) } - fn build_inner(&self, link_nodes: &[LinkNode>>]) -> Bindings { + fn build_inner(&self, link_nodes: &[LinkNode>]) -> Bindings { let mut bindings = Bindings::default(); let mut nodes = Vec::new(); self.collect_nodes(link_nodes, &mut nodes); @@ -281,7 +261,7 @@ impl BindingsBuilder { &'a self, id: usize, len: usize, - nested_refs: &mut Vec<&'a [LinkNode>>]>, + nested_refs: &mut Vec<&'a [LinkNode>]>, ) { self.nested[id].iter().take(len).for_each(|it| match it { LinkNode::Node(id) => nested_refs.push(&self.nodes[*id]), @@ -289,7 +269,7 @@ impl BindingsBuilder { }); } - fn collect_nested(&self, idx: usize, nested_idx: usize, nested: &mut Vec>) { + fn collect_nested(&self, idx: usize, nested_idx: usize, nested: &mut Vec) { let last = &self.nodes[idx]; let mut nested_refs: Vec<&[_]> = Vec::new(); self.nested[nested_idx].iter().for_each(|it| match *it { @@ -300,7 +280,7 @@ impl BindingsBuilder { nested.extend(nested_refs.into_iter().map(|iter| self.build_inner(iter))); } - fn collect_nodes_ref<'a>(&'a self, id: usize, len: usize, nodes: &mut Vec<&'a BindingKind>) { + fn collect_nodes_ref<'a>(&'a self, id: usize, len: usize, nodes: &mut Vec<&'a BindingKind>) { self.nodes[id].iter().take(len).for_each(|it| match it { LinkNode::Node(it) => nodes.push(it), LinkNode::Parent { idx, len } => self.collect_nodes_ref(*idx, *len, nodes), @@ -309,8 +289,8 @@ impl BindingsBuilder { fn collect_nodes<'a>( &'a self, - link_nodes: &'a [LinkNode>>], - nodes: &mut Vec<&'a BindingKind>, + link_nodes: &'a [LinkNode>], + nodes: &mut Vec<&'a BindingKind>, ) { link_nodes.iter().for_each(|it| match it { LinkNode::Node(it) => nodes.push(it), @@ -320,22 +300,22 @@ impl BindingsBuilder { } #[derive(Debug, Clone)] -struct MatchState<'t, S> { +struct MatchState<'t> { /// The position of the "dot" in this matcher - dot: OpDelimitedIter<'t, S>, + dot: OpDelimitedIter<'t>, /// Token subtree stack /// When matching against matchers with nested delimited submatchers (e.g., `pat ( pat ( .. ) /// pat ) pat`), we need to keep track of the matchers we are descending into. This stack does /// that where the bottom of the stack is the outermost matcher. - stack: SmallVec<[OpDelimitedIter<'t, S>; 4]>, + stack: SmallVec<[OpDelimitedIter<'t>; 4]>, /// The "parent" matcher position if we are in a repetition. That is, the matcher position just /// before we enter the repetition. - up: Option>>, + up: Option>>, /// The separator if we are in a repetition. - sep: Option>, + sep: Option, /// The KleeneOp of this sequence if we are in a repetition. sep_kind: Option, @@ -347,7 +327,7 @@ struct MatchState<'t, S> { bindings: BindingsIdx, /// Cached result of meta variable parsing - meta_result: Option<(TtIter<'t, S>, ExpandResult>>)>, + meta_result: Option<(TtIter<'t, Span>, ExpandResult>)>, /// Is error occurred in this state, will `poised` to "parent" is_error: bool, @@ -372,18 +352,18 @@ struct MatchState<'t, S> { /// - `bb_items`: the set of items that are waiting for the black-box parser. /// - `error_items`: the set of items in errors, used for error-resilient parsing #[inline] -fn match_loop_inner<'t, S: Span>( - src: TtIter<'t, S>, - stack: &[TtIter<'t, S>], - res: &mut Match, - bindings_builder: &mut BindingsBuilder, - cur_items: &mut SmallVec<[MatchState<'t, S>; 1]>, - bb_items: &mut SmallVec<[MatchState<'t, S>; 1]>, - next_items: &mut Vec>, - eof_items: &mut SmallVec<[MatchState<'t, S>; 1]>, - error_items: &mut SmallVec<[MatchState<'t, S>; 1]>, +fn match_loop_inner<'t>( + src: TtIter<'t, Span>, + stack: &[TtIter<'t, Span>], + res: &mut Match, + bindings_builder: &mut BindingsBuilder, + cur_items: &mut SmallVec<[MatchState<'t>; 1]>, + bb_items: &mut SmallVec<[MatchState<'t>; 1]>, + next_items: &mut Vec>, + eof_items: &mut SmallVec<[MatchState<'t>; 1]>, + error_items: &mut SmallVec<[MatchState<'t>; 1]>, is_2021: bool, - delim_span: tt::DelimSpan, + delim_span: tt::DelimSpan, ) { macro_rules! try_push { ($items: expr, $it:expr) => { @@ -607,10 +587,10 @@ fn match_loop_inner<'t, S: Span>( } } -fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree, is_2021: bool) -> Match { +fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree, is_2021: bool) -> Match { let span = src.delimiter.delim_span(); let mut src = TtIter::new(src); - let mut stack: SmallVec<[TtIter<'_, S>; 1]> = SmallVec::new(); + let mut stack: SmallVec<[TtIter<'_, Span>; 1]> = SmallVec::new(); let mut res = Match::default(); let mut error_recover_item = None; @@ -758,12 +738,12 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree, is_2021: } } -fn match_meta_var( +fn match_meta_var( kind: MetaVarKind, - input: &mut TtIter<'_, S>, + input: &mut TtIter<'_, Span>, is_2021: bool, - delim_span: DelimSpan, -) -> ExpandResult>> { + delim_span: DelimSpan, +) -> ExpandResult> { let fragment = match kind { MetaVarKind::Path => { return input.expect_fragment(parser::PrefixEntryPoint::Path).map(|it| { @@ -846,7 +826,7 @@ fn match_meta_var( input.expect_fragment(fragment).map(|it| it.map(Fragment::Tokens)) } -fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) { +fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate) { for op in pattern.iter() { match op { Op::Var { name, .. } => collector_fun(name.clone()), @@ -859,11 +839,11 @@ fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &Meta } } } -impl MetaTemplate { - fn iter_delimited_with(&self, delimiter: tt::Delimiter) -> OpDelimitedIter<'_, S> { +impl MetaTemplate { + fn iter_delimited_with(&self, delimiter: tt::Delimiter) -> OpDelimitedIter<'_> { OpDelimitedIter { inner: &self.0, idx: 0, delimited: delimiter } } - fn iter_delimited(&self, span: tt::DelimSpan) -> OpDelimitedIter<'_, S> { + fn iter_delimited(&self, span: tt::DelimSpan) -> OpDelimitedIter<'_> { OpDelimitedIter { inner: &self.0, idx: 0, @@ -873,27 +853,27 @@ impl MetaTemplate { } #[derive(Debug, Clone, Copy)] -enum OpDelimited<'a, S> { - Op(&'a Op), +enum OpDelimited<'a> { + Op(&'a Op), Open, Close, } #[derive(Debug, Clone, Copy)] -struct OpDelimitedIter<'a, S> { - inner: &'a [Op], - delimited: tt::Delimiter, +struct OpDelimitedIter<'a> { + inner: &'a [Op], + delimited: tt::Delimiter, idx: usize, } -impl<'a, S: Span> OpDelimitedIter<'a, S> { +impl<'a> OpDelimitedIter<'a> { fn is_eof(&self) -> bool { let len = self.inner.len() + if self.delimited.kind != tt::DelimiterKind::Invisible { 2 } else { 0 }; self.idx >= len } - fn peek(&self) -> Option> { + fn peek(&self) -> Option> { match self.delimited.kind { tt::DelimiterKind::Invisible => self.inner.get(self.idx).map(OpDelimited::Op), _ => match self.idx { @@ -909,8 +889,8 @@ impl<'a, S: Span> OpDelimitedIter<'a, S> { } } -impl<'a, S: Span> Iterator for OpDelimitedIter<'a, S> { - type Item = OpDelimited<'a, S>; +impl<'a> Iterator for OpDelimitedIter<'a> { + type Item = OpDelimited<'a>; fn next(&mut self) -> Option { let res = self.peek(); @@ -926,8 +906,8 @@ impl<'a, S: Span> Iterator for OpDelimitedIter<'a, S> { } } -impl TtIter<'_, S> { - fn expect_separator(&mut self, separator: &Separator) -> bool { +impl TtIter<'_, Span> { + fn expect_separator(&mut self, separator: &Separator) -> bool { let mut fork = self.clone(); let ok = match separator { Separator::Ident(lhs) => match fork.expect_ident_or_underscore() { @@ -957,7 +937,7 @@ impl TtIter<'_, S> { ok } - fn expect_tt(&mut self) -> Result, ()> { + fn expect_tt(&mut self) -> Result, ()> { if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = self.peek_n(0) { if punct.char == '\'' { self.expect_lifetime() @@ -976,7 +956,7 @@ impl TtIter<'_, S> { } } - fn expect_lifetime(&mut self) -> Result, ()> { + fn expect_lifetime(&mut self) -> Result, ()> { let punct = self.expect_single_punct()?; if punct.char != '\'' { return Err(()); @@ -997,7 +977,7 @@ impl TtIter<'_, S> { .into()) } - fn eat_char(&mut self, c: char) -> Option> { + fn eat_char(&mut self, c: char) -> Option> { let mut fork = self.clone(); match fork.expect_char(c) { Ok(_) => { diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs index 6d3055da2860..5e6e45f1521b 100644 --- a/crates/mbe/src/expander/transcriber.rs +++ b/crates/mbe/src/expander/transcriber.rs @@ -1,8 +1,9 @@ //! Transcriber takes a template, like `fn $ident() {}`, a set of bindings like //! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}` +use span::Span; use syntax::SmolStr; -use tt::{Delimiter, Span}; +use tt::Delimiter; use crate::{ expander::{Binding, Bindings, Fragment}, @@ -10,8 +11,8 @@ use crate::{ CountError, ExpandError, ExpandResult, MetaTemplate, }; -impl Bindings { - fn get(&self, name: &str) -> Result<&Binding, ExpandError> { +impl Bindings { + fn get(&self, name: &str) -> Result<&Binding, ExpandError> { match self.inner.get(name) { Some(binding) => Ok(binding), None => Err(ExpandError::UnresolvedBinding(Box::new(Box::from(name)))), @@ -21,10 +22,10 @@ impl Bindings { fn get_fragment( &self, name: &str, - mut span: S, + mut span: Span, nesting: &mut [NestingState], - marker: impl Fn(&mut S), - ) -> Result, ExpandError> { + marker: impl Fn(&mut Span), + ) -> Result { macro_rules! binding_err { ($($arg:tt)*) => { ExpandError::binding_error(format!($($arg)*)) }; } @@ -134,15 +135,15 @@ impl Bindings { } } -pub(super) fn transcribe( - template: &MetaTemplate, - bindings: &Bindings, - marker: impl Fn(&mut S) + Copy, +pub(super) fn transcribe( + template: &MetaTemplate, + bindings: &Bindings, + marker: impl Fn(&mut Span) + Copy, new_meta_vars: bool, - call_site: S, -) -> ExpandResult> { + call_site: Span, +) -> ExpandResult> { let mut ctx = ExpandCtx { bindings, nesting: Vec::new(), new_meta_vars, call_site }; - let mut arena: Vec> = Vec::new(); + let mut arena: Vec> = Vec::new(); expand_subtree(&mut ctx, template, None, &mut arena, marker) } @@ -158,20 +159,20 @@ struct NestingState { } #[derive(Debug)] -struct ExpandCtx<'a, S> { - bindings: &'a Bindings, +struct ExpandCtx<'a> { + bindings: &'a Bindings, nesting: Vec, new_meta_vars: bool, - call_site: S, + call_site: Span, } -fn expand_subtree( - ctx: &mut ExpandCtx<'_, S>, - template: &MetaTemplate, - delimiter: Option>, - arena: &mut Vec>, - marker: impl Fn(&mut S) + Copy, -) -> ExpandResult> { +fn expand_subtree( + ctx: &mut ExpandCtx<'_>, + template: &MetaTemplate, + delimiter: Option>, + arena: &mut Vec>, + marker: impl Fn(&mut Span) + Copy, +) -> ExpandResult> { // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation let start_elements = arena.len(); let mut err = None; @@ -332,12 +333,12 @@ fn expand_subtree( } } -fn expand_var( - ctx: &mut ExpandCtx<'_, S>, +fn expand_var( + ctx: &mut ExpandCtx<'_>, v: &SmolStr, - id: S, - marker: impl Fn(&mut S), -) -> ExpandResult> { + id: Span, + marker: impl Fn(&mut Span), +) -> ExpandResult { // We already handle $crate case in mbe parser debug_assert!(v != "crate"); @@ -378,15 +379,15 @@ fn expand_var( } } -fn expand_repeat( - ctx: &mut ExpandCtx<'_, S>, - template: &MetaTemplate, +fn expand_repeat( + ctx: &mut ExpandCtx<'_>, + template: &MetaTemplate, kind: RepeatKind, - separator: &Option>, - arena: &mut Vec>, - marker: impl Fn(&mut S) + Copy, -) -> ExpandResult> { - let mut buf: Vec> = Vec::new(); + separator: &Option, + arena: &mut Vec>, + marker: impl Fn(&mut Span) + Copy, +) -> ExpandResult { + let mut buf: Vec> = Vec::new(); ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false }); // Dirty hack to make macro-expansion terminate. // This should be replaced by a proper macro-by-example implementation @@ -478,11 +479,7 @@ fn expand_repeat( ExpandResult { value: Fragment::Tokens(tt), err } } -fn push_fragment( - ctx: &ExpandCtx<'_, S>, - buf: &mut Vec>, - fragment: Fragment, -) { +fn push_fragment(ctx: &ExpandCtx<'_>, buf: &mut Vec>, fragment: Fragment) { match fragment { Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt), Fragment::Expr(sub) => { @@ -494,7 +491,7 @@ fn push_fragment( } } -fn push_subtree(buf: &mut Vec>, tt: tt::Subtree) { +fn push_subtree(buf: &mut Vec>, tt: tt::Subtree) { match tt.delimiter.kind { tt::DelimiterKind::Invisible => buf.extend(Vec::from(tt.token_trees)), _ => buf.push(tt.into()), @@ -504,10 +501,10 @@ fn push_subtree(buf: &mut Vec>, tt: tt::Subtree) { /// Inserts the path separator `::` between an identifier and its following generic /// argument list, and then pushes into the buffer. See [`Fragment::Path`] for why /// we need this fixup. -fn fix_up_and_push_path_tt( - ctx: &ExpandCtx<'_, S>, - buf: &mut Vec>, - subtree: tt::Subtree, +fn fix_up_and_push_path_tt( + ctx: &ExpandCtx<'_>, + buf: &mut Vec>, + subtree: tt::Subtree, ) { stdx::always!(matches!(subtree.delimiter.kind, tt::DelimiterKind::Invisible)); let mut prev_was_ident = false; @@ -546,11 +543,7 @@ fn fix_up_and_push_path_tt( /// Handles `${count(t, depth)}`. `our_depth` is the recursion depth and `count_depth` is the depth /// defined by the metavar expression. -fn count( - binding: &Binding, - depth_curr: usize, - depth_max: usize, -) -> Result { +fn count(binding: &Binding, depth_curr: usize, depth_max: usize) -> Result { match binding { Binding::Nested(bs) => { if depth_curr == depth_max { @@ -564,8 +557,8 @@ fn count( } } -fn count_old( - binding: &Binding, +fn count_old( + binding: &Binding, our_depth: usize, count_depth: Option, ) -> Result { diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 62fdce36892f..2d68f6f6a53d 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs @@ -17,8 +17,8 @@ mod tt_iter; #[cfg(test)] mod benchmark; +use span::Span; use stdx::impl_from; -use tt::Span; use std::fmt; @@ -127,8 +127,8 @@ impl fmt::Display for CountError { /// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident` /// and `$()*` have special meaning (see `Var` and `Repeat` data structures) #[derive(Clone, Debug, PartialEq, Eq)] -pub struct DeclarativeMacro { - rules: Box<[Rule]>, +pub struct DeclarativeMacro { + rules: Box<[Rule]>, // This is used for correctly determining the behavior of the pat fragment // FIXME: This should be tracked by hygiene of the fragment identifier! is_2021: bool, @@ -136,23 +136,23 @@ pub struct DeclarativeMacro { } #[derive(Clone, Debug, PartialEq, Eq)] -struct Rule { - lhs: MetaTemplate, - rhs: MetaTemplate, +struct Rule { + lhs: MetaTemplate, + rhs: MetaTemplate, } -impl DeclarativeMacro { - pub fn from_err(err: ParseError, is_2021: bool) -> DeclarativeMacro { +impl DeclarativeMacro { + pub fn from_err(err: ParseError, is_2021: bool) -> DeclarativeMacro { DeclarativeMacro { rules: Box::default(), is_2021, err: Some(Box::new(err)) } } /// The old, `macro_rules! m {}` flavor. pub fn parse_macro_rules( - tt: &tt::Subtree, + tt: &tt::Subtree, is_2021: bool, // FIXME: Remove this once we drop support for rust 1.76 (defaults to true then) new_meta_vars: bool, - ) -> DeclarativeMacro { + ) -> DeclarativeMacro { // Note: this parsing can be implemented using mbe machinery itself, by // matching against `$($lhs:tt => $rhs:tt);*` pattern, but implementing // manually seems easier. @@ -189,11 +189,11 @@ impl DeclarativeMacro { /// The new, unstable `macro m {}` flavor. pub fn parse_macro2( - tt: &tt::Subtree, + tt: &tt::Subtree, is_2021: bool, // FIXME: Remove this once we drop support for rust 1.76 (defaults to true then) new_meta_vars: bool, - ) -> DeclarativeMacro { + ) -> DeclarativeMacro { let mut src = TtIter::new(tt); let mut rules = Vec::new(); let mut err = None; @@ -249,18 +249,18 @@ impl DeclarativeMacro { pub fn expand( &self, - tt: &tt::Subtree, - marker: impl Fn(&mut S) + Copy, + tt: &tt::Subtree, + marker: impl Fn(&mut Span) + Copy, new_meta_vars: bool, - call_site: S, - ) -> ExpandResult> { + call_site: Span, + ) -> ExpandResult> { expander::expand_rules(&self.rules, tt, marker, self.is_2021, new_meta_vars, call_site) } } -impl Rule { +impl Rule { fn parse( - src: &mut TtIter<'_, S>, + src: &mut TtIter<'_, Span>, expect_arrow: bool, new_meta_vars: bool, ) -> Result { @@ -278,7 +278,7 @@ impl Rule { } } -fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { +fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> { for op in pattern.iter() { match op { Op::Subtree { tokens, .. } => validate(tokens)?, diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index afdbbef23147..560dcf61a822 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs @@ -2,8 +2,8 @@ //! trees. use smallvec::{smallvec, SmallVec}; +use span::Span; use syntax::SmolStr; -use tt::Span; use crate::{tt_iter::TtIter, ParseError}; @@ -21,25 +21,25 @@ use crate::{tt_iter::TtIter, ParseError}; /// Stuff to the right is a [`MetaTemplate`] template which is used to produce /// output. #[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct MetaTemplate(pub(crate) Box<[Op]>); +pub(crate) struct MetaTemplate(pub(crate) Box<[Op]>); -impl MetaTemplate { - pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result { +impl MetaTemplate { + pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result { MetaTemplate::parse(pattern, Mode::Pattern, false) } pub(crate) fn parse_template( - template: &tt::Subtree, + template: &tt::Subtree, new_meta_vars: bool, ) -> Result { MetaTemplate::parse(template, Mode::Template, new_meta_vars) } - pub(crate) fn iter(&self) -> impl Iterator> { + pub(crate) fn iter(&self) -> impl Iterator { self.0.iter() } - fn parse(tt: &tt::Subtree, mode: Mode, new_meta_vars: bool) -> Result { + fn parse(tt: &tt::Subtree, mode: Mode, new_meta_vars: bool) -> Result { let mut src = TtIter::new(tt); let mut res = Vec::new(); @@ -53,15 +53,15 @@ impl MetaTemplate { } #[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum Op { +pub(crate) enum Op { Var { name: SmolStr, kind: Option, - id: S, + id: Span, }, Ignore { name: SmolStr, - id: S, + id: Span, }, Index { depth: usize, @@ -75,17 +75,17 @@ pub(crate) enum Op { depth: Option, }, Repeat { - tokens: MetaTemplate, + tokens: MetaTemplate, kind: RepeatKind, - separator: Option>, + separator: Option, }, Subtree { - tokens: MetaTemplate, - delimiter: tt::Delimiter, + tokens: MetaTemplate, + delimiter: tt::Delimiter, }, - Literal(tt::Literal), - Punct(SmallVec<[tt::Punct; 3]>), - Ident(tt::Ident), + Literal(tt::Literal), + Punct(SmallVec<[tt::Punct; 3]>), + Ident(tt::Ident), } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -114,15 +114,15 @@ pub(crate) enum MetaVarKind { } #[derive(Clone, Debug, Eq)] -pub(crate) enum Separator { - Literal(tt::Literal), - Ident(tt::Ident), - Puncts(SmallVec<[tt::Punct; 3]>), +pub(crate) enum Separator { + Literal(tt::Literal), + Ident(tt::Ident), + Puncts(SmallVec<[tt::Punct; 3]>), } // Note that when we compare a Separator, we just care about its textual value. -impl PartialEq for Separator { - fn eq(&self, other: &Separator) -> bool { +impl PartialEq for Separator { + fn eq(&self, other: &Separator) -> bool { use Separator::*; match (self, other) { @@ -144,12 +144,12 @@ enum Mode { Template, } -fn next_op( - first_peeked: &tt::TokenTree, - src: &mut TtIter<'_, S>, +fn next_op( + first_peeked: &tt::TokenTree, + src: &mut TtIter<'_, Span>, mode: Mode, new_meta_vars: bool, -) -> Result, ParseError> { +) -> Result { let res = match first_peeked { tt::TokenTree::Leaf(tt::Leaf::Punct(p @ tt::Punct { char: '$', .. })) => { src.next().expect("first token already peeked"); @@ -240,8 +240,8 @@ fn next_op( Ok(res) } -fn eat_fragment_kind( - src: &mut TtIter<'_, S>, +fn eat_fragment_kind( + src: &mut TtIter<'_, Span>, mode: Mode, ) -> Result, ParseError> { if let Mode::Pattern = mode { @@ -271,13 +271,11 @@ fn eat_fragment_kind( Ok(None) } -fn is_boolean_literal(lit: &tt::Literal) -> bool { +fn is_boolean_literal(lit: &tt::Literal) -> bool { matches!(lit.text.as_str(), "true" | "false") } -fn parse_repeat( - src: &mut TtIter<'_, S>, -) -> Result<(Option>, RepeatKind), ParseError> { +fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option, RepeatKind), ParseError> { let mut separator = Separator::Puncts(SmallVec::new()); for tt in src { let tt = match tt { @@ -314,7 +312,7 @@ fn parse_repeat( Err(ParseError::InvalidRepeat) } -fn parse_metavar_expr(new_meta_vars: bool, src: &mut TtIter<'_, S>) -> Result, ()> { +fn parse_metavar_expr(new_meta_vars: bool, src: &mut TtIter<'_, Span>) -> Result { let func = src.expect_ident()?; let args = src.expect_subtree()?; @@ -352,7 +350,7 @@ fn parse_metavar_expr(new_meta_vars: bool, src: &mut TtIter<'_, S>) -> Ok(op) } -fn parse_depth(src: &mut TtIter<'_, S>) -> Result { +fn parse_depth(src: &mut TtIter<'_, Span>) -> Result { if src.len() == 0 { Ok(0) } else if let tt::Leaf::Literal(lit) = src.expect_literal()? { @@ -363,7 +361,7 @@ fn parse_depth(src: &mut TtIter<'_, S>) -> Result { } } -fn try_eat_comma(src: &mut TtIter<'_, S>) -> bool { +fn try_eat_comma(src: &mut TtIter<'_, Span>) -> bool { if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. }))) = src.peek_n(0) { let _ = src.next(); return true; From 6d1071962f17cb2f8ded66bae28b571c8f49f76b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 19 Mar 2024 19:48:09 +0100 Subject: [PATCH 3/3] =?UTF-8?q?Resolve=20whether=20$pat=20is=20$pat=5Fpara?= =?UTF-8?q?m=20or=20not=20via=20=F0=9F=8C=9Fhygiene=F0=9F=8C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hir-def/src/macro_expansion_tests/mbe.rs | 85 +++++++++++++++++++ crates/hir-expand/src/declarative.rs | 34 +++++--- crates/mbe/src/benchmark.rs | 10 ++- crates/mbe/src/expander.rs | 3 +- crates/mbe/src/expander/matcher.rs | 14 ++- crates/mbe/src/lib.rs | 30 +++---- crates/mbe/src/parser.rs | 36 +++++--- 7 files changed, 158 insertions(+), 54 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs index 965f329acb9e..c5c26e26bc0e 100644 --- a/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -1449,6 +1449,7 @@ ok!(); #[test] fn test_new_std_matches() { check( + //- edition:2021 r#" macro_rules! matches { ($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => { @@ -1480,6 +1481,90 @@ fn main() { ); } +#[test] +fn test_hygienic_pat() { + check( + r#" +//- /new.rs crate:new deps:old edition:2015 +old::make!(); +fn main() { + matches!(0, 0 | 1 if true); +} +//- /old.rs crate:old edition:2021 +#[macro_export] +macro_rules! make { + () => { + macro_rules! matches { + ($expression:expr, $pattern:pat if $guard:expr ) => { + match $expression { + $pattern if $guard => true, + _ => false + } + }; + } + } +} + "#, + expect![[r#" +macro_rules !matches { + ($expression: expr, $pattern: pat if $guard: expr) = > { + match $expression { + $pattern if $guard = > true , _ = > false + } + } + ; +} +fn main() { + match 0 { + 0|1 if true =>true , _=>false + }; +} +"#]], + ); + check( + r#" +//- /new.rs crate:new deps:old edition:2021 +old::make!(); +fn main() { + matches/*+errors*/!(0, 0 | 1 if true); +} +//- /old.rs crate:old edition:2015 +#[macro_export] +macro_rules! make { + () => { + macro_rules! matches { + ($expression:expr, $pattern:pat if $guard:expr ) => { + match $expression { + $pattern if $guard => true, + _ => false + } + }; + } + } +} + "#, + expect![[r#" +macro_rules !matches { + ($expression: expr, $pattern: pat if $guard: expr) = > { + match $expression { + $pattern if $guard = > true , _ = > false + } + } + ; +} +fn main() { + /* error: unexpected token in input *//* parse error: expected expression */ +/* parse error: expected FAT_ARROW */ +/* parse error: expected `,` */ +/* parse error: expected pattern */ +match 0 { + 0 if $guard=>true , _=>false + }; +} +"#]], + ); +} + #[test] fn test_dollar_crate_lhs_is_not_meta() { check( diff --git a/crates/hir-expand/src/declarative.rs b/crates/hir-expand/src/declarative.rs index eceb20df5f84..9a0b218e6d1d 100644 --- a/crates/hir-expand/src/declarative.rs +++ b/crates/hir-expand/src/declarative.rs @@ -2,7 +2,7 @@ use std::sync::OnceLock; use base_db::{CrateId, VersionReq}; -use span::{Edition, MacroCallId, Span}; +use span::{MacroCallId, Span, SyntaxContextId}; use syntax::{ast, AstNode}; use triomphe::Arc; @@ -10,7 +10,7 @@ use crate::{ attrs::RawAttrs, db::ExpandDatabase, hygiene::{apply_mark, Transparency}, - tt, AstId, ExpandError, ExpandResult, + tt, AstId, ExpandError, ExpandResult, Lookup, }; /// Old-style `macro_rules` or the new macros 2.0 @@ -94,8 +94,6 @@ impl DeclarativeMacroExpander { def_crate: CrateId, id: AstId, ) -> Arc { - let crate_data = &db.crate_graph()[def_crate]; - let is_2021 = crate_data.edition >= Edition::Edition2021; let (root, map) = crate::db::parse_with_map(db, id.file_id); let root = root.syntax_node(); @@ -133,6 +131,16 @@ impl DeclarativeMacroExpander { ) }); + let edition = |ctx: SyntaxContextId| { + let crate_graph = db.crate_graph(); + if ctx.is_root() { + crate_graph[def_crate].edition + } else { + let data = db.lookup_intern_syntax_context(ctx); + // UNWRAP-SAFETY: Only the root context has no outer expansion + crate_graph[data.outer_expn.unwrap().lookup(db).def.krate].edition + } + }; let (mac, transparency) = match id.to_ptr(db).to_node(&root) { ast::Macro::MacroRules(macro_rules) => ( match macro_rules.token_tree() { @@ -145,12 +153,11 @@ impl DeclarativeMacroExpander { ), ); - mbe::DeclarativeMacro::parse_macro_rules(&tt, is_2021, new_meta_vars) + mbe::DeclarativeMacro::parse_macro_rules(&tt, edition, new_meta_vars) } - None => mbe::DeclarativeMacro::from_err( - mbe::ParseError::Expected("expected a token tree".into()), - is_2021, - ), + None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected( + "expected a token tree".into(), + )), }, transparency(¯o_rules).unwrap_or(Transparency::SemiTransparent), ), @@ -163,12 +170,11 @@ impl DeclarativeMacroExpander { map.span_for_range(macro_def.macro_token().unwrap().text_range()), ); - mbe::DeclarativeMacro::parse_macro2(&tt, is_2021, new_meta_vars) + mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars) } - None => mbe::DeclarativeMacro::from_err( - mbe::ParseError::Expected("expected a token tree".into()), - is_2021, - ), + None => mbe::DeclarativeMacro::from_err(mbe::ParseError::Expected( + "expected a token tree".into(), + )), }, transparency(¯o_def).unwrap_or(Transparency::Opaque), ), diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs index cacd5ed81a52..4d5531ae307f 100644 --- a/crates/mbe/src/benchmark.rs +++ b/crates/mbe/src/benchmark.rs @@ -23,7 +23,11 @@ fn benchmark_parse_macro_rules() { let _pt = bench("mbe parse macro rules"); rules .values() - .map(|it| DeclarativeMacro::parse_macro_rules(it, true, true).rules.len()) + .map(|it| { + DeclarativeMacro::parse_macro_rules(it, |_| span::Edition::CURRENT, true) + .rules + .len() + }) .sum() }; assert_eq!(hash, 1144); @@ -54,7 +58,9 @@ fn benchmark_expand_macro_rules() { fn macro_rules_fixtures() -> FxHashMap { macro_rules_fixtures_tt() .into_iter() - .map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, true, true))) + .map(|(id, tt)| { + (id, DeclarativeMacro::parse_macro_rules(&tt, |_| span::Edition::CURRENT, true)) + }) .collect() } diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs index 9e365232656d..2f2c0aa6ff59 100644 --- a/crates/mbe/src/expander.rs +++ b/crates/mbe/src/expander.rs @@ -15,13 +15,12 @@ pub(crate) fn expand_rules( rules: &[crate::Rule], input: &tt::Subtree, marker: impl Fn(&mut Span) + Copy, - is_2021: bool, new_meta_vars: bool, call_site: Span, ) -> ExpandResult> { let mut match_: Option<(matcher::Match, &crate::Rule)> = None; for rule in rules { - let new_match = matcher::match_(&rule.lhs, input, is_2021); + let new_match = matcher::match_(&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 e14e13856fd2..3170834d54ff 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -108,8 +108,8 @@ impl Match { } /// Matching errors are added to the `Match`. -pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree, is_2021: bool) -> Match { - let mut res = match_loop(pattern, input, is_2021); +pub(super) fn match_(pattern: &MetaTemplate, input: &tt::Subtree) -> Match { + let mut res = match_loop(pattern, input); res.bound_count = count(res.bindings.bindings()); return res; @@ -362,7 +362,6 @@ fn match_loop_inner<'t>( next_items: &mut Vec>, eof_items: &mut SmallVec<[MatchState<'t>; 1]>, error_items: &mut SmallVec<[MatchState<'t>; 1]>, - is_2021: bool, delim_span: tt::DelimSpan, ) { macro_rules! try_push { @@ -474,7 +473,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, is_2021, delim_span); + let match_res = match_meta_var(kind, &mut fork, delim_span); match match_res.err { None => { // Some meta variables are optional (e.g. vis) @@ -587,7 +586,7 @@ fn match_loop_inner<'t>( } } -fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree, is_2021: bool) -> Match { +fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match { let span = src.delimiter.delim_span(); let mut src = TtIter::new(src); let mut stack: SmallVec<[TtIter<'_, Span>; 1]> = SmallVec::new(); @@ -627,7 +626,6 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree, is_2021: bool) -> &mut next_items, &mut eof_items, &mut error_items, - is_2021, span, ); stdx::always!(cur_items.is_empty()); @@ -741,7 +739,6 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree, is_2021: bool) -> fn match_meta_var( kind: MetaVarKind, input: &mut TtIter<'_, Span>, - is_2021: bool, delim_span: DelimSpan, ) -> ExpandResult> { let fragment = match kind { @@ -751,8 +748,7 @@ fn match_meta_var( }); } MetaVarKind::Ty => parser::PrefixEntryPoint::Ty, - MetaVarKind::Pat if is_2021 => parser::PrefixEntryPoint::PatTop, - MetaVarKind::Pat => parser::PrefixEntryPoint::Pat, + MetaVarKind::Pat => parser::PrefixEntryPoint::PatTop, MetaVarKind::PatParam => parser::PrefixEntryPoint::Pat, MetaVarKind::Stmt => parser::PrefixEntryPoint::Stmt, MetaVarKind::Block => parser::PrefixEntryPoint::Block, diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 2d68f6f6a53d..3a853512660e 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs @@ -17,7 +17,7 @@ mod tt_iter; #[cfg(test)] mod benchmark; -use span::Span; +use span::{Edition, Span, SyntaxContextId}; use stdx::impl_from; use std::fmt; @@ -129,9 +129,6 @@ impl fmt::Display for CountError { #[derive(Clone, Debug, PartialEq, Eq)] pub struct DeclarativeMacro { rules: Box<[Rule]>, - // This is used for correctly determining the behavior of the pat fragment - // FIXME: This should be tracked by hygiene of the fragment identifier! - is_2021: bool, err: Option>, } @@ -142,14 +139,14 @@ struct Rule { } impl DeclarativeMacro { - pub fn from_err(err: ParseError, is_2021: bool) -> DeclarativeMacro { - DeclarativeMacro { rules: Box::default(), is_2021, err: Some(Box::new(err)) } + pub fn from_err(err: ParseError) -> DeclarativeMacro { + DeclarativeMacro { rules: Box::default(), err: Some(Box::new(err)) } } /// The old, `macro_rules! m {}` flavor. pub fn parse_macro_rules( tt: &tt::Subtree, - is_2021: bool, + edition: impl Copy + Fn(SyntaxContextId) -> Edition, // FIXME: Remove this once we drop support for rust 1.76 (defaults to true then) new_meta_vars: bool, ) -> DeclarativeMacro { @@ -161,7 +158,7 @@ impl DeclarativeMacro { let mut err = None; while src.len() > 0 { - let rule = match Rule::parse(&mut src, true, new_meta_vars) { + let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) { Ok(it) => it, Err(e) => { err = Some(Box::new(e)); @@ -184,13 +181,13 @@ impl DeclarativeMacro { } } - DeclarativeMacro { rules: rules.into_boxed_slice(), is_2021, err } + DeclarativeMacro { rules: rules.into_boxed_slice(), err } } /// The new, unstable `macro m {}` flavor. pub fn parse_macro2( tt: &tt::Subtree, - is_2021: bool, + edition: impl Copy + Fn(SyntaxContextId) -> Edition, // FIXME: Remove this once we drop support for rust 1.76 (defaults to true then) new_meta_vars: bool, ) -> DeclarativeMacro { @@ -201,7 +198,7 @@ impl DeclarativeMacro { if tt::DelimiterKind::Brace == tt.delimiter.kind { cov_mark::hit!(parse_macro_def_rules); while src.len() > 0 { - let rule = match Rule::parse(&mut src, true, new_meta_vars) { + let rule = match Rule::parse(edition, &mut src, true, new_meta_vars) { Ok(it) => it, Err(e) => { err = Some(Box::new(e)); @@ -220,7 +217,7 @@ impl DeclarativeMacro { } } else { cov_mark::hit!(parse_macro_def_simple); - match Rule::parse(&mut src, false, new_meta_vars) { + match Rule::parse(edition, &mut src, false, new_meta_vars) { Ok(rule) => { if src.len() != 0 { err = Some(Box::new(ParseError::expected("remaining tokens in macro def"))); @@ -240,7 +237,7 @@ impl DeclarativeMacro { } } - DeclarativeMacro { rules: rules.into_boxed_slice(), is_2021, err } + DeclarativeMacro { rules: rules.into_boxed_slice(), err } } pub fn err(&self) -> Option<&ParseError> { @@ -254,12 +251,13 @@ impl DeclarativeMacro { new_meta_vars: bool, call_site: Span, ) -> ExpandResult> { - expander::expand_rules(&self.rules, tt, marker, self.is_2021, new_meta_vars, call_site) + expander::expand_rules(&self.rules, tt, marker, new_meta_vars, call_site) } } impl Rule { fn parse( + edition: impl Copy + Fn(SyntaxContextId) -> Edition, src: &mut TtIter<'_, Span>, expect_arrow: bool, new_meta_vars: bool, @@ -271,8 +269,8 @@ impl Rule { } let rhs = src.expect_subtree().map_err(|()| ParseError::expected("expected subtree"))?; - let lhs = MetaTemplate::parse_pattern(lhs)?; - let rhs = MetaTemplate::parse_template(rhs, new_meta_vars)?; + let lhs = MetaTemplate::parse_pattern(edition, lhs)?; + let rhs = MetaTemplate::parse_template(edition, rhs, new_meta_vars)?; Ok(crate::Rule { lhs, rhs }) } diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index 560dcf61a822..eaf2fd8c273f 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs @@ -2,7 +2,7 @@ //! trees. use smallvec::{smallvec, SmallVec}; -use span::Span; +use span::{Edition, Span, SyntaxContextId}; use syntax::SmolStr; use crate::{tt_iter::TtIter, ParseError}; @@ -24,27 +24,36 @@ use crate::{tt_iter::TtIter, ParseError}; pub(crate) struct MetaTemplate(pub(crate) Box<[Op]>); impl MetaTemplate { - pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Result { - MetaTemplate::parse(pattern, Mode::Pattern, false) + pub(crate) fn parse_pattern( + edition: impl Copy + Fn(SyntaxContextId) -> Edition, + pattern: &tt::Subtree, + ) -> Result { + MetaTemplate::parse(edition, pattern, Mode::Pattern, false) } pub(crate) fn parse_template( + edition: impl Copy + Fn(SyntaxContextId) -> Edition, template: &tt::Subtree, new_meta_vars: bool, ) -> Result { - MetaTemplate::parse(template, Mode::Template, new_meta_vars) + MetaTemplate::parse(edition, template, Mode::Template, new_meta_vars) } pub(crate) fn iter(&self) -> impl Iterator { self.0.iter() } - fn parse(tt: &tt::Subtree, mode: Mode, new_meta_vars: bool) -> Result { + fn parse( + edition: impl Copy + Fn(SyntaxContextId) -> Edition, + tt: &tt::Subtree, + mode: Mode, + new_meta_vars: bool, + ) -> Result { let mut src = TtIter::new(tt); let mut res = Vec::new(); while let Some(first) = src.peek_n(0) { - let op = next_op(first, &mut src, mode, new_meta_vars)?; + let op = next_op(edition, first, &mut src, mode, new_meta_vars)?; res.push(op); } @@ -145,6 +154,7 @@ enum Mode { } fn next_op( + edition: impl Copy + Fn(SyntaxContextId) -> Edition, first_peeked: &tt::TokenTree, src: &mut TtIter<'_, Span>, mode: Mode, @@ -162,7 +172,7 @@ fn next_op( tt::TokenTree::Subtree(subtree) => match subtree.delimiter.kind { tt::DelimiterKind::Parenthesis => { let (separator, kind) = parse_repeat(src)?; - let tokens = MetaTemplate::parse(subtree, mode, new_meta_vars)?; + let tokens = MetaTemplate::parse(edition, subtree, mode, new_meta_vars)?; Op::Repeat { tokens, separator, kind } } tt::DelimiterKind::Brace => match mode { @@ -189,13 +199,13 @@ fn next_op( Op::Ident(tt::Ident { text: "$crate".into(), span: ident.span }) } tt::Leaf::Ident(ident) => { - let kind = eat_fragment_kind(src, mode)?; + let kind = eat_fragment_kind(edition, src, mode)?; let name = ident.text.clone(); let id = ident.span; Op::Var { name, kind, id } } tt::Leaf::Literal(lit) if is_boolean_literal(lit) => { - let kind = eat_fragment_kind(src, mode)?; + let kind = eat_fragment_kind(edition, src, mode)?; let name = lit.text.clone(); let id = lit.span; Op::Var { name, kind, id } @@ -233,7 +243,7 @@ fn next_op( tt::TokenTree::Subtree(subtree) => { src.next().expect("first token already peeked"); - let tokens = MetaTemplate::parse(subtree, mode, new_meta_vars)?; + let tokens = MetaTemplate::parse(edition, subtree, mode, new_meta_vars)?; Op::Subtree { tokens, delimiter: subtree.delimiter } } }; @@ -241,6 +251,7 @@ fn next_op( } fn eat_fragment_kind( + edition: impl Copy + Fn(SyntaxContextId) -> Edition, src: &mut TtIter<'_, Span>, mode: Mode, ) -> Result, ParseError> { @@ -252,7 +263,10 @@ fn eat_fragment_kind( let kind = match ident.text.as_str() { "path" => MetaVarKind::Path, "ty" => MetaVarKind::Ty, - "pat" => MetaVarKind::Pat, + "pat" => match edition(ident.span.ctx) { + Edition::Edition2015 | Edition::Edition2018 => MetaVarKind::PatParam, + Edition::Edition2021 | Edition::Edition2024 => MetaVarKind::Pat, + }, "pat_param" => MetaVarKind::PatParam, "stmt" => MetaVarKind::Stmt, "block" => MetaVarKind::Block,