diff --git a/.travis.yml b/.travis.yml index 94edf04dbd4602..1f7ff08e6711f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,7 +81,7 @@ before_install: brew install -v staticfloat/juliadeps/libgfortran; brew install -v --only-dependencies --HEAD julia; BUILDOPTS="-j3 USECLANG=1 LLVM_CONFIG=$(brew --prefix llvm37-julia)/bin/llvm-config-3.7.1 LLVM_SIZE=$(brew --prefix llvm37-julia)/bin/llvm-size-3.7.1"; - BUILDOPTS="$BUILDOPTS VERBOSE=1 USE_BLAS64=0 SUITESPARSE_INC=-I$(brew --prefix suite-sparse-julia)/include FORCE_ASSERTIONS=1 STAGE2_DEPS=utf8proc"; + BUILDOPTS="$BUILDOPTS VERBOSE=1 USE_BLAS64=0 SUITESPARSE_INC=-I$(brew --prefix suite-sparse-julia)/include FORCE_ASSERTIONS=1"; BUILDOPTS="$BUILDOPTS LIBBLAS=-lopenblas LIBBLASNAME=libopenblas LIBLAPACK=-lopenblas LIBLAPACKNAME=libopenblas"; for lib in LLVM SUITESPARSE ARPACK BLAS FFTW LAPACK GMP MPFR PCRE LIBUNWIND; do export BUILDOPTS="$BUILDOPTS USE_SYSTEM_$lib=1"; @@ -111,6 +111,10 @@ script: - export JULIA_CPU_CORES=2 && export JULIA_TEST_MAXRSS_MB=600 && cd /tmp/julia/share/julia/test && /tmp/julia/bin/julia --check-bounds=yes runtests.jl $TESTSTORUN && /tmp/julia/bin/julia --check-bounds=yes runtests.jl libgit2-online pkg - - cd `dirname $TRAVIS_BUILD_DIR` && mv julia2 julia && rm -rf julia/deps/build/julia-env + - cd `dirname $TRAVIS_BUILD_DIR` && mv julia2 julia && + rm -rf julia/deps/build/julia-env && + rm -rf julia/deps/build/libssh2-*/CMakeFiles/Makefile2 && + rm -rf julia/deps/build/curl-*/config.log && + rm -rf julia/deps/build/curl-*/libtool # uncomment the following if failures are suspected to be due to the out-of-memory killer # - dmesg diff --git a/LICENSE.md b/LICENSE.md index fd312fcee06f38..ab11841e04e273 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -57,6 +57,7 @@ their own licenses: - [FFTW](http://fftw.org/doc/License-and-Copyright.html) [GPL2+] - [GMP](http://gmplib.org/manual/Copying.html#Copying) [LGPL3+ or GPL2+] - [LIBGIT2](https://github.com/libgit2/libgit2/blob/development/COPYING) [GPL2+ with unlimited linking exception] +- [CURL](https://curl.haxx.se/docs/copyright.html) [MIT/X derivative] - [LIBSSH2](https://github.com/libssh2/libssh2/blob/master/COPYING) [BSD-3] - [MBEDTLS](https://tls.mbed.org/how-to-get) [either GPLv2 or Apache 2.0] - [MPFR](http://www.mpfr.org/mpfr-current/mpfr.html#Copying) [LGPL3+] diff --git a/Make.inc b/Make.inc index 8bd586dd92cb8b..b8b04c93323132 100644 --- a/Make.inc +++ b/Make.inc @@ -38,6 +38,7 @@ USE_SYSTEM_LIBUV:=0 USE_SYSTEM_UTF8PROC:=0 USE_SYSTEM_MBEDTLS:=0 USE_SYSTEM_LIBSSH2:=0 +USE_SYSTEM_CURL:=0 USE_SYSTEM_LIBGIT2:=0 USE_SYSTEM_PATCHELF:=0 @@ -339,6 +340,11 @@ endif STDLIBCPP_FLAG := +ifeq ($(OS), FreeBSD) +USEGCC := 0 +USECLANG := 1 +endif + ifeq ($(OS), Darwin) DARWINVER := $(shell uname -r | cut -b 1-2) DARWINVER_GTE13 := $(shell expr `uname -r | cut -b 1-2` \>= 13) @@ -459,6 +465,7 @@ endif #ARCH LD := link endif #USEMSVC RANLIB := $(CROSS_COMPILE)ranlib +OBJCOPY := $(CROSS_COMPILE)objcopy # file extensions ifeq ($(OS), WINNT) diff --git a/Makefile b/Makefile index 8b20b2e4585e8b..c10090e4b73c26 100644 --- a/Makefile +++ b/Makefile @@ -277,6 +277,9 @@ endif ifeq ($(USE_SYSTEM_LIBSSH2),0) JL_PRIVATE_LIBS += ssh2 endif +ifeq ($(USE_SYSTEM_CURL),0) +JL_PRIVATE_LIBS += curl +endif ifeq ($(USE_SYSTEM_LIBGIT2),0) JL_PRIVATE_LIBS += git2 endif @@ -468,7 +471,11 @@ endif ifeq ($(OS), WINNT) [ ! -d $(JULIAHOME)/dist-extras ] || ( cd $(JULIAHOME)/dist-extras && \ - cp 7z.exe 7z.dll busybox.exe libexpat-1.dll zlib1.dll $(BUILDROOT)/julia-$(JULIA_COMMIT)/bin ) + cp 7z.exe 7z.dll libexpat-1.dll zlib1.dll libgfortran-3.dll libquadmath-0.dll libstdc++-6.dll libgcc_s_s*-1.dll libssp-0.dll $(BUILDROOT)/julia-$(JULIA_COMMIT)/bin ) +ifeq ($(USE_GPL_LIBS), 1) + [ ! -d $(JULIAHOME)/dist-extras ] || ( cd $(JULIAHOME)/dist-extras && \ + cp busybox.exe $(BUILDROOT)/julia-$(JULIA_COMMIT)/bin ) +endif cd $(BUILDROOT)/julia-$(JULIA_COMMIT)/bin && rm -f llvm* llc.exe lli.exe opt.exe LTO.dll bugpoint.exe macho-dump.exe # create file listing for uninstall. note: must have Windows path separators and line endings. @@ -593,7 +600,14 @@ ifneq (,$(filter $(ARCH), i386 i486 i586 i686)) $(JLDOWNLOAD) http://downloads.sourceforge.net/sevenzip/7z920.exe && \ 7z x -y 7z920.exe 7z.exe 7z.dll && \ ../contrib/windows/winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_13.2 \ - "mingw32-libgfortran3 mingw32-libquadmath0 mingw32-libstdc++6 mingw32-libgcc_s_sjlj1 mingw32-libssp0 mingw32-libexpat1 mingw32-zlib1" && \ + "mingw32-libexpat1 mingw32-zlib1" && \ + $(JLDOWNLOAD) https://julialang.s3.amazonaws.com/bin/winnt/extras/mingw32-libgfortran3-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://julialang.s3.amazonaws.com/bin/winnt/extras/mingw32-libquadmath0-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://julialang.s3.amazonaws.com/bin/winnt/extras/mingw32-libstdc++6-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://julialang.s3.amazonaws.com/bin/winnt/extras/mingw32-libgcc_s_sjlj1-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://julialang.s3.amazonaws.com/bin/winnt/extras/mingw32-libssp0-5.3.0-1.1.noarch.rpm && \ + for i in *.rpm; do 7z x -y $$i; done && \ + for i in *.cpio; do 7z x -y $$i; done && \ cp usr/i686-w64-mingw32/sys-root/mingw/bin/*.dll . else ifeq ($(ARCH),x86_64) cd $(JULIAHOME)/dist-extras && \ @@ -602,7 +616,14 @@ else ifeq ($(ARCH),x86_64) mv _7z.dll 7z.dll && \ mv _7z.exe 7z.exe && \ ../contrib/windows/winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win64/openSUSE_13.2 \ - "mingw64-libgfortran3 mingw64-libquadmath0 mingw64-libstdc++6 mingw64-libgcc_s_seh1 mingw64-libssp0 mingw64-libexpat1 mingw64-zlib1" && \ + "mingw64-libexpat1 mingw64-zlib1" && \ + $(JLDOWNLOAD) https://julialang.s3.amazonaws.com/bin/winnt/extras/mingw64-libgfortran3-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://julialang.s3.amazonaws.com/bin/winnt/extras/mingw64-libquadmath0-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://julialang.s3.amazonaws.com/bin/winnt/extras/mingw64-libstdc++6-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://julialang.s3.amazonaws.com/bin/winnt/extras/mingw64-libgcc_s_seh1-5.3.0-1.1.noarch.rpm && \ + $(JLDOWNLOAD) https://julialang.s3.amazonaws.com/bin/winnt/extras/mingw64-libssp0-5.3.0-1.1.noarch.rpm && \ + for i in *.rpm; do 7z x -y $$i; done && \ + for i in *.cpio; do 7z x -y $$i; done && \ cp usr/x86_64-w64-mingw32/sys-root/mingw/bin/*.dll . else $(error no win-extras target for ARCH=$(ARCH)) @@ -610,12 +631,15 @@ endif cd $(JULIAHOME)/dist-extras && \ $(JLDOWNLOAD) http://downloads.sourceforge.net/sevenzip/7z920_extra.7z && \ $(JLDOWNLOAD) https://unsis.googlecode.com/files/nsis-2.46.5-Unicode-setup.exe && \ - $(JLDOWNLOAD) busybox.exe http://frippery.org/files/busybox/busybox-w32-FRP-483-g31277ab.exe && \ chmod a+x 7z.exe && \ chmod a+x 7z.dll && \ $(call spawn,./7z.exe) x -y -onsis nsis-2.46.5-Unicode-setup.exe && \ - chmod a+x ./nsis/makensis.exe && \ + chmod a+x ./nsis/makensis.exe +ifeq ($(USE_GPL_LIBS), 1) + cd $(JULIAHOME)/dist-extras && \ + $(JLDOWNLOAD) busybox.exe http://frippery.org/files/busybox/busybox-w32-FRP-483-g31277ab.exe && \ chmod a+x busybox.exe +endif # various statistics about the build that may interest the user ifeq ($(USE_SYSTEM_LLVM), 1) diff --git a/README.arm.md b/README.arm.md index 1c50538172cb94..f31eed9d51ef3a 100644 --- a/README.arm.md +++ b/README.arm.md @@ -1,7 +1,12 @@ # Julia binaries for ARM [Nightly builds](https://status.julialang.org/download/linux-arm) are -available for ARM. +available for ARMv7-A. + +# Hardware requirements + +Julia requires at least `armv6` and `vfpv2` instruction sets. It's recommended +to use at least `armv7-a`. `armv5` or soft float are not supported. # Building Julia on ARM diff --git a/README.md b/README.md index a1d390f724d6d8..bf89ab33271bfd 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ developers may find the notes in [CONTRIBUTING](https://github.com/JuliaLang/jul - **FreeBSD** - **Windows** -All systems are supported with both x86/64 (64-bit) and x86 (32-bit) architectures. Experimental and early support for [ARM](https://github.com/JuliaLang/julia/blob/master/README.arm.md) is available too. +All systems are supported with both x86/64 (64-bit) and x86 (32-bit) architectures. Experimental and early support for [ARM](https://github.com/JuliaLang/julia/blob/master/README.arm.md), AARCH64, and POWER (little-endian) is available too. ## Source Download and Compilation @@ -235,12 +235,22 @@ When building Julia, or its dependencies, libraries installed by third party pac ### FreeBSD -On *FreeBSD Release 9.0*, install the `gcc47`, `git`, and `gmake` packages/ports, and compile Julia with the command: +On *FreeBSD Release 11.0*, install the gfortran, git, cmake, and gmake packages/ports (`pkg install gcc6 gmake git cmake`), and compile Julia with the command: - $ gmake FC=gfortran47 + $ echo 'FC=gfortran6' >> Make.user + $ gmake You must use the `gmake` command on FreeBSD instead of `make`. +Note that Julia is community-supported and we have little control over our upstream dependencies, you may still run into issues with dependencies and YMMV. Current known issues include: + + - The x86 arch doesn't support threading due to lack of compiler runtime library support (set `JULIA_THREADS=0`). + - libunwind needs a small patch to its tests to compile. + - OpenBLAS patches in pkg haven't been upstreamed. + - gfortran can't link binaries. Set `FFLAGS=-Wl,-rpath,/usr/local/lib/gcc6` to work around this (upstream bug submitted to FreeBSD pkg maintainers). + - System libraries installed by pkg are not on the compiler path by default. You may need to add `LDFLAGS=/usr/local/lib` and `CPPFLAGS=/usr/local/include` to your environment or `Make.user` file to build successfully. + + ### Windows In order to build Julia on Windows, see [README.windows](https://github.com/JuliaLang/julia/blob/master/README.windows.md). @@ -263,6 +273,7 @@ Building Julia requires that the following software be installed: - **[patch]** — for modifying source code. - **[cmake]** — needed to build `libgit2`. - **[openssl]** — needed for HTTPS support in `libgit2` on Linux, install via `apt-get install libssl-dev` or `yum install openssl-devel`. +- **[pkg-config]** - needed to build libgit2 correctly, especially for proxy support Julia uses the following external libraries, which are automatically downloaded (or in a few cases, included in the Julia source repository) and then compiled from source the first time you run `make`: @@ -283,6 +294,7 @@ Julia uses the following external libraries, which are automatically downloaded - **[GMP]** (>= 5.0) — GNU multiple precision arithmetic library, needed for `BigInt` support. - **[MPFR]** (>= 3.0) — GNU multiple precision floating point library, needed for arbitrary precision floating point (`BigFloat`) support. - **[libgit2]** (>= 0.23) — Git linkable library, used by Julia's package manager +- **[curl]** (>= 7.50) — libcurl provides download and proxy support for Julia's package manager - **[libssh2]** (>= 1.7) — library for SSH transport, used by libgit2 for packages with SSH remotes - **[mbedtls]** (>= 2.2) — library used for cryptography and transport layer security, used by libssh2 - **[utf8proc]** (>= 2.0) — a library for processing UTF-8 encoded Unicode strings @@ -325,6 +337,7 @@ For a longer overview of Julia's dependencies, see these [slides](https://github [openssl]: https://www.openssl.org [libssh2]: https://www.libssh2.org [mbedtls]: https://tls.mbed.org/ +[pkg-config]: https://www.freedesktop.org/wiki/Software/pkg-config/ ### System Provided Libraries diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 74dc06ccccf680..fbecc43efa4f8d 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -9,6 +9,7 @@ typealias RangeIndex Union{Int, Range{Int}, AbstractUnitRange{Int}, Colon} typealias DimOrInd Union{Integer, AbstractUnitRange} typealias IntOrInd Union{Int, AbstractUnitRange} typealias DimsOrInds{N} NTuple{N,DimOrInd} +typealias NeedsShaping Union{Tuple{Integer,Vararg{Integer}}, Tuple{OneTo,Vararg{OneTo}}} macro _inline_pure_meta() Expr(:meta, :inline, :pure) @@ -51,7 +52,11 @@ size{N}(x, d1::Integer, d2::Integer, dx::Vararg{Integer, N}) = (size(x, d1), siz Returns the valid range of indices for array `A` along dimension `d`. """ -indices{T,N}(A::AbstractArray{T,N}, d) = d <= N ? indices(A)[d] : OneTo(1) +function indices{T,N}(A::AbstractArray{T,N}, d) + @_inline_meta + d <= N ? indices(A)[d] : OneTo(1) +end + """ indices(A) @@ -59,7 +64,7 @@ Returns the tuple of valid indices for array `A`. """ function indices(A) @_inline_meta - map(s->OneTo(s), size(A)) + map(OneTo, size(A)) end # Performance optimization: get rid of a branch on `d` in `indices(A, @@ -177,12 +182,15 @@ function _strides{M,T,N}(out::NTuple{M}, A::AbstractArray{T,N}) end function isassigned(a::AbstractArray, i::Int...) - # TODO try a[i...] true - catch - false + catch e + if isa(e, BoundsError) || isa(e, UndefRefError) + return false + else + rethrow(e) + end end end @@ -413,14 +421,14 @@ different element type it will create a regular `Array` instead: 2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314 """ -similar{T}(a::AbstractArray{T}) = similar(a, T) -similar( a::AbstractArray, T::Type) = similar(a, T, to_shape(indices(a))) -similar{T}(a::AbstractArray{T}, dims::Tuple) = similar(a, T, to_shape(dims)) -similar{T}(a::AbstractArray{T}, dims::DimOrInd...) = similar(a, T, to_shape(dims)) -similar( a::AbstractArray, T::Type, dims::DimOrInd...) = similar(a, T, to_shape(dims)) -similar( a::AbstractArray, T::Type, dims) = similar(a, T, to_shape(dims)) +similar{T}(a::AbstractArray{T}) = similar(a, T) +similar{T}(a::AbstractArray, ::Type{T}) = similar(a, T, to_shape(indices(a))) +similar{T}(a::AbstractArray{T}, dims::Tuple) = similar(a, T, to_shape(dims)) +similar{T}(a::AbstractArray{T}, dims::DimOrInd...) = similar(a, T, to_shape(dims)) +similar{T}(a::AbstractArray, ::Type{T}, dims::DimOrInd...) = similar(a, T, to_shape(dims)) +similar{T}(a::AbstractArray, ::Type{T}, dims::NeedsShaping) = similar(a, T, to_shape(dims)) # similar creates an Array by default -similar{N}(a::AbstractArray, T::Type, dims::Dims{N}) = Array{T,N}(dims) +similar{T,N}(a::AbstractArray, ::Type{T}, dims::Dims{N}) = Array{T,N}(dims) to_shape(::Tuple{}) = () to_shape(dims::Dims) = dims @@ -709,10 +717,6 @@ of_indices(x, y) = similar(dims->y, oftype(indices(x), indices(y))) full(x::AbstractArray) = x -map(::Type{Integer}, a::Array) = map!(Integer, similar(a,typeof(Integer(one(eltype(a))))), a) -map(::Type{Signed}, a::Array) = map!(Signed, similar(a,typeof(Signed(one(eltype(a))))), a) -map(::Type{Unsigned}, a::Array) = map!(Unsigned, similar(a,typeof(Unsigned(one(eltype(a))))), a) - ## range conversions ## map{T<:Real}(::Type{T}, r::StepRange) = T(r.start):T(r.step):T(last(r)) @@ -1653,12 +1657,12 @@ end # These are needed because map(eltype, As) is not inferrable promote_eltype_op(::Any) = (@_pure_meta; Bottom) +promote_eltype_op(op, A) = (@_pure_meta; promote_op(op, eltype(A))) promote_eltype_op{T}(op, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, T)) -promote_eltype_op{T}(op, ::T ) = (@_pure_meta; promote_op(op, T)) +promote_eltype_op{T}(op, ::AbstractArray{T}, A) = (@_pure_meta; promote_op(op, T, eltype(A))) +promote_eltype_op{T}(op, A, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, eltype(A), T)) promote_eltype_op{R,S}(op, ::AbstractArray{R}, ::AbstractArray{S}) = (@_pure_meta; promote_op(op, R, S)) -promote_eltype_op{R,S}(op, ::AbstractArray{R}, ::S) = (@_pure_meta; promote_op(op, R, S)) -promote_eltype_op{R,S}(op, ::R, ::AbstractArray{S}) = (@_pure_meta; promote_op(op, R, S)) -promote_eltype_op(op, A, B, C, D...) = (@_pure_meta; promote_op(op, eltype(A), promote_eltype_op(op, B, C, D...))) +promote_eltype_op(op, A, B, C, D...) = (@_pure_meta; promote_eltype_op(op, promote_eltype_op(op, A, B), C, D...)) ## 1 argument map!{F}(f::F, A::AbstractArray) = map!(f, A, A) diff --git a/base/array.jl b/base/array.jl index 4eba2f531ad788..2e0f5b4feb98bf 100644 --- a/base/array.jl +++ b/base/array.jl @@ -126,7 +126,7 @@ similar{N}(a::Array, T::Type, dims::Dims{N}) = Array{T,N}(dims) similar{T,N}(a::Array{T}, dims::Dims{N}) = Array{T,N}(dims) # T[x...] constructs Array{T,1} -function getindex(T::Type, vals...) +function getindex{T}(::Type{T}, vals...) a = Array{T,1}(length(vals)) @inbounds for i = 1:length(vals) a[i] = vals[i] @@ -134,10 +134,10 @@ function getindex(T::Type, vals...) return a end -getindex(T::Type) = Array{T,1}(0) -getindex(T::Type, x) = (a = Array{T,1}(1); @inbounds a[1] = x; a) -getindex(T::Type, x, y) = (a = Array{T,1}(2); @inbounds (a[1] = x; a[2] = y); a) -getindex(T::Type, x, y, z) = (a = Array{T,1}(3); @inbounds (a[1] = x; a[2] = y; a[3] = z); a) +getindex{T}(::Type{T}) = (@_inline_meta; Array{T,1}(0)) +getindex{T}(::Type{T}, x) = (@_inline_meta; a = Array{T,1}(1); @inbounds a[1] = x; a) +getindex{T}(::Type{T}, x, y) = (@_inline_meta; a = Array{T,1}(2); @inbounds (a[1] = x; a[2] = y); a) +getindex{T}(::Type{T}, x, y, z) = (@_inline_meta; a = Array{T,1}(3); @inbounds (a[1] = x; a[2] = y; a[3] = z); a) function getindex(::Type{Any}, vals::ANY...) a = Array{Any,1}(length(vals)) @@ -288,8 +288,8 @@ else _default_eltype(itr::ANY) = Any end -_array_for(T, itr, ::HasLength) = Array{T,1}(Int(length(itr)::Integer)) -_array_for(T, itr, ::HasShape) = similar(Array{T}, indices(itr)) +_array_for{T}(::Type{T}, itr, ::HasLength) = Array{T,1}(Int(length(itr)::Integer)) +_array_for{T}(::Type{T}, itr, ::HasShape) = similar(Array{T}, indices(itr)) function collect(itr::Generator) isz = iteratorsize(itr.iter) @@ -1077,15 +1077,18 @@ function find(testf::Function, A) # use a dynamic-length array to store the indexes, then copy to a non-padded # array for the return tmpI = Array{Int,1}(0) + inds = _index_remapper(A) for (i,a) = enumerate(A) if testf(a) - push!(tmpI, i) + push!(tmpI, inds[i]) end end I = Array{Int,1}(length(tmpI)) copy!(I, tmpI) return I end +_index_remapper(A::AbstractArray) = linearindices(A) +_index_remapper(iter) = Colon() # safe for objects that don't implement length """ find(A) @@ -1110,9 +1113,10 @@ function find(A) nnzA = countnz(A) I = Vector{Int}(nnzA) count = 1 + inds = _index_remapper(A) for (i,a) in enumerate(A) if a != 0 - I[count] = i + I[count] = inds[i] count += 1 end end diff --git a/base/arraymath.jl b/base/arraymath.jl index 60b78f0a2fed3c..171d301fb48e9b 100644 --- a/base/arraymath.jl +++ b/base/arraymath.jl @@ -35,30 +35,26 @@ function !(A::AbstractArray{Bool}) end ## Binary arithmetic operators ## -@pure promote_array_type{S<:Number, A<:AbstractArray}(F, ::Type{S}, ::Type{A}) = - promote_array_type(F, S, eltype(A), promote_op(F, S, eltype(A))) -@pure promote_array_type{S<:Number, A<:AbstractArray}(F, ::Type{A}, ::Type{S}) = - promote_array_type(F, S, eltype(A), promote_op(F, eltype(A), S)) - -@pure promote_array_type{S, A, P}(F, ::Type{S}, ::Type{A}, ::Type{P}) = P -@pure promote_array_type{S<:Real, A<:AbstractFloat, P}(F, ::Type{S}, ::Type{A}, ::Type{P}) = A -@pure promote_array_type{S<:Integer, A<:Integer, P}(F::typeof(./), ::Type{S}, ::Type{A}, ::Type{P}) = P -@pure promote_array_type{S<:Integer, A<:Integer, P}(F::typeof(.\), ::Type{S}, ::Type{A}, ::Type{P}) = P -@pure promote_array_type{S<:Integer, A<:Integer, P}(F, ::Type{S}, ::Type{A}, ::Type{P}) = A -@pure promote_array_type{S<:Integer, P}(F::typeof(./), ::Type{S}, ::Type{Bool}, ::Type{P}) = P -@pure promote_array_type{S<:Integer, P}(F::typeof(.\), ::Type{S}, ::Type{Bool}, ::Type{P}) = P -@pure promote_array_type{S<:Integer, P}(F, ::Type{S}, ::Type{Bool}, ::Type{P}) = P + +promote_array_type(F, ::Type, ::Type, T::Type) = T +promote_array_type{S<:Real, A<:AbstractFloat}(F, ::Type{S}, ::Type{A}, ::Type) = A +promote_array_type{S<:Integer, A<:Integer}(F, ::Type{S}, ::Type{A}, ::Type) = A +promote_array_type{S<:Integer, A<:Integer}(::typeof(./), ::Type{S}, ::Type{A}, T::Type) = T +promote_array_type{S<:Integer, A<:Integer}(::typeof(.\), ::Type{S}, ::Type{A}, T::Type) = T +promote_array_type{S<:Integer}(::typeof(./), ::Type{S}, ::Type{Bool}, T::Type) = T +promote_array_type{S<:Integer}(::typeof(.\), ::Type{S}, ::Type{Bool}, T::Type) = T +promote_array_type{S<:Integer}(F, ::Type{S}, ::Type{Bool}, T::Type) = T for f in (:+, :-, :div, :mod, :&, :|, :$) - @eval ($f){S,T}(A::AbstractArray{S}, B::AbstractArray{T}) = - _elementwise($f, A, B, promote_eltype_op($f, A, B)) + @eval ($f){R,S}(A::AbstractArray{R}, B::AbstractArray{S}) = + _elementwise($f, promote_op($f, R, S), A, B) end -function _elementwise{S,T}(op, A::AbstractArray{S}, B::AbstractArray{T}, ::Type{Any}) - promote_shape(A,B) # check size compatibility +function _elementwise(op, ::Type{Any}, A::AbstractArray, B::AbstractArray) + promote_shape(A, B) # check size compatibility return broadcast(op, A, B) end -function _elementwise{S,T,R}(op, A::AbstractArray{S}, B::AbstractArray{T}, ::Type{R}) - F = similar(A, R, promote_shape(A,B)) +function _elementwise{T}(op, ::Type{T}, A::AbstractArray, B::AbstractArray) + F = similar(A, T, promote_shape(A, B)) for (iF, iA, iB) in zip(eachindex(F), eachindex(A), eachindex(B)) @inbounds F[iF] = op(A[iA], B[iB]) end @@ -68,14 +64,20 @@ end for f in (:.+, :.-, :.*, :./, :.\, :.^, :.÷, :.%, :.<<, :.>>, :div, :mod, :rem, :&, :|, :$) @eval begin function ($f){T}(A::Number, B::AbstractArray{T}) - F = similar(B, promote_array_type($f,typeof(A),typeof(B))) + R = promote_op($f, typeof(A), T) + S = promote_array_type($f, typeof(A), T, R) + S === Any && return [($f)(A, b) for b in B] + F = similar(B, S) for (iF, iB) in zip(eachindex(F), eachindex(B)) @inbounds F[iF] = ($f)(A, B[iB]) end return F end function ($f){T}(A::AbstractArray{T}, B::Number) - F = similar(A, promote_array_type($f,typeof(A),typeof(B))) + R = promote_op($f, T, typeof(B)) + S = promote_array_type($f, typeof(B), T, R) + S === Any && return [($f)(a, B) for a in A] + F = similar(A, S) for (iF, iA) in zip(eachindex(F), eachindex(A)) @inbounds F[iF] = ($f)(A[iA], B) end diff --git a/base/base.jl b/base/base.jl index 910db8d8a6fec2..9fa8d77cb4a150 100644 --- a/base/base.jl +++ b/base/base.jl @@ -1,5 +1,10 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license +""" + SystemError(prefix::AbstractString, [errno::Int32]) + +A system call failed with an error code (in the `errno` global variable). +""" type SystemError <: Exception prefix::AbstractString errnum::Int32 @@ -9,10 +14,22 @@ type SystemError <: Exception SystemError(p::AbstractString) = new(p, Libc.errno()) end +""" + ParseError(msg) + +The expression passed to the `parse` function could not be interpreted as a valid Julia +expression. +""" type ParseError <: Exception msg::AbstractString end +""" + ArgumentError(msg) + +The parameters to a function call do not match a valid signature. Argument `msg` is a +descriptive error string. +""" type ArgumentError <: Exception msg::AbstractString end @@ -21,25 +38,53 @@ end # var::Symbol #end +""" + KeyError(key) + +An indexing operation into an `Associative` (`Dict`) or `Set` like object tried to access or +delete a non-existent element. +""" type KeyError <: Exception key end +""" + MethodError(f, args) + +A method with the required type signature does not exist in the given generic function. +Alternatively, there is no unique most-specific method. +""" type MethodError <: Exception f args end +""" + EOFError() + +No more data was available to read from a file or stream. +""" type EOFError <: Exception end +""" + DimensionMismatch([msg]) + +The objects called do not have matching dimensionality. Optional argument `msg` is a +descriptive error string. +""" type DimensionMismatch <: Exception msg::AbstractString end DimensionMismatch() = DimensionMismatch("") +""" + AssertionError([msg]) + +The asserted condition did not evaluate to `true`. +Optional argument `msg` is a descriptive error string. +""" type AssertionError <: Exception msg::AbstractString - AssertionError() = new("") AssertionError(msg) = new(msg) end @@ -48,12 +93,24 @@ end #Subtypes should put the exception in an 'error' field abstract WrappedException <: Exception +""" + LoadError(file::AbstractString, line::Int, error) + +An error occurred while `include`ing, `require`ing, or `using` a file. The error specifics +should be available in the `.error` field. +""" type LoadError <: WrappedException file::AbstractString line::Int error end +""" + InitError(mod::Symbol, error) + +An error occurred when running a module's `__init__` function. The actual error thrown is +available in the `.error` field. +""" type InitError <: WrappedException mod::Symbol error diff --git a/base/bitarray.jl b/base/bitarray.jl index 72272422c7f208..3e67d3c86e9115 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -1052,18 +1052,29 @@ for f in (:+, :-) return r end end + for (f) in (:.+, :.-) - for (arg1, arg2, T, fargs) in ((:(B::BitArray), :(x::Bool) , Int , :(b, x)), - (:(B::BitArray), :(x::Number) , :(promote_array_type($f, BitArray, typeof(x))), :(b, x)), - (:(x::Bool) , :(B::BitArray), Int , :(x, b)), - (:(x::Number) , :(B::BitArray), :(promote_array_type($f, typeof(x), BitArray)), :(x, b))) + for (arg1, arg2, T, t) in ((:(B::BitArray), :(x::Bool) , Int , (:b, :x)), + (:(B::BitArray), :(x::Number) , :(Bool, typeof(x)), (:b, :x)), + (:(x::Bool) , :(B::BitArray), Int , (:x, :b)), + (:(x::Number) , :(B::BitArray), :(typeof(x), Bool), (:x, :b))) @eval function ($f)($arg1, $arg2) - r = Array{$T}(size(B)) + $(if T === Int + quote + r = Array{Int}(size(B)) + end + else + quote + T = promote_op($f, $(T.args[1]), $(T.args[2])) + T === Any && return [($f)($(t[1]), $(t[2])) for b in B] + r = Array{T}(size(B)) + end + end) bi = start(B) ri = 1 while !done(B, bi) b, bi = next(B, bi) - @inbounds r[ri] = ($f)($fargs...) + @inbounds r[ri] = ($f)($(t[1]), $(t[2])) ri += 1 end return r @@ -1095,9 +1106,8 @@ function div(x::Bool, B::BitArray) end function div(x::Number, B::BitArray) all(B) || throw(DivideError()) - pt = promote_array_type(div, typeof(x), BitArray) y = div(x, true) - reshape(pt[ y for i = 1:length(B) ], size(B)) + return fill(y, size(B)) end function mod(A::BitArray, B::BitArray) @@ -1116,15 +1126,16 @@ function mod(x::Bool, B::BitArray) end function mod(x::Number, B::BitArray) all(B) || throw(DivideError()) - pt = promote_array_type(mod, typeof(x), BitArray) y = mod(x, true) - reshape(pt[ y for i = 1:length(B) ], size(B)) + return fill(y, size(B)) end for f in (:div, :mod) @eval begin function ($f)(B::BitArray, x::Number) - F = Array{promote_array_type($f, BitArray, typeof(x))}(size(B)) + T = promote_op($f, Bool, typeof(x)) + T === Any && return [($f)(b, x) for b in B] + F = Array{T}(size(B)) for i = 1:length(F) F[i] = ($f)(B[i], x) end diff --git a/base/broadcast.jl b/base/broadcast.jl index 937d66375bd9ab..e42f2a67edfbc4 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -3,7 +3,7 @@ module Broadcast using Base.Cartesian -using Base: promote_op, promote_eltype, promote_eltype_op, @get!, _msk_end, unsafe_bitgetindex, linearindices, tail, OneTo, to_shape +using Base: promote_eltype_op, @get!, _msk_end, unsafe_bitgetindex, linearindices, tail, OneTo, to_shape import Base: .+, .-, .*, ./, .\, .//, .==, .<, .!=, .<=, .÷, .%, .<<, .>>, .^ export broadcast, broadcast!, bitbroadcast, dotview export broadcast_getindex, broadcast_setindex! @@ -299,7 +299,7 @@ end ## elementwise operators ## for op in (:÷, :%, :<<, :>>, :-, :/, :\, ://, :^) - @eval $(Symbol(:., op))(A::AbstractArray, B::AbstractArray) = broadcast($(op), A, B) + @eval $(Symbol(:., op))(A::AbstractArray, B::AbstractArray) = broadcast($op, A, B) end .+(As::AbstractArray...) = broadcast(+, As...) .*(As::AbstractArray...) = broadcast(*, As...) diff --git a/base/char.jl b/base/char.jl index 52aa1492e2f862..58481c6d39c2a1 100644 --- a/base/char.jl +++ b/base/char.jl @@ -40,10 +40,6 @@ hash(x::Char, h::UInt) = hash_uint64(((UInt64(x)+hashchar_seed)<<32) $ UInt64(h) +(x::Char, y::Integer) = Char(Int32(x) + Int32(y)) +(x::Integer, y::Char) = y + x -Base.promote_op{I<:Integer}(::typeof(-), ::Type{Char}, ::Type{I}) = Char -Base.promote_op{I<:Integer}(::typeof(+), ::Type{Char}, ::Type{I}) = Char -Base.promote_op{I<:Integer}(::typeof(+), ::Type{I}, ::Type{Char}) = Char - bswap(x::Char) = Char(bswap(UInt32(x))) print(io::IO, c::Char) = (write(io, c); nothing) diff --git a/base/complex.jl b/base/complex.jl index da644f94123317..7be18a036f9512 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -804,7 +804,8 @@ big{T<:AbstractFloat,N}(A::AbstractArray{Complex{T},N}) = convert(AbstractArray{ ## promotion to complex ## -promote_array_type{S<:Union{Complex, Real}, AT<:AbstractFloat, P}(F, ::Type{S}, ::Type{Complex{AT}}, ::Type{P}) = Complex{AT} +_default_type(T::Type{Complex}) = Complex{Int} +promote_array_type{S<:Union{Complex, Real}, T<:AbstractFloat}(F, ::Type{S}, ::Type{Complex{T}}, ::Type) = Complex{T} function complex{S<:Real,T<:Real}(A::AbstractArray{S}, B::AbstractArray{T}) if size(A) != size(B); throw(DimensionMismatch()); end diff --git a/base/dates/arithmetic.jl b/base/dates/arithmetic.jl index 4a94fc13df9116..94752ffe2390ad 100644 --- a/base/dates/arithmetic.jl +++ b/base/dates/arithmetic.jl @@ -94,21 +94,3 @@ end # AbstractArray{TimeType}, AbstractArray{TimeType} (-){T<:TimeType}(x::OrdinalRange{T}, y::OrdinalRange{T}) = collect(x) - collect(y) (-){T<:TimeType}(x::Range{T}, y::Range{T}) = collect(x) - collect(y) - -# promotion rules - -for op in (:+, :-, :.+, :.-) - @eval begin - Base.promote_op{P<:Period}(::typeof($op), ::Type{P}, ::Type{P}) = P - Base.promote_op{P1<:Period,P2<:Period}(::typeof($op), ::Type{P1}, ::Type{P2}) = CompoundPeriod - Base.promote_op{D<:Date}(::typeof($op), ::Type{D}, ::Type{D}) = Day - Base.promote_op{D<:DateTime}(::typeof($op), ::Type{D}, ::Type{D}) = Millisecond - end -end - -for op in (:/, :%, :div, :mod, :./, :.%) - @eval begin - Base.promote_op{P<:Period}(::typeof($op), ::Type{P}, ::Type{P}) = typeof($op(1,1)) - Base.promote_op{P<:Period,R<:Real}(::typeof($op), ::Type{P}, ::Type{R}) = P - end -end diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 3a669992c71f33..f02519fb3f3174 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -1226,7 +1226,7 @@ Return an array of substrings by splitting the given string on occurrences of th character delimiters, which may be specified in any of the formats allowed by `search`'s second argument (i.e. a single character, collection of characters, string, or regular expression). If `chars` is omitted, it defaults to the set of all space characters, and -`keep` is taken to be `false`. The two keyword arguments are optional: they are are a +`keep` is taken to be `false`. The two keyword arguments are optional: they are a maximum size for the result and a flag determining whether empty fields should be kept in the result. """ @@ -2127,17 +2127,6 @@ Largest integer less than or equal to `x/y`. """ fld -""" - withenv(f::Function, kv::Pair...) - -Execute `f()` in an environment that is temporarily modified (not replaced as in `setenv`) -by zero or more `"var"=>val` arguments `kv`. `withenv` is generally used via the -`withenv(kv...) do ... end` syntax. A value of `nothing` can be used to temporarily unset an -environment variable (if it is set). When `withenv` returns, the original environment has -been restored. -""" -withenv - """ setdiff!(s, iterable) @@ -2145,13 +2134,6 @@ Remove each element of `iterable` from set `s` in-place. """ setdiff! -""" - EOFError() - -No more data was available to read from a file or stream. -""" -EOFError - """ isascii(c::Union{Char,AbstractString}) -> Bool @@ -2912,21 +2894,6 @@ Squared absolute value of `x`. """ abs2 -""" - write(stream::IO, x) - write(filename::AbstractString, x) - -Write the canonical binary representation of a value to the given I/O stream or file. -Returns the number of bytes written into the stream. - -You can write multiple values with the same :func:`write` call. i.e. the following are -equivalent: - - write(stream, x, y...) - write(stream, x) + write(stream, y...) -""" -write - """ sizehint!(s, n) @@ -2968,12 +2935,6 @@ handle properly. """ OutOfMemoryError -""" - SystemError(prefix::AbstractString, [errno::Int32]) - -A system call failed with an error code (in the `errno` global variable). -""" -SystemError """ binomial(n,k) @@ -3012,14 +2973,6 @@ detailed system information is shown as well. """ versioninfo -""" - DimensionMismatch([msg]) - -The objects called do not have matching dimensionality. Optional argument `msg` is a -descriptive error string. -""" -DimensionMismatch - """ sort!(v, [alg=,] [by=,] [lt=,] [rev=false]) @@ -3590,13 +3543,6 @@ cannot be used with empty collections (see `reduce(op, itr)`). """ foldr(op, itr) -""" - ParseError(msg) - -The expression passed to the `parse` function could not be interpreted as a valid Julia expression. -""" -ParseError - """ delete!(collection, key) @@ -4449,22 +4395,6 @@ Get the file name part of a path. """ basename -""" - ArgumentError(msg) - -The parameters to a function call do not match a valid signature. Argument `msg` is a -descriptive error string. -""" -ArgumentError - -""" - KeyError(key) - -An indexing operation into an `Associative` (`Dict`) or `Set` like object tried to access or -delete a non-existent element. -""" -KeyError - """ isdiag(A) -> Bool @@ -5321,13 +5251,6 @@ the array length. If the array length is excessive, the excess portion is filled """ digits! -""" - MethodError(f, args) - -A method with the required type signature does not exist in the given generic function. Alternatively, there is no unique most-specific method. -""" -MethodError - """ cat(dims, A...) @@ -6620,22 +6543,6 @@ Compute the phase angle in radians of a complex number `z`. """ angle -""" - LoadError(file::AbstractString, line::Int, error) - -An error occurred while `include`ing, `require`ing, or `using` a file. The error specifics -should be available in the `.error` field. -""" -LoadError - -""" - InitError(mod::Symbol, error) - -An error occurred when running a module's `__init__` function. The actual error thrown is -available in the `.error` field. -""" -InitError - """ copy!(dest, src) @@ -7512,14 +7419,6 @@ Integer division was attempted with a denominator value of 0. """ DivideError -""" - AssertionError([msg]) - -The asserted condition did not evaluate to `true`. -Optional argument `msg` is a descriptive error string. -""" -AssertionError - """ Ac_ldiv_Bc(A, B) diff --git a/base/env.jl b/base/env.jl index fc3fe87e78c703..db7d8514823e8b 100644 --- a/base/env.jl +++ b/base/env.jl @@ -1,61 +1,59 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license if is_windows() -const ERROR_ENVVAR_NOT_FOUND = UInt32(203) + const ERROR_ENVVAR_NOT_FOUND = UInt32(203) -_getenvlen(var::Vector{UInt16}) = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32),var,C_NULL,0) -_hasenv(s::Vector{UInt16}) = _getenvlen(s) != 0 || Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND -_hasenv(s::AbstractString) = _hasenv(cwstring(s)) + _getenvlen(var::Vector{UInt16}) = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32),var,C_NULL,0) + _hasenv(s::Vector{UInt16}) = _getenvlen(s) != 0 || Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND + _hasenv(s::AbstractString) = _hasenv(cwstring(s)) -function access_env(onError::Function, str::AbstractString) - var = cwstring(str) - len = _getenvlen(var) - if len == 0 - return Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND ? "" : onError(str) + function access_env(onError::Function, str::AbstractString) + var = cwstring(str) + len = _getenvlen(var) + if len == 0 + return Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND ? "" : onError(str) + end + val = zeros(UInt16,len) + ret = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32),var,val,len) + if (ret == 0 && len != 1) || ret != len-1 || val[end] != 0 + error(string("getenv: ", str, ' ', len, "-1 != ", ret, ": ", Libc.FormatMessage())) + end + pop!(val) # NUL + return transcode(String, val) end - val = zeros(UInt16,len) - ret = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32),var,val,len) - if (ret == 0 && len != 1) || ret != len-1 || val[end] != 0 - error(string("getenv: ", str, ' ', len, "-1 != ", ret, ": ", Libc.FormatMessage())) + + function _setenv(svar::AbstractString, sval::AbstractString, overwrite::Bool=true) + var = cwstring(svar) + val = cwstring(sval) + if overwrite || !_hasenv(var) + ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,val) + systemerror(:setenv, ret == 0) + end end - pop!(val) # NUL - return transcode(String, val) -end -function _setenv(svar::AbstractString, sval::AbstractString, overwrite::Bool=true) - var = cwstring(svar) - val = cwstring(sval) - if overwrite || !_hasenv(var) - ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,val) + function _unsetenv(svar::AbstractString) + var = cwstring(svar) + ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,C_NULL) systemerror(:setenv, ret == 0) end -end - -function _unsetenv(svar::AbstractString) - var = cwstring(svar) - ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,C_NULL) - systemerror(:setenv, ret == 0) -end - else # !windows -_getenv(var::AbstractString) = ccall(:getenv, Cstring, (Cstring,), var) -_hasenv(s::AbstractString) = _getenv(s) != C_NULL - -function access_env(onError::Function, var::AbstractString) - val = _getenv(var) - val == C_NULL ? onError(var) : unsafe_string(val) -end + _getenv(var::AbstractString) = ccall(:getenv, Cstring, (Cstring,), var) + _hasenv(s::AbstractString) = _getenv(s) != C_NULL -function _setenv(var::AbstractString, val::AbstractString, overwrite::Bool=true) - ret = ccall(:setenv, Int32, (Cstring,Cstring,Int32), var, val, overwrite) - systemerror(:setenv, ret != 0) -end + function access_env(onError::Function, var::AbstractString) + val = _getenv(var) + val == C_NULL ? onError(var) : unsafe_string(val) + end -function _unsetenv(var::AbstractString) - ret = ccall(:unsetenv, Int32, (Cstring,), var) - systemerror(:unsetenv, ret != 0) -end + function _setenv(var::AbstractString, val::AbstractString, overwrite::Bool=true) + ret = ccall(:setenv, Int32, (Cstring,Cstring,Int32), var, val, overwrite) + systemerror(:setenv, ret != 0) + end + function _unsetenv(var::AbstractString) + ret = ccall(:unsetenv, Int32, (Cstring,), var) + systemerror(:unsetenv, ret != 0) + end end # os test ## ENV: hash interface ## @@ -83,45 +81,43 @@ setindex!(::EnvHash, v, k::AbstractString) = _setenv(k,string(v)) push!(::EnvHash, k::AbstractString, v) = setindex!(ENV, v, k) if is_windows() -start(hash::EnvHash) = (pos = ccall(:GetEnvironmentStringsW,stdcall,Ptr{UInt16},()); (pos,pos)) -function done(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}}) - if unsafe_load(block[1]) == 0 - ccall(:FreeEnvironmentStringsW, stdcall, Int32, (Ptr{UInt16},), block[2]) - return true + start(hash::EnvHash) = (pos = ccall(:GetEnvironmentStringsW,stdcall,Ptr{UInt16},()); (pos,pos)) + function done(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}}) + if unsafe_load(block[1]) == 0 + ccall(:FreeEnvironmentStringsW, stdcall, Int32, (Ptr{UInt16},), block[2]) + return true + end + return false end - return false -end -function next(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}}) - pos = block[1] - blk = block[2] - len = ccall(:wcslen, UInt, (Ptr{UInt16},), pos) - buf = Array{UInt16}(len) - unsafe_copy!(pointer(buf), pos, len) - env = transcode(String, buf) - m = match(r"^(=?[^=]+)=(.*)$"s, env) - if m === nothing - error("malformed environment entry: $env") + function next(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}}) + pos = block[1] + blk = block[2] + len = ccall(:wcslen, UInt, (Ptr{UInt16},), pos) + buf = Array{UInt16}(len) + unsafe_copy!(pointer(buf), pos, len) + env = transcode(String, buf) + m = match(r"^(=?[^=]+)=(.*)$"s, env) + if m === nothing + error("malformed environment entry: $env") + end + return (Pair{String,String}(m.captures[1], m.captures[2]), (pos+(len+1)*2, blk)) end - return (Pair{String,String}(m.captures[1], m.captures[2]), (pos+len*2, blk)) -end - else # !windows -start(::EnvHash) = 0 -done(::EnvHash, i) = (ccall(:jl_environ, Any, (Int32,), i) === nothing) + start(::EnvHash) = 0 + done(::EnvHash, i) = (ccall(:jl_environ, Any, (Int32,), i) === nothing) -function next(::EnvHash, i) - env = ccall(:jl_environ, Any, (Int32,), i) - if env === nothing - throw(BoundsError()) - end - env = env::String - m = match(r"^(.*?)=(.*)$"s, env) - if m === nothing - error("malformed environment entry: $env") + function next(::EnvHash, i) + env = ccall(:jl_environ, Any, (Int32,), i) + if env === nothing + throw(BoundsError()) + end + env = env::String + m = match(r"^(.*?)=(.*)$"s, env) + if m === nothing + error("malformed environment entry: $env") + end + return (Pair{String,String}(m.captures[1], m.captures[2]), i+1) end - return (Pair{String,String}(m.captures[1], m.captures[2]), i+1) -end - end # os-test #TODO: Make these more efficent @@ -139,7 +135,15 @@ function show(io::IO, ::EnvHash) end end -# temporarily set and then restore an environment value +""" + withenv(f::Function, kv::Pair...) + +Execute `f()` in an environment that is temporarily modified (not replaced as in `setenv`) +by zero or more `"var"=>val` arguments `kv`. `withenv` is generally used via the +`withenv(kv...) do ... end` syntax. A value of `nothing` can be used to temporarily unset an +environment variable (if it is set). When `withenv` returns, the original environment has +been restored. +""" function withenv{T<:AbstractString}(f::Function, keyvals::Pair{T}...) old = Dict{T,Any}() for (key,val) in keyvals diff --git a/base/essentials.jl b/base/essentials.jl index fed6c191ea4de9..30b8d83148f467 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -202,7 +202,7 @@ function isassigned(v::SimpleVector, i::Int) end # index colon -type Colon +immutable Colon end const (:) = Colon() diff --git a/base/float.jl b/base/float.jl index 20b7e9a2513ca3..01767dd3d4123a 100644 --- a/base/float.jl +++ b/base/float.jl @@ -230,6 +230,8 @@ promote_rule(::Type{Float64}, ::Type{Float32}) = Float64 widen(::Type{Float16}) = Float32 widen(::Type{Float32}) = Float64 +_default_type(T::Union{Type{Real},Type{AbstractFloat}}) = Float64 + ## floating point arithmetic ## -(x::Float32) = box(Float32,neg_float(unbox(Float32,x))) -(x::Float64) = box(Float64,neg_float(unbox(Float64,x))) diff --git a/base/inference.jl b/base/inference.jl index 4022da0726a60f..2649514a32bd15 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -9,7 +9,8 @@ const MAX_TUPLETYPE_LEN = 15 const MAX_TUPLE_DEPTH = 4 const MAX_TUPLE_SPLAT = 16 -const MAX_UNION_SPLITTING = 6 +const MAX_UNION_SPLITTING = 4 +const UNION_SPLIT_MISMATCH_ERROR = false # alloc_elim_pass! relies on `Slot_AssignedOnce | Slot_UsedUndef` being # SSA. This should be true now but can break if we start to track conditional @@ -408,7 +409,7 @@ function limit_type_depth(t::ANY, d::Int, cov::Bool, vars) else return t end - if inexact && !isvarargtype(R) + if inexact && (!cov || !isvarargtype(R)) R = TypeVar(:_,R) push!(vars, R) end @@ -467,15 +468,18 @@ function getfield_tfunc(s0::ANY, name) end end snames = s.name.names - for i=1:length(snames) + for i = 1:length(snames) if is(snames[i],fld) R = s.types[i] if isempty(s.parameters) return R, true else + # conservatively limit the type depth here, + # since the UnionAll type bound is otherwise incorrect + # in the current type system typ = limit_type_depth(R, 0, true, filter!(x->isa(x,TypeVar), Any[s.parameters...])) - return typ, isleaftype(s) && typeseq(typ, R) + return typ, isleaftype(s) && isa(R, Type) && typeof(R) === typeof(typ) && typeseq(R, typ) end end end @@ -493,8 +497,21 @@ function getfield_tfunc(s0::ANY, name) return Bottom, true end return s.types[i], false + elseif isempty(s.types) + return Bottom, true + elseif length(s.types) == 1 && isempty(s.parameters) + return s.types[1], true else - return reduce(tmerge, Bottom, map(unwrapva,s.types)) #=Union{s.types...}=#, false + R = reduce(tmerge, Bottom, map(unwrapva, s.types)) #=Union{s.types...}=# + alleq = isa(R, Type) && typeof(R) === typeof(s.types[1]) && typeseq(R, s.types[1]) + # do the same limiting as the known-symbol case to preserve type-monotonicity + if isempty(s.parameters) + return R, alleq + else + typ = limit_type_depth(R, 0, true, + filter!(x->isa(x,TypeVar), Any[s.parameters...])) + return typ, alleq && isleaftype(s) && typeof(R) === typeof(typ) && typeseq(R, typ) + end end end add_tfunc(getfield, 2, 2, (s,name)->getfield_tfunc(s,name)[1]) @@ -1037,6 +1054,23 @@ function abstract_call(f::ANY, fargs, argtypes::Vector{Any}, vtypes::VarTable, s return Type end + if sv.inlining + # need to model the special inliner for ^ + # to ensure we have added the same edge + if isdefined(Main, :Base) && + ((isdefined(Main.Base, :^) && is(f, Main.Base.:^)) || + (isdefined(Main.Base, :.^) && is(f, Main.Base.:.^))) && + length(argtypes) == 3 && (argtypes[3] ⊑ Int32 || argtypes[3] ⊑ Int64) + + a1 = argtypes[2] + basenumtype = Union{corenumtype, Main.Base.Complex64, Main.Base.Complex128, Main.Base.Rational} + if a1 ⊑ basenumtype + ftimes = Main.Base.:* + ta1 = widenconst(a1) + abstract_call_gf_by_type(ftimes, Tuple{typeof(ftimes), ta1, ta1}, sv) + end + end + end return abstract_call_gf_by_type(f, atype, sv) end @@ -1074,7 +1108,7 @@ function abstract_eval(e::ANY, vtypes::VarTable, sv::InferenceState) if isa(e,QuoteNode) return abstract_eval_constant((e::QuoteNode).value) elseif isa(e,SSAValue) - return abstract_eval_ssavalue(e::SSAValue, sv) + return abstract_eval_ssavalue(e::SSAValue, sv.linfo) elseif isa(e,Slot) return vtypes[e.id].typ elseif isa(e,Symbol) @@ -1158,8 +1192,8 @@ function abstract_eval_global(M::Module, s::Symbol) return Any end -function abstract_eval_ssavalue(s::SSAValue, sv::InferenceState) - typ = sv.linfo.ssavaluetypes[s.id+1] +function abstract_eval_ssavalue(s::SSAValue, linfo::LambdaInfo) + typ = linfo.ssavaluetypes[s.id + 1] if typ === NF return Bottom end @@ -1436,7 +1470,11 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, needtr end end - if caller === nothing && in_typeinf_loop + ccall(:jl_typeinf_begin, Void, ()) + thread_in_typeinf_loop = in_typeinf_loop::Bool + ccall(:jl_typeinf_end, Void, ()) + + if caller === nothing && thread_in_typeinf_loop # if the caller needed the ast, but we are already in the typeinf loop # then just return early -- we can't fulfill this request # if the client was inlining, then this means we decided not to try to infer this @@ -1889,7 +1927,7 @@ function finish(me::InferenceState) if !ispure && length(me.linfo.code) < 10 ispure = true for stmt in me.linfo.code - if !statement_effect_free(stmt, me) + if !statement_effect_free(stmt, me.linfo) ispure = false; break end end @@ -2145,20 +2183,21 @@ function occurs_more(e::ANY, pred, n) return 0 end -function exprtype(x::ANY, sv::InferenceState) - if isa(x,Expr) +function exprtype(x::ANY, linfo::LambdaInfo) + if isa(x, Expr) return (x::Expr).typ - elseif isa(x,SlotNumber) - return sv.linfo.slottypes[x.id] - elseif isa(x,TypedSlot) + elseif isa(x, SlotNumber) + return linfo.slottypes[x.id] + elseif isa(x, TypedSlot) return (x::Slot).typ - elseif isa(x,SSAValue) - return abstract_eval_ssavalue(x::SSAValue, sv) - elseif isa(x,Symbol) - return abstract_eval_global(sv.mod, x::Symbol) - elseif isa(x,QuoteNode) + elseif isa(x, SSAValue) + return abstract_eval_ssavalue(x::SSAValue, linfo) + elseif isa(x, Symbol) + mod = isdefined(linfo, :def) ? linfo.def.module : current_module() + return abstract_eval_global(mod, x::Symbol) + elseif isa(x, QuoteNode) return abstract_eval_constant((x::QuoteNode).value) - elseif isa(x,GlobalRef) + elseif isa(x, GlobalRef) return abstract_eval_global(x.mod, (x::GlobalRef).name) else return abstract_eval_constant(x) @@ -2189,28 +2228,28 @@ function is_pure_builtin(f::ANY) return false end -function statement_effect_free(e::ANY, sv) - if isa(e,Expr) +function statement_effect_free(e::ANY, linfo::LambdaInfo) + if isa(e, Expr) if e.head === :(=) - return !isa(e.args[1],GlobalRef) && effect_free(e.args[2], sv, false) + return !isa(e.args[1], GlobalRef) && effect_free(e.args[2], linfo, false) elseif e.head === :gotoifnot - return effect_free(e.args[1], sv, false) + return effect_free(e.args[1], linfo, false) end - elseif isa(e,LabelNode) || isa(e,GotoNode) + elseif isa(e, LabelNode) || isa(e, GotoNode) return true end - return effect_free(e, sv, false) + return effect_free(e, linfo, false) end # detect some important side-effect-free calls (allow_volatile=true) # and some affect-free calls (allow_volatile=false) -- affect_free means the call # cannot be affected by previous calls, except assignment nodes -function effect_free(e::ANY, sv, allow_volatile::Bool) - if isa(e,GlobalRef) +function effect_free(e::ANY, linfo::LambdaInfo, allow_volatile::Bool) + if isa(e, GlobalRef) return (isdefined(e.mod, e.name) && (allow_volatile || isconst(e.mod, e.name))) - elseif isa(e,Symbol) + elseif isa(e, Symbol) return allow_volatile - elseif isa(e,Expr) + elseif isa(e, Expr) e = e::Expr head = e.head if head === :static_parameter || head === :meta || head === :line || @@ -2219,32 +2258,20 @@ function effect_free(e::ANY, sv, allow_volatile::Bool) end ea = e.args if head === :call && !isa(e.args[1], SSAValue) && !isa(e.args[1], Slot) - if is_known_call_p(e, is_pure_builtin, sv) + if is_known_call_p(e, is_pure_builtin, linfo) if !allow_volatile - if is_known_call(e, arrayref, sv) || is_known_call(e, arraylen, sv) + if is_known_call(e, arrayref, linfo) || is_known_call(e, arraylen, linfo) return false - elseif is_known_call(e, getfield, sv) - # arguments must be immutable to ensure e is affect_free - first = true - for a in ea - if first # first "arg" is the function name - first = false - continue - end - if isa(a,Symbol) - return false - end - if isa(a,SSAValue) - typ = widenconst(exprtype(a,sv)) - if !isa(typ,DataType) || typ.mutable - return false - end - end - if !effect_free(a,sv,allow_volatile) + elseif is_known_call(e, getfield, linfo) + et = exprtype(e,linfo) + if !isa(et,Const) && !(isType(et) && isleaftype(et)) + # first argument must be immutable to ensure e is affect_free + a = ea[2] + typ = widenconst(exprtype(a, linfo)) + if !isa(typ, DataType) || typ.mutable || typ.abstract return false end end - return true end end # fall-through @@ -2254,7 +2281,7 @@ function effect_free(e::ANY, sv, allow_volatile::Bool) elseif head === :new if !allow_volatile a = ea[1] - typ = widenconst(exprtype(a,sv)) + typ = widenconst(exprtype(a, linfo)) if !isType(typ) || !isa((typ::Type).parameters[1],DataType) || ((typ::Type).parameters[1]::DataType).mutable return false end @@ -2268,11 +2295,11 @@ function effect_free(e::ANY, sv, allow_volatile::Bool) return false end for a in ea - if !effect_free(a,sv,allow_volatile) + if !effect_free(a, linfo, allow_volatile) return false end end - elseif isa(e,LabelNode) || isa(e,GotoNode) + elseif isa(e, LabelNode) || isa(e, GotoNode) return false end return true @@ -2281,12 +2308,12 @@ end #### post-inference optimizations #### -function inline_as_constant(val::ANY, argexprs, sv) +function inline_as_constant(val::ANY, argexprs, linfo::LambdaInfo) # check if any arguments aren't effect_free and need to be kept around stmts = Any[] for i = 1:length(argexprs) arg = argexprs[i] - if !effect_free(arg, sv, false) + if !effect_free(arg, linfo, false) push!(stmts, arg) end end @@ -2333,7 +2360,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference istopfunction(topmod, f, :typejoin) || istopfunction(topmod, f, :promote_type)) # XXX: compute effect_free for the actual arguments - if length(argexprs) < 2 || effect_free(argexprs[2], sv, true) + if length(argexprs) < 2 || effect_free(argexprs[2], enclosing, true) return (e.typ.parameters[1],()) else return (e.typ.parameters[1], Any[argexprs[2]]) @@ -2341,11 +2368,11 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference end end if istopfunction(topmod, f, :isbits) && length(atypes)==2 && isType(atypes[2]) && - effect_free(argexprs[2],sv,true) && isleaftype(atypes[2].parameters[1]) + effect_free(argexprs[2], enclosing, true) && isleaftype(atypes[2].parameters[1]) return (isbits(atypes[2].parameters[1]),()) end if is(f, Core.kwfunc) && length(argexprs) == 2 && isa(e.typ, Const) - if effect_free(argexprs[2], sv, true) + if effect_free(argexprs[2], enclosing, true) return (e.typ.val, ()) else return (e.typ.val, Any[argexprs[2]]) @@ -2375,7 +2402,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference local ti = atypes[i] if arg_hoisted || isa(ti, Union) aei = ex.args[i] - if !effect_free(aei, sv, false) + if !effect_free(aei, enclosing, false) arg_hoisted = true newvar = newvar!(sv, ti) insert!(stmts, 1, Expr(:(=), newvar, aei)) @@ -2411,7 +2438,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference all = false end end - if all + if UNION_SPLIT_MISMATCH_ERROR && all error_label === nothing && (error_label = genlabel(sv)) push!(stmts, GotoNode(error_label.label)) else @@ -2484,11 +2511,11 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference (isType(e.typ) || isa(e.typ,Const)) if isType(e.typ) if !has_typevars(e.typ.parameters[1]) - return inline_as_constant(e.typ.parameters[1], argexprs, sv) + return inline_as_constant(e.typ.parameters[1], argexprs, enclosing) end else assert(isa(e.typ,Const)) - return inline_as_constant(e.typ.val, argexprs, sv) + return inline_as_constant(e.typ.val, argexprs, enclosing) end end @@ -2503,7 +2530,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference end if linfo !== nothing && linfo.jlcall_api == 2 # in this case function can be inlined to a constant - return inline_as_constant(linfo.constval, argexprs, sv) + return inline_as_constant(linfo.constval, argexprs, enclosing) elseif linfo !== nothing && !linfo.inlineable return invoke_NF() elseif linfo === nothing || linfo.code === nothing @@ -2569,7 +2596,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference for i=na:-1:1 # stmts_free needs to be calculated in reverse-argument order #args_i = args[i] aei = argexprs[i] - aeitype = argtype = widenconst(exprtype(aei,sv)) + aeitype = argtype = widenconst(exprtype(aei, enclosing)) # ok for argument to occur more than once if the actual argument # is a symbol or constant, or is not affected by previous statements @@ -2581,17 +2608,17 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference if occ < 6 occ += occurs_more(b, x->(isa(x,Slot)&&x.id==i), 6) end - # TODO: passing `sv` here is wrong since it refers to the enclosing function - if occ > 0 && affect_free && !effect_free(b, sv, true) #TODO: we could short-circuit this test better by memoizing effect_free(b) in the for loop over i + if occ > 0 && affect_free && !effect_free(b, linfo, true) + #TODO: we might be able to short-circuit this test better by memoizing effect_free(b) in the for loop over i affect_free = false end if occ > 5 && !affect_free break end end - free = effect_free(aei,sv,true) + free = effect_free(aei, enclosing, true) if ((occ==0 && is(aeitype,Bottom)) || (occ > 1 && !inline_worthy(aei, occ*2000)) || - (affect_free && !free) || (!affect_free && !effect_free(aei,sv,false))) + (affect_free && !free) || (!affect_free && !effect_free(aei, enclosing, false))) if occ != 0 vnew = newvar!(sv, aeitype) argexprs[i] = vnew @@ -2793,12 +2820,10 @@ end function mk_tuplecall(args, sv::InferenceState) e = Expr(:call, top_tuple, args...) - e.typ = tuple_tfunc(Tuple{Any[widenconst(exprtype(x,sv)) for x in args]...}) - e + e.typ = tuple_tfunc(Tuple{Any[widenconst(exprtype(x, sv.linfo)) for x in args]...}) + return e end -const corenumtype = Union{Int32,Int64,Float32,Float64} - function inlining_pass!(linfo::LambdaInfo, sv::InferenceState) eargs = linfo.code i = 1 @@ -2819,6 +2844,8 @@ function inlining_pass!(linfo::LambdaInfo, sv::InferenceState) end end +const corenumtype = Union{Int32, Int64, Float32, Float64} + function inlining_pass(e::Expr, sv, linfo) if e.head === :method # avoid running the inlining pass on function definitions @@ -2833,11 +2860,11 @@ function inlining_pass(e::Expr, sv, linfo) # don't inline first (global) arguments of ccall, as this needs to be evaluated # by the interpreter and inlining might put in something it can't handle, # like another ccall (or try to move the variables out into the function) - if is_known_call(e, Core.Intrinsics.ccall, sv) + if is_known_call(e, Core.Intrinsics.ccall, linfo) # 4 is rewritten to 2 below to handle the callee. i0 = 4 isccall = true - elseif is_known_call(e, Core.Intrinsics.llvmcall, sv) + elseif is_known_call(e, Core.Intrinsics.llvmcall, linfo) i0 = 5 isccall = false else @@ -2863,8 +2890,8 @@ function inlining_pass(e::Expr, sv, linfo) end res = inlining_pass(ei, sv, linfo) res1 = res[1] - if has_stmts && !effect_free(res1, sv, false) - restype = exprtype(res1,sv) + if has_stmts && !effect_free(res1, linfo, false) + restype = exprtype(res1, linfo) vnew = newvar!(sv, restype) argloc[i] = vnew unshift!(stmts, Expr(:(=), vnew, res1)) @@ -2877,7 +2904,7 @@ function inlining_pass(e::Expr, sv, linfo) prepend!(stmts,res2) if !has_stmts for stmt in res2 - if !effect_free(stmt, sv, true) + if !effect_free(stmt, linfo, true) has_stmts = true end end @@ -2898,7 +2925,7 @@ function inlining_pass(e::Expr, sv, linfo) end end - ft = exprtype(arg1, sv) + ft = exprtype(arg1, linfo) if isa(ft, Const) f = ft.val else @@ -2908,20 +2935,41 @@ function inlining_pass(e::Expr, sv, linfo) end end - if sv.inlining && isdefined(Main, :Base) && - ((isdefined(Main.Base, :^) && is(f, Main.Base.:^)) || - (isdefined(Main.Base, :.^) && is(f, Main.Base.:.^))) - if length(e.args) == 3 && isa(e.args[3],Union{Int32,Int64}) - a1 = e.args[2] - basenumtype = Union{corenumtype, Main.Base.Complex64, Main.Base.Complex128, Main.Base.Rational} - if isa(a1,basenumtype) || ((isa(a1,Symbol) || isa(a1,Slot) || isa(a1,SSAValue)) && - exprtype(a1,sv) ⊑ basenumtype) - if e.args[3]==2 - e.args = Any[GlobalRef(Main.Base,:*), a1, a1] - f = Main.Base.:*; ft = abstract_eval_constant(f) - elseif e.args[3]==3 - e.args = Any[GlobalRef(Main.Base,:*), a1, a1, a1] - f = Main.Base.:*; ft = abstract_eval_constant(f) + if sv.inlining + if isdefined(Main, :Base) && + ((isdefined(Main.Base, :^) && is(f, Main.Base.:^)) || + (isdefined(Main.Base, :.^) && is(f, Main.Base.:.^))) && + length(e.args) == 3 + + a2 = e.args[3] + if isa(a2, Symbol) || isa(a2, Slot) || isa(a2, SSAValue) + ta2 = exprtype(a2, linfo) + if isa(ta2, Const) + a2 = ta2.val + end + end + + square = (a2 === Int32(2) || a2 === Int64(2)) + triple = (a2 === Int32(3) || a2 === Int64(3)) + if square || triple + a1 = e.args[2] + basenumtype = Union{corenumtype, Main.Base.Complex64, Main.Base.Complex128, Main.Base.Rational} + if isa(a1, basenumtype) || ((isa(a1, Symbol) || isa(a1, Slot) || isa(a1, SSAValue)) && + exprtype(a1, linfo) ⊑ basenumtype) + if square + e.args = Any[GlobalRef(Main.Base,:*), a1, a1] + res = inlining_pass(e, sv, linfo) + else + e.args = Any[GlobalRef(Main.Base,:*), Expr(:call, GlobalRef(Main.Base,:*), a1, a1), a1] + res = inlining_pass(e, sv, linfo) + end + if isa(res, Tuple) + if isa(res[2], Array) && !isempty(res[2]) + append!(stmts, res[2]) + end + res = res[1] + end + return (res, stmts) end end end @@ -2931,7 +2979,7 @@ function inlining_pass(e::Expr, sv, linfo) ata = Vector{Any}(length(e.args)) ata[1] = ft for i = 2:length(e.args) - a = exprtype(e.args[i], sv) + a = exprtype(e.args[i], linfo) (a === Bottom || isvarargtype(a)) && return (e, stmts) ata[i] = a end @@ -2946,7 +2994,7 @@ function inlining_pass(e::Expr, sv, linfo) if !is(res,NF) # iteratively inline apply(f, tuple(...), tuple(...), ...) in order # to simplify long vararg lists as in multi-arg + - if isa(res,Expr) && is_known_call(res, _apply, sv) + if isa(res,Expr) && is_known_call(res, _apply, linfo) e = res::Expr f = _apply; ft = abstract_eval_constant(f) else @@ -2954,18 +3002,19 @@ function inlining_pass(e::Expr, sv, linfo) end end - if is(f,_apply) + if is(f, _apply) na = length(e.args) newargs = Vector{Any}(na-2) for i = 3:na aarg = e.args[i] - t = widenconst(exprtype(aarg,sv)) - if isa(aarg,Expr) && (is_known_call(aarg, tuple, sv) || is_known_call(aarg, svec, sv)) + t = widenconst(exprtype(aarg, linfo)) + if isa(aarg,Expr) && (is_known_call(aarg, tuple, linfo) || is_known_call(aarg, svec, linfo)) # apply(f,tuple(x,y,...)) => f(x,y,...) newargs[i-2] = aarg.args[2:end] elseif isa(aarg, Tuple) newargs[i-2] = Any[ QuoteNode(x) for x in aarg ] - elseif isa(t,DataType) && t.name===Tuple.name && !isvatuple(t) && effect_free(aarg,sv,true) && length(t.parameters) <= MAX_TUPLE_SPLAT + elseif isa(t, DataType) && t.name === Tuple.name && !isvatuple(t) && + effect_free(aarg, linfo, true) && length(t.parameters) <= MAX_TUPLE_SPLAT # apply(f,t::(x,y)) => f(t[1],t[2]) tp = t.parameters newargs[i-2] = Any[ mk_getfield(aarg,j,tp[j]) for j=1:length(tp) ] @@ -2977,7 +3026,7 @@ function inlining_pass(e::Expr, sv, linfo) e.args = [Any[e.args[2]]; newargs...] # now try to inline the simplified call - ft = exprtype(e.args[1], sv) + ft = exprtype(e.args[1], linfo) if isa(ft,Const) f = ft.val else @@ -3000,23 +3049,23 @@ function add_slot!(linfo::LambdaInfo, typ, is_sa, name=compiler_temp_sym) push!(linfo.slotnames, name) push!(linfo.slottypes, typ) push!(linfo.slotflags, Slot_Assigned + is_sa * Slot_AssignedOnce) - SlotNumber(id) + return SlotNumber(id) end -function is_known_call(e::Expr, func, sv) +function is_known_call(e::Expr, func::ANY, linfo::LambdaInfo) if e.head !== :call return false end - f = exprtype(e.args[1], sv) - return isa(f,Const) && f.val === func + f = exprtype(e.args[1], linfo) + return isa(f, Const) && f.val === func end -function is_known_call_p(e::Expr, pred, sv) +function is_known_call_p(e::Expr, pred::ANY, linfo::LambdaInfo) if e.head !== :call return false end - f = exprtype(e.args[1], sv) - return isa(f,Const) && pred(f.val) + f = exprtype(e.args[1], linfo) + return isa(f, Const) && pred(f.val) end function delete_var!(linfo, id, T) @@ -3119,7 +3168,7 @@ function occurs_outside_getfield(linfo::LambdaInfo, e::ANY, sym::ANY, end if isa(e,Expr) e = e::Expr - if is_known_call(e, getfield, sv) && symequal(e.args[2],sym) + if is_known_call(e, getfield, linfo) && symequal(e.args[2],sym) idx = e.args[3] if isa(idx,QuoteNode) && (idx.value in field_names) return false @@ -3175,7 +3224,7 @@ function _getfield_elim_pass!(e::Expr, sv) for i = 1:length(e.args) e.args[i] = _getfield_elim_pass!(e.args[i], sv) end - if is_known_call(e, getfield, sv) && length(e.args)==3 && + if is_known_call(e, getfield, sv.linfo) && length(e.args)==3 && (isa(e.args[3],Int) || isa(e.args[3],QuoteNode)) e1 = e.args[2] j = e.args[3] @@ -3190,7 +3239,7 @@ function _getfield_elim_pass!(e::Expr, sv) ok = true for k = 2:length(e1.args) k == j+1 && continue - if !effect_free(e1.args[k], sv, true) + if !effect_free(e1.args[k], sv.linfo, true) ok = false; break end end @@ -3220,10 +3269,10 @@ _getfield_elim_pass!(e::ANY, sv) = e # getfield(..., 1 <= x <= n) or getfield(..., x in f) on the result function is_allocation(e :: ANY, sv::InferenceState) isa(e, Expr) || return false - if is_known_call(e, tuple, sv) + if is_known_call(e, tuple, sv.linfo) return (length(e.args)-1,()) elseif e.head === :new - typ = widenconst(exprtype(e, sv)) + typ = widenconst(exprtype(e, sv.linfo)) if isleaftype(typ) @assert(isa(typ,DataType)) nf = length(e.args)-1 @@ -3252,7 +3301,7 @@ function gotoifnot_elim_pass!(linfo::LambdaInfo, sv::InferenceState) expr = expr::Expr expr.head === :gotoifnot || continue cond = expr.args[1] - condt = exprtype(cond, sv) + condt = exprtype(cond, linfo) isa(condt, Const) || continue val = (condt::Const).val # Codegen should emit an unreachable if val is not a Bool so @@ -3329,7 +3378,7 @@ function alloc_elim_pass!(linfo::LambdaInfo, sv::InferenceState) isa(tupelt,QuoteNode) || isa(tupelt, SSAValue)) vals[j] = tupelt else - elty = exprtype(tupelt,sv) + elty = exprtype(tupelt, linfo) if is_ssa tmpv = newvar!(sv, elty) else @@ -3384,7 +3433,7 @@ end function replace_getfield!(linfo::LambdaInfo, e::Expr, tupname, vals, field_names, sv) for i = 1:length(e.args) a = e.args[i] - if isa(a,Expr) && is_known_call(a, getfield, sv) && + if isa(a,Expr) && is_known_call(a, getfield, linfo) && symequal(a.args[2],tupname) idx = if isa(a.args[3], Int) a.args[3] @@ -3407,7 +3456,7 @@ function replace_getfield!(linfo::LambdaInfo, e::Expr, tupname, vals, field_name end elseif isa(val,SSAValue) val = val::SSAValue - typ = exprtype(val, sv) + typ = exprtype(val, linfo) if a.typ ⊑ typ && !(typ ⊑ a.typ) sv.linfo.ssavaluetypes[val.id+1] = a.typ end diff --git a/base/int.jl b/base/int.jl index ca3242cc682f5a..6b244499f4b0b6 100644 --- a/base/int.jl +++ b/base/int.jl @@ -182,11 +182,11 @@ trailing_ones(x::Integer) = trailing_zeros(~x) # note: this early during bootstrap, `>=` is not yet available # note: we only define Int shift counts here; the generic case is handled later >>(x::BitInteger, y::Int) = - 0 <= y ? x >> unsigned(y) : x << unsigned(-y) + select_value(0 <= y, x >> unsigned(y), x << unsigned(-y)) <<(x::BitInteger, y::Int) = - 0 <= y ? x << unsigned(y) : x >> unsigned(-y) + select_value(0 <= y, x << unsigned(y), x >> unsigned(-y)) >>>(x::BitInteger, y::Int) = - 0 <= y ? x >>> unsigned(y) : x << unsigned(-y) + select_value(0 <= y, x >>> unsigned(y), x << unsigned(-y)) ## integer conversions ## @@ -305,6 +305,9 @@ promote_rule{T<:BitSigned64}(::Type{UInt64}, ::Type{T}) = UInt64 promote_rule{T<:Union{UInt32, UInt64}}(::Type{T}, ::Type{Int128}) = Int128 promote_rule{T<:BitSigned}(::Type{UInt128}, ::Type{T}) = UInt128 +_default_type(T::Type{Unsigned}) = UInt +_default_type(T::Union{Type{Integer},Type{Signed}}) = Int + ## traits ## typemin(::Type{Int8 }) = Int8(-128) diff --git a/base/io.jl b/base/io.jl index 29aa2023146785..9d65ae5e5e1d41 100644 --- a/base/io.jl +++ b/base/io.jl @@ -23,6 +23,20 @@ function iswritable end function copy end function eof end +""" + write(stream::IO, x) + write(filename::AbstractString, x) + +Write the canonical binary representation of a value to the given I/O stream or file. +Returns the number of bytes written into the stream. + +You can write multiple values with the same `write` call. i.e. the following are equivalent: + + write(stream, x, y...) + write(stream, x) + write(stream, y...) +""" +function write end + read(s::IO, ::Type{UInt8}) = error(typeof(s)," does not support byte I/O") write(s::IO, x::UInt8) = error(typeof(s)," does not support byte I/O") diff --git a/base/irrationals.jl b/base/irrationals.jl index e76f40760c0b94..a5e091f5ca1e36 100644 --- a/base/irrationals.jl +++ b/base/irrationals.jl @@ -10,13 +10,6 @@ promote_rule{s}(::Type{Irrational{s}}, ::Type{Float32}) = Float32 promote_rule{s,t}(::Type{Irrational{s}}, ::Type{Irrational{t}}) = Float64 promote_rule{s,T<:Number}(::Type{Irrational{s}}, ::Type{T}) = promote_type(Float64,T) -promote_op{S<:Irrational,T<:Irrational}(op::Any, ::Type{S}, ::Type{T}) = - promote_op(op, Float64, Float64) -promote_op{S<:Irrational,T<:Number}(op::Any, ::Type{S}, ::Type{T}) = - promote_op(op, Float64, T) -promote_op{S<:Irrational,T<:Number}(op::Any, ::Type{T}, ::Type{S}) = - promote_op(op, T, Float64) - convert(::Type{AbstractFloat}, x::Irrational) = Float64(x) convert(::Type{Float16}, x::Irrational) = Float16(Float32(x)) convert{T<:Real}(::Type{Complex{T}}, x::Irrational) = convert(Complex{T}, convert(T,x)) diff --git a/base/iterator.jl b/base/iterator.jl index 3d74fd5da57db8..715ff753bb0fa3 100644 --- a/base/iterator.jl +++ b/base/iterator.jl @@ -21,10 +21,12 @@ end """ enumerate(iter) -An iterator that yields `(i, x)` where `i` is an index starting at 1, and -`x` is the `i`th value from the given iterator. It's useful when you need -not only the values `x` over which you are iterating, but also the index `i` -of the iterations. +An iterator that yields `(i, x)` where `i` is a counter starting at 1, +and `x` is the `i`th value from the given iterator. It's useful when +you need not only the values `x` over which you are iterating, but +also the number of iterations so far. Note that `i` may not be valid +for indexing `iter`; it's also possible that `x != iter[i]`, if `iter` +has indices that do not start at 1. ```jldoctest julia> a = ["a", "b", "c"]; @@ -61,6 +63,7 @@ zip_iteratorsize(a, b) = and_iteratorsize(a,b) # as `and_iteratorsize` but inher zip_iteratorsize(::HasLength, ::IsInfinite) = HasLength() zip_iteratorsize(::HasShape, ::IsInfinite) = HasLength() zip_iteratorsize(a::IsInfinite, b) = zip_iteratorsize(b,a) +zip_iteratorsize(a::IsInfinite, b::IsInfinite) = IsInfinite() immutable Zip1{I} <: AbstractZipIterator diff --git a/base/libgit2/callbacks.jl b/base/libgit2/callbacks.jl index fd2580da27ee75..13f2f88e168de2 100644 --- a/base/libgit2/callbacks.jl +++ b/base/libgit2/callbacks.jl @@ -160,7 +160,7 @@ function authenticate_userpass(creds::UserPasswordCredentials, libgit2credptr::P urlusername : username) userpass = prompt("Password for '$schema$username@$host'", password=true) end - (creds.user != username) || (creds.pass != userpass) && reset!(creds) + ((creds.user != username) || (creds.pass != userpass)) && reset!(creds) creds.user = username # save credentials creds.pass = userpass # save credentials @@ -209,12 +209,10 @@ function credentials_callback(libgit2credptr::Ptr{Ptr{Void}}, url_ptr::Cstring, url = unsafe_string(url_ptr) # parse url for schema and host - urlparts = match(urlmatcher, url) - schema = urlparts.captures[1] - urlusername = urlparts.captures[4] - urlusername = urlusername === nothing ? "" : String(urlusername) - host = urlparts.captures[5] - schema = schema === nothing ? "" : schema*"://" + urlparts = match(URL_REGEX, url) + schema = urlparts[:scheme] === nothing ? "" : urlparts[:scheme] * "://" + urlusername = urlparts[:user] === nothing ? "" : urlparts[:user] + host = urlparts[:host] # get credentials object from payload pointer @assert payload_ptr != C_NULL diff --git a/base/libgit2/utils.jl b/base/libgit2/utils.jl index ba2149dbda5762..ab8928687e3c76 100644 --- a/base/libgit2/utils.jl +++ b/base/libgit2/utils.jl @@ -1,6 +1,12 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license -const urlmatcher = r"^(http[s]?|git|ssh)?(:\/\/)?((\w+)@)?([A-Za-z0-9\-\.]+)(:[0-9]+)?(.*)$" +const URL_REGEX = r""" +^(?:(?https?|git|ssh)\:\/\/)? +(?:(?.*?)(?:\:(?.*?))?@)? +(?[A-Za-z0-9\-\.]+) +(?:\:(?\d+)?)? +(?.*?)$ +"""x function version() major = Ref{Cint}(0) diff --git a/base/linalg/arpack.jl b/base/linalg/arpack.jl index 9b27aa3bc019b7..26a0c55e1dbb60 100644 --- a/base/linalg/arpack.jl +++ b/base/linalg/arpack.jl @@ -114,15 +114,15 @@ function eupd_wrapper(T, n::Integer, sym::Bool, cmplx::Bool, bmat::String, select = Array{BlasInt}(ncv) info = zeros(BlasInt, 1) - dmap = x->abs(x) + dmap = abs if iparam[7] == 3 # shift-and-invert dmap = x->abs(1./(x-sigma)) elseif which == "LR" || which == "LA" || which == "BE" - dmap = x->real(x) + dmap = real elseif which == "SR" || which == "SA" dmap = x->-real(x) elseif which == "LI" - dmap = x->imag(x) + dmap = imag elseif which == "SI" dmap = x->-imag(x) end diff --git a/base/linalg/generic.jl b/base/linalg/generic.jl index 3451999961ba7c..261bed72b8c392 100644 --- a/base/linalg/generic.jl +++ b/base/linalg/generic.jl @@ -19,8 +19,8 @@ function generic_scale!(s::Number, X::AbstractArray) end function generic_scale!(C::AbstractArray, X::AbstractArray, s::Number) - if length(C) != length(X) - throw(DimensionMismatch("first array has length $(length(C)) which does not match the length of the second, $(length(X)).")) + if _length(C) != _length(X) + throw(DimensionMismatch("first array has length $(_length(C)) which does not match the length of the second, $(_length(X)).")) end for (IC, IX) in zip(eachindex(C), eachindex(X)) @inbounds C[IC] = X[IX]*s @@ -29,9 +29,9 @@ function generic_scale!(C::AbstractArray, X::AbstractArray, s::Number) end function generic_scale!(C::AbstractArray, s::Number, X::AbstractArray) - if length(C) != length(X) - throw(DimensionMismatch("first array has length $(length(C)) which does not -match the length of the second, $(length(X)).")) + if _length(C) != _length(X) + throw(DimensionMismatch("first array has length $(_length(C)) which does not +match the length of the second, $(_length(X)).")) end for (IC, IX) in zip(eachindex(C), eachindex(X)) @inbounds C[IC] = s*X[IX] @@ -126,7 +126,7 @@ function generic_vecnorm2(x) s = start(x) (v, s) = next(x, s) T = typeof(maxabs) - if isfinite(length(x)*maxabs*maxabs) && maxabs*maxabs != 0 # Scaling not necessary + if isfinite(_length(x)*maxabs*maxabs) && maxabs*maxabs != 0 # Scaling not necessary sum::promote_type(Float64, T) = norm_sqr(v) while !done(x, s) (v, s) = next(x, s) @@ -156,7 +156,7 @@ function generic_vecnormp(x, p) T = typeof(float(norm(v))) end spp::promote_type(Float64, T) = p - if -1 <= p <= 1 || (isfinite(length(x)*maxabs^spp) && maxabs^spp != 0) # scaling not necessary + if -1 <= p <= 1 || (isfinite(_length(x)*maxabs^spp) && maxabs^spp != 0) # scaling not necessary sum::promote_type(Float64, T) = norm(v)^spp while !done(x, s) (v, s) = next(x, s) @@ -253,14 +253,14 @@ end @inline norm(x::Number, p::Real=2) = vecnorm(x, p) function vecdot(x::AbstractArray, y::AbstractArray) - lx = length(x) - if lx != length(y) - throw(DimensionMismatch("first array has length $(lx) which does not match the length of the second, $(length(y)).")) + lx = _length(x) + if lx != _length(y) + throw(DimensionMismatch("first array has length $(lx) which does not match the length of the second, $(_length(y)).")) end if lx == 0 return dot(zero(eltype(x)), zero(eltype(y))) end - s = zero(dot(x[1], y[1])) + s = zero(dot(first(x), first(y))) for (Ix, Iy) in zip(eachindex(x), eachindex(y)) @inbounds s += dot(x[Ix], y[Iy]) end @@ -378,11 +378,11 @@ condskeel(A::AbstractMatrix, x::AbstractVector, p::Real=Inf) = norm(abs(inv(A))* condskeel{T<:Integer}(A::AbstractMatrix{T}, x::AbstractVector, p::Real=Inf) = norm(abs(inv(float(A)))*abs(A)*abs(x), p) function issymmetric(A::AbstractMatrix) - m, n = size(A) - if m != n + indsm, indsn = indices(A) + if indsm != indsn return false end - for i = 1:(n-1), j = (i+1):n + for i = first(indsn):last(indsn)-1, j = (i+1):last(indsn) if A[i,j] != transpose(A[j,i]) return false end @@ -393,11 +393,11 @@ end issymmetric(x::Number) = true function ishermitian(A::AbstractMatrix) - m, n = size(A) - if m != n + indsm, indsn = indices(A) + if indsm != indsn return false end - for i = 1:n, j = i:n + for i = indsn, j = i:last(indsn) if A[i,j] != ctranspose(A[j,i]) return false end @@ -497,26 +497,26 @@ end # BLAS-like in-place y = x*α+y function (see also the version in blas.jl # for BlasFloat Arrays) function axpy!(α, x::AbstractArray, y::AbstractArray) - n = length(x) - if n != length(y) - throw(DimensionMismatch("x has length $n, but y has length $(length(y))")) + n = _length(x) + if n != _length(y) + throw(DimensionMismatch("x has length $n, but y has length $(_length(y))")) end - for i = 1:n - @inbounds y[i] += x[i]*α + for (IY, IX) in zip(eachindex(y), eachindex(x)) + @inbounds y[IY] += x[IX]*α end y end function axpy!{Ti<:Integer,Tj<:Integer}(α, x::AbstractArray, rx::AbstractArray{Ti}, y::AbstractArray, ry::AbstractArray{Tj}) - if length(rx) != length(ry) - throw(DimensionMismatch("rx has length $(length(rx)), but ry has length $(length(ry))")) - elseif minimum(rx) < 1 || maximum(rx) > length(x) + if _length(rx) != _length(ry) + throw(DimensionMismatch("rx has length $(_length(rx)), but ry has length $(_length(ry))")) + elseif !checkindex(Bool, linearindices(x), rx) throw(BoundsError(x, rx)) - elseif minimum(ry) < 1 || maximum(ry) > length(y) + elseif !checkindex(Bool, linearindices(y), ry) throw(BoundsError(y, ry)) end - for i = 1:length(rx) - @inbounds y[ry[i]] += x[rx[i]]*α + for (IY, IX) in zip(eachindex(ry), eachindex(rx)) + @inbounds y[ry[IY]] += x[rx[IX]]*α end y end diff --git a/base/linalg/linalg.jl b/base/linalg/linalg.jl index dc36d649fae31f..556020776082aa 100644 --- a/base/linalg/linalg.jl +++ b/base/linalg/linalg.jl @@ -10,7 +10,9 @@ import Base: USE_BLAS64, abs, big, ceil, conj, convert, copy, copy!, copy_transp imag, inv, isapprox, kron, ndims, parent, power_by_squaring, print_matrix, promote_rule, real, round, setindex!, show, similar, size, transpose, transpose!, trunc -using Base: promote_op +using Base: promote_op, _length +# We use `_length` because of non-1 indices; releases after julia 0.5 +# can go back to `length`. `_length(A)` is equivalent to `length(linearindices(A))`. export # Modules diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 6c9117a3cd06e5..aa713321a42bb5 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -76,11 +76,11 @@ At_mul_B{T<:BlasComplex}(x::StridedVector{T}, y::StridedVector{T}) = [BLAS.dotu( # Matrix-vector multiplication function (*){T<:BlasFloat,S}(A::StridedMatrix{T}, x::StridedVector{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) A_mul_B!(similar(x, TS, size(A,1)), A, convert(AbstractVector{TS}, x)) end function (*){T,S}(A::AbstractMatrix{T}, x::AbstractVector{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) A_mul_B!(similar(x,TS,size(A,1)),A,x) end (*)(A::AbstractVector, B::AbstractMatrix) = reshape(A,length(A),1)*B @@ -99,22 +99,22 @@ end A_mul_B!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = generic_matvecmul!(y, 'N', A, x) function At_mul_B{T<:BlasFloat,S}(A::StridedMatrix{T}, x::StridedVector{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) At_mul_B!(similar(x,TS,size(A,2)), A, convert(AbstractVector{TS}, x)) end function At_mul_B{T,S}(A::AbstractMatrix{T}, x::AbstractVector{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) At_mul_B!(similar(x,TS,size(A,2)), A, x) end At_mul_B!{T<:BlasFloat}(y::StridedVector{T}, A::StridedVecOrMat{T}, x::StridedVector{T}) = gemv!(y, 'T', A, x) At_mul_B!(y::AbstractVector, A::AbstractVecOrMat, x::AbstractVector) = generic_matvecmul!(y, 'T', A, x) function Ac_mul_B{T<:BlasFloat,S}(A::StridedMatrix{T}, x::StridedVector{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) Ac_mul_B!(similar(x,TS,size(A,2)),A,convert(AbstractVector{TS},x)) end function Ac_mul_B{T,S}(A::AbstractMatrix{T}, x::AbstractVector{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) Ac_mul_B!(similar(x,TS,size(A,2)), A, x) end @@ -142,14 +142,14 @@ end A_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'N', A, B) function At_mul_B{T,S}(A::AbstractMatrix{T}, B::AbstractMatrix{S}) - TS = promote_op(*,arithtype(T), arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) At_mul_B!(similar(B, TS, (size(A,2), size(B,2))), A, B) end At_mul_B!{T<:BlasFloat}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = is(A,B) ? syrk_wrapper!(C, 'T', A) : gemm_wrapper!(C, 'T', 'N', A, B) At_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'T', 'N', A, B) function A_mul_Bt{T,S}(A::AbstractMatrix{T}, B::AbstractMatrix{S}) - TS = promote_op(*,arithtype(T), arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) A_mul_Bt!(similar(B, TS, (size(A,1), size(B,1))), A, B) end A_mul_Bt!{T<:BlasFloat}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = is(A,B) ? syrk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'T', A, B) @@ -166,7 +166,7 @@ end A_mul_Bt!(C::AbstractVecOrMat, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'T', A, B) function At_mul_Bt{T,S}(A::AbstractMatrix{T}, B::AbstractVecOrMat{S}) - TS = promote_op(*,arithtype(T), arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) At_mul_Bt!(similar(B, TS, (size(A,2), size(B,1))), A, B) end At_mul_Bt!{T<:BlasFloat}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = gemm_wrapper!(C, 'T', 'T', A, B) @@ -175,7 +175,7 @@ At_mul_Bt!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generi Ac_mul_B{T<:BlasReal}(A::StridedMatrix{T}, B::StridedMatrix{T}) = At_mul_B(A, B) Ac_mul_B!{T<:BlasReal}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = At_mul_B!(C, A, B) function Ac_mul_B{T,S}(A::AbstractMatrix{T}, B::AbstractMatrix{S}) - TS = promote_op(*,arithtype(T), arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) Ac_mul_B!(similar(B, TS, (size(A,2), size(B,2))), A, B) end Ac_mul_B!{T<:BlasComplex}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = is(A,B) ? herk_wrapper!(C,'C',A) : gemm_wrapper!(C,'C', 'N', A, B) @@ -184,13 +184,14 @@ Ac_mul_B!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic A_mul_Bc{T<:BlasFloat,S<:BlasReal}(A::StridedMatrix{T}, B::StridedMatrix{S}) = A_mul_Bt(A, B) A_mul_Bc!{T<:BlasFloat,S<:BlasReal}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{S}) = A_mul_Bt!(C, A, B) function A_mul_Bc{T,S}(A::AbstractMatrix{T}, B::AbstractMatrix{S}) - TS = promote_op(*,arithtype(T),arithtype(S)) + TS = promote_op(*, arithtype(T), arithtype(S)) A_mul_Bc!(similar(B,TS,(size(A,1),size(B,1))),A,B) end A_mul_Bc!{T<:BlasComplex}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = is(A,B) ? herk_wrapper!(C, 'N', A) : gemm_wrapper!(C, 'N', 'C', A, B) A_mul_Bc!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'N', 'C', A, B) -Ac_mul_Bc{T,S}(A::AbstractMatrix{T}, B::AbstractMatrix{S}) = Ac_mul_Bc!(similar(B, promote_op(*,arithtype(T), arithtype(S)), (size(A,2), size(B,1))), A, B) +Ac_mul_Bc{T,S}(A::AbstractMatrix{T}, B::AbstractMatrix{S}) = + Ac_mul_Bc!(similar(B, promote_op(*, arithtype(T), arithtype(S)), (size(A,2), size(B,1))), A, B) Ac_mul_Bc!{T<:BlasFloat}(C::StridedMatrix{T}, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) = gemm_wrapper!(C, 'C', 'C', A, B) Ac_mul_Bc!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'C', 'C', A, B) Ac_mul_Bt!(C::AbstractMatrix, A::AbstractVecOrMat, B::AbstractVecOrMat) = generic_matmatmul!(C, 'C', 'T', A, B) @@ -423,7 +424,7 @@ end function generic_matmatmul{T,S}(tA, tB, A::AbstractVecOrMat{T}, B::AbstractMatrix{S}) mA, nA = lapack_size(tA, A) mB, nB = lapack_size(tB, B) - C = similar(B, promote_op(*,arithtype(T),arithtype(S)), mA, nB) + C = similar(B, promote_op(*, arithtype(T), arithtype(S)), mA, nB) generic_matmatmul!(C, tA, tB, A, B) end @@ -617,7 +618,7 @@ end # multiply 2x2 matrices function matmul2x2{T,S}(tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S}) - matmul2x2!(similar(B, promote_op(*,T,S), 2, 2), tA, tB, A, B) + matmul2x2!(similar(B, promote_op(*, T, S), 2, 2), tA, tB, A, B) end function matmul2x2!{T,S,R}(C::AbstractMatrix{R}, tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S}) @@ -646,7 +647,7 @@ end # Multiply 3x3 matrices function matmul3x3{T,S}(tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S}) - matmul3x3!(similar(B, promote_op(*,T,S), 3, 3), tA, tB, A, B) + matmul3x3!(similar(B, promote_op(*, T, S), 3, 3), tA, tB, A, B) end function matmul3x3!{T,S,R}(C::AbstractMatrix{R}, tA, tB, A::AbstractMatrix{T}, B::AbstractMatrix{S}) diff --git a/base/linalg/uniformscaling.jl b/base/linalg/uniformscaling.jl index 227e41ac5dc0c0..91098a08da173b 100644 --- a/base/linalg/uniformscaling.jl +++ b/base/linalg/uniformscaling.jl @@ -29,6 +29,11 @@ one{T}(J::UniformScaling{T}) = one(UniformScaling{T}) zero{T}(::Type{UniformScaling{T}}) = UniformScaling(zero(T)) zero{T}(J::UniformScaling{T}) = zero(UniformScaling{T}) +istriu(::UniformScaling) = true +istril(::UniformScaling) = true +issymmetric(::UniformScaling) = true +ishermitian(J::UniformScaling) = isreal(J.λ) + (+)(J1::UniformScaling, J2::UniformScaling) = UniformScaling(J1.λ+J2.λ) (+){T}(B::BitArray{2},J::UniformScaling{T}) = Array(B) + J (+)(J::UniformScaling, B::BitArray{2}) = J + Array(B) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index a6e22e481601b9..6c1cb66584808c 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -79,7 +79,7 @@ end CartesianRange{N}(index::CartesianIndex{N}) = CartesianRange(one(index), index) CartesianRange(::Tuple{}) = CartesianRange{CartesianIndex{0}}(CartesianIndex{0}(()),CartesianIndex{0}(())) CartesianRange{N}(sz::NTuple{N,Int}) = CartesianRange(CartesianIndex(sz)) -CartesianRange{N}(rngs::NTuple{N,Union{Integer,AbstractUnitRange}}) = CartesianRange(CartesianIndex(map(r->first(r), rngs)), CartesianIndex(map(r->last(r), rngs))) +CartesianRange{N}(rngs::NTuple{N,Union{Integer,AbstractUnitRange}}) = CartesianRange(CartesianIndex(map(first, rngs)), CartesianIndex(map(last, rngs))) ndims(R::CartesianRange) = length(R.start) ndims{I<:CartesianIndex}(::Type{CartesianRange{I}}) = length(I) @@ -318,7 +318,7 @@ function _unsafe_getindex(::LinearFast, src::AbstractArray, I::AbstractArray{Boo D = eachindex(dest) Ds = start(D) - s = 0 + s = first(linearindices(src))-1 for i in eachindex(I) s += 1 @inbounds if I[i] diff --git a/base/number.jl b/base/number.jl index d2d3270f1cfc45..42ffb708736ee2 100644 --- a/base/number.jl +++ b/base/number.jl @@ -63,16 +63,4 @@ zero{T<:Number}(::Type{T}) = convert(T,0) one(x::Number) = oftype(x,1) one{T<:Number}(::Type{T}) = convert(T,1) -promote_op{R,S<:Number}(::Type{R}, ::Type{S}) = (@_pure_meta; R) # to fix ambiguities -function promote_op{T<:Number}(op, ::Type{T}) - S = typeof(op(one(T))) - # preserve the most general (abstract) type when possible - return isleaftype(T) ? S : typejoin(S, T) -end -function promote_op{R<:Number,S<:Number}(op, ::Type{R}, ::Type{S}) - T = typeof(op(one(R), one(S))) - # preserve the most general (abstract) type when possible - return isleaftype(R) && isleaftype(S) ? T : typejoin(R, S, T) -end - factorial(x::Number) = gamma(x + 1) # fallback for x not Integer diff --git a/base/operators.jl b/base/operators.jl index 31faf73b1d77fe..be5ccf5c5354f3 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -230,7 +230,7 @@ end Unsigned right bit shift operator, `x >>> n`. For `n >= 0`, the result is `x` shifted right by `n` bits, where `n >= 0`, filling with `0`s. For `n < 0`, this -is equivalent to `x [<<](:func:`<<`) -n`]. +is equivalent to `x << -n`. For `Unsigned` integer types, this is equivalent to [`>>`](:func:`>>`). For `Signed` integer types, this is equivalent to `signed(unsigned(x) >> n)`. diff --git a/base/pkg/resolve/fieldvalue.jl b/base/pkg/resolve/fieldvalue.jl index a3666388d35a7d..fe175ce356b0bc 100644 --- a/base/pkg/resolve/fieldvalue.jl +++ b/base/pkg/resolve/fieldvalue.jl @@ -42,7 +42,6 @@ Base.typemin(::Type{FieldValue}) = (x=typemin(Int); y=typemin(VersionWeight); Fi Base.:-(a::FieldValue, b::FieldValue) = FieldValue(a.l0-b.l0, a.l1-b.l1, a.l2-b.l2, a.l3-b.l3, a.l4-b.l4) Base.:+(a::FieldValue, b::FieldValue) = FieldValue(a.l0+b.l0, a.l1+b.l1, a.l2+b.l2, a.l3+b.l3, a.l4+b.l4) -Base.promote_op(::Union{typeof(+), typeof(-)}, ::Type{FieldValue}, ::Type{FieldValue}) = FieldValue function Base.isless(a::FieldValue, b::FieldValue) a.l0 < b.l0 && return true diff --git a/base/pkg/types.jl b/base/pkg/types.jl index 152b3e5af0c240..9d5556a370b663 100644 --- a/base/pkg/types.jl +++ b/base/pkg/types.jl @@ -37,7 +37,7 @@ end VersionSet(versions::VersionNumber...) = VersionSet(VersionNumber[versions...]) show(io::IO, s::VersionSet) = join(io, s.intervals, " ∪ ") -isempty(s::VersionSet) = all(i->isempty(i), s.intervals) +isempty(s::VersionSet) = all(isempty, s.intervals) in(v::VersionNumber, s::VersionSet) = any(i->in(v,i), s.intervals) function intersect(A::VersionSet, B::VersionSet) ivals = vec([ intersect(a,b) for a in A.intervals, b in B.intervals ]) diff --git a/base/promotion.jl b/base/promotion.jl index 778de13c004c9f..4952126dc8cd80 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -217,13 +217,37 @@ max(x::Real, y::Real) = max(promote(x,y)...) min(x::Real, y::Real) = min(promote(x,y)...) minmax(x::Real, y::Real) = minmax(promote(x, y)...) -# "Promotion" that takes a function into account. You can override this -# as needed. For example, if you need to provide a custom result type -# for the multiplication of two types, -# promote_op{R<:MyType,S<:MyType}(::typeof(*), ::Type{R}, ::Type{S}) = MyType{multype(R,S)} -promote_op(::Any) = (@_pure_meta; Bottom) -promote_op(::Any, ::Any, ::Any...) = (@_pure_meta; Any) -promote_op{T}(::Type{T}, ::Any) = (@_pure_meta; T) +# "Promotion" that takes a function into account. These are meant to be +# used mainly by broadcast methods, so it is advised against overriding them +if isdefined(Core, :Inference) + function _promote_op(op, T::ANY) + G = Tuple{Generator{Tuple{T},typeof(op)}} + return Core.Inference.return_type(first, G) + end + function _promote_op(op, R::ANY, S::ANY) + F = typeof(a -> op(a...)) + G = Tuple{Generator{Zip2{Tuple{R},Tuple{S}},F}} + return Core.Inference.return_type(first, G) + end +else + _promote_op(::ANY...) = (@_pure_meta; Any) +end +_default_type(T::Type) = (@_pure_meta; T) + +promote_op(::Any...) = (@_pure_meta; Any) +promote_op(T::Type, ::Any) = (@_pure_meta; T) +promote_op(T::Type, ::Type) = (@_pure_meta; T) # To handle ambiguities +# Promotion that tries to preserve non-concrete types +function promote_op{S}(f, ::Type{S}) + T = _promote_op(f, _default_type(S)) + isleaftype(S) && return isleaftype(T) ? T : Any + return typejoin(S, T) +end +function promote_op{R,S}(f, ::Type{R}, ::Type{S}) + T = _promote_op(f, _default_type(R), _default_type(S)) + isleaftype(R) && isleaftype(S) && return isleaftype(T) ? T : Any + return typejoin(R, S, T) +end ## catch-alls to prevent infinite recursion when definitions are missing ## diff --git a/base/random.jl b/base/random.jl index c6cf2bfdeb2c07..03e9b94c5d4f3f 100644 --- a/base/random.jl +++ b/base/random.jl @@ -15,7 +15,7 @@ export srand, randsubseq,randsubseq!, shuffle,shuffle!, randperm, randcycle, - AbstractRNG, RNG, MersenneTwister, RandomDevice, + AbstractRNG, MersenneTwister, RandomDevice, GLOBAL_RNG, randjump diff --git a/base/range.jl b/base/range.jl index caca0808025533..00b2b217c1f6a8 100644 --- a/base/range.jl +++ b/base/range.jl @@ -499,10 +499,11 @@ end getindex(r::Range, ::Colon) = copy(r) -function getindex{T<:Integer}(r::UnitRange, s::AbstractUnitRange{T}) +function getindex{T<:Integer}(r::AbstractUnitRange, s::AbstractUnitRange{T}) @_inline_meta @boundscheck checkbounds(r, s) - st = oftype(r.start, r.start + first(s)-1) + f = first(r) + st = oftype(f, f + first(s)-1) range(st, length(s)) end diff --git a/base/rational.jl b/base/rational.jl index 067b8b570deaca..6ff823701088d8 100644 --- a/base/rational.jl +++ b/base/rational.jl @@ -375,8 +375,8 @@ function ^(x::Rational, n::Integer) end ^(x::Number, y::Rational) = x^(y.num/y.den) -^{T<:AbstractFloat}(x::T, y::Rational) = x^(convert(T, y.num / y.den)) -^{T<:AbstractFloat}(x::Complex{T}, y::Rational) = x^(convert(T, y.num / y.den)) +^{T<:AbstractFloat}(x::T, y::Rational) = x^convert(T,y) +^{T<:AbstractFloat}(x::Complex{T}, y::Rational) = x^convert(T,y) ^{T<:Rational}(z::Complex{T}, n::Bool) = n ? z : one(z) # to resolve ambiguity function ^{T<:Rational}(z::Complex{T}, n::Integer) diff --git a/base/replutil.jl b/base/replutil.jl index 3c26308f06b641..fbd14f79b46080 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -533,7 +533,8 @@ function show_method_candidates(io::IO, ex::MethodError, kwargs::Vector=Any[]) end if !isempty(unexpected) Base.with_output_color(:red, buf) do buf - print(buf, " got an unsupported keyword argument \"", join(unexpected, "\", \""), "\"") + plur = length(unexpected) > 1 ? "s" : "" + print(buf, " got unsupported keyword argument$plur \"", join(unexpected, "\", \""), "\"") end end end diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index 0f82bcca73d641..fa00f37b0001b7 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -36,8 +36,9 @@ start(R::ReshapedArrayIterator) = start(R.iter) end length(R::ReshapedArrayIterator) = length(R.iter) -reshape(parent::AbstractArray, shp::Tuple) = _reshape(parent, to_shape(shp)) reshape(parent::AbstractArray, dims::IntOrInd...) = reshape(parent, dims) +reshape(parent::AbstractArray, shp::NeedsShaping) = reshape(parent, to_shape(shp)) +reshape(parent::AbstractArray, dims::Dims) = _reshape(parent, dims) reshape{T,N}(parent::AbstractArray{T,N}, ndims::Type{Val{N}}) = parent function reshape{T,AN,N}(parent::AbstractArray{T,AN}, ndims::Type{Val{N}}) @@ -47,24 +48,34 @@ end # dimensionality N, either filling with OneTo(1) or collapsing the # product of trailing dims into the last element @pure rdims{N}(out::NTuple{N}, inds::Tuple{}, ::Type{Val{N}}) = out -@pure rdims{N}(out::NTuple{N}, inds::Tuple{Any, Vararg{Any}}, ::Type{Val{N}}) = (front(out)..., length(last(out)) * prod(map(length, inds))) +@pure function rdims{N}(out::NTuple{N}, inds::Tuple{Any, Vararg{Any}}, ::Type{Val{N}}) + l = length(last(out)) * prod(map(length, inds)) + (front(out)..., OneTo(l)) +end @pure rdims{N}(out::Tuple, inds::Tuple{}, ::Type{Val{N}}) = rdims((out..., OneTo(1)), (), Val{N}) @pure rdims{N}(out::Tuple, inds::Tuple{Any, Vararg{Any}}, ::Type{Val{N}}) = rdims((out..., first(inds)), tail(inds), Val{N}) -function _reshape(parent::AbstractArray, dims::Dims) - n = _length(parent) - prod(dims) == n || throw(DimensionMismatch("parent has $n elements, which is incompatible with size $dims")) - __reshape((parent, linearindexing(parent)), dims) -end -_reshape(R::ReshapedArray, dims::Dims) = _reshape(R.parent, dims) +# _reshape on Array returns an Array +_reshape(parent::Vector, dims::Dims{1}) = parent +_reshape(parent::Array, dims::Dims{1}) = reshape(parent, dims) +_reshape(parent::Array, dims::Dims) = reshape(parent, dims) # When reshaping Vector->Vector, don't wrap with a ReshapedArray -_reshape{T}(v::ReshapedArray{T,1}, dims::Tuple{Int}) = _reshape(v.parent, dims) -function _reshape(v::AbstractVector, dims::Tuple{Int}) +function _reshape(v::AbstractVector, dims::Dims{1}) len = dims[1] len == length(v) || throw(DimensionMismatch("parent has $(length(v)) elements, which is incompatible with length $len")) v end +# General reshape +function _reshape(parent::AbstractArray, dims::Dims) + n = _length(parent) + prod(dims) == n || throw(DimensionMismatch("parent has $n elements, which is incompatible with size $dims")) + __reshape((parent, linearindexing(parent)), dims) +end + +# Reshaping a ReshapedArray +_reshape{T}(v::ReshapedArray{T,1}, dims::Dims{1}) = _reshape(v.parent, dims) +_reshape(R::ReshapedArray, dims::Dims) = _reshape(R.parent, dims) function __reshape(p::Tuple{AbstractArray,LinearSlow}, dims::Dims) parent = p[1] diff --git a/base/rounding.jl b/base/rounding.jl index 43fe9565440e2a..cbb740af82889b 100644 --- a/base/rounding.jl +++ b/base/rounding.jl @@ -100,12 +100,18 @@ end setrounding(T, mode) Set the rounding mode of floating point type `T`, controlling the rounding of basic -arithmetic functions ([`+`](:func:`+`), [`-`](:func:`-`), [`*`](:func:`*`), [`/`](:func:`/`) -and [`sqrt`](:func:`sqrt`)) and type conversion. +arithmetic functions ([`+`](:func:`+`), [`-`](:func:`-`), [`*`](:func:`*`), +[`/`](:func:`/`) and [`sqrt`](:func:`sqrt`)) and type conversion. Other numerical +functions may give incorrect or invalid values when using rounding modes other than the +default `RoundNearest`. Note that this may affect other types, for instance changing the rounding mode of `Float64` will change the rounding mode of `Float32`. See [`RoundingMode`](:obj:`RoundingMode`) for available modes. + +!!! warning + + This feature is still experimental, and may give unexpected or incorrect values. """ setrounding(T::Type, mode) @@ -138,6 +144,28 @@ equivalent to: setrounding(T, old) See [`RoundingMode`](:obj:`RoundingMode`) for available rounding modes. + +!!! warning + + This feature is still experimental, and may give unexpected or incorrect values. A + known problem is the interaction with compiler optimisations, e.g. + + julia> setrounding(Float64,RoundDown) do + 1.1 + 0.1 + end + 1.2000000000000002 + + Here the compiler is *constant folding*, that is evaluating a known constant + expression at compile time, however the rounding mode is only changed at runtime, so + this is not reflected in the function result. This can be avoided by moving constants + outside the expression, e.g. + + julia> x = 1.1; y = 0.1; + + julia> setrounding(Float64,RoundDown) do + x + y + end + 1.2 """ function setrounding{T}(f::Function, ::Type{T}, rounding::RoundingMode) old_rounding_raw = rounding_raw(T) diff --git a/base/sort.jl b/base/sort.jl index d388e55f6647cd..91e752202c57bb 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -184,6 +184,7 @@ for s in [:searchsortedfirst, :searchsortedlast, :searchsorted] $s(v::AbstractVector, x; lt=isless, by=identity, rev::Bool=false, order::Ordering=Forward) = $s(v,x,ord(lt,by,rev,order)) + $s(v::AbstractVector, x) = $s(v, x, Forward) end end diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index db2a603232e33e..26076fcce833c3 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -2,7 +2,7 @@ ### Common definitions -import Base: scalarmax, scalarmin, sort +import Base: scalarmax, scalarmin, sort, find, findnz ### The SparseVector @@ -426,8 +426,8 @@ function Base.getindex{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, i::Integer, J::Abstract @inbounds for j = 1:nJ col = J[j] rowI = i - ptrA = colptrA[col] - stopA = colptrA[col+1]-1 + ptrA = Int(colptrA[col]) + stopA = Int(colptrA[col+1]-1) if ptrA <= stopA if rowvalA[ptrA] <= rowI ptrA = searchsortedfirst(rowvalA, rowI, ptrA, stopA, Base.Order.Forward) @@ -560,6 +560,55 @@ function getindex{Tv}(A::SparseMatrixCSC{Tv}, I::AbstractVector) SparseVector(n, rowvalB, nzvalB) end +function find{Tv,Ti}(x::SparseVector{Tv,Ti}) + numnz = nnz(x) + I = Array(Ti, numnz) + + nzind = x.nzind + nzval = x.nzval + + count = 1 + @inbounds for i = 1 : numnz + if nzval[i] != 0 + I[count] = nzind[i] + count += 1 + end + end + + count -= 1 + if numnz != count + deleteat!(I, (count+1):numnz) + end + + return I +end + +function findnz{Tv,Ti}(x::SparseVector{Tv,Ti}) + numnz = nnz(x) + + I = Array(Ti, numnz) + V = Array(Tv, numnz) + + nzind = x.nzind + nzval = x.nzval + + count = 1 + @inbounds for i = 1 : numnz + if nzval[i] != 0 + I[count] = nzind[i] + V[count] = nzval[i] + count += 1 + end + end + + count -= 1 + if numnz != count + deleteat!(I, (count+1):numnz) + deleteat!(V, (count+1):numnz) + end + + return (I, V) +end ### Generic functions operating on AbstractSparseVector @@ -883,7 +932,6 @@ function _binarymap{Tx,Ty}(f::Function, x::AbstractSparseVector{Tx}, y::AbstractSparseVector{Ty}, mode::Int) - 0 <= mode <= 2 || throw(ArgumentError("Incorrect mode $mode.")) R = typeof(f(zero(Tx), zero(Ty))) n = length(x) @@ -1025,7 +1073,6 @@ function _binarymap{Tx,Ty}(f::Function, x::AbstractVector{Tx}, y::AbstractSparseVector{Ty}, mode::Int) - 0 <= mode <= 2 || throw(ArgumentError("Incorrect mode $mode.")) R = typeof(f(zero(Tx), zero(Ty))) n = length(x) @@ -1068,7 +1115,6 @@ function _binarymap{Tx,Ty}(f::Function, x::AbstractSparseVector{Tx}, y::AbstractVector{Ty}, mode::Int) - 0 <= mode <= 2 || throw(ArgumentError("Incorrect mode $mode.")) R = typeof(f(zero(Tx), zero(Ty))) n = length(x) diff --git a/base/stacktraces.jl b/base/stacktraces.jl index b4be771e44628f..55a7d901225ad5 100644 --- a/base/stacktraces.jl +++ b/base/stacktraces.jl @@ -56,7 +56,7 @@ immutable StackFrame # this type should be kept platform-agnostic so that profil "true if the code is from an inlined frame" inlined::Bool "representation of the pointer to the execution context as returned by `backtrace`" - pointer::Int64 # Large enough to be read losslessly on 32- and 64-bit machines. + pointer::UInt64 # Large enough to be read losslessly on 32- and 64-bit machines. end StackFrame(func, file, line) = StackFrame(func, file, line, Nullable{LambdaInfo}(), false, false, 0) @@ -123,7 +123,7 @@ inlined at that point, innermost function first. """ function lookup(pointer::Ptr{Void}) infos = ccall(:jl_lookup_code_address, Any, (Ptr{Void}, Cint), pointer - 1, false) - isempty(infos) && return [StackFrame(empty_sym, empty_sym, -1, Nullable{LambdaInfo}(), true, false, convert(Int64, pointer))] + isempty(infos) && return [StackFrame(empty_sym, empty_sym, -1, Nullable{LambdaInfo}(), true, false, convert(UInt64, pointer))] res = Array{StackFrame}(length(infos)) for i in 1:length(infos) info = infos[i] diff --git a/base/test.jl b/base/test.jl index 7d23115354bbde..0b2009ba72465d 100644 --- a/base/test.jl +++ b/base/test.jl @@ -720,6 +720,13 @@ function testset_forloop(args, testloop) # wrapped in the outer loop provided by the user tests = testloop.args[2] blk = quote + # Trick to handle `break` and `continue` in the test code before + # they can be handled properly by `finally` lowering. + if !first_iteration + pop_testset() + push!(arr, finish(ts)) + end + first_iteration = false ts = $(testsettype)($desc; $options...) push_testset(ts) try @@ -729,13 +736,20 @@ function testset_forloop(args, testloop) # error in this test set record(ts, Error(:nontest_error, :(), err, catch_backtrace())) end - pop_testset() - finish(ts) end quote arr = Array{Any,1}(0) - $(Expr(:for, Expr(:block, [esc(v) for v in loopvars]...), - :(push!(arr, $blk)))) + first_iteration = true + local ts + try + $(Expr(:for, Expr(:block, [esc(v) for v in loopvars]...), blk)) + finally + # Handle `return` in test body + if !first_iteration + pop_testset() + push!(arr, finish(ts)) + end + end arr end end diff --git a/base/threadcall.jl b/base/threadcall.jl index be3e99f324cb8c..da877d97071090 100644 --- a/base/threadcall.jl +++ b/base/threadcall.jl @@ -75,6 +75,7 @@ function do_threadcall(wrapper::Function, rettype::Type, argtypes::Vector, argva y = cconvert(T, x) push!(roots, y) unsafe_store!(convert(Ptr{T}, ptr), unsafe_convert(T, y)) + ptr += sizeof(T) end # create return buffer diff --git a/contrib/windows/msys_build.sh b/contrib/windows/msys_build.sh index 2d91f26a6af726..7ada885dbf90e9 100755 --- a/contrib/windows/msys_build.sh +++ b/contrib/windows/msys_build.sh @@ -178,9 +178,7 @@ echo 'override LIBLAPACKNAME = $(LIBBLASNAME)' >> Make.user # libuv since its static lib is no longer included in the binaries # openlibm since we need it as a static library to work properly # utf8proc since its headers are not in the binary download -echo 'override STAGE1_DEPS = libuv' >> Make.user -echo 'override STAGE2_DEPS = utf8proc' >> Make.user -echo 'override STAGE3_DEPS = ' >> Make.user +echo 'override DEP_LIBS = libuv utf8proc' >> Make.user if [ -n "$USEMSVC" ]; then # Openlibm doesn't build well with MSVC right now @@ -192,14 +190,14 @@ if [ -n "$USEMSVC" ]; then make -C deps install-libuv install-utf8proc cp usr/lib/uv.lib usr/lib/libuv.a echo 'override CC += -TP' >> Make.user - echo 'override STAGE1_DEPS += dsfmt' >> Make.user + echo 'override DEP_LIBS += dsfmt' >> Make.user # Create a modified version of compile for wrapping link sed -e 's/-link//' -e 's/cl/link/g' -e 's/ -Fe/ -OUT:/' \ -e 's|$dir/$lib|$dir/lib$lib|g' deps/srccache/libuv/compile > linkld chmod +x linkld else - echo 'override STAGE1_DEPS += openlibm' >> Make.user + echo 'override DEP_LIBS += openlibm' >> Make.user make check-whitespace make VERBOSE=1 -C base version_git.jl.phony echo 'NO_GIT = 1' >> Make.user diff --git a/deps/Makefile b/deps/Makefile index 08c3f96fc503e4..5e59c43fb7e15f 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -17,7 +17,7 @@ include $(SRCDIR)/llvm-ver.make # additionally all targets should be listed in the getall target for easier off-line compilation # if you are adding a new target, it can help to copy an similar, existing target # -# autoconf configure-driven scripts: llvm pcre arpack fftw unwind gmp mpfr patchelf libuv +# autoconf configure-driven scripts: llvm pcre arpack fftw unwind gmp mpfr patchelf libuv curl # custom Makefile rules: openlibm dsfmt suitesparse-wrapper suitesparse lapack openblas utf8proc objconv osxunwind # entirely custom: virtualenv # CMake libs: libgit2 libssh2 mbedtls @@ -47,6 +47,8 @@ CMAKE_CC_ARG := $(CC_ARG) $(DEPS_CFLAGS) CMAKE_CXX_ARG := $(CXX_ARG) $(DEPS_CXXFLAGS) CMAKE_COMMON := -DCMAKE_INSTALL_PREFIX:PATH=$(build_prefix) -DCMAKE_PREFIX_PATH=$(build_prefix) +CMAKE_COMMON += -DCMAKE_INSTALL_LIBDIR=$(build_libdir) -DCMAKE_INSTALL_BINDIR=$(build_bindir) +CMAKE_COMMON += -DLIB_INSTALL_DIR=$(build_shlibdir) ifneq ($(VERBOSE), 0) CMAKE_COMMON += -DCMAKE_VERBOSE_MAKEFILE=ON endif @@ -88,31 +90,29 @@ MAKE_COMMON := DESTDIR="" prefix=$(build_prefix) bindir=$(build_depsbindir) libd # prevent installing libs into usr/lib64 on opensuse unexport CONFIG_SITE -STAGE1_DEPS := -STAGE2_DEPS := ifeq ($(USE_GPL_LIBS), 1) -STAGE3_DEPS := suitesparse-wrapper +DEP_LIBS := suitesparse-wrapper else -STAGE3_DEPS := +DEP_LIBS := endif ifeq ($(USE_SYSTEM_LIBUV), 0) -STAGE1_DEPS += libuv +DEP_LIBS += libuv endif ifeq ($(USE_SYSTEM_LIBUNWIND), 0) ifeq ($(OS), Linux) -STAGE1_DEPS += unwind +DEP_LIBS += unwind else ifeq ($(OS), FreeBSD) -STAGE1_DEPS += unwind +DEP_LIBS += unwind else ifeq ($(OS), Darwin) -STAGE1_DEPS += osxunwind +DEP_LIBS += osxunwind endif endif ifeq ($(OS), Linux) ifeq ($(USE_SYSTEM_PATCHELF), 0) -STAGE1_DEPS += patchelf +DEP_LIBS += patchelf PATCHELF:=$(build_depsbindir)/patchelf else PATCHELF:=patchelf @@ -124,73 +124,79 @@ PATCHELF_BIN := $(CUSTOM_LD_LIBRARY_PATH) $(PATCHELF) ifeq ($(USE_SYSTEM_OPENLIBM), 0) ifeq ($(USE_SYSTEM_LIBM), 0) -STAGE1_DEPS += openlibm +DEP_LIBS += openlibm endif endif ifeq ($(USE_SYSTEM_OPENSPECFUN), 0) -STAGE1_DEPS += openspecfun +DEP_LIBS += openspecfun endif ifeq ($(USE_SYSTEM_DSFMT), 0) -STAGE1_DEPS += dsfmt +DEP_LIBS += dsfmt endif ifeq ($(USE_SYSTEM_LLVM), 0) -STAGE1_DEPS += llvm +DEP_LIBS += llvm endif ifeq ($(USE_SYSTEM_PCRE), 0) -STAGE1_DEPS += pcre +DEP_LIBS += pcre endif ifeq ($(USE_SYSTEM_BLAS), 0) -STAGE1_DEPS += openblas +DEP_LIBS += openblas ifeq ($(USE_BLAS64), 1) ifeq ($(OS), Darwin) -STAGE1_DEPS += objconv +DEP_LIBS += objconv endif endif endif ifeq ($(USE_GPL_LIBS), 1) ifeq ($(USE_SYSTEM_FFTW), 0) -STAGE1_DEPS += fftw +DEP_LIBS += fftw endif endif ifeq ($(USE_SYSTEM_GMP), 0) -STAGE1_DEPS += gmp +DEP_LIBS += gmp endif +ifeq ($(USE_SYSTEM_LIBGIT2), 0) ifeq ($(USE_SYSTEM_MBEDTLS), 0) -STAGE1_DEPS += mbedtls +DEP_LIBS += mbedtls endif ifeq ($(USE_SYSTEM_LIBSSH2), 0) -STAGE2_DEPS += libssh2 +DEP_LIBS += libssh2 endif -ifeq ($(USE_SYSTEM_LIBGIT2), 0) -STAGE3_DEPS += libgit2 +ifneq ($(OS), WINNT) +ifeq ($(USE_SYSTEM_CURL), 0) +DEP_LIBS += curl +endif endif +DEP_LIBS += libgit2 +endif # USE_SYSTEM_LIBGIT2 + ifeq ($(USE_SYSTEM_MPFR), 0) -STAGE2_DEPS += mpfr +DEP_LIBS += mpfr endif ifeq ($(USE_SYSTEM_ARPACK), 0) -STAGE2_DEPS += arpack +DEP_LIBS += arpack endif ifeq ($(USE_GPL_LIBS), 1) ifeq ($(USE_SYSTEM_SUITESPARSE), 0) -STAGE2_DEPS += suitesparse +DEP_LIBS += suitesparse endif endif ifeq ($(USE_SYSTEM_UTF8PROC), 0) -STAGE2_DEPS += utf8proc +DEP_LIBS += utf8proc endif # Only compile standalone LAPACK if we are not using OpenBLAS. @@ -199,7 +205,7 @@ endif # build LAPACK as the vendor LAPACK may be too old (eg. Apple vecLib) ifeq ($(USE_SYSTEM_BLAS), 1) ifeq ($(USE_SYSTEM_LAPACK), 0) -STAGE2_DEPS += lapack +DEP_LIBS += lapack endif endif @@ -211,8 +217,6 @@ endif ## Common build target prefixes -DEP_LIBS := $(STAGE1_DEPS) $(STAGE2_DEPS) $(STAGE3_DEPS) - default: install | $(build_prefix) get: $(addprefix get-, $(DEP_LIBS)) configure: $(addprefix configure-, $(DEP_LIBS)) @@ -222,7 +226,7 @@ install: $(addprefix install-, $(DEP_LIBS)) cleanall: $(addprefix clean-, $(DEP_LIBS)) distcleanall: $(addprefix distclean-, $(DEP_LIBS)) rm -rf $(build_prefix) -getall: get-llvm get-libuv get-pcre get-openlibm get-openspecfun get-dsfmt get-openblas get-lapack get-fftw get-suitesparse get-arpack get-unwind get-osxunwind get-gmp get-mpfr get-patchelf get-utf8proc get-virtualenv get-objconv get-mbedtls get-libssh2 get-libgit2 +getall: get-llvm get-libuv get-pcre get-openlibm get-openspecfun get-dsfmt get-openblas get-lapack get-fftw get-suitesparse get-arpack get-unwind get-osxunwind get-gmp get-mpfr get-patchelf get-utf8proc get-virtualenv get-objconv get-mbedtls get-libssh2 get-curl get-libgit2 ## PATHS ## # sort is used to remove potential duplicates @@ -271,6 +275,7 @@ include $(SRCDIR)/mpfr.mk include $(SRCDIR)/patchelf.mk include $(SRCDIR)/mbedtls.mk include $(SRCDIR)/libssh2.mk +include $(SRCDIR)/curl.mk include $(SRCDIR)/libgit2.mk include $(SRCDIR)/virtualenv.mk diff --git a/deps/Versions.make b/deps/Versions.make index 4d6c5fc751b79c..cdf2c1eb84de9a 100644 --- a/deps/Versions.make +++ b/deps/Versions.make @@ -13,3 +13,4 @@ MPFR_VER = 3.1.4 PATCHELF_VER = 0.9 VIRTUALENV_VER = 15.0.0 MBEDTLS_VER = 2.3.0 +CURL_VER = 7.50.1 diff --git a/deps/arpack.mk b/deps/arpack.mk index 91a5c72f05b905..7d65c10af78609 100644 --- a/deps/arpack.mk +++ b/deps/arpack.mk @@ -32,10 +32,9 @@ ARPACK_OBJ_TARGET := $(build_shlibdir)/libarpack.$(SHLIB_EXT) ARPACK_MFLAGS := F77="$(FC)" MPIF77="$(FC)" ARPACK_FFLAGS += $(FFLAGS) $(JFFLAGS) -ARPACK_FLAGS := --with-blas="$(LIBBLAS)" --with-lapack="$(LIBLAPACK)" --disable-mpi --enable-shared FFLAGS="$(ARPACK_FFLAGS)" CFLAGS="$(CFLAGS) $(ARPACK_CFLAGS)" -ifneq ($(OS),WINNT) -ARPACK_FLAGS += LDFLAGS="$(LDFLAGS) -Wl,-rpath,'$(build_libdir)'" -endif +ARPACK_FLAGS := --with-blas="$(LIBBLAS)" --with-lapack="$(LIBLAPACK)" \ + --disable-mpi --enable-shared FFLAGS="$(ARPACK_FFLAGS)" \ + CFLAGS="$(CFLAGS) $(ARPACK_CFLAGS)" LDFLAGS="$(LDFLAGS) $(RPATH_ESCAPED_ORIGIN)" # ARPACK-NG upstream keeps changing their download filenames $(SRCDIR)/srccache/arpack-ng-$(ARPACK_VER).tar.gz: | $(SRCDIR)/srccache diff --git a/deps/blas.mk b/deps/blas.mk index fcd6cd8074bb0f..809c4c7297932b 100644 --- a/deps/blas.mk +++ b/deps/blas.mk @@ -200,10 +200,9 @@ LAPACK_OBJ_TARGET := LAPACK_OBJ_SOURCE := endif -LAPACK_MFLAGS := NOOPT="$(FFLAGS) $(JFFLAGS) $(GFORTBLAS_FFLAGS) -O0" OPTS="$(FFLAGS) $(JFFLAGS) $(GFORTBLAS_FFLAGS)" FORTRAN="$(FC)" LOADER="$(FC)" -ifneq ($(OS),WINNT) -LAPACK_MFLAGS += BLASLIB="-Wl,-rpath,'$(build_libdir)' $(LIBBLAS)" -endif +LAPACK_MFLAGS := NOOPT="$(FFLAGS) $(JFFLAGS) $(GFORTBLAS_FFLAGS) -O0" \ + OPTS="$(FFLAGS) $(JFFLAGS) $(GFORTBLAS_FFLAGS)" FORTRAN="$(FC)" \ + LOADER="$(FC)" BLASLIB="$(RPATH_ESCAPED_ORIGIN) $(LIBBLAS)" $(SRCDIR)/srccache/lapack-$(LAPACK_VER).tgz: | $(SRCDIR)/srccache $(JLDOWNLOAD) $@ http://www.netlib.org/lapack/$(notdir $@) diff --git a/deps/checksums/curl-7.50.1.tar.bz2/md5 b/deps/checksums/curl-7.50.1.tar.bz2/md5 new file mode 100644 index 00000000000000..111b5757285351 --- /dev/null +++ b/deps/checksums/curl-7.50.1.tar.bz2/md5 @@ -0,0 +1 @@ +015f6a0217ca6f2c5442ca406476920b diff --git a/deps/checksums/curl-7.50.1.tar.bz2/sha512 b/deps/checksums/curl-7.50.1.tar.bz2/sha512 new file mode 100644 index 00000000000000..95a02a7febe1cc --- /dev/null +++ b/deps/checksums/curl-7.50.1.tar.bz2/sha512 @@ -0,0 +1 @@ +94acd91fcf8ff2605e1ba2d086c2c366257b61eaf516b9ea44e574e315feb5b30f6e47d89051f259e026ef5dd9edde5f7b15a6af9ee6a38f641da354e1e677b1 diff --git a/deps/checksums/libuv-28743d6091531340cfe316de2b2d385fe1778ff5.tar.gz/md5 b/deps/checksums/libuv-28743d6091531340cfe316de2b2d385fe1778ff5.tar.gz/md5 deleted file mode 100644 index e42a20ffd5a35a..00000000000000 --- a/deps/checksums/libuv-28743d6091531340cfe316de2b2d385fe1778ff5.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -cc07a8ef026fa42eeaddf7b6e074096e diff --git a/deps/checksums/libuv-28743d6091531340cfe316de2b2d385fe1778ff5.tar.gz/sha512 b/deps/checksums/libuv-28743d6091531340cfe316de2b2d385fe1778ff5.tar.gz/sha512 deleted file mode 100644 index bec2d8d44203fc..00000000000000 --- a/deps/checksums/libuv-28743d6091531340cfe316de2b2d385fe1778ff5.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -e128cec9548ff2f52a78743203d3f06dceef3cf7cbeb3a7a5f7453b132576833f82688eed52cf74c035f57828deac079cd845ad47c8cd6197a8e0bebf3586fc2 diff --git a/deps/checksums/libuv-8d5131b6c1595920dd30644cd1435b4f344b46c8.tar.gz/md5 b/deps/checksums/libuv-8d5131b6c1595920dd30644cd1435b4f344b46c8.tar.gz/md5 new file mode 100644 index 00000000000000..89795f7987bbce --- /dev/null +++ b/deps/checksums/libuv-8d5131b6c1595920dd30644cd1435b4f344b46c8.tar.gz/md5 @@ -0,0 +1 @@ +4c91d4c9161555c911630b0a70ddec03 diff --git a/deps/checksums/libuv-8d5131b6c1595920dd30644cd1435b4f344b46c8.tar.gz/sha512 b/deps/checksums/libuv-8d5131b6c1595920dd30644cd1435b4f344b46c8.tar.gz/sha512 new file mode 100644 index 00000000000000..faf62292a62af8 --- /dev/null +++ b/deps/checksums/libuv-8d5131b6c1595920dd30644cd1435b4f344b46c8.tar.gz/sha512 @@ -0,0 +1 @@ +c53513a5aea84405bf302b084a23f24f54148aac90a2bd666219ce14879723baab959942934d0d801a4572fffd07e60a7d574ade8d7eb57b6da8216063c20a48 diff --git a/deps/curl.mk b/deps/curl.mk new file mode 100644 index 00000000000000..893e15aa859ef1 --- /dev/null +++ b/deps/curl.mk @@ -0,0 +1,62 @@ +## CURL ## + +CURL_SRC_TARGET := $(BUILDDIR)/curl-$(CURL_VER)/lib/.libs/libcurl.$(SHLIB_EXT) +CURL_OBJ_TARGET := $(build_shlibdir)/libcurl.$(SHLIB_EXT) + +CURL_LDFLAGS := $(RPATH_ESCAPED_ORIGIN) + +$(SRCDIR)/srccache/curl-$(CURL_VER).tar.bz2: | $(SRCDIR)/srccache + $(JLDOWNLOAD) $@ https://curl.haxx.se/download/curl-$(CURL_VER).tar.bz2 + +$(SRCDIR)/srccache/curl-$(CURL_VER)/configure: $(SRCDIR)/srccache/curl-$(CURL_VER).tar.bz2 + $(JLCHECKSUM) $< + cd $(dir $<) && $(TAR) jxf $(notdir $<) + touch -c $@ + +ifeq ($(USE_SYSTEM_MBEDTLS), 0) +$(BUILDDIR)/curl-$(CURL_VER)/config.status: $(MBEDTLS_OBJ_TARGET) +endif +ifeq ($(USE_SYSTEM_LIBSSH2), 0) +$(BUILDDIR)/curl-$(CURL_VER)/config.status: $(LIBSSH2_OBJ_TARGET) +endif +$(BUILDDIR)/curl-$(CURL_VER)/config.status: $(SRCDIR)/srccache/curl-$(CURL_VER)/configure + mkdir -p $(dir $@) + cd $(dir $@) && \ + $< $(CONFIGURE_COMMON) --includedir=$(build_includedir) \ + --without-ssl --without-gnutls --without-gssapi --without-zlib \ + --without-libidn --without-libmetalink --without-librtmp \ + --without-nghttp2 --without-nss --without-polarssl \ + --without-spnego --without-libpsl --disable-ares \ + --disable-ldap --disable-ldaps --without-zsh-functions-dir \ + --with-libssh2=$(build_prefix) --with-mbedtls=$(build_prefix) \ + CFLAGS="$(CFLAGS) $(CURL_CFLAGS)" LDFLAGS="$(LDFLAGS) $(CURL_LDFLAGS)" + touch -c $@ + +$(CURL_SRC_TARGET): $(BUILDDIR)/curl-$(CURL_VER)/config.status + $(MAKE) -C $(dir $<) $(LIBTOOL_CCLD) + touch -c $@ + +$(BUILDDIR)/curl-$(CURL_VER)/checked: $(CURL_SRC_TARGET) +ifeq ($(OS),$(BUILD_OS)) +ifneq ($(OS),WINNT) + $(MAKE) -C $(dir $@) check -j1 +endif +endif + echo 1 > $@ + +$(CURL_OBJ_TARGET): $(CURL_SRC_TARGET) + $(call make-install,curl-$(CURL_VER),$(LIBTOOL_CCLD)) + $(INSTALL_NAME_CMD)libcurl.$(SHLIB_EXT) $@ + touch -c $@ + +clean-curl: + -$(MAKE) -C $(BUILDDIR)/curl-$(CURL_VER) clean + -rm -f $(build_shlibdir)/libcurl* +distclean-curl: + -rm -rf $(SRCDIR)/srccache/curl-$(CURL_VER).tar.bz2 $(SRCDIR)/srccache/curl-$(CURL_VER) $(BUILDDIR)/curl-$(CURL_VER) + +get-curl: $(SRCDIR)/srccache/curl-$(CURL_VER).tar.bz2 +configure-curl: $(BUILDDIR)/curl-$(CURL_VER)/config.status +compile-curl: $(CURL_SRC_TARGET) +check-curl: $(BUILDDIR)/curl-$(CURL_VER)/checked +install-curl: $(CURL_OBJ_TARGET) diff --git a/deps/libgit2.mk b/deps/libgit2.mk index 113fbcea7c388f..c1e0a2cc82b6b2 100644 --- a/deps/libgit2.mk +++ b/deps/libgit2.mk @@ -19,6 +19,8 @@ else LIBGIT2_OPTS += -DBUILD_CLAR=OFF -DDLLTOOL=`which $(CROSS_COMPILE)dlltool` LIBGIT2_OPTS += -DCMAKE_FIND_ROOT_PATH=/usr/$(XC_HOST) -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY endif +else +LIBGIT2_OPTS += -DCURL_INCLUDE_DIRS=$(build_includedir) -DCURL_LIBRARIES="-L$(build_shlibdir) -lcurl" endif ifeq ($(OS),Linux) @@ -44,7 +46,15 @@ $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-openssl-hang.patch-applied: | $(SR ifeq ($(OS),Linux) $(BUILDDIR)/$(LIBGIT2_SRC_DIR)/Makefile: $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-require-openssl.patch-applied $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-openssl-hang.patch-applied endif -$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/Makefile: $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/CMakeLists.txt $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-ssh.patch-applied $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-agent-nonfatal.patch-applied $(LIBSSH2_OBJ_TARGET) +ifneq ($(OS),WINNT) +ifeq ($(USE_SYSTEM_CURL), 0) +$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/Makefile: $(CURL_OBJ_TARGET) +endif +endif +ifeq ($(USE_SYSTEM_LIBSSH2), 0) +$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/Makefile: $(LIBSSH2_OBJ_TARGET) +endif +$(BUILDDIR)/$(LIBGIT2_SRC_DIR)/Makefile: $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/CMakeLists.txt $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-ssh.patch-applied $(SRCDIR)/srccache/$(LIBGIT2_SRC_DIR)/libgit2-agent-nonfatal.patch-applied mkdir -p $(dir $@) cd $(dir $@) && \ $(CMAKE) $(dir $<) $(LIBGIT2_OPTS) @@ -61,7 +71,7 @@ endif echo 1 > $@ $(LIBGIT2_OBJ_TARGET): $(LIBGIT2_OBJ_SOURCE) | $(build_shlibdir) -ifeq ($(BUILD_OS),WINNT) +ifeq ($(OS),WINNT) cp $< $@ else $(call make-install,$(LIBGIT2_SRC_DIR),) @@ -73,14 +83,14 @@ ifeq ($(OS),Linux) for LIB in libssl libcrypto; do \ LIB_PATH=$$(echo "$$LIBGIT_LIBS" | grep "$$LIB"); \ echo "LIB_PATH for $$LIB: $$LIB_PATH"; \ - [ ! -z "$$LIB_PATH" ] && cp -v "$$LIB_PATH" $(build_shlibdir); \ + [ ! -z "$$LIB_PATH" ] && cp -v -f "$$LIB_PATH" $(build_shlibdir); \ done endif touch -c $@ clean-libgit2: -$(MAKE) -C $(BUILDDIR)/$(LIBGIT2_SRC_DIR) clean - -rm -f $(LIBGIT2_OBJ_TARGET) + -rm -f $(build_shlibdir)/libgit2* $(build_shlibdir)/libssl* $(build_shlibdir)/libcrypto* get-libgit2: $(LIBGIT2_SRC_FILE) configure-libgit2: $(BUILDDIR)/$(LIBGIT2_SRC_DIR)/Makefile diff --git a/deps/libssh2.mk b/deps/libssh2.mk index be13f58c8653e5..48f111dfcc5e9f 100644 --- a/deps/libssh2.mk +++ b/deps/libssh2.mk @@ -8,7 +8,7 @@ LIBSSH2_OBJ_SOURCE := $(BUILDDIR)/$(LIBSSH2_SRC_DIR)/src/libssh2.$(SHLIB_EXT) LIBSSH2_OBJ_TARGET := $(build_shlibdir)/libssh2.$(SHLIB_EXT) LIBSSH2_OPTS := $(CMAKE_COMMON) -DBUILD_SHARED_LIBS=ON -DBUILD_EXAMPLES=OFF \ - -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_LIBDIR=lib + -DCMAKE_BUILD_TYPE=Release ifeq ($(OS),WINNT) LIBSSH2_OPTS += -DCRYPTO_BACKEND=WinCNG -DENABLE_ZLIB_COMPRESSION=OFF @@ -16,7 +16,7 @@ ifeq ($(BUILD_OS),WINNT) LIBSSH2_OPTS += -G"MSYS Makefiles" endif else -LIBSSH2_OPTS += -DCRYPTO_BACKEND=mbedTLS -DENABLE_ZLIB_COMPRESSION=ON +LIBSSH2_OPTS += -DCRYPTO_BACKEND=mbedTLS -DENABLE_ZLIB_COMPRESSION=OFF endif ifeq ($(OS),Linux) @@ -30,7 +30,10 @@ $(SRCDIR)/srccache/$(LIBSSH2_SRC_DIR)/libssh2-encryptedpem.patch-applied: | $(SR cd $(SRCDIR)/srccache/$(LIBSSH2_SRC_DIR) && patch -p1 -f < $(SRCDIR)/patches/libssh2-encryptedpem.patch echo 1 > $@ -$(BUILDDIR)/$(LIBSSH2_SRC_DIR)/Makefile: $(SRCDIR)/srccache/$(LIBSSH2_SRC_DIR)/CMakeLists.txt $(SRCDIR)/srccache/$(LIBSSH2_SRC_DIR)/libssh2-mbedtls.patch-applied $(SRCDIR)/srccache/$(LIBSSH2_SRC_DIR)/libssh2-encryptedpem.patch-applied $(MBEDTLS_OBJ_TARGET) +ifeq ($(USE_SYSTEM_MBEDTLS), 0) +$(BUILDDIR)/$(LIBSSH2_SRC_DIR)/Makefile: $(MBEDTLS_OBJ_TARGET) +endif +$(BUILDDIR)/$(LIBSSH2_SRC_DIR)/Makefile: $(SRCDIR)/srccache/$(LIBSSH2_SRC_DIR)/CMakeLists.txt $(SRCDIR)/srccache/$(LIBSSH2_SRC_DIR)/libssh2-mbedtls.patch-applied $(SRCDIR)/srccache/$(LIBSSH2_SRC_DIR)/libssh2-encryptedpem.patch-applied mkdir -p $(dir $@) cd $(dir $@) && \ $(CMAKE) $(dir $<) $(LIBSSH2_OPTS) diff --git a/deps/libuv.version b/deps/libuv.version index 478ebca66589a4..4ba4b36712aaf7 100644 --- a/deps/libuv.version +++ b/deps/libuv.version @@ -1,2 +1,2 @@ LIBUV_BRANCH=julia-uv1.9.0 -LIBUV_SHA1=28743d6091531340cfe316de2b2d385fe1778ff5 +LIBUV_SHA1=8d5131b6c1595920dd30644cd1435b4f344b46c8 diff --git a/deps/mbedtls.mk b/deps/mbedtls.mk index 1ed14a48ab8a0b..f9a340f83c9c1e 100644 --- a/deps/mbedtls.mk +++ b/deps/mbedtls.mk @@ -11,15 +11,11 @@ MBEDTLS_OBJ_SOURCE := $(BUILDDIR)/mbedtls-$(MBEDTLS_VER)/library/libmbedcrypto.$ MBEDTLS_OBJ_TARGET := $(build_shlibdir)/libmbedcrypto.$(SHLIB_EXT) MBEDTLS_OPTS := $(CMAKE_COMMON) -DUSE_SHARED_MBEDTLS_LIBRARY=ON \ - -DENABLE_PROGRAMS=OFF -DCMAKE_BUILD_TYPE=Release + -DUSE_STATIC_MBEDTLS_LIBRARY=OFF -DENABLE_PROGRAMS=OFF -DCMAKE_BUILD_TYPE=Release -ifeq ($(OS),WINNT) MBEDTLS_OPTS += -DENABLE_ZLIB_SUPPORT=OFF ifeq ($(BUILD_OS),WINNT) -MBEDTLS_OPTS += -G"MSYS Makefiles" -DENABLE_TESTING=OFF -endif -else -MBEDTLS_OPTS += -DENABLE_ZLIB_SUPPORT=ON +MBEDTLS_OPTS += -G"MSYS Makefiles" endif ifeq ($(OS),Linux) @@ -35,7 +31,11 @@ $(SRCDIR)/srccache/$(MBEDTLS_SRC)/CMakeLists.txt: $(SRCDIR)/srccache/$(MBEDTLS_S $(TAR) -C $(dir $@) --strip-components 1 -xf $< touch -c $@ -$(BUILDDIR)/mbedtls-$(MBEDTLS_VER)/Makefile: $(SRCDIR)/srccache/$(MBEDTLS_SRC)/CMakeLists.txt +$(SRCDIR)/srccache/$(MBEDTLS_SRC)/mbedtls-ssl.h.patch-applied: | $(SRCDIR)/srccache/$(MBEDTLS_SRC)/CMakeLists.txt + cd $(SRCDIR)/srccache/$(MBEDTLS_SRC)/include/mbedtls && patch -p0 -f < $(SRCDIR)/patches/mbedtls-ssl.h.patch + echo 1 > $@ + +$(BUILDDIR)/mbedtls-$(MBEDTLS_VER)/Makefile: $(SRCDIR)/srccache/$(MBEDTLS_SRC)/CMakeLists.txt $(SRCDIR)/srccache/$(MBEDTLS_SRC)/mbedtls-ssl.h.patch-applied mkdir -p $(dir $@) cd $(dir $@) && \ $(CMAKE) $(dir $<) $(MBEDTLS_OPTS) @@ -54,6 +54,8 @@ endif $(MBEDTLS_OBJ_TARGET): $(MBEDTLS_OBJ_SOURCE) | $(build_shlibdir) ifeq ($(OS), WINNT) cp $^ $(build_shlibdir) + cp $(BUILDDIR)/mbedtls-$(MBEDTLS_VER)/library/libmbedx509.$(SHLIB_EXT) $(build_shlibdir) + cp $(BUILDDIR)/mbedtls-$(MBEDTLS_VER)/library/libmbedtls.$(SHLIB_EXT) $(build_shlibdir) else $(call make-install,mbedtls-$(MBEDTLS_VER),) endif @@ -67,7 +69,7 @@ endif clean-mbedtls: -$(MAKE) -C $(BUILDDIR)/mbedtls-$(MBEDTLS_VER) clean - -rm -f $(MBEDTLS_OBJ_TARGET) + -rm -f $(MBEDTLS_OBJ_TARGET) $(build_shlibdir)/libmbed* distclean-mbedtls: -rm -rf $(SRCDIR)/srccache/$(MBEDTLS_SRC).tgz \ diff --git a/deps/openspecfun.mk b/deps/openspecfun.mk index 6e3ccce12d02a5..f6c5dfead968f1 100644 --- a/deps/openspecfun.mk +++ b/deps/openspecfun.mk @@ -13,7 +13,7 @@ OPENSPECFUN_OBJ_TARGET := $(build_shlibdir)/libopenspecfun.$(SHLIB_EXT) OPENSPECFUN_OBJ_SOURCE := $(BUILDDIR)/$(OPENSPECFUN_SRC_DIR)/libopenspecfun.$(SHLIB_EXT) OPENSPECFUN_FLAGS := ARCH="$(ARCH)" CC="$(CC)" FC="$(FC)" AR="$(AR)" OS="$(OS)" \ USECLANG=$(USECLANG) USEGCC=$(USEGCC) FFLAGS="$(JFFLAGS)" \ - CFLAGS="$(CFLAGS) $(OPENSPECFUN_CFLAGS)" LDFLAGS="$(RPATH_ESCAPED_ORIGIN)" + CFLAGS="$(CFLAGS) $(OPENSPECFUN_CFLAGS)" LDFLAGS="$(LDFLAGS) $(RPATH_ESCAPED_ORIGIN)" ifeq ($(USE_SYSTEM_LIBM),0) OPENSPECFUN_FLAGS += USE_OPENLIBM=1 diff --git a/deps/patches/mbedtls-ssl.h.patch b/deps/patches/mbedtls-ssl.h.patch new file mode 100644 index 00000000000000..11785c5d88c607 --- /dev/null +++ b/deps/patches/mbedtls-ssl.h.patch @@ -0,0 +1,12 @@ +--- ssl.h.old 2016-06-28 18:12:06.000000000 +0530 ++++ ssl.h 2016-08-03 18:51:34.000000000 +0530 +@@ -54,7 +54,8 @@ + #endif + + #if defined(MBEDTLS_HAVE_TIME) +-#include ++//#include ++#include "platform.h" + #endif + + /* diff --git a/deps/pcre.mk b/deps/pcre.mk index c66197fc7f50ce..b251f0c8aeae1b 100644 --- a/deps/pcre.mk +++ b/deps/pcre.mk @@ -5,9 +5,7 @@ PCRE_OBJ_TARGET := $(build_shlibdir)/libpcre2-8.$(SHLIB_EXT) # Force optimization for PCRE flags (Issue #11668) PCRE_CFLAGS := -O3 -ifneq ($(OS),WINNT) -PCRE_LDFLAGS := "-Wl,-rpath,'$(build_libdir)'" -endif +PCRE_LDFLAGS := $(RPATH_ESCAPED_ORIGIN) $(SRCDIR)/srccache/pcre2-$(PCRE_VER).tar.bz2: | $(SRCDIR)/srccache $(JLDOWNLOAD) $@ https://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre2-$(PCRE_VER).tar.bz2 @@ -36,7 +34,7 @@ $(PCRE_OBJ_TARGET): $(PCRE_SRC_TARGET) touch -c $@ clean-pcre: - -$(MAKE) -C pcre2-$(PCRE_VER) clean + -$(MAKE) -C $(BUILDDIR)/pcre2-$(PCRE_VER) clean -rm -f $(build_shlibdir)/libpcre* distclean-pcre: -rm -rf $(SRCDIR)/srccache/pcre2-$(PCRE_VER).tar.bz2 $(SRCDIR)/srccache/pcre2-$(PCRE_VER) $(BUILDDIR)/pcre2-$(PCRE_VER) diff --git a/deps/suitesparse.mk b/deps/suitesparse.mk index 975572e762466f..87a07adfe898df 100644 --- a/deps/suitesparse.mk +++ b/deps/suitesparse.mk @@ -22,9 +22,7 @@ ifneq ($(OS), WINNT) SUITE_SPARSE_LIB += -lrt endif endif -ifneq ($(OS), WINNT) -SUITE_SPARSE_LIB += -Wl,-rpath,'$(build_libdir)' -endif +SUITE_SPARSE_LIB += $(RPATH_ESCAPED_ORIGIN) SUITESPARSE_MFLAGS := CC="$(CC)" CXX="$(CXX)" F77="$(FC)" AR="$(AR)" RANLIB="$(RANLIB)" BLAS="$(LIBBLAS)" LAPACK="$(LIBLAPACK)" \ INSTALL_LIB="$(build_libdir)" INSTALL_INCLUDE="$(build_includedir)" LIB="$(SUITE_SPARSE_LIB)" \ UMFPACK_CONFIG="$(UMFPACK_CONFIG)" CHOLMOD_CONFIG="$(CHOLMOD_CONFIG)" SPQR_CONFIG="$(SPQR_CONFIG)" diff --git a/doc/devdocs/C.rst b/doc/devdocs/C.rst index 60150eb777d9b5..b5866a7fa18eaf 100644 --- a/doc/devdocs/C.rst +++ b/doc/devdocs/C.rst @@ -12,3 +12,4 @@ backtraces debuggingtips valgrind + sanitizers diff --git a/doc/devdocs/object.rst b/doc/devdocs/object.rst index 38c31075ddc511..99137ea5be0947 100644 --- a/doc/devdocs/object.rst +++ b/doc/devdocs/object.rst @@ -43,7 +43,7 @@ the values can also be extracted directly as an array access:: As an example, a "boxed" :c:type:`uint16_t` is stored as follows:: struct { - oqaque metadata; + opaque metadata; struct { uint16_t data; -- 2 bytes } jl_value_t; diff --git a/doc/devdocs/promote-op.rst b/doc/devdocs/promote-op.rst deleted file mode 100644 index 53a5a937685498..00000000000000 --- a/doc/devdocs/promote-op.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. currentmodule:: Base - -.. _devdocs-promote-op: - -Operator-sensitive promotion -============================ - -In certain cases, the :ref:`simple rules for promotion -` may not be sufficient. For example, consider a -type that can represent an object with physical units, here restricted -to a single unit like "meter":: - - immutable MeterUnits{T,P} <: Number - val::T - end - MeterUnits{T}(val::T, pow::Int) = MeterUnits{T,pow}(val) - - m = MeterUnits(1.0, 1) # 1.0 meter, i.e. units of length - m2 = MeterUnits(1.0, 2) # 1.0 meter^2, i.e. units of area - -Now let's define the operations ``+`` and ``*`` for these objects: -``m+m`` should have the type of ``m`` but ``m*m`` should have the type -of ``m2``. When the result type depends on the operation, and not -just the input types, ``promote_rule`` will be inadequate. - -Fortunately, it's possible to provide such definitions via ``promote_op``:: - - Base.promote_op{R,S}(::typeof(+), ::Type{MeterUnits{R,1}}, ::Type{MeterUnits{S,1}}) = MeterUnits{promote_type(R,S),1} - Base.promote_op{R,S}(::typeof(*), ::Type{MeterUnits{R,1}}, ::Type{MeterUnits{S,1}}) = MeterUnits{promote_type(R,S),2} - Base.promote_op{R,S}(::typeof(.*), ::Type{MeterUnits{R,1}}, ::Type{MeterUnits{S,1}}) = MeterUnits{promote_type(R,S),2} - -The first one defines the promotion rule for ``+``, and the second one -for ``*``. - -It's worth noting that as julia's internal representation of functions -evolves, this interface may change in a future version of Julia. diff --git a/doc/devdocs/sanitizers.rst b/doc/devdocs/sanitizers.rst new file mode 100644 index 00000000000000..262e259825d5c4 --- /dev/null +++ b/doc/devdocs/sanitizers.rst @@ -0,0 +1,44 @@ +***************** +Sanitizer support +***************** + +General considerations +---------------------- + +Using Clang's sanitizers obviously require you to use Clang (``USECLANG=1``), but there's +another catch: most sanitizers require a run-time library, provided by the host compiler, +while the instrumented code generated by Julia's JIT relies on functionality from that +library. This implies that the LLVM version of your host compiler matches that of the LLVM +library used within Julia. + +An easy solution is to have an dedicated build folder for providing a matching toolchain, by +building with ``BUILD_LLVM_CLANG=1`` and overriding ``LLVM_USE_CMAKE=1`` (Autotool-based +builds are incompatible with ASAN). You can then refer to this toolchain from another build +folder by specifying ``USECLANG=1`` while overriding the ``CC`` and ``CXX`` variables. + + +Address Sanitizer (ASAN) +------------------------ + +For detecting or debugging memory bugs, you can use Clang's `address sanitizer (ASAN) +`_. By compiling with +``SANITIZE=1`` you enable ASAN for the Julia compiler and its generated code. In addition, +you can specify ``LLVM_SANITIZE=1`` to sanitize the LLVM library as well. Note that these +options incur a high performance and memory cost. For example, using ASAN for Julia and LLVM +makes ``testall1`` takes 8-10 times as long while using 20 times as much memory (this can +be reduced to respectively a factor of 3 and 4 by using the options described below). + +By default, Julia sets the ``allow_user_segv_handler=1`` ASAN flag, which is required for +signal delivery to work properly. You can define other options using the ``ASAN_OPTIONS`` +environment flag, in which case you'll need to repeat the default option mentioned before. +For example, memory usage can be reduced by specifying ``fast_unwind_on_malloc=0`` and +``malloc_context_size=2``, at the cost of backtrace accuracy. For now, Julia also sets +``detect_leaks=0``, but this should be removed in the future. + + +Memory Sanitizer (MSAN) +----------------------- + +For detecting use of uninitialized memory, you can use Clang's `memory sanitizer (MSAN) +`_ by compiling with +``SANITIZE_MEMORY=1``. diff --git a/doc/manual/conversion-and-promotion.rst b/doc/manual/conversion-and-promotion.rst index 61969179addc5e..f9cfd8fe3950f9 100644 --- a/doc/manual/conversion-and-promotion.rst +++ b/doc/manual/conversion-and-promotion.rst @@ -90,6 +90,16 @@ action: julia> typeof(ans) Float64 + julia> a = Any[1 2 3; 4 5 6] + 2×3 Array{Any,2}: + 1 2 3 + 4 5 6 + + julia> convert(Array{Float64}, a) + 2×3 Array{Float64,2}: + 1.0 2.0 3.0 + 4.0 5.0 6.0 + Conversion isn't always possible, in which case a no method error is thrown indicating that ``convert`` doesn't know how to perform the requested conversion: diff --git a/doc/manual/documentation.rst b/doc/manual/documentation.rst index a6d481f340a58f..b40dedf5038a01 100644 --- a/doc/manual/documentation.rst +++ b/doc/manual/documentation.rst @@ -441,6 +441,32 @@ Global Variables Adds docstring ``"..."`` to the ``Binding``\ s ``a``, ``b``, and ``c``. +.. note:: + + When a ``const`` definition is only used to define an alias of another definition, such + as is the case with the function ``div`` and its alias ``÷`` in ``Base``, do not + document the alias and instead document the actual function. + + If the alias is documented and not the real definition then the docsystem (``?`` mode) + will not return the docstring attached to the alias when the real definition is + searched for. + + For example you should write + + .. code-block:: julia + + "..." + f(x) = x + 1 + const alias = f + + rather than + + .. code-block:: julia + + f(x) = x + 1 + "..." + const alias = f + .. code-block:: julia "..." diff --git a/doc/manual/integers-and-floating-point-numbers.rst b/doc/manual/integers-and-floating-point-numbers.rst index 0c6f3cf304f0b0..136e5e92e463f6 100644 --- a/doc/manual/integers-and-floating-point-numbers.rst +++ b/doc/manual/integers-and-floating-point-numbers.rst @@ -505,14 +505,17 @@ Rounding modes If a number doesn't have an exact floating-point representation, it must be rounded to an appropriate representable value, however, if wanted, the manner in which this rounding is done can be changed according to the rounding modes -presented in the `IEEE 754 standard `_:: +presented in the `IEEE 754 standard `_. +.. doctest:: + + julia> x = 1.1; y = 0.1; - julia> 1.1 + 0.1 + julia> x + y 1.2000000000000002 julia> setrounding(Float64,RoundDown) do - 1.1 + 0.1 + x + y end 1.2 diff --git a/doc/manual/interfaces.rst b/doc/manual/interfaces.rst index 22b1e808c946f2..fc8fbf349f1225 100644 --- a/doc/manual/interfaces.rst +++ b/doc/manual/interfaces.rst @@ -66,7 +66,7 @@ A simple example is an iterable sequence of square numbers with a defined length end Base.start(::Squares) = 1 Base.next(S::Squares, state) = (state*state, state+1) - Base.done(S::Squares, s) = s > S.count; + Base.done(S::Squares, state) = state > S.count; Base.eltype(::Type{Squares}) = Int # Note that this is defined for the type Base.length(S::Squares) = S.count; diff --git a/doc/manual/mathematical-operations.rst b/doc/manual/mathematical-operations.rst index c7925dea544e6d..36fba25e8c46fe 100644 --- a/doc/manual/mathematical-operations.rst +++ b/doc/manual/mathematical-operations.rst @@ -427,7 +427,7 @@ The following examples show the different forms. julia> round(Int8,127.6) ERROR: InexactError() - in trunc(::Type{Int8}, ::Float64) at ./float.jl:456 + in trunc(::Type{Int8}, ::Float64) at ./float.jl:458 in round(::Type{Int8}, ::Float64) at ./float.jl:211 ... diff --git a/doc/manual/modules.rst b/doc/manual/modules.rst index aab14db34fb528..72241c2ea00a79 100644 --- a/doc/manual/modules.rst +++ b/doc/manual/modules.rst @@ -36,7 +36,7 @@ not meant to be run, but is shown for illustrative purposes:: bar(x) = 2x foo(a::MyType) = bar(a.x) + 1 - show(io, a::MyType) = print(io, "MyType $(a.x)") + show(io::IO, a::MyType) = print(io, "MyType $(a.x)") end Note that the style is not to indent the body of the module, since diff --git a/doc/stdlib/collections.rst b/doc/stdlib/collections.rst index 59abf1b78aba23..3c2eac2380a99c 100644 --- a/doc/stdlib/collections.rst +++ b/doc/stdlib/collections.rst @@ -81,7 +81,7 @@ type. .. Docstring generated from Julia source - An iterator that yields ``(i, x)`` where ``i`` is an index starting at 1, and ``x`` is the ``i``\ th value from the given iterator. It's useful when you need not only the values ``x`` over which you are iterating, but also the index ``i`` of the iterations. + An iterator that yields ``(i, x)`` where ``i`` is a counter starting at 1, and ``x`` is the ``i``\ th value from the given iterator. It's useful when you need not only the values ``x`` over which you are iterating, but also the number of iterations so far. Note that ``i`` may not be valid for indexing ``iter``\ ; it's also possible that ``x != iter[i]``\ , if ``iter`` has indices that do not start at 1. .. doctest:: diff --git a/doc/stdlib/io-network.rst b/doc/stdlib/io-network.rst index 4e747354dda2a4..67a1b123c57b6a 100644 --- a/doc/stdlib/io-network.rst +++ b/doc/stdlib/io-network.rst @@ -134,7 +134,7 @@ General I/O Write the canonical binary representation of a value to the given I/O stream or file. Returns the number of bytes written into the stream. - You can write multiple values with the same :func:``write`` call. i.e. the following are equivalent: + You can write multiple values with the same ``write`` call. i.e. the following are equivalent: .. code-block:: julia diff --git a/doc/stdlib/math.rst b/doc/stdlib/math.rst index cf4a4ad72312de..206f9e38733f79 100644 --- a/doc/stdlib/math.rst +++ b/doc/stdlib/math.rst @@ -284,7 +284,7 @@ Mathematical Operators .. Docstring generated from Julia source - Unsigned right bit shift operator, ``x >>> n``\ . For ``n >= 0``\ , the result is ``x`` shifted right by ``n`` bits, where ``n >= 0``\ , filling with ``0``\ s. For ``n < 0``\ , this is equivalent to ``x [<<](:func:``\ <<``) -n``\ ]. + Unsigned right bit shift operator, ``x >>> n``\ . For ``n >= 0``\ , the result is ``x`` shifted right by ``n`` bits, where ``n >= 0``\ , filling with ``0``\ s. For ``n < 0``\ , this is equivalent to ``x << -n``\ . For ``Unsigned`` integer types, this is equivalent to :func:`>>`\ . For ``Signed`` integer types, this is equivalent to ``signed(unsigned(x) >> n)``\ . diff --git a/doc/stdlib/numbers.rst b/doc/stdlib/numbers.rst index ae1d47fa34c5fd..1d89e90c5db580 100644 --- a/doc/stdlib/numbers.rst +++ b/doc/stdlib/numbers.rst @@ -371,10 +371,14 @@ General Number Functions and Constants .. Docstring generated from Julia source - Set the rounding mode of floating point type ``T``\ , controlling the rounding of basic arithmetic functions (:func:`+`\ , :func:`-`\ , :func:`*`\ , :func:`/` and :func:`sqrt`\ ) and type conversion. + Set the rounding mode of floating point type ``T``\ , controlling the rounding of basic arithmetic functions (:func:`+`\ , :func:`-`\ , :func:`*`\ , :func:`/` and :func:`sqrt`\ ) and type conversion. Other numerical functions may give incorrect or invalid values when using rounding modes other than the default ``RoundNearest``\ . Note that this may affect other types, for instance changing the rounding mode of ``Float64`` will change the rounding mode of ``Float32``\ . See :obj:`RoundingMode` for available modes. + .. warning:: + This feature is still experimental, and may give unexpected or incorrect values. + + .. function:: setrounding(f::Function, T, mode) .. Docstring generated from Julia source @@ -390,6 +394,28 @@ General Number Functions and Constants See :obj:`RoundingMode` for available rounding modes. + .. warning:: + This feature is still experimental, and may give unexpected or incorrect values. A known problem is the interaction with compiler optimisations, e.g. + + .. code-block:: julia + + julia> setrounding(Float64,RoundDown) do + 1.1 + 0.1 + end + 1.2000000000000002 + + Here the compiler is *constant folding*, that is evaluating a known constant expression at compile time, however the rounding mode is only changed at runtime, so this is not reflected in the function result. This can be avoided by moving constants outside the expression, e.g. + + .. code-block:: julia + + julia> x = 1.1; y = 0.1; + + julia> setrounding(Float64,RoundDown) do + x + y + end + 1.2 + + .. function:: get_zero_subnormals() -> Bool .. Docstring generated from Julia source diff --git a/doc/stdlib/strings.rst b/doc/stdlib/strings.rst index ff929e55114c2e..bfb8999981544c 100644 --- a/doc/stdlib/strings.rst +++ b/doc/stdlib/strings.rst @@ -259,7 +259,7 @@ .. Docstring generated from Julia source - Return an array of substrings by splitting the given string on occurrences of the given character delimiters, which may be specified in any of the formats allowed by ``search``\ 's second argument (i.e. a single character, collection of characters, string, or regular expression). If ``chars`` is omitted, it defaults to the set of all space characters, and ``keep`` is taken to be ``false``\ . The two keyword arguments are optional: they are are a maximum size for the result and a flag determining whether empty fields should be kept in the result. + Return an array of substrings by splitting the given string on occurrences of the given character delimiters, which may be specified in any of the formats allowed by ``search``\ 's second argument (i.e. a single character, collection of characters, string, or regular expression). If ``chars`` is omitted, it defaults to the set of all space characters, and ``keep`` is taken to be ``false``\ . The two keyword arguments are optional: they are a maximum size for the result and a flag determining whether empty fields should be kept in the result. .. function:: rsplit(string, [chars]; limit=0, keep=true) diff --git a/src/Makefile b/src/Makefile index ebf8219150674c..d7ec864f27e42a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -123,8 +123,26 @@ $(BUILDDIR)/%.dbg.obj: $(SRCDIR)/%.cpp $(SRCDIR)/llvm-version.h $(HEADERS) $(LLV @$(call PRINT_CC, $(CXX) $(shell $(LLVM_CONFIG_HOST) --cxxflags) $(CPPFLAGS) $(CXXFLAGS) $(DEBUGFLAGS) -c $< -o $@) libccalltest: $(build_shlibdir)/libccalltest.$(SHLIB_EXT) + +ifeq ($(OS), Linux) +JULIA_SPLITDEBUG := 1 +else +JULIA_SPLITDEBUG := 0 +endif $(build_shlibdir)/libccalltest.$(SHLIB_EXT): $(SRCDIR)/ccalltest.c - @$(call PRINT_CC, $(CC) $(CFLAGS) $(CPPFLAGS) $(DEBUGFLAGS) -O3 $< $(fPIC) -shared -o $@ $(LDFLAGS)) + @$(call PRINT_CC, $(CC) $(CFLAGS) $(CPPFLAGS) $(DEBUGFLAGS) -O3 $< $(fPIC) -shared -o $@.tmp $(LDFLAGS)) +ifeq ($(JULIA_SPLITDEBUG),1) + @# Create split debug info file for libccalltest stacktraces test + @# packagers should disable this by setting JULIA_SPLITDEBUG=0 if this is already done by your build system + $(OBJCOPY) --only-keep-debug $@.tmp $@.debug + $(OBJCOPY) --strip-debug $@.tmp + $(OBJCOPY) --add-gnu-debuglink=$@.debug $@.tmp +endif + @## clang should have made the dSYM split-debug directory, + @## but we are intentionally not going to give it the correct name + @## because we want to test the non-default debug configuration + @#rm -r $@.dSYM && mv $@.tmp.dSYM $@.dSYM + mv $@.tmp $@ julia_flisp.boot.inc.phony: $(BUILDDIR)/julia_flisp.boot.inc @@ -220,9 +238,11 @@ ifneq ($(OS), WINNT) @ln -sf libjulia-debug.$(JL_MAJOR_MINOR_SHLIB_EXT) $(build_shlibdir)/libjulia-debug.$(SHLIB_EXT) endif $(DSYMUTIL) $@ + $(BUILDDIR)/libjulia-debug.a: $(SRCDIR)/julia.expmap $(DOBJS) $(BUILDDIR)/flisp/libflisp-debug.a $(BUILDDIR)/support/libsupport-debug.a rm -f $@ @$(call PRINT_LINK, ar -rcs $@ $(DOBJS)) + libjulia-debug: $(build_shlibdir)/libjulia-debug.$(JL_MAJOR_MINOR_SHLIB_EXT) $(build_shlibdir)/libjulia.$(JL_MAJOR_MINOR_SHLIB_EXT): $(SRCDIR)/julia.expmap $(OBJS) $(BUILDDIR)/flisp/libflisp.a $(BUILDDIR)/support/libsupport.a $(LIBUV) @@ -233,6 +253,7 @@ ifneq ($(OS), WINNT) @ln -sf libjulia.$(JL_MAJOR_MINOR_SHLIB_EXT) $(build_shlibdir)/libjulia.$(SHLIB_EXT) endif $(DSYMUTIL) $@ + $(BUILDDIR)/libjulia.a: julia.expmap $(OBJS) $(BUILDDIR)/flisp/libflisp.a $(BUILDDIR)/support/libsupport.a rm -f $@ @$(call PRINT_LINK, ar -rcs $@ $(OBJS)) diff --git a/src/ccalltest.c b/src/ccalltest.c index e01aafa300fb26..ccd7e1cd57fdea 100644 --- a/src/ccalltest.c +++ b/src/ccalltest.c @@ -21,6 +21,7 @@ int verbose = 1; int c_int = 0; + ////////////////////////////////// // Test for proper argument register truncation @@ -520,6 +521,7 @@ JL_DLLEXPORT void finalizer_cptr(void* v) set_c_int(-1); } + ////////////////////////////////// // Turn off verbose for automated tests, leave on for debugging @@ -527,6 +529,10 @@ JL_DLLEXPORT void set_verbose(int level) { verbose = level; } + +////////////////////////////////// +// Other tests + JL_DLLEXPORT void *test_echo_p(void *p) { return p; } @@ -723,3 +729,7 @@ JL_DLLEXPORT float32x4_t test_ppc64_vec2(int64_t d1, float32x4_t a, float32x4_t } #endif + +JL_DLLEXPORT int threadcall_args(int a, int b) { + return a + b; +} diff --git a/src/cgmemmgr.cpp b/src/cgmemmgr.cpp index 5c3b187ecab251..a85dfa57a227bf 100644 --- a/src/cgmemmgr.cpp +++ b/src/cgmemmgr.cpp @@ -47,7 +47,7 @@ static void *map_anon_page(size_t size) mem = (char*)LLT_ALIGN(uintptr_t(mem), jl_page_size); #else // _OS_WINDOWS_ void *mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, - MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); assert(mem != MAP_FAILED && "Cannot allocate RW memory"); #endif // _OS_WINDOWS_ return mem; diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 9ad239345595d2..4a93d229b6df75 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -96,7 +96,18 @@ static DIType julia_type_to_di(jl_value_t *jt, DIBuilder *dbuilder, bool isboxed jl_datatype_t *jdt = (jl_datatype_t*)jt; if (jdt->ditype != NULL) { #ifdef LLVM37 - return (llvm::DIType*)jdt->ditype; + DIType* t = (DIType*)jdt->ditype; +#ifndef LLVM39 + // On LLVM 3.7 and 3.8, DICompositeType with a unique name + // are ref'd by their unique name and needs to be explicitly + // retained in order to be used in the module. + if (auto *Composite = dyn_cast(t)) { + if (Composite->getRawIdentifier()) { + dbuilder->retainType(Composite); + } + } +#endif + return t; #else return DIType((llvm::MDNode*)jdt->ditype); #endif @@ -130,17 +141,22 @@ static DIType julia_type_to_di(jl_value_t *jt, DIBuilder *dbuilder, bool isboxed else if (jl_is_structtype(jt)) { jl_datatype_t *jst = (jl_datatype_t*)jt; size_t ntypes = jl_datatype_nfields(jst); + const char *tname = jl_symbol_name(jdt->name->name); + std::stringstream unique_name; + unique_name << tname << "_" << globalUnique++; llvm::DICompositeType *ct = dbuilder->createStructType( NULL, // Scope - jl_symbol_name(jdt->name->name), // Name + tname, // Name NULL, // File 0, // LineNumber 8 * jdt->size, // SizeInBits - 8 * jdt->layout->alignment, // AlignmentInBits + 8 * jdt->layout->alignment, // AlignInBits 0, // Flags NULL, // DerivedFrom DINodeArray(), // Elements - dwarf::DW_LANG_Julia // RuntimeLanguage + dwarf::DW_LANG_Julia, // RuntimeLanguage + nullptr, // VTableHolder + unique_name.str() // UniqueIdentifier ); jdt->ditype = ct; std::vector Elements; diff --git a/src/codegen.cpp b/src/codegen.cpp index 55b8aafba01180..db21394b3e61c7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -87,6 +87,7 @@ #if defined(_CPU_ARM_) || defined(_CPU_AARCH64_) # include +# include #endif #if defined(USE_POLLY) #include @@ -4745,6 +4746,8 @@ static std::unique_ptr emit_function(jl_lambda_info_t *lam, jl_llvm_func } } + builder.ClearInsertionPoint(); + // step 14, Apply LLVM level inlining for(std::vector::iterator it = ctx.to_inline.begin(); it != ctx.to_inline.end(); ++it) { Function *inlinef = (*it)->getCalledFunction(); @@ -5560,10 +5563,68 @@ static void init_julia_llvm_env(Module *m) addOptimizationPasses(jl_globalPM); } +static inline std::string getNativeTarget() +{ + std::string cpu = sys::getHostCPUName(); +#if defined(_CPU_ARM_) + // Try slightly harder than LLVM at determine the CPU architecture. + if (cpu == "generic") { + // This is the most reliable way I can find + // `/proc/cpuinfo` changes between kernel versions + struct utsname name; + if (uname(&name) >= 0) { + // name.machine is the elf_platform in the kernel. + if (strcmp(name.machine, "armv6l") == 0) { + return "armv6"; + } + if (strcmp(name.machine, "armv7l") == 0) { + return "armv7"; + } + if (strcmp(name.machine, "armv7ml") == 0) { + // Thumb + return "armv7-m"; + } + if (strcmp(name.machine, "armv8l") == 0 || + strcmp(name.machine, "aarch64") == 0) { + return "armv8"; + } + } + } +#endif + return cpu; +} + +#if defined(_CPU_ARM_) || defined(_CPU_AARCH64_) +// Check if the cpu name is a ARM/AArch64 arch name and return a +// string that can be used as LLVM feature name +static inline std::string checkARMArchFeature(const std::string &cpu) +{ + const char *prefix = "armv"; + size_t prefix_len = strlen(prefix); + if (cpu.size() <= prefix_len || + memcmp(cpu.data(), prefix, prefix_len) != 0 || + cpu[prefix_len] < '1' || cpu[prefix_len] > '9') + return std::string(); +#if defined(_CPU_ARM_) + // "v7" and "v8" are not available in the form of `armv*` + // in the feature list + if (cpu == "armv7") { + return "v7"; + } + else if (cpu == "armv8") { + return "v8"; + } + return cpu; +#else + return cpu.substr(3); +#endif +} +#endif + // Helper to figure out what features to set for the LLVM target // If the user specifies native (or does not specify) we default // using the API provided by LLVM -static inline SmallVector getTargetFeatures() +static inline SmallVector getTargetFeatures(std::string &cpu) { StringMap HostFeatures; if (!strcmp(jl_options.cpu_target,"native")) { @@ -5592,16 +5653,63 @@ static inline SmallVector getTargetFeatures() #endif // Figure out if we know the cpu_target - std::string cpu = strcmp(jl_options.cpu_target,"native") ? jl_options.cpu_target : sys::getHostCPUName(); - if (cpu.empty() || cpu == "generic") { - jl_printf(JL_STDERR, "WARNING: unable to determine host cpu name.\n"); -#if defined(_CPU_ARM_) && defined(__ARM_PCS_VFP) - // Check if this is required when you have read the features directly from the processor - // This affects the platform calling convention. - // TODO: enable vfp3 for ARMv7+ (but adapt the ABI) - HostFeatures["vfp2"] = true; -#endif + cpu = (strcmp(jl_options.cpu_target,"native") ? jl_options.cpu_target : + getNativeTarget()); +#if defined(_CPU_ARM_) + // Figure out what we are compiling against from the C defines. + // This might affect ABI but is fine since + // 1. We define the C ABI explicitly. + // 2. This does not change when running the same binary on different + // machines. + // This shouldn't affect making generic binaries since that requires a + // generic C -march anyway. + HostFeatures["vfp2"] = true; + + // Arch version +#if __ARM_ARCH >= 8 + HostFeatures["v8"] = true; +#elif __ARM_ARCH >= 7 + HostFeatures["v7"] = true; +#else + // minimum requirement + HostFeatures["v6"] = true; +#endif + + // ARM profile + // Only do this on ARM and not AArch64 since LLVM aarch64 backend + // doesn't support setting profiles. + // AFAIK there's currently no 64bit R and M profile either + // (v8r and v8m are both 32bit) +#if defined(__ARM_ARCH_PROFILE) +# if __ARM_ARCH_PROFILE == 'A' + HostFeatures["aclass"] = true; +# elif __ARM_ARCH_PROFILE == 'R' + HostFeatures["rclass"] = true; +# elif __ARM_ARCH_PROFILE == 'M' + // Thumb + HostFeatures["mclass"] = true; +# endif +#endif +#endif // _CPU_ARM_ + + // On ARM and AArch64, allow using cpu_target to specify a CPU architecture + // which is specified in the feature set in LLVM. +#if defined(_CPU_ARM_) || defined(_CPU_AARCH64_) + // Supported ARM arch names on LLVM 3.8: + // armv6, armv6-m, armv6j, armv6k, armv6kz, armv6s-m, armv6t2, + // armv7, armv7-a, armv7-m, armv7-r, armv7e-m, armv7k, armv7s, + // armv8, armv8-a, armv8.1-a, armv8.2-a + // Additional ARM arch names on LLVM 3.9: + // armv8-m.base, armv8-m.main + // + // Supported AArch64 arch names on LLVM 3.8: + // armv8.1a, armv8.2a + std::string arm_arch = checkARMArchFeature(cpu); + if (!arm_arch.empty()) { + HostFeatures[arm_arch] = true; + cpu = "generic"; } +#endif SmallVector attr; for (StringMap::const_iterator it = HostFeatures.begin(); it != HostFeatures.end(); it++) { @@ -5718,8 +5826,8 @@ extern "C" void jl_init_codegen(void) TheTriple.setEnvironment(Triple::ELF); #endif #endif - std::string TheCPU = strcmp(jl_options.cpu_target,"native") ? jl_options.cpu_target : sys::getHostCPUName(); - SmallVector targetFeatures = getTargetFeatures( ); + std::string TheCPU; + SmallVector targetFeatures = getTargetFeatures(TheCPU); jl_TargetMachine = eb.selectTarget( TheTriple, "", diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index b61abe00e817cb..6d0ef5b01660c6 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -29,14 +29,10 @@ #else #include #endif -#ifdef _OS_DARWIN_ #include -#endif -#ifdef _OS_WINDOWS_ #include -# ifdef LLVM37 -# include -# endif +#ifdef LLVM37 +# include #endif #if defined(USE_MCJIT) && !defined(LLVM36) && defined(_OS_DARWIN_) @@ -666,10 +662,19 @@ static int lookup_pointer(DIContext *context, jl_frame_t **frames, // This function is not allowed to reference any TLS variables // since it can be called from an unmanaged thread on OSX. if (!context) { - if (demangle && (*frames)[0].func_name != NULL) { - char *oldname = (*frames)[0].func_name; - (*frames)[0].func_name = jl_demangle(oldname); - free(oldname); + if (demangle) { + if ((*frames)[0].func_name != NULL) { + char *oldname = (*frames)[0].func_name; + (*frames)[0].func_name = jl_demangle(oldname); + free(oldname); + } + else { + // We do this to hide the jlcall wrappers when getting julia backtraces, + // but it is still good to have them for regular lookup of C frames. + // Technically not true, but we don't want them + // in julia backtraces, so close enough + (*frames)[0].fromC = 1; + } } return 1; } @@ -686,6 +691,9 @@ static int lookup_pointer(DIContext *context, jl_frame_t **frames, int fromC = (*frames)[0].fromC; int n_frames = inlineInfo.getNumberOfFrames(); + if (n_frames == 0) + // no line number info available in the context, return without the context + return lookup_pointer(NULL, frames, pointer, demangle, noInline); if (noInline) n_frames = 1; if (n_frames > 1) { @@ -748,6 +756,8 @@ static int lookup_pointer(DIContext *context, jl_frame_t **frames, #ifdef _OS_DARWIN_ #include +#else +#define LC_UUID 0 #endif #ifndef _OS_WINDOWS_ #include @@ -761,11 +771,10 @@ typedef struct { typedef std::map obfiletype; static obfiletype objfilemap; -#ifdef _OS_DARWIN_ static bool getObjUUID(llvm::object::MachOObjectFile *obj, uint8_t uuid[16]) { # ifdef LLVM37 - for (auto Load : obj->load_commands ()) { + for (auto Load : obj->load_commands()) # else # ifdef LLVM35 uint32_t LoadCommandCount = obj->getHeader().ncmds; @@ -773,8 +782,9 @@ static bool getObjUUID(llvm::object::MachOObjectFile *obj, uint8_t uuid[16]) uint32_t LoadCommandCount = obj->getHeader().NumLoadCommands; # endif llvm::object::MachOObjectFile::LoadCommandInfo Load = obj->getFirstLoadCommandInfo(); - for (unsigned I = 0; ; ++I) { + for (unsigned I = 0; ; ++I) # endif + { if ( # ifdef LLVM35 Load.C.cmd == LC_UUID @@ -782,7 +792,7 @@ static bool getObjUUID(llvm::object::MachOObjectFile *obj, uint8_t uuid[16]) Load.C.Type == LC_UUID # endif ) { - memcpy(uuid,((MachO::uuid_command*)Load.Ptr)->uuid,16); + memcpy(uuid, ((const MachO::uuid_command*)Load.Ptr)->uuid, 16); return true; } # ifndef LLVM37 @@ -796,6 +806,136 @@ static bool getObjUUID(llvm::object::MachOObjectFile *obj, uint8_t uuid[16]) } return false; } + +#ifdef LLVM36 +struct debug_link_info { + StringRef filename; + uint32_t crc32; +}; +static debug_link_info getDebuglink(const object::ObjectFile &Obj) +{ + debug_link_info info = {}; + for (const object::SectionRef &Section: Obj.sections()) { + StringRef sName; + if (!Section.getName(sName) && sName == ".gnu_debuglink") { + StringRef Contents; + if (!Section.getContents(Contents)) { + size_t length = Contents.find('\0'); + info.filename = Contents.substr(0, length); + info.crc32 = *(const uint32_t*)Contents.substr(LLT_ALIGN(length + 1, 4), 4).data(); + break; + } + } + } + return info; +} +/* + * crc function from http://svnweb.freebsd.org/base/head/sys/libkern/crc32.c (and lldb) + * + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ +static uint32_t +calc_gnu_debuglink_crc32(const void *buf, size_t size) +{ + static const uint32_t g_crc32_tab[] = + { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; + const uint8_t *p = (const uint8_t *)buf; + uint32_t crc; + + crc = ~0U; + while (size--) + crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + return crc ^ ~0U; +} + +#ifdef LLVM39 +static Expected> +#else +static ErrorOr> +#endif +openDebugInfo(StringRef debuginfopath, const debug_link_info &info) +{ + auto SplitFile = MemoryBuffer::getFile(debuginfopath); + if (std::error_code EC = SplitFile.getError()) { +#ifdef LLVM39 + return errorCodeToError(EC); +#else + return EC; +#endif + } + + uint32_t crc32 = calc_gnu_debuglink_crc32( + SplitFile.get()->getBufferStart(), + SplitFile.get()->getBufferSize()); + if (crc32 != info.crc32) { +#ifdef LLVM39 + return errorCodeToError(object::object_error::arch_not_found); +#else + return object::object_error::arch_not_found; +#endif + } + + auto error_splitobj = object::ObjectFile::createObjectFile( + SplitFile.get().get()->getMemBufferRef(), + sys::fs::file_magic::unknown); + if (!error_splitobj) { +#ifdef LLVM39 + return error_splitobj.takeError(); +#else + return error_splitobj.getError(); +#endif + } + + // successfully validated and loaded split debug info file + return object::OwningBinary( + std::move(error_splitobj.get()), + std::move(SplitFile.get())); +} #endif static uint64_t jl_sysimage_base; @@ -810,6 +950,15 @@ extern "C" void jl_register_fptrs(uint64_t sysimage_base, void **fptrs, jl_lambd sysimg_fvars_n = n; } +template +static inline void ignoreError(T &err) +{ +#if defined(LLVM39) && !defined(NDEBUG) + consumeError(err.takeError()); +#endif +} + +extern "C" void jl_refresh_dbg_module_list(void); bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj, llvm::DIContext **context, int64_t *slide, int64_t *section_slide, bool onlySysImg, bool *isSysImg, void **saddr, char **name, char **filename) { @@ -817,55 +966,58 @@ bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj, *context = NULL; *slide = 0; *section_slide = 0; + // GOAL: Determine containing Library -// Assigning fname, fbase, msize +// Assigning fname, fbase #ifdef _OS_WINDOWS_ IMAGEHLP_MODULE64 ModuleInfo; - bool isvalid; ModuleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); + jl_refresh_dbg_module_list(); jl_in_stackwalk = 1; - isvalid = SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)pointer, &ModuleInfo); + bool isvalid = SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)pointer, &ModuleInfo); jl_in_stackwalk = 0; - if (isvalid) { - char *fname = ModuleInfo.LoadedImageName; - if (!fname[0]) // empirically, LoadedImageName might be missing - fname = ModuleInfo.ImageName; - DWORD64 fbase = ModuleInfo.BaseOfImage; - bool insysimage = (fbase == jl_sysimage_base); - if (isSysImg) - *isSysImg = insysimage; - if (onlySysImg && !insysimage) { - return false; - } - static char frame_info_func[ - sizeof(SYMBOL_INFO) + - MAX_SYM_NAME * sizeof(TCHAR)]; - DWORD64 dwDisplacement64 = 0; - DWORD64 dwAddress = pointer; - PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)frame_info_func; - pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); - pSymbol->MaxNameLen = MAX_SYM_NAME; - jl_in_stackwalk = 1; - if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement64, - pSymbol)) { - // SymFromAddr returned success - // errors are ignored, but are hopefully patched up by - // using llvm to read the object (below) - if (name) - jl_copy_str(name, pSymbol->Name); - if (saddr) - *saddr = (void*)(uintptr_t)pSymbol->Address; - } - else if (saddr) { - *saddr = NULL; - } + if (!isvalid) return false; + + StringRef fname = ModuleInfo.LoadedImageName; + if (fname.empty()) // empirically, LoadedImageName might be missing + fname = ModuleInfo.ImageName; + DWORD64 fbase = ModuleInfo.BaseOfImage; + bool insysimage = (fbase == jl_sysimage_base); + if (isSysImg) + *isSysImg = insysimage; + if (onlySysImg && !insysimage) { + return false; + } + static char frame_info_func[ + sizeof(SYMBOL_INFO) + + MAX_SYM_NAME * sizeof(TCHAR)]; + DWORD64 dwDisplacement64 = 0; + DWORD64 dwAddress = pointer; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)frame_info_func; + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + jl_in_stackwalk = 1; + if (SymFromAddr(GetCurrentProcess(), dwAddress, &dwDisplacement64, + pSymbol)) { + // SymFromAddr returned success + // errors are ignored, but are hopefully patched up by + // using llvm to read the object (below) + if (name) + jl_copy_str(name, pSymbol->Name); + if (saddr) + *saddr = (void*)(uintptr_t)pSymbol->Address; + } + else if (saddr) { + *saddr = NULL; + } - // If we didn't find the filename before in the debug - // info, use the dll name - if (filename && !*filename) - jl_copy_str(filename, fname); + // If we didn't find the filename before in the debug + // info, use the dll name + if (filename && !*filename) + jl_copy_str(filename, fname.data()); + + jl_in_stackwalk = 0; - jl_in_stackwalk = 0; #else // ifdef _OS_WINDOWS_ Dl_info dlinfo; int dladdr_success; @@ -876,201 +1028,249 @@ bool jl_dylib_DI_for_fptr(size_t pointer, const llvm::object::ObjectFile **obj, #else dladdr_success = dladdr((void*)pointer, &dlinfo) != 0; #endif + if (!dladdr_success || !dlinfo.dli_fname) + return false; - if (dladdr_success && dlinfo.dli_fname) { #ifdef __GLIBC__ - // dlinfo.dli_fbase is not the right value for the main executable on linux - fbase = (uintptr_t)extra_info->l_addr; + // dlinfo.dli_fbase is not the right value for the main executable on linux + fbase = (uintptr_t)extra_info->l_addr; #else - fbase = (uintptr_t)dlinfo.dli_fbase; -#endif - const char *fname; - if (saddr) - *saddr = dlinfo.dli_saddr; + fbase = (uintptr_t)dlinfo.dli_fbase; +#endif + StringRef fname; + if (saddr) + *saddr = dlinfo.dli_saddr; + bool insysimage = (fbase == jl_sysimage_base); + if (isSysImg) + *isSysImg = insysimage; + if (onlySysImg && !insysimage) { + return false; + } + // In case we fail with the debug info lookup, we at least still + // have the function name, even if we don't have line numbers + if (name) + jl_copy_str(name, dlinfo.dli_sname); + if (filename) + jl_copy_str(filename, dlinfo.dli_fname); + fname = dlinfo.dli_fname; +#endif // ifdef _OS_WINDOWS_ + + int isdarwin = 0, islinux = 0, iswindows = 0; #if defined(_OS_DARWIN_) - size_t msize = (size_t)(((uint64_t)-1)-fbase); + isdarwin = 1; +#elif defined(_OS_LINUX_) || defined(_OS_FREEBSD_) + islinux = 1; +#elif defined(_OS_WINDOWS_) + iswindows = 1; +#endif + +#ifndef LLVM35 + if (iswindows) { + return true; + } #endif - bool insysimage = (fbase == jl_sysimage_base); - if (isSysImg) - *isSysImg = insysimage; - if (onlySysImg && !insysimage) { - return false; - } - // In case we fail with the debug info lookup, we at least still - // have the function name, even if we don't have line numbers - if (name) - jl_copy_str(name, dlinfo.dli_sname); - if (filename) - jl_copy_str(filename, dlinfo.dli_fname); - fname = dlinfo.dli_fname; -#endif // ifdef _OS_WINDOWS_ // GOAL: Read debuginfo from file -#if !defined(_OS_WINDOWS_) || defined(LLVM35) - // TODO: need read/write lock here for objfilemap synchronization - obfiletype::iterator it = objfilemap.find(fbase); - if (it != objfilemap.end()) { - // Return cached value - *obj = it->second.obj; - *context = it->second.ctx; - *slide = it->second.slide; - *section_slide = it->second.section_slide; - } - else { + // TODO: need read/write lock here for objfilemap synchronization + obfiletype::iterator it = objfilemap.find(fbase); + if (it != objfilemap.end()) { + // Return cached value + *obj = it->second.obj; + *context = it->second.ctx; + *slide = it->second.slide; + *section_slide = it->second.section_slide; + return true; + } + // GOAL: Assign errorobj -#if defined(_OS_DARWIN_) + StringRef objpath; + std::string debuginfopath; + uint8_t uuid[16], uuid2[16]; + if (isdarwin) { + size_t msize = (size_t)(((uint64_t)-1) - fbase); #ifdef LLVM36 - std::unique_ptr membuf = MemoryBuffer::getMemBuffer( - StringRef((const char *)fbase, msize), "", false); - auto origerrorobj = llvm::object::ObjectFile::createObjectFile( - membuf->getMemBufferRef(), sys::fs::file_magic::unknown); -#elif defined(LLVM35) - MemoryBuffer *membuf = MemoryBuffer::getMemBuffer( - StringRef((const char *)fbase, msize), "", false); - std::unique_ptr buf(membuf); - auto origerrorobj = llvm::object::ObjectFile::createObjectFile( - buf, sys::fs::file_magic::unknown); -#else - MemoryBuffer *membuf = MemoryBuffer::getMemBuffer( + std::unique_ptr membuf = MemoryBuffer::getMemBuffer( StringRef((const char *)fbase, msize), "", false); - llvm::object::ObjectFile *origerrorobj = llvm::object::ObjectFile::createObjectFile( - membuf); -#endif - if (!origerrorobj) { - objfileentry_t entry = {*obj,*context,*slide,*section_slide}; - objfilemap[fbase] = entry; - return true; - } - -#ifdef LLVM36 - *obj = (llvm::object::MachOObjectFile *)origerrorobj.get().release(); + auto origerrorobj = llvm::object::ObjectFile::createObjectFile( + membuf->getMemBufferRef(), sys::fs::file_magic::unknown); #elif defined(LLVM35) - *obj = (llvm::object::MachOObjectFile *)origerrorobj.get(); + MemoryBuffer *membuf = MemoryBuffer::getMemBuffer( + StringRef((const char *)fbase, msize), "", false); + std::unique_ptr buf(membuf); + auto origerrorobj = llvm::object::ObjectFile::createObjectFile( + buf, sys::fs::file_magic::unknown); #else - *obj = (llvm::object::MachOObjectFile *)origerrorobj; + MemoryBuffer *membuf = MemoryBuffer::getMemBuffer( + StringRef((const char *)fbase, msize), "", false); + std::unique_ptr origerrorobj(llvm::object::ObjectFile::createObjectFile( + membuf)); #endif - llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile *)*obj; - - - // First find the uuid of the object file (we'll use this to make sure we find the - // correct debug symbol file). - uint8_t uuid[16], uuid2[16]; - if (!getObjUUID(morigobj,uuid)) { - objfileentry_t entry = {*obj,*context,*slide,*section_slide}; - objfilemap[fbase] = entry; - return true; - } + if (!origerrorobj) { + objfileentry_t entry = {}; + objfilemap[fbase] = entry; + return true; + } - // On OS X debug symbols are not contained in the dynamic library and that's why - // we can't have nice things (easily). For now we only support .dSYM files in the same directory - // as the shared library. In the future we may use DBGCopyFullDSYMURLForUUID from CoreFoundation to make - // use of spotlight to find the .dSYM file. - char dsympath[PATH_MAX]; - strlcpy(dsympath, fname, sizeof(dsympath)); - strlcat(dsympath, ".dSYM/Contents/Resources/DWARF/", sizeof(dsympath)); - strlcat(dsympath, strrchr(fname,'/')+1, sizeof(dsympath)); -#ifdef LLVM35 - auto errorobj = llvm::object::ObjectFile::createObjectFile(dsympath); + llvm::object::MachOObjectFile *morigobj = (llvm::object::MachOObjectFile*) +#ifdef LLVM36 + origerrorobj.get().get(); #else - llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(dsympath); + origerrorobj.get(); #endif -#else // ifndef _OS_DARWIN_ + // First find the uuid of the object file (we'll use this to make sure we find the + // correct debug symbol file). + if (!getObjUUID(morigobj, uuid)) { + objfileentry_t entry = {}; + objfilemap[fbase] = entry; + return true; + } - // On Linux systems we need to mmap another copy because of the permissions on the mmap'ed shared library. - // On Windows we need to mmap another copy since reading the in-memory copy seems to return object_error:unexpected_eof + // On OS X debug symbols are not contained in the dynamic library. + // For now we only support .dSYM files in the same directory + // as the shared library. In the future we may use DBGCopyFullDSYMURLForUUID from CoreFoundation to make + // use of spotlight to find the .dSYM file. + size_t sep = fname.rfind('/'); + debuginfopath = fname; + debuginfopath += ".dSYM/Contents/Resources/DWARF/"; + debuginfopath += fname.substr(sep + 1); + objpath = debuginfopath; + } + else { + // On Linux systems we need to mmap another copy because of the permissions on the mmap'ed shared library. + // On Windows we need to mmap another copy since reading the in-memory copy seems to return object_error:unexpected_eof + objpath = fname; + } #ifdef LLVM35 - auto errorobj = llvm::object::ObjectFile::createObjectFile(fname); + auto errorobj = llvm::object::ObjectFile::createObjectFile(objpath); #else - llvm::object::ObjectFile *errorobj = llvm::object::ObjectFile::createObjectFile(fname); + std::unique_ptr errorobj(llvm::object::ObjectFile::createObjectFile(objpath)); #endif -#endif // ifdef _OS_DARWIN_ // GOAL: Assign *obj, *context, *slide (if above succeeded) - if (errorobj) { + if (errorobj) { #ifdef LLVM36 - auto binary = errorobj.get().takeBinary(); - *obj = binary.first.release(); - binary.second.release(); -#elif defined(LLVM35) - *obj = errorobj.get(); -#else - *obj = errorobj; -#endif -#ifdef _OS_DARWIN_ - if (getObjUUID((llvm::object::MachOObjectFile *)*obj,uuid2) && - memcmp(uuid,uuid2,sizeof(uuid)) == 0) { -#endif -#ifdef LLVM37 - *context = new DWARFContextInMemory(**obj); -#elif defined(LLVM36) - *context = DIContext::getDWARFContext(**obj); + auto *debugobj = errorobj->getBinary(); #else - *context = DIContext::getDWARFContext(const_cast(*obj)); + auto *debugobj = errorobj.get(); #endif - *slide = -(int64_t)fbase; -#ifdef _OS_DARWIN_ - } - else { - // If we're here the, the dsym does not match the dylib. Use the original - // object instead. For consistency (and to make sure we get a sensible size - // for the memory buffer), we also use a fresh copy mapped from - // the file rather than reusing the one in memory. We may want to revisit - // that in the future (ideally, once we support fewer LLVM versions). - errorobj = llvm::object::ObjectFile::createObjectFile(fname); - assert(errorobj); + + if (islinux) { #ifdef LLVM36 - auto binary = errorobj.get().takeBinary(); - *obj = binary.first.release(); - binary.second.release(); -#elif defined(LLVM35) - *obj = errorobj.get(); + // if the file has a .gnu_debuglink section, + // try to load its companion file instead + // in the expected locations + // for now, we don't support the build-id method + debug_link_info info = getDebuglink(*debugobj); + if (!info.filename.empty()) { + size_t sep = fname.rfind('/'); +#ifdef LLVM39 + Expected> + DebugInfo(errorCodeToError(std::make_error_code(std::errc::no_such_file_or_directory))); + // Can't find a way to construct an empty Expected object + // that can be ignored. + ignoreError(DebugInfo); #else - *obj = errorobj; + ErrorOr> + DebugInfo(std::errc::no_such_file_or_directory); #endif - delete morigobj; + if (fname.substr(sep + 1) != info.filename) { + debuginfopath = fname.substr(0, sep + 1); + debuginfopath += info.filename; + DebugInfo = openDebugInfo(debuginfopath, info); } -#endif -#if defined(_OS_WINDOWS_) - assert((*obj)->isCOFF()); - const llvm::object::COFFObjectFile *coffobj = (const llvm::object::COFFObjectFile *)*obj; - const llvm::object::pe32plus_header *pe32plus; - coffobj->getPE32PlusHeader(pe32plus); - if (pe32plus != NULL) { - *slide = pe32plus->ImageBase - fbase; - *section_slide = -(int64_t)pe32plus->ImageBase; + if (!DebugInfo) { + debuginfopath = fname.substr(0, sep + 1); + debuginfopath += ".debug/"; + debuginfopath += info.filename; + ignoreError(DebugInfo); + DebugInfo = openDebugInfo(debuginfopath, info); + } + if (!DebugInfo) { + debuginfopath = "/usr/lib/debug/"; + debuginfopath += fname.substr(0, sep + 1); + debuginfopath += info.filename; + ignoreError(DebugInfo); + DebugInfo = openDebugInfo(debuginfopath, info); + } + if (DebugInfo) { + errorobj = std::move(DebugInfo); + // Yes, we've checked, and yes LLVM want us to check again. + assert(errorobj); + debugobj = errorobj->getBinary(); } else { - const llvm::object::pe32_header *pe32; - coffobj->getPE32Header(pe32); - if (pe32 == NULL) { - *obj = NULL; - *context = NULL; - *slide = 0; - } - else { - *slide = pe32->ImageBase - fbase; - *section_slide = -(int64_t)pe32->ImageBase; - } + ignoreError(DebugInfo); } + } #endif + } + + if (isdarwin) { + // verify the UUID matches + if (!getObjUUID((llvm::object::MachOObjectFile*)debugobj, uuid2) || + memcmp(uuid, uuid2, sizeof(uuid)) != 0) { + objfileentry_t entry = {}; + objfilemap[fbase] = entry; + return true; + } + } + + if (iswindows) { +#ifdef LLVM35 + assert(debugobj->isCOFF()); + const llvm::object::COFFObjectFile *coffobj = (const llvm::object::COFFObjectFile*)debugobj; + const llvm::object::pe32plus_header *pe32plus; + coffobj->getPE32PlusHeader(pe32plus); + if (pe32plus != NULL) { + *slide = pe32plus->ImageBase - fbase; + *section_slide = -(int64_t)pe32plus->ImageBase; } -#ifdef LLVM39 else { - // TODO: report the error instead of silently consuming it? - // jl_error might run into the same error again... - consumeError(errorobj.takeError()); + const llvm::object::pe32_header *pe32; + coffobj->getPE32Header(pe32); + if (pe32 == NULL) { + objfileentry_t entry = {}; + objfilemap[fbase] = entry; + return true; + } + else { + *slide = pe32->ImageBase - fbase; + *section_slide = -(int64_t)pe32->ImageBase; + } } #endif - - // update cache - objfileentry_t entry = {*obj,*context,*slide,*section_slide}; - objfilemap[fbase] = entry; } + else { + *slide = -(int64_t)fbase; + } + +#ifdef LLVM37 + *context = new DWARFContextInMemory(*debugobj); +#elif defined(LLVM36) + *context = DIContext::getDWARFContext(*debugobj); +#else + *context = DIContext::getDWARFContext(debugobj); +#endif + *obj = debugobj; +#ifdef LLVM36 + auto binary = errorobj->takeBinary(); + binary.first.release(); + binary.second.release(); +#else + errorobj.release(); #endif - return true; } - return false; + else { + // TODO: report the error instead of silently consuming it? + // jl_error might run into the same error again... + ignoreError(errorobj); + } + + // update cache + objfileentry_t entry = {*obj, *context, *slide, *section_slide}; + objfilemap[fbase] = entry; + return true; } // *name and *filename should be either NULL or malloc'd pointer diff --git a/src/disasm.cpp b/src/disasm.cpp index df3f15604e11b7..356e57add0b9b6 100644 --- a/src/disasm.cpp +++ b/src/disasm.cpp @@ -370,9 +370,7 @@ void jl_dump_asm_internal(uintptr_t Fptr, size_t Fsize, int64_t slide, { // GC safe // Get the host information - std::string TripleName; - if (TripleName.empty()) - TripleName = sys::getDefaultTargetTriple(); + std::string TripleName = sys::getDefaultTargetTriple(); Triple TheTriple(Triple::normalize(TripleName)); std::string MCPU = sys::getHostCPUName(); diff --git a/src/flisp/Makefile b/src/flisp/Makefile index 5d7cf6fc51ccd6..5de2aff8a48889 100644 --- a/src/flisp/Makefile +++ b/src/flisp/Makefile @@ -77,10 +77,10 @@ CCLD := $(LD) endif $(BUILDDIR)/$(EXENAME)-debug: $(DOBJS) $(LIBFILES_debug) $(BUILDDIR)/$(LIBTARGET)-debug.a $(BUILDDIR)/flmain.dbg.obj | $(BUILDDIR)/flisp.boot - @$(call PRINT_LINK, $(CCLD) $(DEBUGFLAGS) $(DOBJS) $(BUILDDIR)/flmain.dbg.obj -o $@ $(BUILDDIR)/$(LIBTARGET)-debug.a $(LIBFILES_debug) $(LIBS) $(OSLIBS)) + @$(call PRINT_LINK, $(CCLD) $(DEBUGFLAGS) $(LDFLAGS) $(DOBJS) $(BUILDDIR)/flmain.dbg.obj -o $@ $(BUILDDIR)/$(LIBTARGET)-debug.a $(LIBFILES_debug) $(LIBS) $(OSLIBS)) $(BUILDDIR)/$(EXENAME): $(OBJS) $(LIBFILES_release) $(BUILDDIR)/$(LIBTARGET).a $(BUILDDIR)/flmain.o | $(BUILDDIR)/flisp.boot - @$(call PRINT_LINK, $(CCLD) $(SHIPFLAGS) $(OBJS) $(BUILDDIR)/flmain.o -o $@ $(BUILDDIR)/$(LIBTARGET).a $(LIBFILES_release) $(LIBS) $(OSLIBS)) + @$(call PRINT_LINK, $(CCLD) $(SHIPFLAGS) $(LDFLAGS) $(OBJS) $(BUILDDIR)/flmain.o -o $@ $(BUILDDIR)/$(LIBTARGET).a $(LIBFILES_release) $(LIBS) $(OSLIBS)) ifneq ($(BUILDDIR),.) $(BUILDDIR)/flisp.boot: flisp.boot diff --git a/src/gc-pages.c b/src/gc-pages.c index ead16010cee15f..fbe2b27450fe33 100644 --- a/src/gc-pages.c +++ b/src/gc-pages.c @@ -37,6 +37,10 @@ void jl_gc_init_page(void) #endif } +#ifndef MAP_NORESERVE // not defined in POSIX, FreeBSD, etc. +#define MAP_NORESERVE (0) +#endif + // Try to allocate a memory block for a region with `pg_cnt` pages. // Return `NULL` if allocation failed. Result is aligned to `GC_PAGE_SZ`. static char *jl_gc_try_alloc_region(int pg_cnt) diff --git a/src/gc.c b/src/gc.c index b5ac77e6a7c4dc..5ad35d739d318c 100644 --- a/src/gc.c +++ b/src/gc.c @@ -618,7 +618,11 @@ JL_DLLEXPORT jl_value_t *jl_gc_big_alloc(jl_ptls_t ptls, size_t sz) bigval_t *v = (bigval_t*)malloc_cache_align(allocsz); if (v == NULL) jl_throw(jl_memory_exception); +#ifdef JULIA_ENABLE_THREADING jl_atomic_fetch_add(&gc_num.allocd, allocsz); +#else + gc_num.allocd += allocsz; +#endif gc_num.bigalloc++; #ifdef MEMDEBUG memset(v, 0xee, allocsz); @@ -1596,7 +1600,7 @@ static void post_mark(arraylist_t *list) } // collector entry point and control -static volatile uint64_t jl_gc_disable_counter = 0; +static volatile uint32_t jl_gc_disable_counter = 0; JL_DLLEXPORT int jl_gc_enable(int on) { @@ -2087,7 +2091,7 @@ void *jl_gc_perm_alloc_nolock(size_t sz) pool = (void*)LLT_ALIGN((uintptr_t)pool, JL_SMALL_BYTE_ALIGNMENT); #else void *pool = mmap(0, GC_PERM_POOL_SIZE, PROT_READ | PROT_WRITE, - MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (__unlikely(pool == MAP_FAILED)) return NULL; #endif diff --git a/src/init.c b/src/init.c index a2d74fe60cc919..d4bf640a181fef 100644 --- a/src/init.c +++ b/src/init.c @@ -46,6 +46,14 @@ extern BOOL (WINAPI *hSymRefreshModuleList)(HANDLE); #include #endif +#ifdef JL_ASAN_ENABLED +JL_DLLEXPORT const char* __asan_default_options() { + return "allow_user_segv_handler=1:detect_leaks=0"; + // FIXME: enable LSAN after fixing leaks & defining __lsan_default_suppressions(), + // or defining __lsan_default_options = exitcode=0 once publicly available +} +#endif + static const char system_image_path[256] = "\0" JL_SYSTEM_IMAGE_PATH; jl_options_t jl_options = { 0, // quiet @@ -628,17 +636,6 @@ void _julia_init(JL_IMAGE_SEARCH rel) } #endif - -#ifdef JL_ASAN_ENABLED - const char *asan_options = getenv("ASAN_OPTIONS"); - if (!asan_options || !(strstr(asan_options, "allow_user_segv_handler=1") || - strstr(asan_options, "handle_segv=0"))) { - jl_printf(JL_STDERR,"WARNING: ASAN overrides Julia's SIGSEGV handler; " - "disable SIGSEGV handling or allow custom handlers.\n"); - } - -#endif - jl_init_threading(); jl_gc_init(); diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 444a76b853f7d1..1d9844e20e944a 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -50,6 +50,14 @@ JL_DLLEXPORT uint32_t jl_get_LLVM_VERSION(void) ; } +extern "C" JL_DLLEXPORT int8_t jl_is_memdebug() { +#ifdef MEMDEBUG + return true; +#else + return false; +#endif +} + /* low-level intrinsics design: TODO: fix description below functions like add_int expect unboxed values of matching bit-length. diff --git a/src/jltypes.c b/src/jltypes.c index 74f54e98eb7686..b50ebdb2e94ca0 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -83,7 +83,7 @@ static int jl_has_typevars__(jl_value_t *v, int incl_wildcard, jl_value_t **p, s jl_has_typevars__(((jl_tvar_t*)v)->lb, incl_wildcard, p, np)) return 1; if (p != NULL) { - for(i=0; i < np; i++) { + for (i = 0; i < np; i++) { if (v == p[i]) return 1; } @@ -102,7 +102,7 @@ static int jl_has_typevars__(jl_value_t *v, int incl_wildcard, jl_value_t **p, s } else if (jl_is_datatype(v)) { if (is_unspec((jl_datatype_t*)v)) - return 0; + return 0; // TODO: fix expect in this case if (p == NULL) { if (incl_wildcard) expect = ((jl_datatype_t*)v)->haswildcard; @@ -118,7 +118,7 @@ static int jl_has_typevars__(jl_value_t *v, int incl_wildcard, jl_value_t **p, s return 0; } size_t l = jl_svec_len(t); - for(i=0; i < l; i++) { + for (i = 0; i < l; i++) { jl_value_t *elt = jl_svecref(t, i); if (elt != v) { if (jl_has_typevars__(elt, incl_wildcard, p, np)) { @@ -392,10 +392,14 @@ static void extend(jl_value_t *var, jl_value_t *val, cenv_t *soln) } static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, - cenv_t *penv, cenv_t *eqc, variance_t var); + cenv_t *penv, cenv_t *eqc, + int *recheck_tuple_intersection, + variance_t var); static jl_value_t *intersect_union(jl_uniontype_t *a, jl_value_t *b, - cenv_t *penv, cenv_t *eqc, variance_t var) + cenv_t *penv, cenv_t *eqc, + int *recheck_tuple_intersection, + variance_t var) { int eq0 = eqc->n, co0 = penv->n; size_t i, l = jl_svec_len(a->types); @@ -411,11 +415,11 @@ static jl_value_t *intersect_union(jl_uniontype_t *a, jl_value_t *b, for(i=0; i < l; i++) { int eq_l = eqc->n, co_l = penv->n; jl_value_t *ti = jl_type_intersect(jl_svecref(a->types,i), b, - penv, eqc, var); + penv, eqc, recheck_tuple_intersection, var); if (ti == (jl_value_t*)jl_bottom_type) { eqc->n = eq0; penv->n = co0; ti = jl_type_intersect(jl_svecref(a->types,i), b, - penv, eqc, var); + penv, eqc, recheck_tuple_intersection, var); if (ti != (jl_value_t*)jl_bottom_type) { // tvar conflict among union elements; keep the conflicting // constraints rolled back @@ -553,10 +557,10 @@ to be returned, with one exception illustrated by: where typeintersect(B,C) == Bottom. */ -int recheck_tuple_intersection = 0; // "flag" above - static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, - cenv_t *penv, cenv_t *eqc, variance_t var) + cenv_t *penv, cenv_t *eqc, + int *recheck_tuple_intersection, // "flag" above + variance_t var) { jl_svec_t *ap = a->parameters, *bp = b->parameters; size_t alenr = jl_svec_len(ap), blenr = jl_svec_len(bp); @@ -590,7 +594,7 @@ static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, // Do we need to store "at least N" constraints in penv? // Formerly, typeintersect(Tuple{A,Vararg{B}}, NTuple{N,C}) did that if (akind == JL_VARARG_BOUND || bkind == JL_VARARG_BOUND) - recheck_tuple_intersection = 1; + *recheck_tuple_intersection = 1; } if (bottom) return (jl_value_t*) jl_bottom_type; if (n == 0) return jl_typeof(jl_emptytuple); @@ -626,17 +630,17 @@ static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, bi++; } assert(ae!=NULL && be!=NULL); - ce = jl_type_intersect(ae,be,penv,eqc,var); + ce = jl_type_intersect(ae, be, penv, eqc, recheck_tuple_intersection, var); if (ce == (jl_value_t*)jl_bottom_type) { if (var!=invariant && aseq && bseq) { // (X∩Y)==∅ → (X...)∩(Y...) == () // We don't need to set bindings here because - // recheck_tuple_intersection=1 + // *recheck_tuple_intersection = 1 if (n == 1) { JL_GC_POP(); return (jl_value_t*)jl_typeof(jl_emptytuple); } - jl_svec_set_len_unsafe(tc,jl_svec_len(tc)-1); + jl_svec_set_len_unsafe(tc, jl_svec_len(tc) - 1); goto done_intersect_tuple; } JL_GC_POP(); @@ -653,7 +657,9 @@ static jl_value_t *intersect_tuple(jl_datatype_t *a, jl_datatype_t *b, } static jl_value_t *intersect_tag(jl_datatype_t *a, jl_datatype_t *b, - cenv_t *penv, cenv_t *eqc, variance_t var) + cenv_t *penv, cenv_t *eqc, + int *recheck_tuple_intersection, + variance_t var) { assert(a->name == b->name); assert(jl_svec_len(a->parameters) == jl_svec_len(b->parameters)); @@ -678,7 +684,7 @@ static jl_value_t *intersect_tag(jl_datatype_t *a, jl_datatype_t *b, return (jl_value_t*)jl_bottom_type; } } - ti = jl_type_intersect(ap,bp,penv,eqc,invariant); + ti = jl_type_intersect(ap, bp, penv, eqc, recheck_tuple_intersection, invariant); if (bp == (jl_value_t*)jl_bottom_type && !((jl_tvar_t*)ap)->bound) { // "Union{}" as a type parameter @@ -687,7 +693,7 @@ static jl_value_t *intersect_tag(jl_datatype_t *a, jl_datatype_t *b, } } else if (jl_is_typevar(bp)) { - ti = jl_type_intersect(ap,bp,penv,eqc,invariant); + ti = jl_type_intersect(ap, bp, penv, eqc, recheck_tuple_intersection, invariant); if (ap == (jl_value_t*)jl_bottom_type && !((jl_tvar_t*)bp)->bound) { // "Union{}" as a type parameter @@ -701,7 +707,7 @@ static jl_value_t *intersect_tag(jl_datatype_t *a, jl_datatype_t *b, if (tva || tvb) { if (jl_subtype_invariant(ap,bp,0) || jl_subtype_invariant(bp,ap,0)) { - ti = jl_type_intersect(ap,bp,penv,eqc,invariant); + ti = jl_type_intersect(ap, bp, penv, eqc, recheck_tuple_intersection, invariant); } else { ti = (jl_value_t*)jl_bottom_type; @@ -786,7 +792,9 @@ static int match_intersection_mode = 0; static jl_value_t *meet_tvars(jl_tvar_t *a, jl_tvar_t *b); static jl_value_t *intersect_typevar(jl_tvar_t *a, jl_value_t *b, - cenv_t *penv, cenv_t *eqc, variance_t var) + cenv_t *penv, cenv_t *eqc, + int *recheck_tuple_intersection, + variance_t var) { jl_value_t *both=NULL; jl_tvar_t *new_b=NULL; @@ -828,7 +836,7 @@ static jl_value_t *intersect_typevar(jl_tvar_t *a, jl_value_t *b, } } else { - b = jl_type_intersect(a->ub, b, penv, eqc, covariant); + b = jl_type_intersect(a->ub, b, penv, eqc, recheck_tuple_intersection, covariant); if (b == jl_bottom_type) { JL_GC_POP(); return b; @@ -924,7 +932,7 @@ static jl_value_t *intersect_typevar(jl_tvar_t *a, jl_value_t *b, return (jl_value_t*)a; } -static jl_value_t *approxify_type(jl_datatype_t *dt, jl_svec_t *pp) +static jl_value_t *approxify_type(jl_datatype_t *dt, jl_svec_t *pp, int *recheck_tuple_intersection) { size_t i, l = jl_svec_len(dt->parameters); jl_svec_t *p = jl_alloc_svec(l); @@ -942,7 +950,9 @@ static jl_value_t *approxify_type(jl_datatype_t *dt, jl_svec_t *pp) } static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, - cenv_t *penv, cenv_t *eqc, variance_t var) + cenv_t *penv, cenv_t *eqc, + int *recheck_tuple_intersection, + variance_t var) { if (jl_is_typector(a)) a = (jl_value_t*)((jl_typector_t*)a)->body; @@ -953,13 +963,13 @@ static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, if (var == covariant && !((jl_tvar_t*)a)->bound) a = ((jl_tvar_t*)a)->ub; else if (a != jl_ANY_flag) - return intersect_typevar((jl_tvar_t*)a, b, penv, eqc, var); + return intersect_typevar((jl_tvar_t*)a, b, penv, eqc, recheck_tuple_intersection, var); } if (jl_is_typevar(b)) { if (var == covariant && !((jl_tvar_t*)b)->bound) b = ((jl_tvar_t*)b)->ub; else if (b != jl_ANY_flag) - return intersect_typevar((jl_tvar_t*)b, a, penv, eqc, var); + return intersect_typevar((jl_tvar_t*)b, a, penv, eqc, recheck_tuple_intersection, var); } if (a == (jl_value_t*)jl_bottom_type || b == (jl_value_t*)jl_bottom_type) return (jl_value_t*)jl_bottom_type; @@ -971,19 +981,19 @@ static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, } // union if (jl_is_uniontype(a)) - return intersect_union((jl_uniontype_t*)a, b, penv, eqc, var); + return intersect_union((jl_uniontype_t*)a, b, penv, eqc, recheck_tuple_intersection, var); if (jl_is_uniontype(b)) - return intersect_union((jl_uniontype_t*)b, a, penv, eqc, var); + return intersect_union((jl_uniontype_t*)b, a, penv, eqc, recheck_tuple_intersection, var); if (a == (jl_value_t*)jl_any_type || a == jl_ANY_flag) return b; if (b == (jl_value_t*)jl_any_type || b == jl_ANY_flag) return a; // tuple if (jl_is_tuple_type(a)) { if (jl_is_tuple_type(b)) { - return intersect_tuple((jl_datatype_t*)a, (jl_datatype_t*)b, penv,eqc,var); + return intersect_tuple((jl_datatype_t*)a, (jl_datatype_t*)b, penv, eqc, recheck_tuple_intersection, var); } } if (jl_is_tuple_type(b)) { - return jl_type_intersect(b, a, penv,eqc,var); + return jl_type_intersect(b, a, penv, eqc, recheck_tuple_intersection, var); } // tag if (!jl_is_datatype(a) || !jl_is_datatype(b)) @@ -991,7 +1001,7 @@ static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, jl_datatype_t *tta = (jl_datatype_t*)a; jl_datatype_t *ttb = (jl_datatype_t*)b; if (tta->name == ttb->name) - return (jl_value_t*)intersect_tag(tta, ttb, penv, eqc, var); + return (jl_value_t*)intersect_tag(tta, ttb, penv, eqc, recheck_tuple_intersection, var); jl_datatype_t *super = NULL; jl_datatype_t *sub = NULL; jl_value_t *env = NULL; @@ -1055,10 +1065,10 @@ static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, if (var == covariant && sub == (jl_datatype_t*)sub->name->primary && jl_has_typevars_from((jl_value_t*)sub->super, ((jl_datatype_t*)sub->name->primary)->parameters)) - env = approxify_type((jl_datatype_t*)sub->super, ((jl_datatype_t*)sub->name->primary)->parameters); + env = approxify_type((jl_datatype_t*)sub->super, ((jl_datatype_t*)sub->name->primary)->parameters, recheck_tuple_intersection); else env = (jl_value_t*)sub->super; - super = (jl_datatype_t*)jl_type_intersect((jl_value_t*)env, (jl_value_t*)super, penv, eqc, var); + super = (jl_datatype_t*)jl_type_intersect((jl_value_t*)env, (jl_value_t*)super, penv, eqc, recheck_tuple_intersection, var); if ((jl_value_t*)super == jl_bottom_type) { JL_GC_POP(); @@ -1128,7 +1138,7 @@ static jl_value_t *jl_type_intersect(jl_value_t *a, jl_value_t *b, for(int e=0; e < jl_svec_len(env); e+=2) { if (jl_svecref(env, e) == tp) { elt = jl_type_intersect(elt, jl_svecref(env, e+1), - penv, eqc, invariant); + penv, eqc, recheck_tuple_intersection, invariant); // note: elt might be Union{} if "Union{}" was the type parameter break; } @@ -1490,14 +1500,14 @@ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, jl_value_t **pti = &rts[0]; jl_value_t **extraroot = &rts[1]; - recheck_tuple_intersection = 0; + int recheck_tuple_intersection = 0; JL_TRY { // This is kind of awful, but an inner call to instantiate_type // might fail due to a mismatched type parameter. The problem is // that we allow Range{T} to exist, even though the declaration of // Range specifies Range{T<:Real}. Therefore intersection cannot see // that some parameter values actually don't match. - *pti = jl_type_intersect(a, b, &env, &eqc, covariant); + *pti = jl_type_intersect(a, b, &env, &eqc, &recheck_tuple_intersection, covariant); } JL_CATCH { *pti = (jl_value_t*)jl_bottom_type; @@ -1511,8 +1521,8 @@ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, int e; if (recheck_tuple_intersection) { - for(e=0; e < eqc.n; e+=2) { - jl_value_t *val = eqc.data[e+1]; + for (e = 0; e < eqc.n; e += 2) { + jl_value_t *val = eqc.data[e + 1]; if (jl_is_long(val)) break; } @@ -1526,7 +1536,7 @@ jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, to find all other constraints on N first, then do intersection again with that knowledge. */ - *pti = jl_type_intersect(a, b, &env, &eqc, covariant); + *pti = jl_type_intersect(a, b, &env, &eqc, &recheck_tuple_intersection, covariant); if (*pti == (jl_value_t*)jl_bottom_type) { JL_GC_POP(); return *pti; diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index f456a68bf1ea46..f762753a5f80f2 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -522,8 +522,9 @@ ,else))) (if (null? restkw) ;; if no rest kw, give error for unrecognized - `(call (top kwerr) ,kw ,@(map arg-name pargl),@(if (null? vararg) '() - (list `(... ,(arg-name (car vararg)))))) + `(call (top kwerr) ,kw ,@(map arg-name pargl) + ,@(if (null? vararg) '() + (list `(... ,(arg-name (car vararg)))))) ;; otherwise add to rest keywords `(ccall 'jl_array_ptr_1d_push Void (tuple Any Any) ,rkw (tuple ,elt @@ -1694,7 +1695,7 @@ (expand-forms `(call (top broadcast!) ,(from-lambda (cadr e)) ,lhs-view ,@(caddr e)))) (if (null? lhs) (expand-forms e) - (expand-forms `(call (top broadcast!) identity ,lhs-view ,e)))))) + (expand-forms `(call (top broadcast!) (top identity) ,lhs-view ,e)))))) ;; table mapping expression head to a function expanding that form (define expand-table @@ -2870,7 +2871,7 @@ f(x) = yt(x) (let* ((exprs (lift-toplevel (convert-lambda lam2 '|#anon| #t '()))) (top-stmts (cdr exprs)) (newlam (renumber-slots-and-labels (linearize (car exprs))))) - `(block + `(toplevel-butlast ,@top-stmts ,@sp-inits (method ,name ,(cl-convert sig fname lam namemap toplevel interp) diff --git a/src/julia_internal.h b/src/julia_internal.h index 8346c247e5808a..6eec5c076d43a5 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -49,9 +49,6 @@ void jl_call_tracer(tracer_cb callback, jl_value_t *tracee); extern size_t jl_page_size; extern jl_function_t *jl_typeinf_func; -#if defined(JL_USE_INTEL_JITEVENTS) -extern unsigned sig_stack_size; -#endif JL_DLLEXPORT extern int jl_lineno; JL_DLLEXPORT extern const char *jl_filename; diff --git a/src/julia_threads.h b/src/julia_threads.h index e18eb7283e1d43..5302fa88c31d6a 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -159,7 +159,7 @@ static inline unsigned long JL_CONST_FUNC jl_thread_self(void) * 2. (most importantly) we need interoperability between code written * in different languages. * The current c++ standard (c++14) does not allow using c11 atomic - * functions or types and there's currently no grantee that the two + * functions or types and there's currently no guarantee that the two * types are compatible (although most of them probably are). * We also need to access these atomic variables from the LLVM JIT code * which is very hard unless the layout of the object is fully diff --git a/src/llvm-ptls.cpp b/src/llvm-ptls.cpp index 019975cc3ba059..a3d669a3946553 100644 --- a/src/llvm-ptls.cpp +++ b/src/llvm-ptls.cpp @@ -147,6 +147,7 @@ void LowerPTLS::runOnFunction(LLVMContext &ctx, Module &M, Function *F, Value *tls = nullptr; assert(0 && "Cannot emit thread pointer for this architecture."); # endif + (void)T_pint8; ptlsStates->replaceAllUsesWith(tls); ptlsStates->eraseFromParent(); } diff --git a/src/safepoint.c b/src/safepoint.c index 6644f32b63c61d..2874266ebe4b51 100644 --- a/src/safepoint.c +++ b/src/safepoint.c @@ -93,7 +93,7 @@ void jl_safepoint_init(void) char *addr = (char*)VirtualAlloc(NULL, pgsz * 3, MEM_COMMIT, PAGE_READONLY); #else char *addr = (char*)mmap(0, pgsz * 3, PROT_READ, - MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) addr = NULL; #endif diff --git a/src/signals-unix.c b/src/signals-unix.c index 9557dd0a3bd600..23843d3e9b5b9c 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -28,14 +28,10 @@ #define HAVE_TIMER #endif -#if defined(JL_USE_INTEL_JITEVENTS) -unsigned sig_stack_size = SIGSTKSZ; -#elif defined(_CPU_AARCH64_) -// The default SIGSTKSZ causes stack overflow in libunwind. -#define sig_stack_size (1 << 16) -#else -#define sig_stack_size SIGSTKSZ -#endif +// 8M signal stack, same as default stack size and enough +// for reasonable finalizers. +// Should also be enough for parallel GC when we have it =) +#define sig_stack_size (8 * 1024 * 1024) static bt_context_t *jl_to_bt_context(void *sigctx) { @@ -315,7 +311,7 @@ static void *alloc_sigstack(size_t size) // Add one guard page to catch stack overflow in the signal handler size = LLT_ALIGN(size, pagesz) + pagesz; void *stackbuff = mmap(0, size, PROT_READ | PROT_WRITE, - MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (stackbuff == MAP_FAILED) jl_errorf("fatal error allocating signal stack: mmap: %s", strerror(errno)); diff --git a/src/stackwalk.c b/src/stackwalk.c index e67308ea01b255..f45b840a0c24c0 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -194,17 +194,21 @@ static DWORD64 WINAPI JuliaGetModuleBase64( #endif } +// Might be called from unmanaged thread. int needsSymRefreshModuleList; BOOL (WINAPI *hSymRefreshModuleList)(HANDLE); -static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *Context) +void jl_refresh_dbg_module_list(void) { - // Might be called from unmanaged thread. if (needsSymRefreshModuleList && hSymRefreshModuleList != 0 && !jl_in_stackwalk) { jl_in_stackwalk = 1; hSymRefreshModuleList(GetCurrentProcess()); jl_in_stackwalk = 0; needsSymRefreshModuleList = 0; } +} +static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *Context) +{ + jl_refresh_dbg_module_list(); #if !defined(_CPU_X86_64_) if (jl_in_stackwalk) { return 0; @@ -372,7 +376,7 @@ JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC) jl_svecset(r, 3, frame.linfo != NULL ? (jl_value_t*)frame.linfo : jl_nothing); jl_svecset(r, 4, jl_box_bool(frame.fromC)); jl_svecset(r, 5, jl_box_bool(frame.inlined)); - jl_svecset(r, 6, jl_box_long((intptr_t)ip)); + jl_svecset(r, 6, jl_box_voidpointer(ip)); } free(frames); JL_GC_POP(); diff --git a/src/support/hashing.h b/src/support/hashing.h index 1be2a9e7b5ec0c..5f9b41d6f700d3 100644 --- a/src/support/hashing.h +++ b/src/support/hashing.h @@ -3,6 +3,9 @@ #ifndef HASHING_H #define HASHING_H +#include "utils.h" +#include "dtypes.h" + #ifdef __cplusplus extern "C" { #endif @@ -22,10 +25,17 @@ JL_DLLEXPORT uint32_t memhash32(const char *buf, size_t n); JL_DLLEXPORT uint32_t memhash32_seed(const char *buf, size_t n, uint32_t seed); #ifdef _P64 -#define bitmix(a,b) int64hash((a)^bswap_64(b)) +STATIC_INLINE uint64_t bitmix(uint64_t a, uint64_t b) +{ + return int64hash(a^bswap_64(b)); +} #else -#define bitmix(a,b) int64to32hash((((uint64_t)a)<<32)|((uint64_t)b)) +STATIC_INLINE uint32_t bitmix(uint32_t a, uint32_t b) +{ + return int64to32hash((((uint64_t)a) << 32) | (uint64_t)b); +} #endif +#define bitmix(a, b) (bitmix)((uintptr_t)(a), (uintptr_t)(b)) #ifdef __cplusplus } diff --git a/src/task.c b/src/task.c index b1cf229bd1248e..2c1c249f9670e4 100644 --- a/src/task.c +++ b/src/task.c @@ -353,7 +353,7 @@ static void ctx_switch(jl_ptls_t ptls, jl_task_t *t, jl_jmp_buf *where) " push %%ebp;\n" // instead of ESP " jmp %P1;\n" // call `start_task` with fake stack frame " ud2" - : : "r" (stackbase), ""(&start_task) : "memory" ); + : : "r" (stackbase), "X"(&start_task) : "memory" ); #elif defined(_CPU_AARCH64_) asm(" mov sp, %0;\n" " mov x29, xzr;\n" // Clear link register (x29) and frame pointer diff --git a/src/threading.c b/src/threading.c index 6b1d373c7f1f68..7ff20c565338a7 100644 --- a/src/threading.c +++ b/src/threading.c @@ -778,13 +778,6 @@ void jl_init_threading(void) jl_all_tls_states = &_jl_all_tls_states; jl_n_threads = 1; -#if defined(__linux__) && defined(JL_USE_INTEL_JITEVENTS) - if (jl_using_intel_jitevents) - // Intel VTune Amplifier needs at least 64k for alternate stack. - if (SIGSTKSZ < 1<<16) - sig_stack_size = 1<<16; -#endif - ti_init_master_thread(); } diff --git a/test/TestHelpers.jl b/test/TestHelpers.jl index b57b0d10f77ee8..fef9a3089d6aac 100644 --- a/test/TestHelpers.jl +++ b/test/TestHelpers.jl @@ -43,4 +43,101 @@ function with_fake_pty(f) close(master) end +# OffsetArrays (arrays with indexing that doesn't start at 1) + +# This test file is designed to exercise support for generic indexing, +# even though offset arrays aren't implemented in Base. + +module OAs + +using Base: Indices, LinearSlow, LinearFast, tail + +export OffsetArray + +immutable OffsetArray{T,N,AA<:AbstractArray} <: AbstractArray{T,N} + parent::AA + offsets::NTuple{N,Int} +end +typealias OffsetVector{T,AA<:AbstractArray} OffsetArray{T,1,AA} + +OffsetArray{T,N}(A::AbstractArray{T,N}, offsets::NTuple{N,Int}) = OffsetArray{T,N,typeof(A)}(A, offsets) +OffsetArray{T,N}(A::AbstractArray{T,N}, offsets::Vararg{Int,N}) = OffsetArray(A, offsets) + +(::Type{OffsetArray{T,N}}){T,N}(inds::Indices{N}) = OffsetArray{T,N,Array{T,N}}(Array{T,N}(map(length, inds)), map(indsoffset, inds)) +(::Type{OffsetArray{T}}){T,N}(inds::Indices{N}) = OffsetArray{T,N}(inds) + +Base.linearindexing{T<:OffsetArray}(::Type{T}) = Base.linearindexing(parenttype(T)) +parenttype{T,N,AA}(::Type{OffsetArray{T,N,AA}}) = AA +parenttype(A::OffsetArray) = parenttype(typeof(A)) + +Base.parent(A::OffsetArray) = A.parent + +errmsg(A) = error("size not supported for arrays with indices $(indices(A)); see http://docs.julialang.org/en/latest/devdocs/offset-arrays/") +Base.size(A::OffsetArray) = errmsg(A) +Base.size(A::OffsetArray, d) = errmsg(A) +Base.eachindex(::LinearSlow, A::OffsetArray) = CartesianRange(indices(A)) +Base.eachindex(::LinearFast, A::OffsetVector) = indices(A, 1) + +# Implementations of indices and indices1. Since bounds-checking is +# performance-critical and relies on indices, these are usually worth +# optimizing thoroughly. +@inline Base.indices(A::OffsetArray, d) = 1 <= d <= length(A.offsets) ? indices(parent(A))[d] + A.offsets[d] : (1:1) +@inline Base.indices(A::OffsetArray) = _indices(indices(parent(A)), A.offsets) # would rather use ntuple, but see #15276 +@inline _indices(inds, offsets) = (inds[1]+offsets[1], _indices(tail(inds), tail(offsets))...) +_indices(::Tuple{}, ::Tuple{}) = () +Base.indices1{T}(A::OffsetArray{T,0}) = 1:1 # we only need to specialize this one + +function Base.similar(A::OffsetArray, T::Type, dims::Dims) + B = similar(parent(A), T, dims) +end +function Base.similar(A::AbstractArray, T::Type, inds::Tuple{UnitRange,Vararg{UnitRange}}) + B = similar(A, T, map(length, inds)) + OffsetArray(B, map(indsoffset, inds)) +end + +Base.similar(f::Union{Function,DataType}, shape::Tuple{UnitRange,Vararg{UnitRange}}) = OffsetArray(f(map(length, shape)), map(indsoffset, shape)) + +Base.reshape(A::AbstractArray, inds::Tuple{UnitRange,Vararg{UnitRange}}) = OffsetArray(reshape(A, map(length, inds)), map(indsoffset, inds)) + +@inline function Base.getindex{T,N}(A::OffsetArray{T,N}, I::Vararg{Int,N}) + checkbounds(A, I...) + @inbounds ret = parent(A)[offset(A.offsets, I)...] + ret +end +@inline function Base._getindex(::LinearFast, A::OffsetVector, i::Int) + checkbounds(A, i) + @inbounds ret = parent(A)[offset(A.offsets, (i,))[1]] + ret +end +@inline function Base._getindex(::LinearFast, A::OffsetArray, i::Int) + checkbounds(A, i) + @inbounds ret = parent(A)[i] + ret +end +@inline function Base.setindex!{T,N}(A::OffsetArray{T,N}, val, I::Vararg{Int,N}) + checkbounds(A, I...) + @inbounds parent(A)[offset(A.offsets, I)...] = val + val +end +@inline function Base._setindex!(::LinearFast, A::OffsetVector, val, i::Int) + checkbounds(A, i) + @inbounds parent(A)[offset(A.offsets, (i,))[1]] = val + val +end +@inline function Base._setindex!(::LinearFast, A::OffsetArray, val, i::Int) + checkbounds(A, i) + @inbounds parent(A)[i] = val + val +end + +# Computing a shifted index (subtracting the offset) +offset{N}(offsets::NTuple{N,Int}, inds::NTuple{N,Int}) = _offset((), offsets, inds) +_offset(out, ::Tuple{}, ::Tuple{}) = out +@inline _offset(out, offsets, inds) = _offset((out..., inds[1]-offsets[1]), Base.tail(offsets), Base.tail(inds)) + +indsoffset(r::Range) = first(r) - 1 +indsoffset(i::Integer) = 0 + +end + end diff --git a/test/abstractarray.jl b/test/abstractarray.jl index b3ff1b2f18c778..db26e0099f896a 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -408,6 +408,13 @@ function test_primitives{T}(::Type{T}, shape, ::Type{TestAbstractArray}) @test convert(Array, X) == X end +let + type TestThrowNoGetindex{T} <: AbstractVector{T} end + Base.length(::TestThrowNoGetindex) = 2 + Base.size(::TestThrowNoGetindex) = (2,) + @test_throws ErrorException isassigned(TestThrowNoGetindex{Float64}(), 1) +end + function test_in_bounds(::Type{TestAbstractArray}) n = rand(2:5) sz = rand(2:5, n) @@ -709,3 +716,21 @@ let @test !issparse(m1) @test !issparse(m2) end + +#isinteger and isreal +@test isinteger(Diagonal(rand(1:5,5))) +@test isreal(Diagonal(rand(5))) + +#unary ops +let A = Diagonal(rand(1:5,5)) + @test +(A) == A + @test *(A) == A +end + +#flipdim on empty +@test flipdim(Diagonal([]),1) == Diagonal([]) + +# ndims and friends +@test ndims(Diagonal(rand(1:5,5))) == 2 +@test ndims(Diagonal{Float64}) == 2 +@test Base.elsize(Diagonal(rand(1:5,5))) == sizeof(Int) diff --git a/test/arrayops.jl b/test/arrayops.jl index 984128a58816a0..7a68a0492af76b 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -124,6 +124,14 @@ a = zeros(0, 5) # an empty linearslow array s = view(a, :, [2,3,5]) @test length(reshape(s, length(s))) == 0 +# reshape(a, Val{N}) +a = ones(Int,3,3) +s = view(a, 1:2, 1:2) +for N in (1,3) + @test isa(reshape(a, Val{N}), Array{Int,N}) + @test isa(reshape(s, Val{N}), Base.ReshapedArray{Int,N}) +end + @test reshape(1:5, (5,)) === 1:5 @test reshape(1:5, 5) === 1:5 @@ -1439,7 +1447,6 @@ b = rand(6,7) @test_throws ArgumentError copy!(a,2:3,1:3,b,1:5,2:7) @test_throws ArgumentError Base.copy_transpose!(a,2:3,1:3,b,1:5,2:7) -# return type declarations (promote_op) module RetTypeDecl using Base.Test import Base: +, *, .*, convert @@ -1457,7 +1464,6 @@ module RetTypeDecl (*){T}(x::MeterUnits{T,1}, y::MeterUnits{T,1}) = MeterUnits{T,2}(x.val*y.val) (.*){T}(x::MeterUnits{T,1}, y::MeterUnits{T,1}) = MeterUnits{T,2}(x.val*y.val) convert{T,pow}(::Type{MeterUnits{T,pow}}, y::Real) = MeterUnits{T,pow}(convert(T,y)) - Base.promote_op{R,S}(::typeof(*), ::Type{MeterUnits{R,1}}, ::Type{MeterUnits{S,1}}) = MeterUnits{promote_type(R,S),2} @test @inferred(m+[m,m]) == [m+m,m+m] @test @inferred([m,m]+m) == [m+m,m+m] diff --git a/test/backtrace.jl b/test/backtrace.jl index bdc93b000e0d91..5a73200d79d079 100644 --- a/test/backtrace.jl +++ b/test/backtrace.jl @@ -121,7 +121,8 @@ end @test_broken hasbt2 function btmacro() - @time backtrace() + ret = @timed backtrace() + ret[1] end lkup = map(StackTraces.lookup, btmacro()) hasme = hasbtmacro = false diff --git a/test/broadcast.jl b/test/broadcast.jl index f14788413f05ae..dfbbeed1c8950e 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -225,12 +225,11 @@ let x = sin.(1:10) @test sin.(atan2.(x, 3.7)) == broadcast(x -> sin(atan2(x,3.7)), x) @test atan2.(x, 3.7) == broadcast(x -> atan2(x,3.7), x) == broadcast(atan2, x, 3.7) end -# Use side effects to check for loop fusion. Note that, due to #17314, -# a broadcasted function is currently called an extra time with an argument 1. +# Use side effects to check for loop fusion. let g = Int[] - f17300(x) = begin; push!(g, x); x+1; end + f17300(x) = begin; push!(g, x); x+2; end f17300.(f17300.(f17300.(1:3))) - @test g == [1,2,3, 1,2,3, 2,3,4, 3,4,5] + @test g == [1,3,5, 2,4,6, 3,5,7] end # fusion with splatted args: let x = sin.(1:10), a = [x] @@ -285,6 +284,10 @@ let d = Dict(:foo => [1,3,7], (3,4) => [5,9]) d[3,4] .-= 1 @test d[3,4] == [4,8] end +let identity = error, x = [1,2,3] + x .= 1 # make sure it goes to broadcast!(Base.identity, ...), not identity + @test x == [1,1,1] +end # PR 16988 @test Base.promote_op(+, Bool) === Int @@ -295,3 +298,15 @@ end let foo = [[1,2,3],[4,5,6],[7,8,9]] @test max.(foo...) == broadcast(max, foo...) == [7,8,9] end + +# Issue 17314 +@test broadcast(x->log(log(log(x))), [1000]) == [log(log(log(1000)))] +let f17314 = x -> x < 0 ? false : x + @test eltype(broadcast(f17314, 1:3)) === Int + @test eltype(broadcast(f17314, -1:1)) === Integer + @test eltype(broadcast(f17314, Int[])) === Union{} +end +let io = IOBuffer() + broadcast(x->print(io,x), 1:5) # broadcast with side effects + @test takebuf_array(io) == [0x31,0x32,0x33,0x34,0x35] +end diff --git a/test/ccall.jl b/test/ccall.jl index 7f0792a87fdd51..56a6b1bf3f5be3 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -589,6 +589,10 @@ threadcall_test_func(x) = @test threadcall_test_func(3) == 1 @test threadcall_test_func(259) == 1 +# issue 17819 +# NOTE: can't use cfunction or reuse ccalltest Struct methods, as those call into the runtime +@test @threadcall((:threadcall_args, libccalltest), Cint, (Cint, Cint), 1, 2) == 3 + let n=3 tids = Culong[] @sync for i in 1:10^n diff --git a/test/choosetests.jl b/test/choosetests.jl index d02ed1dcf3cf06..f15e61a139d6c0 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -26,7 +26,7 @@ function choosetests(choices = []) "priorityqueue", "file", "read", "mmap", "version", "resolve", "pollfd", "mpfr", "broadcast", "complex", "socket", "floatapprox", "datafmt", "reflection", "regex", "float16", - "combinatorics", "sysinfo", "rounding", "ranges", "mod2pi", + "combinatorics", "sysinfo", "env", "rounding", "ranges", "mod2pi", "euler", "show", "lineedit", "replcompletions", "repl", "replutil", "sets", "test", "goto", "llvmcall", "grisu", "nullable", "meta", "stacktraces", "profile", "libgit2", "docs", diff --git a/test/core.jl b/test/core.jl index ee4605ff607046..66ba2ef72368fe 100644 --- a/test/core.jl +++ b/test/core.jl @@ -4469,3 +4469,18 @@ let k(x) = (k = x; k) @test k(1) == 1 end + +# PR #18054: compilation of cfunction leaves IRBuilder in bad state, +# causing heap-use-after-free when compiling f18054 +function f18054() + return Cint(0) +end +cfunction(f18054, Cint, ()) + +# issue #18085 +f18085(a,x...) = (0,) +for (f,g) in ((:asin,:sin), (:acos,:cos)) + gx = eval(g) + f18085(::Type{Val{f}},x...) = map(x->2gx(x), f18085(Val{g},x...)) +end +@test f18085(Val{:asin},3) === (0.0,) diff --git a/test/env.jl b/test/env.jl new file mode 100644 index 00000000000000..030fe3cf9b5903 --- /dev/null +++ b/test/env.jl @@ -0,0 +1,72 @@ +# This file is a part of Julia. License is MIT: http://julialang.org/license + +@test !("f=a=k=e=n=a=m=e" ∈ keys(ENV)) + +# issue #10994 +@test_throws ArgumentError ENV["bad\0name"] = "ok" +@test_throws ArgumentError ENV["okname"] = "bad\0val" +@test_throws ArgumentError Sys.set_process_title("bad\0title") + +withenv("bad"=>"dog") do + @test_throws ArgumentError ENV["bad\0cat"] +end + +# issue #11170 +withenv("TEST"=>"nonempty") do + @test ENV["TEST"] == "nonempty" +end +withenv("TEST"=>"") do + @test ENV["TEST"] == "" +end + +let c = collect(ENV) + @test isa(c, Vector) + @test length(ENV) == length(c) + @test isempty(ENV) || first(ENV) in c +end + +# test for non-existent keys +key = randstring(25) +@test !haskey(ENV,key) +@test_throws KeyError ENV[key] +@test get(ENV,key,"default") == "default" + +# Test for #17956 +@test length(ENV) > 1 +k1, k2 = "__test__", "__test1__" +withenv(k1=>k1, k2=>k2) do + b_k1, b_k2 = false, false + for (k, v) in ENV + if k==k1 + b_k1=true + elseif k==k2 + b_k2=true + end + end + @test b_k1 && b_k2 + io = IOBuffer() + show(io, ENV) + s = takebuf_string(io) + @test contains(s, "$k1=$k1") + @test contains(s, "$k2=$k2") + + @test pop!(ENV, k1) == k1 + @test !haskey(ENV, k1) + ENV[k1] = k1 + @test pop!(ENV, k1) == k1 + @test pop!(ENV, k1, "not_there") == "not_there" + + ENV[k1] = k1 + @test delete!(ENV, k1) == ENV + @test !haskey(ENV, k1) +end + +# Test for #10853 +@test withenv(Dict{Any,Any}()...) do; true; end + +# Test for #18141 +for (k, v) in ENV + if length(v) > 0 + @test v[end] != '\0' + end +end diff --git a/test/functional.jl b/test/functional.jl index b495ddb7158479..4b8db1d0af7503 100644 --- a/test/functional.jl +++ b/test/functional.jl @@ -32,6 +32,10 @@ end # maps of strings (character arrays) -- string.jl @test map((c)->Char(c+1), "abcDEF") == "bcdEFG" +# issue #10633 +@test isa(map(Integer, Any[1, 2]), Vector{Int}) +@test isa(map(Integer, Any[]), Vector{Integer}) + # filter -- array.jl @test isequal(filter(x->(x>1), [0 1 2 3 2 1 0]), [2, 3, 2]) # TODO: @test_throws isequal(filter(x->x+1, [0 1 2 3 2 1 0]), [2, 3, 2]) @@ -185,6 +189,7 @@ end @test Base.iteratorsize(repeated(0, 5)) == Base.HasLength() @test Base.iteratoreltype(repeated(0)) == Base.HasEltype() @test Base.iteratoreltype(repeated(0, 5)) == Base.HasEltype() +@test Base.iteratorsize(zip(repeated(0), repeated(0))) == Base.IsInfinite() # product diff --git a/test/inference.jl b/test/inference.jl index 2615e9cc4847a1..a324716b2511b2 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -68,7 +68,7 @@ end abstract Outer5906{T} immutable Inner5906{T} - a:: T + a:: T end immutable Empty5906{T} <: Outer5906{T} @@ -282,3 +282,58 @@ let I = Integer[] push!(I, 1) @test I == Any[1] end + +# issue #16530 +type Foo16530a{dim} + c::Vector{NTuple{dim, Float64}} + d::Vector +end +type Foo16530b{dim} + c::Vector{NTuple{dim, Float64}} +end +f16530a() = fieldtype(Foo16530a, :c) +f16530a(c) = fieldtype(Foo16530a, c) +f16530b() = fieldtype(Foo16530b, :c) +f16530b(c) = fieldtype(Foo16530b, c) + +let T = Array{Tuple{Vararg{Float64,TypeVar(:dim)}},1}, + TTlim = Type{TypeVar(:_,Array{TypeVar(:_,Tuple),1})} + + @test f16530a() == T + @test f16530a(:c) == T + @test Base.return_types(f16530a, ()) == Any[TTlim] + @test Base.return_types(f16530b, ()) == Any[TTlim] + @test Base.return_types(f16530b, (Symbol,)) == Any[TTlim] +end +@test f16530a(:d) == Vector + +let T1 = Tuple{Int, Float64}, + T2 = Tuple{Int, Float32}, + T = Tuple{T1, T2} + + global f18037 + f18037() = fieldtype(T, 1) + f18037(i) = fieldtype(T, i) + + @test f18037() === T1 + @test f18037(1) === T1 + @test f18037(2) === T2 + + @test Base.return_types(f18037, ()) == Any[Type{T1}] + @test Base.return_types(f18037, (Int,)) == Any[Type{TypeVar(:T, Tuple{Int, AbstractFloat})}] +end + +# issue #18015 +type Triple18015 + a::Int + b::Int + c::Int +end +a18015(tri) = tri.a +b18015(tri) = tri.b +c18015(tri) = tri.c +setabc18015!(tri, a, b, c) = (tri.a = a; tri.b = b; tri.c = c) +let tri = Triple18015(1, 2, 3) + setabc18015!(tri, b18015(tri), c18015(tri), a18015(tri)) + @test tri.a === 2 && tri.b === 3 && tri.c === 1 +end diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 7a6c84c54670e8..822bad6805a07f 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -2,6 +2,7 @@ # Int32 and Int64 take different code paths -- test both for T in (Int32, Int64) + @test gcd(T(3)) === T(3) @test gcd(T(3), T(5)) === T(1) @test gcd(T(3), T(15)) === T(3) @test gcd(T(0), T(15)) === T(15) @@ -16,6 +17,7 @@ for T in (Int32, Int64) @test gcd(typemin(T), T(1)) === T(1) @test_throws OverflowError gcd(typemin(T), typemin(T)) + @test lcm(T(2)) === T(2) @test lcm(T(2), T(3)) === T(6) @test lcm(T(4), T(6)) === T(12) @test lcm(T(3), T(0)) === T(0) @@ -86,6 +88,8 @@ let n = rand(Int) @test ndigits(n) == ndigits(big(n)) == ndigits(n, 10) end +@test bin('3') == "110011" +@test bin('3',7) == "0110011" @test bin(3) == "11" @test bin(3, 2) == "11" @test bin(3, 3) == "011" @@ -103,8 +107,11 @@ end @test base(2, 5, 7) == "0000101" +@test bits(Int16(3)) == "0000000000000011" +@test bits('3') == "00000000000000000000000000110011" @test bits(1035) == (Int == Int32 ? "00000000000000000000010000001011" : "0000000000000000000000000000000000000000000000000000010000001011") +@test bits(Int128(3)) == "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011" @test digits(4, 2) == [0, 0, 1] @test digits(5, 3) == [2, 1] @@ -116,6 +123,9 @@ end @test count_zeros(Int64(1)) == 63 +@test factorial(3) == 6 +@test_throws DomainError factorial(-3) + @test isqrt(4) == 2 @test isqrt(5) == 2 # issue #4884 diff --git a/test/intset.jl b/test/intset.jl index 5ebd531a46e096..ff062ba16c859e 100644 --- a/test/intset.jl +++ b/test/intset.jl @@ -14,6 +14,7 @@ data_out = collect(s) # eltype, similar @test is(eltype(IntSet()), Int64) +@test is(eltype(IntSet), Int64) @test isequal(similar(IntSet([1,2,3])), IntSet()) # show @@ -33,6 +34,8 @@ s = IntSet([1,2,10,20,200,300,1000,10000,10002]) @test !in(1,s) @test !in(10002,s) @test in(10000,s) +@test in(10000.0,s) +@test !in(10002.0,s) @test_throws ArgumentError first(IntSet()) @test_throws ArgumentError last(IntSet()) t = copy(s) diff --git a/test/keywordargs.jl b/test/keywordargs.jl index 7a582b73645f15..8030e3dce0ee11 100644 --- a/test/keywordargs.jl +++ b/test/keywordargs.jl @@ -9,7 +9,7 @@ kwf1(ones; tens=0, hundreds=0) = ones + 10*tens + 100*hundreds @test kwf1(3, tens=7, hundreds=2) == 273 @test_throws MethodError kwf1() # no method, too few args -@test_throws MethodError kwf1(1, z=0) # unsupported keyword +@test_throws MethodError kwf1(1, z=0) # unsupported keyword @test_throws MethodError kwf1(1, 2) # no method, too many positional args # keyword args plus varargs diff --git a/test/libgit2-online.jl b/test/libgit2-online.jl index 436003eb37160a..dd02d6c42d37f7 100644 --- a/test/libgit2-online.jl +++ b/test/libgit2-online.jl @@ -7,13 +7,11 @@ ######### # init & clone mktempdir() do dir - repo_url = "github.com/JuliaLang/Example.jl" - https_prefix = "https://" - ssh_prefix = "git@" + repo_url = "https://github.com/JuliaLang/Example.jl" #@testset "Cloning repository" begin #@testset "with 'https' protocol" begin repo_path = joinpath(dir, "Example1") - repo = LibGit2.clone(https_prefix*repo_url, repo_path) + repo = LibGit2.clone(repo_url, repo_path) try @test isdir(repo_path) @test isdir(joinpath(repo_path, ".git")) @@ -27,24 +25,13 @@ mktempdir() do dir repo_path = joinpath(dir, "Example2") # credentials are required because github tries to authenticate on unknown repo cred = LibGit2.UserPasswordCredentials("","") # empty credentials cause authentication error - LibGit2.clone(https_prefix*repo_url*randstring(10), repo_path, payload=Nullable(cred)) + LibGit2.clone(repo_url*randstring(10), repo_path, payload=Nullable(cred)) error("unexpected") catch ex @test isa(ex, LibGit2.Error.GitError) @test ex.code == LibGit2.Error.EAUTH end #end - - #TODO: remove or condition on libgit2 features this test when ssh protocol will be supported - #@testset "with 'ssh' protocol (by default is not supported)" begin - try - repo_path = joinpath(dir, "Example3") - @test_throws LibGit2.Error.GitError LibGit2.clone(ssh_prefix*repo_url, repo_path) - catch ex - # but we cloned succesfully, so check that repo was created - ex.fail == 1 && @test isdir(joinpath(path, ".git")) - end - #end #end end diff --git a/test/libgit2.jl b/test/libgit2.jl index db7d4924688c98..4597c57e03465e 100644 --- a/test/libgit2.jl +++ b/test/libgit2.jl @@ -76,10 +76,60 @@ const LIBGIT2_MIN_VER = v"0.23.0" @test sig3.email == sig.email #end +#@testset "URL parsing" begin + # HTTPS URL + m = match(LibGit2.URL_REGEX, "https://user:pass@server.com:80/org/project.git") + @test m[:scheme] == "https" + @test m[:user] == "user" + @test m[:password] == "pass" + @test m[:host] == "server.com" + @test m[:port] == "80" + @test m[:path] == "/org/project.git" + + # SSH URL + m = match(LibGit2.URL_REGEX, "ssh://user:pass@server:22/project.git") + @test m[:scheme] == "ssh" + @test m[:user] == "user" + @test m[:password] == "pass" + @test m[:host] == "server" + @test m[:port] == "22" + @test m[:path] == "/project.git" + + # SSH URL using scp-like syntax + m = match(LibGit2.URL_REGEX, "user@server:project.git") + @test m[:scheme] == nothing + @test m[:user] == "user" + @test m[:password] == nothing + @test m[:host] == "server" + @test m[:port] == nothing + @test m[:path] == "project.git" + + # Realistic example from GitHub using HTTPS + m = match(LibGit2.URL_REGEX, "https://github.com/JuliaLang/Example.jl.git") + @test m[:scheme] == "https" + @test m[:user] == nothing + @test m[:password] == nothing + @test m[:host] == "github.com" + @test m[:port] == nothing + @test m[:path] == "/JuliaLang/Example.jl.git" + + # Realistic example from GitHub using SSH + m = match(LibGit2.URL_REGEX, "git@github.com:JuliaLang/Example.jl.git") + @test m[:scheme] == nothing + @test m[:user] == "git" + @test m[:password] == nothing + @test m[:host] == "github.com" + @test m[:port] == nothing + @test m[:path] == "JuliaLang/Example.jl.git" + + # Make sure usernames can contain special characters + m = match(LibGit2.URL_REGEX, "user-name@hostname.com") + @test m[:user] == "user-name" +#end + mktempdir() do dir # test parameters repo_url = "https://github.com/JuliaLang/Example.jl" - ssh_prefix = "git@" cache_repo = joinpath(dir, "Example") test_repo = joinpath(dir, "Example.Test") test_sig = LibGit2.Signature("TEST", "TEST@TEST.COM", round(time(), 0), 0) diff --git a/test/linalg/diagonal.jl b/test/linalg/diagonal.jl index be856257cef9d4..6d87b0f97b3cba 100644 --- a/test/linalg/diagonal.jl +++ b/test/linalg/diagonal.jl @@ -36,6 +36,13 @@ for relty in (Float32, Float64, BigFloat), elty in (relty, Complex{relty}) @test D[1,1] == d[1] @test D[1,2] == 0 + @test issymmetric(D) + @test istriu(D) + @test istril(D) + if elty <: Real + @test ishermitian(D) + end + debug && println("Simple unary functions") for op in (-,) @test op(D)==op(DM) @@ -69,6 +76,10 @@ for relty in (Float32, Float64, BigFloat), elty in (relty, Complex{relty}) debug && println("Linear solve") @test_approx_eq_eps D*v DM*v n*eps(relty)*(elty<:Complex ? 2:1) @test_approx_eq_eps D*U DM*U n^2*eps(relty)*(elty<:Complex ? 2:1) + + @test U.'*D ≈ U.'*full(D) + @test U'*D ≈ U'*full(D) + if relty != BigFloat @test_approx_eq_eps D\v DM\v 2n^2*eps(relty)*(elty<:Complex ? 2:1) @test_approx_eq_eps D\U DM\U 2n^3*eps(relty)*(elty<:Complex ? 2:1) @@ -95,98 +106,100 @@ for relty in (Float32, Float64, BigFloat), elty in (relty, Complex{relty}) b = view(rand(elty,n+1),collect(1:n+1)) @test_throws DimensionMismatch A_ldiv_B!(D,b) end + end + end + debug && println("Binary operations") + d = convert(Vector{elty}, randn(n)) + D2 = Diagonal(d) + DM2= diagm(d) + for op in (+, -, *) + @test full(op(D, D2)) ≈ op(DM, DM2) + end + # binary ops with plain numbers + a = rand() + @test full(a*D) ≈ a*DM + @test full(D*a) ≈ DM*a + @test full(D/a) ≈ DM/a + if relty <: BlasFloat + b = rand(elty,n,n) + b = sparse(b) + @test A_mul_B!(copy(D), copy(b)) ≈ full(D)*full(b) + @test At_mul_B!(copy(D), copy(b)) ≈ full(D).'*full(b) + @test Ac_mul_B!(copy(D), copy(b)) ≈ full(D)'*full(b) + end - debug && println("Binary operations") - d = convert(Vector{elty}, randn(n)) - D2 = Diagonal(d) - DM2= diagm(d) - for op in (+, -, *) - @test full(op(D, D2)) ≈ op(DM, DM2) - end - # binary ops with plain numbers - a = rand() - @test full(a*D) ≈ a*DM - @test full(D*a) ≈ DM*a - @test full(D/a) ≈ DM/a - if relty <: BlasFloat - b = rand(elty,n,n) - b = sparse(b) - @test A_mul_B!(copy(D), copy(b)) ≈ full(D)*full(b) - @test At_mul_B!(copy(D), copy(b)) ≈ full(D).'*full(b) - @test Ac_mul_B!(copy(D), copy(b)) ≈ full(D)'*full(b) - end + #a few missing mults + bd = Bidiagonal(D2) + @test D*D2.' ≈ full(D)*full(D2).' + @test D2*D.' ≈ full(D2)*full(D).' + @test D2*D' ≈ full(D2)*full(D)' - @test U.'*D ≈ U.'*full(D) - @test U'*D ≈ U'*full(D) + #division of two Diagonals + @test D/D2 ≈ Diagonal(D.diag./D2.diag) + @test D\D2 ≈ Diagonal(D2.diag./D.diag) + # test triu/tril + @test istriu(D) + @test istril(D) + @test triu(D,1) == zeros(D) + @test triu(D,0) == D + @test triu(D,-1) == D + @test tril(D,1) == D + @test tril(D,-1) == zeros(D) + @test tril(D,0) == D + @test_throws ArgumentError tril(D,n+1) + @test_throws ArgumentError triu(D,n+1) - #division of two Diagonals - @test D/D2 ≈ Diagonal(D.diag./D2.diag) - @test D\D2 ≈ Diagonal(D2.diag./D.diag) - # test triu/tril - @test istriu(D) - @test istril(D) - @test triu(D,1) == zeros(D) - @test triu(D,0) == D - @test triu(D,-1) == D - @test tril(D,1) == D - @test tril(D,-1) == zeros(D) - @test tril(D,0) == D - @test_throws ArgumentError tril(D,n+1) - @test_throws ArgumentError triu(D,n+1) - - # factorize - @test factorize(D) == D - - debug && println("Eigensystem") - eigD = eigfact(D) - @test Diagonal(eigD[:values]) ≈ D - @test eigD[:vectors] == eye(D) - - debug && println("ldiv") - v = rand(n + 1) - @test_throws DimensionMismatch D\v - v = rand(n) - @test D\v ≈ DM\v - V = rand(n + 1, n) - @test_throws DimensionMismatch D\V - V = rand(n, n) - @test D\V ≈ DM\V - - debug && println("conj and transpose") - @test transpose(D) == D - if elty <: BlasComplex - @test full(conj(D)) ≈ conj(DM) - @test ctranspose(D) == conj(D) - end + # factorize + @test factorize(D) == D - #logdet - if relty <: Real - ld=convert(Vector{relty},rand(n)) - @test logdet(Diagonal(ld)) ≈ logdet(diagm(ld)) - end + debug && println("Eigensystem") + eigD = eigfact(D) + @test Diagonal(eigD[:values]) ≈ D + @test eigD[:vectors] == eye(D) - #similar - @test isa(similar(D), Diagonal{elty}) - @test isa(similar(D, Int), Diagonal{Int}) - @test isa(similar(D, (3,2)), Matrix{elty}) - @test isa(similar(D, Int, (3,2)), Matrix{Int}) - - #10036 - @test issymmetric(D2) - @test ishermitian(D2) - if elty <: Complex - dc = d + im*convert(Vector{elty}, ones(n)) - D3 = Diagonal(dc) - @test issymmetric(D3) - @test !ishermitian(D3) - end + debug && println("ldiv") + v = rand(n + 1) + @test_throws DimensionMismatch D\v + v = rand(n) + @test D\v ≈ DM\v + V = rand(n + 1, n) + @test_throws DimensionMismatch D\V + V = rand(n, n) + @test D\V ≈ DM\V - U, s, V = svd(D) - @test (U*Diagonal(s))*V' ≈ D - @test svdvals(D) == s - @test svdfact(D)[:V] == V - end + debug && println("conj and transpose") + @test transpose(D) == D + if elty <: BlasComplex + @test full(conj(D)) ≈ conj(DM) + @test ctranspose(D) == conj(D) end + + #logdet + if relty <: Real + ld=convert(Vector{relty},rand(n)) + @test logdet(Diagonal(ld)) ≈ logdet(diagm(ld)) + end + + #similar + @test isa(similar(D), Diagonal{elty}) + @test isa(similar(D, Int), Diagonal{Int}) + @test isa(similar(D, (3,2)), Matrix{elty}) + @test isa(similar(D, Int, (3,2)), Matrix{Int}) + + #10036 + @test issymmetric(D2) + @test ishermitian(D2) + if elty <: Complex + dc = d + im*convert(Vector{elty}, ones(n)) + D3 = Diagonal(dc) + @test issymmetric(D3) + @test !ishermitian(D3) + end + + U, s, V = svd(D) + @test (U*Diagonal(s))*V' ≈ D + @test svdvals(D) == s + @test svdfact(D)[:V] == V end D = Diagonal(Matrix{Float64}[randn(3,3), randn(2,2)]) diff --git a/test/linalg/matmul.jl b/test/linalg/matmul.jl index 44bb9a6afa85bf..4755f1d9ddd647 100644 --- a/test/linalg/matmul.jl +++ b/test/linalg/matmul.jl @@ -320,10 +320,10 @@ end immutable RootInt i::Int end -import Base: *, transpose, promote_op +import Base: *, transpose (*)(x::RootInt, y::RootInt) = x.i*y.i transpose(x::RootInt) = x -promote_op(::typeof(*), ::Type{RootInt}, ::Type{RootInt}) = Int +@test Base.promote_op(*, RootInt, RootInt) === Int a = [RootInt(3)] C = [0] diff --git a/test/linalg/uniformscaling.jl b/test/linalg/uniformscaling.jl index 4d1c3e20d0ad8a..477306c6fc6ba4 100644 --- a/test/linalg/uniformscaling.jl +++ b/test/linalg/uniformscaling.jl @@ -8,12 +8,20 @@ srand(123) @test I[1,1] == 1 # getindex @test I[1,2] == 0 # getindex @test I === I' # transpose +@test ndims(I) == 2 @test one(UniformScaling{Float32}) == UniformScaling(one(Float32)) @test zero(UniformScaling{Float32}) == UniformScaling(zero(Float32)) +@test eltype(one(UniformScaling{Float32})) == Float32 @test zero(UniformScaling(rand(Complex128))) == zero(UniformScaling{Complex128}) @test one(UniformScaling(rand(Complex128))) == one(UniformScaling{Complex128}) @test eltype(one(UniformScaling(rand(Complex128)))) == Complex128 @test -one(UniformScaling(2)) == UniformScaling(-1) +@test istriu(I) +@test istril(I) +@test issymmetric(I) +@test issymmetric(UniformScaling(complex(1.0,1.0))) +@test ishermitian(I) +@test !ishermitian(UniformScaling(complex(1.0,1.0))) α = randn() @test α .* UniformScaling(1.0) == UniformScaling(1.0) .* α diff --git a/test/misc.jl b/test/misc.jl index d10b46aafa7320..114c0f2b9079f4 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -206,6 +206,15 @@ end @test isa(ex, ErrorException) && ex.msg == "cannot assign variables in other modules" end +@test !Base.is_unix(:Windows) +@test !Base.is_linux(:Windows) +@test Base.is_linux(:Linux) +@test Base.is_windows(:Windows) +@test Base.is_windows(:NT) +@test !Base.is_windows(:Darwin) +@test Base.is_apple(:Darwin) +@test Base.is_apple(:Apple) +@test !Base.is_apple(:Windows) @test Base.is_unix(:Darwin) @test Base.is_unix(:FreeBSD) @test_throws ArgumentError Base.is_unix(:BeOS) @@ -221,7 +230,8 @@ module Tmp14173 A = randn(2000, 2000) end whos(IOBuffer(), Tmp14173) # warm up -@test @allocated(whos(IOBuffer(), Tmp14173)) < 10000 +const MEMDEBUG = ccall(:jl_is_memdebug, Bool, ()) +@test @allocated(whos(IOBuffer(), Tmp14173)) < (MEMDEBUG ? 30000 : 8000) ## test conversion from UTF-8 to UTF-16 (for Windows APIs) diff --git a/test/numbers.jl b/test/numbers.jl index 8ef819c0685ae1..5c5f322e265f55 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -2139,7 +2139,8 @@ rationalize(nextfloat(0.0)) == 0//1 # rational-exponent promotion rules (issue #3155): @test 2.0f0^(1//3) == 2.0f0^(1.0f0/3) @test 2^(1//3) == 2^(1/3) - +# no loss of precision for rational powers (issue #18114) +@test BigFloat(2)^(BigFloat(1)/BigFloat(3)) == BigFloat(2)^(1//3) # large shift amounts @test Int32(-1)>>31 == -1 @@ -2772,11 +2773,17 @@ testmi(map(UInt32, 0:1000), map(UInt32, 1:100)) testmi(typemax(UInt32)-UInt32(1000):typemax(UInt32), map(UInt32, 1:100)) @test ndims(1) == 0 +@test ndims(Integer) == 0 @test size(1,1) == 1 @test_throws BoundsError size(1,-1) @test indices(1) == () @test indices(1,1) == 1:1 @test_throws BoundsError indices(1,-1) +@test isinteger(Integer(2)) == true +@test size(1) == () +@test length(1) == 1 +@test endof(1) == 1 +@test eltype(Integer) == Integer # issue #15920 @test Rational(0, 1) / Complex(3, 2) == 0 @@ -2791,21 +2798,21 @@ let types = (Base.BitInteger_types..., BigInt, Bool, Complex{Int}, Complex{UInt}, Complex32, Complex64, Complex128) for S in types for op in (+, -) - T = @inferred Base.promote_op(op, S) + T = @inferred Base._promote_op(op, S) t = @inferred op(one(S)) @test T === typeof(t) end - end - - @test @inferred(Base.promote_op(!, Bool)) === Bool - for R in types, S in types - for op in (+, -, *, /, ^) - T = @inferred Base.promote_op(op, R, S) - t = @inferred op(one(R), one(S)) - @test T === typeof(t) + for R in types + for op in (+, -, *, /, ^) + T = @inferred Base._promote_op(op, S, R) + t = @inferred op(one(S), one(R)) + @test T === typeof(t) + end end end + + @test @inferred(Base._promote_op(!, Bool)) === Bool end let types = (Base.BitInteger_types..., BigInt, Bool, @@ -2813,23 +2820,23 @@ let types = (Base.BitInteger_types..., BigInt, Bool, Float16, Float32, Float64, BigFloat) for S in types, T in types for op in (<, >, <=, >=, (==)) - @test @inferred(Base.promote_op(op, S, T)) === Bool + @test @inferred(Base._promote_op(op, S, T)) === Bool end end end let types = (Base.BitInteger_types..., BigInt, Bool) for S in types - T = @inferred Base.promote_op(~, S) + T = @inferred Base._promote_op(~, S) t = @inferred ~one(S) @test T === typeof(t) - end - for S in types, T in types - for op in (&, |, <<, >>, (>>>), %, ÷) - T = @inferred Base.promote_op(op, S, T) - t = @inferred op(one(S), one(T)) - @test T === typeof(t) + for R in types + for op in (&, |, <<, >>, (>>>), %, ÷) + T = @inferred Base._promote_op(op, S, R) + t = @inferred op(one(S), one(R)) + @test T === typeof(t) + end end end end diff --git a/test/offsetarray.jl b/test/offsetarray.jl index a509e17d3a8fb2..0a200ac96a7921 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -1,108 +1,13 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license -# OffsetArrays (arrays with indexing that doesn't start at 1) - -# This test file is designed to exercise support for generic indexing, -# even though offset arrays aren't implemented in Base. - -module OAs - -using Base: Indices, LinearSlow, LinearFast, tail - -export OffsetArray - -immutable OffsetArray{T,N,AA<:AbstractArray} <: AbstractArray{T,N} - parent::AA - offsets::NTuple{N,Int} -end -typealias OffsetVector{T,AA<:AbstractArray} OffsetArray{T,1,AA} - -OffsetArray{T,N}(A::AbstractArray{T,N}, offsets::NTuple{N,Int}) = OffsetArray{T,N,typeof(A)}(A, offsets) -OffsetArray{T,N}(A::AbstractArray{T,N}, offsets::Vararg{Int,N}) = OffsetArray(A, offsets) - -(::Type{OffsetArray{T,N}}){T,N}(inds::Indices{N}) = OffsetArray{T,N,Array{T,N}}(Array{T,N}(map(length, inds)), map(indsoffset, inds)) -(::Type{OffsetArray{T}}){T,N}(inds::Indices{N}) = OffsetArray{T,N}(inds) - -Base.linearindexing{T<:OffsetArray}(::Type{T}) = Base.linearindexing(parenttype(T)) -parenttype{T,N,AA}(::Type{OffsetArray{T,N,AA}}) = AA -parenttype(A::OffsetArray) = parenttype(typeof(A)) - -Base.parent(A::OffsetArray) = A.parent - -errmsg(A) = error("size not supported for arrays with indices $(indices(A)); see http://docs.julialang.org/en/latest/devdocs/offset-arrays/") -Base.size(A::OffsetArray) = errmsg(A) -Base.size(A::OffsetArray, d) = errmsg(A) -Base.eachindex(::LinearSlow, A::OffsetArray) = CartesianRange(indices(A)) -Base.eachindex(::LinearFast, A::OffsetVector) = indices(A, 1) - -# Implementations of indices and indices1. Since bounds-checking is -# performance-critical and relies on indices, these are usually worth -# optimizing thoroughly. -@inline Base.indices(A::OffsetArray, d) = 1 <= d <= length(A.offsets) ? indices(parent(A))[d] + A.offsets[d] : (1:1) -@inline Base.indices(A::OffsetArray) = _indices(indices(parent(A)), A.offsets) # would rather use ntuple, but see #15276 -@inline _indices(inds, offsets) = (inds[1]+offsets[1], _indices(tail(inds), tail(offsets))...) -_indices(::Tuple{}, ::Tuple{}) = () -Base.indices1{T}(A::OffsetArray{T,0}) = 1:1 # we only need to specialize this one - -function Base.similar(A::OffsetArray, T::Type, dims::Dims) - B = similar(parent(A), T, dims) -end -function Base.similar(A::AbstractArray, T::Type, inds::Tuple{UnitRange,Vararg{UnitRange}}) - B = similar(A, T, map(length, inds)) - OffsetArray(B, map(indsoffset, inds)) -end - -Base.similar(f::Union{Function,DataType}, shape::Tuple{UnitRange,Vararg{UnitRange}}) = OffsetArray(f(map(length, shape)), map(indsoffset, shape)) - -Base.reshape(A::AbstractArray, inds::Tuple{UnitRange,Vararg{UnitRange}}) = OffsetArray(reshape(A, map(length, inds)), map(indsoffset, inds)) - -@inline function Base.getindex{T,N}(A::OffsetArray{T,N}, I::Vararg{Int,N}) - checkbounds(A, I...) - @inbounds ret = parent(A)[offset(A.offsets, I)...] - ret -end -@inline function Base._getindex(::LinearFast, A::OffsetVector, i::Int) - checkbounds(A, i) - @inbounds ret = parent(A)[offset(A.offsets, (i,))[1]] - ret -end -@inline function Base._getindex(::LinearFast, A::OffsetArray, i::Int) - checkbounds(A, i) - @inbounds ret = parent(A)[i] - ret -end -@inline function Base.setindex!{T,N}(A::OffsetArray{T,N}, val, I::Vararg{Int,N}) - checkbounds(A, I...) - @inbounds parent(A)[offset(A.offsets, I)...] = val - val -end -@inline function Base._setindex!(::LinearFast, A::OffsetVector, val, i::Int) - checkbounds(A, i) - @inbounds parent(A)[offset(A.offsets, (i,))[1]] = val - val -end -@inline function Base._setindex!(::LinearFast, A::OffsetArray, val, i::Int) - checkbounds(A, i) - @inbounds parent(A)[i] = val - val -end - -# Computing a shifted index (subtracting the offset) -offset{N}(offsets::NTuple{N,Int}, inds::NTuple{N,Int}) = _offset((), offsets, inds) -_offset(out, ::Tuple{}, ::Tuple{}) = out -@inline _offset(out, offsets, inds) = _offset((out..., inds[1]-offsets[1]), Base.tail(offsets), Base.tail(inds)) - -indsoffset(r::Range) = first(r) - 1 -indsoffset(i::Integer) = 0 - -end - -using OAs +isdefined(:TestHelpers) || include(joinpath(dirname(@__FILE__), "TestHelpers.jl")) +using TestHelpers.OAs let # Basics v0 = rand(4) v = OffsetArray(v0, (-3,)) +h = OffsetArray([-1,1,-2,2,0], (-3,)) @test indices(v) == (-2:1,) @test_throws ErrorException size(v) @test_throws ErrorException size(v, 1) @@ -144,6 +49,16 @@ S = OffsetArray(view(A0, 1:2, 1:2), (-1,2)) # LinearSlow @test eachindex(A) == 1:4 @test eachindex(S) == CartesianRange((0:1,3:4)) +# logical indexing +@test A[A .> 2] == [3,4] +@test_throws BoundsError h[trues(2)] +@test_throws BoundsError h[trues(5)] +@test h[OffsetArray(trues(5), (-3,))] == parent(h) +@test h[OffsetArray([true,false,false,true,true], (-3,))] == parent(h)[[1,4,5]] +@test A[OffsetArray([true false; false true], A.offsets)] == [1,4] +@test A[OffsetArray([true true; false true], A.offsets)] == [1,3,4] +@test_throws BoundsError A[[true true; false true]] + # view S = view(A, :, 3) @test S == OffsetArray([1,2], (A.offsets[1],)) @@ -219,11 +134,11 @@ cmp_showf(Base.print_matrix, io, OffsetArray(rand(5,5), (10,-9))) # rows&c cmp_showf(Base.print_matrix, io, OffsetArray(rand(10^3,5), (10,-9))) # columns fit cmp_showf(Base.print_matrix, io, OffsetArray(rand(5,10^3), (10,-9))) # rows fit cmp_showf(Base.print_matrix, io, OffsetArray(rand(10^3,10^3), (10,-9))) # neither fits -targets1 = ["0-dimensional OAs.OffsetArray{Float64,0,Array{Float64,0}}:\n1.0", - "OAs.OffsetArray{Float64,1,Array{Float64,1}} with indices 2:2:\n 1.0", - "OAs.OffsetArray{Float64,2,Array{Float64,2}} with indices 2:2×3:3:\n 1.0", - "OAs.OffsetArray{Float64,3,Array{Float64,3}} with indices 2:2×3:3×4:4:\n[:, :, 4] =\n 1.0", - "OAs.OffsetArray{Float64,4,Array{Float64,4}} with indices 2:2×3:3×4:4×5:5:\n[:, :, 4, 5] =\n 1.0"] +targets1 = ["0-dimensional TestHelpers.OAs.OffsetArray{Float64,0,Array{Float64,0}}:\n1.0", + "TestHelpers.OAs.OffsetArray{Float64,1,Array{Float64,1}} with indices 2:2:\n 1.0", + "TestHelpers.OAs.OffsetArray{Float64,2,Array{Float64,2}} with indices 2:2×3:3:\n 1.0", + "TestHelpers.OAs.OffsetArray{Float64,3,Array{Float64,3}} with indices 2:2×3:3×4:4:\n[:, :, 4] =\n 1.0", + "TestHelpers.OAs.OffsetArray{Float64,4,Array{Float64,4}} with indices 2:2×3:3×4:4×5:5:\n[:, :, 4, 5] =\n 1.0"] targets2 = ["(1.0,1.0)", "([1.0],[1.0])", "(\n[1.0],\n\n[1.0])", @@ -268,9 +183,6 @@ v = view(A0, i1, 1) v = view(A0, 1:1, i1) @test indices(v) === (Base.OneTo(1), -4:-3) -# logical indexing -@test A[A .> 2] == [3,4] - # copy! and fill! a = OffsetArray{Int}((-3:-1,)) fill!(a, -1) @@ -377,6 +289,14 @@ I,J,N = findnz(z) @test I == [-1] @test J == [0] @test N == [2] +@test find(h) == [-2:1;] +@test find(x->x>0, h) == [-1,1] +@test find(x->x<0, h) == [-2,0] +@test find(x->x==0, h) == [2] + +@test_approx_eq vecnorm(v) vecnorm(parent(v)) +@test_approx_eq vecnorm(A) vecnorm(parent(A)) +@test_approx_eq vecdot(v, v) vecdot(v0, v0) v = OffsetArray([1,1e100,1,-1e100], (-3,))*1000 v2 = OffsetArray([1,-1e100,1,1e100], (5,))*1000 @@ -418,3 +338,22 @@ v = OffsetArray(rand(8), (-2,)) @test A+A == OffsetArray(parent(A)+parent(A), A.offsets) @test A.*A == OffsetArray(parent(A).*parent(A), A.offsets) end + +end # let + +# Check that similar throws a MethodError rather than a +# StackOverflowError if no appropriate method has been defined +# (#18107) +module SimilarUR + using Base.Test + immutable MyURange <: AbstractUnitRange{Int} + start::Int + stop::Int + end + ur = MyURange(1,3) + a = Array{Int}(2) + @test_throws MethodError similar(a, ur) + @test_throws MethodError similar(a, Float64, ur) + @test_throws MethodError similar(a, Float64, (ur,)) + @test_throws MethodError similar(a, (2.0,3.0)) +end diff --git a/test/parallel_exec.jl b/test/parallel_exec.jl index a5be3fa85915d5..faeb7d165ae143 100644 --- a/test/parallel_exec.jl +++ b/test/parallel_exec.jl @@ -473,6 +473,18 @@ for (x,i) in enumerate(d) @test x == i end +# complex +sd = SharedArray(Int,10) +se = SharedArray(Int,10) +@sync @parallel for i=1:10 + sd[i] = i + se[i] = i +end +sc = complex(sd,se) +for (x,i) in enumerate(sc) + @test i == complex(x,x) +end + # Once finalized accessing remote references and shared arrays should result in exceptions. function finalize_and_test(r) finalize(r) diff --git a/test/parse.jl b/test/parse.jl index f33e55273118e8..50a6b61f437ae2 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -662,3 +662,11 @@ end # issue #17701 @test expand(:(i==3 && i+=1)) == Expr(:error, "invalid assignment location \"==(i,3)&&i\"") + +# PR #15592 +let str = "[1] [2]" + @test_throws ParseError parse(str) +end + +# issue 15896 and PR 15913 +@test_throws ErrorException eval(:(macro test15896(d; y=0) end)) diff --git a/test/perf/Makefile b/test/perf/Makefile index 0ff723aa70f7b7..adc07a2425e640 100644 --- a/test/perf/Makefile +++ b/test/perf/Makefile @@ -9,11 +9,7 @@ all: micro kernel cat shootout blas lapack simd sort spell sparse micro kernel cat shootout blas lapack simd sort spell sparse: @$(MAKE) $(QUIET_MAKE) -C $(SRCDIR)/shootout -ifneq ($(OS),WINNT) - @$(call spawn,$(JULIA_EXECUTABLE)) $(SRCDIR)/$@/perf.jl | perl -nle '@_=split/,/; printf "%-18s %8.3f %8.3f %8.3f %8.3f\n", $$_[1], $$_[2], $$_[3], $$_[4], $$_[5]' -else - @$(call spawn,$(JULIA_EXECUTABLE)) $(SRCDIR)/$@/perf.jl 2> /dev/null -endif + @$(call spawn,$(JULIA_EXECUTABLE)) $(call cygpath_w,$(SRCDIR)/$@/perf.jl) | perl -nle '@_=split/,/; printf "%-18s %8.3f %8.3f %8.3f %8.3f\n", $$_[1], $$_[2], $$_[3], $$_[4], $$_[5]' codespeed: @$(MAKE) $(QUIET_MAKE) -C $(SRCDIR)/shootout diff --git a/test/perf/shootout/README b/test/perf/shootout/README index 948bb7eeb447cd..ec8c91df1749cf 100644 --- a/test/perf/shootout/README +++ b/test/perf/shootout/README @@ -1,6 +1,6 @@ This directory contains the Julia version of the "The Computer Language Benchmarks Game": -http://shootout.alioth.debian.org/ +https://benchmarksgame.alioth.debian.org/ The source code for all the benchmarks are available there: http://alioth.debian.org/scm/viewvc.php/shootout/bench/?root=shootout diff --git a/test/perf/shootout/fasta.jl b/test/perf/shootout/fasta.jl index 13bbec2c228754..fe8129d1d74c7f 100644 --- a/test/perf/shootout/fasta.jl +++ b/test/perf/shootout/fasta.jl @@ -22,7 +22,7 @@ const IA = 3877.0 const IC = 29573.0 function gen_random() - global rng_state::Float64 = ((rng_state::Float64 * IA + IC) % IM) / IM + global rng_state = ((rng_state::Float64 * IA + IC) % IM) / IM end function repeat_fasta(src, n) k = length(src) @@ -55,7 +55,7 @@ end rng_state = 42.0 function fasta(n=25000000) - repeat_fasta(alu, 2n) - random_fasta(iub1, iub2, 3n) - random_fasta(homosapiens1, homosapiens2, 5n) + repeat_fasta(alu, 2n) + random_fasta(iub1, iub2, 3n) + random_fasta(homosapiens1, homosapiens2, 5n) end diff --git a/test/ranges.jl b/test/ranges.jl index c92ebeb385bbf4..b22db9b77a1b43 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -755,6 +755,7 @@ r = Base.OneTo(3) @test minimum(r) == 1 @test maximum(r) == 3 @test r[2] == 2 +@test r[2:3] === 2:3 @test_throws BoundsError r[4] @test_throws BoundsError r[0] @test r+1 === 2:4 diff --git a/test/replutil.jl b/test/replutil.jl index 4ad026f3a8f807..54e1f2a7aaf2c4 100644 --- a/test/replutil.jl +++ b/test/replutil.jl @@ -127,19 +127,19 @@ showerror(buf, m_error) error_out3 = takebuf_string(buf) if Base.have_color - @test contains(error_out, "method_c6(; x)$cfile$(c6line + 1)\e[1m\e[31m got an unsupported keyword argument \"y\"\e[0m") + @test contains(error_out, "method_c6(; x)$cfile$(c6line + 1)\e[1m\e[31m got unsupported keyword argument \"y\"\e[0m") @test contains(error_out, "method_c6(\e[1m\e[31m::Any\e[0m; y)$cfile$(c6line + 2)") - @test contains(error_out1, "method_c6(::Any; y)$cfile$(c6line + 2)\e[1m\e[31m got an unsupported keyword argument \"x\"\e[0m") - @test contains(error_out2, "method_c6_in_module(; x)$cfile$(c6mline + 2)\e[1m\e[31m got an unsupported keyword argument \"y\"\e[0m") + @test contains(error_out1, "method_c6(::Any; y)$cfile$(c6line + 2)\e[1m\e[31m got unsupported keyword argument \"x\"\e[0m") + @test contains(error_out2, "method_c6_in_module(; x)$cfile$(c6mline + 2)\e[1m\e[31m got unsupported keyword argument \"y\"\e[0m") @test contains(error_out2, "method_c6_in_module(\e[1m\e[31m::Any\e[0m; y)$cfile$(c6mline + 3)") - @test contains(error_out3, "method_c6_in_module(::Any; y)$cfile$(c6mline + 3)\e[1m\e[31m got an unsupported keyword argument \"x\"\e[0m") + @test contains(error_out3, "method_c6_in_module(::Any; y)$cfile$(c6mline + 3)\e[1m\e[31m got unsupported keyword argument \"x\"\e[0m") else - @test contains(error_out, "method_c6(; x)$cfile$(c6line + 1) got an unsupported keyword argument \"y\"") + @test contains(error_out, "method_c6(; x)$cfile$(c6line + 1) got unsupported keyword argument \"y\"") @test contains(error_out, "method_c6(!Matched::Any; y)$cfile$(c6line + 2)") - @test contains(error_out1, "method_c6(::Any; y)$cfile$(c6line + 2) got an unsupported keyword argument \"x\"") - @test contains(error_out2, "method_c6_in_module(; x)$cfile$(c6mline + 2) got an unsupported keyword argument \"y\"") + @test contains(error_out1, "method_c6(::Any; y)$cfile$(c6line + 2) got unsupported keyword argument \"x\"") + @test contains(error_out2, "method_c6_in_module(; x)$cfile$(c6mline + 2) got unsupported keyword argument \"y\"") @test contains(error_out2, "method_c6_in_module(!Matched::Any; y)$cfile$(c6mline + 3)") - @test contains(error_out3, "method_c6_in_module(::Any; y)$cfile$(c6mline + 3) got an unsupported keyword argument \"x\"") + @test contains(error_out3, "method_c6_in_module(::Any; y)$cfile$(c6mline + 3) got unsupported keyword argument \"x\"") end c7line = @__LINE__ + 1 @@ -150,16 +150,16 @@ test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c7(::Any, ::Any; c8line = @__LINE__ + 1 method_c8(a, b; y=1, w=1) = a Base.show_method_candidates(buf, MethodError(method_c8, (1, 1)), [(:x, 1), (:y, 2), (:z, 1), (:w, 1)]) -test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c8(::Any, ::Any; y, w)$cfile$c8line\e[1m\e[31m got an unsupported keyword argument \"x\", \"z\"\e[0m\e[0m", - "\nClosest candidates are:\n method_c8(::Any, ::Any; y, w)$cfile$c8line got an unsupported keyword argument \"x\", \"z\"") +test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c8(::Any, ::Any; y, w)$cfile$c8line\e[1m\e[31m got unsupported keyword arguments \"x\", \"z\"\e[0m\e[0m", + "\nClosest candidates are:\n method_c8(::Any, ::Any; y, w)$cfile$c8line got unsupported keyword arguments \"x\", \"z\"") ac15639line = @__LINE__ addConstraint_15639(c::Int32) = c addConstraint_15639(c::Int64; uncset=nothing) = addConstraint_15639(Int32(c), uncset=uncset) Base.show_method_candidates(buf, MethodError(addConstraint_15639, (Int32(1),)), [(:uncset, nothing)]) -test_have_color(buf, "\e[0m\nClosest candidates are:\n addConstraint_15639(::Int32)$cfile$(ac15639line + 1)\e[1m\e[31m got an unsupported keyword argument \"uncset\"\e[0m\n addConstraint_15639(\e[1m\e[31m::Int64\e[0m; uncset)$cfile$(ac15639line + 2)\e[0m", - "\nClosest candidates are:\n addConstraint_15639(::Int32)$cfile$(ac15639line + 1) got an unsupported keyword argument \"uncset\"\n addConstraint_15639(!Matched::Int64; uncset)$cfile$(ac15639line + 2)") +test_have_color(buf, "\e[0m\nClosest candidates are:\n addConstraint_15639(::Int32)$cfile$(ac15639line + 1)\e[1m\e[31m got unsupported keyword argument \"uncset\"\e[0m\n addConstraint_15639(\e[1m\e[31m::Int64\e[0m; uncset)$cfile$(ac15639line + 2)\e[0m", + "\nClosest candidates are:\n addConstraint_15639(::Int32)$cfile$(ac15639line + 1) got unsupported keyword argument \"uncset\"\n addConstraint_15639(!Matched::Int64; uncset)$cfile$(ac15639line + 2)") macro except_str(expr, err_type) return quote diff --git a/test/sparsedir/sparse.jl b/test/sparsedir/sparse.jl index e6d4e9767e2b1d..4cfc2b248097de 100644 --- a/test/sparsedir/sparse.jl +++ b/test/sparsedir/sparse.jl @@ -1588,3 +1588,8 @@ end # Test temporary fix for issue #16548 in PR #16979. Brittle. Expect to remove with `\` revisions. @test which(\, (SparseMatrixCSC, AbstractVecOrMat)).module == Base.SparseArrays + +# Row indexing a SparseMatrixCSC with non-Int integer type +let A = sparse(UInt32[1,2,3], UInt32[1,2,3], [1.0,2.0,3.0]) + @test A[1,1:3] == A[1,:] == [1,0,0] +end diff --git a/test/sparsedir/sparsevector.jl b/test/sparsedir/sparsevector.jl index 62a7649cc1e4d0..3811cb8bdeb214 100644 --- a/test/sparsedir/sparsevector.jl +++ b/test/sparsedir/sparsevector.jl @@ -225,6 +225,13 @@ let x = SparseVector(10, [2, 7, 9], [2.0, 7.0, 9.0]) @test Base.SparseArrays.dropstored!(x, 5) == SparseVector(10, [7, 9], [7.0, 9.0]) end +# find and findnz tests +@test find(spv_x1) == find(x1_full) +@test findnz(spv_x1) == (find(x1_full), filter(x->x!=0, x1_full)) +let xc = SparseVector(8, [2, 3, 5], [1.25, 0, -0.75]), fc = full(xc) + @test find(xc) == find(fc) + @test findnz(xc) == ([2, 5], [1.25, -0.75]) +end ### Array manipulation diff --git a/test/spawn.jl b/test/spawn.jl index 21ce279b5eb3e6..5379300b83ed42 100644 --- a/test/spawn.jl +++ b/test/spawn.jl @@ -428,3 +428,11 @@ if is_unix() end end end + +# Test for PR 17803 +let p=Pipe() + Base.link_pipe(p; julia_only_read=true, julia_only_write=true) + ccall(:jl_static_show, Void, (Ptr{Void}, Any), p.in, Int128(-1)) + @async close(p.in) + @test readstring(p.out) == "Int128(0xffffffffffffffffffffffffffffffff)" +end diff --git a/test/stacktraces.jl b/test/stacktraces.jl index 2f36384a11112a..2ba19b597b3ded 100644 --- a/test/stacktraces.jl +++ b/test/stacktraces.jl @@ -109,3 +109,13 @@ let li = typeof(getfield).name.mt.cache.func::LambdaInfo, repr = string(sf) @test repr == " in getfield(...) at b:3" end + +let ctestptr = cglobal((:ctest, "libccalltest")), + ctest = StackTraces.lookup(ctestptr + 1) + + @test length(ctest) == 1 + @test ctest[1].func === :ctest + @test isnull(ctest[1].linfo) + @test ctest[1].from_c + @test ctest[1].pointer === UInt64(ctestptr) +end diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 1008ce9566a177..e736da9e698906 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -7,6 +7,11 @@ let d = [0x61,0x62,0x63,0x21] end @test String("abc!") == "abc!" +@test isempty(string()) +@test eltype(GenericString) == Char +@test start("abc") == 1 +@test cmp("ab","abc") == -1 + # {starts,ends}with @test startswith("abcd", 'a') @test startswith("abcd", "a") diff --git a/test/strings/search.jl b/test/strings/search.jl index 6cc7b7233619af..8fcfe9c62d5d34 100644 --- a/test/strings/search.jl +++ b/test/strings/search.jl @@ -373,3 +373,5 @@ end # string searchindex with a two-char UTF-8 (4 byte) string literal @test rsearchindex("\U1f596\U1f596", "\U1f596\U1f596") == 1 @test rsearchindex("\U1f596\U1f596", "\U1f596\U1f596", endof("\U1f596\U1f596\U1f596")) == 1 + +@test_throws ErrorException "ab" ∈ "abc" diff --git a/test/subarray.jl b/test/subarray.jl index 0ca8b0b05c858f..2cfc8d772955d2 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -484,3 +484,15 @@ u = (1,2:3) let size=(x,y)-> error("should not happen") @test X[1:end,2,2] == @view X[1:end,2,2] end + +# issue #18034 +# ensure that it is possible to create an isbits, LinearFast view of an immutable Array +let + immutable ImmutableTestArray{T, N} <: Base.DenseArray{T, N} + end + Base.size(::Union{ImmutableTestArray, Type{ImmutableTestArray}}) = (0, 0) + Base.linearindexing(::Union{ImmutableTestArray, Type{ImmutableTestArray}}) = Base.LinearFast() + a = ImmutableTestArray{Float64, 2}() + @test Base.linearindexing(view(a, :, :)) == Base.LinearFast() + @test isbits(view(a, :, :)) +end diff --git a/test/sysinfo.jl b/test/sysinfo.jl index 645c34efce7658..261935ac715f15 100644 --- a/test/sysinfo.jl +++ b/test/sysinfo.jl @@ -6,34 +6,3 @@ sprint(Base.Sys.cpu_summary) @test Base.Sys.uptime() > 0 Base.Sys.loadavg() - -@test !("f=a=k=e=n=a=m=e" ∈ keys(ENV)) - -# issue #10994 -@test_throws ArgumentError ENV["bad\0name"] = "ok" -@test_throws ArgumentError ENV["okname"] = "bad\0val" -@test_throws ArgumentError Sys.set_process_title("bad\0title") - -withenv("bad"=>"dog") do - @test_throws ArgumentError ENV["bad\0cat"] -end - -# issue #11170 -withenv("TEST"=>"nonempty") do - @test ENV["TEST"] == "nonempty" -end -withenv("TEST"=>"") do - @test ENV["TEST"] == "" -end - -let c = collect(ENV) - @test isa(c, Vector) - @test length(ENV) == length(c) - @test isempty(ENV) || first(ENV) in c -end - -# test for non-existent keys -key = randstring(25) -@test !haskey(ENV,key) -@test_throws KeyError ENV[key] -@test get(ENV,key,"default") == "default" diff --git a/test/test.jl b/test/test.jl index d168a38eeb859f..7e2e8b70823af7 100644 --- a/test/test.jl +++ b/test/test.jl @@ -183,6 +183,50 @@ end @test typeof(tss[1]) == Base.Test.DefaultTestSet @test typeof(tss[1].results[1]) == Base.Test.Pass +# Issue #17908 (return) +testset_depth17908 = Test.get_testset_depth() +@testset for i in 1:3 + i > 1 && return + @test i == 1 +end +# The return aborts the control flow so the expression above doesn't return a +# value. The only thing we can test is whether the testset is properly popped. +# Do not use `@test` since the issue this is testing will swallow the error. +@assert testset_depth17908 == Test.get_testset_depth() + +# Issue #17462 and Issue #17908 (break, continue) +testset_depth17462 = Test.get_testset_depth() +counter_17462_pre = 0 +counter_17462_post = 0 +tss17462 = @testset for x in [1,2,3,4] + counter_17462_pre += 1 + if x == 1 + @test counter_17462_pre == x + continue + @test false + elseif x == 3 + @test counter_17462_pre == x + break + @test false + elseif x == 4 + @test false + else + @test counter_17462_pre == x + @test x == 2 + @test counter_17462_post == 0 + end + counter_17462_post += 1 +end +# Do not use `@test` since the issue this is testing will swallow the error. +# Same for the `@assert` in the for loop below +@assert testset_depth17462 == Test.get_testset_depth() +@assert length(tss17462) == 3 +for ts17462 in tss17462 + @assert isa(ts17462, Base.Test.DefaultTestSet) +end +@test counter_17462_pre == 3 +@test counter_17462_post == 1 + # now we're done running tests with DefaultTestSet so we can go back to STDOUT redirect_stdout(OLD_STDOUT) @@ -320,28 +364,3 @@ end @test @inferred(inferrable_kwtest(1; y=1)) == 2 @test @inferred(uninferrable_kwtest(1)) == 3 @test_throws ErrorException @inferred(uninferrable_kwtest(1; y=2)) == 2 - -# Issue #17462 -counter_17462_pre = 0 -counter_17462_post = 0 -@testset for x in [1,2,3,4] - counter_17462_pre += 1 - if x == 1 - @test counter_17462_pre == x - continue - @test false - elseif x == 3 - @test counter_17462_pre == x - break - @test false - elseif x == 4 - @test false - else - @test counter_17462_pre == x - @test x == 2 - @test counter_17462_post == 0 - end - counter_17462_post += 1 -end -@test counter_17462_pre == 3 -@test counter_17462_post == 1