Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
909bb5a
rdr: migrate ExpnData and rmeta tables from Span to SpanRef
davidbarsky Jan 16, 2026
f9ceeac
rdr: introduce IdentRef for identifier storage
davidbarsky Jan 16, 2026
f511992
rdr: serialize diagnostic spans as SpanRef
davidbarsky Jan 16, 2026
6b263f3
rdr: split source_map encoding into separate .spans file
davidbarsky Jan 16, 2026
c7a9592
rdr: lazy loading of span files
davidbarsky Jan 16, 2026
c4161d2
rdr: graceful span degradation when .spans file unavailable
davidbarsky Jan 16, 2026
b867a1f
rdr: SpanRef respects hash_spans() for RDR fingerprinting
davidbarsky Jan 16, 2026
6cf2679
rdr: implement SpanResolver and span file loading infrastructure
davidbarsky Jan 16, 2026
48df429
rdr: implement diagnostic gating for codegen safety
davidbarsky Jan 16, 2026
56a1f4f
rdr: make SVH stable when only private items change
davidbarsky Jan 16, 2026
de0cb57
rdr: add tests for panic locations, debuginfo, and coverage
davidbarsky Jan 16, 2026
d6d497a
test: update function_interfaces.rs for correct typeck invalidation
davidbarsky Jan 17, 2026
b7bad85
rdr: consolidate span loading
davidbarsky Jan 17, 2026
7d02a56
rdr: add a bunch of tests exercising rdr
davidbarsky Jan 17, 2026
f0233d8
rdr: rename `-Zseparate-spans` to `-Zstable-crate-hash`
davidbarsky Jan 17, 2026
20f7d4f
rdr: add a test that shows adding a private item doesn't cause rebuilds
davidbarsky Jan 18, 2026
770d5fe
rdr: migrate some queries from `Span` to `SpanRef`
davidbarsky Jan 18, 2026
69ccd5a
rdr: fix SpanRef resolution and optimize metadata encoding
davidbarsky Jan 18, 2026
8c20bd8
rdr: add a test that exercises RDR with `-Zshare-generics`
davidbarsky Jan 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions compiler/rustc_error_messages/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use fluent_syntax::parser::ParserError;
use intl_memoizer::concurrent::IntlLangMemoizer;
use rustc_data_structures::sync::{DynSend, IntoDynSyncSend};
use rustc_macros::{Decodable, Encodable};
use rustc_span::Span;
use rustc_serialize::{Decodable, Encodable};
use rustc_span::{Span, SpanDecoder, SpanEncoder};
use tracing::{instrument, trace};
pub use unic_langid::{LanguageIdentifier, langid};

Expand Down Expand Up @@ -391,7 +392,10 @@ pub struct SpanLabel {
/// the error, and would be rendered with `^^^`.
/// - They can have a *label*. In this case, the label is written next
/// to the mark in the snippet when we render.
#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable)]
// Manual `Encodable`/`Decodable` impls serialize spans as `SpanRef` to support
// RDR (Relink, Don't Rebuild). We keep `Span` internally for performance since
// `primary_spans()` returns `&[Span]` directly.
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct MultiSpan {
primary_spans: Vec<Span>,
span_labels: Vec<(Span, DiagMessage)>,
Expand Down Expand Up @@ -508,6 +512,38 @@ impl From<Vec<Span>> for MultiSpan {
}
}

impl<E: SpanEncoder> Encodable<E> for MultiSpan {
fn encode(&self, e: &mut E) {
self.primary_spans.len().encode(e);
for span in &self.primary_spans {
e.encode_span_as_span_ref(*span);
}
self.span_labels.len().encode(e);
for (span, msg) in &self.span_labels {
e.encode_span_as_span_ref(*span);
msg.encode(e);
}
}
}

impl<D: SpanDecoder> Decodable<D> for MultiSpan {
fn decode(d: &mut D) -> Self {
let primary_len: usize = Decodable::decode(d);
let mut primary_spans = Vec::with_capacity(primary_len);
for _ in 0..primary_len {
primary_spans.push(d.decode_span_ref_as_span());
}
let labels_len: usize = Decodable::decode(d);
let mut span_labels = Vec::with_capacity(labels_len);
for _ in 0..labels_len {
let span = d.decode_span_ref_as_span();
let msg = Decodable::decode(d);
span_labels.push((span, msg));
}
MultiSpan { primary_spans, span_labels }
}
}

fn icu_locale_from_unic_langid(lang: LanguageIdentifier) -> Option<icu_locale::Locale> {
icu_locale::Locale::try_from_str(&lang.to_string()).ok()
}
Expand Down
44 changes: 42 additions & 2 deletions compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ use rustc_data_structures::fx::FxIndexMap;
use rustc_error_messages::{DiagArgName, DiagArgValue, IntoDiagArg};
use rustc_lint_defs::{Applicability, LintExpectationId};
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::{Decodable, Encodable};
use rustc_span::source_map::Spanned;
use rustc_span::{DUMMY_SP, Span, Symbol};
use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol};
use tracing::debug;

