Auto merge of #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 https://github.com/rust-lang/compiler-team/issues/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.
This commit is contained in:
bors 2021-09-11 23:35:28 +00:00
commit 547d9374d2
68 changed files with 2800 additions and 1170 deletions

View file

@ -32,7 +32,13 @@ impl<'a, 'b> DefCollector<'a, 'b> {
fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId {
let parent_def = self.parent_def;
debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def);
self.resolver.create_def(parent_def, node_id, data, self.expansion.to_expn_id(), span)
self.resolver.create_def(
parent_def,
node_id,
data,
self.expansion.to_expn_id(),
span.with_parent(None),
)
}
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) {

View file

@ -768,6 +768,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
args[1].span.lo(),
args.last().unwrap().span.hi(),
call_span.ctxt(),
None,
))
} else {
None

View file

@ -1012,8 +1012,6 @@ pub struct Resolver<'a> {
next_node_id: NodeId,
def_id_to_span: IndexVec<LocalDefId, Span>,
node_id_to_def_id: FxHashMap<ast::NodeId, LocalDefId>,
def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>,
@ -1116,6 +1114,11 @@ impl ResolverAstLowering for Resolver<'_> {
}
}
#[inline]
fn def_span(&self, id: LocalDefId) -> Span {
self.definitions.def_span(id)
}
fn item_generics_num_lifetimes(&self, def_id: DefId) -> usize {
if let Some(def_id) = def_id.as_local() {
self.item_generics_num_lifetimes[&def_id]
@ -1197,9 +1200,7 @@ impl ResolverAstLowering for Resolver<'_> {
disambiguator
};
let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator);
assert_eq!(self.def_id_to_span.push(span), def_id);
let def_id = self.definitions.create_def(parent, data, expn_id, next_disambiguator, span);
// Some things for which we allocate `LocalDefId`s don't correspond to
// anything in the AST, so they don't have a `NodeId`. For these cases
@ -1225,6 +1226,11 @@ impl<'a, 'b> rustc_span::HashStableContext for ExpandHasher<'a, 'b> {
true
}
#[inline]
fn def_span(&self, id: LocalDefId) -> Span {
self.resolver.def_span(id)
}
#[inline]
fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
self.resolver.def_path_hash(def_id)
@ -1269,14 +1275,12 @@ impl<'a> Resolver<'a> {
let mut module_map = FxHashMap::default();
module_map.insert(root_local_def_id, graph_root);
let definitions = Definitions::new(session.local_stable_crate_id());
let definitions = Definitions::new(session.local_stable_crate_id(), krate.span);
let root = definitions.get_root_def();
let mut visibilities = FxHashMap::default();
visibilities.insert(root_local_def_id, ty::Visibility::Public);
let mut def_id_to_span = IndexVec::default();
assert_eq!(def_id_to_span.push(rustc_span::DUMMY_SP), root);
let mut def_id_to_node_id = IndexVec::default();
assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), root);
let mut node_id_to_def_id = FxHashMap::default();
@ -1393,7 +1397,6 @@ impl<'a> Resolver<'a> {
.collect(),
lint_buffer: LintBuffer::default(),
next_node_id: NodeId::from_u32(1),
def_id_to_span,
node_id_to_def_id,
def_id_to_node_id,
placeholder_field_indices: Default::default(),
@ -3360,7 +3363,7 @@ impl<'a> Resolver<'a> {
/// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
#[inline]
pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
if let Some(def_id) = def_id.as_local() { Some(self.def_id_to_span[def_id]) } else { None }
def_id.as_local().map(|def_id| self.definitions.def_span(def_id))
}
/// Checks if an expression refers to a function marked with

View file

@ -180,6 +180,10 @@ impl<'a> ResolverExpand for Resolver<'a> {
self.next_node_id()
}
fn invocation_parent(&self, id: LocalExpnId) -> LocalDefId {
self.invocation_parents[&id].0
}
fn resolve_dollar_crates(&mut self) {
hygiene::update_dollar_crate_names(|ctxt| {
let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));