Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions base/essentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,28 @@ macro generated(f)
end
end

argtail(x, rest...) = rest
tail(x::Tuple) = argtail(x...)

tuple_type_head(::Type{Union{}}) = throw(MethodError(tuple_type_head, (Union{},)))
function tuple_type_head{T<:Tuple}(::Type{T})
tuple_type_head(T::TypeConstructor) = tuple_type_head(T.body)
function tuple_type_head(T::DataType)
@_pure_meta
T.parameters[1]
T.name === Tuple.name || throw(MethodError(tuple_type_head, (T,)))
return T.parameters[1]
end

isvarargtype(t::ANY) = isa(t,DataType)&&is((t::DataType).name,Vararg.name)
isvatuple(t::DataType) = (n = length(t.parameters); n > 0 && isvarargtype(t.parameters[n]))
unwrapva(t::ANY) = isvarargtype(t) ? t.parameters[1] : t

function tuple_type_tail{T<:Tuple}(::Type{T})
tuple_type_tail(T::TypeConstructor) = tuple_type_tail(T.body)
function tuple_type_tail(T::DataType)
@_pure_meta
T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,)))
if isvatuple(T) && length(T.parameters) == 1
return T
end
Tuple{argtail(T.parameters...)...}
return Tuple{argtail(T.parameters...)...}
end

argtail(x, rest...) = rest
tail(x::Tuple) = argtail(x...)
isvarargtype(t::ANY) = isa(t, DataType) && is((t::DataType).name, Vararg.name)
isvatuple(t::DataType) = (n = length(t.parameters); n > 0 && isvarargtype(t.parameters[n]))
unwrapva(t::ANY) = isvarargtype(t) ? t.parameters[1] : t

convert{T<:Tuple{Any,Vararg{Any}}}(::Type{T}, x::Tuple{Any, Vararg{Any}}) =
tuple(convert(tuple_type_head(T),x[1]), convert(tuple_type_tail(T), tail(x))...)
Expand Down
30 changes: 16 additions & 14 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,16 @@ type InferenceState
inferred::Bool
tfunc_bp::Union{TypeMapEntry, Void}

function InferenceState(linfo::LambdaInfo, atypes::ANY, sparams::SimpleVector, optimize::Bool)
function InferenceState(linfo::LambdaInfo, optimize::Bool)
@assert isa(linfo.code,Array{Any,1})
linfo.inInference = true
nslots = length(linfo.slotnames)
nl = label_counter(linfo.code)+1

if length(linfo.sparam_vals) > 0
sp = linfo.sparam_vals
elseif isempty(sparams) && !isempty(linfo.sparam_syms)
if isempty(linfo.sparam_vals) && !isempty(linfo.sparam_syms)
sp = svec(Any[ TypeVar(sym, Any, true) for sym in linfo.sparam_syms ]...)
else
sp = sparams
sp = linfo.sparam_vals
end

if !isa(linfo.slottypes, Array)
Expand All @@ -101,6 +99,7 @@ type InferenceState
# initial types
s[1] = Any[ VarState(Bottom,true) for i=1:nslots ]

