Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

grabbag of subtyping punchlist items #20407

Merged
merged 13 commits into from
Feb 11, 2017
Merged
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
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ export
≤,
==,
>,
>:,
>=,
≥,
>>,
Expand Down
51 changes: 29 additions & 22 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion base/methodshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
2 changes: 1 addition & 1 deletion base/multimedia.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 8 additions & 1 deletion base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -24,6 +24,13 @@ false
"""
const (<:) = issubtype

"""
>:(T1, T2)

Supertype operator, equivalent to `issubtype(T2, T1)`.
"""
const (>:)(a::ANY, b::ANY) = issubtype(b, a)
Copy link
Member

Choose a reason for hiding this comment

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

I believe this needs special inference support to be able to infer Const(true) or Const(false).

Copy link
Member Author

Choose a reason for hiding this comment

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

Probably doable, and perhaps not a bad idea anyways (so that it doesn't attempt to actually specialize on any arguments that it sees). I guess the idea is that it's preferable to ensure >: and <: behave the same. Should I make both of them (issupertype) builtins to keep it identical, or just make it close enough via inference?

Copy link
Member

Choose a reason for hiding this comment

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

I'd rather not add more builtins; let's just add it to inference.


"""
supertype(T::DataType)

Expand Down
2 changes: 1 addition & 1 deletion base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion base/replutil.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
97 changes: 53 additions & 44 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)

Expand All @@ -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, '}')
Expand Down Expand Up @@ -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, "(")
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1242,17 +1229,39 @@ 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)
elseif isa(t, DataType) && directsubtype(t::DataType, x)
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, " ")
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions base/sparse/sparsematrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions base/sparse/sparsevector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions doc/src/manual/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
1 change: 1 addition & 0 deletions doc/src/stdlib/base.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Base.identity
Base.supertype
Core.issubtype
Base.:(<:)
Base.:(>:)
Base.subtypes
Base.typemin
Base.typemax
Expand Down
1 change: 0 additions & 1 deletion doc/src/stdlib/io-network.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ Base.readavailable
Base.IOContext
Base.IOContext(::IO, ::Pair)
Base.IOContext(::IO, ::IOContext)
Base.IOContext(::IO)
```

## Text I/O
Expand Down
3 changes: 3 additions & 0 deletions doc/src/stdlib/punctuation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 ===) |
Loading