//! This module contains `HashStable` implementations for various data types //! from libsyntax in no particular order. use crate::ich::StableHashingContext; use std::hash as std_hash; use std::mem; use syntax::ast; use syntax::feature_gate; use syntax::parse::token; use syntax::symbol::{InternedString, LocalInternedString}; use syntax::tokenstream; use syntax_pos::SourceFile; use crate::hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX}; use smallvec::SmallVec; use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; impl<'a> HashStable> for InternedString { #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.with(|s| s.hash_stable(hcx, hasher)) } } impl<'a> ToStableHashKey> for InternedString { type KeyType = InternedString; #[inline] fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> InternedString { self.clone() } } impl<'a> HashStable> for LocalInternedString { #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let s: &str = &**self; s.hash_stable(hcx, hasher); } } impl<'a> ToStableHashKey> for LocalInternedString { type KeyType = LocalInternedString; #[inline] fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> LocalInternedString { self.clone() } } impl<'a> HashStable> for ast::Name { #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.as_str().hash_stable(hcx, hasher); } } impl<'a> ToStableHashKey> for ast::Name { type KeyType = InternedString; #[inline] fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> InternedString { self.as_interned_str() } } impl_stable_hash_for!(enum ::syntax::ast::AsmDialect { Att, Intel }); impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { Bang, Attr, Derive, ProcMacroStub, }); impl_stable_hash_for!(enum ::rustc_target::spec::abi::Abi { Cdecl, Stdcall, Fastcall, Vectorcall, Thiscall, Aapcs, Win64, SysV64, PtxKernel, Msp430Interrupt, X86Interrupt, AmdGpuKernel, Rust, C, System, RustIntrinsic, RustCall, PlatformIntrinsic, Unadjusted }); impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note }); impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr, promotable, allow_const_fn_ptr, const_stability }); impl_stable_hash_for!(enum ::syntax::edition::Edition { Edition2015, Edition2018, }); impl<'a> HashStable> for ::syntax::attr::StabilityLevel { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => { reason.hash_stable(hcx, hasher); issue.hash_stable(hcx, hasher); } ::syntax::attr::StabilityLevel::Stable { ref since } => { since.hash_stable(hcx, hasher); } } } } impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason, suggestion }); impl_stable_hash_for!(enum ::syntax::attr::IntType { SignedInt(int_ty), UnsignedInt(uint_ty) }); impl_stable_hash_for!(enum ::syntax::ast::LitIntType { Signed(int_ty), Unsigned(int_ty), Unsuffixed }); impl_stable_hash_for_spanned!(::syntax::ast::LitKind); impl_stable_hash_for!(enum ::syntax::ast::LitKind { Str(value, style), Err(value), ByteStr(value), Byte(value), Char(value), Int(value, lit_int_type), Float(value, float_ty), FloatUnsuffixed(value), Bool(value) }); impl_stable_hash_for!(enum ::syntax::ast::IntTy { Isize, I8, I16, I32, I64, I128 }); impl_stable_hash_for!(enum ::syntax::ast::UintTy { Usize, U8, U16, U32, U64, U128 }); impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 }); impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal }); impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst }); impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final }); impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, ident }); impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); impl<'a> HashStable> for [ast::Attribute] { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { if self.len() == 0 { self.len().hash_stable(hcx, hasher); return } // Some attributes are always ignored during hashing. let filtered: SmallVec<[&ast::Attribute; 8]> = self .iter() .filter(|attr| { !attr.is_sugared_doc && !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)) }) .collect(); filtered.len().hash_stable(hcx, hasher); for attr in filtered { attr.hash_stable(hcx, hasher); } } } impl<'a> HashStable> for ast::Path { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.segments.len().hash_stable(hcx, hasher); for segment in &self.segments { segment.ident.name.hash_stable(hcx, hasher); } } } impl<'a> HashStable> for ast::Attribute { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { // Make sure that these have been filtered out. debug_assert!(!self.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name))); debug_assert!(!self.is_sugared_doc); let ast::Attribute { id: _, style, ref path, ref tokens, is_sugared_doc: _, span, } = *self; style.hash_stable(hcx, hasher); path.hash_stable(hcx, hasher); for tt in tokens.trees() { tt.hash_stable(hcx, hasher); } span.hash_stable(hcx, hasher); } } impl<'a> HashStable> for tokenstream::TokenTree { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { tokenstream::TokenTree::Token(span, ref token) => { span.hash_stable(hcx, hasher); hash_token(token, hcx, hasher); } tokenstream::TokenTree::Delimited(span, delim, ref tts) => { span.hash_stable(hcx, hasher); std_hash::Hash::hash(&delim, hasher); for sub_tt in tts.trees() { sub_tt.hash_stable(hcx, hasher); } } } } } impl<'a> HashStable> for tokenstream::TokenStream { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { for sub_tt in self.trees() { sub_tt.hash_stable(hcx, hasher); } } } fn hash_token<'a, 'gcx, W: StableHasherResult>( token: &token::Token, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher, ) { mem::discriminant(token).hash_stable(hcx, hasher); match *token { token::Token::Eq | token::Token::Lt | token::Token::Le | token::Token::EqEq | token::Token::Ne | token::Token::Ge | token::Token::Gt | token::Token::AndAnd | token::Token::OrOr | token::Token::Not | token::Token::Tilde | token::Token::At | token::Token::Dot | token::Token::DotDot | token::Token::DotDotDot | token::Token::DotDotEq | token::Token::Comma | token::Token::Semi | token::Token::Colon | token::Token::ModSep | token::Token::RArrow | token::Token::LArrow | token::Token::FatArrow | token::Token::Pound | token::Token::Dollar | token::Token::Question | token::Token::SingleQuote | token::Token::Whitespace | token::Token::Comment | token::Token::Eof => {} token::Token::BinOp(bin_op_token) | token::Token::BinOpEq(bin_op_token) => { std_hash::Hash::hash(&bin_op_token, hasher); } token::Token::OpenDelim(delim_token) | token::Token::CloseDelim(delim_token) => { std_hash::Hash::hash(&delim_token, hasher); } token::Token::Literal(ref lit, ref opt_name) => { mem::discriminant(lit).hash_stable(hcx, hasher); match *lit { token::Lit::Byte(val) | token::Lit::Char(val) | token::Lit::Err(val) | token::Lit::Integer(val) | token::Lit::Float(val) | token::Lit::Str_(val) | token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher), token::Lit::StrRaw(val, n) | token::Lit::ByteStrRaw(val, n) => { val.hash_stable(hcx, hasher); n.hash_stable(hcx, hasher); } }; opt_name.hash_stable(hcx, hasher); } token::Token::Ident(ident, is_raw) => { ident.name.hash_stable(hcx, hasher); is_raw.hash_stable(hcx, hasher); } token::Token::Lifetime(ident) => ident.name.hash_stable(hcx, hasher), token::Token::Interpolated(_) => { bug!("interpolated tokens should not be present in the HIR") } token::Token::DocComment(val) | token::Token::Shebang(val) => val.hash_stable(hcx, hasher), } } impl_stable_hash_for!(enum ::syntax::ast::NestedMetaItem { MetaItem(meta_item), Literal(lit) }); impl_stable_hash_for!(struct ::syntax::ast::MetaItem { path, node, span }); impl_stable_hash_for!(enum ::syntax::ast::MetaItemKind { Word, List(nested_items), NameValue(lit) }); impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { call_site, def_site, format, allow_internal_unstable, allow_internal_unsafe, local_inner_macros, edition }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { MacroAttribute(sym), MacroBang(sym), CompilerDesugaring(kind) }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { Async, QuestionMark, ExistentialReturnType, ForLoop, TryBlock }); impl_stable_hash_for!(enum ::syntax_pos::FileName { Real(pb), Macros(s), QuoteExpansion(s), Anon(s), MacroExpansion(s), ProcMacroSourceCode(s), CliCrateAttr(s), CfgSpec(s), Custom(s), DocTest(pb, line), }); impl<'a> HashStable> for SourceFile { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let SourceFile { name: _, // We hash the smaller name_hash instead of this name_hash, name_was_remapped, unmapped_path: _, crate_of_origin, // Do not hash the source as it is not encoded src: _, src_hash, external_src: _, start_pos, end_pos: _, ref lines, ref multibyte_chars, ref non_narrow_chars, } = *self; (name_hash as u64).hash_stable(hcx, hasher); name_was_remapped.hash_stable(hcx, hasher); DefId { krate: CrateNum::from_u32(crate_of_origin), index: CRATE_DEF_INDEX, }.hash_stable(hcx, hasher); src_hash.hash_stable(hcx, hasher); // We only hash the relative position within this source_file lines.len().hash_stable(hcx, hasher); for &line in lines.iter() { stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); } // We only hash the relative position within this source_file multibyte_chars.len().hash_stable(hcx, hasher); for &char_pos in multibyte_chars.iter() { stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); } non_narrow_chars.len().hash_stable(hcx, hasher); for &char_pos in non_narrow_chars.iter() { stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); } } } fn stable_byte_pos(pos: ::syntax_pos::BytePos, source_file_start: ::syntax_pos::BytePos) -> u32 { pos.0 - source_file_start.0 } fn stable_multibyte_char(mbc: ::syntax_pos::MultiByteChar, source_file_start: ::syntax_pos::BytePos) -> (u32, u32) { let ::syntax_pos::MultiByteChar { pos, bytes, } = mbc; (pos.0 - source_file_start.0, bytes as u32) } fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar, source_file_start: ::syntax_pos::BytePos) -> (u32, u32) { let pos = swc.pos(); let width = swc.width(); (pos.0 - source_file_start.0, width as u32) } impl<'gcx> HashStable> for feature_gate::Features { fn hash_stable(&self, hcx: &mut StableHashingContext<'gcx>, hasher: &mut StableHasher) { // Unfortunately we cannot exhaustively list fields here, since the // struct is macro generated. self.declared_lang_features.hash_stable(hcx, hasher); self.declared_lib_features.hash_stable(hcx, hasher); self.walk_feature_fields(|feature_name, value| { feature_name.hash_stable(hcx, hasher); value.hash_stable(hcx, hasher); }); } }