Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-expand/src/lib.rs')
-rw-r--r--crates/hir-expand/src/lib.rs224
1 files changed, 130 insertions, 94 deletions
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index d7819b315c..b5197d4c25 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -6,20 +6,21 @@
#![warn(rust_2018_idioms, unused_lifetimes)]
-pub mod db;
pub mod ast_id_map;
-pub mod name;
-pub mod hygiene;
+pub mod attrs;
pub mod builtin_attr_macro;
pub mod builtin_derive_macro;
pub mod builtin_fn_macro;
-pub mod proc_macro;
-pub mod quote;
+pub mod db;
pub mod eager;
-pub mod mod_path;
-pub mod attrs;
-pub mod span;
pub mod files;
+pub mod change;
+pub mod hygiene;
+pub mod mod_path;
+pub mod name;
+pub mod proc_macro;
+pub mod quote;
+pub mod span_map;
mod fixup;
use attrs::collect_attrs;
@@ -27,11 +28,9 @@ use triomphe::Arc;
use std::{fmt, hash::Hash};
-use base_db::{
- span::{HirFileIdRepr, SpanData, SyntaxContextId},
- CrateId, FileId, FileRange, ProcMacroKind,
-};
+use base_db::{CrateId, Edition, FileId};
use either::Either;
+use span::{FileRange, HirFileIdRepr, Span, SyntaxContextId};
use syntax::{
ast::{self, AstNode},
SyntaxNode, SyntaxToken, TextRange, TextSize,
@@ -42,35 +41,86 @@ use crate::{
builtin_attr_macro::BuiltinAttrExpander,
builtin_derive_macro::BuiltinDeriveExpander,
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
- db::TokenExpander,
+ db::{ExpandDatabase, TokenExpander},
fixup::SyntaxFixupUndoInfo,
+ hygiene::SyntaxContextData,
mod_path::ModPath,
- proc_macro::ProcMacroExpander,
- span::{ExpansionSpanMap, SpanMap},
+ proc_macro::{CustomProcMacroExpander, ProcMacroKind},
+ span_map::{ExpansionSpanMap, SpanMap},
};
pub use crate::ast_id_map::{AstId, ErasedAstId, ErasedFileAstId};
pub use crate::files::{InFile, InMacroFile, InRealFile};
-pub use base_db::span::{HirFileId, MacroCallId, MacroFileId};
pub use mbe::ValueResult;
+pub use span::{HirFileId, MacroCallId, MacroFileId};
-pub type DeclarativeMacro = ::mbe::DeclarativeMacro<tt::SpanData>;
+pub type DeclarativeMacro = ::mbe::DeclarativeMacro<tt::Span>;
pub mod tt {
- pub use base_db::span::SpanData;
- pub use tt::{DelimiterKind, Spacing, Span, SpanAnchor};
-
- pub type Delimiter = ::tt::Delimiter<SpanData>;
- pub type DelimSpan = ::tt::DelimSpan<SpanData>;
- pub type Subtree = ::tt::Subtree<SpanData>;
- pub type Leaf = ::tt::Leaf<SpanData>;
- pub type Literal = ::tt::Literal<SpanData>;
- pub type Punct = ::tt::Punct<SpanData>;
- pub type Ident = ::tt::Ident<SpanData>;
- pub type TokenTree = ::tt::TokenTree<SpanData>;
+ pub use span::Span;
+ pub use tt::{DelimiterKind, Spacing};
+
+ pub type Delimiter = ::tt::Delimiter<Span>;
+ pub type DelimSpan = ::tt::DelimSpan<Span>;
+ pub type Subtree = ::tt::Subtree<Span>;
+ pub type Leaf = ::tt::Leaf<Span>;
+ pub type Literal = ::tt::Literal<Span>;
+ pub type Punct = ::tt::Punct<Span>;
+ pub type Ident = ::tt::Ident<Span>;
+ pub type TokenTree = ::tt::TokenTree<Span>;
+}
+
+#[macro_export]
+macro_rules! impl_intern_lookup {
+ ($db:ident, $id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
+ impl $crate::Intern for $loc {
+ type Database<'db> = dyn $db + 'db;
+ type ID = $id;
+ fn intern<'db>(self, db: &Self::Database<'db>) -> $id {
+ db.$intern(self)
+ }
+ }
+
+ impl $crate::Lookup for $id {
+ type Database<'db> = dyn $db + 'db;
+ type Data = $loc;
+ fn lookup<'db>(&self, db: &Self::Database<'db>) -> $loc {
+ db.$lookup(*self)
+ }
+ }
+ };
+}
+
+// ideally these would be defined in base-db, but the orphan rule doesn't let us
+pub trait Intern {
+ type Database<'db>: ?Sized;
+ type ID;
+ fn intern<'db>(self, db: &Self::Database<'db>) -> Self::ID;
+}
+
+pub trait Lookup {
+ type Database<'db>: ?Sized;
+ type Data;
+ fn lookup<'db>(&self, db: &Self::Database<'db>) -> Self::Data;
}
+impl_intern_lookup!(
+ ExpandDatabase,
+ MacroCallId,
+ MacroCallLoc,
+ intern_macro_call,
+ lookup_intern_macro_call
+);
+
+impl_intern_lookup!(
+ ExpandDatabase,
+ SyntaxContextId,
+ SyntaxContextData,
+ intern_syntax_context,
+ lookup_intern_syntax_context
+);
+
pub type ExpandResult<T> = ValueResult<T, ExpandError>;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
@@ -117,18 +167,20 @@ pub struct MacroCallLoc {
pub krate: CrateId,
/// Some if this is a macro call for an eager macro. Note that this is `None`
/// for the eager input macro file.
+ // FIXME: This seems bad to save in an interned structure
eager: Option<Arc<EagerCallInfo>>,
pub kind: MacroCallKind,
- pub call_site: SyntaxContextId,
+ pub call_site: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId {
pub krate: CrateId,
+ pub edition: Edition,
pub kind: MacroDefKind,
pub local_inner: bool,
pub allow_internal_unsafe: bool,
- // pub def_site: SyntaxContextId,
+ pub span: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -138,7 +190,7 @@ pub enum MacroDefKind {
BuiltInAttr(BuiltinAttrExpander, AstId<ast::Macro>),
BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
BuiltInEager(EagerExpander, AstId<ast::Macro>),
- ProcMacro(ProcMacroExpander, ProcMacroKind, AstId<ast::Fn>),
+ ProcMacro(CustomProcMacroExpander, ProcMacroKind, AstId<ast::Fn>),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -179,40 +231,39 @@ pub enum MacroCallKind {
pub trait HirFileIdExt {
/// Returns the original file of this macro call hierarchy.
- fn original_file(self, db: &dyn db::ExpandDatabase) -> FileId;
+ fn original_file(self, db: &dyn ExpandDatabase) -> FileId;
/// Returns the original file of this macro call hierarchy while going into the included file if
/// one of the calls comes from an `include!``.
- fn original_file_respecting_includes(self, db: &dyn db::ExpandDatabase) -> FileId;
+ fn original_file_respecting_includes(self, db: &dyn ExpandDatabase) -> FileId;
/// If this is a macro call, returns the syntax node of the very first macro call this file resides in.
- fn original_call_node(self, db: &dyn db::ExpandDatabase) -> Option<InRealFile<SyntaxNode>>;
+ fn original_call_node(self, db: &dyn ExpandDatabase) -> Option<InRealFile<SyntaxNode>>;
/// Return expansion information if it is a macro-expansion file
- fn expansion_info(self, db: &dyn db::ExpandDatabase) -> Option<ExpansionInfo>;
+ fn expansion_info(self, db: &dyn ExpandDatabase) -> Option<ExpansionInfo>;
- fn as_builtin_derive_attr_node(&self, db: &dyn db::ExpandDatabase)
- -> Option<InFile<ast::Attr>>;
+ fn as_builtin_derive_attr_node(&self, db: &dyn ExpandDatabase) -> Option<InFile<ast::Attr>>;
}
impl HirFileIdExt for HirFileId {
- fn original_file(self, db: &dyn db::ExpandDatabase) -> FileId {
+ fn original_file(self, db: &dyn ExpandDatabase) -> FileId {
let mut file_id = self;
loop {
match file_id.repr() {
HirFileIdRepr::FileId(id) => break id,
HirFileIdRepr::MacroFile(MacroFileId { macro_call_id }) => {
- file_id = db.lookup_intern_macro_call(macro_call_id).kind.file_id();
+ file_id = macro_call_id.lookup(db).kind.file_id();
}
}
}
}
- fn original_file_respecting_includes(mut self, db: &dyn db::ExpandDatabase) -> FileId {
+ fn original_file_respecting_includes(mut self, db: &dyn ExpandDatabase) -> FileId {
loop {
match self.repr() {
- base_db::span::HirFileIdRepr::FileId(id) => break id,
- base_db::span::HirFileIdRepr::MacroFile(file) => {
+ HirFileIdRepr::FileId(id) => break id,
+ HirFileIdRepr::MacroFile(file) => {
let loc = db.lookup_intern_macro_call(file.macro_call_id);
if loc.def.is_include() {
if let Some(eager) = &loc.eager {
@@ -231,7 +282,7 @@ impl HirFileIdExt for HirFileId {
}
}
- fn original_call_node(self, db: &dyn db::ExpandDatabase) -> Option<InRealFile<SyntaxNode>> {
+ fn original_call_node(self, db: &dyn ExpandDatabase) -> Option<InRealFile<SyntaxNode>> {
let mut call = db.lookup_intern_macro_call(self.macro_file()?.macro_call_id).to_node(db);
loop {
match call.file_id.repr() {
@@ -246,14 +297,11 @@ impl HirFileIdExt for HirFileId {
}
/// Return expansion information if it is a macro-expansion file
- fn expansion_info(self, db: &dyn db::ExpandDatabase) -> Option<ExpansionInfo> {
+ fn expansion_info(self, db: &dyn ExpandDatabase) -> Option<ExpansionInfo> {
Some(ExpansionInfo::new(db, self.macro_file()?))
}
- fn as_builtin_derive_attr_node(
- &self,
- db: &dyn db::ExpandDatabase,
- ) -> Option<InFile<ast::Attr>> {
+ fn as_builtin_derive_attr_node(&self, db: &dyn ExpandDatabase) -> Option<InFile<ast::Attr>> {
let macro_file = self.macro_file()?;
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
let attr = match loc.def.kind {
@@ -265,32 +313,32 @@ impl HirFileIdExt for HirFileId {
}
pub trait MacroFileIdExt {
- fn expansion_level(self, db: &dyn db::ExpandDatabase) -> u32;
+ fn expansion_level(self, db: &dyn ExpandDatabase) -> u32;
/// If this is a macro call, returns the syntax node of the call.
- fn call_node(self, db: &dyn db::ExpandDatabase) -> InFile<SyntaxNode>;
+ fn call_node(self, db: &dyn ExpandDatabase) -> InFile<SyntaxNode>;
- fn expansion_info(self, db: &dyn db::ExpandDatabase) -> ExpansionInfo;
+ fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo;
- fn is_builtin_derive(&self, db: &dyn db::ExpandDatabase) -> bool;
- fn is_custom_derive(&self, db: &dyn db::ExpandDatabase) -> bool;
+ fn is_builtin_derive(&self, db: &dyn ExpandDatabase) -> bool;
+ fn is_custom_derive(&self, db: &dyn ExpandDatabase) -> bool;
/// Return whether this file is an include macro
- fn is_include_macro(&self, db: &dyn db::ExpandDatabase) -> bool;
+ fn is_include_macro(&self, db: &dyn ExpandDatabase) -> bool;
- fn is_eager(&self, db: &dyn db::ExpandDatabase) -> bool;
+ fn is_eager(&self, db: &dyn ExpandDatabase) -> bool;
/// Return whether this file is an attr macro
- fn is_attr_macro(&self, db: &dyn db::ExpandDatabase) -> bool;
+ fn is_attr_macro(&self, db: &dyn ExpandDatabase) -> bool;
/// Return whether this file is the pseudo expansion of the derive attribute.
/// See [`crate::builtin_attr_macro::derive_attr_expand`].
- fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::ExpandDatabase) -> bool;
+ fn is_derive_attr_pseudo_expansion(&self, db: &dyn ExpandDatabase) -> bool;
}
impl MacroFileIdExt for MacroFileId {
- fn call_node(self, db: &dyn db::ExpandDatabase) -> InFile<SyntaxNode> {
+ fn call_node(self, db: &dyn ExpandDatabase) -> InFile<SyntaxNode> {
db.lookup_intern_macro_call(self.macro_call_id).to_node(db)
}
- fn expansion_level(self, db: &dyn db::ExpandDatabase) -> u32 {
+ fn expansion_level(self, db: &dyn ExpandDatabase) -> u32 {
let mut level = 0;
let mut macro_file = self;
loop {
@@ -305,39 +353,39 @@ impl MacroFileIdExt for MacroFileId {
}
/// Return expansion information if it is a macro-expansion file
- fn expansion_info(self, db: &dyn db::ExpandDatabase) -> ExpansionInfo {
+ fn expansion_info(self, db: &dyn ExpandDatabase) -> ExpansionInfo {
ExpansionInfo::new(db, self)
}
- fn is_custom_derive(&self, db: &dyn db::ExpandDatabase) -> bool {
+ fn is_custom_derive(&self, db: &dyn ExpandDatabase) -> bool {
matches!(
db.lookup_intern_macro_call(self.macro_call_id).def.kind,
MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _)
)
}
- fn is_builtin_derive(&self, db: &dyn db::ExpandDatabase) -> bool {
+ fn is_builtin_derive(&self, db: &dyn ExpandDatabase) -> bool {
matches!(
db.lookup_intern_macro_call(self.macro_call_id).def.kind,
MacroDefKind::BuiltInDerive(..)
)
}
- fn is_include_macro(&self, db: &dyn db::ExpandDatabase) -> bool {
+ fn is_include_macro(&self, db: &dyn ExpandDatabase) -> bool {
db.lookup_intern_macro_call(self.macro_call_id).def.is_include()
}
- fn is_eager(&self, db: &dyn db::ExpandDatabase) -> bool {
+ fn is_eager(&self, db: &dyn ExpandDatabase) -> bool {
let loc: MacroCallLoc = db.lookup_intern_macro_call(self.macro_call_id);
matches!(loc.def.kind, MacroDefKind::BuiltInEager(..))
}
- fn is_attr_macro(&self, db: &dyn db::ExpandDatabase) -> bool {
+ fn is_attr_macro(&self, db: &dyn ExpandDatabase) -> bool {
let loc: MacroCallLoc = db.lookup_intern_macro_call(self.macro_call_id);
matches!(loc.kind, MacroCallKind::Attr { .. })
}
- fn is_derive_attr_pseudo_expansion(&self, db: &dyn db::ExpandDatabase) -> bool {
+ fn is_derive_attr_pseudo_expansion(&self, db: &dyn ExpandDatabase) -> bool {
let loc: MacroCallLoc = db.lookup_intern_macro_call(self.macro_call_id);
loc.def.is_attribute_derive()
}
@@ -346,15 +394,15 @@ impl MacroFileIdExt for MacroFileId {
impl MacroDefId {
pub fn as_lazy_macro(
self,
- db: &dyn db::ExpandDatabase,
+ db: &dyn ExpandDatabase,
krate: CrateId,
kind: MacroCallKind,
- call_site: SyntaxContextId,
+ call_site: Span,
) -> MacroCallId {
- db.intern_macro_call(MacroCallLoc { def: self, krate, eager: None, kind, call_site })
+ MacroCallLoc { def: self, krate, eager: None, kind, call_site }.intern(db)
}
- pub fn definition_range(&self, db: &dyn db::ExpandDatabase) -> InFile<TextRange> {
+ pub fn definition_range(&self, db: &dyn ExpandDatabase) -> InFile<TextRange> {
match self.kind {
MacroDefKind::Declarative(id)
| MacroDefKind::BuiltIn(_, id)
@@ -419,19 +467,7 @@ impl MacroDefId {
}
impl MacroCallLoc {
- pub fn span(&self, db: &dyn db::ExpandDatabase) -> SpanData {
- let ast_id = self.kind.erased_ast_id();
- let file_id = self.kind.file_id();
- let range = db.ast_id_map(file_id).get_erased(ast_id).text_range();
- match file_id.repr() {
- HirFileIdRepr::FileId(file_id) => db.real_span_map(file_id).span_for_range(range),
- HirFileIdRepr::MacroFile(m) => {
- db.parse_macro_expansion(m).value.1.span_at(range.start())
- }
- }
- }
-
- pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> InFile<SyntaxNode> {
+ pub fn to_node(&self, db: &dyn ExpandDatabase) -> InFile<SyntaxNode> {
match self.kind {
MacroCallKind::FnLike { ast_id, .. } => {
ast_id.with_value(ast_id.to_node(db).syntax().clone())
@@ -498,7 +534,7 @@ impl MacroCallKind {
}
}
- fn erased_ast_id(&self) -> ErasedFileAstId {
+ pub fn erased_ast_id(&self) -> ErasedFileAstId {
match *self {
MacroCallKind::FnLike { ast_id: InFile { value, .. }, .. } => value.erase(),
MacroCallKind::Derive { ast_id: InFile { value, .. }, .. } => value.erase(),
@@ -509,7 +545,7 @@ impl MacroCallKind {
/// Returns the original file range that best describes the location of this macro call.
///
/// Unlike `MacroCallKind::original_call_range`, this also spans the item of attributes and derives.
- pub fn original_call_range_with_body(self, db: &dyn db::ExpandDatabase) -> FileRange {
+ pub fn original_call_range_with_body(self, db: &dyn ExpandDatabase) -> FileRange {
let mut kind = self;
let file_id = loop {
match kind.file_id().repr() {
@@ -534,7 +570,7 @@ impl MacroCallKind {
/// Here we try to roughly match what rustc does to improve diagnostics: fn-like macros
/// get the whole `ast::MacroCall`, attribute macros get the attribute's range, and derives
/// get only the specific derive that is being referred to.
- pub fn original_call_range(self, db: &dyn db::ExpandDatabase) -> FileRange {
+ pub fn original_call_range(self, db: &dyn ExpandDatabase) -> FileRange {
let mut kind = self;
let file_id = loop {
match kind.file_id().repr() {
@@ -573,7 +609,7 @@ impl MacroCallKind {
FileRange { range, file_id }
}
- fn arg(&self, db: &dyn db::ExpandDatabase) -> InFile<Option<SyntaxNode>> {
+ fn arg(&self, db: &dyn ExpandDatabase) -> InFile<Option<SyntaxNode>> {
match self {
MacroCallKind::FnLike { ast_id, .. } => {
ast_id.to_in_file_node(db).map(|it| Some(it.token_tree()?.syntax().clone()))
@@ -617,7 +653,7 @@ impl ExpansionInfo {
/// Maps the passed in file range down into a macro expansion if it is the input to a macro call.
pub fn map_range_down<'a>(
&'a self,
- span: SpanData,
+ span: Span,
) -> Option<InMacroFile<impl Iterator<Item = SyntaxToken> + 'a>> {
let tokens = self
.exp_map
@@ -630,7 +666,7 @@ impl ExpansionInfo {
/// Looks up the span at the given offset.
pub fn span_for_offset(
&self,
- db: &dyn db::ExpandDatabase,
+ db: &dyn ExpandDatabase,
offset: TextSize,
) -> (FileRange, SyntaxContextId) {
debug_assert!(self.expanded.value.text_range().contains(offset));
@@ -646,12 +682,12 @@ impl ExpansionInfo {
/// Maps up the text range out of the expansion hierarchy back into the original file its from.
pub fn map_node_range_up(
&self,
- db: &dyn db::ExpandDatabase,
+ db: &dyn ExpandDatabase,
range: TextRange,
) -> Option<(FileRange, SyntaxContextId)> {
debug_assert!(self.expanded.value.text_range().contains_range(range));
let mut spans = self.exp_map.spans_for_range(range);
- let SpanData { range, anchor, ctx } = spans.next()?;
+ let Span { range, anchor, ctx } = spans.next()?;
let mut start = range.start();
let mut end = range.end();
@@ -676,7 +712,7 @@ impl ExpansionInfo {
/// Maps up the text range out of the expansion into is macro call.
pub fn map_range_up_once(
&self,
- db: &dyn db::ExpandDatabase,
+ db: &dyn ExpandDatabase,
token: TextRange,
) -> InFile<smallvec::SmallVec<[TextRange; 1]>> {
debug_assert!(self.expanded.value.text_range().contains_range(token));
@@ -705,7 +741,7 @@ impl ExpansionInfo {
}
}
- pub fn new(db: &dyn db::ExpandDatabase, macro_file: MacroFileId) -> ExpansionInfo {
+ pub fn new(db: &dyn ExpandDatabase, macro_file: MacroFileId) -> ExpansionInfo {
let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id);
let arg_tt = loc.kind.arg(db);
@@ -718,7 +754,7 @@ impl ExpansionInfo {
let (macro_arg, _) = db.macro_arg(macro_file.macro_call_id).value.unwrap_or_else(|| {
(
Arc::new(tt::Subtree {
- delimiter: tt::Delimiter::DUMMY_INVISIBLE,
+ delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
token_trees: Vec::new(),
}),
SyntaxFixupUndoInfo::NONE,