@@ -3706,6 +3706,107 @@ function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
37063706    return  typ
37073707end 
37083708
3709+ struct  AbstractEvalBasicStatementResult
3710+     rt
3711+     exct
3712+     effects:: Union{Nothing,Effects} 
3713+     changes:: Union{Nothing,StateUpdate} 
3714+     refinements #  ::Union{Nothing,SlotRefinement,Vector{Any}}
3715+     currsaw_latestworld:: Bool 
3716+     function  AbstractEvalBasicStatementResult (rt, exct, effects:: Union{Nothing,Effects} ,
3717+         changes:: Union{Nothing,StateUpdate} , refinements, currsaw_latestworld:: Bool )
3718+         @nospecialize  rt exct refinements
3719+         return  new (rt, exct, effects, changes, refinements, currsaw_latestworld)
3720+     end 
3721+ end 
3722+ 
3723+ function  abstract_eval_basic_statement (interp:: AbstractInterpreter , @nospecialize (stmt), sstate:: StatementState , frame:: InferenceState ,
3724+                                        result:: Union{Nothing,Future{RTEffects}} = nothing )
3725+     rt =  nothing 
3726+     exct =  Bottom
3727+     changes =  nothing 
3728+     refinements =  nothing 
3729+     effects =  nothing 
3730+     currsaw_latestworld =  sstate. saw_latestworld
3731+     if  result != =  nothing 
3732+         @goto  injectresult
3733+     end 
3734+     if  isa (stmt, NewvarNode)
3735+         changes =  StateUpdate (stmt. slot, VarState (Bottom, true ))
3736+     elseif  isa (stmt, PhiNode)
3737+         add_curr_ssaflag! (frame, IR_FLAGS_REMOVABLE)
3738+         #  Implement convergence for PhiNodes. In particular, PhiNodes need to tmerge over
3739+         #  the incoming values from all iterations, but `abstract_eval_phi` will only tmerge
3740+         #  over the first and last iterations. By tmerging in the current old_rt, we ensure that
3741+         #  we will not lose an intermediate value.
3742+         rt =  abstract_eval_phi (interp, stmt, sstate, frame)
3743+         old_rt =  frame. ssavaluetypes[frame. currpc]
3744+         rt =  old_rt ===  NOT_FOUND ?  rt :  tmerge (typeinf_lattice (interp), old_rt, rt)
3745+     else 
3746+         lhs =  nothing 
3747+         if  isexpr (stmt, :(= ))
3748+             lhs =  stmt. args[1 ]
3749+             stmt =  stmt. args[2 ]
3750+         end 
3751+         if  ! isa (stmt, Expr)
3752+             (; rt, exct, effects, refinements) =  abstract_eval_special_value (interp, stmt, sstate, frame)
3753+         else 
3754+             hd =  stmt. head
3755+             if  hd ===  :method 
3756+                 fname =  stmt. args[1 ]
3757+                 if  isa (fname, SlotNumber)
3758+                     changes =  StateUpdate (fname, VarState (Any, false ))
3759+                 end 
3760+             elseif  (hd ===  :code_coverage_effect  || 
3761+                     #  :boundscheck can be narrowed to Bool
3762+                     (hd != =  :boundscheck  &&  is_meta_expr (stmt)))
3763+                 rt =  Nothing
3764+             elseif  hd ===  :latestworld 
3765+                 currsaw_latestworld =  true 
3766+                 rt =  Nothing
3767+             else 
3768+                 result =  abstract_eval_statement_expr (interp, stmt, sstate, frame):: Future{RTEffects} 
3769+                 if  ! isready (result) ||  ! isempty (frame. tasks)
3770+                     return  result
3771+ 
3772+                     @label  injectresult
3773+                     #  reload local variables
3774+                     lhs =  nothing 
3775+                     if  isexpr (stmt, :(= ))
3776+                         lhs =  stmt. args[1 ]
3777+                         stmt =  stmt. args[2 ]
3778+                     end 
3779+                 end 
3780+                 result =  result[]
3781+                 (; rt, exct, effects, refinements) =  result
3782+                 if  effects. noub ===  NOUB_IF_NOINBOUNDS
3783+                     if  has_curr_ssaflag (frame, IR_FLAG_INBOUNDS)
3784+                         effects =  Effects (effects; noub= ALWAYS_FALSE)
3785+                     elseif  ! propagate_inbounds (frame)
3786+                         #  The callee read our inbounds flag, but unless we propagate inbounds,
3787+                         #  we ourselves don't read our parent's inbounds.
3788+                         effects =  Effects (effects; noub= ALWAYS_TRUE)
3789+                     end 
3790+                 end 
3791+                 @assert  ! isa (rt, TypeVar) " unhandled TypeVar" 
3792+                 rt =  maybe_singleton_const (rt)
3793+                 if  ! isempty (frame. pclimitations)
3794+                     if  rt isa  Const ||  rt ===  Union{}
3795+                         empty! (frame. pclimitations)
3796+                     else 
3797+                         rt =  LimitedAccuracy (rt, frame. pclimitations)
3798+                         frame. pclimitations =  IdSet {InferenceState} ()
3799+                     end 
3800+                 end 
3801+             end 
3802+         end 
3803+         if  lhs != =  nothing  &&  rt != =  Bottom
3804+             changes =  StateUpdate (lhs:: SlotNumber , VarState (rt, false ))
3805+         end 
3806+     end 
3807+     return  AbstractEvalBasicStatementResult (rt, exct, effects, changes, refinements, currsaw_latestworld)
3808+ end 
3809+ 
37093810struct  BestguessInfo{Interp<: AbstractInterpreter }
37103811    interp:: Interp 
37113812    bestguess
@@ -3986,14 +4087,16 @@ end
39864087
39874088#  make as much progress on `frame` as possible (without handling cycles)
39884089struct  CurrentState
3989-     result:: Future 
4090+     result:: Future{RTEffects}  
39904091    currstate:: VarTable 
39914092    currsaw_latestworld:: Bool 
39924093    bbstart:: Int 
39934094    bbend:: Int 
3994-     CurrentState (result:: Future , currstate:: VarTable , currsaw_latestworld:: Bool , bbstart:: Int , bbend:: Int ) =  new (result, currstate, currsaw_latestworld, bbstart, bbend)
4095+     CurrentState (result:: Future{RTEffects} , currstate:: VarTable , currsaw_latestworld:: Bool , bbstart:: Int , bbend:: Int ) = 
4096+         new (result, currstate, currsaw_latestworld, bbstart, bbend)
39954097    CurrentState () =  new ()
39964098end 
4099+ 
39974100function  typeinf_local (interp:: AbstractInterpreter , frame:: InferenceState , nextresult:: CurrentState )
39984101    @assert  ! is_inferred (frame)
39994102    W =  frame. ip
@@ -4012,7 +4115,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
40124115        bbend =  nextresult. bbend
40134116        currstate =  nextresult. currstate
40144117        currsaw_latestworld =  nextresult. currsaw_latestworld
4015-         @goto  injectresult
4118+         stmt =  frame. src. code[currpc]
4119+         result =  abstract_eval_basic_statement (interp, stmt, StatementState (currstate, currsaw_latestworld), frame, nextresult. result)
4120+         @goto  injected_result
40164121    end 
40174122
40184123    if  currbb !=  1 
@@ -4165,87 +4270,15 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
41654270            end 
41664271            #  Process non control-flow statements
41674272            @assert  isempty (frame. tasks)
4168-             rt =  nothing 
4169-             exct =  Bottom
4170-             changes =  nothing 
4171-             refinements =  nothing 
4172-             effects =  nothing 
4173-             if  isa (stmt, NewvarNode)
4174-                 changes =  StateUpdate (stmt. slot, VarState (Bottom, true ))
4175-             elseif  isa (stmt, PhiNode)
4176-                 add_curr_ssaflag! (frame, IR_FLAGS_REMOVABLE)
4177-                 #  Implement convergence for PhiNodes. In particular, PhiNodes need to tmerge over
4178-                 #  the incoming values from all iterations, but `abstract_eval_phi` will only tmerge
4179-                 #  over the first and last iterations. By tmerging in the current old_rt, we ensure that
4180-                 #  we will not lose an intermediate value.
4181-                 rt =  abstract_eval_phi (interp, stmt, StatementState (currstate, currsaw_latestworld), frame)
4182-                 old_rt =  frame. ssavaluetypes[currpc]
4183-                 rt =  old_rt ===  NOT_FOUND ?  rt :  tmerge (typeinf_lattice (interp), old_rt, rt)
4273+             sstate =  StatementState (currstate, currsaw_latestworld)
4274+             result =  abstract_eval_basic_statement (interp, stmt, sstate, frame)
4275+             if  result isa  Future{RTEffects}
4276+                 return  CurrentState (result, currstate, currsaw_latestworld, bbstart, bbend)
41844277            else 
4185-                 lhs =  nothing 
4186-                 if  isexpr (stmt, :(= ))
4187-                     lhs =  stmt. args[1 ]
4188-                     stmt =  stmt. args[2 ]
4189-                 end 
4190-                 if  ! isa (stmt, Expr)
4191-                     (; rt, exct, effects, refinements) =  abstract_eval_special_value (interp, stmt, StatementState (currstate, currsaw_latestworld), frame)
4192-                 else 
4193-                     hd =  stmt. head
4194-                     if  hd ===  :method 
4195-                         fname =  stmt. args[1 ]
4196-                         if  isa (fname, SlotNumber)
4197-                             changes =  StateUpdate (fname, VarState (Any, false ))
4198-                         end 
4199-                     elseif  (hd ===  :code_coverage_effect  ||  (
4200-                             hd != =  :boundscheck  &&  #  :boundscheck can be narrowed to Bool
4201-                             is_meta_expr (stmt)))
4202-                         rt =  Nothing
4203-                     elseif  hd ===  :latestworld 
4204-                         currsaw_latestworld =  true 
4205-                         rt =  Nothing
4206-                     else 
4207-                         result =  abstract_eval_statement_expr (interp, stmt, StatementState (currstate, currsaw_latestworld), frame):: Future 
4208-                         if  ! isready (result) ||  ! isempty (frame. tasks)
4209-                             return  CurrentState (result, currstate, currsaw_latestworld, bbstart, bbend)
4210-                             @label  injectresult
4211-                             #  reload local variables
4212-                             stmt =  frame. src. code[currpc]
4213-                             changes =  nothing 
4214-                             lhs =  nothing 
4215-                             if  isexpr (stmt, :(= ))
4216-                                 lhs =  stmt. args[1 ]
4217-                                 stmt =  stmt. args[2 ]
4218-                             end 
4219-                             result =  nextresult. result:: Future{RTEffects} 
4220-                         end 
4221-                         result =  result[]
4222-                         (; rt, exct, effects, refinements) =  result
4223-                         if  effects. noub ===  NOUB_IF_NOINBOUNDS
4224-                             if  has_curr_ssaflag (frame, IR_FLAG_INBOUNDS)
4225-                                 effects =  Effects (effects; noub= ALWAYS_FALSE)
4226-                             elseif  ! propagate_inbounds (frame)
4227-                                 #  The callee read our inbounds flag, but unless we propagate inbounds,
4228-                                 #  we ourselves don't read our parent's inbounds.
4229-                                 effects =  Effects (effects; noub= ALWAYS_TRUE)
4230-                             end 
4231-                         end 
4232-                         @assert  ! isa (rt, TypeVar) " unhandled TypeVar" 
4233-                         rt =  maybe_singleton_const (rt)
4234-                         if  ! isempty (frame. pclimitations)
4235-                             if  rt isa  Const ||  rt ===  Union{}
4236-                                 empty! (frame. pclimitations)
4237-                             else 
4238-                                 rt =  LimitedAccuracy (rt, frame. pclimitations)
4239-                                 frame. pclimitations =  IdSet {InferenceState} ()
4240-                             end 
4241-                         end 
4242-                     end 
4243-                 end 
4244-                 effects ===  nothing  ||  merge_override_effects! (interp, effects, frame)
4245-                 if  lhs != =  nothing  &&  rt != =  Bottom
4246-                     changes =  StateUpdate (lhs:: SlotNumber , VarState (rt, false ))
4247-                 end 
4278+                 @label  injected_result
4279+                 (; rt, exct, effects, changes, refinements, currsaw_latestworld) =  result
42484280            end 
4281+             effects ===  nothing  ||  merge_override_effects! (interp, effects, frame)
42494282            if  ! has_curr_ssaflag (frame, IR_FLAG_NOTHROW)
42504283                if  exct != =  Union{}
42514284                    update_exc_bestguess! (interp, exct, frame)
0 commit comments