Skip to content

Commit ca6b948

Browse files
authored
Merge pull request #12 from invenia/ox/overhaul
Overhaul name_of_type
2 parents 4b175b0 + cba2e15 commit ca6b948

File tree

3 files changed

+61
-14
lines changed

3 files changed

+61
-14
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ExprTools"
22
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
33
authors = ["Invenia Technical Computing"]
4-
version = "0.1.2"
4+
version = "0.1.3"
55

66
[compat]
77
julia = "1"

src/method.jl

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,24 +58,61 @@ function argument_types(sig)
5858
return parameters(sig)[2:end]
5959
end
6060

61-
name_of_type(x) = x
61+
module DummyThatHasOnlyDefaultImports end # for working out visibility
62+
63+
function name_of_module(m::Module)
64+
if Base.is_root_module(m)
65+
return nameof(m)
66+
else
67+
return :($(name_of_module(parentmodule(m))).$(nameof(m)))
68+
end
69+
end
70+
function name_of_type(x::Core.TypeName)
71+
# TODO: could let user pass this in, then we could be using what is inscope for them
72+
# but this is not important as we will give a correct (if overly verbose) output as is.
73+
from = DummyThatHasOnlyDefaultImports
74+
if Base.isvisible(x.name, x.module, from) # avoid qualifying things that are in scope
75+
return x.name
76+
else
77+
return :($(name_of_module(x.module)).$(x.name))
78+
end
79+
end
80+
81+
name_of_type(x::Symbol) = QuoteNode(x) # Literal type-param e.g. `Val{:foo}`
82+
function name_of_type(x::T) where T # Literal type-param e.g. `Val{1}`
83+
# If this error is thrown, there is an issue with out implementation
84+
isbits(x) || throw(DomainError((x, T), "not a valid type-param"))
85+
return x
86+
end
6287
name_of_type(tv::TypeVar) = tv.name
6388
function name_of_type(x::DataType)
64-
name_sym = Symbol(x.name)
65-
if isempty(x.parameters)
66-
return name_sym
89+
name = name_of_type(x.name)
90+
# because tuples are varadic in number of type parameters having no parameters does not
91+
# mean you should not write the `{}`, so we special case them here.
92+
if isempty(x.parameters) && x != Tuple{}
93+
return name
6794
else
68-
parameter_names = name_of_type.(x.parameters)
69-
return :($(name_sym){$(parameter_names...)})
95+
parameter_names = map(name_of_type, x.parameters)
96+
return :($(name){$(parameter_names...)})
7097
end
7198
end
99+
100+
72101
function name_of_type(x::UnionAll)
73-
name = name_of_type(x.body)
74-
whereparam = where_parameters(x.var)
75-
return :($name where $whereparam)
102+
# we do nested union all unwrapping so we can make the more compact:
103+
# `foo{T,A} where {T, A}`` rather than the longer: `(foo{T,A} where T) where A`
104+
where_params = []
105+
while x isa UnionAll
106+
push!(where_params, where_constraint(x.var))
107+
x = x.body
108+
end
109+
110+
name = name_of_type(x)
111+
return :($name where {$(where_params...)})
76112
end
113+
77114
function name_of_type(x::Union)
78-
parameter_names = name_of_type.(Base.uniontypes(x))
115+
parameter_names = map(name_of_type, Base.uniontypes(x))
79116
return :(Union{$(parameter_names...)})
80117
end
81118

@@ -95,7 +132,7 @@ function arguments(m::Method)
95132
end
96133
end
97134

98-
function where_parameters(x::TypeVar)
135+
function where_constraint(x::TypeVar)
99136
if x.lb === Union{} && x.ub === Any
100137
return x.name
101138
elseif x.lb === Union{}
@@ -112,7 +149,7 @@ where_parameters(sig) = nothing
112149
function where_parameters(sig::UnionAll)
113150
whereparams = []
114151
while sig isa UnionAll
115-
push!(whereparams, where_parameters(sig.var))
152+
push!(whereparams, where_constraint(sig.var))
116153
sig = sig.body
117154
end
118155
return whereparams
@@ -125,7 +162,7 @@ function type_parameters(sig)
125162

126163
function_type = first(parameters(typeof_type)) # will be e.g. Foo{P}
127164
parameter_types = parameters(function_type)
128-
return [name_of_type(type) for type in parameter_types]
165+
return map(name_of_type, parameter_types)
129166
end
130167

131168
function kwargs(m::Method)

test/method.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ end
5050
@test_signature basic4() = 2
5151
end
5252

53+
@testset "Tuple{}" begin
54+
@test_signature empty_tuple_constraint(x::Tuple{}) = 2
55+
end
56+
57+
@testset "Scope Qualification" begin
58+
@test_signature qualified_constraint(x::Base.CoreLogging.LogLevel) = 2
59+
end
60+
5361
@testset "missing argnames" begin
5462
@test_signature ma1(::Int32) = 2x
5563
@test_signature ma2(::Int32, ::Bool) = 2x
@@ -93,6 +101,8 @@ end
93101
r"^\QExpr[:(x::(Array{\E(.*?)\Q, 1} where \E\1\Q <: Real))]\E$",
94102
string(f16_alt_sig[:args])
95103
)
104+
105+
@test_signature f_symbol_param(x::Val{:foobar}) where T = 2x
96106
end
97107

98108
@testset "anon functions" begin

0 commit comments

Comments
 (0)