Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed May 15, 2024
1 parent e14c539 commit e503632
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 78 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//! This API is completely unstable and subject to change.

// tidy-alphabetical-start
#![allow(incomplete_features)]
#![allow(internal_features)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
Expand All @@ -31,6 +32,7 @@
#![feature(round_char_boundary)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![feature(unnamed_fields)]
// tidy-alphabetical-end

extern crate self as rustc_span;
Expand Down
222 changes: 144 additions & 78 deletions compiler/rustc_span/src/span_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,95 @@ pub struct Span {
ctxt_or_parent_or_marker: u16,
}

#[derive(Clone, Copy)]
struct SpanInlineCtxt {
lo: u32,
len: u16,
ctxt: u16,
}
#[derive(Clone, Copy)]
struct SpanInlineParent {
lo: u32,
len_with_tag: u16,
parent: u16,
}
#[derive(Clone, Copy)]
struct SpanPartiallyInterned {
index: u32,
_marker1: u16,
ctxt: u16,
}
#[derive(Clone, Copy)]
struct SpanInterned {
index: u32,
_marker1: u16,
_marker2: u16,
}

#[allow(dead_code)]
union SpanRepr {
inline_ctxt: SpanInlineCtxt,
inline_parent: SpanInlineParent,
partially_interned: SpanPartiallyInterned,
interned: SpanInterned,
}

enum Fmt<'a> {
InlineCtxt(&'a mut SpanInlineCtxt),
InlineParent(&'a mut SpanInlineParent),
PartiallyInterned(&'a mut SpanPartiallyInterned),
Interned(&'a mut SpanInterned),
}

impl SpanInlineCtxt {
fn data(self) -> SpanData {
let len = self.len as u32;
debug_assert!(len <= MAX_LEN);
SpanData {
lo: BytePos(self.lo),
hi: BytePos(self.lo.debug_strict_add(len)),
ctxt: SyntaxContext::from_u32(self.ctxt as u32),
parent: None,
}
}
}
impl SpanInlineParent {
fn data(self) -> SpanData {
let len = (self.len_with_tag & !PARENT_TAG) as u32;
debug_assert!(len <= MAX_LEN);
let parent = LocalDefId { local_def_index: DefIndex::from_u32(self.parent as u32) };
SpanData {
lo: BytePos(self.lo),
hi: BytePos(self.lo.debug_strict_add(len)),
ctxt: SyntaxContext::root(),
parent: Some(parent),
}
}
}
impl SpanPartiallyInterned {
fn data(self) -> SpanData {
SpanData {
ctxt: SyntaxContext::from_u32(self.ctxt as u32),
..with_span_interner(|interner| interner.spans[self.index as usize])
}
}
}
impl SpanInterned {
fn data(self) -> SpanData {
with_span_interner(|interner| interner.spans[self.index as usize])
}
}
impl Fmt<'_> {
fn data(self) -> SpanData {
match self {
Fmt::InlineCtxt(span) => span.data(),
Fmt::InlineParent(span) => span.data(),
Fmt::PartiallyInterned(span) => span.data(),
Fmt::Interned(span) => span.data(),
}
}
}

// `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from
// `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.)
const MAX_LEN: u32 = 0b0111_1111_1111_1110;
Expand Down Expand Up @@ -137,6 +226,7 @@ impl Span {

// Partially-interned or fully-interned format.
let (ctxt_or_parent_or_marker, ctxt) = if ctxt2 <= MAX_CTXT {
// any value, should never be read
(ctxt2 as u16, SyntaxContext::from_u32(u32::MAX)) // partially-interned
} else {
(CTXT_INTERNED_MARKER, ctxt) // fully-interned
Expand All @@ -162,43 +252,8 @@ impl Span {
/// Internal function to translate between an encoded span and the expanded representation.
/// This function must not be used outside the incremental engine.
#[inline]
pub fn data_untracked(self) -> SpanData {
if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
// Inline-context format.
let len = self.len_with_tag_or_marker as u32;
debug_assert!(len <= MAX_LEN);
SpanData {
lo: BytePos(self.lo_or_index),
hi: BytePos(self.lo_or_index.debug_strict_add(len)),
ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32),
parent: None,
}
} else {
// Inline-parent format.
let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32;
debug_assert!(len <= MAX_LEN);
let parent = LocalDefId {
local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32),
};
SpanData {
lo: BytePos(self.lo_or_index),
hi: BytePos(self.lo_or_index.debug_strict_add(len)),
ctxt: SyntaxContext::root(),
parent: Some(parent),
}
}
} else {
// Fully-interned or partially-interned format. In either case,
// the interned value contains all the data, so we don't need to
// distinguish them.
let index = self.lo_or_index;
let mut data = with_span_interner(|interner| interner.spans[index as usize]);
if data.ctxt.as_u32() == u32::MAX {
data.ctxt = SyntaxContext::from_u32(u32::from(self.ctxt_or_parent_or_marker));
}
data
}
pub fn data_untracked(mut self) -> SpanData {
self.fmt().data()
}

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

#[inline]
fn fmt(&mut self) -> Fmt<'_> {
unsafe {
if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
Fmt::InlineCtxt(std::mem::transmute(self))
} else {
Fmt::InlineParent(std::mem::transmute(self))
}
} else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
Fmt::PartiallyInterned(std::mem::transmute(self))
} else {
Fmt::Interned(std::mem::transmute(self))
}
}
}