use crate::snippet::Style;
Expand Down Expand Up @@ -234,8 +235,9 @@ impl StringPart {
/// used for most operations, and should be used instead whenever possible.
/// This type should only be used when `Diag`'s lifetime causes difficulties,
/// e.g. when storing diagnostics within `DiagCtxt`.
// Manual impls serialize `sort_span` as `SpanRef` for RDR.
#[must_use]
#[derive(Clone, Debug, Encodable, Decodable)]
#[derive(Clone, Debug)]
pub struct DiagInner {
// NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
// outside of what methods in this crate themselves allow.
Expand Down Expand Up @@ -265,6 +267,44 @@ pub struct DiagInner {
pub(crate) emitted_at: DiagLocation,
}

impl<E: SpanEncoder> Encodable<E> for DiagInner {
fn encode(&self, e: &mut E) {
self.level.encode(e);
self.messages.encode(e);
self.code.encode(e);
self.lint_id.encode(e);
self.span.encode(e);
self.children.encode(e);
self.suggestions.encode(e);
self.args.encode(e);
self.reserved_args.encode(e);
e.encode_span_as_span_ref(self.sort_span);
self.is_lint.encode(e);
self.long_ty_path.encode(e);
self.emitted_at.encode(e);
}
}

impl<D: SpanDecoder> Decodable<D> for DiagInner {
fn decode(d: &mut D) -> Self {
DiagInner {
level: Decodable::decode(d),
messages: Decodable::decode(d),
code: Decodable::decode(d),
lint_id: Decodable::decode(d),
span: Decodable::decode(d),
children: Decodable::decode(d),
suggestions: Decodable::decode(d),
args: Decodable::decode(d),
reserved_args: Decodable::decode(d),
sort_span: d.decode_span_ref_as_span(),
is_lint: Decodable::decode(d),
long_ty_path: Decodable::decode(d),
emitted_at: Decodable::decode(d),
}
}
}

impl DiagInner {
#[track_caller]
pub fn new<M: Into<DiagMessage>>(level: Level, message: M) -> Self {
Expand Down
41 changes: 38 additions & 3 deletions compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ use rustc_hashes::Hash128;
use rustc_lint_defs::LintExpectationId;
pub use rustc_lint_defs::{Applicability, listify, pluralize};
use rustc_macros::{Decodable, Encodable};
use rustc_serialize::{Decodable, Encodable};
pub use rustc_span::ErrorGuaranteed;
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
use rustc_span::source_map::SourceMap;
use rustc_span::{BytePos, DUMMY_SP, Loc, Span};
use rustc_span::{BytePos, DUMMY_SP, Loc, Span, SpanDecoder, SpanEncoder};
pub use snippet::Style;
use tracing::debug;

Expand Down Expand Up @@ -205,19 +206,53 @@ pub struct Substitution {
pub parts: Vec<SubstitutionPart>,
}

#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
// Manual impls serialize spans as `SpanRef` for RDR.
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct SubstitutionPart {
pub span: Span,
pub snippet: String,
}

#[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
impl<E: SpanEncoder> Encodable<E> for SubstitutionPart {
fn encode(&self, e: &mut E) {
e.encode_span_as_span_ref(self.span);
self.snippet.encode(e);
}
}

impl<D: SpanDecoder> Decodable<D> for SubstitutionPart {
fn decode(d: &mut D) -> Self {
let span = d.decode_span_ref_as_span();
let snippet: String = Decodable::decode(d);
SubstitutionPart { span, snippet }
}
}

// Manual impls serialize spans as `SpanRef` for RDR.
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct TrimmedSubstitutionPart {
pub original_span: Span,
pub span: Span,
pub snippet: String,
}

impl<E: SpanEncoder> Encodable<E> for TrimmedSubstitutionPart {
fn encode(&self, e: &mut E) {
e.encode_span_as_span_ref(self.original_span);
e.encode_span_as_span_ref(self.span);
self.snippet.encode(e);
}
}

impl<D: SpanDecoder> Decodable<D> for TrimmedSubstitutionPart {
fn decode(d: &mut D) -> Self {
let original_span = d.decode_span_ref_as_span();
let span = d.decode_span_ref_as_span();
let snippet: String = Decodable::decode(d);
TrimmedSubstitutionPart { original_span, span, snippet }
}
}

/// Used to translate between `Span`s and byte positions within a single output line in highlighted
/// code of structured suggestions.
#[derive(Debug, Clone, Copy)]
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ fn check_opaque_meets_bounds<'tcx>(
for (predicate, pred_span) in
tcx.explicit_item_bounds(def_id).iter_instantiated_copied(tcx, args)
{
let pred_span = tcx.resolve_span_ref(pred_span);
let predicate = predicate.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |ty| if ty == opaque_ty { hidden_ty } else { ty },
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,7 @@ where
.explicit_item_bounds(proj.def_id)
.iter_instantiated_copied(self.cx(), proj.args)
{
let pred_span = self.cx().resolve_span_ref(pred_span);
let pred = pred.fold_with(self);
let pred = self.ocx.normalize(
&ObligationCause::misc(self.span, self.body_id),
Expand Down Expand Up @@ -2413,6 +2414,7 @@ pub(super) fn check_type_bounds<'tcx>(
tcx,
tcx.explicit_item_bounds(trait_ty.def_id).iter_instantiated_copied(tcx, rebased_args).map(
|(concrete_ty_bound, span)| {
let span = tcx.resolve_span_ref(span);
debug!(?concrete_ty_bound);
traits::Obligation::new(tcx, mk_cause(span), param_env, concrete_ty_bound)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
impl_bounds.extend(elaborate(
tcx,
tcx.explicit_item_bounds(impl_opaque.def_id)
.iter_instantiated_copied(tcx, impl_opaque.args),
.iter_instantiated_copied(tcx, impl_opaque.args)
.map(|(clause, span)| (clause, tcx.resolve_span_ref(span))),
));

pairs.push((trait_projection, impl_opaque));
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt

debug!("check_associated_type_bounds: bounds={:?}", bounds);
let wf_obligations = bounds.iter_identity_copied().flat_map(|(bound, bound_span)| {
let bound_span = wfcx.tcx().resolve_span_ref(bound_span);
traits::wf::clause_obligations(
wfcx.infcx,
wfcx.param_env,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use rustc_middle::ty::{
self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, fold_regions,
};
use rustc_middle::{bug, span_bug};
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
use rustc_span::{DUMMY_SP, Ident, Span, SpanRef, Symbol, kw, sym};
use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{
Expand Down Expand Up @@ -358,7 +358,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
span: Span,
def_id: LocalDefId,
assoc_ident: Ident,
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, SpanRef)]> {
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_ident))
}

Expand Down
21 changes: 15 additions & 6 deletions compiler/rustc_hir_analysis/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,17 @@ use rustc_middle::ty::{
Upcast, shift_vars,
};
use rustc_middle::{bug, span_bug};
use rustc_span::Span;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{Span, SpanRef};

fn convert_to_span_ref<'tcx>(
tcx: TyCtxt<'tcx>,
bounds: &[(ty::Clause<'tcx>, Span)],
) -> &'tcx [(ty::Clause<'tcx>, SpanRef)] {
tcx.arena.alloc_from_iter(
bounds.iter().map(|(clause, span)| (*clause, tcx.span_ref_from_span(*span))),
)
}
use tracing::{debug, instrument};

use super::ItemCtxt;
Expand Down Expand Up @@ -403,30 +412,30 @@ fn opaque_type_bounds<'tcx>(
pub(super) fn explicit_item_bounds(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, SpanRef)]> {
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::All)
}

pub(super) fn explicit_item_self_bounds(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, SpanRef)]> {
explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::SelfOnly)
}

pub(super) fn explicit_item_bounds_with_filter(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
filter: PredicateFilter,
) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, SpanRef)]> {
match tcx.opt_rpitit_info(def_id.to_def_id()) {
// RPITIT's bounds are the same as opaque type bounds, but with
// a projection self type.
Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
let opaque_ty = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_opaque_ty();
let bounds =
associated_type_bounds(tcx, def_id, opaque_ty.bounds, opaque_ty.span, filter);
return ty::EarlyBinder::bind(bounds);
return ty::EarlyBinder::bind(convert_to_span_ref(tcx, bounds));
}
Some(ty::ImplTraitInTraitData::Impl { .. }) => {
span_bug!(tcx.def_span(def_id), "RPITIT in impl should not have item bounds")
Expand Down Expand Up @@ -482,7 +491,7 @@ pub(super) fn explicit_item_bounds_with_filter(
node => bug!("item_bounds called on {def_id:?} => {node:?}"),
};

ty::EarlyBinder::bind(bounds)
ty::EarlyBinder::bind(convert_to_span_ref(tcx, bounds))
}

pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
Expand Down
Loading
Loading