Skip to content

Commit

Permalink
Simulate iteration protocal when inferring splatted arguments
Browse files Browse the repository at this point in the history
Closes #20518 and improves inference when splatting genetal iterables.
  • Loading branch information
martinholters committed Feb 13, 2017
1 parent dc2459d commit a434dfc
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 2 deletions.
25 changes: 23 additions & 2 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1421,13 +1421,34 @@ function precise_container_type(arg, typ, vtypes::VarTable, sv)
else
return tti.parameters
end
elseif tti <: AbstractArray
elseif tti <: Array
return Any[Vararg{eltype(tti)}]
else
return Any[Vararg{Any}]
return Any[Vararg{abstract_iteration(tti, vtypes, sv)}]
end
end

# simulate iteration protocol on container type up to fixpoint
function abstract_iteration(itertype, vtypes::VarTable, sv)
if !isdefined(Main, :Base) || !isdefined(Main.Base, :start) || !isdefined(Main.Base, :next)
return Any
end
statetype = abstract_call(Main.Base.start, (), Any[Const(Main.Base.start), itertype], vtypes, sv)
valtype = Bottom
while valtype !== Any
nt = abstract_call(Main.Base.next, (), Any[Const(Main.Base.next), itertype, statetype], vtypes, sv)
if !isa(nt, DataType) || !(nt <: Tuple) || isvatuple(nt) || length(nt.parameters) != 2
return Any
end
if nt.parameters[1] <: valtype && nt.parameters[2] <: statetype
break
end
valtype = tmerge(valtype, nt.parameters[1])
statetype = tmerge(statetype, nt.parameters[2])
end
return valtype
end

# do apply(af, fargs...), where af is a function value
function abstract_apply(af::ANY, fargs, aargtypes::Vector{Any}, vtypes::VarTable, sv)
res = Union{}
Expand Down
12 changes: 12 additions & 0 deletions test/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,18 @@ function i20343()
f20343([1,2,3]..., 4)
end
@test Base.return_types(i20343, ()) == [Int8]
immutable Foo20518 <: AbstractVector{Int}; end # issue #20518; inference assumed AbstractArrays
Base.getindex(::Foo20518, ::Int) = "oops" # not to lie about their element type
Base.indices(::Foo20518) = (Base.OneTo(4),)
foo20518(xs::Any...) = -1
foo20518(xs::Int...) = [0]
bar20518(xs) = sum(foo20518(xs...))
@test bar20518(Foo20518()) == -1
f19957(::Int) = Int8(1) # issue #19957, inference failure when splatting a number
f19957(::Int...) = Int16(1)
f19957(::Any...) = "no"
g19957(x) = f19957(x...)
@test all(t -> t<:Union{Int8,Int16}, Base.return_types(g19957, (Int,))) # with a full fix, this should just be Int8

# Inference for some type-level computation
fUnionAll{T}(::Type{T}) = Type{S} where S <: T
Expand Down

0 comments on commit a434dfc

Please sign in to comment.