diff --git a/base/exports.jl b/base/exports.jl index c044051ddb263..34131c20e7e39 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -222,6 +222,7 @@ export ≤, ==, >, + >:, >=, ≥, >>, diff --git a/base/inference.jl b/base/inference.jl index aefdfde6c1661..d0983b7f4e71e 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -1704,6 +1704,12 @@ function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vect return Const(rty.val === false) end return rty + elseif length(fargs) == 3 && istopfunction(tm, f, :(>:)) + # swap T1 and T2 arguments and call issubtype + fargs = Any[issubtype, fargs[3], fargs[2]] + argtypes = Any[typeof(issubtype), argtypes[3], argtypes[2]] + rty = abstract_call(issubtype, fargs, argtypes, vtypes, sv) + return rty end if length(argtypes)>2 && argtypes[3] ⊑ Int @@ -3510,36 +3516,19 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference # typeassert(x::S, T) => x, when S<:T if isType(atypes[3]) && isleaftype(atypes[3]) && atypes[2] ⊑ atypes[3].parameters[1] - return (argexprs[2],()) + return (argexprs[2], ()) end end topmod = _topmod(sv) # special-case inliners for known pure functions that compute types if sv.params.inlining if isa(e.typ, Const) # || isconstType(e.typ) - # XXX: this is needlessly buggy and should just call `inline_as_constant` if (f === apply_type || f === fieldtype || f === typeof || istopfunction(topmod, f, :typejoin) || - istopfunction(topmod, f, :promote_type)) - # XXX: compute effect_free for the actual arguments - if length(argexprs) < 2 || effect_free(argexprs[2], sv.src, sv.mod, true) - return (e.typ.val, ()) - else - return (e.typ.val, Any[argexprs[2]]) - end - end - end - if istopfunction(topmod, f, :isbits) && length(atypes)==2 && isType(atypes[2]) && - effect_free(argexprs[2], sv.src, sv.mod, true) && isleaftype(atypes[2].parameters[1]) - # TODO: this is needlessly complicated and should just call `inline_as_constant` - return (isbits(atypes[2].parameters[1]),()) - end - if f === Core.kwfunc && length(argexprs) == 2 && isa(e.typ, Const) - # TODO: replace with a call to `inline_as_constant` - if effect_free(argexprs[2], sv.src, sv.mod, true) - return (e.typ.val, ()) - else - return (e.typ.val, Any[argexprs[2]]) + istopfunction(topmod, f, :isbits) || + istopfunction(topmod, f, :promote_type) || + (f === Core.kwfunc && length(argexprs) == 2)) + return inline_as_constant(e.typ.val, argexprs, sv, nothing) end end end @@ -3605,6 +3594,24 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference not_is.typ = Bool not_is.args[2].typ = Bool return (not_is, ()) + elseif length(atypes) == 3 && istopfunction(topmod, f, :(>:)) + # special-case inliner for issupertype + # that works, even though inference generally avoids inferring the `>:` Method + if isa(e.typ, Const) + return inline_as_constant(e.typ.val, argexprs, sv, nothing) + end + arg_T1 = argexprs[2] + arg_T2 = argexprs[3] + issubtype_stmts = () + if !effect_free(arg_T2, sv.src, sv.mod, false) + # spill first argument to preserve order-of-execution + issubtype_vnew = newvar!(sv, widenconst(exprtype(arg_T1, sv.src, sv.mod))) + issubtype_stmts = Any[ Expr(:(=), issubtype_vnew, arg_T1) ] + arg_T1 = issubtype_vnew + end + issubtype_expr = Expr(:call, GlobalRef(Core, :issubtype), arg_T2, arg_T1) + issubtype_expr.typ = Bool + return (issubtype_expr, issubtype_stmts) end if length(atype_unlimited.parameters) - 1 > sv.params.MAX_TUPLETYPE_LEN diff --git a/base/methodshow.jl b/base/methodshow.jl index 92bc591b8ae96..95623a477b542 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -58,7 +58,11 @@ function arg_decl_parts(m::Method) line = m.line if src !== nothing && src.slotnames !== nothing argnames = src.slotnames[1:m.nargs] - decls = Any[argtype_decl(:tvar_env => tv, argnames[i], sig, i, m.nargs, m.isva) + show_env = ImmutableDict{Symbol, Any}() + for t in tv + show_env = ImmutableDict(show_env, :unionall_env => t) + end + decls = Any[argtype_decl(show_env, argnames[i], sig, i, m.nargs, m.isva) for i = 1:m.nargs] else decls = Any[("", "") for i = 1:length(sig.parameters)] diff --git a/base/multimedia.jl b/base/multimedia.jl index 377874407ab36..9314d4b5ab553 100644 --- a/base/multimedia.jl +++ b/base/multimedia.jl @@ -39,7 +39,7 @@ mimewritable{mime}(::MIME{mime}, x) = show(io::IO, m::AbstractString, x) = show(io, MIME(m), x) mimewritable(m::AbstractString, x) = mimewritable(MIME(m), x) -verbose_show(io, m, x) = show(IOContext(io,limit=false), m, x) +verbose_show(io, m, x) = show(IOContext(io, :limit => false), m, x) """ reprmime(mime, x) diff --git a/base/operators.jl b/base/operators.jl index f9817d60ef165..7d541134af226 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -9,7 +9,7 @@ typealias Indices{N} NTuple{N,AbstractUnitRange} """ <:(T1, T2) -Subtype operator, equivalent to `issubtype(T1,T2)`. +Subtype operator, equivalent to `issubtype(T1, T2)`. ```jldoctest julia> Float64 <: AbstractFloat @@ -24,6 +24,13 @@ false """ const (<:) = issubtype +""" + >:(T1, T2) + +Supertype operator, equivalent to `issubtype(T2, T1)`. +""" +const (>:)(a::ANY, b::ANY) = issubtype(b, a) + """ supertype(T::DataType) diff --git a/base/range.jl b/base/range.jl index 622be41a12620..a42e6a0c239d1 100644 --- a/base/range.jl +++ b/base/range.jl @@ -254,7 +254,7 @@ function print_range(io::IO, r::Range, limit = get(io, :limit, false) sz = displaysize(io) if !haskey(io, :compact) - io = IOContext(io, compact=true) + io = IOContext(io, :compact => true) end screenheight, screenwidth = sz[1] - 4, sz[2] screenwidth -= length(pre) + length(post) diff --git a/base/replutil.jl b/base/replutil.jl index 16afccc64c111..e9fb7c59f79aa 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -39,7 +39,7 @@ function show{K,V}(io::IO, ::MIME"text/plain", t::Associative{K,V}) recur_io = IOContext(io, :SHOWN_SET => t) limit::Bool = get(io, :limit, false) if !haskey(io, :compact) - recur_io = IOContext(recur_io, compact=true) + recur_io = IOContext(recur_io, :compact => true) end print(io, summary(t)) diff --git a/base/show.jl b/base/show.jl index 4f4a34ac851cd..9dbc7454c228f 100644 --- a/base/show.jl +++ b/base/show.jl @@ -25,21 +25,24 @@ end The same as `IOContext(io::IO, KV::Pair)`, but accepting properties as keyword arguments. """ -IOContext(io::IO; kws...) = IOContext(IOContext(io, ImmutableDict{Symbol,Any}()); kws...) +IOContext(io::IO; kws...) = IOContext(convert(IOContext, io); kws...) function IOContext(io::IOContext; kws...) for (k, v) in kws io = IOContext(io, k, v) end - io + return io end +convert(::Type{IOContext}, io::IOContext) = io +convert(::Type{IOContext}, io::IO) = IOContext(io, ImmutableDict{Symbol, Any}()) + IOContext(io::IOContext, dict::ImmutableDict) = typeof(io)(io.io, dict) IOContext(io::IO, dict::ImmutableDict) = IOContext{typeof(io)}(io, dict) +IOContext(io::IOContext, key, value) = IOContext(io.io, ImmutableDict{Symbol, Any}(io.dict, key, value)) IOContext(io::IO, key, value) = IOContext(io, ImmutableDict{Symbol, Any}(key, value)) -IOContext(io::IOContext, key, value) = IOContext(io, ImmutableDict{Symbol, Any}(io.dict, key, value)) -IOContext(io::IO, context::IO) = IOContext(io) +IOContext(io::IO, context::IO) = convert(IOContext, io) """ IOContext(io::IO, context::IOContext) @@ -184,32 +187,14 @@ function show(io::IO, x::UnionAll) if print_without_params(x) return show(io, unwrap_unionall(x).name) end - tvar_env = get(io, :tvar_env, false) - if tvar_env !== false && isa(tvar_env, AbstractVector) - tvar_env = Any[tvar_env..., x.var] - else - tvar_env = Any[x.var] - end - show(IOContext(io, tvar_env = tvar_env), x.body) + show(IOContext(io, :unionall_env => x.var), x.body) print(io, " where ") show(io, x.var) end -function show_type_parameter(io::IO, p::ANY, has_tvar_env::Bool) - if has_tvar_env - show(io, p) - else - show(IOContext(io, :tvar_env, true), p) - end -end - show(io::IO, x::DataType) = show_datatype(io, x) function show_datatype(io::IO, x::DataType) - # tvar_env is a `::Vector{Any}` when we are printing a method signature - # and `true` if we are printing type parameters outside a method signature. - has_tvar_env = get(io, :tvar_env, false) !== false - if (!isempty(x.parameters) || x.name === Tuple.name) && x !== Tuple n = length(x.parameters) @@ -224,7 +209,7 @@ function show_datatype(io::IO, x::DataType) # since this information is still useful. print(io, '{') for (i, p) in enumerate(x.parameters) - show_type_parameter(io, p, has_tvar_env) + show(io, p) i < n && print(io, ',') end print(io, '}') @@ -1076,16 +1061,12 @@ function ismodulecall(ex::Expr) end function show(io::IO, tv::TypeVar) - # If `tvar_env` exist and we are in it, the type constraint are - # already printed and we don't need to print it again. + # If we are in the `unionall_env`, the type-variable is bound + # and the type constraints are already printed. + # We don't need to print it again. # Otherwise, the lower bound should be printed if it is not `Bottom` # and the upper bound should be printed if it is not `Any`. - tvar_env = isa(io, IOContext) && get(io, :tvar_env, false) - if isa(tvar_env, Vector{Any}) - in_env = (tv in tvar_env::Vector{Any}) - else - in_env = false - end + in_env = (:unionall_env => tv) in io function show_bound(io::IO, b::ANY) parens = isa(b,UnionAll) && !print_without_params(b) parens && print(io, "(") @@ -1204,16 +1185,22 @@ function dump(io::IO, x::DataType, n::Int, indent) if x !== Any print(io, " <: ", supertype(x)) end - if !(x <: Tuple) - tvar_io = IOContext(io, :tvar_env => Any[x.parameters...]) - fields = fieldnames(x) - if n > 0 - for idx in 1:length(fields) - println(io) - print(io, indent, " ", fields[idx], "::") - print(tvar_io, fieldtype(x, idx)) + if n > 0 && !(x <: Tuple) + tvar_io::IOContext = io + for tparam in x.parameters + # approximately recapture the list of tvar parameterization + # that may be used by the internal fields + if isa(tparam, TypeVar) + tvar_io = IOContext(tvar_io, :unionall_env => tparam) end end + fields = fieldnames(x) + fieldtypes = x.types + for idx in 1:length(fields) + println(io) + print(io, indent, " ", fields[idx], "::") + print(tvar_io, fieldtypes[idx]) + end end nothing end @@ -1242,9 +1229,30 @@ function dumpsubtypes(io::IO, x::DataType, m::Module, n::Int, indent) # recurse into primary module bindings dumpsubtypes(io, x, t, n, indent) elseif isa(t, UnionAll) && directsubtype(t::UnionAll, x) + dt = unwrap_unionall(t) println(io) - print(io, indent, " ", m, ".", s) - print(io, " = ", t) + if isa(dt, DataType) && dt.name.wrapper === t + # primary type binding + print(io, indent, " ") + dumptype(io, dt, n - 1, string(indent, " ")) + else + # aliases to types + print(io, indent, " ", m, ".", s, "{") + tvar_io::IOContext = io + tp = t + while true + show(tvar_io, tp.var) + tvar_io = IOContext(tvar_io, :unionall_env, tp.var) + tp = tp.body + if isa(tp, UnionAll) + print(io, ", ") + else + print(io, "} = ") + break + end + end + show(tvar_io, tp) + end elseif isa(t, Union) && directsubtype(t::Union, x) println(io) print(io, indent, " ", m, ".", s, " = ", t) @@ -1252,7 +1260,8 @@ function dumpsubtypes(io::IO, x::DataType, m::Module, n::Int, indent) println(io) if t.name.module !== m || t.name.name != s # aliases to types - print(io, indent, " ", m, ".", s, " = ", t) + print(io, indent, " ", m, ".", s, " = ") + show(io, t) else # primary type binding print(io, indent, " ") @@ -1647,7 +1656,7 @@ function showarray(io::IO, X::AbstractArray, repr::Bool = true; header = true) return show_vector(io, X, "[", "]") end if !haskey(io, :compact) - io = IOContext(io, compact=true) + io = IOContext(io, :compact => true) end if !repr && get(io, :limit, false) && eltype(X) === Method # override usual show method for Vector{Method}: don't abbreviate long lists diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index a9e0496a1659c..7e0dfcb58761e 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -125,7 +125,8 @@ function Base.show(io::IO, ::MIME"text/plain", S::SparseMatrixCSC) end end -function Base.show(io::IO, S::SparseMatrixCSC) +Base.show(io::IO, S::SparseMatrixCSC) = Base.show(convert(IOContext, io), S::SparseMatrixCSC) +function Base.show(io::IOContext, S::SparseMatrixCSC) if nnz(S) == 0 return show(io, MIME("text/plain"), S) end @@ -140,7 +141,6 @@ function Base.show(io::IO, S::SparseMatrixCSC) pad = ndigits(max(S.m,S.n)) k = 0 sep = "\n " - io = IOContext(io) if !haskey(io, :compact) io = IOContext(io, :compact => true) end diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index 5b3850325c06f..25d9183954be2 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -681,7 +681,8 @@ function show(io::IO, ::MIME"text/plain", x::AbstractSparseVector) show(io, x) end -function show(io::IO, x::AbstractSparseVector) +show(io::IO, x::AbstractSparseVector) = show(convert(IOContext, io), x) +function show(io::IOContext, x::AbstractSparseVector) # TODO: make this a one-line form n = length(x) nzind = nonzeroinds(x) @@ -692,7 +693,6 @@ function show(io::IO, x::AbstractSparseVector) half_screen_rows = limit ? div(displaysize(io)[1] - 8, 2) : typemax(Int) pad = ndigits(n) sep = "\n\t" - io = IOContext(io) if !haskey(io, :compact) io = IOContext(io, :compact => true) end diff --git a/doc/src/manual/types.md b/doc/src/manual/types.md index 0659db24d0e44..8cef435181167 100644 --- a/doc/src/manual/types.md +++ b/doc/src/manual/types.md @@ -1067,6 +1067,10 @@ end Of course, this depends on what `Int` is aliased to -- but that is predefined to be the correct type -- either `Int32` or `Int64`. +(Note that unlike `Int`, `Float` does not exist as a type-alias for a specific sized `AbstractFloat`. +Unlike with integer registers, the floating point register sizes are specified by the IEEE-754 standard. +Whereas the size of `Int` reflects the size of a native pointer on that machine.) + For parametric types, `typealias` can be convenient for providing names for cases where some of the parameter choices are fixed: diff --git a/doc/src/stdlib/base.md b/doc/src/stdlib/base.md index ec8ff88a4ad51..018a1a4c25315 100644 --- a/doc/src/stdlib/base.md +++ b/doc/src/stdlib/base.md @@ -89,6 +89,7 @@ Base.identity Base.supertype Core.issubtype Base.:(<:) +Base.:(>:) Base.subtypes Base.typemin Base.typemax diff --git a/doc/src/stdlib/io-network.md b/doc/src/stdlib/io-network.md index 0d710513d427a..cb697abfbac33 100644 --- a/doc/src/stdlib/io-network.md +++ b/doc/src/stdlib/io-network.md @@ -51,7 +51,6 @@ Base.readavailable Base.IOContext Base.IOContext(::IO, ::Pair) Base.IOContext(::IO, ::IOContext) -Base.IOContext(::IO) ``` ## Text I/O diff --git a/doc/src/stdlib/punctuation.md b/doc/src/stdlib/punctuation.md index 0b44fbb77391a..e380a378854ef 100644 --- a/doc/src/stdlib/punctuation.md +++ b/doc/src/stdlib/punctuation.md @@ -42,3 +42,6 @@ Extended documentation for mathematical symbols & functions is [here](@ref math- | `::` | type annotation, depending on context | | `:( )` | quoted expression | | `:a` | symbol a | +| `<:` | [`subtype operator`](@ref <:) | +| `>:` | [`supertype operator`](@ref >:) (reverse of subtype operator) | +| `===` | [`egal comparison operator`](@ref ===) | diff --git a/examples/typetree.jl b/examples/typetree.jl index bda8fe239459a..08c05b946f7bd 100644 --- a/examples/typetree.jl +++ b/examples/typetree.jl @@ -14,7 +14,7 @@ Base.isless(a::Binding, b::Binding) = isless(a.sym, b.sym) # The node type holds the type of the current node and a dict of subtypes struct TTNode - typ::Type + typ # ::Type subtypes::Dict{Binding, TTNode} TTNode(t::ANY) = new(t, Dict{Binding, TTNode}()) @@ -38,21 +38,29 @@ function store_type(sname::Binding, t::Union) # store unions under Union type subtypes = store_type(Binding(suptype.name), suptype) add_ttnode(subtypes, sname, tnode) + store_union(sname, tnode, t) # unions are also in a sense related to the types of their components - for suptype = t.types - if isa(suptype, DataType) # ignore TypeConstructors - subtypes = store_type(Binding(suptype.name), suptype) - add_ttnode(subtypes, sname, tnode) - end - end return tnode.subtypes end +function store_union(sname::Binding, tnode::TTNode, t::ANY) + t = Base.unwrap_unionall(t) + if isa(t, Union) + store_union(sname, tnode, t.a) + store_union(sname, tnode, t.b) + elseif isa(t, DataType) + binding = Binding(t.name) + subtypes = store_type(binding, t) + add_ttnode(subtypes, sname, tnode) + end + nothing +end -function store_type(sname::Binding, t::TypeConstructor) - suptype = t.body - subtypes = store_type(isa(suptype, DataType) ? Binding(suptype.name) : Binding(Main, string(suptype::Union)), suptype) +function store_type(sname::Binding, t::UnionAll) + suptype = Base.unwrap_unionall(t) + binding = isa(suptype, DataType) ? Binding(suptype.name) : Binding(Main, string(suptype::Union)) + subtypes = store_type(binding, suptype) tnode = add_ttnode(subtypes, sname, t) return tnode.subtypes end @@ -69,7 +77,7 @@ function store_all_from(m::Module) for s in names(m, true) if isdefined(m, s) && !Base.isdeprecated(m, s) t = getfield(m, s) - if isa(t, Type) + if isa(t, Type) && t !== Union{} store_type(Binding(m, s), t) elseif isa(t, Module) && module_name(t) === s && module_parent(t) === m && t !== m store_all_from(t) @@ -93,17 +101,34 @@ type_props(typ::DataType) = string("<<", function print_tree(subtypes::Dict{Binding, TTNode}, pfx::String="") for b in sort!(collect(keys(subtypes))) v = subtypes[b] + ishidden = unsafe_load(Base.unsafe_convert(Ptr{UInt8}, b.sym)) == UInt8('#') + if ishidden && supertype(v.typ) === Function + continue + end if b.mod === Main n = string(b.sym) elseif !isa(v.typ, DataType) || v.typ.name.module != b.mod || v.typ.name.name != b.sym - n = string(b.mod, '.', b.sym, (isa(v.typ, TypeConstructor) ? ("{", join(v.typ.parameters, ","), "}") : ())...) + n_io = IOBuffer() + print(n_io, b.mod, '.', b.sym) + ua = v.typ + if isa(ua, UnionAll) + print(n_io, "{") + while true + print(n_io, ua.var) + ua = ua.body + if isa(ua, UnionAll) + print(n_io, ", ") + else + break + end + end + print(n_io, "}") + end + n = String(take!(n_io)) else n = string(v.typ) end - ishidden = unsafe_load(Base.unsafe_convert(Ptr{UInt8}, b.sym)) == UInt8('#') - if ishidden && supertype(v.typ) === Function - continue - elseif n == string(v.typ) + if n == string(v.typ) println(pfx, "+- ", n, " ", type_props(v.typ)) else println(pfx, "+- ", n, " = ", v.typ, " ", type_props(v.typ)) diff --git a/src/gf.c b/src/gf.c index 1bef3426bcdcc..84a2bcb3923dc 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1094,22 +1094,21 @@ static int check_ambiguous_visitor(jl_typemap_entry_t *oldentry, struct typemap_ jl_method_t *m = closure->newentry->func.method; jl_tupletype_t *sig = oldentry->sig; jl_value_t *isect = closure->match.ti; - if (jl_types_equal(isect, (jl_value_t*)(closure->after ? sig : type))) { - // we're ok if the new definition is actually the one we just - // inferred to be required (see issue #3609). ideally this would - // never happen, since if New ⊓ Old == New then we should have - // considered New more specific, but jl_type_morespecific is not - // perfect, so this is a useful fallback. - return 1; - } // we know type ∩ sig != Union{} and - // we know !jl_type_morespecific(type, sig) [before] - // or !jl_type_morespecific(sig, type) [after] + // we are assuming that + // !jl_type_morespecific(type, sig) [before] + // or !jl_type_morespecific(sig, type) [after] + // based on their sort order in the typemap // now we are checking that the reverse is true if (!jl_type_morespecific((jl_value_t*)(closure->after ? type : sig), (jl_value_t*)(closure->after ? sig : type))) { - jl_typemap_entry_t *l = jl_typemap_assoc_by_type(map, (jl_tupletype_t*)isect, NULL, 0, 0, 0, + // see if the intersection is covered by another existing method + // that will resolve the ambiguity (by being more specific than either) + // (if type-morespecific made a mistake, this also might end up finding + // that isect == type or isect == sig and return the original match) + jl_typemap_entry_t *l = jl_typemap_assoc_by_type( + map, (jl_tupletype_t*)isect, NULL, 0, 0, 0, closure->newentry->min_world); if (l != NULL) // ok, intersection is covered return 1; @@ -2596,11 +2595,9 @@ static int ml_matches_visitor(jl_typemap_entry_t *ml, struct typemap_intersectio } } else { - // the current method doesn't match if there is an intersection with an - // ambiguous method that covers our intersection with this one. - jl_value_t *ambi = jl_type_intersection_env((jl_value_t*)ml->sig, - (jl_value_t*)mambig->sig, &env); - if (jl_subtype(closure->match.ti, ambi)) { + // the current method definitely never matches if the intersection with this method + // is also fully covered by an ambiguous method's signature + if (jl_subtype(closure->match.ti, mambig->sig)) { return_this_match = 0; break; } diff --git a/src/task.c b/src/task.c index 7b2ce67637292..be99b9afdda9a 100644 --- a/src/task.c +++ b/src/task.c @@ -663,7 +663,7 @@ void jl_init_tasks(void) jl_new_datatype(jl_symbol("Task"), jl_any_type, jl_emptysvec, - jl_svec(13, + jl_svec(9, jl_symbol("parent"), jl_symbol("storage"), jl_symbol("state"), @@ -672,19 +672,17 @@ void jl_init_tasks(void) jl_symbol("result"), jl_symbol("exception"), jl_symbol("backtrace"), - jl_symbol("code"), - jl_symbol("ctx"), - jl_symbol("bufsz"), - jl_symbol("stkbuf"), - jl_symbol("ssize")), - jl_svec(13, + jl_symbol("code")), + jl_svec(9, jl_any_type, - jl_any_type, jl_sym_type, - jl_any_type, jl_any_type, - jl_any_type, jl_any_type, - jl_any_type, jl_any_type, - jl_tupletype_fill(sizeof(jl_jmp_buf), (jl_value_t*)jl_uint8_type), - jl_long_type, jl_voidpointer_type, jl_long_type), + jl_any_type, + jl_sym_type, + jl_any_type, + jl_any_type, + jl_any_type, + jl_any_type, + jl_any_type, + jl_any_type), 0, 1, 8); jl_svecset(jl_task_type->types, 0, (jl_value_t*)jl_task_type); diff --git a/src/typemap.c b/src/typemap.c index 4d1fc4c70bcc0..eb5ee8aefcfd0 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -434,14 +434,14 @@ static int jl_typemap_intersection_array_visitor(struct jl_ordereddict_t *a, jl_ if (tparam) t = jl_tparam0(t); } + // `t` is a leaftype, so intersection test becomes subtype if (ty == (jl_value_t*)jl_any_type || // easy case: Any always matches - (tparam ? // need to compute `ty <: Type{t}` - (jl_is_uniontype(ty) || // punt on Union{...} right now - jl_typeof(t) == ty || // deal with kinds (e.g. ty == DataType && t == Type{t}) - jl_isa(t, ty)) // deal with ty == Type{T} - : jl_subtype(t, ty))) // `t` is a leaftype, so intersection test becomes subtype - if (!jl_typemap_intersection_visitor(ml, offs+1, closure)) + (tparam + ? (jl_typeof(t) == ty || jl_isa(t, ty)) // (Type{t} <: ty), where is_leaf_type(t) => isa(t, ty) + : (t == ty || jl_subtype(t, ty)))) { + if (!jl_typemap_intersection_visitor(ml, offs + 1, closure)) return 0; + } } return 1; } diff --git a/test/Makefile b/test/Makefile index 50cf2c51219f0..2e2ca44796304 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,8 @@ BUILDDIR := . include $(JULIAHOME)/Make.inc # TODO: this Makefile ignores BUILDDIR, except for computing JULIA_EXECUTABLE -TESTS = all linalg sparse unicode strings dates $(filter-out TestHelpers runtests testdefs,$(patsubst $(SRCDIR)/%.jl,%,$(wildcard $(SRCDIR)/*.jl $(SRCDIR)/linalg/*.jl))) +TESTS = all linalg sparse unicode strings dates \ + $(filter-out TestHelpers runtests testdefs,$(patsubst $(SRCDIR)/%.jl,%,$(wildcard $(SRCDIR)/*.jl $(SRCDIR)/*/*.jl))) default: all diff --git a/test/dict.jl b/test/dict.jl index 916c764366e40..9fb3926c08295 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -268,7 +268,7 @@ for d in (Dict("\n" => "\n", "1" => "\n", "\n" => "2"), for cols in (12, 40, 80), rows in (2, 10, 24) # Ensure output is limited as requested s = IOBuffer() - io = Base.IOContext(s, limit=true, displaysize=(rows, cols)) + io = Base.IOContext(Base.IOContext(s, :limit => true), :displaysize => (rows, cols)) Base.show(io, MIME("text/plain"), d) out = split(String(take!(s)),'\n') for line in out[2:end] @@ -278,7 +278,7 @@ for d in (Dict("\n" => "\n", "1" => "\n", "\n" => "2"), for f in (keys, values) s = IOBuffer() - io = Base.IOContext(s, limit=true, displaysize=(rows, cols)) + io = Base.IOContext(Base.IOContext(s, :limit => true), :displaysize => (rows, cols)) Base.show(io, MIME("text/plain"), f(d)) out = split(String(take!(s)),'\n') for line in out[2:end] @@ -311,7 +311,7 @@ end mutable struct Alpha end Base.show(io::IO, ::Alpha) = print(io,"α") let sbuff = IOBuffer(), - io = Base.IOContext(sbuff, limit=true, displaysize=(10, 20)) + io = Base.IOContext(Base.IOContext(sbuff, :limit => true), :displaysize => (10, 20)) Base.show(io, MIME("text/plain"), Dict(Alpha()=>1)) @test !contains(String(sbuff), "…") diff --git a/test/nullable.jl b/test/nullable.jl index 6cf58550c2ff3..db433bf8e5bbb 100644 --- a/test/nullable.jl +++ b/test/nullable.jl @@ -103,13 +103,13 @@ for (i, T) in enumerate(types) @test String(take!(io1)) == @sprintf("Nullable{%s}(%s)", T, String(take!(io2))) a1 = [x2] - show(IOContext(io1, compact=false), a1) - show(IOContext(io2, compact=false), x2) + show(IOContext(io1, :compact => false), a1) + show(IOContext(io2, :compact => false), x2) @test String(take!(io1)) == @sprintf("Nullable{%s}[%s]", string(T), String(take!(io2))) show(io1, a1) - show(IOContext(io2, compact=true), x2) + show(IOContext(io2, :compact => true), x2) @test String(take!(io1)) == @sprintf("Nullable{%s}[%s]", string(T), String(take!(io2))) end diff --git a/test/offsetarray.jl b/test/offsetarray.jl index 3b35ca9880a76..d03bae73254e2 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -139,7 +139,7 @@ smry = summary(v) @test contains(smry, "OffsetArray{Float64,1") @test contains(smry, "with indices -1:1") function cmp_showf(printfunc, io, A) - ioc = IOContext(io, limit=true, compact=true) + ioc = IOContext(IOContext(io, :limit => true), :compact => true) printfunc(ioc, A) str1 = String(take!(io)) printfunc(ioc, parent(A)) @@ -162,9 +162,9 @@ targets2 = ["(1.0, 1.0)", "([1.0], [1.0])"] for n = 0:4 a = OffsetArray(ones(Float64,ntuple(d->1,n)), ntuple(identity,n)) - show(IOContext(io, limit=true), MIME("text/plain"), a) + show(IOContext(io, :limit => true), MIME("text/plain"), a) @test String(take!(io)) == targets1[n+1] - show(IOContext(io, limit=true), MIME("text/plain"), (a,a)) + show(IOContext(io, :limit => true), MIME("text/plain"), (a,a)) @test String(take!(io)) == targets2[n+1] end P = OffsetArray(rand(8,8), (1,1)) diff --git a/test/ranges.jl b/test/ranges.jl index 04f30ab641fcf..da0ed2d3a4df4 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -626,7 +626,7 @@ end # stringmime/show should display the range or linspace nicely # to test print_range in range.jl -replstrmime(x) = sprint((io,x) -> show(IOContext(io, limit=true), MIME("text/plain"), x), x) +replstrmime(x) = sprint((io,x) -> show(IOContext(io, :limit => true), MIME("text/plain"), x), x) @test replstrmime(1:4) == "1:4" @test stringmime("text/plain", 1:4) == "1:4" @test stringmime("text/plain", linspace(1,5,7)) == "1.0:0.6666666666666666:5.0" diff --git a/test/show.jl b/test/show.jl index 599154c8e78ed..89309804a6c15 100644 --- a/test/show.jl +++ b/test/show.jl @@ -4,7 +4,7 @@ const curmod = current_module() const curmod_name = fullname(curmod) const curmod_prefix = "$(["$m." for m in curmod_name]...)" -replstr(x) = sprint((io,x) -> show(IOContext(io, limit=true), MIME("text/plain"), x), x) +replstr(x) = sprint((io,x) -> show(IOContext(io, :limit => true), MIME("text/plain"), x), x) @test replstr(Array{Any}(2)) == "2-element Array{Any,1}:\n #undef\n #undef" @test replstr(Array{Any}(2,2)) == "2×2 Array{Any,2}:\n #undef #undef\n #undef #undef" @@ -533,14 +533,14 @@ end # PR #16651 @test !contains(repr(ones(10,10)), "\u2026") -@test contains(sprint((io,x)->show(IOContext(io,:limit=>true), x), ones(30,30)), "\u2026") +@test contains(sprint((io, x) -> show(IOContext(io, :limit => true), x), ones(30, 30)), "\u2026") # showcompact() also sets :multiline=>false (#16817) let io = IOBuffer() x = [1, 2] showcompact(io, x) @test String(take!(io)) == "[1, 2]" - showcompact(IOContext(io, :compact=>true), x) + showcompact(IOContext(io, :compact => true), x) @test String(take!(io)) == "[1, 2]" end @@ -564,12 +564,15 @@ let repr = sprint(dump, Int64) @test repr == "Int64 <: Signed\n" end # Make sure a `TypeVar` in a `Union` doesn't break subtype dump. -typealias BreakDump17529{T} Union{T,Void} +typealias BreakDump17529{T} Union{T, Void} +# make sure dependent parameters are represented correctly +typealias VectorVI{I, VI<:AbstractVector{I}} Vector{VI} let repr = sprint(dump, Any) @test length(repr) > 100000 @test ismatch(r"^Any\n [^ \t\n]", repr) @test endswith(repr, '\n') - @test_broken contains(repr, " Base.Vector{T} = Array{T,1}\n") + @test contains(repr, " Base.Vector{T} = Array{T,1}\n") + @test contains(repr, ".VectorVI{I, VI<:AbstractArray{I,1}} = Array{VI,1}\n") @test !contains(repr, "Core.Vector{T}") end let repr = sprint(dump, Integer) diff --git a/test/subtype.jl b/test/subtype.jl index 01698e27af9d6..27b33350782a0 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -911,3 +911,7 @@ ftwoparams(::TwoParams{<:Real,<:Real}) = 3 @test TwoParams{Real,Complex}(3,0im) isa TwoParams{>:Int,<:Number} @test !(TwoParams(3.0,0im) isa TwoParams{>:Int,<:Number}) @test !(TwoParams(3,'x') isa TwoParams{>:Int,<:Number}) + +# supertype operator +@test !(Int >: Integer) +@test Integer >: Int