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