// Returns either syntactic context, if it can be retrieved without taking the interner lock,
// or an index into the interner if it cannot.
fn inline_ctxt(self) -> Result<SyntaxContext, usize> {
Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
// Inline-context format.
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
} else {
// Inline-parent format. We know that the SyntaxContext is root.
SyntaxContext::root()
fn inline_ctxt(mut self) -> Result<SyntaxContext, usize> {
match self.fmt() {
Fmt::InlineCtxt(SpanInlineCtxt { ctxt, .. })
| Fmt::PartiallyInterned(SpanPartiallyInterned { ctxt, .. }) => {
Ok(SyntaxContext::from_u32(*ctxt as u32))
}
} else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
// Partially-interned format. This path avoids looking up the
// interned value, and is the whole point of the
// partially-interned format.
SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)
} else {
// Fully-interned format.
return Err(self.lo_or_index as usize);
})
Fmt::InlineParent(_) => Ok(SyntaxContext::root()),
Fmt::Interned(span) => Err(span.index as usize),
}
}

pub fn update_ctxt(&mut self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) {
pub fn update_ctxt(&mut self, update: impl Fn(SyntaxContext) -> SyntaxContext) {
let orig_data = self.data_untracked();

let updated_ctxt32;
let data;
if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
if self.len_with_tag_or_marker & PARENT_TAG == 0 {
// Inline-context format.
updated_ctxt32 =
update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32();
match self.fmt() {
Fmt::InlineCtxt(span) => {
updated_ctxt32 = update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32();
if updated_ctxt32 <= MAX_CTXT {
self.ctxt_or_parent_or_marker = updated_ctxt32 as u16;
span.ctxt = updated_ctxt32 as u16;
assert_eq!(*self, orig_data.with_ctxt(update(orig_data.ctxt)));
return;
}
} else {
// Inline-parent format. We know that the SyntaxContext is root.
data = span.data();
}
Fmt::PartiallyInterned(span) => {
updated_ctxt32 = update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32();
if updated_ctxt32 <= MAX_CTXT {
span.ctxt = updated_ctxt32 as u16;
assert_eq!(*self, orig_data.with_ctxt(update(orig_data.ctxt)));
return;
}
data = span.data();
}
Fmt::InlineParent(span) => {
updated_ctxt32 = update(SyntaxContext::root()).as_u32();
if updated_ctxt32 == 0 {
// do nothing
assert_eq!(*self, orig_data.with_ctxt(update(orig_data.ctxt)));
return;
}
data = span.data();
}
data = self.data_untracked();
} else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER {
// Partially-interned format. This path avoids looking up the
// interned value, and is the whole point of the
// partially-interned format.
updated_ctxt32 =
update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32();
if updated_ctxt32 <= MAX_CTXT {
self.ctxt_or_parent_or_marker = updated_ctxt32 as u16;
return;
Fmt::Interned(span) => {
data = span.data();
updated_ctxt32 = update(data.ctxt).as_u32();
}
data = self.data_untracked();
} else {
data = self.data_untracked();
updated_ctxt32 = update(data.ctxt).as_u32();
};
}

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

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

0 comments on commit e503632

Please sign in to comment.