@@ -199,3 +199,115 @@ end
199
199
notify (c26506_1)
200
200
wait (c26506_2)
201
201
@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
+ applyf (c) = f (c[1 ])
262
+ f (:: Int ) = 1
263
+ f (:: Float64 ) = 2
264
+ applyf ([1 ])
265
+ applyf ([1.0 ])
266
+ applyf (Any[1 ])
267
+ wint = worlds (instance (applyf, (Vector{Int},)))
268
+ wfloat = worlds (instance (applyf, (Vector{Float64},)))
269
+ wany2 = worlds (instance (applyf, (Vector{Any},)))
270
+ src2 = code_typed (applyf, (Vector{Any},))[1 ]
271
+ f (:: String ) = 3
272
+ applyf (Any[1 ])
273
+ @test worlds (instance (applyf, (Vector{Int},))) == wint
274
+ @test worlds (instance (applyf, (Vector{Float64},))) == wfloat
275
+ wany3 = worlds (instance (applyf, (Vector{Any},)))
276
+ src3 = code_typed (applyf, (Vector{Any},))[1 ]
277
+ @test (wany3 == wany2) == equal (src3, src2) # don't invalidate unless you also change the code
278
+ f (:: AbstractVector ) = 4 # next test would pass if this were ::Vector{Int}
279
+ applyf (Any[1 ])
280
+ wany4 = worlds (instance (applyf, (Vector{Any},)))
281
+ src4 = code_typed (applyf, (Vector{Any},))[1 ]
282
+ @test_broken (wany4 == wany3) == equal (src4, src3)
283
+ f (:: Dict ) = 5
284
+ applyf (Any[1 ])
285
+ wany5 = worlds (instance (applyf, (Vector{Any},)))
286
+ src5 = code_typed (applyf, (Vector{Any},))[1 ]
287
+ @test (wany5 == wany4) == equal (src5, src4)
288
+ f (:: Set ) = 6 # with current settings, this shouldn't invalidate
289
+ applyf (Any[1 ])
290
+ wany6 = worlds (instance (applyf, (Vector{Any},)))
291
+ src6 = code_typed (applyf, (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 FixedPoint{T <: Integer } <: Real end
301
+ struct Normed <: FixedPoint{UInt8}
302
+ i:: UInt8
303
+ Normed (i:: Integer , _) = new (i % UInt8)
304
+ end
305
+ (:: Type{X} )(x:: Real ) where X<: FixedPoint{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 Colorant end
312
+ Base. convert (:: Type{C} , c) where C<: Colorant = false
313
+ @test_broken worlds (mi) == w
0 commit comments