Skip to content

Commit c365dd1

Browse files
committed
wip
1 parent 13560a7 commit c365dd1

File tree

2 files changed

+274
-200
lines changed

2 files changed

+274
-200
lines changed

base/staticdata.jl

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,51 @@ function get_method_from_edge(@nospecialize t)
293293
end
294294
end
295295

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+
296341
function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n::Int, world::UInt, fully_covers::Bool, matches::Vector{Any})
297342
# verify that these edges intersect with the same methods as before
298343
mi = nothing
@@ -344,14 +389,19 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
344389
interference_fast_path_success = true
345390
if !fully_covers
346391
# 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.
347394
for j = 1:n
348395
meth = get_method_from_edge(expecteds[i+j-1])
349396
if !iszero(meth.dispatch_status & METHOD_SIG_LATEST_HAS_NOTMORESPECIFIC)
350397
interference_fast_path_success = false
351398
for j = reverse(1:n)
352399
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
355405
end
356406
end
357407
if !interference_fast_path_success
@@ -360,6 +410,7 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
360410
end
361411
end
362412
end
413+
# If it didn't fail yet, then check that all interference methods are either expected, or not applicable.
363414
if interference_fast_path_success
364415
local interference_minworld::UInt = 1
365416
for j = 1:n
@@ -387,10 +438,10 @@ function verify_call(@nospecialize(sig), expecteds::Core.SimpleVector, i::Int, n
387438
if !found_in_expecteds
388439
ti = typeintersect(sig, interference_method.sig)
389440
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
391442
for j = 1:n
392443
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
394445
found_in_expecteds = true
395446
break
396447
end

0 commit comments

Comments
 (0)