@@ -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
@@ -520,33 +526,35 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, resul
520
526
@nospecialize (f), argtypes:: Vector{Any} , match:: MethodMatch ,
521
527
sv:: InferenceState , va_override:: Bool )
522
528
mi = maybe_get_const_prop_profitable (interp, result, f, argtypes, match, sv)
523
- mi === nothing && return Any, nothing
529
+ mi === nothing && return nothing
524
530
# try constant prop'
525
531
inf_cache = get_inference_cache (interp)
526
532
inf_result = cache_lookup (mi, argtypes, inf_cache)
527
533
if inf_result === nothing
528
534
# if there might be a cycle, check to make sure we don't end up
529
535
# calling ourselves here.
530
- if result. edgecycle && _any (InfStackUnwind (sv)) do infstate
531
- # if the type complexity limiting didn't decide to limit the call signature (`result.edgelimited = false`)
532
- # we can relax the cycle detection by comparing `MethodInstance`s and allow inference to
533
- # propagate different constant elements if the recursion is finite over the lattice
534
- return (result. edgelimited ? match. method === infstate. linfo. def : mi === infstate. linfo) &&
535
- any (infstate. result. overridden_by_const)
536
+ let result = result # prevent capturing
537
+ if result. edgecycle && _any (InfStackUnwind (sv)) do infstate
538
+ # if the type complexity limiting didn't decide to limit the call signature (`result.edgelimited = false`)
539
+ # we can relax the cycle detection by comparing `MethodInstance`s and allow inference to
540
+ # propagate different constant elements if the recursion is finite over the lattice
541
+ return (result. edgelimited ? match. method === infstate. linfo. def : mi === infstate. linfo) &&
542
+ any (infstate. result. overridden_by_const)
543
+ end
544
+ add_remark! (interp, sv, " [constprop] Edge cycle encountered" )
545
+ return nothing
536
546
end
537
- add_remark! (interp, sv, " [constprop] Edge cycle encountered" )
538
- return Any, nothing
539
547
end
540
548
inf_result = InferenceResult (mi, argtypes, va_override)
541
549
frame = InferenceState (inf_result, #= cache=# false , interp)
542
- frame === nothing && return Any, nothing # this is probably a bad generated function (unsound), but just ignore it
550
+ frame === nothing && return nothing # this is probably a bad generated function (unsound), but just ignore it
543
551
frame. parent = sv
544
552
push! (inf_cache, inf_result)
545
- typeinf (interp, frame) || return Any, nothing
553
+ typeinf (interp, frame) || return nothing
546
554
end
547
555
result = inf_result. result
548
556
# if constant inference hits a cycle, just bail out
549
- isa (result, InferenceState) && return Any, nothing
557
+ isa (result, InferenceState) && return nothing
550
558
add_backedge! (mi, sv)
551
559
return result, inf_result
552
560
end
@@ -1178,7 +1186,8 @@ function abstract_invoke(interp::AbstractInterpreter, argtypes::Vector{Any}, sv:
1178
1186
nargtype === Bottom && return CallMeta (Bottom, false )
1179
1187
nargtype isa DataType || return CallMeta (Any, false ) # other cases are not implemented below
1180
1188
isdispatchelem (ft) || return CallMeta (Any, false ) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
1181
- types = rewrap_unionall (Tuple{ft, unwrap_unionall (types). parameters... }, types)
1189
+ ft = ft:: DataType
1190
+ types = rewrap_unionall (Tuple{ft, unwrap_unionall (types). parameters... }, types):: Type
1182
1191
nargtype = Tuple{ft, nargtype. parameters... }
1183
1192
argtype = Tuple{ft, argtype. parameters... }
1184
1193
result = findsup (types, method_table (interp))
@@ -1200,12 +1209,14 @@ function abstract_invoke(interp::AbstractInterpreter, argtypes::Vector{Any}, sv:
1200
1209
# t, a = ti.parameters[i], argtypes′[i]
1201
1210
# argtypes′[i] = t ⊑ a ? t : a
1202
1211
# end
1203
- const_rt, const_result = abstract_call_method_with_const_args (interp, result, argtype_to_function (ft′), argtypes′, match, sv, false )
1204
- if const_rt != = rt && const_rt ⊑ rt
1205
- return CallMeta (collect_limitations! (const_rt, sv), InvokeCallInfo (match, const_result))
1206
- else
1207
- return CallMeta (collect_limitations! (rt, sv), InvokeCallInfo (match, nothing ))
1212
+ const_result = abstract_call_method_with_const_args (interp, result, argtype_to_function (ft′), argtypes′, match, sv, false )
1213
+ if const_result != = nothing
1214
+ const_rt, const_result = const_result
1215
+ if const_rt != = rt && const_rt ⊑ rt
1216
+ return CallMeta (collect_limitations! (const_rt, sv), InvokeCallInfo (match, const_result))
1217
+ end
1208
1218
end
1219
+ return CallMeta (collect_limitations! (rt, sv), InvokeCallInfo (match, nothing ))
1209
1220
end
1210
1221
1211
1222
# call where the function is known exactly
@@ -1307,19 +1318,20 @@ end
1307
1318
function abstract_call_opaque_closure (interp:: AbstractInterpreter , closure:: PartialOpaque , argtypes:: Vector{Any} , sv:: InferenceState )
1308
1319
pushfirst! (argtypes, closure. env)
1309
1320
sig = argtypes_to_type (argtypes)
1310
- (; rt, edge) = result = abstract_call_method (interp, closure. source:: Method , sig, Core. svec (), false , sv)
1321
+ (; rt, edge) = result = abstract_call_method (interp, closure. source, sig, Core. svec (), false , sv)
1311
1322
edge != = nothing && add_backedge! (edge, sv)
1312
1323
tt = closure. typ
1313
- sigT = unwrap_unionall (tt). parameters[1 ]
1314
- match = MethodMatch (sig, Core. svec (), closure. source:: Method , sig <: rewrap_unionall (sigT, tt))
1324
+ sigT = ( unwrap_unionall (tt) :: DataType ). parameters[1 ]
1325
+ match = MethodMatch (sig, Core. svec (), closure. source, sig <: rewrap_unionall (sigT, tt))
1315
1326
info = OpaqueClosureCallInfo (match)
1316
1327
if ! result. edgecycle
1317
- const_rettype, const_result = abstract_call_method_with_const_args (interp, result, closure, argtypes,
1328
+ const_result = abstract_call_method_with_const_args (interp, result, closure, argtypes,
1318
1329
match, sv, closure. isva)
1319
- if const_rettype ⊑ rt
1320
- rt = const_rettype
1321
- end
1322
1330
if const_result != = nothing
1331
+ const_rettype, const_result = const_result
1332
+ if const_rettype ⊑ rt
1333
+ rt = const_rettype
1334
+ end
1323
1335
info = ConstCallInfo (info, Union{Nothing,InferenceResult}[const_result])
1324
1336
end
1325
1337
end
@@ -1329,7 +1341,7 @@ end
1329
1341
function most_general_argtypes (closure:: PartialOpaque )
1330
1342
ret = Any[]
1331
1343
cc = widenconst (closure)
1332
- argt = unwrap_unionall (cc). parameters[1 ]
1344
+ argt = ( unwrap_unionall (cc) :: DataType ). parameters[1 ]
1333
1345
if ! isa (argt, DataType) || argt. name != = typename (Tuple)
1334
1346
argt = Tuple
1335
1347
end
@@ -1344,8 +1356,8 @@ function abstract_call(interp::AbstractInterpreter, fargs::Union{Nothing,Vector{
1344
1356
f = argtype_to_function (ft)
1345
1357
if isa (ft, PartialOpaque)
1346
1358
return abstract_call_opaque_closure (interp, ft, argtypes[2 : end ], sv)
1347
- elseif isa ( unwrap_unionall (ft), DataType) && unwrap_unionall (ft) . name === typename (Core. OpaqueClosure)
1348
- return CallMeta (rewrap_unionall (unwrap_unionall (ft ). parameters[2 ], ft), false )
1359
+ elseif (uft = unwrap_unionall (ft); isa (uft , DataType) && uft . name === typename (Core. OpaqueClosure) )
1360
+ return CallMeta (rewrap_unionall ((uft :: DataType ). parameters[2 ], ft), false )
1349
1361
elseif f === nothing
1350
1362
# non-constant function, but the number of arguments is known
1351
1363
# and the ft is not a Builtin or IntrinsicFunction
@@ -1541,12 +1553,12 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
1541
1553
if length (e. args) == 2 && isconcretetype (t) && ! ismutabletype (t)
1542
1554
at = abstract_eval_value (interp, e. args[2 ], vtypes, sv)
1543
1555
n = fieldcount (t)
1544
- if isa (at, Const) && isa (at. val, Tuple) && n == length (at. val) &&
1545
- let t = t; _all (i-> getfield (at. val, i) isa fieldtype (t, i), 1 : n); end
1556
+ if isa (at, Const) && isa (at. val, Tuple) && n == length (at. val:: Tuple ) &&
1557
+ let t = t; _all (i-> getfield (at. val:: Tuple , i) isa fieldtype (t, i), 1 : n); end
1546
1558
t = Const (ccall (:jl_new_structt , Any, (Any, Any), t, at. val))
1547
- elseif isa (at, PartialStruct) && at ⊑ Tuple && n == length (at. fields) &&
1548
- let t = t, at = at; _all (i-> at. fields[i] ⊑ fieldtype (t, i), 1 : n); end
1549
- t = PartialStruct (t, at. fields)
1559
+ elseif isa (at, PartialStruct) && at ⊑ Tuple && n == length (at. fields:: Vector{Any} ) &&
1560
+ let t = t, at = at; _all (i-> ( at. fields:: Vector{Any} ) [i] ⊑ fieldtype (t, i), 1 : n); end
1561
+ t = PartialStruct (t, at. fields:: Vector{Any} )
1550
1562
end
1551
1563
end
1552
1564
elseif ehead === :new_opaque_closure
@@ -1594,7 +1606,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
1594
1606
sym = e. args[1 ]
1595
1607
t = Bool
1596
1608
if isa (sym, SlotNumber)
1597
- vtyp = vtypes[slot_id (sym)]
1609
+ vtyp = vtypes[slot_id (sym)]:: VarState
1598
1610
if vtyp. typ === Bottom
1599
1611
t = Const (false ) # never assigned previously
1600
1612
elseif ! vtyp. undef
@@ -1609,7 +1621,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
1609
1621
t = Const (true )
1610
1622
end
1611
1623
elseif isa (sym, Expr) && sym. head === :static_parameter
1612
- n = sym. args[1 ]
1624
+ n = sym. args[1 ]:: Int
1613
1625
if 1 <= n <= length (sv. sptypes)
1614
1626
spty = sv. sptypes[n]
1615
1627
if isa (spty, Const)
@@ -1644,7 +1656,7 @@ function abstract_eval_global(M::Module, s::Symbol)
1644
1656
end
1645
1657
1646
1658
function abstract_eval_ssavalue (s:: SSAValue , src:: CodeInfo )
1647
- typ = src. ssavaluetypes[s. id]
1659
+ typ = ( src. ssavaluetypes:: Vector{Any} ) [s. id]
1648
1660
if typ === NOT_FOUND
1649
1661
return Bottom
1650
1662
end
@@ -1732,6 +1744,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1732
1744
isva = isa (def, Method) && def. isva
1733
1745
nslots = nargs - isva
1734
1746
slottypes = frame. slottypes
1747
+ ssavaluetypes = frame. src. ssavaluetypes:: Vector{Any}
1735
1748
while frame. pc´´ <= n
1736
1749
# make progress on the active ip set
1737
1750
local pc:: Int = frame. pc´´
@@ -1832,7 +1845,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1832
1845
for (caller, caller_pc) in frame. cycle_backedges
1833
1846
# notify backedges of updated type information
1834
1847
typeassert (caller. stmt_types[caller_pc], VarTable) # we must have visited this statement before
1835
- if ! (caller. src. ssavaluetypes[caller_pc] === Any)
1848
+ if ! (( caller. src. ssavaluetypes:: Vector{Any} ) [caller_pc] === Any)
1836
1849
# no reason to revisit if that call-site doesn't affect the final result
1837
1850
if caller_pc < caller. pc´´
1838
1851
caller. pc´´ = caller_pc
@@ -1842,6 +1855,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1842
1855
end
1843
1856
end
1844
1857
elseif hd === :enter
1858
+ stmt = stmt:: Expr
1845
1859
l = stmt. args[1 ]:: Int
1846
1860
# propagate type info to exception handler
1847
1861
old = states[l]
@@ -1857,16 +1871,18 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1857
1871
elseif hd === :leave
1858
1872
else
1859
1873
if hd === :(= )
1874
+ stmt = stmt:: Expr
1860
1875
t = abstract_eval_statement (interp, stmt. args[2 ], changes, frame)
1861
1876
if t === Bottom
1862
1877
break
1863
1878
end
1864
- frame . src . ssavaluetypes[pc] = t
1879
+ ssavaluetypes[pc] = t
1865
1880
lhs = stmt. args[1 ]
1866
1881
if isa (lhs, SlotNumber)
1867
1882
changes = StateUpdate (lhs, VarState (t, false ), changes, false )
1868
1883
end
1869
1884
elseif hd === :method
1885
+ stmt = stmt:: Expr
1870
1886
fname = stmt. args[1 ]
1871
1887
if isa (fname, SlotNumber)
1872
1888
changes = StateUpdate (fname, VarState (Any, false ), changes, false )
@@ -1881,7 +1897,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1881
1897
if ! isempty (frame. ssavalue_uses[pc])
1882
1898
record_ssa_assign (pc, t, frame)
1883
1899
else
1884
- frame . src . ssavaluetypes[pc] = t
1900
+ ssavaluetypes[pc] = t
1885
1901
end
1886
1902
end
1887
1903
if isa (changes, StateUpdate)
@@ -1908,7 +1924,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1908
1924
1909
1925
if t === nothing
1910
1926
# mark other reached expressions as `Any` to indicate they don't throw
1911
- frame . src . ssavaluetypes[pc] = Any
1927
+ ssavaluetypes[pc] = Any
1912
1928
end
1913
1929
1914
1930
pc´ > n && break # can't proceed with the fast-path fall-through
0 commit comments