Skip to content

Commit b7f6cc0

Browse files
oxinaboxmzgubic
andauthored
Support extra hygiene for signature(::Methood) (#25)
* Support extra hygiene for signature(::Methood) * Update src/method.jl Co-authored-by: Miha Zgubic <mzgubic@users.noreply.github.com> Co-authored-by: Miha Zgubic <mzgubic@users.noreply.github.com>
1 parent 3d15ed4 commit b7f6cc0

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

src/method.jl

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,23 @@ with [`CodeTracking.definition`](https://github.com/timholy/CodeTracking.jl).
2727
The dictionary of components returned by `signature` match those returned by
2828
[`splitdef`](@ref) and include all that are required by [`combinedef`](@ref), except for
2929
the `:body` component.
30+
31+
# keywords
32+
33+
- `extra_hygiene=false`: if set to `true` this forces name-hygiene on the `TypeVar`s in
34+
`UnionAll`s, regenerating each with a unique name via `gensym`. This shouldn't actually
35+
be required as they are scoped such that they are not supposed to leak. However, there is
36+
a long-standing [julia bug](https://github.com/JuliaLang/julia/issues/39876) that means
37+
they do leak if they clash with function type-vars.
3038
"""
31-
function signature(m::Method)
39+
function signature(m::Method; extra_hygiene=false)
40+
sig = extra_hygiene ? _truly_rename_unionall(m.sig) : m.sig
41+
3242
def = Dict{Symbol, Any}()
3343
def[:name] = m.name
3444

35-
def[:args] = arguments(m)
36-
def[:whereparams] = where_parameters(m)
45+
def[:args] = arguments(m, sig)
46+
def[:whereparams] = where_parameters(sig)
3747
def[:params] = type_parameters(m)
3848
def[:kwargs] = kwargs(m)
3949

@@ -168,9 +178,9 @@ function name_of_type(x::Union)
168178
return :(Union{$(parameter_names...)})
169179
end
170180

171-
function arguments(m::Method)
181+
function arguments(m::Method, sig=m.sig)
172182
arg_names = argument_names(m)
173-
arg_types = argument_types(m)
183+
arg_types = argument_types(sig)
174184
map(arg_names, arg_types) do name, type
175185
has_name = name !== Symbol("#unused#")
176186
type_name = name_of_type(type)

test/method.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,26 @@ struct TestCallableStruct end
249249
)
250250
end
251251

252+
@testset "extra_hygiene" begin
253+
hy1(::T,::Array) where T = 2
254+
no_hygiene = signature(only_method(hy1))
255+
@test no_hygiene == Dict(
256+
:name => :hy1,
257+
:args => Expr[:(::T), :(::(Array{T, N} where {T, N}))],
258+
:whereparams => Any[:T],
259+
)
260+
hygiene = signature(only_method(hy1); extra_hygiene=true)
261+
@test no_hygiene[:name] == hygiene[:name]
262+
@test length(no_hygiene[:args]) == 2
263+
@test no_hygiene[:args][1] != hygiene[:args][1] # different Symbols
264+
@test no_hygiene[:args][2] == hygiene[:args][2]
265+
266+
@test length(no_hygiene[:whereparams]) == 1
267+
@test no_hygiene[:whereparams] != hygiene[:whereparams] # different Symbols
268+
# very coarse test to make sure the renamed arg is in the expression it should be
269+
@test occursin(string(no_hygiene[:whereparams][1]), string(no_hygiene[:args][1]))
270+
end
271+
252272
@testset "signature(type_tuple)" begin
253273
# our tests here are much less comprehensive than for `signature(::Method)`
254274
# but that is OK, as most of the code is shared between the two

0 commit comments

Comments
 (0)