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
179 changes: 109 additions & 70 deletions Compiler/src/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2426,11 +2426,15 @@ function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, s
end

function abstract_eval_getglobal(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
if length(argtypes) == 3
return abstract_eval_getglobal(interp, sv, saw_latestworld, argtypes[2], argtypes[3])
elseif length(argtypes) == 4
return abstract_eval_getglobal(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
elseif !isvarargtype(argtypes[end]) || length(argtypes) > 5
if !isvarargtype(argtypes[end])
if length(argtypes) == 3
return abstract_eval_getglobal(interp, sv, saw_latestworld, argtypes[2], argtypes[3])
elseif length(argtypes) == 4
return abstract_eval_getglobal(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
else
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
end
elseif length(argtypes) > 5
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
else
return CallMeta(Any, generic_getglobal_exct, generic_getglobal_effects, NoCallInfo())
Expand Down Expand Up @@ -2471,12 +2475,17 @@ end
end

function abstract_eval_get_binding_type(interp::AbstractInterpreter, sv::AbsIntState, argtypes::Vector{Any})
if length(argtypes) == 3
return abstract_eval_get_binding_type(interp, sv, argtypes[2], argtypes[3])
elseif !isvarargtype(argtypes[end]) || length(argtypes) > 4
if !isvarargtype(argtypes[end])
if length(argtypes) == 3
return abstract_eval_get_binding_type(interp, sv, argtypes[2], argtypes[3])
else
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
end
elseif length(argtypes) > 4
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
else
return CallMeta(Type, Union{TypeError, ArgumentError}, EFFECTS_THROWS, NoCallInfo())
end
return CallMeta(Type, Union{TypeError, ArgumentError}, EFFECTS_THROWS, NoCallInfo())
end

const setglobal!_effects = Effects(EFFECTS_TOTAL; effect_free=ALWAYS_FALSE, nothrow=false, inaccessiblememonly=ALWAYS_FALSE)
Expand Down Expand Up @@ -2509,11 +2518,15 @@ end
const generic_setglobal!_exct = Union{ArgumentError, TypeError, ErrorException, ConcurrencyViolationError}

function abstract_eval_setglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
if length(argtypes) == 4
return abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
elseif length(argtypes) == 5
return abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4], argtypes[5])
elseif !isvarargtype(argtypes[end]) || length(argtypes) > 6
if !isvarargtype(argtypes[end])
if length(argtypes) == 4
return abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
elseif length(argtypes) == 5
return abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4], argtypes[5])
else
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
end
elseif length(argtypes) > 6
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
else
return CallMeta(Any, generic_setglobal!_exct, setglobal!_effects, NoCallInfo())
Expand All @@ -2537,75 +2550,87 @@ function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState,
end

function abstract_eval_swapglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
if length(argtypes) == 4
return abstract_eval_swapglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
elseif length(argtypes) == 5
return abstract_eval_swapglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4], argtypes[5])
elseif !isvarargtype(argtypes[end]) || length(argtypes) > 6
if !isvarargtype(argtypes[end])
if length(argtypes) == 4
return abstract_eval_swapglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
elseif length(argtypes) == 5
return abstract_eval_swapglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4], argtypes[5])
else
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
end
elseif length(argtypes) > 6
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
else
return CallMeta(Any, Union{generic_getglobal_exct,generic_setglobal!_exct}, setglobal!_effects, NoCallInfo())
end
end

