Skip to content

Commit c3195cd

Browse files
authored
Add invalidation-insulating accessors (#101)
Because IdDict's `setindex!` uses `@nospecialize` on both the key and value, it makes callers vulnerable to invalidation. These convenience utilities allow callers to insulate themselves from invalidation. These will be used by Revise.
1 parent e902a6d commit c3195cd

File tree

3 files changed

+14
-2
lines changed

3 files changed

+14
-2
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "CodeTracking"
22
uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2"
33
authors = ["Tim Holy <[email protected]>"]
4-
version = "1.1.2"
4+
version = "1.2.0"
55

66
[deps]
77
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

src/utils.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,10 @@ end
149149
getpkgid(project::AbstractString, libname) = getpkgid(Base.project_deps_get(project, libname), libname)
150150
getpkgid(id::PkgId, libname) = id
151151
getpkgid(uuid::UUID, libname) = PkgId(uuid, libname)
152+
153+
# Because IdDict's `setindex!` uses `@nospecialize` on both the key and value, it makes
154+
# callers vulnerable to invalidation. These convenience utilities allow callers to insulate
155+
# themselves from invalidation. These are used by Revise.
156+
# example package triggering invalidation: StaticArrays (new `convert(Type{Array{T,N}}, ::AbstractArray)` methods)
157+
invoked_setindex!(dct::IdDict{K,V}, @nospecialize(val), @nospecialize(key)) where {K,V} = Base.invokelatest(setindex!, dct, val, key)::typeof(dct)
158+
invoked_get!(::Type{T}, dct::IdDict{K,V}, @nospecialize(key)) where {K,V,T<:V} = Base.invokelatest(get!, T, dct, key)::V

test/runtests.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,11 @@ isdefined(Main, :Revise) ? Main.Revise.includet("script.jl") : include("script.j
162162
deleteat!(ex.args[2].args, 1) # delete the file & line number info
163163
eval(ex)
164164
@test code_string(f_no_linenum, (Int,)) === nothing
165+
166+
# Invalidation-insulating methods used by Revise and perhaps others
167+
d = IdDict{Union{String,Symbol},Union{Function,Vector{Function}}}()
168+
CodeTracking.invoked_setindex!(d, sin, "sin")
169+
@test CodeTracking.invoked_get!(Vector{Function}, d, :cos) isa Vector{Function}
165170
end
166171

167172
@testset "With Revise" begin
@@ -281,7 +286,7 @@ struct Functor end
281286
@test body == "(::Functor)(x, y) = x+y"
282287
end
283288

284-
if VERSION >= v"1.6.0"
289+
if v"1.6" <= VERSION < v"1.9"
285290
@testset "kwfuncs" begin
286291
body, _ = CodeTracking.definition(String, @which fkw(; x=1))
287292
@test body == """

0 commit comments

Comments
 (0)