Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/abstractinterpret/abstractanalyzer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,25 @@ struct AbstractBindingState
AbstractBindingState(isconst::Bool, maybeundef::Bool, @nospecialize typ) = new(isconst, maybeundef, typ)
AbstractBindingState(isconst::Bool, maybeundef::Bool) = new(isconst, maybeundef)
end
const AbstractBindings = IdDict{Core.BindingPartition,AbstractBindingState}

# `report_package` analyzes signatures concurrently while all task analyzers share a single
# `binding_states::AbstractBindings` (see `AnalyzerState`). Guard the underlying `IdDict` with
# a lock so concurrent `setindex!`/rehash cannot corrupt it; the accesses are infrequent
# (only on global binding assignments and binding-partition lookups), so the uncontended lock
# cost is negligible.
struct AbstractBindings
bindings::IdDict{Core.BindingPartition,AbstractBindingState}
lock::ReentrantLock
AbstractBindings() = new(IdDict{Core.BindingPartition,AbstractBindingState}(), ReentrantLock())
end
@inline Base.getindex(b::AbstractBindings, partition::Core.BindingPartition) =
@lock b.lock b.bindings[partition]
@inline Base.setindex!(b::AbstractBindings, binding_state::AbstractBindingState, partition::Core.BindingPartition) =
(@lock b.lock b.bindings[partition] = binding_state; return b)
@inline Base.haskey(b::AbstractBindings, partition::Core.BindingPartition) =
@lock b.lock haskey(b.bindings, partition)
@inline Base.get(b::AbstractBindings, partition::Core.BindingPartition, @nospecialize(default)) =
@lock b.lock get(b.bindings, partition, default)

"""
mutable struct AnalyzerState
Expand Down
25 changes: 14 additions & 11 deletions src/abstractinterpret/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -558,18 +558,21 @@ function const_assignment_rt_exct(analyzer::ToplevelAbstractAnalyzer, sv::Infere
if rt !== Union{}
# `:const` assignment destructively overrides the binding type
binding_states = get_binding_states(analyzer)
if !isconditional
binding_state = AbstractBindingState(true, false, new_binding_typ′[])
elseif haskey(binding_states, partition)
old_binding_state = binding_states[partition]
@assert old_binding_state.isconst && isdefined(old_binding_state, :typ)
newmaybeundef = old_binding_state.maybeundef & isconditional
newtyp = old_binding_state.typ ⊔ new_binding_typ′[]
binding_state = AbstractBindingState(true, newmaybeundef, newtyp)
else
binding_state = AbstractBindingState(true, true, new_binding_typ′[])
binding_state = @lock binding_states.lock begin
if !isconditional
new_state = AbstractBindingState(true, false, new_binding_typ′[])
elseif haskey(binding_states, partition)
old_binding_state = binding_states[partition]
@assert old_binding_state.isconst && isdefined(old_binding_state, :typ)
newmaybeundef = old_binding_state.maybeundef & isconditional
newtyp = old_binding_state.typ ⊔ new_binding_typ′[]
new_state = AbstractBindingState(true, newmaybeundef, newtyp)
else
new_state = AbstractBindingState(true, true, new_binding_typ′[])
end
binding_states[partition] = new_state
new_state
end
binding_states[partition] = binding_state
# HACK/FIXME Concretize `AbstractBindingState`
# For top-level analysis implementation reasons, we actually define this
# `AbstractBindingState` in the analyzed module’s namespace.
Expand Down
Loading