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

+1-1
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

+3-1
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

+16-4
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

+2-1
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

+14-1
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

+1-1
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

+23-1
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

+11
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

+2-1
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

+13-13
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);

compiler/rustc_middle/src/hir/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ pub fn provide(providers: &mut Providers) {
153153
index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
154154
};
155155
providers.hir_attrs = |tcx, id| AttributeMap { map: &tcx.untracked_crate.attrs, prefix: id };
156+
providers.source_span = |tcx, def_id| tcx.resolutions(()).definitions.def_span(def_id);
156157
providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
157158
providers.fn_arg_names = |tcx, id| {
158159
let hir = tcx.hir();

compiler/rustc_middle/src/ich/hcx.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_hir::definitions::{DefPathHash, Definitions};
1212
use rustc_session::Session;
1313
use rustc_span::source_map::SourceMap;
1414
use rustc_span::symbol::Symbol;
15-
use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData};
15+
use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData};
1616

1717
use smallvec::SmallVec;
1818
use std::cmp::Ord;
@@ -227,6 +227,11 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
227227
self.def_path_hash(def_id)
228228
}
229229

230+
#[inline]
231+
fn def_span(&self, def_id: LocalDefId) -> Span {
232+
self.definitions.def_span(def_id)
233+
}
234+
230235
fn span_data_to_lines_and_cols(
231236
&mut self,
232237
span: &SpanData,

compiler/rustc_middle/src/query/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ rustc_queries! {
2020
desc { "get the resolver outputs" }
2121
}
2222

23+
/// Return the span for a definition.
24+
/// Contrary to `def_span` below, this query returns the full absolute span of the definition.
25+
/// This span is meant for dep-tracking rather than diagnostics. It should not be used outside
26+
/// of rustc_middle::hir::source_map.
27+
query source_span(key: LocalDefId) -> Span {
28+
desc { "get the source span" }
29+
}
30+
2331
/// Represents crate as a whole (as distinct from the top-level crate module).
2432
/// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`),
2533
/// we will have to assume that any change means that you need to be recompiled.

compiler/rustc_middle/src/ty/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,7 @@ fn foo(&self) -> Self::T { String::new() }
964964
{
965965
let (span, sugg) = if has_params {
966966
let pos = span.hi() - BytePos(1);
967-
let span = Span::new(pos, pos, span.ctxt());
967+
let span = Span::new(pos, pos, span.ctxt(), span.parent());
968968
(span, format!(", {} = {}", assoc.ident, ty))
969969
} else {
970970
let item_args = self.format_generic_args(assoc_substs);

compiler/rustc_mir_transform/src/coverage/spans.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,11 @@ impl CoverageSpan {
196196
/// body_span), returns the macro name symbol.
197197
pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> {
198198
if let Some(current_macro) = self.current_macro() {
199-
if self.expn_span.parent().unwrap_or_else(|| bug!("macro must have a parent")).ctxt()
199+
if self
200+
.expn_span
201+
.parent_callsite()
202+
.unwrap_or_else(|| bug!("macro must have a parent"))
203+
.ctxt()
200204
== body_span.ctxt()
201205
{
202206
return Some(current_macro);

compiler/rustc_parse/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ fn maybe_source_file_to_parser(
131131
let mut parser = stream_to_parser(sess, stream, None);
132132
parser.unclosed_delims = unclosed_delims;
133133
if parser.token == token::Eof {
134-
parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt());
134+
parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None);
135135
}
136136

137137
Ok(parser)

0 commit comments

Comments
 (0)