Skip to content
This repository has been archived by the owner on Feb 7, 2019. It is now read-only.

Commit

Permalink
Started to use TypeVar but not there yet. Seems to fail because of
Browse files Browse the repository at this point in the history
  • Loading branch information
mauro3 committed Nov 19, 2014
1 parent 943a3a2 commit 92b0b37
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 11 deletions.
56 changes: 52 additions & 4 deletions src/helpers.jl
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
# helper useful for users
# helpers useful for users
export deparameterize_type

@doc """Removes type parameters from types, e.g. Array{Int}->Array.
It is often useful to make an associated type with this to match
against methods which do not specialize on the type parameters.
""" -> deparameterize_type(A::Type) = eval(A.name.module,
A.name.name)::DataType
""" ->
deparameterize_type(A::Type) = eval(A.name.module, A.name.name)::DataType

###############
# Internal helpers
##################
function eval_curmod(expr::Union(Symbol,Expr,QuoteNode))
# evaluates a symbol or expression in the current module.
# I.e. the one where the macro definition is.
Expand Down Expand Up @@ -36,6 +37,53 @@ function Base.done(lns::Lines, nr)
end
end


## Parsing
####
# translate a symbol in a array of expressions and/or symbols
function translate!(ex::Vector{Any}, di::Dict)
for (i,e) in enumerate(ex)
if isa(e, Symbol)
ex[i] = get(di, e, e)
else
translate!(e.args, di)
end
end
nothing
end

# expressions like :(I<:Int) are not parsed into TypeVar expressions
# but subtype comparisons. This function translates this
function subt2tvar!(exs::Vector{Any})
for (i,ex) in enumerate(exs)
if isa(ex, Symbol)
# do nothing
elseif ex.head==:comparison
exs[i] = Expr(:<:, ex.args[1], ex.args[3])
else
subt2tvar!(ex.args)
end
end
nothing
end

function tvar2tvar!(exs::Vector{Any})
# tranlates x<:Int -> TypeVar(:X, Int)
for (i,ex) in enumerate(exs)
if isa(ex, Symbol)
# do nothing
elseif ex.head==:<:
var = ex.args[1]
exs[i] = :(TypeVar(symbol($(string(var))), $(ex.args[2])))
else
tvar2tvar!(ex.args)
end
end
nothing
end



# function return_types_v2(f::Function, typs::ANY)
# # for some reason this function take forever to JIT. (about 4 secs!)
# a = code_typed(f, typs)
Expand Down
21 changes: 14 additions & 7 deletions src/traitdef.jl
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,20 @@ function parsefnstypes!(outfns, ln)
function parsefn(def)
# Parse to get function signature.
# parses f(X,Y), f{X <:T}(X,Y) and X+Y
tvars = Any[]
if isa(def.args[1], Symbol)
fn = def.args[1]
fn = def.args[1]
elseif def.args[1].head==:curly
fn = def.args[1].args[1]
# todo
fn = def.args[1].args[1]
# get
tvars = def.args[1].args[2:end]
else
throw(TraitException(
"Something went wrong parsing the trait definition body with line:\n$ln"))
end
argtype = :()
append!(argtype.args, def.args[2:end])
return fn, argtype # typvars
return fn, argtype, tvars
end
function parseret!(rettype, ln)
# parse to get return types
Expand All @@ -170,7 +172,7 @@ function parsefnstypes!(outfns, ln)

if ln.head==:(->) # f1(X,Y) -> x
parseret!(rettype, ln)
fn, argtype = parsefn(ln.args[1])
fn, argtype, tvars = parsefn(ln.args[1])
elseif ln.head==:call # either f1(X,Y) or X + Y -> Z
if isa(ln.args[end], Expr) && ln.args[end].head==:(->) # X + Y -> Z
def = Expr(:call)
Expand All @@ -185,13 +187,18 @@ function parsefnstypes!(outfns, ln)
def = ln
rettype = :((Any...))
end
fn, argtype = parsefn(def)
fn, argtype, tvars = parsefn(def)
else
throw(TraitException(
"Something went wrong parsing the trait definition body with line:\n$ln"))
end
# replace types with constraints by TypeVars
#...
trans = Dict(zip([t.args[1] for t in tvars], tvars)) # this will error if there is a type-var without constraints!
translate!(argtype.args, trans)
tvar2tvar!(argtype.args)
subt2tvar!(rettype.args)
translate!(rettype.args, trans)
tvar2tvar!(rettype.args)

push!(outfns.args, :($fn => ($argtype, $rettype)))
end
Expand Down
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type A2 end

# BUG flags: set to false once fixed to activate tests
method_exists_bug = true # see https://github.com/JuliaLang/julia/issues/8959
method_exists_bug2 = true # see https://github.com/JuliaLang/julia/issues/9043

# manual implementations
include("manual-traitdef.jl")
Expand Down
41 changes: 41 additions & 0 deletions test/traitdef.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ end)
a,b,c = Traits.parsebody(td3.args[end])
@test a==Expr(:dict, :((fn) => ((X,),(Type{X},))))

td4 = :(@traitdef Cr20{X} begin
fn{Y<:II}(X,Y) -> Type{X}
fn76{K<:FloatingPoint, I<:Integer}(X, Vector{I}, Vector{K}) -> I
end)
a,b,c = Traits.parsebody(td4.args[end])
v = :(TypeVar(symbol("Y"),II))
t = :(TypeVar(symbol("I"),Integer))
k = :(TypeVar(symbol("K"),FloatingPoint))

@test a==Expr(:dict, :(fn=>((X,$v),(Type{X},))),
:(fn76=>((X,Vector{$t},Vector{$k}),($t,)))
)


## test making traits

@traitdef MyIter{X} begin
Expand Down Expand Up @@ -150,6 +164,33 @@ end

#--> need to be able to do this in terms of type variables.

# test functions parameterized on non-trait parameters

@traitdef Pr0{X} begin
fn75{Y <: Integer}(X, Y) -> Y
end
fn75{Y <: Integer}(x::UInt8, y::Y) = y+x
if method_exists_bug2
@test !istrait(Pr0{UInt8})
else
@test istrait(Pr0{UInt8})
end
@test !istrait(Pr0{Int8})

fn75(x::UInt8, y::Int8) = y+x
@test !istrait(Pr0{UInt8}) # this works, not because only for y::Int8 not for all Integers

@traitdef Pr1{X} begin
fn76{I<:Integer}(X, Vector{I}) -> I
end
fn76{I<:Integer}(x::Uint8, v::Vector{I}) = v[x]
if method_exists_bug2
@test !istrait(Pr1{UInt8})
else
@test istrait(Pr1{UInt8})
end
@test !istrait(Pr1{UInt8})

# test constraints

@traitdef Cr20{X} begin
Expand Down

0 comments on commit 92b0b37

Please sign in to comment.