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