Skip to content

Commit 48bd673

Browse files
authored
Prevent type infer hang of "simple" recursive functions (#58273)
Prevent infinite inference when dealing with LimitedAccuracy by declining to cache them. Presence in the cache triggers further compilation to resolve it, so removing infinite work from the cache also prevents infinite work at pre-compile/jit compile time. Fix #57098 Fix #57873
1 parent 35bfba9 commit 48bd673

File tree

2 files changed

+32
-8
lines changed

2 files changed

+32
-8
lines changed

Compiler/src/typeinfer.jl

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -613,18 +613,17 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter, cycleid::
613613
istoplevel = !(me.linfo.def isa Method)
614614
istoplevel || compute_edges!(me) # don't add backedges to toplevel method instance
615615

616-
if limited_ret
617-
# a parent may be cached still, but not this intermediate work:
618-
# we can throw everything else away now
616+
if limited_ret || limited_src
617+
# A parent may be cached still, but not this intermediate work:
618+
# we can throw everything else away now. Caching anything can confuse later
619+
# heuristics to consider it worth trying to pursue compiling this further and
620+
# finding infinite work as a result. Avoiding caching helps to ensure there is only
621+
# a finite amount of work that can be discovered later (although potentially still a
622+
# large multiplier on it).
619623
result.src = nothing
620624
result.tombstone = true
621625
me.cache_mode = CACHE_MODE_NULL
622626
set_inlineable!(me.src, false)
623-
elseif limited_src
624-
# a type result will be cached still, but not this intermediate work:
625-
# we can throw everything else away now
626-
result.src = nothing
627-
set_inlineable!(me.src, false)
628627
else
629628
# annotate fulltree with type information,
630629
# either because we are the outermost code, or we might use this later

Compiler/test/inference.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6460,4 +6460,29 @@ A58257.B58257.get! # Creates binding partition in A.B, N+1:∞
64606460
Base.invoke_in_world(UInt(38678), getglobal, A58257, :get!) # Expands binding partition in A through <N
64616461
@test Base.infer_return_type(A58257.f) == typeof(Base.get!) # Attempt to lookup A.B in world age N hangs
64626462

6463+
function tt57873(a::Vector{String}, pref)
6464+
ret = String[]
6465+
for j in a
6466+
append!(ret, tt57873(a[2:end], (pref..., "")))
6467+
end
6468+
return ret
6469+
end
6470+
let code = Compiler.typeinf_ext_toplevel(Any[Core.svec(Any,Tuple{typeof(tt57873),Vector{String},Tuple{String}})], [Base.get_world_counter()], Base.Compiler.TRIM_NO)
6471+
@test !isempty(code)
6472+
## If we were to run trim here, we should fail with:
6473+
# Verifier error #1: unresolved invoke from statement tt57873(::Vector{String}, ::Tuple{String, String})::Vector{String}
6474+
#Stacktrace:
6475+
# [1] tt57873(a::Vector{String}, pref::Tuple{String})
6476+
# @ Main REPL[1]:4
6477+
end
6478+
6479+
function ss57873(a::Vector{String}, pref)
6480+
ret = String[]
6481+
for j in a
6482+
append!(ret, ss57873(a[2:end], (pref..., "")))
6483+
end
6484+
return ret
6485+
end
6486+
@test ss57873(["a", "b", "c"], ("",)) == String[]
6487+
64636488
end # module inference

0 commit comments

Comments
 (0)