Skip to content

Commit e503632

Browse files
committed
WIP
1 parent e14c539 commit e503632

File tree

2 files changed

+146
-78
lines changed

2 files changed

+146
-78
lines changed

compiler/rustc_span/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//! This API is completely unstable and subject to change.
1717
1818
// tidy-alphabetical-start
19+
#![allow(incomplete_features)]
1920
#![allow(internal_features)]
2021
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
2122
#![doc(rust_logo)]
@@ -31,6 +32,7 @@
3132
#![feature(round_char_boundary)]
3233
#![feature(rustc_attrs)]
3334
#![feature(rustdoc_internals)]
35+
#![feature(unnamed_fields)]
3436
// tidy-alphabetical-end
3537

3638
extern crate self as rustc_span;

compiler/rustc_span/src/span_encoding.rs

+144-78
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,95 @@ pub struct Span {
8787
ctxt_or_parent_or_marker: u16,
8888
}
8989

90+
#[derive(Clone, Copy)]
91+
struct SpanInlineCtxt {
92+
lo: u32,
93+
len: u16,
94+
ctxt: u16,
95+
}
96+
#[derive(Clone, Copy)]
97+
struct SpanInlineParent {
98+
lo: u32,
99+
len_with_tag: u16,
100+
parent: u16,
101+
}
102+
#[derive(Clone, Copy)]
103+
struct SpanPartiallyInterned {
104+
index: u32,
105+
_marker1: u16,
106+
ctxt: u16,
107+
}
108+
#[derive(Clone, Copy)]
109+
struct SpanInterned {
110+
index: u32,
111+
_marker1: u16,
112+
_marker2: u16,
113+
}
114+
115+
#[allow(dead_code)]
116+
union SpanRepr {
117+
inline_ctxt: SpanInlineCtxt,
118+
inline_parent: SpanInlineParent,
119+
partially_interned: SpanPartiallyInterned,
120+
interned: SpanInterned,
121+
}
122+
123+
enum Fmt<'a> {
124+
InlineCtxt(&'a mut SpanInlineCtxt),
125+
InlineParent(&'a mut SpanInlineParent),
126+
PartiallyInterned(&'a mut SpanPartiallyInterned),
127+
Interned(&'a mut SpanInterned),
128+
}
129+
130+
impl SpanInlineCtxt {
131+
fn data(self) -> SpanData {
132+
let len = self.len as u32;
133+
debug_assert!(len <= MAX_LEN);
134+
SpanData {
135+
lo: BytePos(self.lo),
136+
hi: BytePos(self.lo.debug_strict_add(len)),
137+
ctxt: SyntaxContext::from_u32(self.ctxt as u32),
138+
parent: None,
139+
}
140+
}
141+
}
142+
impl SpanInlineParent {
143+
fn data(self) -> SpanData {
144+
let len = (self.len_with_tag & !PARENT_TAG) as u32;
145+
debug_assert!(len <= MAX_LEN);
146+
let parent = LocalDefId { local_def_index: DefIndex::from_u32(self.parent as u32) };
147+
SpanData {
148+
lo: BytePos(self.lo),
149+
hi: BytePos(self.lo.debug_strict_add(len)),
150+
ctxt: SyntaxContext::root(),
151+
parent: Some(parent),
152+
}
153+
}
154+
}
155+
impl SpanPartiallyInterned {
156+
fn data(self) -> SpanData {
157+
SpanData {
158+
ctxt: SyntaxContext::from_u32(self.ctxt as u32),
159+
..with_span_interner(|interner| interner.spans[self.index as usize])
160+
}
161+
}
162+
}
163+
impl SpanInterned {
164+
fn data(self) -> SpanData {
165+
with_span_interner(|interner| interner.spans[self.index as usize])
166+
}
167+
}
168+
impl Fmt<'_> {
169+
fn data(self) -> SpanData {
170+
match self {
171+
Fmt::InlineCtxt(span) => span.data(),
172+
Fmt::InlineParent(span) => span.data(),
173+
Fmt::PartiallyInterned(span) => span.data(),
174+
Fmt::Interned(span) => span.data(),
175+
}
176+
}
177+
}
178+
90179
// `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from
91180
// `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.)
92181
const MAX_LEN: u32 = 0b0111_1111_1111_1110;
@@ -137,6 +226,7 @@ impl Span {
137226

138227
// Partially-interned or fully-interned format.
139228
let (ctxt_or_parent_or_marker, ctxt) = if ctxt2 <= MAX_CTXT {
229+
// any value, should never be read
140230
(ctxt2 as u16, SyntaxContext::from_u32(u32::MAX)) // partially-interned
141231
} else {
142232
(CTXT_INTERNED_MARKER, ctxt) // fully-interned
@@ -162,43 +252,8 @@ impl Span {
162252
/// Internal function to translate between an encoded span and the expanded representation.
163253
/// This function must not be used outside the incremental engine.
164254
#[inline]
165-
pub fn data_untracked(self) -> SpanData {
166-
if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
167-
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
168-
// Inline-context format.
169-
let len = self.len_with_tag_or_marker as u32;
170-
debug_assert!(len <= MAX_LEN);
171-
SpanData {
172-
lo: BytePos(self.lo_or_index),
173-
hi: BytePos(self.lo_or_index.debug_strict_add(len)),
174-
ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32),
175-
parent: None,
176-
}
177-
} else {
178-
// Inline-parent format.
179-
let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32;
180-
debug_assert!(len <= MAX_LEN);
181-
let parent = LocalDefId {
182-
local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32),
183-
};
184-
SpanData {
185-
lo: BytePos(self.lo_or_index),
186-
hi: BytePos(self.lo_or_index.debug_strict_add(len)),
187-
ctxt: SyntaxContext::root(),
188-
parent: Some(parent),
189-
}
190-
}
191-
} else {
192-
// Fully-interned or partially-interned format. In either case,
193-
// the interned value contains all the data, so we don't need to
194-
// distinguish them.
195-
let index = self.lo_or_index;
196-
let mut data = with_span_interner(|interner| interner.spans[index as usize]);
197-
if data.ctxt.as_u32() == u32::MAX {
198-
data.ctxt = SyntaxContext::from_u32(u32::from(self.ctxt_or_parent_or_marker));
199-
}
200-
data
201-
}
255+
pub fn data_untracked(mut self) -> SpanData {
256+
self.fmt().data()
202257
}
203258

204259
/// Returns `true` if this is a dummy span with any hygienic context.
@@ -218,66 +273,77 @@ impl Span {
218273
}
219274
}
220275

276+
#[inline]
277+
fn fmt(&mut self) -> Fmt<'_> {
278+
unsafe {
279+
if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
280+
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
281+
Fmt::InlineCtxt(std::mem::transmute(self))
282+
} else {
283+
Fmt::InlineParent(std::mem::transmute(self))
284+
}
285+
} else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
286+
Fmt::PartiallyInterned(std::mem::transmute(self))
287+
} else {
288+
Fmt::Interned(std::mem::transmute(self))
289+
}
290+
}
291+
}
292+
221293
// Returns either syntactic context, if it can be retrieved without taking the interner lock,
222294
// or an index into the interner if it cannot.
223-
fn inline_ctxt(self) -> Result<SyntaxContext, usize> {
224-
Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
225-
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
226-
// Inline-context format.
227-
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
228-
} else {
229-
// Inline-parent format. We know that the SyntaxContext is root.
230-
SyntaxContext::root()
295+
fn inline_ctxt(mut self) -> Result<SyntaxContext, usize> {
296+
match self.fmt() {
297+
Fmt::InlineCtxt(SpanInlineCtxt { ctxt, .. })
298+
| Fmt::PartiallyInterned(SpanPartiallyInterned { ctxt, .. }) => {
299+
Ok(SyntaxContext::from_u32(*ctxt as u32))
231300
}
232-
} else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
233-
// Partially-interned format. This path avoids looking up the
234-
// interned value, and is the whole point of the
235-
// partially-interned format.
236-
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
237-
} else {
238-
// Fully-interned format.
239-
return Err(self.lo_or_index as usize);
240-
})
301+
Fmt::InlineParent(_) => Ok(SyntaxContext::root()),
302+
Fmt::Interned(span) => Err(span.index as usize),
303+
}
241304
}
242305

