From 4aa020585bcb7d8369c94d787674717c84928a37 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 26 Oct 2017 19:21:39 -0400 Subject: [PATCH] remove fallback `hash` method. fixes #12198 --- base/Enums.jl | 2 ++ base/atomics.jl | 2 +- base/dates/io.jl | 4 ++-- base/deprecated.jl | 2 +- base/distributed/clusterserialize.jl | 12 ++++++++++-- base/distributed/workerpool.jl | 6 +++--- base/hashing.jl | 12 ++++++------ base/markdown/parse/config.jl | 2 +- base/reflection.jl | 12 ++++++------ base/repl/LineEdit.jl | 4 ++-- base/show.jl | 4 ++-- test/dict.jl | 1 + 12 files changed, 37 insertions(+), 26 deletions(-) diff --git a/base/Enums.jl b/base/Enums.jl index b10ff6cf79039..1feb2a49232b7 100644 --- a/base/Enums.jl +++ b/base/Enums.jl @@ -14,6 +14,8 @@ Base.convert(::Type{T}, x::Enum{T2}) where {T<:Integer,T2<:Integer} = convert(T, Base.write(io::IO, x::Enum{T}) where {T<:Integer} = write(io, T(x)) Base.read(io::IO, ::Type{T}) where {T<:Enum} = T(read(io, Enums.basetype(T))) +Base.hash(x::Enum, h::UInt) = Base.hash_uint(3h - object_id(x)) + # generate code to test whether expr is in the given set of values function membershiptest(expr, values) lo, hi = extrema(values) diff --git a/base/atomics.jl b/base/atomics.jl index 51c6964a13e16..81a70eb47b1ac 100644 --- a/base/atomics.jl +++ b/base/atomics.jl @@ -316,7 +316,7 @@ function atomic_min! end unsafe_convert(::Type{Ptr{T}}, x::Atomic{T}) where {T} = convert(Ptr{T}, pointer_from_objref(x)) setindex!(x::Atomic{T}, v) where {T} = setindex!(x, convert(T, v)) -const llvmtypes = Dict( +const llvmtypes = ObjectIdDict( Bool => "i1", Int8 => "i8", UInt8 => "i8", Int16 => "i16", UInt16 => "i16", diff --git a/base/dates/io.jl b/base/dates/io.jl index fdff3d9204386..445551a502482 100644 --- a/base/dates/io.jl +++ b/base/dates/io.jl @@ -267,7 +267,7 @@ const CONVERSION_SPECIFIERS = Dict{Char, Type}( # Default values are needed when a conversion specifier is used in a DateFormat for parsing # and we have reached the end of the input string. # Note: Allow `Any` value as a default to support extensibility -const CONVERSION_DEFAULTS = Dict{Type, Any}( +const CONVERSION_DEFAULTS = ObjectIdDict( Year => Int64(1), Month => Int64(1), DayOfWeekToken => Int64(0), @@ -282,7 +282,7 @@ const CONVERSION_DEFAULTS = Dict{Type, Any}( # Specifies the required fields in order to parse a TimeType # Note: Allows for addition of new TimeTypes -const CONVERSION_TRANSLATIONS = Dict{Type{<:TimeType}, Tuple}( +const CONVERSION_TRANSLATIONS = ObjectIdDict( Date => (Year, Month, Day), DateTime => (Year, Month, Day, Hour, Minute, Second, Millisecond), Time => (Hour, Minute, Second, Millisecond, Microsecond, Nanosecond), diff --git a/base/deprecated.jl b/base/deprecated.jl index 2236f3c8081d7..906b0eca45fa9 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -632,7 +632,7 @@ for (Bsig, A1sig, A2sig, gbb, funcname) in (SparseMatrixCSC , BitArray , SparseMatrixCSC, :gen_broadcast_body_zpreserving, :_broadcast_zpreserving!), (SparseMatrixCSC , SparseMatrixCSC , BitArray, :gen_broadcast_body_zpreserving, :_broadcast_zpreserving!), ) - @eval let cache = Dict{Function,Function}() + @eval let cache = ObjectIdDict() global $funcname function $funcname(f::Function, B::$Bsig, A1::$A1sig, A2::$A2sig) func = @get! cache f gen_broadcast_function_sparse($gbb, f, ($A1sig) <: SparseMatrixCSC) diff --git a/base/distributed/clusterserialize.jl b/base/distributed/clusterserialize.jl index 2a42f35a7f572..47e0404d597e9 100644 --- a/base/distributed/clusterserialize.jl +++ b/base/distributed/clusterserialize.jl @@ -98,6 +98,14 @@ function serialize(s::ClusterSerializer, g::GlobalRef) invoke(serialize, Tuple{AbstractSerializer, GlobalRef}, s, g) end +function hash_any(@nospecialize x) + try + return hash(x) + catch + return object_id(x) + end +end + # Send/resend a global object if # a) has not been sent previously, i.e., we are seeing this object_id for the first time, or, # b) hash value has changed or @@ -114,7 +122,7 @@ function syms_2b_sent(s::ClusterSerializer, identifier) oid = object_id(v) if haskey(s.glbs_sent, oid) # We have sent this object before, see if it has changed. - s.glbs_sent[oid] != hash(sym, hash(v)) && push!(lst, sym) + s.glbs_sent[oid] != hash(sym, hash_any(v)) && push!(lst, sym) else push!(lst, sym) end @@ -143,7 +151,7 @@ function serialize_global_from_main(s::ClusterSerializer, sym) end end end - record_v && (s.glbs_sent[oid] = hash(sym, hash(v))) + record_v && (s.glbs_sent[oid] = hash(sym, hash_any(v))) serialize(s, isconst(Main, sym)) serialize(s, v) diff --git a/base/distributed/workerpool.jl b/base/distributed/workerpool.jl index 7aedd63c844c4..f70e458de149d 100644 --- a/base/distributed/workerpool.jl +++ b/base/distributed/workerpool.jl @@ -218,11 +218,11 @@ mutable struct CachingPool <: AbstractWorkerPool channel::Channel{Int} workers::Set{Int} - # Mapping between a tuple (worker_id, f) and a remote_ref - map_obj2ref::Dict{Tuple{Int, Function}, RemoteChannel} + # Mapping from a tuple (worker_id, f) to a remote_ref + map_obj2ref::ObjectIdDict function CachingPool() - wp = new(Channel{Int}(typemax(Int)), Set{Int}(), Dict{Int, Function}()) + wp = new(Channel{Int}(typemax(Int)), Set{Int}(), ObjectIdDict()) finalizer(wp, clear!) wp end diff --git a/base/hashing.jl b/base/hashing.jl index e2847342a8c57..99b66d3fb6758 100644 --- a/base/hashing.jl +++ b/base/hashing.jl @@ -16,9 +16,8 @@ Typically, any type that implements `hash` should also implement its own `==` (h hash(x::Any) = hash(x, zero(UInt)) hash(w::WeakRef, h::UInt) = hash(w.value, h) -## hashing general objects ## - -hash(@nospecialize(x), h::UInt) = hash_uint(3h - object_id(x)) +# some types for which == and === are the same +hash(x::Union{Symbol,Slot,TypeName,Method,Module,Void,Core.IntrinsicFunction}, h::UInt) = hash_uint(3h - object_id(x)) ## core data hashing functions ## @@ -67,12 +66,13 @@ end ## symbol & expression hashing ## if UInt === UInt64 - hash(x::Expr, h::UInt) = hash(x.args, hash(x.head, h + 0x83c7900696d26dc6)) + hash(x::Expr, h::UInt) = hash(x.args, hash(x.head, h + 0x83c7900696d26dc6)) + hash(x::QuoteNode, h::UInt) = hash(x.value, h + 0x2c97bf8b3de87020) else - hash(x::Expr, h::UInt) = hash(x.args, hash(x.head, h + 0x96d26dc6)) + hash(x::Expr, h::UInt) = hash(x.args, hash(x.head, h + 0x96d26dc6)) + hash(x::QuoteNode, h::UInt) = hash(x.value, h + 0x469d72af) end -hash(x::QuoteNode, h::UInt) = hash(x.value, hash(QuoteNode, h)) # hashing ranges by component at worst leads to collisions for very similar ranges const hashr_seed = UInt === UInt64 ? 0x80707b6821b70087 : 0x21b70087 diff --git a/base/markdown/parse/config.jl b/base/markdown/parse/config.jl index 14d3a7aa77a07..5c92733661152 100644 --- a/base/markdown/parse/config.jl +++ b/base/markdown/parse/config.jl @@ -10,7 +10,7 @@ end Config() = Config(Function[], Function[], InnerConfig()) -const META = Dict{Function, Dict{Symbol, Any}}() +const META = ObjectIdDict() getset(coll, key, default) = coll[key] = get(coll, key, default) diff --git a/base/reflection.jl b/base/reflection.jl index 27a24eb540fd0..b87553848e17e 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -507,7 +507,7 @@ function instances end # subtypes function _subtypes(m::Module, x::Union{DataType,UnionAll}, - sts=Set{Union{DataType,UnionAll}}(), visited=Set{Module}()) + sts=ObjectIdDict(), visited=Set{Module}()) push!(visited, m) xt = unwrap_unionall(x) if !isa(xt, DataType) @@ -521,7 +521,7 @@ function _subtypes(m::Module, x::Union{DataType,UnionAll}, t = t::DataType if t.name.name === s && supertype(t).name == xt.name ti = typeintersect(t, x) - ti != Bottom && push!(sts, ti) + ti != Bottom && push!(sts, ti=>true) end elseif isa(t, UnionAll) t = t::UnionAll @@ -530,7 +530,7 @@ function _subtypes(m::Module, x::Union{DataType,UnionAll}, tt = tt::DataType if tt.name.name === s && supertype(tt).name == xt.name ti = typeintersect(t, x) - ti != Bottom && push!(sts, ti) + ti != Bottom && push!(sts, ti=>true) end elseif isa(t, Module) t = t::Module @@ -544,14 +544,14 @@ end function _subtypes_in(mods::Array, x::Union{DataType,UnionAll}) if !isabstract(x) # Fast path - return Union{DataType,UnionAll}[] + return Any[] end - sts = Set{Union{DataType,UnionAll}}() + sts = ObjectIdDict() visited = Set{Module}() for m in mods _subtypes(m, x, sts, visited) end - return sort!(collect(sts), by=string) + return sort!(collect(Any, keys(sts)), by=string) end subtypes(m::Module, x::Union{DataType,UnionAll}) = _subtypes_in([m], x) diff --git a/base/repl/LineEdit.jl b/base/repl/LineEdit.jl index 43e5b494ce77e..846ec67c45c29 100644 --- a/base/repl/LineEdit.jl +++ b/base/repl/LineEdit.jl @@ -45,7 +45,7 @@ mutable struct MIState interface::ModalInterface current_mode::TextInterface aborted::Bool - mode_state::Dict + mode_state::ObjectIdDict kill_ring::Vector{String} kill_idx::Int previous_key::Vector{Char} @@ -1949,7 +1949,7 @@ init_state(terminal, prompt::Prompt) = #=indent(spaces)=# -1, Threads.SpinLock(), 0.0) function init_state(terminal, m::ModalInterface) - s = MIState(m, m.modes[1], false, Dict{Any,Any}()) + s = MIState(m, m.modes[1], false, ObjectIdDict()) for mode in m.modes s.mode_state[mode] = init_state(terminal, mode) end diff --git a/base/show.jl b/base/show.jl index da6c84e11fa4f..2c6488983221d 100644 --- a/base/show.jl +++ b/base/show.jl @@ -738,7 +738,7 @@ function show_list(io::IO, items, sep, indent::Int, prec::Int=0, enclose_operato !first && print(io, sep) parens = !is_quoted(item) && (first && prec >= prec_power && - ((item isa Expr && item.head === :call && item.args[1] in uni_ops) || + ((item isa Expr && item.head === :call && item.args[1] isa Symbol && item.args[1] in uni_ops) || (item isa Real && item < 0))) || (enclose_operators && item isa Symbol && isoperator(item)) parens && print(io, '(') @@ -922,7 +922,7 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) func = args[1] fname = isa(func,GlobalRef) ? func.name : func func_prec = operator_precedence(fname) - if func_prec > 0 || fname in uni_ops + if func_prec > 0 || (fname isa Symbol && fname in uni_ops) func = fname end func_args = args[2:end] diff --git a/test/dict.jl b/test/dict.jl index 8c0f22e383592..06f41f4d55199 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -312,6 +312,7 @@ end mutable struct Alpha end Base.show(io::IO, ::Alpha) = print(io,"α") +Base.hash(a::Alpha, h::UInt) = xor(h, object_id(a)) @testset "issue #9463" begin sbuff = IOBuffer() io = Base.IOContext(sbuff, :limit => true, :displaysize => (10, 20))