@@ -496,13 +496,13 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
496
496
add_remark! (interp, sv, " Refusing to infer into `depwarn`" )
497
497
return MethodCallResult (Any, false , false , nothing , Effects ())
498
498
end
499
- topmost = nothing
499
+
500
500
# Limit argument type tuple growth of functions:
501
501
# look through the parents list to see if there's a call to the same method
502
502
# and from the same method.
503
503
# Returns the topmost occurrence of that repeated edge.
504
- edgecycle = false
505
- edgelimited = false
504
+ edgecycle = edgelimited = false
505
+ topmost = nothing
506
506
507
507
for infstate in InfStackUnwind (sv)
508
508
if method === infstate. linfo. def
@@ -617,9 +617,13 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
617
617
# this edge is known to terminate
618
618
effects = Effects (effects; terminates= ALWAYS_TRUE)
619
619
elseif edgecycle
620
- # Some sort of recursion was detected. Even if we did not limit types,
621
- # we cannot guarantee that the call will terminate
622
- effects = Effects (effects; terminates= ALWAYS_FALSE)
620
+ # Some sort of recursion was detected.
621
+ if edge != = nothing && ! edgelimited && ! is_edge_recursed (edge, sv)
622
+ # no `MethodInstance` cycles -- don't taint :terminate
623
+ else
624
+ # we cannot guarantee that the call will terminate
625
+ effects = Effects (effects; terminates= ALWAYS_FALSE)
626
+ end
623
627
end
624
628
625
629
return MethodCallResult (rt, edgecycle, edgelimited, edge, effects)
@@ -691,6 +695,30 @@ function matches_sv(parent::InferenceState, sv::InferenceState)
691
695
return parent. linfo. def === sv. linfo. def && sv_method2 === parent_method2
692
696
end
693
697
698
+ function is_edge_recursed (edge:: MethodInstance , sv:: InferenceState )
699
+ return any (InfStackUnwind (sv)) do infstate
700
+ return edge === infstate. linfo
701
+ end
702
+ end
703
+
704
+ function is_method_recursed (method:: Method , sv:: InferenceState )
705
+ return any (InfStackUnwind (sv)) do infstate
706
+ return method === infstate. linfo. def
707
+ end
708
+ end
709
+
710
+ function is_constprop_edge_recursed (edge:: MethodInstance , sv:: InferenceState )
711
+ return any (InfStackUnwind (sv)) do infstate
712
+ return edge === infstate. linfo && any (infstate. result. overridden_by_const)
713
+ end
714
+ end
715
+
716
+ function is_constprop_method_recursed (method:: Method , sv:: InferenceState )
717
+ return any (InfStackUnwind (sv)) do infstate
718
+ return method === infstate. linfo. def && any (infstate. result. overridden_by_const)
719
+ end
720
+ end
721
+
694
722
# keeps result and context information of abstract_method_call, which will later be used for
695
723
# backedge computation, and concrete evaluation or constant-propagation
696
724
struct MethodCallResult
@@ -799,8 +827,7 @@ function const_prop_enabled(interp::AbstractInterpreter, sv::InferenceState, mat
799
827
add_remark! (interp, sv, " [constprop] Disabled by parameter" )
800
828
return false
801
829
end
802
- method = match. method
803
- if method. constprop == 0x02
830
+ if is_no_constprop (match. method)
804
831
add_remark! (interp, sv, " [constprop] Disabled by method parameter" )
805
832
return false
806
833
end
@@ -836,17 +863,14 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, resul
836
863
if inf_result === nothing
837
864
# if there might be a cycle, check to make sure we don't end up
838
865
# calling ourselves here.
839
- let result = result # prevent capturing
840
- if result. edgecycle && _any (InfStackUnwind (sv)) do infstate
841
- # if the type complexity limiting didn't decide to limit the call signature (`result.edgelimited = false`)
842
- # we can relax the cycle detection by comparing `MethodInstance`s and allow inference to
843
- # propagate different constant elements if the recursion is finite over the lattice
844
- return (result. edgelimited ? match. method === infstate. linfo. def : mi === infstate. linfo) &&
845
- any (infstate. result. overridden_by_const)
846
- end
847
- add_remark! (interp, sv, " [constprop] Edge cycle encountered" )
848
- return nothing
849
- end
866
+ if result. edgecycle && (result. edgelimited ?
867
+ is_constprop_method_recursed (match. method, sv) :
868
+ # if the type complexity limiting didn't decide to limit the call signature (`result.edgelimited = false`)
869
+ # we can relax the cycle detection by comparing `MethodInstance`s and allow inference to
870
+ # propagate different constant elements if the recursion is finite over the lattice
871
+ is_constprop_edge_recursed (mi, sv))
872
+ add_remark! (interp, sv, " [constprop] Edge cycle encountered" )
873
+ return nothing
850
874
end
851
875
inf_result = InferenceResult (mi, (arginfo, sv))
852
876
if ! any (inf_result. overridden_by_const)
@@ -963,8 +987,8 @@ function is_const_prop_profitable_arg(@nospecialize(arg))
963
987
isa (arg, PartialOpaque) && return true
964
988
isa (arg, Const) || return true
965
989
val = arg. val
966
- # don't consider mutable values or Strings useful constants
967
- return isa (val, Symbol) || isa (val, Type) || ( ! isa (val, String) && ! ismutable (val) )
990
+ # don't consider mutable values useful constants
991
+ return isa (val, Symbol) || isa (val, Type) || ! ismutable (val)
968
992
end
969
993
970
994
function is_const_prop_profitable_conditional (cnd:: Conditional , fargs:: Vector{Any} , sv:: InferenceState )
@@ -1003,7 +1027,7 @@ function is_all_overridden((; fargs, argtypes)::ArgInfo, sv::InferenceState)
1003
1027
end
1004
1028
1005
1029
function force_const_prop (interp:: AbstractInterpreter , @nospecialize (f), method:: Method )
1006
- return method. constprop == 0x01 ||
1030
+ return is_aggressive_constprop ( method) ||
1007
1031
InferenceParams (interp). aggressive_constant_propagation ||
1008
1032
istopfunction (f, :getproperty ) ||
1009
1033
istopfunction (f, :setproperty! )
@@ -1345,7 +1369,7 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::
1345
1369
end
1346
1370
cti = Any[Vararg{argt}]
1347
1371
end
1348
- if _any (t -> t === Bottom, cti)
1372
+ if any ( @nospecialize (t) -> t === Bottom, cti)
1349
1373
continue
1350
1374
end
1351
1375
for j = 1 : length (ctypes)
@@ -2031,6 +2055,8 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
2031
2055
for i = 3 : length (e. args)
2032
2056
if abstract_eval_value (interp, e. args[i], vtypes, sv) === Bottom
2033
2057
t = Bottom
2058
+ tristate_merge! (sv, EFFECTS_THROWS)
2059
+ @goto t_computed
2034
2060
end
2035
2061
end
2036
2062
cconv = e. args[5 ]
0 commit comments