mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 06:03:58 +00:00
minor: Add some basic docs for spans/hygiene handling
This commit is contained in:
parent
9efa23c4da
commit
eb7a4f293e
5 changed files with 184 additions and 129 deletions
|
@ -5,7 +5,7 @@ use either::Either;
|
||||||
use limit::Limit;
|
use limit::Limit;
|
||||||
use mbe::{syntax_node_to_token_tree, ValueResult};
|
use mbe::{syntax_node_to_token_tree, ValueResult};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use span::SyntaxContextId;
|
use span::{SyntaxContextData, SyntaxContextId};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, HasAttrs},
|
ast::{self, HasAttrs},
|
||||||
AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T,
|
AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T,
|
||||||
|
@ -19,10 +19,7 @@ use crate::{
|
||||||
builtin_fn_macro::EagerExpander,
|
builtin_fn_macro::EagerExpander,
|
||||||
declarative::DeclarativeMacroExpander,
|
declarative::DeclarativeMacroExpander,
|
||||||
fixup::{self, reverse_fixups, SyntaxFixupUndoInfo},
|
fixup::{self, reverse_fixups, SyntaxFixupUndoInfo},
|
||||||
hygiene::{
|
hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt},
|
||||||
span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt,
|
|
||||||
SyntaxContextData,
|
|
||||||
},
|
|
||||||
proc_macro::ProcMacros,
|
proc_macro::ProcMacros,
|
||||||
span_map::{RealSpanMap, SpanMap, SpanMapRef},
|
span_map::{RealSpanMap, SpanMap, SpanMapRef},
|
||||||
tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
|
tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
|
||||||
|
|
|
@ -1,94 +1,34 @@
|
||||||
//! This modules handles hygiene information.
|
//! Machinery for hygienic macros.
|
||||||
//!
|
//!
|
||||||
//! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at
|
//! Inspired by Matthew Flatt et al., “Macros That Work Together: Compile-Time Bindings, Partial
|
||||||
//! this moment, this is horribly incomplete and handles only `$crate`.
|
//! Expansion, and Definition Contexts,” *Journal of Functional Programming* 22, no. 2
|
||||||
|
//! (March 1, 2012): 181–216, <https://doi.org/10.1017/S0956796812000093>.
|
||||||
// FIXME: Consider moving this into the span crate.
|
//!
|
||||||
|
//! Also see https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies
|
||||||
|
//!
|
||||||
|
//! # The Expansion Order Hierarchy
|
||||||
|
//!
|
||||||
|
//! `ExpnData` in rustc, rust-analyzer's version is [`MacroCallLoc`]. Traversing the hierarchy
|
||||||
|
//! upwards can be achieved by walking up [`MacroCallLoc::kind`]'s contained file id, as
|
||||||
|
//! [`MacroFile`]s are interned [`MacroCallLoc`]s.
|
||||||
|
//!
|
||||||
|
//! # The Macro Definition Hierarchy
|
||||||
|
//!
|
||||||
|
//! `SyntaxContextData` in rustc and rust-analyzer. Basically the same in both.
|
||||||
|
//!
|
||||||
|
//! # The Call-site Hierarchy
|
||||||
|
//!
|
||||||
|
//! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer.
|
||||||
|
// FIXME: Move this into the span crate? Not quite possible today as that depends on `MacroCallLoc`
|
||||||
|
// which contains a bunch of unrelated things
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use base_db::salsa::{self, InternValue};
|
use span::{MacroCallId, Span, SyntaxContextData, SyntaxContextId};
|
||||||
use span::{MacroCallId, Span, SyntaxContextId};
|
|
||||||
|
|
||||||
use crate::db::{ExpandDatabase, InternSyntaxContextQuery};
|
use crate::db::{ExpandDatabase, InternSyntaxContextQuery};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
pub use span::Transparency;
|
||||||
pub struct SyntaxContextData {
|
|
||||||
pub outer_expn: Option<MacroCallId>,
|
|
||||||
pub outer_transparency: Transparency,
|
|
||||||
pub parent: SyntaxContextId,
|
|
||||||
/// This context, but with all transparent and semi-transparent expansions filtered away.
|
|
||||||
pub opaque: SyntaxContextId,
|
|
||||||
/// This context, but with all transparent expansions filtered away.
|
|
||||||
pub opaque_and_semitransparent: SyntaxContextId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InternValue for SyntaxContextData {
|
|
||||||
type Key = (SyntaxContextId, Option<MacroCallId>, Transparency);
|
|
||||||
|
|
||||||
fn into_key(&self) -> Self::Key {
|
|
||||||
(self.parent, self.outer_expn, self.outer_transparency)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for SyntaxContextData {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.debug_struct("SyntaxContextData")
|
|
||||||
.field("outer_expn", &self.outer_expn)
|
|
||||||
.field("outer_transparency", &self.outer_transparency)
|
|
||||||
.field("parent", &self.parent)
|
|
||||||
.field("opaque", &self.opaque)
|
|
||||||
.field("opaque_and_semitransparent", &self.opaque_and_semitransparent)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SyntaxContextData {
|
|
||||||
pub fn root() -> Self {
|
|
||||||
SyntaxContextData {
|
|
||||||
outer_expn: None,
|
|
||||||
outer_transparency: Transparency::Opaque,
|
|
||||||
parent: SyntaxContextId::ROOT,
|
|
||||||
opaque: SyntaxContextId::ROOT,
|
|
||||||
opaque_and_semitransparent: SyntaxContextId::ROOT,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fancy_debug(
|
|
||||||
self,
|
|
||||||
self_id: SyntaxContextId,
|
|
||||||
db: &dyn ExpandDatabase,
|
|
||||||
f: &mut std::fmt::Formatter<'_>,
|
|
||||||
) -> std::fmt::Result {
|
|
||||||
write!(f, "#{self_id} parent: #{}, outer_mark: (", self.parent)?;
|
|
||||||
match self.outer_expn {
|
|
||||||
Some(id) => {
|
|
||||||
write!(f, "{:?}::{{{{expn{:?}}}}}", db.lookup_intern_macro_call(id).krate, id)?
|
|
||||||
}
|
|
||||||
None => write!(f, "root")?,
|
|
||||||
}
|
|
||||||
write!(f, ", {:?})", self.outer_transparency)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A property of a macro expansion that determines how identifiers
|
|
||||||
/// produced by that expansion are resolved.
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
|
|
||||||
pub enum Transparency {
|
|
||||||
/// Identifier produced by a transparent expansion is always resolved at call-site.
|
|
||||||
/// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
|
|
||||||
Transparent,
|
|
||||||
/// Identifier produced by a semi-transparent expansion may be resolved
|
|
||||||
/// either at call-site or at definition-site.
|
|
||||||
/// If it's a local variable, label or `$crate` then it's resolved at def-site.
|
|
||||||
/// Otherwise it's resolved at call-site.
|
|
||||||
/// `macro_rules` macros behave like this, built-in macros currently behave like this too,
|
|
||||||
/// but that's an implementation detail.
|
|
||||||
SemiTransparent,
|
|
||||||
/// Identifier produced by an opaque expansion is always resolved at definition-site.
|
|
||||||
/// Def-site spans in procedural macros, identifiers from `macro` by default use this.
|
|
||||||
Opaque,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn span_with_def_site_ctxt(db: &dyn ExpandDatabase, span: Span, expn_id: MacroCallId) -> Span {
|
pub fn span_with_def_site_ctxt(db: &dyn ExpandDatabase, span: Span, expn_id: MacroCallId) -> Span {
|
||||||
span_with_ctxt_from_mark(db, span, expn_id, Transparency::Opaque)
|
span_with_ctxt_from_mark(db, span, expn_id, Transparency::Opaque)
|
||||||
|
@ -157,6 +97,8 @@ fn apply_mark_internal(
|
||||||
call_id: Option<MacroCallId>,
|
call_id: Option<MacroCallId>,
|
||||||
transparency: Transparency,
|
transparency: Transparency,
|
||||||
) -> SyntaxContextId {
|
) -> SyntaxContextId {
|
||||||
|
use base_db::salsa;
|
||||||
|
|
||||||
let syntax_context_data = db.lookup_intern_syntax_context(ctxt);
|
let syntax_context_data = db.lookup_intern_syntax_context(ctxt);
|
||||||
let mut opaque = syntax_context_data.opaque;
|
let mut opaque = syntax_context_data.opaque;
|
||||||
let mut opaque_and_semitransparent = syntax_context_data.opaque_and_semitransparent;
|
let mut opaque_and_semitransparent = syntax_context_data.opaque_and_semitransparent;
|
||||||
|
@ -199,6 +141,7 @@ fn apply_mark_internal(
|
||||||
opaque_and_semitransparent,
|
opaque_and_semitransparent,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SyntaxContextExt {
|
pub trait SyntaxContextExt {
|
||||||
fn normalize_to_macro_rules(self, db: &dyn ExpandDatabase) -> Self;
|
fn normalize_to_macro_rules(self, db: &dyn ExpandDatabase) -> Self;
|
||||||
fn normalize_to_macros_2_0(self, db: &dyn ExpandDatabase) -> Self;
|
fn normalize_to_macros_2_0(self, db: &dyn ExpandDatabase) -> Self;
|
||||||
|
@ -277,9 +220,26 @@ pub(crate) fn dump_syntax_contexts(db: &dyn ExpandDatabase) -> String {
|
||||||
|
|
||||||
impl<'a> std::fmt::Debug for SyntaxContextDebug<'a> {
|
impl<'a> std::fmt::Debug for SyntaxContextDebug<'a> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.2.fancy_debug(self.1, self.0, f)
|
fancy_debug(self.2, self.1, self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fancy_debug(
|
||||||
|
this: &SyntaxContextData,
|
||||||
|
self_id: SyntaxContextId,
|
||||||
|
db: &dyn ExpandDatabase,
|
||||||
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "#{self_id} parent: #{}, outer_mark: (", this.parent)?;
|
||||||
|
match this.outer_expn {
|
||||||
|
Some(id) => {
|
||||||
|
write!(f, "{:?}::{{{{expn{:?}}}}}", db.lookup_intern_macro_call(id).krate, id)?
|
||||||
|
}
|
||||||
|
None => write!(f, "root")?,
|
||||||
|
}
|
||||||
|
write!(f, ", {:?})", this.outer_transparency)
|
||||||
|
}
|
||||||
|
|
||||||
stdx::format_to!(s, "{:?}\n", SyntaxContextDebug(db, e.key, &e.value.unwrap()));
|
stdx::format_to!(s, "{:?}\n", SyntaxContextDebug(db, e.key, &e.value.unwrap()));
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
|
|
|
@ -32,7 +32,7 @@ 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, Edition, FileId};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use span::{FileRange, HirFileIdRepr, Span, SyntaxContextId};
|
use span::{FileRange, HirFileIdRepr, Span, SyntaxContextData, SyntaxContextId};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
SyntaxNode, SyntaxToken, TextRange, TextSize,
|
SyntaxNode, SyntaxToken, TextRange, TextSize,
|
||||||
|
@ -44,7 +44,6 @@ use crate::{
|
||||||
builtin_derive_macro::BuiltinDeriveExpander,
|
builtin_derive_macro::BuiltinDeriveExpander,
|
||||||
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
|
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
|
||||||
db::{ExpandDatabase, TokenExpander},
|
db::{ExpandDatabase, TokenExpander},
|
||||||
hygiene::SyntaxContextData,
|
|
||||||
mod_path::ModPath,
|
mod_path::ModPath,
|
||||||
proc_macro::{CustomProcMacroExpander, ProcMacroKind},
|
proc_macro::{CustomProcMacroExpander, ProcMacroKind},
|
||||||
span_map::{ExpansionSpanMap, SpanMap},
|
span_map::{ExpansionSpanMap, SpanMap},
|
||||||
|
|
129
crates/span/src/hygiene.rs
Normal file
129
crates/span/src/hygiene.rs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
//! Machinery for hygienic macros.
|
||||||
|
//!
|
||||||
|
//! Inspired by Matthew Flatt et al., “Macros That Work Together: Compile-Time Bindings, Partial
|
||||||
|
//! Expansion, and Definition Contexts,” *Journal of Functional Programming* 22, no. 2
|
||||||
|
//! (March 1, 2012): 181–216, <https://doi.org/10.1017/S0956796812000093>.
|
||||||
|
//!
|
||||||
|
//! Also see https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies
|
||||||
|
//!
|
||||||
|
//! # The Expansion Order Hierarchy
|
||||||
|
//!
|
||||||
|
//! `ExpnData` in rustc, rust-analyzer's version is [`MacroCallLoc`]. Traversing the hierarchy
|
||||||
|
//! upwards can be achieved by walking up [`MacroCallLoc::kind`]'s contained file id, as
|
||||||
|
//! [`MacroFile`]s are interned [`MacroCallLoc`]s.
|
||||||
|
//!
|
||||||
|
//! # The Macro Definition Hierarchy
|
||||||
|
//!
|
||||||
|
//! `SyntaxContextData` in rustc and rust-analyzer. Basically the same in both.
|
||||||
|
//!
|
||||||
|
//! # The Call-site Hierarchy
|
||||||
|
//!
|
||||||
|
//! `ExpnData::call_site` in rustc, [`MacroCallLoc::call_site`] in rust-analyzer.
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use salsa::{InternId, InternValue};
|
||||||
|
|
||||||
|
use crate::MacroCallId;
|
||||||
|
|
||||||
|
/// Interned [`SyntaxContextData`].
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct SyntaxContextId(InternId);
|
||||||
|
|
||||||
|
impl salsa::InternKey for SyntaxContextId {
|
||||||
|
fn from_intern_id(v: salsa::InternId) -> Self {
|
||||||
|
SyntaxContextId(v)
|
||||||
|
}
|
||||||
|
fn as_intern_id(&self) -> salsa::InternId {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SyntaxContextId {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0.as_u32())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SyntaxContextId {
|
||||||
|
/// The root context, which is the parent of all other contexts. All [`FileId`]s have this context.
|
||||||
|
pub const ROOT: Self = SyntaxContextId(unsafe { InternId::new_unchecked(0) });
|
||||||
|
|
||||||
|
pub fn is_root(self) -> bool {
|
||||||
|
self == Self::ROOT
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deconstruct a `SyntaxContextId` into a raw `u32`.
|
||||||
|
/// This should only be used for deserialization purposes for the proc-macro server.
|
||||||
|
pub fn into_u32(self) -> u32 {
|
||||||
|
self.0.as_u32()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a `SyntaxContextId` from a raw `u32`.
|
||||||
|
/// This should only be used for serialization purposes for the proc-macro server.
|
||||||
|
pub fn from_u32(u32: u32) -> Self {
|
||||||
|
Self(InternId::from(u32))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A syntax context describes a hierarchy tracking order of macro definitions.
|
||||||
|
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct SyntaxContextData {
|
||||||
|
pub outer_expn: Option<MacroCallId>,
|
||||||
|
pub outer_transparency: Transparency,
|
||||||
|
pub parent: SyntaxContextId,
|
||||||
|
/// This context, but with all transparent and semi-transparent expansions filtered away.
|
||||||
|
pub opaque: SyntaxContextId,
|
||||||
|
/// This context, but with all transparent expansions filtered away.
|
||||||
|
pub opaque_and_semitransparent: SyntaxContextId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InternValue for SyntaxContextData {
|
||||||
|
type Key = (SyntaxContextId, Option<MacroCallId>, Transparency);
|
||||||
|
|
||||||
|
fn into_key(&self) -> Self::Key {
|
||||||
|
(self.parent, self.outer_expn, self.outer_transparency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for SyntaxContextData {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("SyntaxContextData")
|
||||||
|
.field("outer_expn", &self.outer_expn)
|
||||||
|
.field("outer_transparency", &self.outer_transparency)
|
||||||
|
.field("parent", &self.parent)
|
||||||
|
.field("opaque", &self.opaque)
|
||||||
|
.field("opaque_and_semitransparent", &self.opaque_and_semitransparent)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SyntaxContextData {
|
||||||
|
pub fn root() -> Self {
|
||||||
|
SyntaxContextData {
|
||||||
|
outer_expn: None,
|
||||||
|
outer_transparency: Transparency::Opaque,
|
||||||
|
parent: SyntaxContextId::ROOT,
|
||||||
|
opaque: SyntaxContextId::ROOT,
|
||||||
|
opaque_and_semitransparent: SyntaxContextId::ROOT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A property of a macro expansion that determines how identifiers
|
||||||
|
/// produced by that expansion are resolved.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
|
||||||
|
pub enum Transparency {
|
||||||
|
/// Identifier produced by a transparent expansion is always resolved at call-site.
|
||||||
|
/// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
|
||||||
|
Transparent,
|
||||||
|
/// Identifier produced by a semi-transparent expansion may be resolved
|
||||||
|
/// either at call-site or at definition-site.
|
||||||
|
/// If it's a local variable, label or `$crate` then it's resolved at def-site.
|
||||||
|
/// Otherwise it's resolved at call-site.
|
||||||
|
/// `macro_rules` macros behave like this, built-in macros currently behave like this too,
|
||||||
|
/// but that's an implementation detail.
|
||||||
|
SemiTransparent,
|
||||||
|
/// Identifier produced by an opaque expansion is always resolved at definition-site.
|
||||||
|
/// Def-site spans in procedural macros, identifiers from `macro` by default use this.
|
||||||
|
Opaque,
|
||||||
|
}
|
|
@ -3,9 +3,14 @@ use std::fmt::{self, Write};
|
||||||
|
|
||||||
use salsa::InternId;
|
use salsa::InternId;
|
||||||
|
|
||||||
|
mod hygiene;
|
||||||
mod map;
|
mod map;
|
||||||
|
|
||||||
pub use crate::map::{RealSpanMap, SpanMap};
|
pub use self::{
|
||||||
|
hygiene::{SyntaxContextData, SyntaxContextId, Transparency},
|
||||||
|
map::{RealSpanMap, SpanMap},
|
||||||
|
};
|
||||||
|
|
||||||
pub use syntax::{TextRange, TextSize};
|
pub use syntax::{TextRange, TextSize};
|
||||||
pub use vfs::FileId;
|
pub use vfs::FileId;
|
||||||
|
|
||||||
|
@ -23,7 +28,7 @@ pub struct FileRange {
|
||||||
|
|
||||||
pub type ErasedFileAstId = la_arena::Idx<syntax::SyntaxNodePtr>;
|
pub type ErasedFileAstId = la_arena::Idx<syntax::SyntaxNodePtr>;
|
||||||
|
|
||||||
// The first inde is always the root node's AstId
|
// The first index is always the root node's AstId
|
||||||
pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId =
|
pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId =
|
||||||
la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(0));
|
la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(0));
|
||||||
|
|
||||||
|
@ -68,41 +73,6 @@ impl fmt::Display for Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
pub struct SyntaxContextId(InternId);
|
|
||||||
|
|
||||||
impl salsa::InternKey for SyntaxContextId {
|
|
||||||
fn from_intern_id(v: salsa::InternId) -> Self {
|
|
||||||
SyntaxContextId(v)
|
|
||||||
}
|
|
||||||
fn as_intern_id(&self) -> salsa::InternId {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for SyntaxContextId {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.0.as_u32())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// inherent trait impls please tyvm
|
|
||||||
impl SyntaxContextId {
|
|
||||||
pub const ROOT: Self = SyntaxContextId(unsafe { InternId::new_unchecked(0) });
|
|
||||||
|
|
||||||
pub fn is_root(self) -> bool {
|
|
||||||
self == Self::ROOT
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_u32(self) -> u32 {
|
|
||||||
self.0.as_u32()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_u32(u32: u32) -> Self {
|
|
||||||
Self(InternId::from(u32))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct SpanAnchor {
|
pub struct SpanAnchor {
|
||||||
pub file_id: FileId,
|
pub file_id: FileId,
|
||||||
|
|
Loading…
Reference in a new issue