243-
pub fn update_ctxt(&mut self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) {
306+
pub fn update_ctxt(&mut self, update: impl Fn(SyntaxContext) -> SyntaxContext) {
307+
let orig_data = self.data_untracked();
308+
244309
let updated_ctxt32;
245310
let data;
246-
if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
247-
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
248-
// Inline-context format.
249-
updated_ctxt32 =
250-
update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32();
311+
match self.fmt() {
312+
Fmt::InlineCtxt(span) => {
313+
updated_ctxt32 = update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32();
251314
if updated_ctxt32 <= MAX_CTXT {
252-
self.ctxt_or_parent_or_marker = updated_ctxt32 as u16;
315+
span.ctxt = updated_ctxt32 as u16;
316+
assert_eq!(*self, orig_data.with_ctxt(update(orig_data.ctxt)));
253317
return;
254318
}
255-
} else {
256-
// Inline-parent format. We know that the SyntaxContext is root.
319+
data = span.data();
320+
}
321+
Fmt::PartiallyInterned(span) => {
322+
updated_ctxt32 = update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32();
323+
if updated_ctxt32 <= MAX_CTXT {
324+
span.ctxt = updated_ctxt32 as u16;
325+
assert_eq!(*self, orig_data.with_ctxt(update(orig_data.ctxt)));
326+
return;
327+
}
328+
data = span.data();
329+
}
330+
Fmt::InlineParent(span) => {
257331
updated_ctxt32 = update(SyntaxContext::root()).as_u32();
258332
if updated_ctxt32 == 0 {
259333
// do nothing
334+
assert_eq!(*self, orig_data.with_ctxt(update(orig_data.ctxt)));
260335
return;
261336
}
337+
data = span.data();
262338
}
263-
data = self.data_untracked();
264-
} else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
265-
// Partially-interned format. This path avoids looking up the
266-
// interned value, and is the whole point of the
267-
// partially-interned format.
268-
updated_ctxt32 =
269-
update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32();
270-
if updated_ctxt32 <= MAX_CTXT {
271-
self.ctxt_or_parent_or_marker = updated_ctxt32 as u16;
272-
return;
339+
Fmt::Interned(span) => {
340+
data = span.data();
341+
updated_ctxt32 = update(data.ctxt).as_u32();
273342
}
274-
data = self.data_untracked();
275-
} else {
276-
data = self.data_untracked();
277-
updated_ctxt32 = update(data.ctxt).as_u32();
278-
};
343+
}
279344

280345
*self = data.with_ctxt(SyntaxContext::from_u32(updated_ctxt32));
346+
assert_eq!(*self, orig_data.with_ctxt(update(orig_data.ctxt)));
281347
}
282348

283349
/// This function is used as a fast path when decoding the full `SpanData` is not necessary.

0 commit comments

Comments
 (0)