diff --git a/NEWS.md b/NEWS.md index 0e0320df33686..62e2983c8e7f5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -258,6 +258,10 @@ This section lists changes that do not have deprecation warnings. * `homedir` now determines the user's home directory via `libuv`'s `uv_os_homedir`, rather than from environment variables ([#19636]). + * Workers now listen on an ephemeral port assigned by the OS. Previously workers would + listen on the first free port available from 9009 ([#21818]). + + Library improvements -------------------- diff --git a/base/abstractarray.jl b/base/abstractarray.jl index e2e5749998e36..8df9186d4ab07 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -407,9 +407,10 @@ function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple{Any}) end function checkbounds_linear_indices(::Type{Bool}, IA::Tuple{Vararg{OneTo}}, i) @_inline_meta - if checkindex(Bool, IA[1], i) + ts = trailingsize(IA) + if checkindex(Bool, IA[1], i) && ts > 0 return true - elseif checkindex(Bool, OneTo(trailingsize(IA)), i) # partial linear indexing + elseif checkindex(Bool, OneTo(ts), i) # partial linear indexing partial_linear_indexing_warning_lookup(length(IA)) return true # TODO: Return false after the above function is removed in deprecated.jl end @@ -801,7 +802,7 @@ A[iter] = 0 If you supply more than one `AbstractArray` argument, `eachindex` will create an iterable object that is fast for all arguments (a `UnitRange` -if all inputs have fast linear indexing, a `CartesianRange` +if all inputs have fast linear indexing, a [`CartesianRange`](@ref) otherwise). If the arrays have different sizes and/or dimensionalities, `eachindex` returns an iterable that spans the largest range along each dimension. @@ -1718,6 +1719,7 @@ For multiple iterable arguments, `f` is called elementwise. `foreach` should be used instead of `map` when the results of `f` are not needed, for example in `foreach(println, array)`. +# Example ```jldoctest julia> a = 1:3:7; @@ -1745,6 +1747,7 @@ colons go in this expression. The results are concatenated along the remaining d For example, if `dims` is `[1,2]` and `A` is 4-dimensional, `f` is called on `A[:,:,i,j]` for all `i` and `j`. +# Examples ```jldoctest julia> a = reshape(collect(1:16),(2,2,2,2)) 2×2×2×2 Array{Int64,4}: @@ -1871,6 +1874,7 @@ map(f, A::Union{AbstractArray,AbstractSet,Associative}) = collect_similar(A, Gen Transform collection `c` by applying `f` to each element. For multiple collection arguments, apply `f` elementwise. +# Examples ```jldoctest julia> map(x -> x * 2, [1, 2, 3]) 3-element Array{Int64,1}: @@ -1913,6 +1917,7 @@ end Like [`map`](@ref), but stores the result in `destination` rather than a new collection. `destination` must be at least as large as the first collection. +# Example ```jldoctest julia> x = zeros(3); diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 058170e3d5041..7ccea62e60ed1 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -16,6 +16,7 @@ Reshape the array `a` as a one-dimensional column vector. The resulting array shares the same underlying data as `a`, so modifying one will also modify the other. +# Example ```jldoctest julia> a = [1 2 3; 4 5 6] 2×3 Array{Int64,2}: @@ -48,6 +49,7 @@ Remove the dimensions specified by `dims` from array `A`. Elements of `dims` must be unique and within the range `1:ndims(A)`. `size(A,i)` must equal 1 for all `i` in `dims`. +# Example ```jldoctest julia> a = reshape(collect(1:4),(2,2,1,1)) 2×2×1×1 Array{Int64,4}: @@ -101,6 +103,7 @@ imag(x::AbstractArray{<:Real}) = zero(x) Return all the data of `A` where the index for dimension `d` equals `i`. Equivalent to `A[:,:,...,i,:,:,...]` where `i` is in position `d`. +# Example ```jldoctest julia> A = [1 2 3 4; 5 6 7 8] 2×4 Array{Int64,2}: @@ -125,6 +128,7 @@ end Reverse `A` in dimension `d`. +# Example ```jldoctest julia> b = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -177,6 +181,7 @@ circshift(a::AbstractArray, shiftamt::DimsInteger) = circshift!(similar(a), a, s Circularly shift the data in an array. The second argument is a vector giving the amount to shift in each dimension. +# Example ```jldoctest julia> b = reshape(collect(1:16), (4,4)) 4×4 Array{Int64,2}: @@ -281,6 +286,7 @@ end Construct a matrix by repeating the given matrix (or vector) `m` times in dimension 1 and `n` times in dimension 2. +# Examples ```jldoctest julia> repmat([1, 2, 3], 2) 6-element Array{Int64,1}: @@ -337,6 +343,7 @@ repeated. The i-th element of `outer` specifies the number of times that a slice i-th dimension of `A` should be repeated. If `inner` or `outer` are omitted, no repetition is performed. +# Examples ```jldoctest julia> repeat(1:2, inner=2) 4-element Array{Int64,1}: @@ -390,7 +397,11 @@ _rshps(shp, shp_i, sz, i, ::Tuple{}) = _reperr(s, n, N) = throw(ArgumentError("number of " * s * " repetitions " * "($n) cannot be less than number of dimensions of input ($N)")) -@propagate_inbounds function _repeat(A::AbstractArray, inner, outer) +# We need special handling when repeating arrays of arrays +cat_fill!(R, X, inds) = (R[inds...] = X) +cat_fill!(R, X::AbstractArray, inds) = fill!(view(R, inds...), X) + +@noinline function _repeat(A::AbstractArray, inner, outer) shape, inner_shape = rep_shapes(A, inner, outer) R = similar(A, shape) @@ -408,7 +419,7 @@ _reperr(s, n, N) = throw(ArgumentError("number of " * s * " repetitions " * n = inner[i] inner_indices[i] = (1:n) + ((c[i] - 1) * n) end - R[inner_indices...] = A[c] + cat_fill!(R, A[c], inner_indices) end end diff --git a/base/array.jl b/base/array.jl index 2fe19b8f50f3f..633dfed5c1469 100644 --- a/base/array.jl +++ b/base/array.jl @@ -272,6 +272,26 @@ end `m`-by-`n` identity matrix. The default element type is [`Float64`](@ref). + +# Examples + +```jldoctest +julia> eye(3, 4) +3×4 Array{Float64,2}: + 1.0 0.0 0.0 0.0 + 0.0 1.0 0.0 0.0 + 0.0 0.0 1.0 0.0 + +julia> eye(2, 2) +2×2 Array{Float64,2}: + 1.0 0.0 + 0.0 1.0 + +julia> eye(Int, 2, 2) +2×2 Array{Int64,2}: + 1 0 + 0 1 +``` """ function eye(::Type{T}, m::Integer, n::Integer) where T a = zeros(T,m,n) @@ -293,6 +313,19 @@ eye(::Type{T}, n::Integer) where {T} = eye(T, n, n) `n`-by-`n` identity matrix. The default element type is [`Float64`](@ref). + +# Examples +```jldoctest +julia> eye(Int, 2) +2×2 Array{Int64,2}: + 1 0 + 0 1 + +julia> eye(2) +2×2 Array{Float64,2}: + 1.0 0.0 + 0.0 1.0 +``` """ eye(n::Integer) = eye(Float64, n) @@ -382,6 +415,7 @@ Return an `Array` of all items in a collection or iterator. For associative coll `Pair{KeyType, ValType}`. If the argument is array-like or is an iterator with the `HasShape()` trait, the result will have the same shape and number of dimensions as the argument. +# Example ```jldoctest julia> collect(1:2:13) 7-element Array{Int64,1}: @@ -658,6 +692,7 @@ end Insert the elements of `items` to the beginning of `a`. +# Example ```jldoctest julia> prepend!([3],[1,2]) 3-element Array{Int64,1}: @@ -710,25 +745,27 @@ Resize `a` to contain `n` elements. If `n` is smaller than the current collectio length, the first `n` elements will be retained. If `n` is larger, the new elements are not guaranteed to be initialized. +# Examples ```jldoctest julia> resize!([6, 5, 4, 3, 2, 1], 3) 3-element Array{Int64,1}: 6 5 4 -``` -```julia-repl -julia> resize!([6, 5, 4, 3, 2, 1], 8) -8-element Array{Int64,1}: +julia> a = resize!([6, 5, 4, 3, 2, 1], 8); + +julia> length(a) +8 + +julia> a[1:6] +6-element Array{Int64,1}: 6 5 4 3 2 1 - 0 - 0 ``` """ function resize!(a::Vector, nl::Integer) @@ -763,6 +800,7 @@ end Insert one or more `items` at the beginning of `collection`. +# Example ```jldoctest julia> unshift!([1, 2, 3, 4], 5, 6) 6-element Array{Int64,1}: @@ -796,6 +834,7 @@ end Insert an `item` into `a` at the given `index`. `index` is the index of `item` in the resulting `a`. +# Example ```jldoctest julia> insert!([6, 5, 4, 2, 1], 4, 3) 6-element Array{Int64,1}: @@ -822,6 +861,7 @@ end Remove the item at the given `i` and return the modified `a`. Subsequent items are shifted to fill the resulting gap. +# Example ```jldoctest julia> deleteat!([6, 5, 4, 3, 2, 1], 2) 5-element Array{Int64,1}: @@ -849,6 +889,7 @@ Subsequent items are shifted to fill the resulting gap. `inds` can be either an iterator or a collection of sorted and unique integer indices, or a boolean vector of the same length as `a` with `true` indicating entries to delete. +# Examples ```jldoctest julia> deleteat!([6, 5, 4, 3, 2, 1], 1:2:5) 3-element Array{Int64,1}: @@ -865,8 +906,8 @@ julia> deleteat!([6, 5, 4, 3, 2, 1], [true, false, true, false, true, false]) julia> deleteat!([6, 5, 4, 3, 2, 1], (2, 2)) ERROR: ArgumentError: indices must be unique and sorted Stacktrace: - [1] _deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:885 - [2] deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:872 + [1] _deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:926 + [2] deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:913 ``` """ deleteat!(a::Vector, inds) = _deleteat!(a, inds) @@ -924,6 +965,7 @@ Subsequent items are shifted left to fill the resulting gap. If specified, replacement values from an ordered collection will be spliced in place of the removed item. +# Examples ```jldoctest splice! julia> A = [6, 5, 4, 3, 2, 1]; splice!(A, 5) 2 @@ -994,6 +1036,7 @@ place of the removed items. To insert `replacement` before an index `n` without removing any items, use `splice!(collection, n:n-1, replacement)`. +# Example ```jldoctest splice! julia> splice!(A, 4:3, 2) 0-element Array{Int64,1} @@ -1150,6 +1193,7 @@ cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(x->1, n-1)..., length(x Find the next linear index >= `i` of a non-zero element of `A`, or `0` if not found. +# Examples ```jldoctest julia> A = [0 0; 1 0] 2×2 Array{Int64,2}: @@ -1178,6 +1222,7 @@ end Return the linear index of the first non-zero value in `A` (determined by `A[i]!=0`). Returns `0` if no such value is found. +# Examples ```jldoctest julia> A = [0 0; 1 0] 2×2 Array{Int64,2}: @@ -1186,6 +1231,9 @@ julia> A = [0 0; 1 0] julia> findfirst(A) 2 + +julia> findfirst(zeros(3)) +0 ``` """ findfirst(A) = findnext(A, 1) @@ -1195,6 +1243,7 @@ findfirst(A) = findnext(A, 1) Find the next linear index >= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found. +# Examples ```jldoctest julia> A = [1 4; 2 2] 2×2 Array{Int64,2}: @@ -1222,6 +1271,7 @@ end Return the linear index of the first element equal to `v` in `A`. Returns `0` if `v` is not found. +# Examples ```jldoctest julia> A = [4 6; 2 2] 2×2 Array{Int64,2}: @@ -1242,6 +1292,7 @@ findfirst(A, v) = findnext(A, v, 1) Find the next linear index >= `i` of an element of `A` for which `predicate` returns `true`, or `0` if not found. +# Examples ```jldoctest julia> A = [1 4; 2 2] 2×2 Array{Int64,2}: @@ -1270,6 +1321,7 @@ end Return the linear index of the first element of `A` for which `predicate` returns `true`. Returns `0` if there is no such element. +# Examples ```jldoctest julia> A = [1 4; 2 2] 2×2 Array{Int64,2}: @@ -1290,6 +1342,7 @@ findfirst(testf::Function, A) = findnext(testf, A, 1) Find the previous linear index <= `i` of a non-zero element of `A`, or `0` if not found. +# Examples ```jldoctest julia> A = [0 0; 1 2] 2×2 Array{Int64,2}: @@ -1316,6 +1369,7 @@ end Return the linear index of the last non-zero value in `A` (determined by `A[i]!=0`). Returns `0` if there is no non-zero value in `A`. +# Examples ```jldoctest julia> A = [1 0; 1 0] 2×2 Array{Int64,2}: @@ -1341,6 +1395,7 @@ findlast(A) = findprev(A, length(A)) Find the previous linear index <= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found. +# Examples ```jldoctest julia> A = [0 0; 1 2] 2×2 Array{Int64,2}: @@ -1367,6 +1422,7 @@ end Return the linear index of the last element equal to `v` in `A`. Returns `0` if there is no element of `A` equal to `v`. +# Examples ```jldoctest julia> A = [1 2; 2 1] 2×2 Array{Int64,2}: @@ -1391,6 +1447,7 @@ findlast(A, v) = findprev(A, v, length(A)) Find the previous linear index <= `i` of an element of `A` for which `predicate` returns `true`, or `0` if not found. +# Examples ```jldoctest julia> A = [4 6; 1 2] 2×2 Array{Int64,2}: @@ -1417,6 +1474,7 @@ end Return the linear index of the last element of `A` for which `predicate` returns `true`. Returns `0` if there is no such element. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -1438,6 +1496,7 @@ findlast(testf::Function, A) = findprev(testf, A, length(A)) Return a vector `I` of the linear indexes of `A` where `f(A[I])` returns `true`. If there are no such elements of `A`, find returns an empty array. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -1448,6 +1507,9 @@ julia> find(isodd,A) 2-element Array{Int64,1}: 1 2 + +julia> find(isodd, [2, 4]) +0-element Array{Int64,1} ``` """ function find(testf::Function, A) @@ -1474,6 +1536,7 @@ Return a vector of the linear indexes of the non-zeros in `A` (determined by `A[ common use of this is to convert a boolean array to an array of indexes of the `true` elements. If there are no non-zero elements of `A`, `find` returns an empty array. +# Examples ```jldoctest julia> A = [true false; false true] 2×2 Array{Bool,2}: @@ -1484,6 +1547,9 @@ julia> find(A) 2-element Array{Int64,1}: 1 4 + +julia> find(zeros(3)) +0-element Array{Int64,1} ``` """ function find(A) @@ -1512,6 +1578,7 @@ Return a vector of indexes for each dimension giving the locations of the non-ze (determined by `A[i]!=0`). If there are no non-zero elements of `A`, `findn` returns a 2-tuple of empty arrays. +# Examples ```jldoctest julia> A = [1 2 0; 0 0 3; 0 4 0] 3×3 Array{Int64,2}: @@ -1552,6 +1619,7 @@ end Return a tuple `(I, J, V)` where `I` and `J` are the row and column indexes of the non-zero values in matrix `A`, and `V` is a vector of the non-zero values. +# Example ```jldoctest julia> A = [1 2 0; 0 0 3; 0 4 0] 3×3 Array{Int64,2}: @@ -1592,6 +1660,7 @@ all elements are `NaN`. The collection must not be empty. +# Examples ```jldoctest julia> findmax([8,0.1,-9,pi]) (8.0, 1) @@ -1630,6 +1699,7 @@ all elements are `NaN`. The collection must not be empty. +# Examples ```jldoctest julia> findmin([8,0.1,-9,pi]) (-9.0, 3) @@ -1668,6 +1738,7 @@ elements are `NaN`. The collection must not be empty. +# Examples ```jldoctest julia> indmax([8,0.1,-9,pi]) 1 @@ -1690,6 +1761,7 @@ elements are `NaN`. The collection must not be empty. +# Examples ```jldoctest julia> indmin([8,0.1,-9,pi]) 3 @@ -1711,6 +1783,7 @@ Returns a vector containing the highest index in `b` for each value in `a` that is a member of `b` . The output vector contains 0 wherever `a` is not a member of `b`. +# Examples ```jldoctest julia> a = ['a', 'b', 'c', 'b', 'd', 'a']; @@ -1742,6 +1815,7 @@ end Returns the indices of elements in collection `a` that appear in collection `b`. +# Examples ```jldoctest julia> a = collect(1:3:15) 5-element Array{Int64,1}: @@ -1803,6 +1877,7 @@ end Return a copy of `collection`, removing elements for which `function` is `false`. For associative collections, the function is passed two arguments (key and value). +# Examples ```jldocttest julia> a = 1:10 1:10 @@ -1814,6 +1889,15 @@ julia> filter(isodd, a) 5 7 9 + +julia> d = Dict(1=>"a", 2=>"b") +Dict{Int64,String} with 2 entries: + 2 => "b" + 1 => "a" + +julia> filter((x,y)->isodd(x), d) +Dict{Int64,String} with 1 entry: + 1 => "a" ``` """ filter(f, As::AbstractArray) = As[map(f, As)::AbstractArray{Bool}] @@ -1889,6 +1973,7 @@ both arguments must be collections, and both will be iterated over. In particula `setdiff(set,element)` where `element` is a potential member of `set`, will not work in general. +# Example ```jldoctest julia> setdiff([1,2,3],[3,4,5]) 2-element Array{Int64,1}: @@ -1922,6 +2007,7 @@ symdiff(a, b) = union(setdiff(a,b), setdiff(b,a)) Construct the symmetric difference of elements in the passed in sets or arrays. Maintains order with arrays. +# Example ```jldoctest julia> symdiff([1,2,3],[3,4,5],[4,5,6]) 3-element Array{Int64,1}: diff --git a/base/arraymath.jl b/base/arraymath.jl index 54ac4418c5e45..020dd9f736fbc 100644 --- a/base/arraymath.jl +++ b/base/arraymath.jl @@ -9,6 +9,7 @@ Transform an array to its complex conjugate in-place. See also [`conj`](@ref). +# Example ```jldoctest julia> A = [1+im 2-im; 2+2im 3+im] 2×2 Array{Complex{Int64},2}: @@ -116,6 +117,7 @@ end Rotate matrix `A` left 90 degrees. +# Example ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -143,6 +145,7 @@ end Rotate matrix `A` right 90 degrees. +# Example ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -169,6 +172,7 @@ end Rotate matrix `A` 180 degrees. +# Example ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -196,6 +200,7 @@ end Rotate matrix `A` left 90 degrees an integer `k` number of times. If `k` is zero or a multiple of four, this is equivalent to a `copy`. +# Examples ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -235,6 +240,7 @@ end Rotate matrix `A` right 90 degrees an integer `k` number of times. If `k` is zero or a multiple of four, this is equivalent to a `copy`. +# Examples ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -269,6 +275,7 @@ rotr90(A::AbstractMatrix, k::Integer) = rotl90(A,-k) Rotate matrix `A` 180 degrees an integer `k` number of times. If `k` is even, this is equivalent to a `copy`. +# Examples ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: diff --git a/base/associative.jl b/base/associative.jl index 8c276ee8dc078..564c3fd5578bd 100644 --- a/base/associative.jl +++ b/base/associative.jl @@ -412,6 +412,16 @@ function rehash!(t::ObjectIdDict, newsz = length(t.ht)) t end +function sizehint!(t::ObjectIdDict, newsz) + newsz = _tablesz(newsz*2) # *2 for keys and values in same array + oldsz = length(t.ht) + # grow at least 25% + if newsz < (oldsz*5)>>2 + return t + end + rehash!(t, newsz) +end + function setindex!(t::ObjectIdDict, v::ANY, k::ANY) if t.ndel >= ((3*length(t.ht))>>2) rehash!(t, max(length(t.ht)>>1, 32)) diff --git a/base/bitarray.jl b/base/bitarray.jl index 261853f02aa1c..7fd2ba6b65a0f 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -1145,6 +1145,7 @@ end Performs a bitwise not operation on `B`. See [`~`](@ref). +# Example ```jldoctest julia> A = trues(2,2) 2×2 BitArray{2}: @@ -1497,6 +1498,7 @@ Performs a left rotation operation, returning a new `BitVector`. `i` controls how far to rotate the bits. See also [`rol!`](@ref). +# Examples ```jldoctest julia> A = BitArray([true, true, false, false, true]) 5-element BitArray{1}: @@ -1566,6 +1568,7 @@ Performs a right rotation operation on `B`, returning a new `BitVector`. `i` controls how far to rotate the bits. See also [`ror!`](@ref). +# Examples ```jldoctest julia> A = BitArray([true, true, false, false, true]) 5-element BitArray{1}: diff --git a/base/boot.jl b/base/boot.jl index 55721469c6867..13c6cc10c8153 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -332,6 +332,7 @@ function Symbol(a::Array{UInt8,1}) ccall(:jl_array_ptr, Ptr{UInt8}, (Any,), a), Intrinsics.arraylen(a)) end +Symbol(s::Symbol) = s # docsystem basics macro doc(x...) @@ -370,10 +371,10 @@ end show(io::IO, x::ANY) = ccall(:jl_static_show, Void, (Ptr{Void}, Any), io_pointer(io), x) print(io::IO, x::Char) = ccall(:jl_uv_putc, Void, (Ptr{Void}, Char), io_pointer(io), x) -print(io::IO, x::String) = write(io, x) +print(io::IO, x::String) = (write(io, x); nothing) print(io::IO, x::ANY) = show(io, x) print(io::IO, x::ANY, a::ANY...) = (print(io, x); print(io, a...)) -println(io::IO) = write(io, 0x0a) # 0x0a = '\n' +println(io::IO) = (write(io, 0x0a); nothing) # 0x0a = '\n' println(io::IO, x::ANY...) = (print(io, x...); println(io)) show(a::ANY) = show(STDOUT, a) diff --git a/base/broadcast.jl b/base/broadcast.jl index 2d98b4031b0d9..48de50d54d5c4 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -592,6 +592,16 @@ If you want to *avoid* adding dots for selected function calls in (no dot for `sort`). (`@.` is equivalent to a call to `@__dot__`.) + +```jldoctest +julia> x = 1.0:3.0; y = similar(x); + +julia> @. y = x + 3 * sin(x) +3-element Array{Float64,1}: + 3.52441 + 4.72789 + 3.42336 +``` """ macro __dot__(x) esc(__dot__(x)) diff --git a/base/c.jl b/base/c.jl index 3385e18b4e9d2..405c7e5819ca1 100644 --- a/base/c.jl +++ b/base/c.jl @@ -4,6 +4,23 @@ import Core.Intrinsics: cglobal, bitcast +""" + cfunction(function::Function, ReturnType::Type, ArgumentTypes::Type) + +Generate C-callable function pointer from Julia function. Type annotation of the return +value in the callback function is a must for situations where Julia cannot infer the return +type automatically. + +# Examples +```julia-repl +julia> function foo(x::Int, y::Int) + return x + y + end + +julia> cfunction(foo, Int, Tuple{Int,Int}) +Ptr{Void} @0x000000001b82fcd0 +``` +""" cfunction(f, r, a) = ccall(:jl_function_ptr, Ptr{Void}, (Any, Any, Any), f, r, a) if ccall(:jl_is_char_signed, Ref{Bool}, ()) diff --git a/base/combinatorics.jl b/base/combinatorics.jl index 920f6c23d944e..7cf2eccbbaef8 100644 --- a/base/combinatorics.jl +++ b/base/combinatorics.jl @@ -61,6 +61,7 @@ end Returns `true` if `v` is a valid permutation. +# Examples ```jldoctest julia> isperm([1; 2]) true @@ -112,8 +113,9 @@ to verify that `p` is a permutation. To return a new permutation, use `v[p]`. Note that this is generally faster than `permute!(v,p)` for large vectors. -See also [`ipermute!`](@ref) +See also [`ipermute!`](@ref). +# Example ```jldoctest julia> A = [1, 1, 3, 4]; @@ -157,8 +159,9 @@ end """ ipermute!(v, p) -Like `permute!`, but the inverse of the given permutation is applied. +Like [`permute!`](@ref), but the inverse of the given permutation is applied. +# Example ```jldoctest julia> A = [1, 1, 3, 4]; @@ -182,6 +185,7 @@ ipermute!(a, p::AbstractVector) = ipermute!!(a, copymutable(p)) Return the inverse permutation of `v`. If `B = A[v]`, then `A == B[invperm(v)]`. +# Example ```jldoctest julia> v = [2; 4; 3; 1]; @@ -233,6 +237,7 @@ invperm(a::Tuple) = (invperm([a...])...,) Next integer greater than or equal to `n` that can be written as ``\\prod k_i^{p_i}`` for integers ``p_1``, ``p_2``, etc. +# Example ```jldoctest julia> nextprod([2, 3], 105) 108 diff --git a/base/deprecated.jl b/base/deprecated.jl index 12bb33fe3a527..118e8039b23a5 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -96,6 +96,15 @@ function firstcaller(bt::Array{Ptr{Void},1}, funcsyms) end found && @goto found found = lkup.func in funcsyms + # look for constructor type name + if !found && !isnull(lkup.linfo) + li = get(lkup.linfo) + ft = ccall(:jl_first_argument_datatype, Any, (Any,), li.def.sig) + if isa(ft,DataType) && ft.name === Type.body.name + ft = unwrap_unionall(ft.parameters[1]) + found = (isa(ft,DataType) && ft.name.name in funcsyms) + end + end end end return StackTraces.UNKNOWN @@ -217,7 +226,7 @@ macro dep_vectorize_1arg(S, f) T = esc(:T) x = esc(:x) AbsArr = esc(:AbstractArray) - :( @deprecate $f{$T<:$S}($x::$AbsArr{$T}) $f.($x) ) + :( @deprecate $f($x::$AbsArr{$T}) where {$T<:$S} $f.($x) ) end macro dep_vectorize_2arg(S, f) S = esc(S) @@ -228,9 +237,9 @@ macro dep_vectorize_2arg(S, f) y = esc(:y) AbsArr = esc(:AbstractArray) quote - @deprecate $f{$T1<:$S}($x::$S, $y::$AbsArr{$T1}) $f.($x,$y) - @deprecate $f{$T1<:$S}($x::$AbsArr{$T1}, $y::$S) $f.($x,$y) - @deprecate $f{$T1<:$S,$T2<:$S}($x::$AbsArr{$T1}, $y::$AbsArr{$T2}) $f.($x,$y) + @deprecate $f($x::$S, $y::$AbsArr{$T1}) where {$T1<:$S} $f.($x,$y) + @deprecate $f($x::$AbsArr{$T1}, $y::$S) where {$T1<:$S} $f.($x,$y) + @deprecate $f($x::$AbsArr{$T1}, $y::$AbsArr{$T2}) where {$T1<:$S,$T2<:$S} $f.($x,$y) end end @@ -481,7 +490,7 @@ Filesystem.stop_watching(stream::Filesystem._FDWatcher) = depwarn("stop_watching filter(fun, dr) end end - recur{T<:TimeType}(fun::Function, start::T, stop::T; step::Period=Day(1), negate::Bool=false, limit::Int=10000) = recur(fun, start:step:stop; negate=negate) + recur(fun::Function, start::T, stop::T; step::Period=Day(1), negate::Bool=false, limit::Int=10000) where {T<:TimeType} = recur(fun, start:step:stop; negate=negate) end # Index conversions revamp; #19730 @@ -708,19 +717,19 @@ export Collections @deprecate bitbroadcast broadcast # Deprecate two-argument map! (map!(f, A)) for a cycle in anticipation of semantic change -@deprecate map!{F}(f::F, A::AbstractArray) map!(f, A, A) +@deprecate map!(f::F, A::AbstractArray) where {F} map!(f, A, A) @deprecate asyncmap!(f, c; ntasks=0, batch_size=nothing) asyncmap!(f, c, c; ntasks=ntasks, batch_size=batch_size) # Not exported, but used outside Base _promote_array_type(F, ::Type, ::Type, T::Type) = T -_promote_array_type{A<:AbstractFloat}(F, ::Type{<:Real}, ::Type{A}, ::Type) = A -_promote_array_type{A<:Integer}(F, ::Type{<:Integer}, ::Type{A}, ::Type) = A +_promote_array_type(F, ::Type{<:Real}, ::Type{A}, ::Type) where {A<:AbstractFloat} = A +_promote_array_type(F, ::Type{<:Integer}, ::Type{A}, ::Type) where {A<:Integer} = A _promote_array_type(::typeof(/), ::Type{<:Integer}, ::Type{<:Integer}, T::Type) = T _promote_array_type(::typeof(\), ::Type{<:Integer}, ::Type{<:Integer}, T::Type) = T _promote_array_type(::typeof(/), ::Type{<:Integer}, ::Type{Bool}, T::Type) = T _promote_array_type(::typeof(\), ::Type{<:Integer}, ::Type{Bool}, T::Type) = T _promote_array_type(F, ::Type{<:Integer}, ::Type{Bool}, T::Type) = T -_promote_array_type{T<:AbstractFloat}(F, ::Type{<:Union{Complex, Real}}, ::Type{Complex{T}}, ::Type) = Complex{T} +_promote_array_type(F, ::Type{<:Union{Complex, Real}}, ::Type{Complex{T}}, ::Type) where {T<:AbstractFloat} = Complex{T} function promote_array_type(F, R, S, T) Base.depwarn("`promote_array_type` is deprecated as it is no longer needed " * "in Base. See https://github.com/JuliaLang/julia/issues/19669 " * @@ -753,8 +762,8 @@ end @deprecate round(M::Bidiagonal) round.(M) @deprecate round(M::Tridiagonal) round.(M) @deprecate round(M::SymTridiagonal) round.(M) -@deprecate round{T}(::Type{T}, x::AbstractArray) round.(T, x) -@deprecate round{T}(::Type{T}, x::AbstractArray, r::RoundingMode) round.(T, x, r) +@deprecate round(::Type{T}, x::AbstractArray) where {T} round.(T, x) +@deprecate round(::Type{T}, x::AbstractArray, r::RoundingMode) where {T} round.(T, x, r) @deprecate round(x::AbstractArray, r::RoundingMode) round.(x, r) @deprecate round(x::AbstractArray, digits::Integer, base::Integer = 10) round.(x, digits, base) @@ -762,21 +771,21 @@ end @deprecate trunc(M::Bidiagonal) trunc.(M) @deprecate trunc(M::Tridiagonal) trunc.(M) @deprecate trunc(M::SymTridiagonal) trunc.(M) -@deprecate trunc{T}(::Type{T}, x::AbstractArray) trunc.(T, x) +@deprecate trunc(::Type{T}, x::AbstractArray) where {T} trunc.(T, x) @deprecate trunc(x::AbstractArray, digits::Integer, base::Integer = 10) trunc.(x, digits, base) # Deprecate manually vectorized floor methods in favor of compact broadcast syntax @deprecate floor(M::Bidiagonal) floor.(M) @deprecate floor(M::Tridiagonal) floor.(M) @deprecate floor(M::SymTridiagonal) floor.(M) -@deprecate floor{T}(::Type{T}, A::AbstractArray) floor.(T, A) +@deprecate floor(::Type{T}, A::AbstractArray) where {T} floor.(T, A) @deprecate floor(A::AbstractArray, digits::Integer, base::Integer = 10) floor.(A, digits, base) # Deprecate manually vectorized ceil methods in favor of compact broadcast syntax @deprecate ceil(M::Bidiagonal) ceil.(M) @deprecate ceil(M::Tridiagonal) ceil.(M) @deprecate ceil(M::SymTridiagonal) ceil.(M) -@deprecate ceil{T}(::Type{T}, x::AbstractArray) ceil.(T, x) +@deprecate ceil(::Type{T}, x::AbstractArray) where {T} ceil.(T, x) @deprecate ceil(x::AbstractArray, digits::Integer, base::Integer = 10) ceil.(x, digits, base) # Deprecate manually vectorized `big` methods in favor of compact broadcast syntax @@ -805,10 +814,10 @@ end @deprecate rem(A::AbstractArray, B::Number) rem.(A, B) # Deprecate manually vectorized div, mod, and % methods for dates -@deprecate div{P<:Dates.Period}(X::StridedArray{P}, y::P) div.(X, y) +@deprecate div(X::StridedArray{P}, y::P) where {P<:Dates.Period} div.(X, y) @deprecate div(X::StridedArray{<:Dates.Period}, y::Integer) div.(X, y) -@deprecate (%){P<:Dates.Period}(X::StridedArray{P}, y::P) X .% y -@deprecate mod{P<:Dates.Period}(X::StridedArray{P}, y::P) mod.(X, y) +@deprecate (%)(X::StridedArray{P}, y::P) where {P<:Dates.Period} X .% y +@deprecate mod(X::StridedArray{P}, y::P) where {P<:Dates.Period} mod.(X, y) # Deprecate manually vectorized mod methods in favor of compact broadcast syntax @deprecate mod(B::BitArray, x::Bool) mod.(B, x) @@ -1023,7 +1032,7 @@ isempty(::Task) = error("isempty not defined for Tasks") end end - array_eps{T}(a::AbstractArray{Complex{T}}) = eps(float(maximum(x->(isfinite(x) ? abs(x) : T(NaN)), a))) + array_eps(a::AbstractArray{Complex{T}}) where {T} = eps(float(maximum(x->(isfinite(x) ? abs(x) : T(NaN)), a))) array_eps(a) = eps(float(maximum(x->(isfinite(x) ? abs(x) : oftype(x,NaN)), a))) test_approx_eq(va, vb, astr, bstr) = @@ -1097,22 +1106,22 @@ function partial_linear_indexing_warning(n) end # Deprecate Array(T, dims...) in favor of proper type constructors -@deprecate Array{T,N}(::Type{T}, d::NTuple{N,Int}) Array{T}(d) -@deprecate Array{T}(::Type{T}, d::Int...) Array{T}(d...) -@deprecate Array{T}(::Type{T}, m::Int) Array{T}(m) -@deprecate Array{T}(::Type{T}, m::Int,n::Int) Array{T}(m,n) -@deprecate Array{T}(::Type{T}, m::Int,n::Int,o::Int) Array{T}(m,n,o) -@deprecate Array{T}(::Type{T}, d::Integer...) Array{T}(convert(Tuple{Vararg{Int}}, d)) -@deprecate Array{T}(::Type{T}, m::Integer) Array{T}(Int(m)) -@deprecate Array{T}(::Type{T}, m::Integer,n::Integer) Array{T}(Int(m),Int(n)) -@deprecate Array{T}(::Type{T}, m::Integer,n::Integer,o::Integer) Array{T}(Int(m),Int(n),Int(o)) +@deprecate Array(::Type{T}, d::NTuple{N,Int}) where {T,N} Array{T}(d) +@deprecate Array(::Type{T}, d::Int...) where {T} Array{T}(d...) +@deprecate Array(::Type{T}, m::Int) where {T} Array{T}(m) +@deprecate Array(::Type{T}, m::Int,n::Int) where {T} Array{T}(m,n) +@deprecate Array(::Type{T}, m::Int,n::Int,o::Int) where {T} Array{T}(m,n,o) +@deprecate Array(::Type{T}, d::Integer...) where {T} Array{T}(convert(Tuple{Vararg{Int}}, d)) +@deprecate Array(::Type{T}, m::Integer) where {T} Array{T}(Int(m)) +@deprecate Array(::Type{T}, m::Integer,n::Integer) where {T} Array{T}(Int(m),Int(n)) +@deprecate Array(::Type{T}, m::Integer,n::Integer,o::Integer) where {T} Array{T}(Int(m),Int(n),Int(o)) # Likewise for SharedArrays -@deprecate SharedArray{T,N}(::Type{T}, dims::Dims{N}; kwargs...) SharedArray{T}(dims; kwargs...) -@deprecate SharedArray{T}(::Type{T}, dims::Int...; kwargs...) SharedArray{T}(dims...; kwargs...) -@deprecate(SharedArray{T,N}(filename::AbstractString, ::Type{T}, dims::NTuple{N,Int}, offset; kwargs...), +@deprecate SharedArray(::Type{T}, dims::Dims{N}; kwargs...) where {T,N} SharedArray{T}(dims; kwargs...) +@deprecate SharedArray(::Type{T}, dims::Int...; kwargs...) where {T} SharedArray{T}(dims...; kwargs...) +@deprecate(SharedArray(filename::AbstractString, ::Type{T}, dims::NTuple{N,Int}, offset; kwargs...) where {T,N}, SharedArray{T}(filename, dims, offset; kwargs...)) -@deprecate(SharedArray{T}(filename::AbstractString, ::Type{T}, dims::NTuple, offset; kwargs...), +@deprecate(SharedArray(filename::AbstractString, ::Type{T}, dims::NTuple, offset; kwargs...) where {T}, SharedArray{T}(filename, dims, offset; kwargs...)) @noinline function is_intrinsic_expr(x::ANY) @@ -1123,14 +1132,14 @@ end @deprecate EachLine(stream, ondone) EachLine(stream, ondone=ondone) # These conversions should not be defined, see #19896 -@deprecate convert{T<:Number}(::Type{T}, x::Dates.Period) convert(T, Dates.value(x)) -@deprecate convert{T<:Dates.Period}(::Type{T}, x::Real) T(x) -@deprecate convert{R<:Real}(::Type{R}, x::Dates.DateTime) R(Dates.value(x)) -@deprecate convert{R<:Real}(::Type{R}, x::Dates.Date) R(Dates.value(x)) -@deprecate convert(::Type{Dates.DateTime}, x::Real) Dates.DateTime(Dates.Millisecond(x)) -@deprecate convert(::Type{Dates.Date}, x::Real) Dates.Date(Dates.Day(x)) - -function colon{T<:Dates.Period}(start::T, stop::T) +@deprecate convert(::Type{T}, x::Dates.Period) where {T<:Number} convert(T, Dates.value(x)) +@deprecate convert(::Type{T}, x::Real) where {T<:Dates.Period} T(x) +@deprecate convert(::Type{R}, x::Dates.DateTime) where {R<:Real} R(Dates.value(x)) +@deprecate convert(::Type{R}, x::Dates.Date) where {R<:Real} R(Dates.value(x)) +@deprecate convert(::Type{Dates.DateTime}, x::Real) Dates.DateTime(Dates.Millisecond(x)) +@deprecate convert(::Type{Dates.Date}, x::Real) Dates.Date(Dates.Day(x)) + +function colon(start::T, stop::T) where T<:Dates.Period depwarn("$start:$stop is deprecated, use $start:$T(1):$stop instead.", :colon) colon(start, T(1), stop) end @@ -1141,13 +1150,13 @@ end Base.@deprecate_binding GitAnyObject GitUnknownObject @deprecate owner(x) repository(x) false - @deprecate get{T<:GitObject}(::Type{T}, repo::GitRepo, x) T(repo, x) false - @deprecate get{T<:GitObject}(::Type{T}, repo::GitRepo, oid::GitHash, oid_size::Int) T(repo, GitShortHash(oid, oid_size)) false + @deprecate get(::Type{T}, repo::GitRepo, x) where {T<:GitObject} T(repo, x) false + @deprecate get(::Type{T}, repo::GitRepo, oid::GitHash, oid_size::Int) where {T<:GitObject} T(repo, GitShortHash(oid, oid_size)) false @deprecate revparse(repo::GitRepo, objname::AbstractString) GitObject(repo, objname) false @deprecate object(repo::GitRepo, te::GitTreeEntry) GitObject(repo, te) false @deprecate commit(ann::GitAnnotated) GitHash(ann) false @deprecate lookup(repo::GitRepo, oid::GitHash) GitBlob(repo, oid) false - function Base.cat{T<:GitObject}(repo::GitRepo, ::Type{T}, spec::Union{AbstractString,AbstractGitHash}) + function Base.cat(repo::GitRepo, ::Type{T}, spec::Union{AbstractString,AbstractGitHash}) where T<:GitObject Base.depwarn("cat(repo::GitRepo, T, spec) is deprecated, use content(T(repo, spec))", :cat) try return content(GitBlob(repo, spec)) @@ -1198,9 +1207,9 @@ step(r::Use_StepRangeLen_Instead) = r.step/r.divisor length(r::Use_StepRangeLen_Instead) = Integer(r.len) -first{T}(r::Use_StepRangeLen_Instead{T}) = convert(T, r.start/r.divisor) +first(r::Use_StepRangeLen_Instead{T}) where {T} = convert(T, r.start/r.divisor) -last{T}(r::Use_StepRangeLen_Instead{T}) = convert(T, (r.start + (r.len-1)*r.step)/r.divisor) +last(r::Use_StepRangeLen_Instead{T}) where {T} = convert(T, (r.start + (r.len-1)*r.step)/r.divisor) start(r::Use_StepRangeLen_Instead) = 0 done(r::Use_StepRangeLen_Instead, i::Int) = length(r) <= i @@ -1322,7 +1331,7 @@ end for fname in (:ones, :zeros) @eval @deprecate ($fname)(T::Type, arr) ($fname)(T, size(arr)) @eval ($fname)(T::Type, i::Integer) = ($fname)(T, (i,)) - @eval function ($fname){T}(::Type{T}, arr::Array{T}) + @eval function ($fname)(::Type{T}, arr::Array{T}) where T msg = string("`", $fname, "{T}(::Type{T}, arr::Array{T})` is deprecated, use ", "`", $fname , "(T, size(arr))` instead. ", ) diff --git a/base/distributed/cluster.jl b/base/distributed/cluster.jl index 77bc037c126ba..c12f8ed847176 100644 --- a/base/distributed/cluster.jl +++ b/base/distributed/cluster.jl @@ -153,8 +153,8 @@ function start_worker(out::IO, cookie::AbstractString) init_worker(cookie) interface = IPv4(LPROC.bind_addr) if LPROC.bind_port == 0 - (actual_port,sock) = listenany(interface, UInt16(9009)) - LPROC.bind_port = actual_port + (port, sock) = listenany(interface, UInt16(0)) + LPROC.bind_port = port else sock = listen(interface, LPROC.bind_port) end @@ -256,9 +256,9 @@ end function parse_connection_info(str) m = match(r"^julia_worker:(\d+)#(.*)", str) if m !== nothing - (m.captures[2], parse(Int16, m.captures[1])) + (m.captures[2], parse(UInt16, m.captures[1])) else - ("", Int16(-1)) + ("", UInt16(0)) end end diff --git a/base/distributed/clusterserialize.jl b/base/distributed/clusterserialize.jl index 163d8d9636284..9fb256d1e261b 100644 --- a/base/distributed/clusterserialize.jl +++ b/base/distributed/clusterserialize.jl @@ -88,8 +88,9 @@ function serialize(s::ClusterSerializer, g::GlobalRef) # Record if required and then invoke the default GlobalRef serializer. sym = g.name if g.mod === Main && isdefined(g.mod, sym) - v = getfield(Main, sym) - if (binding_module(Main, sym) === Main) && (s.anonfunc_id != 0) + if (binding_module(Main, sym) === Main) && (s.anonfunc_id != 0) && + !startswith(string(sym), "#") # Anonymous functions are handled via FULL_GLOBALREF_TAG + push!(get!(s.glbs_in_tnobj, s.anonfunc_id, []), sym) end end diff --git a/base/distributed/managers.jl b/base/distributed/managers.jl index 269a69033f12d..66753ee09be6d 100644 --- a/base/distributed/managers.jl +++ b/base/distributed/managers.jl @@ -456,31 +456,35 @@ end const client_port = Ref{Cushort}(0) function socket_reuse_port() - s = TCPSocket() - client_host = Ref{Cuint}(0) - ccall(:jl_tcp_bind, Int32, - (Ptr{Void}, UInt16, UInt32, Cuint), - s.handle, hton(client_port.x), hton(UInt32(0)), 0) < 0 && throw(SystemError("bind() : ")) - - # TODO: Support OSX and change the above code to call setsockopt before bind once libuv provides - # early access to a socket fd, i.e., before a bind call. - - @static if is_linux() - try - rc = ccall(:jl_tcp_reuseport, Int32, (Ptr{Void},), s.handle) - if rc > 0 # SO_REUSEPORT is unsupported, just return the ephemerally bound socket - return s - elseif rc < 0 - throw(SystemError("setsockopt() SO_REUSEPORT : ")) - end - getsockname(s) - catch e + @static if is_linux() || is_apple() + s = TCPSocket(delay = false) + + # Linux requires the port to be bound before setting REUSEPORT, OSX after. + is_linux() && bind_client_port(s) + rc = ccall(:jl_tcp_reuseport, Int32, (Ptr{Void},), s.handle) + if rc > 0 # SO_REUSEPORT is unsupported, just return the ephemerally bound socket + return s + elseif rc < 0 # This is an issue only on systems with lots of client connections, hence delay the warning - nworkers() > 128 && warn_once("Error trying to reuse client port number, falling back to plain socket : ", e) + nworkers() > 128 && warn_once("Error trying to reuse client port number, falling back to regular socket.") + # provide a clean new socket return TCPSocket() end + is_apple() && bind_client_port(s) + return s + else + return TCPSocket() end +end + +function bind_client_port(s) + err = ccall(:jl_tcp_bind, Int32, (Ptr{Void}, UInt16, UInt32, Cuint), + s.handle, hton(client_port[]), hton(UInt32(0)), 0) + Base.uv_error("bind() failed", err) + + _addr, port = Base._sockname(s, true) + client_port[] = port return s end diff --git a/base/distributed/remotecall.jl b/base/distributed/remotecall.jl index ff1de61be8222..ce1fd71bafef0 100644 --- a/base/distributed/remotecall.jl +++ b/base/distributed/remotecall.jl @@ -455,16 +455,11 @@ end wait(r::Future) = (!isnull(r.v) && return r; call_on_owner(wait_ref, r, myid()); r) wait(r::RemoteChannel, args...) = (call_on_owner(wait_ref, r, myid(), args...); r) -function fetch_future(rid, callee) - rv = lookup_ref(rid) - v = fetch(rv.c) - del_client(rid, callee) - v -end function fetch(r::Future) !isnull(r.v) && return get(r.v) - v=call_on_owner(fetch_future, r, myid()) + v=call_on_owner(fetch_ref, r) r.v=v + send_del_client(r) v end diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 23753f86f2625..3894e2635d526 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -232,9 +232,9 @@ function doc!(b::Binding, str::DocStr, sig::ANY = Union{}) m = get!(meta(), b, MultiDoc()) if haskey(m.docs, sig) # We allow for docstrings to be updated, but print a warning since it is possible - # that over-writing a docstring *may* have been accidental. - s = "replacing docs for '$b :: $sig' in module '$(current_module())'." - isdefined(Base, :STDERR) ? warn(s) : ccall(:jl_, Void, (Any,), "WARNING: $s") + # that over-writing a docstring *may* have been accidental. The warning + # is suppressed for symbols in Main, for interactive use (#23011). + current_module() == Main || warn("replacing docs for '$b :: $sig' in module '$(current_module())'.") else # The ordering of docstrings for each Binding is defined by the order in which they # are initially added. Replacing a specific docstring does not change it's ordering. diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 93eff004af71f..1328d5196d1fc 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -9,6 +9,7 @@ Fill array `A` with the value `x`. If `x` is an object reference, all elements w the same object. `fill!(A, Foo())` will return `A` filled with the result of evaluating `Foo()` once. +# Examples ```jldoctest julia> A = zeros(2,3) 2×3 Array{Float64,2}: @@ -81,6 +82,7 @@ Subtraction operator. A string giving the literal bit representation of a number. +# Example ```jldoctest julia> bits(4) "0000000000000000000000000000000000000000000000000000000000000100" @@ -97,6 +99,7 @@ bits Construct a 1-d array of the specified type. This is usually called with the syntax `Type[]`. Element values can be specified using `Type[a,b,c,...]`. +# Example ```jldoctest julia> Int8[1, 2, 3] 3-element Array{Int8,1}: @@ -120,6 +123,7 @@ Returns a subset of array `A` as specified by `inds`, where each `ind` may be an `Int`, a `Range`, or a `Vector`. See the manual section on [array indexing](@ref man-array-indexing) for details. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -149,6 +153,7 @@ getindex(::AbstractArray, inds...) Retrieve the value(s) stored at the given key or index within a collection. The syntax `a[i,j,...]` is converted by the compiler to `getindex(a, i, j, ...)`. +# Example ```jldoctest julia> A = Dict("a" => 1, "b" => 2) Dict{String,Int64} with 2 entries: @@ -219,6 +224,7 @@ unsafe_copy!(dest::Array, d, src::Array, so, N) Create a Float32 from `x`. If `x` is not exactly representable then `mode` determines how `x` is rounded. +# Examples ```jldoctest julia> Float32(1/3, RoundDown) 0.3333333f0 @@ -310,6 +316,7 @@ Mmap.mmap(io, ::BitArray, dims = ?, offset = ?) Update `collection`, removing elements for which `function` is `false`. For associative collections, the function is passed two arguments (key and value). +# Example ```jldoctest julia> filter!(isodd, collect(1:10)) 5-element Array{Int64,1}: @@ -327,6 +334,7 @@ filter! Size, in bytes, of the canonical binary representation of the given DataType `T`, if any. +# Examples ```jldoctest julia> sizeof(Float32) 4 @@ -378,6 +386,7 @@ oftype Insert one or more `items` at the end of `collection`. +# Example ```jldoctest julia> push!([1, 2, 3], 4, 5, 6) 6-element Array{Int64,1}: @@ -399,6 +408,12 @@ push! promote(xs...) Convert all arguments to their common promotion type (if any), and return them all (as a tuple). + +# Example +```jldoctest +julia> promote(Int8(1), Float16(4.5), Float32(4.1)) +(1.0f0, 4.5f0, 4.1f0) +``` """ promote @@ -418,6 +433,7 @@ Create an array of all ones with the same layout as `A`, element type `T` and si The `A` argument can be skipped, which behaves like `Array{Float64,0}()` was passed. For convenience `dims` may also be passed in variadic form. +# Examples ```jldoctest julia> ones(Complex128, 2, 3) 2×3 Array{Complex{Float64},2}: @@ -483,6 +499,23 @@ Returns the range of indices of `a` which compare as equal to `x` (using binary according to the order specified by the `by`, `lt` and `rev` keywords, assuming that `a` is already sorted in that order. Returns an empty range located at the insertion point if `a` does not contain values equal to `x`. + +# Examples + +```jldoctest +julia> a = [4, 3, 2, 1] +4-element Array{Int64,1}: + 4 + 3 + 2 + 1 + +julia> searchsorted(a, 4) +5:4 + +julia> searchsorted(a, 4, rev=true) +1:1 +``` """ searchsorted @@ -549,6 +582,7 @@ print_shortest Construct a tuple of the given objects. +# Example ```jldoctest julia> tuple(1, 'a', pi) (1, 'a', π = 3.1415926535897...) @@ -570,6 +604,7 @@ eachmatch Get a hexadecimal string of the binary representation of a floating point number. +# Example ```jldoctest julia> num2hex(2.2) "400199999999999a" @@ -590,6 +625,7 @@ truncate Compute ``10^x``. +# Examples ```jldoctest julia> exp10(2) 100.0 @@ -605,6 +641,7 @@ exp10 Bitwise and. +# Examples ```jldoctest julia> 4 & 10 0 @@ -618,7 +655,7 @@ julia> 4 & 12 """ select(v, k, [by=,] [lt=,] [rev=false]) -Variant of `select!` which copies `v` before partially sorting it, thereby returning the +Variant of [`select!`](@ref) which copies `v` before partially sorting it, thereby returning the same thing as `select!` but leaving `v` unmodified. """ select @@ -664,6 +701,41 @@ ErrorException reverse(v [, start=1 [, stop=length(v) ]] ) Return a copy of `v` reversed from start to stop. + +# Examples +```jldoctest +julia> A = collect(1:5) +5-element Array{Int64,1}: + 1 + 2 + 3 + 4 + 5 + +julia> reverse(A) +5-element Array{Int64,1}: + 5 + 4 + 3 + 2 + 1 + +julia> reverse(A, 1, 4) +5-element Array{Int64,1}: + 4 + 3 + 2 + 1 + 5 + +julia> reverse(A, 3, 5) +5-element Array{Int64,1}: + 1 + 2 + 5 + 4 + 3 +``` """ reverse @@ -686,15 +758,14 @@ UndefRefError Add the elements of `collection2` to the end of `collection`. +# Examples ```jldoctest julia> append!([1],[2,3]) 3-element Array{Int64,1}: 1 2 3 -``` -```jldoctest julia> append!([1, 2, 3], [4, 5, 6]) 6-element Array{Int64,1}: 1 @@ -730,6 +801,7 @@ setdiff! Return `z` which has the magnitude of `x` and the same sign as `y`. +# Examples ```jldoctest julia> copysign(1, -2) -1 @@ -767,6 +839,7 @@ showcompact Extract a named field from a `value` of composite type. The syntax `a.b` calls `getfield(a, :b)`. +# Example ```jldoctest julia> a = 1//2 1//2 @@ -786,6 +859,48 @@ at the position where it would appear if the array were fully sorted via a non-s algorithm. If `k` is a single index, that value is returned; if `k` is a range, an array of values at those indices is returned. Note that `select!` does not fully sort the input array. + +# Examples + +```jldoctest +julia> a = [1, 2, 4, 3, 4] +5-element Array{Int64,1}: + 1 + 2 + 4 + 3 + 4 + +julia> select!(a, 4) +4 + +julia> a +5-element Array{Int64,1}: + 1 + 2 + 3 + 4 + 4 + +julia> a = [1, 2, 4, 3, 4] +5-element Array{Int64,1}: + 1 + 2 + 4 + 3 + 4 + +julia> select!(a, 4, rev=true) +2 + +julia> a +5-element Array{Int64,1}: + 4 + 4 + 3 + 2 + 1 +``` """ select! @@ -795,6 +910,15 @@ select! Create a random ASCII string of length `len`, consisting of upper- and lower-case letters and the digits 0-9. The optional `rng` argument specifies a random number generator, see [Random Numbers](@ref). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randstring(rng, 4) +"mbDd" +``` """ randstring @@ -804,6 +928,7 @@ randstring Create a Float64 from `x`. If `x` is not exactly representable then `mode` determines how `x` is rounded. +# Examples ```jldoctest julia> Float64(pi, RoundDown) 3.141592653589793 @@ -821,6 +946,28 @@ Float64(x) ∪(s1,s2...) Construct the union of two or more sets. Maintains order with arrays. + +# Examples +```jldoctest +julia> union([1, 2], [3, 4]) +4-element Array{Int64,1}: + 1 + 2 + 3 + 4 + +julia> union([1, 2], [2, 4]) +3-element Array{Int64,1}: + 1 + 2 + 4 + +julia> union([4, 2], [1, 2]) +3-element Array{Int64,1}: + 4 + 2 + 1 +``` """ union @@ -829,6 +976,7 @@ union The highest finite value representable by the given floating-point DataType `T`. +# Examples ```jldoctest julia> realmax(Float16) Float16(6.55e4) @@ -855,6 +1003,7 @@ serialize The lowest value representable by the given (real) numeric DataType `T`. +# Examples ```jldoctest julia> typemin(Float16) -Inf16 @@ -938,6 +1087,7 @@ cglobal Returns the last index of the collection. +# Example ```jldoctest julia> endof([1,2,4]) 3 @@ -950,6 +1100,7 @@ endof For a given iterable object and iteration state, return the current item and the next iteration state. +# Examples ```jldoctest julia> next(1:5, 3) (3, 4) @@ -1010,6 +1161,14 @@ stop as soon as it has parsed a valid expression. Incomplete but otherwise synta valid expressions will return `Expr(:incomplete, "(error message)")`. If `raise` is `true` (default), syntax errors other than incomplete expressions will raise an error. If `raise` is `false`, `parse` will return an expression that will raise an error upon evaluation. + +```jldoctest +julia> parse("x = 3, y = 5", 7) +(:(y = 5), 13) + +julia> parse("x = 3, y = 5", 5) +(:((3, y) = 5), 13) +``` """ parse(str, start) @@ -1020,6 +1179,22 @@ Parse the expression string greedily, returning a single expression. An error is there are additional characters after the first expression. If `raise` is `true` (default), syntax errors will raise an error; otherwise, `parse` will return an expression that will raise an error upon evaluation. + +```jldoctest +julia> parse("x = 3") +:(x = 3) + +julia> parse("x = ") +:($(Expr(:incomplete, "incomplete: premature end of input"))) + +julia> parse("1.0.2") +ERROR: ParseError("invalid numeric constant \\\"1.0.\\\"") +Stacktrace: +[...] + +julia> parse("1.0.2"; raise = false) +:($(Expr(:error, "invalid numeric constant \"1.0.\""))) +``` """ parse(str) @@ -1029,6 +1204,20 @@ parse(str) Parse a string as a number. If the type is an integer type, then a base can be specified (the default is 10). If the type is a floating point type, the string is parsed as a decimal floating point number. If the string does not contain a valid number, an error is raised. + +```jldoctest +julia> parse(Int, "1234") +1234 + +julia> parse(Int, "1234", 5) +194 + +julia> parse(Int, "afc", 16) +2812 + +julia> parse(Float64, "1.2e-3") +0.0012 +``` """ parse(T::Type, str, base=Int) @@ -1047,9 +1236,9 @@ Return a partial permutation of the vector `v`, according to the order specified if `k` is a range) values of a fully sorted version of `v`. If `k` is a single index (Integer), an array of the first `k` indices is returned; if `k` is a range, an array of those indices is returned. Note that the handling of integer values for `k` is different -from `select` in that it returns a vector of `k` elements instead of just the `k` th +from [`select`](@ref) in that it returns a vector of `k` elements instead of just the `k` th element. Also note that this is equivalent to, but more efficient than, calling -`sortperm(...)[k]` +`sortperm(...)[k]`. """ selectperm @@ -1063,6 +1252,15 @@ For example, `reinterpret(Float32, UInt32(7))` interprets the 4 bytes corresponding to `UInt32(7)` as a [`Float32`](@ref). +!!! warning + + It is not allowed to `reinterpret` an array to an element type with a larger alignment then + the alignment of the array. For a normal `Array`, this is the alignment of its element type. + For a reinterpreted array, this is the alignment of the `Array` it was reinterpreted from. + For example, `reinterpret(UInt32, UInt8[0, 0, 0, 0])` is not allowed but + `reinterpret(UInt32, reinterpret(UInt8, Float32[1.0]))` is allowed. + +# Examples ```jldoctest julia> reinterpret(Float32, UInt32(7)) 1.0f-44 @@ -1079,6 +1277,7 @@ reinterpret Bitwise not. +# Examples ```jldoctest julia> ~4 -5 @@ -1097,6 +1296,7 @@ false Byte-swap an integer. Flip the bits of its binary representation. +# Examples ```jldoctest julia> a = bswap(4) 288230376151711744 @@ -1118,12 +1318,32 @@ bswap The largest integer losslessly representable by the given floating-point DataType `T`. """ -maxintfloat +maxintfloat(T) + +""" + maxintfloat(T, S) + +The largest integer losslessly representable by the given floating-point DataType `T` that +also does not exceed the maximum integer representable by the integer DataType `S`. +""" +maxintfloat(T, S) """ delete!(collection, key) Delete the mapping for the given key in a collection, and return the collection. + +# Example +```jldoctest +julia> d = Dict("a"=>1, "b"=>2) +Dict{String,Int64} with 2 entries: + "b" => 2 + "a" => 1 + +julia> delete!(d, "b") +Dict{String,Int64} with 1 entry: + "a" => 1 +``` """ delete! @@ -1133,6 +1353,20 @@ delete! Returns the index of the first value in `a` greater than or equal to `x`, according to the specified order. Returns `length(a)+1` if `x` is greater than all values in `a`. +`a` is assumed to be sorted. + +# Examples + +```jldoctest +julia> searchsortedfirst([1, 2, 4, 5, 14], 4) +3 + +julia> searchsortedfirst([1, 2, 4, 5, 14], 4, rev=true) +1 + +julia> searchsortedfirst([1, 2, 4, 5, 14], 15) +6 +``` """ searchsortedfirst @@ -1162,7 +1396,7 @@ typejoin """ selectperm!(ix, v, k, [alg=,] [by=,] [lt=,] [rev=false,] [initialized=false]) -Like `selectperm`, but accepts a preallocated index vector `ix`. If `initialized` is `false` +Like [`selectperm`](@ref), but accepts a preallocated index vector `ix`. If `initialized` is `false` (the default), ix is initialized to contain the values `1:length(ix)`. """ selectperm! @@ -1186,6 +1420,17 @@ cot Return the value stored for the given key, or the given default value if no mapping for the key is present. + +# Examples +```jldoctest +julia> d = Dict("a"=>1, "b"=>2); + +julia> get(d, "a", 3) +1 + +julia> get(d, "c", 3) +3 +``` """ get(collection,key,default) @@ -1246,6 +1491,7 @@ read(stream, t) Remove the first `item` from `collection`. +# Example ```jldoctest julia> A = [1, 2, 3, 4, 5, 6] 6-element Array{Int64,1}: @@ -1342,6 +1588,7 @@ copy Determine whether a collection is empty (has no elements). +# Examples ```jldoctest julia> isempty([]) true @@ -1396,6 +1643,7 @@ IntSet Create a `Task` (i.e. coroutine) to execute the given function (which must be callable with no arguments). The task exits when this function returns. +# Example ```jldoctest julia> a() = det(rand(1000, 1000)); @@ -1497,7 +1745,7 @@ mean! Test whether `x` is less than `y`, according to a canonical total order. Values that are normally unordered, such as `NaN`, are ordered in an arbitrary but consistent fashion. This -is the default comparison used by `sort`. Non-numeric types with a canonical total order +is the default comparison used by [`sort`](@ref). Non-numeric types with a canonical total order should implement this function. Numeric types only need to implement it if they have special values such as `NaN`. """ @@ -1617,6 +1865,7 @@ show(x) Return `true` if and only if all values of `type1` are also of `type2`. Can also be written using the `<:` infix operator as `type1 <: type2`. +# Examples ```jldoctest julia> issubtype(Int8, Int32) false @@ -1701,6 +1950,7 @@ matchall Return the value stored for the given key, or if no mapping for the key is present, store `key => default`, and return `default`. +# Examples ```jldoctest julia> d = Dict("a"=>1, "b"=>2, "c"=>3); @@ -1727,11 +1977,12 @@ Return the value stored for the given key, or if no mapping for the key is prese `key => f()`, and return `f()`. This is intended to be called using `do` block syntax: - - get!(dict, key) do - # default value calculated here - time() - end +```julia +get!(dict, key) do + # default value calculated here + time() +end +``` """ get!(f::Function,collection,key) @@ -1761,6 +2012,7 @@ For ordered, indexable collections, returns the maximum index `i` for which `get is valid. For unordered collections, returns the number of elements. +# Examples ```jldoctest julia> length(1:5) 5 @@ -1775,7 +2027,21 @@ length(collection) searchsortedlast(a, x, [by=,] [lt=,] [rev=false]) Returns the index of the last value in `a` less than or equal to `x`, according to the -specified order. Returns `0` if `x` is less than all values in `a`. +specified order. Returns `0` if `x` is less than all values in `a`. `a` is assumed to +be sorted. + +# Examples + +```jldoctest +julia> searchsortedlast([1, 2, 4, 5, 14], 4) +3 + +julia> searchsortedlast([1, 2, 4, 5, 14], 4, rev=true) +5 + +julia> searchsortedlast([1, 2, 4, 5, 14], -1) +0 +``` """ searchsortedlast @@ -1800,25 +2066,6 @@ An attempted access to a [`Nullable`](@ref) with no defined value. """ NullException -""" - cfunction(function::Function, ReturnType::Type, (ArgumentTypes...)) - -Generate C-callable function pointer from Julia function. Type annotation of the return -value in the callback function is a must for situations where Julia cannot infer the return -type automatically. - -For example: - - function foo() - # body - - retval::Float64 - end - - bar = cfunction(foo, Float64, ()) -""" -cfunction - """ intersect(s1,s2...) ∩(s1,s2) @@ -1874,6 +2121,7 @@ coth Get initial iteration state for an iterable object. +# Examples ```jldoctest julia> start(1:5) 1 @@ -1908,6 +2156,7 @@ isa Test whether we are done iterating. +# Examples ```jldoctest julia> done(1:5, 3) false @@ -1930,6 +2179,7 @@ If `T` is an [`Integer`](@ref) type, an [`InexactError`](@ref) will be raised if is not representable by `T`, for example if `x` is not integer-valued, or is outside the range supported by `T`. +# Examples ```jldoctest julia> convert(Int, 3.0) 3 @@ -1996,6 +2246,7 @@ convert Determine whether the given generic function has a method applicable to the given arguments. +# Examples ```jldoctest julia> function f(x, y) x + y @@ -2079,6 +2330,15 @@ throw ⊊(a,b) -> Bool Determine whether every element of `a` is also in `b`, using [`in`](@ref). + +# Examples +```jldoctest +julia> issubset([1, 2], [1, 2, 3]) +true + +julia> issubset([1, 2, 3], [1, 2]) +false +``` """ issubset(a,b) @@ -2097,7 +2357,7 @@ Create an array of all zeros with the same layout as `A`, element type `T` and s The `A` argument can be skipped, which behaves like `Array{Float64,0}()` was passed. For convenience `dims` may also be passed in variadic form. - +# Examples ```jldoctest julia> zeros(1) 1-element Array{Float64,1}: @@ -2162,6 +2422,18 @@ isvalid(T,value) Convert a number to an unsigned integer. If the argument is signed, it is reinterpreted as unsigned without checking for negative values. + +# Examples +```jldoctest +julia> unsigned(-2) +0xfffffffffffffffe + +julia> unsigned(2) +0x0000000000000002 + +julia> signed(unsigned(-2)) +-2 +``` """ unsigned @@ -2179,6 +2451,7 @@ reverseind Returns `true` if the value of the sign of `x` is negative, otherwise `false`. +# Examples ```jldoctest julia> signbit(-4) true @@ -2270,6 +2543,7 @@ If `x` is a type, return a "larger" type (for numeric types, this will be a type with at least as much range and precision as the argument, and usually more). Otherwise `x` is converted to `widen(typeof(x))`. +# Examples ```jldoctest julia> widen(Int32) Int64 @@ -2312,6 +2586,7 @@ Val Bitwise or. +# Examples ```jldoctest julia> 4 | 10 14 @@ -2328,6 +2603,7 @@ Base.:(|) Delete and return the mapping for `key` if it exists in `collection`, otherwise return `default`, or throw an error if `default` is not specified. +# Examples ```jldoctest julia> d = Dict("a"=>1, "b"=>2, "c"=>3); @@ -2350,6 +2626,7 @@ pop!(collection,key,?) Remove the last item in `collection` and return it. +# Examples ```jldoctest julia> A=[1, 2, 3, 4, 5, 6] 6-element Array{Int64,1}: diff --git a/base/docs/utils.jl b/base/docs/utils.jl index 0daf26f78c183..c597f39c28055 100644 --- a/base/docs/utils.jl +++ b/base/docs/utils.jl @@ -414,6 +414,7 @@ Strip all Markdown markup from x, leaving the result in plain text. Used internally by apropos to make docstrings containing more than one markdown element searchable. """ +stripmd(x::ANY) = string(x) # for random objects interpolated into the docstring stripmd(x::AbstractString) = x # base case stripmd(x::Void) = " " stripmd(x::Vector) = string(map(stripmd, x)...) diff --git a/base/essentials.jl b/base/essentials.jl index 6e06e23302d1d..cdeb952d83449 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -59,13 +59,13 @@ end argtail(x, rest...) = rest tail(x::Tuple) = argtail(x...) -tuple_type_head(T::UnionAll) = tuple_type_head(T.body) +tuple_type_head(T::UnionAll) = (@_pure_meta; UnionAll(T.var, tuple_type_head(T.body))) function tuple_type_head(T::DataType) @_pure_meta T.name === Tuple.name || throw(MethodError(tuple_type_head, (T,))) return unwrapva(T.parameters[1]) end -tuple_type_tail(T::UnionAll) = tuple_type_tail(T.body) +tuple_type_tail(T::UnionAll) = (@_pure_meta; UnionAll(T.var, tuple_type_tail(T.body))) function tuple_type_tail(T::DataType) @_pure_meta T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,))) @@ -314,7 +314,7 @@ end Colons (:) are used to signify indexing entire objects or dimensions at once. Very few operations are defined on Colons directly; instead they are converted -by `to_indices` to an internal vector type (`Base.Slice`) to represent the +by [`to_indices`](@ref) to an internal vector type (`Base.Slice`) to represent the collection of indices they span before being used. """ struct Colon diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index a5973c7d99986..88f5723a9ebd0 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -20,6 +20,7 @@ maxintfloat(::Type{Float64}) = 9007199254740992. maxintfloat(::Type{Float32}) = Float32(16777216.) maxintfloat(::Type{Float16}) = Float16(2048f0) maxintfloat(x::T) where {T<:AbstractFloat} = maxintfloat(T) +maxintfloat(::Type{S}, ::Type{T}) where {S<:AbstractFloat, T<:Integer} = min(maxintfloat(S), S(typemax(T))) maxintfloat() = maxintfloat(Float64) isinteger(x::AbstractFloat) = (x - trunc(x) == 0) diff --git a/base/gmp.jl b/base/gmp.jl index 7696c56b15e0e..e8e7d814aa88e 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -578,26 +578,21 @@ oct(n::BigInt, pad::Int) = base( 8, n, pad) dec(n::BigInt, pad::Int) = base(10, n, pad) hex(n::BigInt, pad::Int) = base(16, n, pad) -function base(b::Integer, n::BigInt) +function base(b::Integer, n::BigInt, pad::Integer=1) + b < 0 && return base(Int(b), n, pad, (b>0) & (n.size<0)) 2 <= b <= 62 || throw(ArgumentError("base must be 2 ≤ base ≤ 62, got $b")) - nd = ndigits(n, b) - str = Base._string_n(n < 0 ? nd+1 : nd) - ccall((:__gmpz_get_str,:libgmp), Ptr{UInt8}, (Ptr{UInt8}, Cint, Ptr{BigInt}), str, b, &n) - return str -end - -function base(b::Integer, n::BigInt, pad::Integer) - s = base(b, n) - buf = IOBuffer() - if n < 0 - s = s[2:end] - write(buf, '-') + nd1 = ndigits(n, b) + nd = max(nd1, pad) + str = Base._string_n(nd + isneg(n) + 1) # +1 for final '\0' + ptr = pointer(str) + ccall((:__gmpz_get_str,:libgmp), Ptr{UInt8}, (Ptr{UInt8}, Cint, Ref{BigInt}), ptr + nd - nd1, b, n) + for i = (0:nd-nd1-1) + isneg(n) + unsafe_store!(ptr+i, '0' % UInt8) end - for i in 1:pad-sizeof(s) # `s` is known to be ASCII, and `length` is slower - write(buf, '0') - end - write(buf, s) - String(buf) + isneg(n) && unsafe_store!(ptr, '-' % UInt8) + str.len -= 1 # final '\0' + iszero(n) && pad < 1 && (str.len -= 1) + str end function ndigits0z(x::BigInt, b::Integer=10) diff --git a/base/inference.jl b/base/inference.jl index 17220ed7cd4d6..8455889e807b5 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -131,14 +131,11 @@ mutable struct InferenceState # ssavalue sparsity and restart info ssavalue_uses::Vector{IntSet} ssavalue_init::Vector{Any} - # call-graph edges connecting from a caller to a callee (and back) - # we shouldn't need to iterate edges very often, so we use it to optimize the lookup from edge -> linenum - # whereas backedges is optimized for iteration - edges::ObjectIdDict # a Dict{InferenceState, Vector{LineNum}} - backedges::Vector{Tuple{InferenceState, Vector{LineNum}}} - # iteration fixed-point detection - fixedpoint::Bool - inworkq::Bool + + backedges::Vector{Tuple{InferenceState, LineNum}} # call-graph backedges connecting from callee to caller + callers_in_cycle::Vector{InferenceState} + parent::Union{Void, InferenceState} + const_api::Bool const_ret::Bool @@ -148,6 +145,8 @@ mutable struct InferenceState inferred::Bool + dont_work_on_me::Bool + # src is assumed to be a newly-allocated CodeInfo, that can be modified in-place to contain intermediate results function InferenceState(linfo::MethodInstance, src::CodeInfo, optimize::Bool, cached::Bool, params::InferenceParams) @@ -268,41 +267,43 @@ mutable struct InferenceState Union{}, W, 1, n, cur_hand, handler_at, n_handlers, ssavalue_uses, ssavalue_init, - ObjectIdDict(), # Dict{InferenceState, Vector{LineNum}}(), - Vector{Tuple{InferenceState, Vector{LineNum}}}(), - false, false, false, false, optimize, cached, false) - push!(active, frame) - nactive[] += 1 + Vector{Tuple{InferenceState,LineNum}}(), # backedges + Vector{InferenceState}(), # callers_in_cycle + #=parent=#nothing, + false, false, optimize, cached, false, false) return frame end end -# create copies of the CodeInfo definition, and any fields that type-inference might modify -# TODO: post-inference see if we can swap back to the original arrays -function get_source(li::MethodInstance) - if isa(li.def.source, Array{UInt8,1}) - src = ccall(:jl_uncompress_ast, Any, (Any, Any), li.def, li.def.source) +function InferenceState(linfo::MethodInstance, + optimize::Bool, cached::Bool, params::InferenceParams) + # prepare an InferenceState object for inferring lambda + # create copies of the CodeInfo definition, and any fields that type-inference might modify + if linfo.def.isstaged + try + # user code might throw errors – ignore them + src = get_staged(linfo) + catch + return nothing + end else - src = ccall(:jl_copy_code_info, Ref{CodeInfo}, (Any,), li.def.source) - src.code = copy_exprargs(src.code) - src.slotnames = copy(src.slotnames) - src.slotflags = copy(src.slotflags) + # TODO: post-inference see if we can swap back to the original arrays? + if isa(linfo.def.source, Array{UInt8,1}) + src = ccall(:jl_uncompress_ast, Any, (Any, Any), linfo.def, linfo.def.source) + else + src = ccall(:jl_copy_code_info, Ref{CodeInfo}, (Any,), linfo.def.source) + src.code = copy_exprargs(src.code) + src.slotnames = copy(src.slotnames) + src.slotflags = copy(src.slotflags) + end end - return src + return InferenceState(linfo, src, optimize, cached, params) end function get_staged(li::MethodInstance) return ccall(:jl_code_for_staged, Any, (Any,), li)::CodeInfo end - -#### current global inference state #### - -const active = Vector{Any}() # set of all InferenceState objects being processed -const nactive = Array{Int,0}() -nactive[] = 0 -const workq = Vector{InferenceState}() # set of InferenceState objects that can make immediate progress - #### helper functions #### @inline slot_id(s) = isa(s, SlotNumber) ? (s::SlotNumber).id : (s::TypedSlot).id # using a function to ensure we can infer this @@ -371,25 +372,30 @@ end add_tfunc(throw, 1, 1, (x::ANY) -> Bottom) # the inverse of typeof_tfunc +# returns (type, isexact) +# if isexact is false, the actual runtime type may (will) be a subtype of t function instanceof_tfunc(t::ANY) - # TODO improve - if t === Bottom - return t + if t === Bottom || t === typeof(Bottom) + return Bottom, true elseif isa(t, Const) if isa(t.val, Type) - return t.val + return t.val, true end elseif isType(t) - return t.parameters[1] - elseif isa(t,UnionAll) + tp = t.parameters[1] + return tp, !has_free_typevars(tp) + elseif isa(t, UnionAll) t′ = unwrap_unionall(t) - return rewrap_unionall(instanceof_tfunc(t′), t) - elseif isa(t,Union) - return Union{instanceof_tfunc(t.a), instanceof_tfunc(t.b)} + t′′, isexact = instanceof_tfunc(t′) + return rewrap_unionall(t′′, t), isexact + elseif isa(t, Union) + ta, isexact_a = instanceof_tfunc(t.a) + tb, isexact_b = instanceof_tfunc(t.b) + return Union{ta, tb}, false # at runtime, will be exactly one of these end - return Any + return Any, false end -bitcast_tfunc(t::ANY, x::ANY) = instanceof_tfunc(t) +bitcast_tfunc(t::ANY, x::ANY) = instanceof_tfunc(t)[1] math_tfunc(x::ANY) = widenconst(x) math_tfunc(x::ANY, y::ANY) = widenconst(x) math_tfunc(x::ANY, y::ANY, z::ANY) = widenconst(x) @@ -504,7 +510,7 @@ add_tfunc(checked_smul_int, 2, 2, chk_tfunc) add_tfunc(checked_umul_int, 2, 2, chk_tfunc) ## other, misc intrinsics ## add_tfunc(Core.Intrinsics.llvmcall, 3, IInf, - (fptr::ANY, rt::ANY, at::ANY, a...) -> instanceof_tfunc(rt)) + (fptr::ANY, rt::ANY, at::ANY, a...) -> instanceof_tfunc(rt)[1]) cglobal_tfunc(fptr::ANY) = Ptr{Void} cglobal_tfunc(fptr::ANY, t::ANY) = (isType(t) ? Ptr{t.parameters[1]} : Ptr) cglobal_tfunc(fptr::ANY, t::Const) = (isa(t.val, Type) ? Ptr{t.val} : Ptr) @@ -611,7 +617,7 @@ end add_tfunc(typeof, 1, 1, typeof_tfunc) add_tfunc(typeassert, 2, 2, function (v::ANY, t::ANY) - t = instanceof_tfunc(t) + t, isexact = instanceof_tfunc(t) t === Any && return v if isa(v, Const) if !has_free_typevars(t) && !isa(v.val, t) @@ -628,24 +634,38 @@ add_tfunc(typeassert, 2, 2, end) add_tfunc(isa, 2, 2, function (v::ANY, t::ANY) - t = instanceof_tfunc(t) - if t !== Any && !has_free_typevars(t) - if v ⊑ t - return Const(true) + t, isexact = instanceof_tfunc(t) + if !has_free_typevars(t) + if t === Bottom + return Const(false) + elseif v ⊑ t + if isexact + return Const(true) + end elseif isa(v, Const) || isa(v, Conditional) || (isleaftype(v) && !iskindtype(v)) return Const(false) + elseif isexact && typeintersect(v, t) === Bottom + if !iskindtype(v) #= subtyping currently intentionally answers this query incorrectly for kinds =# + return Const(false) + end end end # TODO: handle non-leaftype(t) by testing against lower and upper bounds return Bool end) -add_tfunc(issubtype, 2, 2, +add_tfunc(<:, 2, 2, function (a::ANY, b::ANY) - if (isa(a,Const) || isType(a)) && (isa(b,Const) || isType(b)) - a = instanceof_tfunc(a) - b = instanceof_tfunc(b) - if !has_free_typevars(a) && !has_free_typevars(b) - return Const(issubtype(a, b)) + a, isexact_a = instanceof_tfunc(a) + b, isexact_b = instanceof_tfunc(b) + if !has_free_typevars(a) && !has_free_typevars(b) + if a <: b + if isexact_b || a === Bottom + return Const(true) + end + else + if isexact_a || (b !== Bottom && typeintersect(a, b) === Union{}) + return Const(false) + end end end return Bool @@ -756,7 +776,6 @@ function const_datatype_getfield_tfunc(sv, fld) return nothing end -# returns (type, isexact) function getfield_tfunc(s00::ANY, name) if isa(s00, TypeVar) s00 = s00.ub @@ -891,7 +910,7 @@ function fieldtype_tfunc(s0::ANY, name::ANY) return Bottom end - s = instanceof_tfunc(s0) + s = instanceof_tfunc(s0)[1] u = unwrap_unionall(s) if isa(u,Union) @@ -1092,7 +1111,9 @@ function invoke_tfunc(f::ANY, types::ANY, argtype::ANY, sv::InferenceState) meth = entry.func (ti, env) = ccall(:jl_match_method, Ref{SimpleVector}, (Any, Any), argtype, meth.sig) - return typeinf_edge(meth::Method, ti, env, sv) + rt, edge = typeinf_edge(meth::Method, ti, env, sv) + edge !== nothing && add_backedge!(edge::MethodInstance, sv) + return rt end function tuple_tfunc(argtype::ANY) @@ -1287,43 +1308,31 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState) # this means too many methods matched return Any end - x::Array{Any,1} = applicable + applicable = applicable::Array{Any,1} fullmatch = false - for (m::SimpleVector) in x + for (m::SimpleVector) in applicable sig = m[1] sigtuple = unwrap_unionall(sig)::DataType method = m[3]::Method sparams = m[2]::SimpleVector recomputesvec = false - if !fullmatch && typeseq(sig, argtype) + if !fullmatch && (argtype <: method.sig) fullmatch = true end # limit argument type tuple growth - msig = unwrap_unionall(m[3].sig) + msig = unwrap_unionall(method.sig) lsig = length(msig.parameters) ls = length(sigtuple.parameters) td = type_depth(sig) - # look at the existing edges to detect growing argument lists mightlimitlength = ls > lsig + 1 mightlimitdepth = td > 2 - limitlength = false - if mightlimitlength - for (callee, _) in sv.edges - callee = callee::InferenceState - if method === callee.linfo.def && ls > length(unwrap_unionall(callee.linfo.specTypes).parameters) - limitlength = true - break - end - end - end - - # limit argument type size growth if mightlimitlength || mightlimitdepth # TODO: FIXME: this heuristic depends on non-local state making type-inference unpredictable - for infstate in active - infstate === nothing && continue + cyclei = 0 + infstate = sv + while infstate !== nothing infstate = infstate::InferenceState if isdefined(infstate.linfo, :def) && method === infstate.linfo.def if mightlimitlength && ls > length(unwrap_unionall(infstate.linfo.specTypes).parameters) @@ -1363,6 +1372,14 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState) end end end + # iterate through the cycle before walking to the parent + if cyclei < length(infstate.callers_in_cycle) + cyclei += 1 + infstate = infstate.callers_in_cycle[cyclei] + else + cyclei = 0 + infstate = infstate.parent + end end end @@ -1400,7 +1417,8 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState) end sparams = recomputed[2]::SimpleVector end - rt = typeinf_edge(method, sig, sparams, sv) + rt, edge = typeinf_edge(method, sig, sparams, sv) + edge !== nothing && add_backedge!(edge::MethodInstance, sv) rettype = tmerge(rettype, rt) if rettype === Any break @@ -1412,7 +1430,7 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState) add_mt_backedge(ftname.mt, argtype, sv) update_valid_age!(min_valid[1], max_valid[1], sv) end - if isempty(x) + if isempty(applicable) # TODO: this is needed because type intersection is wrong in some cases return Any end @@ -1687,14 +1705,9 @@ function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vect a = fargs[2] if isa(a, fieldtype(Conditional, :var)) aty = widenconst(argtypes[2]) - tty = instanceof_tfunc(argtypes[3]) - if tty !== Any && tty !== Bottom - if isa(tty, TypeVar) - tty_ub = tty.ub - tty_lb = tty.lb - else - tty_ub = tty_lb = tty - end + tty_ub, isexact_tty = instanceof_tfunc(argtypes[3]) + if isexact_tty && !isa(tty_ub, TypeVar) + tty_lb = tty_ub # TODO: this would be wrong if !isexact_tty, but instanceof_tfunc doesn't preserve this info if !has_free_typevars(tty_lb) && !has_free_typevars(tty_ub) ifty = typeintersect(aty, tty_ub) elsety = typesubtract(aty, tty_lb) @@ -1729,7 +1742,7 @@ function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vect elseif f === Core.kwfunc if length(fargs) == 2 ft = widenconst(argtypes[2]) - if isa(ft,DataType) && isdefined(ft.name, :mt) && isdefined(ft.name.mt, :kwsorter) + if isa(ft, DataType) && isdefined(ft.name, :mt) && isdefined(ft.name.mt, :kwsorter) return Const(ft.name.mt.kwsorter) end end @@ -1938,7 +1951,7 @@ function abstract_eval(e::ANY, vtypes::VarTable, sv::InferenceState) elseif e.head === :null t = Void elseif e.head === :new - t = instanceof_tfunc(abstract_eval(e.args[1], vtypes, sv)) + t = instanceof_tfunc(abstract_eval(e.args[1], vtypes, sv))[1] for i = 2:length(e.args) if abstract_eval(e.args[i], vtypes, sv) === Bottom rt = Bottom @@ -2333,31 +2346,6 @@ end inlining_enabled() = (JLOptions().can_inline == 1) coverage_enabled() = (JLOptions().code_coverage != 0) -# TODO: track the worlds for which this InferenceState -# is being used, and split it if the WIP requires it? -function converge_valid_age!(sv::InferenceState) - # push the validity range of sv into its fixedpoint callers - # recursing as needed to cover the graph - for (i, _) in sv.backedges - if i.fixedpoint - updated = false - if i.min_valid < sv.min_valid - i.min_valid = sv.min_valid - updated = true - end - if i.max_valid > sv.max_valid - i.max_valid = sv.max_valid - updated = true - end - @assert !isdefined(i.linfo, :def) || !i.cached || i.min_valid <= i.params.world <= i.max_valid "invalid age range update" - if updated - converge_valid_age!(i) - end - end - end - nothing -end - # work towards converging the valid age range for sv function update_valid_age!(min_valid::UInt, max_valid::UInt, sv::InferenceState) sv.min_valid = max(sv.min_valid, min_valid) @@ -2369,7 +2357,7 @@ update_valid_age!(edge::InferenceState, sv::InferenceState) = update_valid_age!( update_valid_age!(li::MethodInstance, sv::InferenceState) = update_valid_age!(min_world(li), max_world(li), sv) # temporarily accumulate our edges to later add as backedges in the callee -function add_backedge(li::MethodInstance, caller::InferenceState) +function add_backedge!(li::MethodInstance, caller::InferenceState) isdefined(caller.linfo, :def) || return # don't add backedges to toplevel exprs if caller.stmt_edges[caller.currpc] === () caller.stmt_edges[caller.currpc] = [] @@ -2435,72 +2423,92 @@ function code_for_method(method::Method, atypes::ANY, sparams::SimpleVector, wor return ccall(:jl_specializations_get_linfo, Ref{MethodInstance}, (Any, Any, Any, UInt), method, atypes, sparams, world) end -function typeinf_active(linfo::MethodInstance) - for infstate in active - infstate === nothing && continue - infstate = infstate::InferenceState - if linfo === infstate.linfo && infstate.cached - return infstate - end +function typeinf_active(linfo::MethodInstance, sv::InferenceState) + for infstate in sv.callers_in_cycle + linfo === infstate.linfo && return infstate end return nothing end -function add_backedge(frame::InferenceState, caller::InferenceState, currpc::Int) +function add_backedge!(frame::InferenceState, caller::InferenceState, currpc::Int) update_valid_age!(frame, caller) - if haskey(caller.edges, frame) - Ws = caller.edges[frame]::Vector{Int} - if !(currpc in Ws) - push!(Ws, currpc) + backedge = (caller, currpc) + contains_is(frame.backedges, backedge) || push!(frame.backedges, backedge) + return frame +end + +# at the end, all items in b's cycle +# will now be added to a's cycle +function union_caller_cycle!(a::InferenceState, b::InferenceState) + callers_in_cycle = b.callers_in_cycle + b.parent = a.parent + b.callers_in_cycle = a.callers_in_cycle + contains_is(a.callers_in_cycle, b) || push!(a.callers_in_cycle, b) + if callers_in_cycle !== a.callers_in_cycle + for caller in callers_in_cycle + if caller !== b + caller.parent = a.parent + caller.callers_in_cycle = a.callers_in_cycle + push!(a.callers_in_cycle, caller) + end end - else - Ws = Int[currpc] - caller.edges[frame] = Ws - push!(frame.backedges, (caller, Ws)) end + return end -# build (and start inferring) the inference frame for the linfo -function typeinf_frame(linfo::MethodInstance, caller, optimize::Bool, cached::Bool, - params::InferenceParams) - # println(params.world, ' ', linfo) - if cached && linfo.inInference - # inference on this signature may be in progress, - # find the corresponding frame in the active list - frame = typeinf_active(linfo) - # TODO: this assertion seems iffy - assert(frame !== nothing) - else - # inference not started yet, make a new frame for a new lambda - if linfo.def.isstaged - try - # user code might throw errors – ignore them - src = get_staged(linfo) - catch - return nothing +function merge_call_chain!(parent::InferenceState, ancestor::InferenceState, child::InferenceState) + # add backedge of parent <- child + # then add all backedges of parent <- parent.parent + # and merge all of the callers into ancestor.callers_in_cycle + # and ensure that walking the parent list will get the same result (DAG) from everywhere + while true + add_backedge!(child, parent, parent.currpc) + union_caller_cycle!(ancestor, child) + child = parent + parent = child.parent + child === ancestor && break + end +end + +# Walk through `linfo`'s upstream call chain, starting at `parent`. If a parent +# frame matching `linfo` is encountered, then there is a cycle in the call graph +# (i.e. `linfo` is a descendant callee of itself). Upon encountering this cycle, +# we "resolve" it by merging the call chain, which entails unioning each intermediary +# frame's `callers_in_cycle` field and adding the appropriate backedges. Finally, +# we return `linfo`'s pre-existing frame. If no cycles are found, `nothing` is +# returned instead. +function resolve_call_cycle!(linfo::MethodInstance, parent::InferenceState) + frame = parent + while isa(frame, InferenceState) + if frame.linfo === linfo + merge_call_chain!(parent, frame, frame) + return frame + end + for caller in frame.callers_in_cycle + if caller.linfo === linfo + merge_call_chain!(parent, frame, caller) + return caller end - else - src = get_source(linfo) end - cached && (linfo.inInference = true) - frame = InferenceState(linfo, src, optimize, cached, params) + frame = frame.parent end - frame = frame::InferenceState + return nothing +end - if isa(caller, InferenceState) - # if we were called from inside inference, the caller will be the InferenceState object - # for which the edge was required - @assert caller.currpc > 0 - add_backedge(frame, caller, caller.currpc) - end - typeinf_loop(frame) +# build (and start inferring) the inference frame for the linfo +function typeinf_frame(linfo::MethodInstance, + optimize::Bool, cached::Bool, params::InferenceParams) + frame = InferenceState(linfo, optimize, cached, params) + frame === nothing && return nothing + cached && (linfo.inInference = true) + typeinf(frame) return frame end # compute (and cache) an inferred AST and return the current best estimate of the result type function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, caller::InferenceState) code = code_for_method(method, atypes, sparams, caller.params.world) - code === nothing && return Any + code === nothing && return Any, nothing code = code::MethodInstance if isdefined(code, :inferred) # return rettype if the code is already inferred @@ -2508,18 +2516,27 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, caller # so need to check whether the code itself is also inferred inf = code.inferred if !isa(inf, CodeInfo) || (inf::CodeInfo).inferred - add_backedge(code, caller) if isdefined(code, :inferred_const) - return abstract_eval_constant(code.inferred_const) + return abstract_eval_constant(code.inferred_const), code else - return code.rettype + return code.rettype, code end end end - frame = typeinf_frame(code, caller, true, true, caller.params) - frame === nothing && return Any + frame = resolve_call_cycle!(code, caller) + if frame === nothing + code.inInference = true + frame = InferenceState(code, true, true, caller.params) # always optimize and cache edge targets + if frame === nothing + code.inInference = false + return Any, nothing + end + frame.parent = caller + typeinf(frame) + return frame.bestguess, frame.inferred ? frame.linfo : nothing + end frame = frame::InferenceState - return frame.bestguess + return frame.bestguess, nothing end #### entry points for inferring a MethodInstance given a type signature #### @@ -2563,7 +2580,7 @@ function typeinf_code(linfo::MethodInstance, optimize::Bool, cached::Bool, end end end - frame = typeinf_frame(linfo, nothing, optimize, cached, params) + frame = typeinf_frame(linfo, optimize, cached, params) ccall(:jl_typeinf_end, Void, ()) frame === nothing && return svec(nothing, nothing, Any) frame = frame::InferenceState @@ -2591,7 +2608,7 @@ function typeinf_type(method::Method, atypes::ANY, sparams::SimpleVector, end end end - frame = typeinf_frame(code, nothing, cached, cached, params) + frame = typeinf_frame(code, cached, cached, params) ccall(:jl_typeinf_end, Void, ()) frame === nothing && return nothing frame = frame::InferenceState @@ -2605,11 +2622,10 @@ function typeinf_ext(linfo::MethodInstance, world::UInt) return typeinf_code(linfo, true, true, InferenceParams(world)) else # toplevel lambda - infer directly - linfo.inInference = true ccall(:jl_typeinf_begin, Void, ()) frame = InferenceState(linfo, linfo.inferred::CodeInfo, true, true, InferenceParams(world)) - typeinf_loop(frame) + typeinf(frame) ccall(:jl_typeinf_end, Void, ()) @assert frame.inferred # TODO: deal with this better @assert frame.linfo === linfo @@ -2619,83 +2635,9 @@ end #### do the work of inference #### -in_typeinf_loop = false -function typeinf_loop(frame) - global in_typeinf_loop - if in_typeinf_loop - frame.inworkq || typeinf_frame(frame) - return - end - try - in_typeinf_loop = true - # the core type-inference algorithm - # processes everything in workq, - # and returns when there is nothing left - while nactive[] > 0 - while active[end] === nothing - pop!(active) - end - if isempty(workq) - frame = active[end]::InferenceState - else - frame = pop!(workq) - end - typeinf_frame(frame) - if isempty(workq) && nactive[] > 0 - # nothing in active has an edge that hasn't reached a fixed-point - # so all of them can be considered finished now - fplist = Any[] - for i in active - i === nothing && continue - i = i::InferenceState - if i.fixedpoint - push!(fplist, i) - i.inworkq = true - end - end - for i in length(fplist):-1:1 - # optimize and record the results - # the reverse order makes it more likely to inline a callee into its caller - optimize(fplist[i]::InferenceState) # this may add incomplete work to active - end - for i in fplist - # push valid ages from each node across the graph cycle - converge_valid_age!(i::InferenceState) - end - for i in fplist - # record the results - finish(i::InferenceState) - end - for i in fplist - # update and record all of the back edges for the finished world - finalize_backedges(i::InferenceState) - end - end - end - # cleanup the active queue - empty!(active) - # while active[end] === nothing - # # this pops everything, but with exaggerated care just in case - # # something managed to add something to the queue at the same time - # # (or someone decides to use an alternative termination condition) - # pop!(active) - # end - in_typeinf_loop = false - catch ex - println("WARNING: An error occurred during inference. Type inference is now partially disabled.") - println(ex) - ccall(:jlbacktrace, Void, ()) - end - nothing -end - -global_sv = nothing -function typeinf_frame(frame) - global global_sv # TODO: actually pass this to all functions that need it - last_global_sv = global_sv - global_sv = frame +function typeinf_work(frame::InferenceState) @assert !frame.inferred - frame.inworkq = true + frame.dont_work_on_me = true # mark that this function is currently on the stack W = frame.ip s = frame.stmt_types n = frame.nstmts @@ -2781,18 +2723,15 @@ function typeinf_frame(frame) if tchanged(rt, frame.bestguess) # new (wider) return type for frame frame.bestguess = tmerge(frame.bestguess, rt) - for (caller, callerW) in frame.backedges + for (caller, caller_pc) in frame.backedges # notify backedges of updated type information - for caller_pc in callerW - if caller.stmt_types[caller_pc] !== () - if caller_pc < caller.pc´´ - caller.pc´´ = caller_pc - end - push!(caller.ip, caller_pc) + if caller.stmt_types[caller_pc] !== () + if caller_pc < caller.pc´´ + caller.pc´´ = caller_pc end + push!(caller.ip, caller_pc) end end - unmark_fixedpoint(frame) end elseif hd === :enter l = stmt.args[1]::Int @@ -2840,53 +2779,72 @@ function typeinf_frame(frame) end end end + frame.dont_work_on_me = false +end - # with no active ip's, type inference on frame is done if there are no outstanding (unfinished) edges - #@assert isempty(W) - @assert !frame.inferred - finished = isempty(frame.edges) - if isempty(workq) - # oops, there's a cycle somewhere in the `edges` graph - # so we've run out off the tree and will need to start work on the loop - frame.fixedpoint = true - end - - if finished || frame.fixedpoint - if finished - optimize(frame) - finish(frame) - finalize_backedges(frame) - else # fixedpoint propagation - for (i, _) in frame.edges - i = i::InferenceState - if !i.fixedpoint - update_valid_age!(i, frame) # work towards converging age at the same time - if !i.inworkq - push!(workq, i) - i.inworkq = true - end - i.fixedpoint = true - end +function typeinf(frame::InferenceState) + + typeinf_work(frame) + + # If the current frame is part of a cycle, solve the cycle before finishing + no_active_ips_in_callers = false + while !no_active_ips_in_callers + no_active_ips_in_callers = true + for caller in frame.callers_in_cycle + caller.dont_work_on_me && return + if caller.pc´´ <= caller.nstmts # equivalent to `isempty(caller.ip)` + # Note that `typeinf_work(caller)` can potentially modify the other frames + # `frame.callers_in_cycle`, which is why making incremental progress requires the + # outer while loop. + typeinf_work(caller) + no_active_ips_in_callers = false + end + if caller.min_valid < frame.min_valid + caller.min_valid = frame.min_valid + end + if caller.max_valid > frame.max_valid + caller.max_valid = frame.max_valid end end end - frame.inworkq = false - global_sv = last_global_sv - nothing -end -function unmark_fixedpoint(frame::InferenceState) - # type information changed for frame, so its edges are no longer stuck - # recursively unmark any nodes that had previously been thought to be at a fixedpoint - # based upon (recursively) assuming that frame was stuck - if frame.fixedpoint - frame.fixedpoint = false - for (i, _) in frame.backedges - unmark_fixedpoint(i) + # with no active ip's, type inference on frame is done + + if isempty(frame.callers_in_cycle) + @assert !(frame.dont_work_on_me) + frame.dont_work_on_me = true + optimize(frame) + finish(frame) + finalize_backedges(frame) + else # frame is in frame.callers_in_cycle + for caller in frame.callers_in_cycle + @assert !(caller.dont_work_on_me) + caller.dont_work_on_me = true + end + for caller in frame.callers_in_cycle + optimize(caller) + if frame.min_valid < caller.min_valid + frame.min_valid = caller.min_valid + end + if frame.max_valid > caller.max_valid + frame.max_valid = caller.max_valid + end + end + for caller in frame.callers_in_cycle + caller.min_valid = frame.min_valid + end + for caller in frame.callers_in_cycle + finish(caller) + end + for caller in frame.callers_in_cycle + finalize_backedges(caller) end end + + nothing end + function record_ssa_assign(ssa_id::Int, new::ANY, frame::InferenceState) old = frame.src.ssavaluetypes[ssa_id] if old === NF || !(new ⊑ old) @@ -2932,16 +2890,6 @@ end # inference completed on `me` # now converge the optimization work function optimize(me::InferenceState) - for (i, _) in me.edges - i = i::InferenceState - @assert i.fixedpoint - end - # below may call back into inference and - # see this InferenceState is in an incomplete state - # set `inworkq` to prevent it from trying to look - # at the object in any detail - @assert me.inworkq - # annotate fulltree with type information type_annotate!(me) @@ -3034,7 +2982,7 @@ function finish(me::InferenceState) # check if the existing me.linfo metadata is also sufficient to describe the current inference result # to decide if it is worth caching it again (which would also clear any generated code) - already_inferred = false + already_inferred = !me.linfo.inInference if isdefined(me.linfo, :inferred) inf = me.linfo.inferred if !isa(inf, CodeInfo) || (inf::CodeInfo).inferred @@ -3085,20 +3033,9 @@ function finish(me::InferenceState) end end - # lazy-delete the item from active for several reasons: - # efficiency, correctness, and recursion-safety - nactive[] -= 1 - active[findlast(active, me)] = nothing - - # update all of the callers by traversing the backedges + # update all of the callers with real backedges by traversing the temporary list of backedges for (i, _) in me.backedges - if !me.fixedpoint || !i.fixedpoint - # wake up each backedge, unless both me and it already reached a fixed-point (cycle resolution stage) - delete!(i.edges, me) - i.inworkq || push!(workq, i) - i.inworkq = true - end - add_backedge(me.linfo, i) + add_backedge!(me.linfo, i) end # finalize and record the linfo result @@ -3611,7 +3548,7 @@ function invoke_NF(argexprs, etype::ANY, atypes, sv, atype_unlimited::ANY, local sig = argtypes_to_type(atypes) local li = get_spec_lambda(sig, sv, invoke_data) li === nothing && return false - add_backedge(li, sv) + add_backedge!(li, sv) local stmt = [] push!(stmt, Expr(:(=), linfo_var, li)) spec_hit === nothing && (spec_hit = genlabel(sv)) @@ -3682,7 +3619,7 @@ function invoke_NF(argexprs, etype::ANY, atypes, sv, atype_unlimited::ANY, else local cache_linfo = get_spec_lambda(atype_unlimited, sv, invoke_data) cache_linfo === nothing && return NF - add_backedge(cache_linfo, sv) + add_backedge!(cache_linfo, sv) unshift!(argexprs, cache_linfo) ex = Expr(:invoke) ex.args = argexprs @@ -3920,7 +3857,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference linfo = linfo::MethodInstance if linfo.jlcall_api == 2 # in this case function can be inlined to a constant - add_backedge(linfo, sv) + add_backedge!(linfo, sv) return inline_as_constant(linfo.inferred_const, argexprs, sv, invoke_data) end @@ -3937,22 +3874,19 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference # as we'll be able to fix that up at the end of inlinable when we verify the return type. # But `next` and `indexed_next` make tuples which would end up burying some of that information in the AST # where we can't easily correct it afterwards. - frame = InferenceState(linfo, get_source(linfo), #=optimize=#true, #=cache=#false, sv.params) + frame = InferenceState(linfo, #=optimize=#true, #=cache=#false, sv.params) frame.stmt_types[1][3] = VarState(atypes[3], false) - typeinf_loop(frame) + typeinf(frame) else if isdefined(linfo, :inferred) && linfo.inferred !== nothing # use cache inferred = linfo.inferred - elseif linfo.inInference - # use WIP - frame = typeinf_active(linfo) elseif force_infer # create inferred code on-demand # but if we decided in the past not to try to infer this particular signature # (due to signature coarsening in abstract_call_gf_by_type) # don't infer it now, as attempting to force it now would be a bad idea (non terminating) - frame = typeinf_frame(linfo, nothing, #=optimize=#true, #=cache=#true, sv.params) + frame = typeinf_frame(linfo, #=optimize=#true, #=cache=#true, sv.params) end end @@ -3963,9 +3897,9 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference inferred = frame.src if frame.const_api # handle like jlcall_api == 2 if frame.inferred || !frame.cached - add_backedge(frame.linfo, sv) + add_backedge!(frame.linfo, sv) else - add_backedge(frame, sv, 0) + add_backedge!(frame, sv, 0) end if isa(frame.bestguess, Const) inferred_const = (frame.bestguess::Const).val @@ -4026,9 +3960,9 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference if isa(frame, InferenceState) && !frame.inferred && frame.cached # in this case, the actual backedge linfo hasn't been computed # yet, but will be when inference on the frame finishes - add_backedge(frame, sv, 0) + add_backedge!(frame, sv, 0) else - add_backedge(linfo, sv) + add_backedge!(linfo, sv) end spvals = Any[] @@ -5481,7 +5415,7 @@ end # especially try to make sure any recursive and leaf functions have concrete signatures, # since we won't be able to specialize & infer them at runtime -let fs = Any[typeinf_ext, typeinf_loop, typeinf_edge, occurs_outside_getfield, pure_eval_call], +let fs = Any[typeinf_ext, typeinf, typeinf_edge, occurs_outside_getfield, pure_eval_call], world = ccall(:jl_get_world_counter, UInt, ()) for x in t_ffunc_val push!(fs, x[3]) diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 8c949d1710706..c50c570014adb 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -324,14 +324,35 @@ problematic for performance, so the results need to be used judiciously. See [`@code_warntype`](@ref man-code-warntype) for more information. """ function code_warntype(io::IO, f, t::ANY) + function slots_used(ci, slotnames) + used = falses(length(slotnames)) + scan_exprs!(used, ci.code) + return used + end + + function scan_exprs!(used, exprs) + for ex in exprs + if isa(ex, Slot) + used[ex.id] = true + elseif isa(ex, Expr) + scan_exprs!(used, ex.args) + end + end + end + emph_io = IOContext(io, :TYPEEMPHASIZE => true) for (src, rettype) in code_typed(f, t) println(emph_io, "Variables:") slotnames = sourceinfo_slotnames(src) + used_slotids = slots_used(src, slotnames) for i = 1:length(slotnames) print(emph_io, " ", slotnames[i]) - if isa(src.slottypes, Array) - show_expr_type(emph_io, src.slottypes[i], true) + if used_slotids[i] + if isa(src.slottypes, Array) + show_expr_type(emph_io, src.slottypes[i], true) + end + else + print(emph_io, " ") end print(emph_io, '\n') end diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 91191d4048c18..9eea4a79081ba 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -7,6 +7,7 @@ Greatest common (positive) divisor (or zero if `x` and `y` are both zero). +# Examples ```jldoctest julia> gcd(6,9) 3 @@ -51,6 +52,8 @@ end lcm(x,y) Least common (non-negative) multiple. + +# Examples ```jldoctest julia> lcm(2,3) 6 @@ -86,12 +89,11 @@ Computes the greatest common (positive) divisor of `x` and `y` and their Bézout coefficients, i.e. the integer coefficients `u` and `v` that satisfy ``ux+vy = d = gcd(x,y)``. ``gcdx(x,y)`` returns ``(d,u,v)``. +# Examples ```jldoctest julia> gcdx(12, 42) (6, -3, 1) -``` -```jldoctest julia> gcdx(240, 46) (2, -9, 47) ``` @@ -131,6 +133,7 @@ Take the inverse of `x` modulo `m`: `y` such that ``x y = 1 \\pmod m``, with ``div(x,y) = 0``. This is undefined for ``m = 0``, or if ``gcd(x,m) \\neq 1``. +# Examples ```jldoctest julia> invmod(2,5) 3 @@ -224,6 +227,24 @@ const HWNumber = Union{HWReal, Complex{<:HWReal}, Rational{<:HWReal}} powermod(x::Integer, p::Integer, m) Compute ``x^p \\pmod m``. + +# Examples +```jldoctest +julia> powermod(2, 6, 5) +4 + +julia> mod(2^6, 5) +4 + +julia> powermod(5, 2, 20) +5 + +julia> powermod(5, 2, 19) +6 + +julia> powermod(5, 3, 19) +11 +``` """ function powermod(x::Integer, p::Integer, m::T) where T<:Integer p < 0 && return powermod(invmod(x, m), -p, m) @@ -257,6 +278,7 @@ powermod(x::Integer, p::Integer, m::Union{Int128,UInt128}) = oftype(m, powermod( The smallest power of two not less than `n`. Returns 0 for `n==0`, and returns `-nextpow2(-n)` for negative arguments. +# Examples ```jldoctest julia> nextpow2(16) 16 @@ -274,9 +296,13 @@ nextpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -nextpow2(unsigned(-x)) : n The largest power of two not greater than `n`. Returns 0 for `n==0`, and returns `-prevpow2(-n)` for negative arguments. +# Examples ```jldoctest julia> prevpow2(5) 4 + +julia> prevpow2(0) +0 ``` """ prevpow2(x::Unsigned) = one(x) << unsigned((sizeof(x)<<3)-leading_zeros(x)-1) @@ -287,6 +313,7 @@ prevpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -prevpow2(unsigned(-x)) : p Test whether `n` is a power of two. +# Examples ```jldoctest julia> ispow2(4) true @@ -302,6 +329,23 @@ ispow2(x::Integer) = x > 0 && count_ones(x) == 1 The smallest `a^n` not less than `x`, where `n` is a non-negative integer. `a` must be greater than 1, and `x` must be greater than 0. + +# Examples +```jldoctest +julia> nextpow(2, 7) +8 + +julia> nextpow(2, 9) +16 + +julia> nextpow(5, 20) +25 + +julia> nextpow(4, 16) +16 +``` + +See also [`prevpow`](@ref). """ function nextpow(a::Real, x::Real) (a <= 1 || x <= 0) && throw(DomainError()) @@ -317,6 +361,22 @@ end The largest `a^n` not greater than `x`, where `n` is a non-negative integer. `a` must be greater than 1, and `x` must not be less than 1. + +# Examples +```jldoctest +julia> prevpow(2, 7) +4 + +julia> prevpow(2, 9) +8 + +julia> prevpow(5, 20) +5 + +julia> prevpow(4, 16) +16 +``` +See also [`nextpow`](@ref). """ function prevpow(a::Real, x::Real) (a <= 1 || x < 1) && throw(DomainError()) @@ -358,6 +418,7 @@ function ndigits0znb(n::Signed, b::Int) end function ndigits0z(n::Unsigned, b::Int) + n == 0 && return 0 b < 0 && return ndigits0znb(signed(n), b) b == 2 && return sizeof(n)<<3 - leading_zeros(n) b == 8 && return (sizeof(n)<<3 - leading_zeros(n) + 2) ÷ 3 @@ -386,10 +447,54 @@ ndigitsnb(x::Integer, b::Integer) = x==0 ? 1 : ndigits0znb(x, b) ndigits(x::Unsigned, b::Integer) = x==0 ? 1 : ndigits0z(x,Int(b)) ndigits(x::Unsigned) = x==0 ? 1 : ndigits0z(x) +# The suffix "0z" means that the output is 0 on input zero (cf. #16841) +""" + ndigits0z(n::Integer, b::Integer=10) + +Return 0 if `n == 0`, otherwise compute the number of digits in +integer `n` written in base `b` (i.e. equal to `ndigits(n, b)` +in this case). +The base `b` must not be in `[-1, 0, 1]`. + +# Examples +```jldoctest +julia> Base.ndigits0z(0, 16) +0 + +julia> Base.ndigits(0, 16) +1 + +julia> Base.ndigits0z(0) +0 + +julia> Base.ndigits0z(10, 2) +4 + +julia> Base.ndigits0z(10) +2 +``` + +See also [`ndigits`](@ref). +""" +ndigits0z + """ ndigits(n::Integer, b::Integer=10) Compute the number of digits in integer `n` written in base `b`. +The base `b` must not be in `[-1, 0, 1]`. + +# Examples +```jldoctest +julia> ndigits(12345) +5 + +julia> ndigits(1022, 16) +3 + +julia> base(16, 1022) +"3fe" +``` """ ndigits(x::Integer, b::Integer) = b >= 0 ? ndigits(unsigned(abs(x)),Int(b)) : ndigitsnb(x, b) ndigits(x::Integer) = ndigits(unsigned(abs(x))) @@ -511,21 +616,49 @@ bin """ hex(n, pad::Int=1) -Convert an integer to a hexadecimal string, optionally specifying a number of digits to pad to. +Convert an integer to a hexadecimal string, optionally specifying a number of +digits to pad to. + +```jldoctest +julia> hex(20) +"14" + +julia> hex(20, 3) +"014" +``` """ hex """ oct(n, pad::Int=1) -Convert an integer to an octal string, optionally specifying a number of digits to pad to. +Convert an integer to an octal string, optionally specifying a number of digits +to pad to. + +```jldoctest +julia> oct(20) +"24" + +julia> oct(20, 3) +"024" +``` """ oct """ dec(n, pad::Int=1) -Convert an integer to a decimal string, optionally specifying a number of digits to pad to. +Convert an integer to a decimal string, optionally specifying a number of digits +to pad to. + +# Examples +```jldoctest +julia> dec(20) +"20" + +julia> dec(20, 3) +"020" +``` """ dec @@ -541,6 +674,30 @@ bits(x::Union{Int128,UInt128}) = bin(reinterpret(UInt128,x),128) Returns an array with element type `T` (default `Int`) of the digits of `n` in the given base, optionally padded with zeros to a specified size. More significant digits are at higher indexes, such that `n == sum([digits[k]*base^(k-1) for k=1:length(digits)])`. + +# Examples +```jldoctest +julia> digits(10, 10) +2-element Array{Int64,1}: + 0 + 1 + +julia> digits(10, 2) +4-element Array{Int64,1}: + 0 + 1 + 0 + 1 + +julia> digits(10, 2, 6) +6-element Array{Int64,1}: + 0 + 1 + 0 + 1 + 0 + 0 +``` """ digits(n::Integer, base::T=10, pad::Integer=1) where {T<:Integer} = digits(T, n, base, pad) @@ -555,6 +712,25 @@ end Fills an array of the digits of `n` in the given base. More significant digits are at higher indexes. If the array length is insufficient, the least significant digits are filled up to the array length. If the array length is excessive, the excess portion is filled with zeros. + +# Examples +```jldoctest +julia> digits!([2,2,2,2], 10, 2) +4-element Array{Int64,1}: + 0 + 1 + 0 + 1 + +julia> digits!([2,2,2,2,2,2], 10, 2) +6-element Array{Int64,1}: + 0 + 1 + 0 + 1 + 0 + 0 +``` """ function digits!(a::AbstractArray{T,1}, n::Integer, base::Integer=10) where T<:Integer 2 <= base || throw(ArgumentError("base must be ≥ 2, got $base")) @@ -598,9 +774,18 @@ function factorial(n::Integer) end """ - binomial(n,k) + binomial(n, k) Number of ways to choose `k` out of `n` items. + +# Example +```jldoctest +julia> binomial(5, 3) +10 + +julia> factorial(5) ÷ (factorial(5-3) * factorial(3)) +10 +``` """ function binomial(n::T, k::T) where T<:Integer k < 0 && return zero(T) diff --git a/base/intset.jl b/base/intset.jl index 13b9fce6325d9..1e45f8076c903 100644 --- a/base/intset.jl +++ b/base/intset.jl @@ -140,7 +140,7 @@ symdiff!(s::IntSet, ns) = (for n in ns; symdiff!(s, n); end; s) The set `s` is destructively modified to toggle the inclusion of integer `n`. """ function symdiff!(s::IntSet, n::Integer) - 0 <= n < typemax(Int) || _throw_intset_bounds_err() + 0 < n < typemax(Int) || _throw_intset_bounds_err() val = !(n in s) _setint!(s, n, val) s diff --git a/base/iobuffer.jl b/base/iobuffer.jl index c9d4226462dac..6441461b43383 100644 --- a/base/iobuffer.jl +++ b/base/iobuffer.jl @@ -36,8 +36,8 @@ StringVector(n::Integer) = Vector{UInt8}(_string_n(n)) Create an `IOBuffer`, which may optionally operate on a pre-existing array. If the readable/writable arguments are given, they restrict whether or not the buffer may be read -from or written to respectively. By default the buffer is readable but not writable. The -last argument optionally specifies a size beyond which the buffer may not be grown. +from or written to respectively. The last argument optionally specifies a size beyond which +the buffer may not be grown. """ IOBuffer(data::AbstractVector{UInt8}, readable::Bool=true, writable::Bool=false, maxsize::Int=typemax(Int)) = AbstractIOBuffer(data, readable, writable, true, false, maxsize) diff --git a/base/iterators.jl b/base/iterators.jl index 1c2ab13f8e113..ef4e7acf66f66 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -43,6 +43,8 @@ for indexing `iter`; it's also possible that `x != iter[i]`, if `iter` has indices that do not start at 1. See the `enumerate(IndexLinear(), iter)` method if you want to ensure that `i` is an index. +# Example + ```jldoctest julia> a = ["a", "b", "c"]; @@ -90,6 +92,8 @@ specifying `IndexCartesian()` ensures that `i` will be a `CartesianIndex`; specifying `IndexStyle(A)` chooses whichever has been defined as the native indexing style for array `A`. +# Examples + ```jldoctest julia> A = ["a" "d"; "b" "e"; "c" "f"]; @@ -202,6 +206,8 @@ the `i`th component of each input iterable. Note that [`zip`](@ref) is its own inverse: `collect(zip(zip(a...)...)) == collect(a)`. +# Example + ```jldoctest julia> a = 1:5 1:5 @@ -357,6 +363,8 @@ end An iterator that generates at most the first `n` elements of `iter`. +# Example + ```jldoctest julia> a = 1:2:11 1:2:11 @@ -412,6 +420,8 @@ end An iterator that generates all but the first `n` elements of `iter`. +# Example + ```jldoctest julia> a = 1:2:11 1:2:11 @@ -505,6 +515,8 @@ repeated(x) = Repeated(x) An iterator that generates the value `x` forever. If `n` is specified, generates `x` that many times (equivalent to `take(repeated(x), n)`). +# Example + ```jldoctest julia> a = Iterators.repeated([1 2], 4); @@ -594,6 +606,8 @@ Returns an iterator over the product of several iterators. Each generated elemen a tuple whose `i`th element comes from the `i`th argument iterator. The first iterator changes the fastest. Example: +# Example + ```jldoctest julia> collect(Iterators.product(1:2,3:5)) 2×3 Array{Tuple{Int64,Int64},2}: @@ -669,7 +683,9 @@ end Given an iterator that yields iterators, return an iterator that yields the elements of those iterators. -Put differently, the elements of the argument iterator are concatenated. Example: +Put differently, the elements of the argument iterator are concatenated. + +# Example ```jldoctest julia> collect(Iterators.flatten((1:2, 8:9))) @@ -724,6 +740,8 @@ end Iterate over a collection `n` elements at a time. +# Example + ```jldoctest julia> collect(Iterators.partition([1,2,3,4,5], 2)) 3-element Array{Array{Int64,1},1}: diff --git a/base/libdl.jl b/base/libdl.jl index 439b10bb40410..c15ab2a4ffec6 100644 --- a/base/libdl.jl +++ b/base/libdl.jl @@ -221,7 +221,7 @@ if is_bsd() && !is_apple() phnum::Cshort end - function dl_phdr_info_callback(di::dl_phdr_info, size::Csize_t, dy_libs::Array{AbstractString,1}) + function dl_phdr_info_callback(di::dl_phdr_info, size::Csize_t, dy_libs::Vector{AbstractString}) name = unsafe_string(di.name) if !isempty(name) push!(dy_libs, name) @@ -235,8 +235,8 @@ function dllist() @static if is_linux() const callback = cfunction(dl_phdr_info_callback, Cint, - (Ref{dl_phdr_info}, Csize_t, Ref{Array{AbstractString,1}} )) - ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Array{AbstractString,1}}), callback, dynamic_libraries) + Tuple{Ref{dl_phdr_info}, Csize_t, Ref{Vector{AbstractString}}}) + ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Vector{AbstractString}}), callback, dynamic_libraries) end @static if is_apple() @@ -255,8 +255,8 @@ function dllist() @static if is_bsd() && !is_apple() const callback = cfunction(dl_phdr_info_callback, Cint, - (Ref{dl_phdr_info}, Csize_t, Ref{Array{AbstractString,1}} )) - ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Array{AbstractString,1}}), callback, dynamic_libraries) + Tuple{Ref{dl_phdr_info}, Csize_t, Ref{Vector{AbstractString}}}) + ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Vector{AbstractString}}), callback, dynamic_libraries) shift!(dynamic_libraries) end diff --git a/base/libgit2/callbacks.jl b/base/libgit2/callbacks.jl index 0a78f48949f47..639a874121bd2 100644 --- a/base/libgit2/callbacks.jl +++ b/base/libgit2/callbacks.jl @@ -258,8 +258,8 @@ function fetchhead_foreach_callback(ref_name::Cstring, remote_url::Cstring, end "C function pointer for `mirror_callback`" -mirror_cb() = cfunction(mirror_callback, Cint, (Ptr{Ptr{Void}}, Ptr{Void}, Cstring, Cstring, Ptr{Void})) +mirror_cb() = cfunction(mirror_callback, Cint, Tuple{Ptr{Ptr{Void}}, Ptr{Void}, Cstring, Cstring, Ptr{Void}}) "C function pointer for `credentials_callback`" -credentials_cb() = cfunction(credentials_callback, Cint, (Ptr{Ptr{Void}}, Cstring, Cstring, Cuint, Ptr{Void})) +credentials_cb() = cfunction(credentials_callback, Cint, Tuple{Ptr{Ptr{Void}}, Cstring, Cstring, Cuint, Ptr{Void}}) "C function pointer for `fetchhead_foreach_callback`" -fetchhead_foreach_cb() = cfunction(fetchhead_foreach_callback, Cint, (Cstring, Cstring, Ptr{GitHash}, Cuint, Ptr{Void})) +fetchhead_foreach_cb() = cfunction(fetchhead_foreach_callback, Cint, Tuple{Cstring, Cstring, Ptr{GitHash}, Cuint, Ptr{Void}}) diff --git a/base/libgit2/tree.jl b/base/libgit2/tree.jl index 3f9162f3823b9..60da6a821f0be 100644 --- a/base/libgit2/tree.jl +++ b/base/libgit2/tree.jl @@ -8,7 +8,7 @@ Function parameter should have following signature: (Cstring, Ptr{Void}, Ptr{Void}) -> Cint """ function treewalk(f::Function, tree::GitTree, payload=Any[], post::Bool = false) - cbf = cfunction(f, Cint, (Cstring, Ptr{Void}, Ptr{Void})) + cbf = cfunction(f, Cint, Tuple{Cstring, Ptr{Void}, Ptr{Void}}) cbf_payload = Ref{typeof(payload)}(payload) @check ccall((:git_tree_walk, :libgit2), Cint, (Ptr{Void}, Cint, Ptr{Void}, Ptr{Void}), diff --git a/base/libuv.jl b/base/libuv.jl index 702fad7392081..63894de44b087 100644 --- a/base/libuv.jl +++ b/base/libuv.jl @@ -86,17 +86,17 @@ function process_events(block::Bool) end function reinit_stdio() - global uv_jl_alloc_buf = cfunction(uv_alloc_buf, Void, (Ptr{Void}, Csize_t, Ptr{Void})) - global uv_jl_readcb = cfunction(uv_readcb, Void, (Ptr{Void}, Cssize_t, Ptr{Void})) - global uv_jl_connectioncb = cfunction(uv_connectioncb, Void, (Ptr{Void}, Cint)) - global uv_jl_connectcb = cfunction(uv_connectcb, Void, (Ptr{Void}, Cint)) - global uv_jl_writecb_task = cfunction(uv_writecb_task, Void, (Ptr{Void}, Cint)) - global uv_jl_getaddrinfocb = cfunction(uv_getaddrinfocb, Void, (Ptr{Void},Cint,Ptr{Void})) - global uv_jl_recvcb = cfunction(uv_recvcb, Void, (Ptr{Void}, Cssize_t, Ptr{Void}, Ptr{Void}, Cuint)) - global uv_jl_sendcb = cfunction(uv_sendcb, Void, (Ptr{Void}, Cint)) - global uv_jl_return_spawn = cfunction(uv_return_spawn, Void, (Ptr{Void}, Int64, Int32)) - global uv_jl_asynccb = cfunction(uv_asynccb, Void, (Ptr{Void},)) - global uv_jl_timercb = cfunction(uv_timercb, Void, (Ptr{Void},)) + global uv_jl_alloc_buf = cfunction(uv_alloc_buf, Void, Tuple{Ptr{Void}, Csize_t, Ptr{Void}}) + global uv_jl_readcb = cfunction(uv_readcb, Void, Tuple{Ptr{Void}, Cssize_t, Ptr{Void}}) + global uv_jl_connectioncb = cfunction(uv_connectioncb, Void, Tuple{Ptr{Void}, Cint}) + global uv_jl_connectcb = cfunction(uv_connectcb, Void, Tuple{Ptr{Void}, Cint}) + global uv_jl_writecb_task = cfunction(uv_writecb_task, Void, Tuple{Ptr{Void}, Cint}) + global uv_jl_getaddrinfocb = cfunction(uv_getaddrinfocb, Void, Tuple{Ptr{Void}, Cint, Ptr{Void}}) + global uv_jl_recvcb = cfunction(uv_recvcb, Void, Tuple{Ptr{Void}, Cssize_t, Ptr{Void}, Ptr{Void}, Cuint}) + global uv_jl_sendcb = cfunction(uv_sendcb, Void, Tuple{Ptr{Void}, Cint}) + global uv_jl_return_spawn = cfunction(uv_return_spawn, Void, Tuple{Ptr{Void}, Int64, Int32}) + global uv_jl_asynccb = cfunction(uv_asynccb, Void, Tuple{Ptr{Void}}) + global uv_jl_timercb = cfunction(uv_timercb, Void, Tuple{Ptr{Void}}) global uv_eventloop = ccall(:jl_global_event_loop, Ptr{Void}, ()) global STDIN = init_stdio(ccall(:jl_stdin_stream, Ptr{Void}, ())) diff --git a/base/linalg/cholesky.jl b/base/linalg/cholesky.jl index 5ba08622ded9c..4629fb9341aec 100644 --- a/base/linalg/cholesky.jl +++ b/base/linalg/cholesky.jl @@ -160,7 +160,7 @@ end chol(A) -> U Compute the Cholesky factorization of a positive definite matrix `A` -and return the UpperTriangular matrix `U` such that `A = U'U`. +and return the [`UpperTriangular`](@ref) matrix `U` such that `A = U'U`. # Example diff --git a/base/linalg/diagonal.jl b/base/linalg/diagonal.jl index a94414d2c3ddb..def3471397f94 100644 --- a/base/linalg/diagonal.jl +++ b/base/linalg/diagonal.jl @@ -150,9 +150,9 @@ end (*)(D::Diagonal, B::AbstractTriangular) = A_mul_B!(D, copy(B)) (*)(A::AbstractMatrix, D::Diagonal) = - scale!(similar(A, promote_op(*, eltype(A), eltype(D.diag))), A, D.diag) + scale!(similar(A, promote_op(*, eltype(A), eltype(D.diag)), size(A)), A, D.diag) (*)(D::Diagonal, A::AbstractMatrix) = - scale!(similar(A, promote_op(*, eltype(A), eltype(D.diag))), D.diag, A) + scale!(similar(A, promote_op(*, eltype(A), eltype(D.diag)), size(A)), D.diag, A) A_mul_B!(A::Union{LowerTriangular,UpperTriangular}, D::Diagonal) = typeof(A)(A_mul_B!(A.data, D)) diff --git a/base/linalg/generic.jl b/base/linalg/generic.jl index 6f44208621bd4..01af43e527ecf 100644 --- a/base/linalg/generic.jl +++ b/base/linalg/generic.jl @@ -702,6 +702,21 @@ values of `M` have magnitude greater than `tol`. By default, the value of `tol` is the largest dimension of `M` multiplied by the [`eps`](@ref) of the [`eltype`](@ref) of `M`. + +# Example +```jldoctest +julia> rank(eye(3)) +3 + +julia> rank(diagm([1, 0, 2])) +2 + +julia> rank(diagm([1, 0.001, 2]), 0.1) +2 + +julia> rank(diagm([1, 0.001, 2]), 0.00001) +3 +``` """ rank(A::AbstractMatrix, tol::Real) = mapreduce(x -> x > tol, +, 0, svdvals(A)) function rank(A::AbstractMatrix) @@ -834,13 +849,15 @@ condskeel(A::AbstractMatrix, p::Real=Inf) = norm(abs.(inv(A))*abs.(A), p) condskeel(M, [x, p::Real=Inf]) ```math -\\kappa_S(M, p) & = \\left\\Vert \\left\\vert M \\right\\vert \\left\\vert M^{-1} \\right\\vert \\right\\Vert_p \\\\ -\\kappa_S(M, x, p) & = \\left\\Vert \\left\\vert M \\right\\vert \\left\\vert M^{-1} \\right\\vert \\left\\vert x \\right\\vert \\right\\Vert_p +\\kappa_S(M, p) = \\left\\Vert \\left\\vert M \\right\\vert \\left\\vert M^{-1} \\right\\vert \\right\\Vert_p \\\\ +\\kappa_S(M, x, p) = \\left\\Vert \\left\\vert M \\right\\vert \\left\\vert M^{-1} \\right\\vert \\left\\vert x \\right\\vert \\right\\Vert_p ``` Skeel condition number ``\\kappa_S`` of the matrix `M`, optionally with respect to the -vector `x`, as computed using the operator `p`-norm. -`p` is `Inf` by default, if not provided. Valid values for `p` are `1`, `2`, or `Inf`. +vector `x`, as computed using the operator `p`-norm. ``\\left\\vert M \\right\\vert`` +denotes the matrix of (entry wise) absolute values of ``M``; +``\\left\\vert M \\right\\vert_{ij} = \\left\\vert M_{ij} \\right\\vert``. +Valid values for `p` are `1`, `2` and `Inf` (default). This quantity is also known in the literature as the Bauer condition number, relative condition number, or componentwise relative condition number. @@ -852,7 +869,7 @@ condskeel(A::AbstractMatrix, x::AbstractVector, p::Real=Inf) = norm(abs.(inv(A)) Test whether a matrix is symmetric. -# Example +# Examples ```jldoctest julia> a = [1 2; 2 -1] @@ -892,7 +909,7 @@ issymmetric(x::Number) = x == x Test whether a matrix is Hermitian. -# Example +# Examples ```jldoctest julia> a = [1 2; 2 -1] @@ -932,7 +949,7 @@ ishermitian(x::Number) = (x == conj(x)) Test whether a matrix is upper triangular. -# Example +# Examples ```jldoctest julia> a = [1 2; 2 -1] @@ -967,7 +984,7 @@ end Test whether a matrix is lower triangular. -# Example +# Examples ```jldoctest julia> a = [1 2; 2 -1] @@ -1002,7 +1019,7 @@ end Test whether a matrix is diagonal. -# Example +# Examples ```jldoctest julia> a = [1 2; 2 -1] @@ -1224,7 +1241,7 @@ logabsdet(A::AbstractMatrix) = logabsdet(lufact(A)) Log of matrix determinant. Equivalent to `log(det(M))`, but may provide increased accuracy and/or speed. -# Example +# Examples ```jldoctest julia> M = [1 0; 2 2] @@ -1322,7 +1339,7 @@ Normalize the vector `v` so that its `p`-norm equals unity, i.e. `norm(v, p) == vecnorm(v, p) == 1`. See also [`normalize!`](@ref) and [`vecnorm`](@ref). -# Example +# Examples ```jldoctest julia> a = [1,2,4]; diff --git a/base/linalg/lapack.jl b/base/linalg/lapack.jl index 14d8f76df34ae..9810ad17bf054 100644 --- a/base/linalg/lapack.jl +++ b/base/linalg/lapack.jl @@ -5479,13 +5479,13 @@ for (gees, gges, elty) in # $ WR( * ) function gees!(jobvs::Char, A::StridedMatrix{$elty}) chkstride1(A) - n = checksquare(A) - sdim = Vector{BlasInt}(1) - wr = similar(A, $elty, n) - wi = similar(A, $elty, n) - ldvs = jobvs == 'V' ? n : 1 - vs = similar(A, $elty, ldvs, n) - work = Vector{$elty}(1) + n = checksquare(A) + sdim = Vector{BlasInt}(1) + wr = similar(A, $elty, n) + wi = similar(A, $elty, n) + vs = similar(A, $elty, jobvs == 'V' ? n : 0, n) + ldvs = max(size(vs, 1), 1) + work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 @@ -5572,13 +5572,13 @@ for (gees, gges, elty, relty) in # COMPLEX*16 A( LDA, * ), VS( LDVS, * ), W( * ), WORK( * ) function gees!(jobvs::Char, A::StridedMatrix{$elty}) chkstride1(A) - n = checksquare(A) - sort = 'N' - sdim = BlasInt(0) - w = similar(A, $elty, n) - ldvs = jobvs == 'V' ? n : 1 - vs = similar(A, $elty, ldvs, n) - work = Vector{$elty}(1) + n = checksquare(A) + sort = 'N' + sdim = BlasInt(0) + w = similar(A, $elty, n) + vs = similar(A, $elty, jobvs == 'V' ? n : 1, n) + ldvs = max(size(vs, 1), 1) + work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(n) info = Ref{BlasInt}() diff --git a/base/linalg/qr.jl b/base/linalg/qr.jl index 13aa153575f1e..1e5941b60a1d6 100644 --- a/base/linalg/qr.jl +++ b/base/linalg/qr.jl @@ -694,9 +694,13 @@ function A_ldiv_B!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where T<:B mA, nA = size(A.factors) nr = min(mA,nA) nrhs = size(B, 2) - if nr == 0 return zeros(T, 0, nrhs), 0 end + if nr == 0 + return zeros(T, 0, nrhs), 0 + end ar = abs(A.factors[1]) - if ar == 0 return zeros(T, nr, nrhs), 0 end + if ar == 0 + return zeros(T, nA, nrhs), 0 + end rnk = 1 xmin = ones(T, 1) xmax = ones(T, 1) diff --git a/base/linalg/svd.jl b/base/linalg/svd.jl index 639d528a1b812..94b14247665e8 100644 --- a/base/linalg/svd.jl +++ b/base/linalg/svd.jl @@ -27,7 +27,7 @@ function svdfact!(A::StridedMatrix{T}; thin::Bool=true) where T<:BlasFloat end """ - svdfact(A, thin::Bool=true) -> SVD + svdfact(A; thin::Bool=true) -> SVD Compute the singular value decomposition (SVD) of `A` and return an `SVD` object. @@ -68,7 +68,7 @@ svdfact(x::Number; thin::Bool=true) = SVD(x == 0 ? fill(one(x), 1, 1) : fill(x/a svdfact(x::Integer; thin::Bool=true) = svdfact(float(x), thin=thin) """ - svd(A, thin::Bool=true) -> U, S, V + svd(A; thin::Bool=true) -> U, S, V Computes the SVD of `A`, returning `U`, vector `S`, and `V` such that `A == U*diagm(S)*V'`. The singular values in `S` are sorted in descending order. diff --git a/base/linalg/symmetric.jl b/base/linalg/symmetric.jl index 6d9c865edca32..c101d6ae65763 100644 --- a/base/linalg/symmetric.jl +++ b/base/linalg/symmetric.jl @@ -8,7 +8,8 @@ end """ Symmetric(A, uplo=:U) -Construct a `Symmetric` matrix from the upper (if `uplo = :U`) or lower (if `uplo = :L`) triangle of `A`. +Construct a `Symmetric` view of the upper (if `uplo = :U`) or lower (if `uplo = :L`) +triangle of the matrix `A`. # Example @@ -57,7 +58,8 @@ end """ Hermitian(A, uplo=:U) -Construct a `Hermitian` matrix from the upper (if `uplo = :U`) or lower (if `uplo = :L`) triangle of `A`. +Construct a `Hermitian` view of the upper (if `uplo = :U`) or lower (if `uplo = :L`) +triangle of the matrix `A`. # Example @@ -448,6 +450,8 @@ eigvals!(A::HermOrSym{T,S}, B::HermOrSym{T,S}) where {T<:BlasReal,S<:StridedMatr eigvals!(A::Hermitian{T,S}, B::Hermitian{T,S}) where {T<:BlasComplex,S<:StridedMatrix} = LAPACK.sygvd!(1, 'N', A.uplo, A.data, B.uplo == A.uplo ? B.data : B.data')[1] +eigvecs(A::HermOrSym) = eigvecs(eigfact(A)) + function svdvals!(A::RealHermSymComplexHerm) vals = eigvals!(A) for i = 1:length(vals) diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index a9935851177cc..8c95da6f19839 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -50,6 +50,51 @@ LowerTriangular(U::UpperTriangular) = throw(ArgumentError( UpperTriangular(U::LowerTriangular) = throw(ArgumentError( "cannot create an UpperTriangular matrix from a LowerTriangular input")) +""" + LowerTriangular(A::AbstractMatrix) + +Construct a `LowerTriangular` view of the the matrix `A`. + +# Example + +```jldoctest +julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0] +3×3 Array{Float64,2}: + 1.0 2.0 3.0 + 4.0 5.0 6.0 + 7.0 8.0 9.0 + +julia> LowerTriangular(A) +3×3 LowerTriangular{Float64,Array{Float64,2}}: + 1.0 ⋅ ⋅ + 4.0 5.0 ⋅ + 7.0 8.0 9.0 +``` +""" +LowerTriangular +""" + UpperTriangular(A::AbstractMatrix) + +Construct an `UpperTriangular` view of the the matrix `A`. + +# Example + +```jldoctest +julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0] +3×3 Array{Float64,2}: + 1.0 2.0 3.0 + 4.0 5.0 6.0 + 7.0 8.0 9.0 + +julia> UpperTriangular(A) +3×3 UpperTriangular{Float64,Array{Float64,2}}: + 1.0 2.0 3.0 + ⋅ 5.0 6.0 + ⋅ ⋅ 9.0 +``` +""" +UpperTriangular + imag(A::UpperTriangular) = UpperTriangular(imag(A.data)) imag(A::LowerTriangular) = LowerTriangular(imag(A.data)) imag(A::UnitLowerTriangular) = LowerTriangular(tril!(imag(A.data),-1)) diff --git a/base/loading.jl b/base/loading.jl index a09f605aa3bce..113b4e583ead4 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -269,10 +269,17 @@ const _require_dependencies = Any[] # a list of (path, mtime) tuples that are th const _track_dependencies = Ref(false) # set this to true to track the list of file dependencies function _include_dependency(_path::AbstractString) prev = source_path(nothing) - path = (prev === nothing) ? abspath(_path) : joinpath(dirname(prev), _path) + if prev === nothing + if myid() == 1 + path = abspath(_path) + else + path = joinpath(remotecall_fetch(abspath, 1, "."), _path) + end + else + path = joinpath(dirname(prev), _path) + end if myid() == 1 && _track_dependencies[] - apath = abspath(path) - push!(_require_dependencies, (apath, mtime(apath))) + push!(_require_dependencies, (path, mtime(path))) end return path, prev end diff --git a/base/methodshow.jl b/base/methodshow.jl index c9f304a509c9e..9db69228b0cae 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -97,15 +97,16 @@ end function show(io::IO, m::Method; kwtype::Nullable{DataType}=Nullable{DataType}()) tv, decls, file, line = arg_decl_parts(m) sig = unwrap_unionall(m.sig) - ft = unwrap_unionall(sig.parameters[1]) + ft0 = sig.parameters[1] + ft = unwrap_unionall(ft0) d1 = decls[1] if sig === Tuple print(io, m.name) decls = Any[(), ("...", "")] - elseif ft <: Function && + elseif ft <: Function && isa(ft, DataType) && isdefined(ft.name.module, ft.name.mt.name) && # TODO: more accurate test? (tn.name === "#" name) - ft == typeof(getfield(ft.name.module, ft.name.mt.name)) + ft0 === typeof(getfield(ft.name.module, ft.name.mt.name)) print(io, ft.name.mt.name) elseif isa(ft, DataType) && ft.name === Type.body.name && isleaftype(ft) f = ft.parameters[1] @@ -222,11 +223,12 @@ end function show(io::IO, ::MIME"text/html", m::Method; kwtype::Nullable{DataType}=Nullable{DataType}()) tv, decls, file, line = arg_decl_parts(m) sig = unwrap_unionall(m.sig) - ft = sig.parameters[1] + ft0 = sig.parameters[1] + ft = unwrap_unionall(ft0) d1 = decls[1] - if ft <: Function && + if ft <: Function && isa(ft, DataType) && isdefined(ft.name.module, ft.name.mt.name) && - ft == typeof(getfield(ft.name.module, ft.name.mt.name)) + ft0 === typeof(getfield(ft.name.module, ft.name.mt.name)) print(io, ft.name.mt.name) elseif isa(ft, DataType) && ft.name === Type.body.name && isleaftype(ft) f = ft.parameters[1] diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 6659185b5f273..bb9bdafb519ef 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -27,6 +27,37 @@ module IteratorsMD A `CartesianIndex` is sometimes produced by [`eachindex`](@ref), and always when iterating with an explicit [`CartesianRange`](@ref). + + # Example + + ```jldoctest + julia> A = reshape(collect(1:16), (2, 2, 2, 2)) + 2×2×2×2 Array{Int64,4}: + [:, :, 1, 1] = + 1 3 + 2 4 + + [:, :, 2, 1] = + 5 7 + 6 8 + + [:, :, 1, 2] = + 9 11 + 10 12 + + [:, :, 2, 2] = + 13 15 + 14 16 + + julia> A[CartesianIndex((1, 1, 1, 1))] + 1 + + julia> A[CartesianIndex((1, 1, 1, 2))] + 9 + + julia> A[CartesianIndex((1, 1, 2, 1))] + 5 + ``` """ struct CartesianIndex{N} <: AbstractCartesianIndex{N} I::NTuple{N,Int} @@ -92,6 +123,16 @@ module IteratorsMD _isless(ret, ::Tuple{}, ::Tuple{}) = ifelse(ret==1, true, false) icmp(a, b) = ifelse(isless(a,b), 1, ifelse(a==b, 0, -1)) + # hashing + const cartindexhash_seed = UInt == UInt64 ? 0xd60ca92f8284b8b0 : 0xf2ea7c2e + function Base.hash(ci::CartesianIndex, h::UInt) + h += cartindexhash_seed + for i in ci.I + h = hash(i, h) + end + return h + end + # Iteration """ CartesianRange(Istart::CartesianIndex, Istop::CartesianIndex) -> R @@ -111,6 +152,18 @@ module IteratorsMD Consequently these can be useful for writing algorithms that work in arbitrary dimensions. + + ```jldoctest + julia> foreach(println, CartesianRange((2, 2, 2))) + CartesianIndex{3}((1, 1, 1)) + CartesianIndex{3}((2, 1, 1)) + CartesianIndex{3}((1, 2, 1)) + CartesianIndex{3}((2, 2, 1)) + CartesianIndex{3}((1, 1, 2)) + CartesianIndex{3}((2, 1, 2)) + CartesianIndex{3}((1, 2, 2)) + CartesianIndex{3}((2, 2, 2)) + ``` """ struct CartesianRange{I<:CartesianIndex} start::I @@ -850,7 +903,7 @@ Circularly shift the data in `src`, storing the result in The `dest` array must be distinct from the `src` array (they cannot alias each other). -See also `circshift`. +See also [`circshift`](@ref). """ @noinline function circshift!(dest::AbstractArray{T,N}, src, shiftamt::DimsInteger) where {T,N} dest === src && throw(ArgumentError("dest and src must be separate arrays")) @@ -903,6 +956,7 @@ their indices; any offset results in a (circular) wraparound. If the arrays have overlapping indices, then on the domain of the overlap `dest` agrees with `src`. +# Example ```julia-repl julia> src = reshape(collect(1:16), (4,4)) 4×4 Array{Int64,2}: @@ -1440,26 +1494,23 @@ function extrema(A::AbstractArray, dims) return extrema!(B, A) end -@generated function extrema!(B, A::AbstractArray{T,N}) where {T,N} - return quote - sA = size(A) - sB = size(B) - @nloops $N i B begin - AI = @nref $N A i - (@nref $N B i) = (AI, AI) - end - Bmax = sB - Istart = Int[sB[i] == 1 != sA[i] ? 2 : 1 for i = 1:ndims(A)] - @inbounds @nloops $N i d->(Istart[d]:size(A,d)) begin - AI = @nref $N A i - @nexprs $N d->(j_d = min(Bmax[d], i_{d})) - BJ = @nref $N B j - if AI < BJ[1] - (@nref $N B j) = (AI, BJ[2]) - elseif AI > BJ[2] - (@nref $N B j) = (BJ[1], AI) - end +@noinline function extrema!(B, A) + sA = size(A) + sB = size(B) + for I in CartesianRange(sB) + AI = A[I] + B[I] = (AI, AI) + end + Bmax = CartesianIndex(sB) + @inbounds @simd for I in CartesianRange(sA) + J = min(Bmax,I) + BJ = B[J] + AI = A[I] + if AI < BJ[1] + B[J] = (AI, BJ[2]) + elseif AI > BJ[2] + B[J] = (BJ[1], AI) end - return B end + return B end diff --git a/base/number.jl b/base/number.jl index c7f2286465629..75abda083a87c 100644 --- a/base/number.jl +++ b/base/number.jl @@ -85,6 +85,11 @@ abs(x::Real) = ifelse(signbit(x), -x, x) abs2(x) Squared absolute value of `x`. + +```jldoctest +julia> abs2(-3) +9 +``` """ abs2(x::Real) = x*x @@ -92,6 +97,14 @@ abs2(x::Real) = x*x flipsign(x, y) Return `x` with its sign flipped if `y` is negative. For example `abs(x) = flipsign(x,x)`. + +```jldoctest +julia> flipsign(5, 3) +5 + +julia> flipsign(5, -3) +-5 +``` """ flipsign(x::Real, y::Real) = ifelse(signbit(y), -x, x) copysign(x::Real, y::Real) = ifelse(signbit(x)!=signbit(y), -x, x) @@ -126,6 +139,19 @@ map(f, x::Number, ys::Number...) = f(x, ys...) zero(x) Get the additive identity element for the type of `x` (`x` can also specify the type itself). + +```jldoctest +julia> zero(1) +0 + +julia> zero(big"2.0") +0.000000000000000000000000000000000000000000000000000000000000000000000000000000 + +julia> zero(rand(2,2)) +2×2 Array{Float64,2}: + 0.0 0.0 + 0.0 0.0 +``` """ zero(x::Number) = oftype(x,0) zero(::Type{T}) where {T<:Number} = convert(T,0) diff --git a/base/path.jl b/base/path.jl index 28ac0b520e85d..940ae4cd2d6e0 100644 --- a/base/path.jl +++ b/base/path.jl @@ -68,7 +68,7 @@ function homedir() if rc == 0 resize!(buf, sz[]) return String(buf) - elseif rc == UV_ENOBUFS + elseif rc == Base.UV_ENOBUFS resize!(buf, sz[] - 1) else error("unable to retrieve home directory") diff --git a/base/permuteddimsarray.jl b/base/permuteddimsarray.jl index c51b8cb34caff..fee5d3af0b66b 100644 --- a/base/permuteddimsarray.jl +++ b/base/permuteddimsarray.jl @@ -89,6 +89,7 @@ equivalent to `permutedims(A, [2,1])`. See also: [`PermutedDimsArray`](@ref). +# Example ```jldoctest julia> A = reshape(collect(1:8), (2,2,2)) 2×2×2 Array{Int64,3}: @@ -124,6 +125,8 @@ vector specifying a permutation of length `ndims(src)`. The preallocated array ` have `size(dest) == size(src)[perm]` and is completely overwritten. No in-place permutation is supported and unexpected results will happen if `src` and `dest` have overlapping memory regions. + +See also [`permutedims`](@ref). """ function Base.permutedims!(dest, src::AbstractArray, perm) Base.checkdims_perm(dest, src, perm) diff --git a/base/pkg/entry.jl b/base/pkg/entry.jl index 82bb1f5ab2fb9..bbf93962a8b9d 100644 --- a/base/pkg/entry.jl +++ b/base/pkg/entry.jl @@ -613,7 +613,7 @@ function build(pkg::AbstractString, build_file::AbstractString, errfile::Abstrac --eval $code ``` - success(pipeline(cmd, stderr=STDERR)) + success(pipeline(cmd, stdout=STDOUT, stderr=STDERR)) end function build!(pkgs::Vector, seen::Set, errfile::AbstractString) diff --git a/base/pkg/pkg.jl b/base/pkg/pkg.jl index 7d60ec9e6ce9d..2614c8d3d3939 100644 --- a/base/pkg/pkg.jl +++ b/base/pkg/pkg.jl @@ -225,7 +225,7 @@ optimal set of packages versions. Without arguments, updates all installed packages. When one or more package names are provided as arguments, only those packages and their dependencies are updated. """ -update(upkgs::AbstractString...) = cd(Entry.update,Dir.getmetabranch(),Set{String}([upkgs...])) +update(upkgs::AbstractString...) = cd(Entry.update,Dir.getmetabranch(),Set{String}(splitjl.([upkgs...]))) """ resolve() diff --git a/base/poll.jl b/base/poll.jl index a670a10f0a979..af6b40fad375c 100644 --- a/base/poll.jl +++ b/base/poll.jl @@ -263,9 +263,9 @@ function _uv_hook_close(uv::FileMonitor) end function __init__() - global uv_jl_pollcb = cfunction(uv_pollcb, Void, (Ptr{Void}, Cint, Cint)) - global uv_jl_fspollcb = cfunction(uv_fspollcb, Void, (Ptr{Void}, Cint, Ptr{Void}, Ptr{Void})) - global uv_jl_fseventscb = cfunction(uv_fseventscb, Void, (Ptr{Void}, Ptr{Int8}, Int32, Int32)) + global uv_jl_pollcb = cfunction(uv_pollcb, Void, Tuple{Ptr{Void}, Cint, Cint}) + global uv_jl_fspollcb = cfunction(uv_fspollcb, Void, Tuple{Ptr{Void}, Cint, Ptr{Void}, Ptr{Void}}) + global uv_jl_fseventscb = cfunction(uv_fseventscb, Void, Tuple{Ptr{Void}, Ptr{Int8}, Int32, Int32}) end function uv_fseventscb(handle::Ptr{Void}, filename::Ptr, events::Int32, status::Int32) diff --git a/base/precompile.jl b/base/precompile.jl index 8bc84db37f499..a604830733728 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -822,9 +822,8 @@ precompile(Tuple{getfield(Base.Cartesian, Symbol("#@nexprs")), Int64, Expr}) precompile(Tuple{typeof(Base.Cartesian._nexprs), Int64, Expr}) precompile(Tuple{typeof(Core.Inference.findnext), Array{Function, 1}, typeof(===), Int64}) precompile(Tuple{typeof(Core.Inference.builtin_tfunction), typeof(===), Array{Any, 1}, Core.Inference.InferenceState, Core.Inference.InferenceParams}) -precompile(Tuple{typeof(Core.Inference.typeinf_frame), Core.MethodInstance, Void, Bool, Bool, Core.Inference.InferenceParams}) -precompile(Tuple{typeof(Core.Inference.typeinf_loop), Core.Inference.InferenceState}) -precompile(Tuple{typeof(Core.Inference.typeinf_frame), Core.Inference.InferenceState}) +precompile(Tuple{typeof(Core.Inference.typeinf_frame), Core.MethodInstance, Bool, Bool, Core.Inference.InferenceParams}) +precompile(Tuple{typeof(Core.Inference.typeinf), Core.Inference.InferenceState}) precompile(Tuple{typeof(Base.Cartesian.inlineanonymous), Expr, Int64}) precompile(Tuple{typeof(Base.Cartesian.lreplace), Expr, Symbol, Int64}) precompile(Tuple{typeof(Base.copy), Expr}) @@ -869,7 +868,6 @@ precompile(Tuple{typeof(Core.Inference._widen_all_consts!), Expr, Array{Bool, 1} precompile(Tuple{typeof(Core.Inference._delete!), Core.Inference.IntSet, Int64}) precompile(Tuple{typeof(Core.Inference.promote_type), Type{Float16}, Type{Int64}}) precompile(Tuple{typeof(Core.Inference.mk_tuplecall), Array{Any, 1}, Core.Inference.InferenceState}) -precompile(Tuple{typeof(Core.Inference.get_source), Core.MethodInstance}) precompile(Tuple{typeof(Core.Inference.inlining_pass), Expr, Core.Inference.InferenceState, Array{Any, 1}, Int64}) precompile(Tuple{typeof(Core.Inference.annotate_slot_load!), Expr, Array{Any, 1}, Core.Inference.InferenceState, Array{Bool, 1}}) precompile(Tuple{typeof(Core.Inference.record_slot_assign!), Core.Inference.InferenceState}) @@ -886,7 +884,6 @@ precompile(Tuple{typeof(Core.Inference.return_type_tfunc), Array{Any, 1}, Array{ precompile(Tuple{typeof(Core.Inference.abstract_call), typeof(===), Tuple{}, Array{Any, 1}, Array{Any, 1}, Core.Inference.InferenceState}) precompile(Tuple{typeof(Core.Inference.abstract_call), typeof(===), Array{Any, 1}, Array{Any, 1}, Array{Any, 1}, Core.Inference.InferenceState}) precompile(Tuple{typeof(Core.Inference.type_too_complex), TypeVar, Int64}) -precompile(Tuple{typeof(Core.Inference.typeinf_frame), Core.MethodInstance, Core.Inference.InferenceState, Bool, Bool, Core.Inference.InferenceParams}) precompile(Tuple{typeof(Core.Inference.abstract_eval), Expr, Array{Any, 1}, Core.Inference.InferenceState}) precompile(Tuple{typeof(Core.Inference._setint!), Core.Inference.IntSet, Int64, Bool}) precompile(Tuple{typeof(Core.Inference.stupdate1!), Array{Any, 1}, Core.Inference.StateUpdate}) @@ -1672,7 +1669,6 @@ precompile(Tuple{typeof(Base.isempty), Base.IntSet}) precompile(Tuple{typeof(Base.any), Base.BitArray{1}}) precompile(Tuple{typeof(Base.uvfinalize), Base.PipeEndpoint}) precompile(Tuple{typeof(Base.uvfinalize), Base.Process}) -precompile(Tuple{getfield(Base.Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Base.Distributed.remotecall_fetch), typeof(Base.Distributed.fetch_future), Base.Distributed.Worker, Base.Distributed.RRID, Int64}) precompile(Tuple{getfield(Base.Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Base.Distributed.remotecall_fetch), typeof(Base.find_in_path), Base.Distributed.LocalProcess, String, Void}) precompile(Tuple{getfield(Base.Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Base.Distributed.remotecall_fetch), typeof(Base.find_in_path), Base.Distributed.Worker, String, Void}) precompile(Tuple{getfield(Base.Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Base.Distributed.remotecall_fetch), typeof(Base.open), Base.Distributed.LocalProcess, typeof(Base.read), String}) @@ -1705,10 +1701,7 @@ precompile(Tuple{typeof(Base.compilecache), String}) precompile(Tuple{typeof(Base.copy!), Array{Tuple{String, Float64}, 1}, Int64, Array{Tuple{String, Float64}, 1}, Int64, Int64}) precompile(Tuple{typeof(Base.create_expr_cache), String, String, Array{Any, 1}}) precompile(Tuple{typeof(Base._delete!), Base.Dict{Symbol, Base.Condition}, Int64}) -precompile(Tuple{typeof(Base.Distributed.call_on_owner), typeof(Base.Distributed.fetch_future), Base.Distributed.Future, Int64}) -precompile(Tuple{typeof(Base.Distributed.fetch_future), Base.Distributed.RRID, Int64}) precompile(Tuple{typeof(Base.Distributed.flush_gc_msgs), Base.Distributed.Worker}) -precompile(Tuple{typeof(Base.Distributed.remotecall_fetch), typeof(Base.Distributed.fetch_future), Base.Distributed.Worker, Base.Distributed.RRID, Int64}) precompile(Tuple{typeof(Base.Distributed.remotecall_fetch), typeof(Base.find_in_path), Base.Distributed.LocalProcess, String, Void}) precompile(Tuple{typeof(Base.Distributed.remotecall_fetch), typeof(Base.find_in_path), Base.Distributed.Worker, String, Void}) precompile(Tuple{typeof(Base.Distributed.remotecall_fetch), typeof(Base.open), Base.Distributed.LocalProcess, typeof(Base.read), String}) diff --git a/base/random.jl b/base/random.jl index ff8f9cccd39ba..80c276389c261 100644 --- a/base/random.jl +++ b/base/random.jl @@ -93,6 +93,11 @@ MersenneTwister(seed::Vector{UInt32}, state::DSFMT_state) = Create a `MersenneTwister` RNG object. Different RNG objects can have their own seeds, which may be useful for generating different streams of random numbers. + +# Example +```jldoctest +julia> rng = MersenneTwister(1234); +``` """ MersenneTwister(seed) = srand(MersenneTwister(Vector{UInt32}(), DSFMT_state()), seed) @@ -290,6 +295,20 @@ rand(r::AbstractArray) = rand(GLOBAL_RNG, r) Populate the array `A` with random values. If the indexable collection `coll` is specified, the values are picked randomly from `coll`. This is equivalent to `copy!(A, rand(rng, coll, size(A)))` or `copy!(A, rand(rng, eltype(A), size(A)))` but without allocating a new array. + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> rand!(rng, zeros(5)) +5-element Array{Float64,1}: + 0.590845 + 0.766797 + 0.566237 + 0.460085 + 0.794026 +``` """ rand!(A::AbstractArray, r::AbstractArray) = rand!(GLOBAL_RNG, A, r) @@ -692,6 +711,25 @@ end bitrand([rng=GLOBAL_RNG], [dims...]) Generate a `BitArray` of random boolean values. + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> bitrand(rng, 10) +10-element BitArray{1}: + true + true + true + false + true + false + false + true + false + true +``` """ bitrand(r::AbstractRNG, dims::Dims) = rand!(r, BitArray(dims)) bitrand(r::AbstractRNG, dims::Int...) = rand!(r, BitArray(dims)) @@ -1200,6 +1238,20 @@ Generate a normally-distributed random number of type `T` with mean 0 and standa Optionally generate an array of normally-distributed random numbers. The `Base` module currently provides an implementation for the types [`Float16`](@ref), [`Float32`](@ref), and [`Float64`](@ref) (the default). + +# Examples + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randn(rng, Float64) +0.8673472019512456 + +julia> randn(rng, Float32, (2, 4)) +2×4 Array{Float32,2}: + -0.901744 -0.902914 2.21188 -0.271735 + -0.494479 0.864401 0.532813 0.502334 +``` """ @inline function randn(rng::AbstractRNG=GLOBAL_RNG) @inbounds begin @@ -1234,6 +1286,21 @@ Generate a random number of type `T` according to the exponential distribution w Optionally generate an array of such random numbers. The `Base` module currently provides an implementation for the types [`Float16`](@ref), [`Float32`](@ref), and [`Float64`](@ref) (the default). + +# Examples + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randexp(rng, Float32) +2.4835055f0 + +julia> randexp(rng, 3, 3) +3×3 Array{Float64,2}: + 1.5167 1.30652 0.344435 + 0.604436 2.78029 0.418516 + 0.695867 0.693292 0.643644 +``` """ @inline function randexp(rng::AbstractRNG=GLOBAL_RNG) @inbounds begin @@ -1260,6 +1327,20 @@ end Fill the array `A` with normally-distributed (mean 0, standard deviation 1) random numbers. Also see the [`rand`](@ref) function. + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randn!(rng, zeros(5)) +5-element Array{Float64,1}: + 0.867347 + -0.901744 + -0.494479 + -0.902914 + 0.864401 +``` """ function randn! end @@ -1267,6 +1348,20 @@ function randn! end randexp!([rng=GLOBAL_RNG], A::AbstractArray) -> A Fill the array `A` with random numbers following the exponential distribution (with scale 1). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randexp!(rng, zeros(5)) +5-element Array{Float64,1}: + 2.48351 + 1.5167 + 0.604436 + 0.695867 + 1.30652 +``` """ function randexp! end @@ -1316,6 +1411,15 @@ end Generates a version 1 (time-based) universally unique identifier (UUID), as specified by RFC 4122. Note that the Node ID is randomly generated (does not identify the host) according to section 4.5 of the RFC. + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> Base.Random.uuid1(rng) +2cc938da-5937-11e7-196e-0f4ef71aa64b +``` """ function uuid1(rng::AbstractRNG=GLOBAL_RNG) u = rand(rng, UInt128) @@ -1345,6 +1449,14 @@ end Generates a version 4 (random or pseudo-random) universally unique identifier (UUID), as specified by RFC 4122. + +# Example +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> Base.Random.uuid4(rng) +82015f10-44cc-4827-996e-0f4ef71aa64b +``` """ function uuid4(rng::AbstractRNG=GLOBAL_RNG) u = rand(rng, UInt128) @@ -1357,6 +1469,15 @@ end uuid_version(u::UUID) -> Integer Inspects the given UUID and returns its version (see RFC 4122). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> Base.Random.uuid_version(Base.Random.uuid4(rng)) +4 +``` """ function uuid_version(u::UUID) Int((u.value >> 76) & 0xf) @@ -1472,6 +1593,31 @@ end In-place version of [`shuffle`](@ref): randomly permute the array `v` in-place, optionally supplying the random-number generator `rng`. + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> shuffle!(rng, collect(1:16)) +16-element Array{Int64,1}: + 2 + 15 + 5 + 14 + 1 + 9 + 10 + 6 + 11 + 3 + 16 + 7 + 4 + 12 + 8 + 13 +``` """ function shuffle!(r::AbstractRNG, a::AbstractVector) n = length(a) @@ -1494,6 +1640,25 @@ Return a randomly permuted copy of `v`. The optional `rng` argument specifies a number generator (see [Random Numbers](@ref)). To permute `v` in-place, see [`shuffle!`](@ref). To obtain randomly permuted indices, see [`randperm`](@ref). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> shuffle(rng, collect(1:10)) +10-element Array{Int64,1}: + 6 + 1 + 10 + 2 + 3 + 9 + 5 + 7 + 4 + 8 +``` """ shuffle(r::AbstractRNG, a::AbstractVector) = shuffle!(r, copymutable(a)) shuffle(a::AbstractVector) = shuffle(GLOBAL_RNG, a) @@ -1505,6 +1670,19 @@ Construct a random permutation of length `n`. The optional `rng` argument specif number generator (see [Random Numbers](@ref)). To randomly permute a arbitrary vector, see [`shuffle`](@ref) or [`shuffle!`](@ref). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randperm(rng, 4) +4-element Array{Int64,1}: + 2 + 1 + 4 + 3 +``` """ function randperm(r::AbstractRNG, n::Integer) a = Vector{typeof(n)}(n) @@ -1531,6 +1709,21 @@ randperm(n::Integer) = randperm(GLOBAL_RNG, n) Construct a random cyclic permutation of length `n`. The optional `rng` argument specifies a random number generator, see [Random Numbers](@ref). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randcycle(rng, 6) +6-element Array{Int64,1}: + 3 + 5 + 4 + 6 + 1 + 2 +``` """ function randcycle(r::AbstractRNG, n::Integer) a = Vector{typeof(n)}(n) diff --git a/base/reducedim.jl b/base/reducedim.jl index a2ba674ee6d64..e857f579b3b55 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -219,6 +219,7 @@ reducedim!(op, R::AbstractArray{RT}, A::AbstractArray) where {RT} = Evaluates to the same as `reducedim(op, map(f, A), region, f(v0))`, but is generally faster because the intermediate array is avoided. +# Examples ```jldoctest julia> a = reshape(collect(1:16), (4,4)) 4×4 Array{Int64,2}: @@ -252,6 +253,7 @@ The associativity of the reduction is implementation-dependent; if you need a pa associativity, e.g. left-to-right, you should write your own loop. See documentation for [`reduce`](@ref). +# Examples ```jldoctest julia> a = reshape(collect(1:16), (4,4)) 4×4 Array{Int64,2}: @@ -282,6 +284,7 @@ reducedim(op, A::AbstractArray, region) = mapreducedim(identity, op, A, region) Sum elements of an array over the given dimensions. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -305,6 +308,7 @@ sum(A, dims) Sum elements of `A` over the singleton dimensions of `r`, and write results to `r`. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -328,6 +332,7 @@ sum!(r, A) Multiply elements of an array over the given dimensions. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -351,6 +356,7 @@ prod(A, dims) Multiply elements of `A` over the singleton dimensions of `r`, and write results to `r`. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -399,6 +405,7 @@ maximum(A, dims) Compute the maximum value of `A` over the singleton dimensions of `r`, and write results to `r`. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -424,6 +431,7 @@ Compute the minimum value of an array over the given dimensions. See also the [`min(a,b)`](@ref) function to take the minimum of two or more arguments, which can be applied elementwise to arrays via `min.(a,b)`. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -447,6 +455,7 @@ minimum(A, dims) Compute the minimum value of `A` over the singleton dimensions of `r`, and write results to `r`. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -470,6 +479,7 @@ minimum!(r, A) Test whether all values along the given dimensions of an array are `true`. +# Examples ```jldoctest julia> A = [true false; true true] 2×2 Array{Bool,2}: @@ -493,6 +503,7 @@ all(A::AbstractArray, dims) Test whether all values in `A` along the singleton dimensions of `r` are `true`, and write results to `r`. +# Examples ```jldoctest julia> A = [true false; true false] 2×2 Array{Bool,2}: @@ -516,6 +527,7 @@ all!(r, A) Test whether any values along the given dimensions of an array are `true`. +# Examples ```jldoctest julia> A = [true false; true false] 2×2 Array{Bool,2}: @@ -540,6 +552,7 @@ any(::AbstractArray,dims) Test whether any values in `A` along the singleton dimensions of `r` are `true`, and write results to `r`. +# Examples ```jldoctest julia> A = [true false; true false] 2×2 Array{Bool,2}: @@ -637,6 +650,7 @@ end For an array input, returns the value and index of the minimum over the given region. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -675,6 +689,7 @@ end For an array input, returns the value and index of the maximum over the given region. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: diff --git a/base/serialize.jl b/base/serialize.jl index d453e9e0a33f9..a1a688374dcdc 100644 --- a/base/serialize.jl +++ b/base/serialize.jl @@ -130,7 +130,7 @@ end # cycle handling function serialize_cycle(s::AbstractSerializer, x) - offs = get(s.table, x, -1) + offs = get(s.table, x, -1)::Int if offs != -1 if offs <= typemax(UInt16) writetag(s.io, SHORTBACKREF_TAG) @@ -212,8 +212,8 @@ function serialize(s::AbstractSerializer, x::Symbol) end function serialize_array_data(s::IO, a) - elty = eltype(a) - if elty === Bool && !isempty(a) + isempty(a) && return 0 + if eltype(a) === Bool last = a[1] count = 1 for i = 2:length(a) @@ -246,7 +246,8 @@ function serialize(s::AbstractSerializer, a::Array) if isbits(elty) serialize_array_data(s.io, a) else - for i in eachindex(a) + sizehint!(s.table, div(length(a),4)) # prepare for lots of pointers + @inbounds for i in eachindex(a) if isassigned(a, i) serialize(s, a[i]) else @@ -434,7 +435,9 @@ function serialize(s::AbstractSerializer, t::Task) end function serialize(s::AbstractSerializer, g::GlobalRef) - if g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name) + if (g.mod === __deserialized_types__ ) || + (g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name)) + v = getfield(g.mod, g.name) unw = unwrap_unionall(v) if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw) @@ -865,10 +868,11 @@ function deserialize_array(s::AbstractSerializer) end A = Array{elty, length(dims)}(dims) s.table[slot] = A + sizehint!(s.table, s.counter + div(length(A),4)) for i = eachindex(A) tag = Int32(read(s.io, UInt8)::UInt8) if tag != UNDEFREF_TAG - A[i] = handle_deserialize(s, tag) + @inbounds A[i] = handle_deserialize(s, tag) end end return A diff --git a/base/show.jl b/base/show.jl index 37850aa17c5cc..b62e0d9acfc1f 100644 --- a/base/show.jl +++ b/base/show.jl @@ -671,23 +671,19 @@ function show_generator(io, ex, indent) fg = ex ranges = Any[] while isa(fg, Expr) && fg.head === :flatten - push!(ranges, fg.args[1].args[2]) + push!(ranges, fg.args[1].args[2:end]) fg = fg.args[1].args[1] end - push!(ranges, fg.args[2]) + push!(ranges, fg.args[2:end]) show_unquoted(io, fg.args[1], indent) for r in ranges print(io, " for ") - show_unquoted(io, r, indent) + show_list(io, r, ", ", indent) end else show_unquoted(io, ex.args[1], indent) print(io, " for ") - show_unquoted(io, ex.args[2], indent) - for i = 3:length(ex.args) - print(io, ", ") - show_unquoted(io, ex.args[i], indent) - end + show_list(io, ex.args[2:end], ", ", indent) end end @@ -1467,9 +1463,8 @@ function print_matrix(io::IO, X::AbstractVecOrMat, postsp = "" @assert strwidth(hdots) == strwidth(ddots) sepsize = length(sep) - inds1, inds2 = indices(X,1), indices(X,2) - m, n = length(inds1), length(inds2) - rowsA, colsA = collect(inds1), collect(inds2) + rowsA, colsA = indices(X,1), indices(X,2) + m, n = length(rowsA), length(colsA) # To figure out alignments, only need to look at as many rows as could # fit down screen. If screen has at least as many rows as A, look at A. # If not, then we only need to look at the first and last chunks of A, diff --git a/base/socket.jl b/base/socket.jl index 6bfebd0efbbec..e104b40383d6c 100644 --- a/base/socket.jl +++ b/base/socket.jl @@ -282,10 +282,14 @@ mutable struct TCPSocket <: LibuvStream return tcp end end -function TCPSocket() + +# kw arg "delay": if true, libuv delays creation of the socket fd till the first bind call +function TCPSocket(; delay=true) tcp = TCPSocket(Libc.malloc(_sizeof_uv_tcp), StatusUninit) - err = ccall(:uv_tcp_init, Cint, (Ptr{Void}, Ptr{Void}), - eventloop(), tcp.handle) + af_spec = delay ? 0 : 2 # AF_UNSPEC is 0, AF_INET is 2 + + err = ccall(:uv_tcp_init_ex, Cint, (Ptr{Void}, Ptr{Void}, Cuint), + eventloop(), tcp.handle, af_spec) uv_error("failed to create tcp socket", err) tcp.status = StatusInit return tcp @@ -822,6 +826,10 @@ function listenany(host::IPAddr, default_port) while true sock = TCPServer() if bind(sock, addr) && trylisten(sock) == 0 + if default_port == 0 + _addr, port = _sockname(sock, true) + return (port, sock) + end return (addr.port, sock) end close(sock) @@ -840,16 +848,18 @@ listenany(default_port) = listenany(IPv4(UInt32(0)), default_port) Get the IP address and the port that the given `TCPSocket` is connected to (or bound to, in the case of `TCPServer`). """ -function getsockname(sock::Union{TCPServer,TCPSocket}) +getsockname(sock::Union{TCPServer, TCPSocket}) = _sockname(sock, isa(sock, TCPServer)) + +function _sockname(sock, self) rport = Ref{Cushort}(0) raddress = zeros(UInt8, 16) rfamily = Ref{Cuint}(0) - r = if isa(sock, TCPServer) - ccall(:jl_tcp_getsockname, Int32, + if self + r = ccall(:jl_tcp_getsockname, Int32, (Ptr{Void}, Ref{Cushort}, Ptr{Void}, Ref{Cuint}), sock.handle, rport, raddress, rfamily) else - ccall(:jl_tcp_getpeername, Int32, + r = ccall(:jl_tcp_getpeername, Int32, (Ptr{Void}, Ref{Cushort}, Ptr{Void}, Ref{Cuint}), sock.handle, rport, raddress, rfamily) end diff --git a/base/sort.jl b/base/sort.jl index 846723518a9b7..cc71c26177f1f 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -63,6 +63,7 @@ end Test whether a vector is in sorted order. The `lt`, `by` and `rev` keywords modify what order is considered to be sorted just as they do for [`sort`](@ref). +# Examples ```jldoctest julia> issorted([1, 2, 3]) true @@ -447,6 +448,8 @@ options are independent and can be used together in all possible combinations: i and `lt` are specified, the `lt` function is applied to the result of the `by` function; `rev=true` reverses whatever ordering specified via the `by` and `lt` keywords. +# Examples + ```jldoctest julia> v = [3, 1, 2]; sort!(v); v 3-element Array{Int64,1}: @@ -522,6 +525,8 @@ end Variant of [`sort!`](@ref) that returns a sorted copy of `v` leaving `v` itself unmodified. +# Examples + ```jldoctest julia> v = [3, 1, 2]; @@ -578,6 +583,8 @@ specified using the same keywords as `sort!`. See also [`sortperm!`](@ref). +# Examples + ```jldoctest julia> v = [3, 1, 2]; @@ -626,6 +633,8 @@ end Like [`sortperm`](@ref), but accepts a preallocated index vector `ix`. If `initialized` is `false` (the default), `ix` is initialized to contain the values `1:length(v)`. +# Examples + ```jldoctest julia> v = [3, 1, 2]; p = zeros(Int, 3); @@ -691,6 +700,8 @@ Sort a multidimensional array `A` along the given dimension. See [`sort!`](@ref) for a description of possible keyword arguments. +# Examples + ```jldoctest julia> A = [4 3; 1 2] 2×2 Array{Int64,2}: diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index 2d812d07bba85..9ea5bd3bd07cd 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -1365,8 +1365,8 @@ end cholfact!(F::Factor, A; shift = 0.0) -> CHOLMOD.Factor Compute the Cholesky (``LL'``) factorization of `A`, reusing the symbolic -factorization `F`. `A` must be a `SparseMatrixCSC`, `Symmetric{SparseMatrixCSC}`, -or `Hermitian{SparseMatrixCSC}`. Note that even if `A` doesn't +factorization `F`. `A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/ +[`Hermitian`](@ref) view of a `SparseMatrixCSC`. Note that even if `A` doesn't have the type tag, it must still be symmetric or Hermitian. See also [`cholfact`](@ref). @@ -1406,8 +1406,8 @@ end cholfact(A; shift = 0.0, perm = Int[]) -> CHOLMOD.Factor Compute the Cholesky factorization of a sparse positive definite matrix `A`. -`A` must be a `SparseMatrixCSC`, `Symmetric{SparseMatrixCSC}`, or -`Hermitian{SparseMatrixCSC}`. Note that even if `A` doesn't +`A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/[`Hermitian`](@ref) +view of a `SparseMatrixCSC`. Note that even if `A` doesn't have the type tag, it must still be symmetric or Hermitian. A fill-reducing permutation is used. `F = cholfact(A)` is most frequently used to solve systems of equations with `F\\b`, @@ -1457,8 +1457,8 @@ end ldltfact!(F::Factor, A; shift = 0.0) -> CHOLMOD.Factor Compute the ``LDL'`` factorization of `A`, reusing the symbolic factorization `F`. -`A` must be a `SparseMatrixCSC`, `Symmetric{SparseMatrixCSC}`, or -`Hermitian{SparseMatrixCSC}`. Note that even if `A` doesn't +`A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/[`Hermitian`](@ref) +view of a `SparseMatrixCSC`. Note that even if `A` doesn't have the type tag, it must still be symmetric or Hermitian. See also [`ldltfact`](@ref). @@ -1505,8 +1505,8 @@ end ldltfact(A; shift = 0.0, perm=Int[]) -> CHOLMOD.Factor Compute the ``LDL'`` factorization of a sparse matrix `A`. -`A` must be a `SparseMatrixCSC`, `Symmetric{SparseMatrixCSC}`, or -`Hermitian{SparseMatrixCSC}`. Note that even if `A` doesn't +`A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/[`Hermitian`](@ref) +view of a `SparseMatrixCSC`. Note that even if `A` doesn't have the type tag, it must still be symmetric or Hermitian. A fill-reducing permutation is used. `F = ldltfact(A)` is most frequently used to solve systems of equations `A*x = b` with `F\\b`. The returned diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 6fca07fa37682..974c43da233c2 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -5,12 +5,18 @@ # Assumes that row values in rowval for each column are sorted # issorted(rowval[colptr[i]:(colptr[i+1]-1)]) == true +""" + SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti} + +Matrix type for storing sparse matrices in the +[Compressed Sparse Column](@ref man-csc) format. +""" struct SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti} m::Int # Number of rows n::Int # Number of columns colptr::Vector{Ti} # Column i is in colptr[i]:(colptr[i+1]-1) - rowval::Vector{Ti} # Row values of nonzeros - nzval::Vector{Tv} # Nonzero values + rowval::Vector{Ti} # Row indices of stored values + nzval::Vector{Tv} # Stored values, typically nonzeros function SparseMatrixCSC{Tv,Ti}(m::Integer, n::Integer, colptr::Vector{Ti}, rowval::Vector{Ti}, nzval::Vector{Tv}) where {Tv,Ti<:Integer} @@ -32,6 +38,7 @@ size(S::SparseMatrixCSC) = (S.m, S.n) Returns the number of stored (filled) elements in a sparse array. +# Example ```jldoctest julia> A = speye(3) 3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: @@ -56,6 +63,7 @@ vector points directly to the internal nonzero storage of `A`, and any modifications to the returned vector will mutate `A` as well. See [`rowvals`](@ref) and [`nzrange`](@ref). +# Example ```jldoctest julia> A = speye(3) 3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: @@ -80,6 +88,7 @@ vector will mutate `A` as well. Providing access to how the row indices are stored internally can be useful in conjunction with iterating over structural nonzero values. See also [`nonzeros`](@ref) and [`nzrange`](@ref). +# Example ```jldoctest julia> A = speye(3) 3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: @@ -348,6 +357,7 @@ full(S::SparseMatrixCSC) = convert(Array, S) Convert a sparse matrix or vector `S` into a dense matrix or vector. +# Example ```jldoctest julia> A = speye(3) 3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: @@ -378,6 +388,7 @@ vec(S::SparseMatrixCSC) = S[:] Convert an AbstractMatrix `A` into a sparse matrix. +# Example ```jldoctest julia> A = eye(3) 3×3 Array{Float64,2}: @@ -458,6 +469,7 @@ retained as structural nonzeros; to drop numerical zeros, use [`dropzeros!`](@re For additional documentation and an expert driver, see `Base.SparseArrays.sparse!`. +# Example ```jldoctest julia> Is = [1; 2; 3]; @@ -524,8 +536,8 @@ Parent of and expert driver for [`sparse`](@ref); see [`sparse`](@ref) for basic usage. This method allows the user to provide preallocated storage for `sparse`'s intermediate objects and result as described below. This capability enables more efficient successive construction -of `SparseMatrixCSC`s from coordinate representations, and also enables extraction of an -unsorted-column representation of the result's transpose at no additional cost. +of [`SparseMatrixCSC`](@ref)s from coordinate representations, and also enables extraction +of an unsorted-column representation of the result's transpose at no additional cost. This method consists of three major steps: (1) Counting-sort the provided coordinate representation into an unsorted-row CSR form including repeated entries. (2) Sweep through @@ -725,8 +737,8 @@ and `length(X.nzval) >= nnz(A)`). Column-permutation `q`'s length must match `A count (`length(q) == A.n`). This method is the parent of several methods performing transposition and permutation -operations on `SparseMatrixCSC`s. As this method performs no argument checking, prefer -the safer child methods (`[c]transpose[!]`, `permute[!]`) to direct use. +operations on [`SparseMatrixCSC`](@ref)s. As this method performs no argument checking, +prefer the safer child methods (`[c]transpose[!]`, `permute[!]`) to direct use. This method implements the `HALFPERM` algorithm described in F. Gustavson, "Two fast algorithms for sparse matrices: multiplication and permuted transposition," ACM TOMS 4(3), @@ -844,8 +856,8 @@ end C::SparseMatrixCSC{Tv,Ti}, workcolptr::Vector{Ti}) See [`permute!`](@ref) for basic usage. Parent of `permute!` -methods operating on `SparseMatrixCSC`s where the source and destination matrices are the -same. See `unchecked_noalias_permute!` +methods operating on [`SparseMatrixCSC`](@ref)s where the source and destination matrices +are the same. See `unchecked_noalias_permute!` for additional information; these methods are identical but for this method's requirement of the additional `workcolptr`, `length(workcolptr) >= A.n + 1`, which enables efficient handling of the source-destination aliasing. @@ -1001,7 +1013,7 @@ For additional (algorithmic) information, and for versions of these methods that argument checking, see (unexported) parent methods `unchecked_noalias_permute!` and `unchecked_aliasing_permute!`. -See also: [`permute`](@ref) +See also: [`permute`](@ref). """ function permute!{Tv,Ti}(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) @@ -1054,6 +1066,39 @@ match `A`'s column count (`length(q) == A.n`). Row-permutation `p`'s length must row count (`length(p) == A.m`). For expert drivers and additional information, see [`permute!`](@ref). + +# Example +```jldoctest +julia> A = spdiagm([1, 2, 3, 4], 0, 4, 4) + spdiagm([5, 6, 7], 1, 4, 4) +4×4 SparseMatrixCSC{Int64,Int64} with 7 stored entries: + [1, 1] = 1 + [1, 2] = 5 + [2, 2] = 2 + [2, 3] = 6 + [3, 3] = 3 + [3, 4] = 7 + [4, 4] = 4 + +julia> permute(A, [4, 3, 2, 1], [1, 2, 3, 4]) +4×4 SparseMatrixCSC{Int64,Int64} with 7 stored entries: + [4, 1] = 1 + [3, 2] = 2 + [4, 2] = 5 + [2, 3] = 3 + [3, 3] = 6 + [1, 4] = 4 + [2, 4] = 7 + +julia> permute(A, [1, 2, 3, 4], [4, 3, 2, 1]) +4×4 SparseMatrixCSC{Int64,Int64} with 7 stored entries: + [3, 1] = 7 + [4, 1] = 4 + [2, 2] = 6 + [3, 2] = 3 + [1, 3] = 5 + [2, 3] = 2 + [1, 4] = 1 +``` """ function permute{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) @@ -1078,6 +1123,21 @@ value. This method makes a single sweep through `A`, requiring `O(A.n, nnz(A))`-time for matrices and `O(nnz(A))`-time for vectors and no space beyond that passed in. If `trim` is `true`, this method trims `A.rowval` or `A.nzind` and `A.nzval` to length `nnz(A)` after dropping elements. + +# Example +```jldoctest +julia> A = spdiagm([1, 2, 3, 4]) +4×4 SparseMatrixCSC{Int64,Int64} with 4 stored entries: + [1, 1] = 1 + [2, 2] = 2 + [3, 3] = 3 + [4, 4] = 4 + +julia> Base.SparseArrays.fkeep!(A, (i, j, v) -> isodd(v)) +4×4 SparseMatrixCSC{Int64,Int64} with 2 stored entries: + [1, 1] = 1 + [3, 3] = 3 +``` """ function fkeep!(A::SparseMatrixCSC, f, trim::Bool = true) An = A.n @@ -1153,6 +1213,20 @@ Generates a copy of `A` and removes stored numerical zeros from that copy, optio trimming excess space from the result's `rowval` and `nzval` arrays when `trim` is `true`. For an in-place version and algorithmic information, see [`dropzeros!`](@ref). + +# Example +```jldoctest +julia> A = sparse([1, 2, 3], [1, 2, 3], [1.0, 0.0, 1.0]) +3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: + [1, 1] = 1.0 + [2, 2] = 0.0 + [3, 3] = 1.0 + +julia> dropzeros(A) +3×3 SparseMatrixCSC{Float64,Int64} with 2 stored entries: + [1, 1] = 1.0 + [3, 3] = 1.0 +``` """ dropzeros(A::SparseMatrixCSC, trim::Bool = true) = dropzeros!(copy(A), trim) @@ -1263,6 +1337,7 @@ values are sampled from the distribution specified by `rfn` and have the type `t distribution is used in case `rfn` is not specified. The optional `rng` argument specifies a random number generator, see [Random Numbers](@ref). +# Example ```jldoctest julia> rng = MersenneTwister(1234); @@ -1314,6 +1389,7 @@ with the specified (independent) probability `p` of any entry being nonzero, where nonzero values are sampled from the normal distribution. The optional `rng` argument specifies a random number generator, see [Random Numbers](@ref). +# Example ```jldoctest julia> rng = MersenneTwister(1234); @@ -1334,6 +1410,7 @@ sprandn(m::Integer, n::Integer, density::AbstractFloat) = sprandn(GLOBAL_RNG,m,n Create a sparse array with the same structure as that of `S`, but with every nonzero element having the value `1.0`. +# Example ```jldoctest julia> A = sparse([1,2,3,4],[2,4,3,1],[5.,4.,3.,2.]) 4×4 SparseMatrixCSC{Float64,Int64} with 4 stored entries: @@ -1363,6 +1440,7 @@ sparse array will not contain any nonzero values. No storage will be allocated for nonzero values during construction. The type defaults to [`Float64`](@ref) if not specified. +# Examples ```jldoctest julia> spzeros(3, 3) 3×3 SparseMatrixCSC{Float64,Int64} with 0 stored entries @@ -1391,6 +1469,7 @@ speye(m::Integer, n::Integer) = speye(Float64, m, n) Create a sparse identity matrix with the same size as `S`. +# Example ```jldoctest julia> A = sparse([1,2,3,4],[2,4,3,1],[5.,4.,3.,2.]) 4×4 SparseMatrixCSC{Float64,Int64} with 4 stored entries: @@ -2817,6 +2896,22 @@ stored and otherwise do nothing. Derivative forms: dropstored!(A::SparseMatrixCSC, i::Integer, J::AbstractVector{<:Integer}) dropstored!(A::SparseMatrixCSC, I::AbstractVector{<:Integer}, j::Integer) + +# Example +```jldoctest +julia> A = spdiagm([1, 2, 3, 4]) +4×4 SparseMatrixCSC{Int64,Int64} with 4 stored entries: + [1, 1] = 1 + [2, 2] = 2 + [3, 3] = 3 + [4, 4] = 4 + +julia> Base.SparseArrays.dropstored!(A, [1, 2], [1, 1]) +4×4 SparseMatrixCSC{Int64,Int64} with 3 stored entries: + [2, 2] = 2 + [3, 3] = 3 + [4, 4] = 4 +``` """ function dropstored!(A::SparseMatrixCSC, I::AbstractVector{<:Integer}, J::AbstractVector{<:Integer}) @@ -3199,6 +3294,7 @@ one diagonal, `B` can be a vector (instead of a tuple) and `d` can be the diagon (instead of a tuple), defaulting to 0 (diagonal). Optionally, `m` and `n` specify the size of the resulting sparse matrix. +# Example ```jldoctest julia> spdiagm(([1,2,3,4],[4,3,2,1]),(-1,1)) 5×5 SparseMatrixCSC{Int64,Int64} with 8 stored entries: diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index 63daae89a130a..28b892125b6dd 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -9,10 +9,15 @@ import Base.LinAlg: promote_to_array_type, promote_to_arrays_ ### Types +""" + SparseVector{Tv,Ti<:Integer} <: AbstractSparseVector{Tv,Ti} + +Vector type for storing sparse vectors. +""" struct SparseVector{Tv,Ti<:Integer} <: AbstractSparseVector{Tv,Ti} - n::Int # the number of elements - nzind::Vector{Ti} # the indices of nonzeros - nzval::Vector{Tv} # the values of nonzeros + n::Int # Length of the sparse vector + nzind::Vector{Ti} # Indices of stored values + nzval::Vector{Tv} # Stored values, typically nonzeros function SparseVector{Tv,Ti}(n::Integer, nzind::Vector{Ti}, nzval::Vector{Tv}) where {Tv,Ti<:Integer} n >= 0 || throw(ArgumentError("The number of elements must be non-negative.")) @@ -253,6 +258,7 @@ setindex!(x::SparseVector{Tv,Ti}, v, i::Integer) where {Tv,Ti<:Integer} = Drop entry `x[i]` from `x` if `x[i]` is stored and otherwise do nothing. +# Examples ```jldoctest julia> x = sparsevec([1, 3], [1.0, 2.0]) 3-element SparseVector{Float64,Int64} with 2 stored entries: @@ -305,6 +311,7 @@ convert(::Type{SparseVector}, s::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = Convert a vector `A` into a sparse vector of length `m`. +# Example ```jldoctest julia> sparsevec([1.0, 2.0, 0.0, 0.0, 3.0, 0.0]) 6-element SparseVector{Float64,Int64} with 3 stored entries: @@ -927,7 +934,7 @@ vcat(X::Union{Vector,SparseVector}...) = vcat(map(sparse, X)...) # TODO: A definition similar to the third exists in base/linalg/bidiag.jl. These definitions # should be consolidated in a more appropriate location, e.g. base/linalg/special.jl. -const _SparseArrays = Union{SparseVector, SparseMatrixCSC} +const _SparseArrays = Union{SparseVector, SparseMatrixCSC, RowVector{<:Any, <:SparseVector}} const _SpecialArrays = Union{Diagonal, Bidiagonal, Tridiagonal, SymTridiagonal} const _SparseConcatArrays = Union{_SpecialArrays, _SparseArrays} @@ -942,9 +949,9 @@ const _Triangular_DenseArrays{T,A<:Matrix} = Base.LinAlg.AbstractTriangular{T,A} const _Annotated_DenseArrays = Union{_Triangular_DenseArrays, _Symmetric_DenseArrays, _Hermitian_DenseArrays} const _Annotated_Typed_DenseArrays{T} = Union{_Triangular_DenseArrays{T}, _Symmetric_DenseArrays{T}, _Hermitian_DenseArrays{T}} -const _SparseConcatGroup = Union{Vector, Matrix, _SparseConcatArrays, _Annotated_SparseConcatArrays, _Annotated_DenseArrays} -const _DenseConcatGroup = Union{Vector, Matrix, _Annotated_DenseArrays} -const _TypedDenseConcatGroup{T} = Union{Vector{T}, Matrix{T}, _Annotated_Typed_DenseArrays{T}} +const _SparseConcatGroup = Union{Vector, RowVector{<:Any, <:Vector}, Matrix, _SparseConcatArrays, _Annotated_SparseConcatArrays, _Annotated_DenseArrays} +const _DenseConcatGroup = Union{Vector, RowVector{<:Any, <:Vector}, Matrix, _Annotated_DenseArrays} +const _TypedDenseConcatGroup{T} = Union{Vector{T}, RowVector{T,Vector{T}}, Matrix{T}, _Annotated_Typed_DenseArrays{T}} # Concatenations involving un/annotated sparse/special matrices/vectors should yield sparse arrays function cat(catdims, Xin::_SparseConcatGroup...) @@ -1928,6 +1935,20 @@ Generates a copy of `x` and removes numerical zeros from that copy, optionally t excess space from the result's `nzind` and `nzval` arrays when `trim` is `true`. For an in-place version and algorithmic information, see [`dropzeros!`](@ref). + +# Example +```jldoctest +julia> A = sparsevec([1, 2, 3], [1.0, 0.0, 1.0]) +3-element SparseVector{Float64,Int64} with 3 stored entries: + [1] = 1.0 + [2] = 0.0 + [3] = 1.0 + +julia> dropzeros(A) +3-element SparseVector{Float64,Int64} with 2 stored entries: + [1] = 1.0 + [3] = 1.0 +``` """ dropzeros(x::SparseVector, trim::Bool = true) = dropzeros!(copy(x), trim) diff --git a/base/statistics.jl b/base/statistics.jl index 21124f3e0ec5e..2b9969afa95bd 100644 --- a/base/statistics.jl +++ b/base/statistics.jl @@ -210,22 +210,24 @@ varm(iterable, m::Number; corrected::Bool=true) = ## variances over ranges function varm(v::Range, m::Number) - f = first(v) - m - s = step(v) - l = length(v) + f = first(v) - m + s = step(v) + l = length(v) + vv = f^2 * l / (l - 1) + f * s * l + s^2 * l * (2 * l - 1) / 6 if l == 0 || l == 1 - return NaN + return typeof(vv)(NaN) end - return f^2 * l / (l - 1) + f * s * l + s^2 * l * (2 * l - 1) / 6 + return vv end function var(v::Range) - s = step(v) - l = length(v) + s = step(v) + l = length(v) + vv = abs2(s) * (l + 1) * l / 12 if l == 0 || l == 1 - return NaN + return typeof(vv)(NaN) end - return abs2(s) * (l + 1) * l / 12 + return vv end diff --git a/base/strings/basic.jl b/base/strings/basic.jl index df3e4bdf6db81..d46e490e50e84 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -46,6 +46,8 @@ Symbol(s::AbstractString) = Symbol(String(s)) The number of bytes in string `s`. +# Example + ```jldoctest julia> sizeof("❤") 3 @@ -62,6 +64,8 @@ eltype(::Type{<:AbstractString}) = Char Concatenate strings. The `*` operator is an alias to this function. +# Example + ```jldoctest julia> "Hello " * "world" "Hello world" @@ -78,6 +82,8 @@ length(s::DirectIndexString) = endof(s) The number of characters in string `s`. +# Example + ```jldoctest julia> length("jμΛIα") 5 @@ -138,6 +144,8 @@ isvalid(s::DirectIndexString, i::Integer) = (start(s) <= i <= endof(s)) Tells whether index `i` is valid for the given string. +# Examples + ```jldoctest julia> str = "αβγdef"; @@ -179,6 +187,8 @@ nextind(s::AbstractArray , i::Integer) = Int(i)+1 Get the previous valid string index before `i`. Returns a value less than `1` at the beginning of the string. +# Examples + ```jldoctest julia> prevind("αβγdef", 3) 1 @@ -208,6 +218,8 @@ end Get the next valid string index after `i`. Returns a value greater than `endof(str)` at or after the end of the string. +# Examples + ```jldoctest julia> str = "αβγdef"; @@ -255,6 +267,8 @@ respect to string `s`. See also [`chr2ind`](@ref). +# Example + ```jldoctest julia> str = "αβγdef"; @@ -286,6 +300,8 @@ Convert a character index `i` to a byte index. See also [`ind2chr`](@ref). +# Example + ```jldoctest julia> str = "αβγdef"; @@ -328,6 +344,8 @@ eltype(::Type{EachStringIndex}) = Int Gives the number of columns needed to print a string. +# Example + ```jldoctest julia> strwidth("March") 5 @@ -354,6 +372,8 @@ promote_rule(::Type{<:AbstractString}, ::Type{<:AbstractString}) = String Tests whether a character is a valid hexadecimal digit. Note that this does not include `x` (as in the standard `0x` prefix). +# Example + ```jldoctest julia> isxdigit('a') true @@ -371,6 +391,8 @@ isxdigit(c::Char) = '0'<=c<='9' || 'a'<=c<='f' || 'A'<=c<='F' Returns `s` with all characters converted to uppercase. +# Example + ```jldoctest julia> uppercase("Julia") "JULIA" @@ -383,6 +405,8 @@ uppercase(s::AbstractString) = map(uppercase, s) Returns `s` with all characters converted to lowercase. +# Example + ```jldoctest julia> lowercase("STRINGS AND THINGS") "strings and things" @@ -395,6 +419,8 @@ lowercase(s::AbstractString) = map(lowercase, s) Capitalizes the first character of each word in `s`. +# Example + ```jldoctest julia> titlecase("the julia programming language") "The Julia Programming Language" @@ -420,6 +446,8 @@ end Returns `string` with the first character converted to uppercase. +# Example + ```jldoctest julia> ucfirst("python") "Python" @@ -434,6 +462,8 @@ end Returns `string` with the first character converted to lowercase. +# Example + ```jldoctest julia> lcfirst("Julia") "julia" diff --git a/base/strings/string.jl b/base/strings/string.jl index a78f2372e77e2..34eb44cece4c6 100644 --- a/base/strings/string.jl +++ b/base/strings/string.jl @@ -427,8 +427,12 @@ function repeat(s::String, r::Integer) r < 0 && throw(ArgumentError("can't repeat a string $r times")) n = s.len out = _string_n(n*r) - for i=1:r - unsafe_copy!(pointer(out, 1+(i-1)*n), pointer(s), n) + if n == 1 # common case: repeating a single ASCII char + ccall(:memset, Ptr{Void}, (Ptr{UInt8}, Cint, Csize_t), out, unsafe_load(pointer(s)), r) + else + for i=1:r + unsafe_copy!(pointer(out, 1+(i-1)*n), pointer(s), n) + end end return out end diff --git a/base/strings/utf8proc.jl b/base/strings/utf8proc.jl index 8b90af4d06c7c..a3ebd46ca0414 100644 --- a/base/strings/utf8proc.jl +++ b/base/strings/utf8proc.jl @@ -354,6 +354,7 @@ letter combined with an accent mark is a single grapheme.) graphemes(s::AbstractString) = GraphemeIterator{typeof(s)}(s) eltype(::Type{GraphemeIterator{S}}) where {S} = SubString{S} +eltype(::Type{GraphemeIterator{SubString{S}}}) where {S} = SubString{S} function length(g::GraphemeIterator) c0 = Char(0x00ad) # soft hyphen (grapheme break always allowed after this) diff --git a/base/sysimg.jl b/base/sysimg.jl index d9851dbf30a0d..0f7b163990718 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -21,7 +21,6 @@ include("coreio.jl") eval(x) = Core.eval(Base, x) eval(m, x) = Core.eval(m, x) -(::Type{T})(arg) where {T} = convert(T, arg)::T # Hidden from the REPL. VecElement{T}(arg) where {T} = VecElement{T}(convert(T, arg)) convert(::Type{T}, arg) where {T<:VecElement} = T(arg) convert(::Type{T}, arg::T) where {T<:VecElement} = arg @@ -73,6 +72,10 @@ include("refpointer.jl") include("checked.jl") importall .Checked +# buggy handling of ispure in type-inference means this should be +# after re-defining the basic operations that they might try to call +(::Type{T})(arg) where {T} = convert(T, arg)::T # Hidden from the REPL. + # vararg Symbol constructor Symbol(x...) = Symbol(string(x...)) @@ -141,7 +144,7 @@ using .Iterators: zip, enumerate using .Iterators: Flatten, product # for generators # Definition of StridedArray -StridedReshapedArray{T,N,A<:DenseArray} = ReshapedArray{T,N,A} +StridedReshapedArray{T,N,A<:Union{DenseArray,FastContiguousSubArray}} = ReshapedArray{T,N,A} StridedArray{T,N,A<:Union{DenseArray,StridedReshapedArray}, I<:Tuple{Vararg{Union{RangeIndex, AbstractCartesianIndex}}}} = Union{DenseArray{T,N}, SubArray{T,N,A,I}, StridedReshapedArray{T,N}} diff --git a/base/test.jl b/base/test.jl index fdff18c1f58a2..aab681221480d 100644 --- a/base/test.jl +++ b/base/test.jl @@ -67,9 +67,9 @@ struct Pass <: Result value end function Base.show(io::IO, t::Pass) - print_with_color(:green, io, "Test Passed\n"; bold = true) + print_with_color(:green, io, "Test Passed"; bold = true) if !(t.orig_expr === nothing) - print(io, " Expression: ", t.orig_expr) + print(io, "\n Expression: ", t.orig_expr) end if t.test_type == :test_throws # The correct type of exception was thrown @@ -1041,10 +1041,10 @@ Int64 julia> @code_warntype f(1,2,3) Variables: - #self#::#f - a::Int64 + #self# + a b::Int64 - c::Int64 + c Body: begin diff --git a/base/threadcall.jl b/base/threadcall.jl index d1e0b75e65f23..fee9ef8222700 100644 --- a/base/threadcall.jl +++ b/base/threadcall.jl @@ -11,7 +11,7 @@ function notify_fun(idx) end function init_threadcall() - global c_notify_fun = cfunction(notify_fun, Void, (Cint,)) + global c_notify_fun = cfunction(notify_fun, Void, Tuple{Cint}) end """ @@ -64,7 +64,7 @@ end function do_threadcall(wrapper::Function, rettype::Type, argtypes::Vector, argvals::Vector) # generate function pointer - fun_ptr = cfunction(wrapper, Int, (Ptr{Void}, Ptr{Void})) + fun_ptr = cfunction(wrapper, Int, Tuple{Ptr{Void}, Ptr{Void}}) # cconvert, root and unsafe_convert arguments roots = Any[] diff --git a/base/twiceprecision.jl b/base/twiceprecision.jl index 539afe54cee62..afa39160bc85b 100644 --- a/base/twiceprecision.jl +++ b/base/twiceprecision.jl @@ -106,7 +106,7 @@ end function floatrange(a::AbstractFloat, st::AbstractFloat, len::Real, divisor::AbstractFloat) T = promote_type(typeof(a), typeof(st), typeof(divisor)) - m = maxintfloat(T) + m = maxintfloat(T, Int) if abs(a) <= m && abs(st) <= m && abs(divisor) <= m ia, ist, idivisor = round(Int, a), round(Int, st), round(Int, divisor) if ia == a && ist == st && idivisor == divisor @@ -131,7 +131,7 @@ function colon(start::T, step::T, stop::T) where T<:Union{Float16,Float32,Float6 if start_d != 0 && stop_d != 0 && T(start_n/start_d) == start && T(stop_n/stop_d) == stop den = lcm(start_d, step_d) # use same denominator for start and step - m = maxintfloat(T) + m = maxintfloat(T, Int) if den != 0 && abs(start*den) <= m && abs(step*den) <= m && # will round succeed? rem(den, start_d) == 0 && rem(den, step_d) == 0 # check lcm overflow start_n = round(Int, start*den) @@ -167,7 +167,7 @@ function range(a::T, st::T, len::Integer) where T<:Union{Float16,Float32,Float64 if start_d != 0 && step_d != 0 && T(start_n/start_d) == a && T(step_n/step_d) == st den = lcm(start_d, step_d) - m = maxintfloat(T) + m = maxintfloat(T, Int) if abs(den*a) <= m && abs(den*st) <= m && rem(den, start_d) == 0 && rem(den, step_d) == 0 start_n = round(Int, den*a) @@ -257,7 +257,7 @@ function _convertSRL(::Type{StepRangeLen{T,R,S}}, r::Range{U}) where {T,R,S,U} if start_d != 0 && step_d != 0 && U(start_n/start_d) == f && U(step_n/step_d) == s den = lcm(start_d, step_d) - m = maxintfloat(T) + m = maxintfloat(T, Int) if den != 0 && abs(f*den) <= m && abs(s*den) <= m && rem(den, start_d) == 0 && rem(den, step_d) == 0 start_n = round(Int, f*den) @@ -326,7 +326,7 @@ function linspace(start::T, stop::T, len::Integer) where T<:Union{Float16,Float3 stop_n, stop_d = rat(stop) if start_d != 0 && stop_d != 0 den = lcm(start_d, stop_d) - m = maxintfloat(T) + m = maxintfloat(T, Int) if den != 0 && abs(den*start) <= m && abs(den*stop) <= m start_n = round(Int, den*start) stop_n = round(Int, den*stop) @@ -422,7 +422,7 @@ function rat(x) y = x a = d = 1 b = c = 0 - m = maxintfloat(narrow(typeof(x))) + m = maxintfloat(narrow(typeof(x)), Int) while abs(y) <= m f = trunc(Int,y) y -= f @@ -435,6 +435,7 @@ function rat(x) return a, b end +narrow(::Type{T}) where {T<:AbstractFloat} = Float64 narrow(::Type{Float64}) = Float32 narrow(::Type{Float32}) = Float16 narrow(::Type{Float16}) = Float16 diff --git a/contrib/build_sysimg.jl b/contrib/build_sysimg.jl index 8c08248f5a767..7ca643f9204b5 100644 --- a/contrib/build_sysimg.jl +++ b/contrib/build_sysimg.jl @@ -13,7 +13,7 @@ function default_sysimg_path(debug=false) end """ - build_sysimg(sysimg_path=default_sysimg_path, cpu_target="native", userimg_path=nothing; force=false) + build_sysimg(sysimg_path=default_sysimg_path(), cpu_target="native", userimg_path=nothing; force=false) Rebuild the system image. Store it in `sysimg_path`, which defaults to a file named `sys.ji` that sits in the same folder as `libjulia.{so,dylib}`, except on Windows where it defaults diff --git a/deps/llvm.mk b/deps/llvm.mk index 5883e4dc734ab..f8cb58f36dc82 100644 --- a/deps/llvm.mk +++ b/deps/llvm.mk @@ -494,6 +494,9 @@ $(eval $(call LLVM_PATCH,llvm-D28759-loopclearance)) $(eval $(call LLVM_PATCH,llvm-D28786-callclearance)) $(eval $(call LLVM_PATCH,llvm-rL293230-icc17-cmake)) # Remove for 4.0 $(eval $(call LLVM_PATCH,llvm-PR29010-i386-xmm)) # Remove for 4.0 +$(eval $(call LLVM_PATCH,llvm-D32593)) +$(eval $(call LLVM_PATCH,llvm-D33179)) +$(eval $(call LLVM_PATCH,llvm-3.9.0-D37576-NVPTX-sm_70)) # NVPTX, Remove for 6.0 endif # LLVM_VER ifeq ($(LLVM_VER),3.7.1) diff --git a/deps/patches/llvm-3.9.0-D37576-NVPTX-sm_70.patch b/deps/patches/llvm-3.9.0-D37576-NVPTX-sm_70.patch new file mode 100644 index 0000000000000..0ac8e44cc5c64 --- /dev/null +++ b/deps/patches/llvm-3.9.0-D37576-NVPTX-sm_70.patch @@ -0,0 +1,62 @@ +From 4059d374ce981827223ab6b1dae7af4ec5f8e74a Mon Sep 17 00:00:00 2001 +From: Artem Belevich +Date: Thu, 7 Sep 2017 18:14:32 +0000 +Subject: [PATCH] [CUDA] Added rudimentary support for CUDA-9 and sm_70. + +For now CUDA-9 is not included in the list of CUDA versions clang +searches for, so the path to CUDA-9 must be explicitly passed +via --cuda-path=. + +On LLVM side NVPTX added sm_70 GPU type which bumps required +PTX version to 6.0, but otherwise is equivalent to sm_62 at the moment. + +Differential Revision: https://reviews.llvm.org/D37576 + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@312734 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + lib/Target/NVPTX/NVPTX.td | 5 +++++ + test/CodeGen/NVPTX/sm-version-70.ll | 5 +++++ + 2 files changed, 10 insertions(+) + create mode 100644 test/CodeGen/NVPTX/sm-version-70.ll + +diff --git a/lib/Target/NVPTX/NVPTX.td b/lib/Target/NVPTX/NVPTX.td +index c77ddbc9978..aba37d36359 100644 +--- a/lib/Target/NVPTX/NVPTX.td ++++ b/lib/Target/NVPTX/NVPTX.td +@@ -50,6 +50,8 @@ def SM61 : SubtargetFeature<"sm_61", "SmVersion", "61", + "Target SM 6.1">; + def SM62 : SubtargetFeature<"sm_62", "SmVersion", "62", + "Target SM 6.2">; ++def SM70 : SubtargetFeature<"sm_70", "SmVersion", "70", ++ "Target SM 7.0">; + + def SATOM : SubtargetFeature<"satom", "HasAtomScope", "true", + "Atomic operations with scope">; +@@ -67,6 +69,8 @@ def PTX43 : SubtargetFeature<"ptx43", "PTXVersion", "43", + "Use PTX version 4.3">; + def PTX50 : SubtargetFeature<"ptx50", "PTXVersion", "50", + "Use PTX version 5.0">; ++def PTX60 : SubtargetFeature<"ptx60", "PTXVersion", "60", ++ "Use PTX version 6.0">; + + //===----------------------------------------------------------------------===// + // NVPTX supported processors. +@@ -87,6 +91,7 @@ def : Proc<"sm_53", [SM53, PTX42]>; + def : Proc<"sm_60", [SM60, PTX50]>; + def : Proc<"sm_61", [SM61, PTX50]>; + def : Proc<"sm_62", [SM62, PTX50]>; ++def : Proc<"sm_70", [SM70, PTX60]>; + + def NVPTXInstrInfo : InstrInfo { + } +diff --git a/test/CodeGen/NVPTX/sm-version-70.ll b/test/CodeGen/NVPTX/sm-version-70.ll +new file mode 100644 +index 00000000000..8b72d50747a +--- /dev/null ++++ b/test/CodeGen/NVPTX/sm-version-70.ll +@@ -0,0 +1,5 @@ ++; RUN: llc < %s -march=nvptx -mcpu=sm_70 | FileCheck %s ++; RUN: llc < %s -march=nvptx64 -mcpu=sm_70 | FileCheck %s ++ ++; CHECK: .version 6.0 ++; CHECK: .target sm_70 diff --git a/deps/patches/llvm-4.0.0-D37576-NVPTX-sm_70.patch b/deps/patches/llvm-4.0.0-D37576-NVPTX-sm_70.patch new file mode 100644 index 0000000000000..9fee1f36e2a95 --- /dev/null +++ b/deps/patches/llvm-4.0.0-D37576-NVPTX-sm_70.patch @@ -0,0 +1,62 @@ +From 4059d374ce981827223ab6b1dae7af4ec5f8e74a Mon Sep 17 00:00:00 2001 +From: Artem Belevich +Date: Thu, 7 Sep 2017 18:14:32 +0000 +Subject: [PATCH] [CUDA] Added rudimentary support for CUDA-9 and sm_70. + +For now CUDA-9 is not included in the list of CUDA versions clang +searches for, so the path to CUDA-9 must be explicitly passed +via --cuda-path=. + +On LLVM side NVPTX added sm_70 GPU type which bumps required +PTX version to 6.0, but otherwise is equivalent to sm_62 at the moment. + +Differential Revision: https://reviews.llvm.org/D37576 + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@312734 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + lib/Target/NVPTX/NVPTX.td | 5 +++++ + test/CodeGen/NVPTX/sm-version-70.ll | 5 +++++ + 2 files changed, 10 insertions(+) + create mode 100644 test/CodeGen/NVPTX/sm-version-70.ll + +diff --git a/lib/Target/NVPTX/NVPTX.td b/lib/Target/NVPTX/NVPTX.td +index c77ddbc9978..aba37d36359 100644 +--- a/lib/Target/NVPTX/NVPTX.td ++++ b/lib/Target/NVPTX/NVPTX.td +@@ -50,6 +50,8 @@ def SM61 : SubtargetFeature<"sm_61", "SmVersion", "61", + "Target SM 6.1">; + def SM62 : SubtargetFeature<"sm_62", "SmVersion", "62", + "Target SM 6.2">; ++def SM70 : SubtargetFeature<"sm_70", "SmVersion", "70", ++ "Target SM 7.0">; + + def SATOM : SubtargetFeature<"satom", "HasAtomScope", "true", + "Atomic operations with scope">; +@@ -67,6 +69,8 @@ def PTX43 : SubtargetFeature<"ptx43", "PTXVersion", "43", + "Use PTX version 4.3">; + def PTX50 : SubtargetFeature<"ptx50", "PTXVersion", "50", + "Use PTX version 5.0">; ++def PTX60 : SubtargetFeature<"ptx60", "PTXVersion", "60", ++ "Use PTX version 6.0">; + + //===----------------------------------------------------------------------===// + // NVPTX supported processors. +@@ -87,6 +91,7 @@ def : Proc<"sm_53", [SM53, PTX42]>; + def : Proc<"sm_60", [SM60, PTX50, SATOM]>; + def : Proc<"sm_61", [SM61, PTX50, SATOM]>; + def : Proc<"sm_62", [SM62, PTX50, SATOM]>; ++def : Proc<"sm_70", [SM70, PTX60, SATOM]>; + + def NVPTXInstrInfo : InstrInfo { + } +diff --git a/test/CodeGen/NVPTX/sm-version-70.ll b/test/CodeGen/NVPTX/sm-version-70.ll +new file mode 100644 +index 00000000000..8b72d50747a +--- /dev/null ++++ b/test/CodeGen/NVPTX/sm-version-70.ll +@@ -0,0 +1,5 @@ ++; RUN: llc < %s -march=nvptx -mcpu=sm_70 | FileCheck %s ++; RUN: llc < %s -march=nvptx64 -mcpu=sm_70 | FileCheck %s ++ ++; CHECK: .version 6.0 ++; CHECK: .target sm_70 diff --git a/deps/patches/llvm-D32593.patch b/deps/patches/llvm-D32593.patch new file mode 100644 index 0000000000000..19c4acb960f97 --- /dev/null +++ b/deps/patches/llvm-D32593.patch @@ -0,0 +1,83 @@ +From 5eeab81d22e07b6e12821067fced590f534c251a Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Thu, 27 Apr 2017 14:33:33 -0400 +Subject: [PATCH] [SROA] Fix crash due to bad bitcast + +Summary: +As shown in the test case, SROA was crashing when trying to split +stores (to the alloca) of loads (from anywhere), because it assumed +the pointer operand to the loads and stores had to have the same +address space. This isn't the case. Make sure to use the correct +pointer type for both the load and the store. + +Reviewers: chandlerc, majnemer, sanjoy + +Subscribers: arsenm, llvm-commits + +Differential Revision: https://reviews.llvm.org/D32593 +--- + lib/Transforms/Scalar/SROA.cpp | 7 ++++--- + test/Transforms/SROA/address-spaces.ll | 18 ++++++++++++++++++ + 2 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/lib/Transforms/Scalar/SROA.cpp b/lib/Transforms/Scalar/SROA.cpp +index d01e91a..610d5a8 100644 +--- a/lib/Transforms/Scalar/SROA.cpp ++++ b/lib/Transforms/Scalar/SROA.cpp +@@ -3697,7 +3697,8 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { + int Idx = 0, Size = Offsets.Splits.size(); + for (;;) { + auto *PartTy = Type::getIntNTy(Ty->getContext(), PartSize * 8); +- auto *PartPtrTy = PartTy->getPointerTo(SI->getPointerAddressSpace()); ++ auto *LoadPartPtrTy = PartTy->getPointerTo(LI->getPointerAddressSpace()); ++ auto *StorePartPtrTy = PartTy->getPointerTo(SI->getPointerAddressSpace()); + + // Either lookup a split load or create one. + LoadInst *PLoad; +@@ -3708,7 +3709,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { + PLoad = IRB.CreateAlignedLoad( + getAdjustedPtr(IRB, DL, LoadBasePtr, + APInt(DL.getPointerSizeInBits(), PartOffset), +- PartPtrTy, LoadBasePtr->getName() + "."), ++ LoadPartPtrTy, LoadBasePtr->getName() + "."), + getAdjustedAlignment(LI, PartOffset, DL), /*IsVolatile*/ false, + LI->getName()); + } +@@ -3718,7 +3719,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { + StoreInst *PStore = IRB.CreateAlignedStore( + PLoad, getAdjustedPtr(IRB, DL, StoreBasePtr, + APInt(DL.getPointerSizeInBits(), PartOffset), +- PartPtrTy, StoreBasePtr->getName() + "."), ++ StorePartPtrTy, StoreBasePtr->getName() + "."), + getAdjustedAlignment(SI, PartOffset, DL), /*IsVolatile*/ false); + + // Now build a new slice for the alloca. +diff --git a/test/Transforms/SROA/address-spaces.ll b/test/Transforms/SROA/address-spaces.ll +index 119f225..8fba30c 100644 +--- a/test/Transforms/SROA/address-spaces.ll ++++ b/test/Transforms/SROA/address-spaces.ll +@@ -83,3 +83,21 @@ define void @pr27557() { + store i32 addrspace(3)* @l, i32 addrspace(3)** %3, align 8 + ret void + } ++ ++; Make sure pre-splitting doesn't try to introduce an illegal bitcast ++define float @presplit(i64 addrspace(1)* %p) { ++entry: ++; CHECK-LABEL: @presplit( ++; CHECK: %[[CAST:.*]] = bitcast i64 addrspace(1)* {{.*}} to i32 addrspace(1)* ++; CHECK: load i32, i32 addrspace(1)* %[[CAST]] ++ %b = alloca i64 ++ %b.cast = bitcast i64* %b to [2 x float]* ++ %b.gep1 = getelementptr [2 x float], [2 x float]* %b.cast, i32 0, i32 0 ++ %b.gep2 = getelementptr [2 x float], [2 x float]* %b.cast, i32 0, i32 1 ++ %l = load i64, i64 addrspace(1)* %p ++ store i64 %l, i64* %b ++ %f1 = load float, float* %b.gep1 ++ %f2 = load float, float* %b.gep2 ++ %ret = fadd float %f1, %f2 ++ ret float %ret ++} +-- +2.9.3 + diff --git a/deps/patches/llvm-D33179.patch b/deps/patches/llvm-D33179.patch new file mode 100644 index 0000000000000..2be915018de24 --- /dev/null +++ b/deps/patches/llvm-D33179.patch @@ -0,0 +1,64 @@ +From b1a005ba688397ca360e89cd6c6f51f232d6c25e Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Fri, 19 May 2017 18:42:20 -0400 +Subject: [PATCH] [Sink] Fix predicate in legality check + +Summary: +isSafeToSpeculativelyExecute is the wrong predicate to use here. +All that checks for is whether it is safe to hoist a value due to +unaligned/un-dereferencable accesses. However, not only are we doing +sinking rather than hoisting, our concern is that the location +we're loading from may have been modified. Instead forbid sinking +any load across a critical edge. + +Reviewers: majnemer + +Subscribers: llvm-commits + +Differential Revision: https://reviews.llvm.org/D33179 +--- + lib/Transforms/Scalar/Sink.cpp | 2 +- + test/Transforms/Sink/badloadsink.ll | 18 ++++++++++++++++++ + 2 files changed, 19 insertions(+), 1 deletion(-) + create mode 100644 test/Transforms/Sink/badloadsink.ll + +diff --git a/lib/Transforms/Scalar/Sink.cpp b/lib/Transforms/Scalar/Sink.cpp +index 102e9ea..5210f16 100644 +--- a/lib/Transforms/Scalar/Sink.cpp ++++ b/lib/Transforms/Scalar/Sink.cpp +@@ -114,7 +114,7 @@ static bool IsAcceptableTarget(Instruction *Inst, BasicBlock *SuccToSinkTo, + if (SuccToSinkTo->getUniquePredecessor() != Inst->getParent()) { + // We cannot sink a load across a critical edge - there may be stores in + // other code paths. +- if (!isSafeToSpeculativelyExecute(Inst)) ++ if (isa(Inst)) + return false; + + // We don't want to sink across a critical edge if we don't dominate the +diff --git a/test/Transforms/Sink/badloadsink.ll b/test/Transforms/Sink/badloadsink.ll +new file mode 100644 +index 0000000..e3f4884 +--- /dev/null ++++ b/test/Transforms/Sink/badloadsink.ll +@@ -0,0 +1,18 @@ ++; RUN: opt < %s -basicaa -sink -S | FileCheck %s ++declare void @foo(i64 *) ++define i64 @sinkload(i1 %cmp) { ++; CHECK-LABEL: @sinkload ++top: ++ %a = alloca i64 ++; CHECK: call void @foo(i64* %a) ++; CHECK-NEXT: %x = load i64, i64* %a ++ call void @foo(i64* %a) ++ %x = load i64, i64* %a ++ br i1 %cmp, label %A, label %B ++A: ++ store i64 0, i64 *%a ++ br label %B ++B: ++; CHECK-NOT: load i64, i64 *%a ++ ret i64 %x ++} +-- +2.9.3 + diff --git a/doc/src/devdocs/subarrays.md b/doc/src/devdocs/subarrays.md index 16a11c39cf7e3..d77c7f68fb96b 100644 --- a/doc/src/devdocs/subarrays.md +++ b/doc/src/devdocs/subarrays.md @@ -17,9 +17,10 @@ allows you to combine these styles of indexing: for example, a 3d array `A3` can For `Array`s, linear indexing appeals to the underlying storage format: an array is laid out as a contiguous block of memory, and hence the linear index is just the offset (+1) of the corresponding entry relative to the beginning of the array. However, this is not true for many other `AbstractArray` -types: examples include `SparseMatrixCSC`, arrays that require some kind of computation (such -as interpolation), and the type under discussion here, `SubArray`. For these types, the underlying -information is more naturally described in terms of cartesian indexes. +types: examples include [`SparseMatrixCSC`](@ref), arrays that require some kind of +computation (such as interpolation), and the type under discussion here, `SubArray`. +For these types, the underlying information is more naturally described in terms of +cartesian indexes. You can manually convert from a cartesian index to a linear index with `sub2ind`, and vice versa using `ind2sub`. `getindex` and `setindex!` functions for `AbstractArray` types may include similar diff --git a/doc/src/manual/arrays.md b/doc/src/manual/arrays.md index b99ae2cb050df..755c66e9fc343 100644 --- a/doc/src/manual/arrays.md +++ b/doc/src/manual/arrays.md @@ -702,18 +702,19 @@ julia> r 0.0 0.866567 ``` -## Sparse Matrices +## Sparse Vectors and Matrices -[Sparse matrices](https://en.wikipedia.org/wiki/Sparse_matrix) are matrices that contain enough -zeros that storing them in a special data structure leads to savings in space and execution time. -Sparse matrices may be used when operations on the sparse representation of a matrix lead to considerable -gains in either time or space when compared to performing the same operations on a dense matrix. +Julia has built-in support for sparse vectors and +[sparse matrices](https://en.wikipedia.org/wiki/Sparse_matrix). Sparse arrays are arrays +that contain enough zeros that storing them in a special data structure leads to savings +in space and execution time, compared to dense arrays. -### Compressed Sparse Column (CSC) Storage +### [Compressed Sparse Column (CSC) Sparse Matrix Storage](@id man-csc) In Julia, sparse matrices are stored in the [Compressed Sparse Column (CSC) format](https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_column_.28CSC_or_CCS.29). -Julia sparse matrices have the type `SparseMatrixCSC{Tv,Ti}`, where `Tv` is the type of the stored -values, and `Ti` is the integer type for storing column pointers and row indices.: +Julia sparse matrices have the type [`SparseMatrixCSC{Tv,Ti}`](@ref), where `Tv` is the +type of the stored values, and `Ti` is the integer type for storing column pointers and +row indices. The internal representation of `SparseMatrixCSC` is as follows: ```julia struct SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti} @@ -743,19 +744,50 @@ In some applications, it is convenient to store explicit zero values in a `Spars *are* accepted by functions in `Base` (but there is no guarantee that they will be preserved in mutating operations). Such explicitly stored zeros are treated as structural nonzeros by many routines. The [`nnz()`](@ref) function returns the number of elements explicitly stored in the -sparse data structure, including structural nonzeros. In order to count the exact number of actual -values that are nonzero, use [`countnz()`](@ref), which inspects every stored element of a sparse -matrix. +sparse data structure, including structural nonzeros. In order to count the exact number of +numerical nonzeros, use [`countnz()`](@ref), which inspects every stored element of a sparse +matrix. [`dropzeros()`](@ref), and the in-place [`dropzeros!()`](@ref), can be used to +remove stored zeros from the sparse matrix. -### Sparse matrix constructors +```jldoctest +julia> A = sparse([1, 2, 3], [1, 2, 3], [0, 2, 0]) +3×3 SparseMatrixCSC{Int64,Int64} with 3 stored entries: + [1, 1] = 0 + [2, 2] = 2 + [3, 3] = 0 + +julia> dropzeros(A) +3×3 SparseMatrixCSC{Int64,Int64} with 1 stored entry: + [2, 2] = 2 +``` + +### Sparse Vector Storage + +Sparse vectors are stored in a close analog to compressed sparse column format for sparse +matrices. In Julia, sparse vectors have the type [`SparseVector{Tv,Ti}`](@ref) where `Tv` +is the type of the stored values and `Ti` the integer type for the indices. The internal +representation is as follows: + +```julia +struct SparseVector{Tv,Ti<:Integer} <: AbstractSparseVector{Tv,Ti} + n::Int # Length of the sparse vector + nzind::Vector{Ti} # Indices of stored values + nzval::Vector{Tv} # Stored values, typically nonzeros +end +``` + +As for [`SparseMatrixCSC`](@ref), the `SparseVector` type can also contain explicitly +stored zeros. (See [Sparse Matrix Storage](@ref man-csc).). -The simplest way to create sparse matrices is to use functions equivalent to the [`zeros()`](@ref) -and [`eye()`](@ref) functions that Julia provides for working with dense matrices. To produce -sparse matrices instead, you can use the same names with an `sp` prefix: +### Sparse Vector and Matrix Constructors + +The simplest way to create sparse arrays is to use functions equivalent to the [`zeros()`](@ref) +and [`eye()`](@ref) functions that Julia provides for working with dense arrays. To produce +sparse arrays instead, you can use the same names with an `sp` prefix: ```jldoctest -julia> spzeros(3,5) -3×5 SparseMatrixCSC{Float64,Int64} with 0 stored entries +julia> spzeros(3) +3-element SparseVector{Float64,Int64} with 0 stored entries julia> speye(3,5) 3×5 SparseMatrixCSC{Float64,Int64} with 3 stored entries: @@ -764,9 +796,14 @@ julia> speye(3,5) [3, 3] = 1.0 ``` -The [`sparse()`](@ref) function is often a handy way to construct sparse matrices. It takes as -its input a vector `I` of row indices, a vector `J` of column indices, and a vector `V` of stored -values. `sparse(I,J,V)` constructs a sparse matrix such that `S[I[k], J[k]] = V[k]`. +The [`sparse()`](@ref) function is often a handy way to construct sparse arrays. For +example, to construct a sparse matrix we can input a vector `I` of row indices, a vector +`J` of column indices, and a vector `V` of stored values (this is also known as the +[COO (coordinate) format](https://en.wikipedia.org/wiki/Sparse_matrix#Coordinate_list_.28COO.29)). +`sparse(I,J,V)` then constructs a sparse matrix such that `S[I[k], J[k]] = V[k]`. The +equivalent sparse vector constructor is [`sparsevec`](@ref), which takes the (row) index +vector `I` and the vector `V` with the stored values and constructs a sparse vector `R` +such that `R[I[k]] = V[k]`. ```jldoctest sparse_function julia> I = [1, 4, 3, 5]; J = [4, 7, 18, 9]; V = [1, 2, -5, 3]; @@ -777,20 +814,38 @@ julia> S = sparse(I,J,V) [4 , 7] = 2 [5 , 9] = 3 [3 , 18] = -5 + +julia> R = sparsevec(I,V) +5-element SparseVector{Int64,Int64} with 4 stored entries: + [1] = 1 + [3] = -5 + [4] = 2 + [5] = 3 ``` -The inverse of the [`sparse()`](@ref) function is [`findn()`](@ref), which retrieves the inputs -used to create the sparse matrix. +The inverse of the [`sparse()`](@ref) and [`sparsevec`](@ref) functions is +[`findnz()`](@ref), which retrieves the inputs used to create the sparse array. +There is also a [`findn`](@ref) function which only returns the index vectors. ```jldoctest sparse_function +julia> findnz(S) +([1, 4, 5, 3], [4, 7, 9, 18], [1, 2, 3, -5]) + julia> findn(S) ([1, 4, 5, 3], [4, 7, 9, 18]) -julia> findnz(S) -([1, 4, 5, 3], [4, 7, 9, 18], [1, 2, 3, -5]) +julia> findnz(R) +([1, 3, 4, 5], [1, -5, 2, 3]) + +julia> findn(R) +4-element Array{Int64,1}: + 1 + 3 + 4 + 5 ``` -Another way to create sparse matrices is to convert a dense matrix into a sparse matrix using +Another way to create a sparse array is to convert a dense array into a sparse array using the [`sparse()`](@ref) function: ```jldoctest @@ -801,9 +856,14 @@ julia> sparse(eye(5)) [3, 3] = 1.0 [4, 4] = 1.0 [5, 5] = 1.0 + +julia> sparse([1.0, 0.0, 1.0]) +3-element SparseVector{Float64,Int64} with 2 stored entries: + [1] = 1.0 + [3] = 1.0 ``` -You can go in the other direction using the [`full()`](@ref) function. The [`issparse()`](@ref) +You can go in the other direction using the [`Array`](@ref) constructor. The [`issparse()`](@ref) function can be used to query if a matrix is sparse. ```jldoctest @@ -828,8 +888,8 @@ differ from their dense counterparts in that the resulting matrix follows the sa as a given sparse matrix `S`, or that the resulting sparse matrix has density `d`, i.e. each matrix element has a probability `d` of being non-zero. -Details can be found in the [Sparse Vectors and Matrices](@ref) section of the standard library -reference. +Details can be found in the [Sparse Vectors and Matrices](@ref stdlib-sparse-arrays) +section of the standard library reference. | Sparse | Dense | Description | |:-------------------------- |:---------------------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index 462eb8c3b72da..7c5263a2f27c6 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -235,8 +235,8 @@ ERROR: DomainError: Cannot raise an integer x to a negative power -n. Make x a float by adding a zero decimal (e.g. 2.0^-n instead of 2^-n), or write 1/x^n, float(x)^-n, or (x//1)^-n. Stacktrace: - [1] power_by_squaring(::Int64, ::Int64) at ./intfuncs.jl:170 - [2] literal_pow(::Base.#^, ::Int64, ::Type{Val{-5}}) at ./intfuncs.jl:205 + [1] power_by_squaring(::Int64, ::Int64) at ./intfuncs.jl:173 + [2] literal_pow(::Base.#^, ::Int64, ::Type{Val{-5}}) at ./intfuncs.jl:208 ``` This behavior is an inconvenient consequence of the requirement for type-stability. In the case diff --git a/doc/src/manual/functions.md b/doc/src/manual/functions.md index 1793befa0beed..a6bf9ed8c72e0 100644 --- a/doc/src/manual/functions.md +++ b/doc/src/manual/functions.md @@ -392,7 +392,7 @@ interprets a string as a number in some base. The `base` argument defaults to `1 can be expressed concisely as: ```julia -function parse(type, num, base=10) +function parse(T, num, base=10) ### end ``` diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 91ae4fbe21e57..3b679db3d8aa8 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -231,8 +231,9 @@ arrays are simple: just define `getindex(A::ArrayType, i::Int)`. When the array indexed with a multidimensional set of indices, the fallback `getindex(A::AbstractArray, I...)()` efficiently converts the indices into one linear index and then calls the above method. `IndexCartesian()` arrays, on the other hand, require methods to be defined for each supported dimensionality with -`ndims(A)``Int` indices. For example, the builtin `SparseMatrixCSC` type only supports two dimensions, -so it just defines `getindex(A::SparseMatrixCSC, i::Int, j::Int)()`. The same holds for `setindex!()`. +`ndims(A)` `Int` indices. For example, the built-in [`SparseMatrixCSC`](@ref) type only +supports two dimensions, so it just defines +`getindex(A::SparseMatrixCSC, i::Int, j::Int)`. The same holds for `setindex!()`. Returning to the sequence of squares from above, we could instead define it as a subtype of an `AbstractArray{Int, 1}`: diff --git a/doc/src/manual/linear-algebra.md b/doc/src/manual/linear-algebra.md index af5ff9a2766f4..16ba1b10fb70c 100644 --- a/doc/src/manual/linear-algebra.md +++ b/doc/src/manual/linear-algebra.md @@ -144,29 +144,29 @@ specialized routines that are specially developed for particular matrix types. The following tables summarize the types of special matrices that have been implemented in Julia, as well as whether hooks to various optimized methods for them in LAPACK are available. -| Type | Description | -|:------------------------ |:-------------------------------------------------------------------------------- | -| [`Hermitian`](@ref) | [Hermitian matrix](https://en.wikipedia.org/wiki/Hermitian_matrix) | -| `UpperTriangular` | Upper [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) | -| `LowerTriangular` | Lower [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) | -| [`Tridiagonal`](@ref) | [Tridiagonal matrix](https://en.wikipedia.org/wiki/Tridiagonal_matrix) | -| [`SymTridiagonal`](@ref) | Symmetric tridiagonal matrix | -| [`Bidiagonal`](@ref) | Upper/lower [bidiagonal matrix](https://en.wikipedia.org/wiki/Bidiagonal_matrix) | -| [`Diagonal`](@ref) | [Diagonal matrix](https://en.wikipedia.org/wiki/Diagonal_matrix) | -| `UniformScaling` | [Uniform scaling operator](https://en.wikipedia.org/wiki/Uniform_scaling) | +| Type | Description | +|:------------------------- |:-------------------------------------------------------------------------------- | +| [`Hermitian`](@ref) | [Hermitian matrix](https://en.wikipedia.org/wiki/Hermitian_matrix) | +| [`UpperTriangular`](@ref) | Upper [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) | +| [`LowerTriangular`](@ref) | Lower [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) | +| [`Tridiagonal`](@ref) | [Tridiagonal matrix](https://en.wikipedia.org/wiki/Tridiagonal_matrix) | +| [`SymTridiagonal`](@ref) | Symmetric tridiagonal matrix | +| [`Bidiagonal`](@ref) | Upper/lower [bidiagonal matrix](https://en.wikipedia.org/wiki/Bidiagonal_matrix) | +| [`Diagonal`](@ref) | [Diagonal matrix](https://en.wikipedia.org/wiki/Diagonal_matrix) | +| `UniformScaling` | [Uniform scaling operator](https://en.wikipedia.org/wiki/Uniform_scaling) | ### Elementary operations -| Matrix type | `+` | `-` | `*` | `\` | Other functions with optimized methods | -|:------------------------ |:--- |:--- |:--- |:--- |:------------------------------------------------------------------- | -| [`Hermitian`](@ref) |   |   |   | MV | [`inv()`](@ref), [`sqrtm()`](@ref), [`expm()`](@ref) | -| `UpperTriangular` |   |   | MV | MV | [`inv()`](@ref), [`det()`](@ref) | -| `LowerTriangular` |   |   | MV | MV | [`inv()`](@ref), [`det()`](@ref) | -| [`SymTridiagonal`](@ref) | M | M | MS | MV | [`eigmax()`](@ref), [`eigmin()`](@ref) | -| [`Tridiagonal`](@ref) | M | M | MS | MV |   | -| [`Bidiagonal`](@ref) | M | M | MS | MV |   | -| [`Diagonal`](@ref) | M | M | MV | MV | [`inv()`](@ref), [`det()`](@ref), [`logdet()`](@ref), [`/()`](@ref) | -| `UniformScaling` | M | M | MVS | MVS | [`/()`](@ref) | +| Matrix type | `+` | `-` | `*` | `\` | Other functions with optimized methods | +|:------------------------- |:--- |:--- |:--- |:--- |:------------------------------------------------------------------- | +| [`Hermitian`](@ref) |   |   |   | MV | [`inv()`](@ref), [`sqrtm()`](@ref), [`expm()`](@ref) | +| [`UpperTriangular`](@ref) |   |   | MV | MV | [`inv()`](@ref), [`det()`](@ref) | +| [`LowerTriangular`](@ref) |   |   | MV | MV | [`inv()`](@ref), [`det()`](@ref) | +| [`SymTridiagonal`](@ref) | M | M | MS | MV | [`eigmax()`](@ref), [`eigmin()`](@ref) | +| [`Tridiagonal`](@ref) | M | M | MS | MV |   | +| [`Bidiagonal`](@ref) | M | M | MS | MV |   | +| [`Diagonal`](@ref) | M | M | MV | MV | [`inv()`](@ref), [`det()`](@ref), [`logdet()`](@ref), [`/()`](@ref) | +| `UniformScaling` | M | M | MVS | MVS | [`/()`](@ref) | Legend: @@ -178,15 +178,15 @@ Legend: ### Matrix factorizations -| Matrix type | LAPACK | [`eig()`](@ref) | [`eigvals()`](@ref) | [`eigvecs()`](@ref) | [`svd()`](@ref) | [`svdvals()`](@ref) | -|:------------------------ |:------ |:--------------- |:------------------- |:------------------- |:--------------- |:------------------- | -| [`Hermitian`](@ref) | HE |   | ARI |   |   |   | -| `UpperTriangular` | TR | A | A | A |   |   | -| `LowerTriangular` | TR | A | A | A |   |   | -| [`SymTridiagonal`](@ref) | ST | A | ARI | AV |   |   | -| [`Tridiagonal`](@ref) | GT |   |   |   |   |   | -| [`Bidiagonal`](@ref) | BD |   |   |   | A | A | -| [`Diagonal`](@ref) | DI |   | A |   |   |   | +| Matrix type | LAPACK | [`eig()`](@ref) | [`eigvals()`](@ref) | [`eigvecs()`](@ref) | [`svd()`](@ref) | [`svdvals()`](@ref) | +|:------------------------- |:------ |:--------------- |:------------------- |:------------------- |:--------------- |:------------------- | +| [`Hermitian`](@ref) | HE |   | ARI |   |   |   | +| [`UpperTriangular`](@ref) | TR | A | A | A |   |   | +| [`LowerTriangular`](@ref) | TR | A | A | A |   |   | +| [`SymTridiagonal`](@ref) | ST | A | ARI | AV |   |   | +| [`Tridiagonal`](@ref) | GT |   |   |   |   |   | +| [`Bidiagonal`](@ref) | BD |   |   |   | A | A | +| [`Diagonal`](@ref) | DI |   | A |   |   |   | Legend: diff --git a/doc/src/manual/mathematical-operations.md b/doc/src/manual/mathematical-operations.md index a6e8da1fff8f3..4ec482ff36f64 100644 --- a/doc/src/manual/mathematical-operations.md +++ b/doc/src/manual/mathematical-operations.md @@ -397,7 +397,7 @@ julia> Int8(127) julia> Int8(128) ERROR: InexactError() Stacktrace: - [1] Int8(::Int64) at ./sysimg.jl:24 + [1] Int8(::Int64) at ./sysimg.jl:77 julia> Int8(127.0) 127 @@ -406,13 +406,13 @@ julia> Int8(3.14) ERROR: InexactError() Stacktrace: [1] convert(::Type{Int8}, ::Float64) at ./float.jl:658 - [2] Int8(::Float64) at ./sysimg.jl:24 + [2] Int8(::Float64) at ./sysimg.jl:77 julia> Int8(128.0) ERROR: InexactError() Stacktrace: [1] convert(::Type{Int8}, ::Float64) at ./float.jl:658 - [2] Int8(::Float64) at ./sysimg.jl:24 + [2] Int8(::Float64) at ./sysimg.jl:77 julia> 127 % Int8 127 diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index 1668bfe5a0260..e1a0118b6f658 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -33,7 +33,7 @@ julia> typeof(ex1) Expr ``` -`Expr` objects contain three parts: +`Expr` objects contain two parts: * a `Symbol` identifying the kind of expression. A symbol is an [interned string](https://en.wikipedia.org/wiki/String_interning) identifier (more discussion below). @@ -53,14 +53,6 @@ julia> ex1.args 1 ``` - * finally, the expression result type, which may be annotated by the user or inferred by the compiler - (and may be ignored completely for the purposes of this chapter): - -```jldoctest prog -julia> ex1.typ -Any -``` - Expressions may also be constructed directly in [prefix notation](https://en.wikipedia.org/wiki/Polish_notation): ```jldoctest prog diff --git a/doc/src/manual/noteworthy-differences.md b/doc/src/manual/noteworthy-differences.md index 98740263fc364..ba2e1cae9cb34 100644 --- a/doc/src/manual/noteworthy-differences.md +++ b/doc/src/manual/noteworthy-differences.md @@ -146,7 +146,7 @@ For users coming to Julia from R, these are some noteworthy differences: For example: * Functions pertaining to probability distributions are provided by the [Distributions package](https://github.com/JuliaStats/Distributions.jl). - * The [DataFrames package](https://github.com/JuliaStats/DataFrames.jl) provides data frames. + * The [DataFrames package](https://github.com/JuliaData/DataFrames.jl) provides data frames. * Generalized linear models are provided by the [GLM package](https://github.com/JuliaStats/GLM.jl). * Julia provides tuples and real hash tables, but not R-style lists. When returning multiple items, you should typically use a tuple: instead of `list(a = 1, b = 2)`, use `(1, 2)`. diff --git a/doc/src/manual/packages.md b/doc/src/manual/packages.md index 569806656811f..ea024571f6f32 100644 --- a/doc/src/manual/packages.md +++ b/doc/src/manual/packages.md @@ -978,25 +978,20 @@ By "forking" the main METADATA repository, you can create a personal copy (of ME your GitHub account. Once that copy exists, you can push your local changes to your copy (just like any other GitHub project). -1. go to [https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2FJuliaLang%2FMETADATA.jl%2Ffork](https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2FJuliaLang%2FMETADATA.jl%2Ffork) -and create your own fork. +1. Create a [fork of METADATA.jl](https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2FJuliaLang%2FMETADATA.jl%2Ffork). -2. add your fork as a remote repository for the METADATA repository on your local computer (in -the terminal where USERNAME is your github username): +2. Add your fork as a remote repository for the METADATA repository on your local computer (in + the terminal where USERNAME is your github username): -``` -cd ~/.julia/v0.6/METADATA -git remote add USERNAME https://github.com/USERNAME/METADATA.jl.git -``` + cd ~/.julia/v0.6/METADATA + git remote add USERNAME https://github.com/USERNAME/METADATA.jl.git -1. push your changes to your fork: +3. Push your changes to your fork: - ``` - git push USERNAME metadata-v2 - ``` + git push USERNAME metadata-v2 4. If all of that works, then go back to the GitHub page for your fork, and click the "pull request" -link. + link. ## Fixing Package Requirements diff --git a/doc/src/manual/parallel-computing.md b/doc/src/manual/parallel-computing.md index 4d2fb1e97de39..8b3c15dc379c3 100644 --- a/doc/src/manual/parallel-computing.md +++ b/doc/src/manual/parallel-computing.md @@ -1231,8 +1231,8 @@ as local laptops, departmental clusters, or even the cloud. This section covers requirements for the inbuilt `LocalManager` and `SSHManager`: * The master process does not listen on any port. It only connects out to the workers. - * Each worker binds to only one of the local interfaces and listens on the first free port starting - from `9009`. + * Each worker binds to only one of the local interfaces and listens on an ephemeral port number + assigned by the OS. * `LocalManager`, used by `addprocs(N)`, by default binds only to the loopback interface. This means that workers started later on remote hosts (or by anyone with malicious intentions) are unable to connect to the cluster. An `addprocs(4)` followed by an `addprocs(["remote_host"])` will fail. @@ -1250,8 +1250,9 @@ requirements for the inbuilt `LocalManager` and `SSHManager`: authenticated via public key infrastructure (PKI). Authentication credentials can be supplied via `sshflags`, for example ```sshflags=`-e ` ```. - Note that worker-worker connections are still plain TCP and the local security policy on the remote - cluster must allow for free connections between worker nodes, at least for ports 9009 and above. + In an all-to-all topology (the default), all workers connect to each other via plain TCP sockets. + The security policy on the cluster nodes must thus ensure free connectivity between workers for + the ephemeral port range (varies by OS). Securing and encrypting all worker-worker traffic (via SSH) or encrypting individual messages can be done via a custom ClusterManager. diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index a1298af12de5b..206878a8becf3 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -712,7 +712,7 @@ julia> m[2] ``` Captures can be referenced in a substitution string when using [`replace()`](@ref) by using `\n` -to refer to the nth capture group and prefixing the subsitution string with `s`. Capture group +to refer to the nth capture group and prefixing the substitution string with `s`. Capture group 0 refers to the entire match object. Named capture groups can be referenced in the substitution with `g`. For example: diff --git a/doc/src/manual/types.md b/doc/src/manual/types.md index 97c59738623ec..938a32e39f011 100644 --- a/doc/src/manual/types.md +++ b/doc/src/manual/types.md @@ -651,7 +651,7 @@ ERROR: MethodError: Cannot `convert` an object of type Float64 to an object of t This may have arisen from a call to the constructor Point{Float64}(...), since type constructors fall back to convert methods. Stacktrace: - [1] Point{Float64}(::Float64) at ./sysimg.jl:24 + [1] Point{Float64}(::Float64) at ./sysimg.jl:77 julia> Point{Float64}(1.0,2.0,3.0) ERROR: MethodError: no method matching Point{Float64}(::Float64, ::Float64, ::Float64) diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index 2fc43f52bee53..9249b11925f47 100644 --- a/doc/src/stdlib/arrays.md +++ b/doc/src/stdlib/arrays.md @@ -172,12 +172,14 @@ Base.ror! Base.ror ``` -## Sparse Vectors and Matrices +## [Sparse Vectors and Matrices](@id stdlib-sparse-arrays) Sparse vectors and matrices largely support the same set of operations as their dense counterparts. The following functions are specific to sparse arrays. ```@docs +Base.SparseArrays.SparseVector +Base.SparseArrays.SparseMatrixCSC Base.SparseArrays.sparse Base.SparseArrays.sparsevec Base.SparseArrays.issparse diff --git a/doc/src/stdlib/linalg.md b/doc/src/stdlib/linalg.md index 66dde6330d3e8..3e90cb5b2cafe 100644 --- a/doc/src/stdlib/linalg.md +++ b/doc/src/stdlib/linalg.md @@ -18,6 +18,8 @@ Base.LinAlg.SymTridiagonal Base.LinAlg.Tridiagonal Base.LinAlg.Symmetric Base.LinAlg.Hermitian +Base.LinAlg.LowerTriangular +Base.LinAlg.UpperTriangular Base.LinAlg.lu Base.LinAlg.lufact Base.LinAlg.lufact! diff --git a/doc/src/stdlib/test.md b/doc/src/stdlib/test.md index 62ec7e4f3d4ac..baf78ae1c16b6 100644 --- a/doc/src/stdlib/test.md +++ b/doc/src/stdlib/test.md @@ -1,5 +1,11 @@ # Unit Testing +```@meta +DocTestSetup = quote + using Base.Test +end +``` + ## Testing Base Julia Julia is under rapid development and has an extensive test suite to verify functionality across @@ -26,7 +32,7 @@ Base.Test.@test_throws For example, suppose we want to check our new function `foo(x)` works as expected: -```julia-repl +```jldoctest testfoo julia> using Base.Test julia> foo(x) = length(x)^2 @@ -35,28 +41,22 @@ foo (generic function with 1 method) If the condition is true, a `Pass` is returned: -```julia-repl +```jldoctest testfoo julia> @test foo("bar") == 9 Test Passed - Expression: foo("bar") == 9 - Evaluated: 9 == 9 julia> @test foo("fizz") >= 10 Test Passed - Expression: foo("fizz") >= 10 - Evaluated: 16 >= 10 ``` If the condition is false, then a `Fail` is returned and an exception is thrown: -```julia-repl +```jldoctest testfoo julia> @test foo("f") == 20 Test Failed Expression: foo("f") == 20 Evaluated: 1 == 20 ERROR: There was an error during testing - in record at test.jl:268 - in do_test at test.jl:191 ``` If the condition could not be evaluated because an exception was thrown, which occurs in this @@ -68,23 +68,24 @@ julia> @test foo(:cat) == 1 Error During Test Test threw an exception of type MethodError Expression: foo(:cat) == 1 - MethodError: `length` has no method matching length(::Symbol) - in foo at none:1 - in anonymous at test.jl:159 - in do_test at test.jl:180 + MethodError: no method matching length(::Symbol) + Closest candidates are: + length(::SimpleVector) at essentials.jl:256 + length(::Base.MethodList) at reflection.jl:521 + length(::MethodTable) at reflection.jl:597 + ... + Stacktrace: + [...] ERROR: There was an error during testing - in record at test.jl:268 - in do_test at test.jl:191 ``` If we expect that evaluating an expression *should* throw an exception, then we can use `@test_throws()` to check that this occurs: -```julia-repl +```jldoctest testfoo julia> @test_throws MethodError foo(:cat) Test Passed - Expression: foo(:cat) - Evaluated: MethodError + Thrown: MethodError ``` ## Working with Test Sets @@ -104,19 +105,19 @@ Base.Test.@testset We can put our tests for the `foo(x)` function in a test set: -```julia-repl +```jldoctest testfoo julia> @testset "Foo Tests" begin @test foo("a") == 1 @test foo("ab") == 4 @test foo("abc") == 9 - end + end; Test Summary: | Pass Total Foo Tests | 3 3 ``` Test sets can also be nested: -```julia-repl +```jldoctest testfoo julia> @testset "Foo Tests" begin @testset "Animals" begin @test foo("cat") == 9 @@ -126,7 +127,7 @@ julia> @testset "Foo Tests" begin @test foo(zeros(i)) == i^2 @test foo(ones(i)) == i^2 end - end + end; Test Summary: | Pass Total Foo Tests | 8 8 ``` @@ -153,14 +154,13 @@ julia> @testset "Foo Tests" begin Arrays: Test Failed Expression: foo(ones(4)) == 15 Evaluated: 16 == 15 - in record at test.jl:297 - in do_test at test.jl:191 +Stacktrace: + [...] Test Summary: | Pass Fail Total Foo Tests | 3 1 4 Animals | 2 2 Arrays | 1 1 2 ERROR: Some tests did not pass: 3 passed, 1 failed, 0 errored, 0 broken. - in finish at test.jl:362 ``` ## Other Test Macros @@ -169,15 +169,15 @@ As calculations on floating-point values can be imprecise, you can perform appro checks using either `@test a ≈ b` (where `≈`, typed via tab completion of `\approx`, is the [`isapprox()`](@ref) function) or use [`isapprox()`](@ref) directly. -```julia-repl +```jldoctest julia> @test 1 ≈ 0.999999999 +Test Passed julia> @test 1 ≈ 0.999999 -ERROR: test failed: 1 isapprox 0.999999 - in expression: 1 ≈ 0.999999 - in error at error.jl:21 - in default_handler at test.jl:30 - in do_test at test.jl:53 +Test Failed + Expression: 1 ≈ 0.999999 + Evaluated: 1 ≈ 0.999999 +ERROR: There was an error during testing ``` ```@docs @@ -264,3 +264,7 @@ And using that testset looks like: end end ``` + +```@meta +DocTestSetup = nothing +``` diff --git a/examples/embedding/embedding-test.jl b/examples/embedding/embedding-test.jl index 336169085db4c..8081bdc6d36bc 100644 --- a/examples/embedding/embedding-test.jl +++ b/examples/embedding/embedding-test.jl @@ -4,17 +4,19 @@ using Base.Test @test length(ARGS) == 1 -let +@testset "embedding example" begin stdout = Pipe() stderr = Pipe() p = spawn(pipeline(Cmd(ARGS), stdin=DevNull, stdout=stdout, stderr=stderr)) close(stdout.in) close(stderr.in) - stderr_task = @async readlines(stderr) - lines = readlines(stdout) - @test length(lines) == 6 - @test parse(Float64, lines[1]) ≈ sqrt(2) - lines = wait(stderr_task) - @test lines == ["UndefVarError(:this_function_does_not_exist)"] + stdout_task = @async readlines(stdout) + stderr = readstring(stderr) + @test stderr == "MethodError: no method matching this_function_has_no_methods()\n" @test success(p) + lines = wait(stdout_task) + @test length(lines) == 9 + @test parse(Float64, lines[1]) ≈ sqrt(2) + @test lines[8] == "called bar" + @test lines[9] == "calling new bar" end diff --git a/examples/embedding/embedding.c b/examples/embedding/embedding.c index 5bb70aadc04c2..a4172a1b18583 100644 --- a/examples/embedding/embedding.c +++ b/examples/embedding/embedding.c @@ -12,22 +12,39 @@ double my_c_sqrt(double x) return sqrt(x); } +jl_value_t *checked_eval_string(const char* code) +{ + jl_value_t *result = jl_eval_string(code); + if (jl_exception_occurred()) { + // none of these allocate, so a gc-root (JL_GC_PUSH) is not necessary + jl_call2(jl_get_function(jl_base_module, "showerror"), + jl_stderr_obj(), + jl_exception_occurred()); + jl_printf(jl_stderr_stream(), "\n"); + jl_atexit_hook(1); + exit(1); + } + assert(result && "Missing return value but no exception occurred!"); + return result; +} + int main() { jl_init(); { - // Simple running Julia code + // Simple running of Julia code - jl_eval_string("println(sqrt(2.0))"); + checked_eval_string("println(sqrt(2.0))"); } { // Accessing the return value - jl_value_t *ret = jl_eval_string("sqrt(2.0)"); + jl_value_t *ret = checked_eval_string("sqrt(2.0)"); double retDouble = jl_unbox_float64(ret); printf("sqrt(2.0) in C: %e\n", retDouble); + fflush(stdout); } { @@ -38,62 +55,98 @@ int main() jl_value_t* ret = jl_call1(func, argument); double retDouble = jl_unbox_float64(ret); printf("sqrt(2.0) in C: %e\n", retDouble); + fflush(stdout); } { // 1D arrays - jl_value_t* array_type = jl_apply_array_type( (jl_value_t*)jl_float64_type, 1 ); - jl_array_t* x = jl_alloc_array_1d(array_type , 10); + jl_value_t* array_type = jl_apply_array_type((jl_value_t*)jl_float64_type, 1); + jl_array_t* x = jl_alloc_array_1d(array_type, 10); + // JL_GC_PUSH* is required here to ensure that `x` is not deleted before + // (aka, is gc-rooted until) the program reaches the corresponding JL_GC_POP() JL_GC_PUSH1(&x); double* xData = jl_array_data(x); size_t i; - for(i=0; i println( ccall(my_c_sqrt, Float64, (Float64,), 2.0) )"); + jl_call1(call_by_ptr, jl_box_voidpointer(my_c_sqrt)); } { - // check for exceptions + // Handling exceptions gracefully - jl_eval_string("this_function_does_not_exist()"); + jl_value_t *f = checked_eval_string("function this_function_has_no_methods end"); + jl_call0(f); if (jl_exception_occurred()) { - jl_call2(jl_get_function(jl_base_module, "show"), jl_stderr_obj(), jl_exception_occurred()); + jl_call2(jl_get_function(jl_base_module, "showerror"), + jl_stderr_obj(), + jl_exception_occurred()); jl_printf(jl_stderr_stream(), "\n"); } } + { + // Creating and using a native C function handle + // to a Julia function signature + + checked_eval_string( + "function bar()\n" + " println(\"called bar\")\n" + " random_return_value = 42\n" + "end"); + checked_eval_string( + "function bar_from_c()\n" + " bar()\n" + " nothing\n" + "end"); + typedef void (*Func_VOID__VOID)(void); + jl_value_t *pbar = jl_eval_string("cfunction(bar_from_c, Void, ())"); + Func_VOID__VOID bar = (Func_VOID__VOID)jl_unbox_voidpointer(pbar); + bar(); + checked_eval_string("bar() = println(\"calling new bar\")"); + bar(); + } + int ret = 0; jl_atexit_hook(ret); return ret; diff --git a/src/ccall.cpp b/src/ccall.cpp index 6edf5cd222532..f0553fb4d9ee6 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1977,7 +1977,6 @@ jl_cgval_t function_sig_t::emit_a_ccall( else { if (jl_is_abstract_ref_type(jargty)) { emit_error("ccall: & on a Ref{T} argument is invalid", ctx); - JL_GC_POP(); return jl_cgval_t(); } v = julia_to_address(largty, jargty_in_env, unionall_env, arg, @@ -1986,7 +1985,6 @@ jl_cgval_t function_sig_t::emit_a_ccall( } if (isa(v)) { - JL_GC_POP(); return jl_cgval_t(); } assert(v->getType() == pargty); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index e9554702765fb..44f60c84f990a 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1726,17 +1726,24 @@ static Value *emit_array_nd_index(const jl_cgval_t &ainfo, jl_value_t *ex, ssize // the accessed array, i.e. `if !(i < alen) goto error`. if (nidxs > 1) { // TODO: REMOVE DEPWARN AND RETURN FALSE AFTER 0.6. - // We need to check if this is inside the non-linearized size + // We need to check if this index is inside its non-linearized dimension BasicBlock *partidx = BasicBlock::Create(jl_LLVMContext, "partlinidx"); BasicBlock *partidxwarn = BasicBlock::Create(jl_LLVMContext, "partlinidxwarn"); + BasicBlock *trailingcheck = BasicBlock::Create(jl_LLVMContext, "trailingcheck"); Value *d = emit_arraysize_for_unsafe_dim(ainfo, ex, nidxs, nd, ctx); - builder.CreateCondBr(builder.CreateICmpULT(ii, d), endBB, partidx); + Value *alen = emit_arraylen(ainfo, ex, ctx); + builder.CreateCondBr(builder.CreateICmpULT(ii, d), trailingcheck, partidx); + + // If it is inside its own dimension, we still need to ensure all other + // dimensions are non-zero + ctx->f->getBasicBlockList().push_back(trailingcheck); + builder.SetInsertPoint(trailingcheck); + builder.CreateCondBr(builder.CreateICmpULT(ii, alen), endBB, failBB); // We failed the normal bounds check; check to see if we're // inside the linearized size (partial linear indexing): ctx->f->getBasicBlockList().push_back(partidx); builder.SetInsertPoint(partidx); - Value *alen = emit_arraylen(ainfo, ex, ctx); builder.CreateCondBr(builder.CreateICmpULT(i, alen), partidxwarn, failBB); // We passed the linearized bounds check; now throw the depwarn: diff --git a/src/codegen.cpp b/src/codegen.cpp index 66b7d73a6228c..1e08cfce6b336 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2620,6 +2620,8 @@ static Value *emit_f_is(const jl_cgval_t &arg1, const jl_cgval_t &arg2, jl_codec if ((jl_is_type_type(rt1) && jl_is_leaf_type(jl_tparam0(rt1))) || (jl_is_type_type(rt2) && jl_is_leaf_type(jl_tparam0(rt2)))) // can compare leaf types by pointer ptr_comparable = 1; + if (rt1 == (jl_value_t*)jl_simplevector_type && rt2 == (jl_value_t*)jl_simplevector_type) + ptr_comparable = 0; // technically mutable, but compared by contents if (ptr_comparable) { Value *varg1 = arg1.constant ? literal_pointer_val(arg1.constant) : arg1.V; Value *varg2 = arg2.constant ? literal_pointer_val(arg2.constant) : arg2.V; diff --git a/src/dump.c b/src/dump.c index baa4729c98be3..0b9d3e228da5e 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1277,8 +1277,8 @@ static void jl_collect_backedges_to(jl_method_instance_t *caller, jl_array_t *di jl_array_t **pcallees = (jl_array_t**)ptrhash_bp(&edges_map, (void*)caller), *callees = *pcallees; if (callees != HT_NOTFOUND) { - arraylist_push(to_restore, (void*)pcallees); arraylist_push(to_restore, (void*)callees); + arraylist_push(to_restore, (void*)pcallees); *pcallees = (jl_array_t*) HT_NOTFOUND; jl_array_ptr_1d_append(direct_callees, callees); size_t i, l = jl_array_len(callees); diff --git a/src/gf.c b/src/gf.c index 44dbb4ad28005..5886714211dc1 100644 --- a/src/gf.c +++ b/src/gf.c @@ -238,46 +238,39 @@ jl_code_info_t *jl_type_infer(jl_method_instance_t **pli, size_t world, int forc JL_TIMING(INFERENCE); if (jl_typeinf_func == NULL) return NULL; - jl_code_info_t *src = NULL; #ifdef ENABLE_INFERENCE jl_method_instance_t *li = *pli; - jl_module_t *mod = NULL; - if (li->def != NULL) - mod = li->def->module; - static int inInference = 0; - int lastIn = inInference; - size_t last_age = jl_get_ptls_states()->world_age; - inInference = 1; - if (force || - (last_age != jl_typeinf_world && - mod != jl_gf_mtable(jl_typeinf_func)->module && - (mod != jl_core_module || !lastIn))) { // avoid any potential recursion in calling jl_typeinf_func on itself - assert(li->inInference == 0 && "unexpectedly asked to infer a method that is already being inferred"); - jl_value_t **fargs; - JL_GC_PUSHARGS(fargs, 3); - fargs[0] = (jl_value_t*)jl_typeinf_func; - fargs[1] = (jl_value_t*)li; - fargs[2] = jl_box_ulong(world); + if (li->inInference && !force) + return NULL; + + jl_value_t **fargs; + JL_GC_PUSHARGS(fargs, 3); + fargs[0] = (jl_value_t*)jl_typeinf_func; + fargs[1] = (jl_value_t*)li; + fargs[2] = jl_box_ulong(world); #ifdef TRACE_INFERENCE - if (li->specTypes != (jl_value_t*)jl_emptytuple_type) { - jl_printf(JL_STDERR,"inference on "); - jl_static_show_func_sig(JL_STDERR, (jl_value_t*)li->specTypes); - jl_printf(JL_STDERR, "\n"); - } + if (li->specTypes != (jl_value_t*)jl_emptytuple_type) { + jl_printf(JL_STDERR,"inference on "); + jl_static_show_func_sig(JL_STDERR, (jl_value_t*)li->specTypes); + jl_printf(JL_STDERR, "\n"); + } #endif - jl_get_ptls_states()->world_age = jl_typeinf_world; - jl_svec_t *linfo_src_rettype = (jl_svec_t*)jl_apply_with_saved_exception_state(fargs, 3, 0); - jl_get_ptls_states()->world_age = last_age; - assert((li->def || li->inInference == 0) && "inference failed on a toplevel expr"); - if (jl_is_svec(linfo_src_rettype) && jl_svec_len(linfo_src_rettype) == 3 && - jl_is_method_instance(jl_svecref(linfo_src_rettype, 0)) && - jl_is_code_info(jl_svecref(linfo_src_rettype, 1))) { - *pli = (jl_method_instance_t*)jl_svecref(linfo_src_rettype, 0); - src = (jl_code_info_t*)jl_svecref(linfo_src_rettype, 1); - } - JL_GC_POP(); + jl_ptls_t ptls = jl_get_ptls_states(); + size_t last_age = ptls->world_age; + ptls->world_age = jl_typeinf_world; + li->inInference = 1; + jl_svec_t *linfo_src_rettype = (jl_svec_t*)jl_apply_with_saved_exception_state(fargs, 3, 0); + ptls->world_age = last_age; + assert((li->def || li->inInference == 0) && "inference failed on a toplevel expr"); + + jl_code_info_t *src = NULL; + if (jl_is_svec(linfo_src_rettype) && jl_svec_len(linfo_src_rettype) == 3 && + jl_is_method_instance(jl_svecref(linfo_src_rettype, 0)) && + jl_is_code_info(jl_svecref(linfo_src_rettype, 1))) { + *pli = (jl_method_instance_t*)jl_svecref(linfo_src_rettype, 0); + src = (jl_code_info_t*)jl_svecref(linfo_src_rettype, 1); } - inInference = lastIn; + JL_GC_POP(); #endif return src; } @@ -1169,10 +1162,10 @@ static int check_ambiguous_visitor(jl_typemap_entry_t *oldentry, struct typemap_ jl_static_show_func_sig(s, isect); jl_printf(s, "\nbefore the new definition.\n"); } - return 1; // there may be multiple ambiguities, keep going } - else if (closure->after) { + if (!msp || closure->after) { // record that this method definition is being partially replaced + // (either with a real definition, or an ambiguity error) if (closure->shadowed == NULL) { closure->shadowed = oldentry->func.value; } @@ -1661,7 +1654,7 @@ jl_llvm_functions_t jl_compile_for_dispatch(jl_method_instance_t **pli, size_t w return decls; jl_code_info_t *src = NULL; - if (li->def && !jl_is_rettype_inferred(li) && !li->inInference && + if (li->def && !jl_is_rettype_inferred(li) && jl_symbol_name(li->def->name)[0] != '@') { // don't bother with typeinf on macros or toplevel thunks // but try to infer everything else diff --git a/src/interpreter.c b/src/interpreter.c index 4e78fea57383a..99fc01c7c7bb0 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -85,7 +85,7 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state for (i = 1; i < nargs; i++) argv[i - 1] = eval(args[i], s); jl_method_instance_t *meth = (jl_method_instance_t*)args[0]; - assert(jl_is_method_instance(meth) && !meth->inInference); + assert(jl_is_method_instance(meth)); jl_value_t *result = jl_call_method_internal(meth, argv, nargs - 1); JL_GC_POP(); return result; diff --git a/src/jltypes.c b/src/jltypes.c index f3a869236fc13..ea7418dfb19a9 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -748,15 +748,35 @@ static int within_typevar(jl_value_t *t, jl_value_t *vlb, jl_value_t *vub) return jl_subtype(vlb, lb) && jl_subtype(ub, vub); } +typedef struct _jl_typestack_t jl_typestack_t; + +static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, + int cacheable, jl_typestack_t *stack); + jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n) { if (tc == (jl_value_t*)jl_anytuple_type) return (jl_value_t*)jl_apply_tuple_type_v(params, n); if (tc == (jl_value_t*)jl_uniontype_type) return (jl_value_t*)jl_type_union(params, n); + size_t i; + if (n > 1) { + // detect common case of applying a wrapper, where we know that all parameters will + // end up as direct parameters of a certain datatype, which can be optimized. + jl_value_t *u = jl_unwrap_unionall(tc); + if (jl_is_datatype(u) && n == jl_nparams((jl_datatype_t*)u) && + ((jl_datatype_t*)u)->name->wrapper == tc) { + int cacheable = 1; + for(i=0; i < n; i++) { + if (jl_has_free_typevars(params[i])) { + cacheable = 0; break; + } + } + return inst_datatype((jl_datatype_t*)u, NULL, params, n, cacheable, NULL); + } + } JL_GC_PUSH1(&tc); jl_value_t *tc0 = tc; - size_t i; for (i=0; i < n; i++) { if (!jl_is_unionall(tc0)) jl_error("too many parameters for type"); @@ -827,11 +847,7 @@ JL_DLLEXPORT jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *v) } typedef struct _jl_typestack_t { - union { - jl_value_t *ua; - jl_datatype_t *tt; - }; - jl_value_t *ua_new; + jl_datatype_t *tt; struct _jl_typestack_t *prev; } jl_typestack_t; @@ -999,8 +1015,8 @@ static jl_value_t *normalize_vararg(jl_value_t *va) return va; } -static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, - int cacheable, jl_typestack_t *stack, jl_typeenv_t *env) +static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, + int cacheable, jl_typestack_t *stack, jl_typeenv_t *env) { jl_ptls_t ptls = jl_get_ptls_states(); jl_typestack_t top; @@ -1198,6 +1214,25 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i return (jl_value_t*)ndt; } +// Build an environment mapping a TypeName's parameters to parameter values. +// This is the environment needed for instantiating a type's supertype and field types. +static jl_value_t *inst_datatype_env(jl_value_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, + int cacheable, jl_typestack_t *stack, jl_typeenv_t *env, int c) +{ + if (jl_is_datatype(dt)) + return inst_datatype_inner((jl_datatype_t*)dt, p, iparams, ntp, cacheable, stack, env); + assert(jl_is_unionall(dt)); + jl_unionall_t *ua = (jl_unionall_t*)dt; + jl_typeenv_t e = { ua->var, iparams[c], env }; + return inst_datatype_env(ua->body, p, iparams, ntp, cacheable, stack, &e, c+1); +} + +static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, + int cacheable, jl_typestack_t *stack) +{ + return inst_datatype_env(dt->name->wrapper, p, iparams, ntp, cacheable, stack, NULL, 0); +} + static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params) { int cacheable = 1; @@ -1206,7 +1241,7 @@ static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec cacheable = 0; } jl_datatype_t *ndt = (jl_datatype_t*)inst_datatype(jl_anytuple_type, params, p, np, - cacheable, NULL, NULL); + cacheable, NULL); return ndt; } @@ -1222,12 +1257,12 @@ JL_DLLEXPORT jl_tupletype_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np) jl_datatype_t *jl_inst_concrete_tupletype(jl_svec_t *p) { - return (jl_datatype_t*)inst_datatype(jl_anytuple_type, p, jl_svec_data(p), jl_svec_len(p), 1, NULL, NULL); + return (jl_datatype_t*)inst_datatype(jl_anytuple_type, p, jl_svec_data(p), jl_svec_len(p), 1, NULL); } jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np) { - return (jl_datatype_t*)inst_datatype(jl_anytuple_type, NULL, p, np, 1, NULL, NULL); + return (jl_datatype_t*)inst_datatype(jl_anytuple_type, NULL, p, np, 1, NULL); } static jl_svec_t *inst_all(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack, int check) @@ -1294,8 +1329,7 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ if (cacheable && !jl_is_leaf_type(pi)) cacheable = 0; } - jl_value_t *result = inst_datatype((jl_datatype_t*)tt, ip_heap, iparams, ntp, cacheable, - stack, env); + jl_value_t *result = inst_datatype((jl_datatype_t*)tt, ip_heap, iparams, ntp, cacheable, stack); JL_GC_POP(); return result; } @@ -1320,29 +1354,22 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t return (jl_value_t*)t; } if (jl_is_unionall(t)) { - jl_typestack_t *sp = stack; - while (sp != NULL) { - if (sp->ua == t) - return sp->ua_new; - sp = sp->prev; - } if (!jl_has_free_typevars(t)) return t; jl_unionall_t *ua = (jl_unionall_t*)t; jl_value_t *res=NULL, *lb=ua->var->lb, *ub=ua->var->ub; JL_GC_PUSH3(&lb, &ub, &res); res = jl_new_struct(jl_unionall_type, ua->var, NULL); - jl_typestack_t top = { {t}, res, stack }; if (jl_has_bound_typevars(ua->var->lb, env)) - lb = inst_type_w_(ua->var->lb, env, &top, check); + lb = inst_type_w_(ua->var->lb, env, stack, check); if (jl_has_bound_typevars(ua->var->ub, env)) - ub = inst_type_w_(ua->var->ub, env, &top, check); + ub = inst_type_w_(ua->var->ub, env, stack, check); if (lb != ua->var->lb || ub != ua->var->ub) { ((jl_unionall_t*)res)->var = jl_new_typevar(ua->var->name, lb, ub); jl_gc_wb(res, ((jl_unionall_t*)res)->var); } jl_typeenv_t newenv = { ua->var, (jl_value_t*)((jl_unionall_t*)res)->var, env }; - jl_value_t *newbody = inst_type_w_(ua->body, &newenv, &top, check); + jl_value_t *newbody = inst_type_w_(ua->body, &newenv, stack, check); if (newbody == (jl_value_t*)jl_emptytuple_type) { // NTuple{0} => Tuple{} can make a typevar disappear res = (jl_value_t*)jl_emptytuple_type; @@ -1394,8 +1421,7 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t // if t's parameters are not bound in the environment, return it uncopied (#9378) if (!bound) { JL_GC_POP(); return (jl_value_t*)t; } - jl_value_t *result = inst_datatype((jl_datatype_t*)tt, NULL, iparams, ntp, cacheable, - stack, env); + jl_value_t *result = inst_datatype((jl_datatype_t*)tt, NULL, iparams, ntp, cacheable, stack); JL_GC_POP(); return result; } @@ -2059,8 +2085,8 @@ void jl_init_types(void) jl_svecset(jl_methtable_type->types, 7, jl_int32_type); // DWORD #endif jl_svecset(jl_methtable_type->types, 8, jl_int32_type); // uint32_t + jl_svecset(jl_method_type->types, 10, jl_method_instance_type); jl_svecset(jl_method_type->types, 11, jl_method_instance_type); - jl_svecset(jl_method_type->types, 12, jl_method_instance_type); jl_svecset(jl_method_instance_type->types, 12, jl_voidpointer_type); jl_svecset(jl_method_instance_type->types, 13, jl_voidpointer_type); jl_svecset(jl_method_instance_type->types, 14, jl_voidpointer_type); diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 4a96f21d17c7c..4c1803c4226f1 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -45,6 +45,9 @@ ((not (length> l 8)) (eval `(lambda (x) (not (not (,(if (every symbol? l) 'memq 'memv) x (quote ,l))))))) + ((and (every symbol? l) (not (length> l 20))) + (eval `(lambda (x) + (not (not (memq x (quote ,l))))))) (else (let ((t (table))) (for-each (lambda (x) (put! t x #t)) l) @@ -70,6 +73,8 @@ (define unary-ops (append! '(|<:| |>:|) (add-dots '(+ - ! ~ ¬ √ ∛ ∜)))) +(define unary-op? (Set unary-ops)) + ; operators that are both unary and binary (define unary-and-binary-ops '(+ - $ & ~ |.+| |.-|)) @@ -126,6 +131,13 @@ (define reserved-word? (Set reserved-words)) +(define closing-token? + (let ((closer? (Set '(else elseif catch finally #\, #\) #\] #\} #\;)))) + (lambda (tok) + (or (and (eq? tok 'end) (not end-symbol)) + (closer? tok) + (eof-object? tok))))) + ;; Parser state variables ; disable range colon for parsing ternary conditional operator @@ -572,113 +584,182 @@ (list 'call t ex (,self ,s)))) ex))) -(define (parse-cond s) - (let ((ex (parse-arrow s))) - (cond ((eq? (peek-token s) '?) - (begin (take-token s) - (let ((then (without-range-colon (parse-eq* s)))) - (if (not (eq? (take-token s) ':)) - (error "colon expected in \"?\" expression") - (list 'if ex then (parse-eq* s)))))) - (else ex)))) +(define (line-number-node s) + `(line ,(input-port-line (ts:port s)) ,current-filename)) -(define (parse-where-chain s first) - (with-bindings ((where-enabled #f)) - (let loop ((ex first) - (t 'where)) - (if (eq? t 'where) - (begin (take-token s) - (let ((var (parse-comparison s))) - (loop (if (and (pair? var) (eq? (car var) 'cell1d)) - (list* 'where ex (cdr var)) ;; form `x where {T,S}` - (list 'where ex var)) - (peek-token s)))) - ex)))) +;; parse a@b@c@... as (@ a b c ...) for some operator @ +;; ops: operators to look for +;; head: the expression head to yield in the result, e.g. "a;b" => (block a b) +;; closer?: predicate to identify tokens that stop parsing +;; however, this doesn't consume the closing token, just looks at it +;; ow, my eyes!! +(define (parse-Nary s down ops head closer? add-linenums) + (let ((t (require-token s))) + (if (closer? t) + (if add-linenums ;; empty block + (list head (line-number-node s)) + (list head)) + (let loop ((ex + ;; skip leading runs of operator + (if (memv t ops) + (if add-linenums + (list (line-number-node s)) + '()) + (if add-linenums + (let ((loc (line-number-node s))) + ;; note: line-number must happen before (down s) + (list (down s) loc)) + (list (down s))))) + (first? #t) + (t (peek-token s))) + (if (not (memv t ops)) + (begin + (if (not (or (eof-object? t) (eqv? t #\newline) (closer? t))) + (error (string "extra token \"" t "\" after end of expression"))) + (if (or (null? ex) (pair? (cdr ex)) (not first?)) + ;; () => (head) + ;; (ex2 ex1) => (head ex1 ex2) + ;; (ex1) if operator appeared => (head ex1) (handles "x;") + (cons head (reverse! ex)) + ;; (ex1) => ex1 + (car ex))) + (begin (take-token s) + ;; allow input to end with the operator, as in a;b; + (if (or (eof-object? (peek-token s)) + (closer? (peek-token s)) + (memv (peek-token s) ops)) + (loop ex #f (peek-token s)) + (if (and add-linenums + (not (and (pair? (car ex)) + (eq? (caar ex) 'line)))) + (let ((loc (line-number-node s))) + (loop (list* (down s) loc ex) #f (peek-token s))) + (loop (cons (down s) ex) #f (peek-token s)))))))))) -(define (parse-where s down) - ;; `where` needs to be below unary for `+(x::T,y::T) where {T} = ...` to work - (let ((ex (down s))) - (if (and where-enabled - (eq? (peek-token s) 'where)) - (parse-where-chain s ex) - ex))) +;; the principal non-terminals follow, in increasing precedence order -(define (invalid-initial-token? tok) - (or (eof-object? tok) - (memv tok '(#\) #\] #\} else elseif catch finally =)))) +(define (parse-block s (down parse-eq)) + (parse-Nary s down '(#\newline #\;) 'block + (lambda (x) (memq x '(end else elseif catch finally))) #t)) -(define (line-number-node s) - `(line ,(input-port-line (ts:port s)) ,current-filename)) +;; ";" at the top level produces a sequence of top level expressions +(define (parse-stmts s) + (let ((ex (parse-Nary s (lambda (s) (parse-docstring s parse-eq)) + '(#\;) 'toplevel (lambda (x) (eqv? x #\newline)) #f))) + ;; check for unparsed junk after an expression + (let ((t (peek-token s))) + (if (not (or (eof-object? t) (eqv? t #\newline) (eq? t #f))) + (error (string "extra token \"" t "\" after end of expression")))) + ex)) + +(define (parse-eq s) (parse-assignment s parse-comma)) -(define (eventually-call ex) +;; symbol tokens that do not simply parse to themselves when appearing alone as +;; an element of an argument list +(define non-standalone-symbol-token? + (Set (append operators reserved-words '(.... mutable primitive)))) + +; parse-eq* is used where commas are special, for example in an argument list +(define (parse-eq* s) + (let ((t (peek-token s))) + ;; optimization: skip checking the whole precedence stack if we have a simple + ;; token followed by a common closing token + (if (or (number? t) (and (symbol? t) (not (non-standalone-symbol-token? t)))) + (begin (take-token s) + (let ((nxt (peek-token s))) + (if (or (eqv? nxt #\,) (eqv? nxt #\) ) (eqv? nxt #\}) (eqv? nxt #\])) + t + (begin (ts:put-back! s t) + (parse-assignment s parse-cond))))) + (parse-assignment s parse-cond)))) + +(define (eventually-call? ex) (and (pair? ex) (or (eq? (car ex) 'call) (and (or (eq? (car ex) 'where) (eq? (car ex) '|::|)) - (eventually-call (cadr ex)))))) + (eventually-call? (cadr ex)))))) -;; insert line/file for short-form function defs, otherwise leave alone (define (short-form-function-loc ex lno) - (if (and (pair? ex) - (eq? (car ex) '=) - (eventually-call (cadr ex))) + (if (eventually-call? (cadr ex)) `(= ,(cadr ex) (block (line ,lno ,current-filename) ,(caddr ex))) ex)) -;; parse a@b@c@... as (@ a b c ...) for some operator @ -;; op: the operator to look for -;; head: the expression head to yield in the result, e.g. "a;b" => (block a b) -;; closers: a list of tokens that will stop the process -;; however, this doesn't consume the closing token, just looks at it -;; allow-empty: if true will ignore runs of the operator, like a@@@@b -;; ow, my eyes!! -(define (parse-Nary s down ops head closer? allow-empty add-linenums) - (let ((t (require-token s))) - (if (invalid-initial-token? t) - (error (string "unexpected \"" t "\""))) - (if (closer? t) - (if add-linenums ;; empty block - (list head (line-number-node s)) - (list head)) - (let loop ((ex - ;; in allow-empty mode skip leading runs of operator - (if (and allow-empty (memv t ops)) - (if add-linenums - (list (line-number-node s)) - '()) - (if add-linenums - (let ((loc (line-number-node s))) - ;; note: line-number must happen before (down s) - (list (down s) loc)) - (list (down s))))) - (first? #t) - (t (peek-token s))) - (if (not (memv t ops)) - (begin - (if (not (or (eof-object? t) (eqv? t #\newline) (memv #\, ops) - (closer? t))) - (error (string "extra token \"" t "\" after end of expression"))) - (if (or (null? ex) (pair? (cdr ex)) (not first?)) - ;; () => (head) - ;; (ex2 ex1) => (head ex1 ex2) - ;; (ex1) if operator appeared => (head ex1) (handles "x;") - (cons head (reverse! ex)) - ;; (ex1) => ex1 - (car ex))) - (begin (take-token s) - ;; allow input to end with the operator, as in a;b; - (if (or (eof-object? (peek-token s)) - (closer? (peek-token s)) - (and allow-empty - (memv (peek-token s) ops)) - (and (eqv? (car ops) #\,) - (eq? (peek-token s) '=))) - (loop ex #f (peek-token s)) - (if (and add-linenums - (not (and (pair? (car ex)) - (eq? (caar ex) 'line)))) - (let ((loc (line-number-node s))) - (loop (list* (down s) loc ex) #f (peek-token s))) - (loop (cons (down s) ex) #f (peek-token s)))))))))) +(define (parse-assignment s down) + (let loop ((ex (down s)) + (t (peek-token s))) + (if (not (is-prec-assignment? t)) + ex + (begin + (take-token s) + (cond ((eq? t '~) + (if (and space-sensitive (ts:space? s) + (not (eqv? (peek-char (ts:port s)) #\ ))) + (begin (ts:put-back! s t) + ex) + (list 'call t ex (parse-assignment s down)))) + ((eq? t '=>) ;; ~ and => are the only non-syntactic assignment-precedence operators + (list 'call t ex (parse-assignment s down))) + ((eq? t '=) + ;; insert line/file for short-form function defs, otherwise leave alone + (let ((lno (input-port-line (ts:port s)))) + (short-form-function-loc + (list t ex (parse-assignment s down)) lno))) + (else + (list t ex (parse-assignment s down)))))))) + +; parse-comma is needed for commas outside parens, for example a = b,c +(define (parse-comma s) + (let loop ((ex (list (parse-cond s))) + (first? #t) + (t (peek-token s))) + (if (not (eqv? t #\,)) + (if (or (pair? (cdr ex)) (not first?)) + ;; () => (tuple) + ;; (ex2 ex1) => (tuple ex1 ex2) + ;; (ex1,) => (tuple ex1) + (cons 'tuple (reverse! ex)) + ;; (ex1) => ex1 + (car ex)) + (begin (take-token s) + (if (or (eof-object? (peek-token s)) (eq? (peek-token s) '=)) + (loop ex #f (peek-token s)) + (loop (cons (parse-cond s) ex) #f (peek-token s))))))) + +(define (parse-cond s) + (let ((ex (parse-arrow s))) + (cond ((eq? (peek-token s) '?) + (begin (take-token s) + (let ((then (without-range-colon (parse-eq* s)))) + (if (not (eq? (take-token s) ':)) + (error "colon expected in \"?\" expression") + (list 'if ex then (parse-eq* s)))))) + (else ex)))) + +(define (parse-arrow s) (parse-RtoL s parse-or is-prec-arrow? (eq? t '-->) parse-arrow)) +(define (parse-or s) (parse-RtoL s parse-and is-prec-lazy-or? #t parse-or)) +(define (parse-and s) (parse-RtoL s parse-comparison is-prec-lazy-and? #t parse-and)) + +(define (parse-comparison s) + (let loop ((ex (parse-pipes s)) + (first #t)) + (let ((t (peek-token s))) + (cond ((is-prec-comparison? t) + (begin (take-token s) + (if first + (loop (list 'comparison ex t (parse-pipes s)) #f) + (loop (append ex (list t (parse-pipes s))) #f)))) + (first ex) + ((length= ex 4) + ;; only a single comparison; special chained syntax not required + (let ((op (caddr ex)) + (arg1 (cadr ex)) + (arg2 (cadddr ex))) + (if (or (eq? op '|<:|) (eq? op '|>:|)) + `(,op ,arg1 ,arg2) + `(call ,op ,arg1 ,arg2)))) + (else ex))))) + +(define (parse-pipes s) (parse-LtoR s parse-range is-prec-pipe?)) ; parse ranges and postfix ... ; colon is strange; 3 arguments with 2 colons yields one call: @@ -728,64 +809,14 @@ (list '... ex)) (else ex))))) -;; the principal non-terminals follow, in increasing precedence order - -(define (parse-block s (down parse-eq)) - (parse-Nary s down '(#\newline #\;) 'block - (lambda (x) (memq x '(end else elseif catch finally))) #t #t)) - -;; ";" at the top level produces a sequence of top level expressions -(define (parse-stmts s) - (let ((ex (parse-Nary s (lambda (s) (parse-docstring s parse-eq)) - '(#\;) 'toplevel (lambda (x) (eqv? x #\newline)) #t #f))) - ;; check for unparsed junk after an expression - (let ((t (peek-token s))) - (if (not (or (eof-object? t) (eqv? t #\newline) (eq? t #f))) - (error (string "extra token \"" t "\" after end of expression")))) - ex)) - -(define (parse-assignment s down) - (let loop ((ex (down s)) - (t (peek-token s))) - (if (not (is-prec-assignment? t)) - ex - (begin (take-token s) - (if (eq? t '~) - (if (and space-sensitive (ts:space? s) - (not (eqv? (peek-char (ts:port s)) #\ ))) - (begin (ts:put-back! s t) - ex) - (list 'call t ex (parse-assignment s down))) - (if (eq? t '=>) ;; ~ and => are the only non-syntactic assignment-precedence operators - (list 'call t ex (parse-assignment s down)) - (list t ex (parse-assignment s down)))))))) - -(define (parse-eq s) - (let ((lno (input-port-line (ts:port s)))) - (short-form-function-loc - (parse-assignment s parse-comma) lno))) - -; parse-eq* is used where commas are special, for example in an argument list -(define (parse-eq* s) - (let ((lno (input-port-line (ts:port s)))) - (short-form-function-loc - (parse-assignment s parse-cond) lno))) - -; parse-comma is needed for commas outside parens, for example a = b,c -(define (parse-comma s) (parse-Nary s parse-cond '(#\,) 'tuple (lambda (x) #f) #f #f)) -(define (parse-arrow s) (parse-RtoL s parse-or is-prec-arrow? (eq? t '-->) parse-arrow)) -(define (parse-or s) (parse-RtoL s parse-and is-prec-lazy-or? #t parse-or)) -(define (parse-and s) (parse-RtoL s parse-comparison is-prec-lazy-and? #t parse-and)) - ;; parse left to right chains of a certain binary operator ;; returns a list of arguments (define (parse-chain s down op) (let loop ((chain (list (down s)))) - (let* ((t (peek-token s)) - (spc (ts:space? s))) + (let ((t (peek-token s))) (if (not (eq? t op)) (reverse! chain) - (begin + (let ((spc (ts:space? s))) (take-token s) (cond ((and space-sensitive spc (memq t unary-and-binary-ops) (not (eqv? (peek-char (ts:port s)) #\ ))) @@ -799,11 +830,10 @@ ;; e.g. a+b+c => (call + a b c) (define (parse-with-chains s down ops chain-ops) (let loop ((ex (down s))) - (let* ((t (peek-token s)) - (spc (ts:space? s))) + (let ((t (peek-token s))) (if (not (ops t)) ex - (begin + (let ((spc (ts:space? s))) (take-token s) (cond ((and space-sensitive spc (memq t unary-and-binary-ops) (not (eqv? (peek-char (ts:port s)) #\ ))) @@ -816,42 +846,50 @@ (else (loop (list 'call t ex (down s)))))))))) -(define (parse-expr s) (parse-with-chains s parse-shift is-prec-plus? '(+ ++))) - -(define (parse-shift s) (parse-LtoR s parse-term is-prec-bitshift?)) +(define (parse-expr s) (parse-with-chains s parse-shift is-prec-plus? '(+ ++))) +(define (parse-shift s) (parse-LtoR s parse-term is-prec-bitshift?)) +(define (parse-term s) (parse-with-chains s parse-rational is-prec-times? '(*))) +(define (parse-rational s) (parse-LtoR s parse-unary-subtype is-prec-rational?)) -(define (parse-term s) (parse-with-chains s parse-rational is-prec-times? '(*))) - -(define (parse-rational s) (parse-LtoR s (lambda (s) (parse-unary-subtype s)) is-prec-rational?)) - -(define (parse-pipes s) (parse-LtoR s parse-range is-prec-pipe?)) +;; parse `<: A where B` as `<: (A where B)` (issue #21545) +(define (parse-unary-subtype s) + (let ((op (require-token s))) + (if (or (eq? op '|<:|) (eq? op '|>:|)) + (begin (take-token s) + (let ((next (peek-token s))) + (cond ((or (closing-token? next) (newline? next) (eq? next '=)) + op) ; return operator by itself, as in (<:) + ;; parse <:{T}(x::T) or <:(x::T) like other unary operators + ((or (eqv? next #\{) (eqv? next #\( )) + (ts:put-back! s op) + (parse-where s parse-unary)) + (else + (let ((arg (parse-where s parse-unary))) + (if (and (pair? arg) (eq? (car arg) 'tuple)) + (cons op (cdr arg)) + (list op arg))))))) + (parse-where s parse-unary)))) -(define (parse-comparison s) - (let loop ((ex (parse-pipes s)) - (first #t)) - (let ((t (peek-token s))) - (cond ((is-prec-comparison? t) - (begin (take-token s) - (if first - (loop (list 'comparison ex t (parse-pipes s)) #f) - (loop (append ex (list t (parse-pipes s))) #f)))) - (first ex) - ((length= ex 4) - ;; only a single comparison; special chained syntax not required - (let ((op (caddr ex)) - (arg1 (cadr ex)) - (arg2 (cadddr ex))) - (if (or (eq? op '|<:|) (eq? op '|>:|)) - `(,op ,arg1 ,arg2) - `(call ,op ,arg1 ,arg2)))) - (else ex))))) +(define (parse-where-chain s first) + (with-bindings ((where-enabled #f)) + (let loop ((ex first) + (t 'where)) + (if (eq? t 'where) + (begin (take-token s) + (let ((var (parse-comparison s))) + (loop (if (and (pair? var) (eq? (car var) 'cell1d)) + (list* 'where ex (cdr var)) ;; form `x where {T,S}` + (list 'where ex var)) + (peek-token s)))) + ex)))) -(define closing-token? - (let ((closer? (Set '(else elseif catch finally #\, #\) #\] #\} #\;)))) - (lambda (tok) - (or (and (eq? tok 'end) (not end-symbol)) - (closer? tok) - (eof-object? tok))))) +(define (parse-where s down) + ;; `where` needs to be below unary for `+(x::T,y::T) where {T} = ...` to work + (let ((ex (down s))) + (if (and where-enabled + (eq? (peek-token s) 'where)) + (parse-where-chain s ex) + ex))) (define (maybe-negate op num) (if (eq? op '-) @@ -864,6 +902,53 @@ (- num))) num)) +;; operators handled by parse-unary at the start of an expression +(define initial-operator? + ;; TODO: ? should probably not be listed here except for the syntax hack in osutils.jl + (Set (diff operators (append '(: |'| ?) syntactic-unary-operators syntactic-operators)))) + +(define (parse-unary s) + (let ((op (require-token s))) + (if (closing-token? op) + (error (string "unexpected \"" op "\""))) + (if (initial-operator? op) + (begin + (take-token s) + (if (or (eq? op '-) (eq? op '+)) + (let ((nch (peek-char (ts:port s)))) + (if (or (and (char? nch) (char-numeric? nch)) + (and (eqv? nch #\.) (read-char (ts:port s)))) + (let ((num (parse-juxtapose + (read-number (ts:port s) (eqv? nch #\.) (eq? op '-)) + s))) + (if (is-prec-power? (peek-token s)) + ;; -2^x parsed as (- (^ 2 x)) + (begin (ts:put-back! s (maybe-negate op num)) + (list 'call op (parse-factor s))) + num)) + (parse-unary-call s op #t))) + (parse-unary-call s op (unary-op? op)))) + (parse-juxtapose (parse-factor s) s)))) + +(define (parse-unary-call s op un) + (let ((next (peek-token s))) + (cond ((or (closing-token? next) (newline? next) (eq? next '=)) + op) ; return operator by itself, as in (+) + ((or (eqv? next #\{) ;; this case is +{T}(x::T) = ... + (and (not un) (eqv? next #\( ))) + (ts:put-back! s op) + (parse-factor s)) + ((not un) + (error (string "\"" op "\" is not a unary operator"))) + (else + (let* ((arg (parse-unary s)) + (args (if (and (pair? arg) (eq? (car arg) 'tuple)) + (cons op (cdr arg)) + (list op arg)))) + (if (or (eq? op '|<:|) (eq? op '|>:|)) + args + (cons 'call args))))))) + ;; given an expression and the next token, is there a juxtaposition ;; operator between them? (define (juxtapose? s expr t) @@ -897,83 +982,11 @@ `(call * ,ex ,(parse-unary s)))) (else ex)))) -(define (invalid-identifier-name? ex) - (or (syntactic-op? ex) (eq? ex '....))) - -;; parse `<: A where B` as `<: (A where B)` (issue #21545) -(define (parse-unary-subtype s) - (let ((op (require-token s))) - (if (or (eq? op '|<:|) (eq? op '|>:|)) - (begin (take-token s) - (let ((next (peek-token s))) - (cond ((or (closing-token? next) (newline? next) (eq? next '=)) - op) ; return operator by itself, as in (<:) - ;; parse <:{T}(x::T) or <:(x::T) like other unary operators - ((or (eqv? next #\{) (eqv? next #\( )) - (ts:put-back! s op) - (parse-where s parse-unary)) - (else - (let ((arg (parse-where s parse-unary))) - (if (and (pair? arg) (eq? (car arg) 'tuple)) - (cons op (cdr arg)) - (list op arg))))))) - (parse-where s parse-unary)))) - -(define (parse-unary s) - (let ((t (require-token s))) - (if (closing-token? t) - (error (string "unexpected " t))) - ;; TODO: ? should probably not be listed here except for the syntax hack in osutils.jl - (cond ((and (operator? t) (not (memq t '(: |'| ?))) (not (syntactic-unary-op? t)) - (not (invalid-identifier-name? t))) - (let* ((op (take-token s)) - (nch (peek-char (ts:port s)))) - (if (and (or (eq? op '-) (eq? op '+)) - (or (and (char? nch) (char-numeric? nch)) - (and (eqv? nch #\.) (read-char (ts:port s))))) - (let ((num (parse-juxtapose - (read-number (ts:port s) (eqv? nch #\.) (eq? op '-)) - s))) - (if (is-prec-power? (peek-token s)) - ;; -2^x parsed as (- (^ 2 x)) - (begin (ts:put-back! s (maybe-negate op num)) - (list 'call op (parse-factor s))) - num)) - (let ((next (peek-token s))) - (cond ((or (closing-token? next) (newline? next) (eq? next '=)) - op) ; return operator by itself, as in (+) - ((or (eqv? next #\{) ;; this case is +{T}(x::T) = ... - (and (not (memq op unary-ops)) - (eqv? next #\( ))) - (ts:put-back! s op) - (parse-factor s)) - ((not (memq op unary-ops)) - (error (string "\"" op "\" is not a unary operator"))) - (else - (let* ((arg (parse-unary s)) - (args (if (and (pair? arg) (eq? (car arg) 'tuple)) - (cons op (cdr arg)) - (list op arg)))) - (if (or (eq? op '|<:|) (eq? op '|>:|)) - args - (cons 'call args))))))))) - (else - (parse-juxtapose (parse-factor s) s))))) - ;; handle ^ and .^ -(define (parse-factor-h s down ops) - (let ((ex (down s)) - (t (peek-token s))) - (cond ((not (ops t)) - ex) - (else - (list 'call - (take-token s) ex (parse-factor-h s parse-unary ops)))))) - ;; -2^3 is parsed as -(2^3), so call parse-decl for the first argument, ;; and parse-unary from then on (to handle 2^-3) -(define (parse-factor s) - (parse-factor-h s parse-decl is-prec-power?)) +(define (parse-factor s) (parse-RtoL s parse-decl is-prec-power? #f parse-factor-after)) +(define (parse-factor-after s) (parse-RtoL s parse-unary is-prec-power? #f parse-factor-after)) (define (parse-decl s) (let loop ((ex (parse-call s))) @@ -989,24 +1002,25 @@ (else ex))))) +;; parse function call, indexing, dot, and transpose expressions +;; also handles looking for syntactic reserved words +(define (parse-call s) + (let ((ex (parse-unary-prefix s))) + (if (or (initial-reserved-word? ex) (eq? ex 'mutable) (eq? ex 'primitive)) + (parse-resword s ex) + (parse-call-chain s ex #f)))) + (define (parse-unary-prefix s) (let ((op (peek-token s))) (if (syntactic-unary-op? op) (begin (take-token s) (cond ((let ((next (peek-token s))) - (or (closing-token? next) (newline? next))) op) + (or (closing-token? next) (newline? next))) + op) ((memq op '(& |::|)) (list op (parse-where s parse-call))) (else (list op (parse-unary-prefix s))))) (parse-atom s)))) -;; parse function call, indexing, dot, and transpose expressions -;; also handles looking for syntactic reserved words -(define (parse-call s) - (let ((ex (parse-unary-prefix s))) - (if (or (initial-reserved-word? ex) (memq ex '(mutable primitive))) - (parse-resword s ex) - (parse-call-chain s ex #f)))) - (define (parse-def s is-func) (let* ((ex (parse-unary-prefix s)) (sig (if (or (and is-func (reserved-word? ex)) (initial-reserved-word? ex)) @@ -1156,6 +1170,11 @@ (and (eq? (car sig) 'where) (valid-func-sig? paren (cadr sig)))))) +(define (valid-1arg-func-sig? sig) + (or (symbol? sig) + (and (pair? sig) (eq? (car sig) '|::|) + (symbol? (cadr sig))))) + (define (unwrap-where x) (if (and (pair? x) (eq? (car x) 'where)) (unwrap-where (cadr x)) @@ -1288,9 +1307,9 @@ (take-token s) `(function ,sig)) (let* ((usig (unwrap-where sig)) - (def (if (or (symbol? usig) - (and (pair? usig) (eq? (car usig) '|::|) - (symbol? (cadr usig)))) + (def (if (or (valid-1arg-func-sig? usig) + (and (assignment? usig) + (valid-1arg-func-sig? (cadr usig)))) (if paren ;; in "function (x)" the (x) is a tuple (rewrap-where `(tuple ,usig) sig) @@ -1971,9 +1990,9 @@ ;; process escape sequences using lisp read (read (open-input-string (string #\" s #\")))))) -(define (check-identifier ex) - (if (invalid-identifier-name? ex) - (error (string "invalid identifier name \"" ex "\"")))) +(define-macro (check-identifier ex) + `(if (or (syntactic-op? ,ex) (eq? ,ex '....)) + (error (string "invalid identifier name \"" ,ex "\"")))) ;; parse numbers, identifiers, parenthesized expressions, lists, vectors, etc. (define (parse-atom s (checked #t)) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index ddf261da58c60..18fab57cf4bc5 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1104,12 +1104,25 @@ (eq? (caar binds) '=)) ;; some kind of assignment (cond + ((eventually-call? (cadar binds)) + ;; f() = c + (let ((asgn (butlast (expand-forms (car binds)))) + (name (assigned-name (cadar binds)))) + (if (not (symbol? name)) + (error "invalid let syntax")) + (loop (cdr binds) + `(scope-block + (block + ,(if (expr-contains-eq name (caddar binds)) + `(local ,name) ;; might need a Box for recursive functions + `(local-def ,name)) + ,asgn + ,blk))))) ((or (symbol? (cadar binds)) (decl? (cadar binds))) (let ((vname (decl-var (cadar binds)))) (loop (cdr binds) - (if (contains (lambda (x) (eq? x vname)) - (caddar binds)) + (if (expr-contains-eq vname (caddar binds)) (let ((tmp (make-ssavalue))) `(scope-block (block (= ,tmp ,(caddar binds)) @@ -1123,23 +1136,6 @@ (local-def ,(cadar binds)) (= ,vname ,(caddar binds)) ,blk)))))) - ((and (pair? (cadar binds)) - (or (eq? (caadar binds) 'call) - (and (eq? (caadar binds) 'comparison) - (length= (cadar binds) 4)))) - ;; f()=c - (let* ((asgn (butlast (expand-forms (car binds)))) - (name (cadr (cadar binds))) - (name (cond ((symbol? name) name) - ((and (pair? name) (eq? (car name) 'curly)) - (cadr name)) - (else (error "invalid let syntax"))))) - (loop (cdr binds) - `(scope-block - (block - (local-def ,name) - ,asgn - ,blk))))) ;; (a, b, c, ...) = rhs ((and (pair? (cadar binds)) (eq? (caadar binds) 'tuple)) @@ -1332,7 +1328,7 @@ (define (assigned-name e) (cond ((atom? e) e) ((or (memq (car e) '(call curly where)) - (and (eq? (car e) '|::|) (eventually-call e))) + (and (eq? (car e) '|::|) (eventually-call? e))) (assigned-name (cadr e))) (else e))) @@ -1379,24 +1375,32 @@ (unnecessary (tuple ,@(reverse elts)))) (let ((L (car lhss)) (R (car rhss))) - (if (and (symbol-like? L) - (or (not (pair? R)) (quoted? R) (equal? R '(null))) - ;; overwrite var immediately if it doesn't occur elsewhere - (not (contains (lambda (e) (eq-sym? e L)) (cdr rhss))) - (not (contains (lambda (e) (eq-sym? e R)) assigned))) - (loop (cdr lhss) - (cons L assigned) - (cdr rhss) - (cons (make-assignment L R) stmts) - after - (cons R elts)) - (let ((temp (make-ssavalue))) - (loop (cdr lhss) - (cons L assigned) - (cdr rhss) - (cons (make-assignment temp R) stmts) - (cons (make-assignment L temp) after) - (cons temp elts)))))))) + (cond ((and (symbol-like? L) + (or (not (pair? R)) (quoted? R) (equal? R '(null))) + ;; overwrite var immediately if it doesn't occur elsewhere + (not (contains (lambda (e) (eq-sym? e L)) (cdr rhss))) + (not (contains (lambda (e) (eq-sym? e R)) assigned))) + (loop (cdr lhss) + (cons L assigned) + (cdr rhss) + (cons (make-assignment L R) stmts) + after + (cons R elts))) + ((vararg? R) + (let ((temp (make-ssavalue))) + `(block ,@(reverse stmts) + ,(make-assignment temp (cadr R)) + ,@(reverse after) + (= (tuple ,@lhss) ,temp) + (unnecessary (tuple ,@(reverse elts) (... ,temp)))))) + (else + (let ((temp (if (eventually-call? L) (gensy) (make-ssavalue)))) + (loop (cdr lhss) + (cons L assigned) + (cdr rhss) + (cons (make-assignment temp R) stmts) + (cons (make-assignment L temp) after) + (cons temp elts))))))))) ;; convert (lhss...) = x to tuple indexing (define (lower-tuple-assignment lhss x) @@ -1406,7 +1410,7 @@ ,@(let loop ((lhs lhss) (i 1)) (if (null? lhs) '((null)) - (cons (if (eventually-call (car lhs)) + (cons (if (eventually-call? (car lhs)) ;; if this is a function assignment, avoid putting our ssavalue ;; inside the function and instead create a capture-able variable. ;; issue #22032 @@ -1674,6 +1678,7 @@ (if (and (null? splat) (length= expr 3) (eq? (car expr) 'call) (eq? (caddr expr) argname) + (not (dotop? (cadr expr))) (not (expr-contains-eq argname (cadr expr)))) (cadr expr) ;; eta reduce `x->f(x)` => `f` `(-> ,argname (block ,@splat ,expr))))) @@ -1966,13 +1971,20 @@ ;; multiple assignment (let ((lhss (cdr lhs)) (x (caddr e))) + (define (sides-match? l r) + ;; l and r either have equal lengths, or r has a trailing ... + (cond ((null? l) (null? r)) + ((null? r) #f) + ((vararg? (car r)) (null? (cdr r))) + (else (sides-match? (cdr l) (cdr r))))) (if (and (pair? x) (pair? lhss) (eq? (car x) 'tuple) - (length= lhss (length (cdr x)))) + (sides-match? lhss (cdr x))) ;; (a, b, ...) = (x, y, ...) (expand-forms (tuple-to-assignments lhss x)) ;; (a, b, ...) = other - (let* ((xx (if (and (symbol? x) (not (memq x lhss))) + (let* ((xx (if (or (and (symbol? x) (not (memq x lhss))) + (ssavalue? x)) x (make-ssavalue))) (ini (if (eq? x xx) '() `((= ,xx ,(expand-forms x))))) (st (gensy))) @@ -2433,7 +2445,7 @@ (else '()))) (define (all-decl-vars e) ;; map decl-var over every level of an assignment LHS - (cond ((eventually-call e) e) + (cond ((eventually-call? e) e) ((decl? e) (decl-var e)) ((and (pair? e) (eq? (car e) 'tuple)) (cons 'tuple (map all-decl-vars (cdr e)))) diff --git a/src/macroexpand.scm b/src/macroexpand.scm index 8f2ad5784bb87..e0d55c3b99862 100644 --- a/src/macroexpand.scm +++ b/src/macroexpand.scm @@ -107,8 +107,7 @@ ;; a=b -> add argument (loop (cdr binds) (cons (decl-var (cadar binds)) vars))) - ((and (pair? (cadar binds)) - (eq? (caadar binds) 'call)) + ((eventually-call? (cadar binds)) ;; f()=c (let ((asgn (cadr (julia-expand0 (car binds))))) (loop (cdr binds) @@ -390,7 +389,7 @@ (define (function-def? e) (and (pair? e) (or (eq? (car e) 'function) (eq? (car e) '->) (and (eq? (car e) '=) (length= e 3) - (eventually-call (cadr e)))))) + (eventually-call? (cadr e)))))) (define (find-declared-vars-in-expansion e decl (outer #t)) (cond ((or (not (pair? e)) (quoted? e)) '()) diff --git a/src/rtutils.c b/src/rtutils.c index 954c352186e52..e5b2c8d8f11f8 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -841,14 +841,16 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt if (nb > 0 && tlen == 0) { uint8_t *data = (uint8_t*)v; n += jl_printf(out, "0x"); - for(int i=nb-1; i >= 0; --i) + for(int i = nb - 1; i >= 0; --i) n += jl_printf(out, "%02" PRIx8, data[i]); } else { - for (size_t i = 0; i < tlen; i++) { + size_t i = 0; + if (vt == jl_typemap_entry_type) + i = 1; + for (; i < tlen; i++) { if (!istuple) { n += jl_printf(out, "%s", jl_symbol_name((jl_sym_t*)jl_svecref(vt->name->names, i))); - //jl_fielddesc_t f = t->fields[i]; n += jl_printf(out, "="); } size_t offs = jl_field_offset(vt, i); @@ -861,11 +863,15 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt (jl_datatype_t*)jl_field_type(vt, i), depth); } - if (istuple && tlen==1) + if (istuple && tlen == 1) n += jl_printf(out, ","); - else if (i != tlen-1) + else if (i != tlen - 1) n += jl_printf(out, ", "); } + if (vt == jl_typemap_entry_type) { + n += jl_printf(out, ", next=↩︎\n "); + n += jl_static_show_x(out, jl_fieldref(v, 0), depth); + } } n += jl_printf(out, ")"); } diff --git a/src/subtype.c b/src/subtype.c index b0a4a81e1705b..b636d77bba83d 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -420,9 +420,10 @@ static int subtype_ufirst(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) static void record_var_occurrence(jl_varbinding_t *vb, jl_stenv_t *e, int param) { if (vb != NULL && param) { - if (param == 2 && e->invdepth > vb->depth0) + // saturate counters at 2; we don't need values bigger than that + if (param == 2 && e->invdepth > vb->depth0 && vb->occurs_inv < 2) vb->occurs_inv++; - else + else if (vb->occurs_cov < 2) vb->occurs_cov++; } } @@ -883,21 +884,9 @@ static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param) } if (jl_is_type_type(y) && !jl_is_type_type(x) && x != (jl_value_t*)jl_typeofbottom_type) { jl_value_t *tp0 = jl_tparam0(yd); - if (!jl_is_typevar(tp0)) + if (!jl_is_typevar(tp0) || !jl_is_kind(x)) return 0; - if (!jl_is_kind(x)) return 0; - jl_varbinding_t *yy = lookup(e, (jl_tvar_t*)tp0); - jl_value_t *ub = yy ? yy->ub : ((jl_tvar_t*)tp0)->ub; - int ans; - if (ub == (jl_value_t*)jl_any_type) { - ans = subtype((jl_value_t*)jl_type_type, y, e, param); - } - else { - e->invdepth++; - ans = forall_exists_equal(x, tp0, e); - e->invdepth--; - } - return ans; + return subtype((jl_value_t*)jl_type_type, y, e, param); } while (xd != jl_any_type && xd->name != yd->name) { if (xd->super == NULL) @@ -2158,20 +2147,9 @@ jl_value_t *jl_type_intersection_env_s(jl_value_t *a, jl_value_t *b, jl_svec_t * else { sz = szb; // TODO: compute better `env` directly during intersection. - // we assume that if the intersection is a leaf type, we have - // full information in `env`. however the intersection algorithm - // does not yet provide that in all cases so use subtype. + // for now, we attempt to compute env by using subtype on the intersection result if (szb > 0 && !jl_types_equal(b, (jl_value_t*)jl_type_type)) { - if (jl_subtype_env(*ans, b, env, szb)) { - if (jl_is_leaf_type(*ans)) { - for(i=0; i < sz; i++) { - if (jl_is_typevar(env[i])) { - *ans = jl_bottom_type; goto bot; - } - } - } - } - else { + if (!jl_subtype_env(*ans, b, env, szb)) { sz = 0; } } diff --git a/src/threading.c b/src/threading.c index abf183ae3576d..c9958f9e69b03 100644 --- a/src/threading.c +++ b/src/threading.c @@ -263,6 +263,8 @@ static void ti_initthread(int16_t tid) #ifndef _OS_WINDOWS_ ptls->system_id = pthread_self(); #endif + assert(ptls->world_age == 0); + ptls->world_age = 1; // OK to run Julia code on this thread ptls->tid = tid; ptls->pgcstack = NULL; ptls->gc_state = 0; // GC unsafe diff --git a/src/typemap.c b/src/typemap.c index b06be06415d76..3b99326620f31 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -1045,6 +1045,8 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par newrec->isleafsig = 0; // Type{} may have a higher priority than DataType else if (decl == (jl_value_t*)jl_unionall_type) newrec->isleafsig = 0; // Type{} may have a higher priority than UnionAll + else if (decl == (jl_value_t*)jl_uniontype_type) + newrec->isleafsig = 0; // Type{} may have a higher priority than Union else if (jl_is_type_type(decl)) newrec->isleafsig = 0; // Type{} may need special processing to compute the match else if (jl_is_vararg_type(decl)) diff --git a/test/ambiguous.jl b/test/ambiguous.jl index 32139c496a44f..14c03f877b8da 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -85,6 +85,16 @@ cfunction(ambig, Int, (UInt8, Int)) # test for a crash (doesn't throw an error) ambig(x, y::Integer) = 3 @test_throws MethodError ambig(2, 0x03) +# Method overwriting by an ambiguity should also invalidate the method cache (#21963) +ambig(x::Union{Char, Int8}) = 'r' +@test ambig('c') == 'r' +@test ambig(Int8(1)) == 'r' +@test_throws MethodError ambig(Int16(1)) +ambig(x::Union{Char, Int16}) = 's' +@test_throws MethodError ambig('c') +@test ambig(Int8(1)) == 'r' +@test ambig(Int16(1)) == 's' + # Automatic detection of ambiguities module Ambig1 ambig(x, y) = 1 diff --git a/test/arrayops.jl b/test/arrayops.jl index a275f6aef0540..e1a0a2497edac 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -107,6 +107,7 @@ end @test_throws MethodError convert(Array{Int,2}, r) @test convert(Array{Int}, r) == [2,3,4] @test Base.unsafe_convert(Ptr{Int}, r) == Base.unsafe_convert(Ptr{Int}, s) + @test isa(r, StridedArray) # issue #22411 end @testset "linearslow" begin s = view(a, :, [2,3,5]) @@ -792,6 +793,11 @@ end R = repeat(1:2, inner=(3,), outer=(2,)) @test R == [1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2] + # Arrays of arrays + @test repeat([[1], [2]], inner=2) == [[1], [1], [2], [2]] + @test repeat([[1], [2]], outer=2) == [[1], [2], [1], [2]] + @test repeat([[1], [2]], inner=2, outer=2) == [[1], [1], [2], [2], [1], [1], [2], [2]] + @test size(repeat([1], inner=(0,))) == (0,) @test size(repeat([1], outer=(0,))) == (0,) @test size(repeat([1 1], inner=(0, 1))) == (0, 2) @@ -1548,6 +1554,11 @@ end @test CartesianRange((3,-7:7)) == CartesianRange(CartesianIndex{2}(3,-7),CartesianIndex{2}(3,7)) end +# All we really care about is that we have an optimized +# implementation, but the seed is a useful way to check that. +@test hash(CartesianIndex()) == Base.IteratorsMD.cartindexhash_seed +@test hash(CartesianIndex(1, 2)) != hash((1, 2)) + @testset "itr, start, done, next" begin r = 2:3 itr = eachindex(r) @@ -1971,6 +1982,10 @@ end # module AutoRetType @test isa(hvcat((2,), densearray, densearray), Array) @test isa(cat((1,2), densearray, densearray), Array) end + @test isa([[1,2,3]'; [1,2,3]'], Matrix{Int}) + @test isa([[1,2,3]' [1,2,3]'], RowVector{Int, Vector{Int}}) + @test isa([Any[1.0, 2]'; Any[2.0, 2]'], Matrix{Any}) + @test isa([Any[1.0, 2]' Any[2.0, 2']'], RowVector{Any, Vector{Any}}) # Test that concatenations of heterogeneous Matrix-Vector pairs yield dense matrices @test isa(hcat(densemat, densevec), Array) @test isa(hcat(densevec, densemat), Array) @@ -2104,3 +2119,8 @@ Base.:(==)(a::T11053, b::T11053) = a.a == b.a #15907 @test typeof(Array{Int,0}()) == Array{Int,0} + +@testset "issue 23629" begin + @test_throws BoundsError zeros(2,3,0)[2,3] + @test_throws BoundsError checkbounds(zeros(2,3,0), 2, 3) +end diff --git a/test/bigint.jl b/test/bigint.jl index 4bf485ccb8e29..771e6343e770b 100644 --- a/test/bigint.jl +++ b/test/bigint.jl @@ -333,6 +333,12 @@ let padding = 4, low = big(4), high = big(2^20) @test hex(-high, padding) == "-100000" end +# respect 0-padding on big(0) +for f in (bin, oct, dec, hex) + @test f(big(0), 0) == "" +end +@test base(rand(2:62), big(0), 0) == "" + @test isqrt(big(4)) == 2 @test isqrt(big(5)) == 2 diff --git a/test/broadcast.jl b/test/broadcast.jl index 8e89a12e65a89..ccb54599d6dbf 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -247,6 +247,11 @@ let x = [1:4;] @test sin.(f17300kw.(x, y=1)) == sin.(f17300kw.(x; y=1)) == sin.(x .+ 1) end +# issue #23236 +let X = [[true,false],[false,true]] + @test [.!x for x in X] == [[false,true],[true,false]] +end + # splice escaping of @. let x = [4, -9, 1, -16] @test [2, 3, 4, 5] == @.(1 + sqrt($sort(abs(x)))) diff --git a/test/codegen.jl b/test/codegen.jl new file mode 100644 index 0000000000000..6925ef1266ff8 --- /dev/null +++ b/test/codegen.jl @@ -0,0 +1,247 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# tests for codegen and optimizations + +const opt_level = Base.JLOptions().opt_level +const coverage = (Base.JLOptions().code_coverage > 0) || (Base.JLOptions().malloc_log > 0) +const Iptr = sizeof(Int) == 8 ? "i64" : "i32" + +# `_dump_function` might be more efficient but it doesn't really matter here... +get_llvm(@nospecialize(f), @nospecialize(t), strip_ir_metadata=true, dump_module=false) = + sprint(code_llvm, f, t, strip_ir_metadata, dump_module) + +if opt_level > 0 + # Make sure getptls call is removed at IR level with optimization on + @test !contains(get_llvm(identity, Tuple{String}), " call ") +end + +jl_string_ptr(s::String) = ccall(:jl_string_ptr, Ptr{UInt8}, (Any,), s) +core_sizeof(o) = Core.sizeof(o) +function test_loads_no_call(ir, load_types) + in_function = false + load_idx = 1 + for line in eachline(IOBuffer(ir)) + if !in_function + if startswith(line, "define ") + in_function = true + end + continue + end + @test !contains(line, " call ") + load_split = split(line, " load ", limit=2) + if !coverage && length(load_split) >= 2 + @test load_idx <= length(load_types) + if load_idx <= length(load_types) + @test startswith(load_split[2], "$(load_types[load_idx]),") + end + load_idx += 1 + end + if startswith(line, "}") + break + end + end + if !coverage + @test load_idx == length(load_types) + 1 + end +end + +# This function tests if functions are output when compiled if jl_dump_compiles is enabled. +# Have to go through pains with recursive function (eval probably not required) to make sure +# that inlining won't happen. +function test_jl_dump_compiles() + tfile = tempname() + io = open(tfile, "w") + @eval(test_jl_dump_compiles_internal(x) = x) + ccall(:jl_dump_compiles, Void, (Ptr{Void},), io.handle) + @eval test_jl_dump_compiles_internal(1) + ccall(:jl_dump_compiles, Void, (Ptr{Void},), C_NULL) + close(io) + tstats = stat(tfile) + tempty = tstats.size == 0 + rm(tfile) + @test tempty == false +end + +# This function tests if a toplevel thunk is output if jl_dump_compiles is enabled. +# The eval statement creates the toplevel thunk. +function test_jl_dump_compiles_toplevel_thunks() + tfile = tempname() + io = open(tfile, "w") + topthunk = expand(Main, :(for i in 1:10; end)) + ccall(:jl_dump_compiles, Void, (Ptr{Void},), io.handle) + Core.eval(Main, topthunk) + ccall(:jl_dump_compiles, Void, (Ptr{Void},), C_NULL) + close(io) + tstats = stat(tfile) + tempty = tstats.size == 0 + rm(tfile) + @test tempty == true +end + +if opt_level > 0 + # Make sure `jl_string_ptr` is inlined + @test !contains(get_llvm(jl_string_ptr, Tuple{String}), " call ") + s = "aaa" + @test jl_string_ptr(s) == pointer_from_objref(s) + sizeof(Int) + # String + test_loads_no_call(get_llvm(core_sizeof, Tuple{String}), [Iptr]) + # String + test_loads_no_call(get_llvm(core_sizeof, Tuple{SimpleVector}), [Iptr]) + # Array + test_loads_no_call(get_llvm(core_sizeof, Tuple{Vector{Int}}), [Iptr]) + # As long as the eltype is known we don't need to load the elsize + test_loads_no_call(get_llvm(core_sizeof, Tuple{Array{Any}}), [Iptr]) + # Check that we load the elsize + test_loads_no_call(get_llvm(core_sizeof, Tuple{Vector}), [Iptr, "i16"]) + + test_jl_dump_compiles() + test_jl_dump_compiles_toplevel_thunks() +end + +# Make sure we will not elide the allocation +@noinline create_ref1() = Ref(1) +function pointer_not_safepoint() + a = create_ref1() + unsafe_store!(Ptr{Int}(pointer_from_objref(a)), 3) + return a[] +end +@test pointer_not_safepoint() == 3 + +# The current memcmp threshold is 512bytes, make sure this struct has the same size on +# 32bits and 64bits +struct LargeStruct + x::NTuple{1024,Int8} + LargeStruct() = new() +end + +const large_struct = LargeStruct() +@noinline create_ref_struct() = Ref(large_struct) +function compare_large_struct(a) + b = create_ref_struct() + if a[] === b[] + b[].x[1] + else + a[].x[2] + end +end + +mutable struct MutableStruct + a::Int + MutableStruct() = new() +end + +breakpoint_mutable(a::MutableStruct) = ccall(:jl_breakpoint, Void, (Ref{MutableStruct},), a) + +# Allocation with uninitialized field as gcroot +mutable struct BadRef + x::MutableStruct + y::MutableStruct + BadRef(x) = new(x) +end +Base.cconvert(::Type{Ptr{BadRef}}, a::MutableStruct) = BadRef(a) +Base.unsafe_convert(::Type{Ptr{BadRef}}, ar::BadRef) = Ptr{BadRef}(pointer_from_objref(ar.x)) + +breakpoint_badref(a::MutableStruct) = ccall(:jl_breakpoint, Void, (Ptr{BadRef},), a) + +struct PtrStruct + a::Ptr{Void} + b::Int +end + +mutable struct RealStruct + a::Float64 + b::Int +end + +function Base.cconvert(::Type{Ref{PtrStruct}}, a::RealStruct) + (a, Ref(PtrStruct(pointer_from_objref(a), a.b))) +end +Base.unsafe_convert(::Type{Ref{PtrStruct}}, at::Tuple) = + Base.unsafe_convert(Ref{PtrStruct}, at[2]) + +breakpoint_ptrstruct(a::RealStruct) = + ccall(:jl_breakpoint, Void, (Ref{PtrStruct},), a) + +if opt_level > 0 + @test !contains(get_llvm(isequal, Tuple{Nullable{BigFloat}, Nullable{BigFloat}}), "%gcframe") + @test !contains(get_llvm(pointer_not_safepoint, Tuple{}), "%gcframe") + compare_large_struct_ir = get_llvm(compare_large_struct, Tuple{typeof(create_ref_struct())}) + @test contains(compare_large_struct_ir, "call i32 @memcmp") + @test !contains(compare_large_struct_ir, "%gcframe") + + @test contains(get_llvm(MutableStruct, Tuple{}), "jl_gc_pool_alloc") + breakpoint_mutable_ir = get_llvm(breakpoint_mutable, Tuple{MutableStruct}) + @test !contains(breakpoint_mutable_ir, "%gcframe") + @test !contains(breakpoint_mutable_ir, "jl_gc_pool_alloc") + + breakpoint_badref_ir = get_llvm(breakpoint_badref, Tuple{MutableStruct}) + @test !contains(breakpoint_badref_ir, "%gcframe") + @test !contains(breakpoint_badref_ir, "jl_gc_pool_alloc") + + breakpoint_ptrstruct_ir = get_llvm(breakpoint_ptrstruct, Tuple{RealStruct}) + @test !contains(breakpoint_ptrstruct_ir, "%gcframe") + @test !contains(breakpoint_ptrstruct_ir, "jl_gc_pool_alloc") +end + +function two_breakpoint(a::Float64) + ccall(:jl_breakpoint, Void, (Ref{Float64},), a) + ccall(:jl_breakpoint, Void, (Ref{Float64},), a) +end + +if opt_level > 0 + breakpoint_f64_ir = get_llvm((a)->ccall(:jl_breakpoint, Void, (Ref{Float64},), a), + Tuple{Float64}) + @test !contains(breakpoint_f64_ir, "jl_gc_pool_alloc") + breakpoint_any_ir = get_llvm((a)->ccall(:jl_breakpoint, Void, (Ref{Any},), a), + Tuple{Float64}) + @test contains(breakpoint_any_ir, "jl_gc_pool_alloc") + two_breakpoint_ir = get_llvm(two_breakpoint, Tuple{Float64}) + @test !contains(two_breakpoint_ir, "jl_gc_pool_alloc") + @test contains(two_breakpoint_ir, "llvm.lifetime.end") +end + +# Issue 22770 +let was_gced = false + @noinline make_tuple(x) = tuple(x) + @noinline use(x) = ccall(:jl_breakpoint, Void, ()) + @noinline assert_not_gced() = @test !was_gced + + function foo22770() + b = Ref(2) + finalizer(b, x -> was_gced = true) + y = make_tuple(b) + x = y[1] + a = Ref(1) + use(x); use(a); use(y) + c = Ref(3) + gc() + assert_not_gced() + use(x) + use(c) + end + foo22770() + gc() + @test was_gced +end + +function egal_svecs() + a = Core.svec(:a, :b) + b = Core.svec(:a, :b) + a === b +end +@test egal_svecs() +@test Core.svec(:a, :b) === Core.svec(:a, :b) + +# issue #22582 +function issue22582!(a::AbstractArray, b) + len = length(a) + if b + ccall(:jl_array_grow_end, Void, (Any, Csize_t), a, 1) + end + return len +end +let c = [1,2,3] + len1 = length(c) + len2 = issue22582!(c, true) + @test len1 == len2 +end diff --git a/test/core.jl b/test/core.jl index 427c00cb72996..d3d7eafa26abd 100644 --- a/test/core.jl +++ b/test/core.jl @@ -177,6 +177,16 @@ struct C21923{T,N}; v::C21923{T,M} where M; end struct D21923{T,N}; v::D21923{T}; end @test fieldtype(D21923, 1) == D21923 +# issue #22624, more circular definitions +struct T22624{A,B,C}; v::Vector{T22624{Int64,A}}; end +let elT = T22624.body.body.body.types[1].parameters[1] + @test elT == T22624{Int64, T22624.var, C} where C + elT2 = elT.body.types[1].parameters[1] + @test elT2 == T22624{Int64, Int64, C} where C + @test elT2.body.types[1].parameters[1] === elT2 + @test isleaftype(elT2.body.types[1]) +end + # issue #3890 mutable struct A3890{T1} x::Matrix{Complex{T1}} @@ -333,6 +343,13 @@ let f = i18408() @test_throws UndefRefError f(0) end +# issue #23558 +c23558(n,k) = + let fact(n) = if (n == 0) 1 else n*fact(n-1) end + fact(n)/fact(k)/fact(n-k) + end +@test c23558(10, 5) == 252 + # variable scope, globals glob_x = 23 function glotest() @@ -476,6 +493,12 @@ let t = (22,33) @test x == 33 end +# issue #23091 +let (f(), x) = (1, 2) + @test f() == 1 + @test x == 2 +end + # issue #21900 f21900_cnt = 0 function f21900() @@ -4969,3 +4992,9 @@ end end @test M22026.foofunction(Int16) === Int16 @test M22026.foofunction2(3) === 6.0f0 + +# issue #23218 +let idx = (7,5,9) + (v,) = (idx...,) + @test v == 7 +end diff --git a/test/deprecation_exec.jl b/test/deprecation_exec.jl new file mode 100644 index 0000000000000..564740af45329 --- /dev/null +++ b/test/deprecation_exec.jl @@ -0,0 +1,64 @@ +using Base.Test + +module DeprecationTests # to test @deprecate + f() = true + + # test the Symbol path of @deprecate + @deprecate f1 f + @deprecate f2 f false # test that f2 is not exported + + # test the Expr path of @deprecate + @deprecate f3() f() + @deprecate f4() f() false # test that f4 is not exported + @deprecate f5(x::T) where T f() + + # test deprecation of a constructor + struct A{T} end + @deprecate A{T}(x::S) where {T, S} f() +end # module +module Foo1234 + export foo1234 + foo1234(x) = x+1 +end + +# issue #21972 +struct T21972 + @noinline function T21972() + Base.depwarn("something", :T21972) + new() + end +end + +@testset "@deprecate" begin + using .DeprecationTests + using .Foo1234 + @test foo1234(3) == 4 + + # enable when issue #22043 is fixed + # @test @test_warn "f1 is deprecated, use f instead." f1() + # @test @test_nowarn f1() + + # @test_throws UndefVarError f2() # not exported + # @test @test_warn "f2 is deprecated, use f instead." DeprecationTests.f2() + # @test @test_nowarn DeprecationTests.f2() + + # @test @test_warn "f3() is deprecated, use f() instead." f3() + # @test @test_nowarn f3() + + # @test_throws UndefVarError f4() # not exported + # @test @test_warn "f4() is deprecated, use f() instead." DeprecationTests.f4() + # @test @test_nowarn DeprecationTests.f4() + + # @test @test_warn "f5(x::T) where T is deprecated, use f() instead." f5(1) + # @test @test_nowarn f5(1) + + # @test @test_warn "A{T}(x::S) where {T, S} is deprecated, use f() instead." A{Int}(1.) + # @test @test_nowarn A{Int}(1.) + + # issue #21972 + @noinline function f21972() + T21972() + end + @test_warn "deprecated" f21972() + @test_nowarn f21972() +end diff --git a/test/distributed_exec.jl b/test/distributed_exec.jl index 2c196fa65c1a5..821f3c1a31eb0 100644 --- a/test/distributed_exec.jl +++ b/test/distributed_exec.jl @@ -11,6 +11,53 @@ include("testenv.jl") end addprocs_with_testenv(4) +@test nprocs() == 5 + +function reuseport_tests() + # Run the test on all processes. + results = asyncmap(procs()) do p + remotecall_fetch(p) do + ports_lower = [] # ports of pids lower than myid() + ports_higher = [] # ports of pids higher than myid() + for w in Base.Distributed.PGRP.workers + w.id == myid() && continue + port = Base._sockname(w.r_stream, true)[2] + if (w.id == 1) + # master connects to workers + push!(ports_higher, port) + elseif w.id < myid() + push!(ports_lower, port) + elseif w.id > myid() + push!(ports_higher, port) + end + end + @assert (length(ports_lower) + length(ports_higher)) == nworkers() + for portset in [ports_lower, ports_higher] + if (length(portset) > 0) && (length(unique(portset)) != 1) + warn("SO_REUSEPORT TESTS FAILED. UNSUPPORTED/OLDER UNIX VERSION?") + return 0 + end + end + return myid() + end + end + + # Ensure that the code has indeed been successfully executed everywhere + @test all(p -> p in results, procs()) +end + +# Test that the client port is reused. SO_REUSEPORT may not be supported on +# all UNIX platforms, Linux kernels prior to 3.9 and older versions of OSX +if is_unix() + # Run reuse client port tests only if SO_REUSEPORT is supported. + s = TCPSocket(delay = false) + is_linux() && Base.Distributed.bind_client_port(s) + if ccall(:jl_tcp_reuseport, Int32, (Ptr{Void},), s.handle) == 0 + reuseport_tests() + else + info("SO_REUSEPORT is unsupported, skipping reuseport tests.") + end +end id_me = myid() id_other = filter(x -> x != id_me, procs())[rand(1:(nprocs()-1))] @@ -102,6 +149,7 @@ function test_futures_dgc(id) @test isnull(f.v) == true @test fetch(f) == id @test isnull(f.v) == false + yield(); # flush gc msgs @test remotecall_fetch(k->(yield();haskey(Base.Distributed.PGRP.refs, k)), id, fid) == false @@ -111,14 +159,14 @@ function test_futures_dgc(id) @test remotecall_fetch(k->(yield();haskey(Base.Distributed.PGRP.refs, k)), id, fid) == true @test isnull(f.v) == true finalize(f) - Base.Distributed.flush_gc_msgs() + yield(); # flush gc msgs @test remotecall_fetch(k->(yield();haskey(Base.Distributed.PGRP.refs, k)), id, fid) == false end test_futures_dgc(id_me) test_futures_dgc(id_other) -# if sent to another worker, it should not be deleted till the other worker has fetched. +# if sent to another worker, it should not be deleted till all references are fetched. wid1 = workers()[1] wid2 = workers()[2] f = remotecall(myid, wid1) @@ -129,7 +177,8 @@ put!(fstore, f) @test fetch(f) == wid1 @test remotecall_fetch(k->haskey(Base.Distributed.PGRP.refs, k), wid1, fid) == true -remotecall_fetch(r->fetch(fetch(r)), wid2, fstore) +remotecall_fetch(r->(fetch(fetch(r)); yield()), wid2, fstore) +sleep(0.5) # to ensure that wid2 gc messages have been executed on wid1 @test remotecall_fetch(k->haskey(Base.Distributed.PGRP.refs, k), wid1, fid) == false # put! should release remote reference since it would have been cached locally @@ -181,7 +230,7 @@ function test_remoteref_dgc(id) @test fetch(rr) == :OK @test remotecall_fetch(k->(yield();haskey(Base.Distributed.PGRP.refs, k)), id, rrid) == true finalize(rr) - Base.Distributed.flush_gc_msgs() + yield(); # flush gc msgs @test remotecall_fetch(k->(yield();haskey(Base.Distributed.PGRP.refs, k)), id, rrid) == false end test_remoteref_dgc(id_me) @@ -197,12 +246,29 @@ fstore = RemoteChannel(wid2) put!(fstore, rr) @test remotecall_fetch(k->haskey(Base.Distributed.PGRP.refs, k), wid1, rrid) == true -finalize(rr); Base.Distributed.flush_gc_msgs() # finalize locally +finalize(rr) # finalize locally +yield(); # flush gc msgs @test remotecall_fetch(k->haskey(Base.Distributed.PGRP.refs, k), wid1, rrid) == true -remotecall_fetch(r->(finalize(take!(r)); Base.Distributed.flush_gc_msgs(); nothing), wid2, fstore) # finalize remotely +remotecall_fetch(r->(finalize(take!(r)); yield(); nothing), wid2, fstore) # finalize remotely sleep(0.5) # to ensure that wid2 messages have been executed on wid1 @test remotecall_fetch(k->haskey(Base.Distributed.PGRP.refs, k), wid1, rrid) == false +# Tests for issue #23109 - should not hang. +f = @spawn rand(1,1) +@sync begin + for _ in 1:10 + @async fetch(f) + end +end + +wid1,wid2 = workers()[1:2] +f = @spawnat wid1 rand(1,1) +@sync begin + @async fetch(f) + @async remotecall_fetch(()->fetch(f), wid2) +end + + @test fetch(@spawnat id_other myid()) == id_other @test (@fetchfrom id_other myid()) == id_other @@ -935,7 +1001,7 @@ if is_unix() # aka have ssh end end - remotecall_fetch(plst->rmprocs(plst; waitfor=5.0), 1, new_pids) + remotecall_fetch(rmprocs, 1, new_pids) end print("\n\nTesting SSHManager. A minimum of 4GB of RAM is recommended.\n") @@ -1543,6 +1609,20 @@ let thrown = false @test thrown end +#19463 +function foo19463() + w1 = workers()[1] + w2 = workers()[2] + w3 = workers()[3] + + b1 = () -> 1 + b2 = () -> fetch(@spawnat w1 b1()) + 1 + b3 = () -> fetch(@spawnat w2 b2()) + 1 + b4 = () -> fetch(@spawnat w3 b3()) + 1 + b4() +end +@test foo19463() == 4 + # Testing clear! function setup_syms(n, pids) syms = [] @@ -1602,6 +1682,47 @@ catch ex @test ex.captured.ex.exceptions[2].ex == UndefVarError(:DontExistOn1) end +@test let + # creates a new worker in the same folder and tries to include file + tmp_file, temp_file_stream = mktemp() + close(temp_file_stream) + tmp_file = relpath(tmp_file) + try + proc = addprocs_with_testenv(1) + include(tmp_file) + remotecall_fetch(include, proc[1], tmp_file) + rmprocs(proc) + rm(tmp_file) + return true + catch e + println(e) + rm(tmp_file, force=true) + return false + end +end == true + +@test let + # creates a new worker in the different folder and tries to include file + tmp_file, temp_file_stream = mktemp() + close(temp_file_stream) + tmp_file = relpath(tmp_file) + tmp_dir = relpath(mktempdir()) + try + proc = addprocs_with_testenv(1, dir=tmp_dir) + include(tmp_file) + remotecall_fetch(include, proc[1], tmp_file) + rmprocs(proc) + rm(tmp_dir) + rm(tmp_file) + return true + catch e + println(e) + rm(tmp_dir, force=true) + rm(tmp_file, force=true) + return false + end +end == true + # Run topology tests last after removing all workers, since a given # cluster at any time only supports a single topology. rmprocs(workers()) diff --git a/test/docs.jl b/test/docs.jl index 17ba396b79deb..dcb91d974594d 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -34,6 +34,20 @@ macro macro_doctest() end @test (@doc @macro_doctest) !== nothing +# test that random stuff interpolated into docstrings doesn't break search or other methods here +doc""" +break me: + + code + +$:asymbol # a symbol +$1 # a number +$string # a function +$$latex literal$$ +### header! +""" +function break_me_docs end + # issue #11548 module ModuleMacroDoc @@ -996,3 +1010,10 @@ end """ ) +# issue #23011 +@test_nowarn @eval Main begin + @doc "first" f23011() = 1 + @doc "second" f23011() = 2 +end +@test Main.f23011() == 2 +@test docstrings_equal(@doc(Main.f23011), doc"second") diff --git a/test/fastmath.jl b/test/fastmath.jl index 1a89a83503eda..0085d84b40e10 100644 --- a/test/fastmath.jl +++ b/test/fastmath.jl @@ -201,3 +201,9 @@ let a = ones(2,2), b = ones(2,2) local c = 0 @test @fastmath(c |= 1) == 1 end + +# issue #23218 +let a = zeros(1), b = ones(1), idx = (1,) + @fastmath a[idx...] += b[idx...] + @test a == b +end diff --git a/test/floatfuncs.jl b/test/floatfuncs.jl index 3fee77d56dbe3..30e189b372ae9 100644 --- a/test/floatfuncs.jl +++ b/test/floatfuncs.jl @@ -14,11 +14,15 @@ end # maxintfloat -@test maxintfloat(Float16) == Float16(2048f0) +@test maxintfloat(Float16) === Float16(2048f0) for elty in (Float16,Float32,Float64) - @test maxintfloat(rand(elty)) == maxintfloat(elty) + @test maxintfloat(rand(elty)) === maxintfloat(elty) end -@test maxintfloat() == maxintfloat(Float64) +@test maxintfloat() === maxintfloat(Float64) +@test maxintfloat(Float64, Int32) === 2147483647.0 +@test maxintfloat(Float32, Int32) === maxintfloat(Float32) +@test maxintfloat(Float64, Int16) === 32767.0 +@test maxintfloat(Float64, Int64) === maxintfloat(Float64) # isinteger for elty in (Float16,Float32,Float64) diff --git a/test/inference.jl b/test/inference.jl index f6fb97e2fc477..d6111ac96dad9 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -858,7 +858,7 @@ let isa_tfunc = Core.Inference.t_ffunc_val[ @test isa_tfunc(Array, Const(AbstractArray)) === Const(true) @test isa_tfunc(Array, Type{AbstractArray}) === Const(true) @test isa_tfunc(Array, Type{AbstractArray{Int}}) == Bool - @test isa_tfunc(Array{Real}, Type{AbstractArray{Int}}) === Bool # could be improved + @test isa_tfunc(Array{Real}, Type{AbstractArray{Int}}) === Const(false) @test isa_tfunc(Array{Real, 2}, Const(AbstractArray{Real, 2})) === Const(true) @test isa_tfunc(Array{Real, 2}, Const(AbstractArray{Int, 2})) === Const(false) @test isa_tfunc(DataType, Int) === Bool # could be improved @@ -869,9 +869,9 @@ let isa_tfunc = Core.Inference.t_ffunc_val[ @test isa_tfunc(Union, Const(Union{Float32, Float64})) === Bool @test isa_tfunc(Union, Type{Union}) === Const(true) @test isa_tfunc(typeof(Union{}), Const(Int)) === Bool # any result is ok - @test isa_tfunc(typeof(Union{}), Const(Union{})) === Bool # could be improved - @test isa_tfunc(typeof(Union{}), typeof(Union{})) === Bool # could be improved - @test isa_tfunc(typeof(Union{}), Union{}) === Bool # could be improved + @test isa_tfunc(typeof(Union{}), Const(Union{})) === Const(false) + @test isa_tfunc(typeof(Union{}), typeof(Union{})) === Const(false) + @test isa_tfunc(typeof(Union{}), Union{}) === Const(false) # any result is ok @test isa_tfunc(typeof(Union{}), Type{typeof(Union{})}) === Const(true) @test isa_tfunc(typeof(Union{}), Const(typeof(Union{}))) === Const(true) let c = Conditional(Core.SlotNumber(0), Const(Union{}), Const(Union{})) @@ -882,5 +882,73 @@ let isa_tfunc = Core.Inference.t_ffunc_val[ @test isa_tfunc(c, Const(Signed)) === Const(false) @test isa_tfunc(c, Type{Complex}) === Const(false) @test isa_tfunc(c, Type{Complex{T}} where T) === Const(false) - end -end + end + @test isa_tfunc(Val{1}, Type{Val{T}} where T) === Bool + @test isa_tfunc(Val{1}, DataType) === Bool + @test isa_tfunc(Any, Const(Any)) === Const(true) + @test isa_tfunc(Any, Union{}) === Const(false) # any result is ok + @test isa_tfunc(Any, Type{Union{}}) === Const(false) + @test isa_tfunc(Union{Int64, Float64}, Type{Real}) === Const(true) + @test isa_tfunc(Union{Int64, Float64}, Type{Integer}) === Bool + @test isa_tfunc(Union{Int64, Float64}, Type{AbstractArray}) === Const(false) +end + +let subtype_tfunc = Core.Inference.t_ffunc_val[ + findfirst(Core.Inference.t_ffunc_key, <:)][3] + @test subtype_tfunc(Type{<:Array}, Const(AbstractArray)) === Const(true) + @test subtype_tfunc(Type{<:Array}, Type{AbstractArray}) === Const(true) + @test subtype_tfunc(Type{<:Array}, Type{AbstractArray{Int}}) == Bool + @test subtype_tfunc(Type{<:Array{Real}}, Type{AbstractArray{Int}}) === Const(false) + @test subtype_tfunc(Type{<:Array{Real, 2}}, Const(AbstractArray{Real, 2})) === Const(true) + @test subtype_tfunc(Type{Array{Real, 2}}, Const(AbstractArray{Int, 2})) === Const(false) + @test subtype_tfunc(DataType, Int) === Bool + @test subtype_tfunc(DataType, Const(Type{Int})) === Bool + @test subtype_tfunc(DataType, Const(Type{Array})) === Bool + @test subtype_tfunc(UnionAll, Const(Type{Int})) === Bool + @test subtype_tfunc(UnionAll, Const(Type{Array})) === Bool + @test subtype_tfunc(Union, Const(Union{Float32, Float64})) === Bool + @test subtype_tfunc(Union, Type{Union}) === Bool + @test subtype_tfunc(Union{}, Const(Int)) === Const(true) # any result is ok + @test subtype_tfunc(Union{}, Const(Union{})) === Const(true) # any result is ok + @test subtype_tfunc(Union{}, typeof(Union{})) === Const(true) # any result is ok + @test subtype_tfunc(Union{}, Union{}) === Const(true) # any result is ok + @test subtype_tfunc(Union{}, Type{typeof(Union{})}) === Const(true) # any result is ok + @test subtype_tfunc(Union{}, Const(typeof(Union{}))) === Const(true) # any result is ok + @test subtype_tfunc(typeof(Union{}), Const(typeof(Union{}))) === Const(true) # Union{} <: typeof(Union{}) + @test subtype_tfunc(typeof(Union{}), Const(Int)) === Const(true) # Union{} <: Int + @test subtype_tfunc(typeof(Union{}), Const(Union{})) === Const(true) # Union{} <: Union{} + @test subtype_tfunc(typeof(Union{}), Type{typeof(Union{})}) === Const(true) # Union{} <: Union{} + @test subtype_tfunc(typeof(Union{}), Type{typeof(Union{})}) === Const(true) # Union{} <: typeof(Union{}) + @test subtype_tfunc(typeof(Union{}), Type{Union{}}) === Const(true) # Union{} <: Union{} + @test subtype_tfunc(Type{Union{}}, typeof(Union{})) === Const(true) # Union{} <: Union{} + @test subtype_tfunc(Type{Union{}}, Const(typeof(Union{}))) === Const(true) # Union{} <: typeof(Union{}) + @test subtype_tfunc(Type{Union{}}, Const(Int)) === Const(true) # Union{} <: typeof(Union{}) + @test subtype_tfunc(Type{Union{}}, Any) === Const(true) # Union{} <: Any + @test subtype_tfunc(Type{Union{}}, Union{Type{Int64}, Type{Float64}}) === Const(true) + @test subtype_tfunc(Type{Union{}}, Union{Type{T}, Type{Float64}} where T) === Const(true) + let c = Conditional(Core.SlotNumber(0), Const(Union{}), Const(Union{})) + @test subtype_tfunc(c, Const(Bool)) === Bool # any result is ok + end + @test subtype_tfunc(Type{Val{1}}, Type{Val{T}} where T) === Bool + @test subtype_tfunc(Type{Val{1}}, DataType) === Bool + @test subtype_tfunc(Type, Type{Val{T}} where T) === Bool + @test subtype_tfunc(Type{Val{T}} where T, Type) === Bool + @test subtype_tfunc(Any, Const(Any)) === Const(true) + @test subtype_tfunc(Type{Any}, Const(Any)) === Const(true) + @test subtype_tfunc(Any, Union{}) === Bool # any result is ok + @test subtype_tfunc(Type{Any}, Union{}) === Const(false) # any result is ok + @test subtype_tfunc(Type, Union{}) === Bool # any result is ok + @test subtype_tfunc(Type, Type{Union{}}) === Bool + @test subtype_tfunc(Union{Type{Int64}, Type{Float64}}, Type{Real}) === Const(true) + @test subtype_tfunc(Union{Type{Int64}, Type{Float64}}, Type{Integer}) === Bool + @test subtype_tfunc(Union{Type{Int64}, Type{Float64}}, Type{AbstractArray}) === Const(false) +end + +function f23024(::Type{T}, ::Int) where T + 1 + 1 +end +v23024 = 0 +g23024(TT::Tuple{DataType}) = f23024(TT[1], v23024) +@test Base.return_types(f23024, (DataType, Any)) == Any[Int] +@test Base.return_types(g23024, (Tuple{DataType},)) == Any[Int] +@test g23024((UInt8,)) === 2 diff --git a/test/int.jl b/test/int.jl index ad2e9a1e8f1f2..d89811e3fcf61 100644 --- a/test/int.jl +++ b/test/int.jl @@ -207,3 +207,10 @@ for T in [Base.BitInteger_types..., BigInt], U in [Base.BitInteger_types..., BigInt] @test typeof(rand(U(0):U(127)) % T) === T end + + +@testset "left shift with Vector{Int} on BigInt-scalar #13832" begin + x = BigInt(1) .<< [1:70;] + @test x[end] == 1180591620717411303424 + @test eltype(x) == BigInt +end diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 547e826480c52..ed3469f906ffd 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -164,3 +164,8 @@ end # issue #15911 @inferred string(1) + +# issue #22837 +for b in [-100:-2; 2:100;] + @test Base.ndigits0z(0, b) == 0 +end diff --git a/test/intset.jl b/test/intset.jl index 1b8bab5557ec8..6d0afdaaba472 100644 --- a/test/intset.jl +++ b/test/intset.jl @@ -86,6 +86,10 @@ end i = IntSet(1:6) @test symdiff!(i, IntSet([6, 513])) == IntSet([1:5; 513]) + + # issue #23099 : these tests should not segfault + @test_throws ArgumentError symdiff!(IntSet(rand(1:100, 30)), 0) + @test_throws ArgumentError symdiff!(IntSet(rand(1:100, 30)), [0, 2, 4]) end @testset "copy, copy!, similar" begin diff --git a/test/iterators.jl b/test/iterators.jl index 5e8e368c33269..44538ba5058bc 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -406,3 +406,9 @@ end @testset "product iterator infinite loop" begin @test collect(product(1:1, (1, "2"))) == [(1, 1) (1, "2")] end + +@testset "filter empty iterable #16704" begin + arr = filter(n -> true, 1:0) + @test length(arr) == 0 + @test eltype(arr) == Int +end diff --git a/test/libgit2.jl b/test/libgit2.jl index 34db5d20b251a..0f09a6ff02d84 100644 --- a/test/libgit2.jl +++ b/test/libgit2.jl @@ -310,7 +310,9 @@ mktempdir() do dir error("unexpected") catch e @test typeof(e) == LibGit2.GitError - @test startswith(sprint(show,e),"GitError(Code:ENOTFOUND, Class:OS, Failed to resolve path") + @test startswith( + lowercase(sprint(show, e)), + lowercase("GitError(Code:ENOTFOUND, Class:OS, failed to resolve path")) end path = joinpath(dir, "Example.BareTwo") repo = LibGit2.init(path, true) diff --git a/test/linalg/diagonal.jl b/test/linalg/diagonal.jl index 6c2f8b2977bcb..562070e6d7d35 100644 --- a/test/linalg/diagonal.jl +++ b/test/linalg/diagonal.jl @@ -346,3 +346,25 @@ end @test logm(D) == Diagonal([logm([1 2; 3 4]), logm([1 2; 3 4])]) @test sqrtm(D) == Diagonal([sqrtm([1 2; 3 4]), sqrtm([1 2; 3 4])]) end + +@testset "multiplication with Symmetric/Hermitian" begin + for T in (Float64, Complex128) + if T <: Complex + R = Float64 + D = Diagonal(complex.(randn(R, n), randn(R, n))) + A = complex.(randn(R, n, n), randn(R, n, n)) + else + D = Diagonal(randn(T, n)) + A = randn(T, n, n) + end + A = A'A + S = Symmetric(A) + H = Hermitian(A) + for f in (*, Ac_mul_B, A_mul_Bc, Ac_mul_Bc, At_mul_B, A_mul_Bt, At_mul_Bt) + @test f(D, S) ≈ f(Matrix(D), Matrix(S)) + @test f(D, H) ≈ f(Matrix(D), Matrix(H)) + @test f(S, D) ≈ f(Matrix(S), Matrix(D)) + @test f(S, H) ≈ f(Matrix(S), Matrix(H)) + end + end +end diff --git a/test/linalg/qr.jl b/test/linalg/qr.jl index 2de9f65fa774c..d7525732c1462 100644 --- a/test/linalg/qr.jl +++ b/test/linalg/qr.jl @@ -183,3 +183,11 @@ B = rand(7,2) # Issue 16520 @test_throws DimensionMismatch ones(3,2)\(1:5) + +# Issue 22810 +let + A = zeros(1, 2) + B = zeros(1, 1) + @test A \ B == zeros(2, 1) + @test qrfact(A, Val{true}) \ B == zeros(2, 1) +end diff --git a/test/linalg/schur.jl b/test/linalg/schur.jl index 9b48443f278c7..3e9913d1ced96 100644 --- a/test/linalg/schur.jl +++ b/test/linalg/schur.jl @@ -100,4 +100,10 @@ aimg = randn(n,n)/2 @test NS[:Z] ≈ sZ end end + @testset "0x0 matrix" for A in (zeros(eltya, 0, 0), view(rand(eltya, 2, 2), 1:0, 1:0)) + T, Z, λ = Base.LinAlg.schur(A) + @test T == A + @test Z == A + @test λ == zeros(0) + end end diff --git a/test/linalg/symmetric.jl b/test/linalg/symmetric.jl index ac43ea7a5420b..e5a6498a81e13 100644 --- a/test/linalg/symmetric.jl +++ b/test/linalg/symmetric.jl @@ -119,6 +119,7 @@ let n=10 @test eigvals(Hermitian(asym), 1:2) ≈ d[1:2] @test eigvals(Hermitian(asym), d[1] - 1, (d[2] + d[3])/2) ≈ d[1:2] @test full(eigfact(asym)) ≈ asym + @test eigvecs(Hermitian(asym)) ≈ eigvecs(asym) # relation to svdvals @test sum(sort(abs.(eigvals(Hermitian(asym))))) == sum(sort(svdvals(Hermitian(asym)))) diff --git a/test/misc.jl b/test/misc.jl index 599aadf854064..ba6e20da774fb 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -702,43 +702,18 @@ end @test ltoh(0x102030405060708) == 0x102030405060708 @test htol(0x102030405060708) == 0x102030405060708 -module DeprecationTests # to test @deprecate - f() = true - - # test the Symbol path of @deprecate - @deprecate f1 f - @deprecate f2 f false # test that f2 is not exported - - # test the Expr path of @deprecate - @deprecate f3() f() - @deprecate f4() f() false # test that f4 is not exported - @deprecate f5(x::T) where T f() - - # test deprecation of a constructor - struct A{T} end - @deprecate A{T}(x::S) where {T, S} f() -end # module - -@testset "@deprecate" begin - using .DeprecationTests - # enable when issue #22043 is fixed - # @test @test_warn "f1 is deprecated, use f instead." f1() - # @test @test_nowarn f1() - - # @test_throws UndefVarError f2() # not exported - # @test @test_warn "f2 is deprecated, use f instead." DeprecationTests.f2() - # @test @test_nowarn DeprecationTests.f2() - - # @test @test_warn "f3() is deprecated, use f() instead." f3() - # @test @test_nowarn f3() +@testset "inline bug #18735" begin + @noinline f(n) = n ? error() : Int + g() = Union{f(true)} + @test_throws ErrorException g() +end - # @test_throws UndefVarError f4() # not exported - # @test @test_warn "f4() is deprecated, use f() instead." DeprecationTests.f4() - # @test @test_nowarn DeprecationTests.f4() +include("testenv.jl") - # @test @test_warn "f5(x::T) where T is deprecated, use f() instead." f5(1) - # @test @test_nowarn f5(1) +let flags = Cmd(filter(a->!contains(a, "depwarn"), test_exeflags.exec)) + local cmd = `$test_exename $flags deprecation_exec.jl` - # @test @test_warn "A{T}(x::S) where {T, S} is deprecated, use f() instead." A{Int}(1.) - # @test @test_nowarn A{Int}(1.) + if !success(pipeline(cmd; stdout=STDOUT, stderr=STDERR)) + error("Deprecation test failed, cmd : $cmd") + end end diff --git a/test/parse.jl b/test/parse.jl index 91fb3fa163000..052b0c272ef21 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -1204,6 +1204,23 @@ module Test21607 end === 1.0 end +# let-bound functions with `where` and static parameters +@test let f()::Int = 2.0 + f() +end === 2 +@test let (f(x::T)::Tuple{Int,Any}) where {T} = (3.0, T) + f("") +end === (3, String) + # issue #19351 # adding return type decl should not affect parse of function body @test :(t(abc) = 3).args[2] == :(t(abc)::Int = 3).args[2] + +# issue #23234 +let + f = function (x=0) + x + end + @test f() == 0 + @test f(2) == 2 +end diff --git a/test/path.jl b/test/path.jl index a2444e7810681..e02176c33945f 100644 --- a/test/path.jl +++ b/test/path.jl @@ -197,3 +197,15 @@ test_relpath() # Test type stability @test isa(joinpath("a", "b"), String) @test isa(joinpath(abspath("a"), "b"), String) + +# homedir +let var = is_windows() ? "USERPROFILE" : "HOME", + MAX_PATH = is_windows() ? 240 : 1020 + for i = 0:9 + local home = " "^MAX_PATH * "123456789"[1:i] + @test withenv(var => home) do + homedir() + end == home + end + @test isabspath(withenv(homedir, var => nothing)) +end diff --git a/test/pkg.jl b/test/pkg.jl index 670d1dbcc42aa..16ce24d293c85 100644 --- a/test/pkg.jl +++ b/test/pkg.jl @@ -39,6 +39,12 @@ function temp_pkg_dir(fn::Function, tmp_dir=joinpath(tempdir(), randstring()), end end +function write_build(pkg, content) + build_filename = Pkg.dir(pkg, "deps", "build.jl") + mkpath(dirname(build_filename)) + write(build_filename, content) +end + # Test basic operations: adding or removing a package, status, free # Also test for the existence of REQUIRE and META_BRANCH temp_pkg_dir() do @@ -531,6 +537,23 @@ temp_pkg_dir() do "redirect_stderr(STDOUT); using Example; Pkg.update(\"$package\")"`)) @test contains(msg, "- $package\nRestart Julia to use the updated versions.") end + + let package = "Output" + stdout_file = Pkg.dir(package, "stdout.txt") + stderr_file = Pkg.dir(package, "stderr.txt") + content = """ + println(STDOUT, "stdout") + println(STDERR, "stderr") + """ + write_build(package, content) + + code = "Pkg.build(\"$package\")" + msg = run(pipeline( + `$(Base.julia_cmd()) --startup-file=no -e $code`, + stdout=stdout_file, stderr=stderr_file)) + @test last(readlines(stdout_file)) == "stdout" + @test last(readlines(stderr_file)) == "stderr" + end end @testset "Pkg functions with .jl extension" begin @@ -539,6 +562,7 @@ end Pkg.add("Example.jl") @test [keys(Pkg.installed())...] == ["Example"] iob = IOBuffer() + Pkg.update("Example.jl") Pkg.checkout("Example.jl") Pkg.status("Example.jl", iob) str = chomp(String(take!(iob))) @@ -594,12 +618,6 @@ end end temp_pkg_dir(initialize=false) do - function write_build(pkg, content) - build_filename = Pkg.dir(pkg, "deps", "build.jl") - mkpath(dirname(build_filename)) - write(build_filename, content) - end - write_build("Normal", "") write_build("Error", "error(\"An error has occurred while building a package\")") write_build("Exit", "exit()") diff --git a/test/ranges.jl b/test/ranges.jl index 506c030db9a33..82352cd1ff3bc 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -356,8 +356,6 @@ for T = (Float32, Float64,), i = 1:2^15, n = 1:5 # FIXME: these fail some small portion of the time @test_skip start == first(r) @test_skip stop == last(r) - # FIXME: linspace construction fails on 32-bit - Sys.WORD_SIZE == 64 || continue l = linspace(start,stop,n) @test n == length(l) # FIXME: these fail some small portion of the time @@ -365,6 +363,11 @@ for T = (Float32, Float64,), i = 1:2^15, n = 1:5 @test_skip stop == last(l) end +# Inexact errors on 32 bit architectures. #22613 +@test first(linspace(log(0.2), log(10.0), 10)) == log(0.2) +@test last(linspace(log(0.2), log(10.0), 10)) == log(10.0) +@test length(Base.floatrange(-3e9, 1.0, 1, 1.0)) == 1 + # linspace & ranges with very small endpoints for T = (Float32, Float64) z = zero(T) @@ -918,3 +921,10 @@ let linsp = linspace(1.0, 2.0, 10) @test Float32(linsp.ref) === convert(Float32, linsp.ref) @test Float32(linsp.ref) ≈ linsp.ref.hi + linsp.ref.lo end + +# Issue #23300 +x = -5:big(1.0):5 +@test map(Float64, x) === -5.0:1.0:5.0 +@test map(Float32, x) === -5.0f0:1.0f0:5.0f0 +@test map(Float16, x) === Float16(-5.0):Float16(1.0):Float16(5.0) +@test map(BigFloat, x) === x diff --git a/test/reduce.jl b/test/reduce.jl index cf89d564262f8..e537a83638b24 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -197,9 +197,17 @@ prod2(itr) = invoke(prod, Tuple{Any}, itr) @test maximum(collect(Int16(1):Int16(100))) === Int16(100) @test maximum(Int32[1,2]) === Int32(2) -@test extrema(reshape(1:24,2,3,4),1) == reshape([(1,2),(3,4),(5,6),(7,8),(9,10),(11,12),(13,14),(15,16),(17,18),(19,20),(21,22),(23,24)],1,3,4) -@test extrema(reshape(1:24,2,3,4),2) == reshape([(1,5),(2,6),(7,11),(8,12),(13,17),(14,18),(19,23),(20,24)],2,1,4) -@test extrema(reshape(1:24,2,3,4),3) == reshape([(1,19),(2,20),(3,21),(4,22),(5,23),(6,24)],2,3,1) +A = circshift(reshape(1:24,2,3,4), (0,1,1)) +@test extrema(A,1) == reshape([(23,24),(19,20),(21,22),(5,6),(1,2),(3,4),(11,12),(7,8),(9,10),(17,18),(13,14),(15,16)],1,3,4) +@test extrema(A,2) == reshape([(19,23),(20,24),(1,5),(2,6),(7,11),(8,12),(13,17),(14,18)],2,1,4) +@test extrema(A,3) == reshape([(5,23),(6,24),(1,19),(2,20),(3,21),(4,22)],2,3,1) +@test extrema(A,(1,2)) == reshape([(19,24),(1,6),(7,12),(13,18)],1,1,4) +@test extrema(A,(1,3)) == reshape([(5,24),(1,20),(3,22)],1,3,1) +@test extrema(A,(2,3)) == reshape([(1,23),(2,24)],2,1,1) +@test extrema(A,(1,2,3)) == reshape([(1,24)],1,1,1) +@test size(extrema(A,1)) == size(maximum(A,1)) +@test size(extrema(A,(1,2))) == size(maximum(A,(1,2))) +@test size(extrema(A,(1,2,3))) == size(maximum(A,(1,2,3))) # any & all diff --git a/test/reflection.jl b/test/reflection.jl index d66098e3fde77..4af005d53a25b 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -92,6 +92,11 @@ show(iob, expand(:(x->x^2))) str = String(take!(iob)) @test isempty(search(str, tag)) +# Make sure non used variables are not emphasized +has_unused() = (a = rand(5)) +@test !warntype_hastag(has_unused, Tuple{}, tag) +@test warntype_hastag(has_unused, Tuple{}, "") + module ImportIntrinsics15819 # Make sure changing the lookup path of an intrinsic doesn't break # the heuristic for type instability warning. diff --git a/test/show.jl b/test/show.jl index a0f9fa3bd32c9..db221959b5930 100644 --- a/test/show.jl +++ b/test/show.jl @@ -618,6 +618,8 @@ end @test repr(:([x for x = y])) == ":([x for x = y])" @test repr(:([x for x = y if z])) == ":([x for x = y if z])" @test repr(:(z for z = 1:5, y = 1:5)) == ":((z for z = 1:5, y = 1:5))" +@test_repr "(x for i in a, b in c)" +@test_repr "(x for a in b, c in d for e in f)" for op in (:(.=), :(.+=), :(.&=)) @test repr(parse("x $op y")) == ":(x $op y)" @@ -669,3 +671,13 @@ let m = which(T20332{Int}(), (Int,)), end @test sprint(show, Main) == "Main" + +struct f_with_params{t} <: Function +end + +(::f_with_params)(x) = 2x + +let io = IOBuffer() + show(io, MIME"text/html"(), f_with_params.body.name.mt) + @test contains(String(take!(io)), "f_with_params") +end diff --git a/test/socket.jl b/test/socket.jl index aeb76aeff2166..1d215ec237efc 100644 --- a/test/socket.jl +++ b/test/socket.jl @@ -69,27 +69,29 @@ end # test show() function for UDPSocket() @test repr(UDPSocket()) == "UDPSocket(init)" -port = Channel(1) defaultport = rand(2000:4000) -tsk = @async begin - p, s = listenany(defaultport) - put!(port, p) - sock = accept(s) - # test write call - write(sock,"Hello World\n") - - # test "locked" println to a socket - @sync begin - for i in 1:100 - @async println(sock, "a", 1) +for testport in [0, defaultport] + port = Channel(1) + tsk = @async begin + p, s = listenany(testport) + put!(port, p) + sock = accept(s) + # test write call + write(sock,"Hello World\n") + + # test "locked" println to a socket + @sync begin + for i in 1:100 + @async println(sock, "a", 1) + end end + close(s) + close(sock) end - close(s) - close(sock) + wait(port) + @test readstring(connect(fetch(port))) == "Hello World\n" * ("a1\n"^100) + wait(tsk) end -wait(port) -@test readstring(connect(fetch(port))) == "Hello World\n" * ("a1\n"^100) -wait(tsk) mktempdir() do tmpdir socketname = is_windows() ? ("\\\\.\\pipe\\uv-test-" * randstring(6)) : joinpath(tmpdir, "socket") diff --git a/test/specificity.jl b/test/specificity.jl index 6657f544b724b..46d7b543ecda3 100644 --- a/test/specificity.jl +++ b/test/specificity.jl @@ -172,3 +172,8 @@ let A = Tuple{T, Array{T, 1}} where T, @test args_morespecific(C, B) @test args_morespecific(C, A) end + +# issue #22908 +f22908(::Union) = 2 +f22908(::Type{Union{Int, Float32}}) = 1 +@test f22908(Union{Int, Float32}) == 1 diff --git a/test/staged.jl b/test/staged.jl index 34fc90d552a29..ba62fc2d91816 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -147,7 +147,6 @@ module TestGeneratedThrow foo() = (bar(rand() > 0.5 ? 1 : 1.0); error("foo")) function __init__() code_typed(foo,(); optimize = false) - @test Core.Inference.isempty(Core.Inference.active) && Core.Inference.isempty(Core.Inference.workq) cfunction(foo,Void,()) end end @@ -175,7 +174,7 @@ let gf_err, tsk = @async nothing # create a Task for yield to try to run end @test_throws ErrorException gf_err() @test_throws ErrorException gf_err() - @test gf_err_ref[] == 4 + @test gf_err_ref[] == 3 end gf_err_ref[] = 0 diff --git a/test/statistics.jl b/test/statistics.jl index 9e7dbf09f6374..d6ecc279a440a 100644 --- a/test/statistics.jl +++ b/test/statistics.jl @@ -113,6 +113,18 @@ X = [2 3 1 -1; 7 4 5 -4] @test isnan(var(1:1)) @test isnan(var(1:-1)) +@test @inferred(var(1.0:8.0)) == 6. +@test varm(1.0:8.0,1.0) == varm(collect(1.0:8.0),1) +@test isnan(varm(1.0:1.0,1.0)) +@test isnan(var(1.0:1.0)) +@test isnan(var(1.0:-1.0)) + +@test @inferred(var(1.0f0:8.0f0)) === 6.f0 +@test varm(1.0f0:8.0f0,1.0f0) == varm(collect(1.0f0:8.0f0),1) +@test isnan(varm(1.0f0:1.0f0,1.0f0)) +@test isnan(var(1.0f0:1.0f0)) +@test isnan(var(1.0f0:-1.0f0)) + @test varm([1,2,3], 2) ≈ 1. @test var([1,2,3]) ≈ 1. @test var([1,2,3]; corrected=false) ≈ 2.0/3 diff --git a/test/strings/basic.jl b/test/strings/basic.jl index b45b6757d80af..36737bb027499 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -461,6 +461,10 @@ Base.endof(x::CharStr) = endof(x.chars) @test cmp("\U1f596\U1f596", CharStr("\U1f596")) == 1 # Gives BoundsError with bug @test cmp(CharStr("\U1f596"), "\U1f596\U1f596") == -1 +# repeat function +@test repeat("xx",3) == repeat("x",6) == "xxxxxx" +@test repeat("αα",3) == repeat("α",6) == "αααααα" + # issue #12495: check that logical indexing attempt raises ArgumentError @test_throws ArgumentError "abc"[[true, false, true]] @test_throws ArgumentError "abc"[BitArray([true, false, true])] diff --git a/test/subtype.jl b/test/subtype.jl index 4ca0b5b288566..3e2fcab5d01d1 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -446,7 +446,9 @@ function test_Type() @test isa(Int, @UnionAll T<:Number Type{T}) @test !isa(DataType, @UnionAll T<:Number Type{T}) - @test DataType <: (@UnionAll T<:Type Type{T}) + @test !(DataType <: (@UnionAll T<:Type Type{T})) + @test isa(DataType, (@UnionAll T<:Type Type{T})) + @test isa(Tuple{},Type{Tuple{}}) @test !(Tuple{Int,} <: (@UnionAll T<:Tuple Type{T})) @test isa(Tuple{Int}, (@UnionAll T<:Tuple Type{T})) @@ -598,15 +600,25 @@ function test_properties() end macro testintersect(a, b, result) - if isa(result,Expr) && result.head === :call && length(result.args)==2 && result.args[1] === :! + if isa(result, Expr) && result.head === :call && length(result.args) == 2 && result.args[1] === :! result = result.args[2] - cmp = :notequal_type + cmp = :(!=) else - cmp = :isequal_type + cmp = :(==) end + cmp = esc(cmp) + a = esc(a) + b = esc(b) + result = esc(result) Base.remove_linenums!(quote - @test $(esc(cmp))(_type_intersect($(esc(a)), $(esc(b))), $(esc(result))) - @test $(esc(cmp))(_type_intersect($(esc(b)), $(esc(a))), $(esc(result))) + # test real intersect + @test $cmp(_type_intersect($a, $b), $result) + @test $cmp(_type_intersect($b, $a), $result) + # test simplified intersect + if !($result === Union{}) + @test typeintersect($a, $b) != Union{} + @test typeintersect($b, $a) != Union{} + end end) end @@ -1113,3 +1125,27 @@ end @testintersect(Val{Pair{T,T}} where T, Val{Pair{Int,T}} where T, Val{Pair{Int,Int}}) + +# issue #23024 +@testintersect(Tuple{DataType, Any}, + Tuple{Type{T}, Int} where T, + Tuple{DataType, Int}) + +# issue #23430 +@test [0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; + 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; + 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; + 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; + 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; + 0 0.; 0 0.; 0 0.; 0 0.] isa Matrix{Float64} +@test !(Tuple{Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64} <: (Tuple{Vararg{T}} where T<:Number)) diff --git a/test/tuple.jl b/test/tuple.jl index d59b0497cdc9f..bbf224ca0ebe2 100644 --- a/test/tuple.jl +++ b/test/tuple.jl @@ -258,3 +258,7 @@ end for n = 0:15 @test ntuple(identity, Val{n}) == ntuple(identity, n) end + +# https://github.com/JuliaLang/julia/issues/21026#issuecomment-317113307 +const VecTuple21026{T} = Tuple{VecElement{T}} +@test convert(VecTuple21026, (1,)) === (VecElement(1),) diff --git a/test/unicode/utf8proc.jl b/test/unicode/utf8proc.jl index 403c2775f9897..d06106a9abefc 100644 --- a/test/unicode/utf8proc.jl +++ b/test/unicode/utf8proc.jl @@ -311,9 +311,12 @@ end h = hash(str) @test hash(g) == h @test convert(GenericString, g) == str - io = IOBuffer() - show(io, g) - check = "length-14 GraphemeIterator{String} for \"$str\"" - @test String(take!(io)) == check + @test repr(g) == "length-14 GraphemeIterator{String} for \"$str\"" end end + +@testset "#22693: substring graphemes" begin + g = graphemes(SubString("123α56789", 1, 6)) + @test eltype(g) == SubString{String} + @test collect(g) == ["1","2","3","α","5"] +end