Skip to content

Commit e022ab2

Browse files
committed
effects: avoid UndefRefError error check when analyzing arrayset
This helps us prove `:nothrow`-ness of `arrayset` when bounds checking is turned off manually.
1 parent 1eee6ef commit e022ab2

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

base/compiler/tfuncs.jl

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,14 +1999,16 @@ function array_type_undefable(@nospecialize(arytype))
19991999
end
20002000
end
20012001

2002-
function array_builtin_common_nothrow(argtypes::Vector{Any}, first_idx_idx::Int)
2002+
function array_builtin_common_nothrow(argtypes::Vector{Any}, first_idx_idx::Int, isarrayref::Bool)
20032003
length(argtypes) >= 4 || return false
20042004
boundscheck = argtypes[1]
20052005
arytype = argtypes[2]
20062006
array_builtin_common_typecheck(boundscheck, arytype, argtypes, first_idx_idx) || return false
2007-
# If we could potentially throw undef ref errors, bail out now.
2008-
arytype = widenconst(arytype)
2009-
array_type_undefable(arytype) && return false
2007+
if isarrayref
2008+
# If we could potentially throw undef ref errors, bail out now.
2009+
arytype = widenconst(arytype)
2010+
array_type_undefable(arytype) && return false
2011+
end
20102012
# If we have @inbounds (first argument is false), we're allowed to assume
20112013
# we don't throw bounds errors.
20122014
if isa(boundscheck, Const)
@@ -2042,11 +2044,11 @@ end
20422044
@nospecs function _builtin_nothrow(𝕃::AbstractLattice, f, argtypes::Vector{Any}, rt)
20432045
= Core.Compiler.:(𝕃)
20442046
if f === arrayset
2045-
array_builtin_common_nothrow(argtypes, 4) || return false
2047+
array_builtin_common_nothrow(argtypes, 4, #=isarrayref=#false) || return false
20462048
# Additionally check element type compatibility
20472049
return arrayset_typecheck(argtypes[2], argtypes[3])
20482050
elseif f === arrayref || f === const_arrayref
2049-
return array_builtin_common_nothrow(argtypes, 3)
2051+
return array_builtin_common_nothrow(argtypes, 3, #=isarrayref=#true)
20502052
elseif f === Core._expr
20512053
length(argtypes) >= 1 || return false
20522054
return argtypes[1] Symbol

test/compiler/effects.jl

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,9 +455,19 @@ let effects = Base.infer_effects(f_setfield_nothrow, ())
455455
end
456456

457457
# nothrow for arrayset
458-
@test Base.infer_effects((Vector{Int},Int)) do a, i
459-
a[i] = 0 # may throw
458+
@test Base.infer_effects((Vector{Int},Int,Int)) do a, v, i
459+
Base.arrayset(true, a, v, i)
460460
end |> !Core.Compiler.is_nothrow
461+
@test Base.infer_effects((Vector{Int},Int,Int)) do a, v, i
462+
a[i] = v # may throw
463+
end |> !Core.Compiler.is_nothrow
464+
# when bounds checking is turned off, it should be safe
465+
@test Base.infer_effects((Vector{Int},Int,Int)) do a, v, i
466+
Base.arrayset(false, a, v, i)
467+
end |> Core.Compiler.is_nothrow
468+
@test Base.infer_effects((Vector{Number},Number,Int)) do a, v, i
469+
Base.arrayset(false, a, v, i)
470+
end |> Core.Compiler.is_nothrow
461471

462472
# even if 2-arg `getfield` may throw, it should be still `:consistent`
463473
@test Core.Compiler.is_consistent(Base.infer_effects(getfield, (NTuple{5, Float64}, Int)))

0 commit comments

Comments
 (0)