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

M3/heisenbug #11

Closed
wants to merge 15 commits into from
Closed
Prev Previous commit
Next Next commit
New tests for parametric methods in manual-traitdef.jl working
  • Loading branch information
mauro3 committed Apr 10, 2015
commit bccce6e0f80b02462007ca4882ebf2602619d469
30 changes: 16 additions & 14 deletions src/Traits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,9 @@ function isfitting(tm::Method, fm::Method; verbose=false) # tm=trait-method, fm=
# If !(tm.sig<:fm.sig) then tm<<:fm is false
# but the converse is not true:
if !(tm.sig<:fm.sig)
println_verb("Reason fail: !(tm.sig<:fm.sig)")
println_verb("""Reason fail: !(tm.sig<:fm.sig)
tm.sig = $(tm.sig)
fm.sig = $(fm.sig)""")
return false
end
# False if there are not the same number of arguments: (I don't
Expand Down Expand Up @@ -306,17 +308,21 @@ function isfitting(tm::Method, fm::Method; verbose=false) # tm=trait-method, fm=
if !any(locs)
error("Bad: the type variable should feature in at least on location.")
end
# Find the tvar in fm which corresponds to tv. It's ok if ftv
# constrains more arguments than tv!
# Find the tvar in fm which corresponds to tv.
ftvs = Any[]
fmtvars = isa(fm.tvars,TypeVar) ? (fm.tvars,) : fm.tvars
fmtvars = isa(fm.tvars,TypeVar) ? (fm.tvars,) : fm.tvars # make sure it's a tuple of TypeVar
for ftv in fmtvars
flocs = find_tvar(fm.sig, ftv)
if all(flocs[find(locs)])
push!(ftvs,ftv)
end
end
if ftvs==Any[]
if length(ftvs)==0
# TODO this should pass (bug traitdef_bug1):
# g01 => _g01{T<:X}(::T, ::T) = T()
# g01(::Int, ::Int) = Int
#@test istrait(Tr01{Int}, verbose=true)

println_verb("Reason fail: parametric constraints on function method not as severe as on trait-method.")
return false
end
Expand Down Expand Up @@ -344,25 +350,21 @@ function isfitting(tm::Method, fm::Method; verbose=false) # tm=trait-method, fm=
end

# helpers for isfitting
function subs_tvar{T<:_TestType}(tv::TypeVar, arg, TestT::Type{T})
function subs_tvar{T<:_TestType}(tv::TypeVar, arg::DataType, TestT::Type{T})
# Substitute `TestT` for a particular TypeVar `tv` in an argument `arg`.
#
# Example:
# Array{I<:Int64,N} -> Array{_TestType{23},N}
if isa(arg, DataType) && (isleaftype(arg) || length(arg.parameters)==0) # concrete type or abstract type with no parameters
if isleaftype(arg) || length(arg.parameters)==0 # concrete type or abstract type with no parameters
return arg
elseif isa(arg,TypeVar)
if tv===arg # note === this it essential!
return TestT # replace
else
return arg
end
else # It's a parameterized type do substitution on all parameters:
else # It's a parameterized type: do substitution on all parameters:
pa = [ subs_tvar(tv, arg.parameters[i], TestT) for i=1:length(arg.parameters) ]
typ = deparameterize_type(arg)
return typ{pa...}
end
end
subs_tvar{T<:_TestType}(tv::TypeVar, arg::TypeVar, TestT::Type{T}) = tv===arg ? TestT : arg # note === this it essential!
subs_tvar{T<:_TestType}(tv::TypeVar, arg, TestT::Type{T}) = arg # for anything else

# find_tvar finds index of arguments in a function signature `sig` where a
# particular TypeVar `tv` features. Example:
Expand Down
80 changes: 80 additions & 0 deletions test/manual-traitdef.jl
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,83 @@ end
# @test istrait(CTrAs{Integer, Integer}) # doesn't work because return type of /(Integer, Integer)==Any
@test istrait(CTrAs{Int, Int})
@test !istrait(CTrAs{Int, String})

# parametric methods

# @traitdef Tr01{X} begin
# g01{T<:X}(T, T) -> T
# end
immutable Tr01{X} <: Traits.Trait{()}
methods::Traits.FDict
constraints::Vector{Bool}
assoctyps::Vector{Any}
function Tr01()
new(Traits.FDict(
g01 => _g01{T<:X}(::T, ::T) = T()
),
Bool[],
[]
)
end
end


g01(::Int, ::Int) = Int
if traitdef_bug1
@test !istrait(Tr01{Int}) # == true as constraints Int isleaftype
else
@test istrait(Tr01{Int}) # == true as constraints Int isleaftype
end
@test !istrait(Tr01{Integer})
g01{I<:Integer}(::I, ::I) = I
@test istrait(Tr01{Integer}) # == true

# @traitdef Tr02{X} begin
# g02{T<:X}(T, T) -> T
# end
immutable Tr02{X} <: Traits.Trait{()}
methods::Traits.FDict
constraints::Vector{Bool}
assoctyps::Vector{Any}
function Tr02()
new(Traits.FDict(
g02 => _g02{T<:X}(::T, ::T) = T()
),
Bool[],
[]
)
end
end

g02{I<:Integer}(::I, ::I) = Integer
# By using Base.return_types it is not possible to figure out whether
# the returned value is constrained or not by I:
if function_types_bug1
@test istrait(Tr02{Integer})
# or throw an error/warning here saying parametric return types
# are only supported for leaftypes
else
@test !istrait(Tr02{Integer}) # if function types get implemented this should be possible to catch
end
@test istrait(Tr02{Int}) # == true

# @traitdef Tr03{X} begin
# g03{T<:X}(T, Vector{T})
# end
immutable Tr03{X} <: Traits.Trait{()}
methods::Traits.FDict
constraints::Vector{Bool}
assoctyps::Vector{Any}
function Tr03()
new(Traits.FDict(
g03 => _g03{T<:X}(::T, ::Vector{T}) = T()
),
Bool[],
[]
)
end
end

g03{I<:Integer}(::I, ::Vector{I}) = 1
@test istrait(Tr03{Integer})
@test istrait(Tr03{Int})
4 changes: 3 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ using Traits
# Julia issues:
method_exists_bug1 = true # see https://github.com/JuliaLang/julia/issues/8959
method_exists_bug2 = true # see https://github.com/JuliaLang/julia/issues/9043 and https://github.com/mauro3/Traits.jl/issues/2
function_types_bug1 = true # set to false if function types get implemented in Julia
# Traits.jl issues:
dispatch_bug1 = true # in traitdispatch.jl
dispatch_bug1 = true # in traitdispatch.jl
traitdef_bug1 = true

# src/Traits.jl tests
type A1 end
Expand Down