function abstract_eval_setglobalonce!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
if length(argtypes) in (4, 5, 6)
cm = abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
if length(argtypes) >= 5
goe = global_order_exct(argtypes[5], #=loading=#true, #=storing=#true)
cm = merge_exct(cm, goe)
end
if length(argtypes) == 6
goe = global_order_exct(argtypes[6], #=loading=#true, #=storing=#false)
cm = merge_exct(cm, goe)
end
return CallMeta(Bool, cm.exct, cm.effects, cm.info)
elseif !isvarargtype(argtypes[end]) || length(argtypes) > 6
if !isvarargtype(argtypes[end])
if length(argtypes) in (4, 5, 6)
cm = abstract_eval_setglobal!(interp, sv, saw_latestworld, argtypes[2], argtypes[3], argtypes[4])
if length(argtypes) >= 5
goe = global_order_exct(argtypes[5], #=loading=#true, #=storing=#true)
cm = merge_exct(cm, goe)
end
if length(argtypes) == 6
goe = global_order_exct(argtypes[6], #=loading=#true, #=storing=#false)
cm = merge_exct(cm, goe)
end
return CallMeta(Bool, cm.exct, cm.effects, cm.info)
else
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
end
elseif length(argtypes) > 7
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
else
return CallMeta(Bool, generic_setglobal!_exct, setglobal!_effects, NoCallInfo())
end
end

function abstract_eval_replaceglobal!(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
if length(argtypes) in (5, 6, 7)
(M, s, x, v) = argtypes[2], argtypes[3], argtypes[4], argtypes[5]
T = nothing
if isa(M, Const) && isa(s, Const)
M, s = M.val, s.val
M isa Module || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
s isa Symbol || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
gr = GlobalRef(M, s)
v′ = RefValue{Any}(v)
(valid_worlds, (rte, T)) = scan_leaf_partitions(interp, gr, sv.world) do interp::AbstractInterpreter, binding::Core.Binding, partition::Core.BindingPartition
partition_T = nothing
partition_rte = abstract_eval_partition_load(interp, binding, partition)
if binding_kind(partition) == PARTITION_KIND_GLOBAL
partition_T = partition_restriction(partition)
if !isvarargtype(argtypes[end])
if length(argtypes) in (5, 6, 7)
(M, s, x, v) = argtypes[2], argtypes[3], argtypes[4], argtypes[5]
T = nothing
if isa(M, Const) && isa(s, Const)
M, s = M.val, s.val
M isa Module || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
s isa Symbol || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
gr = GlobalRef(M, s)
v′ = RefValue{Any}(v)
(valid_worlds, (rte, T)) = scan_leaf_partitions(interp, gr, sv.world) do interp::AbstractInterpreter, binding::Core.Binding, partition::Core.BindingPartition
partition_T = nothing
partition_rte = abstract_eval_partition_load(interp, binding, partition)
if binding_kind(partition) == PARTITION_KIND_GLOBAL
partition_T = partition_restriction(partition)
end
partition_exct = Union{partition_rte.exct, global_assignment_binding_rt_exct(interp, partition, v′[])[2]}
partition_rte = RTEffects(partition_rte.rt, partition_exct, partition_rte.effects)
Pair{RTEffects, Any}(partition_rte, partition_T)
end
partition_exct = Union{partition_rte.exct, global_assignment_binding_rt_exct(interp, partition, v′[])[2]}
partition_rte = RTEffects(partition_rte.rt, partition_exct, partition_rte.effects)
Pair{RTEffects, Any}(partition_rte, partition_T)
update_valid_age!(sv, valid_worlds)
effects = merge_effects(rte.effects, Effects(setglobal!_effects, nothrow=rte.exct===Bottom))
sg = CallMeta(Any, rte.exct, effects, GlobalAccessInfo(convert(Core.Binding, gr)))
else
sg = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v)
end
if length(argtypes) >= 6
goe = global_order_exct(argtypes[6], #=loading=#true, #=storing=#true)
sg = merge_exct(sg, goe)
end
if length(argtypes) == 7
goe = global_order_exct(argtypes[7], #=loading=#true, #=storing=#false)
sg = merge_exct(sg, goe)
end
update_valid_age!(sv, valid_worlds)
effects = merge_effects(rte.effects, Effects(setglobal!_effects, nothrow=rte.exct===Bottom))
sg = CallMeta(Any, rte.exct, effects, GlobalAccessInfo(convert(Core.Binding, gr)))
rt = T === nothing ?
ccall(:jl_apply_cmpswap_type, Any, (Any,), S) where S :
ccall(:jl_apply_cmpswap_type, Any, (Any,), T)
return CallMeta(rt, sg.exct, sg.effects, sg.info)
else
sg = abstract_eval_setglobal!(interp, sv, saw_latestworld, M, s, v)
end
if length(argtypes) >= 6
goe = global_order_exct(argtypes[6], #=loading=#true, #=storing=#true)
sg = merge_exct(sg, goe)
end
if length(argtypes) == 7
goe = global_order_exct(argtypes[7], #=loading=#true, #=storing=#false)
sg = merge_exct(sg, goe)
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
end
rt = T === nothing ?
ccall(:jl_apply_cmpswap_type, Any, (Any,), S) where S :
ccall(:jl_apply_cmpswap_type, Any, (Any,), T)
return CallMeta(rt, sg.exct, sg.effects, sg.info)
elseif !isvarargtype(argtypes[end]) || length(argtypes) > 8
elseif length(argtypes) > 8
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
else
return CallMeta(Any, Union{generic_getglobal_exct,generic_setglobal!_exct}, setglobal!_effects, NoCallInfo())
Expand Down Expand Up @@ -2662,11 +2687,8 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
return Future(abstract_eval_isdefinedglobal(interp, argtypes[2], argtypes[3], Const(true),
length(argtypes) == 4 ? argtypes[4] : Const(:unordered),
si.saw_latestworld, sv))
elseif f === Core.isdefinedglobal && 3 <= length(argtypes) <= 5
return Future(abstract_eval_isdefinedglobal(interp, argtypes[2], argtypes[3],
length(argtypes) >= 4 ? argtypes[4] : Const(true),
length(argtypes) >= 5 ? argtypes[5] : Const(:unordered),
si.saw_latestworld, sv))
elseif f === Core.isdefinedglobal
return Future(abstract_eval_isdefinedglobal(interp, sv, si.saw_latestworld, argtypes))
elseif f === Core.get_binding_type
return Future(abstract_eval_get_binding_type(interp, sv, argtypes))
end
Expand Down Expand Up @@ -3347,6 +3369,23 @@ function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, @nospecializ
return CallMeta(Bool, Union{exct, TypeError, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo())
end

function abstract_eval_isdefinedglobal(interp::AbstractInterpreter, sv::AbsIntState, saw_latestworld::Bool, argtypes::Vector{Any})
if !isvarargtype(argtypes[end])
if 3 <= length(argtypes) <= 5
return abstract_eval_isdefinedglobal(interp, argtypes[2], argtypes[3],
length(argtypes) >= 4 ? argtypes[4] : Const(true),
length(argtypes) >= 5 ? argtypes[5] : Const(:unordered),
saw_latestworld, sv)
else
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
end
elseif length(argtypes) > 6
return CallMeta(Union{}, ArgumentError, EFFECTS_THROWS, NoCallInfo())
else
return CallMeta(Bool, Union{ConcurrencyViolationError, TypeError, UndefVarError}, generic_isdefinedglobal_effects, NoCallInfo())
end
end

function abstract_eval_throw_undef_if_not(interp::AbstractInterpreter, e::Expr, sstate::StatementState, sv::AbsIntState)
condt = abstract_eval_value(interp, e.args[2], sstate, sv)
condval = maybe_extract_const_bool(condt)
Expand Down
13 changes: 13 additions & 0 deletions Compiler/test/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6486,4 +6486,17 @@ function ss57873(a::Vector{String}, pref)
end
@test ss57873(["a", "b", "c"], ("",)) == String[]

@test Base.infer_return_type((Module,Symbol,Vector{Any})) do m, n, xs
getglobal(m, n, xs...)
end <: Any
@test Base.infer_return_type((Module,Symbol,Any,Vector{Any})) do m, n, v, xs
setglobal!(m, n, v, xs...)
end <: Any
@test Base.infer_return_type((Module,Symbol,Vector{Any})) do m, n, xs
isdefinedglobal(m, n, xs...)
end <: Bool
@test Base.infer_return_type((Module,Symbol,Vector{Any})) do m, n, xs
Core.get_binding_type(m, n, xs...)
end <: Type

end # module inference