diff --git a/LICENSE.md b/LICENSE.md index c3ec670c80402..a09b10901db12 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -83,7 +83,6 @@ Julia's build process uses the following external tools: Julia bundles the following external programs and libraries on some platforms: - [7-Zip](http://www.7-zip.org/license.txt) -- [BUSYBOX](https://github.com/rmyorston/busybox-w32/blob/master/LICENSE) - [GIT](http://git-scm.com/about/free-and-open-source) - [ZLIB](http://zlib.net/zlib_license.html) - [LIBEXPAT](http://expat.cvs.sourceforge.net/viewvc/expat/expat/README) diff --git a/Make.inc b/Make.inc index 569ffd1cee67a..a8e3c9b40284d 100644 --- a/Make.inc +++ b/Make.inc @@ -525,14 +525,9 @@ ISX86=1 else ifeq ($(ARCH),x86_64) BINARY=64 ISX86=1 -else ifneq (,$(findstring arm,$(ARCH))) -ISX86=0 -else ifneq (,$(findstring powerpc,$(ARCH))) -ISX86=0 -else ifneq (,$(findstring ppc,$(ARCH))) -ISX86=0 else -$(error "unknown word-size for arch: $(ARCH)") +# For all other architectures (ARM, PPC, AArch64, etc.) +ISX86=0 endif # If we are running on ARM, set certain options automatically diff --git a/Makefile b/Makefile index c2c6075abad27..06b5685842783 100644 --- a/Makefile +++ b/Makefile @@ -394,6 +394,12 @@ distclean dist-clean: dist: @echo \'dist\' target is deprecated: use \'binary-dist\' instead. +ifeq ($(ARCH),x86_64) +GITCONFIG := $(DESTDIR)$(prefix)/Git/mingw64/etc/gitconfig +else +GITCONFIG := $(DESTDIR)$(prefix)/Git/mingw32/etc/gitconfig +endif + binary-dist: distclean ifeq ($(USE_SYSTEM_BLAS),0) ifeq ($(ISX86),1) @@ -429,10 +435,8 @@ ifeq ($(OS), WINNT) 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 $(bindir) && \ mkdir $(DESTDIR)$(prefix)/Git && \ 7z x PortableGit.7z -o"$(DESTDIR)$(prefix)/Git" && \ - echo "[core] eol = lf" >> "$(DESTDIR)$(prefix)/Git/etc/gitconfig" && \ - sed -i "s/\bautocrlf = true$$/autocrlf = input/" "$(DESTDIR)$(prefix)/Git/etc/gitconfig" && \ - cp busybox.exe $(DESTDIR)$(prefix)/Git/bin/echo.exe && \ - cp busybox.exe $(DESTDIR)$(prefix)/Git/bin/printf.exe ) + echo "[core] eol = lf" >> "$(GITCONFIG)" && \ + sed -i "s/\bautocrlf = true$$/autocrlf = input/" "$(GITCONFIG)" ) cd $(DESTDIR)$(bindir) && 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. @@ -571,9 +575,7 @@ endif cd 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-1-g9eb16cb.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 busybox.exe + chmod a+x ./nsis/makensis.exe diff --git a/base/abstractarray.jl b/base/abstractarray.jl index d460af2ed1632..ba7721dc5ce8c 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -60,7 +60,7 @@ ndims{T,n}(::Type{AbstractArray{T,n}}) = n ndims{T<:AbstractArray}(::Type{T}) = ndims(super(T)) length(t::AbstractArray) = prod(size(t))::Int endof(a::AbstractArray) = length(a) -first(a::AbstractArray) = a[1] +first(a::AbstractArray) = a[first(eachindex(a))] function first(itr) state = start(itr) @@ -409,10 +409,10 @@ next(A::AbstractArray,i) = (@_inline_meta(); (idx, s) = next(i[1], i[2]); (A[idx done(A::AbstractArray,i) = done(i[1], i[2]) iterstate(i) = i +iterstate(i::Tuple{UnitRange{Int},Int}) = i[2] # eachindex iterates over all indices. LinearSlow definitions are later. eachindex(A::AbstractArray) = (@_inline_meta(); eachindex(linearindexing(A), A)) -eachindex(::LinearFast, A::AbstractArray) = 1:length(A) function eachindex(A::AbstractArray, B::AbstractArray) @_inline_meta @@ -422,8 +422,16 @@ function eachindex(A::AbstractArray, B::AbstractArray...) @_inline_meta eachindex(linearindexing(A,B...), A, B...) end -eachindex(::LinearFast, A::AbstractArray, B::AbstractArray) = 1:max(length(A),length(B)) -eachindex(::LinearFast, A::AbstractArray, B::AbstractArray...) = 1:max(length(A), map(length, B)...) +eachindex(::LinearFast, A::AbstractArray) = 1:length(A) +function eachindex(::LinearFast, A::AbstractArray, B::AbstractArray...) + @_inline_meta + 1:_maxlength(A, B...) +end +_maxlength(A) = length(A) +function _maxlength(A, B, C...) + @_inline_meta + max(length(A), _maxlength(B, C...)) +end isempty(a::AbstractArray) = (length(a) == 0) @@ -720,29 +728,29 @@ cat(catdim::Integer) = Array(Any, 0) vcat() = Array(Any, 0) hcat() = Array(Any, 0) +typed_vcat(T::Type) = Array(T, 0) +typed_hcat(T::Type) = Array(T, 0) ## cat: special cases -hcat{T}(X::T...) = T[ X[j] for i=1, j=1:length(X) ] -hcat{T<:Number}(X::T...) = T[ X[j] for i=1, j=1:length(X) ] vcat{T}(X::T...) = T[ X[i] for i=1:length(X) ] vcat{T<:Number}(X::T...) = T[ X[i] for i=1:length(X) ] +hcat{T}(X::T...) = T[ X[j] for i=1, j=1:length(X) ] +hcat{T<:Number}(X::T...) = T[ X[j] for i=1, j=1:length(X) ] -function vcat(X::Number...) - T = promote_typeof(X...) - hvcat_fill(Array(T,length(X)), X) -end +vcat(X::Number...) = hvcat_fill(Array(promote_typeof(X...),length(X)), X) +hcat(X::Number...) = hvcat_fill(Array(promote_typeof(X...),1,length(X)), X) +typed_vcat(T::Type, X::Number...) = hvcat_fill(Array(T,length(X)), X) +typed_hcat(T::Type, X::Number...) = hvcat_fill(Array(T,1,length(X)), X) -function hcat(X::Number...) - T = promote_typeof(X...) - hvcat_fill(Array(T,1,length(X)), X) -end +vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...) +vcat{T}(V::AbstractVector{T}...) = typed_vcat(T, V...) -function vcat{T}(V::AbstractVector{T}...) - n = 0 +function typed_vcat(T::Type, V::AbstractVector...) + n::Int = 0 for Vk in V n += length(Vk) end - a = similar(full(V[1]), n) + a = similar(full(V[1]), T, n) pos = 1 for k=1:length(V) Vk = V[k] @@ -753,7 +761,10 @@ function vcat{T}(V::AbstractVector{T}...) a end -function hcat{T}(A::AbstractVecOrMat{T}...) +hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...) +hcat{T}(A::AbstractVecOrMat{T}...) = typed_hcat(T, A...) + +function typed_hcat(T::Type, A::AbstractVecOrMat...) nargs = length(A) nrows = size(A[1], 1) ncols = 0 @@ -767,7 +778,7 @@ function hcat{T}(A::AbstractVecOrMat{T}...) nd = ndims(Aj) ncols += (nd==2 ? size(Aj,2) : 1) end - B = similar(full(A[1]), nrows, ncols) + B = similar(full(A[1]), T, nrows, ncols) pos = 1 if dense for k=1:nargs @@ -787,7 +798,10 @@ function hcat{T}(A::AbstractVecOrMat{T}...) return B end -function vcat{T}(A::AbstractMatrix{T}...) +vcat(A::AbstractMatrix...) = typed_vcat(promote_eltype(A...), A...) +vcat{T}(A::AbstractMatrix{T}...) = typed_vcat(T, A...) + +function typed_vcat(T::Type, A::AbstractMatrix...) nargs = length(A) nrows = sum(a->size(a, 1), A)::Int ncols = size(A[1], 2) @@ -796,7 +810,7 @@ function vcat{T}(A::AbstractMatrix{T}...) throw(ArgumentError("number of columns of each array must match (got $(map(x->size(x,2), A)))")) end end - B = similar(full(A[1]), nrows, ncols) + B = similar(full(A[1]), T, nrows, ncols) pos = 1 for k=1:nargs Ak = A[k] diff --git a/base/array.jl b/base/array.jl index d425ee3abed6d..51ffb9e055735 100644 --- a/base/array.jl +++ b/base/array.jl @@ -274,7 +274,7 @@ collect(itr) = collect(eltype(itr), itr) ## Iteration ## start(A::Array) = 1 next(a::Array,i) = (a[i],i+1) -done(a::Array,i) = (i > length(a)) +done(a::Array,i) = i == length(a)+1 ## Indexing: getindex ## diff --git a/base/bitarray.jl b/base/bitarray.jl index c84397571604c..6622383e9b327 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -1738,22 +1738,21 @@ function vcat(A::BitMatrix...) return B end +function cat(catdim::Integer, X::Integer...) + reshape([X...], (ones(Int,catdim-1)..., length(X))) +end + # general case, specialized for BitArrays and Integers function cat(catdim::Integer, X::Union{BitArray, Integer}...) nargs = length(X) # using integers results in conversion to Array{Int} # (except in the all-Bool case) - has_bitarray = false has_integer = false for a in X - if isa(a, BitArray) - has_bitarray = true - else - has_integer = true + if isa(a, Integer) + has_integer = true; break end end - # just integers and no BitArrays -> general case - has_bitarray || return invoke(cat, Tuple{Integer, Vararg{Any}}, catdim, X...) dimsX = map((a->isa(a,BitArray) ? size(a) : (1,)), X) ndimsX = map((a->isa(a,BitArray) ? ndims(a) : 1), X) d_max = maximum(ndimsX) diff --git a/base/channels.jl b/base/channels.jl index 4d1b1c881a9cb..a4ef643afae12 100644 --- a/base/channels.jl +++ b/base/channels.jl @@ -1,8 +1,8 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license -abstract AbstractChannel{T} +abstract AbstractChannel -type Channel{T} <: AbstractChannel{T} +type Channel{T} <: AbstractChannel cond_take::Condition # waiting for data to become available cond_put::Condition # waiting for a writeable slot state::Symbol diff --git a/base/client.jl b/base/client.jl index e64e58b2a917b..cd4c35632f482 100644 --- a/base/client.jl +++ b/base/client.jl @@ -212,110 +212,77 @@ function init_bind_addr() LPROC.bind_port = UInt16(bind_port) end -# NOTE: This set of required arguments need to be kept in sync with the required arguments defined in ui/repl.c -let reqarg = Set(UTF8String["--home", "-H", - "--eval", "-e", - "--print", "-E", - "--post-boot", "-P", - "--load", "-L", - "--sysimage", "-J", - "--cpu-target", "-C", - "--procs", "-p", - "--machinefile", - "--color", - "--history-file", - "--startup-file", - "--compile", - "--check-bounds", - "--depwarn", - "--inline", - "--output-o", - "--output-ji", - "--output-bc", - "--bind-to", - "--precompiled"]) - global process_options - function process_options(opts::JLOptions, args::Vector{UTF8String}) - if !isempty(args) - arg = first(args) - if !isempty(arg) && arg[1] == '-' && in(arg, reqarg) - println(STDERR, "julia: option `$arg` is missing an argument") - exit(1) - end - idxs = find(x -> x == "--", args) - if length(idxs) > 1 - println(STDERR, "julia: redundant option terminator `--`") - exit(1) - end - deleteat!(ARGS, idxs) +function process_options(opts::JLOptions, args::Vector{UTF8String}) + if !isempty(args) + arg = first(args) + idxs = find(x -> x == "--", args) + if length(idxs) > 1 + println(STDERR, "julia: redundant option terminator `--`") + exit(1) end - repl = true - startup = (opts.startupfile != 2) - history_file = (opts.historyfile != 0) - quiet = (opts.quiet != 0) - color_set = (opts.color != 0) - global have_color = (opts.color == 1) - global is_interactive = (opts.isinteractive != 0) - while true - # load ~/.juliarc file - startup && load_juliarc() - - # startup worker - if opts.worker != 0 - start_worker() # does not return - end - # add processors - if opts.nprocs > 0 - addprocs(opts.nprocs) - end - # load processes from machine file - if opts.machinefile != C_NULL - addprocs(load_machine_file(bytestring(opts.machinefile))) - end - # load file immediately on all processors - if opts.load != C_NULL - @sync for p in procs() - @async remotecall_fetch(p, include, bytestring(opts.load)) - end - end - # eval expression - if opts.eval != C_NULL - repl = false - eval(Main, parse_input_line(bytestring(opts.eval))) - break - end - # eval expression and show result - if opts.print != C_NULL - repl = false - show(eval(Main, parse_input_line(bytestring(opts.print)))) - println() - break - end - # eval expression but don't disable interactive mode - if opts.postboot != C_NULL - eval(Main, parse_input_line(bytestring(opts.postboot))) - end - # load file - if !isempty(args) - if !isempty(args[1]) && args[1][1] != '-' - # program - repl = false - # remove filename from ARGS - shift!(ARGS) - if !is_interactive - ccall(:jl_exit_on_sigint, Void, (Cint,), 1) - end - include(args[1]) - else - println(STDERR, "julia: unknown option `$(args[1])`") - exit(1) - end + deleteat!(ARGS, idxs) + end + repl = true + startup = (opts.startupfile != 2) + history_file = (opts.historyfile != 0) + quiet = (opts.quiet != 0) + color_set = (opts.color != 0) + global have_color = (opts.color == 1) + global is_interactive = (opts.isinteractive != 0) + while true + # load ~/.juliarc file + startup && load_juliarc() + + # startup worker + if opts.worker != 0 + start_worker() # does not return + end + # add processors + if opts.nprocs > 0 + addprocs(opts.nprocs) + end + # load processes from machine file + if opts.machinefile != C_NULL + addprocs(load_machine_file(bytestring(opts.machinefile))) + end + # load file immediately on all processors + if opts.load != C_NULL + @sync for p in procs() + @async remotecall_fetch(p, include, bytestring(opts.load)) end + end + # eval expression + if opts.eval != C_NULL + repl = false + eval(Main, parse_input_line(bytestring(opts.eval))) + break + end + # eval expression and show result + if opts.print != C_NULL + repl = false + show(eval(Main, parse_input_line(bytestring(opts.print)))) + println() break end - repl |= is_interactive - return (quiet,repl,startup,color_set,history_file) + # eval expression but don't disable interactive mode + if opts.postboot != C_NULL + eval(Main, parse_input_line(bytestring(opts.postboot))) + end + # load file + if !isempty(args) && !isempty(args[1]) + # program + repl = false + # remove filename from ARGS + shift!(ARGS) + if !is_interactive + ccall(:jl_exit_on_sigint, Void, (Cint,), 1) + end + include(args[1]) + end + break end + repl |= is_interactive + return (quiet,repl,startup,color_set,history_file) end const roottask = current_task() diff --git a/base/dates/conversions.jl b/base/dates/conversions.jl index afc7a6e2e1d6c..c37e86837464b 100644 --- a/base/dates/conversions.jl +++ b/base/dates/conversions.jl @@ -14,7 +14,7 @@ Base.convert{R<:Real}(::Type{R},x::Date) = convert(R,value(x)) ### External Conversions const UNIXEPOCH = value(DateTime(1970)) #Rata Die milliseconds for 1970-01-01T00:00:00 function unix2datetime(x) - rata = UNIXEPOCH + round(Int64,1000*x) + rata = UNIXEPOCH + round(Int64, Int64(1000) * x) return DateTime(UTM(rata)) end # Returns unix seconds since 1970-01-01T00:00:00 @@ -32,7 +32,7 @@ datetime2rata(dt::DateTime) = days(dt) # Julian conversions const JULIANEPOCH = value(DateTime(-4713,11,24,12)) function julian2datetime(f) - rata = JULIANEPOCH + round(Int64,86400000*f) + rata = JULIANEPOCH + round(Int64, Int64(86400000) * f) return DateTime(UTM(rata)) end # Returns # of julian days since -4713-11-24T12:00:00 diff --git a/base/dates/types.jl b/base/dates/types.jl index ce9c7cb933ee1..738dd02018c2d 100644 --- a/base/dates/types.jl +++ b/base/dates/types.jl @@ -80,17 +80,17 @@ daysinmonth(y,m) = DAYSINMONTH[m] + (m == 2 && isleapyear(y)) function DateTime(y::Int64,m::Int64=1,d::Int64=1, h::Int64=0,mi::Int64=0,s::Int64=0,ms::Int64=0) 0 < m < 13 || throw(ArgumentError("Month: $m out of range (1:12)")) - 0 < d < daysinmonth(y,m)+1 || throw(ArgumentError("Day: $d out of range (1:$daysinmonth(y,m))")) - -1 < h < 24 || throw(ArgumentError("Hour: $h out of range (1:23)")) - -1 < mi < 60 || throw(ArgumentError("Minute: $mi out of range (1:59)")) - -1 < s < 60 || throw(ArgumentError("Second: $s out of range (1:59)")) - -1 < ms < 1000 || throw(ArgumentError("Millisecond: $ms out of range (1:999)")) + 0 < d < daysinmonth(y,m)+1 || throw(ArgumentError("Day: $d out of range (1:$(daysinmonth(y,m)))")) + -1 < h < 24 || throw(ArgumentError("Hour: $h out of range (0:23)")) + -1 < mi < 60 || throw(ArgumentError("Minute: $mi out of range (0:59)")) + -1 < s < 60 || throw(ArgumentError("Second: $s out of range (0:59)")) + -1 < ms < 1000 || throw(ArgumentError("Millisecond: $ms out of range (0:999)")) rata = ms + 1000*(s + 60mi + 3600h + 86400*totaldays(y,m,d)) return DateTime(UTM(rata)) end function Date(y::Int64,m::Int64=1,d::Int64=1) 0 < m < 13 || throw(ArgumentError("Month: $m out of range (1:12)")) - 0 < d < daysinmonth(y,m)+1 || throw(ArgumentError("Day: $d out of range (1:$daysinmonth(y,m))")) + 0 < d < daysinmonth(y,m)+1 || throw(ArgumentError("Day: $d out of range (1:$(daysinmonth(y,m)))")) return Date(UTD(totaldays(y,m,d))) end @@ -109,22 +109,22 @@ function DateTime(periods::Period...) y = Year(1); m = Month(1); d = Day(1) h = Hour(0); mi = Minute(0); s = Second(0); ms = Millisecond(0) for p in periods - typeof(p) <: Year && (y = p) - typeof(p) <: Month && (m = p) - typeof(p) <: Day && (d = p) - typeof(p) <: Hour && (h = p) - typeof(p) <: Minute && (mi = p) - typeof(p) <: Second && (s = p) - typeof(p) <: Millisecond && (ms = p) + isa(p, Year) && (y = p::Year) + isa(p, Month) && (m = p::Month) + isa(p, Day) && (d = p::Day) + isa(p, Hour) && (h = p::Hour) + isa(p, Minute) && (mi = p::Minute) + isa(p, Second) && (s = p::Second) + isa(p, Millisecond) && (ms = p::Millisecond) end return DateTime(y,m,d,h,mi,s,ms) end function Date(periods::Period...) y = Year(1); m = Month(1); d = Day(1) for p in periods - typeof(p) <: Year && (y = p) - typeof(p) <: Month && (m = p) - typeof(p) <: Day && (d = p) + isa(p, Year) && (y = p::Year) + isa(p, Month) && (m = p::Month) + isa(p, Day) && (d = p::Day) end return Date(y,m,d) end diff --git a/base/deepcopy.jl b/base/deepcopy.jl index 787be75d00165..d705f0f74c00d 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -18,7 +18,10 @@ function deepcopy_internal(x::Function, stackdict::ObjectIdDict) if isa(x.env, Union{MethodTable, Symbol}) || x.env === () return x end - invoke(deepcopy_internal, Tuple{Any, ObjectIdDict}, x, stackdict) + if haskey(stackdict, x) + return stackdict[x] + end + _deepcopy_t(x, typeof(x), stackdict) end function deepcopy_internal(x, stackdict::ObjectIdDict) diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index acad83bc90515..7dc9821c03395 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -88,13 +88,17 @@ function doc!(obj, data) meta()[obj] = data end -"`doc(obj)`: Get the metadata associated with `obj`." -function doc(obj) +function get_obj_meta(obj) for mod in modules haskey(meta(mod), obj) && return meta(mod)[obj] end end +"`doc(obj)`: Get the metadata associated with `obj`." +function doc(obj) + get_obj_meta(obj) +end + function write_lambda_signature(io::IO, lam::LambdaStaticData) ex = Base.uncompressed_ast(lam) write(io, '(') @@ -143,7 +147,7 @@ function functionsummary(func::Function) end function doc(b::Binding) - d = invoke(doc, Tuple{Any}, b) + d = get_obj_meta(b) if d === nothing v = getfield(b.mod,b.var) d = doc(v) @@ -378,7 +382,7 @@ end # Modules function doc(m::Module) - md = invoke(doc, Tuple{Any}, m) + md = get_obj_meta(m) md === nothing || return md readme = Pkg.dir(string(m), "README.md") if isfile(readme) @@ -512,16 +516,12 @@ fexpr(ex) = isexpr(ex, [:function, :stagedfunction, :(=)]) && isexpr(ex.args[1], function docm(meta, def, define = true) - err = ( - "invalid doc expression:", def, isexpr(def, :macrocall) ? - "'$(def.args[1])' is not documentable. See 'help?> Base.@__doc__' for details." : "" - ) - def′ = unblock(def) isexpr(def′, :quote) && isexpr(def′.args[1], :macrocall) && return vardoc(meta, nothing, namify(def′.args[1])) + ex = def # Save unexpanded expression for error reporting. def = macroexpand(def) def′ = unblock(def) @@ -541,8 +541,23 @@ function docm(meta, def, define = true) isvar(def′) ? objdoc(meta, def′) : isexpr(def′, :tuple) ? multidoc(meta, def′.args) : __doc__!(meta, def′) ? esc(def′) : - isa(def′, Expr) ? error(strip(join(err, "\n\n"))) : - objdoc(meta, def′) + isexpr(def′, :error) ? esc(def′) : + + # All other expressions are undocumentable and should be handled on a case-by-case basis + # with `@__doc__`. Unbound string literals are also undocumentable since they cannot be + # retrieved from the `__META__` `ObjectIdDict` without a reference to the string. + isa(def′, Union{AbstractString, Expr}) ? docerror(ex) : objdoc(meta, def′) +end + +function docerror(ex) + txt = """ + invalid doc expression: + + @doc "..." $(isa(ex, AbstractString) ? repr(ex) : ex)""" + if isexpr(ex, :macrocall) + txt *= "\n\n'$(ex.args[1])' not documentable. See 'Base.@__doc__' docs for details." + end + :(error($txt, "\n")) end function docm(ex) diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index bdf5972339a11..fc8ea60defa50 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -501,6 +501,22 @@ keywords[:ccall] = doc""" in a call to `convert(ArgumentType, ArgumentValue)`. """ +keywords[:llvmcall] = doc""" + llvmcall(IR::String, ReturnType, (ArgumentType1, ...), ArgumentValue1, ...) + + Call LLVM IR string in the first argument. Similar to an LLVM function `define` + block, arguments are available as consecutive unnamed SSA variables (%0, %1, etc.). + + Note that the argument type tuple must be a literal tuple, and not a tuple-valued variable or expression. + + Each `ArgumentValue` to `llvmcall` will be converted to the corresponding `ArgumentType`, + by automatic insertion of calls to `unsafe_convert(ArgumentType, cconvert(ArgumentType, ArgumentValue))`. + (see also the documentation for each of these functions for further details). + In most cases, this simply results in a call to `convert(ArgumentType, ArgumentValue)`. + + See `test/llvmcall.jl` for usage examples. + """ + keywords[:begin] = doc""" `begin...end` denotes a block of code. diff --git a/base/docs/bootstrap.jl b/base/docs/bootstrap.jl index 9fbe4b4bfafe9..62f6e7cfc01d0 100644 --- a/base/docs/bootstrap.jl +++ b/base/docs/bootstrap.jl @@ -21,8 +21,8 @@ setexpand!(f) = global _expand_ = f function __bootexpand(str, obj) global docs = List((ccall(:jl_get_current_module, Any, ()), str, obj), docs) - (isa(obj, Expr) && obj.head == :call) && return nothing - (isa(obj, Expr) && obj.head == :module) && return esc(Expr(:toplevel, obj)) + (isa(obj, Expr) && obj.head === :call) && return nothing + (isa(obj, Expr) && obj.head === :module) && return esc(Expr(:toplevel, obj)) esc(obj) end @@ -45,6 +45,11 @@ that were stored in `DocBootstrap.docs` are migrated to their correct modules us """ DocBootstrap +""" + loaddocs() + +Move all docstrings from `DocBootstrap.docs` to their module's `__META__` dict. +""" function loaddocs() node = docs while node ≠ nothing diff --git a/base/docs/helpdb.jl b/base/docs/helpdb.jl index 0ede15da29136..5d3092e931b6a 100644 --- a/base/docs/helpdb.jl +++ b/base/docs/helpdb.jl @@ -328,7 +328,7 @@ Libdl.dlclose doc""" dlsym_e(handle, sym) -Look up a symbol from a shared library handle, silently return NULL pointer on lookup failure. +Look up a symbol from a shared library handle, silently return `NULL` pointer on lookup failure. """ Libdl.dlsym_e @@ -364,6 +364,13 @@ Convert a number of seconds since the epoch to broken-down format, with fields ` """ Libc.TmStruct +doc""" + dlext + +File extension for dynamic libraries (e.g. dll, dylib, so) on the current platform. +""" +Libdl.dlext + doc""" time(t::TmStruct) @@ -2264,7 +2271,7 @@ promote doc""" @schedule -Wrap an expression in a `Task` and add it to the scheduler's queue. +Wrap an expression in a `Task` and add it to the local machine's scheduler queue. """ :@schedule @@ -2438,7 +2445,7 @@ The function calls the C library CHOLMOD and many other functions from the libra ldltfact(A::SparseMatrixCSC; shift=0, perm=Int[]) doc""" - connect([host],port) -> TcpSocket + connect([host],port) -> TCPSocket Connect to the host `host` on port `port` """ @@ -3831,7 +3838,34 @@ utf8(s) doc""" hvcat(rows::Tuple{Vararg{Int}}, values...) -Horizontal and vertical concatenation in one call. This function is called for block matrix syntax. The first argument specifies the number of arguments to concatenate in each block row. For example, `[a b;c d e]` calls `hvcat((2,3),a,b,c,d,e)`. +Horizontal and vertical concatenation in one call. This function is called for block matrix syntax. The first argument specifies the number of arguments to concatenate in each block row. + +```jldoctest +julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6 +(1,2,3,4,5,6) + +julia> [a b c; d e f] +2x3 Array{Int64,2}: + 1 2 3 + 4 5 6 + +julia> hvcat((3,3), a,b,c,d,e,f) +2x3 Array{Int64,2}: + 1 2 3 + 4 5 6 + +julia> [a b;c d; e f] +3x2 Array{Int64,2}: + 1 2 + 3 4 + 5 6 + +julia> hvcat((2,2,2), a,b,c,d,e,f) +3x2 Array{Int64,2}: + 1 2 + 3 4 + 5 6 +``` If the first argument is a single integer `n`, then all block rows are assumed to have `n` block columns. """ @@ -3972,7 +4006,7 @@ doc""" Equivalent to ``addprocs(CPU_CORES)`` -Note that workers do not run a `.juliarc.jl` startup script, nor do they synchronize their global state +Note that workers do not run a ``.juliarc.jl`` startup script, nor do they synchronize their global state (such as global variables, new method definitions, and loaded modules) with any of the other running processes. ``` """ @@ -4183,7 +4217,11 @@ pipeline(command) doc""" serialize(stream, value) -Write an arbitrary value to a stream in an opaque format, such that it can be read back by `deserialize`. The read-back value will be as identical as possible to the original. In general, this process will not work if the reading and writing are done by different versions of Julia, or an instance of Julia with a different system image. +Write an arbitrary value to a stream in an opaque format, such that it can be read back by `deserialize`. +The read-back value will be as identical as possible to the original. +In general, this process will not work if the reading and writing are done by different versions of Julia, +or an instance of Julia with a different system image. +`Ptr` values are serialized as all-zero bit patterns (`NULL`). """ serialize @@ -4428,7 +4466,7 @@ erfinv doc""" @async -Wraps an expression in a closure and schedules it to run on the local machine. Also adds it to the set of items that the nearest enclosing `@sync` waits for. +Like `@schedule`, `@async` wraps an expression in a `Task` and adds it to the local machine's scheduler queue. Additionally it adds the task to the set of items that the nearest enclosing `@sync` waits for. `@async` also wraps the expression in a `let x=x, y=y, ...` block to create a new scope with copies of all variables referenced in the expression. """ :@async @@ -6413,13 +6451,6 @@ Wake up tasks waiting for a condition, passing them `val`. If `all` is `true` (t """ notify -doc""" - unique(itr[, dim]) - -Returns an array containing only the unique elements of the iterable `itr`, in the order that the first of each set of equivalent elements originally appears. If `dim` is specified, returns unique regions of the array `itr` along `dim`. -""" -unique - doc""" ```rst .. sub(A, inds...) @@ -6818,7 +6849,7 @@ A macro to execute an expression, and return the value of the expression, elapse doc""" code_native(f, types) -Prints the native assembly instructions generated for running the method matching the given generic function and type signature to STDOUT. +Prints the native assembly instructions generated for running the method matching the given generic function and type signature to `STDOUT`. """ code_native @@ -6980,9 +7011,9 @@ multiplied by the larger matrix dimension. For inverting dense ill-conditioned matrices in a least-squares sense, ``tol = sqrt(eps(real(float(one(eltype(M))))))`` is recommended. -For more information, see [8859]_, [B96]_, [S84]_, [KY88]_. +For more information, see [issue8859]_, [B96]_, [S84]_, [KY88]_. -.. [8859] Issue 8859, "Fix least squares", https://github.com/JuliaLang/julia/pull/8859 +.. [issue8859] Issue 8859, "Fix least squares", https://github.com/JuliaLang/julia/pull/8859 .. [B96] Åke Björck, "Numerical Methods for Least Squares Problems", SIAM Press, Philadelphia, 1996, "Other Titles in Applied Mathematics", Vol. 51. `doi:10.1137/1.9781611971484 `_ @@ -8640,9 +8671,9 @@ Similar to `search`, but return only the start index at which the substring is f searchindex doc""" - listenany(port_hint) -> (UInt16,TcpServer) + listenany(port_hint) -> (UInt16,TCPServer) -Create a TcpServer on any port, using hint as a starting point. Returns a tuple of the actual port that the server was created on and the server itself. +Create a `TCPServer` on any port, using hint as a starting point. Returns a tuple of the actual port that the server was created on and the server itself. """ listenany @@ -8748,7 +8779,7 @@ Intersects sets `s1` and `s2` and overwrites the set `s1` with the result. If ne intersect! doc""" - listen([addr,]port) -> TcpServer + listen([addr,]port) -> TCPServer Listen on port on the address specified by `addr`. By default this listens on localhost only. To listen on all interfaces pass `IPv4(0)` or `IPv6(0)` as appropriate. """ @@ -10194,14 +10225,14 @@ unescape_string doc""" redirect_stdout() -Create a pipe to which all C and Julia level STDOUT output will be redirected. Returns a tuple (rd,wr) representing the pipe ends. Data written to STDOUT may now be read from the rd end of the pipe. The wr end is given for convenience in case the old STDOUT object was cached by the user and needs to be replaced elsewhere. +Create a pipe to which all C and Julia level `STDOUT` output will be redirected. Returns a tuple `(rd,wr)` representing the pipe ends. Data written to `STDOUT` may now be read from the rd end of the pipe. The wr end is given for convenience in case the old `STDOUT` object was cached by the user and needs to be replaced elsewhere. """ redirect_stdout doc""" redirect_stdout(stream) -Replace STDOUT by stream for all C and julia level output to STDOUT. Note that `stream` must be a TTY, a Pipe or a TcpSocket. +Replace `STDOUT` by stream for all C and julia level output to `STDOUT`. Note that `stream` must be a TTY, a `Pipe` or a `TCPSocket`. """ redirect_stdout(stream) diff --git a/base/docs/utils.jl b/base/docs/utils.jl index 3df0009b0564c..160280da0d85b 100644 --- a/base/docs/utils.jl +++ b/base/docs/utils.jl @@ -126,13 +126,14 @@ repl(ex::Expr) = isregex(ex) ? :(apropos($ex)) : _repl(ex) repl(str::AbstractString) = :(apropos($str)) -repl(other) = nothing +repl(other) = :(@doc $(esc(other))) function _repl(x) docs = :(@doc $(esc(x))) - try - # Handles function call syntax where each argument is a symbol. - isexpr(x, :call) && (docs = Base.gen_call_with_extracted_types(doc, x)) + if isexpr(x, :call) + # Handles function call syntax where each argument is an atom (symbol, number, etc.) + t = Base.gen_call_with_extracted_types(doc, x) + (isexpr(t, :call, 3) && t.args[1] == doc) && (docs = t) end if isfield(x) quote diff --git a/base/float.jl b/base/float.jl index 8f681755f0645..35bb8a412df1c 100644 --- a/base/float.jl +++ b/base/float.jl @@ -399,36 +399,6 @@ end eps() = eps(Float64) end -# fused multiply-add -fma_libm(x::Float32, y::Float32, z::Float32) = - ccall(("fmaf", libm_name), Float32, (Float32,Float32,Float32), x, y, z) -fma_libm(x::Float64, y::Float64, z::Float64) = - ccall(("fma", libm_name), Float64, (Float64,Float64,Float64), x, y, z) -fma_llvm(x::Float32, y::Float32, z::Float32) = - box(Float32,fma_float(unbox(Float32,x),unbox(Float32,y),unbox(Float32,z))) -fma_llvm(x::Float64, y::Float64, z::Float64) = - box(Float64,fma_float(unbox(Float64,x),unbox(Float64,y),unbox(Float64,z))) -# Disable LLVM's fma if it is incorrect, e.g. because LLVM falls back -# onto a broken system libm; if so, use openlibm's fma instead -# 1.0000305f0 = 1 + 1/2^15 -# 1.0000000009313226 = 1 + 1/2^30 -# If fma_llvm() clobbers the rounding mode, the result of 0.1 + 0.2 will be 0.3 -# instead of the properly-rounded 0.30000000000000004; check after calling fma -if (fma_llvm(1.0000305f0, 1.0000305f0, -1.0f0) == 6.103609f-5 && - (fma_llvm(1.0000000009313226, 1.0000000009313226, -1.0) == - 1.8626451500983188e-9) && 0.1 + 0.2 == 0.30000000000000004) - fma(x::Float32, y::Float32, z::Float32) = fma_llvm(x,y,z) - fma(x::Float64, y::Float64, z::Float64) = fma_llvm(x,y,z) -else - fma(x::Float32, y::Float32, z::Float32) = fma_libm(x,y,z) - fma(x::Float64, y::Float64, z::Float64) = fma_libm(x,y,z) -end -# This is necessary at least on 32-bit Intel Linux, since fma_llvm may -# have called glibc, and some broken glibc fma implementations don't -# properly restore the rounding mode -Rounding.set_rounding_raw(Float32, Rounding.JL_FE_TONEAREST) -Rounding.set_rounding_raw(Float64, Rounding.JL_FE_TONEAREST) - ## byte order swaps for arbitrary-endianness serialization/deserialization ## bswap(x::Float32) = box(Float32,bswap_int(unbox(Float32,x))) bswap(x::Float64) = box(Float64,bswap_int(unbox(Float64,x))) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index f3442335f604b..8255399ded5e7 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -177,3 +177,33 @@ const ≈ = isapprox rtoldefault{T<:AbstractFloat}(::Type{T}) = sqrt(eps(T)) rtoldefault{T<:Real}(::Type{T}) = 0 rtoldefault{T<:Number,S<:Number}(x::Union{T,Type{T}}, y::Union{S,Type{S}}) = rtoldefault(promote_type(real(T),real(S))) + +# fused multiply-add +fma_libm(x::Float32, y::Float32, z::Float32) = + ccall(("fmaf", libm_name), Float32, (Float32,Float32,Float32), x, y, z) +fma_libm(x::Float64, y::Float64, z::Float64) = + ccall(("fma", libm_name), Float64, (Float64,Float64,Float64), x, y, z) +fma_llvm(x::Float32, y::Float32, z::Float32) = + box(Float32,fma_float(unbox(Float32,x),unbox(Float32,y),unbox(Float32,z))) +fma_llvm(x::Float64, y::Float64, z::Float64) = + box(Float64,fma_float(unbox(Float64,x),unbox(Float64,y),unbox(Float64,z))) +# Disable LLVM's fma if it is incorrect, e.g. because LLVM falls back +# onto a broken system libm; if so, use openlibm's fma instead +# 1.0000305f0 = 1 + 1/2^15 +# 1.0000000009313226 = 1 + 1/2^30 +# If fma_llvm() clobbers the rounding mode, the result of 0.1 + 0.2 will be 0.3 +# instead of the properly-rounded 0.30000000000000004; check after calling fma +if (ARCH != :i686 && fma_llvm(1.0000305f0, 1.0000305f0, -1.0f0) == 6.103609f-5 && + (fma_llvm(1.0000000009313226, 1.0000000009313226, -1.0) == + 1.8626451500983188e-9) && 0.1 + 0.2 == 0.30000000000000004) + fma(x::Float32, y::Float32, z::Float32) = fma_llvm(x,y,z) + fma(x::Float64, y::Float64, z::Float64) = fma_llvm(x,y,z) +else + fma(x::Float32, y::Float32, z::Float32) = fma_libm(x,y,z) + fma(x::Float64, y::Float64, z::Float64) = fma_libm(x,y,z) +end +# This is necessary at least on 32-bit Intel Linux, since fma_llvm may +# have called glibc, and some broken glibc fma implementations don't +# properly restore the rounding mode +Rounding.set_rounding_raw(Float32, Rounding.JL_FE_TONEAREST) +Rounding.set_rounding_raw(Float64, Rounding.JL_FE_TONEAREST) diff --git a/base/gmp.jl b/base/gmp.jl index 2f0063c51bde6..453110bfd5c4d 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -8,7 +8,7 @@ import Base: *, +, -, /, <, <<, >>, >>>, <=, ==, >, >=, ^, (~), (&), (|), ($), binomial, cmp, convert, div, divrem, factorial, fld, gcd, gcdx, lcm, mod, ndigits, promote_rule, rem, show, isqrt, string, isprime, powermod, sum, trailing_zeros, trailing_ones, count_ones, base, tryparse_internal, - bin, oct, dec, hex, isequal, invmod, prevpow2, nextpow2, ndigits0z, widen, signed + bin, oct, dec, hex, isequal, invmod, prevpow2, nextpow2, ndigits0z, widen, signed, unsafe_trunc, trunc if Clong == Int32 typealias ClongMax Union{Int8, Int16, Int32} @@ -120,13 +120,23 @@ end convert(::Type{BigInt}, x::Bool) = BigInt(UInt(x)) -function convert(::Type{BigInt}, x::Float64) - !isinteger(x) && throw(InexactError()) + +function unsafe_trunc(::Type{BigInt}, x::Union{Float32,Float64}) z = BigInt() ccall((:__gmpz_set_d, :libgmp), Void, (Ptr{BigInt}, Cdouble), &z, x) return z end +function convert(::Type{BigInt}, x::Union{Float32,Float64}) + isinteger(x) || throw(InexactError()) + unsafe_trunc(BigInt,x) +end + +function trunc(::Type{BigInt}, x::Union{Float32,Float64}) + isfinite(x) || throw(InexactError()) + unsafe_trunc(BigInt,x) +end + convert(::Type{BigInt}, x::Float16) = BigInt(Float64(x)) convert(::Type{BigInt}, x::Float32) = BigInt(Float64(x)) diff --git a/base/inference.jl b/base/inference.jl index 6c18058ae1e3e..dc07af2f2e5f5 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -2,7 +2,7 @@ # parameters limiting potentially-infinite types const MAX_TYPEUNION_LEN = 3 -const MAX_TYPE_DEPTH = 5 +const MAX_TYPE_DEPTH = 7 const MAX_TUPLETYPE_LEN = 8 const MAX_TUPLE_DEPTH = 4 diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 9908835420a28..bee7db3be6ebf 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -2,7 +2,14 @@ # editing files -function edit(file::AbstractString, line::Integer) +doc""" + editor() + +Determines the editor to use when running functions like `edit`. Returns an Array compatible +for use within backticks. You can change the editor by setting JULIA_EDITOR, VISUAL, or +EDITOR as an environmental variable. +""" +function editor() if OS_NAME == :Windows || OS_NAME == :Darwin default_editor = "open" elseif isreadable("/etc/alternatives/editor") @@ -10,39 +17,37 @@ function edit(file::AbstractString, line::Integer) else default_editor = "emacs" end - editor = get(ENV,"JULIA_EDITOR", get(ENV,"VISUAL", get(ENV,"EDITOR", default_editor))) - if ispath(editor) - if isreadable(editor) - edpath = realpath(editor) - edname = basename(edpath) - else - error("can't find \"$editor\"") - end - else - edpath = edname = editor - end + # Note: the editor path can include spaces (if escaped) and flags. + command = shell_split(get(ENV,"JULIA_EDITOR", get(ENV,"VISUAL", get(ENV,"EDITOR", default_editor)))) + isempty(command) && error("editor is empty") + return command +end + +function edit(file::AbstractString, line::Integer) + command = editor() + name = basename(first(command)) issrc = length(file)>2 && file[end-2:end] == ".jl" if issrc f = find_source_file(file) f !== nothing && (file = f) end const no_line_msg = "Unknown editor: no line number information passed.\nThe method is defined at line $line." - if startswith(edname, "emacs") || edname == "gedit" - spawn(`$edpath +$line $file`) - elseif edname == "vi" || edname == "vim" || edname == "nvim" || edname == "mvim" || edname == "nano" - run(`$edpath +$line $file`) - elseif edname == "textmate" || edname == "mate" || edname == "kate" - spawn(`$edpath $file -l $line`) - elseif startswith(edname, "subl") || edname == "atom" - spawn(`$(shell_split(edpath)) $file:$line`) - elseif OS_NAME == :Windows && (edname == "start" || edname == "open") + if startswith(name, "emacs") || name == "gedit" + spawn(`$command +$line $file`) + elseif name == "vi" || name == "vim" || name == "nvim" || name == "mvim" || name == "nano" + run(`$command +$line $file`) + elseif name == "textmate" || name == "mate" || name == "kate" + spawn(`$command $file -l $line`) + elseif startswith(name, "subl") || name == "atom" + spawn(`$command $file:$line`) + elseif OS_NAME == :Windows && (name == "start" || name == "open") spawn(`cmd /c start /b $file`) println(no_line_msg) - elseif OS_NAME == :Darwin && (edname == "start" || edname == "open") + elseif OS_NAME == :Darwin && (name == "start" || name == "open") spawn(`open -t $file`) println(no_line_msg) else - run(`$(shell_split(edpath)) $file`) + run(`$command $file`) println(no_line_msg) end nothing diff --git a/base/io.jl b/base/io.jl index 817c1bcaad7a3..ae6192f6a62a1 100644 --- a/base/io.jl +++ b/base/io.jl @@ -62,6 +62,8 @@ write(s::IO, x::Float16) = write(s, reinterpret(Int16,x)) write(s::IO, x::Float32) = write(s, reinterpret(Int32,x)) write(s::IO, x::Float64) = write(s, reinterpret(Int64,x)) +write(to::IO, p::Ptr) = write(to, convert(UInt, p)) + function write(s::IO, a::AbstractArray) nb = 0 for i in eachindex(a) @@ -119,6 +121,8 @@ read(s::IO, ::Type{Float16}) = box(Float16,unbox(Int16,read(s,Int16))) read(s::IO, ::Type{Float32}) = box(Float32,unbox(Int32,read(s,Int32))) read(s::IO, ::Type{Float64}) = box(Float64,unbox(Int64,read(s,Int64))) +read{T}(s::IO, ::Type{Ptr{T}}) = convert(Ptr{T}, read(s,UInt)) + read{T}(s::IO, t::Type{T}, d1::Int, dims::Int...) = read(s, t, tuple(d1,dims...)) read{T}(s::IO, t::Type{T}, d1::Integer, dims::Integer...) = read(s, t, convert(Tuple{Vararg{Int}},tuple(d1,dims...))) diff --git a/base/iobuffer.jl b/base/iobuffer.jl index 0b3c177b02b6e..3c66c7c018453 100644 --- a/base/iobuffer.jl +++ b/base/iobuffer.jl @@ -328,8 +328,6 @@ function write(to::AbstractIOBuffer, a::UInt8) sizeof(UInt8) end -write(to::AbstractIOBuffer, p::Ptr) = write(to, convert(UInt, p)) - function readbytes!(io::AbstractIOBuffer, b::Array{UInt8}, nb=length(b)) nr = min(nb, nb_available(io)) if length(b) < nr diff --git a/base/linalg/arnoldi.jl b/base/linalg/arnoldi.jl index a6c843605eed1..2eaf5bbc76c35 100644 --- a/base/linalg/arnoldi.jl +++ b/base/linalg/arnoldi.jl @@ -47,9 +47,21 @@ The following keyword arguments are supported: =============== ================================== ================================== ``` """ -eigs(A; args...) = eigs(A, I; args...) - - +eigs(A; kwargs...) = eigs(A, I; kwargs...) +eigs{T<:BlasFloat}(A::AbstractMatrix{T}, ::UniformScaling; kwargs...) = _eigs(A, I; kwargs...) + +eigs{T<:BlasFloat}(A::AbstractMatrix{T}, B::AbstractMatrix{T}; kwargs...) = _eigs(A, B; kwargs...) +eigs(A::AbstractMatrix{BigFloat}, B::AbstractMatrix...; kwargs...) = throw(MethodError(eigs, Any[A,B,kwargs...])) +eigs(A::AbstractMatrix{BigFloat}, B::UniformScaling; kwargs...) = throw(MethodError(eigs, Any[A,B,kwargs...])) +function eigs{T}(A::AbstractMatrix{T}, ::UniformScaling; kwargs...) + Tnew = typeof(zero(T)/sqrt(one(T))) + eigs(convert(AbstractMatrix{Tnew}, A), I; kwargs...) +end +function eigs(A::AbstractMatrix, B::AbstractMatrix; kwargs...) + T = promote_type(eltype(A), eltype(B)) + Tnew = typeof(zero(T)/sqrt(one(T))) + eigs(convert(AbstractMatrix{Tnew}, A), convert(AbstractMatrix{Tnew}, B); kwargs...) +end doc""" ```rst .. eigs(A, B; nev=6, ncv=max(20,2*nev+1), which="LM", tol=0.0, maxiter=300, sigma=nothing, ritzvec=true, v0=zeros((0,))) -> (d,[v,],nconv,niter,nmult,resid) @@ -94,7 +106,8 @@ The following keyword arguments are supported: =============== ================================== ================================== ``` """ -function eigs(A, B; +eigs(A, B; kwargs...) = _eigs(A, B; kwargs...) +function _eigs(A, B; nev::Integer=6, ncv::Integer=max(20,2*nev+1), which=:LM, tol=0.0, maxiter::Integer=300, sigma=nothing, v0::Vector=zeros(eltype(A),(0,)), ritzvec::Bool=true) @@ -134,7 +147,7 @@ function eigs(A, B; end if (which != :LM && which != :SM && which != :LR && which != :SR && which != :LI && which != :SI && which != :BE) - throw(ArgumentError("which must be :LM, :SM, :LR, :SR, :LI, :SI, or :BE, got $(repr(which))")) + throw(ArgumentError("which must be :LM, :SM, :LR, :SR, :LI, :SI, or :BE, got $(repr(which))")) end if which == :BE && !sym throw(ArgumentError("which=:BE only possible for real symmetric problem")) @@ -229,12 +242,19 @@ end ## svds - -type SVDOperator{T,S} <: AbstractArray{T, 2} +### Restrict operator to BlasFloat because ARPACK only supports that. Loosen restriction +### when we switch to our own implementation +type SVDOperator{T<:BlasFloat,S} <: AbstractArray{T, 2} X::S m::Int n::Int - SVDOperator(X::S) = new(X, size(X,1), size(X,2)) + SVDOperator(X::AbstractMatrix) = new(X, size(X, 1), size(X, 2)) +end + +function SVDOperator{T}(A::AbstractMatrix{T}) + Tnew = typeof(zero(T)/sqrt(one(T))) + Anew = convert(AbstractMatrix{Tnew}, A) + SVDOperator{Tnew,typeof(Anew)}(Anew) end ## v = [ left_singular_vector; right_singular_vector ] @@ -242,7 +262,14 @@ end size(s::SVDOperator) = s.m + s.n, s.m + s.n issym(s::SVDOperator) = true -function svds{S}(X::S; nsv::Int = 6, ritzvec::Bool = true, tol::Float64 = 0.0, maxiter::Int = 1000) +svds{T<:BlasFloat}(A::AbstractMatrix{T}; kwargs...) = _svds(A; kwargs...) +svds(A::AbstractMatrix{BigFloat}; kwargs...) = throw(MethodError(svds, Any[A, kwargs...])) +function svds{T}(A::AbstractMatrix{T}; kwargs...) + Tnew = typeof(zero(T)/sqrt(one(T))) + svds(convert(AbstractMatrix{Tnew}, A); kwargs...) +end +svds(A; kwargs...) = _svds(A; kwargs...) +function _svds(X; nsv::Int = 6, ritzvec::Bool = true, tol::Float64 = 0.0, maxiter::Int = 1000) if nsv < 1 throw(ArgumentError("number of singular values (nsv) must be ≥ 1, got $nsv")) end @@ -250,7 +277,7 @@ function svds{S}(X::S; nsv::Int = 6, ritzvec::Bool = true, tol::Float64 = 0.0, m throw(ArgumentError("number of singular values (nsv) must be ≤ $(minimum(size(X))), got $nsv")) end otype = eltype(X) - ex = eigs(SVDOperator{otype,S}(X), I; ritzvec = ritzvec, nev = 2*nsv, tol = tol, maxiter = maxiter) + ex = eigs(SVDOperator(X), I; ritzvec = ritzvec, nev = 2*nsv, tol = tol, maxiter = maxiter) ind = [1:2:nsv*2;] sval = abs(ex[1][ind]) diff --git a/base/linalg/arpack.jl b/base/linalg/arpack.jl index 9b31ab38ecb9a..ce564e2553b7e 100644 --- a/base/linalg/arpack.jl +++ b/base/linalg/arpack.jl @@ -59,7 +59,7 @@ function aupd_wrapper(T, matvecA::Function, matvecB::Function, solveSI::Function elseif ido[1] == 99 break else - error("Internal ARPACK error") + throw(ARPACKException("unexpected behavior")) end elseif mode == 3 && bmat == "I" # corresponds to dsdrv2, dndrv2 or zndrv2 if ido[1] == -1 || ido[1] == 1 @@ -67,7 +67,7 @@ function aupd_wrapper(T, matvecA::Function, matvecB::Function, solveSI::Function elseif ido[1] == 99 break else - error("Internal ARPACK error") + throw(ARPACKException("unexpected behavior")) end elseif mode == 2 # corresponds to dsdrv3, dndrv3 or zndrv3 if ido[1] == -1 || ido[1] == 1 @@ -81,7 +81,7 @@ function aupd_wrapper(T, matvecA::Function, matvecB::Function, solveSI::Function elseif ido[1] == 99 break else - error("Internal ARPACK error") + throw(ARPACKException("unexpected behavior")) end elseif mode == 3 && bmat == "G" # corresponds to dsdrv4, dndrv4 or zndrv4 if ido[1] == -1 @@ -93,7 +93,7 @@ function aupd_wrapper(T, matvecA::Function, matvecB::Function, solveSI::Function elseif ido[1] == 99 break else - error("Internal ARPACK error") + throw(ARPACKException("unexpected behavior")) end else throw(ArgumentError("ARPACK mode ($mode) not yet supported")) @@ -133,7 +133,9 @@ function eupd_wrapper(T, n::Integer, sym::Bool, cmplx::Bool, bmat::ByteString, neupd(ritzvec, howmny, select, d, v, ldv, sigmar, workev, bmat, n, which, nev, TOL, resid, ncv, v, ldv, iparam, ipntr, workd, workl, lworkl, rwork, info) - if info[1] != 0; throw(ARPACKException(info[1])); end + if info[1] != 0 + throw(ARPACKException(info[1])) + end p = sortperm(dmap(d[1:nev]), rev=true) return ritzvec ? (d[p], v[1:n, p],iparam[5],iparam[3],iparam[9],resid) : (d[p],iparam[5],iparam[3],iparam[9],resid) @@ -145,7 +147,9 @@ function eupd_wrapper(T, n::Integer, sym::Bool, cmplx::Bool, bmat::ByteString, seupd(ritzvec, howmny, select, d, v, ldv, sigmar, bmat, n, which, nev, TOL, resid, ncv, v, ldv, iparam, ipntr, workd, workl, lworkl, info) - if info[1] != 0; throw(ARPACKException(info[1])); end + if info[1] != 0 + throw(ARPACKException(info[1])) + end p = sortperm(dmap(d), rev=true) return ritzvec ? (d[p], v[1:n, p],iparam[5],iparam[3],iparam[9],resid) : (d,iparam[5],iparam[3],iparam[9],resid) @@ -162,7 +166,9 @@ function eupd_wrapper(T, n::Integer, sym::Bool, cmplx::Bool, bmat::ByteString, neupd(ritzvec, howmny, select, dr, di, v, ldv, sigmar, sigmai, workev, bmat, n, which, nev, TOL, resid, ncv, v, ldv, iparam, ipntr, workd, workl, lworkl, info) - if info[1] != 0; throw(ARPACKException(info[1])); end + if info[1] != 0 + throw(ARPACKException(info[1])) + end evec = complex(Array(T, n, nev+1), Array(T, n, nev+1)) j = 1 @@ -181,7 +187,7 @@ function eupd_wrapper(T, n::Integer, sym::Bool, cmplx::Bool, bmat::ByteString, evec[:,j] = v[:,j] j += 1 else - error("ARPACK unexpected behavior") + throw(ARPACKException("unexpected behavior")) end end diff --git a/base/linalg/exceptions.jl b/base/linalg/exceptions.jl index bd7686193c11e..c8975e45d53fc 100644 --- a/base/linalg/exceptions.jl +++ b/base/linalg/exceptions.jl @@ -11,7 +11,18 @@ type LAPACKException <: Exception end type ARPACKException <: Exception - info::BlasInt + info::ByteString +end + +function ARPACKException(i::Integer) + if i == -8 + return ARPACKException("error return from calculation of a real Schur form.") + elseif i == -9 + return ARPACKException("error return from calculation of eigenvectors.") + elseif i == -14 + return ARPACKException("did not find any eigenvalues to sufficient accuracy. Try with a different starting vector or more Lanczos vectors by increasing the value of ncv.") + end + return ARPACKException("unspecified ARPACK error: $i") end type SingularException <: Exception diff --git a/base/linalg/generic.jl b/base/linalg/generic.jl index bf2bcd1917cde..dd26028b58b60 100644 --- a/base/linalg/generic.jl +++ b/base/linalg/generic.jl @@ -8,8 +8,8 @@ scale(s::Number, X::AbstractArray) = s*X # For better performance when input and output are the same array # See https://github.com/JuliaLang/julia/issues/8415#issuecomment-56608729 function generic_scale!(X::AbstractArray, s::Number) - for i = 1:length(X) - @inbounds X[i] *= s + for I in eachindex(X) + @inbounds X[I] *= s end X end @@ -18,8 +18,14 @@ 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)).")) end - for i = 1:length(X) - @inbounds C[i] = X[i]*s + if size(C) == size(X) + for I in eachindex(C, X) + @inbounds C[I] = X[I]*s + end + else + for (IC, IX) in zip(eachindex(C), eachindex(X)) + @inbounds C[IC] = X[IX]*s + end end C end @@ -427,20 +433,20 @@ function peakflops(n::Integer=2000; parallel::Bool=false) parallel ? sum(pmap(peakflops, [ n for i in 1:nworkers()])) : (2*Float64(n)^3/t) end -# BLAS-like in-place y=alpha*x+y function (see also the version in blas.jl +# BLAS-like in-place y = x*α+y function (see also the version in blas.jl # for BlasFloat Arrays) -function axpy!(alpha, x::AbstractArray, y::AbstractArray) +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))")) end for i = 1:n - @inbounds y[i] += alpha * x[i] + @inbounds y[i] += x[i]*α end y end -function axpy!{Ti<:Integer,Tj<:Integer}(alpha, x::AbstractArray, rx::AbstractArray{Ti}, y::AbstractArray, ry::AbstractArray{Tj}) +function axpy!{Ti<:Integer,Tj<:Integer}(α, x::AbstractArray, rx::AbstractArray{Ti}, y::AbstractArray, ry::AbstractArray{Tj}) if length(x) != length(y) throw(DimensionMismatch("x has length $(length(x)), but y has length $(length(y))")) elseif minimum(rx) < 1 || maximum(rx) > length(x) @@ -451,7 +457,7 @@ function axpy!{Ti<:Integer,Tj<:Integer}(alpha, x::AbstractArray, rx::AbstractArr throw(ArgumentError("rx has length $(length(rx)), but ry has length $(length(ry))")) end for i = 1:length(rx) - @inbounds y[ry[i]] += alpha * x[rx[i]] + @inbounds y[ry[i]] += x[rx[i]]*α end y end diff --git a/base/linalg/lapack.jl b/base/linalg/lapack.jl index 05cb311911a6c..def4f795365bd 100644 --- a/base/linalg/lapack.jl +++ b/base/linalg/lapack.jl @@ -364,7 +364,7 @@ for (gebrd, gelqf, geqlf, geqrf, geqp3, geqrt, geqrt3, gerqf, getrf, elty, relty return A, tau, jpvt end - function geqrt!(A::StridedMatrix{$elty}, T::Matrix{$elty}) + function geqrt!(A::StridedMatrix{$elty}, T::StridedMatrix{$elty}) chkstride1(A) m, n = size(A) minmn = min(m, n) @@ -388,7 +388,7 @@ for (gebrd, gelqf, geqlf, geqrf, geqp3, geqrt, geqrt3, gerqf, getrf, elty, relty A, T end - function geqrt3!(A::StridedMatrix{$elty}, T::Matrix{$elty}) + function geqrt3!(A::StridedMatrix{$elty}, T::StridedMatrix{$elty}) chkstride1(A); chkstride1(T) m, n = size(A); p, q = size(T) if m < n @@ -546,7 +546,7 @@ dimension of `A`. Returns `A` and `T` modified in-place. """ -geqrt!(A::StridedMatrix, T::Matrix) +geqrt!(A::StridedMatrix, T::StridedMatrix) """ geqrt3!(A, T) @@ -559,7 +559,7 @@ equal the smallest dimension of `A`. Returns `A` and `T` modified in-place. """ -geqrt3!(A::StridedMatrix, T::Matrix) +geqrt3!(A::StridedMatrix, T::StridedMatrix) """ geqrf!(A, tau) @@ -1544,7 +1544,7 @@ for (geev, gesvd, gesdd, ggsvd, elty, relty) in # DOUBLE PRECISION ALPHA( * ), BETA( * ), RWORK( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), Q( LDQ, * ), # $ U( LDU, * ), V( LDV, * ), WORK( * ) - function ggsvd!(jobu::Char, jobv::Char, jobq::Char, A::Matrix{$elty}, B::Matrix{$elty}) + function ggsvd!(jobu::Char, jobv::Char, jobq::Char, A::StridedMatrix{$elty}, B::StridedMatrix{$elty}) chkstride1(A, B) m, n = size(A) if size(B, 2) != n @@ -1657,7 +1657,7 @@ diagonal. If `jobu = U`, the orthogonal/unitary matrix `U` is computed. If the orthogonal/unitary matrix `Q` is computed. If `job{u,v,q} = N`, that matrix is not computed. """ -ggsvd!(jobu::Char, jobv::Char, jobq::Char, A::Matrix, B::Matrix) +ggsvd!(jobu::Char, jobv::Char, jobq::Char, A::StridedMatrix, B::StridedMatrix) ## Expert driver and generalized eigenvalue problem for (geevx, ggev, elty) in @@ -2336,10 +2336,10 @@ for (orglq, orgqr, ormlq, ormqr, gemqrt, elty) in end C end - function gemqrt!(side::Char, trans::Char, V::Matrix{$elty}, T::Matrix{$elty}, C::StridedVecOrMat{$elty}) + function gemqrt!(side::Char, trans::Char, V::StridedMatrix{$elty}, T::StridedMatrix{$elty}, C::StridedVecOrMat{$elty}) chktrans(trans) chkside(side) - chkstride1(T, C) + chkstride1(V, T, C) m, n = ndims(C)==2 ? size(C) : (size(C, 1), 1) nb, k = size(T) if k == 0 return C end @@ -2371,7 +2371,7 @@ for (orglq, orgqr, ormlq, ormqr, gemqrt, elty) in if !(1 <= nb <= k) throw(DimensionMismatch("Wrong value for nb = $nb, which must be between 1 and $k")) end - ldc = max(1, stride(C,2)) + ldc = stride(C, 2) work = Array($elty, wss) info = Array(BlasInt, 1) ccall(($(blasfunc(gemqrt)), liblapack), Void, @@ -2381,7 +2381,7 @@ for (orglq, orgqr, ormlq, ormqr, gemqrt, elty) in Ptr{$elty}, Ptr{BlasInt}), &side, &trans, &m, &n, &k, &nb, V, &ldv, - T, &max(1,stride(T,2)), C, &ldc, + T, &max(1,stride(T,2)), C, &max(1,ldc), work, info) @lapackerror return C @@ -2433,7 +2433,7 @@ Computes `Q * C` (`trans = N`), `Q.' * C` (`trans = T`), `Q' * C` for `side = R` using `Q` from a `QR` factorization of `A` computed using `geqrt!`. `C` is overwritten. """ -gemqrt!(side::Char, trans::Char, V::Matrix, T::Matrix, C::StridedVecOrMat) +gemqrt!(side::Char, trans::Char, V::StridedMatrix, T::StridedMatrix, C::StridedVecOrMat) # (PO) positive-definite symmetric matrices, for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index 507cc0a1bffb8..8143a7b0b78cd 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -23,12 +23,12 @@ for t in (:LowerTriangular, :UnitLowerTriangular, :UpperTriangular, :UnitUpperTr convert{T,S}(::Type{Matrix}, A::$t{T,S}) = convert(Matrix{T}, A) function similar{T,S,Tnew}(A::$t{T,S}, ::Type{Tnew}, dims::Dims) - if dims[1] != dims[2] - throw(ArgumentError("Triangular matrix must be square")) - end if length(dims) != 2 throw(ArgumentError("Triangular matrix must have two dimensions")) end + if dims[1] != dims[2] + throw(ArgumentError("Triangular matrix must be square")) + end B = similar(A.data, Tnew, dims) return $t(B) end @@ -119,33 +119,41 @@ getindex{T,S}(A::UpperTriangular{T,S}, i::Integer, j::Integer) = i <= j ? A.data function setindex!(A::UpperTriangular, x, i::Integer, j::Integer) if i > j - throw(BoundsError(A,(i,j))) + x == 0 || throw(ArgumentError("cannot set index in the lower triangular part ($i, $j) of an UpperTriangular matrix to a nonzero value ($x)")) + else + A.data[i,j] = x end - A.data[i,j] = x return A end function setindex!(A::UnitUpperTriangular, x, i::Integer, j::Integer) - if i >= j - throw(BoundsError(A,(i,j))) + if i > j + x == 0 || throw(ArgumentError("cannot set index in the lower triangular part ($i, $j) of a UnitUpperTriangular matrix to a nonzero value ($x)")) + elseif i == j + x == 1 || throw(ArgumentError("cannot set index on the diagonal ($i, $j) of a UnitUpperTriangular matrix to a non-unit value ($x)")) + else + A.data[i,j] = x end - A.data[i,j] = x return A end function setindex!(A::LowerTriangular, x, i::Integer, j::Integer) if i < j - throw(BoundsError(A,(i,j))) + x == 0 || throw(ArgumentError("cannot set index in the upper triangular part ($i, $j) of a LowerTriangular matrix to a nonzero value ($x)")) + else + A.data[i,j] = x end - A.data[i,j] = x return A end function setindex!(A::UnitLowerTriangular, x, i::Integer, j::Integer) - if i <= j - throw(BoundsError(A,(i,j))) + if i < j + x == 0 || throw(ArgumentError("cannot set index in the upper triangular part ($i, $j) of a UnitLowerTriangular matrix to a nonzero value ($x)")) + elseif i == j + x == 1 || throw(ArgumentError("cannot set diagonal index ($i, $j) of a UnitLowerTriangular matrix to a non-unit value ($x)")) + else + A.data[i,j] = x end - A.data[i,j] = x return A end @@ -362,7 +370,7 @@ scale!(c::Number, A::Union{UpperTriangular,LowerTriangular}) = scale!(A,c) A_mul_B!(A::Tridiagonal, B::AbstractTriangular) = A*full!(B) A_mul_B!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = A_mul_B!(A, copy!(C, B)) -A_mul_Bc!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = A_mul_Bc!(A, copy!(C, B)) +A_mul_Bc!(C::AbstractVecOrMat, A::AbstractTriangular, B::AbstractVecOrMat) = A_mul_B!(A, ctranspose!(C, B)) for (t, uploc, isunitc) in ((:LowerTriangular, 'L', 'N'), (:UnitLowerTriangular, 'L', 'U'), @@ -979,41 +987,25 @@ for (f, g) in ((:*, :A_mul_B!), (:Ac_mul_B, :Ac_mul_B!), (:At_mul_B, :At_mul_B!) @eval begin function ($f){TA,TB}(A::AbstractTriangular{TA}, B::StridedVecOrMat{TB}) TAB = typeof(zero(TA)*zero(TB) + zero(TA)*zero(TB)) - ($g)(TA == TAB ? copy(A) : convert(AbstractArray{TAB}, A), TB == TAB ? copy(B) : convert(AbstractArray{TAB}, B)) + ($g)(convert(AbstractArray{TAB}, A), copy_oftype(B, TAB)) end end end ### Left division with triangle to the left hence rhs cannot be transposed. No quotients. for (f, g) in ((:\, :A_ldiv_B!), (:Ac_ldiv_B, :Ac_ldiv_B!), (:At_ldiv_B, :At_ldiv_B!)) @eval begin - function ($f){TA,TB,S}(A::UnitUpperTriangular{TA,S}, B::StridedVecOrMat{TB}) - TAB = typeof(zero(TA)*zero(TB) + zero(TA)*zero(TB)) - ($g)(TA == TAB ? copy(A) : convert(AbstractArray{TAB}, A), TB == TAB ? copy(B) : convert(AbstractArray{TAB}, B)) - end - end -end -for (f, g) in ((:\, :A_ldiv_B!), (:Ac_ldiv_B, :Ac_ldiv_B!), (:At_ldiv_B, :At_ldiv_B!)) - @eval begin - function ($f){TA,TB,S}(A::UnitLowerTriangular{TA,S}, B::StridedVecOrMat{TB}) + function ($f){TA,TB,S}(A::Union{UnitUpperTriangular{TA,S},UnitLowerTriangular{TA,S}}, B::StridedVecOrMat{TB}) TAB = typeof(zero(TA)*zero(TB) + zero(TA)*zero(TB)) - ($g)(TA == TAB ? copy(A) : convert(AbstractArray{TAB}, A), TB == TAB ? copy(B) : convert(AbstractArray{TAB}, B)) + ($g)(convert(AbstractArray{TAB}, A), copy_oftype(B, TAB)) end end end ### Left division with triangle to the left hence rhs cannot be transposed. Quotients. for (f, g) in ((:\, :A_ldiv_B!), (:Ac_ldiv_B, :Ac_ldiv_B!), (:At_ldiv_B, :At_ldiv_B!)) @eval begin - function ($f){TA,TB,S}(A::UpperTriangular{TA,S}, B::StridedVecOrMat{TB}) + function ($f){TA,TB,S}(A::Union{UpperTriangular{TA,S},LowerTriangular{TA,S}}, B::StridedVecOrMat{TB}) TAB = typeof((zero(TA)*zero(TB) + zero(TA)*zero(TB))/one(TA)) - ($g)(TA == TAB ? copy(A) : convert(AbstractArray{TAB}, A), TB == TAB ? copy(B) : convert(AbstractArray{TAB}, B)) - end - end -end -for (f, g) in ((:\, :A_ldiv_B!), (:Ac_ldiv_B, :Ac_ldiv_B!), (:At_ldiv_B, :At_ldiv_B!)) - @eval begin - function ($f){TA,TB,S}(A::LowerTriangular{TA,S}, B::StridedVecOrMat{TB}) - TAB = typeof((zero(TA)*zero(TB) + zero(TA)*zero(TB))/one(TA)) - ($g)(TA == TAB ? copy(A) : convert(AbstractArray{TAB}, A), TB == TAB ? copy(B) : convert(AbstractArray{TAB}, B)) + ($g)(convert(AbstractArray{TAB}, A), copy_oftype(B, TAB)) end end end @@ -1022,41 +1014,25 @@ for (f, g) in ((:*, :A_mul_B!), (:A_mul_Bc, :A_mul_Bc!), (:A_mul_Bt, :A_mul_Bt!) @eval begin function ($f){TA,TB}(A::StridedVecOrMat{TA}, B::AbstractTriangular{TB}) TAB = typeof(zero(TA)*zero(TB) + zero(TA)*zero(TB)) - ($g)(TA == TAB ? copy(A) : convert(AbstractArray{TAB}, A), TB == TAB ? copy(B) : convert(AbstractArray{TAB}, B)) + ($g)(copy_oftype(A, TAB), convert(AbstractArray{TAB}, B)) end end end ### Right division with triangle to the right hence lhs cannot be transposed. No quotients. for (f, g) in ((:/, :A_rdiv_B!), (:A_rdiv_Bc, :A_rdiv_Bc!), (:A_rdiv_Bt, :A_rdiv_Bt!)) @eval begin - function ($f){TA,TB,S}(A::StridedVecOrMat{TA}, B::UnitUpperTriangular{TB,S}) - TAB = typeof(zero(TA)*zero(TB) + zero(TA)*zero(TB)) - ($g)(TA == TAB ? copy(A) : convert(AbstractArray{TAB}, A), TB == TAB ? copy(B) : convert(AbstractArray{TAB}, B)) - end - end -end -for (f, g) in ((:/, :A_rdiv_B!), (:A_rdiv_Bc, :A_rdiv_Bc!), (:A_rdiv_Bt, :A_rdiv_Bt!)) - @eval begin - function ($f){TA,TB,S}(A::StridedVecOrMat{TA}, B::UnitLowerTriangular{TB,S}) + function ($f){TA,TB,S}(A::StridedVecOrMat{TA}, B::Union{UnitUpperTriangular{TB,S},UnitLowerTriangular{TB,S}}) TAB = typeof(zero(TA)*zero(TB) + zero(TA)*zero(TB)) - ($g)(TA == TAB ? copy(A) : convert(AbstractArray{TAB}, A), TB == TAB ? copy(B) : convert(AbstractArray{TAB}, B)) + ($g)(copy_oftype(A, TAB), convert(AbstractArray{TAB}, B)) end end end ### Right division with triangle to the right hence lhs cannot be transposed. Quotients. for (f, g) in ((:/, :A_rdiv_B!), (:A_rdiv_Bc, :A_rdiv_Bc!), (:A_rdiv_Bt, :A_rdiv_Bt!)) @eval begin - function ($f){TA,TB,S}(A::StridedVecOrMat{TA}, B::UpperTriangular{TB,S}) - TAB = typeof((zero(TA)*zero(TB) + zero(TA)*zero(TB))/one(TA)) - ($g)(TA == TAB ? copy(A) : convert(AbstractArray{TAB}, A), TB == TAB ? copy(B) : convert(AbstractArray{TAB}, B)) - end - end -end -for (f, g) in ((:/, :A_rdiv_B!), (:A_rdiv_Bc, :A_rdiv_Bc!), (:A_rdiv_Bt, :A_rdiv_Bt!)) - @eval begin - function ($f){TA,TB,S}(A::StridedVecOrMat{TA}, B::LowerTriangular{TB,S}) + function ($f){TA,TB,S}(A::StridedVecOrMat{TA}, B::Union{UpperTriangular{TB,S},LowerTriangular{TB,S}}) TAB = typeof((zero(TA)*zero(TB) + zero(TA)*zero(TB))/one(TA)) - ($g)(TA == TAB ? copy(A) : convert(AbstractArray{TAB}, A), TB == TAB ? copy(B) : convert(AbstractArray{TAB}, B)) + ($g)(copy_oftype(A, TAB), convert(AbstractArray{TAB}, B)) end end end diff --git a/base/loading.jl b/base/loading.jl index fd6ab8755f89a..0910b8160d8f3 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -336,6 +336,7 @@ function create_expr_cache(input::AbstractString, output::AbstractString) io, pobj = open(detach(`$(julia_cmd()) --output-ji $output --output-incremental=yes --startup-file=no --history-file=no + --color=$(have_color ? "yes" : "no") --eval $code_object`), "w", STDOUT) try serialize(io, quote @@ -429,7 +430,8 @@ function stale_cachefile(modpath, cachefile) return true # cache file was compiled from a different path end for (f,ftime) in files - if mtime(f) != ftime + # Issue #13606: compensate for Docker images rounding mtimes + if mtime(f) ∉ (ftime, floor(ftime)) return true end end diff --git a/base/markdown/render/terminal/render.jl b/base/markdown/render/terminal/render.jl index de76020494e05..9b2798632e78d 100644 --- a/base/markdown/render/terminal/render.jl +++ b/base/markdown/render/terminal/render.jl @@ -28,7 +28,6 @@ function term(io::IO, md::BlockQuote, columns) for line in split(rstrip(s), "\n") println(io, " "^margin, "|", line) end - println(io) end function term(io::IO, md::List, columns) @@ -93,7 +92,7 @@ function terminline(io::IO, content::Vector) end function terminline(io::IO, md::AbstractString) - print(io, md) + print(io, replace(md, r"[\s\t\n]+", " ")) end function terminline(io::IO, md::Bold) @@ -109,7 +108,7 @@ function terminline(io::IO, md::LineBreak) end function terminline(io::IO, md::Image) - print(io, "(Image: $(md.alt))") + terminline(io, "(Image: $(md.alt))") end function terminline(io::IO, md::Link) diff --git a/base/mmap.jl b/base/mmap.jl index 3a331d884bc0f..d7c645af42e97 100644 --- a/base/mmap.jl +++ b/base/mmap.jl @@ -68,16 +68,18 @@ end # @unix_only @windows_only begin -const PAGE_READONLY = UInt32(0x02) -const PAGE_READWRITE = UInt32(0x04) -const PAGE_WRITECOPY = UInt32(0x08) -const PAGE_EXECUTE_READ = UInt32(0x20) -const PAGE_EXECUTE_READWRITE = UInt32(0x40) -const PAGE_EXECUTE_WRITECOPY = UInt32(0x80) -const FILE_MAP_COPY = UInt32(0x01) -const FILE_MAP_WRITE = UInt32(0x02) -const FILE_MAP_READ = UInt32(0x04) -const FILE_MAP_EXECUTE = UInt32(0x20) +typealias DWORD Culong + +const PAGE_READONLY = DWORD(0x02) +const PAGE_READWRITE = DWORD(0x04) +const PAGE_WRITECOPY = DWORD(0x08) +const PAGE_EXECUTE_READ = DWORD(0x20) +const PAGE_EXECUTE_READWRITE = DWORD(0x40) +const PAGE_EXECUTE_WRITECOPY = DWORD(0x80) +const FILE_MAP_COPY = DWORD(0x01) +const FILE_MAP_WRITE = DWORD(0x02) +const FILE_MAP_READ = DWORD(0x04) +const FILE_MAP_EXECUTE = DWORD(0x20) function gethandle(io::IO) handle = Libc._get_osfhandle(RawFD(fd(io))).handle @@ -86,7 +88,7 @@ function gethandle(io::IO) end settings(sh::Anonymous) = utf16(sh.name), sh.readonly, sh.create -settings(io::IO) = convert(Ptr{Cwchar_t},C_NULL), isreadonly(io), true +settings(io::IO) = Ptr{Cwchar_t}(0), isreadonly(io), true end # @windows_only # core impelementation of mmap @@ -121,14 +123,14 @@ function mmap{T,N}(io::IO, @windows_only begin name, readonly, create = settings(io) - szfile = convert(Csize_t, len + offset) + szfile = convert(DWORD, len + offset) readonly && szfile > filesize(io) && throw(ArgumentError("unable to increase file size to $szfile due to read-only permissions")) - handle = create ? ccall(:CreateFileMappingW, stdcall, Ptr{Void}, (Cptrdiff_t, Ptr{Void}, Cint, Cint, Cint, Cwstring), + handle = create ? ccall(:CreateFileMappingW, stdcall, Ptr{Void}, (Cptrdiff_t, Ptr{Void}, DWORD, DWORD, DWORD, Cwstring), file_desc, C_NULL, readonly ? PAGE_READONLY : PAGE_READWRITE, szfile >> 32, szfile & typemax(UInt32), name) : - ccall(:OpenFileMappingW, stdcall, Ptr{Void}, (Cint, Cint, Cwstring), - readonly ? FILE_MAP_READ : FILE_MAP_WRITE, true, name) + ccall(:OpenFileMappingW, stdcall, Ptr{Void}, (DWORD, Cint, Cwstring), + readonly ? FILE_MAP_READ : FILE_MAP_WRITE, true, name) handle == C_NULL && error("could not create file mapping: $(Libc.FormatMessage())") - ptr = ccall(:MapViewOfFile, stdcall, Ptr{Void}, (Ptr{Void}, Cint, Cint, Cint, Csize_t), + ptr = ccall(:MapViewOfFile, stdcall, Ptr{Void}, (Ptr{Void}, DWORD, DWORD, DWORD, Csize_t), handle, readonly ? FILE_MAP_READ : FILE_MAP_WRITE, offset_page >> 32, offset_page & typemax(UInt32), (offset - offset_page) + len) ptr == C_NULL && error("could not create mapping view: $(Libc.FormatMessage())") end # @windows_only diff --git a/base/multi.jl b/base/multi.jl index 3378654457d59..b56ab8ce6a09f 100644 --- a/base/multi.jl +++ b/base/multi.jl @@ -460,7 +460,7 @@ end const client_refs = WeakKeyDict() -type RemoteRef{RemoteStore} +type RemoteRef{T<:AbstractChannel} where::Int whence::Int id::Int @@ -594,6 +594,7 @@ function send_add_client(rr::RemoteRef, i) end end +channel_type{T}(rr::RemoteRef{T}) = T function serialize(s::SerializationState, rr::RemoteRef) i = worker_id_from_socket(s.io) #println("$(myid()) serializing $rr to $i") @@ -604,14 +605,14 @@ function serialize(s::SerializationState, rr::RemoteRef) invoke(serialize, Tuple{SerializationState, Any}, s, rr) end -function deserialize(s::SerializationState, t::Type{RemoteRef}) +function deserialize{T<:RemoteRef}(s::SerializationState, t::Type{T}) rr = invoke(deserialize, Tuple{SerializationState, DataType}, s, t) where = rr.where if where == myid() add_client(rr2id(rr), myid()) end # call ctor to make sure this rr gets added to the client_refs table - RemoteRef(where, rr.whence, rr.id) + RemoteRef{channel_type(rr)}(where, rr.whence, rr.id) end # data stored by the owner of a RemoteRef @@ -743,8 +744,9 @@ function remotecall_wait(w::Worker, f, args...) rv.waitingfor = w.id rr = RemoteRef(w) send_msg(w, CallWaitMsg(f, args, rr2id(rr), prid)) - wait(rv) + v = fetch(rv.c) delete!(PGRP.refs, prid) + isa(v, RemoteException) && throw(v) rr end @@ -777,8 +779,18 @@ function call_on_owner(f, rr::RemoteRef, args...) end end -wait_ref(rid, args...) = (wait(lookup_ref(rid).c, args...); nothing) -wait(r::RemoteRef, args...) = (call_on_owner(wait_ref, r, args...); r) +function wait_ref(rid, callee, args...) + v = fetch_ref(rid, args...) + if isa(v, RemoteException) + if myid() == callee + throw(v) + else + return v + end + end + nothing +end +wait(r::RemoteRef, args...) = (call_on_owner(wait_ref, r, myid(), args...); r) fetch_ref(rid, args...) = fetch(lookup_ref(rid).c, args...) fetch(r::RemoteRef, args...) = call_on_owner(fetch_ref, r, args...) @@ -790,8 +802,12 @@ put_ref(rid, args...) = put!(lookup_ref(rid), args...) put!(rr::RemoteRef, args...) = (call_on_owner(put_ref, rr, args...); rr) take!(rv::RemoteValue, args...) = take!(rv.c, args...) -take_ref(rid, args...) = take!(lookup_ref(rid), args...) -take!(rr::RemoteRef, args...) = call_on_owner(take_ref, rr, args...) +function take_ref(rid, callee, args...) + v=take!(lookup_ref(rid), args...) + isa(v, RemoteException) && (myid() == callee) && throw(v) + v +end +take!(rr::RemoteRef, args...) = call_on_owner(take_ref, rr, myid(), args...) close_ref(rid) = (close(lookup_ref(rid).c); nothing) close(rr::RemoteRef) = call_on_owner(close_ref, rr) @@ -799,10 +815,10 @@ close(rr::RemoteRef) = call_on_owner(close_ref, rr) function deliver_result(sock::IO, msg, oid, value) #print("$(myid()) sending result $oid\n") - if is(msg,:call_fetch) + if is(msg,:call_fetch) || isa(value, RemoteException) val = value else - val = oid + val = :OK end try send_msg_now(sock, ResultMsg(oid, val)) @@ -897,7 +913,7 @@ end function handle_msg(msg::CallWaitMsg, r_stream, w_stream) @schedule begin rv = schedule_call(msg.response_oid, ()->msg.f(msg.args...)) - deliver_result(w_stream, :call_wait, msg.notify_oid, wait(rv)) + deliver_result(w_stream, :call_wait, msg.notify_oid, fetch(rv.c)) end end diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 56f882338ec36..5ff800c1cd492 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -820,6 +820,13 @@ immutable Prehashed end hash(x::Prehashed) = x.hash +doc""" + unique(itr[, dim]) + +Returns an array containing only the unique elements of the iterable `itr`, in +the order that the first of each set of equivalent elements originally appears. +If `dim` is specified, returns unique regions of the array `itr` along `dim`. +""" @generated function unique{T,N}(A::AbstractArray{T,N}, dim::Int) quote 1 <= dim <= $N || return copy(A) diff --git a/base/operators.jl b/base/operators.jl index ad7e66213b9b3..10e5a5982abef 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -252,7 +252,7 @@ end # for permutations that leave array elements in the same linear order. # those are the permutations that preserve the order of the non-singleton # dimensions. -function setindex_shape_check(X::AbstractArray, I::Int...) +function setindex_shape_check(X::AbstractArray, I...) li = ndims(X) lj = length(I) i = j = 1 @@ -289,16 +289,16 @@ end setindex_shape_check(X::AbstractArray) = (length(X)==1 || throw_setindex_mismatch(X,())) -setindex_shape_check(X::AbstractArray, i::Int) = +setindex_shape_check(X::AbstractArray, i) = (length(X)==i || throw_setindex_mismatch(X, (i,))) -setindex_shape_check{T}(X::AbstractArray{T,1}, i::Int) = +setindex_shape_check{T}(X::AbstractArray{T,1}, i) = (length(X)==i || throw_setindex_mismatch(X, (i,))) -setindex_shape_check{T}(X::AbstractArray{T,1}, i::Int, j::Int) = +setindex_shape_check{T}(X::AbstractArray{T,1}, i, j) = (length(X)==i*j || throw_setindex_mismatch(X, (i,j))) -function setindex_shape_check{T}(X::AbstractArray{T,2}, i::Int, j::Int) +function setindex_shape_check{T}(X::AbstractArray{T,2}, i, j) if length(X) != i*j throw_setindex_mismatch(X, (i,j)) end @@ -307,7 +307,7 @@ function setindex_shape_check{T}(X::AbstractArray{T,2}, i::Int, j::Int) throw_setindex_mismatch(X, (i,j)) end end -setindex_shape_check(X, I::Int...) = nothing # Non-arrays broadcast to all idxs +setindex_shape_check(X, I...) = nothing # Non-arrays broadcast to all idxs # convert to a supported index type (Array, Colon, or Int) to_index(i::Int) = i diff --git a/base/pkg/entry.jl b/base/pkg/entry.jl index 202bc382dd614..806f9d3976064 100644 --- a/base/pkg/entry.jl +++ b/base/pkg/entry.jl @@ -646,22 +646,72 @@ function warnbanner(msg...; label="[ WARNING ]", prefix="") warn(prefix="", "="^cols) end -function build!(pkgs::Vector, errs::Dict, seen::Set=Set()) +function build!(pkgs::Vector, buildstream::IO, seen::Set) for pkg in pkgs pkg == "julia" && continue pkg in seen && continue - build!(Read.requires_list(pkg),errs,push!(seen,pkg)) + build!(Read.requires_list(pkg),buildstream,push!(seen,pkg)) Read.isinstalled(pkg) || error("$pkg is not an installed package") path = abspath(pkg,"deps","build.jl") isfile(path) || continue - info("Building $pkg") - cd(dirname(path)) do - try evalfile(path) - catch err - warnbanner(err, label="[ ERROR: $pkg ]") + println(buildstream, path) # send to build process for evalfile + flush(buildstream) + end +end + +function build!(pkgs::Vector, errs::Dict, seen::Set=Set()) + # To isolate the build from the running Julia process, we + # execute the build.jl files in a separate process that + # is sitting there waiting for paths to evaluate. Errors + # are serialized to errfile for later retrieval into errs[pkg] + errfile = tempname() + close(open(errfile, "w")) # create empty file + code = """ + empty!(Base.LOAD_PATH) + append!(Base.LOAD_PATH, $(repr(Base.LOAD_PATH))) + empty!(Base.LOAD_CACHE_PATH) + append!(Base.LOAD_CACHE_PATH, $(repr(Base.LOAD_CACHE_PATH))) + empty!(Base.DL_LOAD_PATH) + append!(Base.DL_LOAD_PATH, $(repr(Base.DL_LOAD_PATH))) + open("$(escape_string(errfile))", "a") do f + for path_ in eachline(STDIN) + path = chomp(path_) + pkg = basename(dirname(dirname(path))) + try + info("Building \$pkg") + cd(dirname(path)) do + evalfile(path) + end + catch err + Base.Pkg.Entry.warnbanner(err, label="[ ERROR: \$pkg ]") + serialize(f, pkg) + serialize(f, err) + end + end + end + """ + io, pobj = open(detach(`$(Base.julia_cmd()) + --history-file=no + --color=$(Base.have_color ? "yes" : "no") + --eval $code`), "w", STDOUT) + try + build!(pkgs, io, seen) + close(io) + wait(pobj) + success(pobj) || error("Build process failed.") + open(errfile, "r") do f + while !eof(f) + pkg = deserialize(f) + err = deserialize(f) errs[pkg] = err end end + catch + kill(pobj) + close(io) + rethrow() + finally + isfile(errfile) && Base.rm(errfile) end end diff --git a/base/pkg/github.jl b/base/pkg/github.jl index 24310b8276f50..ea5ca6e58b87f 100644 --- a/base/pkg/github.jl +++ b/base/pkg/github.jl @@ -61,8 +61,12 @@ end function token(user::AbstractString=user()) tokfile = Dir.path(".github","token") - isfile(tokfile) && return strip(readchomp(tokfile)) - status, header, content = curl("https://api.github.com/authorizations",AUTH_DATA,`-u $user`) + if isfile(tokfile) + tok = strip(readchomp(tokfile)) + !isempty(tok) && return tok + end + params = merge(AUTH_DATA, ["fingerprint" => randstring(40)]) + status, header, content = curl("https://api.github.com/authorizations",params,`-u $user`) tfa = false # Check for two-factor authentication @@ -71,33 +75,12 @@ function token(user::AbstractString=user()) info("Two-factor authentication in use. Enter auth code. (You may have to re-enter your password.)") print(STDERR, "Authentication code: ") code = readline(STDIN) |> chomp - status, header, content = curl("https://api.github.com/authorizations",AUTH_DATA,`-H "X-GitHub-OTP: $code" -u $user`) + status, header, content = curl("https://api.github.com/authorizations",params,`-H "X-GitHub-OTP: $code" -u $user`) end if status == 422 error_code = json().parse(content)["errors"][1]["code"] - if error_code == "already_exists" - if tfa - info("Retrieving existing GitHub token. (You may have to re-enter your password twice more.)") - status, header, content = curl("https://api.github.com/authorizations",AUTH_DATA,`-u $user`) - status != 401 && error("$status: $(json().parse(content)["message"])") - print(STDERR, "New authentication code: ") - code = readline(STDIN) |> chomp - status, header, content = curl("https://api.github.com/authorizations",`-H "X-GitHub-OTP: $code" -u $user`) - else - info("Retrieving existing GitHub token. (You may have to re-enter your password.)") - status, header, content = curl("https://api.github.com/authorizations", `-u $user`) - end - (status >= 400) && error("$status: $(json().parse(content)["message"])") - for entry in json().parse(content) - if entry["note"] == AUTH_NOTE - tok = entry["token"] - break - end - end - else - error("GitHub returned validation error (422): $error_code: $(json().parse(content)["message"])") - end + error("GitHub returned validation error (422): $error_code: $(json().parse(content)["message"])") else (status != 401 && status != 403) || error("$status: $(json().parse(content)["message"])") tok = json().parse(content)["token"] diff --git a/base/reduce.jl b/base/reduce.jl index 7dbf314e7b601..1033394282f68 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -36,10 +36,10 @@ function mapfoldl_impl(f, op, v0, itr, i) # Unroll the while loop once; if v0 is known, the call to op may # be evaluated at compile time if done(itr, i) - return v0 + return r_promote(op, v0) else (x, i) = next(itr, i) - v = op(v0, f(x)) + v = op(r_promote(op, v0), f(x)) while !done(itr, i) (x, i) = next(itr, i) v = op(v, f(x)) @@ -71,10 +71,10 @@ function mapfoldr_impl(f, op, v0, itr, i::Integer) # Unroll the while loop once; if v0 is known, the call to op may # be evaluated at compile time if i == 0 - return v0 + return r_promote(op, v0) else x = itr[i] - v = op(f(x), v0) + v = op(f(x), r_promote(op, v0)) while i > 1 x = itr[i -= 1] v = op(f(x), v) diff --git a/base/reducedim.jl b/base/reducedim.jl index 77d1d0af5e1cb..55fb8c04794a1 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -325,12 +325,18 @@ function findminmax!{T,N}(f, Rval, Rind, A::AbstractArray{T,N}) Rval, Rind end -# findmin + +""" + findmin!(rval, rind, A, [init=true]) -> (minval, index) + +Find the minimum of `A` and the corresponding linear index along singleton +dimensions of `rval` and `rind`, and store the results in `rval` and `rind`. +""" function findmin!{R}(rval::AbstractArray{R}, rind::AbstractArray, A::AbstractArray; init::Bool=true) - findminmax!(LessFun(), initarray!(rval, typemax(R), init), rind, A) + findminmax!(LessFun(), initarray!(rval, MinFun(), init), rind, A) end function findmin{T}(A::AbstractArray{T}, region) @@ -342,12 +348,17 @@ function findmin{T}(A::AbstractArray{T}, region) zeros(Int, reduced_dims0(A, region)), A) end -# findmax +""" + findmax!(rval, rind, A, [init=true]) -> (maxval, index) + +Find the maximum of `A` and the corresponding linear index along singleton +dimensions of `rval` and `rind`, and store the results in `rval` and `rind`. +""" function findmax!{R}(rval::AbstractArray{R}, rind::AbstractArray, A::AbstractArray; init::Bool=true) - findminmax!(MoreFun(), initarray!(rval, typemin(R), init), rind, A) + findminmax!(MoreFun(), initarray!(rval, MaxFun(), init), rind, A) end function findmax{T}(A::AbstractArray{T}, region) diff --git a/base/serialize.jl b/base/serialize.jl index 5681286d1d6fb..1aa98f97a6f50 100644 --- a/base/serialize.jl +++ b/base/serialize.jl @@ -102,7 +102,7 @@ end serialize(s::SerializationState, x::Bool) = x ? writetag(s.io, TRUE_TAG) : writetag(s.io, FALSE_TAG) -serialize(s::SerializationState, ::Ptr) = error("cannot serialize a pointer") +serialize(s::SerializationState, p::Ptr) = serialize_any(s, oftype(p, C_NULL)) serialize(s::SerializationState, ::Tuple{}) = writetag(s.io, EMPTYTUPLE_TAG) @@ -124,7 +124,7 @@ function serialize(s::SerializationState, v::SimpleVector) writetag(s.io, SIMPLEVECTOR_TAG) write(s.io, Int32(length(v))) for i = 1:length(v) - serialize(s.io, v[i]) + serialize(s, v[i]) end end @@ -202,7 +202,7 @@ end function serialize{T<:AbstractString}(s::SerializationState, ss::SubString{T}) # avoid saving a copy of the parent string, keeping the type of ss - invoke(serialize, Tuple{SerializationState,Any}, s, convert(SubString{T}, convert(T,ss))) + serialize_any(s, convert(SubString{T}, convert(T,ss))) end # Don't serialize the pointers @@ -281,6 +281,8 @@ function serialize(s::SerializationState, f::Function) mod = () if isa(f.env,Symbol) mod = Core + elseif isdefined(f.env, :module) && isa(f.env.module, Module) + mod = f.env.module elseif !is(f.env.defs, ()) mod = f.env.defs.func.code.module end @@ -400,7 +402,9 @@ function serialize(s::SerializationState, n::Int) write(s.io, n) end -function serialize(s::SerializationState, x) +serialize(s::SerializationState, x) = serialize_any(s, x) + +function serialize_any(s::SerializationState, x) tag = sertag(x) if tag > 0 return write_as_tag(s.io, tag) @@ -647,8 +651,6 @@ function deserialize_datatype(s::SerializationState) deserialize(s, t) end -deserialize{T}(s::SerializationState, ::Type{Ptr{T}}) = convert(Ptr{T}, 0) - function deserialize(s::SerializationState, ::Type{Task}) t = Task(()->nothing) deserialize_cycle(s, t) diff --git a/base/set.jl b/base/set.jl index 857a36d9ea192..e8f2b10997023 100644 --- a/base/set.jl +++ b/base/set.jl @@ -28,7 +28,7 @@ length(s::Set) = length(s.dict) in(x, s::Set) = haskey(s.dict, x) push!(s::Set, x) = (s.dict[x] = nothing; s) pop!(s::Set, x) = (pop!(s.dict, x); x) -pop!(s::Set, x, deflt) = pop!(s.dict, x, deflt) == deflt ? deflt : x +pop!(s::Set, x, deflt) = x in s ? pop!(s, x) : deflt pop!(s::Set) = (idx = start(s.dict); val = s.dict.keys[idx]; _delete!(s.dict, idx); val) delete!(s::Set, x) = (delete!(s.dict, x); s) diff --git a/base/show.jl b/base/show.jl index 177ef7e7e43a0..68279acb7756d 100644 --- a/base/show.jl +++ b/base/show.jl @@ -342,6 +342,20 @@ is_quoted(ex::Expr) = is_expr(ex, :quote, 1) || is_expr(ex, :inert, 1) unquoted(ex::QuoteNode) = ex.value unquoted(ex::Expr) = ex.args[1] +function is_intrinsic_expr(x::ANY) + isa(x, IntrinsicFunction) && return true + if isa(x, GlobalRef) + x = x::GlobalRef + return (x.mod == Base && isdefined(Base, x.name) && + isa(getfield(Base, x.name), IntrinsicFunction)) + elseif isa(x, TopNode) + x = x::TopNode + return (isdefined(Base, x.name) && + isa(getfield(Base, x.name), IntrinsicFunction)) + end + return false +end + ## AST printing helpers ## const indent_width = 4 @@ -519,7 +533,7 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) head !== :row && print(io, cl) # function call - elseif head == :call && nargs >= 1 + elseif head === :call && nargs >= 1 func = args[1] fname = isa(func,GlobalRef) ? func.name : func func_prec = operator_precedence(fname) @@ -528,7 +542,9 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) end func_args = args[2:end] - if in(ex.args[1], (:box, TopNode(:box), :throw)) || ismodulecall(ex) + if (in(ex.args[1], (GlobalRef(Base, :box), TopNode(:box), :throw)) || + ismodulecall(ex) || + (ex.typ === Any && is_intrinsic_expr(ex.args[1]))) show_type = task_local_storage(:TYPEEMPHASIZE, false) end diff --git a/base/sparse/linalg.jl b/base/sparse/linalg.jl index ffad8c5f4b51a..d0ac6e6b35c52 100644 --- a/base/sparse/linalg.jl +++ b/base/sparse/linalg.jl @@ -181,16 +181,10 @@ end function fwdTriSolve!(A::SparseMatrixCSC, B::AbstractVecOrMat) # forward substitution for CSC matrices - n = length(B) - if isa(B, Vector) - nrowB = n - ncolB = 1 - else - nrowB, ncolB = size(B) - end - ncol = chksquare(A) + nrowB, ncolB = size(B, 1), size(B, 2) + ncol = LinAlg.chksquare(A) if nrowB != ncol - throw(DimensionMismatch("A is $(ncol)X$(ncol) and B has length $(n)")) + throw(DimensionMismatch("A is $(ncol) columns and B has $(nrowB) rows")) end aa = A.nzval @@ -199,33 +193,44 @@ function fwdTriSolve!(A::SparseMatrixCSC, B::AbstractVecOrMat) joff = 0 for k = 1:ncolB - for j = 1:(nrowB-1) - jb = joff + j + for j = 1:nrowB i1 = ia[j] - i2 = ia[j+1]-1 - B[jb] /= aa[i1] - bj = B[jb] - for i = i1+1:i2 - B[joff+ja[i]] -= bj*aa[i] + i2 = ia[j + 1] - 1 + + # loop through the structural zeros + ii = i1 + jai = ja[ii] + while ii <= i2 && jai < j + ii += 1 + jai = ja[ii] + end + + # check for zero pivot and divide with pivot + if jai == j + bj = B[joff + jai]/aa[ii] + B[joff + jai] = bj + ii += 1 + else + throw(LinAlg.SingularException(j)) + end + + # update remaining part + for i = ii:i2 + B[joff + ja[i]] -= bj*aa[i] end end joff += nrowB - B[joff] /= aa[end] end - return B + B end function bwdTriSolve!(A::SparseMatrixCSC, B::AbstractVecOrMat) # backward substitution for CSC matrices - n = length(B) - if isa(B, Vector) - nrowB = n - ncolB = 1 - else - nrowB, ncolB = size(B) + nrowB, ncolB = size(B, 1), size(B, 2) + ncol = LinAlg.chksquare(A) + if nrowB != ncol + throw(DimensionMismatch("A is $(ncol) columns and B has $(nrowB) rows")) end - ncol = chksquare(A) - if nrowB != ncol throw(DimensionMismatch("A is $(ncol)X$(ncol) and B has length $(n)")) end aa = A.nzval ja = A.rowval @@ -233,22 +238,43 @@ function bwdTriSolve!(A::SparseMatrixCSC, B::AbstractVecOrMat) joff = 0 for k = 1:ncolB - for j = nrowB:-1:2 - jb = joff + j + for j = nrowB:-1:1 i1 = ia[j] - i2 = ia[j+1]-1 - B[jb] /= aa[i2] - bj = B[jb] - for i = i2-1:-1:i1 - B[joff+ja[i]] -= bj*aa[i] + i2 = ia[j + 1] - 1 + + # loop through the structural zeros + ii = i2 + jai = ja[ii] + while ii >= i1 && jai > j + ii -= 1 + jai = ja[ii] + end + + # check for zero pivot and divide with pivot + if jai == j + bj = B[joff + jai]/aa[ii] + B[joff + jai] = bj + ii -= 1 + else + throw(LinAlg.SingularException(j)) + end + + # update remaining part + for i = ii:-1:i1 + B[joff + ja[i]] -= bj*aa[i] end end - B[joff+1] /= aa[1] joff += nrowB end - return B + B end +A_ldiv_B!{T,Ti}(L::LowerTriangular{T,SparseMatrixCSC{T,Ti}}, B::StridedVecOrMat) = fwdTriSolve!(L.data, B) +A_ldiv_B!{T,Ti}(U::UpperTriangular{T,SparseMatrixCSC{T,Ti}}, B::StridedVecOrMat) = bwdTriSolve!(U.data, B) + +(\){T,Ti}(L::LowerTriangular{T,SparseMatrixCSC{T,Ti}}, B::SparseMatrixCSC) = A_ldiv_B!(L, full(B)) +(\){T,Ti}(U::UpperTriangular{T,SparseMatrixCSC{T,Ti}}, B::SparseMatrixCSC) = A_ldiv_B!(U, full(B)) + ## triu, tril function triu{Tv,Ti}(S::SparseMatrixCSC{Tv,Ti}, k::Integer=0) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 124a368d751cc..ec0f8f4c1aa71 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -750,8 +750,8 @@ function gen_broadcast_body_sparse(f::Function, is_first_sparse::Bool) colptr1 = A_1.colptr; rowval1 = A_1.rowval; nzval1 = A_1.nzval colptr2 = A_2.colptr; rowval2 = A_2.rowval; nzval2 = A_2.nzval - nnzB = nnz(A_1) * div(B.n, A_1.n) * div(B.m, A_1.m) + - nnz(A_2) * div(B.n, A_2.n) * div(B.m, A_2.m) + nnzB = isempty(B) ? 0 : (nnz(A_1) * div(B.n, A_1.n) * div(B.m, A_1.m) + + nnz(A_2) * div(B.n, A_2.n) * div(B.m, A_2.m)) if length(rowvalB) < nnzB resize!(rowvalB, nnzB) end @@ -910,7 +910,8 @@ function gen_broadcast_body_zpreserving(f::Function, is_first_sparse::Bool) Base.Broadcast.check_broadcast_shape(size(B), $A1) Base.Broadcast.check_broadcast_shape(size(B), $A2) - nnzB = nnz($A1) * div(B.n, ($A1).n) * div(B.m, ($A1).m) + nnzB = isempty(B) ? 0 : + nnz($A1) * div(B.n, ($A1).n) * div(B.m, ($A1).m) if length(B.rowval) < nnzB resize!(B.rowval, nnzB) end @@ -1494,10 +1495,12 @@ function getindex_I_sorted{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVector, # Similar to getindex_general but without the transpose trick. (m, n) = size(A) - nI = length(I) - avgM = div(nnz(A),n) + nI = length(I) + nzA = nnz(A) + avgM = div(nzA,n) # heuristics based on experiments - alg = ((nI - avgM) > 2^8) ? 1 : + alg = ((m > nzA) && (m > nI)) ? 0 : + ((nI - avgM) > 2^8) ? 1 : ((avgM - nI) > 2^10) ? 0 : 2 (alg == 0) ? getindex_I_sorted_bsearch_A(A, I, J) : diff --git a/base/sparse/umfpack.jl b/base/sparse/umfpack.jl index 6310fb8f1d0a5..bbd50bc316c7a 100644 --- a/base/sparse/umfpack.jl +++ b/base/sparse/umfpack.jl @@ -12,45 +12,45 @@ import Base.SparseMatrix: increment, increment!, decrement, decrement!, nnz include("umfpack_h.jl") type MatrixIllConditionedException <: Exception - message :: AbstractString + message::AbstractString end function umferror(status::Integer) - if status==UMFPACK_OK - return - elseif status==UMFPACK_WARNING_singular_matrix - throw(MatrixIllConditionedException("singular matrix")) - elseif status==UMFPACK_WARNING_determinant_underflow - throw(MatrixIllConditionedException("the determinant is nonzero but underflowed")) - elseif status==UMFPACK_WARNING_determinant_overflow - throw(MatrixIllConditionedException("the determinant overflowed")) - elseif status==UMFPACK_ERROR_out_of_memory - throw(OutOfMemoryError()) - elseif status==UMFPACK_ERROR_invalid_Numeric_object - throw(ArgumentError("invalid UMFPack numeric object")) - elseif status==UMFPACK_ERROR_invalid_Symbolic_object - throw(ArgumentError("invalid UMFPack symbolic object")) - elseif status==UMFPACK_ERROR_argument_missing - throw(ArgumentError("a required argument to UMFPack is missing")) - elseif status==UMFPACK_ERROR_n_nonpositive - throw(BoundsError("the number of rows or columns of the matrix must be greater than zero")) - elseif status==UMFPACK_ERROR_invalid_matrix - throw(ArgumentError("invalid matrix")) - elseif status==UMFPACK_ERROR_different_pattern - throw(ArgumentError("pattern of the matrix changed")) - elseif status==UMFPACK_ERROR_invalid_system - throw(ArgumentError("invalid sys argument provided to UMFPack solver")) - elseif status==UMFPACK_ERROR_invalid_permutation - throw(ArgumentError("invalid permutation")) - elseif status==UMFPACK_ERROR_file_IO - throw(ErrorException("error saving / loading UMFPack decomposition")) - elseif status==UMFPACK_ERROR_ordering_failed - throw(ErrorException("the ordering method failed")) - elseif status==UMFPACK_ERROR_internal_error - throw(ErrorException("an internal error has occurred, of unknown cause")) - else - throw(ErrorException("unknown UMFPack error code: $status")) - end + if status==UMFPACK_OK + return + elseif status==UMFPACK_WARNING_singular_matrix + throw(LinAlg.SingularException(0)) + elseif status==UMFPACK_WARNING_determinant_underflow + throw(MatrixIllConditionedException("the determinant is nonzero but underflowed")) + elseif status==UMFPACK_WARNING_determinant_overflow + throw(MatrixIllConditionedException("the determinant overflowed")) + elseif status==UMFPACK_ERROR_out_of_memory + throw(OutOfMemoryError()) + elseif status==UMFPACK_ERROR_invalid_Numeric_object + throw(ArgumentError("invalid UMFPack numeric object")) + elseif status==UMFPACK_ERROR_invalid_Symbolic_object + throw(ArgumentError("invalid UMFPack symbolic object")) + elseif status==UMFPACK_ERROR_argument_missing + throw(ArgumentError("a required argument to UMFPack is missing")) + elseif status==UMFPACK_ERROR_n_nonpositive + throw(BoundsError("the number of rows or columns of the matrix must be greater than zero")) + elseif status==UMFPACK_ERROR_invalid_matrix + throw(ArgumentError("invalid matrix")) + elseif status==UMFPACK_ERROR_different_pattern + throw(ArgumentError("pattern of the matrix changed")) + elseif status==UMFPACK_ERROR_invalid_system + throw(ArgumentError("invalid sys argument provided to UMFPack solver")) + elseif status==UMFPACK_ERROR_invalid_permutation + throw(ArgumentError("invalid permutation")) + elseif status==UMFPACK_ERROR_file_IO + throw(ErrorException("error saving / loading UMFPack decomposition")) + elseif status==UMFPACK_ERROR_ordering_failed + throw(ErrorException("the ordering method failed")) + elseif status==UMFPACK_ERROR_internal_error + throw(ErrorException("an internal error has occurred, of unknown cause")) + else + throw(ErrorException("unknown UMFPack error code: $status")) + end end macro isok(A) @@ -170,8 +170,9 @@ for itype in UmfpackIndexTypes Ptr{Float64}, Ptr{Float64}), U.colptr, U.rowval, U.nzval, U.symbolic, tmp, umf_ctrl, umf_info) - status > 0 && throw(MatrixIllConditionedException("")) - umferror(status) + if status != UMFPACK_WARNING_singular_matrix + umferror(status) + end U.numeric = tmp[1] return U end @@ -184,8 +185,9 @@ for itype in UmfpackIndexTypes Ptr{Float64}, Ptr{Float64}), U.colptr, U.rowval, real(U.nzval), imag(U.nzval), U.symbolic, tmp, umf_ctrl, umf_info) - status > 0 && throw(MatrixIllConditionedException("")) - umferror(status) + if status != UMFPACK_WARNING_singular_matrix + umferror(status) + end U.numeric = tmp[1] return U end diff --git a/base/unicode/utf8proc.jl b/base/unicode/utf8proc.jl index 55ed682974a5c..1ed3c5112b984 100644 --- a/base/unicode/utf8proc.jl +++ b/base/unicode/utf8proc.jl @@ -219,7 +219,7 @@ function next(g::GraphemeIterator, i) k = ℓ c0 = c end - return (s[i:j], k) + return (SubString(s, i, j), k) end ==(g1::GraphemeIterator, g2::GraphemeIterator) = g1.s == g2.s diff --git a/contrib/Julia_Notepad++.xml b/contrib/Julia_Notepad++.xml index f92cbdf4a856f..b36f204656cb6 100644 --- a/contrib/Julia_Notepad++.xml +++ b/contrib/Julia_Notepad++.xml @@ -25,7 +25,7 @@ true false C_NULL Inf NaN Inf32 NaN32 nothing - ASCIIString AbstractArray AbstractMatrix AbstractSparseMatrix AbstractString AbstractVector Any ArgumentError Array Associative AsyncStream BigFloat BigInt BitArray BitMatrix BitVector Bool BunchKaufman ByteString Cchar Cdouble Cfloat Char CharString CholeskyDense CholeskyPivotedDense Cint Cintmax_t Clong Clonglong Colon Complex Complex128 Complex64 ComplexPair Cptrdiff_t Cshort Csize_t Cuchar Cuint Cuintmax_t Culong Culonglong Cushort DArray Dict Dims DisconnectException EOFError EachLine EnvHash ErrorException Exception Expr Factorization FileOffset Filter Float Float32 Float64 Function GSVDDense IO IOBuffer IOStream ImaginaryUnit InsertionSort Int Int128 Int16 Int32 Int64 Int8 IntSet Integer KeyError LDLTTridiagonal LUDense LUTridiagonal LoadError LocalProcess Matrix MergeSort MethodError NTuple Number ObjectIdDict ObjectIdDict OrdinalRange ParseError PipeBuffer ProcessGroup Ptr QRDense QRPivotedDense QuickSort Range Range1 RangeIndex Ranges Rational Real Regex RegexMatch RegexMatchIterator RemoteRef RepString RevString Reverse RopeString SVDDense Set Signed SparseMatrixCSC SpawnNullStream Stat StridedArray StridedMatrix StridedVecOrMat StridedVector SubArray SubDArray SubOrDArray SubString SymTridiagonal Symbol SystemError Task TcpSocket TimSort Tridiagonal Tuple Type TypeError UInt UInt128 UInt16 UInt32 UInt64 UInt8 UTF8String UVError Union Unsigned VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef Zip + ASCIIString AbstractArray AbstractMatrix AbstractSparseMatrix AbstractString AbstractVector Any ArgumentError Array Associative AsyncStream BigFloat BigInt BitArray BitMatrix BitVector Bool BunchKaufman ByteString Cchar Cdouble Cfloat Char CharString CholeskyDense CholeskyPivotedDense Cint Cintmax_t Clong Clonglong Colon Complex Complex128 Complex64 ComplexPair Cptrdiff_t Cshort Csize_t Cuchar Cuint Cuintmax_t Culong Culonglong Cushort DArray Dict Dims DisconnectException EOFError EachLine EnvHash ErrorException Exception Expr Factorization FileOffset Filter Float Float32 Float64 Function GSVDDense IO IOBuffer IOStream ImaginaryUnit InsertionSort Int Int128 Int16 Int32 Int64 Int8 IntSet Integer KeyError LDLTTridiagonal LUDense LUTridiagonal LoadError LocalProcess Matrix MergeSort MethodError NTuple Number ObjectIdDict ObjectIdDict OrdinalRange ParseError PipeBuffer ProcessGroup Ptr QRDense QRPivotedDense QuickSort Range Range1 RangeIndex Ranges Rational Real Regex RegexMatch RegexMatchIterator RemoteRef RepString RevString Reverse RopeString SVDDense Set Signed SparseMatrixCSC SpawnNullStream Stat StridedArray StridedMatrix StridedVecOrMat StridedVector SubArray SubDArray SubOrDArray SubString SymTridiagonal Symbol SystemError Task TCPSocket TimSort Tridiagonal Tuple Type TypeError UInt UInt128 UInt16 UInt32 UInt64 UInt8 UTF8String UVError Union Unsigned VecOrMat Vector VersionNumber Void WeakKeyDict WeakRef Zip abstract begin baremodule bitstype break catch ccall const continue do else elseif end export finally for function global if immutable import importall let local macro module quote return try type typealias using while close enumerate error info open print println read write warn print println diff --git a/contrib/windows/juliarc.jl b/contrib/windows/juliarc.jl index 533dc06c5fd34..db0e0ea61a36f 100644 --- a/contrib/windows/juliarc.jl +++ b/contrib/windows/juliarc.jl @@ -1,6 +1,4 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license -let user_data_dir - ENV["PATH"] = JULIA_HOME*";"*joinpath(JULIA_HOME,"..","Git","bin")*";"*ENV["PATH"] - #haskey(ENV,"JULIA_EDITOR") || (ENV["JULIA_EDITOR"] = "start") #start is not a program, so this doesn't work -end +ENV["PATH"] = JULIA_HOME*";"*joinpath(JULIA_HOME,"..","Git","bin")*";"* + joinpath(JULIA_HOME,"..","Git","usr","bin")*";"*ENV["PATH"] diff --git a/contrib/windows/msys_build.sh b/contrib/windows/msys_build.sh index c73daa86c79db..a6670b5f737ec 100755 --- a/contrib/windows/msys_build.sh +++ b/contrib/windows/msys_build.sh @@ -106,7 +106,8 @@ if ! [ -e julia-installer.exe ]; then echo "Extracting $f" $SEVENZIP x -y $f >> get-deps.log fi -for i in bin/*.dll Git/bin/msys-1.0.dll Git/bin/msys-perl5_8.dll Git/bin/*.exe; do +# TODO: replace Git/bin with Git/usr/bin after 0.4.1 is released +for i in bin/*.dll Git/bin/*.dll Git/bin/*.exe; do $SEVENZIP e -y julia-installer.exe "\$_OUTDIR/$i" \ -ousr\\`dirname $i | sed -e 's|/julia||' -e 's|/|\\\\|g'` >> get-deps.log done @@ -178,8 +179,6 @@ if [ -z "`which make 2>/dev/null`" ]; then fi $SEVENZIP x -y `basename $f.lzma` >> get-deps.log tar -xf `basename $f` - # msysgit has an ancient version of touch that fails with `touch -c nonexistent` - cp usr/Git/bin/echo.exe bin/touch.exe export PATH=$PWD/bin:$PATH fi diff --git a/deps/checksums/openblas-53e849f4fcae4363a64576de00e982722c7304f9.tar.gz/md5 b/deps/checksums/openblas-53e849f4fcae4363a64576de00e982722c7304f9.tar.gz/md5 new file mode 100644 index 0000000000000..43459f64579c2 --- /dev/null +++ b/deps/checksums/openblas-53e849f4fcae4363a64576de00e982722c7304f9.tar.gz/md5 @@ -0,0 +1 @@ +0d12e5bd5beb6a6948ea72efc3126264 diff --git a/deps/checksums/openblas-53e849f4fcae4363a64576de00e982722c7304f9.tar.gz/sha512 b/deps/checksums/openblas-53e849f4fcae4363a64576de00e982722c7304f9.tar.gz/sha512 new file mode 100644 index 0000000000000..da697473111c7 --- /dev/null +++ b/deps/checksums/openblas-53e849f4fcae4363a64576de00e982722c7304f9.tar.gz/sha512 @@ -0,0 +1 @@ +4bfbd7ed531138ec935346c0476a5ff857938c9e1e8090f71ed21fe6329a07b1b38577bfa1e5bfabfc397209c1b800aec315c5bfbe917229ec0dcf5a523ea688 diff --git a/deps/checksums/openblas-d0c51c4de91b2356b770f92862c6b0e1d54953cd.tar.gz/md5 b/deps/checksums/openblas-d0c51c4de91b2356b770f92862c6b0e1d54953cd.tar.gz/md5 deleted file mode 100644 index 293daf8b35e68..0000000000000 --- a/deps/checksums/openblas-d0c51c4de91b2356b770f92862c6b0e1d54953cd.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -806c02d13f31644f021a1c111d0d5c8a diff --git a/deps/checksums/openblas-d0c51c4de91b2356b770f92862c6b0e1d54953cd.tar.gz/sha512 b/deps/checksums/openblas-d0c51c4de91b2356b770f92862c6b0e1d54953cd.tar.gz/sha512 deleted file mode 100644 index 7a77ea4425943..0000000000000 --- a/deps/checksums/openblas-d0c51c4de91b2356b770f92862c6b0e1d54953cd.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -4664e7ad9e3071360948f413acf17be923619aa76d892f1e53749b20665b8da24ff184d04baba023cd67f6c02f8550e4c7142077771a6578f472b9f0203226f9 diff --git a/deps/openblas.version b/deps/openblas.version index 5f672524d5d0b..7c97e1bf1705d 100644 --- a/deps/openblas.version +++ b/deps/openblas.version @@ -1,2 +1,2 @@ -OPENBLAS_BRANCH=v0.2.14 -OPENBLAS_SHA1=d0c51c4de91b2356b770f92862c6b0e1d54953cd +OPENBLAS_BRANCH=v0.2.15 +OPENBLAS_SHA1=53e849f4fcae4363a64576de00e982722c7304f9 diff --git a/doc/README.md b/doc/README.md index 627feb73b262b..060e5ac1bb7e7 100644 --- a/doc/README.md +++ b/doc/README.md @@ -17,7 +17,7 @@ On ubuntu, you'll need the following packages installed: texlive-lang-cjk texlive-latex-extra -On OS X, you can install install MacTex using the GUI installer +On OS X, you can install MacTex using the GUI installer Building the documentation diff --git a/doc/devdocs/eval.rst b/doc/devdocs/eval.rst index e4418453727f3..01986c8d87160 100644 --- a/doc/devdocs/eval.rst +++ b/doc/devdocs/eval.rst @@ -8,15 +8,10 @@ One of the hardest parts about learning how the Julia Language runs code is lear how all of the pieces work together to execute a block of code. Each chunk of code typically makes a trip through many esoteric acronyms such as (in no particular order), -`flisp`, `AST`, `C++`, `LLVM`, `eval`, `typeinf`, `macroexpand`, `sysimg` (or `system image`), `bootstrapping`, -`compile`, `parse`, `execute`, `JIT`, `interpret`, `box`, `unbox`, `intrinsic function`, `primitive function` +``flisp``, ``AST``, ``C++``, ``LLVM``, ``eval``, ``typeinf``, ``macroexpand``, ``sysimg`` (or ``system image``), ``bootstrapping``, +``compile``, ``parse``, ``execute``, ``JIT``, ``interpret``, ``box``, ``unbox``, ``intrinsic function``, ``primitive function`` before turning into the desired result (hopefully). -Julia Execution ---------------- - -The 10,000 foot view of the whole process is as follows: - .. sidebar:: Definitions REPL @@ -29,26 +24,32 @@ The 10,000 foot view of the whole process is as follows: In this form the code has been tokenized for meaning so that it is more suitable for manipulation and execution. -1. The user starts `julia`. -2. The C function :c:func:`main` from `ui/repl.c` gets called. + +Julia Execution +--------------- + +The 10,000 foot view of the whole process is as follows: + +1. The user starts ``julia``. +2. The C function :c:func:`main` from ``ui/repl.c`` gets called. This function processes the command line arguments, filling in the :c:type:`jl_options` struct and setting the variable :code:`ARGS`. It then initializes Julia (by calling `julia_init in task.c `_, which may load a previously compiled sysimg_). Finally, it passes off control to Julia by calling `Base._start() `_. -#. When `_start()` takes over control, the subsequent sequence of commands depends on the command line arguments given. +#. When ``_start()`` takes over control, the subsequent sequence of commands depends on the command line arguments given. For example, if a filename was supplied, it will proceed to execute that file. Otherwise, it will start an interactive REPL. #. Skipping the details about how the REPL interacts with the user, let's just say the program ends up with a block of code that it wants to run. #. If the block of code to run is in a file, `jl_load(char *filename) `_ - gets invoked to load the file and parse_ it. Each fragment of code is then passed to `eval` to execute. + gets invoked to load the file and parse_ it. Each fragment of code is then passed to ``eval`` to execute. #. Each fragment of code (or AST), is handed off to :func:`eval` to turn into results. #. :func:`eval` takes each code fragment and tries to run it in `jl_toplevel_eval_flex() `_. -#. :c:func:`jl_toplevel_eval_flex` decides whether the code is a "toplevel" action (such as `using` or `module`), which would be invalid inside a function. +#. :c:func:`jl_toplevel_eval_flex` decides whether the code is a "toplevel" action (such as ``using`` or ``module``), which would be invalid inside a function. If so, it passes off the code to the toplevel interpreter. #. :c:func:`jl_toplevel_eval_flex` then expands_ the code to eliminate any macros and to "lower" the AST to make it simpler to execute. #. :c:func:`jl_toplevel_eval_flex` then uses some simple heuristics to decide whether to JIT compiler the AST or to interpret it directly. #. The bulk of the work to interpret code is handled by `eval in interpreter.c `_. -#. If instead, the code is compiled, the bulk of the work is handled by `codegen.cpp`. +#. If instead, the code is compiled, the bulk of the work is handled by ``codegen.cpp``. Whenever a Julia function is called for the first time with a given set of argument types, `type inference`_ will be run on that function. This information is used by the codegen_ step to generate faster code. #. Eventually, the user quits the REPL, or the end of the program is reached, and the :func:`_start` method returns. @@ -79,8 +80,8 @@ Macro Expansion --------------- When :func:`eval` encounters a macro, it expands that AST node before attempting to evaluate the expression. -Macro expansion involves a handoff from :func:`eval` (in Julia), to the parser function :c:func:`jl_macroexpand` (written in `flisp`) -to the Julia macro itself (written in - what else - `Julia`) via :c:func:`fl_invoke_julia_macro`, and back. +Macro expansion involves a handoff from :func:`eval` (in Julia), to the parser function :c:func:`jl_macroexpand` (written in ``flisp``) +to the Julia macro itself (written in - what else - Julia) via :c:func:`fl_invoke_julia_macro`, and back. Typically, macro expansion is invoked as a first step during a call to :func:`expand`/:c:func:`jl_expand`, although it can also be invoked directly by a call to :func:`macroexpand`/:c:func:`jl_macroexpand`. @@ -97,11 +98,6 @@ This enables many future optimizations, such as unboxing of known immutable valu and compile-time hoisting of various run-time operations such as computing field offsets and function pointers. Type inference may also include other steps such as constant propagation and inlining. -.. _codegen: - -JIT Code Generation -------------------- - .. sidebar:: More Definitions JIT @@ -143,7 +139,12 @@ JIT Code Generation These pseudo-functions implement operations on raw bits such as add and sign extend that cannot be expressed directly in any other way. Since they operate on bits directly, they must be compiled into a function - and surrounded by a call to `Core.Intrinsics.box(T, ...)` to reassign type information to the value. + and surrounded by a call to ``Core.Intrinsics.box(T, ...)`` to reassign type information to the value. + +.. _codegen: + +JIT Code Generation +------------------- Codegen is the process of turning a Julia AST into native machine code. @@ -163,16 +164,11 @@ Other parts of codegen are handled by various helper files: Handles backtraces for JIT functions `ccall.cpp `_ - Handles the ccall and llvmcall FFI, along with various `abi_*.cpp` files + Handles the ccall and llvmcall FFI, along with various ``abi_*.cpp`` files `intrinsics.cpp `_ Handles the emission of various low-level intrinsic functions -.. _sysimg: - -System Image ------------- - .. sidebar:: Bootstrapping The process of creating a new system image is called "bootstrapping". @@ -181,15 +177,20 @@ System Image and refers to the idea of starting from a very limited set of available functions and definitions and ending with the creation of a full-featured environment. +.. _sysimg: + +System Image +------------ + The system image is a precompiled archive of a set of Julia files. -The `sys.ji` file distributed with Julia is one such system image, +The ``sys.ji`` file distributed with Julia is one such system image, generated by executing the file `sysimg.jl `_, and serializing the resulting environment (including Types, Functions, Modules, and all other defined values) into a file. Therefore, it contains a frozen version of the :mod:`Main`, :mod:`Core`, and :mod:`Base` modules (and whatever else was in the environment at the end of bootstrapping). This serializer/deserializer is implemented by `jl_save_system_image/jl_restore_system_image in dump.c `_. If there is no sysimg file (:code:`jl_options.image_file == NULL`), -this also implies that `--build` was given on the command line, +this also implies that ``--build`` was given on the command line, so the final result should be a new sysimg file. During Julia initialization, minimal :mod:`Core` and :mod:`Main` modules are created. Then a file named ``boot.jl`` is evaluated from the current directory. diff --git a/doc/devdocs/init.rst b/doc/devdocs/init.rst index 8bc4cd0f487c0..3c31c05e083f4 100644 --- a/doc/devdocs/init.rst +++ b/doc/devdocs/init.rst @@ -92,15 +92,6 @@ initialises 8-bit serialisation tags for 256 frequently used ``jl_value_t`` values. The serialisation mechanism uses these tags as shorthand (in lieu of storing whole objects) to save storage space. -.. sidebar:: sysimg - - If there is a sysimg file, it contains a pre-cooked image of the :mod:`Core` and :mod:`Main` modules (and whatever else is created by ``boot.jl``). See :ref:`dev-sysimg`. - - `jl_restore_system_image() `_ de-serialises the saved sysimg into the current Julia runtime environment and initialisation continues after :c:func:`jl_init_box_caches` below... - - Note: `jl_restore_system_image() (and dump.c in general) `_ uses the :ref:`dev-ios`. - - If there is no sysimg file (:code:`!jl_options.image_file`) then then :mod:`Core` and :mod:`Main` modules are created and ``boot.jl`` is evaluated: @@ -164,6 +155,14 @@ Finally `sigint_handler() `_ and main() calls :code:`true_main(argc, (char**)argv)`. +.. sidebar:: sysimg + + If there is a sysimg file, it contains a pre-cooked image of the :mod:`Core` and :mod:`Main` modules (and whatever else is created by ``boot.jl``). See :ref:`dev-sysimg`. + + `jl_restore_system_image() `_ de-serialises the saved sysimg into the current Julia runtime environment and initialisation continues after :c:func:`jl_init_box_caches` below... + + Note: `jl_restore_system_image() (and dump.c in general) `_ uses the :ref:`dev-ios`. + true_main() ----------- diff --git a/doc/devdocs/llvm.rst b/doc/devdocs/llvm.rst index 101122568ca4a..bb966fc52594f 100644 --- a/doc/devdocs/llvm.rst +++ b/doc/devdocs/llvm.rst @@ -37,7 +37,7 @@ directory ``src/``. |``sys.c`` | I/O and operating system utility functions | +---------------------+-------------------------------------------------------------+ -Some of the `.cpp` files form a group that compile to a single object. +Some of the ``.cpp`` files form a group that compile to a single object. The difference between an intrinsic and a builtin is that a builtin is a first class function that can be used like any other Julia function. An intrinsic can operate @@ -50,7 +50,7 @@ Julia currently uses LLVM's `Type Based Alias Analysis `_. +The ``-O`` option enables LLVM's `Basic Alias Analysis `_. Building Julia with a different version of LLVM ----------------------------------------------- @@ -76,7 +76,7 @@ Here are example settings using ``bash`` syntax: * ``export JULIA_LLVM_ARGS = -print-after-all`` dumps IR after each pass. -* ``export JULIA_LLVM_ARGS = -debug-only=loop-vectorize`` dumps LLVM `DEBUG(`...`)` +* ``export JULIA_LLVM_ARGS = -debug-only=loop-vectorize`` dumps LLVM ``DEBUG(...)`` diagnostics for loop vectorizer *if* you built Julia with ``LLVM_ASSERTIONS=1``. Otherwise you will get warnings about "Unknown command line argument". Counter-intuitively, building Julia with ``LLVM_DEBUG=1`` is *not* enough to diff --git a/doc/devdocs/object.rst b/doc/devdocs/object.rst index e8369ae0ce44e..1354638ca8e21 100644 --- a/doc/devdocs/object.rst +++ b/doc/devdocs/object.rst @@ -166,6 +166,9 @@ then tagged with its type:: jl_value_t *jl_gc_allocobj(size_t nbytes); void jl_set_typeof(jl_value_t *v, jl_datatype_t *type); +Note that all objects are allocated in multiples of 4 bytes and aligned to the platform pointer size. +Memory is allocated from a pool for smaller objects, or directly with :c:func:`malloc` for large objects. + .. sidebar:: :ref:`man-singleton-types` Singleton types have only one instance and no data fields. @@ -174,6 +177,3 @@ then tagged with its type:: e.g. :data:`nothing::Void`. See :ref:`man-singleton-types` and :ref:`man-nothing` - -Note that all objects are allocated in multiples of 4 bytes and aligned to the platform pointer size. -Memory is allocated from a pool for smaller objects, or directly with :c:func:`malloc` for large objects. diff --git a/doc/devdocs/types.rst b/doc/devdocs/types.rst index 5b20c2f6e0437..1310a2e2161d5 100644 --- a/doc/devdocs/types.rst +++ b/doc/devdocs/types.rst @@ -362,11 +362,12 @@ type: in getindex at ./essentials.jl:211 in show_delim_array at show.jl:229 in show at show.jl:257 - in anonymous at show.jl:1278 - in with_output_limit at ./show.jl:1255 - in showlimited at show.jl:1277 + in anonymous at show.jl:1294 + in with_output_limit at ./show.jl:1271 + in showlimited at show.jl:1293 in display at multimedia.jl:120 - in display at multimedia.jl:151 + [inlined code] from multimedia.jl:151 + in display at multimedia.jl:162 (The error is triggered because the cache is pre-allocated to have length 8, but only the first two entries are populated.) diff --git a/doc/genstdlib.jl b/doc/genstdlib.jl index ceec399c10729..1bf108b9f3020 100644 --- a/doc/genstdlib.jl +++ b/doc/genstdlib.jl @@ -288,6 +288,8 @@ for folder in ["stdlib", "manual", "devdocs"] end end +println() + exported_missing_count = 0 unexported_missing_count = 0 @@ -303,7 +305,7 @@ for (d, v) in all_docs warn("Exported method missing doc for $val") exported_missing_count += 1 else - info("Unexported method missing doc for $val") + # info("Unexported method missing doc for $val") unexported_missing_count += 1 end # println(tryrst(d, false)) diff --git a/doc/manual/arrays.rst b/doc/manual/arrays.rst index a0bd7526dad2c..001d215b8cb6d 100644 --- a/doc/manual/arrays.rst +++ b/doc/manual/arrays.rst @@ -87,9 +87,9 @@ Function Description defaulting to the element type and dimensions of ``A`` if omitted. :func:`reinterpret(type, A) ` an array with the same binary data as the given array, but with the specified element type -:func:`rand(dims) ` `:obj:`Array` of ``Float64``\ s with random, iid[#]_ and uniformly +:func:`rand(dims) ` :obj:`Array` of ``Float64``\ s with random, iid[#]_ and uniformly distributed values in the half-open interval :math:`[0, 1)` -:func:`randn(dims) ` `:obj:`Array` of ``Float64``\ s with random, iid and standard normally +:func:`randn(dims) ` :obj:`Array` of ``Float64``\ s with random, iid and standard normally distributed random values :func:`eye(n) ` ``n``-by-``n`` identity matrix :func:`eye(m, n) ` ``m``-by-``n`` identity matrix @@ -528,7 +528,7 @@ where elements are stored in column-major order (see additional notes in :ref:`man-performance-tips`). :obj:`Vector` and :obj:`Matrix` are aliases for the 1-d and 2-d cases. Specific operations such as scalar indexing, assignment, and a few other basic storage-specific operations are all -that have to be implemented for `:obj:`Array`, so that the rest of the array +that have to be implemented for :obj:`Array`, so that the rest of the array library can be implemented in a generic manner. :obj:`SubArray` is a specialization of :obj:`AbstractArray` that performs @@ -541,7 +541,7 @@ can later be used to index the original array indirectly. :obj:`StridedVector` and :obj:`StridedMatrix` are convenient aliases defined to make it possible for Julia to call a wider range of BLAS and LAPACK -functions by passing them either `:obj:`Array` or :obj:`SubArray` objects, and +functions by passing them either :obj:`Array` or :obj:`SubArray` objects, and thus saving inefficiencies from memory allocation and copying. The following example computes the QR decomposition of a small section diff --git a/doc/manual/calling-c-and-fortran-code.rst b/doc/manual/calling-c-and-fortran-code.rst index d12ed5910d576..bf363339544fe 100644 --- a/doc/manual/calling-c-and-fortran-code.rst +++ b/doc/manual/calling-c-and-fortran-code.rst @@ -222,7 +222,7 @@ to fail or produce indeterminate results on a different system. Note that no C header files are used anywhere in the process of calling C functions: you are responsible for making sure that your Julia types and call signatures accurately reflect those in the C header file. (The `Clang -package` can be used to auto-generate +package `_ can be used to auto-generate Julia code from a C header file.) Auto-conversion: @@ -236,16 +236,17 @@ each argument to the specified type. For example, the following call:: will behave as if the following were written:: ccall((:foo, "libfoo"), Void, (Int32, Float64), - Base.cconvert(Int32, Base.cconvert_gcroot(Int32, x)), - Base.cconvert(Float64, Base.cconvert_gcroot(Float64, y))) + Base.unsafe_convert(Int32, Base.cconvert(Int32, x)), + Base.unsafe_convert(Float64, Base.cconvert(Float64, y))) -Note that the primary fall-back method for ``cconvert`` is:: +``cconvert`` normally just calls ``convert``, but can be defined to return +an arbitrary new object more appropriate for passing to C. For example, +this is used to convert an ``Array`` of objects (e.g. strings) to an +array of pointers. - cconvert(T,x) = convert(T, x) - -and the primary fallback method for ``cconvert_gcroot`` is:: - - cconvert_gcroot(T,x) = x +``unsafe_convert`` handles conversion to ``Ptr`` types. It is considered +unsafe because converting an object to a native pointer can hide the object +from the garbage collector, causing it to be freed prematurely. Type Correspondences: ~~~~~~~~~~~~~~~~~~~~~ @@ -311,19 +312,18 @@ There are several special types to be aware of, as no other type can be defined :Array{T,N}: When an array is passed to C as a ``Ptr{T}`` argument, it is not reinterpret-cast: Julia requires that the element type of the - array matches ``T``, and then address of the first element is passed. + array matches ``T``, and the address of the first element is passed. Therefore, if an ``Array`` contains data in the wrong format, it will - have to be explicitly converted using a call such as ``int32(a)``. + have to be explicitly converted using a call such as ``trunc(Int32,a)``. To pass an array ``A`` as a pointer of a different type *without* converting the data beforehand (for example, to pass a ``Float64`` array - to a function that operates on uninterpreted bytes), you can either - declare the argument as ``Ptr{Void}`` or you can explicitly call - ``pointer(A)``. + to a function that operates on uninterpreted bytes), you can + declare the argument as ``Ptr{Void}``. If an array of eltype ``Ptr{T}`` is passed as a ``Ptr{Ptr{T}}`` argument, the Julia base library - ``cconvert_gcroot`` function will attempt to first make a null-terminated copy of the array with + ``cconvert`` function will attempt to first make a null-terminated copy of the array with each element replaced by its ``cconvert`` version. This allows, for example, passing an ``argv`` pointer array of type ``Vector{ByteString}`` to an argument of type ``Ptr{Ptr{Cchar}}``. @@ -341,7 +341,7 @@ Julia type with the same name, prefixed by C. This can help for writing portable +===================================+=================+======================+===================================+ | ``unsigned char`` | ``CHARACTER`` | ``Cuchar`` | ``UInt8`` | | | | | | -| ``bool`` (`C++`) | | | | +| ``bool`` (C++) | | | | +-----------------------------------+-----------------+----------------------+-----------------------------------+ | ``short`` | ``INTEGER*2`` | ``Cshort`` | ``Int16`` | | | | | | @@ -351,7 +351,7 @@ Julia type with the same name, prefixed by C. This can help for writing portable +-----------------------------------+-----------------+----------------------+-----------------------------------+ | ``int`` | ``INTEGER*4`` | ``Cint`` | ``Int32`` | | | | | | -| ``BOOL`` (`C`, typical) | ``LOGICAL*4`` | | | +| ``BOOL`` (C, typical) | ``LOGICAL*4`` | | | +-----------------------------------+-----------------+----------------------+-----------------------------------+ | ``unsigned int`` | | ``Cuint`` | ``UInt32`` | +-----------------------------------+-----------------+----------------------+-----------------------------------+ @@ -433,40 +433,55 @@ C name Standard Julia Alias Julia Base Type ``UInt16`` (Windows) ====================== ====================== ======= -`Remember`: when calling a Fortran function, all inputs must be passed by reference, so all type correspondences -above should contain an additional ``Ptr{..}`` or ``Ref{..}`` wrapper around their type specification. +.. note:: + + When calling a Fortran function, all inputs must be passed by reference, so + all type correspondences above should contain an additional ``Ptr{..}`` or + ``Ref{..}`` wrapper around their type specification. + +.. warning:: + + For string arguments (``char*``) the Julia type should be ``Cstring`` (if NUL- + terminated data is expected) or either ``Ptr{Cchar}`` or ``Ptr{UInt8}`` + otherwise (these two pointer types have the same effect), as described above, + not ``ASCIIString``. Similarly, for array arguments (``T[]`` or ``T*``), the + Julia type should again be ``Ptr{T}``, not ``Vector{T}``. + +.. warning:: + + Julia's ``Char`` type is 32 bits, which is not the same as the wide character + type (``wchar_t`` or ``wint_t``) on all platforms. + +.. note:: -`Warning`: For string arguments (``char*``) the Julia type should be ``Cstring`` (if NUL-terminated data is expected) -or either ``Ptr{Cchar}`` or ``Ptr{UInt8}`` otherwise (these two pointer types have the same effect), as described above, -not ``ASCIIString``. Similarly, for array arguments (``T[]`` or ``T*``), the Julia -type should again be ``Ptr{T}``, not ``Vector{T}``. + For ``wchar_t*`` arguments, the Julia type should be ``Cwstring`` (if the C + routine expects a NUL-terminated string) or ``Ptr{Cwchar_t}`` otherwise, and + data can be converted to/from ordinary Julia strings by the ``wstring(s)`` + function (equivalent to either ``utf16(s)`` or ``utf32(s)`` depending upon the + width of ``Cwchar_t``); this conversion will be called automatically for + ``Cwstring`` arguments. Note also that ASCII, UTF-8, UTF-16, and UTF-32 + string data in Julia is internally NUL-terminated, so it can be passed to C + functions expecting NUL-terminated data without making a copy (but using the + ``Cwstring`` type will cause an error to be thrown if the string itself + contains NUL characters). -`Warning`: Julia's ``Char`` type is 32 bits, which is not the same as the wide -character type (``wchar_t`` or ``wint_t``) on all platforms. +.. note:: -`Note`: For ``wchar_t*`` arguments, the Julia type should be ``Cwstring`` (if the C routine -expects a NUL-terminated string) or ``Ptr{Cwchar_t}`` otherwise, -and data can be converted to/from ordinary Julia strings by the -``wstring(s)`` function (equivalent to either ``utf16(s)`` or ``utf32(s)`` -depending upon the width of ``Cwchar_t``); this conversion will be called -automatically for ``Cwstring`` arguments. Note also that ASCII, UTF-8, -UTF-16, and UTF-32 string data in Julia is internally NUL-terminated, so -it can be passed to C functions expecting NUL-terminated data without making -a copy (but using the ``Cwstring`` type will cause an error to be thrown -if the string itself contains NUL characters). + C functions that take an argument of the type ``char**`` can be called by + using a ``Ptr{Ptr{UInt8}}`` type within Julia. For example, C functions of the + form:: -`Note`: C functions that take an argument of the type ``char**`` can be called by using -a ``Ptr{Ptr{UInt8}}`` type within Julia. For example, -C functions of the form:: + int main(int argc, char **argv); - int main(int argc, char **argv); + can be called via the following Julia code:: -can be called via the following Julia code:: + argv = [ "a.out", "arg1", "arg2" ] + ccall(:main, Int32, (Int32, Ptr{Ptr{UInt8}}), length(argv), argv) - argv = [ "a.out", "arg1", "arg2" ] - ccall(:main, Int32, (Int32, Ptr{Ptr{UInt8}}), length(argv), argv) +.. note:: -`Note`: A C function declared to return ``Void`` will return the value ``nothing`` in Julia. + A C function declared to return ``Void`` will return the value ``nothing`` in + Julia. Struct Type correspondences ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -524,7 +539,7 @@ Memory allocation and deallocation of such objects must be handled by calls to the appropriate cleanup routines in the libraries being used, just like in any C program. Do not try to free an object received from a C library with ``Libc.free`` in Julia, as this may result -in the ``free`` function being called via the wrong `libc` library and +in the ``free`` function being called via the wrong ``libc`` library and cause Julia to crash. The reverse (passing an object allocated in Julia to be freed by an external library) is equally invalid. diff --git a/doc/manual/documentation.rst b/doc/manual/documentation.rst index 864d2479825a4..f7b13802e3ae8 100644 --- a/doc/manual/documentation.rst +++ b/doc/manual/documentation.rst @@ -355,7 +355,7 @@ Adds docstring ``"..."`` to expression generated by expanding ``@m expression``. for expressions decorated with ``@inline``, ``@noinline``, ``@generated``, or any other macro to be documented in the same way as undecorated expressions. -Macro authors should take note that only macros that generate a `single expression` will +Macro authors should take note that only macros that generate a single expression will automatically support docstrings. If a macro returns a block containing multiple subexpressions then the subexpression that should be documented must be marked using the :func:`@__doc__` macro. diff --git a/doc/manual/faq.rst b/doc/manual/faq.rst index 06023948b336d..a2e6c4880cd3f 100644 --- a/doc/manual/faq.rst +++ b/doc/manual/faq.rst @@ -128,8 +128,8 @@ inside a specific function or set of functions, you have two options: What does the ``...`` operator do? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The two uses of the `...` operator: slurping and splatting -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The two uses of the ``...`` operator: slurping and splatting +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Many newcomers to Julia find the use of ``...`` operator confusing. Part of what makes the ``...`` operator confusing is that it means two different things @@ -882,7 +882,7 @@ This is happening because, while ``print(i, " Foo ", " Bar ")`` is synchronous, internally, the writing of each argument yields to other tasks while waiting for that part of the I/O to complete. -``println`` to asynchronous streams like STDOUT, TcpSockets, "locks" the stream +``println`` to asynchronous streams like STDOUT, TCPSockets, "locks" the stream during a call. Consequently changing ``print`` to ``println`` in the above example results in:: diff --git a/doc/manual/linear-algebra.rst b/doc/manual/linear-algebra.rst index 6b4d4dfd136c0..47f93ef8c51b2 100644 --- a/doc/manual/linear-algebra.rst +++ b/doc/manual/linear-algebra.rst @@ -126,5 +126,5 @@ Legend: The uniform scaling operator ---------------------------- -A :class:`UniformScaling` operator represents a scalar times the identity operator, ``λ*I``. The identity operator :class:`I` is defined as a constant and is an instance of :class:`UniformScaling`. The size of these operators are generic and match the other matrix in the binary operations :obj:`+`, :obj:`-`, :obj:`*` and :obj:`\\`. For ``A+I`` and ``A-I`` this means that ``A`` must be square. Multiplication with the identity operator :class: `I` is a noop (except for checking that the scaling factor is one) and therefore almost without overhead. +A :class:`UniformScaling` operator represents a scalar times the identity operator, ``λ*I``. The identity operator :class:`I` is defined as a constant and is an instance of :class:`UniformScaling`. The size of these operators are generic and match the other matrix in the binary operations :obj:`+`, :obj:`-`, :obj:`*` and :obj:`\\`. For ``A+I`` and ``A-I`` this means that ``A`` must be square. Multiplication with the identity operator :class:`I` is a noop (except for checking that the scaling factor is one) and therefore almost without overhead. diff --git a/doc/manual/mathematical-operations.rst b/doc/manual/mathematical-operations.rst index baef2c8eb527d..64e6f1e223b37 100644 --- a/doc/manual/mathematical-operations.rst +++ b/doc/manual/mathematical-operations.rst @@ -271,8 +271,8 @@ that Julia does them correctly. For other types, :func:`isequal` defaults to calling :func:`==`, so if you want to define equality for your own types then you only need to add a :func:`==` method. If you define your own equality function, you should probably -define a corresponding :func:`hash` method to ensure that `isequal(x,y)` -implies `hash(x) == hash(y)`. +define a corresponding :func:`hash` method to ensure that ``isequal(x,y)`` +implies ``hash(x) == hash(y)``. Chaining comparisons ~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/manual/metaprogramming.rst b/doc/manual/metaprogramming.rst index ba690d5e7ca47..6cbeaa42c0c8d 100644 --- a/doc/manual/metaprogramming.rst +++ b/doc/manual/metaprogramming.rst @@ -242,7 +242,7 @@ Julia syntax. As an alternative, Julia allows "splicing" or interpolation of literals or expressions into quoted expressions. Interpolation is indicated by the ``$`` prefix. -In this example, the literal value of `a` is interpolated: +In this example, the literal value of ``a`` is interpolated: .. doctest:: @@ -961,7 +961,7 @@ function is generated is really an implementation detail; it *might* be only once, but it *might* also be more often. As a consequence, you should *never* write a generated function with side effects - when, and how often, the side effects occur is undefined. (This is true for macros too - and just -like for macros, the use of `eval` in a generated function is a sign that +like for macros, the use of :func:`eval` in a generated function is a sign that you're doing something the wrong way.) The example generated function ``foo`` above did not do anything a normal @@ -1017,12 +1017,12 @@ These examples are hopefully helpful to illustrate how generated functions work, both in the definition end and at the call site; however, *don't copy them*, for the following reasons: -* the `foo` function has side-effects, and it is undefined exactly when, +* the ``foo`` function has side-effects, and it is undefined exactly when, how often or how many times these side-effects will occur -* the `bar` function solves a problem that is better solved with multiple - dispatch - defining `bar(x) = x` and `bar(x::Integer) = x^2` will do +* the ``bar`` function solves a problem that is better solved with multiple + dispatch - defining ``bar(x) = x`` and ``bar(x::Integer) = x^2`` will do the same thing, but it is both simpler and faster. -* the `baz` function is pathologically insane +* the ``baz`` function is pathologically insane Instead, now that we have a better understanding for how generated functions work, let's use them to build some more advanced functionality... diff --git a/doc/manual/networking-and-streams.rst b/doc/manual/networking-and-streams.rst index ed9cab6d7b7f3..8f15f53e828bb 100644 --- a/doc/manual/networking-and-streams.rst +++ b/doc/manual/networking-and-streams.rst @@ -179,19 +179,19 @@ specified port (2000) in this case. The same function may also be used to create various other kinds of servers:: julia> listen(2000) # Listens on localhost:2000 (IPv4) - TcpServer(active) + TCPServer(active) julia> listen(ip"127.0.0.1",2000) # Equivalent to the first - TcpServer(active) + TCPServer(active) julia> listen(ip"::1",2000) # Listens on localhost:2000 (IPv6) - TcpServer(active) + TCPServer(active) julia> listen(IPv4(0),2001) # Listens on port 2001 on all IPv4 interfaces - TcpServer(active) + TCPServer(active) julia> listen(IPv6(0),2001) # Listens on port 2001 on all IPv6 interfaces - TcpServer(active) + TCPServer(active) julia> listen("testsocket") # Listens on a domain socket/named pipe PipeServer(active) @@ -208,7 +208,7 @@ should be able to pass the same arguments to :func:`connect` as you did to liste establish the connection. So let's try that out (after having created the server above):: julia> connect(2000) - TcpSocket(open, 0 bytes waiting) + TCPSocket(open, 0 bytes waiting) julia> Hello World @@ -228,7 +228,7 @@ A great strength of Julia is that since the API is exposed synchronously even th Task julia> clientside=connect(2001) - TcpSocket(open, 0 bytes waiting) + TCPSocket(open, 0 bytes waiting) julia> @async while true write(STDOUT,readline(clientside)) @@ -250,7 +250,7 @@ given by the ``host`` parameter on the port given by the port parameter. It allows you to do things like:: julia> connect("google.com",80) - TcpSocket(open, 0 bytes waiting) + TCPSocket(open, 0 bytes waiting) At the base of this functionality is :func:`getaddrinfo`, which will do the appropriate address resolution:: diff --git a/doc/manual/noteworthy-differences.rst b/doc/manual/noteworthy-differences.rst index 82ebc7973c380..f023327995f79 100644 --- a/doc/manual/noteworthy-differences.rst +++ b/doc/manual/noteworthy-differences.rst @@ -252,6 +252,11 @@ Noteworthy differences from Python major (C-ordered) by default. To get optimal performance when looping over arrays, the order of the loops should be reversed in Julia relative to NumPy (see relevant section of :ref:`man-performance-tips`). +- Julia's updating operators (e.g. ``+=``, ``-=``, ...) are *not in-place* + whereas NumPy's are. This means ``A = ones(4); B = A; B += 3`` doesn't change + values in ``A``, it rather rebinds the name ``B`` to the result of the right- + hand side ``B = B + 3``, which is a new array. Use ``B[:] += 3``, explicit loops, + or ``InplaceOps.jl``. - Julia evaluates default values of function arguments every time the method is invoked, unlike in Python where the default values are evaluated only once when the function is defined. For example, the function ``f(x=rand()) = x`` @@ -269,7 +274,9 @@ Noteworthy differences from C/C++ See the Julia documentation for the syntax for array construction (it has changed between versions). - In Julia, indexing of arrays, strings, etc. is 1-based not 0-based. - Julia arrays are assigned by reference. After ``A=B``, changing elements of - ``B`` will modify ``A`` as well. + ``B`` will modify ``A`` as well. Updating operators like ``+=`` do not operate + in-place, they are equivalent to ``A = A + B`` which rebinds the left-hand + side to the result of the right-hand side expression. - Julia arrays are column major (Fortran ordered) whereas C/C++ arrays are row major ordered by default. To get optimal performance when looping over arrays, the order of the loops should be reversed in Julia relative to C/C++ @@ -300,7 +307,7 @@ Noteworthy differences from C/C++ characters without quoting it like ``"\""`` String literals can have values of other variables or expressions interpolated into them, indicated by ``$variablename`` or ``$(expression)``, which evaluates the variable name or the expression in the context of the function. -- ``//`` indicates a ``Rational`` number, and not a single-line comment (which is # in Julia) +- ``//`` indicates a ``Rational`` number, and not a single-line comment (which is ``#`` in Julia) - ``#=`` indicates the start of a multiline comment, and ``=#`` ends it. - Functions in Julia return values from their last expression(s) or the ``return`` keyword. Multiple values can be returned from functions and assigned as tuples, e.g. diff --git a/doc/manual/packages.rst b/doc/manual/packages.rst index 49d77e52e338a..6b652024ba70c 100644 --- a/doc/manual/packages.rst +++ b/doc/manual/packages.rst @@ -570,7 +570,7 @@ going to have to do a *force push*: it with ``git remote add myfork https://github.com/myaccount/Foo.jl.git``, where the URL comes from the "clone URL" on your GitHub fork's page. -- Force-push to your fork with ``git push myfork +fixbar``. The `+` +- Force-push to your fork with ``git push myfork +fixbar``. The ``+`` indicates that this should replace the ``fixbar`` branch found at ``myfork``. @@ -800,7 +800,7 @@ on GitHub, push your changes to your fork, and open a pull request:: then you may have encountered an issue from using the GitHub API on multiple systems. The solution is to delete the "Julia Package Manager" personal access token `from your Github account - `_ and try again. + `_ and try again. Other failures may require you to circumvent :func:`Pkg.publish` by `creating a pull request on GitHub @@ -933,7 +933,7 @@ For example, the line:: Distributions 0.1 is satisfied by any version of ``Distributions`` greater than or equal to ``0.1.0``. -Suffixing a version with `-` allows any pre-release versions as well. For example:: +Suffixing a version with ``-`` allows any pre-release versions as well. For example:: Distributions 0.1- diff --git a/doc/manual/parallel-computing.rst b/doc/manual/parallel-computing.rst index 89752a1c367be..a2fdac13847de 100644 --- a/doc/manual/parallel-computing.rst +++ b/doc/manual/parallel-computing.rst @@ -204,7 +204,7 @@ The base Julia installation has in-built support for two types of clusters: Functions :func:`addprocs`, :func:`rmprocs`, :func:`workers`, and others are available as a programmatic means of adding, removing and querying the processes in a cluster. -Note that workers do not run a `.juliarc.jl` startup script, nor do they synchronize their global state +Note that workers do not run a ``.juliarc.jl`` startup script, nor do they synchronize their global state (such as global variables, new method definitions, and loaded modules) with any of the other running processes. Other types of clusters can be supported by writing your own custom diff --git a/doc/manual/strings.rst b/doc/manual/strings.rst index 926cc9cda9620..063c32cf4e34a 100644 --- a/doc/manual/strings.rst +++ b/doc/manual/strings.rst @@ -751,7 +751,7 @@ with the number or name of the capture group:: "45" Captures can be referenced in a substitution string when using :func:`replace` -by using ``\n`` to refer to the `n`th capture group and prefixing the +by using ``\n`` to refer to the nth capture group and prefixing the subsitution string with ``s``. Capture group 0 refers to the entire match object. Named capture groups can be referenced in the substitution with ``g``. For example:: diff --git a/doc/manual/style-guide.rst b/doc/manual/style-guide.rst index 43a2d68baf2a2..98dc69800a6f1 100644 --- a/doc/manual/style-guide.rst +++ b/doc/manual/style-guide.rst @@ -92,8 +92,8 @@ might be better to force the caller to decide how non-integers should be converted (e.g. floor or ceiling). Another issue is that declaring more specific types leaves more "space" for future method definitions. -Append `!` to names of functions that modify their arguments ------------------------------------------------------------- +Append ``!`` to names of functions that modify their arguments +-------------------------------------------------------------- Instead of:: diff --git a/doc/stdlib/arrays.rst b/doc/stdlib/arrays.rst index fd6e168492e3e..af88e9342a287 100644 --- a/doc/stdlib/arrays.rst +++ b/doc/stdlib/arrays.rst @@ -396,7 +396,34 @@ Indexing, Assignment, and Concatenation .. Docstring generated from Julia source - Horizontal and vertical concatenation in one call. This function is called for block matrix syntax. The first argument specifies the number of arguments to concatenate in each block row. For example, ``[a b;c d e]`` calls ``hvcat((2,3),a,b,c,d,e)``\ . + Horizontal and vertical concatenation in one call. This function is called for block matrix syntax. The first argument specifies the number of arguments to concatenate in each block row. + + .. doctest:: + + julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6 + (1,2,3,4,5,6) + + julia> [a b c; d e f] + 2x3 Array{Int64,2}: + 1 2 3 + 4 5 6 + + julia> hvcat((3,3), a,b,c,d,e,f) + 2x3 Array{Int64,2}: + 1 2 3 + 4 5 6 + + julia> [a b;c d; e f] + 3x2 Array{Int64,2}: + 1 2 + 3 4 + 5 6 + + julia> hvcat((2,2,2), a,b,c,d,e,f) + 3x2 Array{Int64,2}: + 1 2 + 3 4 + 5 6 If the first argument is a single integer ``n``\ , then all block rows are assumed to have ``n`` block columns. diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index 43cf418e69b65..a35baa94952e5 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -1371,7 +1371,7 @@ Internals .. Docstring generated from Julia source - Prints the native assembly instructions generated for running the method matching the given generic function and type signature to STDOUT. + Prints the native assembly instructions generated for running the method matching the given generic function and type signature to ``STDOUT``\ . .. function:: @code_native diff --git a/doc/stdlib/c.rst b/doc/stdlib/c.rst index bbb70d6051307..166d88cf9788b 100644 --- a/doc/stdlib/c.rst +++ b/doc/stdlib/c.rst @@ -248,3 +248,20 @@ .. data:: Cdouble Equivalent to the native ``double`` c-type (Float64) + +**************** + LLVM Interface +**************** + +.. function:: llvmcall(IR::String, ReturnType, (ArgumentType1, ...), ArgumentValue1, ...) + + .. Docstring generated from Julia source + + Call LLVM IR string in the first argument. Similar to an LLVM function ``define`` block, arguments are available as consecutive unnamed SSA variables (%0, %1, etc.). + + Note that the argument type tuple must be a literal tuple, and not a tuple-valued variable or expression. + + Each ``ArgumentValue`` to ``llvmcall`` will be converted to the corresponding ``ArgumentType``\ , by automatic insertion of calls to ``unsafe_convert(ArgumentType, cconvert(ArgumentType, ArgumentValue))``\ . (see also the documentation for each of these functions for further details). In most cases, this simply results in a call to ``convert(ArgumentType, ArgumentValue)``\ . + + See ``test/llvmcall.jl`` for usage examples. + diff --git a/doc/stdlib/collections.rst b/doc/stdlib/collections.rst index 0a80a6543a0b9..bcb3ab2ab2e49 100644 --- a/doc/stdlib/collections.rst +++ b/doc/stdlib/collections.rst @@ -347,6 +347,18 @@ Iterable Collections For an array input, returns the value and index of the minimum over the given dimensions. +.. function:: findmax!(rval, rind, A, [init=true]) -> (maxval, index) + + .. Docstring generated from Julia source + + Find the maximum of ``A`` and the corresponding linear index along singleton dimensions of ``rval`` and ``rind``\ , and store the results in ``rval`` and ``rind``\ . + +.. function:: findmin!(rval, rind, A, [init=true]) -> (minval, index) + + .. Docstring generated from Julia source + + Find the minimum of ``A`` and the corresponding linear index along singleton dimensions of ``rval`` and ``rind``\ , and store the results in ``rval`` and ``rind``\ . + .. function:: maxabs(itr) .. Docstring generated from Julia source diff --git a/doc/stdlib/dates.rst b/doc/stdlib/dates.rst index fa2f6a621fc7f..8074d8b074e68 100644 --- a/doc/stdlib/dates.rst +++ b/doc/stdlib/dates.rst @@ -25,7 +25,7 @@ Dates and Time Types .. data:: UTInstant{T} - The ``UTInstant`` represents a machine timeline based on `UT` time (1 day = one revolution of the earth). The ``T`` is a ``Period`` parameter that indicates the resolution or precision of the instant. + The ``UTInstant`` represents a machine timeline based on UT time (1 day = one revolution of the earth). The ``T`` is a ``Period`` parameter that indicates the resolution or precision of the instant. .. data:: TimeType diff --git a/doc/stdlib/io-network.rst b/doc/stdlib/io-network.rst index 30fcdedf32124..33961cb21c1c5 100644 --- a/doc/stdlib/io-network.rst +++ b/doc/stdlib/io-network.rst @@ -237,7 +237,7 @@ General I/O .. Docstring generated from Julia source - Write an arbitrary value to a stream in an opaque format, such that it can be read back by ``deserialize``\ . The read-back value will be as identical as possible to the original. In general, this process will not work if the reading and writing are done by different versions of Julia, or an instance of Julia with a different system image. + Write an arbitrary value to a stream in an opaque format, such that it can be read back by ``deserialize``\ . The read-back value will be as identical as possible to the original. In general, this process will not work if the reading and writing are done by different versions of Julia, or an instance of Julia with a different system image. ``Ptr`` values are serialized as all-zero bit patterns (``NULL``\ ). .. function:: deserialize(stream) @@ -279,13 +279,13 @@ General I/O .. Docstring generated from Julia source - Create a pipe to which all C and Julia level STDOUT output will be redirected. Returns a tuple (rd,wr) representing the pipe ends. Data written to STDOUT may now be read from the rd end of the pipe. The wr end is given for convenience in case the old STDOUT object was cached by the user and needs to be replaced elsewhere. + Create a pipe to which all C and Julia level ``STDOUT`` output will be redirected. Returns a tuple ``(rd,wr)`` representing the pipe ends. Data written to ``STDOUT`` may now be read from the rd end of the pipe. The wr end is given for convenience in case the old ``STDOUT`` object was cached by the user and needs to be replaced elsewhere. .. function:: redirect_stdout(stream) .. Docstring generated from Julia source - Replace STDOUT by stream for all C and julia level output to STDOUT. Note that ``stream`` must be a TTY, a Pipe or a TcpSocket. + Replace ``STDOUT`` by stream for all C and julia level output to ``STDOUT``\ . Note that ``stream`` must be a TTY, a ``Pipe`` or a ``TCPSocket``\ . .. function:: redirect_stderr([stream]) @@ -773,7 +773,7 @@ Memory-mapped I/O Network I/O ----------- -.. function:: connect([host],port) -> TcpSocket +.. function:: connect([host],port) -> TCPSocket .. Docstring generated from Julia source @@ -785,7 +785,7 @@ Network I/O Connect to the Named Pipe / Domain Socket at ``path`` -.. function:: listen([addr,]port) -> TcpServer +.. function:: listen([addr,]port) -> TCPServer .. Docstring generated from Julia source @@ -833,11 +833,11 @@ Network I/O Accepts a connection on the given server and returns a connection to the client. An uninitialized client stream may be provided, in which case it will be used instead of creating a new stream. -.. function:: listenany(port_hint) -> (UInt16,TcpServer) +.. function:: listenany(port_hint) -> (UInt16,TCPServer) .. Docstring generated from Julia source - Create a TcpServer on any port, using hint as a starting point. Returns a tuple of the actual port that the server was created on and the server itself. + Create a ``TCPServer`` on any port, using hint as a starting point. Returns a tuple of the actual port that the server was created on and the server itself. .. function:: poll_fd(fd, timeout_s::Real; readable=false, writable=false) diff --git a/doc/stdlib/libdl.rst b/doc/stdlib/libdl.rst index a7a5f24dd4a5f..aeb21d858d91b 100644 --- a/doc/stdlib/libdl.rst +++ b/doc/stdlib/libdl.rst @@ -60,7 +60,7 @@ .. Docstring generated from Julia source - Look up a symbol from a shared library handle, silently return NULL pointer on lookup failure. + Look up a symbol from a shared library handle, silently return ``NULL`` pointer on lookup failure. .. function:: dlclose(handle) @@ -68,6 +68,10 @@ Close shared library referenced by handle. +.. data:: dlext + + File extension for dynamic libraries (e.g. dll, dylib, so) on the current platform. + .. function:: find_library(names, locations) .. Docstring generated from Julia source diff --git a/doc/stdlib/linalg.rst b/doc/stdlib/linalg.rst index 156bd98d53488..832aaced493e9 100644 --- a/doc/stdlib/linalg.rst +++ b/doc/stdlib/linalg.rst @@ -725,9 +725,9 @@ Linear algebra functions in Julia are largely implemented by calling functions f For inverting dense ill-conditioned matrices in a least-squares sense, ``tol = sqrt(eps(real(float(one(eltype(M))))))`` is recommended. - For more information, see [8859]_, [B96]_, [S84]_, [KY88]_. + For more information, see [issue8859]_, [B96]_, [S84]_, [KY88]_. - .. [8859] Issue 8859, "Fix least squares", https://github.com/JuliaLang/julia/pull/8859 + .. [issue8859] Issue 8859, "Fix least squares", https://github.com/JuliaLang/julia/pull/8859 .. [B96] Åke Björck, "Numerical Methods for Least Squares Problems", SIAM Press, Philadelphia, 1996, "Other Titles in Applied Mathematics", Vol. 51. `doi:10.1137/1.9781611971484 `_ diff --git a/doc/stdlib/parallel.rst b/doc/stdlib/parallel.rst index 7bde525093cb4..5bd56c7e495c2 100644 --- a/doc/stdlib/parallel.rst +++ b/doc/stdlib/parallel.rst @@ -97,7 +97,7 @@ Tasks .. Docstring generated from Julia source - Wrap an expression in a ``Task`` and add it to the scheduler's queue. + Wrap an expression in a ``Task`` and add it to the local machine's scheduler queue. .. function:: @task @@ -156,7 +156,7 @@ General Parallel Computing Support Equivalent to ``addprocs(CPU_CORES)`` - Note that workers do not run a `.juliarc.jl` startup script, nor do they synchronize their global state + Note that workers do not run a ``.juliarc.jl`` startup script, nor do they synchronize their global state (such as global variables, new method definitions, and loaded modules) with any of the other running processes. .. function:: addprocs(machines; tunnel=false, sshflags=``, max_parallel=10, exeflags=``) -> List of process identifiers @@ -401,7 +401,7 @@ General Parallel Computing Support .. Docstring generated from Julia source - Wraps an expression in a closure and schedules it to run on the local machine. Also adds it to the set of items that the nearest enclosing ``@sync`` waits for. + Like ``@schedule``\ , ``@async`` wraps an expression in a ``Task`` and adds it to the local machine's scheduler queue. Additionally it adds the task to the set of items that the nearest enclosing ``@sync`` waits for. ``@async`` also wraps the expression in a ``let x=x, y=y, ...`` block to create a new scope with copies of all variables referenced in the expression. .. function:: @sync diff --git a/doc/stdlib/punctuation.rst b/doc/stdlib/punctuation.rst index 725ab284befdd..dbabd1ddea7e8 100644 --- a/doc/stdlib/punctuation.rst +++ b/doc/stdlib/punctuation.rst @@ -9,7 +9,7 @@ symbol meaning ========= ================================================ ``@m`` invoke macro ``m``; followed by space-separated expressions ``!`` prefix "not" operator -``a!( )`` at the end of a function name, `!` indicates that a function modifies its argument(s) +``a!( )`` at the end of a function name, ``!`` indicates that a function modifies its argument(s) ``#`` begin single line comment ``#=`` begin multi-line comment (these are nestable) ``=#`` end multi-line comment diff --git a/src/builtins.c b/src/builtins.c index 0dd497981bc6a..8495f0261a746 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -837,7 +837,7 @@ DLLEXPORT jl_nullable_float64_t jl_try_substrtod(char *str, size_t offset, size_ bstr = newstr; pend = bstr+len; } - double out = strtod_c(bstr, &p); + double out = jl_strtod_c(bstr, &p); if (errno==ERANGE && (out==0 || out==HUGE_VAL || out==-HUGE_VAL)) { err = 1; @@ -890,9 +890,9 @@ DLLEXPORT jl_nullable_float32_t jl_try_substrtof(char *str, size_t offset, size_ pend = bstr+len; } #if defined(_OS_WINDOWS_) && !defined(_COMPILER_MINGW_) - float out = (float)strtod_c(bstr, &p); + float out = (float)jl_strtod_c(bstr, &p); #else - float out = strtof_c(bstr, &p); + float out = jl_strtof_c(bstr, &p); #endif if (errno==ERANGE && (out==0 || out==HUGE_VALF || out==-HUGE_VALF)) { diff --git a/src/codegen.cpp b/src/codegen.cpp index ac20bf6a93869..efcac59c47309 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1280,8 +1280,10 @@ extern "C" void jl_binding_deprecation_warning(jl_binding_t *b); static void cg_bdw(jl_binding_t *b, jl_codectx_t *ctx) { jl_binding_deprecation_warning(b); - show_source_loc(JL_STDERR, ctx); - jl_printf(JL_STDERR, "\n"); + if (jl_options.depwarn) { + show_source_loc(JL_STDERR, ctx); + jl_printf(JL_STDERR, "\n"); + } } // try to statically evaluate, NULL if not possible @@ -3283,7 +3285,7 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, bool mn = jl_exprarg(mn,0); } theF = emit_expr(mn, ctx); - if (!iskw) { + if (jl_is_expr(mn)) { mn = jl_fieldref(jl_exprarg(mn, 2), 0); } } @@ -4184,6 +4186,7 @@ static Function *emit_function(jl_lambda_info_t *lam) } } ctx.lineno = lno; + int toplineno = lno; DIBuilder dbuilder(*m); ctx.dbuilder = &dbuilder; @@ -4732,23 +4735,24 @@ static Function *emit_function(jl_lambda_info_t *lam) MDNode *funcscope = (MDNode*)dbuilder.createLexicalBlockFile(SP, topfile); MDNode *scope; if ((dfil == topfile || dfil == NULL) && - lno >= ctx.lineno) // if we are in the top-level file - // and the current lineno is less than - // the last, must be same-file inline - // TODO: improve this heuristic... + lno >= toplineno) { - // set location to the current top-level line + // for sequentially-defined code, + // set location to line in top file. + // TODO: improve handling of nested inlines loc = DebugLoc::get(lno, 1, SP, NULL); } else { - // otherwise, we are compiling code from another file, - // so create a location for the top-level line, and - // set the DebugLoc "inlinedAt" parameter. + // otherwise, we are compiling inlined code, + // so set the DebugLoc "inlinedAt" parameter + // to the current line, then use source loc. #ifdef LLVM37 scope = (MDNode*)dbuilder.createLexicalBlockFile(SP,dfil); - MDNode *inlineLocMd = DebugLoc::get(ctx.lineno, 1, funcscope, NULL).getAsMDNode(); + MDNode *inlineLocMd = DebugLoc::get(toplineno, 1, funcscope, NULL). + getAsMDNode(); #else scope = (MDNode*)dbuilder.createLexicalBlockFile(SP,DIFile(dfil)); - MDNode *inlineLocMd = DebugLoc::get(ctx.lineno, 1, funcscope, NULL).getAsMDNode(jl_LLVMContext); + MDNode *inlineLocMd = DebugLoc::get(toplineno, 1, funcscope, NULL). + getAsMDNode(jl_LLVMContext); #endif loc = DebugLoc::get(lno, 1, scope, inlineLocMd); } @@ -4756,7 +4760,7 @@ static Function *emit_function(jl_lambda_info_t *lam) } if (do_coverage) coverageVisitLine(filename, lno); - ctx.lineno = lno; + ctx.lineno = lno; // NOO TOUCHIE; NO TOUCH! See #922 } if (jl_is_labelnode(stmt)) { if (prevlabel) continue; diff --git a/src/flisp/read.c b/src/flisp/read.c index 1764f7da5701c..c8240590c0c23 100644 --- a/src/flisp/read.c +++ b/src/flisp/read.c @@ -39,7 +39,7 @@ int isnumtok_base(char *tok, value_t *pval, int base) return 0; if (!((tok[0]=='0' && tok[1]=='x') || (base >= 15)) && strpbrk(tok, ".eEpP")) { - d = strtod_c(tok, &end); + d = jl_strtod_c(tok, &end); if (*end == '\0') { if (pval) *pval = mk_double(d); return 1; @@ -55,7 +55,7 @@ int isnumtok_base(char *tok, value_t *pval, int base) // hexadecimal float literals else if (((tok[0]=='0' && tok[1]=='x') || (base == 16)) && strpbrk(tok, "pP")) { - d = strtod_c(tok, &end); + d = jl_strtod_c(tok, &end); if (*end == '\0') { if (pval) *pval = mk_double(d); return 1; diff --git a/src/jltypes.c b/src/jltypes.c index 9c76d07c20414..3591bddf2f719 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -637,34 +637,6 @@ static long meet_tuple_lengths(long bv, long vv, int *bot) return vv; } -// convert a type to the value it would have if assigned to a static parameter -// in covariant context. -// example: {Type{Int},} => {DataType,} -// calling f{T}(x::T) as f({Int,}) should give T == {DataType,}, but we -// might temporarily represent this type as {Type{Int},} for more precision. -static jl_value_t *type_to_static_parameter_value(jl_value_t *t) -{ - if (jl_is_type_type(t) && !jl_is_typevar(jl_tparam0(t))) - return jl_typeof(jl_tparam0(t)); - if (jl_is_tuple_type(t)) { - jl_svec_t *p = ((jl_datatype_t*)t)->parameters; - size_t l = jl_svec_len(p); - int changed = 0; - jl_svec_t *np = jl_alloc_svec(l); - JL_GC_PUSH1(&np); - for(size_t i=0; i < l; i++) { - jl_value_t *el = type_to_static_parameter_value(jl_svecref(p,i)); - jl_svecset(np, i, el); - if (el != jl_svecref(p,i)) - changed = 1; - } - jl_value_t *result = changed ? (jl_value_t*)jl_apply_tuple_type(np) : t; - JL_GC_POP(); - return result; - } - return t; -} - static int match_intersection_mode = 0; static jl_value_t *meet_tvars(jl_tvar_t *a, jl_tvar_t *b); @@ -674,10 +646,6 @@ static jl_value_t *intersect_typevar(jl_tvar_t *a, jl_value_t *b, jl_value_t *both=NULL; jl_tvar_t *new_b=NULL; JL_GC_PUSH3(&b, &both, &new_b); - if (var == covariant) { - // matching T to Type{S} in covariant context - b = type_to_static_parameter_value(b); - } if (jl_subtype(b, (jl_value_t*)a, 0)) { if (!is_bnd(a,penv)) { JL_GC_POP(); @@ -765,11 +733,6 @@ static jl_value_t *intersect_typevar(jl_tvar_t *a, jl_value_t *b, JL_GC_POP(); return (jl_value_t*)a; } - jl_value_t *ti = jl_type_intersection(b, penv->data[i+1]); - if (ti == (jl_value_t*)jl_bottom_type) { - JL_GC_POP(); - return ti; - } break; } } @@ -1266,6 +1229,34 @@ static jl_value_t *meet(jl_value_t *X, jl_value_t *Y, variance_t var) return (v == (jl_value_t*)jl_bottom_type ? NULL : v); } +// convert a type to the value it would have if assigned to a static parameter +// in covariant context. +// example: {Type{Int},} => {DataType,} +// calling f{T}(x::T) as f({Int,}) should give T == {DataType,}, but we +// might temporarily represent this type as {Type{Int},} for more precision. +static jl_value_t *type_to_static_parameter_value(jl_value_t *t) +{ + if (jl_is_type_type(t) && !jl_is_typevar(jl_tparam0(t))) + return jl_typeof(jl_tparam0(t)); + if (jl_is_tuple_type(t)) { + jl_svec_t *p = ((jl_datatype_t*)t)->parameters; + size_t l = jl_svec_len(p); + int changed = 0; + jl_svec_t *np = jl_alloc_svec(l); + JL_GC_PUSH1(&np); + for(size_t i=0; i < l; i++) { + jl_value_t *el = type_to_static_parameter_value(jl_svecref(p,i)); + jl_svecset(np, i, el); + if (el != jl_svecref(p,i)) + changed = 1; + } + jl_value_t *result = changed ? (jl_value_t*)jl_apply_tuple_type(np) : t; + JL_GC_POP(); + return result; + } + return t; +} + /* void print_env(cenv_t *soln) { @@ -1282,6 +1273,9 @@ void print_env(cenv_t *soln) static int solve_tvar_constraints(cenv_t *env, cenv_t *soln) { + jl_value_t *rt1=NULL, *rt2=NULL, *S=NULL; + JL_GC_PUSH3(&rt1, &rt2, &S); + while (1) { int old_n = soln->n; @@ -1293,7 +1287,7 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln) if (!jl_is_typevar(*pS)) { // detect cycles if (jl_has_typevars_from_v(*pS, &soln->data[i], 1)) - return 0; + goto ret_no; } } @@ -1313,7 +1307,7 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln) for(int i=0; i < env->n; i+=2) { jl_value_t *T = env->data[i]; jl_value_t **pS = &env->data[i+1]; - jl_value_t *S = *pS; + S = *pS; if (!jl_is_typevar(S)) { for(int j=i+2; j < env->n; j+=2) { jl_value_t *TT = env->data[j]; @@ -1321,8 +1315,10 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln) if (TT == T) { // found T=SS in env if (!jl_is_typevar(SS)) { - jl_value_t *m = meet(S, SS, covariant); - if (m == NULL) return 0; + rt1 = type_to_static_parameter_value(S); + rt2 = type_to_static_parameter_value(SS); + jl_value_t *m = meet(rt1, rt2, covariant); + if (m == NULL) goto ret_no; S = m; } } @@ -1331,7 +1327,7 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln) jl_value_t **pTT = tvar_lookup(soln, &TT); if (pTT != &TT) { jl_value_t *m = meet(S, *pTT, covariant); - if (m == NULL) return 0; + if (m == NULL) goto ret_no; S = m; } } @@ -1348,18 +1344,18 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln) int bot = 0; long mv = meet_tuple_lengths(~lenS, lenT, &bot); if (bot) - return 0; + goto ret_no; // NOTE: this is unused. can we do anything with it? (void)mv; //S = jl_box_long(mv); } else { if (meet(*pT,S,covariant) == NULL) - return 0; + goto ret_no; } } else { - extend(T, S, soln); + extend(T, type_to_static_parameter_value(S), soln); } } else { @@ -1367,7 +1363,7 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln) if (pT != &T) { if (tvar_lookup(soln, &S) == &S) { jl_value_t *v = meet(S, *pT, covariant); - if (v == NULL) return 0; + if (v == NULL) goto ret_no; extend(S, v, soln); *pT = S; } @@ -1383,19 +1379,21 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln) for(int i=0; i < env->n; i+=2) { jl_value_t *T = env->data[i]; jl_value_t **pS = &env->data[i+1]; - jl_value_t *S = *pS; + S = *pS; if (tvar_lookup(soln, &T) == &T) { for(int j=i+2; j < env->n; j+=2) { jl_value_t *TT = env->data[j]; jl_value_t *SS = env->data[j+1]; if (TT == T) { - jl_value_t *m = meet(S, SS, covariant); - if (m == NULL) return 0; + rt1 = type_to_static_parameter_value(S); + rt2 = type_to_static_parameter_value(SS); + jl_value_t *m = meet(rt1, rt2, covariant); + if (m == NULL) goto ret_no; S = m; } else if (SS == T) { jl_value_t *m = meet(S, *tvar_lookup(soln, &TT), covariant); - if (m == NULL) return 0; + if (m == NULL) goto ret_no; S = m; } } @@ -1404,12 +1402,16 @@ static int solve_tvar_constraints(cenv_t *env, cenv_t *soln) S = (jl_value_t*)jl_new_typevar(underscore_sym, (jl_value_t*)jl_bottom_type, S); } - extend(T, S, soln); + extend(T, type_to_static_parameter_value(S), soln); } } } + JL_GC_POP(); return 1; + ret_no: + JL_GC_POP(); + return 0; } jl_value_t *jl_type_intersection_matching(jl_value_t *a, jl_value_t *b, diff --git a/src/support/strtod.c b/src/support/strtod.c index 2d6b1f20a728e..38fd353018103 100644 --- a/src/support/strtod.c +++ b/src/support/strtod.c @@ -28,12 +28,12 @@ locale_t get_c_locale() return c_locale; } -double strtod_c(const char *nptr, char **endptr) +DLLEXPORT double jl_strtod_c(const char *nptr, char **endptr) { return strtod_l(nptr, endptr, get_c_locale()); } -float strtof_c(const char *nptr, char **endptr) +DLLEXPORT float jl_strtof_c(const char *nptr, char **endptr) { return strtof_l(nptr, endptr, get_c_locale()); } @@ -98,7 +98,7 @@ double parse_inf_or_nan(const char *p, char **endptr) } -double strtod_c(const char *nptr, char **endptr) +DLLEXPORT double jl_strtod_c(const char *nptr, char **endptr) { char *fail_pos; double val; @@ -285,9 +285,9 @@ double strtod_c(const char *nptr, char **endptr) } -float strtof_c(const char *nptr, char **endptr) +DLLEXPORT float jl_strtof_c(const char *nptr, char **endptr) { - return (float) strtod_c(nptr, endptr); + return (float) jl_strtod_c(nptr, endptr); } #endif diff --git a/src/support/strtod.h b/src/support/strtod.h index 1758d59b1506b..8dff983d5414b 100644 --- a/src/support/strtod.h +++ b/src/support/strtod.h @@ -7,8 +7,8 @@ extern "C" { #endif -double strtod_c(const char *nptr, char **endptr); -float strtof_c(const char *nptr, char **endptr); +DLLEXPORT double jl_strtod_c(const char *nptr, char **endptr); +DLLEXPORT float jl_strtof_c(const char *nptr, char **endptr); #ifdef __cplusplus } diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 58503c6cde14a..0a8c332324043 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -370,6 +370,17 @@ function test_ind2sub(::Type{TestAbstractArray}) end end +# A custom linear slow array that insists upon Cartesian indexing +type TSlowNIndexes{T,N} <: AbstractArray{T,N} + data::Array{T,N} +end +Base.linearindexing{A<:TSlowNIndexes}(::Type{A}) = Base.LinearSlow() +Base.size(A::TSlowNIndexes) = size(A.data) +Base.getindex(A::TSlowNIndexes, index::Int...) = error("Must use $(ndims(A)) indexes") +Base.getindex{T}(A::TSlowNIndexes{T,2}, i::Int, j::Int) = A.data[i,j] + + + type GenericIterator{N} end Base.start{N}(::GenericIterator{N}) = 1 Base.next{N}(::GenericIterator{N}, i) = (i, i + 1) @@ -452,6 +463,12 @@ function test_vcat_depwarn(::Type{TestAbstractArray}) end end +# Issue 13315 +function test_13315(::Type{TestAbstractArray}) + U = UInt(1):UInt(2) + @test [U;[U;]] == [UInt(1), UInt(2), UInt(1), UInt(2)] +end + #----- run tests -------------------------------------------------------------# for T in (T24Linear, TSlow), shape in ((24,), (2, 12), (2,3,4), (1,2,3,4), (4,3,2,1)) @@ -471,3 +488,9 @@ test_map(TestAbstractArray) test_map_promote(TestAbstractArray) test_UInt_indexing(TestAbstractArray) test_vcat_depwarn(TestAbstractArray) +test_13315(TestAbstractArray) + +A = TSlowNIndexes(rand(2,2)) +@test_throws ErrorException A[1] +@test A[1,1] == A.data[1] +@test first(A) == A.data[1] diff --git a/test/arrayops.jl b/test/arrayops.jl index 20e239ab380bc..ccccea049ee6c 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -1141,10 +1141,10 @@ R = CartesianRange((0,3)) R = CartesianRange((3,0)) @test done(R, start(R)) == true -@test eachindex(Base.LinearSlow(),zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2)) == CartesianRange((3,2,2)) -@test eachindex(Base.LinearFast(),zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2)) == 1:8 -@test eachindex(zeros(3),sub(zeros(3,3),1:2,1:2),zeros(2,2,2),zeros(2,2)) == CartesianRange((3,2,2)) -@test eachindex(zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2)) == 1:8 +@test @inferred(eachindex(Base.LinearSlow(),zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2))) == CartesianRange((3,2,2)) +@test @inferred(eachindex(Base.LinearFast(),zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2))) == 1:8 +@test @inferred(eachindex(zeros(3),sub(zeros(3,3),1:2,1:2),zeros(2,2,2),zeros(2,2))) == CartesianRange((3,2,2)) +@test @inferred(eachindex(zeros(3),zeros(2,2),zeros(2,2,2),zeros(2,2))) == 1:8 #rotates @@ -1286,6 +1286,7 @@ Base.setindex!(A::LinSlowMatrix, v, i::Integer, j::Integer) = A.data[i,j] = v A = rand(3,5) B = LinSlowMatrix(A) +S = sub(A, :, :) @test A == B @test B == A @@ -1295,48 +1296,117 @@ B = LinSlowMatrix(A) for (a,b) in zip(A, B) @test a == b end +for (a,s) in zip(A, S) + @test a == s +end C = copy(B) @test A == C @test B == C -@test vec(A) == vec(B) -@test minimum(A) == minimum(B) -@test maximum(A) == maximum(B) +@test vec(A) == vec(B) == vec(S) +@test minimum(A) == minimum(B) == minimum(S) +@test maximum(A) == maximum(B) == maximum(S) a, ai = findmin(A) b, bi = findmin(B) -@test a == b -@test ai == bi +s, si = findmin(S) +@test a == b == s +@test ai == bi == si a, ai = findmax(A) b, bi = findmax(B) -@test a == b -@test ai == bi +s, si = findmax(S) +@test a == b == s +@test ai == bi == si fill!(B, 2) @test all(x->x==2, B) -i,j = findn(B) iall = (1:size(A,1)).*ones(Int,size(A,2))' jall = ones(Int,size(A,1)).*(1:size(A,2))' +i,j = findn(B) +@test vec(i) == vec(iall) +@test vec(j) == vec(jall) +fill!(S, 2) +i,j = findn(S) @test vec(i) == vec(iall) @test vec(j) == vec(jall) copy!(B, A) - -@test cat(1, A, B) == cat(1, A, A) -@test cat(2, A, B) == cat(2, A, A) - -@test cumsum(A, 1) == cumsum(B, 1) -@test cumsum(A, 2) == cumsum(B, 2) - -@test mapslices(v->sort(v), A, 1) == mapslices(v->sort(v), B, 1) -@test mapslices(v->sort(v), A, 2) == mapslices(v->sort(v), B, 2) - -@test flipdim(A, 1) == flipdim(B, 1) -@test flipdim(A, 2) == flipdim(B, 2) - -@test A + 1 == B + 1 -@test 2*A == 2*B -@test A/3 == B/3 +copy!(S, A) + +@test cat(1, A, B, S) == cat(1, A, A, A) +@test cat(2, A, B, S) == cat(2, A, A, A) + +@test cumsum(A, 1) == cumsum(B, 1) == cumsum(S, 1) +@test cumsum(A, 2) == cumsum(B, 2) == cumsum(S, 2) + +@test mapslices(v->sort(v), A, 1) == mapslices(v->sort(v), B, 1) == mapslices(v->sort(v), S, 1) +@test mapslices(v->sort(v), A, 2) == mapslices(v->sort(v), B, 2) == mapslices(v->sort(v), S, 2) + +@test flipdim(A, 1) == flipdim(B, 1) == flipdim(S, 2) +@test flipdim(A, 2) == flipdim(B, 2) == flipdim(S, 2) + +@test A + 1 == B + 1 == S + 1 +@test 2*A == 2*B == 2*S +@test A/3 == B/3 == S/3 + +# issue #13250 +x13250 = zeros(3) +x13250[UInt(1):UInt(2)] = 1.0 +@test x13250[1] == 1.0 +@test x13250[2] == 1.0 +@test x13250[3] == 0.0 + +# issue #13254 +let A = zeros(Int, 2, 2), B = zeros(Float64, 2, 2) + f1() = [1] + f2() = [1;] + f3() = [1;2] + f4() = [1;2.0] + f5() = [1 2] + f6() = [1 2.0] + f7() = Int[1] + f8() = Float64[1] + f9() = Int[1;] + f10() = Float64[1;] + f11() = Int[1;2] + f12() = Float64[1;2] + f13() = Int[1;2.0] + f14() = Int[1 2] + f15() = Float64[1 2] + f16() = Int[1 2.0] + f17() = [1:2;] + f18() = Int[1:2;] + f19() = Float64[1:2;] + f20() = [1:2;1:2] + f21() = Int[1:2;1:2] + f22() = Float64[1:2;1:2] + f23() = [1:2;1.0:2.0] + f24() = Int[1:2;1.0:2.0] + f25() = [1:2 1:2] + f26() = Int[1:2 1:2] + f27() = Float64[1:2 1:2] + f28() = [1:2 1.0:2.0] + f29() = Int[1:2 1.0:2.0] + f30() = [A;] + f31() = Int[A;] + f32() = Float64[A;] + f33() = [A;A] + f34() = Int[A;A] + f35() = Float64[A;A] + f36() = [A;B] + f37() = Int[A;B] + f38() = [A A] + f39() = Int[A A] + f40() = Float64[A A] + f41() = [A B] + f42() = Int[A B] + + for f in [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16, + f17, f18, f19, f20, f21, f22, f23, f24, f25, f26, f27, f28, f29, f30, + f31, f32, f33, f34, f35, f36, f37, f38, f39, f40, f41, f42] + @test isleaftype(Base.return_types(f, ())[1]) + end +end diff --git a/test/backtrace.jl b/test/backtrace.jl index 19c0f4f17eeeb..16bfec0f626d1 100644 --- a/test/backtrace.jl +++ b/test/backtrace.jl @@ -34,6 +34,7 @@ eval(Expr(:function, Expr(:call, :test_inline_1), # different-file inline eval(Expr(:function, Expr(:call, :test_inline_2), Expr(:block, LineNumberNode(symbol("backtrace.jl"), 99), + LineNumberNode(symbol("foobar.jl"), 666), LineNumberNode(symbol("/foo/bar/baz.jl"), 111), Expr(:call, :throw, "foo")))) @@ -74,6 +75,7 @@ loc = functionloc(f12977) @test endswith(loc[1], "backtrace.jl") @test loc[2] == linenum +# issue #922: SimplifyCFG pass merges throws code_loc(p, skipC=true) = ccall(:jl_lookup_code_address, Any, (Ptr{Void},Cint), p, skipC) @noinline function test_throw_commoning(x) diff --git a/test/bigint.jl b/test/bigint.jl index 50bb8bc3137e6..c2a11443c2d78 100644 --- a/test/bigint.jl +++ b/test/bigint.jl @@ -280,3 +280,19 @@ ndigits_mismatch(n) = ndigits(n) != ndigits(BigInt(n)) @test BigInt(2.0) == BigInt(2.0f0) == BigInt(big(2.0)) == 2 @test_throws InexactError convert(BigInt, 2.1) @test_throws InexactError convert(BigInt, big(2.1)) + +# issue #13367 +@test trunc(BigInt,2.1) == 2 +@test round(BigInt,2.1) == 2 +@test floor(BigInt,2.1) == 2 +@test ceil(BigInt,2.1) == 3 + +@test trunc(BigInt,2.1f0) == 2 +@test round(BigInt,2.1f0) == 2 +@test floor(BigInt,2.1f0) == 2 +@test ceil(BigInt,2.1f0) == 3 + +@test_throws InexactError trunc(BigInt,Inf) +@test_throws InexactError round(BigInt,Inf) +@test_throws InexactError floor(BigInt,Inf) +@test_throws InexactError ceil(BigInt,Inf) diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 8a81dcaa73c05..9a8e9396aed1a 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -227,4 +227,9 @@ let exename = `$(joinpath(JULIA_HOME, Base.julia_exename())) --precompiled=yes` # issue #10562 @test readchomp(`$exename -e 'println(ARGS);' ''`) == "UTF8String[\"\"]" + # issue #12679 + @test readchomp(pipeline(ignorestatus(`$exename -f --compile=yes -foo`),stderr=`cat`)) == "ERROR: unknown option `-o`" + @test readchomp(pipeline(ignorestatus(`$exename -f -p`),stderr=`cat`)) == "ERROR: option `-p/--procs` is missing an argument" + @test readchomp(pipeline(ignorestatus(`$exename -f --inline`),stderr=`cat`)) == "ERROR: option `--inline` is missing an argument" + @test readchomp(pipeline(ignorestatus(`$exename -f -e "@show ARGS" -now -- julia RUN.jl`),stderr=`cat`)) == "ERROR: unknown option `-n`" end diff --git a/test/core.jl b/test/core.jl index 2556753c1f14c..eaaf75a998fa5 100644 --- a/test/core.jl +++ b/test/core.jl @@ -3378,3 +3378,40 @@ g13261() = f13261() type IO13433 <: IO end Base.read(::IO13433, ::Type{UInt8}) = 0x01 @test read!(IO13433(), Array(UInt8, 4)) == [0x01, 0x01, 0x01, 0x01] + +# issue #13647, comparing boxed isbits immutables +immutable X13647 + a::Int + b::Bool +end +function f13647(x, y) + z = false + z = y + x === z +end +@test f13647(X13647(1, false), X13647(1, false)) +@test !f13647(X13647(1, false), X13647(1, true)) +@test !f13647(X13647(2, false), X13647(1, false)) + +# issue #13636 +module I13636 +foo(x) = 1 +end +let cache = Dict() + function I13636.foo(y::Int;k::Int=1) + cache[1] = y+k + end +end +@test I13636.foo(1,k=2) == 3 + +# issue #11327 and #13547 +@test_throws MethodError convert(Type{Int}, Float32) +# TODO: this should probably be a MethodError in `convert`; not sure what's going on +@test_throws TypeError Array{Type{Int64}}([Float32]) +abstract A11327 +abstract B11327 <: A11327 +f11327{T}(::Type{T},x::T) = x +@test_throws MethodError f11327(Type{A11327},B11327) +let T=TypeVar(:T,true) + @test typeintersect(Tuple{Type{T},T}, Tuple{Type{Type{Float64}},Type{Int}}) === Union{} +end diff --git a/test/dates/conversions.jl b/test/dates/conversions.jl index 68136d9a1d8b4..9d749c8d94994 100644 --- a/test/dates/conversions.jl +++ b/test/dates/conversions.jl @@ -71,3 +71,12 @@ end @test Dates.Year(3) < Dates.Month(37) @test_throws InexactError convert(Dates.Year, Dates.Month(37)) @test_throws InexactError Dates.Month(Dates.Year(typemax(Int64))) + +# Ensure that conversion of 32-bit integers work +let dt = DateTime(1915,1,1,12) + unix = Int32(Dates.datetime2unix(dt)) + julian = Int32(Dates.datetime2julian(dt)) + + @test Dates.unix2datetime(unix) == dt + @test Dates.julian2datetime(julian) == dt +end diff --git a/test/docs.jl b/test/docs.jl index 5abb6b059b5c3..033f38f3538df 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -264,6 +264,9 @@ end @test docstrings_equal(@doc(BareModule.A), doc"A") @test docstrings_equal(@doc(BareModule.T), doc"T") +@test_throws ErrorException @doc("...", "error") +@test_throws ErrorException @doc("...", @time 0) + # test that when no docs exist, they fallback to # the docs for the typeof(value) let d1 = @doc(DocsTest.val) @@ -411,6 +414,13 @@ f12593_2() = 1 # test that macro documentation works @test (Docs.@repl @assert) !== nothing +@test (Docs.@repl 0) !== nothing + +let t = @doc(DocsTest.t(::Int, ::Int)) + @test docstrings_equal(Docs.@repl(DocsTest.t(0, 0)), t) + @test docstrings_equal(Docs.@repl(DocsTest.t(::Int, ::Int)), t) +end + # Issue #13467. @test (Docs.@repl @r_str) !== nothing @@ -461,6 +471,9 @@ end @test docstrings_equal(Docs.doc(I13068.A.foo, Tuple{Float64}), doc"foo from B") @test Docs.doc(I13068.A.foo, Tuple{Char}) === nothing +# Issue #13905. +@test macroexpand(:(@doc "" f() = @x)) == Expr(:error, UndefVarError(symbol("@x"))) + # Undocumented DataType Summaries. module Undocumented diff --git a/test/linalg/arnoldi.jl b/test/linalg/arnoldi.jl index 78b14e84b2ba8..89382dbb52e4c 100644 --- a/test/linalg/arnoldi.jl +++ b/test/linalg/arnoldi.jl @@ -204,3 +204,11 @@ let # complex svds test @test_throws ArgumentError svds(A,nsv=0) @test_throws ArgumentError svds(A,nsv=20) end + +# test promotion +eigs(rand(1:10, 10, 10)) +eigs(rand(1:10, 10, 10), rand(1:10, 10, 10) |> t -> t't) +svds(rand(1:10, 10, 8)) +@test_throws MethodError eigs(big(rand(1:10, 10, 10))) +@test_throws MethodError eigs(big(rand(1:10, 10, 10)), rand(1:10, 10, 10)) +@test_throws MethodError svds(big(rand(1:10, 10, 8))) diff --git a/test/linalg/generic.jl b/test/linalg/generic.jl index a1ce1a5061419..7df2a235643f1 100644 --- a/test/linalg/generic.jl +++ b/test/linalg/generic.jl @@ -141,3 +141,12 @@ let x = Vector{Int}[[1,2], [3,4]] @test norm(x, 1) ≈ sqrt(5) + 5 @test norm(x, 3) ≈ cbrt(sqrt(125)+125) end + +# test that LinAlg.axpy! works for element type without commutative multiplication +let + α = ones(Int, 2, 2) + x = fill([1 0; 1 1], 3) + y = fill(zeros(Int, 2, 2), 3) + @test LinAlg.axpy!(α, x, deepcopy(y)) == x .* Matrix{Int}[α] + @test LinAlg.axpy!(α, x, deepcopy(y)) != Matrix{Int}[α] .* x +end diff --git a/test/linalg/qr.jl b/test/linalg/qr.jl index cc77f34f4b072..33c12739fd329 100644 --- a/test/linalg/qr.jl +++ b/test/linalg/qr.jl @@ -54,6 +54,8 @@ debug && println("QR decomposition (without pivoting)") @test_approx_eq_eps A_mul_Bc(eye(eltyb,size(q.factors,2)),q)*full(q, thin=false) eye(n) 5000ε if eltya != Int @test eye(eltyb,n)*q ≈ convert(AbstractMatrix{tab},q) + ac = copy(a) + @test qrfact!(a[:, 1:5])\b == qrfact!(sub(ac, :, 1:5))\b end debug && println("Thin QR decomposition (without pivoting)") diff --git a/test/linalg/triangular.jl b/test/linalg/triangular.jl index f7b7af9a73a05..51a25a98ce4e3 100644 --- a/test/linalg/triangular.jl +++ b/test/linalg/triangular.jl @@ -59,15 +59,23 @@ for elty1 in (Float32, Float64, Complex64, Complex128, BigFloat, Int) for i = 1:size(A1, 1) for j = 1:size(A1, 2) if uplo1 == :U - if i > j || (i == j && t1 == UnitUpperTriangular) - @test_throws BoundsError A1c[i,j] = 0 + if i > j + A1c[i,j] = 0 + @test_throws ArgumentError A1c[i,j] = 1 + elseif i == j && t1 == UnitUpperTriangular + A1c[i,j] = 1 + @test_throws ArgumentError A1c[i,j] = 0 else A1c[i,j] = 0 @test A1c[i,j] == 0 end else - if i < j || (i == j && t1 == UnitLowerTriangular) - @test_throws BoundsError A1c[i,j] = 0 + if i < j + A1c[i,j] = 0 + @test_throws ArgumentError A1c[i,j] = 1 + elseif i == j && t1 == UnitLowerTriangular + A1c[i,j] = 1 + @test_throws ArgumentError A1c[i,j] = 0 else A1c[i,j] = 0 @test A1c[i,j] == 0 @@ -134,6 +142,11 @@ for elty1 in (Float32, Float64, Complex64, Complex128, BigFloat, Int) copy!(B, A1.') @test B == A1.' + #expm/logm + if (elty1 == Float64 || elty1 == Complex128) && (t1 == UpperTriangular || t1 == LowerTriangular) + @test expm(full(logm(A1))) ≈ full(A1) + end + # scale if (t1 == UpperTriangular || t1 == LowerTriangular) unitt = istriu(A1) ? UnitUpperTriangular : UnitLowerTriangular @@ -282,6 +295,10 @@ for elty1 in (Float32, Float64, Complex64, Complex128, BigFloat, Int) @test_approx_eq B[:,1]'A1' B[:,1]'full(A1)' @test_approx_eq B'A1' B'full(A1)' + if eltyB == elty1 + @test_approx_eq A_mul_B!(zeros(B),A1,B) A1*B + @test_approx_eq A_mul_Bc!(zeros(B),A1,B) A1*B' + end #error handling @test_throws DimensionMismatch Base.LinAlg.A_mul_B!(A1, ones(eltyB,n+1)) @test_throws DimensionMismatch Base.LinAlg.A_mul_B!(ones(eltyB,n+1,n+1), A1) @@ -305,6 +322,7 @@ for elty1 in (Float32, Float64, Complex64, Complex128, BigFloat, Int) # Error bounds elty1 != BigFloat && errorbounds(A1, A1\B, B) + end end end diff --git a/test/markdown.jl b/test/markdown.jl index 25c67524ca788..75fb6abfe0f1f 100644 --- a/test/markdown.jl +++ b/test/markdown.jl @@ -75,6 +75,20 @@ World""" |> plain == "Hello\n\n–––\n\nWorld\n" > baz > ```""" |> plain == """> foo\n>\n> * bar\n>\n> ```\n> baz\n> ```\n\n""" +# Terminal (markdown) output + +# multiple whitespace is ignored +@test sprint(term, md"a b") == " a b\n" +@test sprint(term, md"- a + not code") == " • a not code\n" +@test sprint(term, md"[x](https://julialang.org)") == " x\n" +@test sprint(term, md"![x](https://julialang.org)") == " (Image: x)\n" + +# enumeration is normalized +@test sprint(term, md""" + 1. a + 3. b""") == " 1. a\n 2. b\n" + # HTML output @test md"foo *bar* baz" |> html == "

