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

Commit 92b0b37

Browse files
committed
Started to use TypeVar but not there yet. Seems to fail because of
JuliaLang/julia#9043
1 parent 943a3a2 commit 92b0b37

File tree

4 files changed

+108
-11
lines changed

4 files changed

+108
-11
lines changed

src/helpers.jl

+52-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
# helper useful for users
1+
# helpers useful for users
22
export deparameterize_type
33

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

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

40+
41+
## Parsing
42+
####
43+
# translate a symbol in a array of expressions and/or symbols
44+
function translate!(ex::Vector{Any}, di::Dict)
45+
for (i,e) in enumerate(ex)
46+
if isa(e, Symbol)
47+
ex[i] = get(di, e, e)
48+
else
49+
translate!(e.args, di)
50+
end
51+
end
52+
nothing
53+
end
54+
55+
# expressions like :(I<:Int) are not parsed into TypeVar expressions
56+
# but subtype comparisons. This function translates this
57+
function subt2tvar!(exs::Vector{Any})
58+
for (i,ex) in enumerate(exs)
59+
if isa(ex, Symbol)
60+
# do nothing
61+
elseif ex.head==:comparison
62+
exs[i] = Expr(:<:, ex.args[1], ex.args[3])
63+
else
64+
subt2tvar!(ex.args)
65+
end
66+
end
67+
nothing
68+
end
69+
70+
function tvar2tvar!(exs::Vector{Any})
71+
# tranlates x<:Int -> TypeVar(:X, Int)
72+
for (i,ex) in enumerate(exs)
73+
if isa(ex, Symbol)
74+
# do nothing
75+
elseif ex.head==:<:
76+
var = ex.args[1]
77+
exs[i] = :(TypeVar(symbol($(string(var))), $(ex.args[2])))
78+
else
79+
tvar2tvar!(ex.args)
80+
end
81+
end
82+
nothing
83+
end
84+
85+
86+
3987
# function return_types_v2(f::Function, typs::ANY)
4088
# # for some reason this function take forever to JIT. (about 4 secs!)
4189
# a = code_typed(f, typs)

src/traitdef.jl

+14-7
Original file line numberDiff line numberDiff line change
@@ -135,18 +135,20 @@ function parsefnstypes!(outfns, ln)
135135
function parsefn(def)
136136
# Parse to get function signature.
137137
# parses f(X,Y), f{X <:T}(X,Y) and X+Y
138+
tvars = Any[]
138139
if isa(def.args[1], Symbol)
139-
fn = def.args[1]
140+
fn = def.args[1]
140141
elseif def.args[1].head==:curly
141-
fn = def.args[1].args[1]
142-
# todo
142+
fn = def.args[1].args[1]
143+
# get
144+
tvars = def.args[1].args[2:end]
143145
else
144146
throw(TraitException(
145147
"Something went wrong parsing the trait definition body with line:\n$ln"))
146148
end
147149
argtype = :()
148150
append!(argtype.args, def.args[2:end])
149-
return fn, argtype # typvars
151+
return fn, argtype, tvars
150152
end
151153
function parseret!(rettype, ln)
152154
# parse to get return types
@@ -170,7 +172,7 @@ function parsefnstypes!(outfns, ln)
170172

171173
if ln.head==:(->) # f1(X,Y) -> x
172174
parseret!(rettype, ln)
173-
fn, argtype = parsefn(ln.args[1])
175+
fn, argtype, tvars = parsefn(ln.args[1])
174176
elseif ln.head==:call # either f1(X,Y) or X + Y -> Z
175177
if isa(ln.args[end], Expr) && ln.args[end].head==:(->) # X + Y -> Z
176178
def = Expr(:call)
@@ -185,13 +187,18 @@ function parsefnstypes!(outfns, ln)
185187
def = ln
186188
rettype = :((Any...))
187189
end
188-
fn, argtype = parsefn(def)
190+
fn, argtype, tvars = parsefn(def)
189191
else
190192
throw(TraitException(
191193
"Something went wrong parsing the trait definition body with line:\n$ln"))
192194
end
193195
# replace types with constraints by TypeVars
194-
#...
196+
trans = Dict(zip([t.args[1] for t in tvars], tvars)) # this will error if there is a type-var without constraints!
197+
translate!(argtype.args, trans)
198+
tvar2tvar!(argtype.args)
199+
subt2tvar!(rettype.args)
200+
translate!(rettype.args, trans)
201+
tvar2tvar!(rettype.args)
195202

196203
push!(outfns.args, :($fn => ($argtype, $rettype)))
197204
end

test/runtests.jl

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type A2 end
1010

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

1415
# manual implementations
1516
include("manual-traitdef.jl")

test/traitdef.jl

+41
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,20 @@ end)
5050
a,b,c = Traits.parsebody(td3.args[end])
5151
@test a==Expr(:dict, :((fn) => ((X,),(Type{X},))))
5252

53+
td4 = :(@traitdef Cr20{X} begin
54+
fn{Y<:II}(X,Y) -> Type{X}
55+
fn76{K<:FloatingPoint, I<:Integer}(X, Vector{I}, Vector{K}) -> I
56+
end)
57+
a,b,c = Traits.parsebody(td4.args[end])
58+
v = :(TypeVar(symbol("Y"),II))
59+
t = :(TypeVar(symbol("I"),Integer))
60+
k = :(TypeVar(symbol("K"),FloatingPoint))
61+
62+
@test a==Expr(:dict, :(fn=>((X,$v),(Type{X},))),
63+
:(fn76=>((X,Vector{$t},Vector{$k}),($t,)))
64+
)
65+
66+
5367
## test making traits
5468

5569
@traitdef MyIter{X} begin
@@ -150,6 +164,33 @@ end
150164

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

167+
# test functions parameterized on non-trait parameters
168+
169+
@traitdef Pr0{X} begin
170+
fn75{Y <: Integer}(X, Y) -> Y
171+
end
172+
fn75{Y <: Integer}(x::UInt8, y::Y) = y+x
173+
if method_exists_bug2
174+
@test !istrait(Pr0{UInt8})
175+
else
176+
@test istrait(Pr0{UInt8})
177+
end
178+
@test !istrait(Pr0{Int8})
179+
180+
fn75(x::UInt8, y::Int8) = y+x
181+
@test !istrait(Pr0{UInt8}) # this works, not because only for y::Int8 not for all Integers
182+
183+
@traitdef Pr1{X} begin
184+
fn76{I<:Integer}(X, Vector{I}) -> I
185+
end
186+
fn76{I<:Integer}(x::Uint8, v::Vector{I}) = v[x]
187+
if method_exists_bug2
188+
@test !istrait(Pr1{UInt8})
189+
else
190+
@test istrait(Pr1{UInt8})
191+
end
192+
@test !istrait(Pr1{UInt8})
193+
153194
# test constraints
154195

155196
@traitdef Cr20{X} begin

0 commit comments

Comments
 (0)