mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 13:13:18 +00:00 
			
		
		
		
	Auto merge of #16728 - Veykril:span-docs, r=Veykril
minor: Move span stuff around
This commit is contained in:
		
						commit
						c512e2e1bf
					
				
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -1855,7 +1855,9 @@ dependencies = [
 | 
			
		||||
name = "span"
 | 
			
		||||
version = "0.0.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "hashbrown",
 | 
			
		||||
 "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
 | 
			
		||||
 "rustc-hash",
 | 
			
		||||
 "salsa",
 | 
			
		||||
 "stdx",
 | 
			
		||||
 "syntax",
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,6 @@ use std::mem;
 | 
			
		||||
use base_db::CrateId;
 | 
			
		||||
use either::Either;
 | 
			
		||||
use hir_expand::{
 | 
			
		||||
    ast_id_map::AstIdMap,
 | 
			
		||||
    name::{name, AsName, Name},
 | 
			
		||||
    ExpandError, InFile,
 | 
			
		||||
};
 | 
			
		||||
@ -14,6 +13,7 @@ use intern::Interned;
 | 
			
		||||
use profile::Count;
 | 
			
		||||
use rustc_hash::FxHashMap;
 | 
			
		||||
use smallvec::SmallVec;
 | 
			
		||||
use span::AstIdMap;
 | 
			
		||||
use syntax::{
 | 
			
		||||
    ast::{
 | 
			
		||||
        self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasLoopBody, HasName,
 | 
			
		||||
 | 
			
		||||
@ -47,18 +47,13 @@ use std::{
 | 
			
		||||
use ast::{AstNode, StructKind};
 | 
			
		||||
use base_db::CrateId;
 | 
			
		||||
use either::Either;
 | 
			
		||||
use hir_expand::{
 | 
			
		||||
    ast_id_map::{AstIdNode, FileAstId},
 | 
			
		||||
    attrs::RawAttrs,
 | 
			
		||||
    name::Name,
 | 
			
		||||
    ExpandTo, HirFileId, InFile,
 | 
			
		||||
};
 | 
			
		||||
use hir_expand::{attrs::RawAttrs, name::Name, ExpandTo, HirFileId, InFile};
 | 
			
		||||
use intern::Interned;
 | 
			
		||||
use la_arena::{Arena, Idx, IdxRange, RawIdx};
 | 
			
		||||
use profile::Count;
 | 
			
		||||
use rustc_hash::FxHashMap;
 | 
			
		||||
use smallvec::SmallVec;
 | 
			
		||||
use span::Span;
 | 
			
		||||
use span::{AstIdNode, FileAstId, Span};
 | 
			
		||||
use stdx::never;
 | 
			
		||||
use syntax::{ast, match_ast, SyntaxKind};
 | 
			
		||||
use triomphe::Arc;
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,9 @@
 | 
			
		||||
 | 
			
		||||
use std::collections::hash_map::Entry;
 | 
			
		||||
 | 
			
		||||
use hir_expand::{
 | 
			
		||||
    ast_id_map::AstIdMap, mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId,
 | 
			
		||||
};
 | 
			
		||||
use hir_expand::{mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId};
 | 
			
		||||
use la_arena::Arena;
 | 
			
		||||
use span::AstIdMap;
 | 
			
		||||
use syntax::{
 | 
			
		||||
    ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
 | 
			
		||||
    AstNode,
 | 
			
		||||
 | 
			
		||||
@ -76,7 +76,6 @@ use base_db::{
 | 
			
		||||
    CrateId, Edition,
 | 
			
		||||
};
 | 
			
		||||
use hir_expand::{
 | 
			
		||||
    ast_id_map::{AstIdNode, FileAstId},
 | 
			
		||||
    builtin_attr_macro::BuiltinAttrExpander,
 | 
			
		||||
    builtin_derive_macro::BuiltinDeriveExpander,
 | 
			
		||||
    builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
 | 
			
		||||
@ -91,7 +90,7 @@ use hir_expand::{
 | 
			
		||||
use item_tree::ExternBlock;
 | 
			
		||||
use la_arena::Idx;
 | 
			
		||||
use nameres::DefMap;
 | 
			
		||||
use span::{FileId, Span};
 | 
			
		||||
use span::{AstIdNode, FileAstId, FileId, Span};
 | 
			
		||||
use stdx::impl_from;
 | 
			
		||||
use syntax::{ast, AstNode};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,10 @@
 | 
			
		||||
use std::cell::OnceCell;
 | 
			
		||||
 | 
			
		||||
use hir_expand::{
 | 
			
		||||
    ast_id_map::{AstIdMap, AstIdNode},
 | 
			
		||||
    span_map::{SpanMap, SpanMapRef},
 | 
			
		||||
    AstId, HirFileId, InFile,
 | 
			
		||||
};
 | 
			
		||||
use span::{AstIdMap, AstIdNode};
 | 
			
		||||
use syntax::ast;
 | 
			
		||||
use triomphe::Arc;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -61,13 +61,13 @@ use std::ops::Deref;
 | 
			
		||||
 | 
			
		||||
use base_db::{CrateId, Edition, FileId};
 | 
			
		||||
use hir_expand::{
 | 
			
		||||
    ast_id_map::FileAstId, name::Name, proc_macro::ProcMacroKind, HirFileId, InFile, MacroCallId,
 | 
			
		||||
    MacroDefId,
 | 
			
		||||
    name::Name, proc_macro::ProcMacroKind, HirFileId, InFile, MacroCallId, MacroDefId,
 | 
			
		||||
};
 | 
			
		||||
use itertools::Itertools;
 | 
			
		||||
use la_arena::Arena;
 | 
			
		||||
use profile::Count;
 | 
			
		||||
use rustc_hash::{FxHashMap, FxHashSet};
 | 
			
		||||
use span::FileAstId;
 | 
			
		||||
use stdx::format_to;
 | 
			
		||||
use syntax::{ast, SmolStr};
 | 
			
		||||
use triomphe::Arc;
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,6 @@ use base_db::{CrateId, Dependency, Edition, FileId};
 | 
			
		||||
use cfg::{CfgExpr, CfgOptions};
 | 
			
		||||
use either::Either;
 | 
			
		||||
use hir_expand::{
 | 
			
		||||
    ast_id_map::FileAstId,
 | 
			
		||||
    attrs::{Attr, AttrId},
 | 
			
		||||
    builtin_attr_macro::{find_builtin_attr, BuiltinAttrExpander},
 | 
			
		||||
    builtin_derive_macro::find_builtin_derive,
 | 
			
		||||
@ -23,7 +22,7 @@ use itertools::{izip, Itertools};
 | 
			
		||||
use la_arena::Idx;
 | 
			
		||||
use limit::Limit;
 | 
			
		||||
use rustc_hash::{FxHashMap, FxHashSet};
 | 
			
		||||
use span::{ErasedFileAstId, Span, SyntaxContextId};
 | 
			
		||||
use span::{ErasedFileAstId, FileAstId, Span, SyntaxContextId};
 | 
			
		||||
use stdx::always;
 | 
			
		||||
use syntax::{ast, SmolStr};
 | 
			
		||||
use triomphe::Arc;
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ use either::Either;
 | 
			
		||||
use limit::Limit;
 | 
			
		||||
use mbe::{syntax_node_to_token_tree, ValueResult};
 | 
			
		||||
use rustc_hash::FxHashSet;
 | 
			
		||||
use span::SyntaxContextId;
 | 
			
		||||
use span::{AstIdMap, SyntaxContextData, SyntaxContextId};
 | 
			
		||||
use syntax::{
 | 
			
		||||
    ast::{self, HasAttrs},
 | 
			
		||||
    AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T,
 | 
			
		||||
@ -13,16 +13,12 @@ use syntax::{
 | 
			
		||||
use triomphe::Arc;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    ast_id_map::AstIdMap,
 | 
			
		||||
    attrs::collect_attrs,
 | 
			
		||||
    builtin_attr_macro::pseudo_derive_attr_expansion,
 | 
			
		||||
    builtin_fn_macro::EagerExpander,
 | 
			
		||||
    declarative::DeclarativeMacroExpander,
 | 
			
		||||
    fixup::{self, reverse_fixups, SyntaxFixupUndoInfo},
 | 
			
		||||
    hygiene::{
 | 
			
		||||
        span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt,
 | 
			
		||||
        SyntaxContextData,
 | 
			
		||||
    },
 | 
			
		||||
    hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt},
 | 
			
		||||
    proc_macro::ProcMacros,
 | 
			
		||||
    span_map::{RealSpanMap, SpanMap, SpanMapRef},
 | 
			
		||||
    tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
 | 
			
		||||
@ -61,7 +57,6 @@ pub trait ExpandDatabase: SourceDatabase {
 | 
			
		||||
    #[salsa::input]
 | 
			
		||||
    fn proc_macros(&self) -> Arc<ProcMacros>;
 | 
			
		||||
 | 
			
		||||
    #[salsa::invoke(AstIdMap::new)]
 | 
			
		||||
    fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
 | 
			
		||||
 | 
			
		||||
    /// Main public API -- parses a hir file, not caring whether it's a real
 | 
			
		||||
@ -256,6 +251,10 @@ pub fn expand_speculative(
 | 
			
		||||
    Some((node.syntax_node(), token))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn ast_id_map(db: &dyn ExpandDatabase, file_id: span::HirFileId) -> triomphe::Arc<AstIdMap> {
 | 
			
		||||
    triomphe::Arc::new(AstIdMap::from_source(&db.parse_or_expand(file_id)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> SyntaxNode {
 | 
			
		||||
    match file_id.repr() {
 | 
			
		||||
        HirFileIdRepr::FileId(file_id) => db.parse(file_id).syntax_node(),
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,16 @@
 | 
			
		||||
use std::iter;
 | 
			
		||||
 | 
			
		||||
use either::Either;
 | 
			
		||||
use span::{FileId, FileRange, HirFileId, HirFileIdRepr, MacroFileId, SyntaxContextId};
 | 
			
		||||
use syntax::{AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize};
 | 
			
		||||
use span::{
 | 
			
		||||
    AstIdNode, ErasedFileAstId, FileAstId, FileId, FileRange, HirFileId, HirFileIdRepr,
 | 
			
		||||
    MacroFileId, SyntaxContextId,
 | 
			
		||||
};
 | 
			
		||||
use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize};
 | 
			
		||||
 | 
			
		||||
use crate::{db, map_node_range_up, span_for_offset, MacroFileIdExt};
 | 
			
		||||
use crate::{
 | 
			
		||||
    db::{self, ExpandDatabase},
 | 
			
		||||
    map_node_range_up, span_for_offset, MacroFileIdExt,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// `InFile<T>` stores a value of `T` inside a particular file/syntax tree.
 | 
			
		||||
///
 | 
			
		||||
@ -23,6 +29,31 @@ pub type InFile<T> = InFileWrapper<HirFileId, T>;
 | 
			
		||||
pub type InMacroFile<T> = InFileWrapper<MacroFileId, T>;
 | 
			
		||||
pub type InRealFile<T> = InFileWrapper<FileId, T>;
 | 
			
		||||
 | 
			
		||||
/// `AstId` points to an AST node in any file.
 | 
			
		||||
///
 | 
			
		||||
/// It is stable across reparses, and can be used as salsa key/value.
 | 
			
		||||
pub type AstId<N> = crate::InFile<FileAstId<N>>;
 | 
			
		||||
 | 
			
		||||
impl<N: AstIdNode> AstId<N> {
 | 
			
		||||
    pub fn to_node(&self, db: &dyn ExpandDatabase) -> N {
 | 
			
		||||
        self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id))
 | 
			
		||||
    }
 | 
			
		||||
    pub fn to_in_file_node(&self, db: &dyn ExpandDatabase) -> crate::InFile<N> {
 | 
			
		||||
        crate::InFile::new(self.file_id, self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id)))
 | 
			
		||||
    }
 | 
			
		||||
    pub fn to_ptr(&self, db: &dyn ExpandDatabase) -> AstPtr<N> {
 | 
			
		||||
        db.ast_id_map(self.file_id).get(self.value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub type ErasedAstId = crate::InFile<ErasedFileAstId>;
 | 
			
		||||
 | 
			
		||||
impl ErasedAstId {
 | 
			
		||||
    pub fn to_ptr(&self, db: &dyn ExpandDatabase) -> SyntaxNodePtr {
 | 
			
		||||
        db.ast_id_map(self.file_id).get_erased(self.value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<FileKind, T> InFileWrapper<FileKind, T> {
 | 
			
		||||
    pub fn new(file_id: FileKind, value: T) -> Self {
 | 
			
		||||
        Self { file_id, value }
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
//! this moment, this is horribly incomplete and handles only `$crate`.
 | 
			
		||||
 | 
			
		||||
// FIXME: Consider moving this into the span crate.
 | 
			
		||||
//! 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.
 | 
			
		||||
// 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 base_db::salsa::{self, InternValue};
 | 
			
		||||
use span::{MacroCallId, Span, SyntaxContextId};
 | 
			
		||||
use span::{MacroCallId, Span, SyntaxContextData, SyntaxContextId};
 | 
			
		||||
 | 
			
		||||
use crate::db::{ExpandDatabase, InternSyntaxContextQuery};
 | 
			
		||||
 | 
			
		||||
#[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,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 use span::Transparency;
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
@ -122,7 +62,7 @@ pub(super) fn apply_mark(
 | 
			
		||||
    transparency: Transparency,
 | 
			
		||||
) -> SyntaxContextId {
 | 
			
		||||
    if transparency == Transparency::Opaque {
 | 
			
		||||
        return apply_mark_internal(db, ctxt, Some(call_id), transparency);
 | 
			
		||||
        return apply_mark_internal(db, ctxt, call_id, transparency);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let call_site_ctxt = db.lookup_intern_macro_call(call_id).call_site.ctx;
 | 
			
		||||
@ -133,7 +73,7 @@ pub(super) fn apply_mark(
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if call_site_ctxt.is_root() {
 | 
			
		||||
        return apply_mark_internal(db, ctxt, Some(call_id), transparency);
 | 
			
		||||
        return apply_mark_internal(db, ctxt, call_id, transparency);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a
 | 
			
		||||
@ -148,15 +88,19 @@ pub(super) fn apply_mark(
 | 
			
		||||
    for (call_id, transparency) in ctxt.marks(db) {
 | 
			
		||||
        call_site_ctxt = apply_mark_internal(db, call_site_ctxt, call_id, transparency);
 | 
			
		||||
    }
 | 
			
		||||
    apply_mark_internal(db, call_site_ctxt, Some(call_id), transparency)
 | 
			
		||||
    apply_mark_internal(db, call_site_ctxt, call_id, transparency)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn apply_mark_internal(
 | 
			
		||||
    db: &dyn ExpandDatabase,
 | 
			
		||||
    ctxt: SyntaxContextId,
 | 
			
		||||
    call_id: Option<MacroCallId>,
 | 
			
		||||
    call_id: MacroCallId,
 | 
			
		||||
    transparency: Transparency,
 | 
			
		||||
) -> SyntaxContextId {
 | 
			
		||||
    use base_db::salsa;
 | 
			
		||||
 | 
			
		||||
    let call_id = Some(call_id);
 | 
			
		||||
 | 
			
		||||
    let syntax_context_data = db.lookup_intern_syntax_context(ctxt);
 | 
			
		||||
    let mut opaque = syntax_context_data.opaque;
 | 
			
		||||
    let mut opaque_and_semitransparent = syntax_context_data.opaque_and_semitransparent;
 | 
			
		||||
@ -199,13 +143,14 @@ fn apply_mark_internal(
 | 
			
		||||
        opaque_and_semitransparent,
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait SyntaxContextExt {
 | 
			
		||||
    fn normalize_to_macro_rules(self, db: &dyn ExpandDatabase) -> Self;
 | 
			
		||||
    fn normalize_to_macros_2_0(self, db: &dyn ExpandDatabase) -> Self;
 | 
			
		||||
    fn parent_ctxt(self, db: &dyn ExpandDatabase) -> Self;
 | 
			
		||||
    fn remove_mark(&mut self, db: &dyn ExpandDatabase) -> (Option<MacroCallId>, Transparency);
 | 
			
		||||
    fn outer_mark(self, db: &dyn ExpandDatabase) -> (Option<MacroCallId>, Transparency);
 | 
			
		||||
    fn marks(self, db: &dyn ExpandDatabase) -> Vec<(Option<MacroCallId>, Transparency)>;
 | 
			
		||||
    fn marks(self, db: &dyn ExpandDatabase) -> Vec<(MacroCallId, Transparency)>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SyntaxContextExt for SyntaxContextId {
 | 
			
		||||
@ -227,7 +172,7 @@ impl SyntaxContextExt for SyntaxContextId {
 | 
			
		||||
        *self = data.parent;
 | 
			
		||||
        (data.outer_expn, data.outer_transparency)
 | 
			
		||||
    }
 | 
			
		||||
    fn marks(self, db: &dyn ExpandDatabase) -> Vec<(Option<MacroCallId>, Transparency)> {
 | 
			
		||||
    fn marks(self, db: &dyn ExpandDatabase) -> Vec<(MacroCallId, Transparency)> {
 | 
			
		||||
        let mut marks = marks_rev(self, db).collect::<Vec<_>>();
 | 
			
		||||
        marks.reverse();
 | 
			
		||||
        marks
 | 
			
		||||
@ -238,11 +183,15 @@ impl SyntaxContextExt for SyntaxContextId {
 | 
			
		||||
pub fn marks_rev(
 | 
			
		||||
    ctxt: SyntaxContextId,
 | 
			
		||||
    db: &dyn ExpandDatabase,
 | 
			
		||||
) -> impl Iterator<Item = (Option<MacroCallId>, Transparency)> + '_ {
 | 
			
		||||
    iter::successors(Some(ctxt), move |&mark| {
 | 
			
		||||
        Some(mark.parent_ctxt(db)).filter(|&it| it != SyntaxContextId::ROOT)
 | 
			
		||||
    })
 | 
			
		||||
    .map(|ctx| ctx.outer_mark(db))
 | 
			
		||||
) -> impl Iterator<Item = (MacroCallId, Transparency)> + '_ {
 | 
			
		||||
    iter::successors(Some(ctxt), move |&mark| Some(mark.parent_ctxt(db)))
 | 
			
		||||
        .take_while(|&it| !it.is_root())
 | 
			
		||||
        .map(|ctx| {
 | 
			
		||||
            let mark = ctx.outer_mark(db);
 | 
			
		||||
            // We stop before taking the root expansion, as such we cannot encounter a `None` outer
 | 
			
		||||
            // expansion, as only the ROOT has it.
 | 
			
		||||
            (mark.0.unwrap(), mark.1)
 | 
			
		||||
        })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn dump_syntax_contexts(db: &dyn ExpandDatabase) -> String {
 | 
			
		||||
@ -277,9 +226,26 @@ pub(crate) fn dump_syntax_contexts(db: &dyn ExpandDatabase) -> String {
 | 
			
		||||
 | 
			
		||||
        impl<'a> std::fmt::Debug for SyntaxContextDebug<'a> {
 | 
			
		||||
            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)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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()));
 | 
			
		||||
    }
 | 
			
		||||
    s
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,6 @@
 | 
			
		||||
 | 
			
		||||
#![warn(rust_2018_idioms, unused_lifetimes)]
 | 
			
		||||
 | 
			
		||||
pub mod ast_id_map;
 | 
			
		||||
pub mod attrs;
 | 
			
		||||
pub mod builtin_attr_macro;
 | 
			
		||||
pub mod builtin_derive_macro;
 | 
			
		||||
@ -32,7 +31,7 @@ use std::{fmt, hash::Hash};
 | 
			
		||||
 | 
			
		||||
use base_db::{salsa::impl_intern_value_trivial, CrateId, Edition, FileId};
 | 
			
		||||
use either::Either;
 | 
			
		||||
use span::{FileRange, HirFileIdRepr, Span, SyntaxContextId};
 | 
			
		||||
use span::{ErasedFileAstId, FileRange, HirFileIdRepr, Span, SyntaxContextData, SyntaxContextId};
 | 
			
		||||
use syntax::{
 | 
			
		||||
    ast::{self, AstNode},
 | 
			
		||||
    SyntaxNode, SyntaxToken, TextRange, TextSize,
 | 
			
		||||
@ -44,14 +43,12 @@ use crate::{
 | 
			
		||||
    builtin_derive_macro::BuiltinDeriveExpander,
 | 
			
		||||
    builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
 | 
			
		||||
    db::{ExpandDatabase, TokenExpander},
 | 
			
		||||
    hygiene::SyntaxContextData,
 | 
			
		||||
    mod_path::ModPath,
 | 
			
		||||
    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 crate::files::{AstId, ErasedAstId, InFile, InMacroFile, InRealFile};
 | 
			
		||||
 | 
			
		||||
pub use mbe::ValueResult;
 | 
			
		||||
pub use span::{HirFileId, MacroCallId, MacroFileId};
 | 
			
		||||
 | 
			
		||||
@ -358,7 +358,7 @@ pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContextId) ->
 | 
			
		||||
        result_mark = Some(mark);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result_mark.flatten().map(|call| db.lookup_intern_macro_call(call).def.krate)
 | 
			
		||||
    result_mark.map(|call| db.lookup_intern_macro_call(call).def.krate)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub use crate::name as __name;
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,8 @@ authors.workspace = true
 | 
			
		||||
[dependencies]
 | 
			
		||||
la-arena.workspace = true
 | 
			
		||||
salsa.workspace = true
 | 
			
		||||
 | 
			
		||||
rustc-hash.workspace = true
 | 
			
		||||
hashbrown.workspace = true
 | 
			
		||||
 | 
			
		||||
# local deps
 | 
			
		||||
vfs.workspace = true
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,6 @@
 | 
			
		||||
//! item as an ID. That way, id's don't change unless the set of items itself
 | 
			
		||||
//! changes.
 | 
			
		||||
 | 
			
		||||
// FIXME: Consider moving this into the span crate
 | 
			
		||||
 | 
			
		||||
use std::{
 | 
			
		||||
    any::type_name,
 | 
			
		||||
    fmt,
 | 
			
		||||
@ -15,38 +13,12 @@ use std::{
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use la_arena::{Arena, Idx, RawIdx};
 | 
			
		||||
use profile::Count;
 | 
			
		||||
use rustc_hash::FxHasher;
 | 
			
		||||
use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
 | 
			
		||||
 | 
			
		||||
use crate::db::ExpandDatabase;
 | 
			
		||||
 | 
			
		||||
pub use span::ErasedFileAstId;
 | 
			
		||||
 | 
			
		||||
/// `AstId` points to an AST node in any file.
 | 
			
		||||
///
 | 
			
		||||
/// It is stable across reparses, and can be used as salsa key/value.
 | 
			
		||||
pub type AstId<N> = crate::InFile<FileAstId<N>>;
 | 
			
		||||
 | 
			
		||||
impl<N: AstIdNode> AstId<N> {
 | 
			
		||||
    pub fn to_node(&self, db: &dyn ExpandDatabase) -> N {
 | 
			
		||||
        self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id))
 | 
			
		||||
    }
 | 
			
		||||
    pub fn to_in_file_node(&self, db: &dyn ExpandDatabase) -> crate::InFile<N> {
 | 
			
		||||
        crate::InFile::new(self.file_id, self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id)))
 | 
			
		||||
    }
 | 
			
		||||
    pub fn to_ptr(&self, db: &dyn ExpandDatabase) -> AstPtr<N> {
 | 
			
		||||
        db.ast_id_map(self.file_id).get(self.value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub type ErasedAstId = crate::InFile<ErasedFileAstId>;
 | 
			
		||||
 | 
			
		||||
impl ErasedAstId {
 | 
			
		||||
    pub fn to_ptr(&self, db: &dyn ExpandDatabase) -> SyntaxNodePtr {
 | 
			
		||||
        db.ast_id_map(self.file_id).get_erased(self.value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
/// See crates\hir-expand\src\ast_id_map.rs
 | 
			
		||||
/// This is a type erased FileAstId.
 | 
			
		||||
pub type ErasedFileAstId = la_arena::Idx<syntax::SyntaxNodePtr>;
 | 
			
		||||
 | 
			
		||||
/// `AstId` points to an AST node in a specific file.
 | 
			
		||||
pub struct FileAstId<N: AstIdNode> {
 | 
			
		||||
@ -138,7 +110,6 @@ pub struct AstIdMap {
 | 
			
		||||
    arena: Arena<SyntaxNodePtr>,
 | 
			
		||||
    /// Reverse: map ptr to id.
 | 
			
		||||
    map: hashbrown::HashMap<Idx<SyntaxNodePtr>, (), ()>,
 | 
			
		||||
    _c: Count<Self>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Debug for AstIdMap {
 | 
			
		||||
@ -155,14 +126,7 @@ impl PartialEq for AstIdMap {
 | 
			
		||||
impl Eq for AstIdMap {}
 | 
			
		||||
 | 
			
		||||
impl AstIdMap {
 | 
			
		||||
    pub(crate) fn new(
 | 
			
		||||
        db: &dyn ExpandDatabase,
 | 
			
		||||
        file_id: span::HirFileId,
 | 
			
		||||
    ) -> triomphe::Arc<AstIdMap> {
 | 
			
		||||
        triomphe::Arc::new(AstIdMap::from_source(&db.parse_or_expand(file_id)))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn from_source(node: &SyntaxNode) -> AstIdMap {
 | 
			
		||||
    pub fn from_source(node: &SyntaxNode) -> AstIdMap {
 | 
			
		||||
        assert!(node.parent().is_none());
 | 
			
		||||
        let mut res = AstIdMap::default();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										130
									
								
								crates/span/src/hygiene.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								crates/span/src/hygiene.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,130 @@
 | 
			
		||||
//! 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 {
 | 
			
		||||
    /// Invariant: Only [`SyntaxContextId::ROOT`] has a [`None`] outer expansion.
 | 
			
		||||
    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,16 @@ use std::fmt::{self, Write};
 | 
			
		||||
 | 
			
		||||
use salsa::InternId;
 | 
			
		||||
 | 
			
		||||
mod ast_id;
 | 
			
		||||
mod hygiene;
 | 
			
		||||
mod map;
 | 
			
		||||
 | 
			
		||||
pub use crate::map::{RealSpanMap, SpanMap};
 | 
			
		||||
pub use self::{
 | 
			
		||||
    ast_id::{AstIdMap, AstIdNode, ErasedFileAstId, FileAstId},
 | 
			
		||||
    hygiene::{SyntaxContextData, SyntaxContextId, Transparency},
 | 
			
		||||
    map::{RealSpanMap, SpanMap},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub use syntax::{TextRange, TextSize};
 | 
			
		||||
pub use vfs::FileId;
 | 
			
		||||
 | 
			
		||||
@ -21,9 +28,10 @@ pub struct FileRange {
 | 
			
		||||
    pub range: TextRange,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
/// The root ast id always points to the encompassing file, using this in spans is discouraged as
 | 
			
		||||
/// any range relative to it will be effectively absolute, ruining the entire point of anchored
 | 
			
		||||
/// relative text ranges.
 | 
			
		||||
pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId =
 | 
			
		||||
    la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(0));
 | 
			
		||||
 | 
			
		||||
@ -42,6 +50,7 @@ pub struct SpanData<Ctx> {
 | 
			
		||||
    /// We need the anchor for incrementality, as storing absolute ranges will require
 | 
			
		||||
    /// recomputation on every change in a file at all times.
 | 
			
		||||
    pub range: TextRange,
 | 
			
		||||
    /// The anchor this span is relative to.
 | 
			
		||||
    pub anchor: SpanAnchor,
 | 
			
		||||
    /// The syntax context of the span.
 | 
			
		||||
    pub ctx: Ctx,
 | 
			
		||||
@ -68,41 +77,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)]
 | 
			
		||||
pub struct SpanAnchor {
 | 
			
		||||
    pub file_id: FileId,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user