@@ -12,9 +12,11 @@ const _REF_NAME = Ref.body.name
12
12
# logic #
13
13
# ########
14
14
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])
18
20
19
21
# check if this return type is improvable (i.e. whether it's possible that with
20
22
# more information, we might get a more precise type)
@@ -192,6 +194,16 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
192
194
end
193
195
end
194
196
# 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
195
207
return CallMeta (rettype, info)
196
208
end
197
209
@@ -313,7 +325,6 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nosp
313
325
inf_result = InferenceResult (mi, argtypes)
314
326
frame = InferenceState (inf_result, #= cache=# false , interp)
315
327
frame === nothing && return Any # this is probably a bad generated function (unsound), but just ignore it
316
- frame. limited = true
317
328
frame. parent = sv
318
329
push! (inf_cache, inf_result)
319
330
typeinf (interp, frame) || return Any
@@ -394,7 +405,7 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
394
405
parent = parent:: InferenceState
395
406
parent_method2 = parent. src. method_for_inference_limit_heuristics # limit only if user token match
396
407
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
398
409
topmost = infstate
399
410
edgecycle = true
400
411
end
@@ -443,7 +454,8 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
443
454
# (non-typically, this means that we lose the ability to detect a guaranteed StackOverflow in some cases)
444
455
return Any, true , nothing
445
456
end
446
- poison_callstack (sv, topmost:: InferenceState , true )
457
+ topmost = topmost:: InferenceState
458
+ poison_callstack (sv, topmost. parent === nothing ? topmost : topmost. parent)
447
459
sig = newsig
448
460
sparams = svec ()
449
461
end
@@ -1124,7 +1136,12 @@ function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), vtyp
1124
1136
if isa (e, Expr)
1125
1137
return abstract_eval_value_expr (interp, e, vtypes, sv)
1126
1138
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
1128
1145
end
1129
1146
end
1130
1147
@@ -1247,13 +1264,21 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
1247
1264
end
1248
1265
end
1249
1266
else
1250
- return abstract_eval_value_expr (interp, e, vtypes, sv)
1267
+ t = abstract_eval_value_expr (interp, e, vtypes, sv)
1251
1268
end
1252
1269
@assert ! isa (t, TypeVar)
1253
1270
if isa (t, DataType) && isdefined (t, :instance )
1254
1271
# replace singleton types with their equivalent Const object
1255
1272
t = Const (t. instance)
1256
1273
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
1257
1282
return t
1258
1283
end
1259
1284
@@ -1308,10 +1333,18 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1308
1333
elseif isa (stmt, GotoIfNot)
1309
1334
condt = abstract_eval_value (interp, stmt. cond, s[pc], frame)
1310
1335
if condt === Bottom
1336
+ empty! (frame. pclimitations)
1311
1337
break
1312
1338
end
1313
1339
condval = maybe_extract_const_bool (condt)
1314
1340
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
1315
1348
# constant conditions
1316
1349
if condval === true
1317
1350
elseif condval === false
@@ -1346,6 +1379,14 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1346
1379
# and is valid inter-procedurally
1347
1380
rt = widenconst (rt)
1348
1381
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
1349
1390
if tchanged (rt, frame. bestguess)
1350
1391
# new (wider) return type for frame
1351
1392
frame. bestguess = tmerge (frame. bestguess, rt)
@@ -1420,6 +1461,8 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1420
1461
end
1421
1462
end
1422
1463
1464
+ @assert isempty (frame. pclimitations) " unhandled LimitedAccuracy"
1465
+
1423
1466
if t === nothing
1424
1467
# mark other reached expressions as `Any` to indicate they don't throw
1425
1468
frame. src. ssavaluetypes[pc] = Any
0 commit comments