@@ -3706,6 +3706,107 @@ function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
3706
3706
return typ
3707
3707
end
3708
3708
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
+
3709
3810
struct BestguessInfo{Interp<: AbstractInterpreter }
3710
3811
interp:: Interp
3711
3812
bestguess
@@ -3986,14 +4087,16 @@ end
3986
4087
3987
4088
# make as much progress on `frame` as possible (without handling cycles)
3988
4089
struct CurrentState
3989
- result:: Future
4090
+ result:: Future{RTEffects}
3990
4091
currstate:: VarTable
3991
4092
currsaw_latestworld:: Bool
3992
4093
bbstart:: Int
3993
4094
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)
3995
4097
CurrentState () = new ()
3996
4098
end
4099
+
3997
4100
function typeinf_local (interp:: AbstractInterpreter , frame:: InferenceState , nextresult:: CurrentState )
3998
4101
@assert ! is_inferred (frame)
3999
4102
W = frame. ip
@@ -4012,7 +4115,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
4012
4115
bbend = nextresult. bbend
4013
4116
currstate = nextresult. currstate
4014
4117
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
4016
4121
end
4017
4122
4018
4123
if currbb != 1
@@ -4165,87 +4270,15 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
4165
4270
end
4166
4271
# Process non control-flow statements
4167
4272
@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)
4184
4277
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
4248
4280
end
4281
+ effects === nothing || merge_override_effects! (interp, effects, frame)
4249
4282
if ! has_curr_ssaflag (frame, IR_FLAG_NOTHROW)
4250
4283
if exct != = Union{}
4251
4284
update_exc_bestguess! (interp, exct, frame)
0 commit comments