diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index fa14764c42a..9232be8ea2b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -165,6 +165,8 @@ struct LoweringContext<'a, 'hir: 'a> { pub trait ResolverAstLowering { fn def_key(&mut self, id: DefId) -> DefKey; + fn def_span(&self, id: LocalDefId) -> Span; + fn item_generics_num_lifetimes(&self, def: DefId) -> usize; fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option>; @@ -215,6 +217,11 @@ impl<'a> rustc_span::HashStableContext for LoweringHasher<'a> { 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) diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs index 32ccdafaeb4..efb1fc68ce1 100644 --- a/compiler/rustc_middle/src/ich/hcx.rs +++ b/compiler/rustc_middle/src/ich/hcx.rs @@ -12,7 +12,7 @@ use rustc_hir::definitions::{DefPathHash, Definitions}; use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; -use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData}; +use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData}; use smallvec::SmallVec; use std::cmp::Ord; @@ -229,6 +229,11 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { self.def_path_hash(def_id) } + #[inline] + fn def_span(&self, def_id: LocalDefId) -> Span { + self.definitions.def_span(def_id) + } + fn span_data_to_lines_and_cols( &mut self, span: &SpanData, diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index be305e60a0a..63000a295f6 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -23,7 +23,7 @@ use rustc_span::hygiene::{ }; use rustc_span::source_map::{SourceMap, StableSourceFileId}; use rustc_span::CachingSourceMapView; -use rustc_span::{BytePos, ExpnData, ExpnHash, SourceFile, Span, DUMMY_SP}; +use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, SourceFile, Span}; use std::collections::hash_map::Entry; use std::mem; @@ -33,6 +33,7 @@ const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; const TAG_FULL_SPAN: u8 = 0; // A partial span with no location information, encoded only with a `SyntaxContext` const TAG_PARTIAL_SPAN: u8 = 1; +const TAG_RELATIVE_SPAN: u8 = 2; const TAG_SYNTAX_CONTEXT: u8 = 0; const TAG_EXPN_DATA: u8 = 1; @@ -829,11 +830,25 @@ impl<'a, 'tcx> Decodable> for ExpnId { impl<'a, 'tcx> Decodable> for Span { fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result { + let ctxt = SyntaxContext::decode(decoder)?; + let parent = Option::::decode(decoder)?; let tag: u8 = Decodable::decode(decoder)?; if tag == TAG_PARTIAL_SPAN { - let ctxt = SyntaxContext::decode(decoder)?; - return Ok(DUMMY_SP.with_ctxt(ctxt)); + return Ok(Span::new(BytePos(0), BytePos(0), ctxt, parent)); + } else if tag == TAG_RELATIVE_SPAN { + let dlo = u32::decode(decoder)?; + let dto = u32::decode(decoder)?; + + let enclosing = decoder.tcx.definitions_untracked().def_span(parent.unwrap()).data(); + let span = Span::new( + enclosing.lo + BytePos::from_u32(dlo), + enclosing.lo + BytePos::from_u32(dto), + ctxt, + parent, + ); + + return Ok(span); } else { debug_assert_eq!(tag, TAG_FULL_SPAN); } @@ -842,13 +857,12 @@ impl<'a, 'tcx> Decodable> for Span { let line_lo = usize::decode(decoder)?; let col_lo = BytePos::decode(decoder)?; let len = BytePos::decode(decoder)?; - let ctxt = SyntaxContext::decode(decoder)?; let file_lo = decoder.file_index_to_file(file_lo_index); let lo = file_lo.lines[line_lo - 1] + col_lo; let hi = lo + len; - Ok(Span::new(lo, hi, ctxt, None)) + Ok(Span::new(lo, hi, ctxt, parent)) } } @@ -1009,9 +1023,21 @@ where { fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> { let span_data = self.data(); - if self.is_dummy() { - TAG_PARTIAL_SPAN.encode(s)?; - return span_data.ctxt.encode(s); + span_data.ctxt.encode(s)?; + span_data.parent.encode(s)?; + + if span_data.is_dummy() { + return TAG_PARTIAL_SPAN.encode(s); + } + + if let Some(parent) = span_data.parent { + let enclosing = s.tcx.definitions_untracked().def_span(parent).data(); + if enclosing.contains(span_data) { + TAG_RELATIVE_SPAN.encode(s)?; + (span_data.lo - enclosing.lo).to_u32().encode(s)?; + (span_data.hi - enclosing.lo).to_u32().encode(s)?; + return Ok(()); + } } let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo); @@ -1021,8 +1047,7 @@ where }; if partial_span { - TAG_PARTIAL_SPAN.encode(s)?; - return span_data.ctxt.encode(s); + return TAG_PARTIAL_SPAN.encode(s); } let (file_lo, line_lo, col_lo) = pos.unwrap(); @@ -1035,8 +1060,7 @@ where source_file_index.encode(s)?; line_lo.encode(s)?; col_lo.encode(s)?; - len.encode(s)?; - span_data.ctxt.encode(s) + len.encode(s) } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ead3ca9fcde..787c7a625d5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1114,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] @@ -1221,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) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index d744ad4014a..de08c5d8a55 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -2001,6 +2001,7 @@ impl InnerSpan { pub trait HashStableContext { fn def_path_hash(&self, def_id: DefId) -> DefPathHash; fn hash_spans(&self) -> bool; + fn def_span(&self, def_id: LocalDefId) -> Span; fn span_data_to_lines_and_cols( &mut self, span: &SpanData, @@ -2024,22 +2025,35 @@ where fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { const TAG_VALID_SPAN: u8 = 0; const TAG_INVALID_SPAN: u8 = 1; + const TAG_RELATIVE_SPAN: u8 = 2; if !ctx.hash_spans() { return; } - self.ctxt().hash_stable(ctx, hasher); + let span = self.data(); + span.ctxt.hash_stable(ctx, hasher); + span.parent.hash_stable(ctx, hasher); - if self.is_dummy() { + if span.is_dummy() { Hash::hash(&TAG_INVALID_SPAN, hasher); return; } + if let Some(parent) = span.parent { + let def_span = ctx.def_span(parent).data(); + if def_span.contains(span) { + // This span is enclosed in a definition: only hash the relative position. + Hash::hash(&TAG_RELATIVE_SPAN, hasher); + (span.lo - def_span.lo).to_u32().hash_stable(ctx, hasher); + (span.hi - def_span.lo).to_u32().hash_stable(ctx, hasher); + return; + } + } + // If this is not an empty or invalid span, we want to hash the last // position that belongs to it, as opposed to hashing the first // position past it. - let span = self.data(); let (file, line_lo, col_lo, line_hi, col_hi) = match ctx.span_data_to_lines_and_cols(&span) { Some(pos) => pos,