@@ -434,7 +434,7 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
434
434
# Under direct self-recursion, permit much greater use of reducers.
435
435
# here we assume that complexity(specTypes) :>= complexity(sig)
436
436
comparison = sv. linfo. specTypes
437
- l_comparison = length (unwrap_unionall (comparison). parameters)
437
+ l_comparison = length (unwrap_unionall (comparison). parameters):: Int
438
438
spec_len = max (spec_len, l_comparison)
439
439
else
440
440
comparison = method. sig
589
589
590
590
# simulate iteration protocol on container type up to fixpoint
591
591
function abstract_iteration (interp:: AbstractInterpreter , @nospecialize (itft), @nospecialize (itertype), sv:: InferenceState )
592
- if ! isdefined (Main, :Base ) || ! isdefined (Main. Base, :iterate ) || ! isconst (Main. Base, :iterate )
593
- return Any[Vararg{Any}], nothing
594
- end
595
- if itft === nothing
596
- iteratef = getfield (Main. Base, :iterate )
597
- itft = Const (iteratef)
598
- elseif isa (itft, Const)
592
+ if isa (itft, Const)
599
593
iteratef = itft. val
600
594
else
601
595
return Any[Vararg{Any}], nothing
@@ -607,6 +601,7 @@ function abstract_iteration(interp::AbstractInterpreter, @nospecialize(itft), @n
607
601
# Return Bottom if this is not an iterator.
608
602
# WARNING: Changes to the iteration protocol must be reflected here,
609
603
# this is not just an optimization.
604
+ # TODO : this doesn't realize that Array, SimpleVector, Tuple, and NamedTuple do not use the iterate protocol
610
605
stateordonet === Bottom && return Any[Bottom], AbstractIterationInfo (CallMeta[CallMeta (Bottom, info)])
611
606
valtype = statetype = Bottom
612
607
ret = Any[]
@@ -670,7 +665,7 @@ function abstract_apply(interp::AbstractInterpreter, @nospecialize(itft), @nospe
670
665
aftw = widenconst (aft)
671
666
if ! isa (aft, Const) && (! isType (aftw) || has_free_typevars (aftw))
672
667
if ! isconcretetype (aftw) || (aftw <: Builtin )
673
- add_remark! (interp, sv, " Core._apply called on a function of a non-concrete type" )
668
+ add_remark! (interp, sv, " Core._apply_iterate called on a function of a non-concrete type" )
674
669
# bail now, since it seems unlikely that abstract_call will be able to do any better after splitting
675
670
# this also ensures we don't call abstract_call_gf_by_type below on an IntrinsicFunction or Builtin
676
671
return CallMeta (Any, false )
@@ -679,16 +674,20 @@ function abstract_apply(interp::AbstractInterpreter, @nospecialize(itft), @nospe
679
674
res = Union{}
680
675
nargs = length (aargtypes)
681
676
splitunions = 1 < unionsplitcost (aargtypes) <= InferenceParams (interp). MAX_APPLY_UNION_ENUM
682
- ctypes = Any [Any[aft]]
677
+ ctypes = [Any[aft]]
683
678
infos = [Union{Nothing, AbstractIterationInfo}[]]
684
679
for i = 1 : nargs
685
- ctypes´ = []
686
- infos′ = []
680
+ ctypes´ = Vector{Any} []
681
+ infos′ = Vector{Union{Nothing, AbstractIterationInfo}} []
687
682
for ti in (splitunions ? uniontypes (aargtypes[i]) : Any[aargtypes[i]])
688
683
if ! isvarargtype (ti)
689
- cti, info = precise_container_type (interp, itft, ti, sv)
684
+ cti_info = precise_container_type (interp, itft, ti, sv)
685
+ cti = cti_info[1 ]:: Vector{Any}
686
+ info = cti_info[2 ]:: Union{Nothing,AbstractIterationInfo}
690
687
else
691
- cti, info = precise_container_type (interp, itft, unwrapva (ti), sv)
688
+ cti_info = precise_container_type (interp, itft, unwrapva (ti), sv)
689
+ cti = cti_info[1 ]:: Vector{Any}
690
+ info = cti_info[2 ]:: Union{Nothing,AbstractIterationInfo}
692
691
# We can't represent a repeating sequence of the same types,
693
692
# so tmerge everything together to get one type that represents
694
693
# everything.
@@ -705,7 +704,7 @@ function abstract_apply(interp::AbstractInterpreter, @nospecialize(itft), @nospe
705
704
continue
706
705
end
707
706
for j = 1 : length (ctypes)
708
- ct = ctypes[j]
707
+ ct = ctypes[j]:: Vector{Any}
709
708
if isvarargtype (ct[end ])
710
709
# This is vararg, we're not gonna be able to do any inling,
711
710
# drop the info
@@ -826,7 +825,8 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, fargs::U
826
825
end
827
826
rt = builtin_tfunction (interp, f, argtypes[2 : end ], sv)
828
827
if f === getfield && isa (fargs, Vector{Any}) && la == 3 && isa (argtypes[3 ], Const) && isa (argtypes[3 ]. val, Int) && argtypes[2 ] ⊑ Tuple
829
- cti, _ = precise_container_type (interp, nothing , argtypes[2 ], sv)
828
+ # TODO : why doesn't this use the getfield_tfunc?
829
+ cti, _ = precise_container_type (interp, iterate, argtypes[2 ], sv)
830
830
idx = argtypes[3 ]. val:: Int
831
831
if 1 <= idx <= length (cti)
832
832
rt = unwrapva (cti[idx])
@@ -945,11 +945,7 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
945
945
la = length (argtypes)
946
946
947
947
if isa (f, Builtin)
948
- if f === _apply
949
- ft = argtype_by_index (argtypes, 2 )
950
- ft === Bottom && return CallMeta (Bottom, false )
951
- return abstract_apply (interp, nothing , ft, argtype_tail (argtypes, 3 ), sv, max_methods)
952
- elseif f === _apply_iterate
948
+ if f === _apply_iterate
953
949
itft = argtype_by_index (argtypes, 2 )
954
950
ft = argtype_by_index (argtypes, 3 )
955
951
(itft === Bottom || ft === Bottom) && return CallMeta (Bottom, false )
@@ -1304,6 +1300,28 @@ function abstract_eval_ssavalue(s::SSAValue, src::CodeInfo)
1304
1300
return typ
1305
1301
end
1306
1302
1303
+ function widenreturn (@nospecialize rt)
1304
+ # only propagate information we know we can store
1305
+ # and is valid and good inter-procedurally
1306
+ rt = widenconditional (rt)
1307
+ isa (rt, Const) && return rt
1308
+ isa (rt, Type) && return rt
1309
+ if isa (rt, PartialStruct)
1310
+ fields = copy (rt. fields)
1311
+ haveconst = false
1312
+ for i in 1 : length (fields)
1313
+ a = widenreturn (fields[i])
1314
+ if ! haveconst && has_const_info (a)
1315
+ # TODO : consider adding && const_prop_profitable(a) here?
1316
+ haveconst = true
1317
+ end
1318
+ fields[i] = a
1319
+ end
1320
+ haveconst && return PartialStruct (rt. typ, fields)
1321
+ end
1322
+ return widenconst (rt)
1323
+ end
1324
+
1307
1325
# make as much progress on `frame` as possible (without handling cycles)
1308
1326
function typeinf_local (interp:: AbstractInterpreter , frame:: InferenceState )
1309
1327
@assert ! frame. inferred
@@ -1326,6 +1344,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1326
1344
frame. currpc = pc
1327
1345
frame. cur_hand = frame. handler_at[pc]
1328
1346
frame. stmt_edges[pc] === nothing || empty! (frame. stmt_edges[pc])
1347
+ frame. stmt_info[pc] = nothing
1329
1348
stmt = frame. src. code[pc]
1330
1349
changes = s[pc]:: VarTable
1331
1350
t = nothing
@@ -1338,7 +1357,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1338
1357
elseif isa (stmt, GotoNode)
1339
1358
pc´ = (stmt:: GotoNode ). label
1340
1359
elseif isa (stmt, GotoIfNot)
1341
- condt = abstract_eval_value (interp, stmt. cond, s[pc] , frame)
1360
+ condt = abstract_eval_value (interp, stmt. cond, changes , frame)
1342
1361
if condt === Bottom
1343
1362
empty! (frame. pclimitations)
1344
1363
break
@@ -1369,7 +1388,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1369
1388
end
1370
1389
end
1371
1390
newstate_else = stupdate! (s[l], changes_else)
1372
- if newstate_else != = false
1391
+ if newstate_else != = nothing
1373
1392
# add else branch to active IP list
1374
1393
if l < frame. pc´´
1375
1394
frame. pc´´ = l
@@ -1380,12 +1399,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1380
1399
end
1381
1400
elseif isa (stmt, ReturnNode)
1382
1401
pc´ = n + 1
1383
- rt = widenconditional (abstract_eval_value (interp, stmt. val, s[pc], frame))
1384
- if ! isa (rt, Const) && ! isa (rt, Type) && ! isa (rt, PartialStruct)
1385
- # only propagate information we know we can store
1386
- # and is valid inter-procedurally
1387
- rt = widenconst (rt)
1388
- end
1402
+ rt = widenreturn (abstract_eval_value (interp, stmt. val, changes, frame))
1389
1403
# copy limitations to return value
1390
1404
if ! isempty (frame. pclimitations)
1391
1405
union! (frame. limitations, frame. pclimitations)
@@ -1414,9 +1428,8 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1414
1428
frame. cur_hand = Pair {Any,Any} (l, frame. cur_hand)
1415
1429
# propagate type info to exception handler
1416
1430
old = s[l]
1417
- new = s[pc]:: Array{Any,1}
1418
- newstate_catch = stupdate! (old, new)
1419
- if newstate_catch != = false
1431
+ newstate_catch = stupdate! (old, changes)
1432
+ if newstate_catch != = nothing
1420
1433
if l < frame. pc´´
1421
1434
frame. pc´´ = l
1422
1435
end
@@ -1483,12 +1496,12 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1483
1496
# (such as a terminator for a loop, if-else, or try block),
1484
1497
# consider whether we should jump to an older backedge first,
1485
1498
# to try to traverse the statements in approximate dominator order
1486
- if newstate != = false
1499
+ if newstate != = nothing
1487
1500
s[pc´] = newstate
1488
1501
end
1489
1502
push! (W, pc´)
1490
1503
pc = frame. pc´´
1491
- elseif newstate != = false
1504
+ elseif newstate != = nothing
1492
1505
s[pc´] = newstate
1493
1506
pc = pc´
1494
1507
elseif pc´ in W
0 commit comments