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

type system revision and new subtype algorithm #18457

Merged
merged 18 commits into from
Jan 16, 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
23 changes: 23 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ Julia v0.6.0 Release Notes
New language features
---------------------

* New type system capabilities ([#8974], [#18457])
* Type parameter constraints can refer to previous parameters, e.g.
`type Foo{R<:Real, A<:AbstractArray{R}}`. Can also be used in method definitions.
* New syntax `Array{T} where T<:Integer`, indicating a union of types over all
specified values of `T` (represented by a `UnionAll` type). This provides behavior
similar to parametric methods or `typealias`, but can be used anywhere a type is
accepted. This syntax can also be used in method definitions, e.g.
`function inv(M::Matrix{T}) where T<:AbstractFloat`.
Anonymous functions can have type parameters via the syntax
`((x::Array{T}) where T<:Real) -> 2x`.
* Much more accurate subtype and type intersection algorithms. Method sorting and
identification of equivalent and ambiguous methods are improved as a result.

Language changes
----------------

Expand Down Expand Up @@ -103,6 +116,16 @@ This section lists changes that do not have deprecation warnings.
special 1×n-sized `AbstractMatrix`), not a `Matrix`, etc. In particular, for
`v::AbstractVector` we now have `(v.').' === v` and `v.' * v` is a scalar. ([#19670])

* Parametric types with "unspecified" parameters, such as `Array`, are now represented
as `UnionAll` types instead of `DataType`s ([#18457]).

* `Union` types have two fields, `a` and `b`, instead of a single `types` field.
The empty type `Union{}` is represented by a singleton of type `BottomType` ([#18457]).

* The type `NTuple{N}` now refers to tuples where every element has the same type
(since it is shorthand for `NTuple{N,T} where T`). To get the old behavior of matching
any tuple, use `NTuple{N,Any}` ([#18457]).

Library improvements
--------------------

Expand Down
5 changes: 3 additions & 2 deletions base/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ function get_type(sym, fn)
end
# Method completion on function call expression that look like :(max(1))
function complete_methods(ex_org::Expr)
args_ex = DataType[]
args_ex = Any[]
func, found = get_value(ex_org.args[1], Main)
!found && return String[]
for ex in ex_org.args[2:end]
Expand All @@ -330,7 +330,8 @@ function complete_methods(ex_org::Expr)
io = IOBuffer()
for method in ml
# Check if the method's type signature intersects the input types
if typeintersect(Tuple{method.sig.parameters[1 : min(na, end)]...}, t_in) != Union{}
ms = method.sig
if typeintersect(Base.rewrap_unionall(Tuple{Base.unwrap_unionall(ms).parameters[1 : min(na, end)]...}, ms), t_in) != Union{}
show(io, method, kwtype=kwtype)
push!(out, String(take!(io)))
end
Expand Down
8 changes: 3 additions & 5 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ julia> extrema(b)
"""
linearindices(A) = (@_inline_meta; OneTo(_length(A)))
linearindices(A::AbstractVector) = (@_inline_meta; indices1(A))
eltype{T}(::Type{AbstractArray{T}}) = T
eltype{T,N}(::Type{AbstractArray{T,N}}) = T
eltype(::Type{A}) where A<:AbstractArray{E} where E = E
Copy link
Member

Choose a reason for hiding this comment

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

Nice!

Copy link
Sponsor Member

Choose a reason for hiding this comment

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

As others have pointed out (#18457 (comment)), this combination of long form and short form syntax is hard to read.

elsize{T}(::AbstractArray{T}) = sizeof(T)

"""
Expand Down Expand Up @@ -204,7 +203,7 @@ julia> strides(A)
```
"""
strides(A::AbstractArray) = _strides((1,), A)
_strides{T,N}(out::NTuple{N}, A::AbstractArray{T,N}) = out
_strides{T,N}(out::NTuple{N,Any}, A::AbstractArray{T,N}) = out
function _strides{M,T,N}(out::NTuple{M}, A::AbstractArray{T,N})
@_inline_meta
_strides((out..., out[M]*size(A, M)), A)
Expand Down Expand Up @@ -267,6 +266,7 @@ should define `linearindexing` in the type-domain:
Base.linearindexing{T<:MyArray}(::Type{T}) = Base.LinearFast()
"""
linearindexing(A::AbstractArray) = linearindexing(typeof(A))
linearindexing(::Type{Union{}}) = LinearFast()
linearindexing{T<:AbstractArray}(::Type{T}) = LinearSlow()
linearindexing{T<:Array}(::Type{T}) = LinearFast()
linearindexing{T<:Range}(::Type{T}) = LinearFast()
Expand Down Expand Up @@ -997,8 +997,6 @@ promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
#TODO: ERROR CHECK
cat(catdim::Integer) = Array{Any,1}(0)

vcat() = Array{Any,1}(0)
hcat() = Array{Any,1}(0)
typed_vcat{T}(::Type{T}) = Array{T,1}(0)
typed_hcat{T}(::Type{T}) = Array{T,1}(0)

Expand Down
4 changes: 4 additions & 0 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,10 @@ end


# concatenations of homogeneous combinations of vectors, horizontal and vertical

vcat() = Array{Any,1}(0)
hcat() = Array{Any,1}(0)

function hcat{T}(V::Vector{T}...)
height = length(V[1])
for j = 2:length(V)
Expand Down
24 changes: 9 additions & 15 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
#end

#type Union <: Type
# types::Tuple
# a
# b
#end

#type TypeVar
Expand All @@ -40,8 +41,8 @@
# ub::Type
#end

#type TypeConstructor
# parameters::Tuple
#type UnionAll
# var::TypeVar
# body
#end

Expand Down Expand Up @@ -120,7 +121,7 @@ import Core.Intrinsics.ccall
export
# key types
Any, DataType, Vararg, ANY, NTuple,
Tuple, Type, TypeConstructor, TypeName, TypeVar, Union, Void,
Tuple, Type, UnionAll, TypeName, TypeVar, Union, Void,
SimpleVector, AbstractArray, DenseArray,
# special objects
Function, CodeInfo, Method, MethodTable, TypeMapEntry, TypeMapLevel,
Expand Down Expand Up @@ -258,18 +259,11 @@ end
TypeVar(n::Symbol) =
ccall(:jl_new_typevar, Ref{TypeVar}, (Any, Any, Any), n, Union{}, Any)
TypeVar(n::Symbol, ub::ANY) =
(isa(ub,Bool) ?
ccall(:jl_new_typevar_, Ref{TypeVar}, (Any, Any, Any, Any), n, Union{}, Any, ub) :
ccall(:jl_new_typevar, Ref{TypeVar}, (Any, Any, Any), n, Union{}, ub::Type))
ccall(:jl_new_typevar, Ref{TypeVar}, (Any, Any, Any), n, Union{}, ub)
TypeVar(n::Symbol, lb::ANY, ub::ANY) =
(isa(ub,Bool) ?
ccall(:jl_new_typevar_, Ref{TypeVar}, (Any, Any, Any, Any), n, Union{}, lb::Type, ub) :
ccall(:jl_new_typevar, Ref{TypeVar}, (Any, Any, Any), n, lb::Type, ub::Type))
TypeVar(n::Symbol, lb::ANY, ub::ANY, b::Bool) =
ccall(:jl_new_typevar_, Ref{TypeVar}, (Any, Any, Any, Any), n, lb::Type, ub::Type, b)

TypeConstructor(p::ANY, t::ANY) =
ccall(:jl_new_type_constructor, Ref{TypeConstructor}, (Any, Any), p::SimpleVector, t::Type)
ccall(:jl_new_typevar, Ref{TypeVar}, (Any, Any, Any), n, lb, ub)

UnionAll(v::TypeVar, t::ANY) = ccall(:jl_type_unionall, Any, (Any, Any), v, t)

Void() = nothing

Expand Down
2 changes: 1 addition & 1 deletion base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ typealias ScalarType Union{Type{Any}, Type{Nullable}}
## Broadcasting utilities ##
# fallbacks for some special cases
@inline broadcast(f, x::Number...) = f(x...)
@inline broadcast{N}(f, t::NTuple{N}, ts::Vararg{NTuple{N}}) = map(f, t, ts...)
@inline broadcast{N}(f, t::NTuple{N,Any}, ts::Vararg{NTuple{N,Any}}) = map(f, t, ts...)

# special cases for "X .= ..." (broadcast!) assignments
broadcast!(::typeof(identity), X::AbstractArray, x::Number) = fill!(X, x)
Expand Down
16 changes: 8 additions & 8 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,14 @@ end
@deprecate get_rounding rounding

#13465
@deprecate cov(x::AbstractVector; corrected=true, mean=Base.mean(x)) Base.covm(x, mean, corrected)
@deprecate cov(X::AbstractMatrix; vardim=1, corrected=true, mean=Base.mean(X, vardim)) Base.covm(X, mean, vardim, corrected)
@deprecate cov(x::AbstractVector, y::AbstractVector; corrected=true, mean=(Base.mean(x), Base.mean(y))) Base.covm(x, mean[1], y, mean[2], corrected)
#@deprecate cov(x::AbstractVector; corrected=true, mean=Base.mean(x)) Base.covm(x, mean, corrected)
#@deprecate cov(X::AbstractMatrix; vardim=1, corrected=true, mean=Base.mean(X, vardim)) Base.covm(X, mean, vardim, corrected)
#@deprecate cov(x::AbstractVector, y::AbstractVector; corrected=true, mean=(Base.mean(x), Base.mean(y))) Base.covm(x, mean[1], y, mean[2], corrected)
@deprecate cov(X::AbstractVecOrMat, Y::AbstractVecOrMat; vardim=1, corrected=true, mean=(Base.mean(X, vardim), Base.mean(Y, vardim))) Base.covm(X, mean[1], Y, mean[2], vardim, corrected)
Copy link
Sponsor Member

Choose a reason for hiding this comment

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

these are listed under v0.5 deprecations, so I think we can just do a commit to delete this section rather than commenting some of them out

Copy link
Contributor

Choose a reason for hiding this comment

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

should be a different PR though


@deprecate cor(x::AbstractVector; mean=Base.mean(x)) Base.corm(x, mean)
@deprecate cor(X::AbstractMatrix; vardim=1, mean=Base.mean(X, vardim)) Base.corm(X, mean, vardim)
@deprecate cor(x::AbstractVector, y::AbstractVector; mean=(Base.mean(x), Base.mean(y))) Base.corm(x, mean[1], y, mean[2])
#@deprecate cor(x::AbstractVector; mean=Base.mean(x)) Base.corm(x, mean)
#@deprecate cor(X::AbstractMatrix; vardim=1, mean=Base.mean(X, vardim)) Base.corm(X, mean, vardim)
#@deprecate cor(x::AbstractVector, y::AbstractVector; mean=(Base.mean(x), Base.mean(y))) Base.corm(x, mean[1], y, mean[2])
@deprecate cor(X::AbstractVecOrMat, Y::AbstractVecOrMat; vardim=1, mean=(Base.mean(X, vardim), Base.mean(Y, vardim))) Base.corm(X, mean[1], Y, mean[2], vardim)

@deprecate_binding SparseMatrix SparseArrays
Expand Down Expand Up @@ -315,8 +315,8 @@ for (Fun, func) in [(:IdFun, :identity),
(::Type{typeof($(func))})() = $(func)
end
end
@deprecate_binding CentralizedAbs2Fun typeof(centralizedabs2fun(0)).name.primary
(::Type{typeof(centralizedabs2fun(0)).name.primary})(m::Number) = centralizedabs2fun(m)
@deprecate_binding CentralizedAbs2Fun typeof(centralizedabs2fun(0)).name.wrapper
(::Type{typeof(centralizedabs2fun(0)).name.wrapper})(m::Number) = centralizedabs2fun(m)
@deprecate specialized_unary(f::Function) f
@deprecate specialized_binary(f::Function) f
@deprecate specialized_bitwise_unary(f::Function) f
Expand Down
25 changes: 12 additions & 13 deletions base/dict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,14 @@ const AnyDict = Dict{Any,Any}

Dict{K,V}(ps::Pair{K,V}...) = Dict{K,V}(ps)
Dict{K }(ps::Pair{K}...,) = Dict{K,Any}(ps)
Dict{V }(ps::Pair{TypeVar(:K),V}...,) = Dict{Any,V}(ps)
Dict{V }(ps::(Pair{K,V} where K)...,) = Dict{Any,V}(ps)
Dict( ps::Pair...) = Dict{Any,Any}(ps)

function Dict(kv)
try
Base.associative_with_eltype(Dict, kv, eltype(kv))
associative_with_eltype((K, V) -> Dict{K, V}, kv, eltype(kv))
catch e
if any(x->isempty(methods(x, (typeof(kv),))), [start, next, done]) ||
!all(x->isa(x,Union{Tuple,Pair}),kv)
if !applicable(start, kv) || !all(x->isa(x,Union{Tuple,Pair}),kv)
Copy link
Contributor

Choose a reason for hiding this comment

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

WeakKeyDict now has a constructor that does this same thing

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

Ok, thanks. Fortunately it's not really related to this branch, I just found it in passing.

throw(ArgumentError("Dict(kv): kv needs to be an iterator of tuples or pairs"))
else
rethrow(e)
Expand All @@ -155,17 +154,17 @@ end

typealias TP{K,V} Union{Type{Tuple{K,V}},Type{Pair{K,V}}}

associative_with_eltype{K,V}(DT, kv, ::TP{K,V}) = DT{K,V}(kv)
associative_with_eltype{K,V}(DT, kv::Generator, ::TP{K,V}) = DT{K,V}(kv)
associative_with_eltype{K,V}(DT, ::Type{Pair{K,V}}) = DT{K,V}()
associative_with_eltype(DT, ::Type) = DT()
associative_with_eltype(DT, kv, t) = grow_to!(associative_with_eltype(DT, _default_eltype(typeof(kv))), kv)
function associative_with_eltype(DT, kv::Generator, t)
associative_with_eltype{K,V}(DT_apply, kv, ::TP{K,V}) = DT_apply(K, V)(kv)
associative_with_eltype{K,V}(DT_apply, kv::Generator, ::TP{K,V}) = DT_apply(K, V)(kv)
associative_with_eltype{K,V}(DT_apply, ::Type{Pair{K,V}}) = DT_apply(K, V)()
associative_with_eltype(DT_apply, ::Type) = DT_apply(Any, Any)()
associative_with_eltype{F}(DT_apply::F, kv, t) = grow_to!(associative_with_eltype(DT_apply, _default_eltype(typeof(kv))), kv)
function associative_with_eltype{F}(DT_apply::F, kv::Generator, t)
T = _default_eltype(typeof(kv))
if T <: Union{Pair,NTuple{2}} && isleaftype(T)
return associative_with_eltype(DT, kv, T)
if T <: Union{Pair, Tuple{Any, Any}} && isleaftype(T)
return associative_with_eltype(DT_apply, kv, T)
end
return grow_to!(associative_with_eltype(DT, T), kv)
return grow_to!(associative_with_eltype(DT_apply, T), kv)
end

# this is a special case due to (1) allowing both Pairs and Tuples as elements,
Expand Down
12 changes: 7 additions & 5 deletions base/docs/Docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ function signature(expr::Expr)
end
push!(sig.args[end].args, argtype(arg))
end
Expr(:let, Expr(:block, sig), typevars(expr)...)
tv = typevars(expr)
for i = length(tv):-1:1
sig = Expr(:where, sig, tv[i])
end
sig
else
signature(expr.args[1])
end
Expand All @@ -103,14 +107,11 @@ end
argtype(other) = :Any

function typevars(expr::Expr)
isexpr(expr, :curly) && return [tvar(x) for x in expr.args[2:end]]
isexpr(expr, :curly) && return expr.args[2:end]
typevars(expr.args[1])
end
typevars(::Symbol) = []

tvar(x::Expr) = :($(x.args[1]) = TypeVar($(quot(x.args[1])), $(x.args[2]), true))
tvar(s::Symbol) = :($(s) = TypeVar($(quot(s)), Any, true))

# Docsystem types.
# ================

Expand Down Expand Up @@ -283,6 +284,7 @@ function doc(binding::Binding, sig::Type = Union{})
end

# Some additional convenience `doc` methods that take objects rather than `Binding`s.
doc(obj::UnionAll) = doc(Base.unwrap_unionall(obj))
doc(object, sig::Type = Union{}) = doc(aliasof(object, typeof(object)), sig)
doc(object, sig...) = doc(object, Tuple{sig...})

Expand Down
33 changes: 28 additions & 5 deletions base/essentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

using Core: CodeInfo

typealias Callable Union{Function,DataType}
typealias Callable Union{Function,Type}

const Bottom = Union{}

Expand Down Expand Up @@ -47,13 +47,13 @@ end
argtail(x, rest...) = rest
tail(x::Tuple) = argtail(x...)

tuple_type_head(T::TypeConstructor) = tuple_type_head(T.body)
tuple_type_head(T::UnionAll) = tuple_type_head(T.body)
function tuple_type_head(T::DataType)
@_pure_meta
T.name === Tuple.name || throw(MethodError(tuple_type_head, (T,)))
return T.parameters[1]
end
tuple_type_tail(T::TypeConstructor) = tuple_type_tail(T.body)
tuple_type_tail(T::UnionAll) = tuple_type_tail(T.body)
function tuple_type_tail(T::DataType)
@_pure_meta
T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,)))
Expand All @@ -69,9 +69,31 @@ function tuple_type_cons{S,T<:Tuple}(::Type{S}, ::Type{T})
Tuple{S, T.parameters...}
end

isvarargtype(t::ANY) = isa(t, DataType) && (t::DataType).name === Vararg.name
function unwrap_unionall(a::ANY)
while isa(a,UnionAll)
a = a.body
end
return a
end

function rewrap_unionall(t::ANY, u::ANY)
if !isa(u, UnionAll)
return t
end
return UnionAll(u.var, rewrap_unionall(t, u.body))
end
Copy link
Sponsor Member

Choose a reason for hiding this comment

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

alternate form?

while isa(u, UnionAll)
  t = UnionAll(u.var, t)
  u = u.body
end
return t

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

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

I believe that reverses the order of the UnionAlls.

Copy link
Sponsor Member

Choose a reason for hiding this comment

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

ah, true. probably better not to do that.


const _va_typename = Vararg.body.body.name
function isvarargtype(t::ANY)
t = unwrap_unionall(t)
isa(t, DataType) && (t::DataType).name === _va_typename
end

isvatuple(t::DataType) = (n = length(t.parameters); n > 0 && isvarargtype(t.parameters[n]))
unwrapva(t::ANY) = isvarargtype(t) ? t.parameters[1] : t
function unwrapva(t::ANY)
t2 = unwrap_unionall(t)
isvarargtype(t2) ? t2.parameters[1] : t
end

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 All @@ -90,6 +112,7 @@ ptr_arg_unsafe_convert(::Type{Ptr{Void}}, x) = x
cconvert(T::Type, x) = convert(T, x) # do the conversion eagerly in most cases
cconvert{P<:Ptr}(::Type{P}, x) = x # but defer the conversion to Ptr to unsafe_convert
unsafe_convert{T}(::Type{T}, x::T) = x # unsafe_convert (like convert) defaults to assuming the convert occurred
unsafe_convert{T<:Ptr}(::Type{T}, x::T) = x # to resolve ambiguity with the next method
unsafe_convert{P<:Ptr}(::Type{P}, x::Ptr) = convert(P, x)

reinterpret{T}(::Type{T}, x) = box(T, x)
Expand Down
1 change: 1 addition & 0 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ for t1 in (Float32,Float64)
end
end
end
convert(::Type{Integer}, x::Float16) = convert(Integer, Float32(x))
convert{T<:Integer}(::Type{T}, x::Float16) = convert(T, Float32(x))


Expand Down
Loading