@@ -245,15 +245,21 @@ function _typeinf(interp::AbstractInterpreter, frame::InferenceState)
245
245
# with no active ip's, frame is done
246
246
frames = frame. callers_in_cycle
247
247
isempty (frames) && push! (frames, frame)
248
- valid_worlds = WorldRange ()
248
+ cycle_valid_worlds = WorldRange ()
249
+ cycle_effects = EFFECTS_TOTAL
249
250
for caller in frames
250
251
@assert ! (caller. dont_work_on_me)
251
252
caller. dont_work_on_me = true
252
- # might might not fully intersect these earlier, so do that now
253
- valid_worlds = intersect (caller. valid_worlds, valid_worlds)
253
+ # converge the world age range and effects for this cycle here:
254
+ # all frames in the cycle should have the same bits of `valid_worlds` and `effects`
255
+ # that are simply the intersection of each partial computation, without having
256
+ # dependencies on each other (unlike rt and exct)
257
+ cycle_valid_worlds = intersect (cycle_valid_worlds, caller. valid_worlds)
258
+ cycle_effects = merge_effects (cycle_effects, caller. ipo_effects)
254
259
end
255
260
for caller in frames
256
- caller. valid_worlds = valid_worlds
261
+ caller. valid_worlds = cycle_valid_worlds
262
+ caller. ipo_effects = cycle_effects
257
263
finish (caller, caller. interp)
258
264
end
259
265
for caller in frames
@@ -872,7 +878,8 @@ function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize
872
878
update_valid_age! (caller, frame. valid_worlds)
873
879
isinferred = is_inferred (frame)
874
880
edge = isinferred ? mi : nothing
875
- effects = isinferred ? frame. result. ipo_effects : adjust_effects (Effects (), method) # effects are adjusted already within `finish` for ipo_effects
881
+ effects = isinferred ? frame. result. ipo_effects : # effects are adjusted already within `finish` for ipo_effects
882
+ adjust_effects (effects_for_cycle (frame. ipo_effects), method)
876
883
exc_bestguess = refine_exception_type (frame. exc_bestguess, effects)
877
884
# propagate newly inferred source to the inliner, allowing efficient inlining w/o deserialization:
878
885
# note that this result is cached globally exclusively, we can use this local result destructively
@@ -887,11 +894,16 @@ function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize
887
894
# return the current knowledge about this cycle
888
895
frame = frame:: InferenceState
889
896
update_valid_age! (caller, frame. valid_worlds)
890
- effects = adjust_effects (Effects ( ), method)
897
+ effects = adjust_effects (effects_for_cycle (frame . ipo_effects ), method)
891
898
exc_bestguess = refine_exception_type (frame. exc_bestguess, effects)
892
899
return EdgeCallResult (frame. bestguess, exc_bestguess, nothing , effects)
893
900
end
894
901
902
+ # The `:terminates` effect bit must be conservatively tainted unless recursion cycle has
903
+ # been fully resolved. As for other effects, there's no need to taint them at this moment
904
+ # because they will be tainted as we try to resolve the cycle.
905
+ effects_for_cycle (effects:: Effects ) = Effects (effects; terminates= false )
906
+
895
907
function cached_return_type (code:: CodeInstance )
896
908
rettype = code. rettype
897
909
isdefined (code, :rettype_const ) || return rettype
0 commit comments