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 #[cfg(feature = "salsa")]
55 if self.ctx.is_root() {
56 return Some(other);
57 } else if other.ctx.is_root() {
58 return Some(self);
59 }
60 None
61 } else {
62 Some(Span {
63 range: self.range.cover(other.range),
64 anchor: other.anchor,
65 ctx: other.ctx,
66 })
67 }
68 }
69
70 pub fn eq_ignoring_ctx(self, other: Self) -> bool {
71 self.anchor == other.anchor && self.range == other.range
72 }
73}
74
75#[derive(Clone, Copy, PartialEq, Eq, Hash)]
79pub struct Span {
80 pub range: TextRange,
84 pub anchor: SpanAnchor,
86 pub ctx: SyntaxContext,
88}
89
90impl fmt::Debug for Span {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 if f.alternate() {
93 fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
94 f.write_char(':')?;
95 write!(f, "{:#?}", self.anchor.ast_id)?;
96 f.write_char('@')?;
97 fmt::Debug::fmt(&self.range, f)?;
98 f.write_char('#')?;
99 self.ctx.fmt(f)
100 } else {
101 f.debug_struct("SpanData")
102 .field("range", &self.range)
103 .field("anchor", &self.anchor)
104 .field("ctx", &self.ctx)
105 .finish()
106 }
107 }
108}
109
110impl fmt::Display for Span {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
113 f.write_char(':')?;
114 write!(f, "{:#?}", self.anchor.ast_id)?;
115 f.write_char('@')?;
116 fmt::Debug::fmt(&self.range, f)?;
117 f.write_char('#')?;
118 self.ctx.fmt(f)
119 }
120}
121
122#[derive(Copy, Clone, PartialEq, Eq, Hash)]
123pub struct SpanAnchor {
124 pub file_id: EditionedFileId,
125 pub ast_id: ErasedFileAstId,
126}
127
128impl fmt::Debug for SpanAnchor {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 f.debug_tuple("SpanAnchor").field(&self.file_id).field(&self.ast_id).finish()
131 }
132}
133
134#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
137pub struct EditionedFileId(u32);
138
139impl fmt::Debug for EditionedFileId {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 f.debug_tuple("EditionedFileId")
142 .field(&self.file_id().index())
143 .field(&self.edition())
144 .finish()
145 }
146}
147
148impl From<EditionedFileId> for FileId {
149 fn from(value: EditionedFileId) -> Self {
150 value.file_id()
151 }
152}
153
154const _: () = assert!(
155 EditionedFileId::RESERVED_HIGH_BITS
156 + EditionedFileId::EDITION_BITS
157 + EditionedFileId::FILE_ID_BITS
158 == u32::BITS
159);
160const _: () = assert!(
161 EditionedFileId::RESERVED_MASK ^ EditionedFileId::EDITION_MASK ^ EditionedFileId::FILE_ID_MASK
162 == 0xFFFF_FFFF
163);
164
165impl EditionedFileId {
166 pub const RESERVED_MASK: u32 = 0x8000_0000;
167 pub const EDITION_MASK: u32 = 0x7F80_0000;
168 pub const FILE_ID_MASK: u32 = 0x007F_FFFF;
169
170 pub const MAX_FILE_ID: u32 = Self::FILE_ID_MASK;
171
172 pub const RESERVED_HIGH_BITS: u32 = Self::RESERVED_MASK.count_ones();
173 pub const FILE_ID_BITS: u32 = Self::FILE_ID_MASK.count_ones();
174 pub const EDITION_BITS: u32 = Self::EDITION_MASK.count_ones();
175
176 pub const fn current_edition(file_id: FileId) -> Self {
177 Self::new(file_id, Edition::CURRENT)
178 }
179
180 pub const fn new(file_id: FileId, edition: Edition) -> Self {
181 let file_id = file_id.index();
182 let edition = edition as u32;
183 assert!(file_id <= Self::MAX_FILE_ID);
184 Self(file_id | (edition << Self::FILE_ID_BITS))
185 }
186
187 pub fn from_raw(u32: u32) -> Self {
188 assert!(u32 & Self::RESERVED_MASK == 0);
189 assert!((u32 & Self::EDITION_MASK) >> Self::FILE_ID_BITS <= Edition::LATEST as u32);
190 Self(u32)
191 }
192
193 pub const fn as_u32(self) -> u32 {
194 self.0
195 }
196
197 pub const fn file_id(self) -> FileId {
198 FileId::from_raw(self.0 & Self::FILE_ID_MASK)
199 }
200
201 pub const fn unpack(self) -> (FileId, Edition) {
202 (self.file_id(), self.edition())
203 }
204
205 pub const fn edition(self) -> Edition {
206 let edition = (self.0 & Self::EDITION_MASK) >> Self::FILE_ID_BITS;
207 debug_assert!(edition <= Edition::LATEST as u32);
208 unsafe { std::mem::transmute(edition as u8) }
209 }
210}
211
212#[cfg(not(feature = "salsa"))]
213mod salsa {
214 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
215 pub struct Id(u32);
216}
217
218#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
236pub struct HirFileId(pub salsa::Id);
237
238#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
241pub struct MacroCallId(pub salsa::Id);