1use std::fmt::{self, Write};
3
4mod ast_id;
5mod hygiene;
6mod map;
7
8pub use self::{
9 ast_id::{
10 AstIdMap, AstIdNode, ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, FileAstId,
11 ROOT_ERASED_FILE_AST_ID,
12 },
13 hygiene::{SyntaxContext, Transparency},
14 map::{RealSpanMap, SpanMap},
15};
16
17pub use syntax::Edition;
18pub use text_size::{TextRange, TextSize};
19pub use vfs::FileId;
20
21pub type Span = SpanData<SyntaxContext>;
22
23impl Span {
24 pub fn cover(self, other: Span) -> Span {
25 if self.anchor != other.anchor {
26 return self;
27 }
28 let range = self.range.cover(other.range);
29 Span { range, ..self }
30 }
31}
32
33#[derive(Clone, Copy, PartialEq, Eq, Hash)]
37pub struct SpanData<Ctx> {
38 pub range: TextRange,
42 pub anchor: SpanAnchor,
44 pub ctx: Ctx,
46}
47
48impl<Ctx: fmt::Debug> fmt::Debug for SpanData<Ctx> {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 if f.alternate() {
51 fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
52 f.write_char(':')?;
53 write!(f, "{:#?}", self.anchor.ast_id)?;
54 f.write_char('@')?;
55 fmt::Debug::fmt(&self.range, f)?;
56 f.write_char('#')?;
57 self.ctx.fmt(f)
58 } else {
59 f.debug_struct("SpanData")
60 .field("range", &self.range)
61 .field("anchor", &self.anchor)
62 .field("ctx", &self.ctx)
63 .finish()
64 }
65 }
66}
67
68impl<Ctx: Copy> SpanData<Ctx> {
69 pub fn eq_ignoring_ctx(self, other: Self) -> bool {
70 self.anchor == other.anchor && self.range == other.range
71 }
72}
73
74impl fmt::Display for Span {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
77 f.write_char(':')?;
78 write!(f, "{:#?}", self.anchor.ast_id)?;
79 f.write_char('@')?;
80 fmt::Debug::fmt(&self.range, f)?;
81 f.write_char('#')?;
82 self.ctx.fmt(f)
83 }
84}
85
86#[derive(Copy, Clone, PartialEq, Eq, Hash)]
87pub struct SpanAnchor {
88 pub file_id: EditionedFileId,
89 pub ast_id: ErasedFileAstId,
90}
91
92impl fmt::Debug for SpanAnchor {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 f.debug_tuple("SpanAnchor").field(&self.file_id).field(&self.ast_id).finish()
95 }
96}
97
98#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
101pub struct EditionedFileId(u32);
102
103impl fmt::Debug for EditionedFileId {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.debug_tuple("EditionedFileId")
106 .field(&self.file_id().index())
107 .field(&self.edition())
108 .finish()
109 }
110}
111
112impl From<EditionedFileId> for FileId {
113 fn from(value: EditionedFileId) -> Self {
114 value.file_id()
115 }
116}
117
118const _: () = assert!(
119 EditionedFileId::RESERVED_HIGH_BITS
120 + EditionedFileId::EDITION_BITS
121 + EditionedFileId::FILE_ID_BITS
122 == u32::BITS
123);
124const _: () = assert!(
125 EditionedFileId::RESERVED_MASK ^ EditionedFileId::EDITION_MASK ^ EditionedFileId::FILE_ID_MASK
126 == 0xFFFF_FFFF
127);
128
129impl EditionedFileId {
130 pub const RESERVED_MASK: u32 = 0x8000_0000;
131 pub const EDITION_MASK: u32 = 0x7F80_0000;
132 pub const FILE_ID_MASK: u32 = 0x007F_FFFF;
133
134 pub const MAX_FILE_ID: u32 = Self::FILE_ID_MASK;
135
136 pub const RESERVED_HIGH_BITS: u32 = Self::RESERVED_MASK.count_ones();
137 pub const FILE_ID_BITS: u32 = Self::FILE_ID_MASK.count_ones();
138 pub const EDITION_BITS: u32 = Self::EDITION_MASK.count_ones();
139
140 pub const fn current_edition(file_id: FileId) -> Self {
141 Self::new(file_id, Edition::CURRENT)
142 }
143
144 pub const fn new(file_id: FileId, edition: Edition) -> Self {
145 let file_id = file_id.index();
146 let edition = edition as u32;
147 assert!(file_id <= Self::MAX_FILE_ID);
148 Self(file_id | (edition << Self::FILE_ID_BITS))
149 }
150
151 pub fn from_raw(u32: u32) -> Self {
152 assert!(u32 & Self::RESERVED_MASK == 0);
153 assert!((u32 & Self::EDITION_MASK) >> Self::FILE_ID_BITS <= Edition::LATEST as u32);
154 Self(u32)
155 }
156
157 pub const fn as_u32(self) -> u32 {
158 self.0
159 }
160
161 pub const fn file_id(self) -> FileId {
162 FileId::from_raw(self.0 & Self::FILE_ID_MASK)
163 }
164
165 pub const fn unpack(self) -> (FileId, Edition) {
166 (self.file_id(), self.edition())
167 }
168
169 pub const fn edition(self) -> Edition {
170 let edition = (self.0 & Self::EDITION_MASK) >> Self::FILE_ID_BITS;
171 debug_assert!(edition <= Edition::LATEST as u32);
172 unsafe { std::mem::transmute(edition as u8) }
173 }
174}
175
176#[cfg(not(feature = "salsa"))]
177mod salsa {
178 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
179 pub struct Id(u32);
180}
181
182#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
200pub struct HirFileId(pub salsa::Id);
201
202#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
205pub struct MacroCallId(pub salsa::Id);