diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index f77275926eba3..7002d01322a4d 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -142,7 +142,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { }); let mut upstream_crates: Vec<_> = cstore.crates_untracked().iter().map(|&cnum| { - let name = cstore.crate_name_untracked(cnum).as_str(); + let name = cstore.crate_name_untracked(cnum).as_str().to_owned(); let disambiguator = cstore.crate_disambiguator_untracked(cnum) .to_fingerprint(); let hash = cstore.crate_hash_untracked(cnum); diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 1a2840de447de..39cc78bc9e2b1 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -220,7 +220,7 @@ impl DefKey { DefPathData::EnumVariant(name) | DefPathData::Field(name) | DefPathData::GlobalMetaData(name) => { - name.hash(&mut hasher); + (&name[..]).hash(&mut hasher); } DefPathData::Impl | diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 513b6c835f982..92c0f3e774edd 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -13,6 +13,7 @@ use ich::StableHashingContext; +use std::cmp; use std::hash as std_hash; use std::mem; @@ -29,6 +30,30 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; use rustc_data_structures::accumulate_vec::AccumulateVec; +/// InternedString is not compared lexicographically but by pointer value. So, +/// in order to use it as a stable key we introduce a wrapper type with +/// the correct Ord, Eq, and Hash implementations. +#[derive(Eq, Ord, Clone, Copy)] +pub struct InternedStringSortStable(InternedString); + +impl std_hash::Hash for InternedStringSortStable { + fn hash(&self, state: &mut H) { + std_hash::Hash::hash(&self.0[..], state); + } +} + +impl cmp::PartialOrd for InternedStringSortStable { + fn partial_cmp(&self, other: &InternedStringSortStable) -> Option { + (&self.0[..]).partial_cmp(&other.0[..]) + } +} + +impl cmp::PartialEq for InternedStringSortStable { + fn eq(&self, other: &InternedStringSortStable) -> bool { + (&self.0[..]).eq(&other.0[..]) + } +} + impl<'a> HashStable> for InternedString { #[inline] fn hash_stable(&self, @@ -39,14 +64,16 @@ impl<'a> HashStable> for InternedString { } } +impl_stable_hash_for!(tuple_struct self::InternedStringSortStable { inner }); + impl<'a> ToStableHashKey> for InternedString { - type KeyType = InternedString; + type KeyType = InternedStringSortStable; #[inline] fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) - -> InternedString { - self.clone() + -> InternedStringSortStable { + InternedStringSortStable(self.clone()) } } @@ -60,13 +87,13 @@ impl<'a> HashStable> for ast::Name { } impl<'a> ToStableHashKey> for ast::Name { - type KeyType = InternedString; + type KeyType = InternedStringSortStable; #[inline] fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) - -> InternedString { - self.as_str() + -> InternedStringSortStable { + InternedStringSortStable(self.as_str()) } } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 66360ea50bbe0..277950b66f730 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::ast; +use syntax::symbol::InternedString; use syntax_pos::Span; use ty::{self, Ty}; @@ -53,7 +53,7 @@ pub enum TypeVariableOrigin { MiscVariable(Span), NormalizeProjectionType(Span), TypeInference(Span), - TypeParameterDefinition(Span, ast::Name), + TypeParameterDefinition(Span, InternedString), /// one of the upvars or closure kind parameters in a `ClosureSubsts` /// (before it has been determined) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 7e5dc02798dff..e41613d2734da 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -380,7 +380,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } for param in generics.types.iter() { - let name = param.name.as_str().to_string(); + let name = param.name.to_string(); let ty = trait_ref.substs.type_for_def(param); let ty_str = ty.to_string(); flags.push((name.clone(), diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 8c2c1cfa45472..f7ce55c2e1df2 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -289,7 +289,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { let trait_str = tcx.item_path_str(trait_ref.def_id); let generics = tcx.generics_of(trait_ref.def_id); let generic_map = generics.types.iter().map(|param| { - (param.name.as_str().to_string(), + (param.name.to_string(), trait_ref.substs.type_for_def(param).to_string()) }).collect::>(); diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fd3465f59ebf2..72de171755006 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -69,11 +69,11 @@ use std::iter; use std::sync::mpsc; use std::sync::Arc; use syntax::abi; -use syntax::ast::{self, Name, NodeId}; +use syntax::ast::{self, NodeId}; use syntax::attr; use syntax::codemap::MultiSpan; use syntax::feature_gate; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::{Symbol, keywords, InternedString}; use syntax_pos::Span; use hir; @@ -2221,12 +2221,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_param(self, index: u32, - name: Name) -> Ty<'tcx> { + name: InternedString) -> Ty<'tcx> { self.mk_ty(TyParam(ParamTy { idx: index, name: name })) } pub fn mk_self_type(self) -> Ty<'tcx> { - self.mk_param(0, keywords::SelfType.name()) + self.mk_param(0, keywords::SelfType.name().as_str()) } pub fn mk_param_from_def(self, def: &ty::TypeParameterDef) -> Ty<'tcx> { diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index dd65d4b419071..3da5b5240785f 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -491,7 +491,16 @@ macro_rules! define_maps { span: Span, dep_node: DepNode) -> Result<($V, DepNodeIndex), CycleError<'a, $tcx>> { - debug_assert!(!tcx.dep_graph.dep_node_exists(&dep_node)); + // If the following assertion triggers, it can have two reasons: + // 1. Something is wrong with DepNode creation, either here or + // in DepGraph::try_mark_green() + // 2. Two distinct query keys get mapped to the same DepNode + // (see for example #48923) + assert!(!tcx.dep_graph.dep_node_exists(&dep_node), + "Forcing query with already existing DepNode.\n\ + - query-key: {:?}\n\ + - dep-node: {:?}", + key, dep_node); profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin); let res = tcx.cycle_check(span, Query::$name(key), || { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c915022351925..e8e877c3a3962 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -699,7 +699,7 @@ pub struct FloatVarValue(pub ast::FloatTy); #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct TypeParameterDef { - pub name: Name, + pub name: InternedString, pub def_id: DefId, pub index: u32, pub has_default: bool, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index ae053d7f4f58d..9812076475739 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -23,7 +23,7 @@ use std::iter; use std::cmp::Ordering; use syntax::abi; use syntax::ast::{self, Name}; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, InternedString}; use serialize; @@ -861,16 +861,16 @@ impl<'tcx> PolyFnSig<'tcx> { #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct ParamTy { pub idx: u32, - pub name: Name, + pub name: InternedString, } impl<'a, 'gcx, 'tcx> ParamTy { - pub fn new(index: u32, name: Name) -> ParamTy { + pub fn new(index: u32, name: InternedString) -> ParamTy { ParamTy { idx: index, name: name } } pub fn for_self() -> ParamTy { - ParamTy::new(0, keywords::SelfType.name()) + ParamTy::new(0, keywords::SelfType.name().as_str()) } pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy { @@ -882,7 +882,7 @@ impl<'a, 'gcx, 'tcx> ParamTy { } pub fn is_self(&self) -> bool { - if self.name == keywords::SelfType.name() { + if self.name == keywords::SelfType.name().as_str() { assert_eq!(self.idx, 0); true } else { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 91d460a96f785..38ef2e11869bf 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -714,7 +714,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> } TyParam(p) => { self.hash(p.idx); - self.hash(p.name.as_str()); + self.hash(&p.name[..]); } TyProjection(ref data) => { self.def_id(data.item_def_id); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 97577008377ab..d159cbafc28ba 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -303,7 +303,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn t_param(&self, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - self.infcx.tcx.mk_param(index, Symbol::intern(&name)) + self.infcx.tcx.mk_param(index, Symbol::intern(&name).as_str()) } pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> { diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 7664c88679e0e..87d9623e40038 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -42,7 +42,7 @@ use std::ptr; use syntax_pos::{self, Span, Pos}; use syntax::ast; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, InternedString}; use rustc::ty::layout::{self, LayoutOf}; pub mod gdb; @@ -393,7 +393,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, substs.types().zip(names).map(|(ty, name)| { let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); - let name = CString::new(name.as_str().as_bytes()).unwrap(); + let name = CString::new(name.as_bytes()).unwrap(); unsafe { llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), @@ -412,7 +412,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, return create_DIArray(DIB(cx), &template_params[..]); } - fn get_type_parameter_names(cx: &CodegenCx, generics: &ty::Generics) -> Vec { + fn get_type_parameter_names(cx: &CodegenCx, generics: &ty::Generics) -> Vec { let mut names = generics.parent.map_or(vec![], |def_id| { get_type_parameter_names(cx, cx.tcx.generics_of(def_id)) }); diff --git a/src/librustc_trans_utils/symbol_names.rs b/src/librustc_trans_utils/symbol_names.rs index f9f93730255e6..8a1a3202c511f 100644 --- a/src/librustc_trans_utils/symbol_names.rs +++ b/src/librustc_trans_utils/symbol_names.rs @@ -194,7 +194,7 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } if avoid_cross_crate_conflicts { - hasher.hash(tcx.crate_name.as_str()); + hasher.hash(&tcx.crate_name.as_str()[..]); hasher.hash(tcx.sess.local_crate_disambiguator()); } }); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 827ca79334cbe..ad9cee907e5c8 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -978,7 +978,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let item_def_id = tcx.hir.local_def_id(item_id); let generics = tcx.generics_of(item_def_id); let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id)]; - tcx.mk_param(index, tcx.hir.name(node_id)) + tcx.mk_param(index, tcx.hir.name(node_id).as_str()) } Def::SelfTy(_, Some(def_id)) => { // Self in impl (we know the concrete type). diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 99707a4a3c0e5..050030f67523d 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -76,7 +76,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// and in libcore/intrinsics.rs pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::ForeignItem) { - let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n))); + let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)).as_str()); let name = it.name.as_str(); let (n_tps, inputs, output) = if name.starts_with("atomic_") { let split : Vec<&str> = name.split('_').collect(); @@ -341,7 +341,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::ForeignItem) { let param = |n| { - let name = Symbol::intern(&format!("P{}", n)); + let name = Symbol::intern(&format!("P{}", n)).as_str(); tcx.mk_param(n, name) }; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b94af0a1e0081..fce685ddaab71 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -643,7 +643,7 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) { // local so it should be okay to just unwrap everything. let trait_def_id = impl_params[&method_param.name]; let trait_decl_span = tcx.def_span(trait_def_id); - error_194(tcx, type_span, trait_decl_span, method_param.name); + error_194(tcx, type_span, trait_decl_span, &method_param.name[..]); } } } @@ -739,7 +739,7 @@ fn error_392<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, param_name: ast: err } -fn error_194(tcx: TyCtxt, span: Span, trait_decl_span: Span, name: ast::Name) { +fn error_194(tcx: TyCtxt, span: Span, trait_decl_span: Span, name: &str) { struct_span_err!(tcx.sess, span, E0194, "type parameter `{}` shadows another type parameter of the same name", name) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a17b35dec42d7..bdf0e14c72795 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -240,7 +240,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_owner_def_id = tcx.hir.local_def_id(param_owner); let generics = tcx.generics_of(param_owner_def_id); let index = generics.type_param_to_index[&def_id]; - let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id)); + let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id).as_str()); // Don't look for bounds where the type parameter isn't in scope. let parent = if item_def_id == param_owner_def_id { @@ -838,7 +838,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, opt_self = Some(ty::TypeParameterDef { index: 0, - name: keywords::SelfType.name(), + name: keywords::SelfType.name().as_str(), def_id: tcx.hir.local_def_id(param_id), has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -914,7 +914,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TypeParameterDef { index: type_start + i as u32, - name: p.name, + name: p.name.as_str(), def_id: tcx.hir.local_def_id(p.id), has_default: p.default.is_some(), object_lifetime_default: @@ -933,7 +933,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // add a dummy parameter for the closure kind types.push(ty::TypeParameterDef { index: type_start, - name: Symbol::intern(""), + name: Symbol::intern("").as_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -944,7 +944,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // add a dummy parameter for the closure signature types.push(ty::TypeParameterDef { index: type_start + 1, - name: Symbol::intern(""), + name: Symbol::intern("").as_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -955,7 +955,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.with_freevars(node_id, |fv| { types.extend(fv.iter().zip(2..).map(|(_, i)| ty::TypeParameterDef { index: type_start + i, - name: Symbol::intern(""), + name: Symbol::intern("").as_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -1435,7 +1435,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Collect the predicates that were written inline by the user on each // type parameter (e.g., ``). for param in ast_generics.ty_params() { - let param_ty = ty::ParamTy::new(index, param.name).to_ty(tcx); + let param_ty = ty::ParamTy::new(index, param.name.as_str()).to_ty(tcx); index += 1; let bounds = compute_bounds(&icx, diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 370fc9bbca243..71bdd0cf38c10 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -259,7 +259,9 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { P(hir::Path { span: DUMMY_SP, def: Def::TyParam(param.def_id), - segments: HirVec::from_vec(vec![hir::PathSegment::from_name(param.name)]), + segments: HirVec::from_vec(vec![ + hir::PathSegment::from_name(Symbol::intern(¶m.name)) + ]), }), )), span: DUMMY_SP, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 904c24815cb7f..69c76767ed9b5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,7 +26,7 @@ use syntax::codemap::Spanned; use syntax::feature_gate::UnstableFeatures; use syntax::ptr::P; use syntax::symbol::keywords; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, InternedString}; use syntax_pos::{self, DUMMY_SP, Pos, FileName}; use rustc::middle::const_val::ConstVal; @@ -3199,6 +3199,12 @@ impl Clean for ast::Name { } } +impl Clean for InternedString { + fn clean(&self, _: &DocContext) -> String { + self.to_string() + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Typedef { pub type_: Type, diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9b83d5510fb7d..bd9a249bd3f33 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -25,6 +25,7 @@ #![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(specialization)] +#![feature(macro_lifetime_matcher)] use std::borrow::Cow; use std::cell::Cell; diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 0cba094da641d..4ddcac2c26b2b 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -18,6 +18,8 @@ use GLOBALS; use serialize::{Decodable, Decoder, Encodable, Encoder}; use std::collections::HashMap; use std::fmt; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct Ident { @@ -154,9 +156,11 @@ impl Decodable for Symbol { } } -impl> PartialEq for Symbol { - fn eq(&self, other: &T) -> bool { - self.as_str() == other.deref() +impl PartialEq for Symbol { + #[inline] + fn eq(&self, other: &InternedString) -> bool { + // Compare pointers + self.as_str() == *other } } @@ -344,52 +348,84 @@ fn with_interner T>(f: F) -> T { /// interner lives for the life of the thread, this can be safely treated as an /// immortal string, as long as it never crosses between threads. /// +/// CAUTION: InternedStrings are *not* compared and hashed lexicographically! +/// Instead their pointer values are compared/hashed, so cast to &str +/// if you need things to be stable across process boundaries. +/// /// FIXME(pcwalton): You must be careful about what you do in the destructors /// of objects stored in TLS, because they may run after the interner is /// destroyed. In particular, they must not access string contents. This can /// be fixed in the future by just leaking all strings until thread death /// somehow. -#[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)] +#[derive(Clone, Copy, PartialOrd, Eq, Ord)] pub struct InternedString { string: &'static str, } -impl ::std::convert::AsRef for InternedString where str: ::std::convert::AsRef { - fn as_ref(&self) -> &U { - self.string.as_ref() +impl Hash for InternedString { + fn hash(&self, state: &mut H) { + self.as_ptr().hash(state); } } -impl> ::std::cmp::PartialEq for InternedString { - fn eq(&self, other: &T) -> bool { - self.string == other.deref() +impl ::std::convert::AsRef for InternedString where str: ::std::convert::AsRef { + fn as_ref(&self) -> &U { + self.string.as_ref() } } -impl ::std::cmp::PartialEq for str { +impl ::std::cmp::PartialEq for InternedString { + #[inline] fn eq(&self, other: &InternedString) -> bool { - self == other.string + self.as_ptr() == other.as_ptr() } } -impl<'a> ::std::cmp::PartialEq for &'a str { - fn eq(&self, other: &InternedString) -> bool { - *self == other.string +impl PartialEq for InternedString { + #[inline] + fn eq(&self, other: &Symbol) -> bool { + // Compare pointers + *self == other.as_str() } } -impl ::std::cmp::PartialEq for String { - fn eq(&self, other: &InternedString) -> bool { - self == other.string - } -} +macro_rules! impl_partial_eq_for_symbol_and_interned_string { + ($(impl $(<$impl_lt:lifetime>)* for $t:ty;)*) => ($( + impl<$($impl_lt),*> ::std::cmp::PartialEq<$t> for InternedString { + fn eq(&self, other: &$t) -> bool { + let s: &str = other.deref(); + self.string == s + } + } -impl<'a> ::std::cmp::PartialEq for &'a String { - fn eq(&self, other: &InternedString) -> bool { - *self == other.string - } + impl<$($impl_lt),*> ::std::cmp::PartialEq for $t { + fn eq(&self, other: &InternedString) -> bool { + let s: &str = self.deref(); + s == other.string + } + } + + impl<$($impl_lt),*> ::std::cmp::PartialEq<$t> for Symbol { + fn eq(&self, other: &$t) -> bool { + self.as_str() == *other + } + } + + impl<$($impl_lt),*> ::std::cmp::PartialEq for $t { + fn eq(&self, other: &Symbol) -> bool { + *self == other.as_str() + } + } + )*) } +impl_partial_eq_for_symbol_and_interned_string!( + impl for str; + impl for String; + impl<'a> for &'a str; + impl<'a> for &'a String; +); + impl !Send for InternedString { } impl ::std::ops::Deref for InternedString {