Skip to content

Commit 87a416f

Browse files
authored
fix recursion detection in constant prop (#36148)
1 parent d825de8 commit 87a416f

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
132132
# if there's a possibility we could constant-propagate a better result
133133
# (hopefully without doing too much work), try to do that now
134134
# TODO: it feels like this could be better integrated into abstract_call_method / typeinf_edge
135-
const_rettype = abstract_call_method_with_const_args(interp, rettype, f, argtypes, applicable[nonbot]::SimpleVector, sv)
135+
const_rettype = abstract_call_method_with_const_args(interp, rettype, f, argtypes, applicable[nonbot]::SimpleVector, sv, edgecycle)
136136
if const_rettype rettype
137137
# use the better result, if it's a refinement of rettype
138138
rettype = const_rettype
@@ -185,7 +185,7 @@ function const_prop_profitable(@nospecialize(arg))
185185
return false
186186
end
187187

188-
function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nospecialize(rettype), @nospecialize(f), argtypes::Vector{Any}, match::SimpleVector, sv::InferenceState)
188+
function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nospecialize(rettype), @nospecialize(f), argtypes::Vector{Any}, match::SimpleVector, sv::InferenceState, edgecycle::Bool)
189189
method = match[3]::Method
190190
nargs::Int = method.nargs
191191
method.isva && (nargs -= 1)
@@ -259,6 +259,24 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nosp
259259
inf_cache = get_inference_cache(interp)
260260
inf_result = cache_lookup(mi, argtypes, inf_cache)
261261
if inf_result === nothing
262+
if edgecycle
263+
# if there might be a cycle, check to make sure we don't end up
264+
# calling ourselves here.
265+
infstate = sv
266+
cyclei = 0
267+
while !(infstate === nothing)
268+
if method === infstate.linfo.def && any(infstate.result.overridden_by_const)
269+
return Any
270+
end
271+
if cyclei < length(infstate.callers_in_cycle)
272+
cyclei += 1
273+
infstate = infstate.callers_in_cycle[cyclei]
274+
else
275+
cyclei = 0
276+
infstate = infstate.parent
277+
end
278+
end
279+
end
262280
inf_result = InferenceResult(mi, argtypes)
263281
frame = InferenceState(inf_result, #=cache=#false, interp)
264282
frame === nothing && return Any # this is probably a bad generated function (unsound), but just ignore it

test/compiler/inference.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2623,3 +2623,27 @@ end
26232623
_size_ish(F::NotQRSparse, i::Integer) = size(getprop(F, :B), 1)
26242624
_call_size_ish(x) = _size_ish(x,1)
26252625
@test Base.return_types(_call_size_ish, (NotQRSparse,)) == Any[Int]
2626+
2627+
module TestConstPropRecursion
2628+
mutable struct Node
2629+
data
2630+
child::Node
2631+
sibling::Node
2632+
end
2633+
2634+
function Base.iterate(n::Node, state::Node = n.child)
2635+
n === state && return nothing
2636+
return state, state === state.sibling ? n : state.sibling
2637+
end
2638+
2639+
@inline function depth(node::Node, d)
2640+
childd = d + 1
2641+
for c in node
2642+
d = max(d, depth(c, childd))
2643+
end
2644+
return d
2645+
end
2646+
2647+
f(n) = depth(n, 1)
2648+
end
2649+
@test Base.return_types(TestConstPropRecursion.f, (TestConstPropRecursion.Node,)) == Any[Int]

0 commit comments

Comments
 (0)