Skip to content

Commit

Permalink
Merge pull request #12 from invenia/ox/overhaul
Browse files Browse the repository at this point in the history
Overhaul name_of_type
  • Loading branch information
oxinabox authored Oct 14, 2020
2 parents 4b175b0 + cba2e15 commit ca6b948
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 14 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "ExprTools"
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
authors = ["Invenia Technical Computing"]
version = "0.1.2"
version = "0.1.3"

[compat]
julia = "1"
Expand Down
63 changes: 50 additions & 13 deletions src/method.jl
Original file line number Diff line number Diff line change
Expand Up @@ -58,24 +58,61 @@ function argument_types(sig)
return parameters(sig)[2:end]
end

name_of_type(x) = x
module DummyThatHasOnlyDefaultImports end # for working out visibility

function name_of_module(m::Module)
if Base.is_root_module(m)
return nameof(m)
else
return :($(name_of_module(parentmodule(m))).$(nameof(m)))
end
end
function name_of_type(x::Core.TypeName)
# TODO: could let user pass this in, then we could be using what is inscope for them
# but this is not important as we will give a correct (if overly verbose) output as is.
from = DummyThatHasOnlyDefaultImports
if Base.isvisible(x.name, x.module, from) # avoid qualifying things that are in scope
return x.name
else
return :($(name_of_module(x.module)).$(x.name))
end
end

name_of_type(x::Symbol) = QuoteNode(x) # Literal type-param e.g. `Val{:foo}`
function name_of_type(x::T) where T # Literal type-param e.g. `Val{1}`
# If this error is thrown, there is an issue with out implementation
isbits(x) || throw(DomainError((x, T), "not a valid type-param"))
return x
end
name_of_type(tv::TypeVar) = tv.name
function name_of_type(x::DataType)
name_sym = Symbol(x.name)
if isempty(x.parameters)
return name_sym
name = name_of_type(x.name)
# because tuples are varadic in number of type parameters having no parameters does not
# mean you should not write the `{}`, so we special case them here.
if isempty(x.parameters) && x != Tuple{}
return name
else
parameter_names = name_of_type.(x.parameters)
return :($(name_sym){$(parameter_names...)})
parameter_names = map(name_of_type, x.parameters)
return :($(name){$(parameter_names...)})
end
end


function name_of_type(x::UnionAll)
name = name_of_type(x.body)
whereparam = where_parameters(x.var)
return :($name where $whereparam)
# we do nested union all unwrapping so we can make the more compact:
# `foo{T,A} where {T, A}`` rather than the longer: `(foo{T,A} where T) where A`
where_params = []
while x isa UnionAll
push!(where_params, where_constraint(x.var))
x = x.body
end

name = name_of_type(x)
return :($name where {$(where_params...)})
end

function name_of_type(x::Union)
parameter_names = name_of_type.(Base.uniontypes(x))
parameter_names = map(name_of_type, Base.uniontypes(x))
return :(Union{$(parameter_names...)})
end

Expand All @@ -95,7 +132,7 @@ function arguments(m::Method)
end
end

function where_parameters(x::TypeVar)
function where_constraint(x::TypeVar)
if x.lb === Union{} && x.ub === Any
return x.name
elseif x.lb === Union{}
Expand All @@ -112,7 +149,7 @@ where_parameters(sig) = nothing
function where_parameters(sig::UnionAll)
whereparams = []
while sig isa UnionAll
push!(whereparams, where_parameters(sig.var))
push!(whereparams, where_constraint(sig.var))
sig = sig.body
end
return whereparams
Expand All @@ -125,7 +162,7 @@ function type_parameters(sig)

function_type = first(parameters(typeof_type)) # will be e.g. Foo{P}
parameter_types = parameters(function_type)
return [name_of_type(type) for type in parameter_types]
return map(name_of_type, parameter_types)
end

function kwargs(m::Method)
Expand Down
10 changes: 10 additions & 0 deletions test/method.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ end
@test_signature basic4() = 2
end

@testset "Tuple{}" begin
@test_signature empty_tuple_constraint(x::Tuple{}) = 2
end

@testset "Scope Qualification" begin
@test_signature qualified_constraint(x::Base.CoreLogging.LogLevel) = 2
end

@testset "missing argnames" begin
@test_signature ma1(::Int32) = 2x
@test_signature ma2(::Int32, ::Bool) = 2x
Expand Down Expand Up @@ -93,6 +101,8 @@ end
r"^\QExpr[:(x::(Array{\E(.*?)\Q, 1} where \E\1\Q <: Real))]\E$",
string(f16_alt_sig[:args])
)

@test_signature f_symbol_param(x::Val{:foobar}) where T = 2x
end

@testset "anon functions" begin
Expand Down

4 comments on commit ca6b948

@oxinabox
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An unexpected error occurred during registration.

@oxinabox
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/22953

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.1.3 -m "<description of version>" ca6b94863e785d7fb15892adb2979e08f8dbb1a4
git push origin v0.1.3

Please sign in to comment.