@@ -937,7 +937,7 @@ function getfield_boundscheck((; fargs, argtypes)::ArgInfo) # Symbol
937
937
return :unknown
938
938
end
939
939
940
- function getfield_nothrow (arginfo:: ArgInfo , boundscheck:: Symbol = getfield_boundscheck (arginfo))
940
+ function getfield_nothrow (𝕃 :: AbstractLattice , arginfo:: ArgInfo , boundscheck:: Symbol = getfield_boundscheck (arginfo))
941
941
(;argtypes) = arginfo
942
942
boundscheck === :unknown && return false
943
943
ordering = Const (:not_atomic )
@@ -958,17 +958,19 @@ function getfield_nothrow(arginfo::ArgInfo, boundscheck::Symbol=getfield_boundsc
958
958
if ordering != = :not_atomic # TODO : this is assuming not atomic
959
959
return false
960
960
end
961
- return getfield_nothrow (argtypes[2 ], argtypes[3 ], ! (boundscheck === :off ))
961
+ return getfield_nothrow (𝕃, argtypes[2 ], argtypes[3 ], ! (boundscheck === :off ))
962
962
else
963
963
return false
964
964
end
965
965
end
966
- @nospecs function getfield_nothrow (s00, name, boundscheck:: Bool )
966
+ @nospecs function getfield_nothrow (𝕃 :: AbstractLattice , s00, name, boundscheck:: Bool )
967
967
# If we don't have boundscheck off and don't know the field, don't even bother
968
968
if boundscheck
969
969
isa (name, Const) || return false
970
970
end
971
971
972
+ ⊑ = Core. Compiler.:⊑ (𝕃)
973
+
972
974
# If we have s00 being a const, we can potentially refine our type-based analysis above
973
975
if isa (s00, Const) || isconstType (s00)
974
976
if ! isa (s00, Const)
@@ -984,31 +986,32 @@ end
984
986
end
985
987
return isdefined (sv, nval)
986
988
end
987
- if ! boundscheck && ! isa (sv, Module)
988
- # If bounds checking is disabled and all fields are assigned,
989
- # we may assume that we don't throw
990
- for i = 1 : fieldcount ( typeof (sv))
991
- isdefined (sv, i) || return false
992
- end
993
- return true
989
+ boundscheck && return false
990
+ # If bounds checking is disabled and all fields are assigned,
991
+ # we may assume that we don't throw
992
+ isa (sv, Module) && return false
993
+ name ⊑ Int || name ⊑ Symbol || return false
994
+ for i = 1 : fieldcount ( typeof (sv))
995
+ isdefined (sv, i) || return false
994
996
end
995
- return false
997
+ return true
996
998
end
997
999
998
1000
s0 = widenconst (s00)
999
1001
s = unwrap_unionall (s0)
1000
1002
if isa (s, Union)
1001
- return getfield_nothrow (rewrap_unionall (s. a, s00), name, boundscheck) &&
1002
- getfield_nothrow (rewrap_unionall (s. b, s00), name, boundscheck)
1003
+ return getfield_nothrow (𝕃, rewrap_unionall (s. a, s00), name, boundscheck) &&
1004
+ getfield_nothrow (𝕃, rewrap_unionall (s. b, s00), name, boundscheck)
1003
1005
elseif isType (s) && isTypeDataType (s. parameters[1 ])
1004
1006
s = s0 = DataType
1005
1007
end
1006
1008
if isa (s, DataType)
1007
1009
# Can't say anything about abstract types
1008
1010
isabstracttype (s) && return false
1009
- # If all fields are always initialized, and bounds check is disabled, we can assume
1010
- # we don't throw
1011
+ # If all fields are always initialized, and bounds check is disabled,
1012
+ # we can assume we don't throw
1011
1013
if ! boundscheck && s. name. n_uninitialized == 0
1014
+ name ⊑ Int || name ⊑ Symbol || return false
1012
1015
return true
1013
1016
end
1014
1017
# Else we need to know what the field is
@@ -2012,7 +2015,7 @@ function array_builtin_common_nothrow(argtypes::Vector{Any}, first_idx_idx::Int,
2012
2015
# If we have @inbounds (first argument is false), we're allowed to assume
2013
2016
# we don't throw bounds errors.
2014
2017
if isa (boundscheck, Const)
2015
- ! ( boundscheck. val:: Bool ) && return true
2018
+ boundscheck. val:: Bool || return true
2016
2019
end
2017
2020
# Else we can't really say anything here
2018
2021
# TODO : In the future we may be able to track the shapes of arrays though
@@ -2067,7 +2070,7 @@ end
2067
2070
elseif f === invoke
2068
2071
return false
2069
2072
elseif f === getfield
2070
- return getfield_nothrow (ArgInfo (nothing , Any[Const (f), argtypes... ]))
2073
+ return getfield_nothrow (𝕃, ArgInfo (nothing , Any[Const (f), argtypes... ]))
2071
2074
elseif f === setfield!
2072
2075
if na == 3
2073
2076
return setfield!_nothrow (𝕃, argtypes[1 ], argtypes[2 ], argtypes[3 ])
@@ -2224,7 +2227,7 @@ function isdefined_effects(𝕃::AbstractLattice, argtypes::Vector{Any})
2224
2227
return Effects (EFFECTS_TOTAL; consistent, nothrow)
2225
2228
end
2226
2229
2227
- function getfield_effects (arginfo:: ArgInfo , @nospecialize (rt))
2230
+ function getfield_effects (𝕃 :: AbstractLattice , arginfo:: ArgInfo , @nospecialize (rt))
2228
2231
(;argtypes) = arginfo
2229
2232
# consistent if the argtype is immutable
2230
2233
length (argtypes) < 3 && return EFFECTS_THROWS
@@ -2240,9 +2243,9 @@ function getfield_effects(arginfo::ArgInfo, @nospecialize(rt))
2240
2243
if ! (length (argtypes) ≥ 3 && getfield_notundefined (obj, argtypes[3 ]))
2241
2244
consistent = ALWAYS_FALSE
2242
2245
end
2243
- nothrow = getfield_nothrow (arginfo, :on )
2246
+ bcheck = getfield_boundscheck (arginfo)
2247
+ nothrow = getfield_nothrow (𝕃, arginfo, bcheck)
2244
2248
if ! nothrow
2245
- bcheck = getfield_boundscheck (arginfo)
2246
2249
if ! (bcheck === :on || bcheck === :boundscheck )
2247
2250
# If we cannot independently prove inboundsness, taint consistency.
2248
2251
# The inbounds-ness assertion requires dynamic reachability, while
@@ -2293,7 +2296,7 @@ function builtin_effects(𝕃::AbstractLattice, @nospecialize(f::Builtin), argin
2293
2296
@assert ! contains_is (_SPECIAL_BUILTINS, f)
2294
2297
2295
2298
if f === getfield
2296
- return getfield_effects (arginfo, rt)
2299
+ return getfield_effects (𝕃, arginfo, rt)
2297
2300
end
2298
2301
argtypes = arginfo. argtypes[2 : end ]
2299
2302
0 commit comments