From 897e666be71e6a281d6df24d954d7434c5a4a434 Mon Sep 17 00:00:00 2001 From: Mus M Date: Fri, 12 May 2017 17:19:17 -0400 Subject: [PATCH 01/53] Use uninitialized buffer for get_process_title() --- base/sysinfo.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/sysinfo.jl b/base/sysinfo.jl index fb9119dd668b50..73e7ff33451e65 100644 --- a/base/sysinfo.jl +++ b/base/sysinfo.jl @@ -162,7 +162,7 @@ total_memory() = ccall(:uv_get_total_memory, UInt64, ()) Get the process title. On some systems, will always return empty string. (not exported) """ function get_process_title() - buf = zeros(UInt8, 512) + buf = Vector{UInt8}(512) err = ccall(:uv_get_process_title, Cint, (Ptr{UInt8}, Cint), buf, 512) Base.uv_error("get_process_title", err) return unsafe_string(pointer(buf)) From 4009b0cfc98beed0ae68dea031e373516ea45e50 Mon Sep 17 00:00:00 2001 From: Mus M Date: Tue, 16 May 2017 00:54:23 -0400 Subject: [PATCH 02/53] Use VersionNumber for libllvm_version --- base/Makefile | 2 +- base/atomics.jl | 6 +++--- base/version.jl | 2 ++ test/cmdlineargs.jl | 2 +- test/llvmcall.jl | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/base/Makefile b/base/Makefile index 04c97fda88e8df..02d68c08ea3cd9 100644 --- a/base/Makefile +++ b/base/Makefile @@ -55,7 +55,7 @@ else endif @echo "const libfftw_name = \"$(LIBFFTWNAME)\"" >> $@ @echo "const libfftwf_name = \"$(LIBFFTWFNAME)\"" >> $@ - @echo "const libllvm_version = \"$$($(LLVM_CONFIG_HOST) --version)\"" >> $@ + @echo "const libllvm_version_string = \"$$($(LLVM_CONFIG_HOST) --version)\"" >> $@ @echo "const VERSION_STRING = \"$(JULIA_VERSION)\"" >> $@ @echo "const TAGGED_RELEASE_BANNER = \"$(TAGGED_RELEASE_BANNER)\"" >> $@ @echo "const SYSCONFDIR = \"$(sysconfdir_rel)\"" >> $@ diff --git a/base/atomics.jl b/base/atomics.jl index 7374bad3f4f2e1..a2dfbef623b313 100644 --- a/base/atomics.jl +++ b/base/atomics.jl @@ -17,7 +17,7 @@ export # Disable 128-bit types on 32-bit Intel sytems due to LLVM problems; # see (fixed on LLVM 3.9) # 128-bit atomics do not exist on AArch32. -if (VersionNumber(Base.libllvm_version) < v"3.9-" && ARCH === :i686) || +if (Base.libllvm_version < v"3.9-" && ARCH === :i686) || startswith(string(ARCH), "arm") const inttypes = (Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64) @@ -330,8 +330,8 @@ alignment(::Type{T}) where {T} = ccall(:jl_alignment, Cint, (Csize_t,), sizeof(T for typ in atomictypes lt = llvmtypes[typ] ilt = llvmtypes[inttype(typ)] - rt = VersionNumber(Base.libllvm_version) >= v"3.6" ? "$lt, $lt*" : "$lt*" - irt = VersionNumber(Base.libllvm_version) >= v"3.6" ? "$ilt, $ilt*" : "$ilt*" + rt = Base.libllvm_version >= v"3.6" ? "$lt, $lt*" : "$lt*" + irt = Base.libllvm_version >= v"3.6" ? "$ilt, $ilt*" : "$ilt*" if VersionNumber(Base.libllvm_version) >= v"3.8" @eval getindex(x::Atomic{$typ}) = llvmcall($""" diff --git a/base/version.jl b/base/version.jl index 1bae427a645766..213f603ec53f89 100644 --- a/base/version.jl +++ b/base/version.jl @@ -223,6 +223,8 @@ catch e VersionNumber(0) end +libllvm_version = convert(VersionNumber, libllvm_version_string) + function banner(io::IO = STDOUT) if GIT_VERSION_INFO.tagged_commit commit_string = TAGGED_RELEASE_BANNER diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 802f9ad31d0705..47cb9b24883619 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -322,7 +322,7 @@ let exename = `$(Base.julia_cmd()) --precompiled=yes --startup-file=no` # issue #12671, starting from a non-directory # rm(dir) fails on windows with Permission denied # and was an upstream bug in llvm <= v3.3 - if !is_windows() && VersionNumber(Base.libllvm_version) > v"3.3" + if !is_windows() && Base.libllvm_version > v"3.3" testdir = mktempdir() cd(testdir) do rm(testdir) diff --git a/test/llvmcall.jl b/test/llvmcall.jl index ac75a3575ac294..fc59bd025939f7 100644 --- a/test/llvmcall.jl +++ b/test/llvmcall.jl @@ -177,7 +177,7 @@ module ObjLoadTest end # Test for proper parenting -if VersionNumber(Base.libllvm_version) >= v"3.6" # llvm 3.6 changed the syntax for a gep, so just ignore this test on older versions +if Base.libllvm_version >= v"3.6" # llvm 3.6 changed the syntax for a gep, so just ignore this test on older versions local foo function foo() # this IR snippet triggers an optimization relying From 8bacb65bbab9cbb7da2a266dc384cdd62df372aa Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 19 May 2017 12:06:33 -0400 Subject: [PATCH 03/53] Method overwriting by an ambiguity should also invalidate the method cache fix #21963 --- src/gf.c | 4 ++-- test/ambiguous.jl | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/gf.c b/src/gf.c index 599eabd62b9e15..683b11bc1d24c3 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1162,10 +1162,10 @@ static int check_ambiguous_visitor(jl_typemap_entry_t *oldentry, struct typemap_ jl_static_show_func_sig(s, isect); jl_printf(s, "\nbefore the new definition.\n"); } - return 1; // there may be multiple ambiguities, keep going } - else if (closure->after) { + if (!msp || closure->after) { // record that this method definition is being partially replaced + // (either with a real definition, or an ambiguity error) if (closure->shadowed == NULL) { closure->shadowed = oldentry->func.value; } diff --git a/test/ambiguous.jl b/test/ambiguous.jl index 32139c496a44f1..14c03f877b8da7 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -85,6 +85,16 @@ cfunction(ambig, Int, (UInt8, Int)) # test for a crash (doesn't throw an error) ambig(x, y::Integer) = 3 @test_throws MethodError ambig(2, 0x03) +# Method overwriting by an ambiguity should also invalidate the method cache (#21963) +ambig(x::Union{Char, Int8}) = 'r' +@test ambig('c') == 'r' +@test ambig(Int8(1)) == 'r' +@test_throws MethodError ambig(Int16(1)) +ambig(x::Union{Char, Int16}) = 's' +@test_throws MethodError ambig('c') +@test ambig(Int8(1)) == 'r' +@test ambig(Int16(1)) == 's' + # Automatic detection of ambiguities module Ambig1 ambig(x, y) = 1 From 7f790246229b44f194b7b9937516d3676c2f9a41 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 23 May 2017 17:48:04 -0400 Subject: [PATCH 04/53] Add extra early memcpyopt pass Under certain circumstances, we emit loads/stores of large LLVM structs. A lot of these can be trivially folded to memcpy and memcpyopt is capable of doing so, but we weren't running it until after SROA. SROA unfortunately, likes to take these apart, causing exponential compile-time blow up and reduced runtime peroformance. In one particular case (2000 element tuple), this change results in a 100x improvement in compile time. --- src/jitlayers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 804361fb85ee3e..54a950a4ec99d0 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -161,6 +161,7 @@ void addOptimizationPasses(PassManager *PM) // list of passes from vmkit PM->add(createCFGSimplificationPass()); // Clean up disgusting code PM->add(createPromoteMemoryToRegisterPass()); // Kill useless allocas + PM->add(createMemCpyOptPass()); // hopefully these functions (from llvmcall) don't try to interact with the Julia runtime // or have anything that might corrupt the createLowerPTLSPass pass From 366053546967e1b0cd2c5a10782833f032dce841 Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Thu, 20 Apr 2017 23:11:50 -0400 Subject: [PATCH 05/53] Try to loosen cfunction optimization type check. --- src/ccall.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index 28218547bf1131..c1355d54297774 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1787,18 +1787,26 @@ static jl_cgval_t emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx) jl_value_t *frt = expr_type(args[6], ctx); if (f && (jl_is_type_type((jl_value_t*)frt) && !jl_has_free_typevars(jl_tparam0(frt)))) { fargt = static_eval(args[8], ctx, true, true); - if (fargt) { - if (jl_is_tuple(fargt)) { - // TODO: maybe deprecation warning, better checking - fargt = (jl_value_t*)jl_apply_tuple_type_v((jl_value_t**)jl_data_ptr(fargt), jl_nfields(fargt)); - } - } - else { + if (!fargt) { fargt = expr_type(args[8], ctx); - if (jl_is_type_type((jl_value_t*)fargt)) + if (jl_is_type_type((jl_value_t*)fargt)) { fargt = jl_tparam0(fargt); + if (jl_has_free_typevars(fargt) || !jl_is_tuple_type(fargt)) { + fargt = nullptr; + } + } + else { + fargt = nullptr; + } + } + else if (jl_is_tuple(fargt)) { + // TODO: maybe deprecation warning, better checking + fargt = (jl_value_t*)jl_apply_tuple_type_v((jl_value_t**)jl_data_ptr(fargt), jl_nfields(fargt)); } - if (jl_is_tuple_type(fargt) && jl_is_leaf_type(fargt)) { + else if (!jl_is_tuple_type(fargt)) { + fargt = nullptr; + } + if (fargt) { frt = jl_tparam0(frt); Value *llvmf = NULL; JL_TRY { From 1ee84c8ec4fe0adcac571fe2ab3a8a1c7422c3f0 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 5 May 2017 15:59:50 -0400 Subject: [PATCH 06/53] get loaddocs to give line numbers when it fails --- base/docs/Docs.jl | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 005d4a6a9f881d..53552372a265d9 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -749,11 +749,21 @@ include("utils.jl") # Swap out the bootstrap macro with the real one. Core.atdoc!(docm) +macro local_hygiene(expr) + # removes `esc` Exprs relative to the module argument to expand + # and resolves everything else relative to this (Doc) module + # this allows us to get good errors and backtraces + # from calling docm (by not using macros), + # while also getting macro-expansion correct (by using the macro-expander) + return expr +end function loaddocs(docs) + unescape = GlobalRef(Docs, Symbol("@local_hygiene")) for (mod, ex, str, file, line) in docs data = Dict(:path => string(file), :linenumber => line) doc = docstr(str, data) - eval(mod, :(@doc($doc, $ex, false))) + docstring = eval(mod, Expr(:body, Expr(:return, Expr(:call, QuoteNode(docm), QuoteNode(doc), QuoteNode(ex), false)))) # expand the real @doc macro now (using a hack because macroexpand takes current-module as an implicit argument) + eval(mod, Expr(:macrocall, unescape, nothing, docstring)) end empty!(docs) end From fcdf4376415fde3b76faeb1c6f6841735497c8ea Mon Sep 17 00:00:00 2001 From: Isaiah Date: Fri, 5 May 2017 15:57:25 -0400 Subject: [PATCH 07/53] pass file and line information as an argument named `__source__` to all macros also emit an explicit push_loc in @generated functions rather than depending on the existence of a LineNumberNode and other lowering heuristics to produce it --- NEWS.md | 10 ++ base/boot.jl | 4 +- base/docs/Docs.jl | 12 +- base/docs/basedocs.jl | 7 - base/docs/utils.jl | 2 +- base/exports.jl | 1 + base/expr.jl | 11 +- base/inference.jl | 37 +++-- base/interactiveutil.jl | 6 +- base/loading.jl | 53 ++++--- base/math.jl | 2 +- base/show.jl | 36 +++-- doc/REQUIRE | 2 +- doc/src/devdocs/ast.md | 36 ++--- doc/src/manual/metaprogramming.md | 47 ++++++ doc/src/stdlib/file.md | 2 +- .../clustermanager/simple/UnixDomainCM.jl | 3 +- examples/clustermanager/simple/test_simple.jl | 2 +- src/ast.c | 50 +++++-- src/codegen.cpp | 6 +- src/jltypes.c | 4 +- src/julia-parser.scm | 66 +++++---- src/julia-syntax.scm | 1 + src/julia.h | 17 +-- src/method.c | 50 +++++-- src/rtutils.c | 4 +- test/ambiguous.jl | 2 +- test/docs.jl | 21 +-- test/loading.jl | 12 +- test/parse.jl | 40 +++--- test/reflection.jl | 8 +- test/replutil.jl | 43 +++--- test/show.jl | 136 +++++++++++++----- test/stacktraces.jl | 4 +- test/worlds.jl | 2 +- 35 files changed, 491 insertions(+), 248 deletions(-) diff --git a/NEWS.md b/NEWS.md index 03667d85d753d3..5a00f40c02b005 100644 --- a/NEWS.md +++ b/NEWS.md @@ -24,6 +24,16 @@ This section lists changes that do not have deprecation warnings. * `@__DIR__` returns the current working directory rather than `nothing` when not run from a file ([#21759]). + * `@__FILE__` and `@__DIR__` return information relative to the file that it was parsed from, + rather than from the task-local `SOURCE_PATH` global when it was expanded. + + * All macros receive an extra argument `__source__::LineNumberNode` which describes the + parser location in the source file for the `@` of the macro call. + It can be accessed as a normal argument variable in the body of the macro. + This is implemented by inserting an extra leading argument into the + `Expr(:macrocall, :@name, LineNumberNode(...), args...)` + surface syntax. ([#21746]) + * Passing the same keyword argument multiple times is now a syntax error ([#16937]). * `getsockname` on a `TCPSocket` now returns the locally bound address and port diff --git a/base/boot.jl b/base/boot.jl index d0a686e761bf50..c818bdfd0deadb 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -87,6 +87,7 @@ #struct LineNumberNode # line::Int +# file::Any # nominally Union{Symbol,Void} #end #struct LabelNode @@ -281,7 +282,8 @@ _new(:GotoNode, :Int) _new(:NewvarNode, :SlotNumber) _new(:QuoteNode, :ANY) _new(:SSAValue, :Int) -eval(:((::Type{LineNumberNode})(l::Int) = $(Expr(:new, :LineNumberNode, :l)))) +eval(:((::Type{LineNumberNode})(l::Int) = $(Expr(:new, :LineNumberNode, :l, nothing)))) +eval(:((::Type{LineNumberNode})(l::Int, f::ANY) = $(Expr(:new, :LineNumberNode, :l, :f)))) eval(:((::Type{GlobalRef})(m::Module, s::Symbol) = $(Expr(:new, :GlobalRef, :m, :s)))) eval(:((::Type{SlotNumber})(n::Int) = $(Expr(:new, :SlotNumber, :n)))) eval(:((::Type{TypedSlot})(n::Int, t::ANY) = $(Expr(:new, :TypedSlot, :n, :t)))) diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 53552372a265d9..40bbb74f427297 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -83,9 +83,11 @@ function initmeta(m::Module = current_module()) end function signature!(tv, expr::Expr) - if isexpr(expr, (:call, :macrocall)) + is_macrocall = isexpr(expr, :macrocall) + if is_macrocall || isexpr(expr, :call) sig = :(Union{Tuple{}}) - for arg in expr.args[2:end] + first_arg = is_macrocall ? 3 : 2 # skip function arguments + for arg in expr.args[first_arg:end] isexpr(arg, :parameters) && continue if isexpr(arg, :kw) # optional arg push!(sig.args, :(Tuple{$(sig.args[end].args[2:end]...)})) @@ -599,7 +601,7 @@ function __doc__!(meta, def, define) # the Base image). We just need to convert each `@__doc__` marker to an `@doc`. finddoc(def) do each each.head = :macrocall - each.args = [Symbol("@doc"), meta, each.args[end], define] + each.args = [Symbol("@doc"), nothing, meta, each.args[end], define] # TODO: forward line number info end else # `def` has already been defined during Base image gen so we just need to find and @@ -642,7 +644,7 @@ const BINDING_HEADS = [:typealias, :const, :global, :(=)] # deprecation: remove isquotedmacrocall(x) = isexpr(x, :copyast, 1) && isa(x.args[1], QuoteNode) && - isexpr(x.args[1].value, :macrocall, 1) + isexpr(x.args[1].value, :macrocall, 2) # Simple expressions / atoms the may be documented. isbasicdoc(x) = isexpr(x, :.) || isa(x, Union{QuoteNode, Symbol}) is_signature(x) = isexpr(x, :call) || (isexpr(x, :(::), 2) && isexpr(x.args[1], :call)) || isexpr(x, :where) @@ -730,7 +732,7 @@ function docm(ex) parsedoc(keywords[ex]) elseif isa(ex, Union{Expr, Symbol}) binding = esc(bindingexpr(namify(ex))) - if isexpr(ex, [:call, :macrocall]) + if isexpr(ex, :call) || isexpr(ex, :macrocall) sig = esc(signature(ex)) :($(doc)($binding, $sig)) else diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 9134bbc3925f7b..4221f061bfcc33 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -644,13 +644,6 @@ to be set after construction. See `struct` and the manual for more information. """ kw"mutable struct" -""" - @__LINE__ -> Int - -`@__LINE__` expands to the line number of the call-site. -""" -kw"@__LINE__" - """ ans diff --git a/base/docs/utils.jl b/base/docs/utils.jl index 0daf26f78c183d..4a3a8b1e7a4794 100644 --- a/base/docs/utils.jl +++ b/base/docs/utils.jl @@ -190,7 +190,7 @@ function repl(io::IO, s::Symbol) $(_repl(s)) end end -isregex(x) = isexpr(x, :macrocall, 2) && x.args[1] === Symbol("@r_str") && !isempty(x.args[2]) +isregex(x) = isexpr(x, :macrocall, 3) && x.args[1] === Symbol("@r_str") && !isempty(x.args[3]) repl(io::IO, ex::Expr) = isregex(ex) ? :(apropos($io, $ex)) : _repl(ex) repl(io::IO, str::AbstractString) = :(apropos($io, $str)) repl(io::IO, other) = :(@doc $(esc(other))) diff --git a/base/exports.jl b/base/exports.jl index 376a9704b6d559..3a4c2fafdbd110 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1248,6 +1248,7 @@ export # parser internal @__FILE__, @__DIR__, + @__LINE__, @int128_str, @uint128_str, @big_str, diff --git a/base/expr.jl b/base/expr.jl index 21d66ec4a445c8..d23a1909701f64 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -276,9 +276,16 @@ end remove_linenums!(ex) = ex function remove_linenums!(ex::Expr) - filter!(x->!((isa(x,Expr) && x.head === :line) || isa(x,LineNumberNode)), ex.args) + if ex.head === :body || ex.head === :block || ex.head === :quote + # remove line number expressions from metadata (not argument literal or inert) position + filter!(ex.args) do x + isa(x, Expr) && x.head === :line && return false + isa(x, LineNumberNode) && return false + return true + end + end for subex in ex.args remove_linenums!(subex) end - ex + return ex end diff --git a/base/inference.jl b/base/inference.jl index 9f73259dafcf0d..45c030af11efb3 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -4140,39 +4140,38 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference end do_coverage = coverage_enabled() - if do_coverage - line = method.line - if !isempty(stmts) && isa(stmts[1], LineNumberNode) - line = (shift!(stmts)::LineNumberNode).line + line::Int = method.line + file = method.file + if !isempty(stmts) + if !do_coverage && all(inlining_ignore, stmts) + empty!(stmts) + elseif isa(stmts[1], LineNumberNode) + linenode = shift!(stmts)::LineNumberNode + line = linenode.line + isa(linenode.file, Symbol) && (file = linenode.file) end + end + if do_coverage # Check if we are switching module, which is necessary to catch user # code inlined into `Base` with `--code-coverage=user`. # Assume we are inlining directly into `enclosing` instead of another # function inlined in it mod = method.module if mod === sv.mod - unshift!(stmts, Expr(:meta, :push_loc, method.file, + unshift!(stmts, Expr(:meta, :push_loc, file, method.name, line)) else - unshift!(stmts, Expr(:meta, :push_loc, method.file, + unshift!(stmts, Expr(:meta, :push_loc, file, method.name, line, mod)) end push!(stmts, Expr(:meta, :pop_loc)) elseif !isempty(stmts) - if all(inlining_ignore, stmts) - empty!(stmts) + unshift!(stmts, Expr(:meta, :push_loc, file, + method.name, line)) + if isa(stmts[end], LineNumberNode) + stmts[end] = Expr(:meta, :pop_loc) else - line::Int = method.line - if isa(stmts[1], LineNumberNode) - line = (shift!(stmts)::LineNumberNode).line - end - unshift!(stmts, Expr(:meta, :push_loc, method.file, - method.name, line)) - if isa(stmts[end], LineNumberNode) - stmts[end] = Expr(:meta, :pop_loc) - else - push!(stmts, Expr(:meta, :pop_loc)) - end + push!(stmts, Expr(:meta, :pop_loc)) end end if !isempty(stmts) && !propagate_inbounds diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 5b959f063ea2af..34f77247364938 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -349,7 +349,7 @@ function code_warntype(io::IO, f, t::ANY) end code_warntype(f, t::ANY) = code_warntype(STDOUT, f, t) -typesof(args...) = Tuple{map(a->(isa(a,Type) ? Type{a} : typeof(a)), args)...} +typesof(args...) = Tuple{Any[ Core.Typeof(a) for a in args ]...} gen_call_with_extracted_types(fcn, ex0::Symbol) = Expr(:call, fcn, Meta.quot(ex0)) function gen_call_with_extracted_types(fcn, ex0) @@ -371,9 +371,9 @@ function gen_call_with_extracted_types(fcn, ex0) exret = Expr(:none) is_macro = false ex = expand(ex0) - if isa(ex0, Expr) && ex0.head == :macrocall # Make @edit @time 1+2 edit the macro + if isa(ex0, Expr) && ex0.head == :macrocall # Make @edit @time 1+2 edit the macro by using the types of the *expressions* is_macro = true - exret = Expr(:call, fcn, esc(ex0.args[1]), typesof(ex0.args[2:end]...)) + exret = Expr(:call, fcn, esc(ex0.args[1]), Tuple{#=__source__=#LineNumberNode, Any[ Core.Typeof(a) for a in ex0.args[3:end] ]...}) elseif !isa(ex, Expr) exret = Expr(:call, :error, "expression is not a function call or symbol") elseif ex.head == :call diff --git a/base/loading.jl b/base/loading.jl index 201b483ace14f5..18c4765790531e 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -538,24 +538,6 @@ function source_dir() p === nothing ? pwd() : dirname(p) end -""" - @__FILE__ -> AbstractString - -`@__FILE__` expands to a string with the absolute file path of the file containing the -macro. Returns `nothing` if run from a REPL or an empty string if evaluated by -`julia -e `. Alternatively see [`PROGRAM_FILE`](@ref). -""" -macro __FILE__() source_path() end - -""" - @__DIR__ -> AbstractString - -`@__DIR__` expands to a string with the directory part of the absolute path of the file -containing the macro. Returns the current working directory if run from a REPL or if -evaluated by `julia -e `. -""" -macro __DIR__() source_dir() end - include_from_node1(path::AbstractString) = include_from_node1(String(path)) function include_from_node1(_path::String) path, prev = _include_dependency(_path) @@ -823,3 +805,38 @@ function stale_cachefile(modpath::String, cachefile::String) close(io) end end + +""" + @__LINE__ -> Int + +`@__LINE__` expands to the line number of the location of the macrocall. +Returns `0` if the line number could not be determined. +""" +macro __LINE__() + return __source__.line +end + +""" + @__FILE__ -> AbstractString + +`@__FILE__` expands to a string with the path to the file containing the +macrocall, or an empty string if evaluated by `julia -e `. +Returns `nothing` if the macro was missing parser source information. +Alternatively see [`PROGRAM_FILE`](@ref). +""" +macro __FILE__() + __source__.file === nothing && return nothing + return String(__source__.file) +end + +""" + @__DIR__ -> AbstractString + +`@__DIR__` expands to a string with the absolute path to the directory of the file +containing the macrocall. +Returns the current working directory if run from a REPL or if evaluated by `julia -e `. +""" +macro __DIR__() + __source__.file === nothing && return nothing + return abspath(dirname(String(__source__.file))) +end diff --git a/base/math.jl b/base/math.jl index 4d8eb64fc8d321..a383ca43aeb8c4 100644 --- a/base/math.jl +++ b/base/math.jl @@ -124,7 +124,7 @@ macro evalpoly(z, p...) :(s = muladd(x, x, y*y)), as..., :(muladd($ai, tt, $b))) - R = Expr(:macrocall, Symbol("@horner"), :tt, map(esc, p)...) + R = Expr(:macrocall, Symbol("@horner"), (), :tt, map(esc, p)...) :(let tt = $(esc(z)) isa(tt, Complex) ? $C : $R end) diff --git a/base/show.jl b/base/show.jl index 3e39b419f284bf..f21483c699771a 100644 --- a/base/show.jl +++ b/base/show.jl @@ -505,10 +505,6 @@ const prec_decl = operator_precedence(:(::)) is_expr(ex, head::Symbol) = (isa(ex, Expr) && (ex.head == head)) is_expr(ex, head::Symbol, n::Int) = is_expr(ex, head) && length(ex.args) == n -is_linenumber(ex::LineNumberNode) = true -is_linenumber(ex::Expr) = (ex.head == :line) -is_linenumber(ex) = false - is_quoted(ex) = false is_quoted(ex::QuoteNode) = true is_quoted(ex::Expr) = is_expr(ex, :quote, 1) || is_expr(ex, :inert, 1) @@ -538,18 +534,22 @@ end emphasize(io, str::AbstractString) = have_color ? print_with_color(Base.error_color(), io, str; bold = true) : print(io, uppercase(str)) -show_linenumber(io::IO, line) = print(io," # line ",line,':') -show_linenumber(io::IO, line, file) = print(io," # ", file,", line ",line,':') +show_linenumber(io::IO, line) = print(io, "#= line ", line, " =#") +show_linenumber(io::IO, line, file) = print(io, "#= ", file, ":", line, " =#") +show_linenumber(io::IO, line, file::Void) = show_linenumber(io, line) # show a block, e g if/for/etc function show_block(io::IO, head, args::Vector, body, indent::Int) - print(io, head, ' ') - show_list(io, args, ", ", indent) + print(io, head) + if !isempty(args) + print(io, ' ') + show_list(io, args, ", ", indent) + end ind = head === :module || head === :baremodule ? indent : indent + indent_width exs = (is_expr(body, :block) || is_expr(body, :body)) ? body.args : Any[body] for ex in exs - if !is_linenumber(ex); print(io, '\n', " "^ind); end + print(io, '\n', " "^ind) show_unquoted(io, ex, ind, -1) end print(io, '\n', " "^indent) @@ -566,7 +566,7 @@ end # show an indented list function show_list(io::IO, items, sep, indent::Int, prec::Int=0, enclose_operators::Bool=false) n = length(items) - if n == 0; return end + n == 0 && return indent += indent_width first = true for item in items @@ -613,7 +613,7 @@ end ## AST printing ## show_unquoted(io::IO, sym::Symbol, ::Int, ::Int) = print(io, sym) -show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.line) +show_unquoted(io::IO, ex::LineNumberNode, ::Int, ::Int) = show_linenumber(io, ex.line, ex.file) show_unquoted(io::IO, ex::LabelNode, ::Int, ::Int) = print(io, ex.label, ": ") show_unquoted(io::IO, ex::GotoNode, ::Int, ::Int) = print(io, "goto ", ex.label) show_unquoted(io::IO, ex::GlobalRef, ::Int, ::Int) = print(io, ex.mod, '.', ex.name) @@ -913,12 +913,20 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int) print(io, head, ' ') show_list(io, args, ", ", indent) - elseif head === :macrocall && nargs >= 1 + elseif head === :macrocall && nargs >= 2 + # first show the line number argument as a comment + if isa(args[2], LineNumberNode) || is_expr(args[2], :line) + print(io, args[2], ' ') + end # Use the functional syntax unless specifically designated with prec=-1 + # and hide the line number argument from the argument list if prec >= 0 - show_call(io, :call, ex.args[1], ex.args[2:end], indent) + show_call(io, :call, args[1], args[3:end], indent) else - show_list(io, args, ' ', indent) + show_args = Vector{Any}(length(args) - 1) + show_args[1] = args[1] + show_args[2:end] = args[3:end] + show_list(io, show_args, ' ', indent) end elseif head === :line && 1 <= nargs <= 2 diff --git a/doc/REQUIRE b/doc/REQUIRE index e8869bde5e55a1..aed1a491d52250 100644 --- a/doc/REQUIRE +++ b/doc/REQUIRE @@ -1,3 +1,3 @@ Compat 0.25.0 0.25.0+ DocStringExtensions 0.3.3 0.3.3+ -Documenter 0.10.2 0.10.2+ +Documenter 0.10.3 0.10.3+ diff --git a/doc/src/devdocs/ast.md b/doc/src/devdocs/ast.md index 62006cf4d62d30..157dd60a624c0b 100644 --- a/doc/src/devdocs/ast.md +++ b/doc/src/devdocs/ast.md @@ -407,21 +407,21 @@ call. Finally, chains of comparisons have their own special expression structure ### Macros -| Input | AST | -|:------------- |:------------------------------------- | -| `@m x y` | `(macrocall @m x y)` | -| `Base.@m x y` | `(macrocall (. Base (quote @m)) x y)` | -| `@Base.m x y` | `(macrocall (. Base (quote @m)) x y)` | +| Input | AST | +|:------------- |:-------------------------------------------- | +| `@m x y` | `(macrocall @m (line) x y)` | +| `Base.@m x y` | `(macrocall (. Base (quote @m)) (line) x y)` | +| `@Base.m x y` | `(macrocall (. Base (quote @m)) (line) x y)` | ### Strings -| Input | AST | -|:--------------- |:---------------------------- | -| `"a"` | `"a"` | -| `x"y"` | `(macrocall @x_str "y")` | -| `x"y"z` | `(macrocall @x_str "y" "z")` | -| `"x = $x"` | `(string "x = " x)` | -| ``` `a b c` ``` | `(macrocall @cmd "a b c")` | +| Input | AST | +|:--------------- |:----------------------------------- | +| `"a"` | `"a"` | +| `x"y"` | `(macrocall @x_str (line) "y")` | +| `x"y"z` | `(macrocall @x_str (line) "y" "z")` | +| `"x = $x"` | `(string "x = " x)` | +| ``` `a b c` ``` | `(macrocall @cmd (line) "a b c")` | Doc string syntax: @@ -430,7 +430,7 @@ Doc string syntax: f(x) = x ``` -parses as `(macrocall (|.| Core '@doc) "some docs" (= (call f x) (block x)))`. +parses as `(macrocall (|.| Core '@doc) (line) "some docs" (= (call f x) (block x)))`. ### Imports and such @@ -449,11 +449,11 @@ parses as `(macrocall (|.| Core '@doc) "some docs" (= (call f x) (block x)))`. Julia supports more number types than many scheme implementations, so not all numbers are represented directly as scheme numbers in the AST. -| Input | AST | -|:----------------------- |:------------------------------------------------ | -| `11111111111111111111` | `(macrocall @int128_str "11111111111111111111")` | -| `0xfffffffffffffffff` | `(macrocall @uint128_str "0xfffffffffffffffff")` | -| `1111...many digits...` | `(macrocall @big_str "1111....")` | +| Input | AST | +|:----------------------- |:------------------------------------------------------- | +| `11111111111111111111` | `(macrocall @int128_str (null) "11111111111111111111")` | +| `0xfffffffffffffffff` | `(macrocall @uint128_str (null) "0xfffffffffffffffff")` | +| `1111...many digits...` | `(macrocall @big_str (null) "1111....")` | ### Block forms diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index 6e937ba18b8c2d..50d8c6de6f9248 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -509,6 +509,27 @@ julia> @showarg(println("Yo!")) :(println("Yo!")) ``` +In addition to the given argument list, every macro is passed an extra argument named `__source__` +providing information (in the form of a `LineNumberNode` object) about the parser location +of the `@` sign from the macro invocation. + +This allows macros to include better error diagnostic information, +and is commonly used by logging, string-parser macros, and docs, for example, +as well as to implement the `@__LINE__`, `@__FILE__`, and `@__DIR__` macros. + +The location information can be accessed by referencing `__source__.line` and `__source__.file`: + +```jldoctest +julia> macro __LOCATION__(); return QuoteNode(__source__); end + +julia> dump( + @__LOCATION__( + )) +LineNumberNode + line: Int64 2 + file: Symbol REPL[2] +``` + ### Building an advanced macro Here is a simplified definition of Julia's `@assert` macro: @@ -708,6 +729,32 @@ julia> foo() This kind of manipulation of variables should be used judiciously, but is occasionally quite handy. +Getting the hygiene rules correct can be a formidable challenge. +Before using a macro, you might want to consider whether a function closure +would be sufficient. Another useful strategy is to defer as much work as possible to runtime. +For example, many macros simply wrap their arguments in a QuoteNode or other similar Expr. +Some examples of this include `@task body` which simply returns `schedule(Task(() -> $body))`, +and `@eval expr`, which simply returns `eval(QuoteNode(expr))`. + +To demonstrate, we might rewrite the `@time` example above as: + +```julia +macro time(expr) + return :(timeit(() -> $(esc(expr)))) +end +function timeit(f) + t0 = time() + val = f() + t1 = time() + println("elapsed time: ", t1-t0, " seconds") + return val +end +``` + +However, we don't do this for a good reason: wrapping the `expr` in a new scope block (the anonymous function) +also slightly changes the meaning of the expression (the scope of any variables in it), +while we want `@time` to be usable with minimum impact on the wrapped code. + ## Code Generation When a significant amount of repetitive boilerplate code is required, it is common to generate diff --git a/doc/src/stdlib/file.md b/doc/src/stdlib/file.md index e0f5874d0d5277..26e9f9d5779286 100644 --- a/doc/src/stdlib/file.md +++ b/doc/src/stdlib/file.md @@ -49,7 +49,7 @@ Base.Filesystem.dirname Base.Filesystem.basename Base.@__FILE__ Base.@__DIR__ -@__LINE__ +Base.@__LINE__ Base.Filesystem.isabspath Base.Filesystem.isdirpath Base.Filesystem.joinpath diff --git a/examples/clustermanager/simple/UnixDomainCM.jl b/examples/clustermanager/simple/UnixDomainCM.jl index e3a1f7f9d350aa..afffa610a21b95 100644 --- a/examples/clustermanager/simple/UnixDomainCM.jl +++ b/examples/clustermanager/simple/UnixDomainCM.jl @@ -12,7 +12,8 @@ function launch(manager::UnixDomainCM, params::Dict, launched::Array, c::Conditi for i in 1:manager.np sockname = tempname() try - cmd = `$(params[:exename]) --startup-file=no $(@__FILE__) udwrkr $sockname $cookie` + __file__ = @__FILE__ + cmd = `$(params[:exename]) --startup-file=no $__file__ udwrkr $sockname $cookie` pobj = open(cmd) wconfig = WorkerConfig() diff --git a/examples/clustermanager/simple/test_simple.jl b/examples/clustermanager/simple/test_simple.jl index 57e8a8a0f28fe8..2460eadd77b537 100644 --- a/examples/clustermanager/simple/test_simple.jl +++ b/examples/clustermanager/simple/test_simple.jl @@ -1,6 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -cmanpath = joinpath(dirname(@__FILE__), "UnixDomainCM.jl") +cmanpath = joinpath(@__DIR__, "UnixDomainCM.jl") include(cmanpath) npids = addprocs(UnixDomainCM(2)) diff --git a/src/ast.c b/src/ast.c index 6b9ac084649ff0..9b3b8c124e6a63 100644 --- a/src/ast.c +++ b/src/ast.c @@ -176,19 +176,40 @@ value_t fl_invoke_julia_macro(fl_context_t *fl_ctx, value_t *args, uint32_t narg { JL_TIMING(MACRO_INVOCATION); jl_ptls_t ptls = jl_get_ptls_states(); - if (nargs < 1) - argcount(fl_ctx, "invoke-julia-macro", nargs, 1); + if (nargs < 2) // macro name and location + argcount(fl_ctx, "invoke-julia-macro", nargs, 2); jl_method_instance_t *mfunc = NULL; jl_value_t **margs; // Reserve one more slot for the result JL_GC_PUSHARGS(margs, nargs + 1); int i; - for(i=1; i < nargs; i++) margs[i] = scm_to_julia(fl_ctx, args[i], 1); + margs[0] = scm_to_julia(fl_ctx, args[0], 1); + // __source__ argument + jl_value_t *lno = scm_to_julia(fl_ctx, args[1], 1); + margs[1] = lno; + if (jl_is_expr(lno) && ((jl_expr_t*)lno)->head == line_sym) { + jl_value_t *file = jl_nothing; + jl_value_t *line = NULL; + switch (jl_expr_nargs(lno)) { // fall-through is intentional + case 2: + file = jl_exprarg(lno, 1); // file + case 1: + line = jl_exprarg(lno, 0); // line + default: ; + } + if (line == NULL) + line = jl_box_long(0); + margs[1] = jl_new_struct(jl_linenumbernode_type, line, file); + } + else if (!jl_typeis(lno, jl_linenumbernode_type)) { + margs[1] = jl_new_struct(jl_linenumbernode_type, jl_box_long(0), jl_nothing); + } + for (i = 2; i < nargs; i++) + margs[i] = scm_to_julia(fl_ctx, args[i], 1); jl_value_t *result = NULL; size_t world = jl_get_ptls_states()->world_age; JL_TRY { - margs[0] = scm_to_julia(fl_ctx, args[0], 1); margs[0] = jl_toplevel_eval(margs[0]); mfunc = jl_method_lookup(jl_gf_mtable(margs[0]), margs, nargs, 1, world); if (mfunc == NULL) { @@ -560,10 +581,13 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, int eo) else n++; if (!eo) { - if (sym == line_sym && n==1) { + if (sym == line_sym && (n == 1 || n == 2)) { jl_value_t *linenum = scm_to_julia_(fl_ctx, car_(e), 0); - JL_GC_PUSH1(&linenum); - jl_value_t *temp = jl_new_struct(jl_linenumbernode_type, linenum); + jl_value_t *file = jl_nothing; + JL_GC_PUSH2(&linenum, &file); + if (n == 2) + file = scm_to_julia_(fl_ctx, car_(cdr_(e)), 0); + jl_value_t *temp = jl_new_struct(jl_linenumbernode_type, linenum, file); JL_GC_POP(); return temp; } @@ -724,8 +748,16 @@ static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v) // shouldn't allocate in this case. if (jl_typeis(v, jl_labelnode_type)) return julia_to_list2(fl_ctx, (jl_value_t*)label_sym, jl_fieldref(v,0)); - if (jl_typeis(v, jl_linenumbernode_type)) - return julia_to_list2(fl_ctx, (jl_value_t*)line_sym, jl_fieldref(v,0)); + if (jl_typeis(v, jl_linenumbernode_type)) { + jl_value_t *file = jl_fieldref(v,1); // non-allocating + jl_value_t *line = jl_fieldref(v,0); // allocating + value_t args = julia_to_list2(fl_ctx, line, file); + fl_gc_handle(fl_ctx, &args); + value_t hd = julia_to_scm_(fl_ctx, (jl_value_t*)line_sym); + value_t scmv = fl_cons(fl_ctx, hd, args); + fl_free_gc_handles(fl_ctx, 1); + return scmv; + } if (jl_typeis(v, jl_gotonode_type)) return julia_to_list2(fl_ctx, (jl_value_t*)goto_sym, jl_fieldref(v,0)); if (jl_typeis(v, jl_quotenode_type)) diff --git a/src/codegen.cpp b/src/codegen.cpp index 35061fe614f116..acd0c23ed5fa4f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4083,13 +4083,13 @@ static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx) return emit_getfield((jl_value_t*)jl_globalref_mod(expr), jl_globalref_name(expr), ctx); } if (jl_is_labelnode(expr)) { - jl_error("Labelnode in value position"); + jl_error("LabelNode in value position"); } if (jl_is_linenode(expr)) { - jl_error("Linenode in value position"); + jl_error("LineNumberNode in value position"); } if (jl_is_gotonode(expr)) { - jl_error("Gotonode in value position"); + jl_error("GotoNode in value position"); } if (!jl_is_expr(expr)) { int needroot = true; diff --git a/src/jltypes.c b/src/jltypes.c index bc130b86cf63f2..91a579b36ae50f 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -1850,8 +1850,8 @@ void jl_init_types(void) jl_linenumbernode_type = jl_new_datatype(jl_symbol("LineNumberNode"), jl_any_type, jl_emptysvec, - jl_perm_symsvec(1, "line"), - jl_svec(1, jl_long_type), 0, 0, 1); + jl_perm_symsvec(2, "line", "file"), + jl_svec(2, jl_long_type, jl_any_type), 0, 0, 2); jl_labelnode_type = jl_new_datatype(jl_symbol("LabelNode"), jl_any_type, jl_emptysvec, diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 6626739da4af7b..7e05db3f7ff89e 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -347,10 +347,10 @@ ((eq? pred char-bin?) (fix-uint-neg neg (sized-uint-literal n s 1))) (is-float32-literal (numchk n s) (float n)) (n (if (and (integer? n) (> n 9223372036854775807)) - `(macrocall @int128_str ,s) + `(macrocall @int128_str (null) ,s) n)) - ((within-int128? s) `(macrocall @int128_str ,s)) - (else `(macrocall @big_str ,s)))))) + ((within-int128? s) `(macrocall @int128_str (null) ,s)) + (else `(macrocall @big_str (null) ,s)))))) (define (fix-uint-neg neg n) (if neg @@ -366,7 +366,7 @@ ((<= l 16) (numchk n s) (uint16 n)) ((<= l 32) (numchk n s) (uint32 n)) ((<= l 64) (numchk n s) (uint64 n)) - ((<= l 128) `(macrocall @uint128_str ,s)) + ((<= l 128) `(macrocall @uint128_str (null) ,s)) (else (error "Hex or binary literal too large for UInt128"))))) (define (sized-uint-oct-literal n s) @@ -379,7 +379,7 @@ (else (uint64 n))) (begin (if (equal? s "0o") (numchk n s)) (if (oct-within-uint128? s) - `(macrocall @uint128_str ,s) + `(macrocall @uint128_str (null) ,s) (error "Octal literal too large for UInt128")))))) (define (strip-leading-0s s) @@ -856,11 +856,11 @@ (define (maybe-negate op num) (if (eq? op '-) (if (large-number? num) - (if (eqv? (caddr num) "-170141183460469231731687303715884105728") - `(macrocall @big_str "170141183460469231731687303715884105728") - `(,(car num) ,(cadr num) ,(string.tail (caddr num) 1))) + (if (eqv? (cadddr num) "-170141183460469231731687303715884105728") + `(macrocall @big_str (null) "170141183460469231731687303715884105728") + `(,(car num) ,(cadr num) ,(caddr num) ,(string.tail (cadddr num) 1))) (if (= num -9223372036854775808) - `(macrocall @int128_str "9223372036854775808") + `(macrocall @int128_str (null) "9223372036854775808") (- num))) num)) @@ -1100,7 +1100,7 @@ (else (let ((name (parse-atom s))) (if (and (pair? name) (eq? (car name) 'macrocall)) - `(macrocall (|.| ,ex (quote ,(cadr name))) + `(macrocall (|.| ,ex (quote ,(cadr name))) ; move macrocall outside by rewriting A.@B as @A.B ,@(cddr name)) `(|.| ,ex (quote ,name)))))))) ((|.'| |'|) @@ -1117,16 +1117,17 @@ (not (operator? ex)) (not (ts:space? s))) ;; custom string and command literals; x"s" => @x_str "s" - (let* ((macstr (begin (take-token s) + (let* ((startloc (line-number-node s)) + (macstr (begin (take-token s) (parse-raw-literal s t))) (nxt (peek-token s)) (macname (macroify-name ex (macsuffix t)))) (if (and (symbol? nxt) (not (operator? nxt)) (not (ts:space? s))) ;; string literal suffix, "s"x - (loop `(macrocall ,macname ,macstr + (loop `(macrocall ,macname ,startloc ,macstr ,(string (take-token s)))) - (loop `(macrocall ,macname ,macstr)))) + (loop `(macrocall ,macname ,startloc ,macstr)))) ex)) (else ex)))))) @@ -2122,26 +2123,27 @@ ((eqv? t #\@) (take-token s) (with-space-sensitive - (let ((head (if (eq? (peek-token s) '|.|) + (let ((startloc (line-number-node s)) + (head (if (eq? (peek-token s) '|.|) (begin (take-token s) '__dot__) (parse-unary-prefix s)))) - (if (eq? head '__LINE__) - (input-port-line (ts:port s)) - (begin - (peek-token s) - (if (ts:space? s) - `(macrocall ,(macroify-name head) - ,@(parse-space-separated-exprs s)) - (let ((call (parse-call-chain s head #t))) - (if (and (pair? call) (eq? (car call) 'call)) - `(macrocall ,(macroify-name (cadr call)) ,@(cddr call)) - `(macrocall ,(macroify-name call) - ,@(parse-space-separated-exprs s)))))))))) - + (peek-token s) + (if (ts:space? s) + `(macrocall ,(macroify-name head) + ,startloc + ,@(parse-space-separated-exprs s)) + (let ((call (parse-call-chain s head #t))) + (if (and (pair? call) (eq? (car call) 'call)) + `(macrocall ,(macroify-name (cadr call)) + ,startloc + ,@(cddr call)) + `(macrocall ,(macroify-name call) + ,startloc + ,@(parse-space-separated-exprs s)))))))) ;; command syntax ((eqv? t #\`) (take-token s) - `(macrocall @cmd ,(parse-raw-literal s #\`))) + `(macrocall @cmd ,(line-number-node s) ,(parse-raw-literal s #\`))) ((or (string? t) (number? t) (large-number? t)) (take-token s)) @@ -2167,16 +2169,20 @@ (and (pair? e) (eq? 'string (car e))) ; string interpolation (and (length= e 3) (eq? (car e) 'macrocall) (simple-string-literal? (caddr e)) + (eq? (cadr e) '@doc_str)) + (and (length= e 4) (eq? (car e) 'macrocall) + (simple-string-literal? (cadddr e)) (eq? (cadr e) '@doc_str)))) (define (parse-docstring s production) - (let* ((ex (production s))) + (let ((startloc (line-number-node s)) ; be sure to use the line number from the head of the docstring + (ex (production s))) (if (and (doc-string-literal? ex) (let loop ((t (peek-token s))) (cond ((closing-token? t) #f) ((newline? t) (take-token s) (loop (peek-token s))) (else #t)))) - `(macrocall (core @doc) ,ex ,(production s)) + `(macrocall (core @doc) ,startloc ,ex ,(production s)) ex))) ;; --- main entry point --- diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 86ed90c300ac66..78bdb2cd76d556 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1162,6 +1162,7 @@ (error "macros cannot accept keyword arguments")) (expand-forms `(function (call ,(symbol (string #\@ (cadr (cadr e)))) + (|::| __source__ (core LineNumberNode)) ,@(map (lambda (v) (if (symbol? v) `(|::| ,v (core ANY)) diff --git a/src/julia.h b/src/julia.h index 3af8aad0bf450e..9dbeff414a06e5 100644 --- a/src/julia.h +++ b/src/julia.h @@ -741,17 +741,18 @@ STATIC_INLINE void jl_array_uint8_set(void *a, size_t i, uint8_t x) #define jl_exprargset(e, n, v) jl_array_ptr_set(((jl_expr_t*)(e))->args, n, v) #define jl_expr_nargs(e) jl_array_len(((jl_expr_t*)(e))->args) -#define jl_fieldref(s,i) jl_get_nth_field(((jl_value_t*)s),i) +#define jl_fieldref(s,i) jl_get_nth_field(((jl_value_t*)(s)),i) #define jl_nfields(v) jl_datatype_nfields(jl_typeof(v)) // Not using jl_fieldref to avoid allocations -#define jl_linenode_line(x) (((intptr_t*)x)[0]) -#define jl_labelnode_label(x) (((intptr_t*)x)[0]) -#define jl_slot_number(x) (((intptr_t*)x)[0]) -#define jl_typedslot_get_type(x) (((jl_value_t**)x)[1]) -#define jl_gotonode_label(x) (((intptr_t*)x)[0]) -#define jl_globalref_mod(s) (*(jl_module_t**)s) -#define jl_globalref_name(s) (((jl_sym_t**)s)[1]) +#define jl_linenode_line(x) (((intptr_t*)(x))[0]) +#define jl_linenode_file(x) (((jl_value_t**)(x))[1]) +#define jl_labelnode_label(x) (((intptr_t*)(x))[0]) +#define jl_slot_number(x) (((intptr_t*)(x))[0]) +#define jl_typedslot_get_type(x) (((jl_value_t**)(x))[1]) +#define jl_gotonode_label(x) (((intptr_t*)(x))[0]) +#define jl_globalref_mod(s) (*(jl_module_t**)(s)) +#define jl_globalref_name(s) (((jl_sym_t**)(s))[1]) #define jl_nparams(t) jl_svec_len(((jl_datatype_t*)(t))->parameters) #define jl_tparam0(t) jl_svecref(((jl_datatype_t*)(t))->parameters, 0) diff --git a/src/method.c b/src/method.c index 5a4f9f8100f92d..30e7a702823e25 100644 --- a/src/method.c +++ b/src/method.c @@ -300,19 +300,27 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_array_ptr_set(ex->args, 0, argnames); jl_fill_argnames((jl_array_t*)linfo->def->source, argnames); + // build the rest of the body to pass to expand jl_expr_t *scopeblock = jl_exprn(jl_symbol("scope-block"), 1); jl_array_ptr_set(ex->args, 1, scopeblock); - jl_expr_t *body = jl_exprn(jl_symbol("block"), 2); - jl_array_ptr_set(((jl_expr_t*)jl_exprarg(ex,1))->args, 0, body); + jl_expr_t *body = jl_exprn(jl_symbol("block"), 3); + jl_array_ptr_set(((jl_expr_t*)jl_exprarg(ex, 1))->args, 0, body); + + // add location meta linenum = jl_box_long(linfo->def->line); - jl_value_t *linenode = jl_new_struct(jl_linenumbernode_type, linenum); + jl_value_t *linenode = jl_new_struct(jl_linenumbernode_type, linenum, linfo->def->file); jl_array_ptr_set(body->args, 0, linenode); + jl_expr_t *pushloc = jl_exprn(meta_sym, 3); + jl_array_ptr_set(body->args, 1, pushloc); + jl_array_ptr_set(pushloc->args, 0, jl_symbol("push_loc")); + jl_array_ptr_set(pushloc->args, 1, linfo->def->file); // file + jl_array_ptr_set(pushloc->args, 2, jl_symbol("@generated body")); // function // invoke code generator assert(jl_nparams(tt) == jl_array_len(argnames) || (linfo->def->isva && (jl_nparams(tt) >= jl_array_len(argnames) - 1))); - jl_array_ptr_set(body->args, 1, - jl_call_staged(sparam_vals, generator, jl_svec_data(tt->parameters), jl_nparams(tt))); + jl_value_t *generated_body = jl_call_staged(sparam_vals, generator, jl_svec_data(tt->parameters), jl_nparams(tt)); + jl_array_ptr_set(body->args, 2, generated_body); if (linfo->def->sparam_syms != jl_emptysvec) { // mark this function as having the same static parameters as the generator @@ -335,8 +343,17 @@ JL_DLLEXPORT jl_code_info_t *jl_code_for_staged(jl_method_instance_t *linfo) jl_array_t *stmts = (jl_array_t*)func->code; size_t i, l; for (i = 0, l = jl_array_len(stmts); i < l; i++) { - jl_array_ptr_set(stmts, i, jl_resolve_globals(jl_array_ptr_ref(stmts, i), linfo->def->module, env)); + jl_value_t *stmt = jl_array_ptr_ref(stmts, i); + stmt = jl_resolve_globals(stmt, linfo->def->module, env); + jl_array_ptr_set(stmts, i, stmt); } + + // add pop_loc meta + jl_array_ptr_1d_push(stmts, jl_nothing); + jl_expr_t *poploc = jl_exprn(meta_sym, 1); + jl_array_ptr_set(stmts, jl_array_len(stmts) - 1, poploc); + jl_array_ptr_set(poploc->args, 0, jl_symbol("pop_loc")); + ptls->in_pure_callback = last_in; jl_lineno = last_lineno; ptls->current_module = last_m; @@ -401,10 +418,25 @@ static void jl_method_set_source(jl_method_t *m, jl_code_info_t *src) int set_lineno = 0; for (i = 0; i < n; i++) { jl_value_t *st = jl_array_ptr_ref(stmts, i); - if (jl_is_expr(st) && ((jl_expr_t*)st)->head == line_sym) { + if (jl_is_linenode(st)) { if (!set_lineno) { - m->line = jl_unbox_long(jl_exprarg(st, 0)); - m->file = (jl_sym_t*)jl_exprarg(st, 1); + m->line = jl_linenode_line(st); + jl_value_t *file = jl_linenode_file(st); + if (jl_is_symbol(file)) + m->file = (jl_sym_t*)file; + st = jl_nothing; + set_lineno = 1; + } + } + else if (jl_is_expr(st) && ((jl_expr_t*)st)->head == line_sym) { + if (!set_lineno) { + switch (jl_expr_nargs(st)) { // fall-through is intentional + case 2: + m->file = (jl_sym_t*)jl_exprarg(st, 1); + case 1: + m->line = jl_unbox_long(jl_exprarg(st, 0)); + default: ; + } st = jl_nothing; set_lineno = 1; } diff --git a/src/rtutils.c b/src/rtutils.c index 9397cab1ec0a09..b04ad0228a28ff 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -757,7 +757,9 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt n += jl_printf(out, ">"); } else if (vt == jl_linenumbernode_type) { - n += jl_printf(out, "# line %" PRIuPTR, jl_linenode_line(v)); + n += jl_printf(out, "#= "); + n += jl_static_show_x(out, jl_linenode_file(v), depth); + n += jl_printf(out, ":%" PRIuPTR " =#", jl_linenode_line(v)); } else if (vt == jl_expr_type) { jl_expr_t *e = (jl_expr_t*)v; diff --git a/test/ambiguous.jl b/test/ambiguous.jl index 32139c496a44f1..049cffb7281584 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -1,7 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license # DO NOT ALTER ORDER OR SPACING OF METHODS BELOW -const lineoffset = @__LINE__ + 0 # XXX: __LINE__ at the end of a line is off-by-one +const lineoffset = @__LINE__ ambig(x, y) = 1 ambig(x::Integer, y) = 2 ambig(x, y::Integer) = 3 diff --git a/test/docs.jl b/test/docs.jl index 46b1523e564013..d1d65d5615ae70 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -48,7 +48,7 @@ end # General tests for docstrings. -const LINE_NUMBER = @__LINE__+1 +const LINE_NUMBER = @__LINE__() + 1 "DocsTest" module DocsTest @@ -906,23 +906,24 @@ let x = Binding(Main, :⊕) @test parse(string(x)) == :(⊕) end +doc_util_path = Symbol(joinpath("docs", "utils.jl")) # Docs.helpmode tests: we test whether the correct expressions are being generated here, # rather than complete integration with Julia's REPL mode system. for (line, expr) in Pair[ "sin" => :sin, "Base.sin" => :(Base.sin), - "@time(x)" => :(@time(x)), - "@time" => :(:@time), - ":@time" => :(:@time), - "@time()" => :(@time), - "Base.@time()" => :(Base.@time), + "@time(x)" => Expr(:macrocall, Symbol("@time"), LineNumberNode(1, :none), :x), + "@time" => Expr(:macrocall, Symbol("@time"), LineNumberNode(1, :none)), + ":@time" => Expr(:quote, (Expr(:macrocall, Symbol("@time"), LineNumberNode(1, :none)))), + "@time()" => Expr(:macrocall, Symbol("@time"), LineNumberNode(1, :none)), + "Base.@time()" => Expr(:macrocall, Expr(:., :Base, QuoteNode(Symbol("@time"))), LineNumberNode(1, :none)), "ccall" => :ccall, # keyword "while " => :while, # keyword, trailing spaces should be stripped. "0" => 0, "\"...\"" => "...", - "r\"...\"" => :(r"..."), + "r\"...\"" => Expr(:macrocall, Symbol("@r_str"), LineNumberNode(1, :none), "...") ] - @test Docs.helpmode(line) == :(Base.Docs.@repl($STDOUT, $expr)) + @test Docs.helpmode(line) == Expr(:macrocall, Expr(:., Expr(:., :Base, QuoteNode(:Docs)), QuoteNode(Symbol("@repl"))), LineNumberNode(117, doc_util_path), STDOUT, expr) buf = IOBuffer() @test eval(Base, Docs.helpmode(buf, line)) isa Union{Base.Markdown.MD,Void} end @@ -961,8 +962,8 @@ dynamic_test.x = "test 2" @test @doc(dynamic_test) == "test 2 Union{}" @test @doc(dynamic_test(::String)) == "test 2 Tuple{String}" -@test Docs._repl(:(dynamic_test(1.0))) == :(@doc $(Expr(:escape, :(dynamic_test(::typeof(1.0)))))) -@test Docs._repl(:(dynamic_test(::String))) == :(@doc $(Expr(:escape, :(dynamic_test(::String))))) +@test Docs._repl(:(dynamic_test(1.0))) == Expr(:macrocall, Symbol("@doc"), LineNumberNode(204, doc_util_path), esc(:(dynamic_test(::typeof(1.0))))) +@test Docs._repl(:(dynamic_test(::String))) == Expr(:macrocall, Symbol("@doc"), LineNumberNode(204, doc_util_path), esc(:(dynamic_test(::String)))) # Equality testing diff --git a/test/loading.jl b/test/loading.jl index 80f14a8ba08dbb..b50ca7960966ed 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -2,22 +2,24 @@ using Base.Test -@test @__LINE__ == 5 +@test @__LINE__() == 5 include("test_sourcepath.jl") thefname = "the fname!//\\&\1*" include_string_test_func = include_string("include_string_test() = @__FILE__", thefname) -@test include_string_test_func() == Base.source_path() +@test include_string_test_func() == thefname @test include_string("Base.source_path()", thefname) == Base.source_path() @test basename(@__FILE__) == "loading.jl" @test isabspath(@__FILE__) @test isdir(@__DIR__) @test @__DIR__() == dirname(@__FILE__) -let exename = `$(Base.julia_cmd()) --precompiled=yes --startup-file=no` - wd = sprint(show, pwd()) +let exename = `$(Base.julia_cmd()) --precompiled=yes --startup-file=no`, + wd = sprint(show, abspath(pwd(), "")), + s_dir = sprint(show, joinpath(realpath(tempdir()), "")) + @test wd != s_dir @test readchomp(`$exename -E "@__DIR__" -i`) == wd - @test readchomp(`$exename -E "cd(()->eval(:(@__DIR__)), tempdir())" -i`) != wd + @test readchomp(`$exename -E "cd(()->eval(:(@__DIR__)), $s_dir)" -i`) == s_dir @test readchomp(`$exename -E "@__DIR__"`) == wd # non-interactive end diff --git a/test/parse.jl b/test/parse.jl index 12377dbdbb01ec..c45e8e297a398d 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -147,10 +147,10 @@ macro test999_str(args...); args; end # issue 11970 @test parseall(""" -macro f(args...) end; @f "" + macro f(args...) end; @f "macro argument" """) == Expr(:toplevel, - Expr(:macro, Expr(:call, :f, Expr(:..., :args)), Expr(:block, Expr(:line, 1, :none))), - Expr(:macrocall, Symbol("@f"), "")) + Expr(:macro, Expr(:call, :f, Expr(:..., :args)), Expr(:block, LineNumberNode(1, :none))), + Expr(:macrocall, Symbol("@f"), LineNumberNode(1, :none), "macro argument")) # blocks vs. tuples @test parse("()") == Expr(:tuple) @@ -351,7 +351,7 @@ parsehex(s) = parse(Int,s,16) # issue #17705 @test parse("2e3_") == Expr(:call, :*, 2e3, :_) @test parse("2e-3_") == Expr(:call, :*, 2e-3, :_) -@test parse("2e3_\"x\"") == Expr(:call, :*, 2e3, Expr(:macrocall, Symbol("@__str"), "x")) +@test parse("2e3_\"x\"") == Expr(:call, :*, 2e3, Expr(:macrocall, Symbol("@__str"), LineNumberNode(1, :none), "x")) # multibyte spaces @test parse(Int, "3\u2003\u202F") == 3 @@ -514,7 +514,7 @@ let b = IOBuffer(""" end f() """) - @test Base.parse_input_line(b) == Expr(:let, Expr(:block, Expr(:line, 2, :none), :x), Expr(:(=), :x, :x)) + @test Base.parse_input_line(b) == Expr(:let, Expr(:block, LineNumberNode(2, :none), :x), Expr(:(=), :x, :x)) @test Base.parse_input_line(b) == Expr(:call, :f) @test Base.parse_input_line(b) === nothing end @@ -574,7 +574,7 @@ f16517() = try error(); catch 0; end # issue #16671 @test parse("1.") === 1.0 -isline(x) = isa(x,Expr) && x.head === :line +isline(x) = isa(x, LineNumberNode) # issue #16672 @test count(isline, parse("begin end").args) == 1 @@ -584,9 +584,9 @@ isline(x) = isa(x,Expr) && x.head === :line # issue #16736 let - local lineoffset0 = @__LINE__ + 1 - local lineoffset1 = @__LINE__ - local lineoffset2 = @__LINE__ - 1 + local lineoffset0 = @__LINE__() + 1 + local lineoffset1 = @__LINE__() + local lineoffset2 = @__LINE__() - 1 @test lineoffset0 == lineoffset1 == lineoffset2 end @@ -596,13 +596,13 @@ end y end") == Expr(:try, Expr(:block, - Expr(:line, 1, :none), + LineNumberNode(1, :none), :x), false, Expr(:block, - Expr(:line, 2, :none), + LineNumberNode(2, :none), Expr(:call, :test), - Expr(:line, 3, :none), + LineNumberNode(3, :none), :y)) # test that pre 0.5 deprecated syntax is a parse error @@ -775,12 +775,12 @@ module B15838 end @test A15838.@f() === nothing @test A15838.@f(1) === :b -let nometh = expand(:(A15838.@f(1, 2))) +let nometh = expand(:(A15838.@f(1, 2))), __source__ = LineNumberNode(@__LINE__, Symbol(@__FILE__)) @test (nometh::Expr).head === :error @test length(nometh.args) == 1 e = nometh.args[1]::MethodError @test e.f === getfield(A15838, Symbol("@f")) - @test e.args === (1,2) + @test e.args === (__source__, 1, 2) end # issue 10046 @@ -904,8 +904,8 @@ f1_exprs = get_expr_list(@code_typed(f1(1))[1]) f2_exprs = get_expr_list(@code_typed(f2(1))[1]) @test Meta.isexpr(f1_exprs[end], :return) -@test is_pop_loc(f2_exprs[end - 1]) -@test Meta.isexpr(f2_exprs[end], :return) +@test is_pop_loc(f2_exprs[end]) +@test Meta.isexpr(f2_exprs[end - 1], :return) if Base.JLOptions().code_coverage != 0 && Base.JLOptions().can_inline != 0 @test count_meta_loc(f1_exprs) == 1 @@ -924,10 +924,10 @@ end @test :(x`s\`"\x\$\\`) == :(@x_cmd "s`\"\\x\\\$\\\\") # Check multiline command literals -@test :``` +@test :(@cmd "multiline\ncommand\n") == :``` multiline command -``` == :(@cmd "multiline\ncommand\n") +``` macro julia_cmd(s) Meta.quot(parse(s)) @@ -980,7 +980,7 @@ let ..(x,y) = x + y end # issue #7669 -@test parse("@a(b=1, c=2)") == Expr(:macrocall, Symbol("@a"), :(b=1), :(c=2)) +@test parse("@a(b=1, c=2)") == Expr(:macrocall, Symbol("@a"), LineNumberNode(1, :none), :(b=1), :(c=2)) # issue #19685 let f = function (x; kw...) @@ -1070,7 +1070,7 @@ end @test expand(:(@err20000)) == Expr(:error, "oops!") # issue #20000 -@test parse("@m(a; b=c)") == Expr(:macrocall, Symbol("@m"), +@test parse("@m(a; b=c)") == Expr(:macrocall, Symbol("@m"), LineNumberNode(1, :none), Expr(:parameters, Expr(:kw, :b, :c)), :a) # issue #21054 diff --git a/test/reflection.jl b/test/reflection.jl index d66098e3fde77b..0e00763f70c26c 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -337,7 +337,7 @@ end return true end end -@test functionloc(f14346)[2] == @__LINE__-4 +@test functionloc(f14346)[2] == @__LINE__() - 4 # test jl_get_llvm_fptr. We test functions both in and definitely not in the system image definitely_not_in_sysimg() = nothing @@ -366,10 +366,10 @@ let using .MacroTest a = 1 m = getfield(current_module(), Symbol("@macrotest")) - @test which(m, Tuple{Int,Symbol})==@which @macrotest 1 a - @test which(m, Tuple{Int,Int})==@which @macrotest 1 1 + @test which(m, Tuple{LineNumberNode, Int, Symbol}) == @which @macrotest 1 a + @test which(m, Tuple{LineNumberNode, Int, Int}) == @which @macrotest 1 1 - @test first(methods(m,Tuple{Int, Int}))==@which MacroTest.@macrotest 1 1 + @test first(methods(m, Tuple{LineNumberNode, Int, Int})) == @which MacroTest.@macrotest 1 1 @test functionloc(@which @macrotest 1 1) == @functionloc @macrotest 1 1 end diff --git a/test/replutil.jl b/test/replutil.jl index 63e3091c9b7a7c..ac4bec2258976c 100644 --- a/test/replutil.jl +++ b/test/replutil.jl @@ -12,7 +12,7 @@ function test_have_color(buf, color, no_color) end cfile = " at $(@__FILE__):" -c1line = @__LINE__ + 1 +c1line = @__LINE__() + 1 method_c1(x::Float64, s::AbstractString...) = true buf = IOBuffer() @@ -59,7 +59,7 @@ color = "\e[0m\nClosest candidates are:\n method_c2(\e[1m\e[31m::Int32\e[0m, :: no_color = no_color = "\nClosest candidates are:\n method_c2(!Matched::Int32, ::Float64, ::Any...)$cfile$(c2line+2)\n method_c2(!Matched::Int32, ::Any...)$cfile$(c2line+1)\n method_c2(::T<:Real, ::T<:Real, !Matched::T<:Real) where T<:Real$cfile$(c2line+5)\n ..." test_have_color(buf, color, no_color) -c3line = @__LINE__ + 1 +c3line = @__LINE__() + 1 method_c3(x::Float64, y::Float64) = true Base.show_method_candidates(buf, Base.MethodError(method_c3,(1.,))) color = "\e[0m\nClosest candidates are:\n method_c3(::Float64, \e[1m\e[31m::Float64\e[0m)$cfile$c3line\e[0m" @@ -75,7 +75,7 @@ test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c4(::AbstractString)$cfile$(c4line+2)\n method_c4()$cfile$(c4line+1)\e[0m", "\nClosest candidates are:\n method_c4(::AbstractString)$cfile$(c4line+2)\n method_c4()$cfile$(c4line+1)") -c5line = @__LINE__ + 1 +c5line = @__LINE__() + 1 method_c5(::Type{Float64}) = true Base.show_method_candidates(buf, MethodError(method_c5,(Float64,))) test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c5(::Type{Float64})$cfile$c5line\e[0m", @@ -92,12 +92,12 @@ for f in [getindex, setindex!] test_have_color(buf, "", "") end -PR16155line = @__LINE__ + 2 +PR16155line = @__LINE__() + 2 mutable struct PR16155 a::Int64 b end -PR16155line2 = @__LINE__ + 1 +PR16155line2 = @__LINE__() + 1 (::Type{T}){T<:PR16155}(arg::Any) = "replace call-to-convert method from sysimg" Base.show_method_candidates(buf, MethodError(PR16155,(1.0, 2.0, Int64(3)))) @@ -146,12 +146,12 @@ else @test contains(error_out3, "method_c6_in_module(::Any; y)$cfile$(c6mline + 3) got unsupported keyword argument \"x\"") end -c7line = @__LINE__ + 1 +c7line = @__LINE__() + 1 method_c7(a, b; kargs...) = a Base.show_method_candidates(buf, MethodError(method_c7, (1, 1)), [(:x, 1), (:y, 2)]) test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c7(::Any, ::Any; kargs...)$cfile$c7line\e[0m", "\nClosest candidates are:\n method_c7(::Any, ::Any; kargs...)$cfile$c7line") -c8line = @__LINE__ + 1 +c8line = @__LINE__() + 1 method_c8(a, b; y=1, w=1) = a Base.show_method_candidates(buf, MethodError(method_c8, (1, 1)), [(:x, 1), (:y, 2), (:z, 1), (:w, 1)]) test_have_color(buf, "\e[0m\nClosest candidates are:\n method_c8(::Any, ::Any; y, w)$cfile$c8line\e[1m\e[31m got unsupported keyword arguments \"x\", \"z\"\e[0m\e[0m", @@ -344,7 +344,7 @@ end @test stringmime("text/plain", FunctionLike()) == "(::FunctionLike) (generic function with 0 methods)" @test ismatch(r"^@doc \(macro with \d+ method[s]?\)$", stringmime("text/plain", getfield(Base, Symbol("@doc")))) -method_defs_lineno = @__LINE__+1 +method_defs_lineno = @__LINE__() + 1 Base.Symbol() = throw(ErrorException("1")) (::Symbol)() = throw(ErrorException("2")) EightBitType() = throw(ErrorException("3")) @@ -361,15 +361,24 @@ let err_str, sp = Base.source_path() sn = basename(sp) - @test sprint(show, which(Symbol, Tuple{})) == "Symbol() in $curmod_str at $sp:$(method_defs_lineno + 0)" - @test sprint(show, which(:a, Tuple{})) == "(::Symbol)() in $curmod_str at $sp:$(method_defs_lineno + 1)" - @test sprint(show, which(EightBitType, Tuple{})) == "$(curmod_prefix)EightBitType() in $curmod_str at $sp:$(method_defs_lineno + 2)" - @test sprint(show, which(reinterpret(EightBitType, 0x54), Tuple{})) == "(::$(curmod_prefix)EightBitType)() in $curmod_str at $sp:$(method_defs_lineno + 3)" - @test sprint(show, which(EightBitTypeT, Tuple{})) == "(::Type{$(curmod_prefix)EightBitTypeT})() in $curmod_str at $sp:$(method_defs_lineno + 4)" - @test sprint(show, which(EightBitTypeT{Int32}, Tuple{})) == "(::Type{$(curmod_prefix)EightBitTypeT{T}})() where T in $curmod_str at $sp:$(method_defs_lineno + 5)" - @test sprint(show, which(reinterpret(EightBitTypeT{Int32}, 0x54), Tuple{})) == "(::$(curmod_prefix)EightBitTypeT)() in $curmod_str at $sp:$(method_defs_lineno + 6)" - @test startswith(sprint(show, which(getfield(Base, Symbol("@doc")), Tuple{Vararg{Any}})), "@doc(x...) in Core at boot.jl:") - @test startswith(sprint(show, which(FunctionLike(), Tuple{})), "(::$(curmod_prefix)FunctionLike)() in $curmod_str at $sp:$(method_defs_lineno + 7)") + @test sprint(show, which(Symbol, Tuple{})) == + "Symbol() in $curmod_str at $sp:$(method_defs_lineno + 0)" + @test sprint(show, which(:a, Tuple{})) == + "(::Symbol)() in $curmod_str at $sp:$(method_defs_lineno + 1)" + @test sprint(show, which(EightBitType, Tuple{})) == + "$(curmod_prefix)EightBitType() in $curmod_str at $sp:$(method_defs_lineno + 2)" + @test sprint(show, which(reinterpret(EightBitType, 0x54), Tuple{})) == + "(::$(curmod_prefix)EightBitType)() in $curmod_str at $sp:$(method_defs_lineno + 3)" + @test sprint(show, which(EightBitTypeT, Tuple{})) == + "(::Type{$(curmod_prefix)EightBitTypeT})() in $curmod_str at $sp:$(method_defs_lineno + 4)" + @test sprint(show, which(EightBitTypeT{Int32}, Tuple{})) == + "(::Type{$(curmod_prefix)EightBitTypeT{T}})() where T in $curmod_str at $sp:$(method_defs_lineno + 5)" + @test sprint(show, which(reinterpret(EightBitTypeT{Int32}, 0x54), Tuple{})) == + "(::$(curmod_prefix)EightBitTypeT)() in $curmod_str at $sp:$(method_defs_lineno + 6)" + @test startswith(sprint(show, which(getfield(Base, Symbol("@doc")), Tuple{LineNumberNode, Vararg{Any}})), + "@doc(__source__::LineNumberNode, x...) in Core at boot.jl:") + @test startswith(sprint(show, which(FunctionLike(), Tuple{})), + "(::$(curmod_prefix)FunctionLike)() in $curmod_str at $sp:$(method_defs_lineno + 7)") @test stringmime("text/plain", FunctionLike()) == "(::FunctionLike) (generic function with 1 method)" @test stringmime("text/plain", Core.arraysize) == "arraysize (built-in function)" diff --git a/test/show.jl b/test/show.jl index 44e3cca5a31996..ca12dd1c8d336a 100644 --- a/test/show.jl +++ b/test/show.jl @@ -15,8 +15,8 @@ struct T5589 end @test replstr(T5589(Array{String,1}(100))) == "$(curmod_prefix)T5589(String[#undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef … #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef, #undef])" -@test replstr(parse("mutable struct X end")) == ":(mutable struct X # none, line 1:\n end)" -@test replstr(parse("struct X end")) == ":(struct X # none, line 1:\n end)" +@test replstr(parse("mutable struct X end")) == ":(mutable struct X\n #= none:1 =#\n end)" +@test replstr(parse("struct X end")) == ":(struct X\n #= none:1 =#\n end)" s = "ccall(:f, Int, (Ptr{Void},), &x)" @test replstr(parse(s)) == ":($s)" @@ -42,12 +42,14 @@ macro test_repr(x) local x1 = parse($x) local x2 = eval(parse(repr(x1))) local x3 = eval(parse(repr(x2))) - x3 == x1 ? nothing : error(string( - "repr test failed:", - "\noriginal: ", $x, - "\n\nparsed: ", x2, "\n", sprint(dump, x2), - "\n\nreparsed: ", x3, "\n", sprint(dump, x3) - )) + if x3 != x1 + error(string( + "repr test failed:", + "\noriginal: ", $x, + "\n\nparsed: ", x2, "\n", sprint(dump, x2), + "\n\nreparsed: ", x3, "\n", sprint(dump, x3) + )) + end end end end @@ -94,76 +96,128 @@ end # control structures (shamelessly stolen from base/bitarray.jl) @test_repr """mutable struct BitArray{N} <: AbstractArray{Bool, N} + # line meta chunks::Vector{UInt64} + # line meta len::Int + # line meta dims::NTuple{N,Int} + # line meta function BitArray(dims::Int...) + # line meta if length(dims) != N + # line meta error(\"number of dimensions must be \$N (got \$(length(dims)))\") end + # line meta n = 1 + # line meta for d in dims + # line meta if d < 0 + # line meta error(\"dimension size must be nonnegative (got \$d)\") end + # line meta n *= d end + # line meta nc = num_bit_chunks(n) + # line meta chunks = Array{UInt64,1}(nc) + # line meta if nc > 0 + # line meta chunks[end] = UInt64(0) end + # line meta b = new(chunks, n) + # line meta if N != 1 + # line meta b.dims = dims end + # line meta return b end end""" @test_repr """function copy_chunks(dest::Vector{UInt64}, pos_d::Integer, src::Vector{UInt64}, pos_s::Integer, numbits::Integer) + # line meta if numbits == 0 + # line meta return end + # line meta if dest === src && pos_d > pos_s + # line meta return copy_chunks_rtol(dest, pos_d, pos_s, numbits) end + # line meta kd0, ld0 = get_chunks_id(pos_d) + # line meta kd1, ld1 = get_chunks_id(pos_d + numbits - 1) + # line meta ks0, ls0 = get_chunks_id(pos_s) + # line meta ks1, ls1 = get_chunks_id(pos_s + numbits - 1) + # line meta delta_kd = kd1 - kd0 + # line meta delta_ks = ks1 - ks0 + # line meta u = _msk64 + # line meta if delta_kd == 0 + # line meta msk_d0 = ~(u << ld0) | (u << ld1 << 1) else + # line meta msk_d0 = ~(u << ld0) + # line meta msk_d1 = (u << ld1 << 1) end + # line meta if delta_ks == 0 + # line meta msk_s0 = (u << ls0) & ~(u << ls1 << 1) else + # line meta msk_s0 = (u << ls0) end + # line meta chunk_s0 = glue_src_bitchunks(src, ks0, ks1, msk_s0, ls0) + # line meta dest[kd0] = (dest[kd0] & msk_d0) | ((chunk_s0 << ld0) & ~msk_d0) + # line meta if delta_kd == 0 + # line meta return end + # line meta for i = 1 : kd1 - kd0 - 1 + # line meta chunk_s1 = glue_src_bitchunks(src, ks0 + i, ks1, msk_s0, ls0) + # line meta chunk_s = (chunk_s0 >>> (63 - ld0) >>> 1) | (chunk_s1 << ld0) + # line meta dest[kd0 + i] = chunk_s + # line meta chunk_s0 = chunk_s1 end + # line meta if ks1 >= ks0 + delta_kd + # line meta chunk_s1 = glue_src_bitchunks(src, ks0 + delta_kd, ks1, msk_s0, ls0) else + # line meta chunk_s1 = UInt64(0) end + # line meta chunk_s = (chunk_s0 >>> (63 - ld0) >>> 1) | (chunk_s1 << ld0) + # line meta dest[kd1] = (dest[kd1] & msk_d1) | (chunk_s & ~msk_d1) + # line meta return end""" @@ -201,13 +255,21 @@ end""" @test_repr "[1 2 3; 4 5 6; 7 8 9]'" @test_repr "baremodule X +# line meta +# line meta importall ..A.b +# line meta import ...B.c +# line meta import D +# line meta import B.C.D.E.F.g end" @test_repr "baremodule Y +# line meta +# line meta export A, B, C +# line meta export D, E, F end" @@ -261,22 +323,22 @@ end @test string(:(-{x})) == "-{x}" # issue #11393 -@test_repr "@m(x,y) + z" -@test_repr "(@m(x,y),z)" -@test_repr "[@m(x,y),z]" -@test_repr "A[@m(x,y),z]" -@test_repr "T{@m(x,y),z}" +@test_repr "@m(x, y) + z" +@test_repr "(@m(x, y), z)" +@test_repr "[@m(x, y), z]" +@test_repr "A[@m(x, y), z]" +@test_repr "T{@m(x, y), z}" @test_repr "@m x @n(y) z" -@test_repr "f(@m(x,y);z=@n(a))" -@test_repr "@m(x,y).z" -@test_repr "::@m(x,y)+z" +@test_repr "f(@m(x, y); z=@n(a))" +@test_repr "@m(x, y).z" +@test_repr "::@m(x, y) + z" @test_repr "[@m(x) y z]" @test_repr "[@m(x) y; z]" @test_repr "let @m(x), y=z; end" -@test repr(:(@m x y)) == ":(@m x y)" -@test string(:(@m x y)) == "@m x y" -@test string(:(@m x y;)) == "begin \n @m x y\nend" +@test repr(:(@m x y)) == ":(#= $(@__FILE__):$(@__LINE__) =# @m x y)" +@test string(:(@m x y)) == "#= $(@__FILE__):$(@__LINE__) =# @m x y" +@test string(:(@m x y;)) == "begin\n #= $(@__FILE__):$(@__LINE__) =# @m x y\nend" # issue #11436 @test_repr "1 => 2 => 3" @@ -447,25 +509,33 @@ end # issue #15309 -l1, l2, l2n = Expr(:line,42), Expr(:line,42,:myfile), LineNumberNode(42) -@test string(l2n) == " # line 42:" -@test string(l2) == " # myfile, line 42:" -@test string(l1) == string(l2n) -ex = Expr(:block, l1, :x, l2, :y, l2n, :z) -@test replace(string(ex)," ","") == replace(""" -begin # line 42: - x # myfile, line 42: - y # line 42: - z -end""", " ", "") +let ex, + l1 = Expr(:line, 42), + l2 = Expr(:line, 42, :myfile), + l2n = LineNumberNode(42) + @test string(l2n) == "#= line 42 =#" + @test string(l2) == "#= myfile:42 =#" + @test string(l1) == string(l2n) + ex = Expr(:block, l1, :x, l2, :y, l2n, :z) + @test replace(string(ex)," ","") == replace(""" + begin + #= line 42 =# + x + #= myfile:42 =# + y + #= line 42 =# + z + end""", " ", "") +end # Test the printing of whatever form of line number representation # that is used in the arguments to a macro looks the same as for # regular quoting macro strquote(ex) - QuoteNode(string(ex)) + return QuoteNode(string(ex)) +end +let str_ex2a = @strquote(begin x end), str_ex2b = string(quote x end) + @test str_ex2a == str_ex2b end -str_ex2a, str_ex2b = @strquote(begin x end), string(quote x end) -@test str_ex2a == str_ex2b # test structured zero matrix printing for select structured types diff --git a/test/stacktraces.jl b/test/stacktraces.jl index ac1814354f12c2..19e23aa0f18f1f 100644 --- a/test/stacktraces.jl +++ b/test/stacktraces.jl @@ -6,7 +6,7 @@ let @noinline child() = stacktrace() @noinline parent() = child() @noinline grandparent() = parent() - line_numbers = @__LINE__ - [3, 2, 1] + line_numbers = @__LINE__() - [3, 2, 1] stack = grandparent() # Basic tests. @@ -68,7 +68,7 @@ let ct = current_task() return catch_stacktrace() end end - line_numbers = @__LINE__ .- [15, 10, 5] + line_numbers = @__LINE__() .- [15, 10, 5] # Test try...catch with stacktrace @test try_stacktrace()[1] == StackFrame(:try_stacktrace, @__FILE__, line_numbers[2]) diff --git a/test/worlds.jl b/test/worlds.jl index 13bb28597c0906..1dfea7f6fe8d9c 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -136,7 +136,7 @@ f265(::Int) = 1 # test for method errors h265() = true -loc_h265 = "$(Base.source_path()):$(@__LINE__ - 1)" +loc_h265 = "$(@__FILE__):$(@__LINE__() - 1)" @test h265() @test_throws MethodError put_n_take!(h265, ()) @test_throws MethodError wait(t265) From 6b05e37815448e351c34b35bb76909f22cae6980 Mon Sep 17 00:00:00 2001 From: Chris Foster Date: Tue, 7 Mar 2017 17:40:49 +1000 Subject: [PATCH 08/53] Add tests for new __LINE__ behaviour inside macros --- test/loading.jl | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/test/loading.jl b/test/loading.jl index b50ca7960966ed..a39e0940618599 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -2,7 +2,34 @@ using Base.Test -@test @__LINE__() == 5 +# Tests for @__LINE__ inside and outside of macros +@test (@__LINE__) == 6 + +macro macro_caller_lineno() + @test 9 == (@__LINE__) != __source__.line > 12 + return __source__.line +end + +@test @macro_caller_lineno() == (@__LINE__) > 12 + +# @__LINE__ in a macro expands to the location of the macrocall in the source +# while __source__.line is the location of the macro caller +macro nested_LINE_expansion() + return quote + return (@emit_LINE, $(__source__.line)) + end +end +macro nested_LINE_expansion2() + return :((@emit_LINE, $(__source__.line))) +end +macro emit_LINE() + return quote + (@__LINE__, $(__source__.line)) + end +end +@test (@emit_LINE) == ((@__LINE__) - 3, @__LINE__) +@test @nested_LINE_expansion() == ((@__LINE__() - 4, @__LINE__() - 12), @__LINE__()) +@test @nested_LINE_expansion2() == ((@__LINE__() - 5, @__LINE__() - 9), @__LINE__()) include("test_sourcepath.jl") thefname = "the fname!//\\&\1*" From 4158b5ebfce628bf899fdd7f5b165bbb41cf9901 Mon Sep 17 00:00:00 2001 From: Tony Kelman Date: Thu, 25 May 2017 11:59:28 -0700 Subject: [PATCH 09/53] Fix opensuse repo links for make win-extras (#22058) --- Makefile | 4 ++-- contrib/windows/get_toolchain.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index dda792566108a1..f88264d5ed4fac 100644 --- a/Makefile +++ b/Makefile @@ -590,7 +590,7 @@ ifneq (,$(filter $(ARCH), i386 i486 i586 i686)) cd $(JULIAHOME)/dist-extras && \ $(JLDOWNLOAD) http://downloads.sourceforge.net/sevenzip/7z920.exe && \ 7z x -y 7z920.exe 7z.exe 7z.dll && \ - ../contrib/windows/winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_42.2 \ + ../contrib/windows/winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_Leap_42.2 \ "mingw32-libgfortran3 mingw32-libquadmath0 mingw32-libstdc++6 mingw32-libgcc_s_sjlj1 mingw32-libssp0 mingw32-libwinpthread1 mingw32-libexpat1 mingw32-zlib1" && \ cp usr/i686-w64-mingw32/sys-root/mingw/bin/*.dll . else ifeq ($(ARCH),x86_64) @@ -599,7 +599,7 @@ else ifeq ($(ARCH),x86_64) 7z x -y 7z920-x64.msi _7z.exe _7z.dll && \ mv _7z.dll 7z.dll && \ mv _7z.exe 7z.exe && \ - ../contrib/windows/winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win64/openSUSE_42.2 \ + ../contrib/windows/winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win64/openSUSE_Leap_42.2 \ "mingw64-libgfortran3 mingw64-libquadmath0 mingw64-libstdc++6 mingw64-libgcc_s_seh1 mingw64-libssp0 mingw64-libwinpthread1 mingw64-libexpat1 mingw64-zlib1" && \ cp usr/x86_64-w64-mingw32/sys-root/mingw/bin/*.dll . else diff --git a/contrib/windows/get_toolchain.sh b/contrib/windows/get_toolchain.sh index 290a18195ef589..01e9ad973b2138 100755 --- a/contrib/windows/get_toolchain.sh +++ b/contrib/windows/get_toolchain.sh @@ -27,7 +27,7 @@ case $bits in ;; esac echo "Downloading $host toolchain, check $PWD/get_toolchain.log for full output" -contrib/windows/winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win$bits/openSUSE_42.2 \ +contrib/windows/winrpm.sh http://download.opensuse.org/repositories/windows:/mingw:/win$bits/openSUSE_Leap_42.2 \ "mingw$bits-gcc mingw$bits-gcc-c++ mingw$bits-gcc-fortran \ mingw$bits-libssp0 mingw$bits-libstdc++6 mingw$bits-libgfortran3" > get_toolchain.log From 3900e338d068d933baec8fbbea44f98c0ad62f1f Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 24 May 2017 16:44:33 -0400 Subject: [PATCH 10/53] fix scope rules: implicitly using a global doesn't add it to the scope fix #21900 --- base/REPL.jl | 1 + base/libgit2/libgit2.jl | 2 +- src/jlfrontend.scm | 29 ++++++++------- src/julia-syntax.scm | 54 +++++++++++++--------------- test/core.jl | 78 ++++++++++++++++++++++++++++++++++++++--- test/libgit2.jl | 1 + 6 files changed, 115 insertions(+), 50 deletions(-) diff --git a/base/REPL.jl b/base/REPL.jl index dda4a65ac0dade..8054e048600cbe 100644 --- a/base/REPL.jl +++ b/base/REPL.jl @@ -633,6 +633,7 @@ function respond(f, repl, main; pass_empty = false) line = String(take!(buf)) if !isempty(line) || pass_empty reset(repl) + local val, bt try # note: value wrapped carefully here to ensure it doesn't get passed through expand response = eval(Main, Expr(:body, Expr(:return, Expr(:call, QuoteNode(f), QuoteNode(line))))) diff --git a/base/libgit2/libgit2.jl b/base/libgit2/libgit2.jl index c8ba346ec52f12..800e5a71b53d8b 100644 --- a/base/libgit2/libgit2.jl +++ b/base/libgit2/libgit2.jl @@ -149,10 +149,10 @@ function isdiff(repo::GitRepo, treeish::AbstractString, paths::AbstractString="" diff = diff_tree(repo, tree, paths, cached=cached) result = count(diff) > 0 close(diff) + return result finally close(tree) end - return result end """ diff --git a/src/jlfrontend.scm b/src/jlfrontend.scm index 5c973bacd83f05..28f62d2525fb01 100644 --- a/src/jlfrontend.scm +++ b/src/jlfrontend.scm @@ -50,6 +50,7 @@ (cdr e)))) tab))) +;; find variables that should be forced to be global in a toplevel expr (define (find-possible-globals e) (table.keys (find-possible-globals- e (table)))) @@ -59,19 +60,6 @@ (define (some-gensym? x) (or (gensym? x) (memq x *gensyms*))) -;; find variables that should be forced to be global in a toplevel expr -(define (toplevel-expr-globals e) - (diff - (delete-duplicates - (append - ;; vars assigned at the outer level - (filter (lambda (x) (not (some-gensym? x))) (find-assigned-vars e '())) - ;; vars declared const or global outside any scope block - (find-decls 'const e) - (find-decls 'global e) - ;; vars assigned anywhere, if they have been defined as global - (filter defined-julia-global (find-possible-globals e)))) - (find-decls 'local e))) ;; return a lambda expression representing a thunk for a top-level expression ;; note: expansion of stuff inside module is delayed, so the contents obey @@ -81,11 +69,22 @@ (if (and (pair? ex0) (eq? (car ex0) 'toplevel)) ex0 (let* ((ex (julia-expand0 ex0)) - (gv (toplevel-expr-globals ex)) + (lv (find-decls 'local ex)) + (gv (diff (delete-duplicates + (append (find-decls 'const ex) ;; convert vars declared const outside any scope block to outer-globals + (find-decls 'global ex) ;; convert vars declared global outside any scope block to outer-globals + ;; vars assigned at the outer level + (filter (lambda (x) (not (some-gensym? x))) + (find-assigned-vars ex '())))) + lv)) + ;; vars assigned anywhere, if they have not been explicitly defined + (existing-gv (filter (lambda (x) (and (not (or (memq x lv) (memq x gv))) (defined-julia-global x))) + (find-possible-globals ex))) (th (julia-expand1 `(lambda () () (scope-block - (block ,@(map (lambda (v) `(implicit-global ,v)) gv) + (block ,@(map (lambda (v) `(implicit-global ,v)) existing-gv) + ,@(map (lambda (v) `(implicit-global ,v)) gv) ,ex)))))) (if (and (null? (cdadr (caddr th))) (= 0 (cadddr (caddr th)))) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 86ed90c300ac66..637d25e9d12718 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -2500,7 +2500,7 @@ ;; 3. variables assigned inside this scope-block that don't exist in outer ;; scopes ;; returns lambdas in the form (lambda (args...) (locals...) body) -(define (resolve-scopes- e env implicitglobals lam renames newlam) +(define (resolve-scopes- e env outerglobals implicitglobals lam renames newlam) (cond ((symbol? e) (let ((r (assq e renames))) (if r (cdr r) e))) ;; return the renaming for e, or e ((or (not (pair? e)) (quoted? e) (memq (car e) '(toplevel global))) e) @@ -2511,10 +2511,11 @@ (let* ((lv (lam:vars e)) (env (append lv env)) (body (resolve-scopes- (lam:body e) env - ;; don't propagate implicit globals - ;; issue #7234 + ;; don't propagate implicit or outer globals + '() '() e + ;; remove renames corresponding to local variables from the environment (filter (lambda (ren) (not (memq (car ren) lv))) renames) #t))) @@ -2522,17 +2523,16 @@ ((eq? (car e) 'scope-block) (let* ((blok (cadr e)) ;; body of scope-block expression (other-locals (if lam (caddr lam) '())) ;; locals that are explicitly part of containing lambda expression - (iglo (find-decls 'implicit-global blok)) ;; implicitly defined globals used in blok + (iglo (find-decls 'implicit-global blok)) ;; globals defined implicitly outside blok (glob (diff (find-global-decls blok) iglo)) ;; all globals declared in blok (vars-def (check-dups (find-local-def-decls blok) '())) (locals-declared (check-dups (find-local-decls blok) vars-def)) - (locals-implicit (diff (implicit-locals - blok - ;; being declared global prevents a variable - ;; assignment from introducing a local - (append env glob implicitglobals iglo) - (append glob iglo)) - vars-def)) + (locals-implicit (implicit-locals + blok + ;; being declared global prevents a variable + ;; assignment from introducing a local + (append env glob iglo outerglobals locals-declared vars-def) + (append glob iglo))) (vars (delete-duplicates (append! locals-declared locals-implicit))) (all-vars (append vars vars-def)) (need-rename? @@ -2551,26 +2551,22 @@ (renamed (map named-gensy need-rename)) (renamed-def (map named-gensy need-rename-def)) (new-env (append all-vars glob env)) ;; all variables declared in or outside blok - (new-iglo-table ;; initial list of implicit globals from outside blok which aren't part of the local vars - (let ((tab (table))) - (for-each (lambda (v) (if (not (memq v all-vars)) (put! tab v #t))) iglo) - (for-each (lambda (v) (if (not (memq v all-vars)) (put! tab v #t))) implicitglobals) - tab)) - (new-iglo (table.keys ;; compute list of all globals used implicitly in blok - (unbound-vars blok - new-env ;; list of everything else - new-iglo-table))) + ;; compute list of all globals used implicitly in blok (need renames) + (new-iglo (table.keys (unbound-vars blok + new-env ;; list of everything else + (table)))) ;; combine the list of new renamings with the inherited list (new-renames (append (map cons need-rename renamed) ;; map from definition name -> gensym name (map cons need-rename-def renamed-def) (map (lambda (g) (cons g `(outerref ,g))) new-iglo) (filter (lambda (ren) ;; old renames list, with anything in vars removed - (not (or (memq (car ren) all-vars) - (memq (car ren) iglo) - (memq (car ren) implicitglobals) - (memq (car ren) glob)))) + (let ((var (car ren))) + (not (or (memq var all-vars) ;; remove anything new + (memq var implicitglobals) ;; remove anything only added implicitly in the last scope block + (memq var glob))))) ;; remove anything that's now global renames))) - (body (resolve-scopes- blok new-env new-iglo lam new-renames #f)) + (new-oglo (append iglo outerglobals)) ;; list of all outer-globals from outside blok + (body (resolve-scopes- blok new-env new-oglo new-iglo lam new-renames #f)) (real-new-vars (append (diff vars need-rename) renamed)) (real-new-vars-def (append (diff vars-def need-rename-def) renamed-def))) (for-each (lambda (v) @@ -2590,18 +2586,18 @@ (error "module expression not at top level")) ((eq? (car e) 'break-block) `(break-block ,(cadr e) ;; ignore type symbol of break-block expression - ,(resolve-scopes- (caddr e) env implicitglobals lam renames #f))) ;; body of break-block expression + ,(resolve-scopes- (caddr e) env outerglobals implicitglobals lam renames #f))) ;; body of break-block expression ((eq? (car e) 'with-static-parameters) `(with-static-parameters ;; ignore list of sparams in break-block expression - ,(resolve-scopes- (cadr e) env implicitglobals lam renames #f) + ,(resolve-scopes- (cadr e) env outerglobals implicitglobals lam renames #f) ,@(cddr e))) ;; body of break-block expression (else (cons (car e) (map (lambda (x) - (resolve-scopes- x env implicitglobals lam renames #f)) + (resolve-scopes- x env outerglobals implicitglobals lam renames #f)) (cdr e)))))) -(define (resolve-scopes e) (resolve-scopes- e '() '() #f '() #f)) +(define (resolve-scopes e) (resolve-scopes- e '() '() '() #f '() #f)) ;; pass 3: analyze variables diff --git a/test/core.jl b/test/core.jl index b58b3c1169e3e8..37afe6c68fb26a 100644 --- a/test/core.jl +++ b/test/core.jl @@ -438,16 +438,27 @@ glotest() @test loc_x == 10 # issue #7234 +f7234_cnt = 0 begin glob_x2 = 24 - f7234_a() = (glob_x2 += 1) + function f7234_a() + global f7234_cnt += 1 + glob_x2 += 1 + global f7234_cnt += -10000 + end end @test_throws UndefVarError f7234_a() +@test f7234_cnt == 1 begin global glob_x2 = 24 - f7234_b() = (glob_x2 += 1) + function f7234_b() + global f7234_cnt += 1 + glob_x2 += 1 + global f7235_cnt += -10000 + end end @test_throws UndefVarError f7234_b() +@test f7234_cnt == 2 # existing globals can be inherited by non-function blocks for i = 1:2 glob_x2 += 1 @@ -486,16 +497,23 @@ end @test h19333() == 4 # let - new variables, including undefinedness +let_undef_cnt = 0 function let_undef() first = true for i = 1:2 - let x - if first; x=1; first=false; end - x+1 + let x # new x + if first # not defined on second pass + x = 1 + first = false + end + global let_undef_cnt += 1 + x + 1 + global let_undef_cnt += 23 end end end @test_throws UndefVarError let_undef() +@test let_undef_cnt == 25 # const implies local in a local scope block function const_implies_local() @@ -521,6 +539,56 @@ end @test a[2](10) == 12 @test a[3](10) == 13 +# issue #21900 +f21900_cnt = 0 +function f21900() + for i = 1:1 + x = 0 + end + global f21900_cnt += 1 + x + global f21900_cnt += -1000 + nothing +end +@test_throws UndefVarError f21900() +@test f21900_cnt == 1 + +@test_throws UndefVarError @eval begin + for i21900 = 1:10 + for j21900 = 1:10 + foo21900 = 10 + end + bar21900 = 0 + bar21900 = foo21900 + 1 + end +end +@test !isdefined(:foo21900) +@test !isdefined(:bar21900) +bar21900 = 0 +@test_throws UndefVarError @eval begin + for i21900 = 1:10 + for j21900 = 1:10 + foo21900 = 10 + end + bar21900 = -1 + bar21900 = foo21900 + 1 + end +end +@test bar21900 == -1 +@test !isdefined(:foo21900) +foo21900 = 0 +@test nothing === @eval begin + for i21900 = 1:10 + for j21900 = 1:10 + foo21900 = 10 + end + bar21900 = -1 + bar21900 = foo21900 + 1 + end +end +@test foo21900 == 10 +@test bar21900 == 11 + # ? syntax @test (true ? 1 : false ? 2 : 3) == 1 diff --git a/test/libgit2.jl b/test/libgit2.jl index f179825ae3fda7..18d0137a63555a 100644 --- a/test/libgit2.jl +++ b/test/libgit2.jl @@ -1628,6 +1628,7 @@ mktempdir() do dir loopback = ip"127.0.0.1" for hostname in hostnames + local addr try addr = getaddrinfo(hostname) catch From 53ea47e7e3f82812a81635fe9aadb774c43ca458 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 26 May 2017 02:03:40 +0200 Subject: [PATCH 11/53] check that reinterp on vector of tuples doesnt segfault --- test/inference.jl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/inference.jl b/test/inference.jl index bdcabb2ff7a72f..50ef73ede078b7 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -776,3 +776,15 @@ function break_21369() end end @test_throws ErrorException break_21369() # not TypeError + + +function segfaultfunction_20847{N, T}(A::Vector{NTuple{N, T}}) + B = reinterpret(T, A, (N, length(A))) + return nothing +end + +tuplevec_20847 = Tuple{Float64, Float64}[(0.0,0.0), (1.0,0.0)] + +for A in (1,) + @test segfaultfunction_20847(tuplevec_20847) == nothing +end From 03639b9be834e79880b4a6a3e61f95a4c677f8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= Date: Fri, 26 May 2017 19:37:05 +0200 Subject: [PATCH 12/53] Fix complex exp2 and exp10 with boolean and irrational argument (#21874) Fix #21200. --- base/complex.jl | 6 ++++-- test/complex.jl | 11 ++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/base/complex.jl b/base/complex.jl index 836253b1d65fa6..9d6c49eb870ab5 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -603,19 +603,21 @@ function ^(z::Complex{T}, p::Complex{T})::Complex{T} where T<:AbstractFloat end end -function exp2(z::Complex{T}) where T +function exp2(z::Complex{T}) where T<:AbstractFloat er = exp2(real(z)) theta = imag(z) * log(convert(T, 2)) s, c = sincos(theta) Complex(er * c, er * s) end +exp2(z::Complex) = exp2(float(z)) -function exp10(z::Complex{T}) where T +function exp10(z::Complex{T}) where T<:AbstractFloat er = exp10(real(z)) theta = imag(z) * log(convert(T, 10)) s, c = sincos(theta) Complex(er * c, er * s) end +exp10(z::Complex) = exp10(float(z)) function ^(z::T, p::T) where T<:Complex if isinteger(p) diff --git a/test/complex.jl b/test/complex.jl index 3aa4dd02d25b75..161222835a6869 100644 --- a/test/complex.jl +++ b/test/complex.jl @@ -883,6 +883,7 @@ end @test exp2(1.0+0.0im) == 2.0+0.0im #wolframalpha @test exp2(1.0+3.0im) ≈ -0.9739888359315627962096198412+1.74681016354974281701922im + @test exp2(im) ≈ 0.7692389013639721 + 0.6389612763136348im end @testset "exp10" begin @@ -890,6 +891,7 @@ end @test exp10(1.0+0.0im) == 10.0+0.0im #wolframalpha @test exp10(1.0+2.0im) ≈ -1.0701348355877020772086517528518239460495529361-9.9425756941378968736161937190915602112878340717im + @test exp10(im) ≈ -0.6682015101903132 + 0.7439803369574931im end @testset "round and float, PR #8291" begin @@ -946,9 +948,12 @@ end @testset "Complex Irrationals, issue #21204" begin for x in (pi, e, catalan) # No need to test all of them - @test typeof(Complex(x, x)) == Complex{typeof(x)} - @test exp(complex(x, x)) ≈ exp(x) * cis(x) - @test log1p(complex(x, x)) ≈ log(1 + complex(x, x)) + z = Complex(x, x) + @test typeof(z) == Complex{typeof(x)} + @test exp(z) ≈ exp(x) * cis(x) + @test log1p(z) ≈ log(1 + z) + @test exp2(z) ≈ exp(z * log(2)) + @test exp10(z) ≈ exp(z * log(10)) end end From b1b01b56a28b0a7d6bcd0d8a4b00aba466fc52e6 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Fri, 26 May 2017 21:02:10 +0200 Subject: [PATCH 13/53] improve docs for mktempdir (#22078) --- base/file.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/base/file.jl b/base/file.jl index b344e264b79ecd..b9e85066eaaaae 100644 --- a/base/file.jl +++ b/base/file.jl @@ -359,6 +359,7 @@ mktemp(parent) mktempdir(parent=tempdir()) Create a temporary directory in the `parent` directory and return its path. +If `parent` does not exist, throw an error. """ mktempdir(parent) @@ -366,7 +367,8 @@ mktempdir(parent) """ mktemp(f::Function, parent=tempdir()) -Apply the function `f` to the result of `mktemp(parent)` and remove the temporary file upon completion. +Apply the function `f` to the result of [`mktemp(parent)`](@ref) and remove the +temporary file upon completion. """ function mktemp(fn::Function, parent=tempdir()) (tmp_path, tmp_io) = mktemp(parent) @@ -381,8 +383,8 @@ end """ mktempdir(f::Function, parent=tempdir()) -Apply the function `f` to the result of `mktempdir(parent)` and remove the temporary -directory upon completion. +Apply the function `f` to the result of [`mktempdir(parent)`](@ref) and remove the +temporary directory upon completion. """ function mktempdir(fn::Function, parent=tempdir()) tmpdir = mktempdir(parent) From 6071f1a02e995132a2ca67d0ca0f3bacc09f8964 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 26 May 2017 21:33:06 +0200 Subject: [PATCH 14/53] test 0 dim array constructor (#22080) --- test/arrayops.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/arrayops.jl b/test/arrayops.jl index 8b5e6d559af9fd..480ebca4d89c14 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -2146,3 +2146,6 @@ end Base.:*(a::T11053, b::Real) = T11053(a.a*b) Base.:(==)(a::T11053, b::T11053) = a.a == b.a @test [T11053(1)] * 5 == [T11053(1)] .* 5 == [T11053(5.0)] + +#15907 +@test typeof(Array{Int,0}()) == Array{Int,0} From 64cb7e087c795474a8beba3352affa78fae9a6cd Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 26 May 2017 22:44:27 +0200 Subject: [PATCH 15/53] add test for foldr on one element range (#22085) --- test/reduce.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/reduce.jl b/test/reduce.jl index 74a4c72eee0301..cf89d564262f8f 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -362,3 +362,6 @@ end test18695(r) = sum( t^2 for t in r ) @test @inferred(test18695([1.0,2.0,3.0,4.0])) == 30.0 @test_throws ArgumentError test18695(Any[]) + +# issue #21107 +@test foldr(-,2:2) == 2 From 8c19eec243b6fc9f816f48b3c8061ea33279ad3a Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 26 May 2017 23:34:19 +0200 Subject: [PATCH 16/53] add test for code that used to crash, #17003 (#22081) --- test/inference.jl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/inference.jl b/test/inference.jl index b1a4a3b55e3582..a1d8501efc203f 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -778,6 +778,25 @@ function break_21369() end @test_throws ErrorException break_21369() # not TypeError +# issue #17003 +abstract type AArray_17003{T,N} end +AVector_17003{T} = AArray_17003{T,1} + +struct Nable_17003{T} +end + +struct NArray_17003{T,N} <: AArray_17003{Nable_17003{T},N} +end + +(::Type{NArray_17003}){T,N}(::Array{T,N}) = NArray_17003{T,N}() + +gl_17003 = [1, 2, 3] + +f2_17003(item::AVector_17003) = nothing +f2_17003(::Any) = f2_17003(NArray_17003(gl_17003)) + +@test f2_17003(1) == nothing + # issue #20847 function segfaultfunction_20847{N, T}(A::Vector{NTuple{N, T}}) B = reinterpret(T, A, (N, length(A))) From c3fb8e77cc7747178c1c82551da4f045e8f55921 Mon Sep 17 00:00:00 2001 From: Douglas Bates Date: Fri, 26 May 2017 16:37:20 -0500 Subject: [PATCH 17/53] Remove redundant calls to size (#22086) The values of `p` and `q` are not used in these two methods --- base/linalg/matmul.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/base/linalg/matmul.jl b/base/linalg/matmul.jl index 94a6cb0b7e0a8f..0fce02cbb699fb 100644 --- a/base/linalg/matmul.jl +++ b/base/linalg/matmul.jl @@ -7,7 +7,6 @@ matprod(x, y) = x*y + x*y # multiply by diagonal matrix as vector function scale!(C::AbstractMatrix, A::AbstractMatrix, b::AbstractVector) m, n = size(A) - p, q = size(C) if size(A) != size(C) throw(DimensionMismatch("size of A, $(size(A)), does not match size of C, $(size(C))")) end @@ -25,7 +24,6 @@ end function scale!(C::AbstractMatrix, b::AbstractVector, A::AbstractMatrix) m, n = size(A) - p, q = size(C) if size(A) != size(C) throw(DimensionMismatch("size of A, $(size(A)), does not match size of C, $(size(C))")) end From 85907b0094febaf35c3a97f4d4006c1d7dd50254 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 27 May 2017 01:28:11 +0200 Subject: [PATCH 18/53] add test for code_typed on generated function (#22084) --- test/inference.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/inference.jl b/test/inference.jl index a1d8501efc203f..c03636fb26198d 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -819,3 +819,12 @@ let T = Tuple{Tuple{Int64, Void}, @test Core.Inference.limit_type_depth(T, 1) >: T @test Core.Inference.limit_type_depth(T, 2) >: T end + +# Issue #20902, check that this doesn't error. +@generated function test_20902() + quote + 10 + 11 + end +end +@test length(code_typed(test_20902, (), optimize = false)) == 1 +@test length(code_typed(test_20902, (), optimize = false)) == 1 From 7a05f686a27d9e070efb523b51420f90d9310e43 Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Sat, 27 May 2017 02:51:51 -0500 Subject: [PATCH 19/53] Clarify stored and nonzero values for sparse arrays (#22091) Closes #13427. --- doc/src/manual/arrays.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/src/manual/arrays.md b/doc/src/manual/arrays.md index e9d75f86440725..53aae9054dd262 100644 --- a/doc/src/manual/arrays.md +++ b/doc/src/manual/arrays.md @@ -712,7 +712,7 @@ gains in either time or space when compared to performing the same operations on ### Compressed Sparse Column (CSC) Storage In Julia, sparse matrices are stored in the [Compressed Sparse Column (CSC) format](https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_column_.28CSC_or_CCS.29). -Julia sparse matrices have the type `SparseMatrixCSC{Tv,Ti}`, where `Tv` is the type of the nonzero +Julia sparse matrices have the type `SparseMatrixCSC{Tv,Ti}`, where `Tv` is the type of the stored values, and `Ti` is the integer type for storing column pointers and row indices.: ```julia @@ -720,8 +720,8 @@ struct SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti} m::Int # Number of rows n::Int # Number of columns colptr::Vector{Ti} # Column i is in colptr[i]:(colptr[i+1]-1) - rowval::Vector{Ti} # Row values of nonzeros - nzval::Vector{Tv} # Nonzero values + rowval::Vector{Ti} # Row indices of stored values + nzval::Vector{Tv} # Stored values, typically nonzeros end ``` @@ -765,7 +765,7 @@ julia> speye(3,5) ``` The [`sparse()`](@ref) function is often a handy way to construct sparse matrices. It takes as -its input a vector `I` of row indices, a vector `J` of column indices, and a vector `V` of nonzero +its input a vector `I` of row indices, a vector `J` of column indices, and a vector `V` of stored values. `sparse(I,J,V)` constructs a sparse matrix such that `S[I[k], J[k]] = V[k]`. ```jldoctest sparse_function From 71d14aeaec85f7fc5c7c356378a361dd37eeeeaa Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Sat, 27 May 2017 08:28:13 -0500 Subject: [PATCH 20/53] Test inferability of xcorr with views (#22093) Fix #17351. --- test/subarray.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/subarray.jl b/test/subarray.jl index fb2d8d8300017a..45d31b6fe3ecdf 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -555,3 +555,11 @@ let @test Base.IndexStyle(view(a, :, :)) == Base.IndexLinear() @test isbits(view(a, :, :)) end + +# Issue #17351 +let + x = rand(10) + u = rand(10, 3) + su = view(u, :, 1) + @test size(@inferred(xcorr(x, su))) == (19,) +end From f67f58e525f7b11517e6f77135a767e3a38f2f4d Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Sun, 28 May 2017 00:47:16 +0200 Subject: [PATCH 21/53] add AbstractArray to stdlib (#22059) * add AbstractArray to stdlib and moved constructors to the top * add some references --- doc/src/devdocs/offset-arrays.md | 2 +- doc/src/devdocs/subarrays.md | 2 +- doc/src/devdocs/types.md | 2 +- doc/src/manual/arrays.md | 2 +- doc/src/manual/interfaces.md | 2 +- doc/src/stdlib/arrays.md | 43 ++++++++++++++++---------------- doc/src/stdlib/collections.md | 6 ++--- 7 files changed, 30 insertions(+), 29 deletions(-) diff --git a/doc/src/devdocs/offset-arrays.md b/doc/src/devdocs/offset-arrays.md index 443473d16a61d5..9951c72231de9d 100644 --- a/doc/src/devdocs/offset-arrays.md +++ b/doc/src/devdocs/offset-arrays.md @@ -59,7 +59,7 @@ the ranges may not start at 1. If you just want the range for a particular dime is `indices(A, d)`. Base implements a custom range type, `OneTo`, where `OneTo(n)` means the same thing as `1:n` but -in a form that guarantees (via the type system) that the lower index is 1. For any new `AbstractArray` +in a form that guarantees (via the type system) that the lower index is 1. For any new [`AbstractArray`](@ref) type, this is the default returned by `indices`, and it indicates that this array type uses "conventional" 1-based indexing. Note that if you don't want to be bothered supporting arrays with non-1 indexing, you can add the following line: diff --git a/doc/src/devdocs/subarrays.md b/doc/src/devdocs/subarrays.md index 469907cd8fea1b..16a11c39cf7e3a 100644 --- a/doc/src/devdocs/subarrays.md +++ b/doc/src/devdocs/subarrays.md @@ -1,6 +1,6 @@ # SubArrays -Julia's `SubArray` type is a container encoding a "view" of a parent `AbstractArray`. This page +Julia's `SubArray` type is a container encoding a "view" of a parent [`AbstractArray`](@ref). This page documents some of the design principles and implementation of `SubArray`s. ## Indexing: cartesian vs. linear indexing diff --git a/doc/src/devdocs/types.md b/doc/src/devdocs/types.md index 63a274c61f74b5..44a1a7480e4c50 100644 --- a/doc/src/devdocs/types.md +++ b/doc/src/devdocs/types.md @@ -433,7 +433,7 @@ When we are done evaluating the body of a `UnionAll` type whose variable is diag we look at the final values of the bounds. Since the variable must be concrete, a contradiction occurs if its lower bound could not be a subtype of a concrete type. -For example, an abstract type like `AbstractArray` cannot be a subtype of a concrete +For example, an abstract type like [`AbstractArray`](@ref) cannot be a subtype of a concrete type, but a concrete type like `Int` can be, and the empty type `Bottom` can be as well. If a lower bound fails this test the algorithm stops with the answer `false`. diff --git a/doc/src/manual/arrays.md b/doc/src/manual/arrays.md index 53aae9054dd262..757ac1f384a774 100644 --- a/doc/src/manual/arrays.md +++ b/doc/src/manual/arrays.md @@ -510,7 +510,7 @@ iterate over any array type. ### Array traits -If you write a custom `AbstractArray` type, you can specify that it has fast linear indexing using +If you write a custom [`AbstractArray`](@ref) type, you can specify that it has fast linear indexing using ```julia Base.IndexStyle(::Type{<:MyArray}) = IndexLinear() diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index fd7b5cba85501e..91ae4fbe21e570 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -187,7 +187,7 @@ julia> Squares(10)[[3,4.,5]] While this is starting to support more of the [indexing operations supported by some of the builtin types](@ref man-array-indexing), there's still quite a number of behaviors missing. This `Squares` sequence is starting to look more and more like a vector as we've added behaviors to it. Instead of defining all these behaviors -ourselves, we can officially define it as a subtype of an `AbstractArray`. +ourselves, we can officially define it as a subtype of an [`AbstractArray`](@ref). ## [Abstract Arrays](@id man-interface-array) diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index cb3468061dbc40..2fc43f52bee532 100644 --- a/doc/src/stdlib/arrays.md +++ b/doc/src/stdlib/arrays.md @@ -1,28 +1,9 @@ # [Arrays](@id lib-arrays) -## Basic functions - -```@docs -Base.ndims -Base.size -Base.indices(::Any) -Base.indices(::AbstractArray, ::Any) -Base.length(::AbstractArray) -Base.eachindex -Base.linearindices -Base.IndexStyle -Base.countnz -Base.conj! -Base.stride -Base.strides -Base.ind2sub -Base.sub2ind -Base.LinAlg.checksquare -``` - -## Constructors +## Constructors and Types ```@docs +Core.AbstractArray Core.Array Base.getindex(::Type, ::Any...) Base.zeros @@ -41,6 +22,26 @@ Base.Random.randsubseq Base.Random.randsubseq! ``` +## Basic functions + +```@docs +Base.ndims +Base.size +Base.indices(::Any) +Base.indices(::AbstractArray, ::Any) +Base.length(::AbstractArray) +Base.eachindex +Base.linearindices +Base.IndexStyle +Base.countnz +Base.conj! +Base.stride +Base.strides +Base.ind2sub +Base.sub2ind +Base.LinAlg.checksquare +``` + ## Broadcast and vectorization See also the [dot syntax for vectorizing functions](@ref man-vectorized); diff --git a/doc/src/stdlib/collections.md b/doc/src/stdlib/collections.md index 29d8c38f3b1a8e..1ab225a8542088 100644 --- a/doc/src/stdlib/collections.md +++ b/doc/src/stdlib/collections.md @@ -39,7 +39,7 @@ Fully implemented by: * `UnitRange` * `Tuple` * `Number` - * `AbstractArray` + * [`AbstractArray`](@ref) * [`IntSet`](@ref) * [`ObjectIdDict`](@ref) * [`Dict`](@ref) @@ -63,7 +63,7 @@ Fully implemented by: * `UnitRange` * `Tuple` * `Number` - * `AbstractArray` + * [`AbstractArray`](@ref) * [`IntSet`](@ref) * [`ObjectIdDict`](@ref) * [`Dict`](@ref) @@ -145,7 +145,7 @@ Fully implemented by: * [`Array`](@ref) * [`BitArray`](@ref) - * `AbstractArray` + * [`AbstractArray`](@ref) * `SubArray` * [`ObjectIdDict`](@ref) * [`Dict`](@ref) From 82e96382251a1e163860df03c846acec86d07c36 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sun, 28 May 2017 03:51:40 +0200 Subject: [PATCH 22/53] add test for #19805, cfunction segfault (#22079) --- test/ccall.jl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/ccall.jl b/test/ccall.jl index ad97132813279e..204a40c6080f35 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -1265,3 +1265,15 @@ end (::CallableSingleton)(x, y) = x + y @test ccall(cfunction(CallableSingleton(), Int, Tuple{Int,Int}), Int, (Int, Int), 1, 2) === 3 + +# 19805 +mutable struct callinfos_19805{FUNC_FT<:Function} + f :: FUNC_FT +end + +evalf_callback_19805{FUNC_FT}(ci::callinfos_19805{FUNC_FT}) = ci.f(0.5)::Float64 + +evalf_callback_c_19805{FUNC_FT}(ci::callinfos_19805{FUNC_FT}) = cfunction( + evalf_callback_19805, Float64, (callinfos_19805{FUNC_FT},)) + +@test_throws ErrorException evalf_callback_c_19805( callinfos_19805(sin) ) From f5ed68fbad3ffcd4ef9710dff21e28d623bd9d8b Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Sun, 28 May 2017 14:41:59 +0200 Subject: [PATCH 23/53] Document number types (#22067) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * document π, e, γ and φ * add type-documentation for number types - replace the uninformative list in doc/src/stdlib/numbers.md with these new docstrings - move constructor docstring for BigInt from helpdb/Base.jl to base/gmp.jl - add a doctest for BigInt constructor * add supertypes to number type docs * move irrational to concrete types --- base/complex.jl | 8 ++++ base/docs/helpdb/Base.jl | 94 +++++++++++++++++++++++++++++++++------ base/gmp.jl | 24 ++++++++++ base/irrationals.jl | 13 ++++-- base/mpfr.jl | 39 +++++++++------- base/rational.jl | 5 +++ doc/src/stdlib/numbers.md | 58 +++++++++++++++--------- 7 files changed, 187 insertions(+), 54 deletions(-) diff --git a/base/complex.jl b/base/complex.jl index 9d6c49eb870ab5..237918f122f11d 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -1,5 +1,13 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +""" + Complex{T<:Real} <: Number + +Complex number type with real and imaginary part of type `T`. + +`Complex32`, `Complex64` and `Complex128` are aliases for +`Complex{Float16}`, `Complex{Float32}` and `Complex{Float64}` respectively. +""" struct Complex{T<:Real} <: Number re::T im::T diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index ac2f43e33778e3..d0e408c4cff3e0 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -229,7 +229,7 @@ julia> Float32(1/3, RoundUp) See [`RoundingMode`](@ref) for available rounding modes. """ -Float32 +Float32(x) """ Mmap.mmap(io::Union{IOStream,AbstractString,Mmap.AnonymousMmap}[, type::Type{Array{T,N}}, dims, offset]; grow::Bool=true, shared::Bool=true) @@ -814,7 +814,7 @@ julia> Float64(pi, RoundUp) See [`RoundingMode`](@ref) for available rounding modes. """ -Float64 +Float64(x) """ union(s1,s2...) @@ -1431,18 +1431,6 @@ recurses infinitely. """ StackOverflowError -""" - BigInt(x) - -Create an arbitrary precision integer. `x` may be an `Int` (or anything that can be -converted to an `Int`). The usual mathematical operators are defined for this type, and -results are promoted to a `BigInt`. - -Instances can be constructed from strings via [`parse`](@ref), or using the `big` -string literal. -""" -BigInt - """ ==(x, y) @@ -2414,3 +2402,81 @@ seekend Integer division was attempted with a denominator value of 0. """ DivideError + +""" + Number + +Abstract supertype for all number types. +""" +Number + +""" + Real <: Number + +Abstract supertype for all real numbers. +""" +Real + +""" + AbstractFloat <: Real + +Abstract supertype for all floating point numbers. +""" +AbstractFloat + +""" + Integer <: Real + +Abstract supertype for all integers. +""" +Integer + +""" + Signed <: Integer + +Abstract supertype for all signed integers. +""" +Signed + +""" + Unsigned <: Integer + +Abstract supertype for all unsigned integers. +""" +Unsigned + +""" + Bool <: Integer + +Boolean type. +""" +Bool + +for bit in (16, 32, 64) + @eval begin + """ + Float$($bit) <: AbstractFloat + + $($bit)-bit floating point number type. + """ + $(Symbol("Float", bit)) + end +end + +for bit in (8, 16, 32, 64, 128) + @eval begin + """ + Int$($bit) <: Signed + + $($bit)-bit signed integer type. + """ + $(Symbol("Int", bit)) + + """ + UInt$($bit) <: Unsigned + + $($bit)-bit unsigned integer type. + """ + $(Symbol("UInt", bit)) + end +end diff --git a/base/gmp.jl b/base/gmp.jl index 2e7c667b07d3b6..b78132e4b48562 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -37,7 +37,11 @@ else error("GMP: cannot determine the type mp_limb_t (__gmp_bits_per_limb == $GMP_BITS_PER_LIMB)") end +""" + BigInt <: Integer +Arbitrary precision integer type. +""" mutable struct BigInt <: Integer alloc::Cint size::Cint @@ -50,6 +54,26 @@ mutable struct BigInt <: Integer end end +""" + BigInt(x) + +Create an arbitrary precision integer. `x` may be an `Int` (or anything that can be +converted to an `Int`). The usual mathematical operators are defined for this type, and +results are promoted to a `BigInt`. + +Instances can be constructed from strings via [`parse`](@ref), or using the `big` +string literal. + +```jldoctest +julia> parse(BigInt, "42") +42 + +julia> big"313" +313 +``` +""" +BigInt(x) + function __init__() try if gmp_version().major != GMP_VERSION.major || gmp_bits_per_limb() != GMP_BITS_PER_LIMB diff --git a/base/irrationals.jl b/base/irrationals.jl index d2d76abbc0df07..91d56999474a2e 100644 --- a/base/irrationals.jl +++ b/base/irrationals.jl @@ -2,6 +2,11 @@ ## general machinery for irrational mathematical constants +""" + Irrational <: Real + +Irrational number type. +""" struct Irrational{sym} <: Real end show(io::IO, x::Irrational{sym}) where {sym} = print(io, "$sym = $(string(float(x))[1:15])...") @@ -156,7 +161,7 @@ julia> pi π = 3.1415926535897... ``` """ -const pi = π +π, const pi = π """ e @@ -169,7 +174,7 @@ julia> e e = 2.7182818284590... ``` """ -const eu = e +e, const eu = e """ γ @@ -182,7 +187,7 @@ julia> eulergamma γ = 0.5772156649015... ``` """ -const eulergamma = γ +γ, const eulergamma = γ """ φ @@ -195,7 +200,7 @@ julia> golden φ = 1.6180339887498... ``` """ -const golden = φ +φ, const golden = φ """ catalan diff --git a/base/mpfr.jl b/base/mpfr.jl index 4855ca49096785..4f04480babb692 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -43,23 +43,9 @@ const DEFAULT_PRECISION = [256] # Basic type and initialization definitions """ - BigFloat(x) - -Create an arbitrary precision floating point number. `x` may be an `Integer`, a `Float64` or -a `BigInt`. The usual mathematical operators are defined for this type, and results are -promoted to a `BigFloat`. - -Note that because decimal literals are converted to floating point numbers when parsed, -`BigFloat(2.1)` may not yield what you expect. You may instead prefer to initialize -constants from strings via [`parse`](@ref), or using the `big` string literal. + BigFloat <: AbstractFloat -```jldoctest -julia> BigFloat(2.1) -2.100000000000000088817841970012523233890533447265625000000000000000000000000000 - -julia> big"2.1" -2.099999999999999999999999999999999999999999999999999999999999999999999999999986 -``` +Arbitrary precision floating point number type. """ mutable struct BigFloat <: AbstractFloat prec::Clong @@ -81,6 +67,27 @@ mutable struct BigFloat <: AbstractFloat end end +""" + BigFloat(x) + +Create an arbitrary precision floating point number. `x` may be an `Integer`, a `Float64` or +a `BigInt`. The usual mathematical operators are defined for this type, and results are +promoted to a `BigFloat`. + +Note that because decimal literals are converted to floating point numbers when parsed, +`BigFloat(2.1)` may not yield what you expect. You may instead prefer to initialize +constants from strings via [`parse`](@ref), or using the `big` string literal. + +```jldoctest +julia> BigFloat(2.1) +2.100000000000000088817841970012523233890533447265625000000000000000000000000000 + +julia> big"2.1" +2.099999999999999999999999999999999999999999999999999999999999999999999999999986 +``` +""" +BigFloat(x) + widen(::Type{Float64}) = BigFloat widen(::Type{BigFloat}) = BigFloat diff --git a/base/rational.jl b/base/rational.jl index 611d7ca5e3252e..1fe97049be83fd 100644 --- a/base/rational.jl +++ b/base/rational.jl @@ -1,5 +1,10 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +""" + Rational{T<:Integer} <: Real + +Rational number type, with numerator and denominator of type `T`. +""" struct Rational{T<:Integer} <: Real num::T den::T diff --git a/doc/src/stdlib/numbers.md b/doc/src/stdlib/numbers.md index 36ee7e5634d2ff..df3a4f63ce6371 100644 --- a/doc/src/stdlib/numbers.md +++ b/doc/src/stdlib/numbers.md @@ -2,22 +2,40 @@ ## Standard Numeric Types - * `Bool` - * `Int8` - * `UInt8` - * `Int16` - * `UInt16` - * `Int32` - * `UInt32` - * `Int64` - * `UInt64` - * `Int128` - * `UInt128` - * `Float16` - * `Float32` - * `Float64` - * `Complex64` - * `Complex128` +### Abstract number types + +```@docs +Core.Number +Core.Real +Core.AbstractFloat +Core.Integer +Core.Signed +Core.Unsigned +``` + +### Concrete number types + +```@docs +Core.Float16 +Core.Float32 +Core.Float64 +Base.BigFloat +Core.Bool +Core.Int8 +Core.UInt8 +Core.Int16 +Core.UInt16 +Core.Int32 +Core.UInt32 +Core.Int64 +Core.UInt64 +Core.Int128 +Core.UInt128 +Base.BigInt +Base.Complex +Base.Rational +Base.Irrational +``` ## Data Formats @@ -73,10 +91,10 @@ Base.nextfloat Base.prevfloat Base.isinteger Base.isreal -Core.Float32 -Core.Float64 -Base.GMP.BigInt -Base.MPFR.BigFloat +Core.Float32(::Any) +Core.Float64(::Any) +Base.GMP.BigInt(::Any) +Base.MPFR.BigFloat(::Any) Base.Rounding.rounding Base.Rounding.setrounding(::Type, ::Any) Base.Rounding.setrounding(::Function, ::Type, ::RoundingMode) From 6b0d54e6cb4272c609489a05bf8404e89befab7e Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Sun, 28 May 2017 14:44:10 +0200 Subject: [PATCH 24/53] undeprecate real and imag for sparse matrices (#22090) make sure aliasing is the same as for AbstracArrays for SparseArray{<:Real} add tests for this add shortcut for conj(SparseArray{<:Complex} which is faster than broadcasting --- base/deprecated.jl | 2 +- base/sparse/sparsematrix.jl | 4 ++++ base/sparse/sparsevector.jl | 5 ++--- test/sparse/sparse.jl | 25 +++++++++++++++++-------- test/sparse/sparsevector.jl | 4 +++- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/base/deprecated.jl b/base/deprecated.jl index e882c3be8481a3..5c844f33d238ea 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -200,7 +200,7 @@ end # Deprecate vectorized unary functions over sparse matrices in favor of compact broadcast syntax (#17265). for f in (:sin, :sinh, :sind, :asin, :asinh, :asind, :tan, :tanh, :tand, :atan, :atanh, :atand, - :sinpi, :cosc, :ceil, :floor, :trunc, :round, :real, :imag, + :sinpi, :cosc, :ceil, :floor, :trunc, :round, :log1p, :expm1, :abs, :abs2, :log, :log2, :log10, :exp, :exp2, :exp10, :sinc, :cospi, :cos, :cosh, :cosd, :acos, :acosd, diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index cee5b355164089..58e363a2e299d2 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -1447,6 +1447,10 @@ sparse(S::UniformScaling, m::Integer, n::Integer=m) = speye_scaled(S.λ, m, n) conj!(A::SparseMatrixCSC) = (@inbounds broadcast!(conj, A.nzval, A.nzval); A) (-)(A::SparseMatrixCSC) = SparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), map(-, A.nzval)) +# the rest of real, conj, imag are handled correctly via AbstractArray methods +conj(A::SparseMatrixCSC{<:Complex}) = + SparseMatrixCSC(A.m, A.n, copy(A.colptr), copy(A.rowval), conj(A.nzval)) +imag(A::SparseMatrixCSC{Tv,Ti}) where {Tv<:Real,Ti} = spzeros(Tv, Ti, A.m, A.n) ## Binary arithmetic and boolean operators (+)(A::SparseMatrixCSC, B::SparseMatrixCSC) = map(+, A, B) diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index 7f915492a2fd31..dd9e19d9bc729b 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -985,7 +985,6 @@ hvcat(rows::Tuple{Vararg{Int}}, xs::_TypedDenseConcatGroup{T}...) where {T} = Ba ### Unary Map # zero-preserving functions (z->z, nz->nz) -conj(x::SparseVector) = SparseVector(length(x), copy(nonzeroinds(x)), conj(nonzeros(x))) -(x::SparseVector) = SparseVector(length(x), copy(nonzeroinds(x)), -(nonzeros(x))) # functions f, such that @@ -1019,9 +1018,9 @@ macro unarymap_nz2z_z2z(op, TF) end) end -real(x::AbstractSparseVector{<:Real}) = x +# the rest of real, conj, imag are handled correctly via AbstractArray methods @unarymap_nz2z_z2z real Complex - +conj(x::SparseVector{<:Complex}) = SparseVector(length(x), copy(nonzeroinds(x)), conj(nonzeros(x))) imag(x::AbstractSparseVector{Tv,Ti}) where {Tv<:Real,Ti<:Integer} = SparseVector(length(x), Ti[], Tv[]) @unarymap_nz2z_z2z imag Complex diff --git a/test/sparse/sparse.jl b/test/sparse/sparse.jl index 43a0c4c3465774..e22c0b7fe1d0dc 100644 --- a/test/sparse/sparse.jl +++ b/test/sparse/sparse.jl @@ -538,10 +538,12 @@ end @test tan.(Afull) == Array(tan.(A)) # should be redundant with sin test @test ceil.(Afull) == Array(ceil.(A)) @test floor.(Afull) == Array(floor.(A)) # should be redundant with ceil test - @test real.(Afull) == Array(real.(A)) - @test imag.(Afull) == Array(imag.(A)) - @test real.(Cfull) == Array(real.(C)) - @test imag.(Cfull) == Array(imag.(C)) + @test real.(Afull) == Array(real.(A)) == Array(real(A)) + @test imag.(Afull) == Array(imag.(A)) == Array(imag(A)) + @test conj.(Afull) == Array(conj.(A)) == Array(conj(A)) + @test real.(Cfull) == Array(real.(C)) == Array(real(C)) + @test imag.(Cfull) == Array(imag.(C)) == Array(imag(C)) + @test conj.(Cfull) == Array(conj.(C)) == Array(conj(C)) # Test representatives of [unary functions that map zeros to zeros and nonzeros to nonzeros] @test expm1.(Afull) == Array(expm1.(A)) @test abs.(Afull) == Array(abs.(A)) @@ -559,12 +561,19 @@ end I = rand(T[1:100;], 2, 2) D = R + I*im S = sparse(D) - @test R == real.(S) - @test I == imag.(S) - @test real.(sparse(R)) == R - @test nnz(imag.(sparse(R))) == 0 + spR = sparse(R) + + @test R == real.(S) == real(S) + @test I == imag.(S) == imag(S) + @test conj(full(S)) == conj.(S) == conj(S) + @test real.(spR) == R + @test nnz(imag.(spR)) == nnz(imag(spR)) == 0 @test abs.(S) == abs.(D) @test abs2.(S) == abs2.(D) + + # test aliasing of real and conj of real valued matrix + @test real(spR) === spR + @test conj(spR) === spR end end diff --git a/test/sparse/sparsevector.jl b/test/sparse/sparsevector.jl index 543b7668160fd3..77024341a19ba5 100644 --- a/test/sparse/sparsevector.jl +++ b/test/sparse/sparsevector.jl @@ -637,14 +637,16 @@ let x = spv_x1, x2 = spv_x2 @test exact_equal(complex.(x2, x), SparseVector(8, [1,2,5,6,7], [3.25+0.0im, 4.0+1.25im, -0.75im, -5.5+3.5im, -6.0+0.0im])) - # real & imag + # real, imag and conj @test real(x) === x @test exact_equal(imag(x), spzeros(Float64, length(x))) + @test conj(x) === x xcp = complex.(x, x2) @test exact_equal(real(xcp), x) @test exact_equal(imag(xcp), x2) + @test exact_equal(conj(xcp), complex.(x, -x2)) end ### Zero-preserving math functions: sparse -> sparse From efca045215eba9bd043f8989d5690d8eef303905 Mon Sep 17 00:00:00 2001 From: Mus M Date: Sun, 28 May 2017 14:27:46 -0400 Subject: [PATCH 25/53] Use the pure Julia exp function for fastmath (#21948) --- base/fastmath.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/fastmath.jl b/base/fastmath.jl index 6eca987d0703b2..a66762c2eb6bb7 100644 --- a/base/fastmath.jl +++ b/base/fastmath.jl @@ -251,7 +251,7 @@ sqrt_fast(x::FloatTypes) = sqrt_llvm_fast(x) const libm = Base.libm_name for f in (:acos, :acosh, :asin, :asinh, :atan, :atanh, :cbrt, :cos, - :cosh, :exp2, :exp, :expm1, :lgamma, :log10, :log1p, :log2, + :cosh, :exp2, :expm1, :lgamma, :log10, :log1p, :log2, :log, :sin, :sinh, :tan, :tanh) f_fast = fast_op[f] @eval begin From 06521f178115539b7ae43d702a975206bf2b6d5c Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Sun, 28 May 2017 22:58:04 +0200 Subject: [PATCH 26/53] printf.jl: add missing import of GMP (#22104) --- base/printf.jl | 2 +- test/printf.jl | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/base/printf.jl b/base/printf.jl index 48ead94958f590..f1f4515d3f7987 100644 --- a/base/printf.jl +++ b/base/printf.jl @@ -1,7 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license module Printf -using Base.Grisu +using Base: Grisu, GMP export @printf, @sprintf ### printf formatter generation ### diff --git a/test/printf.jl b/test/printf.jl index 4a50982aa368bc..89d0a7ee7ddf19 100644 --- a/test/printf.jl +++ b/test/printf.jl @@ -25,8 +25,9 @@ for (fmt, val) in (("%i", "42"), ("%f", "42.000000"), ("%g", "42")), num in (UInt16(42), UInt32(42), UInt64(42), UInt128(42), - Int16(42), Int32(42), Int64(42), Int128(42)) + Int16(42), Int32(42), Int64(42), Int128(42), big"42") #big"42" causes stack overflow on %a ; gh #14409 + num isa BigInt && fmt in ["%a", "%#o", "%g"] && continue @test @eval(@sprintf($fmt, $num) == $val) end From 96e430199b7104134e79a0daffe6c97caca84c90 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Mon, 29 May 2017 06:59:42 +0200 Subject: [PATCH 27/53] Reference all the numbers (#22107) * references for Rational * references for Complex * references for Number * references to Real * references for AbstractFloat * references for Integer * references for Signed * references for Unsigned * references to Bool * references for Float16 * references for Float32 * references for Float64 * references for Int8 * references for UInt8 * references for Int16 * references for UInt16 * references for Int32 * references for UInt32 * references for Int64 * references for UInt64 * references for Int128 * references for UInt128 * references for BigInt * references for BigFloat --- base/Enums.jl | 5 +- base/abstractarray.jl | 2 +- base/array.jl | 4 +- base/c.jl | 2 +- base/ctypes.jl | 22 +-- base/dates/accessors.jl | 17 +-- base/dates/adjusters.jl | 8 +- base/dates/conversions.jl | 4 +- base/dates/periods.jl | 2 +- base/dates/query.jl | 2 +- base/dates/rounding.jl | 4 +- base/dates/types.jl | 8 +- base/docs/basedocs.jl | 4 +- base/docs/helpdb/Base.jl | 22 +-- base/error.jl | 2 +- base/float.jl | 16 +-- base/floatfuncs.jl | 2 +- base/gmp.jl | 4 +- base/linalg/qr.jl | 4 +- base/math.jl | 19 +-- base/mpfr.jl | 18 +-- base/number.jl | 4 +- base/operators.jl | 7 +- base/promotion.jl | 4 +- base/random.jl | 17 +-- base/rational.jl | 4 +- base/reflection.jl | 4 +- base/rounding.jl | 8 +- base/show.jl | 2 +- base/socket.jl | 4 +- base/sparse/sparsematrix.jl | 4 +- base/sparse/umfpack.jl | 6 +- base/special/gamma.jl | 2 +- base/test.jl | 2 +- doc/src/devdocs/offset-arrays.md | 4 +- doc/src/devdocs/reflection.md | 2 +- doc/src/devdocs/types.md | 6 +- doc/src/manual/arrays.md | 4 +- doc/src/manual/calling-c-and-fortran-code.md | 8 +- doc/src/manual/constructors.md | 17 +-- doc/src/manual/control-flow.md | 4 +- doc/src/manual/conversion-and-promotion.md | 31 ++-- doc/src/manual/dates.md | 17 +-- doc/src/manual/documentation.md | 4 +- doc/src/manual/embedding.md | 12 +- doc/src/manual/environment-variables.md | 2 +- doc/src/manual/faq.md | 9 +- .../integers-and-floating-point-numbers.md | 52 +++---- doc/src/manual/mathematical-operations.md | 2 +- doc/src/manual/metaprogramming.md | 2 +- doc/src/manual/methods.md | 28 ++-- doc/src/manual/noteworthy-differences.md | 12 +- doc/src/manual/performance-tips.md | 22 +-- doc/src/manual/strings.md | 8 +- doc/src/manual/style-guide.md | 13 +- doc/src/manual/types.md | 136 ++++++++++-------- doc/src/stdlib/linalg.md | 8 +- doc/src/stdlib/numbers.md | 13 +- 58 files changed, 343 insertions(+), 312 deletions(-) diff --git a/base/Enums.jl b/base/Enums.jl index 9e8a144da1e588..13976a72d8e5fe 100644 --- a/base/Enums.jl +++ b/base/Enums.jl @@ -45,8 +45,9 @@ julia> f(apple) "I'm a Fruit with value: 1" ``` -`BaseType`, which defaults to `Int32`, must be a primitive subtype of Integer. Member values can be converted between -the enum type and `BaseType`. `read` and `write` perform these conversions automatically. +`BaseType`, which defaults to [`Int32`](@ref), must be a primitive subtype of `Integer`. +Member values can be converted between the enum type and `BaseType`. `read` and `write` +perform these conversions automatically. """ macro enum(T,syms...) if isempty(syms) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 440372def4d585..af3bfe47825dd7 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -503,7 +503,7 @@ julia> similar(trues(10,10), 2) false ``` -Since `BitArray`s can only store elements of type `Bool`, however, if you request a +Since `BitArray`s can only store elements of type [`Bool`](@ref), however, if you request a different element type it will create a regular `Array` instead: ```julia-repl diff --git a/base/array.jl b/base/array.jl index a4ae57bd971ae5..80c04a30903dc4 100644 --- a/base/array.jl +++ b/base/array.jl @@ -266,7 +266,7 @@ end eye([T::Type=Float64,] m::Integer, n::Integer) `m`-by-`n` identity matrix. -The default element type is `Float64`. +The default element type is [`Float64`](@ref). """ function eye(::Type{T}, m::Integer, n::Integer) where T a = zeros(T,m,n) @@ -287,7 +287,7 @@ eye(::Type{T}, n::Integer) where {T} = eye(T, n, n) eye([T::Type=Float64,] n::Integer) `n`-by-`n` identity matrix. -The default element type is `Float64`. +The default element type is [`Float64`](@ref). """ eye(n::Integer) = eye(Float64, n) diff --git a/base/c.jl b/base/c.jl index 410bb1e2f153e0..80c58a46406144 100644 --- a/base/c.jl +++ b/base/c.jl @@ -45,7 +45,7 @@ Culong """ Cwchar_t -Equivalent to the native `wchar_t` c-type (`Int32`). +Equivalent to the native `wchar_t` c-type ([`Int32`](@ref)). """ Cwchar_t diff --git a/base/ctypes.jl b/base/ctypes.jl index 387fdd9d8c7ddc..26640ed82bef50 100644 --- a/base/ctypes.jl +++ b/base/ctypes.jl @@ -6,7 +6,7 @@ """ Cuchar -Equivalent to the native `unsigned char` c-type (`UInt8`). +Equivalent to the native `unsigned char` c-type ([`UInt8`](@ref)). """ const Cuchar = UInt8 @@ -14,7 +14,7 @@ const Cuchar = UInt8 """ Cshort -Equivalent to the native `signed short` c-type (`Int16`). +Equivalent to the native `signed short` c-type ([`Int16`](@ref)). """ const Cshort = Int16 @@ -22,7 +22,7 @@ const Cshort = Int16 """ Cushort -Equivalent to the native `unsigned short` c-type (`UInt16`). +Equivalent to the native `unsigned short` c-type ([`UInt16`](@ref)). """ const Cushort = UInt16 @@ -30,7 +30,7 @@ const Cushort = UInt16 """ Cint -Equivalent to the native `signed int` c-type (`Int32`). +Equivalent to the native `signed int` c-type ([`Int32`](@ref)). """ const Cint = Int32 @@ -38,7 +38,7 @@ const Cint = Int32 """ Cuint -Equivalent to the native `unsigned int` c-type (`UInt32`). +Equivalent to the native `unsigned int` c-type ([`UInt32`](@ref)). """ const Cuint = UInt32 @@ -70,7 +70,7 @@ const Cssize_t = Int """ Cintmax_t -Equivalent to the native `intmax_t` c-type (`Int64`). +Equivalent to the native `intmax_t` c-type ([`Int64`](@ref)). """ const Cintmax_t = Int64 @@ -78,7 +78,7 @@ const Cintmax_t = Int64 """ Cuintmax_t -Equivalent to the native `uintmax_t` c-type (`UInt64`). +Equivalent to the native `uintmax_t` c-type ([`UInt64`](@ref)). """ const Cuintmax_t = UInt64 @@ -86,7 +86,7 @@ const Cuintmax_t = UInt64 """ Clonglong -Equivalent to the native `signed long long` c-type (`Int64`). +Equivalent to the native `signed long long` c-type ([`Int64`](@ref)). """ const Clonglong = Int64 @@ -94,7 +94,7 @@ const Clonglong = Int64 """ Culonglong -Equivalent to the native `unsigned long long` c-type (`UInt64`). +Equivalent to the native `unsigned long long` c-type ([`UInt64`](@ref)). """ const Culonglong = UInt64 @@ -102,7 +102,7 @@ const Culonglong = UInt64 """ Cfloat -Equivalent to the native `float` c-type (`Float32`). +Equivalent to the native `float` c-type ([`Float32`](@ref)). """ const Cfloat = Float32 @@ -110,6 +110,6 @@ const Cfloat = Float32 """ Cdouble -Equivalent to the native `double` c-type (`Float64`). +Equivalent to the native `double` c-type ([`Float64`](@ref)). """ const Cdouble = Float64 diff --git a/base/dates/accessors.jl b/base/dates/accessors.jl index d6ca8866430012..27c41d118dfc81 100644 --- a/base/dates/accessors.jl +++ b/base/dates/accessors.jl @@ -74,7 +74,7 @@ for func in (:year, :month) @doc """ $($name)(dt::TimeType) -> Int64 - The $($name) of a `Date` or `DateTime` as an `Int64`. + The $($name) of a `Date` or `DateTime` as an [`Int64`](@ref). """ $func(dt::TimeType) end end @@ -83,9 +83,10 @@ end week(dt::TimeType) -> Int64 Return the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date) of a `Date` or -`DateTime` as an `Int64`. Note that the first week of a year is the week that contains the -first Thursday of the year which can result in dates prior to January 4th being in the last -week of the previous year. For example `week(Date(2005,1,1))` is the 53rd week of 2004. +`DateTime` as an [`Int64`](@ref). Note that the first week of a year is the week that +contains the first Thursday of the year which can result in dates prior to January 4th +being in the last week of the previous year. For example `week(Date(2005,1,1))` is the 53rd +week of 2004. """ week(dt::TimeType) @@ -95,7 +96,7 @@ for func in (:day, :dayofmonth) @doc """ $($name)(dt::TimeType) -> Int64 - The day of month of a `Date` or `DateTime` as an `Int64`. + The day of month of a `Date` or `DateTime` as an [`Int64`](@ref). """ $func(dt::TimeType) end end @@ -103,7 +104,7 @@ end """ hour(dt::DateTime) -> Int64 -The hour of day of a `DateTime` as an `Int64`. +The hour of day of a `DateTime` as an [`Int64`](@ref). """ hour(dt::DateTime) @@ -113,7 +114,7 @@ for func in (:minute, :second, :millisecond) @doc """ $($name)(dt::DateTime) -> Int64 - The $($name) of a `DateTime` as an `Int64`. + The $($name) of a `DateTime` as an [`Int64`](@ref). """ $func(dt::DateTime) end end @@ -137,7 +138,7 @@ for func in (:hour, :minute, :second, :millisecond, :microsecond, :nanosecond) @doc """ $($name)(t::Time) -> Int64 - The $($name) of a `Time` as an `Int64`. + The $($name) of a `Time` as an [`Int64`](@ref). """ $func(t::Time) end end diff --git a/base/dates/adjusters.jl b/base/dates/adjusters.jl index 357faec442a27f..b93236e95bd9e5 100644 --- a/base/dates/adjusters.jl +++ b/base/dates/adjusters.jl @@ -253,8 +253,8 @@ tonext(dt::TimeType, dow::Int; same::Bool=false) = adjust(ISDAYOFWEEK[dow], same tonext(func::Function, dt::TimeType; step=Day(1), limit=10000, same=false) -> TimeType Adjusts `dt` by iterating at most `limit` iterations by `step` increments until `func` -returns `true`. `func` must take a single `TimeType` argument and return a `Bool`. `same` -allows `dt` to be considered in satisfying `func`. +returns `true`. `func` must take a single `TimeType` argument and return a [`Bool`](@ref). +`same` allows `dt` to be considered in satisfying `func`. """ function tonext(func::Function, dt::TimeType; step::Period=Day(1), negate=nothing, limit::Int=10000, same::Bool=false) func = deprecate_negate(:tonext, func, "func,dt", negate) @@ -274,8 +274,8 @@ toprev(dt::TimeType, dow::Int; same::Bool=false) = adjust(ISDAYOFWEEK[dow], same toprev(func::Function, dt::TimeType; step=Day(-1), limit=10000, same=false) -> TimeType Adjusts `dt` by iterating at most `limit` iterations by `step` increments until `func` -returns `true`. `func` must take a single `TimeType` argument and return a `Bool`. `same` -allows `dt` to be considered in satisfying `func`. +returns `true`. `func` must take a single `TimeType` argument and return a [`Bool`](@ref). +`same` allows `dt` to be considered in satisfying `func`. """ function toprev(func::Function, dt::TimeType; step::Period=Day(-1), negate=nothing, limit::Int=10000, same::Bool=false) func = deprecate_negate(:toprev, func, "func,dt", negate) diff --git a/base/dates/conversions.jl b/base/dates/conversions.jl index 9016c5600d149b..853f20b01cc771 100644 --- a/base/dates/conversions.jl +++ b/base/dates/conversions.jl @@ -53,7 +53,7 @@ end datetime2unix(dt::DateTime) -> Float64 Takes the given `DateTime` and returns the number of seconds -since the unix epoch `1970-01-01T00:00:00` as a `Float64`. +since the unix epoch `1970-01-01T00:00:00` as a [`Float64`](@ref). """ datetime2unix(dt::DateTime) = (value(dt) - UNIXEPOCH) / 1000.0 @@ -116,6 +116,6 @@ end datetime2julian(dt::DateTime) -> Float64 Takes the given `DateTime` and returns the number of Julian calendar days since the julian -epoch `-4713-11-24T12:00:00` as a `Float64`. +epoch `-4713-11-24T12:00:00` as a [`Float64`](@ref). """ datetime2julian(dt::DateTime) = (value(dt) - JULIANEPOCH) / 86400000.0 diff --git a/base/dates/periods.jl b/base/dates/periods.jl index 7fbba3d59f86fb..27eafa5774ea16 100644 --- a/base/dates/periods.jl +++ b/base/dates/periods.jl @@ -33,7 +33,7 @@ for period in (:Year, :Month, :Week, :Day, :Hour, :Minute, :Second, :Millisecond $($period_str)(v) Construct a `$($period_str)` object with the given `v` value. Input must be - losslessly convertible to an `Int64`. + losslessly convertible to an [`Int64`](@ref). """ $period(v) end end diff --git a/base/dates/query.jl b/base/dates/query.jl index effdd68a1bbdf7..2e632e239566b8 100644 --- a/base/dates/query.jl +++ b/base/dates/query.jl @@ -101,7 +101,7 @@ dayofyear(y, m, d) = MONTHDAYS[m] + d + (m > 2 && isleapyear(y)) """ dayofweek(dt::TimeType) -> Int64 -Returns the day of the week as an `Int64` with `1 = Monday, 2 = Tuesday, etc.`. +Returns the day of the week as an [`Int64`](@ref) with `1 = Monday, 2 = Tuesday, etc.`. """ dayofweek(dt::TimeType) = dayofweek(days(dt)) diff --git a/base/dates/rounding.jl b/base/dates/rounding.jl index b1714fff075ef3..8adbf80902b57b 100644 --- a/base/dates/rounding.jl +++ b/base/dates/rounding.jl @@ -27,7 +27,7 @@ epochms2datetime(i) = DateTime(UTM(DATETIMEEPOCH + Int64(i))) date2epochdays(dt::Date) -> Int64 Takes the given `Date` and returns the number of days since the rounding epoch -(`0000-01-01T00:00:00`) as an `Int64`. +(`0000-01-01T00:00:00`) as an [`Int64`](@ref). """ date2epochdays(dt::Date) = value(dt) - DATEEPOCH @@ -35,7 +35,7 @@ date2epochdays(dt::Date) = value(dt) - DATEEPOCH datetime2epochms(dt::DateTime) -> Int64 Takes the given `DateTime` and returns the number of milliseconds since the rounding epoch -(`0000-01-01T00:00:00`) as an `Int64`. +(`0000-01-01T00:00:00`) as an [`Int64`](@ref). """ datetime2epochms(dt::DateTime) = value(dt) - DATETIMEEPOCH diff --git a/base/dates/types.jl b/base/dates/types.jl index 87871c9ee9f5ac..12e3e62bf25f22 100644 --- a/base/dates/types.jl +++ b/base/dates/types.jl @@ -47,7 +47,7 @@ end Nanosecond(v) Construct a `Period` type with the given `v` value. Input must be losslessly convertible -to an `Int64`. +to an [`Int64`](@ref). """ Period(v) @@ -173,7 +173,7 @@ argerror() = Nullable{ArgumentError}() """ DateTime(y, [m, d, h, mi, s, ms]) -> DateTime -Construct a `DateTime` type by parts. Arguments must be convertible to `Int64`. +Construct a `DateTime` type by parts. Arguments must be convertible to [`Int64`](@ref). """ function DateTime(y::Int64, m::Int64=1, d::Int64=1, h::Int64=0, mi::Int64=0, s::Int64=0, ms::Int64=0) @@ -197,7 +197,7 @@ end """ Date(y, [m, d]) -> Date -Construct a `Date` type by parts. Arguments must be convertible to `Int64`. +Construct a `Date` type by parts. Arguments must be convertible to [`Int64`](@ref). """ function Date(y::Int64, m::Int64=1, d::Int64=1) err = validargs(Date, y, m, d) @@ -214,7 +214,7 @@ end """ Time(h, [mi, s, ms, us, ns]) -> Time -Construct a `Time` type by parts. Arguments must be convertible to `Int64`. +Construct a `Time` type by parts. Arguments must be convertible to [`Int64`](@ref). """ function Time(h::Int64, mi::Int64=0, s::Int64=0, ms::Int64=0, us::Int64=0, ns::Int64=0) err = validargs(Time, h, mi, s, ms, us, ns) diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 4221f061bfcc33..ece074d231a1ac 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -81,7 +81,7 @@ Julia’s type system more than just a collection of object implementations. For abstract type Number end abstract type Real <: Number end -`Number` has no supertype, whereas `Real` is an abstract subtype of `Number`. +[`Number`](@ref) has no supertype, whereas [`Real`](@ref) is an abstract subtype of `Number`. """ kw"abstract type" @@ -124,7 +124,7 @@ primitive type declarations: The number after the name indicates how many bits of storage the type requires. Currently, only sizes that are multiples of 8 bits are supported. -The `Bool` declaration shows how a primitive type can be optionally +The [`Bool`](@ref) declaration shows how a primitive type can be optionally declared to be a subtype of some supertype. """ kw"primitive type" diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index d0e408c4cff3e0..a3f2530e4fef36 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -243,7 +243,7 @@ determines how the bytes of the array are interpreted. Note that the file must b binary format, and no format conversions are possible (this is a limitation of operating systems, not Julia). -`dims` is a tuple or single `Integer` specifying the size or length of the array. +`dims` is a tuple or single [`Integer`](@ref) specifying the size or length of the array. The file is passed via the stream argument, either as an open `IOStream` or filename string. When you initialize the stream, use `"r"` for a "read-only" array, and `"w+"` to create a @@ -1061,7 +1061,7 @@ For arrays, this constructs an array with the same binary data as the given array, but with the specified element type. For example, `reinterpret(Float32, UInt32(7))` interprets the 4 bytes corresponding to `UInt32(7)` as a -`Float32`. +[`Float32`](@ref). !!! warning @@ -1147,8 +1147,8 @@ searchsortedfirst """ big(x) -Convert a number to a maximum precision representation (typically `BigInt` or `BigFloat`). -See [`BigFloat`](@ref) for information about some pitfalls with floating-point numbers. +Convert a number to a maximum precision representation (typically [`BigInt`](@ref) or +`BigFloat`). See [`BigFloat`](@ref) for information about some pitfalls with floating-point numbers. """ big @@ -1434,10 +1434,10 @@ StackOverflowError """ ==(x, y) -Generic equality operator, giving a single `Bool` result. Falls back to `===`. Should be -implemented for all types with a notion of equality, based on the abstract value that an -instance represents. For example, all numeric types are compared by numeric value, ignoring -type. Strings are compared as sequences of characters, ignoring encoding. +Generic equality operator, giving a single [`Bool`](@ref) result. Falls back to `===`. +Should be implemented for all types with a notion of equality, based on the abstract value +that an instance represents. For example, all numeric types are compared by numeric value, +ignoring type. Strings are compared as sequences of characters, ignoring encoding. Follows IEEE semantics for floating-point numbers. @@ -1934,7 +1934,7 @@ done Convert `x` to a value of type `T`. -If `T` is an `Integer` type, an [`InexactError`](@ref) will be raised if `x` +If `T` is an [`Integer`](@ref) type, an [`InexactError`](@ref) will be raised if `x` is not representable by `T`, for example if `x` is not integer-valued, or is outside the range supported by `T`. @@ -1948,7 +1948,7 @@ Stacktrace: [1] convert(::Type{Int64}, ::Float64) at ./float.jl:680 ``` -If `T` is a `AbstractFloat` or `Rational` type, +If `T` is a [`AbstractFloat`](@ref) or [`Rational`](@ref) type, then it will return the closest value to `x` representable by `T`. ```jldoctest @@ -2160,7 +2160,7 @@ isvalid(value) isvalid(T, value) -> Bool Returns `true` if the given value is valid for that type. Types currently can -be either `Char` or `String`. Values for `Char` can be of type `Char` or `UInt32`. +be either `Char` or `String`. Values for `Char` can be of type `Char` or [`UInt32`](@ref). Values for `String` can be of that type, or `Vector{UInt8}`. """ isvalid(T,value) diff --git a/base/error.jl b/base/error.jl index 108f5c83716d4a..f26df61ee91d85 100644 --- a/base/error.jl +++ b/base/error.jl @@ -98,7 +98,7 @@ end """ ExponentialBackOff(; n=1, first_delay=0.05, max_delay=10.0, factor=5.0, jitter=0.1) -A `Float64` iterator of length `n` whose elements exponentially increase at a +A [`Float64`](@ref) iterator of length `n` whose elements exponentially increase at a rate in the interval `factor` * (1 ± `jitter`). The first element is `first_delay` and all elements are clamped to `max_delay`. """ diff --git a/base/float.jl b/base/float.jl index 68d0d5138f0fe1..65836552b2b313 100644 --- a/base/float.jl +++ b/base/float.jl @@ -5,25 +5,25 @@ """ Inf16 -Positive infinity of type `Float16`. +Positive infinity of type [`Float16`](@ref). """ const Inf16 = bitcast(Float16, 0x7c00) """ NaN16 -A not-a-number value of type `Float16`. +A not-a-number value of type [`Float16`](@ref). """ const NaN16 = bitcast(Float16, 0x7e00) """ Inf32 -Positive infinity of type `Float32`. +Positive infinity of type [`Float32`](@ref). """ const Inf32 = bitcast(Float32, 0x7f800000) """ NaN32 -A not-a-number value of type `Float32`. +A not-a-number value of type [`Float32`](@ref). """ const NaN32 = bitcast(Float32, 0x7fc00000) const Inf64 = bitcast(Float64, 0x7ff0000000000000) @@ -32,13 +32,13 @@ const NaN64 = bitcast(Float64, 0x7ff8000000000000) """ Inf -Positive infinity of type `Float64`. +Positive infinity of type [`Float64`](@ref). """ const Inf = Inf64 """ NaN -A not-a-number value of type `Float64`. +A not-a-number value of type [`Float64`](@ref). """ const NaN = NaN64 @@ -750,8 +750,8 @@ of `x` is different, then the larger of the two is taken, that is eps(x) == max(x-prevfloat(x), nextfloat(x)-x) The exceptions to this rule are the smallest and largest finite values -(e.g. `nextfloat(-Inf)` and `prevfloat(Inf)` for `Float64`), which round to the smaller of -the values. +(e.g. `nextfloat(-Inf)` and `prevfloat(Inf)` for [`Float64`](@ref)), which round to the +smaller of the values. The rationale for this behavior is that `eps` bounds the floating point rounding error. Under the default `RoundNearest` rounding mode, if ``y`` is a real number and ``x`` diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index e75486a46257c5..a5973c7d99986a 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -78,7 +78,7 @@ julia> round(pi, 3, 2) !!! note Rounding to specified digits in bases other than 2 can be inexact when - operating on binary floating point numbers. For example, the `Float64` + operating on binary floating point numbers. For example, the [`Float64`](@ref) value represented by `1.15` is actually *less* than 1.15, yet will be rounded to 1.2. diff --git a/base/gmp.jl b/base/gmp.jl index b78132e4b48562..07926f98650423 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -58,8 +58,8 @@ end BigInt(x) Create an arbitrary precision integer. `x` may be an `Int` (or anything that can be -converted to an `Int`). The usual mathematical operators are defined for this type, and -results are promoted to a `BigInt`. +converted to an `Int`). The usual mathematical operators are defined for this type, and +results are promoted to a [`BigInt`](@ref). Instances can be constructed from strings via [`parse`](@ref), or using the `big` string literal. diff --git a/base/linalg/qr.jl b/base/linalg/qr.jl index 2d6d723adefe10..13aa153575f1e7 100644 --- a/base/linalg/qr.jl +++ b/base/linalg/qr.jl @@ -226,8 +226,8 @@ The returned object `F` stores the factorization in a packed format: - if `pivot == Val{true}` then `F` is a [`QRPivoted`](@ref) object, - - otherwise if the element type of `A` is a BLAS type (`Float32`, `Float64`, `Complex64` - or `Complex128`), then `F` is a [`QRCompactWY`](@ref) object, + - otherwise if the element type of `A` is a BLAS type ([`Float32`](@ref), [`Float64`](@ref), + `Complex64` or `Complex128`), then `F` is a [`QRCompactWY`](@ref) object, - otherwise `F` is a [`QR`](@ref) object. diff --git a/base/math.jl b/base/math.jl index 8861d2176e1657..1956adf268260a 100644 --- a/base/math.jl +++ b/base/math.jl @@ -161,7 +161,8 @@ log(b::T, x::T) where {T<:Number} = log(x)/log(b) """ log(b,x) -Compute the base `b` logarithm of `x`. Throws [`DomainError`](@ref) for negative `Real` arguments. +Compute the base `b` logarithm of `x`. Throws [`DomainError`](@ref) for negative +[`Real`](@ref) arguments. ```jldoctest julia> log(4,8) @@ -351,8 +352,8 @@ atanh(x) """ log(x) -Compute the natural logarithm of `x`. Throws [`DomainError`](@ref) for negative `Real` arguments. -Use complex negative arguments to obtain complex results. +Compute the natural logarithm of `x`. Throws [`DomainError`](@ref) for negative +[`Real`](@ref) arguments. Use complex negative arguments to obtain complex results. There is an experimental variant in the `Base.Math.JuliaLibm` module, which is typically faster and more accurate. @@ -362,7 +363,8 @@ log(x) """ log2(x) -Compute the logarithm of `x` to base 2. Throws [`DomainError`](@ref) for negative `Real` arguments. +Compute the logarithm of `x` to base 2. Throws [`DomainError`](@ref) for negative +[`Real`](@ref) arguments. # Example ```jldoctest @@ -379,7 +381,7 @@ log2(x) log10(x) Compute the logarithm of `x` to base 10. -Throws [`DomainError`](@ref) for negative `Real` arguments. +Throws [`DomainError`](@ref) for negative [`Real`](@ref) arguments. # Example ```jldoctest @@ -395,7 +397,8 @@ log10(x) """ log1p(x) -Accurate natural logarithm of `1+x`. Throws [`DomainError`](@ref) for `Real` arguments less than -1. +Accurate natural logarithm of `1+x`. Throws [`DomainError`](@ref) for [`Real`](@ref) +arguments less than -1. There is an experimental variant in the `Base.Math.JuliaLibm` module, which is typically faster and more accurate. @@ -438,8 +441,8 @@ sqrt(x::Float32) = sqrt_llvm(x) """ sqrt(x) -Return ``\\sqrt{x}``. Throws [`DomainError`](@ref) for negative `Real` arguments. Use complex -negative arguments instead. The prefix operator `√` is equivalent to `sqrt`. +Return ``\\sqrt{x}``. Throws [`DomainError`](@ref) for negative [`Real`](@ref) arguments. +Use complex negative arguments instead. The prefix operator `√` is equivalent to `sqrt`. """ sqrt(x::Real) = sqrt(float(x)) diff --git a/base/mpfr.jl b/base/mpfr.jl index 4f04480babb692..40e0fd59cf0ac0 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -70,9 +70,9 @@ end """ BigFloat(x) -Create an arbitrary precision floating point number. `x` may be an `Integer`, a `Float64` or -a `BigInt`. The usual mathematical operators are defined for this type, and results are -promoted to a `BigFloat`. +Create an arbitrary precision floating point number. `x` may be an [`Integer`](@ref), a +[`Float64`](@ref) or a [`BigInt`](@ref). The usual mathematical operators are defined for +this type, and results are promoted to a [`BigFloat`](@ref). Note that because decimal literals are converted to floating point numbers when parsed, `BigFloat(2.1)` may not yield what you expect. You may instead prefer to initialize @@ -133,7 +133,7 @@ float(::Type{BigInt}) = BigFloat """ BigFloat(x, prec::Int) -Create a representation of `x` as a `BigFloat` with precision `prec`. +Create a representation of `x` as a [`BigFloat`](@ref) with precision `prec`. """ function BigFloat(x, prec::Int) setprecision(BigFloat, prec) do @@ -144,7 +144,8 @@ end """ BigFloat(x, prec::Int, rounding::RoundingMode) -Create a representation of `x` as a `BigFloat` with precision `prec` and rounding mode `rounding`. +Create a representation of `x` as a [`BigFloat`](@ref) with precision `prec` and +rounding mode `rounding`. """ function BigFloat(x, prec::Int, rounding::RoundingMode) setrounding(BigFloat, rounding) do @@ -155,7 +156,8 @@ end """ BigFloat(x, rounding::RoundingMode) -Create a representation of `x` as a `BigFloat` with the current global precision and rounding mode `rounding`. +Create a representation of `x` as a [`BigFloat`](@ref) with the current global precision +and rounding mode `rounding`. """ function BigFloat(x::Union{Integer, AbstractFloat, String}, rounding::RoundingMode) BigFloat(x, precision(BigFloat), rounding) @@ -164,7 +166,7 @@ end """ BigFloat(x::String) -Create a representation of the string `x` as a `BigFloat`. +Create a representation of the string `x` as a [`BigFloat`](@ref). """ BigFloat(x::String) = parse(BigFloat, x) @@ -728,7 +730,7 @@ end """ precision(BigFloat) -Get the precision (in bits) currently used for `BigFloat` arithmetic. +Get the precision (in bits) currently used for [`BigFloat`](@ref) arithmetic. """ precision(::Type{BigFloat}) = DEFAULT_PRECISION[end] # precision of the type BigFloat itself diff --git a/base/number.jl b/base/number.jl index 704bf42fc00700..d34f3ba10a438b 100644 --- a/base/number.jl +++ b/base/number.jl @@ -190,8 +190,8 @@ _default_type(::Type{Number}) = Int """ factorial(n) -Factorial of `n`. If `n` is an `Integer`, the factorial is computed as an -integer (promoted to at least 64 bits). Note that this may overflow if `n` is not small, +Factorial of `n`. If `n` is an [`Integer`](@ref), the factorial is computed as an +integer (promoted to at least 64 bits). Note that this may overflow if `n` is not small, but you can use `factorial(big(n))` to compute the result exactly in arbitrary precision. If `n` is not an `Integer`, `factorial(n)` is equivalent to [`gamma(n+1)`](@ref). diff --git a/base/operators.jl b/base/operators.jl index bbec5c09e28f32..47ac4b25de3ea9 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -532,8 +532,8 @@ Unsigned right bit shift operator, `x >>> n`. For `n >= 0`, the result is `x` shifted right by `n` bits, where `n >= 0`, filling with `0`s. For `n < 0`, this is equivalent to `x << -n`. -For `Unsigned` integer types, this is equivalent to [`>>`](@ref). For -`Signed` integer types, this is equivalent to `signed(unsigned(x) >> n)`. +For [`Unsigned`](@ref) integer types, this is equivalent to [`>>`](@ref). For +[`Signed`](@ref) integer types, this is equivalent to `signed(unsigned(x) >> n)`. ```jldoctest julia> Int8(-14) >>> 2 @@ -545,7 +545,8 @@ julia> bits(Int8(-14)) julia> bits(Int8(60)) "00111100" ``` -`BigInt`s are treated as if having infinite size, so no filling is required and this + +[`BigInt`](@ref)s are treated as if having infinite size, so no filling is required and this is equivalent to [`>>`](@ref). See also [`>>`](@ref), [`<<`](@ref). diff --git a/base/promotion.jl b/base/promotion.jl index 4fbe3f7068a2c3..5c55b3d1e34d36 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -137,8 +137,8 @@ promote_type(::Type{Bottom}, ::Type{T}) where {T} = (@_pure_meta; T) Determine a type big enough to hold values of each argument type without loss, whenever possible. In some cases, where no type exists to which both types can be promoted losslessly, some loss is tolerated; for example, `promote_type(Int64, Float64)` returns -`Float64` even though strictly, not all `Int64` values can be represented exactly as -`Float64` values. +[`Float64`](@ref) even though strictly, not all [`Int64`](@ref) values can be represented +exactly as `Float64` values. ```jldoctest julia> promote_type(Int64, Float64) diff --git a/base/random.jl b/base/random.jl index 3697302a05153b..847c61e2f9a1f5 100644 --- a/base/random.jl +++ b/base/random.jl @@ -221,8 +221,8 @@ end Reseed the random number generator. If a `seed` is provided, the RNG will give a reproducible sequence of numbers, otherwise Julia will get entropy from the system. For -`MersenneTwister`, the `seed` may be a non-negative integer or a vector of `UInt32` integers. -`RandomDevice` does not support seeding. +`MersenneTwister`, the `seed` may be a non-negative integer or a vector of [`UInt32`](@ref) +integers. `RandomDevice` does not support seeding. """ srand(r::MersenneTwister) = srand(r, make_seed()) srand(r::MersenneTwister, n::Integer) = srand(r, make_seed(n)) @@ -258,9 +258,10 @@ Pick a random element or array of random elements from the set of values specifi * an indexable collection (for example `1:n` or `['x','y','z']`), or * a type: the set of values to pick from is then equivalent to `typemin(S):typemax(S)` for - integers (this is not applicable to `BigInt`), and to ``[0, 1)`` for floating point numbers; + integers (this is not applicable to [`BigInt`](@ref)), and to ``[0, 1)`` for floating + point numbers; -`S` defaults to `Float64`. +`S` defaults to [`Float64`](@ref). """ @inline rand() = rand(GLOBAL_RNG, CloseOpen) @inline rand(T::Type) = rand(GLOBAL_RNG, T) @@ -1181,9 +1182,9 @@ const ziggurat_exp_r = 7.6971174701310497140446280481 Generate a normally-distributed random number of type `T` with mean 0 and standard deviation 1. Optionally generate an array of normally-distributed random numbers. The `Base` module currently provides an implementation for the types -`Float16`, `Float32`, and `Float64` (the default), and their `Complex` counterparts. -When the type argument is complex, the values are drawn from the circularly symmetric -complex normal distribution. +[`Float16`](@ref), [`Float32`](@ref), and [`Float64`](@ref) (the default), and their +[`Complex`](@ref) counterparts. When the type argument is complex, the values are drawn +from the circularly symmetric complex normal distribution. """ @inline function randn(rng::AbstractRNG=GLOBAL_RNG) @inbounds begin @@ -1217,7 +1218,7 @@ end Generate a random number of type `T` according to the exponential distribution with scale 1. Optionally generate an array of such random numbers. The `Base` module currently provides an implementation for the types -`Float16`, `Float32`, and `Float64` (the default). +[`Float16`](@ref), [`Float32`](@ref), and [`Float64`](@ref) (the default). """ @inline function randexp(rng::AbstractRNG=GLOBAL_RNG) @inbounds begin diff --git a/base/rational.jl b/base/rational.jl index 1fe97049be83fd..b3f901300399ea 100644 --- a/base/rational.jl +++ b/base/rational.jl @@ -27,7 +27,7 @@ end """ //(num, den) -Divide two integers or rational numbers, giving a `Rational` result. +Divide two integers or rational numbers, giving a [`Rational`](@ref) result. ```jldoctest julia> 3 // 5 @@ -109,7 +109,7 @@ widen(::Type{Rational{T}}) where {T} = Rational{widen(T)} """ rationalize([T<:Integer=Int,] x; tol::Real=eps(x)) -Approximate floating point number `x` as a `Rational` number with components +Approximate floating point number `x` as a [`Rational`](@ref) number with components of the given integer type. The result will differ from `x` by no more than `tol`. If `T` is not provided, it defaults to `Int`. diff --git a/base/reflection.jl b/base/reflection.jl index 58d9b67e191771..eb8e279e119778 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -219,8 +219,8 @@ isstructtype(x) = (@_pure_meta; false) isbits(T) Return `true` if `T` is a "plain data" type, meaning it is immutable and contains no -references to other values. Typical examples are numeric types such as `UInt8`, `Float64`, -and `Complex{Float64}`. +references to other values. Typical examples are numeric types such as [`UInt8`](@ref), +[`Float64`](@ref), and [`Complex{Float64}`](@ref). ```jldoctest julia> isbits(Complex{Float64}) diff --git a/base/rounding.jl b/base/rounding.jl index 67f71d9dda57d7..bcb9b6328ac15e 100644 --- a/base/rounding.jl +++ b/base/rounding.jl @@ -37,7 +37,7 @@ Currently supported rounding modes are: - [`RoundNearestTiesAway`](@ref) - [`RoundNearestTiesUp`](@ref) - [`RoundToZero`](@ref) -- `RoundFromZero` (`BigFloat` only) +- `RoundFromZero` ([`BigFloat`](@ref) only) - [`RoundUp`](@ref) - [`RoundDown`](@ref) """ @@ -118,9 +118,9 @@ arithmetic functions ([`+`](@ref), [`-`](@ref), [`*`](@ref), functions may give incorrect or invalid values when using rounding modes other than the default `RoundNearest`. -Note that this may affect other types, for instance changing the rounding mode of `Float64` -will change the rounding mode of `Float32`. See [`RoundingMode`](@ref) for -available modes. +Note that this may affect other types, for instance changing the rounding mode of +[`Float64`](@ref) will change the rounding mode of [`Float32`](@ref). +See [`RoundingMode`](@ref) for available modes. !!! warning diff --git a/base/show.jl b/base/show.jl index f21483c699771a..cdf7450f5713f6 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1570,7 +1570,7 @@ end summary(x) Return a string giving a brief description of a value. By default returns -`string(typeof(x))`, e.g. `Int64`. +`string(typeof(x))`, e.g. [`Int64`](@ref). For arrays, returns a string of size and type info, e.g. `10-element Array{Int64,1}`. diff --git a/base/socket.jl b/base/socket.jl index ae4e055c913254..108624be549174 100644 --- a/base/socket.jl +++ b/base/socket.jl @@ -24,7 +24,7 @@ end """ IPv4(host::Integer) -> IPv4 -Returns an IPv4 object from ip address `host` formatted as an `Integer`. +Returns an IPv4 object from ip address `host` formatted as an [`Integer`](@ref). ```jldoctest julia> IPv4(3223256218) @@ -76,7 +76,7 @@ end """ IPv6(host::Integer) -> IPv6 -Returns an IPv6 object from ip address `host` formatted as an `Integer`. +Returns an IPv6 object from ip address `host` formatted as an [`Integer`](@ref). ```jldoctest julia> IPv6(3223256218) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 58e363a2e299d2..f3986e6b43b063 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -1357,7 +1357,7 @@ spones(S::SparseMatrixCSC{T}) where {T} = Create a sparse vector of length `m` or sparse matrix of size `m x n`. This sparse array will not contain any nonzero values. No storage will be allocated -for nonzero values during construction. The type defaults to `Float64` if not +for nonzero values during construction. The type defaults to [`Float64`](@ref) if not specified. ```jldoctest @@ -1411,7 +1411,7 @@ eye(S::SparseMatrixCSC) = speye(S) speye([type,]m[,n]) Create a sparse identity matrix of size `m x m`. When `n` is supplied, -create a sparse identity matrix of size `m x n`. The type defaults to `Float64` +create a sparse identity matrix of size `m x n`. The type defaults to [`Float64`](@ref) if not specified. `sparse(I, m, n)` is equivalent to `speye(Int, m, n)`, and diff --git a/base/sparse/umfpack.jl b/base/sparse/umfpack.jl index 5e44206760f0fb..edb88f80304de3 100644 --- a/base/sparse/umfpack.jl +++ b/base/sparse/umfpack.jl @@ -107,8 +107,8 @@ end Compute the LU factorization of a sparse matrix `A`. For sparse `A` with real or complex element type, the return type of `F` is -`UmfpackLU{Tv, Ti}`, with `Tv` = `Float64` or `Complex128` respectively and -`Ti` is an integer type (`Int32` or `Int64`). +`UmfpackLU{Tv, Ti}`, with `Tv` = [`Float64`](@ref) or `Complex128` respectively and +`Ti` is an integer type ([`Int32`](@ref) or [`Int64`](@ref)). The individual components of the factorization `F` can be accessed by indexing: @@ -133,7 +133,7 @@ The relation between `F` and `A` is !!! note `lufact(A::SparseMatrixCSC)` uses the UMFPACK library that is part of - SuiteSparse. As this library only supports sparse matrices with `Float64` or + SuiteSparse. As this library only supports sparse matrices with [`Float64`](@ref) or `Complex128` elements, `lufact` converts `A` into a copy that is of type `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{Complex128}` as appropriate. """ diff --git a/base/special/gamma.jl b/base/special/gamma.jl index 479ab58adfc0a2..7415200b409ce4 100644 --- a/base/special/gamma.jl +++ b/base/special/gamma.jl @@ -37,7 +37,7 @@ lfact(x::Integer) = x < 0 ? throw(DomainError()) : lgamma(x + oneunit(x)) lgamma(x) Compute the logarithm of the absolute value of [`gamma`](@ref) for -`Real` `x`, while for `Complex` `x` it computes the +[`Real`](@ref) `x`, while for [`Complex`](@ref) `x` compute the principal branch cut of the logarithm of `gamma(x)` (defined for negative `real(x)` by analytic continuation from positive `real(x)`). """ diff --git a/base/test.jl b/base/test.jl index a64c9679b0264a..9d7dc05bd553e3 100644 --- a/base/test.jl +++ b/base/test.jl @@ -115,7 +115,7 @@ end Error The test condition couldn't be evaluated due to an exception, or -it evaluated to something other than a `Bool`. +it evaluated to something other than a [`Bool`](@ref). In the case of `@test_broken` it is used to indicate that an unexpected `Pass` `Result` occurred. """ diff --git a/doc/src/devdocs/offset-arrays.md b/doc/src/devdocs/offset-arrays.md index 9951c72231de9d..689f856b48d623 100644 --- a/doc/src/devdocs/offset-arrays.md +++ b/doc/src/devdocs/offset-arrays.md @@ -108,8 +108,8 @@ Storage is often allocated with `Array{Int}(dims)` or `similar(A, args...)`. Whe to match the indices of some other array, this may not always suffice. The generic replacement for such patterns is to use `similar(storagetype, shape)`. `storagetype` indicates the kind of underlying "conventional" behavior you'd like, e.g., `Array{Int}` or `BitArray` or even `dims->zeros(Float32, dims)` -(which would allocate an all-zeros array). `shape` is a tuple of `Integer` or `AbstractUnitRange` -values, specifying the indices that you want the result to use. +(which would allocate an all-zeros array). `shape` is a tuple of [`Integer`](@ref) or +`AbstractUnitRange` values, specifying the indices that you want the result to use. Let's walk through a couple of explicit examples. First, if `A` has conventional indices, then `similar(Array{Int}, indices(A))` would end up calling `Array{Int}(size(A))`, and thus return diff --git a/doc/src/devdocs/reflection.md b/doc/src/devdocs/reflection.md index 9579a21eddaf6b..d31188f80b9aa7 100644 --- a/doc/src/devdocs/reflection.md +++ b/doc/src/devdocs/reflection.md @@ -50,7 +50,7 @@ of these fields is the `types` field observed in the example above. ## Subtypes The *direct* subtypes of any `DataType` may be listed using [`subtypes()`](@ref). For example, -the abstract `DataType``AbstractFloat` has four (concrete) subtypes: +the abstract `DataType` [`AbstractFloat`](@ref) has four (concrete) subtypes: ```jldoctest julia> subtypes(AbstractFloat) diff --git a/doc/src/devdocs/types.md b/doc/src/devdocs/types.md index 44a1a7480e4c50..5b3da02716a6ce 100644 --- a/doc/src/devdocs/types.md +++ b/doc/src/devdocs/types.md @@ -14,8 +14,8 @@ have. A *concrete* type `T` describes the set of values whose direct tag, as returned by the `typeof` function, is `T`. An *abstract* type describes some possibly-larger set of values. -`Any` describes the entire universe of possible values. `Integer` is a subset of `Any` that includes -`Int`, `Int8`, and other concrete types. +`Any` describes the entire universe of possible values. [`Integer`](@ref) is a subset of +`Any` that includes `Int`, [`Int8`](@ref), and other concrete types. Internally, Julia also makes heavy use of another type known as `Bottom`, which can also be written as `Union{}`. This corresponds to the empty set. @@ -330,7 +330,7 @@ However, this interpretation causes some practical problems. First, a value of `T` needs to be available inside the method definition. For a call like `f(1, 1.0)`, it's not clear what `T` should be. -It could be `Union{Int,Float64}`, or perhaps `Real`. +It could be `Union{Int,Float64}`, or perhaps [`Real`](@ref). Intuitively, we expect the declaration `x::T` to mean `T === typeof(x)`. To make sure that invariant holds, we need `typeof(x) === typeof(y) === T` in this method. That implies the method should only be called for arguments of the exact same type. diff --git a/doc/src/manual/arrays.md b/doc/src/manual/arrays.md index 757ac1f384a774..b99ae2cb050df7 100644 --- a/doc/src/manual/arrays.md +++ b/doc/src/manual/arrays.md @@ -10,7 +10,7 @@ on implementing a custom array type. An array is a collection of objects stored in a multi-dimensional grid. In the most general case, an array may contain objects of type `Any`. For most computational purposes, arrays should contain -objects of a more specific type, such as `Float64` or `Int32`. +objects of a more specific type, such as [`Float64`](@ref) or [`Int32`](@ref). In general, unlike many other technical computing languages, Julia does not expect programs to be written in a vectorized style for performance. Julia's compiler uses type inference and generates @@ -46,7 +46,7 @@ Many functions for constructing and initializing arrays are provided. In the fol such functions, calls with a `dims...` argument can either take a single tuple of dimension sizes or a series of dimension sizes passed as a variable number of arguments. Most of these functions also accept a first input `T`, which is the element type of the array. If the type `T` is -omitted it will default to `Float64`. +omitted it will default to [`Float64`](@ref). | Function | Description | |:---------------------------------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/doc/src/manual/calling-c-and-fortran-code.md b/doc/src/manual/calling-c-and-fortran-code.md index b8164f86ad8da9..30da54ac330adb 100644 --- a/doc/src/manual/calling-c-and-fortran-code.md +++ b/doc/src/manual/calling-c-and-fortran-code.md @@ -66,7 +66,7 @@ julia> typeof(ans) Int32 ``` -`clock` takes no arguments and returns an `Int32`. One common gotcha is that a 1-tuple must be +`clock` takes no arguments and returns an [`Int32`](@ref). One common gotcha is that a 1-tuple must be written with a trailing comma. For example, to call the `getenv` function to get a pointer to the value of an environment variable, one makes a call like this: @@ -192,8 +192,8 @@ julia> const mycompare_c = cfunction(mycompare, Cint, (Ref{Cdouble}, Ref{Cdouble ``` [`cfunction()`](@ref) accepts three arguments: the Julia function (`mycompare`), the return type -(`Cint`), and a tuple of the argument types, in this case to sort an array of `Cdouble` (`Float64`) -elements. +(`Cint`), and a tuple of the argument types, in this case to sort an array of `Cdouble` +([`Float64`](@ref)) elements. The final call to `qsort` looks like this: @@ -298,7 +298,7 @@ same: * `Signed` Exactly corresponds to the `signed` type annotation in C (or any `INTEGER` type in Fortran). - Any Julia type that is not a subtype of `Signed` is assumed to be unsigned. + Any Julia type that is not a subtype of [`Signed`](@ref) is assumed to be unsigned. * `Ref{T}` diff --git a/doc/src/manual/constructors.md b/doc/src/manual/constructors.md index 607e7026712118..e9b46b392a4439 100644 --- a/doc/src/manual/constructors.md +++ b/doc/src/manual/constructors.md @@ -313,10 +313,10 @@ Point{Float64}(1.0, 2.0) As you can see, for constructor calls with explicit type parameters, the arguments are converted to the implied field types: `Point{Int64}(1,2)` works, but `Point{Int64}(1.0,2.5)` raises an -[`InexactError`](@ref) when converting `2.5` to `Int64`. When the type is implied by the arguments to -the constructor call, as in `Point(1,2)`, then the types of the arguments must agree -- otherwise -the `T` cannot be determined -- but any pair of real arguments with matching type may be given -to the generic `Point` constructor. +[`InexactError`](@ref) when converting `2.5` to [`Int64`](@ref). When the type is implied +by the arguments to the constructor call, as in `Point(1,2)`, then the types of the +arguments must agree -- otherwise the `T` cannot be determined -- but any pair of real +arguments with matching type may be given to the generic `Point` constructor. What's really going on here is that `Point`, `Point{Float64}` and `Point{Int64}` are all different constructor functions. In fact, `Point{T}` is a distinct constructor function for each type `T`. @@ -551,10 +551,11 @@ SummedArray{Int32,Int32}(Int32[1, 2, 3], 6) ``` The problem is that we want `S` to be a larger type than `T`, so that we can sum many elements -with less information loss. For example, when `T` is `Int32`, we would like `S` to be `Int64`. -Therefore we want to avoid an interface that allows the user to construct instances of the type -`SummedArray{Int32,Int32}`. One way to do this is to provide a constructor only for `SummedArray`, -but inside the `type` definition block to suppress generation of default constructors: +with less information loss. For example, when `T` is [`Int32`](@ref), we would like `S` to +be [`Int64`](@ref). Therefore we want to avoid an interface that allows the user to construct +instances of the type `SummedArray{Int32,Int32}`. One way to do this is to provide a +constructor only for `SummedArray`, but inside the `type` definition block to suppress +generation of default constructors: ```jldoctest julia> struct SummedArray{T<:Number,S<:Number} diff --git a/doc/src/manual/control-flow.md b/doc/src/manual/control-flow.md index 1bf0923b6cb402..1dc395b2a31d5f 100644 --- a/doc/src/manual/control-flow.md +++ b/doc/src/manual/control-flow.md @@ -173,8 +173,8 @@ julia> if 1 ERROR: TypeError: non-boolean (Int64) used in boolean context ``` -This error indicates that the conditional was of the wrong type: `Int64` rather than the required -`Bool`. +This error indicates that the conditional was of the wrong type: [`Int64`](@ref) rather +than the required [`Bool`](@ref). The so-called "ternary operator", `?:`, is closely related to the `if`-`elseif`-`else` syntax, but is used where a conditional choice between single expression values is required, as opposed diff --git a/doc/src/manual/conversion-and-promotion.md b/doc/src/manual/conversion-and-promotion.md index b72d2715b6aeb7..3ffd6e2e338566 100644 --- a/doc/src/manual/conversion-and-promotion.md +++ b/doc/src/manual/conversion-and-promotion.md @@ -101,13 +101,14 @@ is to it. For example, the method to convert a real number to a boolean is this: convert(::Type{Bool}, x::Real) = x==0 ? false : x==1 ? true : throw(InexactError()) ``` -The type of the first argument of this method is a [singleton type](@ref man-singleton-types), `Type{Bool}`, the only -instance of which is `Bool`. Thus, this method is only invoked when the first argument is the -type value `Bool`. Notice the syntax used for the first argument: the argument name is omitted -prior to the `::` symbol, and only the type is given. This is the syntax in Julia for a function -argument whose type is specified but whose value is never used in the function body. In this -example, since the type is a singleton, there would never be any reason to use its value within -the body. When invoked, the method determines whether a numeric value is true or false as a boolean, +The type of the first argument of this method is a [singleton type](@ref man-singleton-types), +`Type{Bool}`, the only instance of which is [`Bool`](@ref). Thus, this method is only invoked +when the first argument is the type value `Bool`. Notice the syntax used for the first +argument: the argument name is omitted prior to the `::` symbol, and only the type is given. +This is the syntax in Julia for a function argument whose type is specified but whose value +is never used in the function body. In this example, since the type is a singleton, there +would never be any reason to use its value within the body. When invoked, the method +determines whether a numeric value is true or false as a boolean, by comparing it to one and zero: ```jldoctest @@ -137,7 +138,8 @@ convert(::Type{T}, z::Complex) where {T<:Real} = ### [Case Study: Rational Conversions](@id man-rational-conversion) -To continue our case study of Julia's `Rational` type, here are the conversions declared in [`rational.jl`](https://github.com/JuliaLang/julia/blob/master/base/rational.jl), +To continue our case study of Julia's [`Rational`](@ref) type, here are the conversions declared in +[`rational.jl`](https://github.com/JuliaLang/julia/blob/master/base/rational.jl), right after the declaration of the type and its constructors: ```julia @@ -187,8 +189,8 @@ since the values are converted to a "greater" type -- i.e. one which can represe input values in a single common type. It is important, however, not to confuse this with object-oriented (structural) super-typing, or Julia's notion of abstract super-types: promotion has nothing to do with the type hierarchy, and everything to do with converting between alternate representations. -For instance, although every `Int32` value can also be represented as a `Float64` value, `Int32` -is not a subtype of `Float64`. +For instance, although every [`Int32`](@ref) value can also be represented as a [`Float64`](@ref) value, +`Int32` is not a subtype of `Float64`. Promotion to a common "greater" type is performed in Julia by the `promote` function, which takes any number of arguments, and returns a tuple of the same number of values, converted to a common @@ -286,10 +288,11 @@ promote_rule(::Type{UInt8}, ::Type{Int8}) = Int promote_rule(::Type{BigInt}, ::Type{Int8}) = BigInt ``` -In the latter case, the result type is `BigInt` since `BigInt` is the only type large enough to -hold integers for arbitrary-precision integer arithmetic. Also note that one does not need to -define both `promote_rule(::Type{A}, ::Type{B})` and `promote_rule(::Type{B}, ::Type{A})` -- the -symmetry is implied by the way `promote_rule` is used in the promotion process. +In the latter case, the result type is [`BigInt`](@ref) since `BigInt` is the only type +large enough to hold integers for arbitrary-precision integer arithmetic. Also note that +one does not need to define both `promote_rule(::Type{A}, ::Type{B})` and +`promote_rule(::Type{B}, ::Type{A})` -- the symmetry is implied by the way `promote_rule` +is used in the promotion process. The `promote_rule` function is used as a building block to define a second function called `promote_type`, which, given any number of type objects, returns the common type to which those values, as arguments diff --git a/doc/src/manual/dates.md b/doc/src/manual/dates.md index 70645cacd1d931..476314407e6ab3 100644 --- a/doc/src/manual/dates.md +++ b/doc/src/manual/dates.md @@ -12,10 +12,10 @@ For example, since the [`Date`](@ref) type only resolves to the precision of a s no hours, minutes, or seconds), normal considerations for time zones, daylight savings/summer time, and leap seconds are unnecessary and avoided. -Both [`Date`](@ref) and [`DateTime`](@ref) are basically immutable `Int64` wrappers. The single -`instant` field of either type is actually a `UTInstant{P}` type, which represents a continuously -increasing machine timeline based on the UT second [^1]. The [`DateTime`](@ref) -type is not aware of time zones (*naive*, in Python parlance), +Both [`Date`](@ref) and [`DateTime`](@ref) are basically immutable [`Int64`](@ref) wrappers. +The single `instant` field of either type is actually a `UTInstant{P}` type, which +represents a continuously increasing machine timeline based on the UT second [^1]. The +[`DateTime`](@ref) type is not aware of time zones (*naive*, in Python parlance), analogous to a *LocalDateTime* in Java 8. Additional time zone functionality can be added through the [TimeZones.jl package](https://github.com/JuliaTime/TimeZones.jl/), which compiles the [IANA time zone database](http://www.iana.org/time-zones). Both [`Date`](@ref) and @@ -133,7 +133,7 @@ Finding the length of time between two [`Date`](@ref) or [`DateTime`](@ref) is s given their underlying representation as `UTInstant{Day}` and `UTInstant{Millisecond}`, respectively. The difference between [`Date`](@ref) is returned in the number of [`Day`](@ref), and [`DateTime`](@ref) in the number of [`Millisecond`](@ref). Similarly, comparing [`TimeType`](@ref) is a simple matter -of comparing the underlying machine instants (which in turn compares the internal `Int64` values). +of comparing the underlying machine instants (which in turn compares the internal [`Int64`](@ref) values). ```jldoctest julia> dt = Date(2012,2,29) @@ -190,7 +190,7 @@ julia> dt - dt2 ## Accessor Functions -Because the [`Date`](@ref) and [`DateTime`](@ref) types are stored as single `Int64` values, date +Because the [`Date`](@ref) and [`DateTime`](@ref) types are stored as single [`Int64`](@ref) values, date parts or fields can be retrieved through accessor functions. The lowercase accessors return the field as an integer: @@ -454,7 +454,8 @@ julia> Dates.lastdayofquarter(Date(2014,7,16)) # Adjusts to the last day of the The next two higher-order methods, [`tonext()`](@ref), and [`toprev()`](@ref), generalize working with temporal expressions by taking a `DateFunction` as first argument, along with a starting [`TimeType`](@ref). A `DateFunction` is just a function, usually anonymous, that takes a single -[`TimeType`](@ref) as input and returns a `Bool`, `true` indicating a satisfied adjustment criterion. +[`TimeType`](@ref) as input and returns a [`Bool`](@ref), `true` indicating a satisfied +adjustment criterion. For example: ```jldoctest @@ -511,7 +512,7 @@ Additional examples and tests are available in [`test/dates/adjusters.jl`](https Periods are a human view of discrete, sometimes irregular durations of time. Consider 1 month; it could represent, in days, a value of 28, 29, 30, or 31 depending on the year and month context. Or a year could represent 365 or 366 days in the case of a leap year. [`Period`](@ref) types are -simple `Int64` wrappers and are constructed by wrapping any `Int64` convertible type, i.e. `Year(1)` +simple [`Int64`](@ref) wrappers and are constructed by wrapping any `Int64` convertible type, i.e. `Year(1)` or `Month(3.0)`. Arithmetic between [`Period`](@ref) of the same type behave like integers, and limited `Period-Real` arithmetic is available. diff --git a/doc/src/manual/documentation.md b/doc/src/manual/documentation.md index 59d1a23f2e43d5..94499bf241f72a 100644 --- a/doc/src/manual/documentation.md +++ b/doc/src/manual/documentation.md @@ -109,8 +109,8 @@ As in the example above, we recommend following some simple conventions when wri Calling `rand` and other RNG-related functions should be avoided in doctests since they will not produce consistent outputs during different Julia sessions. - Operating system word size (`Int32` or `Int64`) as well as path separator differences (`/` or - `\`) will also effect the reproducibility of some doctests. + Operating system word size ([`Int32`](@ref) or [`Int64`](@ref)) as well as path separator differences + (`/` or `\`) will also effect the reproducibility of some doctests. Note that whitespace in your doctest is significant! The doctest will fail if you misalign the output of pretty-printing an array, for example. diff --git a/doc/src/manual/embedding.md b/doc/src/manual/embedding.md index 77a132c5b3d205..032b57dcedc439 100644 --- a/doc/src/manual/embedding.md +++ b/doc/src/manual/embedding.md @@ -139,9 +139,9 @@ Now the build command is simply `make`. Real applications will not just need to execute expressions, but also return their values to the host program. `jl_eval_string` returns a `jl_value_t*`, which is a pointer to a heap-allocated -Julia object. Storing simple data types like `Float64` in this way is called `boxing`, and extracting -the stored primitive data is called `unboxing`. Our improved sample program that calculates the -square root of 2 in Julia and reads back the result in C looks as follows: +Julia object. Storing simple data types like [`Float64`](@ref) in this way is called `boxing`, +and extracting the stored primitive data is called `unboxing`. Our improved sample program that +calculates the square root of 2 in Julia and reads back the result in C looks as follows: ```c jl_value_t *ret = jl_eval_string("sqrt(2.0)"); @@ -157,9 +157,9 @@ else { In order to check whether `ret` is of a specific Julia type, we can use the `jl_isa`, `jl_typeis`, or `jl_is_...` functions. -By typing `typeof(sqrt(2.0))` into the Julia shell we can see that the return type is `Float64` -(`double` in C). To convert the boxed Julia value into a C double the `jl_unbox_float64` function -is used in the above code snippet. +By typing `typeof(sqrt(2.0))` into the Julia shell we can see that the return type is +[`Float64`](@ref) (`double` in C). To convert the boxed Julia value into a C double the +`jl_unbox_float64` function is used in the above code snippet. Corresponding `jl_box_...` functions are used to convert the other way: diff --git a/doc/src/manual/environment-variables.md b/doc/src/manual/environment-variables.md index bbb2c41e27a91b..d2fe606136b762 100644 --- a/doc/src/manual/environment-variables.md +++ b/doc/src/manual/environment-variables.md @@ -175,7 +175,7 @@ logical CPU cores available. ### `JULIA_WORKER_TIMEOUT` -A `Float64` that sets the value of `Base.worker_timeout()` (default: `60.0`). +A [`Float64`](@ref) that sets the value of `Base.worker_timeout()` (default: `60.0`). This function gives the number of seconds a worker process will wait for a master process to establish a connection before dying. diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index e019cce47fa78a..4ff850b44ea00c 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -214,9 +214,10 @@ julia> function unstable(flag::Bool) unstable (generic function with 1 method) ``` -It returns either an `Int` or a `Float64` depending on the value of its argument. Since Julia -can't predict the return type of this function at compile-time, any computation that uses it will -have to guard against both types possibly occurring, making generation of fast machine code difficult. +It returns either an `Int` or a [`Float64`](@ref) depending on the value of its argument. +Since Julia can't predict the return type of this function at compile-time, any computation +that uses it will have to guard against both types possibly occurring, making generation of +fast machine code difficult. ### [Why does Julia give a `DomainError` for certain seemingly-sensible operations?](@id faq-domain-errors) @@ -281,7 +282,7 @@ ideal for a high-level programming language to expose this to the user. For nume efficiency and transparency are at a premium, however, the alternatives are worse. One alternative to consider would be to check each integer operation for overflow and promote -results to bigger integer types such as `Int128` or [`BigInt`](@ref) in the case of overflow. +results to bigger integer types such as [`Int128`](@ref) or [`BigInt`](@ref) in the case of overflow. Unfortunately, this introduces major overhead on every integer operation (think incrementing a loop counter) – it requires emitting code to perform run-time overflow checks after arithmetic instructions and branches to handle potential overflows. Worse still, this would cause every computation diff --git a/doc/src/manual/integers-and-floating-point-numbers.md b/doc/src/manual/integers-and-floating-point-numbers.md index 5e1c54347bd3f8..1b819938cc625e 100644 --- a/doc/src/manual/integers-and-floating-point-numbers.md +++ b/doc/src/manual/integers-and-floating-point-numbers.md @@ -18,25 +18,25 @@ The following are Julia's primitive numeric types: * **Integer types:** -| Type | Signed? | Number of bits | Smallest value | Largest value | -|:--------- |:------- |:-------------- |:-------------- |:------------- | -| `Int8` | ✓ | 8 | -2^7 | 2^7 - 1 | -| `UInt8` |   | 8 | 0 | 2^8 - 1 | -| `Int16` | ✓ | 16 | -2^15 | 2^15 - 1 | -| `UInt16` |   | 16 | 0 | 2^16 - 1 | -| `Int32` | ✓ | 32 | -2^31 | 2^31 - 1 | -| `UInt32` |   | 32 | 0 | 2^32 - 1 | -| `Int64` | ✓ | 64 | -2^63 | 2^63 - 1 | -| `UInt64` |   | 64 | 0 | 2^64 - 1 | -| `Int128` | ✓ | 128 | -2^127 | 2^127 - 1 | -| `UInt128` |   | 128 | 0 | 2^128 - 1 | -| `Bool` | N/A | 8 | `false` (0) | `true` (1) | +| Type | Signed? | Number of bits | Smallest value | Largest value | +|:----------------- |:------- |:-------------- |:-------------- |:------------- | +| [`Int8`](@ref) | ✓ | 8 | -2^7 | 2^7 - 1 | +| [`UInt8`](@ref) |   | 8 | 0 | 2^8 - 1 | +| [`Int16`](@ref) | ✓ | 16 | -2^15 | 2^15 - 1 | +| [`UInt16`](@ref) |   | 16 | 0 | 2^16 - 1 | +| [`Int32`](@ref) | ✓ | 32 | -2^31 | 2^31 - 1 | +| [`UInt32`](@ref) |   | 32 | 0 | 2^32 - 1 | +| [`Int64`](@ref) | ✓ | 64 | -2^63 | 2^63 - 1 | +| [`UInt64`](@ref) |   | 64 | 0 | 2^64 - 1 | +| [`Int128`](@ref) | ✓ | 128 | -2^127 | 2^127 - 1 | +| [`UInt128`](@ref) |   | 128 | 0 | 2^128 - 1 | +| [`Bool`](@ref) | N/A | 8 | `false` (0) | `true` (1) | * **Floating-point types:** | Type | Precision | Number of bits | |:----------------- |:------------------------------------------------------------------------------ |:-------------- | -| `Float16` | [half](https://en.wikipedia.org/wiki/Half-precision_floating-point_format) | 16 | +| [`Float16`](@ref) | [half](https://en.wikipedia.org/wiki/Half-precision_floating-point_format) | 16 | | [`Float32`](@ref) | [single](https://en.wikipedia.org/wiki/Single_precision_floating-point_format) | 32 | | [`Float64`](@ref) | [double](https://en.wikipedia.org/wiki/Double_precision_floating-point_format) | 64 | @@ -206,7 +206,7 @@ true Thus, arithmetic with Julia integers is actually a form of [modular arithmetic](https://en.wikipedia.org/wiki/Modular_arithmetic). This reflects the characteristics of the underlying arithmetic of integers as implemented on modern computers. In applications where overflow is possible, explicit checking for wraparound produced -by overflow is essential; otherwise, the `BigInt` type in [Arbitrary Precision Arithmetic](@ref) +by overflow is essential; otherwise, the [`BigInt`](@ref) type in [Arbitrary Precision Arithmetic](@ref) is recommended instead. ### Division errors @@ -243,8 +243,8 @@ julia> 2.5e-4 0.00025 ``` -The above results are all `Float64` values. Literal `Float32` values can be entered by writing -an `f` in place of `e`: +The above results are all [`Float64`](@ref) values. Literal [`Float32`](@ref) values can be +entered by writing an `f` in place of `e`: ```jldoctest julia> 0.5f0 @@ -257,7 +257,7 @@ julia> 2.5f-4 0.00025f0 ``` -Values can be converted to `Float32` easily: +Values can be converted to [`Float32`](@ref) easily: ```jldoctest julia> Float32(-1.5) @@ -267,7 +267,7 @@ julia> typeof(ans) Float32 ``` -Hexadecimal floating-point literals are also valid, but only as `Float64` values: +Hexadecimal floating-point literals are also valid, but only as [`Float64`](@ref) values: ```jldoctest julia> 0x1p0 @@ -283,8 +283,8 @@ julia> typeof(ans) Float64 ``` -Half-precision floating-point numbers are also supported (`Float16`), but they are -implemented in software and use `Float32` for calculations. +Half-precision floating-point numbers are also supported ([`Float16`](@ref)), but they are +implemented in software and use [`Float32`](@ref) for calculations. ```jldoctest julia> sizeof(Float16(4.)) @@ -404,11 +404,11 @@ julia> eps() # same as eps(Float64) 2.220446049250313e-16 ``` -These values are `2.0^-23` and `2.0^-52` as `Float32` and `Float64` values, respectively. The -[`eps()`](@ref) function can also take a floating-point value as an argument, and gives the absolute -difference between that value and the next representable floating point value. That is, `eps(x)` -yields a value of the same type as `x` such that `x + eps(x)` is the next representable floating-point -value larger than `x`: +These values are `2.0^-23` and `2.0^-52` as [`Float32`](@ref) and [`Float64`](@ref) values, +respectively. The [`eps()`](@ref) function can also take a floating-point value as an +argument, and gives the absolute difference between that value and the next representable +floating point value. That is, `eps(x)` yields a value of the same type as `x` such that +`x + eps(x)` is the next representable floating-point value larger than `x`: ```jldoctest julia> eps(1.0) diff --git a/doc/src/manual/mathematical-operations.md b/doc/src/manual/mathematical-operations.md index 2727ec20cd8539..a6ff8bdea53f8b 100644 --- a/doc/src/manual/mathematical-operations.md +++ b/doc/src/manual/mathematical-operations.md @@ -21,7 +21,7 @@ are supported on all primitive numeric types: | `x ^ y` | power | raises `x` to the `y`th power | | `x % y` | remainder | equivalent to `rem(x,y)` | -as well as the negation on `Bool` types: +as well as the negation on [`Bool`](@ref) types: | Expression | Name | Description | |:---------- |:-------- |:---------------------------------------- | diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index 445049ec3cf39d..1804f39559b20b 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -972,7 +972,7 @@ julia> foo(4) 16 ``` -Note that there is no printout of `Int64`. We can see that the body of the generated function +Note that there is no printout of [`Int64`](@ref). We can see that the body of the generated function was only executed once here, for the specific set of argument types, and the result was cached. After that, for this example, the expression returned from the generated function on the first invocation was re-used as the method body. However, the actual caching behavior is an implementation-defined diff --git a/doc/src/manual/methods.md b/doc/src/manual/methods.md index bc649bf4c2f35d..c8843e18b0635e 100644 --- a/doc/src/manual/methods.md +++ b/doc/src/manual/methods.md @@ -58,7 +58,8 @@ julia> f(x::Float64, y::Float64) = 2x + y f (generic function with 1 method) ``` -This function definition applies only to calls where `x` and `y` are both values of type `Float64`: +This function definition applies only to calls where `x` and `y` are both values of type +[`Float64`](@ref): ```jldoctest fofxy julia> f(2.0, 3.0) @@ -87,12 +88,12 @@ julia> f("2.0", "3.0") ERROR: MethodError: no method matching f(::String, ::String) ``` -As you can see, the arguments must be precisely of type `Float64`. Other numeric types, such as -integers or 32-bit floating-point values, are not automatically converted to 64-bit floating-point, -nor are strings parsed as numbers. Because `Float64` is a concrete type and concrete types cannot -be subclassed in Julia, such a definition can only be applied to arguments that are exactly of -type `Float64`. It may often be useful, however, to write more general methods where the declared -parameter types are abstract: +As you can see, the arguments must be precisely of type [`Float64`](@ref). Other numeric +types, such as integers or 32-bit floating-point values, are not automatically converted +to 64-bit floating-point, nor are strings parsed as numbers. Because `Float64` is a concrete +type and concrete types cannot be subclassed in Julia, such a definition can only be applied +to arguments that are exactly of type `Float64`. It may often be useful, however, to write +more general methods where the declared parameter types are abstract: ```jldoctest fofxy julia> f(x::Number, y::Number) = 2x - y @@ -102,9 +103,10 @@ julia> f(2.0, 3) 1.0 ``` -This method definition applies to any pair of arguments that are instances of `Number`. They need -not be of the same type, so long as they are each numeric values. The problem of handling disparate -numeric types is delegated to the arithmetic operations in the expression `2x - y`. +This method definition applies to any pair of arguments that are instances of [`Number`](@ref). +They need not be of the same type, so long as they are each numeric values. The problem of +handling disparate numeric types is delegated to the arithmetic operations in the +expression `2x - y`. To define a function with multiple methods, one simply defines the function multiple times, with different numbers and types of arguments. The first method definition for a function creates the @@ -112,9 +114,9 @@ function object, and subsequent method definitions add new methods to the existi The most specific method definition matching the number and types of the arguments will be executed when the function is applied. Thus, the two method definitions above, taken together, define the behavior for `f` over all pairs of instances of the abstract type `Number` -- but with a different -behavior specific to pairs of `Float64` values. If one of the arguments is a 64-bit float but -the other one is not, then the `f(Float64,Float64)` method cannot be called and the more general -`f(Number,Number)` method must be used: +behavior specific to pairs of [`Float64`](@ref) values. If one of the arguments is a 64-bit +float but the other one is not, then the `f(Float64,Float64)` method cannot be called and +the more general `f(Number,Number)` method must be used: ```jldoctest fofxy julia> f(2.0, 3.0) diff --git a/doc/src/manual/noteworthy-differences.md b/doc/src/manual/noteworthy-differences.md index 5457f201dbd6d1..98740263fc3640 100644 --- a/doc/src/manual/noteworthy-differences.md +++ b/doc/src/manual/noteworthy-differences.md @@ -239,11 +239,11 @@ For users coming to Julia from R, these are some noteworthy differences: unsigned and/or signed vs. unsigned. Decimal literals are always signed, and hexadecimal literals (which start with `0x` like C/C++), are unsigned. Hexadecimal literals also, unlike C/C++/Java and unlike decimal literals in Julia, have a type based on the *length* of the literal, including - leading 0s. For example, `0x0` and `0x00` have type UInt8, `0x000` and `0x0000` have type `UInt16`, - then literals with 5 to 8 hex digits have type `UInt32`, 9 to 16 hex digits type `UInt64` and - 17 to 32 hex digits type `UInt128`. This needs to be taken into account when defining hexadecimal - masks, for example `~0xf == 0xf0` is very different from `~0x000f == 0xfff0`. 64 bit `Float64` - and 32 bit `Float32` bit literals are expressed as `1.0` and `1.0f0` respectively. Floating point + leading 0s. For example, `0x0` and `0x00` have type [`UInt8`](@ref), `0x000` and `0x0000` have type + [`UInt16`](@ref), then literals with 5 to 8 hex digits have type `UInt32`, 9 to 16 hex digits type + `UInt64` and 17 to 32 hex digits type `UInt128`. This needs to be taken into account when defining + hexadecimal masks, for example `~0xf == 0xf0` is very different from `~0x000f == 0xfff0`. 64 bit `Float64` + and 32 bit [`Float32`](@ref) bit literals are expressed as `1.0` and `1.0f0` respectively. Floating point literals are rounded (and not promoted to the `BigFloat` type) if they can not be exactly represented. Floating point literals are closer in behavior to C/C++. Octal (prefixed with `0o`) and binary (prefixed with `0b`) literals are also treated as unsigned. @@ -251,7 +251,7 @@ For users coming to Julia from R, these are some noteworthy differences: `"` 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`](@ref) 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. `(a, b) = myfunction()` or diff --git a/doc/src/manual/performance-tips.md b/doc/src/manual/performance-tips.md index 14c91c0d9e3794..92fd3bc55aa30c 100644 --- a/doc/src/manual/performance-tips.md +++ b/doc/src/manual/performance-tips.md @@ -137,10 +137,10 @@ if (f = rand()) < .8 end ``` -Because `a` is a an array of abstract type `Real`, it must be able to hold any `Real` value. Since -`Real` objects can be of arbitrary size and structure, `a` must be represented as an array of -pointers to individually allocated `Real` objects. Because `f` will always be a [`Float64`](@ref), -we should instead, use: +Because `a` is a an array of abstract type [`Real`](@ref), it must be able to hold any +`Real` value. Since `Real` objects can be of arbitrary size and structure, `a` must be +represented as an array of pointers to individually allocated `Real` objects. Because `f` +will always be a [`Float64`](@ref), we should instead, use: ```julia a = Float64[] # typeof(a) = Array{Float64,1} @@ -188,9 +188,9 @@ MyAmbiguousType `b` and `c` have the same type, yet their underlying representation of data in memory is very different. Even if you stored just numeric values in field `a`, the fact that the memory representation -of a `UInt8` differs from a `Float64` also means that the CPU needs to handle them using two different -kinds of instructions. Since the required information is not available in the type, such decisions -have to be made at run-time. This slows performance. +of a [`UInt8`](@ref) differs from a [`Float64`](@ref) also means that the CPU needs to handle +them using two different kinds of instructions. Since the required information is not available +in the type, such decisions have to be made at run-time. This slows performance. You can do better by declaring the type of `a`. Here, we are focused on the case where `a` might be any one of several types, in which case the natural solution is to use parameters. For example: @@ -473,9 +473,9 @@ function foo(a::Array{Any,1}) end ``` -Here, we happened to know that the first element of `a` would be an `Int32`. Making an annotation -like this has the added benefit that it will raise a run-time error if the value is not of the -expected type, potentially catching certain bugs earlier. +Here, we happened to know that the first element of `a` would be an [`Int32`](@ref). Making +an annotation like this has the added benefit that it will raise a run-time error if the +value is not of the expected type, potentially catching certain bugs earlier. ### Declare types of keyword arguments @@ -1388,7 +1388,7 @@ code defined in `pos`. Starting at `2:`, the variable `y` is defined, and again annotated as a `Union` type. Next, we see that the compiler created the temporary variable `_var1` to hold the result of `y*x`. Because -a [`Float64`](@ref) times *either* an `Int64` or [`Float64`](@ref) yields a [`Float64`](@ref), +a [`Float64`](@ref) times *either* an [`Int64`](@ref) or `Float64` yields a `Float64`, all type-instability ends here. The net result is that `f(x::Float64)` will not be type-unstable in its output, even if some of the intermediate computations are type-unstable. diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index 4d4b9d5a0f1588..a1298af12de5bf 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -64,8 +64,8 @@ julia> typeof(ans) Int64 ``` -On 32-bit architectures, [`typeof(ans)`](@ref) will be `Int32`. You can convert an integer value -back to a `Char` just as easily: +On 32-bit architectures, [`typeof(ans)`](@ref) will be [`Int32`](@ref). You can convert an +integer value back to a `Char` just as easily: ```jldoctest julia> Char(120) @@ -778,8 +778,8 @@ for regular expressions containing quotation marks or newlines). ## [Byte Array Literals](@id man-byte-array-literals) Another useful non-standard string literal is the byte-array string literal: `b"..."`. This form -lets you use string notation to express literal byte arrays -- i.e. arrays of `UInt8` values. -The rules for byte array literals are the following: +lets you use string notation to express literal byte arrays -- i.e. arrays of +[`UInt8`](@ref) values. The rules for byte array literals are the following: * ASCII characters and ASCII escapes produce a single byte. * `\x` and octal escape sequences produce the *byte* corresponding to the escape value. diff --git a/doc/src/manual/style-guide.md b/doc/src/manual/style-guide.md index c4ac88ffc20a61..fccb5559d9272a 100644 --- a/doc/src/manual/style-guide.md +++ b/doc/src/manual/style-guide.md @@ -32,11 +32,12 @@ complex(float(x)) The second version will convert `x` to an appropriate type, instead of always the same type. This style point is especially relevant to function arguments. For example, don't declare an argument -to be of type `Int` or `Int32` if it really could be any integer, expressed with the abstract -type `Integer`. In fact, in many cases you can omit the argument type altogether, unless it is -needed to disambiguate from other method definitions, since a [`MethodError`](@ref) will be thrown -anyway if a type is passed that does not support any of the requisite operations. (This is known -as [duck typing](https://en.wikipedia.org/wiki/Duck_typing).) +to be of type `Int` or [`Int32`](@ref) if it really could be any integer, expressed with the abstract +type [`Integer`](@ref). In fact, in many cases you can omit the argument type altogether, +unless it is needed to disambiguate from other method definitions, since a +[`MethodError`](@ref) will be thrown anyway if a type is passed that does not support any +of the requisite operations. (This is known as +[duck typing](https://en.wikipedia.org/wiki/Duck_typing).) For example, consider the following definitions of a function `addone` that returns one plus its argument: @@ -356,7 +357,7 @@ julia> g(1) As you can see, the second version, where we used an `Int` literal, preserved the type of the input argument, while the first didn't. This is because e.g. `promote_type(Int, Float64) == Float64`, -and promotion happens with the multiplication. Similarly, `Rational` literals are less type disruptive +and promotion happens with the multiplication. Similarly, [`Rational`](@ref) literals are less type disruptive than [`Float64`](@ref) literals, but more disruptive than `Int`s: ```jldoctest diff --git a/doc/src/manual/types.md b/doc/src/manual/types.md index 633ba5b47fac7b..da93e407f2cf26 100644 --- a/doc/src/manual/types.md +++ b/doc/src/manual/types.md @@ -133,18 +133,19 @@ system: they form the conceptual hierarchy which makes Julia's type system more of object implementations. Recall that in [Integers and Floating-Point Numbers](@ref), we introduced a variety of concrete -types of numeric values: `Int8`, `UInt8`, `Int16`, `UInt16`, `Int32`, `UInt32`, `Int64`, `UInt64`, -`Int128`, `UInt128`, `Float16`, [`Float32`](@ref), and [`Float64`](@ref). Although they have -different representation sizes, `Int8`, `Int16`, `Int32`, `Int64` and `Int128` all have in common -that they are signed integer types. Likewise `UInt8`, `UInt16`, `UInt32`, `UInt64` and `UInt128` -are all unsigned integer types, while `Float16`, [`Float32`](@ref) and [`Float64`](@ref) are distinct -in being floating-point types rather than integers. It is common for a piece of code to make sense, -for example, only if its arguments are some kind of integer, but not really depend on what particular -*kind* of integer. For example, the greatest common denominator algorithm works for all kinds -of integers, but will not work for floating-point numbers. Abstract types allow the construction -of a hierarchy of types, providing a context into which concrete types can fit. This allows you, -for example, to easily program to any type that is an integer, without restricting an algorithm -to a specific type of integer. +types of numeric values: [`Int8`](@ref), [`UInt8`](@ref), [`Int16`](@ref), [`UInt16`](@ref), +[`Int32`](@ref), [`UInt32`](@ref), [`Int64`](@ref), [`UInt64`](@ref), [`Int128`](@ref), +[`UInt128`](@ref), [`Float16`](@ref), [`Float32`](@ref), and [`Float64`](@ref). Although +they have different representation sizes, `Int8`, `Int16`, `Int32`, `Int64` and `Int128` +all have in common that they are signed integer types. Likewise `UInt8`, `UInt16`, `UInt32`, +`UInt64` and `UInt128` are all unsigned integer types, while `Float16`, `Float32` and +`Float64` are distinct in being floating-point types rather than integers. It is common for +a piece of code to make sense, for example, only if its arguments are some kind of integer, +but not really depend on what particular *kind* of integer. For example, the greatest common +denominator algorithm works for all kinds of integers, but will not work for floating-point +numbers. Abstract types allow the construction of a hierarchy of types, providing a context +into which concrete types can fit. This allows you, for example, to easily program to any type +that is an integer, without restricting an algorithm to a specific type of integer. Abstract types are declared using the `abstract type` keyword. The general syntaxes for declaring an abstract type are: @@ -175,13 +176,14 @@ abstract type Signed <: Integer end abstract type Unsigned <: Integer end ``` -The `Number` type is a direct child type of `Any`, and `Real` is its child. In turn, `Real` has -two children (it has more, but only two are shown here; we'll get to the others later): `Integer` -and `AbstractFloat`, separating the world into representations of integers and representations -of real numbers. Representations of real numbers include, of course, floating-point types, but -also include other types, such as rationals. Hence, `AbstractFloat` is a proper subtype of `Real`, -including only floating-point representations of real numbers. Integers are further subdivided -into `Signed` and `Unsigned` varieties. +The [`Number`](@ref) type is a direct child type of `Any`, and [`Real`](@ref) is its child. +In turn, `Real` has two children (it has more, but only two are shown here; we'll get to +the others later): [`Integer`](@ref) and [`AbstractFloat`](@ref), separating the world into +representations of integers and representations of real numbers. Representations of real +numbers include, of course, floating-point types, but also include other types, such as +rationals. Hence, `AbstractFloat` is a proper subtype of `Real`, including only +floating-point representations of real numbers. Integers are further subdivided into +[`Signed`](@ref) and [`Unsigned`](@ref) varieties. The `<:` operator in general means "is a subtype of", and, used in declarations like this, declares the right-hand type to be an immediate supertype of the newly declared type. It can also be used @@ -268,19 +270,21 @@ primitive type «name» <: «supertype» «bits» end The number of bits indicates how much storage the type requires and the name gives the new type a name. A primitive type can optionally be declared to be a subtype of some supertype. If a supertype is omitted, then the type defaults to having `Any` as its immediate supertype. The declaration -of `Bool` above therefore means that a boolean value takes eight bits to store, and has `Integer` -as its immediate supertype. Currently, only sizes that are multiples of 8 bits are supported. -Therefore, boolean values, although they really need just a single bit, cannot be declared to -be any smaller than eight bits. - -The types `Bool`, `Int8` and `UInt8` all have identical representations: they are eight-bit chunks -of memory. Since Julia's type system is nominative, however, they are not interchangeable despite -having identical structure. A fundamental difference between them is that they have different -supertypes: `Bool`'s direct supertype is `Integer`, `Int8`'s is `Signed`, and `UInt8`'s is `Unsigned`. -All other differences between `Bool`, `Int8`, and `UInt8` are matters of behavior -- the way functions -are defined to act when given objects of these types as arguments. This is why a nominative type -system is necessary: if structure determined type, which in turn dictates behavior, then it would -be impossible to make `Bool` behave any differently than `Int8` or `UInt8`. +of [`Bool`](@ref) above therefore means that a boolean value takes eight bits to store, and has +[`Integer`](@ref) as its immediate supertype. Currently, only sizes that are multiples of +8 bits are supported. Therefore, boolean values, although they really need just a single bit, +cannot be declared to be any smaller than eight bits. + +The types [`Bool`](@ref), [`Int8`](@ref) and [`UInt8`](@ref) all have identical representations: +they are eight-bit chunks of memory. Since Julia's type system is nominative, however, they +are not interchangeable despite having identical structure. A fundamental difference between +them is that they have different supertypes: [`Bool`](@ref)'s direct supertype is [`Integer`](@ref), +[`Int8`](@ref)'s is [`Signed`](@ref), and [`UInt8`](@ref)'s is [`Unsigned`](@ref). All other +differences between [`Bool`](@ref), [`Int8`](@ref), and [`UInt8`](@ref) are matters of +behavior -- the way functions are defined to act when given objects of these types as +arguments. This is why a nominative type system is necessary: if structure determined type, +which in turn dictates behavior, then it would be impossible to make [`Bool`](@ref) behave +any differently than [`Int8`](@ref) or [`UInt8`](@ref). ## Composite Types @@ -586,14 +590,16 @@ have different representations in memory: * An instance of `Point{Float64}` can be represented compactly and efficiently as an immediate pair of 64-bit values; - * An instance of `Point{Real}` must be able to hold any pair of instances of `Real`. Since objects - that are instances of `Real` can be of arbitrary size and structure, in practice an instance of - `Point{Real}` must be represented as a pair of pointers to individually allocated `Real` objects. + * An instance of `Point{Real}` must be able to hold any pair of instances of [`Real`](@ref). + Since objects that are instances of `Real` can be of arbitrary size and structure, in + practice an instance of `Point{Real}` must be represented as a pair of pointers to + individually allocated `Real` objects. The efficiency gained by being able to store `Point{Float64}` objects with immediate values is magnified enormously in the case of arrays: an `Array{Float64}` can be stored as a contiguous memory block of 64-bit floating-point values, whereas an `Array{Real}` must be an array of pointers -to individually allocated `Real` objects -- which may well be [boxed](https://en.wikipedia.org/wiki/Object_type_%28object-oriented_programming%29#Boxing) +to individually allocated [`Real`](@ref) objects -- which may well be +[boxed](https://en.wikipedia.org/wiki/Object_type_%28object-oriented_programming%29#Boxing) 64-bit floating-point values, but also might be arbitrarily large, complex objects, which are declared to be implementations of the `Real` abstract type. @@ -607,7 +613,7 @@ end ``` A correct way to define a method that accepts all arguments of type `Point{T}` where `T` is -a subtype of `Real` is: +a subtype of [`Real`](@ref) is: ```julia function norm(p::Point{<:Real}) @@ -784,8 +790,8 @@ possible types. In such situations, one can constrain the range of `T` like so: julia> abstract type Pointy{T<:Real} end ``` -With such a declaration, it is acceptable to use any type that is a subtype of `Real` in place -of `T`, but not types that are not subtypes of `Real`: +With such a declaration, it is acceptable to use any type that is a subtype of +[`Real`](@ref) in place of `T`, but not types that are not subtypes of `Real`: ```jldoctest realpointytype julia> Pointy{Float64} @@ -811,8 +817,8 @@ end ``` To give a real-world example of how all this parametric type machinery can be useful, here is -the actual definition of Julia's `Rational` immutable type (except that we omit the constructor -here for simplicity), representing an exact ratio of integers: +the actual definition of Julia's [`Rational`](@ref) immutable type (except that we omit the +constructor here for simplicity), representing an exact ratio of integers: ```julia struct Rational{T<:Integer} <: Real @@ -822,8 +828,8 @@ end ``` It only makes sense to take ratios of integer values, so the parameter type `T` is restricted -to being a subtype of `Integer`, and a ratio of integers represents a value on the real number -line, so any `Rational` is an instance of the `Real` abstraction. +to being a subtype of [`Integer`](@ref), and a ratio of integers represents a value on the +real number line, so any [`Rational`](@ref) is an instance of the [`Real`](@ref) abstraction. ### Tuple Types @@ -1008,21 +1014,22 @@ Using explicit `where` syntax, any subset of parameters can be fixed. For exampl 1-dimensional arrays can be written as `Array{T,1} where T`. Type variables can be restricted with subtype relations. -`Array{T} where T<:Integer` refers to all arrays whose element type is some kind of `Integer`. +`Array{T} where T<:Integer` refers to all arrays whose element type is some kind of +[`Integer`](@ref). The syntax `Array{<:Integer}` is a convenient shorthand for `Array{T} where T<:Integer`. Type variables can have both lower and upper bounds. -`Array{T} where Int<:T<:Number` refers to all arrays of `Number`s that are able to contain `Int`s -(since `T` must be at least as big as `Int`). +`Array{T} where Int<:T<:Number` refers to all arrays of [`Number`](@ref)s that are able to +contain `Int`s (since `T` must be at least as big as `Int`). The syntax `where T>:Int` also works to specify only the lower bound of a type variable, and `Array{>:Int}` is equivalent to `Array{T} where T>:Int`. Since `where` expressions nest, type variable bounds can refer to outer type variables. -For example `Tuple{T,Array{S}} where S<:AbstractArray{T} where T<:Real` refers to 2-tuples whose first -element is some `Real`, and whose second element is an `Array` of any kind of array whose element type -contains the type of the first tuple element. +For example `Tuple{T,Array{S}} where S<:AbstractArray{T} where T<:Real` refers to 2-tuples +whose first element is some [`Real`](@ref), and whose second element is an `Array` of any +kind of array whose element type contains the type of the first tuple element. -The `where` keyword itself can be nested inside a more complex declaration. For example, consider the -two types created by the following declarations: +The `where` keyword itself can be nested inside a more complex declaration. For example, +consider the two types created by the following declarations: ```jldoctest julia> const T1 = Array{Array{T,1} where T, 1} @@ -1056,8 +1063,8 @@ element type. Sometimes it is convenient to introduce a new name for an already expressible type. This can be done with a simple assignment statement. -For example, `UInt` is aliased to either `UInt32` or `UInt64` as is appropriate -for the size of pointers on the system: +For example, `UInt` is aliased to either [`UInt32`](@ref) or [`UInt64`](@ref) as is +appropriate for the size of pointers on the system: ```julia-repl # 32-bit system: @@ -1080,11 +1087,12 @@ end ``` Of course, this depends on what `Int` is aliased to -- but that is predefined to be the correct -type -- either `Int32` or `Int64`. +type -- either [`Int32`](@ref) or [`Int64`](@ref). -(Note that unlike `Int`, `Float` does not exist as a type alias for a specific sized `AbstractFloat`. -Unlike with integer registers, the floating point register sizes are specified by the IEEE-754 standard. -Whereas the size of `Int` reflects the size of a native pointer on that machine.) +(Note that unlike `Int`, `Float` does not exist as a type alias for a specific sized +[`AbstractFloat`](@ref). Unlike with integer registers, the floating point register sizes +are specified by the IEEE-754 standard. Whereas the size of `Int` reflects the size of a +native pointer on that machine.) ## Operations on Types @@ -1175,11 +1183,13 @@ julia> Polar(r::Real,Θ::Real) = Polar(promote(r,Θ)...) Polar ``` -Here, we've added a custom constructor function so that it can take arguments of different `Real` -types and promote them to a common type (see [Constructors](@ref man-constructors) and [Conversion and Promotion](@ref conversion-and-promotion)). -(Of course, we would have to define lots of other methods, too, to make it act like a `Number`, -e.g. `+`, `*`, `one`, `zero`, promotion rules and so on.) By default, instances of this type display -rather simply, with information about the type name and the field values, as e.g. `Polar{Float64}(3.0,4.0)`. +Here, we've added a custom constructor function so that it can take arguments of different +[`Real`](@ref) types and promote them to a common type (see [Constructors](@ref man-constructors) +and [Conversion and Promotion](@ref conversion-and-promotion)). +(Of course, we would have to define lots of other methods, too, to make it act like a +[`Number`](@ref), e.g. `+`, `*`, `one`, `zero`, promotion rules and so on.) By default, +instances of this type display rather simply, with information about the type name and +the field values, as e.g. `Polar{Float64}(3.0,4.0)`. If we want it to display instead as `3.0 * exp(4.0im)`, we would define the following method to print the object to a given output object `io` (representing a file, terminal, buffer, etcetera; @@ -1247,7 +1257,7 @@ julia> show(STDOUT, "text/html", Polar(3.0,4.0)) In Julia, you can't dispatch on a *value* such as `true` or `false`. However, you can dispatch on parametric types, and Julia allows you to include "plain bits" values (Types, Symbols, Integers, floating-point numbers, tuples, etc.) as type parameters. A common example is the dimensionality -parameter in `Array{T,N}`, where `T` is a type (e.g., `Float64`) but `N` is just an `Int`. +parameter in `Array{T,N}`, where `T` is a type (e.g., [`Float64`](@ref)) but `N` is just an `Int`. You can create your own custom types that take values as parameters, and use them to control dispatch of custom types. By way of illustration of this idea, let's introduce a parametric type, `Val{T}`, diff --git a/doc/src/stdlib/linalg.md b/doc/src/stdlib/linalg.md index bee85bb1522274..0f415013c51dcb 100644 --- a/doc/src/stdlib/linalg.md +++ b/doc/src/stdlib/linalg.md @@ -154,13 +154,13 @@ Base.At_rdiv_Bt In Julia (as in much of scientific computation), dense linear-algebra operations are based on the [LAPACK library](http://www.netlib.org/lapack/), which in turn is built on top of basic linear-algebra -building-blocks known as the [BLAS](http://www.netlib.org/blas/). There are highly optimized +building-blocks known as the [BLAS](http://www.netlib.org/blas/). There are highly optimized implementations of BLAS available for every computer architecture, and sometimes in high-performance linear algebra routines it is useful to call the BLAS functions directly. `Base.LinAlg.BLAS` provides wrappers for some of the BLAS functions. Those BLAS functions that overwrite one of the input arrays have names ending in `'!'`. Usually, a BLAS function has -four methods defined, for `Float64`, `Float32`, `Complex128`, and `Complex64` arrays. +four methods defined, for [`Float64`](@ref), [`Float32`](@ref), `Complex128`, and `Complex64` arrays. ### [BLAS Character Arguments](@id stdlib-blas-chars) Many BLAS functions accept arguments that determine whether to transpose an argument (`trans`), @@ -245,8 +245,8 @@ Base.LinAlg.I `Base.LinAlg.LAPACK` provides wrappers for some of the LAPACK functions for linear algebra. Those functions that overwrite one of the input arrays have names ending in `'!'`. -Usually a function has 4 methods defined, one each for `Float64`, `Float32`, `Complex128` and -`Complex64` arrays. +Usually a function has 4 methods defined, one each for [`Float64`](@ref), [`Float32`](@ref), +`Complex128` and `Complex64` arrays. Note that the LAPACK API provided by Julia can and will change in the future. Since this API is not user-facing, there is no commitment to support/deprecate this specific set of functions in diff --git a/doc/src/stdlib/numbers.md b/doc/src/stdlib/numbers.md index df3a4f63ce6371..af00def34e64ec 100644 --- a/doc/src/stdlib/numbers.md +++ b/doc/src/stdlib/numbers.md @@ -117,7 +117,8 @@ Base.iseven ## BigFloats -The `BigFloat` type implements arbitrary-precision floating-point arithmetic using the [GNU MPFR library](http://www.mpfr.org/). +The [`BigFloat`](@ref) type implements arbitrary-precision floating-point arithmetic using +the [GNU MPFR library](http://www.mpfr.org/). ```@docs Base.precision @@ -143,10 +144,12 @@ dimension specifications `dims...` (which can be given as a tuple) to generate a values. A `MersenneTwister` or `RandomDevice` RNG can generate random numbers of the following types: -`Float16`, `Float32`, `Float64`, `Bool`, `Int8`, `UInt8`, `Int16`, `UInt16`, `Int32`, `UInt32`, -`Int64`, `UInt64`, `Int128`, `UInt128`, `BigInt` (or complex numbers of those types). Random floating -point numbers are generated uniformly in ``[0, 1)``. As `BigInt` represents unbounded integers, -the interval must be specified (e.g. `rand(big(1:6))`). +[`Float16`](@ref), [`Float32`](@ref), [`Float64`](@ref), [`Bool`](@ref), [`Int8`](@ref), +[`UInt8`](@ref), [`Int16`](@ref), [`UInt16`](@ref), [`Int32`](@ref), [`UInt32`](@ref), +[`Int64`](@ref), [`UInt64`](@ref), [`Int128`](@ref), [`UInt128`](@ref), [`BigInt`](@ref) +(or complex numbers of those types). Random floating point numbers are generated uniformly +in ``[0, 1)``. As `BigInt` represents unbounded integers, the interval must be specified +(e.g. `rand(big(1:6))`). ```@docs Base.Random.srand From 3aa4db871f0bfcd586ebe12de2e50761a4050758 Mon Sep 17 00:00:00 2001 From: "Jane E. Herriman" Date: Sun, 28 May 2017 12:42:55 -0700 Subject: [PATCH 28/53] Fix failing doctests --- base/array.jl | 4 ++-- base/math.jl | 2 +- doc/src/devdocs/reflection.md | 3 ++- doc/src/manual/complex-and-rational-numbers.md | 6 +++--- doc/src/manual/control-flow.md | 2 +- doc/src/manual/conversion-and-promotion.md | 2 +- doc/src/manual/faq.md | 2 +- doc/src/manual/metaprogramming.md | 12 ++++++++---- 8 files changed, 19 insertions(+), 14 deletions(-) diff --git a/base/array.jl b/base/array.jl index 80c04a30903dc4..e7adc6e67eb2b2 100644 --- a/base/array.jl +++ b/base/array.jl @@ -860,8 +860,8 @@ julia> deleteat!([6, 5, 4, 3, 2, 1], [true, false, true, false, true, false]) julia> deleteat!([6, 5, 4, 3, 2, 1], (2, 2)) ERROR: ArgumentError: indices must be unique and sorted Stacktrace: - [1] _deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:873 - [2] deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:860 + [1] _deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:880 + [2] deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:867 ``` """ deleteat!(a::Vector, inds) = _deleteat!(a, inds) diff --git a/base/math.jl b/base/math.jl index 1956adf268260a..c033f2d8e8efd8 100644 --- a/base/math.jl +++ b/base/math.jl @@ -462,7 +462,7 @@ julia> √(a^2 + a^2) # a^2 overflows ERROR: DomainError: sqrt will only return a complex result if called with a complex argument. Try sqrt(complex(x)). Stacktrace: - [1] sqrt(::Int64) at ./math.jl:431 + [1] sqrt(::Int64) at ./math.jl:447 ``` """ hypot(x::Number, y::Number) = hypot(promote(x, y)...) diff --git a/doc/src/devdocs/reflection.md b/doc/src/devdocs/reflection.md index d31188f80b9aa7..8baa61a222508e 100644 --- a/doc/src/devdocs/reflection.md +++ b/doc/src/devdocs/reflection.md @@ -99,7 +99,8 @@ and variable assignments: julia> expand( :(f() = 1) ) :(begin $(Expr(:method, :f)) - $(Expr(:method, :f, :((Core.svec)((Core.svec)((Core.Typeof)(f)), (Core.svec)())), CodeInfo(:(begin # none, line 1: + $(Expr(:method, :f, :((Core.svec)((Core.svec)((Core.Typeof)(f)), (Core.svec)())), CodeInfo(:(begin + #= none:1 =# return 1 end)), false)) return f diff --git a/doc/src/manual/complex-and-rational-numbers.md b/doc/src/manual/complex-and-rational-numbers.md index d3245c27a96393..29636b4a2f1398 100644 --- a/doc/src/manual/complex-and-rational-numbers.md +++ b/doc/src/manual/complex-and-rational-numbers.md @@ -143,7 +143,7 @@ julia> sqrt(-1) ERROR: DomainError: sqrt will only return a complex result if called with a complex argument. Try sqrt(complex(x)). Stacktrace: - [1] sqrt(::Int64) at ./math.jl:431 + [1] sqrt(::Int64) at ./math.jl:447 julia> sqrt(-1 + 0im) 0.0 + 1.0im @@ -283,8 +283,8 @@ Trying to construct a [`NaN`](@ref) rational value, however, is not: julia> 0//0 ERROR: ArgumentError: invalid rational: zero(Int64)//zero(Int64) Stacktrace: - [1] Rational{Int64}(::Int64, ::Int64) at ./rational.jl:8 - [2] //(::Int64, ::Int64) at ./rational.jl:35 + [1] Rational{Int64}(::Int64, ::Int64) at ./rational.jl:13 + [2] //(::Int64, ::Int64) at ./rational.jl:40 ``` As usual, the promotion system makes interactions with other numeric types effortless: diff --git a/doc/src/manual/control-flow.md b/doc/src/manual/control-flow.md index 1dc395b2a31d5f..e06586239edd1e 100644 --- a/doc/src/manual/control-flow.md +++ b/doc/src/manual/control-flow.md @@ -571,7 +571,7 @@ julia> sqrt(-1) ERROR: DomainError: sqrt will only return a complex result if called with a complex argument. Try sqrt(complex(x)). Stacktrace: - [1] sqrt(::Int64) at ./math.jl:431 + [1] sqrt(::Int64) at ./math.jl:447 ``` You may define your own exceptions in the following way: diff --git a/doc/src/manual/conversion-and-promotion.md b/doc/src/manual/conversion-and-promotion.md index 3ffd6e2e338566..5cc15a893ef4ed 100644 --- a/doc/src/manual/conversion-and-promotion.md +++ b/doc/src/manual/conversion-and-promotion.md @@ -121,7 +121,7 @@ false julia> convert(Bool, 1im) ERROR: InexactError() Stacktrace: - [1] convert(::Type{Bool}, ::Complex{Int64}) at ./complex.jl:23 + [1] convert(::Type{Bool}, ::Complex{Int64}) at ./complex.jl:31 julia> convert(Bool, 0im) false diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index 4ff850b44ea00c..39a03f30c13fd5 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -228,7 +228,7 @@ julia> sqrt(-2.0) ERROR: DomainError: sqrt will only return a complex result if called with a complex argument. Try sqrt(complex(x)). Stacktrace: - [1] sqrt(::Float64) at ./math.jl:422 + [1] sqrt(::Float64) at ./math.jl:438 julia> 2^-5 ERROR: DomainError: diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index 1804f39559b20b..a6d3fa57840e59 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -194,9 +194,12 @@ julia> ex = quote y = 2 x + y end -quote # none, line 2: - x = 1 # none, line 3: - y = 2 # none, line 4: +quote + #= none:2 =# + x = 1 + #= none:3 =# + y = 2 + #= none:4 =# x + y end @@ -521,13 +524,14 @@ The location information can be accessed by referencing `__source__.line` and `_ ```jldoctest julia> macro __LOCATION__(); return QuoteNode(__source__); end +@__LOCATION__ (macro with 1 method) julia> dump( @__LOCATION__( )) LineNumberNode line: Int64 2 - file: Symbol REPL[2] + file: Symbol none ``` ### Building an advanced macro From 55a7bea619ee1ed82c10c7b95c0763eeed215d24 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Fri, 19 May 2017 12:17:16 +0200 Subject: [PATCH 29/53] add rand(::IntSet) --- base/random.jl | 16 +++++++++++++++- test/random.jl | 7 ++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/base/random.jl b/base/random.jl index 847c61e2f9a1f5..6357acccc8b2de 100644 --- a/base/random.jl +++ b/base/random.jl @@ -339,7 +339,7 @@ function rand(r::AbstractRNG, ::Type{Char}) (c < 0xd800) ? Char(c) : Char(c+0x800) end -# random values from Dict or Set (for efficiency) +# random values from Dict, Set, IntSet (for efficiency) function rand(r::AbstractRNG, t::Dict) isempty(t) && throw(ArgumentError("dict must be non-empty")) n = length(t.slots) @@ -352,6 +352,20 @@ rand(t::Dict) = rand(GLOBAL_RNG, t) rand(r::AbstractRNG, s::Set) = rand(r, s.dict).first rand(s::Set) = rand(GLOBAL_RNG, s) +function rand(r::AbstractRNG, s::IntSet) + isempty(s) && throw(ArgumentError("collection must be non-empty")) + # s can be empty while s.bits is not, so we cannot rely on the + # length check in RangeGenerator below + rg = RangeGenerator(1:length(s.bits)) + while true + n = rand(r, rg) + @inbounds b = s.bits[n] + b && return n + end +end + +rand(s::IntSet) = rand(GLOBAL_RNG, s) + ## Arrays of random numbers rand(r::AbstractRNG, dims::Dims) = rand(r, Float64, dims) diff --git a/test/random.jl b/test/random.jl index 0d54f0a426cc4e..8a1a918167caf9 100644 --- a/test/random.jl +++ b/test/random.jl @@ -53,11 +53,16 @@ let mt = MersenneTwister(0) rand(coll, 2, 3) end -# rand using Dict, Set +# rand using Dict, Set, IntSet adict = Dict(1=>2, 3=>4, 5=>6) @test rand(adict) in adict +@test_throws ArgumentError rand(Dict()) aset = Set(1:10) @test rand(aset) in aset +@test_throws ArgumentError rand(Set()) +anintset = IntSet(1:10) +@test rand(anintset) in anintset +@test_throws ArgumentError rand(IntSet()) # randn @test randn(MersenneTwister(42)) == -0.5560268761463861 From 97702900e19c65646d0b3a40cfc251e49ec5f410 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Fri, 19 May 2017 12:29:35 +0200 Subject: [PATCH 30/53] optimize rand(::Dict) And change "dict" -> "collection" in the exception, as it is also used from rand(::Set). --- base/random.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base/random.jl b/base/random.jl index 6357acccc8b2de..3c63686376152f 100644 --- a/base/random.jl +++ b/base/random.jl @@ -341,11 +341,11 @@ end # random values from Dict, Set, IntSet (for efficiency) function rand(r::AbstractRNG, t::Dict) - isempty(t) && throw(ArgumentError("dict must be non-empty")) - n = length(t.slots) + isempty(t) && throw(ArgumentError("collection must be non-empty")) + rg = RangeGenerator(1:length(t.slots)) while true - i = rand(r, 1:n) - Base.isslotfilled(t, i) && return (t.keys[i] => t.vals[i]) + i = rand(r, rg) + Base.isslotfilled(t, i) && @inbounds return (t.keys[i] => t.vals[i]) end end rand(t::Dict) = rand(GLOBAL_RNG, t) From 99f207d3a6701bba422ac23beccf4aa99f44c923 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Sat, 20 May 2017 16:08:39 +0200 Subject: [PATCH 31/53] complete the rand API with Dict, Set, IntSet --- base/random.jl | 29 ++++++++++++++++++++++++++++- test/random.jl | 30 +++++++++++++++++++----------- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/base/random.jl b/base/random.jl index 3c63686376152f..7d15e802b678ad 100644 --- a/base/random.jl +++ b/base/random.jl @@ -257,11 +257,22 @@ globalRNG() = GLOBAL_RNG Pick a random element or array of random elements from the set of values specified by `S`; `S` can be * an indexable collection (for example `1:n` or `['x','y','z']`), or +* a `Dict`, a `Set` or an `IntSet`, or * a type: the set of values to pick from is then equivalent to `typemin(S):typemax(S)` for integers (this is not applicable to [`BigInt`](@ref)), and to ``[0, 1)`` for floating point numbers; `S` defaults to [`Float64`](@ref). + +```julia-repl +julia> rand(Int, 2) +2-element Array{Int64,1}: + 1339893410598768192 + 1575814717733606317 + +julia> rand(MersenneTwister(0), Dict(1=>2, 3=>4)) +1=>2 +``` """ @inline rand() = rand(GLOBAL_RNG, CloseOpen) @inline rand(T::Type) = rand(GLOBAL_RNG, T) @@ -276,7 +287,7 @@ rand(r::AbstractArray) = rand(GLOBAL_RNG, r) """ rand!([rng=GLOBAL_RNG], A, [coll]) -Populate the array `A` with random values. If the indexable collection `coll` is specified, +Populate the array `A` with random values. If the collection `coll` is specified, the values are picked randomly from `coll`. This is equivalent to `copy!(A, rand(rng, coll, size(A)))` or `copy!(A, rand(rng, eltype(A), size(A)))` but without allocating a new array. """ @@ -384,6 +395,22 @@ function rand!{T}(r::AbstractRNG, A::AbstractArray{T}) A end +function rand!(r::AbstractRNG, A::AbstractArray, s::Union{Dict,Set,IntSet}) + for i in eachindex(A) + @inbounds A[i] = rand(r, s) + end + A +end + +rand!(A::AbstractArray, s::Union{Dict,Set,IntSet}) = rand!(GLOBAL_RNG, A, s) + +rand(r::AbstractRNG, s::Dict{K,V}, dims::Dims) where {K,V} = rand!(r, Array{Pair{K,V}}(dims), s) +rand(r::AbstractRNG, s::Set{T}, dims::Dims) where {T} = rand!(r, Array{T}(dims), s) +rand(r::AbstractRNG, s::IntSet, dims::Dims) = rand!(r, Array{Int}(dims), s) +rand(r::AbstractRNG, s::Union{Dict,Set,IntSet}, dims::Integer...) = rand(r, s, convert(Dims, dims)) +rand(s::Union{Dict,Set,IntSet}, dims::Integer...) = rand(GLOBAL_RNG, s, dims) +rand(s::Union{Dict,Set,IntSet}, dims::Dims) = rand(GLOBAL_RNG, s, dims) + # MersenneTwister function rand_AbstractArray_Float64!{I<:FloatInterval}(r::MersenneTwister, A::AbstractArray{Float64}, n=length(A), ::Type{I}=CloseOpen) diff --git a/test/random.jl b/test/random.jl index 8a1a918167caf9..79bbc7ecb21266 100644 --- a/test/random.jl +++ b/test/random.jl @@ -53,17 +53,6 @@ let mt = MersenneTwister(0) rand(coll, 2, 3) end -# rand using Dict, Set, IntSet -adict = Dict(1=>2, 3=>4, 5=>6) -@test rand(adict) in adict -@test_throws ArgumentError rand(Dict()) -aset = Set(1:10) -@test rand(aset) in aset -@test_throws ArgumentError rand(Set()) -anintset = IntSet(1:10) -@test rand(anintset) in anintset -@test_throws ArgumentError rand(IntSet()) - # randn @test randn(MersenneTwister(42)) == -0.5560268761463861 A = zeros(2, 2) @@ -320,6 +309,11 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()]) ftypes = [Float16, Float32, Float64] cftypes = [Complex32, Complex64, Complex128, ftypes...] types = [Bool, Char, Base.BitInteger_types..., ftypes...] + collections = [(IntSet(rand(1:100, 20)), Int), + (Set(rand(Int, 20)), Int), + (Dict(zip(rand(Int,10), rand(Int, 10))), Pair{Int,Int}), + (1:100, Int), + (rand(Int, 100), Int)] b2 = big(2) u3 = UInt(3) for f in [rand, randn, randexp] @@ -341,6 +335,20 @@ for rng in ([], [MersenneTwister(0)], [RandomDevice()]) end end end + for (C, T) in collections + a0 = rand(rng..., C) ::T + a1 = rand(rng..., C, 5) ::Vector{T} + a2 = rand(rng..., C, 2, 3) ::Array{T, 2} + a3 = rand!(rng..., Array{T}(5), C) ::Vector{T} + a4 = rand!(rng..., Array{T}(2, 3), C) ::Array{T, 2} + for a in [a0, a1..., a2..., a3..., a4...] + @test a in C + end + end + for C in [1:0, Dict(), Set(), IntSet(), Int[]] + @test_throws ArgumentError rand(rng..., C) + @test_throws ArgumentError rand(rng..., C, 5) + end for f! in [rand!, randn!, randexp!] for T in (f! === rand! ? types : f! === randn! ? cftypes : ftypes) X = T == Bool ? T[0,1] : T[0,1,2] From 15e736977bc94a8a8c0cb02465a00ede2fb71254 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 22 May 2017 16:06:48 -0400 Subject: [PATCH 32/53] improve inference of methods with Type{leaftype} parameters --- base/inference.jl | 4 +++- test/inference.jl | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/base/inference.jl b/base/inference.jl index 45c030af11efb3..f0606e2e9e01af 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -220,6 +220,8 @@ mutable struct InferenceState if isa(atyp, DataType) && isdefined(atyp, :instance) # replace singleton types with their equivalent Const object atyp = Const(atyp.instance) + elseif isconstType(atyp) + atype = Const(atyp.parameters[1]) else atyp = rewrap_unionall(atyp, linfo.specTypes) end @@ -999,7 +1001,7 @@ function apply_type_tfunc(headtypetype::ANY, args::ANY...) ai = args[i] if isType(ai) aip1 = ai.parameters[1] - canconst &= isleaftype(aip1) + canconst &= (isleaftype(aip1) || aip1 === Union{}) push!(tparams, aip1) elseif isa(ai, Const) && (isa(ai.val, Type) || isa(ai.val, TypeVar) || valid_tparam(ai.val)) push!(tparams, ai.val) diff --git a/test/inference.jl b/test/inference.jl index c03636fb26198d..33b5d4ba7d0af1 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -828,3 +828,10 @@ end end @test length(code_typed(test_20902, (), optimize = false)) == 1 @test length(code_typed(test_20902, (), optimize = false)) == 1 + +# normalization of arguments with constant Types as parameters +g21771(T) = T +f21771(::Val{U}) where {U} = Tuple{g21771(U)} +@test @inferred(f21771(Val{Int}())) === Tuple{Int} +@test @inferred(f21771(Val{Union{}}())) === Tuple{Union{}} +@test Base.return_types(f21771, typeof((Val{Integer}(),))) == Any[Type{<:Tuple{Integer}}] # apply_type might be overly conservative here From 8ee2e062cabcfb5956386a25cc7c949c0efca1f4 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 22 May 2017 16:13:03 -0400 Subject: [PATCH 33/53] apply_type on Type{T} is valid whenever T is valid removes performance bug added by 0292c42c --- base/inference.jl | 9 +++++---- test/inference.jl | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index f0606e2e9e01af..24cb9f0bfcbae5 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -1001,7 +1001,7 @@ function apply_type_tfunc(headtypetype::ANY, args::ANY...) ai = args[i] if isType(ai) aip1 = ai.parameters[1] - canconst &= (isleaftype(aip1) || aip1 === Union{}) + canconst &= !has_free_typevars(aip1) push!(tparams, aip1) elseif isa(ai, Const) && (isa(ai.val, Type) || isa(ai.val, TypeVar) || valid_tparam(ai.val)) push!(tparams, ai.val) @@ -1784,6 +1784,10 @@ function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vect else return Any end + if !isa(body, Type) && !isa(body, TypeVar) + return Any + end + has_free_typevars(body) || return body if isa(argtypes[2], Const) tv = argtypes[2].val elseif isa(argtypes[2], PartialTypeVar) @@ -1794,9 +1798,6 @@ function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vect return Any end !isa(tv, TypeVar) && return Any - if !isa(body, Type) && !isa(body, TypeVar) - return Any - end theunion = UnionAll(tv, body) ret = canconst ? abstract_eval_constant(theunion) : Type{theunion} return ret diff --git a/test/inference.jl b/test/inference.jl index 33b5d4ba7d0af1..76917a3a4fef7f 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -834,4 +834,4 @@ g21771(T) = T f21771(::Val{U}) where {U} = Tuple{g21771(U)} @test @inferred(f21771(Val{Int}())) === Tuple{Int} @test @inferred(f21771(Val{Union{}}())) === Tuple{Union{}} -@test Base.return_types(f21771, typeof((Val{Integer}(),))) == Any[Type{<:Tuple{Integer}}] # apply_type might be overly conservative here +@test @inferred(f21771(Val{Integer}())) === Tuple{Integer} From f97d9e85822b353b7e4b7a665514fab1f556f957 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 22 May 2017 16:08:11 -0400 Subject: [PATCH 34/53] handling Base printing of Expr.typ fields not containing a Type this allows printing of the Exprs flowing through inference (which might instead have the field set to something like a Const object) --- base/show.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/show.jl b/base/show.jl index cdf7450f5713f6..5cfa8acdd032d1 100644 --- a/base/show.jl +++ b/base/show.jl @@ -518,7 +518,7 @@ typeemphasize(io::IO) = get(io, :TYPEEMPHASIZE, false) === true const indent_width = 4 -function show_expr_type(io::IO, ty, emph) +function show_expr_type(io::IO, ty::ANY, emph::Bool) if ty === Function print(io, "::F") elseif ty === Core.IntrinsicFunction @@ -627,7 +627,7 @@ function show_unquoted(io::IO, ex::Slot, ::Int, ::Int) if isa(slottypes, Array) && slotid <= length(slottypes::Array) slottype = slottypes[slotid] # The Slot in assignment can somehow have an Any type - if slottype <: typ + if isa(slottype, Type) && isa(typ, Type) && slottype <: typ typ = slottype end end From 76a30fb4968dccab2adcdc3bb5eee00184df0eba Mon Sep 17 00:00:00 2001 From: Andy Ferris Date: Wed, 10 May 2017 21:42:30 +1000 Subject: [PATCH 35/53] remove many unneeded pure annotations Removing actually may enable inference to get a sharper result, since it is no longer being directed to ignore backedges and correctness assumptions Replaces pure annotations in promotion with inline --- base/inference.jl | 4 ++-- base/linalg/uniformscaling.jl | 4 ++-- base/promotion.jl | 41 +++++++++++++++++++---------------- base/sparse/abstractsparse.jl | 2 +- base/sparse/sparsevector.jl | 6 ++--- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 24cb9f0bfcbae5..99507b270f1972 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -1865,8 +1865,8 @@ function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vect t = pure_eval_call(f, argtypes, atype, sv) t !== false && return t - if istopfunction(tm, f, :promote_type) || istopfunction(tm, f, :typejoin) - return Type + if istopfunction(tm, f, :typejoin) || f === return_type + return Type # don't try to infer these function edges directly -- it won't actually come up with anything useful elseif length(argtypes) == 2 && istopfunction(tm, f, :typename) return typename_static(argtypes[2]) end diff --git a/base/linalg/uniformscaling.jl b/base/linalg/uniformscaling.jl index 92f1c81434d58d..81a3ee1e6b29cf 100644 --- a/base/linalg/uniformscaling.jl +++ b/base/linalg/uniformscaling.jl @@ -1,7 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license import Base: copy, ctranspose, getindex, show, transpose, one, zero, inv, - @_pure_meta, hcat, vcat, hvcat + hcat, vcat, hvcat import Base.LinAlg: SingularException struct UniformScaling{T<:Number} @@ -201,7 +201,7 @@ promote_to_arrays(n,k, ::Type{T}, A, B, C) where {T} = (promote_to_arrays_(n[k], T, A), promote_to_arrays_(n[k+1], T, B), promote_to_arrays_(n[k+2], T, C)) promote_to_arrays(n,k, ::Type{T}, A, B, Cs...) where {T} = (promote_to_arrays_(n[k], T, A), promote_to_arrays_(n[k+1], T, B), promote_to_arrays(n,k+2, T, Cs...)...) -promote_to_array_type(A::Tuple{Vararg{Union{AbstractVecOrMat,UniformScaling}}}) = (@_pure_meta; Matrix) +promote_to_array_type(A::Tuple{Vararg{Union{AbstractVecOrMat,UniformScaling}}}) = Matrix for (f,dim,name) in ((:hcat,1,"rows"), (:vcat,2,"cols")) @eval begin diff --git a/base/promotion.jl b/base/promotion.jl index 5c55b3d1e34d36..2972a7da99cce2 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -122,14 +122,14 @@ end ## promotion mechanism ## -promote_type() = (@_pure_meta; Bottom) -promote_type(T) = (@_pure_meta; T) -promote_type(T, S, U, V...) = (@_pure_meta; promote_type(T, promote_type(S, U, V...))) +promote_type() = Bottom +promote_type(T) = T +promote_type(T, S, U, V...) = (@_inline_meta; promote_type(T, promote_type(S, U, V...))) -promote_type(::Type{Bottom}, ::Type{Bottom}) = (@_pure_meta; Bottom) -promote_type(::Type{T}, ::Type{T}) where {T} = (@_pure_meta; T) -promote_type(::Type{T}, ::Type{Bottom}) where {T} = (@_pure_meta; T) -promote_type(::Type{Bottom}, ::Type{T}) where {T} = (@_pure_meta; T) +promote_type(::Type{Bottom}, ::Type{Bottom}) = Bottom +promote_type(::Type{T}, ::Type{T}) where {T} = T +promote_type(::Type{T}, ::Type{Bottom}) where {T} = T +promote_type(::Type{Bottom}, ::Type{T}) where {T} = T """ promote_type(type1, type2) @@ -152,7 +152,7 @@ BigFloat ``` """ function promote_type(::Type{T}, ::Type{S}) where {T,S} - @_pure_meta + @_inline_meta # Try promote_rule in both orders. Typically only one is defined, # and there is a fallback returning Bottom below, so the common case is # promote_type(T, S) => @@ -161,26 +161,29 @@ function promote_type(::Type{T}, ::Type{S}) where {T,S} promote_result(T, S, promote_rule(T,S), promote_rule(S,T)) end -promote_rule(T, S) = (@_pure_meta; Bottom) +promote_rule(::Type{<:Any}, ::Type{<:Any}) = Bottom -promote_result(t,s,T,S) = (@_pure_meta; promote_type(T,S)) +promote_result(::Type{<:Any},::Type{<:Any},::Type{T},::Type{S}) where {T,S} = (@_inline_meta; promote_type(T,S)) # If no promote_rule is defined, both directions give Bottom. In that # case use typejoin on the original types instead. -promote_result(::Type{T},::Type{S},::Type{Bottom},::Type{Bottom}) where {T,S} = (@_pure_meta; typejoin(T, S)) +promote_result(::Type{T},::Type{S},::Type{Bottom},::Type{Bottom}) where {T,S} = (@_inline_meta; typejoin(T, S)) promote() = () promote(x) = (x,) function promote(x::T, y::S) where {T,S} + @_inline_meta (convert(promote_type(T,S),x), convert(promote_type(T,S),y)) end -promote_typeof(x) = (@_pure_meta; typeof(x)) -promote_typeof(x, xs...) = (@_pure_meta; promote_type(typeof(x), promote_typeof(xs...))) +promote_typeof(x) = typeof(x) +promote_typeof(x, xs...) = (@_inline_meta; promote_type(typeof(x), promote_typeof(xs...))) function promote(x, y, z) + @_inline_meta (convert(promote_typeof(x,y,z), x), convert(promote_typeof(x,y,z), y), convert(promote_typeof(x,y,z), z)) end function promote(x, y, zs...) + @_inline_meta (convert(promote_typeof(x,y,zs...), x), convert(promote_typeof(x,y,zs...), y), convert(Tuple{Vararg{promote_typeof(x,y,zs...)}}, zs)...) @@ -195,16 +198,16 @@ end # happens, and +(promote(x,y)...) is called again, causing a stack # overflow. function promote_result(::Type{T},::Type{S},::Type{Bottom},::Type{Bottom}) where {T<:Number,S<:Number} - @_pure_meta + @_inline_meta promote_to_supertype(T, S, typejoin(T,S)) end # promote numeric types T and S to typejoin(T,S) if T<:S or S<:T # for example this makes promote_type(Integer,Real) == Real without # promoting arbitrary pairs of numeric types to Number. -promote_to_supertype(::Type{T}, ::Type{T}, ::Type{T}) where {T<:Number} = (@_pure_meta; T) -promote_to_supertype(::Type{T}, ::Type{S}, ::Type{T}) where {T<:Number,S<:Number} = (@_pure_meta; T) -promote_to_supertype(::Type{T}, ::Type{S}, ::Type{S}) where {T<:Number,S<:Number} = (@_pure_meta; S) +promote_to_supertype(::Type{T}, ::Type{T}, ::Type{T}) where {T<:Number} = (@_inline_meta; T) +promote_to_supertype(::Type{T}, ::Type{S}, ::Type{T}) where {T<:Number,S<:Number} = (@_inline_meta; T) +promote_to_supertype(::Type{T}, ::Type{S}, ::Type{S}) where {T<:Number,S<:Number} = (@_inline_meta; S) promote_to_supertype(::Type{T}, ::Type{S}, ::Type) where {T<:Number,S<:Number} = error("no promotion exists for ", T, " and ", S) @@ -304,7 +307,7 @@ minmax(x::Real, y::Real) = minmax(promote(x, y)...) # "Promotion" that takes a function into account and tries to preserve # non-concrete types. These are meant to be used mainly by elementwise # operations, so it is advised against overriding them -_default_type(T::Type) = (@_pure_meta; T) +_default_type(T::Type) = (@_inline_meta; T) if isdefined(Core, :Inference) const _return_type = Core.Inference.return_type @@ -312,7 +315,7 @@ else _return_type(f::ANY, t::ANY) = Any end -promote_op(::Any...) = (@_pure_meta; Any) +promote_op(::Any...) = (@_inline_meta; Any) function promote_op{S}(f, ::Type{S}) @_inline_meta T = _return_type(f, Tuple{_default_type(S)}) diff --git a/base/sparse/abstractsparse.jl b/base/sparse/abstractsparse.jl index 6de3403b5d6de5..e17d3be97dbcbb 100644 --- a/base/sparse/abstractsparse.jl +++ b/base/sparse/abstractsparse.jl @@ -20,4 +20,4 @@ issparse(S::LinAlg.UnitLowerTriangular{<:Any,<:AbstractSparseMatrix}) = true issparse(S::UpperTriangular{<:Any,<:AbstractSparseMatrix}) = true issparse(S::LinAlg.UnitUpperTriangular{<:Any,<:AbstractSparseMatrix}) = true -indtype(S::AbstractSparseArray{<:Any,Ti}) where {Ti} = (Base.@_pure_meta; Ti) +indtype(S::AbstractSparseArray{<:Any,Ti}) where {Ti} = Ti diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index dd9e19d9bc729b..d4f43de2296670 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -2,7 +2,7 @@ ### Common definitions -import Base: scalarmax, scalarmin, sort, find, findnz, @_pure_meta +import Base: scalarmax, scalarmin, sort, find, findnz import Base.LinAlg: promote_to_array_type, promote_to_arrays_ ### The SparseVector @@ -962,8 +962,8 @@ function hvcat(rows::Tuple{Vararg{Int}}, X::_SparseConcatGroup...) end # make sure UniformScaling objects are converted to sparse matrices for concatenation -promote_to_array_type(A::Tuple{Vararg{Union{_SparseConcatGroup,UniformScaling}}}) = (@_pure_meta; SparseMatrixCSC) -promote_to_array_type(A::Tuple{Vararg{Union{_DenseConcatGroup,UniformScaling}}}) = (@_pure_meta; Matrix) +promote_to_array_type(A::Tuple{Vararg{Union{_SparseConcatGroup,UniformScaling}}}) = SparseMatrixCSC +promote_to_array_type(A::Tuple{Vararg{Union{_DenseConcatGroup,UniformScaling}}}) = Matrix promote_to_arrays_(n::Int, ::Type{SparseMatrixCSC}, J::UniformScaling) = sparse(J, n, n) # Concatenations strictly involving un/annotated dense matrices/vectors should yield dense arrays From 1c5cfb0c98004a42d44118ad2899c0ae5b5c10a3 Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Mon, 29 May 2017 12:01:27 -0400 Subject: [PATCH 36/53] Fix new fallthrough warnings --- src/ast.c | 4 +++- src/method.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ast.c b/src/ast.c index 9b3b8c124e6a63..ed44ab1509d092 100644 --- a/src/ast.c +++ b/src/ast.c @@ -190,11 +190,13 @@ value_t fl_invoke_julia_macro(fl_context_t *fl_ctx, value_t *args, uint32_t narg if (jl_is_expr(lno) && ((jl_expr_t*)lno)->head == line_sym) { jl_value_t *file = jl_nothing; jl_value_t *line = NULL; - switch (jl_expr_nargs(lno)) { // fall-through is intentional + switch (jl_expr_nargs(lno)) { case 2: file = jl_exprarg(lno, 1); // file + JL_FALLTHROUGH; case 1: line = jl_exprarg(lno, 0); // line + JL_FALLTHROUGH; default: ; } if (line == NULL) diff --git a/src/method.c b/src/method.c index 30e7a702823e25..4cd52b82776e94 100644 --- a/src/method.c +++ b/src/method.c @@ -430,11 +430,13 @@ static void jl_method_set_source(jl_method_t *m, jl_code_info_t *src) } else if (jl_is_expr(st) && ((jl_expr_t*)st)->head == line_sym) { if (!set_lineno) { - switch (jl_expr_nargs(st)) { // fall-through is intentional + switch (jl_expr_nargs(st)) { case 2: m->file = (jl_sym_t*)jl_exprarg(st, 1); + JL_FALLTHROUGH; case 1: m->line = jl_unbox_long(jl_exprarg(st, 0)); + JL_FALLTHROUGH; default: ; } st = jl_nothing; From 9116ec7dd81b0f9670400ee2e66f418f6e493dd6 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 28 May 2017 21:10:22 -0400 Subject: [PATCH 37/53] pass correct paths through to docstrings fix #22105 --- Makefile | 1 + base/boot.jl | 4 +-- base/docs/Docs.jl | 74 +++++++++++++++++++-------------------- base/docs/core.jl | 15 ++++---- base/markdown/Markdown.jl | 20 +++++------ base/precompile.jl | 6 ++-- test/docs.jl | 56 +++++++++++++++++++---------- 7 files changed, 96 insertions(+), 80 deletions(-) diff --git a/Makefile b/Makefile index f88264d5ed4fac..90b566fc828ed0 100644 --- a/Makefile +++ b/Makefile @@ -186,6 +186,7 @@ $(build_private_libdir)/%.$(SHLIB_EXT): $(build_private_libdir)/%.o CORE_SRCS := $(addprefix $(JULIAHOME)/, \ base/boot.jl base/coreimg.jl \ + base/docs/core.jl \ base/abstractarray.jl \ base/array.jl \ base/bool.jl \ diff --git a/base/boot.jl b/base/boot.jl index c818bdfd0deadb..23e803b81fe063 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -337,7 +337,7 @@ end # docsystem basics macro doc(x...) - atdoc(x...) + atdoc(__source__, x...) end macro __doc__(x) Expr(:escape, Expr(:block, Expr(:meta, :doc), x)) @@ -345,7 +345,7 @@ end macro doc_str(s) Expr(:escape, s) end -atdoc = (str, expr) -> Expr(:escape, expr) +atdoc = (source, str, expr) -> Expr(:escape, expr) atdoc!(λ) = global atdoc = λ diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 40bbb74f427297..bd9af3efe71d77 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -169,10 +169,10 @@ _docstr(doc::DocStr, data) = (doc.data = merge(data, doc.data); doc) macro ref(x) binding = bindingexpr(namify(x)) typesig = signature(x) - esc(docexpr(binding, typesig)) + esc(docexpr(__source__, binding, typesig)) end -docexpr(args...) = Expr(:call, docstr, args...) +docexpr(__source__, args...) = Expr(:call, docstr, args...) function formatdoc(d::DocStr) buffer = IOBuffer() @@ -482,26 +482,27 @@ isfield(x) = isexpr(x, :.) && # ========================= """ - Docs.metadata(expr) + Docs.metadata(source, expr) Build a `Dict` expression containing metadata captured from the expression `expr`. Fields that may be included in the returned `Dict`: -- `:path`: String representing the file where `expr` is defined. +- `:path`: Symbol representing the file where `expr` is defined. - `:linenumber`: Linenumber where `expr` is defined. - `:module`: Module where the docstring is defined. - `:fields`: `Dict` of all field docs found in `expr`. Only for concrete types. """ -function metadata(expr) +function metadata(__source__, expr) args = [] # Filename and linenumber of the docstring. - push!(args, :($(Pair)(:path, $(Base).@__FILE__))) - push!(args, :($(Pair)(:linenumber, $(unsafe_load(cglobal(:jl_lineno, Cint)))))) + __file__ = isa(__source__.file, Symbol) ? String(__source__.file) : "" + push!(args, Pair(:path, __file__)) + push!(args, Pair(:linenumber, __source__.line)) # Module in which the docstring is defined. push!(args, :($(Pair)(:module, $(current_module)()))) - # Field docs for concrete types. if isexpr(expr, :type) + # Field docs for concrete types. fields = [] tmp = nothing for each in expr.args[3].args @@ -518,37 +519,36 @@ function metadata(expr) :($(Dict)($(args...))) end -function keyworddoc(str, def) - docstr = esc(docexpr(lazy_iterpolate(str), metadata(def))) - :($(keywords)[$(esc(quot(def.name)))] = $docstr) +function keyworddoc(__source__, str, def) + docstr = esc(docexpr(__source__, lazy_iterpolate(str), metadata(__source__, def))) + return :($(keywords)[$(esc(quot(def.name)))] = $docstr) end -function objectdoc(str, def, expr, sig = :(Union{})) +function objectdoc(__source__, str, def, expr, sig = :(Union{})) binding = esc(bindingexpr(namify(expr))) - docstr = esc(docexpr(lazy_iterpolate(str), metadata(expr))) + docstr = esc(docexpr(__source__, lazy_iterpolate(str), metadata(__source__, expr))) quote $(esc(def)) $(doc!)($binding, $docstr, $(esc(sig))) end end -function calldoc(str, def) +function calldoc(__source__, str, def) args = def.args[2:end] if isempty(args) || all(validcall, args) - objectdoc(str, nothing, def, signature(def)) + objectdoc(__source__, str, nothing, def, signature(def)) else docerror(def) end end validcall(x) = isa(x, Symbol) || isexpr(x, (:(::), :..., :kw, :parameters)) -function moduledoc(meta, def, def′) +function moduledoc(__source__, meta, def, def′) name = namify(def′) docex = Expr(:call, doc!, bindingexpr(name), - docexpr(lazy_iterpolate(meta), metadata(name)) - ) + docexpr(__source__, lazy_iterpolate(meta), metadata(__source__, name))) if def === nothing - esc(:(eval($name, $(quot(docex))))) + esc(:($eval($name, $(quot(docex))))) else def = unblock(def) block = def.args[3].args @@ -562,18 +562,18 @@ function moduledoc(meta, def, def′) end # Shares a single doc, `meta`, between several expressions from the tuple expression `ex`. -function multidoc(meta, ex, define) +function multidoc(__source__, meta, ex, define) out = Expr(:toplevel) - str = docexpr(lazy_iterpolate(meta), metadata(ex)) + str = docexpr(__source__, lazy_iterpolate(meta), metadata(__source__, ex)) ref = Ref{DocStr}() for (n, arg) in enumerate(ex.args) # The first `arg` to be documented needs to also create the docstring for the group. # Subsequent `arg`s just need `ref` to be able to find the docstring without having # to create an entirely new one each. docstr = n === 1 ? :($(ref)[] = $str) : :($(ref)[]) - push!(out.args, :(@doc($docstr, $arg, $define))) + push!(out.args, docm(__source__, docstr, arg, define)) end - esc(out) + return out end """ @@ -649,7 +649,7 @@ isquotedmacrocall(x) = isbasicdoc(x) = isexpr(x, :.) || isa(x, Union{QuoteNode, Symbol}) is_signature(x) = isexpr(x, :call) || (isexpr(x, :(::), 2) && isexpr(x.args[1], :call)) || isexpr(x, :where) -function docm(meta, ex, define = true) +function docm(source::LineNumberNode, meta, ex, define = true) # Some documented expressions may be decorated with macro calls which obscure the actual # expression. Expand the macro calls and remove extra blocks. x = unblock(macroexpand(ex)) @@ -665,7 +665,7 @@ function docm(meta, ex, define = true) # "..." # kw"if", kw"else" # - isa(x, Base.BaseDocs.Keyword) ? keyworddoc(meta, x) : + isa(x, Base.BaseDocs.Keyword) ? keyworddoc(source, meta, x) : # Method / macro definitions and "call" syntax. # @@ -675,9 +675,9 @@ function docm(meta, ex, define = true) # function f end # f(...) # - isexpr(x, FUNC_HEADS) && is_signature(x.args[1]) ? objectdoc(meta, def, x, signature(x)) : - isexpr(x, :function) && !isexpr(x.args[1], :call) ? objectdoc(meta, def, x) : - isexpr(x, :call) ? calldoc(meta, x) : + isexpr(x, FUNC_HEADS) && is_signature(x.args[1]) ? objectdoc(source, meta, def, x, signature(x)) : + isexpr(x, :function) && !isexpr(x.args[1], :call) ? objectdoc(source, meta, def, x) : + isexpr(x, :call) ? calldoc(source, meta, x) : # Type definitions. # @@ -685,7 +685,7 @@ function docm(meta, ex, define = true) # abstract T # bitstype N T # - isexpr(x, [:type, :abstract, :bitstype]) ? objectdoc(meta, def, x) : + isexpr(x, [:type, :abstract, :bitstype]) ? objectdoc(source, meta, def, x) : # "Bindings". Names that resolve to objects with different names, ie. # @@ -693,20 +693,20 @@ function docm(meta, ex, define = true) # T = S # global T = S # - isexpr(x, BINDING_HEADS) && !isexpr(x.args[1], :call) ? objectdoc(meta, def, x) : + isexpr(x, BINDING_HEADS) && !isexpr(x.args[1], :call) ? objectdoc(source, meta, def, x) : # Quoted macrocall syntax. `:@time` / `:(Base.@time)`. - isquotedmacrocall(x) ? objectdoc(meta, def, x) : + isquotedmacrocall(x) ? objectdoc(source, meta, def, x) : # Modules and baremodules. - isexpr(x, :module) ? moduledoc(meta, def, x) : + isexpr(x, :module) ? moduledoc(source, meta, def, x) : # Document several expressions with the same docstring. `a, b, c`. - isexpr(x, :tuple) ? multidoc(meta, x, define) : + isexpr(x, :tuple) ? multidoc(source, meta, x, define) : # Errors generated by calling `macroexpand` are passed back to the call site. isexpr(x, :error) ? esc(x) : # When documenting macro-generated code we look for embedded `@__doc__` calls. __doc__!(meta, x, define) ? esc(x) : # Any "basic" expression such as a bare function or module name or numeric literal. - isbasicdoc(x) ? objectdoc(meta, nothing, x) : + isbasicdoc(x) ? objectdoc(source, meta, nothing, x) : # 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 @@ -725,9 +725,9 @@ function docerror(ex) :($(error)($txt, "\n")) end -function docm(ex) +function docm(source::LineNumberNode, ex) if isexpr(ex, :->) - docm(ex.args...) + docm(source, ex.args...) elseif haskey(keywords, ex) parsedoc(keywords[ex]) elseif isa(ex, Union{Expr, Symbol}) @@ -764,7 +764,7 @@ function loaddocs(docs) for (mod, ex, str, file, line) in docs data = Dict(:path => string(file), :linenumber => line) doc = docstr(str, data) - docstring = eval(mod, Expr(:body, Expr(:return, Expr(:call, QuoteNode(docm), QuoteNode(doc), QuoteNode(ex), false)))) # expand the real @doc macro now (using a hack because macroexpand takes current-module as an implicit argument) + docstring = eval(mod, Expr(:body, Expr(:return, Expr(:call, QuoteNode(docm), QuoteNode(LineNumberNode(line, file)), QuoteNode(doc), QuoteNode(ex), false)))) # expand the real @doc macro now (using a hack because macroexpand takes current-module as an implicit argument) eval(mod, Expr(:macrocall, unescape, nothing, docstring)) end empty!(docs) diff --git a/base/docs/core.jl b/base/docs/core.jl index 9b8cf34c7f48a9..747afab704aa30 100644 --- a/base/docs/core.jl +++ b/base/docs/core.jl @@ -4,12 +4,8 @@ module CoreDocs import ..esc, ..push!, ..getindex, ..current_module, ..unsafe_load, ..Csize_t -function doc!(str, ex) - ptr = unsafe_load(Core.Intrinsics.cglobal(:jl_filename, Ptr{UInt8})) - len = ccall(:strlen, Csize_t, (Ptr{UInt8},), ptr) - file = ccall(:jl_symbol_n, Any, (Ptr{UInt8}, Csize_t), ptr, len) - line = unsafe_load(Core.Intrinsics.cglobal(:jl_lineno, Int32)) # Cint - push!(DOCS, (current_module(), ex, str, file, line)) +function doc!(source::LineNumberNode, str, ex) + push!(DOCS, (current_module(), ex, str, source.file, source.line)) end const DOCS = Array{Any, 1}() @@ -18,11 +14,12 @@ isexpr(x, h) = isa(x, Expr) && x.head === h lazy_iterpolate(s::AbstractString) = Expr(:call, Core.svec, s) lazy_iterpolate(x) = isexpr(x, :string) ? Expr(:call, Core.svec, x.args...) : x -function docm(str, x) - out = esc(Expr(:call, doc!, lazy_iterpolate(str), Expr(:quote, x))) +function docm(source::LineNumberNode, str, x) + out = esc(Expr(:call, doc!, QuoteNode(source), lazy_iterpolate(str), Expr(:quote, x))) isexpr(x, :module) ? Expr(:toplevel, out, esc(x)) : isexpr(x, :call) ? out : Expr(:block, esc(x), out) end -docm(x) = isexpr(x, :->) ? docm(x.args[1], x.args[2].args[2]) : error("invalid '@doc'.") +docm(source::LineNumberNode, x) = + isexpr(x, :->) ? docm(source, x.args[1], x.args[2].args[2]) : error("invalid '@doc'.") end diff --git a/base/markdown/Markdown.jl b/base/markdown/Markdown.jl index d32ae9fa8d983d..fff30da7fec3ca 100644 --- a/base/markdown/Markdown.jl +++ b/base/markdown/Markdown.jl @@ -37,25 +37,23 @@ function mdexpr(s, flavor = :julia) esc(toexpr(md)) end -function docexpr(s, flavor = :julia) - quote - let md = $(mdexpr(s, flavor)) - md.meta[:path] = @__FILE__ - md.meta[:module] = current_module() - md - end - end +function docexpr(source::LineNumberNode, s, flavor = :julia) + :($doc_str($(mdexpr(s, flavor)), $(QuoteNode(source)))) end macro md_str(s, t...) mdexpr(s, t...) end -doc_str(md, file, mod) = (md.meta[:path] = file; md.meta[:module] = mod; md) -doc_str(md::AbstractString, file, mod) = doc_str(parse(md), file, mod) +function doc_str(md, source::LineNumberNode) + md.meta[:path] = isa(source.file, Symbol) ? String(source.file) : "" + md.meta[:module] = current_module() + md +end +doc_str(md::AbstractString, source::LineNumberNode) = doc_str(parse(md), source) macro doc_str(s::AbstractString, t...) - :($(doc_str)($(mdexpr(s, t...)), $(Base).@__FILE__, $(current_module)())) + docexpr(__source__, s, t...) end function Base.display(d::Base.REPL.REPLDisplay, md::Vector{MD}) diff --git a/base/precompile.jl b/base/precompile.jl index 9bd0f90f30572f..5149aed65b3324 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -743,7 +743,7 @@ precompile(Tuple{getfield(Base.Docs, Symbol("#@repl")), Base.TTY, Symbol}) precompile(Tuple{typeof(Base.Docs.repl), Base.TTY, Symbol}) precompile(Tuple{typeof(Base.Docs._repl), Symbol}) precompile(Tuple{getfield(Core, Symbol("#@doc")), Symbol}) -precompile(Tuple{typeof(Base.Docs.docm), Symbol}) +precompile(Tuple{typeof(Base.Docs.docm), LineNumberNode, Symbol}) precompile(Tuple{typeof(Base._setindex!), Base.Dict{Any, Any}, Base.Markdown.Config, Symbol, Int64}) precompile(Tuple{Type{Base.Markdown.MD}}) precompile(Tuple{typeof(Base.setindex!), Base.Dict{Any, Any}, Base.Markdown.Config, Symbol}) @@ -1720,8 +1720,8 @@ precompile(Tuple{typeof(Base.Distributed.send_msg), Base.Distributed.Worker, Bas precompile(Tuple{typeof(Base.Distributed.send_msg_), Base.Distributed.Worker, Base.Distributed.MsgHeader, Base.Distributed.RemoteDoMsg, Bool}) precompile(Tuple{typeof(Base.Distributed.terminate_all_workers)}) precompile(Tuple{typeof(Base.Distributed.test_existing_ref), Base.Distributed.Future}) -precompile(Tuple{typeof(Base.Docs.docm), String, Expr}) -precompile(Tuple{typeof(Base.Docs.docm), String, Expr, Bool}) +precompile(Tuple{typeof(Base.Docs.docm), LineNumberNode, String, Expr}) +precompile(Tuple{typeof(Base.Docs.docm), LineNumberNode, String, Expr, Bool}) precompile(Tuple{typeof(Base.Docs.keyworddoc), String, Base.BaseDocs.Keyword}) precompile(Tuple{typeof(Base.Docs.objectdoc), String, Expr, Expr, Expr}) precompile(Tuple{typeof(Base.FastMath.make_fastmath), Expr}) diff --git a/test/docs.jl b/test/docs.jl index d1d65d5615ae70..54bae5861ce2e3 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -481,24 +481,26 @@ end # Issue #16359. Error message for invalid doc syntax. -for each in [ # valid syntax - :(f()), - :(f(x)), - :(f(x::Int)), - :(f(x...)), - :(f(x = 1)), - :(f(; x = 1)) - ] - @test Meta.isexpr(Docs.docm("...", each), :block) -end -for each in [ # invalid syntax - :(f("...")), - :(f(1, 2)), - :(f(() -> ())) - ] - result = Docs.docm("...", each) - @test Meta.isexpr(result, :call) - @test result.args[1] === error +let __source__ = LineNumberNode(0) + for each in [ # valid syntax + :(f()), + :(f(x)), + :(f(x::Int)), + :(f(x...)), + :(f(x = 1)), + :(f(; x = 1)) + ] + @test Meta.isexpr(Docs.docm(__source__, "...", each), :block) + end + for each in [ # invalid syntax + :(f("...")), + :(f(1, 2)), + :(f(() -> ())) + ] + result = Docs.docm(__source__, "...", each) + @test Meta.isexpr(result, :call) + @test result.args[1] === error + end end # Issue #15424. Non-markdown docstrings. @@ -1012,3 +1014,21 @@ end """ ) +# issue #22105 +module I22105 + lineno = @__LINE__ + """foo docs""" + function foo end +end + +let foo_docs = meta(I22105)[@var(I22105.foo)].docs + @test length(foo_docs) === 1 + @test isa(first(foo_docs), Pair) + local docstr = first(foo_docs).second + @test isa(docstr, DocStr) + @test docstr.data[:path] == Base.source_path() + @test docstr.data[:linenumber] == I22105.lineno + 1 + @test docstr.data[:module] === I22105 + @test docstr.data[:typesig] === Union{} + @test docstr.data[:binding] == Binding(I22105, :foo) +end From 753fbef68dd3f09fb0137d6a78606db098119099 Mon Sep 17 00:00:00 2001 From: Martin Holters Date: Tue, 9 May 2017 14:51:25 -0400 Subject: [PATCH 38/53] inference: remove hacks around type-system incorrectness infers a missing method (MethodError) as returning `Union{}` and fix tests that were wrong, but not detected previously! --- base/inference.jl | 15 +-------------- test/arrayops.jl | 6 +++--- test/inference.jl | 3 +++ test/strings/basic.jl | 2 +- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 99507b270f1972..7f5e66182ad18f 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -36,8 +36,6 @@ struct InferenceParams end end -const UNION_SPLIT_MISMATCH_ERROR = false - # alloc_elim_pass! relies on `Slot_AssignedOnce | Slot_UsedUndef` being # SSA. This should be true now but can break if we start to track conditional # constants. e.g. @@ -1412,10 +1410,6 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState) add_mt_backedge(ftname.mt, argtype, sv) update_valid_age!(min_valid[1], max_valid[1], sv) end - if isempty(applicable) - # TODO: this is needed because type intersection is wrong in some cases - return Any - end #print("=> ", rettype, "\n") return rettype end @@ -1579,13 +1573,6 @@ function return_type_tfunc(argtypes::ANY, vtypes::VarTable, sv::InferenceState) if isa(af_argtype, DataType) && af_argtype <: Tuple argtypes_vec = Any[aft, af_argtype.parameters...] astype = argtypes_to_type(argtypes_vec) - if !(aft ⊑ Builtin) && - _methods_by_ftype(astype, 0, sv.params.world, - UInt[typemin(UInt)], UInt[typemax(UInt)]) !== false - # return_type returns Bottom if no methods match, even though - # inference doesn't necessarily. - return Const(Bottom) - end if isa(aft, Const) rt = abstract_call(aft.val, (), argtypes_vec, vtypes, sv) elseif isconstType(aft) @@ -3590,7 +3577,7 @@ function invoke_NF(argexprs, etype::ANY, atypes, sv, atype_unlimited::ANY, all = false end end - if UNION_SPLIT_MISMATCH_ERROR && all + if all error_label === nothing && (error_label = genlabel(sv)) push!(stmts, GotoNode(error_label.label)) else diff --git a/test/arrayops.jl b/test/arrayops.jl index 480ebca4d89c14..56a06f325628aa 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -2082,12 +2082,12 @@ struct F21666{T <: Base.TypeArithmetic} x::Float32 end +Base.TypeArithmetic(::Type{F21666{T}}) where {T} = T() +Base.:+(x::F, y::F) where {F <: F21666} = F(x.x + y.x) +Base.convert(::Type{Float64}, x::F21666) = Float64(x.x) @testset "Exactness of cumsum # 21666" begin # test that cumsum uses more stable algorithm # for types with unknown/rounding arithmetic - Base.TypeArithmetic(::Type{F21666{T}}) where {T} = T - Base.:+(x::F, y::F) where {F <: F21666} = F(x.x + y.x) - Base.convert(::Type{Float64}, x::F21666) = Float64(x.x) # we make v pretty large, because stable algorithm may have a large base case v = zeros(300); v[1] = 2; v[200:end] = eps(Float32) diff --git a/test/inference.jl b/test/inference.jl index 76917a3a4fef7f..5f62946ddde726 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -835,3 +835,6 @@ f21771(::Val{U}) where {U} = Tuple{g21771(U)} @test @inferred(f21771(Val{Int}())) === Tuple{Int} @test @inferred(f21771(Val{Union{}}())) === Tuple{Union{}} @test @inferred(f21771(Val{Integer}())) === Tuple{Integer} + +# missing method should be inferred as Union{}, ref https://github.com/JuliaLang/julia/issues/20033#issuecomment-282228948 +@test Base.return_types(f -> f(1), (typeof((x::String) -> x),)) == Any[Union{}] diff --git a/test/strings/basic.jl b/test/strings/basic.jl index 4c155f92b1b270..551d46305d0f8e 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -194,7 +194,7 @@ gstr = GenericString("12") @test ind2chr(gstr,2)==2 # issue #10307 -@test typeof(map(Int16,AbstractString[])) == Vector{Int16} +@test typeof(map(x -> parse(Int16, x), AbstractString[])) == Vector{Int16} for T in [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128] for i in [typemax(T), typemin(T)] From 7b22adb9e4f152305c91d894f6b81127e2ef070c Mon Sep 17 00:00:00 2001 From: Jeremy Date: Mon, 29 May 2017 16:59:11 -0400 Subject: [PATCH 39/53] Fix sparse type parameter (fixes #22110) (#22111) * Fix type sparse type parameter (fixes #22110) * No brackets for singular type param --- base/sparse/sparsematrix.jl | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index f3986e6b43b063..af40843ddabe9c 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -292,7 +292,10 @@ function copy!(A::SparseMatrixCSC, B::SparseMatrixCSC) return A end -similar(S::SparseMatrixCSC, Tv::Type = eltype(S)) = SparseMatrixCSC(S.m, S.n, copy(S.colptr), copy(S.rowval), Vector{Tv}(length(S.nzval))) +function similar(S::SparseMatrixCSC, ::Type{Tv} = eltype(S)) where Tv + SparseMatrixCSC(S.m, S.n, copy(S.colptr), copy(S.rowval), Vector{Tv}(length(S.nzval))) +end + function similar(S::SparseMatrixCSC, ::Type{Tv}, ::Type{Ti}) where {Tv,Ti} new_colptr = copy!(similar(S.colptr, Ti), S.colptr) new_rowval = copy!(similar(S.rowval, Ti), S.rowval) @@ -1369,16 +1372,18 @@ julia> spzeros(Float32, 4) ``` """ spzeros(m::Integer, n::Integer) = spzeros(Float64, m, n) -spzeros(Tv::Type, m::Integer, n::Integer) = spzeros(Tv, Int, m, n) -function spzeros(Tv::Type, Ti::Type, m::Integer, n::Integer) +spzeros(::Type{Tv}, m::Integer, n::Integer) where {Tv} = spzeros(Tv, Int, m, n) +function spzeros(::Type{Tv}, ::Type{Ti}, m::Integer, n::Integer) where {Tv, Ti} ((m < 0) || (n < 0)) && throw(ArgumentError("invalid Array dimensions")) SparseMatrixCSC(m, n, ones(Ti, n+1), Vector{Ti}(0), Vector{Tv}(0)) end # de-splatting variant -spzeros(Tv::Type, Ti::Type, sz::Tuple{Integer,Integer}) = spzeros(Tv, Ti, sz[1], sz[2]) +function spzeros(::Type{Tv}, ::Type{Ti}, sz::Tuple{Integer,Integer}) where {Tv, Ti} + spzeros(Tv, Ti, sz[1], sz[2]) +end speye(n::Integer) = speye(Float64, n) -speye(T::Type, n::Integer) = speye(T, n, n) +speye(::Type{T}, n::Integer) where {T} = speye(T, n, n) speye(m::Integer, n::Integer) = speye(Float64, m, n) """ @@ -1418,7 +1423,7 @@ if not specified. `sparse(α*I, m, n)` can be used to efficiently create a sparse multiple `α` of the identity matrix. """ -speye(T::Type, m::Integer, n::Integer) = speye_scaled(T, oneunit(T), m, n) +speye(::Type{T}, m::Integer, n::Integer) where {T} = speye_scaled(T, oneunit(T), m, n) function one(S::SparseMatrixCSC{T}) where T m,n = size(S) @@ -1428,7 +1433,7 @@ end speye_scaled(diag, m::Integer, n::Integer) = speye_scaled(typeof(diag), diag, m, n) -function speye_scaled(T, diag, m::Integer, n::Integer) +function speye_scaled(::Type{T}, diag, m::Integer, n::Integer) where T ((m < 0) || (n < 0)) && throw(ArgumentError("invalid array dimensions")) if iszero(diag) return SparseMatrixCSC(m, n, ones(Int, n+1), Vector{Int}(0), Vector{T}(0)) @@ -1509,7 +1514,7 @@ Base.reducedim_initarray0{R}(A::SparseMatrixCSC, region, v0, ::Type{R}) = fill!(similar(dims->Array{R}(dims), Base.reduced_indices0(A,region)), v0) # General mapreduce -function _mapreducezeros(f, op, T::Type, nzeros::Int, v0) +function _mapreducezeros(f, op, ::Type{T}, nzeros::Int, v0) where T nzeros == 0 && return v0 # Reduce over first zero @@ -1543,9 +1548,9 @@ function Base._mapreduce{T}(f, op, ::Base.IndexCartesian, A::SparseMatrixCSC{T}) end # Specialized mapreduce for +/* -_mapreducezeros(f, ::typeof(+), T::Type, nzeros::Int, v0) = +_mapreducezeros(f, ::typeof(+), ::Type{T}, nzeros::Int, v0) where {T} = nzeros == 0 ? v0 : f(zero(T))*nzeros + v0 -_mapreducezeros(f, ::typeof(*), T::Type, nzeros::Int, v0) = +_mapreducezeros(f, ::typeof(*), ::Type{T}, nzeros::Int, v0) where {T} = nzeros == 0 ? v0 : f(zero(T))^nzeros * v0 function Base._mapreduce{T}(f, op::typeof(*), A::SparseMatrixCSC{T}) From 2ba1c50e3815260e2b1f7488d230b7df2e3c30ac Mon Sep 17 00:00:00 2001 From: ScottPJones Date: Tue, 30 May 2017 01:25:57 -0400 Subject: [PATCH 40/53] Fix bug with nul at end when printing BigFloat with >322 precision --- base/printf.jl | 8 +++++--- test/printf.jl | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/base/printf.jl b/base/printf.jl index f1f4515d3f7987..b743ab6e05529f 100644 --- a/base/printf.jl +++ b/base/printf.jl @@ -1128,10 +1128,12 @@ function bigfloat_printf(out, d, flags::String, width::Int, precision::Int, c::C write(fmt, UInt8(0)) printf_fmt = take!(fmt) @assert length(printf_fmt) == fmt_len - bufsiz = length(DIGITS) - 1 - lng = ccall((:mpfr_snprintf,:libmpfr), Int32, (Ptr{UInt8}, Culong, Ptr{UInt8}, Ptr{BigFloat}...), DIGITS, bufsiz, printf_fmt, &d) + bufsiz = length(DIGITS) + lng = ccall((:mpfr_snprintf,:libmpfr), Int32, + (Ptr{UInt8}, Culong, Ptr{UInt8}, Ptr{BigFloat}...), + DIGITS, bufsiz, printf_fmt, &d) lng > 0 || error("invalid printf formatting for BigFloat") - unsafe_write(out, pointer(DIGITS), min(lng,bufsiz)) + unsafe_write(out, pointer(DIGITS), min(lng, bufsiz-1)) return (false, ()) end diff --git a/test/printf.jl b/test/printf.jl index 89d0a7ee7ddf19..2885ddc8df3bd2 100644 --- a/test/printf.jl +++ b/test/printf.jl @@ -256,3 +256,6 @@ end # @printf @test_throws ArgumentError eval(:(@printf 1)) + +# Check bug with trailing nul printing BigFloat +@test (@sprintf("%.330f", BigFloat(1)))[end] != '\0' From fdf97c1dfbc1a5b8f9ef2c9d73119a36009fcf4c Mon Sep 17 00:00:00 2001 From: Mus M Date: Tue, 30 May 2017 05:19:53 -0400 Subject: [PATCH 41/53] Use where syntax in sparsematrix.jl (#22112) * Use where syntax in sparsematrix.jl * Update sparsematrix.jl * Update sparsematrix.jl --- base/sparse/sparsematrix.jl | 82 ++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index af40843ddabe9c..bb18c058bb2b46 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -830,9 +830,9 @@ information. See also: `unchecked_aliasing_permute!` """ -function unchecked_noalias_permute!{Tv,Ti}(X::SparseMatrixCSC{Tv,Ti}, +function unchecked_noalias_permute!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, - q::AbstractVector{<:Integer}, C::SparseMatrixCSC{Tv,Ti}) + q::AbstractVector{<:Integer}, C::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} halfperm!(C, A, q) _computecolptrs_permute!(X, A, q, X.colptr) _distributevals_halfperm!(X, C, p, identity) @@ -850,9 +850,9 @@ for additional information; these methods are identical but for this method's re the additional `workcolptr`, `length(workcolptr) >= A.n + 1`, which enables efficient handling of the source-destination aliasing. """ -function unchecked_aliasing_permute!{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, +function unchecked_aliasing_permute!(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}, - C::SparseMatrixCSC{Tv,Ti}, workcolptr::Vector{Ti}) + C::SparseMatrixCSC{Tv,Ti}, workcolptr::Vector{Ti}) where {Tv,Ti} halfperm!(C, A, q) _computecolptrs_permute!(A, A, q, workcolptr) _distributevals_halfperm!(A, C, p, identity) @@ -864,8 +864,8 @@ Computes `PAQ`'s column pointers, storing them shifted one position forward in ` `_distributevals_halfperm!` fixes this shift. Saves some work relative to `_computecolptrs_halfperm!` as described in `uncheckednoalias_permute!`'s documentation. """ -function _computecolptrs_permute!{Tv,Ti}(X::SparseMatrixCSC{Tv,Ti}, - A::SparseMatrixCSC{Tv,Ti}, q::AbstractVector{<:Integer}, workcolptr::Vector{Ti}) +function _computecolptrs_permute!(X::SparseMatrixCSC{Tv,Ti}, + A::SparseMatrixCSC{Tv,Ti}, q::AbstractVector{<:Integer}, workcolptr::Vector{Ti}) where {Tv,Ti} # Compute `A[p,q]`'s column counts. Store shifted forward one position in workcolptr. @inbounds for k in 1:A.n workcolptr[k+1] = A.colptr[q[k] + 1] - A.colptr[q[k]] @@ -901,9 +901,9 @@ end Helper method for `permute` and `permute!` methods operating on `SparseMatrixCSC`s. Checks whether row- and column- permutation arguments `p` and `q` are valid permutations. """ -function _checkargs_permutationsvalid_permute!{Ti<:Integer}( +function _checkargs_permutationsvalid_permute!( p::AbstractVector{<:Integer}, pcheckspace::Vector{Ti}, - q::AbstractVector{<:Integer}, qcheckspace::Vector{Ti}) + q::AbstractVector{<:Integer}, qcheckspace::Vector{Ti}) where Ti<:Integer if !_ispermutationvalid_permute!(p, pcheckspace) throw(ArgumentError("row-permutation argument `p` must be a valid permutation")) elseif !_ispermutationvalid_permute!(q, qcheckspace) @@ -1003,42 +1003,42 @@ and `unchecked_aliasing_permute!`. See also: [`permute`](@ref) """ -function permute!{Tv,Ti}(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, - p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) +function permute!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, + p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) where {Tv,Ti} _checkargs_sourcecompatdest_permute!(A, X) _checkargs_sourcecompatperms_permute!(A, p, q) C = SparseMatrixCSC(A.n, A.m, Vector{Ti}(A.m + 1), Vector{Ti}(nnz(A)), Vector{Tv}(nnz(A))) _checkargs_permutationsvalid_permute!(p, C.colptr, q, X.colptr) unchecked_noalias_permute!(X, A, p, q, C) end -function permute!{Tv,Ti}(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, +function permute!(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}, - C::SparseMatrixCSC{Tv,Ti}) + C::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} _checkargs_sourcecompatdest_permute!(A, X) _checkargs_sourcecompatperms_permute!(A, p, q) _checkargs_sourcecompatworkmat_permute!(A, C) _checkargs_permutationsvalid_permute!(p, C.colptr, q, X.colptr) unchecked_noalias_permute!(X, A, p, q, C) end -function permute!{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, - q::AbstractVector{<:Integer}) +function permute!(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, + q::AbstractVector{<:Integer}) where {Tv,Ti} _checkargs_sourcecompatperms_permute!(A, p, q) C = SparseMatrixCSC(A.n, A.m, Vector{Ti}(A.m + 1), Vector{Ti}(nnz(A)), Vector{Tv}(nnz(A))) workcolptr = Vector{Ti}(A.n + 1) _checkargs_permutationsvalid_permute!(p, C.colptr, q, workcolptr) unchecked_aliasing_permute!(A, p, q, C, workcolptr) end -function permute!{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, - q::AbstractVector{<:Integer}, C::SparseMatrixCSC{Tv,Ti}) +function permute!(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, + q::AbstractVector{<:Integer}, C::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} _checkargs_sourcecompatperms_permute!(A, p, q) _checkargs_sourcecompatworkmat_permute!(A, C) workcolptr = Vector{Ti}(A.n + 1) _checkargs_permutationsvalid_permute!(p, C.colptr, q, workcolptr) unchecked_aliasing_permute!(A, p, q, C, workcolptr) end -function permute!{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, +function permute!(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}, C::SparseMatrixCSC{Tv,Ti}, - workcolptr::Vector{Ti}) + workcolptr::Vector{Ti}) where {Tv,Ti} _checkargs_sourcecompatperms_permute!(A, p, q) _checkargs_sourcecompatworkmat_permute!(A, C) _checkargs_sourcecompatworkcolptr_permute!(A, workcolptr) @@ -1055,8 +1055,8 @@ row count (`length(p) == A.m`). For expert drivers and additional information, see [`permute!`](@ref). """ -function permute{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, - q::AbstractVector{<:Integer}) +function permute(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, + q::AbstractVector{<:Integer}) where {Tv,Ti} _checkargs_sourcecompatperms_permute!(A, p, q) X = SparseMatrixCSC(A.m, A.n, Vector{Ti}(A.n + 1), Vector{Ti}(nnz(A)), Vector{Tv}(nnz(A))) C = SparseMatrixCSC(A.n, A.m, Vector{Ti}(A.m + 1), Vector{Ti}(nnz(A)), Vector{Tv}(nnz(A))) @@ -1276,8 +1276,8 @@ julia> sprand(rng, Float64, 3, 0.75) [3] = 0.298614 ``` """ -function sprand{T}(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloat, - rfn::Function, ::Type{T}=eltype(rfn(r,1))) +function sprand(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloat, + rfn::Function, ::Type{T}=eltype(rfn(r,1))) where T N = m*n N == 0 && return spzeros(T,m,n) N == 1 && return rand(r) <= density ? sparse([1], [1], rfn(r,1)) : spzeros(T,1,1) @@ -1286,8 +1286,8 @@ function sprand{T}(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloa sparse_IJ_sorted!(I, J, rfn(r,length(I)), m, n, +) # it will never need to combine end -function sprand{T}(m::Integer, n::Integer, density::AbstractFloat, - rfn::Function, ::Type{T}=eltype(rfn(1))) +function sprand(m::Integer, n::Integer, density::AbstractFloat, + rfn::Function, ::Type{T}=eltype(rfn(1))) where T N = m*n N == 0 && return spzeros(T,m,n) N == 1 && return rand() <= density ? sparse([1], [1], rfn(1)) : spzeros(T,1,1) @@ -1468,7 +1468,7 @@ imag(A::SparseMatrixCSC{Tv,Ti}) where {Tv<:Real,Ti} = spzeros(Tv, Ti, A.m, A.n) ## full equality function ==(A1::SparseMatrixCSC, A2::SparseMatrixCSC) - size(A1)!=size(A2) && return false + size(A1) != size(A2) && return false vals1, vals2 = nonzeros(A1), nonzeros(A2) rows1, rows2 = rowvals(A1), rowvals(A2) m, n = size(A1) @@ -1476,7 +1476,7 @@ function ==(A1::SparseMatrixCSC, A2::SparseMatrixCSC) nz1,nz2 = nzrange(A1,i), nzrange(A2,i) j1,j2 = first(nz1), first(nz2) # step through the rows of both matrices at once: - while j1<=last(nz1) && j2<=last(nz2) + while j1 <= last(nz1) && j2 <= last(nz2) r1,r2 = rows1[j1], rows2[j2] if r1==r2 vals1[j1]!=vals2[j2] && return false @@ -1508,9 +1508,9 @@ end # In general, output of sparse matrix reductions will not be sparse, # and computing reductions along columns into SparseMatrixCSC is # non-trivial, so use Arrays for output -Base.reducedim_initarray{R}(A::SparseMatrixCSC, region, v0, ::Type{R}) = +Base.reducedim_initarray(A::SparseMatrixCSC, region, v0, ::Type{R}) where {R} = fill!(similar(dims->Array{R}(dims), Base.reduced_indices(A,region)), v0) -Base.reducedim_initarray0{R}(A::SparseMatrixCSC, region, v0, ::Type{R}) = +Base.reducedim_initarray0(A::SparseMatrixCSC, region, v0, ::Type{R}) where {R} = fill!(similar(dims->Array{R}(dims), Base.reduced_indices0(A,region)), v0) # General mapreduce @@ -1533,7 +1533,7 @@ function _mapreducezeros(f, op, ::Type{T}, nzeros::Int, v0) where T v end -function Base._mapreduce{T}(f, op, ::Base.IndexCartesian, A::SparseMatrixCSC{T}) +function Base._mapreduce(f, op, ::Base.IndexCartesian, A::SparseMatrixCSC{T}) where T z = nnz(A) n = length(A) if z == 0 @@ -1553,7 +1553,7 @@ _mapreducezeros(f, ::typeof(+), ::Type{T}, nzeros::Int, v0) where {T} = _mapreducezeros(f, ::typeof(*), ::Type{T}, nzeros::Int, v0) where {T} = nzeros == 0 ? v0 : f(zero(T))^nzeros * v0 -function Base._mapreduce{T}(f, op::typeof(*), A::SparseMatrixCSC{T}) +function Base._mapreduce(f, op::typeof(*), A::SparseMatrixCSC{T}) where T nzeros = length(A)-nnz(A) if nzeros == 0 # No zeros, so don't compute f(0) since it might throw @@ -1566,7 +1566,7 @@ function Base._mapreduce{T}(f, op::typeof(*), A::SparseMatrixCSC{T}) end # General mapreducedim -function _mapreducerows!{T}(f, op, R::AbstractArray, A::SparseMatrixCSC{T}) +function _mapreducerows!(f, op, R::AbstractArray, A::SparseMatrixCSC{T}) where T colptr = A.colptr rowval = A.rowval nzval = A.nzval @@ -1581,7 +1581,7 @@ function _mapreducerows!{T}(f, op, R::AbstractArray, A::SparseMatrixCSC{T}) R end -function _mapreducecols!{Tv,Ti}(f, op, R::AbstractArray, A::SparseMatrixCSC{Tv,Ti}) +function _mapreducecols!(f, op, R::AbstractArray, A::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} colptr = A.colptr rowval = A.rowval nzval = A.nzval @@ -1600,7 +1600,7 @@ function _mapreducecols!{Tv,Ti}(f, op, R::AbstractArray, A::SparseMatrixCSC{Tv,T R end -function Base._mapreducedim!{T}(f, op, R::AbstractArray, A::SparseMatrixCSC{T}) +function Base._mapreducedim!(f, op, R::AbstractArray, A::SparseMatrixCSC{T}) where T lsiz = Base.check_reducedims(R,A) isempty(A) && return R @@ -1650,7 +1650,7 @@ end # Specialized mapreducedim for + cols to avoid allocating a # temporary array when f(0) == 0 -function _mapreducecols!{Tv,Ti}(f, op::typeof(+), R::AbstractArray, A::SparseMatrixCSC{Tv,Ti}) +function _mapreducecols!(f, op::typeof(+), R::AbstractArray, A::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} nzval = A.nzval m, n = size(A) if length(nzval) == m*n @@ -1690,7 +1690,7 @@ function _mapreducecols!{Tv,Ti}(f, op::typeof(+), R::AbstractArray, A::SparseMat end # findmax/min and indmax/min methods -function _findz{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, rows=1:A.m, cols=1:A.n) +function _findz(A::SparseMatrixCSC{Tv,Ti}, rows=1:A.m, cols=1:A.n) where {Tv,Ti} colptr = A.colptr; rowval = A.rowval; nzval = A.nzval zval = zero(Tv) col = cols[1]; row = 0 @@ -1895,7 +1895,7 @@ function getindex(A::SparseMatrixCSC{Tv,Ti}, I::Range, J::AbstractVector) where return SparseMatrixCSC(nI, nJ, colptrS, rowvalS, nzvalS) end -function getindex_I_sorted{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVector, J::AbstractVector) +function getindex_I_sorted(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVector, J::AbstractVector) where {Tv,Ti} # Sorted vectors for indexing rows. # Similar to getindex_general but without the transpose trick. (m, n) = size(A) @@ -1915,7 +1915,7 @@ function getindex_I_sorted{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVector, getindex_I_sorted_linear(A, I, J) end -function getindex_I_sorted_bsearch_A{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVector, J::AbstractVector) +function getindex_I_sorted_bsearch_A(A::SparseMatrixCSC{Tv,Ti}, I::AbstractVector, J::AbstractVector) where {Tv,Ti} const nI = length(I) const nJ = length(J) @@ -3258,7 +3258,7 @@ function next(d::SpDiagIterator{Tv}, j) where Tv (((r1 > r2) || (A.rowval[r1] != j)) ? zero(Tv) : A.nzval[r1], j+1) end -function trace{Tv}(A::SparseMatrixCSC{Tv}) +function trace(A::SparseMatrixCSC{Tv}) where Tv if size(A,1) != size(A,2) throw(DimensionMismatch("expected square matrix")) end @@ -3269,10 +3269,10 @@ function trace{Tv}(A::SparseMatrixCSC{Tv}) s end -diag{Tv}(A::SparseMatrixCSC{Tv}) = Tv[d for d in SpDiagIterator(A)] +diag(A::SparseMatrixCSC{Tv}) where {Tv} = Tv[d for d in SpDiagIterator(A)] -function diagm{Tv,Ti}(v::SparseMatrixCSC{Tv,Ti}) - if (size(v,1) != 1 && size(v,2) != 1) +function diagm(v::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} + if size(v,1) != 1 && size(v,2) != 1 throw(DimensionMismatch("input should be nx1 or 1xn")) end From 9b51302a295880bbcb1d2f1c6e098722c424d025 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Tue, 30 May 2017 11:30:32 +0200 Subject: [PATCH 42/53] Store info in Cholesky type (#21976) * add info field to Cholesky type and delay throwing for non-positive definiteness * comment update [ci skip] * remove comment [ci skip] --- base/linalg/cholesky.jl | 79 ++++++++++++++++++++++++++--------------- base/linalg/dense.jl | 8 +++-- base/linalg/lapack.jl | 4 +-- test/linalg/cholesky.jl | 24 +++++++++---- 4 files changed, 74 insertions(+), 41 deletions(-) diff --git a/base/linalg/cholesky.jl b/base/linalg/cholesky.jl index 0d09fa998028d2..2b5c89cad03efc 100644 --- a/base/linalg/cholesky.jl +++ b/base/linalg/cholesky.jl @@ -18,6 +18,11 @@ # through the Hermitian and Symmetric views or exact symmetric or Hermitian elements which # is checked for and an error is thrown if the check fails. +# The internal structure is as follows +# - _chol! returns the factor and info without checking positive definiteness +# - chol/chol! returns the factor and checks for positive definiteness +# - cholfact/cholfact! returns Cholesky with checking positive definiteness + # FixMe? The dispatch below seems overly complicated. One simplification could be to # merge the two Cholesky types into one. It would remove the need for Val completely but # the cost would be extra unnecessary/unused fields for the unpivoted Cholesky and runtime @@ -27,9 +32,12 @@ struct Cholesky{T,S<:AbstractMatrix} <: Factorization{T} factors::S uplo::Char + info::BlasInt end -Cholesky{T}(A::AbstractMatrix{T}, uplo::Symbol) = Cholesky{T,typeof(A)}(A, char_uplo(uplo)) -Cholesky{T}(A::AbstractMatrix{T}, uplo::Char) = Cholesky{T,typeof(A)}(A, uplo) +Cholesky{T}(A::AbstractMatrix{T}, uplo::Symbol, info::BlasInt) = + Cholesky{T,typeof(A)}(A, char_uplo(uplo), info) +Cholesky{T}(A::AbstractMatrix{T}, uplo::Char, info::BlasInt) = + Cholesky{T,typeof(A)}(A, uplo, info) struct CholeskyPivoted{T,S<:AbstractMatrix} <: Factorization{T} factors::S @@ -49,11 +57,11 @@ end ## BLAS/LAPACK element types function _chol!(A::StridedMatrix{<:BlasFloat}, ::Type{UpperTriangular}) C, info = LAPACK.potrf!('U', A) - return @assertposdef UpperTriangular(C) info + return UpperTriangular(C), info end function _chol!(A::StridedMatrix{<:BlasFloat}, ::Type{LowerTriangular}) C, info = LAPACK.potrf!('L', A) - return @assertposdef LowerTriangular(C) info + return LowerTriangular(C), info end ## Non BLAS/LAPACK element types (generic) @@ -64,7 +72,10 @@ function _chol!(A::AbstractMatrix, ::Type{UpperTriangular}) for i = 1:k - 1 A[k,k] -= A[i,k]'A[i,k] end - Akk = _chol!(A[k,k], UpperTriangular) + Akk, info = _chol!(A[k,k], UpperTriangular) + if info != 0 + return UpperTriangular(A), info + end A[k,k] = Akk AkkInv = inv(Akk') for j = k + 1:n @@ -75,7 +86,7 @@ function _chol!(A::AbstractMatrix, ::Type{UpperTriangular}) end end end - return UpperTriangular(A) + return UpperTriangular(A), convert(BlasInt, 0) end function _chol!(A::AbstractMatrix, ::Type{LowerTriangular}) n = checksquare(A) @@ -84,7 +95,10 @@ function _chol!(A::AbstractMatrix, ::Type{LowerTriangular}) for i = 1:k - 1 A[k,k] -= A[k,i]*A[k,i]' end - Akk = _chol!(A[k,k], LowerTriangular) + Akk, info = _chol!(A[k,k], LowerTriangular) + if info != 0 + return LowerTriangular(A), info + end A[k,k] = Akk AkkInv = inv(Akk) for j = 1:k @@ -99,30 +113,33 @@ function _chol!(A::AbstractMatrix, ::Type{LowerTriangular}) end end end - return LowerTriangular(A) + return LowerTriangular(A), convert(BlasInt, 0) end ## Numbers function _chol!(x::Number, uplo) rx = real(x) - if rx != abs(x) - throw(ArgumentError("x must be positive semidefinite")) - end - rxr = sqrt(rx) - convert(promote_type(typeof(x), typeof(rxr)), rxr) + rxr = sqrt(abs(rx)) + rval = convert(promote_type(typeof(x), typeof(rxr)), rxr) + rx == abs(x) ? (rval, convert(BlasInt, 0)) : (rval, convert(BlasInt, 1)) end +chol!(x::Number, uplo) = ((C, info) = _chol!(x, uplo); @assertposdef C info) + non_hermitian_error(f) = throw(ArgumentError("matrix is not symmetric/" * "Hermitian. This error can be avoided by calling $f(Hermitian(A)) " * "which will ignore either the upper or lower triangle of the matrix.")) # chol!. Destructive methods for computing Cholesky factor of real symmetric or Hermitian # matrix -chol!(A::RealHermSymComplexHerm{<:Real,<:StridedMatrix}) = - _chol!(A.uplo == 'U' ? A.data : LinAlg.copytri!(A.data, 'L', true), UpperTriangular) +function chol!(A::RealHermSymComplexHerm{<:Real,<:StridedMatrix}) + C, info = _chol!(A.uplo == 'U' ? A.data : LinAlg.copytri!(A.data, 'L', true), UpperTriangular) + @assertposdef C info +end function chol!(A::StridedMatrix) ishermitian(A) || non_hermitian_error("chol!") - return _chol!(A, UpperTriangular) + C, info = _chol!(A, UpperTriangular) + @assertposdef C info end @@ -184,7 +201,7 @@ julia> chol(16) 4.0 ``` """ -chol(x::Number, args...) = _chol!(x, nothing) +chol(x::Number, args...) = ((C, info) = _chol!(x, nothing); @assertposdef C info) @@ -193,9 +210,11 @@ chol(x::Number, args...) = _chol!(x, nothing) ## No pivoting function cholfact!(A::RealHermSymComplexHerm, ::Type{Val{false}}) if A.uplo == 'U' - Cholesky(_chol!(A.data, UpperTriangular).data, 'U') + CU, info = _chol!(A.data, UpperTriangular) + Cholesky(CU.data, 'U', info) else - Cholesky(_chol!(A.data, LowerTriangular).data, 'L') + CL, info = _chol!(A.data, LowerTriangular) + Cholesky(CL.data, 'L', info) end end @@ -354,14 +373,15 @@ end ## Number function cholfact(x::Number, uplo::Symbol=:U) - xf = fill(chol(x), 1, 1) - Cholesky(xf, uplo) + C, info = _chol!(x, uplo) + xf = fill(C, 1, 1) + Cholesky(xf, uplo, info) end function convert(::Type{Cholesky{T}}, C::Cholesky) where T Cnew = convert(AbstractMatrix{T}, C.factors) - Cholesky{T, typeof(Cnew)}(Cnew, C.uplo) + Cholesky{T, typeof(Cnew)}(Cnew, C.uplo, C.info) end convert(::Type{Factorization{T}}, C::Cholesky{T}) where {T} = C convert(::Type{Factorization{T}}, C::Cholesky) where {T} = convert(Cholesky{T}, C) @@ -386,7 +406,7 @@ convert(::Type{Matrix}, F::CholeskyPivoted) = convert(Array, convert(AbstractArr convert(::Type{Array}, F::CholeskyPivoted) = convert(Matrix, F) full(F::CholeskyPivoted) = convert(AbstractArray, F) -copy(C::Cholesky) = Cholesky(copy(C.factors), C.uplo) +copy(C::Cholesky) = Cholesky(copy(C.factors), C.uplo, C.info) copy(C::CholeskyPivoted) = CholeskyPivoted(copy(C.factors), C.uplo, C.piv, C.rank, C.tol, C.info) size(C::Union{Cholesky, CholeskyPivoted}) = size(C.factors) @@ -417,7 +437,7 @@ show(io::IO, C::Cholesky{<:Any,<:AbstractMatrix}) = (println(io, "$(typeof(C)) with factor:");show(io,C[:UL])) A_ldiv_B!(C::Cholesky{T,<:AbstractMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} = - LAPACK.potrs!(C.uplo, C.factors, B) + @assertposdef LAPACK.potrs!(C.uplo, C.factors, B) C.info function A_ldiv_B!(C::Cholesky{<:Any,<:AbstractMatrix}, B::StridedVecOrMat) if C.uplo == 'L' @@ -465,16 +485,18 @@ function A_ldiv_B!(C::CholeskyPivoted, B::StridedMatrix) end function det(C::Cholesky) + C.info == 0 || throw(PosDefException(C.info)) dd = one(real(eltype(C))) - for i in 1:size(C.factors,1) + @inbounds for i in 1:size(C.factors,1) dd *= real(C.factors[i,i])^2 end dd end function logdet(C::Cholesky) + C.info == 0 || throw(PosDefException(C.info)) dd = zero(real(eltype(C))) - for i in 1:size(C.factors,1) + @inbounds for i in 1:size(C.factors,1) dd += log(real(C.factors[i,i])) end dd + dd # instead of 2.0dd which can change the type @@ -505,10 +527,9 @@ function logdet(C::CholeskyPivoted) end inv!(C::Cholesky{<:BlasFloat,<:StridedMatrix}) = - copytri!(LAPACK.potri!(C.uplo, C.factors), C.uplo, true) + @assertposdef copytri!(LAPACK.potri!(C.uplo, C.factors), C.uplo, true) C.info -inv(C::Cholesky{<:BlasFloat,<:StridedMatrix}) = - inv!(copy(C)) +inv(C::Cholesky{<:BlasFloat,<:StridedMatrix}) = inv!(copy(C)) function inv(C::CholeskyPivoted) chkfullrank(C) diff --git a/base/linalg/dense.jl b/base/linalg/dense.jl index 0f96ffc3ab5dd8..c1dc43965e13b5 100644 --- a/base/linalg/dense.jl +++ b/base/linalg/dense.jl @@ -770,10 +770,12 @@ function factorize(A::StridedMatrix{T}) where T return UpperTriangular(A) end if herm - try - return cholfact(A) + cf = cholfact(A) + if cf.info == 0 + return cf + else + return factorize(Hermitian(A)) end - return factorize(Hermitian(A)) end if sym return factorize(Symmetric(A)) diff --git a/base/linalg/lapack.jl b/base/linalg/lapack.jl index 14d8f76df34ae7..1f9c71488a7737 100644 --- a/base/linalg/lapack.jl +++ b/base/linalg/lapack.jl @@ -2963,10 +2963,10 @@ for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in (Ptr{UInt8}, Ptr{BlasInt}, Ptr{$elty}, Ptr{BlasInt}, Ptr{BlasInt}), &uplo, &size(A,1), A, &lda, info) chkargsok(info[]) - #info[1]>0 means the leading minor of order info[i] is not positive definite + #info[] > 0 means the leading minor of order info[] is not positive definite #ordinarily, throw Exception here, but return error code here #this simplifies isposdef! and factorize - return A, info[] + return A, info[] # info stored in Cholesky end # SUBROUTINE DPOTRI( UPLO, N, A, LDA, INFO ) diff --git a/test/linalg/cholesky.jl b/test/linalg/cholesky.jl index e6aabd7f8ff179..b6d92d89ba9f7a 100644 --- a/test/linalg/cholesky.jl +++ b/test/linalg/cholesky.jl @@ -4,7 +4,7 @@ debug = false using Base.Test -using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted +using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException n = 10 @@ -60,7 +60,7 @@ for eltya in (Float32, Float64, Complex64, Complex128, BigFloat, Int) apos = apd[1,1] # test chol(x::Number), needs x>0 @test all(x -> x ≈ √apos, cholfact(apos).factors) - @test_throws ArgumentError chol(-one(eltya)) + @test_throws PosDefException chol(-one(eltya)) if eltya <: Real capds = cholfact(apds) @@ -194,10 +194,9 @@ end begin # Cholesky factor of Matrix with non-commutative elements, here 2x2-matrices - X = Matrix{Float64}[0.1*rand(2,2) for i in 1:3, j = 1:3] - L = full(Base.LinAlg._chol!(X*X', LowerTriangular)) - U = full(Base.LinAlg._chol!(X*X', UpperTriangular)) + L = full(Base.LinAlg._chol!(X*X', LowerTriangular)[1]) + U = full(Base.LinAlg._chol!(X*X', UpperTriangular)[1]) XX = full(X*X') @test sum(sum(norm, L*L' - XX)) < eps() @@ -212,8 +211,8 @@ for elty in (Float32, Float64, Complex{Float32}, Complex{Float64}) A = randn(5,5) end A = convert(Matrix{elty}, A'A) - @test full(cholfact(A)[:L]) ≈ full(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{LowerTriangular}}, copy(A), LowerTriangular)) - @test full(cholfact(A)[:U]) ≈ full(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{UpperTriangular}}, copy(A), UpperTriangular)) + @test full(cholfact(A)[:L]) ≈ full(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{LowerTriangular}}, copy(A), LowerTriangular)[1]) + @test full(cholfact(A)[:U]) ≈ full(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{UpperTriangular}}, copy(A), UpperTriangular)[1]) end # Test up- and downdates @@ -272,3 +271,14 @@ end # Fail for non-BLAS element types @test_throws ArgumentError cholfact!(Hermitian(rand(Float16, 5,5)), Val{true}) + +@testset "throw for non positive matrix" begin + for T in (Float32, Float64, Complex64, Complex128) + A = T[1 2; 2 1]; B = T[1, 1] + C = cholfact(A) + @show typeof(A), typeof(B), typeof(C.factors) + @test_throws PosDefException C\B + @test_throws PosDefException det(C) + @test_throws PosDefException logdet(C) + end +end From 7c4edd36992924b61272b33aaee5dab5b3001c62 Mon Sep 17 00:00:00 2001 From: Rory Hartong-Redden Date: Tue, 30 May 2017 03:14:27 -0700 Subject: [PATCH 43/53] Update documentation.md (#22121) --- doc/src/manual/documentation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/documentation.md b/doc/src/manual/documentation.md index 94499bf241f72a..284fe75c499112 100644 --- a/doc/src/manual/documentation.md +++ b/doc/src/manual/documentation.md @@ -110,7 +110,7 @@ As in the example above, we recommend following some simple conventions when wri produce consistent outputs during different Julia sessions. Operating system word size ([`Int32`](@ref) or [`Int64`](@ref)) as well as path separator differences - (`/` or `\`) will also effect the reproducibility of some doctests. + (`/` or `\`) will also affect the reproducibility of some doctests. Note that whitespace in your doctest is significant! The doctest will fail if you misalign the output of pretty-printing an array, for example. From 9b9c93b13dd02602957ce396e57963d38514c2d9 Mon Sep 17 00:00:00 2001 From: Fengyang Wang Date: Tue, 30 May 2017 04:16:29 -0700 Subject: [PATCH 44/53] Generate instead of hard coding factorial tables (#22096) * Generate instead of hard coding factorial tables * Preallocate factorial tables * Add tests with old literal tables --- base/combinatorics.jl | 34 +++++++++++----------------------- test/combinatorics.jl | 30 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/base/combinatorics.jl b/base/combinatorics.jl index 920f6c23d944e6..645a9499f1c63f 100644 --- a/base/combinatorics.jl +++ b/base/combinatorics.jl @@ -2,29 +2,17 @@ # Factorials -const _fact_table64 = - Int64[1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800, - 87178291200,1307674368000,20922789888000,355687428096000,6402373705728000, - 121645100408832000,2432902008176640000] - -const _fact_table128 = - UInt128[0x00000000000000000000000000000001, 0x00000000000000000000000000000002, - 0x00000000000000000000000000000006, 0x00000000000000000000000000000018, - 0x00000000000000000000000000000078, 0x000000000000000000000000000002d0, - 0x000000000000000000000000000013b0, 0x00000000000000000000000000009d80, - 0x00000000000000000000000000058980, 0x00000000000000000000000000375f00, - 0x00000000000000000000000002611500, 0x0000000000000000000000001c8cfc00, - 0x0000000000000000000000017328cc00, 0x0000000000000000000000144c3b2800, - 0x00000000000000000000013077775800, 0x00000000000000000000130777758000, - 0x00000000000000000001437eeecd8000, 0x00000000000000000016beecca730000, - 0x000000000000000001b02b9306890000, 0x000000000000000021c3677c82b40000, - 0x0000000000000002c5077d36b8c40000, 0x000000000000003ceea4c2b3e0d80000, - 0x000000000000057970cd7e2933680000, 0x00000000000083629343d3dcd1c00000, - 0x00000000000cd4a0619fb0907bc00000, 0x00000000014d9849ea37eeac91800000, - 0x00000000232f0fcbb3e62c3358800000, 0x00000003d925ba47ad2cd59dae000000, - 0x0000006f99461a1e9e1432dcb6000000, 0x00000d13f6370f96865df5dd54000000, - 0x0001956ad0aae33a4560c5cd2c000000, 0x0032ad5a155c6748ac18b9a580000000, - 0x0688589cc0e9505e2f2fee5580000000, 0xde1bc4d19efcac82445da75b00000000] +const _fact_table64 = Vector{Int64}(20) +_fact_table64[1] = 1 +for n in 2:20 + _fact_table64[n] = _fact_table64[n-1] * n +end + +const _fact_table128 = Vector{UInt128}(34) +_fact_table128[1] = 1 +for n in 2:34 + _fact_table128[n] = _fact_table128[n-1] * n +end function factorial_lookup(n::Integer, table, lim) n < 0 && throw(DomainError()) diff --git a/test/combinatorics.jl b/test/combinatorics.jl index 95fc8c5046ddde..c8fdeedf6df95a 100644 --- a/test/combinatorics.jl +++ b/test/combinatorics.jl @@ -67,4 +67,34 @@ end @test factorial(Int32(12)) === Int32(479001600) @test_throws OverflowError factorial(Int32(13)) end + + _fact_table64 = + Int64[1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800, + 87178291200,1307674368000,20922789888000,355687428096000,6402373705728000, + 121645100408832000,2432902008176640000] + + _fact_table128 = + UInt128[0x00000000000000000000000000000001, 0x00000000000000000000000000000002, + 0x00000000000000000000000000000006, 0x00000000000000000000000000000018, + 0x00000000000000000000000000000078, 0x000000000000000000000000000002d0, + 0x000000000000000000000000000013b0, 0x00000000000000000000000000009d80, + 0x00000000000000000000000000058980, 0x00000000000000000000000000375f00, + 0x00000000000000000000000002611500, 0x0000000000000000000000001c8cfc00, + 0x0000000000000000000000017328cc00, 0x0000000000000000000000144c3b2800, + 0x00000000000000000000013077775800, 0x00000000000000000000130777758000, + 0x00000000000000000001437eeecd8000, 0x00000000000000000016beecca730000, + 0x000000000000000001b02b9306890000, 0x000000000000000021c3677c82b40000, + 0x0000000000000002c5077d36b8c40000, 0x000000000000003ceea4c2b3e0d80000, + 0x000000000000057970cd7e2933680000, 0x00000000000083629343d3dcd1c00000, + 0x00000000000cd4a0619fb0907bc00000, 0x00000000014d9849ea37eeac91800000, + 0x00000000232f0fcbb3e62c3358800000, 0x00000003d925ba47ad2cd59dae000000, + 0x0000006f99461a1e9e1432dcb6000000, 0x00000d13f6370f96865df5dd54000000, + 0x0001956ad0aae33a4560c5cd2c000000, 0x0032ad5a155c6748ac18b9a580000000, + 0x0688589cc0e9505e2f2fee5580000000, 0xde1bc4d19efcac82445da75b00000000] + + for expected in Any[_fact_table64, _fact_table128] + for (n, factn) in enumerate(expected) + @test factorial(oftype(factn, n)) === factn + end + end end From ca22001c01051374f3bd73aa26342f84a52d3e60 Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Mon, 29 May 2017 20:37:45 -0400 Subject: [PATCH 45/53] Test if selfmem can write to RX page Also open only one `/proc/self/mem`. There are apparently two instances of `RTDyldMemoryManagerJL` created. Fix #22082 --- src/cgmemmgr.cpp | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/cgmemmgr.cpp b/src/cgmemmgr.cpp index ea59a6a3c42c77..6b2f43ebffdcf2 100644 --- a/src/cgmemmgr.cpp +++ b/src/cgmemmgr.cpp @@ -264,9 +264,9 @@ static void *alloc_shared_page(size_t size, size_t *id, bool exec) #ifdef _OS_LINUX_ // Using `/proc/self/mem`, A.K.A. Keno's remote memory manager. -static int self_mem_fd = -1; - -static int init_self_mem() +// Do not call this directly. +// Use `get_self_mem_fd` which has a guard to call this only once. +static int _init_self_mem() { struct utsname kernel; uname(&kernel); @@ -288,22 +288,34 @@ static int init_self_mem() return -1; fcntl(fd, F_SETFD, FD_CLOEXEC); #endif - // buffer to check if write works; - volatile uint64_t buff = 0; - uint64_t v = 0x12345678; - int ret = pwrite(fd, (void*)&v, sizeof(uint64_t), (uintptr_t)&buff); - if (ret != sizeof(uint64_t) || buff != 0x12345678) { + + // Check if we can write to a RX page + void *test_pg = mmap(nullptr, jl_page_size, PROT_READ | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + // We can ignore this though failure to allocate executable memory would be a bigger problem. + assert(test_pg != MAP_FAILED && "Cannot allocate executable memory"); + + const uint64_t v = 0xffff000012345678u; + int ret = pwrite(fd, (const void*)&v, sizeof(uint64_t), (uintptr_t)test_pg); + if (ret != sizeof(uint64_t) || *(volatile uint64_t*)test_pg != v) { + munmap(test_pg, jl_page_size); close(fd); return -1; } - self_mem_fd = fd; + munmap(test_pg, jl_page_size); + return fd; +} + +static int get_self_mem_fd() +{ + static int fd = _init_self_mem(); return fd; } static void write_self_mem(void *dest, void *ptr, size_t size) { while (size > 0) { - ssize_t ret = pwrite(self_mem_fd, ptr, size, (uintptr_t)dest); + ssize_t ret = pwrite(get_self_mem_fd(), ptr, size, (uintptr_t)dest); if ((size_t)ret == size) return; if (ret == -1 && (errno == EAGAIN || errno == EINTR)) @@ -657,7 +669,7 @@ class SelfMemAllocator : public ROAllocator { : ROAllocator(), temp_buff() { - assert(self_mem_fd != -1); + assert(get_self_mem_fd() != -1); } void finalize() override { @@ -717,7 +729,7 @@ class RTDyldMemoryManagerJL : public SectionMemoryManager { code_allocated(false) { #ifdef _OS_LINUX_ - if (!ro_alloc && init_self_mem() != -1) { + if (!ro_alloc && get_self_mem_fd() != -1) { ro_alloc.reset(new SelfMemAllocator()); exe_alloc.reset(new SelfMemAllocator()); } From 6698ac40cc9023e55bdd14b817bf9177a23fe087 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 30 May 2017 12:59:17 -0400 Subject: [PATCH 46/53] inference: fix some cases of invalid age range updates ref #21653 --- base/REPLCompletions.jl | 2 +- base/inference.jl | 5 +++-- base/reflection.jl | 5 ++--- test/inference.jl | 5 +++++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/base/REPLCompletions.jl b/base/REPLCompletions.jl index f5626e5f5c57ab..d58aebe5f98329 100644 --- a/base/REPLCompletions.jl +++ b/base/REPLCompletions.jl @@ -282,7 +282,7 @@ function get_type_call(expr::Expr) found ? push!(args, typ) : push!(args, Any) end # use _methods_by_ftype as the function is supplied as a type - world = typemax(UInt) + world = ccall(:jl_get_world_counter, UInt, ()) mt = Base._methods_by_ftype(Tuple{ft, args...}, -1, world) length(mt) == 1 || return (Any, false) m = first(mt) diff --git a/base/inference.jl b/base/inference.jl index 7f5e66182ad18f..8ea12fd2b2eac1 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -5415,7 +5415,8 @@ end # especially try to make sure any recursive and leaf functions have concrete signatures, # since we won't be able to specialize & infer them at runtime -let fs = Any[typeinf_ext, typeinf, typeinf_edge, occurs_outside_getfield, pure_eval_call] +let fs = Any[typeinf_ext, typeinf, typeinf_edge, occurs_outside_getfield, pure_eval_call], + world = ccall(:jl_get_world_counter, UInt, ()) for x in t_ffunc_val push!(fs, x[3]) end @@ -5434,7 +5435,7 @@ let fs = Any[typeinf_ext, typeinf, typeinf_edge, occurs_outside_getfield, pure_e typ[i] = typ[i].ub end end - typeinf_type(m[3], Tuple{typ...}, m[2], true, InferenceParams(typemax(UInt))) + typeinf_type(m[3], Tuple{typ...}, m[2], true, InferenceParams(world)) end end end diff --git a/base/reflection.jl b/base/reflection.jl index eb8e279e119778..e322a22dfe020a 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -763,7 +763,6 @@ function func_for_method_checked(m::Method, types::ANY) return m end - """ code_typed(f, types; optimize=true) @@ -778,7 +777,7 @@ function code_typed(f::ANY, types::ANY=Tuple; optimize=true) end types = to_tuple_type(types) asts = [] - world = typemax(UInt) + world = ccall(:jl_get_world_counter, UInt, ()) params = Core.Inference.InferenceParams(world) for x in _methods(f, types, -1, world) meth = func_for_method_checked(x[3], types) @@ -796,7 +795,7 @@ function return_types(f::ANY, types::ANY=Tuple) end types = to_tuple_type(types) rt = [] - world = typemax(UInt) + world = ccall(:jl_get_world_counter, UInt, ()) params = Core.Inference.InferenceParams(world) for x in _methods(f, types, -1, world) meth = func_for_method_checked(x[3], types) diff --git a/test/inference.jl b/test/inference.jl index 5f62946ddde726..61d283c73368c3 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -838,3 +838,8 @@ f21771(::Val{U}) where {U} = Tuple{g21771(U)} # missing method should be inferred as Union{}, ref https://github.com/JuliaLang/julia/issues/20033#issuecomment-282228948 @test Base.return_types(f -> f(1), (typeof((x::String) -> x),)) == Any[Union{}] + +# issue #21653 +# ensure that we don't try to resolve cycles using uncached edges +f21653() = f21653() +@test code_typed(f21653, Tuple{}, optimize=false)[1] isa Pair{CodeInfo, typeof(Union{})} From 95677b061cc654e911f2cca1727db238a27ac67a Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 30 May 2017 17:49:06 -0400 Subject: [PATCH 47/53] prevent Docs.apropos from breaking on random stuff interpolated into docs --- base/docs/utils.jl | 1 + test/docs.jl | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/base/docs/utils.jl b/base/docs/utils.jl index 4a3a8b1e7a4794..895edf349e5be8 100644 --- a/base/docs/utils.jl +++ b/base/docs/utils.jl @@ -414,6 +414,7 @@ Strip all Markdown markup from x, leaving the result in plain text. Used internally by apropos to make docstrings containing more than one markdown element searchable. """ +stripmd(x::ANY) = string(x) # for random objects interpolated into the docstring stripmd(x::AbstractString) = x # base case stripmd(x::Void) = " " stripmd(x::Vector) = string(map(stripmd, x)...) diff --git a/test/docs.jl b/test/docs.jl index 54bae5861ce2e3..eadd59e65cad16 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -34,6 +34,20 @@ macro macro_doctest() end @test (@doc @macro_doctest) !== nothing +# test that random stuff interpolated into docstrings doesn't break search or other methods here +doc""" +break me: + + code + +$:asymbol # a symbol +$1 # a number +$string # a function +$$latex literal$$ +### header! +""" +function break_me_docs end + # issue #11548 module ModuleMacroDoc From 5ecbae0563a219a35a4babb81129070a670121ca Mon Sep 17 00:00:00 2001 From: Amit Murthy Date: Wed, 31 May 2017 08:13:06 +0530 Subject: [PATCH 48/53] NEWS.md update : move getpeername to the correct section (#22141) --- NEWS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 787a916a6c6d82..75dc3d9ff86e9c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,9 +3,6 @@ Julia v0.7.0 Release Notes New language features --------------------- - * `getpeername` on a `TCPSocket` returns the address and port of the remote - endpoint of the TCP connection ([#21825]). - Language changes ---------------- @@ -53,6 +50,9 @@ Library improvements method can be opened in an editor by entering the corresponding number in the REPL and pressing `^Q` ([#22007]). + * `getpeername` on a `TCPSocket` returns the address and port of the remote + endpoint of the TCP connection ([#21825]). + Compiler/Runtime improvements ----------------------------- From 422a7436653caa0cbbb5416d70711494204f8835 Mon Sep 17 00:00:00 2001 From: Mus M Date: Tue, 30 May 2017 23:05:28 -0400 Subject: [PATCH 49/53] make libllvm version const --- base/version.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/version.jl b/base/version.jl index 213f603ec53f89..08938b3f48af9b 100644 --- a/base/version.jl +++ b/base/version.jl @@ -223,7 +223,7 @@ catch e VersionNumber(0) end -libllvm_version = convert(VersionNumber, libllvm_version_string) +const libllvm_version = convert(VersionNumber, libllvm_version_string) function banner(io::IO = STDOUT) if GIT_VERSION_INFO.tagged_commit From eb67a56e8d187c80edb2ba0a75508f53e5497165 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 25 May 2017 00:28:29 -0400 Subject: [PATCH 50/53] windows readme: add automation tips --- README.windows.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/README.windows.md b/README.windows.md index 96ccc1a7f9f17c..15278e2802f989 100644 --- a/README.windows.md +++ b/README.windows.md @@ -184,6 +184,12 @@ versions of the MinGW-w64 compilers available through Cygwin's package manager. either 32 or 64 bit Julia from either 32 or 64 bit Cygwin. 64 bit Cygwin has a slightly smaller but often more up-to-date selection of packages. + Advanced: you may skip steps 2-4 by running: + + setup-x86_64.exe -s -q -P cmake,gcc-g++,git,make,patch,curl,m4,python,p7zip,mingw64-i686-gcc-g++,mingw64-i686-gcc-fortran,mingw64-x86_64-gcc-g++,mingw64-x86_64-gcc-fortran + :: replace with a site from https://cygwin.com/mirrors.html + :: or run setup manually first and select a mirror + 2. Select installation location and download mirror. 3. At the '*Select Packages'* step, select the following: @@ -207,7 +213,7 @@ versions of the MinGW-w64 compilers available through Cygwin's package manager. 1. Get the Julia sources ```sh - git clone --recursive https://github.com/JuliaLang/julia.git + git clone https://github.com/JuliaLang/julia.git cd julia ``` Tip: If you get an `error: cannot fork() for fetch-pack: Resource @@ -219,7 +225,7 @@ versions of the MinGW-w64 compilers available through Cygwin's package manager. ```sh echo 'XC_HOST = i686-w64-mingw32' > Make.user # for 32 bit Julia # or - echo 'XC_HOST = x86_64-w64-mingw32' > Make.user #for 64 bit Julia + echo 'XC_HOST = x86_64-w64-mingw32' > Make.user # for 64 bit Julia ``` 3. Start the build @@ -227,6 +233,20 @@ versions of the MinGW-w64 compilers available through Cygwin's package manager. make -j 4 # Adjust the number of cores (4) to match your build environment. ``` + + > Protip: build both! + > ```sh + > make O=julia-win32 configure + > make O=julia-win64 configure + > echo 'XC_HOST = i686-w64-mingw32' > julia-win32/Make.user + > echo 'XC_HOST = x86_64-w64-mingw32' > julia-win64/Make.user + > echo 'ifeq ($(BUILDROOT),$(JULIAHOME)) + > $(error "in-tree build disabled") + > endif' >> Make.user + > make -C julia-win32 # build for Windows x86 in julia-win32 folder + > make -C julia-win64 # build for Windows x86-64 in julia-win64 folder + > ``` + 7. Run Julia using the Julia executables directly ```sh usr/bin/julia.exe From b11bc921b0922abbbdb6e66019de336df31b497a Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Wed, 31 May 2017 16:51:23 +0200 Subject: [PATCH 51/53] use testsets in cholesky test (#22138) --- test/linalg/cholesky.jl | 324 ++++++++++++++++++++-------------------- 1 file changed, 159 insertions(+), 165 deletions(-) diff --git a/test/linalg/cholesky.jl b/test/linalg/cholesky.jl index b6d92d89ba9f7a..0364b4bfb9fa27 100644 --- a/test/linalg/cholesky.jl +++ b/test/linalg/cholesky.jl @@ -1,165 +1,157 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -debug = false - using Base.Test using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException -n = 10 +@testset "core functionality" begin + n = 10 -# Split n into 2 parts for tests needing two matrices -n1 = div(n, 2) -n2 = 2*n1 + # Split n into 2 parts for tests needing two matrices + n1 = div(n, 2) + n2 = 2*n1 -srand(1234321) + srand(1234321) -areal = randn(n,n)/2 -aimg = randn(n,n)/2 -a2real = randn(n,n)/2 -a2img = randn(n,n)/2 -breal = randn(n,2)/2 -bimg = randn(n,2)/2 + areal = randn(n,n)/2 + aimg = randn(n,n)/2 + a2real = randn(n,n)/2 + a2img = randn(n,n)/2 + breal = randn(n,2)/2 + bimg = randn(n,2)/2 -for eltya in (Float32, Float64, Complex64, Complex128, BigFloat, Int) - a = eltya == Int ? rand(1:7, n, n) : convert(Matrix{eltya}, eltya <: Complex ? complex.(areal, aimg) : areal) - a2 = eltya == Int ? rand(1:7, n, n) : convert(Matrix{eltya}, eltya <: Complex ? complex.(a2real, a2img) : a2real) - apd = a'*a # symmetric positive-definite + for eltya in (Float32, Float64, Complex64, Complex128, BigFloat, Int) + a = eltya == Int ? rand(1:7, n, n) : convert(Matrix{eltya}, eltya <: Complex ? complex.(areal, aimg) : areal) + a2 = eltya == Int ? rand(1:7, n, n) : convert(Matrix{eltya}, eltya <: Complex ? complex.(a2real, a2img) : a2real) + apd = a'*a # symmetric positive-definite - apds = Symmetric(apd) - apdsL = Symmetric(apd, :L) - apdh = Hermitian(apd) - apdhL = Hermitian(apd, :L) - ε = εa = eps(abs(float(one(eltya)))) + apds = Symmetric(apd) + apdsL = Symmetric(apd, :L) + apdh = Hermitian(apd) + apdhL = Hermitian(apd, :L) + ε = εa = eps(abs(float(one(eltya)))) - @inferred cholfact(apd) - @inferred chol(apd) - capd = factorize(apd) - r = capd[:U] - κ = cond(apd, 1) #condition number + @inferred cholfact(apd) + @inferred chol(apd) + capd = factorize(apd) + r = capd[:U] + κ = cond(apd, 1) #condition number - #getindex - @test_throws KeyError capd[:Z] + #getindex + @test_throws KeyError capd[:Z] - #Test error bound on reconstruction of matrix: LAWNS 14, Lemma 2.1 + #Test error bound on reconstruction of matrix: LAWNS 14, Lemma 2.1 - #these tests were failing on 64-bit linux when inside the inner loop - #for eltya = Complex64 and eltyb = Int. The E[i,j] had NaN32 elements - #but only with srand(1234321) set before the loops. - E = abs.(apd - r'*r) - for i=1:n, j=1:n - @test E[i,j] <= (n+1)ε/(1-(n+1)ε)*real(sqrt(apd[i,i]*apd[j,j])) - end - E = abs.(apd - full(capd)) - for i=1:n, j=1:n - @test E[i,j] <= (n+1)ε/(1-(n+1)ε)*real(sqrt(apd[i,i]*apd[j,j])) - end - @test apd*inv(capd) ≈ eye(n) - @test abs((det(capd) - det(apd))/det(capd)) <= ε*κ*n # Ad hoc, but statistically verified, revisit - @test @inferred(logdet(capd)) ≈ log(det(capd)) # logdet is less likely to overflow - - apos = apd[1,1] # test chol(x::Number), needs x>0 - @test all(x -> x ≈ √apos, cholfact(apos).factors) - @test_throws PosDefException chol(-one(eltya)) - - if eltya <: Real - capds = cholfact(apds) - @test inv(capds)*apds ≈ eye(n) - @test abs((det(capds) - det(apd))/det(capds)) <= ε*κ*n - if eltya <: BlasReal - capds = cholfact!(copy(apds)) + #these tests were failing on 64-bit linux when inside the inner loop + #for eltya = Complex64 and eltyb = Int. The E[i,j] had NaN32 elements + #but only with srand(1234321) set before the loops. + E = abs.(apd - r'*r) + for i=1:n, j=1:n + @test E[i,j] <= (n+1)ε/(1-(n+1)ε)*real(sqrt(apd[i,i]*apd[j,j])) + end + E = abs.(apd - full(capd)) + for i=1:n, j=1:n + @test E[i,j] <= (n+1)ε/(1-(n+1)ε)*real(sqrt(apd[i,i]*apd[j,j])) + end + @test apd*inv(capd) ≈ eye(n) + @test abs((det(capd) - det(apd))/det(capd)) <= ε*κ*n # Ad hoc, but statistically verified, revisit + @test @inferred(logdet(capd)) ≈ log(det(capd)) # logdet is less likely to overflow + + apos = apd[1,1] # test chol(x::Number), needs x>0 + @test all(x -> x ≈ √apos, cholfact(apos).factors) + @test_throws PosDefException chol(-one(eltya)) + + if eltya <: Real + capds = cholfact(apds) @test inv(capds)*apds ≈ eye(n) @test abs((det(capds) - det(apd))/det(capds)) <= ε*κ*n + if eltya <: BlasReal + capds = cholfact!(copy(apds)) + @test inv(capds)*apds ≈ eye(n) + @test abs((det(capds) - det(apd))/det(capds)) <= ε*κ*n + end + ulstring = sprint(show,capds[:UL]) + @test sprint(show,capds) == "$(typeof(capds)) with factor:\n$ulstring" + else + capdh = cholfact(apdh) + @test inv(capdh)*apdh ≈ eye(n) + @test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n + capdh = cholfact!(copy(apdh)) + @test inv(capdh)*apdh ≈ eye(n) + @test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n + capdh = cholfact!(copy(apd)) + @test inv(capdh)*apdh ≈ eye(n) + @test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n + capdh = cholfact!(copy(apd), :L) + @test inv(capdh)*apdh ≈ eye(n) + @test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n + ulstring = sprint(show,capdh[:UL]) + @test sprint(show,capdh) == "$(typeof(capdh)) with factor:\n$ulstring" end - ulstring = sprint(show,capds[:UL]) - @test sprint(show,capds) == "$(typeof(capds)) with factor:\n$ulstring" - else - capdh = cholfact(apdh) - @test inv(capdh)*apdh ≈ eye(n) - @test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n - capdh = cholfact!(copy(apdh)) - @test inv(capdh)*apdh ≈ eye(n) - @test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n - capdh = cholfact!(copy(apd)) - @test inv(capdh)*apdh ≈ eye(n) - @test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n - capdh = cholfact!(copy(apd), :L) - @test inv(capdh)*apdh ≈ eye(n) - @test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n - ulstring = sprint(show,capdh[:UL]) - @test sprint(show,capdh) == "$(typeof(capdh)) with factor:\n$ulstring" - end - # test chol of 2x2 Strang matrix - S = convert(AbstractMatrix{eltya},full(SymTridiagonal([2,2],[-1]))) - U = Bidiagonal([2,sqrt(eltya(3))],[-1],true) / sqrt(eltya(2)) - @test full(chol(S)) ≈ full(U) - - #lower Cholesky factor - lapd = cholfact(apd, :L) - @test full(lapd) ≈ apd - l = lapd[:L] - @test l*l' ≈ apd - @test triu(capd.factors) ≈ lapd[:U] - @test tril(lapd.factors) ≈ capd[:L] - if eltya <: Real - capds = cholfact(apds) - lapds = cholfact(apdsL) - cl = chol(apdsL) - ls = lapds[:L] - @test ls*ls' ≈ apd - @test triu(capds.factors) ≈ lapds[:U] - @test tril(lapds.factors) ≈ capds[:L] - @test istriu(cl) - @test cl'cl ≈ apds - @test cl'cl ≈ apdsL - else - capdh = cholfact(apdh) - lapdh = cholfact(apdhL) - cl = chol(apdhL) - ls = lapdh[:L] - @test ls*ls' ≈ apd - @test triu(capdh.factors) ≈ lapdh[:U] - @test tril(lapdh.factors) ≈ capdh[:L] - @test istriu(cl) - @test cl'cl ≈ apdh - @test cl'cl ≈ apdhL - end + # test chol of 2x2 Strang matrix + S = convert(AbstractMatrix{eltya},full(SymTridiagonal([2,2],[-1]))) + U = Bidiagonal([2,sqrt(eltya(3))],[-1],true) / sqrt(eltya(2)) + @test full(chol(S)) ≈ full(U) + + #lower Cholesky factor + lapd = cholfact(apd, :L) + @test full(lapd) ≈ apd + l = lapd[:L] + @test l*l' ≈ apd + @test triu(capd.factors) ≈ lapd[:U] + @test tril(lapd.factors) ≈ capd[:L] + if eltya <: Real + capds = cholfact(apds) + lapds = cholfact(apdsL) + cl = chol(apdsL) + ls = lapds[:L] + @test ls*ls' ≈ apd + @test triu(capds.factors) ≈ lapds[:U] + @test tril(lapds.factors) ≈ capds[:L] + @test istriu(cl) + @test cl'cl ≈ apds + @test cl'cl ≈ apdsL + else + capdh = cholfact(apdh) + lapdh = cholfact(apdhL) + cl = chol(apdhL) + ls = lapdh[:L] + @test ls*ls' ≈ apd + @test triu(capdh.factors) ≈ lapdh[:U] + @test tril(lapdh.factors) ≈ capdh[:L] + @test istriu(cl) + @test cl'cl ≈ apdh + @test cl'cl ≈ apdhL + end - #pivoted upper Cholesky - if eltya != BigFloat - cz = cholfact(zeros(eltya,n,n), :U, Val{true}) - @test_throws Base.LinAlg.RankDeficientException Base.LinAlg.chkfullrank(cz) - cpapd = cholfact(apd, :U, Val{true}) - @test rank(cpapd) == n - @test all(diff(diag(real(cpapd.factors))).<=0.) # diagonal should be non-increasing - if isreal(apd) - @test apd*inv(cpapd) ≈ eye(n) + #pivoted upper Cholesky + if eltya != BigFloat + cz = cholfact(zeros(eltya,n,n), :U, Val{true}) + @test_throws Base.LinAlg.RankDeficientException Base.LinAlg.chkfullrank(cz) + cpapd = cholfact(apd, :U, Val{true}) + @test rank(cpapd) == n + @test all(diff(diag(real(cpapd.factors))).<=0.) # diagonal should be non-increasing + if isreal(apd) + @test apd*inv(cpapd) ≈ eye(n) + end + @test full(cpapd) ≈ apd + #getindex + @test_throws KeyError cpapd[:Z] + + @test size(cpapd) == size(apd) + @test full(copy(cpapd)) ≈ apd + @test det(cpapd) ≈ det(apd) + @test logdet(cpapd) ≈ logdet(apd) + @test cpapd[:P]*cpapd[:L]*cpapd[:U]*cpapd[:P]' ≈ apd end - @test full(cpapd) ≈ apd - #getindex - @test_throws KeyError cpapd[:Z] - @test size(cpapd) == size(apd) - @test full(copy(cpapd)) ≈ apd - @test det(cpapd) ≈ det(apd) - @test logdet(cpapd) ≈ logdet(apd) - @test cpapd[:P]*cpapd[:L]*cpapd[:U]*cpapd[:P]' ≈ apd - end + for eltyb in (Float32, Float64, Complex64, Complex128, Int) + b = eltyb == Int ? rand(1:5, n, 2) : convert(Matrix{eltyb}, eltyb <: Complex ? complex.(breal, bimg) : breal) + εb = eps(abs(float(one(eltyb)))) + ε = max(εa,εb) - for eltyb in (Float32, Float64, Complex64, Complex128, Int) - b = eltyb == Int ? rand(1:5, n, 2) : convert(Matrix{eltyb}, eltyb <: Complex ? complex.(breal, bimg) : breal) - εb = eps(abs(float(one(eltyb)))) - ε = max(εa,εb) - -debug && println("\ntype of a: ", eltya, " type of b: ", eltyb, "\n") - let Bs = b - for atype in ("Array", "SubArray") - if atype == "Array" - b = Bs - else - b = view(Bs, 1:n, 1) - end + for b in (b, view(b, 1:n, 1)) # Array and SubArray # Test error bound on linear solver: LAWNS 14, Theorem 2.1 # This is a surprisingly loose bound @@ -175,7 +167,6 @@ debug && println("\ntype of a: ", eltya, " type of b: ", eltyb, "\n") end @test_throws DimensionMismatch lapd\RowVector(ones(n)) -debug && println("pivoted Cholesky decomposition") if eltya != BigFloat && eltyb != BigFloat # Note! Need to implement pivoted Cholesky decomposition in julia @test norm(apd * (cpapd\b) - b)/norm(b) <= ε*κ*n # Ad hoc, revisit @@ -192,8 +183,7 @@ debug && println("pivoted Cholesky decomposition") end end -begin - # Cholesky factor of Matrix with non-commutative elements, here 2x2-matrices +@testset "Cholesky factor of Matrix with non-commutative elements, here 2x2-matrices" begin X = Matrix{Float64}[0.1*rand(2,2) for i in 1:3, j = 1:3] L = full(Base.LinAlg._chol!(X*X', LowerTriangular)[1]) U = full(Base.LinAlg._chol!(X*X', UpperTriangular)[1]) @@ -204,19 +194,22 @@ begin end # Test generic cholfact! -for elty in (Float32, Float64, Complex{Float32}, Complex{Float64}) - if elty <: Complex - A = complex.(randn(5,5), randn(5,5)) - else - A = randn(5,5) +@testset "generic cholfact!" begin + for elty in (Float32, Float64, Complex{Float32}, Complex{Float64}) + if elty <: Complex + A = complex.(randn(5,5), randn(5,5)) + else + A = randn(5,5) + end + A = convert(Matrix{elty}, A'A) + @test full(cholfact(A)[:L]) ≈ full(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{LowerTriangular}}, copy(A), LowerTriangular)[1]) + @test full(cholfact(A)[:U]) ≈ full(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{UpperTriangular}}, copy(A), UpperTriangular)[1]) end - A = convert(Matrix{elty}, A'A) - @test full(cholfact(A)[:L]) ≈ full(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{LowerTriangular}}, copy(A), LowerTriangular)[1]) - @test full(cholfact(A)[:U]) ≈ full(invoke(Base.LinAlg._chol!, Tuple{AbstractMatrix, Type{UpperTriangular}}, copy(A), UpperTriangular)[1]) end -# Test up- and downdates -let A = complex.(randn(10,5), randn(10, 5)), v = complex.(randn(5), randn(5)) +@testset "cholesky up- and downdates" begin + A = complex.(randn(10,5), randn(10, 5)) + v = complex.(randn(5), randn(5)) for uplo in (:U, :L) AcA = A'A BcB = AcA + v*v' @@ -230,8 +223,8 @@ let A = complex.(randn(10,5), randn(10, 5)), v = complex.(randn(5), randn(5)) end end -# issue #13243, unexpected nans in complex cholfact -let apd = [5.8525753f0 + 0.0f0im -0.79540455f0 + 0.7066077f0im 0.98274714f0 + 1.3824869f0im 2.619998f0 + 1.8532984f0im -1.8306153f0 - 1.2336911f0im 0.32275113f0 + 0.015575029f0im 2.1968813f0 + 1.0640624f0im 0.27894387f0 + 0.97911835f0im 3.0476584f0 + 0.18548489f0im 0.3842994f0 + 0.7050991f0im +@testset "issue #13243, unexpected nans in complex cholfact" begin + apd = [5.8525753f0 + 0.0f0im -0.79540455f0 + 0.7066077f0im 0.98274714f0 + 1.3824869f0im 2.619998f0 + 1.8532984f0im -1.8306153f0 - 1.2336911f0im 0.32275113f0 + 0.015575029f0im 2.1968813f0 + 1.0640624f0im 0.27894387f0 + 0.97911835f0im 3.0476584f0 + 0.18548489f0im 0.3842994f0 + 0.7050991f0im -0.79540455f0 - 0.7066077f0im 8.313246f0 + 0.0f0im -1.8076122f0 - 0.8882447f0im 0.47806996f0 + 0.48494184f0im 0.5096429f0 - 0.5395974f0im -0.7285097f0 - 0.10360408f0im -1.1760061f0 - 2.7146957f0im -0.4271084f0 + 0.042899966f0im -1.7228563f0 + 2.8335886f0im 1.8942566f0 + 0.6389735f0im 0.98274714f0 - 1.3824869f0im -1.8076122f0 + 0.8882447f0im 9.367975f0 + 0.0f0im -0.1838578f0 + 0.6468568f0im -1.8338387f0 + 0.7064959f0im 0.041852742f0 - 0.6556877f0im 2.5673025f0 + 1.9732997f0im -1.1148382f0 - 0.15693812f0im 2.4704504f0 - 1.0389464f0im 1.0858271f0 - 1.298006f0im 2.619998f0 - 1.8532984f0im 0.47806996f0 - 0.48494184f0im -0.1838578f0 - 0.6468568f0im 3.1117508f0 + 0.0f0im -1.956626f0 + 0.22825956f0im 0.07081801f0 - 0.31801307f0im 0.3698375f0 - 0.5400855f0im 0.80686307f0 + 1.5315914f0im 1.5649154f0 - 1.6229297f0im -0.112077385f0 + 1.2014246f0im @@ -261,22 +254,23 @@ let apd = [5.8525753f0 + 0.0f0im -0.79540455f0 + 0.7066077f0im 0.98274714f0 + 1. end end -# Fail if non-Hermitian -@test_throws ArgumentError cholfact(randn(5,5)) -@test_throws ArgumentError cholfact(complex.(randn(5,5), randn(5,5))) -@test_throws ArgumentError Base.LinAlg.chol!(randn(5,5)) -@test_throws ArgumentError Base.LinAlg.cholfact!(randn(5,5),:U,Val{false}) -@test_throws ArgumentError Base.LinAlg.cholfact!(randn(5,5),:U,Val{true}) -@test_throws ArgumentError cholfact(randn(5,5),:U,Val{false}) +@testset "throw if non-Hermitian" begin + @test_throws ArgumentError cholfact(randn(5,5)) + @test_throws ArgumentError cholfact(complex.(randn(5,5), randn(5,5))) + @test_throws ArgumentError Base.LinAlg.chol!(randn(5,5)) + @test_throws ArgumentError Base.LinAlg.cholfact!(randn(5,5),:U,Val{false}) + @test_throws ArgumentError Base.LinAlg.cholfact!(randn(5,5),:U,Val{true}) + @test_throws ArgumentError cholfact(randn(5,5),:U,Val{false}) +end -# Fail for non-BLAS element types -@test_throws ArgumentError cholfact!(Hermitian(rand(Float16, 5,5)), Val{true}) +@testset "fail for non-BLAS element types" begin + @test_throws ArgumentError cholfact!(Hermitian(rand(Float16, 5,5)), Val{true}) +end -@testset "throw for non positive matrix" begin +@testset "throw for non positive definite matrix" begin for T in (Float32, Float64, Complex64, Complex128) A = T[1 2; 2 1]; B = T[1, 1] C = cholfact(A) - @show typeof(A), typeof(B), typeof(C.factors) @test_throws PosDefException C\B @test_throws PosDefException det(C) @test_throws PosDefException logdet(C) From b5ac087664e90d4f69d80522cc48719c9f4f203f Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Wed, 31 May 2017 16:51:52 +0200 Subject: [PATCH 52/53] document order of svdvals (#22148) --- base/linalg/svd.jl | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/base/linalg/svd.jl b/base/linalg/svd.jl index 4ea9291873a898..639d528a1b8123 100644 --- a/base/linalg/svd.jl +++ b/base/linalg/svd.jl @@ -15,10 +15,6 @@ SVD(U::AbstractArray{T}, S::Vector{Tr}, Vt::AbstractArray{T}) where {T,Tr} = SVD `svdfact!` is the same as [`svdfact`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. - -If `thin=true` (default), a thin SVD is returned. For a ``M \\times N`` matrix -`A`, `U` is ``M \\times M`` for a full SVD (`thin=false`) and -``M \\times \\min(M, N)`` for a thin SVD. """ function svdfact!(A::StridedMatrix{T}; thin::Bool=true) where T<:BlasFloat m,n = size(A) @@ -38,6 +34,7 @@ Compute the singular value decomposition (SVD) of `A` and return an `SVD` object `U`, `S`, `V` and `Vt` can be obtained from the factorization `F` with `F[:U]`, `F[:S]`, `F[:V]` and `F[:Vt]`, such that `A = U*diagm(S)*Vt`. The algorithm produces `Vt` and hence `Vt` is more efficient to extract than `V`. +The singular values in `S` are sorted in descending order. If `thin=true` (default), a thin SVD is returned. For a ``M \\times N`` matrix `A`, `U` is ``M \\times M`` for a full SVD (`thin=false`) and @@ -74,7 +71,7 @@ svdfact(x::Integer; thin::Bool=true) = svdfact(float(x), thin=thin) svd(A, thin::Bool=true) -> U, S, V Computes the SVD of `A`, returning `U`, vector `S`, and `V` such that -`A == U*diagm(S)*V'`. +`A == U*diagm(S)*V'`. The singular values in `S` are sorted in descending order. If `thin=true` (default), a thin SVD is returned. For a ``M \\times N`` matrix `A`, `U` is ``M \\times M`` for a full SVD (`thin=false`) and @@ -136,7 +133,7 @@ svdvals(A::AbstractMatrix{<:BlasFloat}) = svdvals!(copy(A)) """ svdvals(A) -Returns the singular values of `A`. +Returns the singular values of `A` in descending order. # Example From 8f8c154aab466453bffa43a1b05faf01d915a3d9 Mon Sep 17 00:00:00 2001 From: Mus M Date: Wed, 31 May 2017 12:55:22 -0400 Subject: [PATCH 53/53] VersionNumber and return build in windows_version (#21837) --- base/sysimg.jl | 2 +- base/sysinfo.jl | 10 +++++----- test/osutils.jl | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/base/sysimg.jl b/base/sysimg.jl index 11a239a5f93bd0..31b1a6132009ea 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -162,7 +162,6 @@ include(string((length(Core.ARGS)>=2 ? Core.ARGS[2] : ""), "version_git.jl")) # include("osutils.jl") include("c.jl") -include("sysinfo.jl") if !isdefined(Core, :Inference) include("docs/core.jl") @@ -222,6 +221,7 @@ importall .Base64 include("version.jl") # system & environment +include("sysinfo.jl") include("libc.jl") using .Libc: getpid, gethostname, time include("libdl.jl") diff --git a/base/sysinfo.jl b/base/sysinfo.jl index 6c171d3649d765..95fc5ccb35f6ba 100644 --- a/base/sysinfo.jl +++ b/base/sysinfo.jl @@ -193,19 +193,19 @@ maxrss() = ccall(:jl_maxrss, Csize_t, ()) if is_windows() function windows_version() verinfo = ccall(:GetVersion, UInt32, ()) - (Int(verinfo & 0xFF), Int((verinfo >> 8) & 0xFF)) + VersionNumber(verinfo & 0xFF, (verinfo >> 8) & 0xFF, verinfo >> 16) end else - windows_version() = (0, 0) + windows_version() = v"0.0" end """ Sys.windows_version() -Returns the version number for the Windows NT Kernel as a (major, minor) pair, -or `(0, 0)` if this is not running on Windows. +Returns the version number for the Windows NT Kernel as a `VersionNumber`, +i.e. `v"major.minor.build"`, or `v"0.0.0"` if this is not running on Windows. """ windows_version -const WINDOWS_VISTA_VER = (6, 0) +const WINDOWS_VISTA_VER = v"6.0" end # module Sys diff --git a/test/osutils.jl b/test/osutils.jl index 270680c54b601b..b84688f55609b3 100644 --- a/test/osutils.jl +++ b/test/osutils.jl @@ -13,9 +13,9 @@ @test Base.is_unix(:FreeBSD) @test_throws ArgumentError Base.is_unix(:BeOS) if !is_windows() - @test Sys.windows_version() === (0, 0) + @test Sys.windows_version() == v"0.0.0" else - @test (Sys.windows_version()::Tuple{Int,Int})[1] > 0 + @test Sys.windows_version() >= v"1.0.0-" end @test (@static true ? 1 : 2) === 1