Skip to content

Commit 547d937

Browse files
committed
Auto merge of rust-lang#84373 - cjgillot:resolve-span, r=michaelwoerister,petrochenkov
Encode spans relative to the enclosing item The aim of this PR is to avoid recomputing queries when code is moved without modification. MCP at rust-lang/compiler-team#443 This is achieved by : 1. storing the HIR owner LocalDefId information inside the span; 2. encoding and decoding spans relative to the enclosing item in the incremental on-disk cache; 3. marking a dependency to the `source_span(LocalDefId)` query when we translate a span from the short (`Span`) representation to its explicit (`SpanData`) representation. Since all client code uses `Span`, step 3 ensures that all manipulations of span byte positions actually create the dependency edge between the caller and the `source_span(LocalDefId)`. This query return the actual absolute span of the parent item. As a consequence, any source code motion that changes the absolute byte position of a node will either: - modify the distance to the parent's beginning, so change the relative span's hash; - dirty `source_span`, and trigger the incremental recomputation of all code that depends on the span's absolute byte position. With this scheme, I believe the dependency tracking to be accurate. For the moment, the spans are marked during lowering. I'd rather do this during def-collection, but the AST MutVisitor is not practical enough just yet. The only difference is that we attach macro-expanded spans to their expansion point instead of the macro itself.
2 parents 8c2b6ea + 7842b80 commit 547d937

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+2822
-1192
lines changed

compiler/rustc_ast/src/attr/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ impl MetaItem {
367367
let is_first = i == 0;
368368
if !is_first {
369369
let mod_sep_span =
370-
Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt());
370+
Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt(), None);
371371
idents.push(TokenTree::token(token::ModSep, mod_sep_span).into());
372372
}
373373
idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into());

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
422422
let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr));
423423
let if_expr = self.expr(span, if_kind, ThinVec::new());
424424
let block = self.block_expr(self.arena.alloc(if_expr));
425-
hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span.with_hi(cond.span.hi()))
425+
let span = self.lower_span(span.with_hi(cond.span.hi()));
426+
let opt_label = self.lower_label(opt_label);
427+
hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span)
426428
}
427429

428430
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ struct LoweringContext<'a, 'hir: 'a> {
165165
pub trait ResolverAstLowering {
166166
fn def_key(&mut self, id: DefId) -> DefKey;
167167

168+
fn def_span(&self, id: LocalDefId) -> Span;
169+
168170
fn item_generics_num_lifetimes(&self, def: DefId) -> usize;
169171

170172
fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>>;
@@ -215,6 +217,11 @@ impl<'a> rustc_span::HashStableContext for LoweringHasher<'a> {
215217
true
216218
}
217219

220+
#[inline]
221+
fn def_span(&self, id: LocalDefId) -> Span {
222+
self.resolver.def_span(id)
223+
}
224+
218225
#[inline]
219226
fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
220227
self.resolver.def_path_hash(def_id)
@@ -711,9 +718,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
711718
}
712719

713720
/// Intercept all spans entering HIR.
714-
/// For now we are not doing anything with the intercepted spans.
721+
/// Mark a span as relative to the current owning item.
715722
fn lower_span(&self, span: Span) -> Span {
716-
span
723+
if self.sess.opts.debugging_opts.incremental_relative_spans {
724+
span.with_parent(Some(self.current_hir_id_owner.0))
725+
} else {
726+
// Do not make spans relative when not using incremental compilation.
727+
span
728+
}
717729
}
718730

719731
fn lower_ident(&self, ident: Ident) -> Ident {
@@ -781,7 +793,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
781793
node_id,
782794
DefPathData::LifetimeNs(str_name),
783795
ExpnId::root(),
784-
span,
796+
span.with_parent(None),
785797
);
786798

787799
hir::GenericParam {
@@ -1513,7 +1525,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
15131525
def_node_id,
15141526
DefPathData::LifetimeNs(name.ident().name),
15151527
ExpnId::root(),
1516-
span,
1528+
span.with_parent(None),
15171529
);
15181530

