@@ -85,9 +85,12 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
85
85
push! (edges, edge)
86
86
end
87
87
this_argtypes = isa (matches, MethodMatches) ? argtypes : matches. applicable_argtypes[i]
88
- const_rt, const_result = abstract_call_method_with_const_args (interp, result, f, this_argtypes, match, sv, false )
89
- if const_rt != = rt && const_rt ⊑ rt
90
- rt = const_rt
88
+ const_result = abstract_call_method_with_const_args (interp, result, f, this_argtypes, match, sv, false )
89
+ if const_result != = nothing
90
+ const_rt, const_result = const_result
91
+ if const_rt != = rt && const_rt ⊑ rt
92
+ rt = const_rt
93
+ end
91
94
end
92
95
push! (const_results, const_result)
93
96
if const_result != = nothing
@@ -107,9 +110,12 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
107
110
# try constant propagation with argtypes for this match
108
111
# this is in preparation for inlining, or improving the return result
109
112
this_argtypes = isa (matches, MethodMatches) ? argtypes : matches. applicable_argtypes[i]
110
- const_this_rt, const_result = abstract_call_method_with_const_args (interp, result, f, this_argtypes, match, sv, false )
111
- if const_this_rt != = this_rt && const_this_rt ⊑ this_rt
112
- this_rt = const_this_rt
113
+ const_result = abstract_call_method_with_const_args (interp, result, f, this_argtypes, match, sv, false )
114
+ if const_result != = nothing
115
+ const_this_rt, const_result = const_result
116
+ if const_this_rt != = this_rt && const_this_rt ⊑ this_rt
117
+ this_rt = const_this_rt
118
+ end
113
119
end
114
120
push! (const_results, const_result)
115
121
if const_result != = nothing
@@ -523,33 +529,35 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, resul
523
529
@nospecialize (f), argtypes:: Vector{Any} , match:: MethodMatch ,
524
530
sv:: InferenceState , va_override:: Bool )
525
531
mi = maybe_get_const_prop_profitable (interp, result, f, argtypes, match, sv)
526
- mi === nothing && return Any, nothing
532
+ mi === nothing && return nothing
527
533
# try constant prop'
528
534
inf_cache = get_inference_cache (interp)
529
535
inf_result = cache_lookup (mi, argtypes, inf_cache)
530
536
if inf_result === nothing
531
537
# if there might be a cycle, check to make sure we don't end up
532
538
# calling ourselves here.
533
- if result. edgecycle && _any (InfStackUnwind (sv)) do infstate
534
- # if the type complexity limiting didn't decide to limit the call signature (`result.edgelimited = false`)
535
- # we can relax the cycle detection by comparing `MethodInstance`s and allow inference to
536
- # propagate different constant elements if the recursion is finite over the lattice
537
- return (result. edgelimited ? match. method === infstate. linfo. def : mi === infstate. linfo) &&
538
- any (infstate. result. overridden_by_const)
539
+ let result = result # prevent capturing
540
+ if result. edgecycle && _any (InfStackUnwind (sv)) do infstate
541
+ # if the type complexity limiting didn't decide to limit the call signature (`result.edgelimited = false`)
542
+ # we can relax the cycle detection by comparing `MethodInstance`s and allow inference to
543
+ # propagate different constant elements if the recursion is finite over the lattice
544
+ return (result. edgelimited ? match. method === infstate. linfo. def : mi === infstate. linfo) &&
545
+ any (infstate. result. overridden_by_const)
546
+ end
547
+ add_remark! (interp, sv, " [constprop] Edge cycle encountered" )
548
+ return nothing
539
549
end
540
- add_remark! (interp, sv, " [constprop] Edge cycle encountered" )
541
- return Any, nothing
542
550
end
543
551
inf_result = InferenceResult (mi, argtypes, va_override)
544
552
frame = InferenceState (inf_result, #= cache=# false , interp)
545
- frame === nothing && return Any, nothing # this is probably a bad generated function (unsound), but just ignore it
553
+ frame === nothing && return nothing # this is probably a bad generated function (unsound), but just ignore it
546
554
frame. parent = sv
547
555
push! (inf_cache, inf_result)
548
- typeinf (interp, frame) || return Any, nothing
556
+ typeinf (interp, frame) || return nothing
549
557
end
550
558
result = inf_result. result
551
559
# if constant inference hits a cycle, just bail out
552
- isa (result, InferenceState) && return Any, nothing
560
+ isa (result, InferenceState) && return nothing
553
561
add_backedge! (mi, sv)
554
562
return result, inf_result
555
563
end
@@ -1174,7 +1182,8 @@ function abstract_invoke(interp::AbstractInterpreter, argtypes::Vector{Any}, sv:
1174
1182
nargtype === Bottom && return CallMeta (Bottom, false )
1175
1183
nargtype isa DataType || return CallMeta (Any, false ) # other cases are not implemented below
1176
1184
isdispatchelem (ft) || return CallMeta (Any, false ) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
1177
- types = rewrap_unionall (Tuple{ft, unwrap_unionall (types). parameters... }, types)
1185
+ ft = ft:: DataType
1186
+ types = rewrap_unionall (Tuple{ft, unwrap_unionall (types). parameters... }, types):: Type
1178
1187
nargtype = Tuple{ft, nargtype. parameters... }
1179
1188
argtype = Tuple{ft, argtype. parameters... }
1180
1189
result = findsup (types, method_table (interp))
@@ -1196,12 +1205,14 @@ function abstract_invoke(interp::AbstractInterpreter, argtypes::Vector{Any}, sv:
1196
1205
# t, a = ti.parameters[i], argtypes′[i]
1197
1206
# argtypes′[i] = t ⊑ a ? t : a
1198
1207
# end
1199
- const_rt, const_result = abstract_call_method_with_const_args (interp, result, argtype_to_function (ft′), argtypes′, match, sv, false )
1200
- if const_rt != = rt && const_rt ⊑ rt
1201
- return CallMeta (const_rt, InvokeCallInfo (match, const_result))
1202
- else
1203
- return CallMeta (rt, InvokeCallInfo (match, nothing ))
1208
+ const_result = abstract_call_method_with_const_args (interp, result, argtype_to_function (ft′), argtypes′, match, sv, false )
1209
+ if const_result != = nothing
1210
+ const_rt, const_result = const_result
1211
+ if const_rt != = rt && const_rt ⊑ rt
1212
+ return CallMeta (const_rt, InvokeCallInfo (match, const_result))
1213
+ end
1204
1214
end
1215
+ return CallMeta (rt, InvokeCallInfo (match, nothing ))
1205
1216
end
1206
1217
1207
1218
# call where the function is known exactly
@@ -1301,19 +1312,20 @@ end
1301
1312
function abstract_call_opaque_closure (interp:: AbstractInterpreter , closure:: PartialOpaque , argtypes:: Vector{Any} , sv:: InferenceState )
1302
1313
pushfirst! (argtypes, closure. env)
1303
1314
sig = argtypes_to_type (argtypes)
1304
- (; rt, edge) = result = abstract_call_method (interp, closure. source:: Method , sig, Core. svec (), false , sv)
1315
+ (; rt, edge) = result = abstract_call_method (interp, closure. source, sig, Core. svec (), false , sv)
1305
1316
edge != = nothing && add_backedge! (edge, sv)
1306
1317
tt = closure. typ
1307
- sigT = unwrap_unionall (tt). parameters[1 ]
1308
- match = MethodMatch (sig, Core. svec (), closure. source:: Method , sig <: rewrap_unionall (sigT, tt))
1318
+ sigT = ( unwrap_unionall (tt) :: DataType ). parameters[1 ]
1319
+ match = MethodMatch (sig, Core. svec (), closure. source, sig <: rewrap_unionall (sigT, tt))
1309
1320
info = OpaqueClosureCallInfo (match)
1310
1321
if ! result. edgecycle
1311
- const_rettype, const_result = abstract_call_method_with_const_args (interp, result, closure, argtypes,
1322
+ const_result = abstract_call_method_with_const_args (interp, result, closure, argtypes,
1312
1323
match, sv, closure. isva)
1313
- if const_rettype ⊑ rt
1314
- rt = const_rettype
1315
- end
1316
1324
if const_result != = nothing
1325
+ const_rettype, const_result = const_result
1326
+ if const_rettype ⊑ rt
1327
+ rt = const_rettype
1328
+ end
1317
1329
info = ConstCallInfo (info, Union{Nothing,InferenceResult}[const_result])
1318
1330
end
1319
1331
end
@@ -1323,7 +1335,7 @@ end
1323
1335
function most_general_argtypes (closure:: PartialOpaque )
1324
1336
ret = Any[]
1325
1337
cc = widenconst (closure)
1326
- argt = unwrap_unionall (cc). parameters[1 ]
1338
+ argt = ( unwrap_unionall (cc) :: DataType ). parameters[1 ]
1327
1339
if ! isa (argt, DataType) || argt. name != = typename (Tuple)
1328
1340
argt = Tuple
1329
1341
end
@@ -1338,8 +1350,8 @@ function abstract_call(interp::AbstractInterpreter, fargs::Union{Nothing,Vector{
1338
1350
f = argtype_to_function (ft)
1339
1351
if isa (ft, PartialOpaque)
1340
1352
return abstract_call_opaque_closure (interp, ft, argtypes[2 : end ], sv)
1341
- elseif isa ( unwrap_unionall (ft), DataType) && unwrap_unionall (ft) . name === typename (Core. OpaqueClosure)
1342
- return CallMeta (rewrap_unionall (unwrap_unionall (ft ). parameters[2 ], ft), false )
1353
+ elseif (uft = unwrap_unionall (ft); isa (uft , DataType) && uft . name === typename (Core. OpaqueClosure) )
1354
+ return CallMeta (rewrap_unionall ((uft :: DataType ). parameters[2 ], ft), false )
1343
1355
elseif f === nothing
1344
1356
# non-constant function, but the number of arguments is known
1345
1357
# and the ft is not a Builtin or IntrinsicFunction
@@ -1534,12 +1546,12 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
1534
1546
if length (e. args) == 2 && isconcretetype (t) && ! ismutabletype (t)
1535
1547
at = abstract_eval_value (interp, e. args[2 ], vtypes, sv)
1536
1548
n = fieldcount (t)
1537
- if isa (at, Const) && isa (at. val, Tuple) && n == length (at. val) &&
1538
- let t = t; _all (i-> getfield (at. val, i) isa fieldtype (t, i), 1 : n); end
1549
+ if isa (at, Const) && isa (at. val, Tuple) && n == length (at. val:: Tuple ) &&
1550
+ let t = t; _all (i-> getfield (at. val:: Tuple , i) isa fieldtype (t, i), 1 : n); end
1539
1551
t = Const (ccall (:jl_new_structt , Any, (Any, Any), t, at. val))
1540
- elseif isa (at, PartialStruct) && at ⊑ Tuple && n == length (at. fields) &&
1541
- let t = t, at = at; _all (i-> at. fields[i] ⊑ fieldtype (t, i), 1 : n); end
1542
- t = PartialStruct (t, at. fields)
1552
+ elseif isa (at, PartialStruct) && at ⊑ Tuple && n == length (at. fields:: Vector{Any} ) &&
1553
+ let t = t, at = at; _all (i-> ( at. fields:: Vector{Any} ) [i] ⊑ fieldtype (t, i), 1 : n); end
1554
+ t = PartialStruct (t, at. fields:: Vector{Any} )
1543
1555
end
1544
1556
end
1545
1557
elseif e. head === :new_opaque_closure
@@ -1587,7 +1599,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
1587
1599
sym = e. args[1 ]
1588
1600
t = Bool
1589
1601
if isa (sym, SlotNumber)
1590
- vtyp = vtypes[slot_id (sym)]
1602
+ vtyp = vtypes[slot_id (sym)]:: VarState
1591
1603
if vtyp. typ === Bottom
1592
1604
t = Const (false ) # never assigned previously
1593
1605
elseif ! vtyp. undef
@@ -1602,7 +1614,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
1602
1614
t = Const (true )
1603
1615
end
1604
1616
elseif isa (sym, Expr) && sym. head === :static_parameter
1605
- n = sym. args[1 ]
1617
+ n = sym. args[1 ]:: Int
1606
1618
if 1 <= n <= length (sv. sptypes)
1607
1619
spty = sv. sptypes[n]
1608
1620
if isa (spty, Const)
@@ -1637,7 +1649,7 @@ function abstract_eval_global(M::Module, s::Symbol)
1637
1649
end
1638
1650
1639
1651
function abstract_eval_ssavalue (s:: SSAValue , src:: CodeInfo )
1640
- typ = src. ssavaluetypes[s. id]
1652
+ typ = ( src. ssavaluetypes:: Vector{Any} ) [s. id]
1641
1653
if typ === NOT_FOUND
1642
1654
return Bottom
1643
1655
end
@@ -1725,6 +1737,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1725
1737
isva = isa (def, Method) && def. isva
1726
1738
nslots = nargs - isva
1727
1739
slottypes = frame. slottypes
1740
+ ssavaluetypes = frame. src. ssavaluetypes:: Vector{Any}
1728
1741
while frame. pc´´ <= n
1729
1742
# make progress on the active ip set
1730
1743
local pc:: Int = frame. pc´´ # current program-counter
@@ -1828,7 +1841,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1828
1841
for (caller, caller_pc) in frame. cycle_backedges
1829
1842
# notify backedges of updated type information
1830
1843
typeassert (caller. stmt_types[caller_pc], VarTable) # we must have visited this statement before
1831
- if ! (caller. src. ssavaluetypes[caller_pc] === Any)
1844
+ if ! (( caller. src. ssavaluetypes:: Vector{Any} ) [caller_pc] === Any)
1832
1845
# no reason to revisit if that call-site doesn't affect the final result
1833
1846
if caller_pc < caller. pc´´
1834
1847
caller. pc´´ = caller_pc
@@ -1838,6 +1851,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1838
1851
end
1839
1852
end
1840
1853
elseif hd === :enter
1854
+ stmt = stmt:: Expr
1841
1855
l = stmt. args[1 ]:: Int
1842
1856
frame. cur_hand = Pair {Any,Any} (l, frame. cur_hand)
1843
1857
# propagate type info to exception handler
@@ -1853,21 +1867,24 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1853
1867
typeassert (states[l], VarTable)
1854
1868
frame. handler_at[l] = frame. cur_hand
1855
1869
elseif hd === :leave
1870
+ stmt = stmt:: Expr
1856
1871
for i = 1 : ((stmt. args[1 ]):: Int )
1857
1872
frame. cur_hand = (frame. cur_hand:: Pair{Any,Any} ). second
1858
1873
end
1859
1874
else
1860
1875
if hd === :(= )
1876
+ stmt = stmt:: Expr
1861
1877
t = abstract_eval_statement (interp, stmt. args[2 ], changes, frame)
1862
1878
if t === Bottom
1863
1879
break
1864
1880
end
1865
- frame . src . ssavaluetypes[pc] = t
1881
+ ssavaluetypes[pc] = t
1866
1882
lhs = stmt. args[1 ]
1867
1883
if isa (lhs, SlotNumber)
1868
1884
changes = StateUpdate (lhs, VarState (t, false ), changes, false )
1869
1885
end
1870
1886
elseif hd === :method
1887
+ stmt = stmt:: Expr
1871
1888
fname = stmt. args[1 ]
1872
1889
if isa (fname, SlotNumber)
1873
1890
changes = StateUpdate (fname, VarState (Any, false ), changes, false )
@@ -1882,7 +1899,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1882
1899
if ! isempty (frame. ssavalue_uses[pc])
1883
1900
record_ssa_assign (pc, t, frame)
1884
1901
else
1885
- frame . src . ssavaluetypes[pc] = t
1902
+ ssavaluetypes[pc] = t
1886
1903
end
1887
1904
end
1888
1905
if frame. cur_hand != = nothing && isa (changes, StateUpdate)
@@ -1903,7 +1920,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1903
1920
1904
1921
if t === nothing
1905
1922
# mark other reached expressions as `Any` to indicate they don't throw
1906
- frame . src . ssavaluetypes[pc] = Any
1923
+ ssavaluetypes[pc] = Any
1907
1924
end
1908
1925
1909
1926
pc´ > n && break # can't proceed with the fast-path fall-through
0 commit comments