atypes = linfo.specTypes
la = linfo.nargs
if la > 0
if linfo.isva
Expand Down Expand Up @@ -873,16 +872,19 @@ function precise_container_types(args, types, vtypes::VarTable, sv)
ai = args[i]
ti = types[i]
tti = widenconst(ti)
if isa(ai,Expr) && ai.head === :call && (abstract_evals_to_constant(ai.args[1], svec, vtypes, sv) ||
abstract_evals_to_constant(ai.args[1], tuple, vtypes, sv))
if isa(tti, TypeConstructor)
tti = tti.body
end
if isa(ai, Expr) && ai.head === :call && (abstract_evals_to_constant(ai.args[1], svec, vtypes, sv) ||
abstract_evals_to_constant(ai.args[1], tuple, vtypes, sv))
aa = ai.args
result[i] = Any[ (isa(aa[j],Expr) ? aa[j].typ : abstract_eval(aa[j],vtypes,sv)) for j=2:length(aa) ]
if _any(isvarargtype, result[i])
return nothing
end
elseif isa(ti, Union)
elseif isa(tti, Union)
return nothing
elseif ti ⊑ Tuple
elseif tti <: Tuple
if i == n
if isvatuple(tti) && length(tti.parameters) == 1
result[i] = Any[Vararg{tti.parameters[1].parameters[1]}]
Expand All @@ -894,7 +896,7 @@ function precise_container_types(args, types, vtypes::VarTable, sv)
else
return nothing
end
elseif ti⊑AbstractArray && i==n
elseif tti <: AbstractArray && i == n
result[i] = Any[Vararg{eltype(tti)}]
else
return nothing
Expand Down Expand Up @@ -1264,7 +1266,7 @@ function tmerge(typea::ANY, typeb::ANY)
typea, typeb = widenconst(typea), widenconst(typeb)
typea === typeb && return typea
if (typea <: Tuple) && (typeb <: Tuple)
if length(typea.parameters) == length(typeb.parameters) && !isvatuple(typea) && !isvatuple(typeb)
if isa(typea, DataType) && isa(typeb, DataType) && length(typea.parameters) == length(typeb.parameters) && !isvatuple(typea) && !isvatuple(typeb)
return typejoin(typea, typeb)
end
return Tuple
Expand Down Expand Up @@ -1507,7 +1509,7 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtr
linfo = specialize_method(method, atypes, sparams)
end
# our stack frame inference context
frame = InferenceState(unshare_linfo!(linfo::LambdaInfo), atypes, sparams, optimize)
frame = InferenceState(unshare_linfo!(linfo::LambdaInfo), optimize)
if cached
frame.tfunc_bp = ccall(:jl_specializations_insert, Ref{TypeMapEntry}, (Any, Any, Any), method, atypes, linfo)
end
Expand Down Expand Up @@ -1551,7 +1553,7 @@ end
function typeinf_ext(linfo::LambdaInfo)
if isdefined(linfo, :def)
# method lambda - infer this specialization via the method cache
(code, _t, _) = typeinf_edge(linfo.def, linfo.specTypes, svec(), true, true, true, linfo)
(code, _t, _) = typeinf_edge(linfo.def, linfo.specTypes, linfo.sparam_vals, true, true, true, linfo)
if code.inferred
linfo.inferred = true
linfo.inInference = false
Expand All @@ -1567,7 +1569,7 @@ function typeinf_ext(linfo::LambdaInfo)
end
else
# toplevel lambda - infer directly
frame = InferenceState(linfo, linfo.specTypes, svec(), true)
frame = InferenceState(linfo, true)
typeinf_loop(frame)
@assert frame.inferred # TODO: deal with this better
end
Expand Down
2 changes: 1 addition & 1 deletion base/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ first(t::Tuple) = t[1]
# eltype

eltype(::Type{Tuple{}}) = Bottom
eltype{T,_}(::Type{NTuple{_,T}}) = T
eltype{T}(::Type{Tuple{Vararg{T}}}) = T

# front (the converse of tail: it skips the last entry)

Expand Down
4 changes: 2 additions & 2 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,15 @@ JL_DLLEXPORT jl_typemap_entry_t *jl_specializations_insert(jl_method_t *m, jl_tu

JL_DLLEXPORT jl_value_t *jl_specializations_lookup(jl_method_t *m, jl_tupletype_t *type)
{
jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(m->specializations, type, NULL, 1, /*subtype*/0, /*offs*/0);
jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(m->specializations, type, NULL, 2, /*subtype*/0, /*offs*/0);
if (!sf)
return jl_nothing;
return sf->func.value;
}

JL_DLLEXPORT jl_value_t *jl_methtable_lookup(jl_methtable_t *mt, jl_tupletype_t *type)
{
jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(mt->defs, type, NULL, 1, /*subtype*/0, /*offs*/0);
jl_typemap_entry_t *sf = jl_typemap_assoc_by_type(mt->defs, type, NULL, 2, /*subtype*/0, /*offs*/0);
if (!sf)
return jl_nothing;
return sf->func.value;
Expand Down
7 changes: 5 additions & 2 deletions src/typemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,8 +514,11 @@ int jl_typemap_intersection_visitor(union jl_typemap_t map, int offs,

int sigs_eq(jl_value_t *a, jl_value_t *b, int useenv)
{
if (jl_has_typevars(a) || jl_has_typevars(b)) {
return jl_types_equal_generic(a,b,useenv);
// useenv == 0 : subtyping + ensure typevars correspond
// useenv == 1 : subtyping + ensure typevars correspond + fail if bound != bound in some typevar match
// useenv == 2 : ignore typevars (because UnionAll getting lost in intersection can cause jl_types_equal to fail in the wrong direction for some purposes)
if (useenv != 2 && (jl_has_typevars(a) || jl_has_typevars(b))) {
return jl_types_equal_generic(a, b, useenv);
}
return jl_subtype(a, b, 0) && jl_subtype(b, a, 0);
}
Expand Down
6 changes: 6 additions & 0 deletions test/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,9 @@ end
let g() = Int <: Real ? 1 : ""
@test Base.return_types(g, Tuple{}) == [Int]
end

typealias NInt{N} Tuple{Vararg{Int, N}}
@test Base.eltype(NInt) === Int
fNInt(x::NInt) = (x...)
gNInt() = f(x)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean fNInt?

@code_typed gNInt()