15191531
let (name, kind) = match name {

compiler/rustc_expand/src/base.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
1515
use rustc_lint_defs::BuiltinLintDiagnostics;
1616
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
1717
use rustc_session::{parse::ParseSess, Limit, Session};
18-
use rustc_span::def_id::{CrateNum, DefId};
18+
use rustc_span::def_id::{CrateNum, DefId, LocalDefId};
1919
use rustc_span::edition::Edition;
2020
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
2121
use rustc_span::source_map::SourceMap;
@@ -843,6 +843,7 @@ pub type DeriveResolutions = Vec<(ast::Path, Annotatable, Option<Lrc<SyntaxExten
843843

844844
pub trait ResolverExpand {
845845
fn next_node_id(&mut self) -> NodeId;
846+
fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId;
846847

847848
fn resolve_dollar_crates(&mut self);
848849
fn visit_ast_fragment_with_placeholders(

compiler/rustc_expand/src/expand.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
588588
// Resolve `$crate`s in the fragment for pretty-printing.
589589
self.cx.resolver.resolve_dollar_crates();
590590

591-
let invocations = {
591+
let mut invocations = {
592592
let mut collector = InvocationCollector {
593593
// Non-derive macro invocations cannot see the results of cfg expansion - they
594594
// will either be removed along with the item, or invoked before the cfg/cfg_attr
@@ -613,6 +613,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
613613
self.cx
614614
.resolver
615615
.visit_ast_fragment_with_placeholders(self.cx.current_expansion.id, &fragment);
616+
617+
if self.cx.sess.opts.debugging_opts.incremental_relative_spans {
618+
for (invoc, _) in invocations.iter_mut() {
619+
let expn_id = invoc.expansion_data.id;
620+
let parent_def = self.cx.resolver.invocation_parent(expn_id);
621+
let span = match &mut invoc.kind {
622+
InvocationKind::Bang { ref mut span, .. } => span,
623+
InvocationKind::Attr { attr, .. } => &mut attr.span,
624+
InvocationKind::Derive { path, .. } => &mut path.span,
625+
};
626+
*span = span.with_parent(Some(parent_def));
627+
}
628+
}
616629
}
617630

618631
(fragment, invocations)

compiler/rustc_expand/src/proc_macro_server.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ impl server::Span for Rustc<'_> {
745745
self.sess.source_map().lookup_char_pos(span.lo()).file
746746
}
747747
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
748-
span.parent()
748+
span.parent_callsite()
749749
}
750750
fn source(&mut self, span: Self::Span) -> Self::Span {
751751
span.source_callsite()

compiler/rustc_hir/src/definitions.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc_data_structures::unhash::UnhashMap;
1414
use rustc_index::vec::IndexVec;
1515
use rustc_span::hygiene::ExpnId;
1616
use rustc_span::symbol::{kw, sym, Symbol};
17+
use rustc_span::Span;
1718

1819
use std::fmt::{self, Write};
1920
use std::hash::Hash;
@@ -107,6 +108,8 @@ pub struct Definitions {
107108

108109
/// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
109110
expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
111+
112+
def_id_to_span: IndexVec<LocalDefId, Span>,
110113
}
111114

112115
/// A unique identifier that we can use to lookup a definition
@@ -324,7 +327,7 @@ impl Definitions {
324327
}
325328

326329
/// Adds a root definition (no parent) and a few other reserved definitions.
327-
pub fn new(stable_crate_id: StableCrateId) -> Definitions {
330+
pub fn new(stable_crate_id: StableCrateId, crate_span: Span) -> Definitions {
328331
let key = DefKey {
329332
parent: None,
330333
disambiguated_data: DisambiguatedDefPathData {
@@ -341,11 +344,18 @@ impl Definitions {
341344
let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
342345
assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
343346

347+
let mut def_id_to_span = IndexVec::new();
348+
// A relative span's parent must be an absolute span.
349+
debug_assert_eq!(crate_span.data_untracked().parent, None);
350+
let _root = def_id_to_span.push(crate_span);
351+
debug_assert_eq!(_root, root);
352+
344353
Definitions {
345354
table,
346355
def_id_to_hir_id: Default::default(),
347356
hir_id_to_def_id: Default::default(),
348357
expansions_that_defined: Default::default(),
358+
def_id_to_span,
349359
}
350360
}
351361

@@ -361,6 +371,7 @@ impl Definitions {
361371
data: DefPathData,
362372
expn_id: ExpnId,
363373
mut next_disambiguator: impl FnMut(LocalDefId, DefPathData) -> u32,
374+
span: Span,
364375
) -> LocalDefId {
365376
debug!("create_def(parent={:?}, data={:?}, expn_id={:?})", parent, data, expn_id);
366377

@@ -385,6 +396,11 @@ impl Definitions {
385396
self.expansions_that_defined.insert(def_id, expn_id);
386397
}
387398

399+
// A relative span's parent must be an absolute span.
400+
debug_assert_eq!(span.data_untracked().parent, None);
401+
let _id = self.def_id_to_span.push(span);
402+
debug_assert_eq!(_id, def_id);
403+
388404
def_id
389405
}
390406

@@ -412,6 +428,12 @@ impl Definitions {
412428
self.expansions_that_defined.get(&id).copied().unwrap_or_else(ExpnId::root)
413429
}
414430

431+
/// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
432+
#[inline]
433+
pub fn def_span(&self, def_id: LocalDefId) -> Span {
434+
self.def_id_to_span[def_id]
435+
}
436+
415437
pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
416438
self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k)
417439
}

compiler/rustc_interface/src/callbacks.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ fn span_debug(span: rustc_span::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result
2525
})
2626
}
2727

28+
fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
29+
tls::with_opt(|tcx| {
30+
if let Some(tcx) = tcx {
31+
let _span = tcx.source_span(def_id);
32+
// Sanity check: relative span's parent must be an absolute span.
33+
debug_assert_eq!(_span.data_untracked().parent, None);
34+
}
35+
})
36+
}
37+
2838
/// This is a callback from `rustc_ast` as it cannot access the implicit state
2939
/// in `rustc_middle` otherwise. It is used to when diagnostic messages are
3040
/// emitted and stores them in the current query, if there is one.
@@ -56,6 +66,7 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
5666
/// TyCtxt in.
5767
pub fn setup_callbacks() {
5868
rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
69+
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
5970
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
6071
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as fn(&_)));
6172
}

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,8 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
536536
let hi =
537537
(hi + source_file.translated_source_file.start_pos) - source_file.original_start_pos;
538538

539-
Ok(Span::new(lo, hi, ctxt))
539+
// Do not try to decode parent for foreign spans.
540+
Ok(Span::new(lo, hi, ctxt, None))
540541
}
541542
}
542543

