1 use crate::ich; 2 3 use rustc_ast as ast; 4 use rustc_data_structures::sorted_map::SortedMap; 5 use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher}; 6 use rustc_data_structures::sync::Lrc; 7 use rustc_hir as hir; 8 use rustc_hir::def_id::{DefId, LocalDefId}; 9 use rustc_hir::definitions::DefPathHash; 10 use rustc_session::cstore::Untracked; 11 use rustc_session::Session; 12 use rustc_span::source_map::SourceMap; 13 use rustc_span::symbol::Symbol; 14 use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData, DUMMY_SP}; 15 16 /// This is the context state available during incr. comp. hashing. It contains 17 /// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e., 18 /// a reference to the `TyCtxt`) and it holds a few caches for speeding up various 19 /// things (e.g., each `DefId`/`DefPath` is only hashed once). 20 #[derive(Clone)] 21 pub struct StableHashingContext<'a> { 22 untracked: &'a Untracked, 23 // The value of `-Z incremental-ignore-spans`. 24 // This field should only be used by `unstable_opts_incremental_ignore_span` 25 incremental_ignore_spans: bool, 26 pub(super) body_resolver: BodyResolver<'a>, 27 // Very often, we are hashing something that does not need the 28 // `CachingSourceMapView`, so we initialize it lazily. 29 raw_source_map: &'a SourceMap, 30 caching_source_map: Option<CachingSourceMapView<'a>>, 31 pub(super) hashing_controls: HashingControls, 32 } 33 34 /// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`. 35 /// We could also just store a plain reference to the `hir::Crate` but we want 36 /// to avoid that the crate is used to get untracked access to all of the HIR. 37 #[derive(Clone, Copy)] 38 pub(super) enum BodyResolver<'tcx> { 39 Forbidden, 40 Ignore, 41 Traverse { 42 owner: hir::OwnerId, 43 bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>>, 44 }, 45 } 46 47 impl<'a> StableHashingContext<'a> { 48 #[inline] new(sess: &'a Session, untracked: &'a Untracked) -> Self49 pub fn new(sess: &'a Session, untracked: &'a Untracked) -> Self { 50 let hash_spans_initial = !sess.opts.unstable_opts.incremental_ignore_spans; 51 52 StableHashingContext { 53 body_resolver: BodyResolver::Forbidden, 54 untracked, 55 incremental_ignore_spans: sess.opts.unstable_opts.incremental_ignore_spans, 56 caching_source_map: None, 57 raw_source_map: sess.source_map(), 58 hashing_controls: HashingControls { hash_spans: hash_spans_initial }, 59 } 60 } 61 62 #[inline] without_hir_bodies(&mut self, f: impl FnOnce(&mut StableHashingContext<'_>))63 pub fn without_hir_bodies(&mut self, f: impl FnOnce(&mut StableHashingContext<'_>)) { 64 f(&mut StableHashingContext { body_resolver: BodyResolver::Ignore, ..self.clone() }); 65 } 66 67 #[inline] with_hir_bodies( &mut self, owner: hir::OwnerId, bodies: &SortedMap<hir::ItemLocalId, &hir::Body<'_>>, f: impl FnOnce(&mut StableHashingContext<'_>), )68 pub fn with_hir_bodies( 69 &mut self, 70 owner: hir::OwnerId, 71 bodies: &SortedMap<hir::ItemLocalId, &hir::Body<'_>>, 72 f: impl FnOnce(&mut StableHashingContext<'_>), 73 ) { 74 f(&mut StableHashingContext { 75 body_resolver: BodyResolver::Traverse { owner, bodies }, 76 ..self.clone() 77 }); 78 } 79 80 #[inline] while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F)81 pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) { 82 let prev_hash_spans = self.hashing_controls.hash_spans; 83 self.hashing_controls.hash_spans = hash_spans; 84 f(self); 85 self.hashing_controls.hash_spans = prev_hash_spans; 86 } 87 88 #[inline] def_path_hash(&self, def_id: DefId) -> DefPathHash89 pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash { 90 if let Some(def_id) = def_id.as_local() { 91 self.local_def_path_hash(def_id) 92 } else { 93 self.untracked.cstore.read().def_path_hash(def_id) 94 } 95 } 96 97 #[inline] local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash98 pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash { 99 self.untracked.definitions.read().def_path_hash(def_id) 100 } 101 102 #[inline] source_map(&mut self) -> &mut CachingSourceMapView<'a>103 pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> { 104 match self.caching_source_map { 105 Some(ref mut sm) => sm, 106 ref mut none => { 107 *none = Some(CachingSourceMapView::new(self.raw_source_map)); 108 none.as_mut().unwrap() 109 } 110 } 111 } 112 113 #[inline] is_ignored_attr(&self, name: Symbol) -> bool114 pub fn is_ignored_attr(&self, name: Symbol) -> bool { 115 ich::IGNORED_ATTRIBUTES.contains(&name) 116 } 117 118 #[inline] hashing_controls(&self) -> HashingControls119 pub fn hashing_controls(&self) -> HashingControls { 120 self.hashing_controls.clone() 121 } 122 } 123 124 impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId { 125 #[inline] hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher)126 fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) { 127 panic!("Node IDs should not appear in incremental state"); 128 } 129 } 130 131 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { 132 #[inline] hash_spans(&self) -> bool133 fn hash_spans(&self) -> bool { 134 self.hashing_controls.hash_spans 135 } 136 137 #[inline] unstable_opts_incremental_ignore_spans(&self) -> bool138 fn unstable_opts_incremental_ignore_spans(&self) -> bool { 139 self.incremental_ignore_spans 140 } 141 142 #[inline] def_path_hash(&self, def_id: DefId) -> DefPathHash143 fn def_path_hash(&self, def_id: DefId) -> DefPathHash { 144 self.def_path_hash(def_id) 145 } 146 147 #[inline] def_span(&self, def_id: LocalDefId) -> Span148 fn def_span(&self, def_id: LocalDefId) -> Span { 149 self.untracked.source_span.get(def_id).unwrap_or(DUMMY_SP) 150 } 151 152 #[inline] span_data_to_lines_and_cols( &mut self, span: &SpanData, ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)>153 fn span_data_to_lines_and_cols( 154 &mut self, 155 span: &SpanData, 156 ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> { 157 self.source_map().span_data_to_lines_and_cols(span) 158 } 159 160 #[inline] hashing_controls(&self) -> HashingControls161 fn hashing_controls(&self) -> HashingControls { 162 self.hashing_controls.clone() 163 } 164 } 165 166 impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {} 167