@@ -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
@@ -1129,7 +1141,12 @@ function abstract_eval_value(interp::AbstractInterpreter, @nospecialize(e), vtyp
1129
1141
if isa (e, Expr)
1130
1142
return abstract_eval_value_expr (interp, e, vtypes, sv)
1131
1143
else
1132
- return abstract_eval_special_value (interp, e, vtypes, sv)
1144
+ typ = abstract_eval_special_value (interp, e, vtypes, sv)
1145
+ if typ isa LimitedAccuracy
1146
+ union! (sv. pclimitations, typ. causes)
1147
+ typ = typ. typ
1148
+ end
1149
+ return typ
1133
1150
end
1134
1151
end
1135
1152
@@ -1252,13 +1269,21 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e),
1252
1269
end
1253
1270
end
1254
1271
else
1255
- return abstract_eval_value_expr (interp, e, vtypes, sv)
1272
+ t = abstract_eval_value_expr (interp, e, vtypes, sv)
1256
1273
end
1257
1274
@assert ! isa (t, TypeVar)
1258
1275
if isa (t, DataType) && isdefined (t, :instance )
1259
1276
# replace singleton types with their equivalent Const object
1260
1277
t = Const (t. instance)
1261
1278
end
1279
+ if ! isempty (sv. pclimitations)
1280
+ if t isa Const || t === Union{}
1281
+ empty! (sv. pclimitations)
1282
+ else
1283
+ t = LimitedAccuracy (t, sv. pclimitations)
1284
+ sv. pclimitations = IdSet {InferenceState} ()
1285
+ end
1286
+ end
1262
1287
return t
1263
1288
end
1264
1289
@@ -1313,10 +1338,18 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1313
1338
elseif isa (stmt, GotoIfNot)
1314
1339
condt = abstract_eval_value (interp, stmt. cond, s[pc], frame)
1315
1340
if condt === Bottom
1341
+ empty! (frame. pclimitations)
1316
1342
break
1317
1343
end
1318
1344
condval = maybe_extract_const_bool (condt)
1319
1345
l = stmt. dest:: Int
1346
+ if ! isempty (frame. pclimitations)
1347
+ # we can't model the possible effect of control
1348
+ # dependencies on the return value, so we propagate it
1349
+ # directly to all the return values (unless we error first)
1350
+ condval isa Bool || union! (frame. limitations, frame. pclimitations)
1351
+ empty! (frame. pclimitations)
1352
+ end
1320
1353
# constant conditions
1321
1354
if condval === true
1322
1355
elseif condval === false
@@ -1351,6 +1384,14 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1351
1384
# and is valid inter-procedurally
1352
1385
rt = widenconst (rt)
1353
1386
end
1387
+ # copy limitations to return value
1388
+ if ! isempty (frame. pclimitations)
1389
+ union! (frame. limitations, frame. pclimitations)
1390
+ empty! (frame. pclimitations)
1391
+ end
1392
+ if ! isempty (frame. limitations)
1393
+ rt = LimitedAccuracy (rt, copy (frame. limitations))
1394
+ end
1354
1395
if tchanged (rt, frame. bestguess)
1355
1396
# new (wider) return type for frame
1356
1397
frame. bestguess = tmerge (frame. bestguess, rt)
@@ -1425,6 +1466,8 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
1425
1466
end
1426
1467
end
1427
1468
1469
+ @assert isempty (frame. pclimitations) " unhandled LimitedAccuracy"
1470
+
1428
1471
if t === nothing
1429
1472
# mark other reached expressions as `Any` to indicate they don't throw
1430
1473
frame. src. ssavaluetypes[pc] = Any
0 commit comments