compiler/rustc_middle/src/hir/map/mod.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -969,22 +969,12 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
969969
.iter_enumerated()
970970
.filter_map(|(def_id, hod)| {
971971
let def_path_hash = tcx.untracked_resolutions.definitions.def_path_hash(def_id);
972-
let mut hasher = StableHasher::new();
973-
hod.as_ref()?.hash_stable(&mut hcx, &mut hasher);
974-
AttributeMap { map: &tcx.untracked_crate.attrs, prefix: def_id }
975-
.hash_stable(&mut hcx, &mut hasher);
976-
Some((def_path_hash, hasher.finish()))
972+
let hash = hod.as_ref()?.hash;
973+
Some((def_path_hash, hash, def_id))
977974
})
978975
.collect();
979976
hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
980977

981-
let node_hashes = hir_body_nodes.iter().fold(
982-
Fingerprint::ZERO,
983-
|combined_fingerprint, &(def_path_hash, fingerprint)| {
984-
combined_fingerprint.combine(def_path_hash.0.combine(fingerprint))
985-
},
986-
);
987-
988978
let upstream_crates = upstream_crates(tcx);
989979

990980
// We hash the final, remapped names of all local source files so we
@@ -1004,7 +994,17 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
1004994
source_file_names.sort_unstable();
1005995

1006996
let mut stable_hasher = StableHasher::new();
1007-
node_hashes.hash_stable(&mut hcx, &mut stable_hasher);
997+
for (def_path_hash, fingerprint, def_id) in hir_body_nodes.iter() {
998+
def_path_hash.0.hash_stable(&mut hcx, &mut stable_hasher);
999+
fingerprint.hash_stable(&mut hcx, &mut stable_hasher);
1000+
AttributeMap { map: &tcx.untracked_crate.attrs, prefix: *def_id }
1001+
.hash_stable(&mut hcx, &mut stable_hasher);
1002+
if tcx.sess.opts.debugging_opts.incremental_relative_spans {
1003+
let span = tcx.untracked_resolutions.definitions.def_span(*def_id);
1004+
debug_assert_eq!(span.parent(), None);
1005+
span.hash_stable(&mut hcx, &mut stable_hasher);
1006+
}
1007+
}
10081008
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
10091009
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
10101010
tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);

0 commit comments

Comments
 (0)