foo bar baz

\n" diff --git a/test/parallel.jl b/test/parallel.jl index 6e3c36055d70f..77e58b7461086 100644 --- a/test/parallel.jl +++ b/test/parallel.jl @@ -377,14 +377,24 @@ catch ex @test collect(1:5) == sort(map(x->parse(Int, x), errors)) end -try - remotecall_fetch(id_other, ()->throw(ErrorException("foobar"))) - error("unexpected") -catch ex - @test typeof(ex) == RemoteException - @test typeof(ex.captured) == CapturedException - @test typeof(ex.captured.ex) == ErrorException - @test ex.captured.ex.msg == "foobar" +macro test_remoteexception_thrown(expr) + quote + try + $(esc(expr)) + error("unexpected") + catch ex + @test typeof(ex) == RemoteException + @test typeof(ex.captured) == CapturedException + @test typeof(ex.captured.ex) == ErrorException + @test ex.captured.ex.msg == "foobar" + end + end +end + +for id in [id_other, id_me] + @test_remoteexception_thrown remotecall_fetch(id, ()->throw(ErrorException("foobar"))) + @test_remoteexception_thrown remotecall_wait(id, ()->throw(ErrorException("foobar"))) + @test_remoteexception_thrown wait(remotecall(id, ()->throw(ErrorException("foobar")))) end # The below block of tests are usually run only on local development systems, since: @@ -529,3 +539,6 @@ end let t = schedule(@task f13168(100)) @test schedule(t) === t end + +# issue #13122 +@test remotecall_fetch(workers()[1], identity, C_NULL) === C_NULL diff --git a/test/perf/micro/Makefile b/test/perf/micro/Makefile index 1516d2e3a5d22..56a83c26ec937 100644 --- a/test/perf/micro/Makefile +++ b/test/perf/micro/Makefile @@ -140,3 +140,5 @@ clean: @rm -rf perf.h bin/perf* bin/fperf* benchmarks/*.csv benchmarks.csv mods *~ octave-core perf.log gopath .PHONY: all perf clean + +.PRECIOUS: bin/perf0 bin/perf1 bin/perf2 bin/perf3 diff --git a/test/perf/micro/perf.c b/test/perf/micro/perf.c index 7d764fccd13ce..7bfa4199e67a7 100644 --- a/test/perf/micro/perf.c +++ b/test/perf/micro/perf.c @@ -59,7 +59,7 @@ double *matmul_aat(int n, double *b) { int mandel(double complex z) { int maxiter = 80; double complex c = z; - for (int n=0; n 2.0) { return n; } @@ -68,19 +68,14 @@ int mandel(double complex z) { return maxiter; } -int mandelperf() { - /* The initialization on the next two lines is deliberately written to - * prevent gcc from optimizing away the entire loop. - * (First observed in gcc 4.9.2) */ - static volatile int mandel_sum_init = 0; - int mandel_sum = mandel_sum_init; - for (int re=-20; re<=5; re+=1) { - for (int im=-10; im<=10; im+=1) { - int m = mandel(re/10.0+I*im/10.0); - mandel_sum += m; +int *mandelperf() { + int *M = (int*) malloc(21*26*sizeof(int)); + for (int i = 0; i < 21; i++) { + for (int j = 0; j < 26; j++) { + M[26*i + j] = mandel((j-20)/10.0 + ((i-10)/10.0)*I); } } - return mandel_sum; + return M; } void quicksort(double *a, int lo, int hi) { @@ -293,20 +288,38 @@ int main() { // print_perf("AtA", tmin); // mandel - int mandel_sum; - int mandel_sum2 = 0; + /* The initialization on the next line is deliberately volatile to + * prevent gcc from optimizing away the entire loop. + * (First observed in gcc 4.9.2) + */ + static volatile int mandel_sum_init = 0; + int mandel_sum2 = mandel_sum_init; tmin = INFINITY; for (int i=0; i a+b, [1 2; 3 4], 2, 0.0) rt = Base.return_types(reducedim, Tuple{Function, Array{Float64, 3}, Int, Float64}) @test length(rt) == 1 && rt[1] == Array{Float64, 3} + ## findmin/findmax A = [1.0 3.0 6.0; 5.0 2.0 4.0] -@test findmin(A, (1,)) == ([1.0 2.0 4.0], [1 4 6]) -@test findmin(A, (2,)) == (reshape([1.0,2.0], 2, 1), reshape([1,4], 2, 1)) -@test findmin(A, (1,2)) == (fill(1.0,1,1),fill(1,1,1)) -@test findmax(A, (1,)) == ([5.0 3.0 6.0], [2 3 5]) -@test findmax(A, (2,)) == (reshape([6.0,5.0], 2, 1), reshape([5,2], 2, 1)) -@test findmax(A, (1,2)) == (fill(6.0,1,1),fill(5,1,1)) +for (tup, rval, rind) in [((1,), [1.0 2.0 4.0], [1 4 6]), + ((2,), reshape([1.0,2.0], 2, 1), reshape([1,4], 2, 1)), + ((1,2), fill(1.0,1,1),fill(1,1,1))] + @test findmin(A, tup) == (rval, rind) + @test Base.findmin!(similar(rval), similar(rind), A) == (rval, rind) +end + +for (tup, rval, rind) in [((1,), [5.0 3.0 6.0], [2 3 5]), + ((2,), reshape([6.0,5.0], 2, 1), reshape([5,2], 2, 1)), + ((1,2), fill(6.0,1,1),fill(5,1,1))] + @test findmax(A, tup) == (rval, rind) + @test Base.findmax!(similar(rval), similar(rind), A) == (rval, rind) +end # issue #6672 @test sum(Real[1 2 3; 4 5.3 7.1], 2) == reshape([6, 16.4], 2, 1) diff --git a/test/reflection.jl b/test/reflection.jl index f3a53e633025e..d37f0e16342f3 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -46,18 +46,19 @@ test_code_reflections(test_bin_reflection, code_native) module WarnType using Base.Test -iob = IOBuffer() +function warntype_hastag(f, types, tag) + iob = IOBuffer() + code_warntype(iob, f, types) + str = takebuf_string(iob) + !isempty(search(str, tag)) +end pos_stable(x) = x > 0 ? x : zero(x) pos_unstable(x) = x > 0 ? x : 0 tag = Base.have_color ? Base.text_colors[:red] : "UNION" -code_warntype(iob, pos_unstable, Tuple{Float64,}) -str = takebuf_string(iob) -@test !isempty(search(str, tag)) -code_warntype(iob, pos_stable, Tuple{Float64,}) -str = takebuf_string(iob) -@test isempty(search(str, tag)) +@test warntype_hastag(pos_unstable, Tuple{Float64}, tag) +@test !warntype_hastag(pos_stable, Tuple{Float64}, tag) type Stable{T,N} A::Array{T,N} @@ -69,15 +70,9 @@ Base.getindex(A::Stable, i) = A.A[i] Base.getindex(A::Unstable, i) = A.A[i] tag = Base.have_color ? Base.text_colors[:red] : "ARRAY{FLOAT64,N}" -code_warntype(iob, getindex, Tuple{Unstable{Float64},Int}) -str = takebuf_string(iob) -@test !isempty(search(str, tag)) -code_warntype(iob, getindex, Tuple{Stable{Float64,2},Int}) -str = takebuf_string(iob) -@test isempty(search(str, tag)) -code_warntype(iob, getindex, Tuple{Stable{Float64},Int}) -str = takebuf_string(iob) -@test !isempty(search(str, tag)) +@test warntype_hastag(getindex, Tuple{Unstable{Float64},Int}, tag) +@test !warntype_hastag(getindex, Tuple{Stable{Float64,2},Int}, tag) +@test warntype_hastag(getindex, Tuple{Stable{Float64},Int}, tag) function funfun(x) function internal(y) @@ -88,16 +83,21 @@ function funfun(x) end tag = Base.have_color ? string("2y",Base.text_colors[:red],"::Any") : "2y::ANY" -code_warntype(iob, funfun, Tuple{Float64}) -str = takebuf_string(iob) -@test !isempty(search(str, tag)) +@test warntype_hastag(funfun, Tuple{Float64}, tag) # Make sure emphasis is not used for other functions tag = Base.have_color ? Base.text_colors[:red] : "ANY" +iob = IOBuffer() show(iob, expand(:(x->x^2))) str = takebuf_string(iob) @test isempty(search(str, tag)) +# issue #13568 +@test !warntype_hastag(+, Tuple{Int,Int}, tag) +@test !warntype_hastag(-, Tuple{Int,Int}, tag) +@test !warntype_hastag(*, Tuple{Int,Int}, tag) +@test !warntype_hastag(/, Tuple{Int,Int}, tag) + end # isbits diff --git a/test/replutil.jl b/test/replutil.jl index c0c8760d10d17..dc054ad9787b7 100644 --- a/test/replutil.jl +++ b/test/replutil.jl @@ -132,3 +132,43 @@ let showerror(buff, MethodError(convert, Tuple{Type, Float64})) showerror(buff, MethodError(convert, Tuple{DataType, Float64})) end + +# Issue #13032 +withenv("JULIA_EDITOR" => nothing, "VISUAL" => nothing, "EDITOR" => nothing) do + + # Make sure editor doesn't error when no ENV editor is set. + @test isa(Base.editor(), Array) + + # Invalid editor + ENV["JULIA_EDITOR"] = "" + @test_throws ErrorException Base.editor() + + # Note: The following testcases should work regardless of whether these editors are + # installed or not. + + # Editor on the path. + ENV["JULIA_EDITOR"] = "vim" + @test Base.editor() == ["vim"] + + # Absolute path to editor. + ENV["JULIA_EDITOR"] = "/usr/bin/vim" + @test Base.editor() == ["/usr/bin/vim"] + + # Editor on the path using arguments. + ENV["JULIA_EDITOR"] = "subl -w" + @test Base.editor() == ["subl", "-w"] + + # Absolute path to editor with spaces. + ENV["JULIA_EDITOR"] = "/Applications/Sublime\\ Text.app/Contents/SharedSupport/bin/subl" + @test Base.editor() == ["/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl"] + + # Paths with spaces and arguments (#13032). + ENV["JULIA_EDITOR"] = "/Applications/Sublime\\ Text.app/Contents/SharedSupport/bin/subl -w" + @test Base.editor() == ["/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", "-w"] + + ENV["JULIA_EDITOR"] = "'/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl' -w" + @test Base.editor() == ["/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", "-w"] + + ENV["JULIA_EDITOR"] = "\"/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl\" -w" + @test Base.editor() == ["/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl", "-w"] +end \ No newline at end of file diff --git a/test/serialize.jl b/test/serialize.jl index 1b63b7fe25734..6b339c4c87fd4 100644 --- a/test/serialize.jl +++ b/test/serialize.jl @@ -39,7 +39,9 @@ end # Ptr create_serialization_stream() do s - @test_throws ErrorException serialize(s, C_NULL) + serialize(s, C_NULL) + seekstart(s) + @test deserialize(s) === C_NULL end # Integer @@ -319,3 +321,26 @@ create_serialization_stream() do s r2 = deserialize(s) @test r1 == r2 end + +# issue #13452 +module Test13452 +using Base.Test + +module Shell +export foo +foo(x) = error("Instances must implement foo") +end + +module Instance1 +using ..Shell +Shell.foo(x::Int) = "This is an Int" +end + +using .Shell, .Instance1 +io = IOBuffer() +serialize(io, foo) +str = takebuf_string(io) +@test isempty(search(str, "Instance1")) +@test !isempty(search(str, "Shell")) + +end # module Test13452 diff --git a/test/sets.jl b/test/sets.jl index 8570042f7f98a..690912338140c 100644 --- a/test/sets.jl +++ b/test/sets.jl @@ -194,7 +194,7 @@ end @test ⊊(Set([1]), Set([1,2])) @test !⊊(Set([1]), Set([1])) @test ⊈(Set([1]), Set([2])) -@test symdiff(Set([1,2,3,4]), Set([2,4,5,6])) == Set([1,3,5, 6]) +@test symdiff(Set([1,2,3,4]), Set([2,4,5,6])) == Set([1,3,5,6]) # unique u = unique([1,1,2]) @@ -212,4 +212,16 @@ filter!(isodd, s) @test_throws ArgumentError first(Set()) @test first(Set(2)) == 2 -# ########## end of set tests ########## +# pop! +let s = Set(1:5) + @test 2 in s + @test pop!(s, 2) == 2 + @test !(2 in s) + @test_throws KeyError pop!(s, 2) + @test pop!(s, 2, ()) == () + @test 3 in s + @test pop!(s, 3, ()) == 3 + @test !(3 in s) +end + +@test pop!(Set(1:2), 2, nothing) == 2 diff --git a/test/sparsedir/sparse.jl b/test/sparsedir/sparse.jl index 1504d6d3e6c79..4cbba2adfc14c 100644 --- a/test/sparsedir/sparse.jl +++ b/test/sparsedir/sparse.jl @@ -221,6 +221,15 @@ b = randn(3) @test scale(0.5, dA) == scale!(0.5, copy(sA)) @test scale!(sC, 0.5, sA) == scale!(sC, sA, 0.5) +# conj + +cA = sprandn(5,5,0.2) + im*sprandn(5,5,0.2) +@test full(conj(cA)) == conj(full(cA)) + +# exp +A = sprandn(5,5,0.2) +@test e.^A ≈ e.^full(A) + # reductions pA = sparse(rand(3, 7)) @@ -879,6 +888,14 @@ let A = sprand(10,10,0.3), B = sprand(10,10,0.3), CF = rand(10,10), AF = full(A @test BF[:,1] .^ A == BF[:,1] .^ AF end +# test broadcasting for empty matrices +@test spzeros(0,0) + spzeros(0,0) == zeros(0,0) +@test spzeros(0,0) * spzeros(0,0) == zeros(0,0) +@test spzeros(1,0) .+ spzeros(2,1) == zeros(2,0) +@test spzeros(1,0) .* spzeros(2,1) == zeros(2,0) +@test spzeros(1,2) .+ spzeros(0,1) == zeros(0,2) +@test spzeros(1,2) .* spzeros(0,1) == zeros(0,2) + # test throws A = sprandbool(5,5,0.2) @test_throws ArgumentError reinterpret(Complex128,A,(5,5)) @@ -942,6 +959,7 @@ perm = randperm(10) @test_throws DimensionMismatch diagm(sparse(ones(5,2))) @test_throws DimensionMismatch diagm(sparse(ones(2,5))) @test diagm(sparse(ones(1,5))) == speye(5) +@test diagm(sparse(ones(5,1))) == speye(5) # triu/tril A = sprand(5,5,0.2) @@ -1140,3 +1158,28 @@ end let A = 2. * speye(5,5) @test full(spones(A)) == eye(full(A)) end + +let + A = spdiagm(rand(5)) + sprandn(5,5,0.2) + im*sprandn(5,5,0.2) + A = A*A' + @test abs(det(factorize(Hermitian(A)))) ≈ abs(det(factorize(full(A)))) + A = spdiagm(rand(5)) + sprandn(5,5,0.2) + A = A*A.' + @test abs(det(factorize(Symmetric(A)))) ≈ abs(det(factorize(full(A)))) + @test_throws ErrorException chol(A) + @test_throws ErrorException lu(A) + @test_throws ErrorException eig(A) + @test_throws ErrorException inv(A) +end + +let + n = 100 + A = sprandn(n, n, 0.5) + sqrt(n)*I + x = LowerTriangular(A)*ones(n) + @test LowerTriangular(A)\x ≈ ones(n) + x = UpperTriangular(A)*ones(n) + @test UpperTriangular(A)\x ≈ ones(n) + A[2,2] = 0 + @test_throws LinAlg.SingularException LowerTriangular(A)\ones(n) + @test_throws LinAlg.SingularException UpperTriangular(A)\ones(n) +end diff --git a/test/sparsedir/umfpack.jl b/test/sparsedir/umfpack.jl index 2a7e708eca2e5..8f436cdca50f6 100644 --- a/test/sparsedir/umfpack.jl +++ b/test/sparsedir/umfpack.jl @@ -59,3 +59,6 @@ end #4523 - complex sparse \ x = speye(2) + im * speye(2) @test_approx_eq (x*(lufact(x) \ ones(2))) ones(2) + +@test det(sparse([1,3,3,1], [1,1,3,3], [1,1,1,1])) == 0 + diff --git a/test/spawn.jl b/test/spawn.jl index a0a4083bda9ae..5707e28a917f1 100644 --- a/test/spawn.jl +++ b/test/spawn.jl @@ -307,3 +307,25 @@ let fname = tempname() @test success(pipeline(`cat $fname`, `$exename -e $code`)) rm(fname) end + +let cmd = AbstractString[] + # Ensure that quoting works + @test Base.shell_split("foo bar baz") == ["foo", "bar", "baz"] + @test Base.shell_split("foo\\ bar baz") == ["foo bar", "baz"] + @test Base.shell_split("'foo bar' baz") == ["foo bar", "baz"] + @test Base.shell_split("\"foo bar\" baz") == ["foo bar", "baz"] + + # "Over quoted" + @test Base.shell_split("'foo\\ bar' baz") == ["foo\\ bar", "baz"] + @test Base.shell_split("\"foo\\ bar\" baz") == ["foo\\ bar", "baz"] + + # Ensure that shell_split handles quoted spaces + cmd = ["/Volumes/External HD/program", "-a"] + @test Base.shell_split("/Volumes/External\\ HD/program -a") == cmd + @test Base.shell_split("'/Volumes/External HD/program' -a") == cmd + @test Base.shell_split("\"/Volumes/External HD/program\" -a") == cmd + + # Backticks should automatically quote where necessary + cmd = ["foo bar", "baz"] + @test string(`$cmd`) == "`'foo bar' baz`" +end diff --git a/test/unicode/utf8proc.jl b/test/unicode/utf8proc.jl index 8f97a160b271a..4f979c347b721 100644 --- a/test/unicode/utf8proc.jl +++ b/test/unicode/utf8proc.jl @@ -239,7 +239,12 @@ let grphtest = (("b\u0300lahβlahb\u0302láh", ["b\u0300","l","a","h", for (s, g) in grphtest s_ = T(normalize_string(s, nf)) g_ = map(s -> normalize_string(s, nf), g) + # #9261 + if length(s_) > 0 + @test typeof(first(graphemes(s_))) == SubString{typeof(s_)} + end grph = collect(graphemes(s_)) + @test eltype(grph) == SubString{typeof(s_)} @test grph == g_ @test length(graphemes(s_)) == length(grph) end diff --git a/ui/repl.c b/ui/repl.c index a4c11ea2dc41b..9378fca2a30a6 100644 --- a/ui/repl.c +++ b/ui/repl.c @@ -160,27 +160,40 @@ void parse_opts(int *argcp, char ***argvp) { 0, 0, 0, 0 } }; // getopt handles argument parsing up to -- delineator - int lastind = optind; int argc = *argcp; + char **argv = *argvp; if (argc > 0) { for (int i=0; i < argc; i++) { - if (!strcmp((*argvp)[i], "--")) { + if (!strcmp(argv[i], "--")) { argc = i; break; } } } - int c; char *endptr; - opterr = 0; - int skip = 0; - while ((c = getopt_long(argc,*argvp,shortopts,longopts,0)) != -1) { + opterr = 0; // suppress getopt warning messages + while (1) { + int lastind = optind; + int c = getopt_long(argc, argv, shortopts, longopts, 0); + if (c == -1) break; switch (c) { case 0: break; case '?': - if (optind != lastind) skip++; - lastind = optind; + case ':': + if (optopt) { + for (struct option *o = longopts; o->val; o++) { + if (optopt == o->val) { + if (strchr(shortopts, o->val)) + jl_errorf("option `-%c/--%s` is missing an argument", o->val, o->name); + else + jl_errorf("option `--%s` is missing an argument", o->name); + } + } + jl_errorf("unknown option `-%c`", optopt); + } else { + jl_errorf("unknown option `%s`", argv[lastind]); + } break; case 'v': // version jl_printf(JL_STDOUT, "julia version %s\n", JULIA_VERSION_STRING); @@ -391,7 +404,6 @@ void parse_opts(int *argcp, char ***argvp) } jl_options.code_coverage = codecov; jl_options.malloc_log = malloclog; - optind -= skip; *argvp += optind; *argcp -= optind; }