Skip to content

Commit 9e88a95

Browse files
committed
Add a few new reflection methods
This is informed by attempting to port some packages to the new type system. I have abstracted out the functionality required by those packages into documented/tested functions. The hope is to avoid introducing too many implementation details to packages. These functions can also be implemented in Compat for older julia versions, such that packages can immediate replace their use of internal APIs with these functions.
1 parent ac9b2e7 commit 9e88a95

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed

base/essentials.jl

+9
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ function unwrapva(t::ANY)
9595
isvarargtype(t2) ? t2.parameters[1] : t
9696
end
9797

98+
typename(a) = error("typename does not apply to this type")
99+
typename(a::DataType) = a.name
100+
function typename(a::Union)
101+
ta = typename(a.a)
102+
tb = typename(a.b)
103+
ta === tb ? tb : error("typename does not apply to unions whose components have different typenames")
104+
end
105+
typename(union::UnionAll) = typename(union.body)
106+
98107
convert{T<:Tuple{Any,Vararg{Any}}}(::Type{T}, x::Tuple{Any, Vararg{Any}}) =
99108
tuple(convert(tuple_type_head(T),x[1]), convert(tuple_type_tail(T), tail(x))...)
100109
convert{T<:Tuple{Any,Vararg{Any}}}(::Type{T}, x::T) = x

base/reflection.jl

+36-2
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,12 @@ fieldnames(t::UnionAll) = fieldnames(unwrap_unionall(t))
144144
fieldnames{T<:Tuple}(t::Type{T}) = Int[n for n in 1:nfields(t)]
145145

146146
"""
147-
Base.datatype_name(t::DataType) -> Symbol
147+
Base.datatype_name(t) -> Symbol
148148
149-
Get the name of a `DataType` (without its parent module) as a symbol.
149+
Get the name of a (potentially UnionAll-wrapped) `DataType` (without its parent module) as a symbol.
150150
"""
151151
datatype_name(t::DataType) = t.name.name
152+
datatype_name(t::UnionAll) = datatype_name(unwrap_unionall(t))
152153

153154
"""
154155
Base.datatype_module(t::DataType) -> Module
@@ -232,6 +233,39 @@ a concrete type that can have instances.
232233
"""
233234
isleaftype(t::ANY) = (@_pure_meta; isa(t, DataType) && t.isleaftype)
234235

236+
"""
237+
Base.isabstract(T)
238+
239+
Determine whether `T` was declared as an abstract type (i.e. using the
240+
`abstract` keyword).
241+
"""
242+
function isabstract(t::ANY)
243+
@_pure_meta
244+
t = unwrap_unionall(t)
245+
isa(t,DataType) && t.abstract
246+
end
247+
248+
"""
249+
Base.parameter_upper_bound(t::UnionAll, idx)
250+
251+
Determine the upper bound of a type parameter in the underlying type. E.g.:
252+
```jldoctest
253+
julia> immutable Foo{T<:AbstractFloat, N}
254+
x::Tuple{T, N}
255+
end
256+
257+
julia> Base.parameter_upper_bound(Foo, 1)
258+
AbstractFloat
259+
260+
julia> Base.parameter_upper_bound(Foo, 2)
261+
Any
262+
```
263+
"""
264+
function parameter_upper_bound(t::UnionAll, idx)
265+
@_pure_meta
266+
rewrap_unionall(unwrap_unionall(t).parameters[idx], t)
267+
end
268+
235269
"""
236270
typeintersect(T, S)
237271

test/reflection.jl

+20
Original file line numberDiff line numberDiff line change
@@ -608,3 +608,23 @@ end
608608
@generated f18883() = nothing
609609
@test !isempty(sprint(io->code_llvm(io, f18883, Tuple{})))
610610
@test !isempty(sprint(io->code_native(io, f18883, Tuple{})))
611+
612+
# New reflection methods in 0.6
613+
immutable ReflectionExample{T<:AbstractFloat, N}
614+
x::Tuple{T, N}
615+
end
616+
617+
@test Base.isabstract(AbstractArray)
618+
@test !Base.isabstract(ReflectionExample)
619+
@test !Base.isabstract(Int)
620+
621+
@test Base.parameter_upper_bound(ReflectionExample, 1) === AbstractFloat
622+
@test Base.parameter_upper_bound(ReflectionExample, 2) === Any
623+
@test Base.parameter_upper_bound(ReflectionExample{T, N} where T where N <: Real, 2) === Real
624+
625+
@test Base.typename(ReflectionExample{Float64, Int64}).wrapper === ReflectionExample
626+
@test Base.typename(ReflectionExample{Float64, N} where N).wrapper === ReflectionExample
627+
@test Base.typename(ReflectionExample{T, Int64} where T).wrapper === ReflectionExample
628+
@test Base.typename(ReflectionExample).wrapper === ReflectionExample
629+
@test Base.typename(Union{ReflectionExample{Union{},1},ReflectionExample{Float64,1}}).wrapper === ReflectionExample
630+
@test_throws ErrorException Base.typename(Union{Int, Float64})

0 commit comments

Comments
 (0)