Skip to content

Commit 9e913d7

Browse files
vtjnashKristofferC
authored andcommitted
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 (cherry picked from commit 48bd673)
1 parent 804c2ce commit 9e913d7

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
@@ -498,18 +498,17 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter, cycleid::
498498
istoplevel = !(me.linfo.def isa Method)
499499
istoplevel || compute_edges!(me) # don't add backedges to toplevel method instance
500500

501-
if limited_ret
502-
# a parent may be cached still, but not this intermediate work:
503-
# we can throw everything else away now
501+
if limited_ret || limited_src
502+
# A parent may be cached still, but not this intermediate work:
503+
# we can throw everything else away now. Caching anything can confuse later
504+
# heuristics to consider it worth trying to pursue compiling this further and
505+
# finding infinite work as a result. Avoiding caching helps to ensure there is only
506+
# a finite amount of work that can be discovered later (although potentially still a
507+
# large multiplier on it).
504508
result.src = nothing
505509
result.tombstone = true
506510
me.cache_mode = CACHE_MODE_NULL
507511
set_inlineable!(me.src, false)
508-
elseif limited_src
509-
# a type result will be cached still, but not this intermediate work:
510-
# we can throw everything else away now
511-
result.src = nothing
512-
set_inlineable!(me.src, false)
513512
else
514513
# annotate fulltree with type information,
515514
# 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
@@ -6231,3 +6231,28 @@ A58257.get! # Creates binding partition in A, N+1:∞
62316231
A58257.B58257.get! # Creates binding partition in A.B, N+1:∞
62326232
Base.invoke_in_world(UInt(38678), getglobal, A58257, :get!) # Expands binding partition in A through <N
62336233
@test Base.infer_return_type(A58257.f) == typeof(Base.get!) # Attempt to lookup A.B in world age N hangs
6234+
6235+
function tt57873(a::Vector{String}, pref)
6236+
ret = String[]
6237+
for j in a
6238+
append!(ret, tt57873(a[2:end], (pref..., "")))
6239+
end
6240+
return ret
6241+
end
6242+
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)
6243+
@test !isempty(code)
6244+
## If we were to run trim here, we should fail with:
6245+
# Verifier error #1: unresolved invoke from statement tt57873(::Vector{String}, ::Tuple{String, String})::Vector{String}
6246+
#Stacktrace:
6247+
# [1] tt57873(a::Vector{String}, pref::Tuple{String})
6248+
# @ Main REPL[1]:4
6249+
end
6250+
6251+
function ss57873(a::Vector{String}, pref)
6252+
ret = String[]
6253+
for j in a
6254+
append!(ret, ss57873(a[2:end], (pref..., "")))
6255+
end
6256+
return ret
6257+
end
6258+
@test ss57873(["a", "b", "c"], ("",)) == String[]

0 commit comments

Comments
 (0)