@@ -12,9 +12,11 @@ const _REF_NAME = Ref.body.name
1212# logic #
1313# ########
1414
15- # see if the inference result might affect the final answer
16- call_result_unused (frame:: InferenceState , pc:: LineNum = frame. currpc) =
17- isexpr (frame. src. code[frame. currpc], :call ) && isempty (frame. ssavalue_uses[pc])
15+ # See if the inference result of the current statement's result value might affect
16+ # the final answer for the method (aside from optimization potential and exceptions).
17+ # To do that, we need to check both for slot assignment and SSA usage.
18+ call_result_unused (frame:: InferenceState ) =
19+ isexpr (frame. src. code[frame. currpc], :call ) && isempty (frame. ssavalue_uses[frame. currpc])
1820
1921# check if this return type is improvable (i.e. whether it's possible that with
2022# more information, we might get a more precise type)
@@ -192,6 +194,16 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
192194 end
193195 end
194196 # print("=> ", rettype, "\n")
197+ if rettype isa LimitedAccuracy
198+ union! (sv. pclimitations, rettype. causes)
199+ rettype = rettype. typ
200+ end
201+ if ! isempty (sv. pclimitations) # remove self, if present
202+ delete! (sv. pclimitations, sv)
203+ for caller in sv. callers_in_cycle
204+ delete! (sv. pclimitations, caller)
205+ end
206+ end
195207 return CallMeta (rettype, info)
196208end
197209
@@ -313,7 +325,6 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nosp
313325 inf_result = InferenceResult (mi, argtypes)
314326 frame = InferenceState (inf_result, #= cache=# false , interp)
315327 frame === nothing && return Any # this is probably a bad generated function (unsound), but just ignore it
316- frame. limited = true
317328 frame. parent = sv
318329 push! (inf_cache, inf_result)
319330 typeinf (interp, frame) || return Any
@@ -394,7 +405,7 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
394405 parent = parent:: InferenceState
395406 parent_method2 = parent. src. method_for_inference_limit_heuristics # limit only if user token match
396407 parent_method2 isa Method || (parent_method2 = nothing ) # Union{Method, Nothing}
397- if (parent. cached || parent. limited ) && parent. linfo. def === sv. linfo. def && sv_method2 === parent_method2
408+ if (parent. cached || parent. parent != = nothing ) && parent. linfo. def === sv. linfo. def && sv_method2 === parent_method2
398409 topmost = infstate
399410 edgecycle = true
400411 end
@@ -443,7 +454,8 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
443454 # (non-typically, this means that we lose the ability to detect a guaranteed StackOverflow in some cases)
444455 return Any, true , nothing
445456 end
446- poison_callstack (sv, topmost:: InferenceState , true )
457+ topmost = topmost:: InferenceState
458+ poison_callstack (sv, topmost. parent === nothing ? topmost : topmost. parent)
447459 sig = newsig
448460 sparams = svec ()
449461 end
@@ -1124,7 +1136,12 @@ function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), vtyp
11241136 if isa (e, Expr)
11251137 return abstract_eval_value_expr (interp, e, vtypes, sv)
11261138 else
1127- return abstract_eval_special_value (interp, e, vtypes, sv)
1139+ typ = abstract_eval_special_value (interp, e, vtypes, sv)
1140+ if typ isa LimitedAccuracy
1141+ union! (sv. pclimitations, typ. causes)
1142+ typ = typ. typ
1143+ end
1144+ return typ
11281145 end
11291146end
11301147
@@ -1247,13 +1264,21 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
12471264 end
12481265 end
12491266 else
1250- return abstract_eval_value_expr (interp, e, vtypes, sv)
1267+ t = abstract_eval_value_expr (interp, e, vtypes, sv)
12511268 end
12521269 @assert ! isa (t, TypeVar)
12531270 if isa (t, DataType) && isdefined (t, :instance )
12541271 # replace singleton types with their equivalent Const object
12551272 t = Const (t. instance)
12561273 end
1274+ if ! isempty (sv. pclimitations)
1275+ if t isa Const || t === Union{}
1276+ empty! (sv. pclimitations)
1277+ else
1278+ t = LimitedAccuracy (t, sv. pclimitations)
1279+ sv. pclimitations = IdSet {InferenceState} ()
1280+ end
1281+ end
12571282 return t
12581283end
12591284
@@ -1308,10 +1333,18 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
13081333 elseif isa (stmt, GotoIfNot)
13091334 condt = abstract_eval_value (interp, stmt. cond, s[pc], frame)
13101335 if condt === Bottom
1336+ empty! (frame. pclimitations)
13111337 break
13121338 end
13131339 condval = maybe_extract_const_bool (condt)
13141340 l = stmt. dest:: Int
1341+ if ! isempty (frame. pclimitations)
1342+ # we can't model the possible effect of control
1343+ # dependencies on the return value, so we propagate it
1344+ # directly to all the return values (unless we error first)
1345+ condval isa Bool || union! (frame. limitations, frame. pclimitations)
1346+ empty! (frame. pclimitations)
1347+ end
13151348 # constant conditions
13161349 if condval === true
13171350 elseif condval === false
@@ -1346,6 +1379,14 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
13461379 # and is valid inter-procedurally
13471380 rt = widenconst (rt)
13481381 end
1382+ # copy limitations to return value
1383+ if ! isempty (frame. pclimitations)
1384+ union! (frame. limitations, frame. pclimitations)
1385+ empty! (frame. pclimitations)
1386+ end
1387+ if ! isempty (frame. limitations)
1388+ rt = LimitedAccuracy (rt, copy (frame. limitations))
1389+ end
13491390 if tchanged (rt, frame. bestguess)
13501391 # new (wider) return type for frame
13511392 frame. bestguess = tmerge (frame. bestguess, rt)
@@ -1420,6 +1461,8 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
14201461 end
14211462 end
14221463
1464+ @assert isempty (frame. pclimitations) " unhandled LimitedAccuracy"
1465+
14231466 if t === nothing
14241467 # mark other reached expressions as `Any` to indicate they don't throw
14251468 frame. src. ssavaluetypes[pc] = Any
0 commit comments