Skip to content

Commit f65561f

Browse files
authored
Add some broken tests for invalidation (#35855)
1 parent 855a08b commit f65561f

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

base/expr.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ end
7777

7878
==(x::Expr, y::Expr) = x.head === y.head && isequal(x.args, y.args)
7979
==(x::QuoteNode, y::QuoteNode) = isequal(x.value, y.value)
80+
==(stmt1::Core.PhiNode, stmt2::Core.PhiNode) = stmt1.edges == stmt2.edges && stmt1.values == stmt2.values
8081

8182
"""
8283
macroexpand(m::Module, x; recursive=true)

test/worlds.jl

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,115 @@ end
199199
notify(c26506_1)
200200
wait(c26506_2)
201201
@test result26506[1] == 3
202+
203+
204+
## Invalidation tests
205+
206+
function instance(f, types)
207+
m = which(f, types)
208+
inst = nothing
209+
tt = Tuple{typeof(f), types...}
210+
specs = m.specializations
211+
if isa(specs, Nothing)
212+
elseif isa(specs, Core.SimpleVector)
213+
for i = 1:length(specs)
214+
if isassigned(specs, i)
215+
mi = specs[i]::Core.MethodInstance
216+
if mi.specTypes === tt
217+
inst = mi
218+
break
219+
end
220+
end
221+
end
222+
else
223+
Base.visit(specs) do mi
224+
if mi.specTypes === tt
225+
inst = mi
226+
end
227+
end
228+
end
229+
return inst
230+
end
231+
232+
function worlds(mi::Core.MethodInstance)
233+
w = Tuple{UInt,UInt}[]
234+
if isdefined(mi, :cache)
235+
ci = mi.cache
236+
push!(w, (ci.min_world, ci.max_world))
237+
while isdefined(ci, :next)
238+
ci = ci.next
239+
push!(w, (ci.min_world, ci.max_world))
240+
end
241+
end
242+
return w
243+
end
244+
245+
# avoid adding this to Base
246+
function equal(ci1::Core.CodeInfo, ci2::Core.CodeInfo)
247+
return ci1.code == ci2.code &&
248+
ci1.codelocs == ci2.codelocs &&
249+
ci1.ssavaluetypes == ci2.ssavaluetypes &&
250+
ci1.ssaflags == ci2.ssaflags &&
251+
ci1.method_for_inference_limit_heuristics == ci2.method_for_inference_limit_heuristics &&
252+
ci1.linetable == ci2.linetable &&
253+
ci1.slotnames == ci2.slotnames &&
254+
ci1.slotflags == ci2.slotflags &&
255+
ci1.slottypes == ci2.slottypes &&
256+
ci1.rettype == ci2.rettype
257+
end
258+
equal(p1::Pair, p2::Pair) = p1.second == p2.second && equal(p1.first, p2.first)
259+
260+
## Union-splitting based on state-of-the-world: check that each invalidation corresponds to new code
261+
applyf35855(c) = f35855(c[1])
262+
f35855(::Int) = 1
263+
f35855(::Float64) = 2
264+
applyf35855([1])
265+
applyf35855([1.0])
266+
applyf35855(Any[1])
267+
wint = worlds(instance(applyf35855, (Vector{Int},)))
268+
wfloat = worlds(instance(applyf35855, (Vector{Float64},)))
269+
wany2 = worlds(instance(applyf35855, (Vector{Any},)))
270+
src2 = code_typed(applyf35855, (Vector{Any},))[1]
271+
f35855(::String) = 3
272+
applyf35855(Any[1])
273+
@test worlds(instance(applyf35855, (Vector{Int},))) == wint
274+
@test worlds(instance(applyf35855, (Vector{Float64},))) == wfloat
275+
wany3 = worlds(instance(applyf35855, (Vector{Any},)))
276+
src3 = code_typed(applyf35855, (Vector{Any},))[1]
277+
@test (wany3 == wany2) == equal(src3, src2) # don't invalidate unless you also change the code
278+
f35855(::AbstractVector) = 4 # next test would pass if this were ::Vector{Int}
279+
applyf35855(Any[1])
280+
wany4 = worlds(instance(applyf35855, (Vector{Any},)))
281+
src4 = code_typed(applyf35855, (Vector{Any},))[1]
282+
@test_broken (wany4 == wany3) == equal(src4, src3)
283+
f35855(::Dict) = 5
284+
applyf35855(Any[1])
285+
wany5 = worlds(instance(applyf35855, (Vector{Any},)))
286+
src5 = code_typed(applyf35855, (Vector{Any},))[1]
287+
@test (wany5 == wany4) == equal(src5, src4)
288+
f35855(::Set) = 6 # with current settings, this shouldn't invalidate
289+
applyf35855(Any[1])
290+
wany6 = worlds(instance(applyf35855, (Vector{Any},)))
291+
src6 = code_typed(applyf35855, (Vector{Any},))[1]
292+
@test (wany6 == wany5) == equal(src6, src5)
293+
294+
## ambiguities do not trigger invalidation
295+
using Printf
296+
Printf.gen("%f")
297+
mi = instance(+, (AbstractChar, UInt8))
298+
w = worlds(mi)
299+
300+
abstract type FixedPoint35855{T <: Integer} <: Real end
301+
struct Normed35855 <: FixedPoint35855{UInt8}
302+
i::UInt8
303+
Normed35855(i::Integer, _) = new(i % UInt8)
304+
end
305+
(::Type{X})(x::Real) where X<:FixedPoint35855{T} where T = X(round(T, typemax(T)*x), 0)
306+
307+
@test_broken worlds(mi) == w
308+
309+
mi = instance(convert, (Type{Nothing}, String))
310+
w = worlds(mi)
311+
abstract type Colorant35855 end
312+
Base.convert(::Type{C}, c) where C<:Colorant35855 = false
313+
@test_broken worlds(mi) == w

0 commit comments

Comments
 (0)