@@ -293,6 +293,51 @@ function get_method_from_edge(@nospecialize t)
293
293
end
294
294
end
295
295
296
+ # Check if method2 is in method1's interferences set
297
+ # Returns true if method2 is found (meaning !morespecific(method1, method2))
298
+ function method_in_interferences (method1:: Method , method2:: Method )
299
+ interferences = method1. interferences
300
+ for k = 1 : length (interferences)
301
+ isassigned (interferences, k) || break
302
+ interference_method = interferences[k]:: Method
303
+ if interference_method === method2
304
+ return true
305
+ end
306
+ end
307
+ return false
308
+ end
309
+
310
+ # Check if method1 is more specific than method2 via the interference graph
311
+ function method_morespecific_via_interferences (method1:: Method , method2:: Method )
312
+ if method1 === method2 || method_in_interferences (method1, method2)
313
+ return false
314
+ end
315
+ return method_in_interferences_recursive (method2, method1, IdSet {Method} ())
316
+ end
317
+
318
+ # Returns true if method2 is in method1's interferences (meaning !morespecific(method2, method1))
319
+ function method_in_interferences_recursive (method2:: Method , method1:: Method , visited:: IdSet{Method} )
320
+ @assert ! method_in_interferences (method1, method2)
321
+ if method_in_interferences (method2, method1)
322
+ return true
323
+ end
324
+
325
+ # Recursively check through interference graph
326
+ push! (visited, method2)
327
+ interferences = method1. interferences
328
+ for k = 1 : length (interferences)
329
+ isassigned (interferences, k) || break
330
+ method3 = interferences[k]:: Method
331
+ if ! (method3 in visited)
332
+ if method_in_interferences_recursive (method3, method1, visited)
333
+ return true # found method1 in the interference graph
334
+ end
335
+ end
336
+ end
337
+
338
+ return false
339
+ end
340
+
296
341
function verify_call (@nospecialize (sig), expecteds:: Core.SimpleVector , i:: Int , n:: Int , world:: UInt , fully_covers:: Bool , matches:: Vector{Any} )
297
342
# verify that these edges intersect with the same methods as before
298
343
mi = nothing
@@ -344,14 +389,19 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
344
389
interference_fast_path_success = true
345
390
if ! fully_covers
346
391
# If expected doesn't fully cover, then need to make sure that no new methods are possibly present
392
+ # by checking that either METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC is set on each method,
393
+ # or that there is another method in the expecteds list that fully upwards-covered it.
347
394
for j = 1 : n
348
395
meth = get_method_from_edge (expecteds[i+ j- 1 ])
349
396
if ! iszero (meth. dispatch_status & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC)
350
397
interference_fast_path_success = false
351
398
for j = reverse (1 : n)
352
399
meth2 = get_method_from_edge (expecteds[i+ j- 1 ])
353
- if meth != = meth2 && typeintersect (sig, meth. sig) <: meth2.sig && ! (meth2. sig <: meth.sig )
354
- interference_fast_path_success = true
400
+ if method_morespecific_via_interferences (meth, meth2)
401
+ if sig <: meth2.sig || (sig != = meth. sig && meth. sig <: meth2.sig ) # eg. faster (but less precise) `typeintersect(sig, meth.sig) <: meth2.sig` test
402
+ interference_fast_path_success = true
403
+ break
404
+ end
355
405
end
356
406
end
357
407
if ! interference_fast_path_success
@@ -360,6 +410,7 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
360
410
end
361
411
end
362
412
end
413
+ # If it didn't fail yet, then check that all interference methods are either expected, or not applicable.
363
414
if interference_fast_path_success
364
415
local interference_minworld:: UInt = 1
365
416
for j = 1 : n
@@ -387,10 +438,10 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
387
438
if ! found_in_expecteds
388
439
ti = typeintersect (sig, interference_method. sig)
389
440
if ! (ti === Union{})
390
- # try looking for a different expected method that fully hides the interference_method anyways
441
+ # try looking for a different expected method that fully covers this interference_method anyways over their intersection
391
442
for j = 1 : n
392
443
meth2 = get_method_from_edge (expecteds[i+ j- 1 ])
393
- if meth2 != = interference_method && ti <: meth2.sig && morespecific (meth2, interference_method)
444
+ if method_morespecific_via_interferences ( meth2, interference_method) && ti <: meth2.sig
394
445
found_in_expecteds = true
395
446
break
396
447
end
0 commit comments