@@ -195,7 +195,7 @@ function finish!(interp::AbstractInterpreter, mi::MethodInstance, ci::CodeInstan
195
195
end
196
196
197
197
function finish_nocycle (:: AbstractInterpreter , frame:: InferenceState )
198
- finishinfer! (frame, frame. interp)
198
+ finishinfer! (frame, frame. interp, frame . cycleid )
199
199
opt = frame. result. src
200
200
if opt isa OptimizationState # implies `may_optimize(caller.interp) === true`
201
201
optimize (frame. interp, opt, frame. result)
@@ -232,7 +232,7 @@ function finish_cycle(::AbstractInterpreter, frames::Vector{AbsIntState}, cyclei
232
232
for frameid = cycleid: length (frames)
233
233
caller = frames[frameid]:: InferenceState
234
234
adjust_cycle_frame! (caller, cycle_valid_worlds, cycle_valid_effects)
235
- finishinfer! (caller, caller. interp)
235
+ finishinfer! (caller, caller. interp, cycleid )
236
236
end
237
237
for frameid = cycleid: length (frames)
238
238
caller = frames[frameid]:: InferenceState
@@ -312,26 +312,21 @@ function cache_result!(interp::AbstractInterpreter, result::InferenceResult, ci:
312
312
return true
313
313
end
314
314
315
- function cycle_fix_limited (@nospecialize (typ), sv:: InferenceState )
315
+ function cycle_fix_limited (@nospecialize (typ), sv:: InferenceState , cycleid :: Int )
316
316
if typ isa LimitedAccuracy
317
- if sv. parentid === 0
318
- # we might have introduced a limit marker, but we should know it must be sv and other callers_in_cycle
319
- # @assert !isempty(callers_in_cycle(sv))
320
- # FIXME : this assert fails, appearing to indicate there is a bug in filtering this list earlier.
321
- # In particular (during doctests for example), during inference of
322
- # show(Base.IOContext{Base.GenericIOBuffer{Memory{UInt8}}}, Base.Multimedia.MIME{:var"text/plain"}, LinearAlgebra.BunchKaufman{Float64, Array{Float64, 2}, Array{Int64, 1}})
323
- # we observed one of the ssavaluetypes here to be Core.Compiler.LimitedAccuracy(typ=Any, causes=Core.Compiler.IdSet(getproperty(LinearAlgebra.BunchKaufman{Float64, Array{Float64, 2}, Array{Int64, 1}}, Symbol)))
324
- return typ. typ
325
- end
326
- causes = copy (typ. causes)
327
- delete! (causes, sv)
328
- for caller in callers_in_cycle (sv)
329
- delete! (causes, caller)
330
- end
331
- if isempty (causes)
332
- return typ. typ
317
+ frames = sv. callstack:: Vector{AbsIntState}
318
+ causes = typ. causes
319
+ for frameid = cycleid: length (frames)
320
+ caller = frames[frameid]:: InferenceState
321
+ caller in causes || continue
322
+ causes === typ. causes && (causes = copy (causes))
323
+ pop! (causes, caller)
324
+ if isempty (causes)
325
+ return typ. typ
326
+ end
333
327
end
334
- if length (causes) != length (typ. causes)
328
+ @assert sv. parentid != 0
329
+ if causes != = typ. causes
335
330
return LimitedAccuracy (typ. typ, causes)
336
331
end
337
332
end
@@ -439,20 +434,23 @@ const empty_edges = Core.svec()
439
434
440
435
# inference completed on `me`
441
436
# update the MethodInstance
442
- function finishinfer! (me:: InferenceState , interp:: AbstractInterpreter )
437
+ function finishinfer! (me:: InferenceState , interp:: AbstractInterpreter , cycleid :: Int )
443
438
# prepare to run optimization passes on fulltree
444
439
@assert isempty (me. ip)
445
440
# inspect whether our inference had a limited result accuracy,
446
441
# else it may be suitable to cache
447
- bestguess = me. bestguess = cycle_fix_limited (me. bestguess, me)
448
- exc_bestguess = me. exc_bestguess = cycle_fix_limited (me. exc_bestguess, me)
442
+ bestguess = me. bestguess = cycle_fix_limited (me. bestguess, me, cycleid )
443
+ exc_bestguess = me. exc_bestguess = cycle_fix_limited (me. exc_bestguess, me, cycleid )
449
444
limited_ret = bestguess isa LimitedAccuracy || exc_bestguess isa LimitedAccuracy
450
445
limited_src = false
451
- if ! limited_ret
446
+ if limited_ret
447
+ @assert me. parentid != 0
448
+ else
452
449
gt = me. ssavaluetypes
453
450
for j = 1 : length (gt)
454
- gt[j] = gtj = cycle_fix_limited (gt[j], me)
455
- if gtj isa LimitedAccuracy && me. parentid != 0
451
+ gt[j] = gtj = cycle_fix_limited (gt[j], me, cycleid)
452
+ if gtj isa LimitedAccuracy
453
+ @assert me. parentid != 0
456
454
limited_src = true
457
455
break
458
456
end
@@ -474,6 +472,7 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter)
474
472
# a parent may be cached still, but not this intermediate work:
475
473
# we can throw everything else away now
476
474
result. src = nothing
475
+ result. tombstone = true
477
476
me. cache_mode = CACHE_MODE_NULL
478
477
set_inlineable! (me. src, false )
479
478
elseif limited_src
@@ -714,7 +713,7 @@ function merge_call_chain!(::AbstractInterpreter, parent::InferenceState, child:
714
713
add_cycle_backedge! (parent, child)
715
714
parent. cycleid === ancestorid && break
716
715
child = parent
717
- parent = frame_parent (child):: InferenceState
716
+ parent = cycle_parent (child):: InferenceState
718
717
end
719
718
# ensure that walking the callstack has the same cycleid (DAG)
720
719
for frameid = reverse (ancestorid: length (frames))
750
749
# returned instead.
751
750
function resolve_call_cycle! (interp:: AbstractInterpreter , mi:: MethodInstance , parent:: AbsIntState )
752
751
# TODO (#48913) implement a proper recursion handling for irinterp:
753
- # This works currently just because the irinterp code doesn't get used much with
752
+ # This works most of the time currently just because the irinterp code doesn't get used much with
754
753
# `@assume_effects`, so it never sees a cycle normally, but that may not be a sustainable solution.
755
754
parent isa InferenceState || return false
756
755
frames = parent. callstack:: Vector{AbsIntState}
@@ -762,7 +761,7 @@ function resolve_call_cycle!(interp::AbstractInterpreter, mi::MethodInstance, pa
762
761
if is_same_frame (interp, mi, frame)
763
762
if uncached
764
763
# our attempt to speculate into a constant call lead to an undesired self-cycle
765
- # that cannot be converged: poison our call-stack (up to the discovered duplicate frame)
764
+ # that cannot be converged: if necessary, poison our call-stack (up to the discovered duplicate frame)
766
765
# with the limited flag and abort (set return type to Any) now
767
766
poison_callstack! (parent, frame)
768
767
return true
0 commit comments