From 88fa433bdf8330f5670c99c9d67629cd2ef25a7d Mon Sep 17 00:00:00 2001 From: Jarrett Revels Date: Mon, 15 May 2017 14:13:07 -0400 Subject: [PATCH 01/88] redesign type inference outer loop (PR #21677) removes the global work queue, which allows increasing the precision of cycle detection and resolution, and decreases the need for the threading synchronization lock surrounding inference updates `inInference` flag usage to be merely a hint for `jl_type_infer` to not bother trying to infer a method (helps avoid accidental infinite recursion over inferring type inference), enable inferring inference (cherry picked from commit 5847317e5e3cc4d353bbfa2225fcc4b36c0e23cd) --- base/inference.jl | 513 +++++++++++++++++++-------------------------- base/precompile.jl | 7 +- base/sysimg.jl | 5 +- src/gf.c | 65 +++--- src/interpreter.c | 2 +- test/staged.jl | 3 +- 6 files changed, 254 insertions(+), 341 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 17220ed7cd4d6..997d66a743df6 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -131,14 +131,11 @@ mutable struct InferenceState # ssavalue sparsity and restart info ssavalue_uses::Vector{IntSet} ssavalue_init::Vector{Any} - # call-graph edges connecting from a caller to a callee (and back) - # we shouldn't need to iterate edges very often, so we use it to optimize the lookup from edge -> linenum - # whereas backedges is optimized for iteration - edges::ObjectIdDict # a Dict{InferenceState, Vector{LineNum}} - backedges::Vector{Tuple{InferenceState, Vector{LineNum}}} - # iteration fixed-point detection - fixedpoint::Bool - inworkq::Bool + + backedges::Vector{Tuple{InferenceState, LineNum}} # call-graph backedges connecting from callee to caller + callers_in_cycle::Vector{InferenceState} + parent::Union{Void, InferenceState} + const_api::Bool const_ret::Bool @@ -148,6 +145,8 @@ mutable struct InferenceState inferred::Bool + dont_work_on_me::Bool + # src is assumed to be a newly-allocated CodeInfo, that can be modified in-place to contain intermediate results function InferenceState(linfo::MethodInstance, src::CodeInfo, optimize::Bool, cached::Bool, params::InferenceParams) @@ -268,41 +267,43 @@ mutable struct InferenceState Union{}, W, 1, n, cur_hand, handler_at, n_handlers, ssavalue_uses, ssavalue_init, - ObjectIdDict(), # Dict{InferenceState, Vector{LineNum}}(), - Vector{Tuple{InferenceState, Vector{LineNum}}}(), - false, false, false, false, optimize, cached, false) - push!(active, frame) - nactive[] += 1 + Vector{Tuple{InferenceState,LineNum}}(), # backedges + Vector{InferenceState}(), # callers_in_cycle + #=parent=#nothing, + false, false, optimize, cached, false, false) return frame end end -# create copies of the CodeInfo definition, and any fields that type-inference might modify -# TODO: post-inference see if we can swap back to the original arrays -function get_source(li::MethodInstance) - if isa(li.def.source, Array{UInt8,1}) - src = ccall(:jl_uncompress_ast, Any, (Any, Any), li.def, li.def.source) +function InferenceState(linfo::MethodInstance, + optimize::Bool, cached::Bool, params::InferenceParams) + # prepare an InferenceState object for inferring lambda + # create copies of the CodeInfo definition, and any fields that type-inference might modify + if linfo.def.isstaged + try + # user code might throw errors – ignore them + src = get_staged(linfo) + catch + return nothing + end else - src = ccall(:jl_copy_code_info, Ref{CodeInfo}, (Any,), li.def.source) - src.code = copy_exprargs(src.code) - src.slotnames = copy(src.slotnames) - src.slotflags = copy(src.slotflags) + # TODO: post-inference see if we can swap back to the original arrays? + if isa(linfo.def.source, Array{UInt8,1}) + src = ccall(:jl_uncompress_ast, Any, (Any, Any), linfo.def, linfo.def.source) + else + src = ccall(:jl_copy_code_info, Ref{CodeInfo}, (Any,), linfo.def.source) + src.code = copy_exprargs(src.code) + src.slotnames = copy(src.slotnames) + src.slotflags = copy(src.slotflags) + end end - return src + return InferenceState(linfo, src, optimize, cached, params) end function get_staged(li::MethodInstance) return ccall(:jl_code_for_staged, Any, (Any,), li)::CodeInfo end - -#### current global inference state #### - -const active = Vector{Any}() # set of all InferenceState objects being processed -const nactive = Array{Int,0}() -nactive[] = 0 -const workq = Vector{InferenceState}() # set of InferenceState objects that can make immediate progress - #### helper functions #### @inline slot_id(s) = isa(s, SlotNumber) ? (s::SlotNumber).id : (s::TypedSlot).id # using a function to ensure we can infer this @@ -1092,7 +1093,9 @@ function invoke_tfunc(f::ANY, types::ANY, argtype::ANY, sv::InferenceState) meth = entry.func (ti, env) = ccall(:jl_match_method, Ref{SimpleVector}, (Any, Any), argtype, meth.sig) - return typeinf_edge(meth::Method, ti, env, sv) + rt, edge = typeinf_edge(meth::Method, ti, env, sv) + edge !== nothing && add_backedge!(edge::MethodInstance, sv) + return rt end function tuple_tfunc(argtype::ANY) @@ -1287,43 +1290,31 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState) # this means too many methods matched return Any end - x::Array{Any,1} = applicable + applicable = applicable::Array{Any,1} fullmatch = false - for (m::SimpleVector) in x + for (m::SimpleVector) in applicable sig = m[1] sigtuple = unwrap_unionall(sig)::DataType method = m[3]::Method sparams = m[2]::SimpleVector recomputesvec = false - if !fullmatch && typeseq(sig, argtype) + if !fullmatch && (argtype <: method.sig) fullmatch = true end # limit argument type tuple growth - msig = unwrap_unionall(m[3].sig) + msig = unwrap_unionall(method.sig) lsig = length(msig.parameters) ls = length(sigtuple.parameters) td = type_depth(sig) - # look at the existing edges to detect growing argument lists mightlimitlength = ls > lsig + 1 mightlimitdepth = td > 2 - limitlength = false - if mightlimitlength - for (callee, _) in sv.edges - callee = callee::InferenceState - if method === callee.linfo.def && ls > length(unwrap_unionall(callee.linfo.specTypes).parameters) - limitlength = true - break - end - end - end - - # limit argument type size growth if mightlimitlength || mightlimitdepth # TODO: FIXME: this heuristic depends on non-local state making type-inference unpredictable - for infstate in active - infstate === nothing && continue + cyclei = 0 + infstate = sv + while infstate !== nothing infstate = infstate::InferenceState if isdefined(infstate.linfo, :def) && method === infstate.linfo.def if mightlimitlength && ls > length(unwrap_unionall(infstate.linfo.specTypes).parameters) @@ -1363,6 +1354,14 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState) end end end + # iterate through the cycle before walking to the parent + if cyclei < length(infstate.callers_in_cycle) + cyclei += 1 + infstate = infstate.callers_in_cycle[cyclei] + else + cyclei = 0 + infstate = infstate.parent + end end end @@ -1400,7 +1399,8 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState) end sparams = recomputed[2]::SimpleVector end - rt = typeinf_edge(method, sig, sparams, sv) + rt, edge = typeinf_edge(method, sig, sparams, sv) + edge !== nothing && add_backedge!(edge::MethodInstance, sv) rettype = tmerge(rettype, rt) if rettype === Any break @@ -1412,7 +1412,7 @@ function abstract_call_gf_by_type(f::ANY, atype::ANY, sv::InferenceState) add_mt_backedge(ftname.mt, argtype, sv) update_valid_age!(min_valid[1], max_valid[1], sv) end - if isempty(x) + if isempty(applicable) # TODO: this is needed because type intersection is wrong in some cases return Any end @@ -2333,31 +2333,6 @@ end inlining_enabled() = (JLOptions().can_inline == 1) coverage_enabled() = (JLOptions().code_coverage != 0) -# TODO: track the worlds for which this InferenceState -# is being used, and split it if the WIP requires it? -function converge_valid_age!(sv::InferenceState) - # push the validity range of sv into its fixedpoint callers - # recursing as needed to cover the graph - for (i, _) in sv.backedges - if i.fixedpoint - updated = false - if i.min_valid < sv.min_valid - i.min_valid = sv.min_valid - updated = true - end - if i.max_valid > sv.max_valid - i.max_valid = sv.max_valid - updated = true - end - @assert !isdefined(i.linfo, :def) || !i.cached || i.min_valid <= i.params.world <= i.max_valid "invalid age range update" - if updated - converge_valid_age!(i) - end - end - end - nothing -end - # work towards converging the valid age range for sv function update_valid_age!(min_valid::UInt, max_valid::UInt, sv::InferenceState) sv.min_valid = max(sv.min_valid, min_valid) @@ -2369,7 +2344,7 @@ update_valid_age!(edge::InferenceState, sv::InferenceState) = update_valid_age!( update_valid_age!(li::MethodInstance, sv::InferenceState) = update_valid_age!(min_world(li), max_world(li), sv) # temporarily accumulate our edges to later add as backedges in the callee -function add_backedge(li::MethodInstance, caller::InferenceState) +function add_backedge!(li::MethodInstance, caller::InferenceState) isdefined(caller.linfo, :def) || return # don't add backedges to toplevel exprs if caller.stmt_edges[caller.currpc] === () caller.stmt_edges[caller.currpc] = [] @@ -2435,72 +2410,92 @@ function code_for_method(method::Method, atypes::ANY, sparams::SimpleVector, wor return ccall(:jl_specializations_get_linfo, Ref{MethodInstance}, (Any, Any, Any, UInt), method, atypes, sparams, world) end -function typeinf_active(linfo::MethodInstance) - for infstate in active - infstate === nothing && continue - infstate = infstate::InferenceState - if linfo === infstate.linfo && infstate.cached - return infstate - end +function typeinf_active(linfo::MethodInstance, sv::InferenceState) + for infstate in sv.callers_in_cycle + linfo === infstate.linfo && return infstate end return nothing end -function add_backedge(frame::InferenceState, caller::InferenceState, currpc::Int) +function add_backedge!(frame::InferenceState, caller::InferenceState, currpc::Int) update_valid_age!(frame, caller) - if haskey(caller.edges, frame) - Ws = caller.edges[frame]::Vector{Int} - if !(currpc in Ws) - push!(Ws, currpc) + backedge = (caller, currpc) + contains_is(frame.backedges, backedge) || push!(frame.backedges, backedge) + return frame +end + +# at the end, all items in b's cycle +# will now be added to a's cycle +function union_caller_cycle!(a::InferenceState, b::InferenceState) + callers_in_cycle = b.callers_in_cycle + b.parent = a.parent + b.callers_in_cycle = a.callers_in_cycle + contains_is(a.callers_in_cycle, b) || push!(a.callers_in_cycle, b) + if callers_in_cycle !== a.callers_in_cycle + for caller in callers_in_cycle + if caller !== b + caller.parent = a.parent + caller.callers_in_cycle = a.callers_in_cycle + push!(a.callers_in_cycle, caller) + end end - else - Ws = Int[currpc] - caller.edges[frame] = Ws - push!(frame.backedges, (caller, Ws)) end + return end -# build (and start inferring) the inference frame for the linfo -function typeinf_frame(linfo::MethodInstance, caller, optimize::Bool, cached::Bool, - params::InferenceParams) - # println(params.world, ' ', linfo) - if cached && linfo.inInference - # inference on this signature may be in progress, - # find the corresponding frame in the active list - frame = typeinf_active(linfo) - # TODO: this assertion seems iffy - assert(frame !== nothing) - else - # inference not started yet, make a new frame for a new lambda - if linfo.def.isstaged - try - # user code might throw errors – ignore them - src = get_staged(linfo) - catch - return nothing +function merge_call_chain!(parent::InferenceState, ancestor::InferenceState, child::InferenceState) + # add backedge of parent <- child + # then add all backedges of parent <- parent.parent + # and merge all of the callers into ancestor.callers_in_cycle + # and ensure that walking the parent list will get the same result (DAG) from everywhere + while true + add_backedge!(child, parent, parent.currpc) + union_caller_cycle!(ancestor, child) + child = parent + parent = child.parent + child === ancestor && break + end +end + +# Walk through `linfo`'s upstream call chain, starting at `parent`. If a parent +# frame matching `linfo` is encountered, then there is a cycle in the call graph +# (i.e. `linfo` is a descendant callee of itself). Upon encountering this cycle, +# we "resolve" it by merging the call chain, which entails unioning each intermediary +# frame's `callers_in_cycle` field and adding the appropriate backedges. Finally, +# we return `linfo`'s pre-existing frame. If no cycles are found, `nothing` is +# returned instead. +function resolve_call_cycle!(linfo::MethodInstance, parent::InferenceState) + frame = parent + while isa(frame, InferenceState) + if frame.linfo === linfo + merge_call_chain!(parent, frame, frame) + return frame + end + for caller in frame.callers_in_cycle + if caller.linfo === linfo + merge_call_chain!(parent, frame, caller) + return caller end - else - src = get_source(linfo) end - cached && (linfo.inInference = true) - frame = InferenceState(linfo, src, optimize, cached, params) + frame = frame.parent end - frame = frame::InferenceState + return nothing +end - if isa(caller, InferenceState) - # if we were called from inside inference, the caller will be the InferenceState object - # for which the edge was required - @assert caller.currpc > 0 - add_backedge(frame, caller, caller.currpc) - end - typeinf_loop(frame) +# build (and start inferring) the inference frame for the linfo +function typeinf_frame(linfo::MethodInstance, + optimize::Bool, cached::Bool, params::InferenceParams) + frame = InferenceState(linfo, optimize, cached, params) + frame === nothing && return nothing + cached && (linfo.inInference = true) + typeinf(frame) return frame end # compute (and cache) an inferred AST and return the current best estimate of the result type function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, caller::InferenceState) code = code_for_method(method, atypes, sparams, caller.params.world) - code === nothing && return Any + code === nothing && return Any, nothing code = code::MethodInstance if isdefined(code, :inferred) # return rettype if the code is already inferred @@ -2508,18 +2503,27 @@ function typeinf_edge(method::Method, atypes::ANY, sparams::SimpleVector, caller # so need to check whether the code itself is also inferred inf = code.inferred if !isa(inf, CodeInfo) || (inf::CodeInfo).inferred - add_backedge(code, caller) if isdefined(code, :inferred_const) - return abstract_eval_constant(code.inferred_const) + return abstract_eval_constant(code.inferred_const), code else - return code.rettype + return code.rettype, code end end end - frame = typeinf_frame(code, caller, true, true, caller.params) - frame === nothing && return Any + frame = resolve_call_cycle!(code, caller) + if frame === nothing + code.inInference = true + frame = InferenceState(code, true, true, caller.params) # always optimize and cache edge targets + if frame === nothing + code.inInference = false + return Any, nothing + end + frame.parent = caller + typeinf(frame) + return frame.bestguess, frame.inferred ? frame.linfo : nothing + end frame = frame::InferenceState - return frame.bestguess + return frame.bestguess, nothing end #### entry points for inferring a MethodInstance given a type signature #### @@ -2563,7 +2567,7 @@ function typeinf_code(linfo::MethodInstance, optimize::Bool, cached::Bool, end end end - frame = typeinf_frame(linfo, nothing, optimize, cached, params) + frame = typeinf_frame(linfo, optimize, cached, params) ccall(:jl_typeinf_end, Void, ()) frame === nothing && return svec(nothing, nothing, Any) frame = frame::InferenceState @@ -2591,7 +2595,7 @@ function typeinf_type(method::Method, atypes::ANY, sparams::SimpleVector, end end end - frame = typeinf_frame(code, nothing, cached, cached, params) + frame = typeinf_frame(code, cached, cached, params) ccall(:jl_typeinf_end, Void, ()) frame === nothing && return nothing frame = frame::InferenceState @@ -2605,11 +2609,10 @@ function typeinf_ext(linfo::MethodInstance, world::UInt) return typeinf_code(linfo, true, true, InferenceParams(world)) else # toplevel lambda - infer directly - linfo.inInference = true ccall(:jl_typeinf_begin, Void, ()) frame = InferenceState(linfo, linfo.inferred::CodeInfo, true, true, InferenceParams(world)) - typeinf_loop(frame) + typeinf(frame) ccall(:jl_typeinf_end, Void, ()) @assert frame.inferred # TODO: deal with this better @assert frame.linfo === linfo @@ -2619,83 +2622,9 @@ end #### do the work of inference #### -in_typeinf_loop = false -function typeinf_loop(frame) - global in_typeinf_loop - if in_typeinf_loop - frame.inworkq || typeinf_frame(frame) - return - end - try - in_typeinf_loop = true - # the core type-inference algorithm - # processes everything in workq, - # and returns when there is nothing left - while nactive[] > 0 - while active[end] === nothing - pop!(active) - end - if isempty(workq) - frame = active[end]::InferenceState - else - frame = pop!(workq) - end - typeinf_frame(frame) - if isempty(workq) && nactive[] > 0 - # nothing in active has an edge that hasn't reached a fixed-point - # so all of them can be considered finished now - fplist = Any[] - for i in active - i === nothing && continue - i = i::InferenceState - if i.fixedpoint - push!(fplist, i) - i.inworkq = true - end - end - for i in length(fplist):-1:1 - # optimize and record the results - # the reverse order makes it more likely to inline a callee into its caller - optimize(fplist[i]::InferenceState) # this may add incomplete work to active - end - for i in fplist - # push valid ages from each node across the graph cycle - converge_valid_age!(i::InferenceState) - end - for i in fplist - # record the results - finish(i::InferenceState) - end - for i in fplist - # update and record all of the back edges for the finished world - finalize_backedges(i::InferenceState) - end - end - end - # cleanup the active queue - empty!(active) - # while active[end] === nothing - # # this pops everything, but with exaggerated care just in case - # # something managed to add something to the queue at the same time - # # (or someone decides to use an alternative termination condition) - # pop!(active) - # end - in_typeinf_loop = false - catch ex - println("WARNING: An error occurred during inference. Type inference is now partially disabled.") - println(ex) - ccall(:jlbacktrace, Void, ()) - end - nothing -end - -global_sv = nothing -function typeinf_frame(frame) - global global_sv # TODO: actually pass this to all functions that need it - last_global_sv = global_sv - global_sv = frame +function typeinf_work(frame::InferenceState) @assert !frame.inferred - frame.inworkq = true + frame.dont_work_on_me = true # mark that this function is currently on the stack W = frame.ip s = frame.stmt_types n = frame.nstmts @@ -2781,18 +2710,15 @@ function typeinf_frame(frame) if tchanged(rt, frame.bestguess) # new (wider) return type for frame frame.bestguess = tmerge(frame.bestguess, rt) - for (caller, callerW) in frame.backedges + for (caller, caller_pc) in frame.backedges # notify backedges of updated type information - for caller_pc in callerW - if caller.stmt_types[caller_pc] !== () - if caller_pc < caller.pc´´ - caller.pc´´ = caller_pc - end - push!(caller.ip, caller_pc) + if caller.stmt_types[caller_pc] !== () + if caller_pc < caller.pc´´ + caller.pc´´ = caller_pc end + push!(caller.ip, caller_pc) end end - unmark_fixedpoint(frame) end elseif hd === :enter l = stmt.args[1]::Int @@ -2840,53 +2766,72 @@ function typeinf_frame(frame) end end end + frame.dont_work_on_me = false +end - # with no active ip's, type inference on frame is done if there are no outstanding (unfinished) edges - #@assert isempty(W) - @assert !frame.inferred - finished = isempty(frame.edges) - if isempty(workq) - # oops, there's a cycle somewhere in the `edges` graph - # so we've run out off the tree and will need to start work on the loop - frame.fixedpoint = true - end - - if finished || frame.fixedpoint - if finished - optimize(frame) - finish(frame) - finalize_backedges(frame) - else # fixedpoint propagation - for (i, _) in frame.edges - i = i::InferenceState - if !i.fixedpoint - update_valid_age!(i, frame) # work towards converging age at the same time - if !i.inworkq - push!(workq, i) - i.inworkq = true - end - i.fixedpoint = true - end +function typeinf(frame::InferenceState) + + typeinf_work(frame) + + # If the current frame is part of a cycle, solve the cycle before finishing + no_active_ips_in_callers = false + while !no_active_ips_in_callers + no_active_ips_in_callers = true + for caller in frame.callers_in_cycle + caller.dont_work_on_me && return + if caller.pc´´ <= caller.nstmts # equivalent to `isempty(caller.ip)` + # Note that `typeinf_work(caller)` can potentially modify the other frames + # `frame.callers_in_cycle`, which is why making incremental progress requires the + # outer while loop. + typeinf_work(caller) + no_active_ips_in_callers = false + end + if caller.min_valid < frame.min_valid + caller.min_valid = frame.min_valid + end + if caller.max_valid > frame.max_valid + caller.max_valid = frame.max_valid end end end - frame.inworkq = false - global_sv = last_global_sv - nothing -end -function unmark_fixedpoint(frame::InferenceState) - # type information changed for frame, so its edges are no longer stuck - # recursively unmark any nodes that had previously been thought to be at a fixedpoint - # based upon (recursively) assuming that frame was stuck - if frame.fixedpoint - frame.fixedpoint = false - for (i, _) in frame.backedges - unmark_fixedpoint(i) + # with no active ip's, type inference on frame is done + + if isempty(frame.callers_in_cycle) + @assert !(frame.dont_work_on_me) + frame.dont_work_on_me = true + optimize(frame) + finish(frame) + finalize_backedges(frame) + else # frame is in frame.callers_in_cycle + for caller in frame.callers_in_cycle + @assert !(caller.dont_work_on_me) + caller.dont_work_on_me = true + end + for caller in frame.callers_in_cycle + optimize(caller) + if frame.min_valid < caller.min_valid + frame.min_valid = caller.min_valid + end + if frame.max_valid > caller.max_valid + frame.max_valid = caller.max_valid + end + end + for caller in frame.callers_in_cycle + caller.min_valid = frame.min_valid + end + for caller in frame.callers_in_cycle + finish(caller) + end + for caller in frame.callers_in_cycle + finalize_backedges(caller) end end + + nothing end + function record_ssa_assign(ssa_id::Int, new::ANY, frame::InferenceState) old = frame.src.ssavaluetypes[ssa_id] if old === NF || !(new ⊑ old) @@ -2932,16 +2877,6 @@ end # inference completed on `me` # now converge the optimization work function optimize(me::InferenceState) - for (i, _) in me.edges - i = i::InferenceState - @assert i.fixedpoint - end - # below may call back into inference and - # see this InferenceState is in an incomplete state - # set `inworkq` to prevent it from trying to look - # at the object in any detail - @assert me.inworkq - # annotate fulltree with type information type_annotate!(me) @@ -3034,7 +2969,7 @@ function finish(me::InferenceState) # check if the existing me.linfo metadata is also sufficient to describe the current inference result # to decide if it is worth caching it again (which would also clear any generated code) - already_inferred = false + already_inferred = !me.linfo.inInference if isdefined(me.linfo, :inferred) inf = me.linfo.inferred if !isa(inf, CodeInfo) || (inf::CodeInfo).inferred @@ -3085,20 +3020,9 @@ function finish(me::InferenceState) end end - # lazy-delete the item from active for several reasons: - # efficiency, correctness, and recursion-safety - nactive[] -= 1 - active[findlast(active, me)] = nothing - - # update all of the callers by traversing the backedges + # update all of the callers with real backedges by traversing the temporary list of backedges for (i, _) in me.backedges - if !me.fixedpoint || !i.fixedpoint - # wake up each backedge, unless both me and it already reached a fixed-point (cycle resolution stage) - delete!(i.edges, me) - i.inworkq || push!(workq, i) - i.inworkq = true - end - add_backedge(me.linfo, i) + add_backedge!(me.linfo, i) end # finalize and record the linfo result @@ -3611,7 +3535,7 @@ function invoke_NF(argexprs, etype::ANY, atypes, sv, atype_unlimited::ANY, local sig = argtypes_to_type(atypes) local li = get_spec_lambda(sig, sv, invoke_data) li === nothing && return false - add_backedge(li, sv) + add_backedge!(li, sv) local stmt = [] push!(stmt, Expr(:(=), linfo_var, li)) spec_hit === nothing && (spec_hit = genlabel(sv)) @@ -3682,7 +3606,7 @@ function invoke_NF(argexprs, etype::ANY, atypes, sv, atype_unlimited::ANY, else local cache_linfo = get_spec_lambda(atype_unlimited, sv, invoke_data) cache_linfo === nothing && return NF - add_backedge(cache_linfo, sv) + add_backedge!(cache_linfo, sv) unshift!(argexprs, cache_linfo) ex = Expr(:invoke) ex.args = argexprs @@ -3920,7 +3844,7 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference linfo = linfo::MethodInstance if linfo.jlcall_api == 2 # in this case function can be inlined to a constant - add_backedge(linfo, sv) + add_backedge!(linfo, sv) return inline_as_constant(linfo.inferred_const, argexprs, sv, invoke_data) end @@ -3937,22 +3861,19 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference # as we'll be able to fix that up at the end of inlinable when we verify the return type. # But `next` and `indexed_next` make tuples which would end up burying some of that information in the AST # where we can't easily correct it afterwards. - frame = InferenceState(linfo, get_source(linfo), #=optimize=#true, #=cache=#false, sv.params) + frame = InferenceState(linfo, #=optimize=#true, #=cache=#false, sv.params) frame.stmt_types[1][3] = VarState(atypes[3], false) - typeinf_loop(frame) + typeinf(frame) else if isdefined(linfo, :inferred) && linfo.inferred !== nothing # use cache inferred = linfo.inferred - elseif linfo.inInference - # use WIP - frame = typeinf_active(linfo) elseif force_infer # create inferred code on-demand # but if we decided in the past not to try to infer this particular signature # (due to signature coarsening in abstract_call_gf_by_type) # don't infer it now, as attempting to force it now would be a bad idea (non terminating) - frame = typeinf_frame(linfo, nothing, #=optimize=#true, #=cache=#true, sv.params) + frame = typeinf_frame(linfo, #=optimize=#true, #=cache=#true, sv.params) end end @@ -3963,9 +3884,9 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference inferred = frame.src if frame.const_api # handle like jlcall_api == 2 if frame.inferred || !frame.cached - add_backedge(frame.linfo, sv) + add_backedge!(frame.linfo, sv) else - add_backedge(frame, sv, 0) + add_backedge!(frame, sv, 0) end if isa(frame.bestguess, Const) inferred_const = (frame.bestguess::Const).val @@ -4026,9 +3947,9 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference if isa(frame, InferenceState) && !frame.inferred && frame.cached # in this case, the actual backedge linfo hasn't been computed # yet, but will be when inference on the frame finishes - add_backedge(frame, sv, 0) + add_backedge!(frame, sv, 0) else - add_backedge(linfo, sv) + add_backedge!(linfo, sv) end spvals = Any[] @@ -5481,7 +5402,7 @@ end # especially try to make sure any recursive and leaf functions have concrete signatures, # since we won't be able to specialize & infer them at runtime -let fs = Any[typeinf_ext, typeinf_loop, typeinf_edge, occurs_outside_getfield, pure_eval_call], +let fs = Any[typeinf_ext, typeinf, typeinf_edge, occurs_outside_getfield, pure_eval_call], world = ccall(:jl_get_world_counter, UInt, ()) for x in t_ffunc_val push!(fs, x[3]) diff --git a/base/precompile.jl b/base/precompile.jl index 8bc84db37f499..9bd0f90f30572 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -822,9 +822,8 @@ precompile(Tuple{getfield(Base.Cartesian, Symbol("#@nexprs")), Int64, Expr}) precompile(Tuple{typeof(Base.Cartesian._nexprs), Int64, Expr}) precompile(Tuple{typeof(Core.Inference.findnext), Array{Function, 1}, typeof(===), Int64}) precompile(Tuple{typeof(Core.Inference.builtin_tfunction), typeof(===), Array{Any, 1}, Core.Inference.InferenceState, Core.Inference.InferenceParams}) -precompile(Tuple{typeof(Core.Inference.typeinf_frame), Core.MethodInstance, Void, Bool, Bool, Core.Inference.InferenceParams}) -precompile(Tuple{typeof(Core.Inference.typeinf_loop), Core.Inference.InferenceState}) -precompile(Tuple{typeof(Core.Inference.typeinf_frame), Core.Inference.InferenceState}) +precompile(Tuple{typeof(Core.Inference.typeinf_frame), Core.MethodInstance, Bool, Bool, Core.Inference.InferenceParams}) +precompile(Tuple{typeof(Core.Inference.typeinf), Core.Inference.InferenceState}) precompile(Tuple{typeof(Base.Cartesian.inlineanonymous), Expr, Int64}) precompile(Tuple{typeof(Base.Cartesian.lreplace), Expr, Symbol, Int64}) precompile(Tuple{typeof(Base.copy), Expr}) @@ -869,7 +868,6 @@ precompile(Tuple{typeof(Core.Inference._widen_all_consts!), Expr, Array{Bool, 1} precompile(Tuple{typeof(Core.Inference._delete!), Core.Inference.IntSet, Int64}) precompile(Tuple{typeof(Core.Inference.promote_type), Type{Float16}, Type{Int64}}) precompile(Tuple{typeof(Core.Inference.mk_tuplecall), Array{Any, 1}, Core.Inference.InferenceState}) -precompile(Tuple{typeof(Core.Inference.get_source), Core.MethodInstance}) precompile(Tuple{typeof(Core.Inference.inlining_pass), Expr, Core.Inference.InferenceState, Array{Any, 1}, Int64}) precompile(Tuple{typeof(Core.Inference.annotate_slot_load!), Expr, Array{Any, 1}, Core.Inference.InferenceState, Array{Bool, 1}}) precompile(Tuple{typeof(Core.Inference.record_slot_assign!), Core.Inference.InferenceState}) @@ -886,7 +884,6 @@ precompile(Tuple{typeof(Core.Inference.return_type_tfunc), Array{Any, 1}, Array{ precompile(Tuple{typeof(Core.Inference.abstract_call), typeof(===), Tuple{}, Array{Any, 1}, Array{Any, 1}, Core.Inference.InferenceState}) precompile(Tuple{typeof(Core.Inference.abstract_call), typeof(===), Array{Any, 1}, Array{Any, 1}, Array{Any, 1}, Core.Inference.InferenceState}) precompile(Tuple{typeof(Core.Inference.type_too_complex), TypeVar, Int64}) -precompile(Tuple{typeof(Core.Inference.typeinf_frame), Core.MethodInstance, Core.Inference.InferenceState, Bool, Bool, Core.Inference.InferenceParams}) precompile(Tuple{typeof(Core.Inference.abstract_eval), Expr, Array{Any, 1}, Core.Inference.InferenceState}) precompile(Tuple{typeof(Core.Inference._setint!), Core.Inference.IntSet, Int64, Bool}) precompile(Tuple{typeof(Core.Inference.stupdate1!), Array{Any, 1}, Core.Inference.StateUpdate}) diff --git a/base/sysimg.jl b/base/sysimg.jl index d9851dbf30a0d..acfb4c7b68ee4 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -21,7 +21,6 @@ include("coreio.jl") eval(x) = Core.eval(Base, x) eval(m, x) = Core.eval(m, x) -(::Type{T})(arg) where {T} = convert(T, arg)::T # Hidden from the REPL. VecElement{T}(arg) where {T} = VecElement{T}(convert(T, arg)) convert(::Type{T}, arg) where {T<:VecElement} = T(arg) convert(::Type{T}, arg::T) where {T<:VecElement} = arg @@ -73,6 +72,10 @@ include("refpointer.jl") include("checked.jl") importall .Checked +# buggy handling of ispure in type-inference means this should be +# after re-defining the basic operations that they might try to call +(::Type{T})(arg) where {T} = convert(T, arg)::T # Hidden from the REPL. + # vararg Symbol constructor Symbol(x...) = Symbol(string(x...)) diff --git a/src/gf.c b/src/gf.c index 44dbb4ad28005..822417e2e0897 100644 --- a/src/gf.c +++ b/src/gf.c @@ -238,46 +238,39 @@ jl_code_info_t *jl_type_infer(jl_method_instance_t **pli, size_t world, int forc JL_TIMING(INFERENCE); if (jl_typeinf_func == NULL) return NULL; - jl_code_info_t *src = NULL; #ifdef ENABLE_INFERENCE jl_method_instance_t *li = *pli; - jl_module_t *mod = NULL; - if (li->def != NULL) - mod = li->def->module; - static int inInference = 0; - int lastIn = inInference; - size_t last_age = jl_get_ptls_states()->world_age; - inInference = 1; - if (force || - (last_age != jl_typeinf_world && - mod != jl_gf_mtable(jl_typeinf_func)->module && - (mod != jl_core_module || !lastIn))) { // avoid any potential recursion in calling jl_typeinf_func on itself - assert(li->inInference == 0 && "unexpectedly asked to infer a method that is already being inferred"); - jl_value_t **fargs; - JL_GC_PUSHARGS(fargs, 3); - fargs[0] = (jl_value_t*)jl_typeinf_func; - fargs[1] = (jl_value_t*)li; - fargs[2] = jl_box_ulong(world); + if (li->inInference && !force) + return NULL; + + jl_value_t **fargs; + JL_GC_PUSHARGS(fargs, 3); + fargs[0] = (jl_value_t*)jl_typeinf_func; + fargs[1] = (jl_value_t*)li; + fargs[2] = jl_box_ulong(world); #ifdef TRACE_INFERENCE - if (li->specTypes != (jl_value_t*)jl_emptytuple_type) { - jl_printf(JL_STDERR,"inference on "); - jl_static_show_func_sig(JL_STDERR, (jl_value_t*)li->specTypes); - jl_printf(JL_STDERR, "\n"); - } + if (li->specTypes != (jl_value_t*)jl_emptytuple_type) { + jl_printf(JL_STDERR,"inference on "); + jl_static_show_func_sig(JL_STDERR, (jl_value_t*)li->specTypes); + jl_printf(JL_STDERR, "\n"); + } #endif - jl_get_ptls_states()->world_age = jl_typeinf_world; - jl_svec_t *linfo_src_rettype = (jl_svec_t*)jl_apply_with_saved_exception_state(fargs, 3, 0); - jl_get_ptls_states()->world_age = last_age; - assert((li->def || li->inInference == 0) && "inference failed on a toplevel expr"); - if (jl_is_svec(linfo_src_rettype) && jl_svec_len(linfo_src_rettype) == 3 && - jl_is_method_instance(jl_svecref(linfo_src_rettype, 0)) && - jl_is_code_info(jl_svecref(linfo_src_rettype, 1))) { - *pli = (jl_method_instance_t*)jl_svecref(linfo_src_rettype, 0); - src = (jl_code_info_t*)jl_svecref(linfo_src_rettype, 1); - } - JL_GC_POP(); + jl_ptls_t ptls = jl_get_ptls_states(); + size_t last_age = ptls->world_age; + ptls->world_age = jl_typeinf_world; + li->inInference = 1; + jl_svec_t *linfo_src_rettype = (jl_svec_t*)jl_apply_with_saved_exception_state(fargs, 3, 0); + ptls->world_age = last_age; + assert((li->def || li->inInference == 0) && "inference failed on a toplevel expr"); + + jl_code_info_t *src = NULL; + if (jl_is_svec(linfo_src_rettype) && jl_svec_len(linfo_src_rettype) == 3 && + jl_is_method_instance(jl_svecref(linfo_src_rettype, 0)) && + jl_is_code_info(jl_svecref(linfo_src_rettype, 1))) { + *pli = (jl_method_instance_t*)jl_svecref(linfo_src_rettype, 0); + src = (jl_code_info_t*)jl_svecref(linfo_src_rettype, 1); } - inInference = lastIn; + JL_GC_POP(); #endif return src; } @@ -1661,7 +1654,7 @@ jl_llvm_functions_t jl_compile_for_dispatch(jl_method_instance_t **pli, size_t w return decls; jl_code_info_t *src = NULL; - if (li->def && !jl_is_rettype_inferred(li) && !li->inInference && + if (li->def && !jl_is_rettype_inferred(li) && jl_symbol_name(li->def->name)[0] != '@') { // don't bother with typeinf on macros or toplevel thunks // but try to infer everything else diff --git a/src/interpreter.c b/src/interpreter.c index 4e78fea57383a..99fc01c7c7bb0 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -85,7 +85,7 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state for (i = 1; i < nargs; i++) argv[i - 1] = eval(args[i], s); jl_method_instance_t *meth = (jl_method_instance_t*)args[0]; - assert(jl_is_method_instance(meth) && !meth->inInference); + assert(jl_is_method_instance(meth)); jl_value_t *result = jl_call_method_internal(meth, argv, nargs - 1); JL_GC_POP(); return result; diff --git a/test/staged.jl b/test/staged.jl index 34fc90d552a29..ba62fc2d91816 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -147,7 +147,6 @@ module TestGeneratedThrow foo() = (bar(rand() > 0.5 ? 1 : 1.0); error("foo")) function __init__() code_typed(foo,(); optimize = false) - @test Core.Inference.isempty(Core.Inference.active) && Core.Inference.isempty(Core.Inference.workq) cfunction(foo,Void,()) end end @@ -175,7 +174,7 @@ let gf_err, tsk = @async nothing # create a Task for yield to try to run end @test_throws ErrorException gf_err() @test_throws ErrorException gf_err() - @test gf_err_ref[] == 4 + @test gf_err_ref[] == 3 end gf_err_ref[] = 0 From e4dc00cacd2f9cd4663c25878bfb687564ce968a Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 5 Jun 2017 11:35:30 -0400 Subject: [PATCH 02/88] various improvements to parser (#22161) - move call to `short-form-function-loc` inside `parse-assignment` this is faster and fixes nested cases like `f(x)=g(x)=1` - fix a case where an `unexpected "foo"` message was missing quotes - optimize common case of arglists of comma-separated simple tokens - some other small optimizations - put code back in precedence order - separate parse-Nary and parse-comma so they're easier to read - cleaner code for parse-unary and parse-factor --- src/julia-parser.scm | 542 ++++++++++++++++++++++--------------------- 1 file changed, 279 insertions(+), 263 deletions(-) diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 4a96f21d17c7c..56b12de1c3a21 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -45,6 +45,9 @@ ((not (length> l 8)) (eval `(lambda (x) (not (not (,(if (every symbol? l) 'memq 'memv) x (quote ,l))))))) + ((and (every symbol? l) (not (length> l 20))) + (eval `(lambda (x) + (not (not (memq x (quote ,l))))))) (else (let ((t (table))) (for-each (lambda (x) (put! t x #t)) l) @@ -70,6 +73,8 @@ (define unary-ops (append! '(|<:| |>:|) (add-dots '(+ - ! ~ ¬ √ ∛ ∜)))) +(define unary-op? (Set unary-ops)) + ; operators that are both unary and binary (define unary-and-binary-ops '(+ - $ & ~ |.+| |.-|)) @@ -126,6 +131,13 @@ (define reserved-word? (Set reserved-words)) +(define closing-token? + (let ((closer? (Set '(else elseif catch finally #\, #\) #\] #\} #\;)))) + (lambda (tok) + (or (and (eq? tok 'end) (not end-symbol)) + (closer? tok) + (eof-object? tok))))) + ;; Parser state variables ; disable range colon for parsing ternary conditional operator @@ -572,43 +584,94 @@ (list 'call t ex (,self ,s)))) ex))) -(define (parse-cond s) - (let ((ex (parse-arrow s))) - (cond ((eq? (peek-token s) '?) - (begin (take-token s) - (let ((then (without-range-colon (parse-eq* s)))) - (if (not (eq? (take-token s) ':)) - (error "colon expected in \"?\" expression") - (list 'if ex then (parse-eq* s)))))) - (else ex)))) +(define (line-number-node s) + `(line ,(input-port-line (ts:port s)) ,current-filename)) -(define (parse-where-chain s first) - (with-bindings ((where-enabled #f)) - (let loop ((ex first) - (t 'where)) - (if (eq? t 'where) - (begin (take-token s) - (let ((var (parse-comparison s))) - (loop (if (and (pair? var) (eq? (car var) 'cell1d)) - (list* 'where ex (cdr var)) ;; form `x where {T,S}` - (list 'where ex var)) - (peek-token s)))) - ex)))) +;; parse a@b@c@... as (@ a b c ...) for some operator @ +;; ops: operators to look for +;; head: the expression head to yield in the result, e.g. "a;b" => (block a b) +;; closer?: predicate to identify tokens that stop parsing +;; however, this doesn't consume the closing token, just looks at it +;; ow, my eyes!! +(define (parse-Nary s down ops head closer? add-linenums) + (let ((t (require-token s))) + (if (closer? t) + (if add-linenums ;; empty block + (list head (line-number-node s)) + (list head)) + (let loop ((ex + ;; skip leading runs of operator + (if (memv t ops) + (if add-linenums + (list (line-number-node s)) + '()) + (if add-linenums + (let ((loc (line-number-node s))) + ;; note: line-number must happen before (down s) + (list (down s) loc)) + (list (down s))))) + (first? #t) + (t (peek-token s))) + (if (not (memv t ops)) + (begin + (if (not (or (eof-object? t) (eqv? t #\newline) (closer? t))) + (error (string "extra token \"" t "\" after end of expression"))) + (if (or (null? ex) (pair? (cdr ex)) (not first?)) + ;; () => (head) + ;; (ex2 ex1) => (head ex1 ex2) + ;; (ex1) if operator appeared => (head ex1) (handles "x;") + (cons head (reverse! ex)) + ;; (ex1) => ex1 + (car ex))) + (begin (take-token s) + ;; allow input to end with the operator, as in a;b; + (if (or (eof-object? (peek-token s)) + (closer? (peek-token s)) + (memv (peek-token s) ops)) + (loop ex #f (peek-token s)) + (if (and add-linenums + (not (and (pair? (car ex)) + (eq? (caar ex) 'line)))) + (let ((loc (line-number-node s))) + (loop (list* (down s) loc ex) #f (peek-token s))) + (loop (cons (down s) ex) #f (peek-token s)))))))))) -(define (parse-where s down) - ;; `where` needs to be below unary for `+(x::T,y::T) where {T} = ...` to work - (let ((ex (down s))) - (if (and where-enabled - (eq? (peek-token s) 'where)) - (parse-where-chain s ex) - ex))) +;; the principal non-terminals follow, in increasing precedence order -(define (invalid-initial-token? tok) - (or (eof-object? tok) - (memv tok '(#\) #\] #\} else elseif catch finally =)))) +(define (parse-block s (down parse-eq)) + (parse-Nary s down '(#\newline #\;) 'block + (lambda (x) (memq x '(end else elseif catch finally))) #t)) -(define (line-number-node s) - `(line ,(input-port-line (ts:port s)) ,current-filename)) +;; ";" at the top level produces a sequence of top level expressions +(define (parse-stmts s) + (let ((ex (parse-Nary s (lambda (s) (parse-docstring s parse-eq)) + '(#\;) 'toplevel (lambda (x) (eqv? x #\newline)) #f))) + ;; check for unparsed junk after an expression + (let ((t (peek-token s))) + (if (not (or (eof-object? t) (eqv? t #\newline) (eq? t #f))) + (error (string "extra token \"" t "\" after end of expression")))) + ex)) + +(define (parse-eq s) (parse-assignment s parse-comma)) + +;; symbol tokens that do not simply parse to themselves when appearing alone as +;; an element of an argument list +(define non-standalone-symbol-token? + (Set (append operators reserved-words '(.... mutable primitive)))) + +; parse-eq* is used where commas are special, for example in an argument list +(define (parse-eq* s) + (let ((t (peek-token s))) + ;; optimization: skip checking the whole precedence stack if we have a simple + ;; token followed by a common closing token + (if (or (number? t) (and (symbol? t) (not (non-standalone-symbol-token? t)))) + (begin (take-token s) + (let ((nxt (peek-token s))) + (if (or (eqv? nxt #\,) (eqv? nxt #\) ) (eqv? nxt #\}) (eqv? nxt #\])) + t + (begin (ts:put-back! s t) + (parse-assignment s parse-cond))))) + (parse-assignment s parse-cond)))) (define (eventually-call ex) (and (pair? ex) @@ -616,7 +679,6 @@ (and (or (eq? (car ex) 'where) (eq? (car ex) '|::|)) (eventually-call (cadr ex)))))) -;; insert line/file for short-form function defs, otherwise leave alone (define (short-form-function-loc ex lno) (if (and (pair? ex) (eq? (car ex) '=) @@ -624,61 +686,82 @@ `(= ,(cadr ex) (block (line ,lno ,current-filename) ,(caddr ex))) ex)) -;; parse a@b@c@... as (@ a b c ...) for some operator @ -;; op: the operator to look for -;; head: the expression head to yield in the result, e.g. "a;b" => (block a b) -;; closers: a list of tokens that will stop the process -;; however, this doesn't consume the closing token, just looks at it -;; allow-empty: if true will ignore runs of the operator, like a@@@@b -;; ow, my eyes!! -(define (parse-Nary s down ops head closer? allow-empty add-linenums) - (let ((t (require-token s))) - (if (invalid-initial-token? t) - (error (string "unexpected \"" t "\""))) - (if (closer? t) - (if add-linenums ;; empty block - (list head (line-number-node s)) - (list head)) - (let loop ((ex - ;; in allow-empty mode skip leading runs of operator - (if (and allow-empty (memv t ops)) - (if add-linenums - (list (line-number-node s)) - '()) - (if add-linenums - (let ((loc (line-number-node s))) - ;; note: line-number must happen before (down s) - (list (down s) loc)) - (list (down s))))) - (first? #t) - (t (peek-token s))) - (if (not (memv t ops)) - (begin - (if (not (or (eof-object? t) (eqv? t #\newline) (memv #\, ops) - (closer? t))) - (error (string "extra token \"" t "\" after end of expression"))) - (if (or (null? ex) (pair? (cdr ex)) (not first?)) - ;; () => (head) - ;; (ex2 ex1) => (head ex1 ex2) - ;; (ex1) if operator appeared => (head ex1) (handles "x;") - (cons head (reverse! ex)) - ;; (ex1) => ex1 - (car ex))) - (begin (take-token s) - ;; allow input to end with the operator, as in a;b; - (if (or (eof-object? (peek-token s)) - (closer? (peek-token s)) - (and allow-empty - (memv (peek-token s) ops)) - (and (eqv? (car ops) #\,) - (eq? (peek-token s) '=))) - (loop ex #f (peek-token s)) - (if (and add-linenums - (not (and (pair? (car ex)) - (eq? (caar ex) 'line)))) - (let ((loc (line-number-node s))) - (loop (list* (down s) loc ex) #f (peek-token s))) - (loop (cons (down s) ex) #f (peek-token s)))))))))) +(define (parse-assignment s down) + (let loop ((ex (down s)) + (t (peek-token s))) + (if (not (is-prec-assignment? t)) + ex + (begin + (take-token s) + (cond ((eq? t '~) + (if (and space-sensitive (ts:space? s) + (not (eqv? (peek-char (ts:port s)) #\ ))) + (begin (ts:put-back! s t) + ex) + (list 'call t ex (parse-assignment s down)))) + ((eq? t '=>) ;; ~ and => are the only non-syntactic assignment-precedence operators + (list 'call t ex (parse-assignment s down))) + ((eq? t '=) + ;; insert line/file for short-form function defs, otherwise leave alone + (let ((lno (input-port-line (ts:port s)))) + (short-form-function-loc + (list t ex (parse-assignment s down)) lno))) + (else + (list t ex (parse-assignment s down)))))))) + +; parse-comma is needed for commas outside parens, for example a = b,c +(define (parse-comma s) + (let loop ((ex (list (parse-cond s))) + (first? #t) + (t (peek-token s))) + (if (not (eqv? t #\,)) + (if (or (pair? (cdr ex)) (not first?)) + ;; () => (tuple) + ;; (ex2 ex1) => (tuple ex1 ex2) + ;; (ex1,) => (tuple ex1) + (cons 'tuple (reverse! ex)) + ;; (ex1) => ex1 + (car ex)) + (begin (take-token s) + (if (or (eof-object? (peek-token s)) (eq? (peek-token s) '=)) + (loop ex #f (peek-token s)) + (loop (cons (parse-cond s) ex) #f (peek-token s))))))) + +(define (parse-cond s) + (let ((ex (parse-arrow s))) + (cond ((eq? (peek-token s) '?) + (begin (take-token s) + (let ((then (without-range-colon (parse-eq* s)))) + (if (not (eq? (take-token s) ':)) + (error "colon expected in \"?\" expression") + (list 'if ex then (parse-eq* s)))))) + (else ex)))) + +(define (parse-arrow s) (parse-RtoL s parse-or is-prec-arrow? (eq? t '-->) parse-arrow)) +(define (parse-or s) (parse-RtoL s parse-and is-prec-lazy-or? #t parse-or)) +(define (parse-and s) (parse-RtoL s parse-comparison is-prec-lazy-and? #t parse-and)) + +(define (parse-comparison s) + (let loop ((ex (parse-pipes s)) + (first #t)) + (let ((t (peek-token s))) + (cond ((is-prec-comparison? t) + (begin (take-token s) + (if first + (loop (list 'comparison ex t (parse-pipes s)) #f) + (loop (append ex (list t (parse-pipes s))) #f)))) + (first ex) + ((length= ex 4) + ;; only a single comparison; special chained syntax not required + (let ((op (caddr ex)) + (arg1 (cadr ex)) + (arg2 (cadddr ex))) + (if (or (eq? op '|<:|) (eq? op '|>:|)) + `(,op ,arg1 ,arg2) + `(call ,op ,arg1 ,arg2)))) + (else ex))))) + +(define (parse-pipes s) (parse-LtoR s parse-range is-prec-pipe?)) ; parse ranges and postfix ... ; colon is strange; 3 arguments with 2 colons yields one call: @@ -728,64 +811,14 @@ (list '... ex)) (else ex))))) -;; the principal non-terminals follow, in increasing precedence order - -(define (parse-block s (down parse-eq)) - (parse-Nary s down '(#\newline #\;) 'block - (lambda (x) (memq x '(end else elseif catch finally))) #t #t)) - -;; ";" at the top level produces a sequence of top level expressions -(define (parse-stmts s) - (let ((ex (parse-Nary s (lambda (s) (parse-docstring s parse-eq)) - '(#\;) 'toplevel (lambda (x) (eqv? x #\newline)) #t #f))) - ;; check for unparsed junk after an expression - (let ((t (peek-token s))) - (if (not (or (eof-object? t) (eqv? t #\newline) (eq? t #f))) - (error (string "extra token \"" t "\" after end of expression")))) - ex)) - -(define (parse-assignment s down) - (let loop ((ex (down s)) - (t (peek-token s))) - (if (not (is-prec-assignment? t)) - ex - (begin (take-token s) - (if (eq? t '~) - (if (and space-sensitive (ts:space? s) - (not (eqv? (peek-char (ts:port s)) #\ ))) - (begin (ts:put-back! s t) - ex) - (list 'call t ex (parse-assignment s down))) - (if (eq? t '=>) ;; ~ and => are the only non-syntactic assignment-precedence operators - (list 'call t ex (parse-assignment s down)) - (list t ex (parse-assignment s down)))))))) - -(define (parse-eq s) - (let ((lno (input-port-line (ts:port s)))) - (short-form-function-loc - (parse-assignment s parse-comma) lno))) - -; parse-eq* is used where commas are special, for example in an argument list -(define (parse-eq* s) - (let ((lno (input-port-line (ts:port s)))) - (short-form-function-loc - (parse-assignment s parse-cond) lno))) - -; parse-comma is needed for commas outside parens, for example a = b,c -(define (parse-comma s) (parse-Nary s parse-cond '(#\,) 'tuple (lambda (x) #f) #f #f)) -(define (parse-arrow s) (parse-RtoL s parse-or is-prec-arrow? (eq? t '-->) parse-arrow)) -(define (parse-or s) (parse-RtoL s parse-and is-prec-lazy-or? #t parse-or)) -(define (parse-and s) (parse-RtoL s parse-comparison is-prec-lazy-and? #t parse-and)) - ;; parse left to right chains of a certain binary operator ;; returns a list of arguments (define (parse-chain s down op) (let loop ((chain (list (down s)))) - (let* ((t (peek-token s)) - (spc (ts:space? s))) + (let ((t (peek-token s))) (if (not (eq? t op)) (reverse! chain) - (begin + (let ((spc (ts:space? s))) (take-token s) (cond ((and space-sensitive spc (memq t unary-and-binary-ops) (not (eqv? (peek-char (ts:port s)) #\ ))) @@ -799,11 +832,10 @@ ;; e.g. a+b+c => (call + a b c) (define (parse-with-chains s down ops chain-ops) (let loop ((ex (down s))) - (let* ((t (peek-token s)) - (spc (ts:space? s))) + (let ((t (peek-token s))) (if (not (ops t)) ex - (begin + (let ((spc (ts:space? s))) (take-token s) (cond ((and space-sensitive spc (memq t unary-and-binary-ops) (not (eqv? (peek-char (ts:port s)) #\ ))) @@ -816,42 +848,50 @@ (else (loop (list 'call t ex (down s)))))))))) -(define (parse-expr s) (parse-with-chains s parse-shift is-prec-plus? '(+ ++))) +(define (parse-expr s) (parse-with-chains s parse-shift is-prec-plus? '(+ ++))) +(define (parse-shift s) (parse-LtoR s parse-term is-prec-bitshift?)) +(define (parse-term s) (parse-with-chains s parse-rational is-prec-times? '(*))) +(define (parse-rational s) (parse-LtoR s parse-unary-subtype is-prec-rational?)) -(define (parse-shift s) (parse-LtoR s parse-term is-prec-bitshift?)) - -(define (parse-term s) (parse-with-chains s parse-rational is-prec-times? '(*))) - -(define (parse-rational s) (parse-LtoR s (lambda (s) (parse-unary-subtype s)) is-prec-rational?)) - -(define (parse-pipes s) (parse-LtoR s parse-range is-prec-pipe?)) +;; parse `<: A where B` as `<: (A where B)` (issue #21545) +(define (parse-unary-subtype s) + (let ((op (require-token s))) + (if (or (eq? op '|<:|) (eq? op '|>:|)) + (begin (take-token s) + (let ((next (peek-token s))) + (cond ((or (closing-token? next) (newline? next) (eq? next '=)) + op) ; return operator by itself, as in (<:) + ;; parse <:{T}(x::T) or <:(x::T) like other unary operators + ((or (eqv? next #\{) (eqv? next #\( )) + (ts:put-back! s op) + (parse-where s parse-unary)) + (else + (let ((arg (parse-where s parse-unary))) + (if (and (pair? arg) (eq? (car arg) 'tuple)) + (cons op (cdr arg)) + (list op arg))))))) + (parse-where s parse-unary)))) -(define (parse-comparison s) - (let loop ((ex (parse-pipes s)) - (first #t)) - (let ((t (peek-token s))) - (cond ((is-prec-comparison? t) - (begin (take-token s) - (if first - (loop (list 'comparison ex t (parse-pipes s)) #f) - (loop (append ex (list t (parse-pipes s))) #f)))) - (first ex) - ((length= ex 4) - ;; only a single comparison; special chained syntax not required - (let ((op (caddr ex)) - (arg1 (cadr ex)) - (arg2 (cadddr ex))) - (if (or (eq? op '|<:|) (eq? op '|>:|)) - `(,op ,arg1 ,arg2) - `(call ,op ,arg1 ,arg2)))) - (else ex))))) +(define (parse-where-chain s first) + (with-bindings ((where-enabled #f)) + (let loop ((ex first) + (t 'where)) + (if (eq? t 'where) + (begin (take-token s) + (let ((var (parse-comparison s))) + (loop (if (and (pair? var) (eq? (car var) 'cell1d)) + (list* 'where ex (cdr var)) ;; form `x where {T,S}` + (list 'where ex var)) + (peek-token s)))) + ex)))) -(define closing-token? - (let ((closer? (Set '(else elseif catch finally #\, #\) #\] #\} #\;)))) - (lambda (tok) - (or (and (eq? tok 'end) (not end-symbol)) - (closer? tok) - (eof-object? tok))))) +(define (parse-where s down) + ;; `where` needs to be below unary for `+(x::T,y::T) where {T} = ...` to work + (let ((ex (down s))) + (if (and where-enabled + (eq? (peek-token s) 'where)) + (parse-where-chain s ex) + ex))) (define (maybe-negate op num) (if (eq? op '-) @@ -864,6 +904,53 @@ (- num))) num)) +;; operators handled by parse-unary at the start of an expression +(define initial-operator? + ;; TODO: ? should probably not be listed here except for the syntax hack in osutils.jl + (Set (diff operators (append '(: |'| ?) syntactic-unary-operators syntactic-operators)))) + +(define (parse-unary s) + (let ((op (require-token s))) + (if (closing-token? op) + (error (string "unexpected \"" op "\""))) + (if (initial-operator? op) + (begin + (take-token s) + (if (or (eq? op '-) (eq? op '+)) + (let ((nch (peek-char (ts:port s)))) + (if (or (and (char? nch) (char-numeric? nch)) + (and (eqv? nch #\.) (read-char (ts:port s)))) + (let ((num (parse-juxtapose + (read-number (ts:port s) (eqv? nch #\.) (eq? op '-)) + s))) + (if (is-prec-power? (peek-token s)) + ;; -2^x parsed as (- (^ 2 x)) + (begin (ts:put-back! s (maybe-negate op num)) + (list 'call op (parse-factor s))) + num)) + (parse-unary-call s op #t))) + (parse-unary-call s op (unary-op? op)))) + (parse-juxtapose (parse-factor s) s)))) + +(define (parse-unary-call s op un) + (let ((next (peek-token s))) + (cond ((or (closing-token? next) (newline? next) (eq? next '=)) + op) ; return operator by itself, as in (+) + ((or (eqv? next #\{) ;; this case is +{T}(x::T) = ... + (and (not un) (eqv? next #\( ))) + (ts:put-back! s op) + (parse-factor s)) + ((not un) + (error (string "\"" op "\" is not a unary operator"))) + (else + (let* ((arg (parse-unary s)) + (args (if (and (pair? arg) (eq? (car arg) 'tuple)) + (cons op (cdr arg)) + (list op arg)))) + (if (or (eq? op '|<:|) (eq? op '|>:|)) + args + (cons 'call args))))))) + ;; given an expression and the next token, is there a juxtaposition ;; operator between them? (define (juxtapose? s expr t) @@ -897,83 +984,11 @@ `(call * ,ex ,(parse-unary s)))) (else ex)))) -(define (invalid-identifier-name? ex) - (or (syntactic-op? ex) (eq? ex '....))) - -;; parse `<: A where B` as `<: (A where B)` (issue #21545) -(define (parse-unary-subtype s) - (let ((op (require-token s))) - (if (or (eq? op '|<:|) (eq? op '|>:|)) - (begin (take-token s) - (let ((next (peek-token s))) - (cond ((or (closing-token? next) (newline? next) (eq? next '=)) - op) ; return operator by itself, as in (<:) - ;; parse <:{T}(x::T) or <:(x::T) like other unary operators - ((or (eqv? next #\{) (eqv? next #\( )) - (ts:put-back! s op) - (parse-where s parse-unary)) - (else - (let ((arg (parse-where s parse-unary))) - (if (and (pair? arg) (eq? (car arg) 'tuple)) - (cons op (cdr arg)) - (list op arg))))))) - (parse-where s parse-unary)))) - -(define (parse-unary s) - (let ((t (require-token s))) - (if (closing-token? t) - (error (string "unexpected " t))) - ;; TODO: ? should probably not be listed here except for the syntax hack in osutils.jl - (cond ((and (operator? t) (not (memq t '(: |'| ?))) (not (syntactic-unary-op? t)) - (not (invalid-identifier-name? t))) - (let* ((op (take-token s)) - (nch (peek-char (ts:port s)))) - (if (and (or (eq? op '-) (eq? op '+)) - (or (and (char? nch) (char-numeric? nch)) - (and (eqv? nch #\.) (read-char (ts:port s))))) - (let ((num (parse-juxtapose - (read-number (ts:port s) (eqv? nch #\.) (eq? op '-)) - s))) - (if (is-prec-power? (peek-token s)) - ;; -2^x parsed as (- (^ 2 x)) - (begin (ts:put-back! s (maybe-negate op num)) - (list 'call op (parse-factor s))) - num)) - (let ((next (peek-token s))) - (cond ((or (closing-token? next) (newline? next) (eq? next '=)) - op) ; return operator by itself, as in (+) - ((or (eqv? next #\{) ;; this case is +{T}(x::T) = ... - (and (not (memq op unary-ops)) - (eqv? next #\( ))) - (ts:put-back! s op) - (parse-factor s)) - ((not (memq op unary-ops)) - (error (string "\"" op "\" is not a unary operator"))) - (else - (let* ((arg (parse-unary s)) - (args (if (and (pair? arg) (eq? (car arg) 'tuple)) - (cons op (cdr arg)) - (list op arg)))) - (if (or (eq? op '|<:|) (eq? op '|>:|)) - args - (cons 'call args))))))))) - (else - (parse-juxtapose (parse-factor s) s))))) - ;; handle ^ and .^ -(define (parse-factor-h s down ops) - (let ((ex (down s)) - (t (peek-token s))) - (cond ((not (ops t)) - ex) - (else - (list 'call - (take-token s) ex (parse-factor-h s parse-unary ops)))))) - ;; -2^3 is parsed as -(2^3), so call parse-decl for the first argument, ;; and parse-unary from then on (to handle 2^-3) -(define (parse-factor s) - (parse-factor-h s parse-decl is-prec-power?)) +(define (parse-factor s) (parse-RtoL s parse-decl is-prec-power? #f parse-factor-after)) +(define (parse-factor-after s) (parse-RtoL s parse-unary is-prec-power? #f parse-factor-after)) (define (parse-decl s) (let loop ((ex (parse-call s))) @@ -989,24 +1004,25 @@ (else ex))))) +;; parse function call, indexing, dot, and transpose expressions +;; also handles looking for syntactic reserved words +(define (parse-call s) + (let ((ex (parse-unary-prefix s))) + (if (or (initial-reserved-word? ex) (eq? ex 'mutable) (eq? ex 'primitive)) + (parse-resword s ex) + (parse-call-chain s ex #f)))) + (define (parse-unary-prefix s) (let ((op (peek-token s))) (if (syntactic-unary-op? op) (begin (take-token s) (cond ((let ((next (peek-token s))) - (or (closing-token? next) (newline? next))) op) + (or (closing-token? next) (newline? next))) + op) ((memq op '(& |::|)) (list op (parse-where s parse-call))) (else (list op (parse-unary-prefix s))))) (parse-atom s)))) -;; parse function call, indexing, dot, and transpose expressions -;; also handles looking for syntactic reserved words -(define (parse-call s) - (let ((ex (parse-unary-prefix s))) - (if (or (initial-reserved-word? ex) (memq ex '(mutable primitive))) - (parse-resword s ex) - (parse-call-chain s ex #f)))) - (define (parse-def s is-func) (let* ((ex (parse-unary-prefix s)) (sig (if (or (and is-func (reserved-word? ex)) (initial-reserved-word? ex)) @@ -1971,9 +1987,9 @@ ;; process escape sequences using lisp read (read (open-input-string (string #\" s #\")))))) -(define (check-identifier ex) - (if (invalid-identifier-name? ex) - (error (string "invalid identifier name \"" ex "\"")))) +(define-macro (check-identifier ex) + `(if (or (syntactic-op? ,ex) (eq? ,ex '....)) + (error (string "invalid identifier name \"" ,ex "\"")))) ;; parse numbers, identifiers, parenthesized expressions, lists, vectors, etc. (define (parse-atom s (checked #t)) From d02d7343867461308d3b2a87d15467227ab8822d Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 5 May 2017 10:35:33 -0400 Subject: [PATCH 03/88] better static printing of typemap entries Ref #21715 (cherry picked from commit 4bcb1bf5205d1fc677a5f62c00ea350dec1991e1) --- base/boot.jl | 4 ++-- src/rtutils.c | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 55721469c6867..d0a686e761bf5 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -370,10 +370,10 @@ end show(io::IO, x::ANY) = ccall(:jl_static_show, Void, (Ptr{Void}, Any), io_pointer(io), x) print(io::IO, x::Char) = ccall(:jl_uv_putc, Void, (Ptr{Void}, Char), io_pointer(io), x) -print(io::IO, x::String) = write(io, x) +print(io::IO, x::String) = (write(io, x); nothing) print(io::IO, x::ANY) = show(io, x) print(io::IO, x::ANY, a::ANY...) = (print(io, x); print(io, a...)) -println(io::IO) = write(io, 0x0a) # 0x0a = '\n' +println(io::IO) = (write(io, 0x0a); nothing) # 0x0a = '\n' println(io::IO, x::ANY...) = (print(io, x...); println(io)) show(a::ANY) = show(STDOUT, a) diff --git a/src/rtutils.c b/src/rtutils.c index 954c352186e52..e5b2c8d8f11f8 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -841,14 +841,16 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt if (nb > 0 && tlen == 0) { uint8_t *data = (uint8_t*)v; n += jl_printf(out, "0x"); - for(int i=nb-1; i >= 0; --i) + for(int i = nb - 1; i >= 0; --i) n += jl_printf(out, "%02" PRIx8, data[i]); } else { - for (size_t i = 0; i < tlen; i++) { + size_t i = 0; + if (vt == jl_typemap_entry_type) + i = 1; + for (; i < tlen; i++) { if (!istuple) { n += jl_printf(out, "%s", jl_symbol_name((jl_sym_t*)jl_svecref(vt->name->names, i))); - //jl_fielddesc_t f = t->fields[i]; n += jl_printf(out, "="); } size_t offs = jl_field_offset(vt, i); @@ -861,11 +863,15 @@ static size_t jl_static_show_x_(JL_STREAM *out, jl_value_t *v, jl_datatype_t *vt (jl_datatype_t*)jl_field_type(vt, i), depth); } - if (istuple && tlen==1) + if (istuple && tlen == 1) n += jl_printf(out, ","); - else if (i != tlen-1) + else if (i != tlen - 1) n += jl_printf(out, ", "); } + if (vt == jl_typemap_entry_type) { + n += jl_printf(out, ", next=↩︎\n "); + n += jl_static_show_x(out, jl_fieldref(v, 0), depth); + } } n += jl_printf(out, ")"); } From c1fe105db7be7049ffd55fa33d5e20e164abe6b1 Mon Sep 17 00:00:00 2001 From: Amit Murthy Date: Thu, 11 May 2017 21:58:02 +0530 Subject: [PATCH 04/88] Fix reuse of client port on Linux. Implement for OSX. Ref #21818 (cherry picked from commit 0394f47f455defd5758dc7031266a0eb0adebc57) --- base/distributed/cluster.jl | 15 +++++++--- base/distributed/managers.jl | 43 +++++++++++++++------------- base/socket.jl | 20 ++++++++----- doc/src/manual/parallel-computing.md | 9 +++--- test/distributed_exec.jl | 37 +++++++++++++++++++++++- 5 files changed, 88 insertions(+), 36 deletions(-) diff --git a/base/distributed/cluster.jl b/base/distributed/cluster.jl index 77bc037c126ba..88d75e2d6e655 100644 --- a/base/distributed/cluster.jl +++ b/base/distributed/cluster.jl @@ -153,8 +153,15 @@ function start_worker(out::IO, cookie::AbstractString) init_worker(cookie) interface = IPv4(LPROC.bind_addr) if LPROC.bind_port == 0 - (actual_port,sock) = listenany(interface, UInt16(9009)) - LPROC.bind_port = actual_port + addr = Base.InetAddr(interface, 0) + sock = Base.TCPServer() + if bind(sock, addr) && Base.trylisten(sock) == 0 + _addr, port = Base._sockname(sock, true) + LPROC.bind_port = port + else + close(sock) + error("no ports available") + end else sock = listen(interface, LPROC.bind_port) end @@ -256,9 +263,9 @@ end function parse_connection_info(str) m = match(r"^julia_worker:(\d+)#(.*)", str) if m !== nothing - (m.captures[2], parse(Int16, m.captures[1])) + (m.captures[2], parse(UInt16, m.captures[1])) else - ("", Int16(-1)) + ("", UInt16(0)) end end diff --git a/base/distributed/managers.jl b/base/distributed/managers.jl index 269a69033f12d..2bd4ceceab952 100644 --- a/base/distributed/managers.jl +++ b/base/distributed/managers.jl @@ -456,31 +456,34 @@ end const client_port = Ref{Cushort}(0) function socket_reuse_port() - s = TCPSocket() - client_host = Ref{Cuint}(0) - ccall(:jl_tcp_bind, Int32, - (Ptr{Void}, UInt16, UInt32, Cuint), - s.handle, hton(client_port.x), hton(UInt32(0)), 0) < 0 && throw(SystemError("bind() : ")) - - # TODO: Support OSX and change the above code to call setsockopt before bind once libuv provides - # early access to a socket fd, i.e., before a bind call. - - @static if is_linux() - try - rc = ccall(:jl_tcp_reuseport, Int32, (Ptr{Void},), s.handle) - if rc > 0 # SO_REUSEPORT is unsupported, just return the ephemerally bound socket - return s - elseif rc < 0 - throw(SystemError("setsockopt() SO_REUSEPORT : ")) - end - getsockname(s) - catch e + @static if is_linux() || is_apple() + s = TCPSocket(delay = false) + + # Linux requires the port to be bound before setting REUSEPORT, OSX after. + is_linux() && bind_client_port(s) + rc = ccall(:jl_tcp_reuseport, Int32, (Ptr{Void},), s.handle) + if rc > 0 # SO_REUSEPORT is unsupported, just return the ephemerally bound socket + return s + elseif rc < 0 # This is an issue only on systems with lots of client connections, hence delay the warning - nworkers() > 128 && warn_once("Error trying to reuse client port number, falling back to plain socket : ", e) + nworkers() > 128 && warn_once("Error trying to reuse client port number, falling back to regular socket.") + # provide a clean new socket return TCPSocket() end + is_apple() && bind_client_port(s) + else + return TCPSocket() end +end + +function bind_client_port(s) + err = ccall(:jl_tcp_bind, Int32, (Ptr{Void}, UInt16, UInt32, Cuint), + s.handle, hton(client_port[]), hton(UInt32(0)), 0) + Base.uv_error("bind() failed", err) + + _addr, port = Base._sockname(s, true) + client_port[] = port return s end diff --git a/base/socket.jl b/base/socket.jl index 6bfebd0efbbec..bd6ef8baf5d22 100644 --- a/base/socket.jl +++ b/base/socket.jl @@ -282,10 +282,14 @@ mutable struct TCPSocket <: LibuvStream return tcp end end -function TCPSocket() + +# kw arg "delay": if true, libuv delays creation of the socket fd till the first bind call +function TCPSocket(; delay=true) tcp = TCPSocket(Libc.malloc(_sizeof_uv_tcp), StatusUninit) - err = ccall(:uv_tcp_init, Cint, (Ptr{Void}, Ptr{Void}), - eventloop(), tcp.handle) + af_spec = delay ? 0 : 2 # AF_UNSPEC is 0, AF_INET is 2 + + err = ccall(:uv_tcp_init_ex, Cint, (Ptr{Void}, Ptr{Void}, Cuint), + eventloop(), tcp.handle, af_spec) uv_error("failed to create tcp socket", err) tcp.status = StatusInit return tcp @@ -840,16 +844,18 @@ listenany(default_port) = listenany(IPv4(UInt32(0)), default_port) Get the IP address and the port that the given `TCPSocket` is connected to (or bound to, in the case of `TCPServer`). """ -function getsockname(sock::Union{TCPServer,TCPSocket}) +getsockname(sock::Union{TCPServer, TCPSocket}) = _sockname(sock, isa(sock, TCPServer)) + +function _sockname(sock, self) rport = Ref{Cushort}(0) raddress = zeros(UInt8, 16) rfamily = Ref{Cuint}(0) - r = if isa(sock, TCPServer) - ccall(:jl_tcp_getsockname, Int32, + if self + r = ccall(:jl_tcp_getsockname, Int32, (Ptr{Void}, Ref{Cushort}, Ptr{Void}, Ref{Cuint}), sock.handle, rport, raddress, rfamily) else - ccall(:jl_tcp_getpeername, Int32, + r = ccall(:jl_tcp_getpeername, Int32, (Ptr{Void}, Ref{Cushort}, Ptr{Void}, Ref{Cuint}), sock.handle, rport, raddress, rfamily) end diff --git a/doc/src/manual/parallel-computing.md b/doc/src/manual/parallel-computing.md index 4d2fb1e97de39..8b3c15dc379c3 100644 --- a/doc/src/manual/parallel-computing.md +++ b/doc/src/manual/parallel-computing.md @@ -1231,8 +1231,8 @@ as local laptops, departmental clusters, or even the cloud. This section covers requirements for the inbuilt `LocalManager` and `SSHManager`: * The master process does not listen on any port. It only connects out to the workers. - * Each worker binds to only one of the local interfaces and listens on the first free port starting - from `9009`. + * Each worker binds to only one of the local interfaces and listens on an ephemeral port number + assigned by the OS. * `LocalManager`, used by `addprocs(N)`, by default binds only to the loopback interface. This means that workers started later on remote hosts (or by anyone with malicious intentions) are unable to connect to the cluster. An `addprocs(4)` followed by an `addprocs(["remote_host"])` will fail. @@ -1250,8 +1250,9 @@ requirements for the inbuilt `LocalManager` and `SSHManager`: authenticated via public key infrastructure (PKI). Authentication credentials can be supplied via `sshflags`, for example ```sshflags=`-e ` ```. - Note that worker-worker connections are still plain TCP and the local security policy on the remote - cluster must allow for free connections between worker nodes, at least for ports 9009 and above. + In an all-to-all topology (the default), all workers connect to each other via plain TCP sockets. + The security policy on the cluster nodes must thus ensure free connectivity between workers for + the ephemeral port range (varies by OS). Securing and encrypting all worker-worker traffic (via SSH) or encrypting individual messages can be done via a custom ClusterManager. diff --git a/test/distributed_exec.jl b/test/distributed_exec.jl index 2c196fa65c1a5..d5cc95f4b98bb 100644 --- a/test/distributed_exec.jl +++ b/test/distributed_exec.jl @@ -12,6 +12,41 @@ include("testenv.jl") addprocs_with_testenv(4) +# Test that the client port is reused. SO_REUSEPORT may not be supported on +# all UNIX platforms, Linux kernels prior to 3.9 and older versions of OSX +if is_unix() + # Run the test on all processes. + results = asyncmap(procs()) do p + remotecall_fetch(p) do + ports_lower = [] # ports of pids lower than myid() + ports_higher = [] # ports of pids higher than myid() + for w in Base.Distributed.PGRP.workers + w.id == myid() && continue + port = Base._sockname(w.r_stream, true)[2] + if (w.id == 1) + # master connects to workers + push!(ports_higher, port) + elseif w.id < myid() + push!(ports_lower, port) + elseif w.id > myid() + push!(ports_higher, port) + end + end + @assert (length(ports_lower) + length(ports_higher)) == nworkers() + for portset in [ports_lower, ports_higher] + if (length(portset) > 0) && (length(unique(portset)) != 1) + warn("SO_REUSEPORT TESTS FAILED. UNSUPPORTED/OLDER UNIX VERSION?") + return 0 + end + end + return myid() + end + end + + # Ensure that the code has indeed been successfully executed everywhere + @test all(p -> p in results, procs()) +end + id_me = myid() id_other = filter(x -> x != id_me, procs())[rand(1:(nprocs()-1))] @@ -935,7 +970,7 @@ if is_unix() # aka have ssh end end - remotecall_fetch(plst->rmprocs(plst; waitfor=5.0), 1, new_pids) + remotecall_fetch(rmprocs, 1, new_pids) end print("\n\nTesting SSHManager. A minimum of 4GB of RAM is recommended.\n") From a50154e36641fe929c8f974ad762630655cf18be Mon Sep 17 00:00:00 2001 From: Amit Murthy Date: Fri, 19 May 2017 13:38:40 +0530 Subject: [PATCH 05/88] fix listenany to return correct port number for porthint of 0 Ref #21818 (cherry picked from commit 22720368896f99c7385f3955fcd25c51718feeba) --- base/distributed/cluster.jl | 11 ++--------- base/socket.jl | 4 ++++ test/socket.jl | 36 +++++++++++++++++++----------------- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/base/distributed/cluster.jl b/base/distributed/cluster.jl index 88d75e2d6e655..c12f8ed847176 100644 --- a/base/distributed/cluster.jl +++ b/base/distributed/cluster.jl @@ -153,15 +153,8 @@ function start_worker(out::IO, cookie::AbstractString) init_worker(cookie) interface = IPv4(LPROC.bind_addr) if LPROC.bind_port == 0 - addr = Base.InetAddr(interface, 0) - sock = Base.TCPServer() - if bind(sock, addr) && Base.trylisten(sock) == 0 - _addr, port = Base._sockname(sock, true) - LPROC.bind_port = port - else - close(sock) - error("no ports available") - end + (port, sock) = listenany(interface, UInt16(0)) + LPROC.bind_port = port else sock = listen(interface, LPROC.bind_port) end diff --git a/base/socket.jl b/base/socket.jl index bd6ef8baf5d22..e104b40383d6c 100644 --- a/base/socket.jl +++ b/base/socket.jl @@ -826,6 +826,10 @@ function listenany(host::IPAddr, default_port) while true sock = TCPServer() if bind(sock, addr) && trylisten(sock) == 0 + if default_port == 0 + _addr, port = _sockname(sock, true) + return (port, sock) + end return (addr.port, sock) end close(sock) diff --git a/test/socket.jl b/test/socket.jl index aeb76aeff2166..1d215ec237efc 100644 --- a/test/socket.jl +++ b/test/socket.jl @@ -69,27 +69,29 @@ end # test show() function for UDPSocket() @test repr(UDPSocket()) == "UDPSocket(init)" -port = Channel(1) defaultport = rand(2000:4000) -tsk = @async begin - p, s = listenany(defaultport) - put!(port, p) - sock = accept(s) - # test write call - write(sock,"Hello World\n") - - # test "locked" println to a socket - @sync begin - for i in 1:100 - @async println(sock, "a", 1) +for testport in [0, defaultport] + port = Channel(1) + tsk = @async begin + p, s = listenany(testport) + put!(port, p) + sock = accept(s) + # test write call + write(sock,"Hello World\n") + + # test "locked" println to a socket + @sync begin + for i in 1:100 + @async println(sock, "a", 1) + end end + close(s) + close(sock) end - close(s) - close(sock) + wait(port) + @test readstring(connect(fetch(port))) == "Hello World\n" * ("a1\n"^100) + wait(tsk) end -wait(port) -@test readstring(connect(fetch(port))) == "Hello World\n" * ("a1\n"^100) -wait(tsk) mktempdir() do tmpdir socketname = is_windows() ? ("\\\\.\\pipe\\uv-test-" * randstring(6)) : joinpath(tmpdir, "socket") From 152f81405e796280b62beb7e1616e78cc8ab13d3 Mon Sep 17 00:00:00 2001 From: Amit Murthy Date: Fri, 19 May 2017 13:49:00 +0530 Subject: [PATCH 06/88] added NEWS entry Ref #21818 (cherry picked from commit fa8c4d2ac0c895de3c3d36924409b44ab6b3f2dd) --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index 0e0320df33686..62e2983c8e7f5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -258,6 +258,10 @@ This section lists changes that do not have deprecation warnings. * `homedir` now determines the user's home directory via `libuv`'s `uv_os_homedir`, rather than from environment variables ([#19636]). + * Workers now listen on an ephemeral port assigned by the OS. Previously workers would + listen on the first free port available from 9009 ([#21818]). + + Library improvements -------------------- From 8b3ec359d084da6e86ba716c385717bd62e968a8 Mon Sep 17 00:00:00 2001 From: Gollor Date: Sat, 13 May 2017 04:07:29 +0300 Subject: [PATCH 07/88] Fixed relative path include on remote machines Ref #21832 Squashed for backporting (cherry picked from commit d86b37cac496e6090061966237272be48a8fc8d2) (cherry picked from commit 7e7393c1e40ea593c96cc767a46d039ec3a59759) (cherry picked from commit 6a4acc0423e4c746166fcee0ce8dedf44f36aeaa) (cherry picked from commit 93cf6d93050465944cde7e6a5cdfc23f8fe28cc6) (cherry picked from commit 23792943a21e18683ca22e528fda5f33fa780cc9) (cherry picked from commit 7ff63220cc479f7e36ac338d49adcd5c2415f023) (cherry picked from commit 49abbf3b24b9658d53f0be9203795f7043b3e475) (cherry picked from commit eadb699d2088658518f907b83599ffbcb201e03b) (cherry picked from commit 1ce1d75e59bae7ce99859d47281f62dbb3644e27) --- base/loading.jl | 13 ++++++++++--- test/distributed_exec.jl | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index a09f605aa3bce..113b4e583ead4 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -269,10 +269,17 @@ const _require_dependencies = Any[] # a list of (path, mtime) tuples that are th const _track_dependencies = Ref(false) # set this to true to track the list of file dependencies function _include_dependency(_path::AbstractString) prev = source_path(nothing) - path = (prev === nothing) ? abspath(_path) : joinpath(dirname(prev), _path) + if prev === nothing + if myid() == 1 + path = abspath(_path) + else + path = joinpath(remotecall_fetch(abspath, 1, "."), _path) + end + else + path = joinpath(dirname(prev), _path) + end if myid() == 1 && _track_dependencies[] - apath = abspath(path) - push!(_require_dependencies, (apath, mtime(apath))) + push!(_require_dependencies, (path, mtime(path))) end return path, prev end diff --git a/test/distributed_exec.jl b/test/distributed_exec.jl index d5cc95f4b98bb..bc9e58e28a596 100644 --- a/test/distributed_exec.jl +++ b/test/distributed_exec.jl @@ -1637,6 +1637,47 @@ catch ex @test ex.captured.ex.exceptions[2].ex == UndefVarError(:DontExistOn1) end +@test let + # creates a new worker in the same folder and tries to include file + tmp_file, temp_file_stream = mktemp() + close(temp_file_stream) + tmp_file = relpath(tmp_file) + try + proc = addprocs_with_testenv(1) + include(tmp_file) + remotecall_fetch(include, proc[1], tmp_file) + rmprocs(proc) + rm(tmp_file) + return true + catch e + println(e) + rm(tmp_file, force=true) + return false + end +end == true + +@test let + # creates a new worker in the different folder and tries to include file + tmp_file, temp_file_stream = mktemp() + close(temp_file_stream) + tmp_file = relpath(tmp_file) + tmp_dir = relpath(mktempdir()) + try + proc = addprocs_with_testenv(1, dir=tmp_dir) + include(tmp_file) + remotecall_fetch(include, proc[1], tmp_file) + rmprocs(proc) + rm(tmp_dir) + rm(tmp_file) + return true + catch e + println(e) + rm(tmp_dir, force=true) + rm(tmp_file, force=true) + return false + end +end == true + # Run topology tests last after removing all workers, since a given # cluster at any time only supports a single topology. rmprocs(workers()) From 4aa8d72bcdf162de33d663f4519b4d30d8d374a2 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 19 May 2017 12:06:33 -0400 Subject: [PATCH 08/88] Method overwriting by an ambiguity should also invalidate the method cache fix #21963 Ref #21965 (cherry picked from commit 8bacb65bbab9cbb7da2a266dc384cdd62df372aa) --- 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 822417e2e0897..5886714211dc1 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 32139c496a44f..14c03f877b8da 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -85,6 +85,16 @@ cfunction(ambig, Int, (UInt8, Int)) # test for a crash (doesn't throw an error) ambig(x, y::Integer) = 3 @test_throws MethodError ambig(2, 0x03) +# Method overwriting by an ambiguity should also invalidate the method cache (#21963) +ambig(x::Union{Char, Int8}) = 'r' +@test ambig('c') == 'r' +@test ambig(Int8(1)) == 'r' +@test_throws MethodError ambig(Int16(1)) +ambig(x::Union{Char, Int16}) = 's' +@test_throws MethodError ambig('c') +@test ambig(Int8(1)) == 'r' +@test ambig(Int16(1)) == 's' + # Automatic detection of ambiguities module Ambig1 ambig(x, y) = 1 From b8cf285645016f62768bc5afdcb19cae6301f695 Mon Sep 17 00:00:00 2001 From: Amit Murthy Date: Mon, 22 May 2017 21:17:58 +0530 Subject: [PATCH 09/88] Return socket correctly in socket_reuse_port (#22017) * Return socket correctly in socket_reuse_port * Run reuseport tests only if SO_REUSEPORT is supported. * Test fix - test for successful addition of workers in distributed test (cherry picked from commit d3bc3295b4596ed5ed916379cdd8d9cab5e49a02) --- base/distributed/managers.jl | 1 + test/distributed_exec.jl | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/base/distributed/managers.jl b/base/distributed/managers.jl index 2bd4ceceab952..66753ee09be6d 100644 --- a/base/distributed/managers.jl +++ b/base/distributed/managers.jl @@ -472,6 +472,7 @@ function socket_reuse_port() return TCPSocket() end is_apple() && bind_client_port(s) + return s else return TCPSocket() end diff --git a/test/distributed_exec.jl b/test/distributed_exec.jl index bc9e58e28a596..3f12f5cb15075 100644 --- a/test/distributed_exec.jl +++ b/test/distributed_exec.jl @@ -11,10 +11,9 @@ include("testenv.jl") end addprocs_with_testenv(4) +@test nprocs() == 5 -# Test that the client port is reused. SO_REUSEPORT may not be supported on -# all UNIX platforms, Linux kernels prior to 3.9 and older versions of OSX -if is_unix() +function reuseport_tests() # Run the test on all processes. results = asyncmap(procs()) do p remotecall_fetch(p) do @@ -47,6 +46,19 @@ if is_unix() @test all(p -> p in results, procs()) end +# Test that the client port is reused. SO_REUSEPORT may not be supported on +# all UNIX platforms, Linux kernels prior to 3.9 and older versions of OSX +if is_unix() + # Run reuse client port tests only if SO_REUSEPORT is supported. + s = TCPSocket(delay = false) + is_linux() && Base.Distributed.bind_client_port(s) + if ccall(:jl_tcp_reuseport, Int32, (Ptr{Void},), s.handle) == 0 + reuseport_tests() + else + info("SO_REUSEPORT is unsupported, skipping reuseport tests.") + end +end + id_me = myid() id_other = filter(x -> x != id_me, procs())[rand(1:(nprocs()-1))] From 718828b9c050e70ca59281d9c5aae06d071809d0 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 19 May 2017 19:06:19 -0400 Subject: [PATCH 10/88] Add necessary LLVM patches Ref #22022 (cherry picked from commit 915910c3e3301891dad754d7443907ca49a9eaa5) --- deps/llvm.mk | 2 + deps/patches/llvm-D32593.patch | 83 ++++++++++++++++++++++++++++++++++ deps/patches/llvm-D33179.patch | 64 ++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 deps/patches/llvm-D32593.patch create mode 100644 deps/patches/llvm-D33179.patch diff --git a/deps/llvm.mk b/deps/llvm.mk index 5883e4dc734ab..5a2a0df4b9a17 100644 --- a/deps/llvm.mk +++ b/deps/llvm.mk @@ -494,6 +494,8 @@ $(eval $(call LLVM_PATCH,llvm-D28759-loopclearance)) $(eval $(call LLVM_PATCH,llvm-D28786-callclearance)) $(eval $(call LLVM_PATCH,llvm-rL293230-icc17-cmake)) # Remove for 4.0 $(eval $(call LLVM_PATCH,llvm-PR29010-i386-xmm)) # Remove for 4.0 +$(eval $(call LLVM_PATCH,llvm-D32593)) +$(eval $(call LLVM_PATCH,llvm-D33179)) endif # LLVM_VER ifeq ($(LLVM_VER),3.7.1) diff --git a/deps/patches/llvm-D32593.patch b/deps/patches/llvm-D32593.patch new file mode 100644 index 0000000000000..19c4acb960f97 --- /dev/null +++ b/deps/patches/llvm-D32593.patch @@ -0,0 +1,83 @@ +From 5eeab81d22e07b6e12821067fced590f534c251a Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Thu, 27 Apr 2017 14:33:33 -0400 +Subject: [PATCH] [SROA] Fix crash due to bad bitcast + +Summary: +As shown in the test case, SROA was crashing when trying to split +stores (to the alloca) of loads (from anywhere), because it assumed +the pointer operand to the loads and stores had to have the same +address space. This isn't the case. Make sure to use the correct +pointer type for both the load and the store. + +Reviewers: chandlerc, majnemer, sanjoy + +Subscribers: arsenm, llvm-commits + +Differential Revision: https://reviews.llvm.org/D32593 +--- + lib/Transforms/Scalar/SROA.cpp | 7 ++++--- + test/Transforms/SROA/address-spaces.ll | 18 ++++++++++++++++++ + 2 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/lib/Transforms/Scalar/SROA.cpp b/lib/Transforms/Scalar/SROA.cpp +index d01e91a..610d5a8 100644 +--- a/lib/Transforms/Scalar/SROA.cpp ++++ b/lib/Transforms/Scalar/SROA.cpp +@@ -3697,7 +3697,8 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { + int Idx = 0, Size = Offsets.Splits.size(); + for (;;) { + auto *PartTy = Type::getIntNTy(Ty->getContext(), PartSize * 8); +- auto *PartPtrTy = PartTy->getPointerTo(SI->getPointerAddressSpace()); ++ auto *LoadPartPtrTy = PartTy->getPointerTo(LI->getPointerAddressSpace()); ++ auto *StorePartPtrTy = PartTy->getPointerTo(SI->getPointerAddressSpace()); + + // Either lookup a split load or create one. + LoadInst *PLoad; +@@ -3708,7 +3709,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { + PLoad = IRB.CreateAlignedLoad( + getAdjustedPtr(IRB, DL, LoadBasePtr, + APInt(DL.getPointerSizeInBits(), PartOffset), +- PartPtrTy, LoadBasePtr->getName() + "."), ++ LoadPartPtrTy, LoadBasePtr->getName() + "."), + getAdjustedAlignment(LI, PartOffset, DL), /*IsVolatile*/ false, + LI->getName()); + } +@@ -3718,7 +3719,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { + StoreInst *PStore = IRB.CreateAlignedStore( + PLoad, getAdjustedPtr(IRB, DL, StoreBasePtr, + APInt(DL.getPointerSizeInBits(), PartOffset), +- PartPtrTy, StoreBasePtr->getName() + "."), ++ StorePartPtrTy, StoreBasePtr->getName() + "."), + getAdjustedAlignment(SI, PartOffset, DL), /*IsVolatile*/ false); + + // Now build a new slice for the alloca. +diff --git a/test/Transforms/SROA/address-spaces.ll b/test/Transforms/SROA/address-spaces.ll +index 119f225..8fba30c 100644 +--- a/test/Transforms/SROA/address-spaces.ll ++++ b/test/Transforms/SROA/address-spaces.ll +@@ -83,3 +83,21 @@ define void @pr27557() { + store i32 addrspace(3)* @l, i32 addrspace(3)** %3, align 8 + ret void + } ++ ++; Make sure pre-splitting doesn't try to introduce an illegal bitcast ++define float @presplit(i64 addrspace(1)* %p) { ++entry: ++; CHECK-LABEL: @presplit( ++; CHECK: %[[CAST:.*]] = bitcast i64 addrspace(1)* {{.*}} to i32 addrspace(1)* ++; CHECK: load i32, i32 addrspace(1)* %[[CAST]] ++ %b = alloca i64 ++ %b.cast = bitcast i64* %b to [2 x float]* ++ %b.gep1 = getelementptr [2 x float], [2 x float]* %b.cast, i32 0, i32 0 ++ %b.gep2 = getelementptr [2 x float], [2 x float]* %b.cast, i32 0, i32 1 ++ %l = load i64, i64 addrspace(1)* %p ++ store i64 %l, i64* %b ++ %f1 = load float, float* %b.gep1 ++ %f2 = load float, float* %b.gep2 ++ %ret = fadd float %f1, %f2 ++ ret float %ret ++} +-- +2.9.3 + diff --git a/deps/patches/llvm-D33179.patch b/deps/patches/llvm-D33179.patch new file mode 100644 index 0000000000000..2be915018de24 --- /dev/null +++ b/deps/patches/llvm-D33179.patch @@ -0,0 +1,64 @@ +From b1a005ba688397ca360e89cd6c6f51f232d6c25e Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Fri, 19 May 2017 18:42:20 -0400 +Subject: [PATCH] [Sink] Fix predicate in legality check + +Summary: +isSafeToSpeculativelyExecute is the wrong predicate to use here. +All that checks for is whether it is safe to hoist a value due to +unaligned/un-dereferencable accesses. However, not only are we doing +sinking rather than hoisting, our concern is that the location +we're loading from may have been modified. Instead forbid sinking +any load across a critical edge. + +Reviewers: majnemer + +Subscribers: llvm-commits + +Differential Revision: https://reviews.llvm.org/D33179 +--- + lib/Transforms/Scalar/Sink.cpp | 2 +- + test/Transforms/Sink/badloadsink.ll | 18 ++++++++++++++++++ + 2 files changed, 19 insertions(+), 1 deletion(-) + create mode 100644 test/Transforms/Sink/badloadsink.ll + +diff --git a/lib/Transforms/Scalar/Sink.cpp b/lib/Transforms/Scalar/Sink.cpp +index 102e9ea..5210f16 100644 +--- a/lib/Transforms/Scalar/Sink.cpp ++++ b/lib/Transforms/Scalar/Sink.cpp +@@ -114,7 +114,7 @@ static bool IsAcceptableTarget(Instruction *Inst, BasicBlock *SuccToSinkTo, + if (SuccToSinkTo->getUniquePredecessor() != Inst->getParent()) { + // We cannot sink a load across a critical edge - there may be stores in + // other code paths. +- if (!isSafeToSpeculativelyExecute(Inst)) ++ if (isa(Inst)) + return false; + + // We don't want to sink across a critical edge if we don't dominate the +diff --git a/test/Transforms/Sink/badloadsink.ll b/test/Transforms/Sink/badloadsink.ll +new file mode 100644 +index 0000000..e3f4884 +--- /dev/null ++++ b/test/Transforms/Sink/badloadsink.ll +@@ -0,0 +1,18 @@ ++; RUN: opt < %s -basicaa -sink -S | FileCheck %s ++declare void @foo(i64 *) ++define i64 @sinkload(i1 %cmp) { ++; CHECK-LABEL: @sinkload ++top: ++ %a = alloca i64 ++; CHECK: call void @foo(i64* %a) ++; CHECK-NEXT: %x = load i64, i64* %a ++ call void @foo(i64* %a) ++ %x = load i64, i64* %a ++ br i1 %cmp, label %A, label %B ++A: ++ store i64 0, i64 *%a ++ br label %B ++B: ++; CHECK-NOT: load i64, i64 *%a ++ ret i64 %x ++} +-- +2.9.3 + From acba61a2a50b822e097d8dc2f78d079d5a991c76 Mon Sep 17 00:00:00 2001 From: Ben Arthur Date: Mon, 29 May 2017 12:44:49 -0400 Subject: [PATCH 11/88] fix extrema(A,dim) when length(dim)>1 Ref #22118 (cherry picked from commit 4a470cb174f8083acb79843261b1aab20d2fdf99) --- base/multidimensional.jl | 37 +++++++++++++++++-------------------- test/reduce.jl | 14 +++++++++++--- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 6659185b5f273..129bb5fe224a7 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -1440,26 +1440,23 @@ function extrema(A::AbstractArray, dims) return extrema!(B, A) end -@generated function extrema!(B, A::AbstractArray{T,N}) where {T,N} - return quote - sA = size(A) - sB = size(B) - @nloops $N i B begin - AI = @nref $N A i - (@nref $N B i) = (AI, AI) - end - Bmax = sB - Istart = Int[sB[i] == 1 != sA[i] ? 2 : 1 for i = 1:ndims(A)] - @inbounds @nloops $N i d->(Istart[d]:size(A,d)) begin - AI = @nref $N A i - @nexprs $N d->(j_d = min(Bmax[d], i_{d})) - BJ = @nref $N B j - if AI < BJ[1] - (@nref $N B j) = (AI, BJ[2]) - elseif AI > BJ[2] - (@nref $N B j) = (BJ[1], AI) - end +@noinline function extrema!(B, A) + sA = size(A) + sB = size(B) + for I in CartesianRange(sB) + AI = A[I] + B[I] = (AI, AI) + end + Bmax = CartesianIndex(sB) + @inbounds @simd for I in CartesianRange(sA) + J = min(Bmax,I) + BJ = B[J] + AI = A[I] + if AI < BJ[1] + B[J] = (AI, BJ[2]) + elseif AI > BJ[2] + B[J] = (BJ[1], AI) end - return B end + return B end diff --git a/test/reduce.jl b/test/reduce.jl index cf89d564262f8..e537a83638b24 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -197,9 +197,17 @@ prod2(itr) = invoke(prod, Tuple{Any}, itr) @test maximum(collect(Int16(1):Int16(100))) === Int16(100) @test maximum(Int32[1,2]) === Int32(2) -@test extrema(reshape(1:24,2,3,4),1) == reshape([(1,2),(3,4),(5,6),(7,8),(9,10),(11,12),(13,14),(15,16),(17,18),(19,20),(21,22),(23,24)],1,3,4) -@test extrema(reshape(1:24,2,3,4),2) == reshape([(1,5),(2,6),(7,11),(8,12),(13,17),(14,18),(19,23),(20,24)],2,1,4) -@test extrema(reshape(1:24,2,3,4),3) == reshape([(1,19),(2,20),(3,21),(4,22),(5,23),(6,24)],2,3,1) +A = circshift(reshape(1:24,2,3,4), (0,1,1)) +@test extrema(A,1) == reshape([(23,24),(19,20),(21,22),(5,6),(1,2),(3,4),(11,12),(7,8),(9,10),(17,18),(13,14),(15,16)],1,3,4) +@test extrema(A,2) == reshape([(19,23),(20,24),(1,5),(2,6),(7,11),(8,12),(13,17),(14,18)],2,1,4) +@test extrema(A,3) == reshape([(5,23),(6,24),(1,19),(2,20),(3,21),(4,22)],2,3,1) +@test extrema(A,(1,2)) == reshape([(19,24),(1,6),(7,12),(13,18)],1,1,4) +@test extrema(A,(1,3)) == reshape([(5,24),(1,20),(3,22)],1,3,1) +@test extrema(A,(2,3)) == reshape([(1,23),(2,24)],2,1,1) +@test extrema(A,(1,2,3)) == reshape([(1,24)],1,1,1) +@test size(extrema(A,1)) == size(maximum(A,1)) +@test size(extrema(A,(1,2))) == size(maximum(A,(1,2))) +@test size(extrema(A,(1,2,3))) == size(maximum(A,(1,2,3))) # any & all From 29cc5b0424cc4ffbca2b30ddd6bef0f9adc7d969 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Tue, 30 May 2017 13:04:39 +0200 Subject: [PATCH 12/88] fix base(b, big(0), 0) == "0" Ref #22133 (cherry picked from commit 994f42c3efee2f5a82fef4cd78ed2cad980f47b4) --- base/gmp.jl | 31 +++++++++++++------------------ test/bigint.jl | 6 ++++++ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/base/gmp.jl b/base/gmp.jl index 7696c56b15e0e..e8e7d814aa88e 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -578,26 +578,21 @@ oct(n::BigInt, pad::Int) = base( 8, n, pad) dec(n::BigInt, pad::Int) = base(10, n, pad) hex(n::BigInt, pad::Int) = base(16, n, pad) -function base(b::Integer, n::BigInt) +function base(b::Integer, n::BigInt, pad::Integer=1) + b < 0 && return base(Int(b), n, pad, (b>0) & (n.size<0)) 2 <= b <= 62 || throw(ArgumentError("base must be 2 ≤ base ≤ 62, got $b")) - nd = ndigits(n, b) - str = Base._string_n(n < 0 ? nd+1 : nd) - ccall((:__gmpz_get_str,:libgmp), Ptr{UInt8}, (Ptr{UInt8}, Cint, Ptr{BigInt}), str, b, &n) - return str -end - -function base(b::Integer, n::BigInt, pad::Integer) - s = base(b, n) - buf = IOBuffer() - if n < 0 - s = s[2:end] - write(buf, '-') + nd1 = ndigits(n, b) + nd = max(nd1, pad) + str = Base._string_n(nd + isneg(n) + 1) # +1 for final '\0' + ptr = pointer(str) + ccall((:__gmpz_get_str,:libgmp), Ptr{UInt8}, (Ptr{UInt8}, Cint, Ref{BigInt}), ptr + nd - nd1, b, n) + for i = (0:nd-nd1-1) + isneg(n) + unsafe_store!(ptr+i, '0' % UInt8) end - for i in 1:pad-sizeof(s) # `s` is known to be ASCII, and `length` is slower - write(buf, '0') - end - write(buf, s) - String(buf) + isneg(n) && unsafe_store!(ptr, '-' % UInt8) + str.len -= 1 # final '\0' + iszero(n) && pad < 1 && (str.len -= 1) + str end function ndigits0z(x::BigInt, b::Integer=10) diff --git a/test/bigint.jl b/test/bigint.jl index 4bf485ccb8e29..771e6343e770b 100644 --- a/test/bigint.jl +++ b/test/bigint.jl @@ -333,6 +333,12 @@ let padding = 4, low = big(4), high = big(2^20) @test hex(-high, padding) == "-100000" end +# respect 0-padding on big(0) +for f in (bin, oct, dec, hex) + @test f(big(0), 0) == "" +end +@test base(rand(2:62), big(0), 0) == "" + @test isqrt(big(4)) == 2 @test isqrt(big(5)) == 2 From 3e6545e761a5ec24df82917a2d177dd0ddf22c20 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 30 May 2017 17:49:06 -0400 Subject: [PATCH 13/88] prevent Docs.apropos from breaking on random stuff interpolated into docs Ref #22150 (cherry picked from commit 95677b061cc654e911f2cca1727db238a27ac67a) --- 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 0daf26f78c183..c597f39c28055 100644 --- a/base/docs/utils.jl +++ b/base/docs/utils.jl @@ -414,6 +414,7 @@ Strip all Markdown markup from x, leaving the result in plain text. Used internally by apropos to make docstrings containing more than one markdown element searchable. """ +stripmd(x::ANY) = string(x) # for random objects interpolated into the docstring stripmd(x::AbstractString) = x # base case stripmd(x::Void) = " " stripmd(x::Vector) = string(map(stripmd, x)...) diff --git a/test/docs.jl b/test/docs.jl index 17ba396b79deb..18e0a21617530 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 ca44bb37b579fa22a83281b87d83091bf53f512a Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Mon, 26 Jun 2017 21:27:49 +0200 Subject: [PATCH 14/88] add some doctest to test (#22287) * fix spurious newlines in Base.Test printing * add some doctest to test (cherry picked from commit 2796b40176dbe489602c5eef9951dfb005316779) --- base/test.jl | 4 +-- doc/src/stdlib/test.md | 66 ++++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/base/test.jl b/base/test.jl index fdff18c1f58a2..4454a213de998 100644 --- a/base/test.jl +++ b/base/test.jl @@ -67,9 +67,9 @@ struct Pass <: Result value end function Base.show(io::IO, t::Pass) - print_with_color(:green, io, "Test Passed\n"; bold = true) + print_with_color(:green, io, "Test Passed"; bold = true) if !(t.orig_expr === nothing) - print(io, " Expression: ", t.orig_expr) + print(io, "\n Expression: ", t.orig_expr) end if t.test_type == :test_throws # The correct type of exception was thrown diff --git a/doc/src/stdlib/test.md b/doc/src/stdlib/test.md index 62ec7e4f3d4ac..baf78ae1c16b6 100644 --- a/doc/src/stdlib/test.md +++ b/doc/src/stdlib/test.md @@ -1,5 +1,11 @@ # Unit Testing +```@meta +DocTestSetup = quote + using Base.Test +end +``` + ## Testing Base Julia Julia is under rapid development and has an extensive test suite to verify functionality across @@ -26,7 +32,7 @@ Base.Test.@test_throws For example, suppose we want to check our new function `foo(x)` works as expected: -```julia-repl +```jldoctest testfoo julia> using Base.Test julia> foo(x) = length(x)^2 @@ -35,28 +41,22 @@ foo (generic function with 1 method) If the condition is true, a `Pass` is returned: -```julia-repl +```jldoctest testfoo julia> @test foo("bar") == 9 Test Passed - Expression: foo("bar") == 9 - Evaluated: 9 == 9 julia> @test foo("fizz") >= 10 Test Passed - Expression: foo("fizz") >= 10 - Evaluated: 16 >= 10 ``` If the condition is false, then a `Fail` is returned and an exception is thrown: -```julia-repl +```jldoctest testfoo julia> @test foo("f") == 20 Test Failed Expression: foo("f") == 20 Evaluated: 1 == 20 ERROR: There was an error during testing - in record at test.jl:268 - in do_test at test.jl:191 ``` If the condition could not be evaluated because an exception was thrown, which occurs in this @@ -68,23 +68,24 @@ julia> @test foo(:cat) == 1 Error During Test Test threw an exception of type MethodError Expression: foo(:cat) == 1 - MethodError: `length` has no method matching length(::Symbol) - in foo at none:1 - in anonymous at test.jl:159 - in do_test at test.jl:180 + MethodError: no method matching length(::Symbol) + Closest candidates are: + length(::SimpleVector) at essentials.jl:256 + length(::Base.MethodList) at reflection.jl:521 + length(::MethodTable) at reflection.jl:597 + ... + Stacktrace: + [...] ERROR: There was an error during testing - in record at test.jl:268 - in do_test at test.jl:191 ``` If we expect that evaluating an expression *should* throw an exception, then we can use `@test_throws()` to check that this occurs: -```julia-repl +```jldoctest testfoo julia> @test_throws MethodError foo(:cat) Test Passed - Expression: foo(:cat) - Evaluated: MethodError + Thrown: MethodError ``` ## Working with Test Sets @@ -104,19 +105,19 @@ Base.Test.@testset We can put our tests for the `foo(x)` function in a test set: -```julia-repl +```jldoctest testfoo julia> @testset "Foo Tests" begin @test foo("a") == 1 @test foo("ab") == 4 @test foo("abc") == 9 - end + end; Test Summary: | Pass Total Foo Tests | 3 3 ``` Test sets can also be nested: -```julia-repl +```jldoctest testfoo julia> @testset "Foo Tests" begin @testset "Animals" begin @test foo("cat") == 9 @@ -126,7 +127,7 @@ julia> @testset "Foo Tests" begin @test foo(zeros(i)) == i^2 @test foo(ones(i)) == i^2 end - end + end; Test Summary: | Pass Total Foo Tests | 8 8 ``` @@ -153,14 +154,13 @@ julia> @testset "Foo Tests" begin Arrays: Test Failed Expression: foo(ones(4)) == 15 Evaluated: 16 == 15 - in record at test.jl:297 - in do_test at test.jl:191 +Stacktrace: + [...] Test Summary: | Pass Fail Total Foo Tests | 3 1 4 Animals | 2 2 Arrays | 1 1 2 ERROR: Some tests did not pass: 3 passed, 1 failed, 0 errored, 0 broken. - in finish at test.jl:362 ``` ## Other Test Macros @@ -169,15 +169,15 @@ As calculations on floating-point values can be imprecise, you can perform appro checks using either `@test a ≈ b` (where `≈`, typed via tab completion of `\approx`, is the [`isapprox()`](@ref) function) or use [`isapprox()`](@ref) directly. -```julia-repl +```jldoctest julia> @test 1 ≈ 0.999999999 +Test Passed julia> @test 1 ≈ 0.999999 -ERROR: test failed: 1 isapprox 0.999999 - in expression: 1 ≈ 0.999999 - in error at error.jl:21 - in default_handler at test.jl:30 - in do_test at test.jl:53 +Test Failed + Expression: 1 ≈ 0.999999 + Evaluated: 1 ≈ 0.999999 +ERROR: There was an error during testing ``` ```@docs @@ -264,3 +264,7 @@ And using that testset looks like: end end ``` + +```@meta +DocTestSetup = nothing +``` From 9e76e657736a5f1b8125c98fb247bbd6836dd71b Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 24 Jun 2017 23:05:03 -0700 Subject: [PATCH 15/88] add a few doctests to broadcast, parse, intfuncs, number and permuteddimsarray (#22289) (cherry picked from commit d9d822359a51db06dbc349e08e17cc98ea418246) --- base/broadcast.jl | 10 ++++++ base/docs/helpdb/Base.jl | 38 +++++++++++++++++++++ base/intfuncs.jl | 69 +++++++++++++++++++++++++++++++++++++++ base/number.jl | 26 +++++++++++++++ base/permuteddimsarray.jl | 2 ++ 5 files changed, 145 insertions(+) diff --git a/base/broadcast.jl b/base/broadcast.jl index 2d98b4031b0d9..48de50d54d5c4 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -592,6 +592,16 @@ If you want to *avoid* adding dots for selected function calls in (no dot for `sort`). (`@.` is equivalent to a call to `@__dot__`.) + +```jldoctest +julia> x = 1.0:3.0; y = similar(x); + +julia> @. y = x + 3 * sin(x) +3-element Array{Float64,1}: + 3.52441 + 4.72789 + 3.42336 +``` """ macro __dot__(x) esc(__dot__(x)) diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 93eff004af71f..4f67be21924dc 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -1010,6 +1010,14 @@ stop as soon as it has parsed a valid expression. Incomplete but otherwise synta valid expressions will return `Expr(:incomplete, "(error message)")`. If `raise` is `true` (default), syntax errors other than incomplete expressions will raise an error. If `raise` is `false`, `parse` will return an expression that will raise an error upon evaluation. + +```jldoctest +julia> parse("x = 3, y = 5", 7) +(:(y = 5), 13) + +julia> parse("x = 3, y = 5", 5) +(:((3, y) = 5), 13) +``` """ parse(str, start) @@ -1020,6 +1028,22 @@ Parse the expression string greedily, returning a single expression. An error is there are additional characters after the first expression. If `raise` is `true` (default), syntax errors will raise an error; otherwise, `parse` will return an expression that will raise an error upon evaluation. + +```jldoctest +julia> parse("x = 3") +:(x = 3) + +julia> parse("x = ") +:($(Expr(:incomplete, "incomplete: premature end of input"))) + +julia> parse("1.0.2") +ERROR: ParseError("invalid numeric constant \\\"1.0.\\\"") +Stacktrace: + [...] + +julia> parse("1.0.2"; raise = false) +:($(Expr(:error, "invalid numeric constant \"1.0.\""))) +``` """ parse(str) @@ -1029,6 +1053,20 @@ parse(str) Parse a string as a number. If the type is an integer type, then a base can be specified (the default is 10). If the type is a floating point type, the string is parsed as a decimal floating point number. If the string does not contain a valid number, an error is raised. + +```jldoctest +julia> parse(Int, "1234") +1234 + +julia> parse(Int, "1234", 5) +194 + +julia> parse(Int, "afc", 16) +2812 + +julia> parse(Float64, "1.2e-3") +0.0012 +``` """ parse(T::Type, str, base=Int) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 91191d4048c18..4f34d7a7ace29 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -224,6 +224,14 @@ const HWNumber = Union{HWReal, Complex{<:HWReal}, Rational{<:HWReal}} powermod(x::Integer, p::Integer, m) Compute ``x^p \\pmod m``. + +```jldoctest +julia> powermod(2, 6, 5) +4 + +julia> mod(2^6, 5) +4 +``` """ function powermod(x::Integer, p::Integer, m::T) where T<:Integer p < 0 && return powermod(invmod(x, m), -p, m) @@ -302,6 +310,16 @@ ispow2(x::Integer) = x > 0 && count_ones(x) == 1 The smallest `a^n` not less than `x`, where `n` is a non-negative integer. `a` must be greater than 1, and `x` must be greater than 0. + +```jldoctest +julia> nextpow(2, 7) +8 + +julia> nextpow(2, 9) +16 +``` + +See also [`prevpow`](@ref). """ function nextpow(a::Real, x::Real) (a <= 1 || x <= 0) && throw(DomainError()) @@ -317,6 +335,16 @@ end The largest `a^n` not greater than `x`, where `n` is a non-negative integer. `a` must be greater than 1, and `x` must not be less than 1. + +```jldoctest +julia> prevpow(2, 7) +4 + +julia> prevpow(2, 9) +8 +``` + +See also [`nextpow`](@ref). """ function prevpow(a::Real, x::Real) (a <= 1 || x < 1) && throw(DomainError()) @@ -386,10 +414,43 @@ ndigitsnb(x::Integer, b::Integer) = x==0 ? 1 : ndigits0znb(x, b) ndigits(x::Unsigned, b::Integer) = x==0 ? 1 : ndigits0z(x,Int(b)) ndigits(x::Unsigned) = x==0 ? 1 : ndigits0z(x) +# The suffix "0z" means that the output is 0 on input zero (cf. #16841) +""" + ndigits0z(n::Integer, b::Integer=10) + +Return 0 if `n == 0`, otherwise compute the number of digits in +integer `n` written in base `b` (i.e. equal to `ndigits(n, b)` +in this case). +The base `b` must not be in `[-1, 0, 1]`. + +```jldoctest +julia> Base.ndigits0z(0, 16) +0 + +julia> Base.ndigits(0, 16) +1 +``` + +See also [`ndigits`](@ref). +""" +ndigits0z + """ ndigits(n::Integer, b::Integer=10) Compute the number of digits in integer `n` written in base `b`. +The base `b` must not be in `[-1, 0, 1]`. + +```jldoctest +julia> ndigits(12345) +5 + +julia> ndigits(1022, 16) +3 + +julia> base(16, 1022) +"3fe" +``` """ ndigits(x::Integer, b::Integer) = b >= 0 ? ndigits(unsigned(abs(x)),Int(b)) : ndigitsnb(x, b) ndigits(x::Integer) = ndigits(unsigned(abs(x))) @@ -601,6 +662,14 @@ end binomial(n,k) Number of ways to choose `k` out of `n` items. + +```jldoctest +julia> binomial(5, 3) +10 + +julia> factorial(5) ÷ (factorial(5-3) * factorial(3)) +10 +``` """ function binomial(n::T, k::T) where T<:Integer k < 0 && return zero(T) diff --git a/base/number.jl b/base/number.jl index c7f2286465629..75abda083a87c 100644 --- a/base/number.jl +++ b/base/number.jl @@ -85,6 +85,11 @@ abs(x::Real) = ifelse(signbit(x), -x, x) abs2(x) Squared absolute value of `x`. + +```jldoctest +julia> abs2(-3) +9 +``` """ abs2(x::Real) = x*x @@ -92,6 +97,14 @@ abs2(x::Real) = x*x flipsign(x, y) Return `x` with its sign flipped if `y` is negative. For example `abs(x) = flipsign(x,x)`. + +```jldoctest +julia> flipsign(5, 3) +5 + +julia> flipsign(5, -3) +-5 +``` """ flipsign(x::Real, y::Real) = ifelse(signbit(y), -x, x) copysign(x::Real, y::Real) = ifelse(signbit(x)!=signbit(y), -x, x) @@ -126,6 +139,19 @@ map(f, x::Number, ys::Number...) = f(x, ys...) zero(x) Get the additive identity element for the type of `x` (`x` can also specify the type itself). + +```jldoctest +julia> zero(1) +0 + +julia> zero(big"2.0") +0.000000000000000000000000000000000000000000000000000000000000000000000000000000 + +julia> zero(rand(2,2)) +2×2 Array{Float64,2}: + 0.0 0.0 + 0.0 0.0 +``` """ zero(x::Number) = oftype(x,0) zero(::Type{T}) where {T<:Number} = convert(T,0) diff --git a/base/permuteddimsarray.jl b/base/permuteddimsarray.jl index c51b8cb34caff..8236a781f39c6 100644 --- a/base/permuteddimsarray.jl +++ b/base/permuteddimsarray.jl @@ -124,6 +124,8 @@ vector specifying a permutation of length `ndims(src)`. The preallocated array ` have `size(dest) == size(src)[perm]` and is completely overwritten. No in-place permutation is supported and unexpected results will happen if `src` and `dest` have overlapping memory regions. + +See also [`permutedims`](@ref) """ function Base.permutedims!(dest, src::AbstractArray, perm) Base.checkdims_perm(dest, src, perm) From 34e485c591cbbabd2c1a0cda8f4127cb007613c2 Mon Sep 17 00:00:00 2001 From: mtfishman Date: Thu, 29 Jun 2017 12:04:59 -0700 Subject: [PATCH 16/88] Extend definition of StridedReshapedArray (#22429) * Extend definition of StridedReshapedArray * Add test (cherry picked from commit 92ff1bc2e3b6c07e7684a54d8d24c282a8f51fbb) --- base/sysimg.jl | 2 +- test/arrayops.jl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/base/sysimg.jl b/base/sysimg.jl index acfb4c7b68ee4..0f7b163990718 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -144,7 +144,7 @@ using .Iterators: zip, enumerate using .Iterators: Flatten, product # for generators # Definition of StridedArray -StridedReshapedArray{T,N,A<:DenseArray} = ReshapedArray{T,N,A} +StridedReshapedArray{T,N,A<:Union{DenseArray,FastContiguousSubArray}} = ReshapedArray{T,N,A} StridedArray{T,N,A<:Union{DenseArray,StridedReshapedArray}, I<:Tuple{Vararg{Union{RangeIndex, AbstractCartesianIndex}}}} = Union{DenseArray{T,N}, SubArray{T,N,A,I}, StridedReshapedArray{T,N}} diff --git a/test/arrayops.jl b/test/arrayops.jl index a275f6aef0540..d9fd754199edc 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -107,6 +107,7 @@ end @test_throws MethodError convert(Array{Int,2}, r) @test convert(Array{Int}, r) == [2,3,4] @test Base.unsafe_convert(Ptr{Int}, r) == Base.unsafe_convert(Ptr{Int}, s) + @test isa(r, StridedArray) # issue #22411 end @testset "linearslow" begin s = view(a, :, [2,3,5]) From 2389523c52dd8a67096c6318bd8b270b5ed0fcb7 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 24 Jun 2017 09:01:41 -0700 Subject: [PATCH 17/88] update docs for sysimg to show that default_sysimg_path is a function (#22449) (cherry picked from commit 3808de924404b44c1c2b8fa00b370e6f9989034f) --- contrib/build_sysimg.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/build_sysimg.jl b/contrib/build_sysimg.jl index 8c08248f5a767..7ca643f9204b5 100644 --- a/contrib/build_sysimg.jl +++ b/contrib/build_sysimg.jl @@ -13,7 +13,7 @@ function default_sysimg_path(debug=false) end """ - build_sysimg(sysimg_path=default_sysimg_path, cpu_target="native", userimg_path=nothing; force=false) + build_sysimg(sysimg_path=default_sysimg_path(), cpu_target="native", userimg_path=nothing; force=false) Rebuild the system image. Store it in `sysimg_path`, which defaults to a file named `sys.ji` that sits in the same folder as `libjulia.{so,dylib}`, except on Windows where it defaults From 96ddec8f4bad8860a710ac14018d981d1688566f Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Wed, 21 Jun 2017 15:37:39 +0200 Subject: [PATCH 18/88] add missing method for eigvecs(A::HermOrSym) (#22453) (cherry picked from commit 15ee73a4d0b6ee964d6ca75217d2e6ea2470b14f) --- base/linalg/symmetric.jl | 2 ++ test/linalg/symmetric.jl | 1 + 2 files changed, 3 insertions(+) diff --git a/base/linalg/symmetric.jl b/base/linalg/symmetric.jl index 6d9c865edca32..7db6d98be6610 100644 --- a/base/linalg/symmetric.jl +++ b/base/linalg/symmetric.jl @@ -448,6 +448,8 @@ eigvals!(A::HermOrSym{T,S}, B::HermOrSym{T,S}) where {T<:BlasReal,S<:StridedMatr eigvals!(A::Hermitian{T,S}, B::Hermitian{T,S}) where {T<:BlasComplex,S<:StridedMatrix} = LAPACK.sygvd!(1, 'N', A.uplo, A.data, B.uplo == A.uplo ? B.data : B.data')[1] +eigvecs(A::HermOrSym) = eigvecs(eigfact(A)) + function svdvals!(A::RealHermSymComplexHerm) vals = eigvals!(A) for i = 1:length(vals) diff --git a/test/linalg/symmetric.jl b/test/linalg/symmetric.jl index ac43ea7a5420b..e5a6498a81e13 100644 --- a/test/linalg/symmetric.jl +++ b/test/linalg/symmetric.jl @@ -119,6 +119,7 @@ let n=10 @test eigvals(Hermitian(asym), 1:2) ≈ d[1:2] @test eigvals(Hermitian(asym), d[1] - 1, (d[2] + d[3])/2) ≈ d[1:2] @test full(eigfact(asym)) ≈ asym + @test eigvecs(Hermitian(asym)) ≈ eigvecs(asym) # relation to svdvals @test sum(sort(abs.(eigvals(Hermitian(asym))))) == sum(sort(svdvals(Hermitian(asym)))) From 464079a84674e444fac98c591f9f123cb50bbcdf Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 20 Jun 2017 21:52:57 -0700 Subject: [PATCH 19/88] fix homedir error handling for 1020+ character usernames or 250 characters for a certain broken OS Ref #22457 (cherry picked from commit 8c1adc82f8ab17bd26612428984c4c9c135a8550) --- base/path.jl | 2 +- test/path.jl | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/base/path.jl b/base/path.jl index 28ac0b520e85d..940ae4cd2d6e0 100644 --- a/base/path.jl +++ b/base/path.jl @@ -68,7 +68,7 @@ function homedir() if rc == 0 resize!(buf, sz[]) return String(buf) - elseif rc == UV_ENOBUFS + elseif rc == Base.UV_ENOBUFS resize!(buf, sz[] - 1) else error("unable to retrieve home directory") diff --git a/test/path.jl b/test/path.jl index a2444e7810681..e02176c33945f 100644 --- a/test/path.jl +++ b/test/path.jl @@ -197,3 +197,15 @@ test_relpath() # Test type stability @test isa(joinpath("a", "b"), String) @test isa(joinpath(abspath("a"), "b"), String) + +# homedir +let var = is_windows() ? "USERPROFILE" : "HOME", + MAX_PATH = is_windows() ? 240 : 1020 + for i = 0:9 + local home = " "^MAX_PATH * "123456789"[1:i] + @test withenv(var => home) do + homedir() + end == home + end + @test isabspath(withenv(homedir, var => nothing)) +end From e205c0f566c8d3b63db90ad2813236357aef88e9 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Sat, 24 Jun 2017 13:50:40 -0400 Subject: [PATCH 20/88] optimize repeat(string, n) for repeating single ASCII chars (#22462) (cherry picked from commit b1c2d7357ab1cd4129c5a9049c17be0377276540) --- base/strings/string.jl | 8 ++++++-- test/strings/basic.jl | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/base/strings/string.jl b/base/strings/string.jl index a78f2372e77e2..34eb44cece4c6 100644 --- a/base/strings/string.jl +++ b/base/strings/string.jl @@ -427,8 +427,12 @@ function repeat(s::String, r::Integer) r < 0 && throw(ArgumentError("can't repeat a string $r times")) n = s.len out = _string_n(n*r) - for i=1:r - unsafe_copy!(pointer(out, 1+(i-1)*n), pointer(s), n) + if n == 1 # common case: repeating a single ASCII char + ccall(:memset, Ptr{Void}, (Ptr{UInt8}, Cint, Csize_t), out, unsafe_load(pointer(s)), r) + else + for i=1:r + unsafe_copy!(pointer(out, 1+(i-1)*n), pointer(s), n) + end end return out end diff --git a/test/strings/basic.jl b/test/strings/basic.jl index b45b6757d80af..36737bb027499 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -461,6 +461,10 @@ Base.endof(x::CharStr) = endof(x.chars) @test cmp("\U1f596\U1f596", CharStr("\U1f596")) == 1 # Gives BoundsError with bug @test cmp(CharStr("\U1f596"), "\U1f596\U1f596") == -1 +# repeat function +@test repeat("xx",3) == repeat("x",6) == "xxxxxx" +@test repeat("αα",3) == repeat("α",6) == "αααααα" + # issue #12495: check that logical indexing attempt raises ArgumentError @test_throws ArgumentError "abc"[[true, false, true]] @test_throws ArgumentError "abc"[BitArray([true, false, true])] From 21dcfec061746bfe8933c92b0d1759d47e988c55 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Sun, 25 Jun 2017 00:20:16 +0200 Subject: [PATCH 21/88] fix matrix multiplication interaction with HermOrSym and Diagonal (#22474) (cherry picked from commit 0990d9beaee7cda528defff8bdadf75c578132f2) --- base/linalg/diagonal.jl | 4 ++-- test/linalg/diagonal.jl | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/base/linalg/diagonal.jl b/base/linalg/diagonal.jl index a94414d2c3ddb..def3471397f94 100644 --- a/base/linalg/diagonal.jl +++ b/base/linalg/diagonal.jl @@ -150,9 +150,9 @@ end (*)(D::Diagonal, B::AbstractTriangular) = A_mul_B!(D, copy(B)) (*)(A::AbstractMatrix, D::Diagonal) = - scale!(similar(A, promote_op(*, eltype(A), eltype(D.diag))), A, D.diag) + scale!(similar(A, promote_op(*, eltype(A), eltype(D.diag)), size(A)), A, D.diag) (*)(D::Diagonal, A::AbstractMatrix) = - scale!(similar(A, promote_op(*, eltype(A), eltype(D.diag))), D.diag, A) + scale!(similar(A, promote_op(*, eltype(A), eltype(D.diag)), size(A)), D.diag, A) A_mul_B!(A::Union{LowerTriangular,UpperTriangular}, D::Diagonal) = typeof(A)(A_mul_B!(A.data, D)) diff --git a/test/linalg/diagonal.jl b/test/linalg/diagonal.jl index 6c2f8b2977bcb..562070e6d7d35 100644 --- a/test/linalg/diagonal.jl +++ b/test/linalg/diagonal.jl @@ -346,3 +346,25 @@ end @test logm(D) == Diagonal([logm([1 2; 3 4]), logm([1 2; 3 4])]) @test sqrtm(D) == Diagonal([sqrtm([1 2; 3 4]), sqrtm([1 2; 3 4])]) end + +@testset "multiplication with Symmetric/Hermitian" begin + for T in (Float64, Complex128) + if T <: Complex + R = Float64 + D = Diagonal(complex.(randn(R, n), randn(R, n))) + A = complex.(randn(R, n, n), randn(R, n, n)) + else + D = Diagonal(randn(T, n)) + A = randn(T, n, n) + end + A = A'A + S = Symmetric(A) + H = Hermitian(A) + for f in (*, Ac_mul_B, A_mul_Bc, Ac_mul_Bc, At_mul_B, A_mul_Bt, At_mul_Bt) + @test f(D, S) ≈ f(Matrix(D), Matrix(S)) + @test f(D, H) ≈ f(Matrix(D), Matrix(H)) + @test f(S, D) ≈ f(Matrix(S), Matrix(D)) + @test f(S, H) ≈ f(Matrix(S), Matrix(H)) + end + end +end From cdb53359d8064441c051be2ac5735e391945c2f1 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Sat, 24 Jun 2017 07:44:08 +0200 Subject: [PATCH 22/88] document Upper/LowerTriangular and clarify that Symmetric/Hermitian are views as well add references to Upper/LowerTriangular in the manual Ref #22504 (cherry picked from commit c964958260f6c0dd1baa51bc4bf66ffcfe93c135) --- base/linalg/cholesky.jl | 2 +- base/linalg/symmetric.jl | 6 ++-- base/linalg/triangular.jl | 45 +++++++++++++++++++++++++ doc/src/manual/linear-algebra.md | 58 ++++++++++++++++---------------- doc/src/stdlib/linalg.md | 2 ++ 5 files changed, 81 insertions(+), 32 deletions(-) diff --git a/base/linalg/cholesky.jl b/base/linalg/cholesky.jl index 5ba08622ded9c..4629fb9341aec 100644 --- a/base/linalg/cholesky.jl +++ b/base/linalg/cholesky.jl @@ -160,7 +160,7 @@ end chol(A) -> U Compute the Cholesky factorization of a positive definite matrix `A` -and return the UpperTriangular matrix `U` such that `A = U'U`. +and return the [`UpperTriangular`](@ref) matrix `U` such that `A = U'U`. # Example diff --git a/base/linalg/symmetric.jl b/base/linalg/symmetric.jl index 7db6d98be6610..c101d6ae65763 100644 --- a/base/linalg/symmetric.jl +++ b/base/linalg/symmetric.jl @@ -8,7 +8,8 @@ end """ Symmetric(A, uplo=:U) -Construct a `Symmetric` matrix from the upper (if `uplo = :U`) or lower (if `uplo = :L`) triangle of `A`. +Construct a `Symmetric` view of the upper (if `uplo = :U`) or lower (if `uplo = :L`) +triangle of the matrix `A`. # Example @@ -57,7 +58,8 @@ end """ Hermitian(A, uplo=:U) -Construct a `Hermitian` matrix from the upper (if `uplo = :U`) or lower (if `uplo = :L`) triangle of `A`. +Construct a `Hermitian` view of the upper (if `uplo = :U`) or lower (if `uplo = :L`) +triangle of the matrix `A`. # Example diff --git a/base/linalg/triangular.jl b/base/linalg/triangular.jl index a9935851177cc..8c95da6f19839 100644 --- a/base/linalg/triangular.jl +++ b/base/linalg/triangular.jl @@ -50,6 +50,51 @@ LowerTriangular(U::UpperTriangular) = throw(ArgumentError( UpperTriangular(U::LowerTriangular) = throw(ArgumentError( "cannot create an UpperTriangular matrix from a LowerTriangular input")) +""" + LowerTriangular(A::AbstractMatrix) + +Construct a `LowerTriangular` view of the the matrix `A`. + +# Example + +```jldoctest +julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0] +3×3 Array{Float64,2}: + 1.0 2.0 3.0 + 4.0 5.0 6.0 + 7.0 8.0 9.0 + +julia> LowerTriangular(A) +3×3 LowerTriangular{Float64,Array{Float64,2}}: + 1.0 ⋅ ⋅ + 4.0 5.0 ⋅ + 7.0 8.0 9.0 +``` +""" +LowerTriangular +""" + UpperTriangular(A::AbstractMatrix) + +Construct an `UpperTriangular` view of the the matrix `A`. + +# Example + +```jldoctest +julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0] +3×3 Array{Float64,2}: + 1.0 2.0 3.0 + 4.0 5.0 6.0 + 7.0 8.0 9.0 + +julia> UpperTriangular(A) +3×3 UpperTriangular{Float64,Array{Float64,2}}: + 1.0 2.0 3.0 + ⋅ 5.0 6.0 + ⋅ ⋅ 9.0 +``` +""" +UpperTriangular + imag(A::UpperTriangular) = UpperTriangular(imag(A.data)) imag(A::LowerTriangular) = LowerTriangular(imag(A.data)) imag(A::UnitLowerTriangular) = LowerTriangular(tril!(imag(A.data),-1)) diff --git a/doc/src/manual/linear-algebra.md b/doc/src/manual/linear-algebra.md index af5ff9a2766f4..16ba1b10fb70c 100644 --- a/doc/src/manual/linear-algebra.md +++ b/doc/src/manual/linear-algebra.md @@ -144,29 +144,29 @@ specialized routines that are specially developed for particular matrix types. The following tables summarize the types of special matrices that have been implemented in Julia, as well as whether hooks to various optimized methods for them in LAPACK are available. -| Type | Description | -|:------------------------ |:-------------------------------------------------------------------------------- | -| [`Hermitian`](@ref) | [Hermitian matrix](https://en.wikipedia.org/wiki/Hermitian_matrix) | -| `UpperTriangular` | Upper [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) | -| `LowerTriangular` | Lower [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) | -| [`Tridiagonal`](@ref) | [Tridiagonal matrix](https://en.wikipedia.org/wiki/Tridiagonal_matrix) | -| [`SymTridiagonal`](@ref) | Symmetric tridiagonal matrix | -| [`Bidiagonal`](@ref) | Upper/lower [bidiagonal matrix](https://en.wikipedia.org/wiki/Bidiagonal_matrix) | -| [`Diagonal`](@ref) | [Diagonal matrix](https://en.wikipedia.org/wiki/Diagonal_matrix) | -| `UniformScaling` | [Uniform scaling operator](https://en.wikipedia.org/wiki/Uniform_scaling) | +| Type | Description | +|:------------------------- |:-------------------------------------------------------------------------------- | +| [`Hermitian`](@ref) | [Hermitian matrix](https://en.wikipedia.org/wiki/Hermitian_matrix) | +| [`UpperTriangular`](@ref) | Upper [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) | +| [`LowerTriangular`](@ref) | Lower [triangular matrix](https://en.wikipedia.org/wiki/Triangular_matrix) | +| [`Tridiagonal`](@ref) | [Tridiagonal matrix](https://en.wikipedia.org/wiki/Tridiagonal_matrix) | +| [`SymTridiagonal`](@ref) | Symmetric tridiagonal matrix | +| [`Bidiagonal`](@ref) | Upper/lower [bidiagonal matrix](https://en.wikipedia.org/wiki/Bidiagonal_matrix) | +| [`Diagonal`](@ref) | [Diagonal matrix](https://en.wikipedia.org/wiki/Diagonal_matrix) | +| `UniformScaling` | [Uniform scaling operator](https://en.wikipedia.org/wiki/Uniform_scaling) | ### Elementary operations -| Matrix type | `+` | `-` | `*` | `\` | Other functions with optimized methods | -|:------------------------ |:--- |:--- |:--- |:--- |:------------------------------------------------------------------- | -| [`Hermitian`](@ref) |   |   |   | MV | [`inv()`](@ref), [`sqrtm()`](@ref), [`expm()`](@ref) | -| `UpperTriangular` |   |   | MV | MV | [`inv()`](@ref), [`det()`](@ref) | -| `LowerTriangular` |   |   | MV | MV | [`inv()`](@ref), [`det()`](@ref) | -| [`SymTridiagonal`](@ref) | M | M | MS | MV | [`eigmax()`](@ref), [`eigmin()`](@ref) | -| [`Tridiagonal`](@ref) | M | M | MS | MV |   | -| [`Bidiagonal`](@ref) | M | M | MS | MV |   | -| [`Diagonal`](@ref) | M | M | MV | MV | [`inv()`](@ref), [`det()`](@ref), [`logdet()`](@ref), [`/()`](@ref) | -| `UniformScaling` | M | M | MVS | MVS | [`/()`](@ref) | +| Matrix type | `+` | `-` | `*` | `\` | Other functions with optimized methods | +|:------------------------- |:--- |:--- |:--- |:--- |:------------------------------------------------------------------- | +| [`Hermitian`](@ref) |   |   |   | MV | [`inv()`](@ref), [`sqrtm()`](@ref), [`expm()`](@ref) | +| [`UpperTriangular`](@ref) |   |   | MV | MV | [`inv()`](@ref), [`det()`](@ref) | +| [`LowerTriangular`](@ref) |   |   | MV | MV | [`inv()`](@ref), [`det()`](@ref) | +| [`SymTridiagonal`](@ref) | M | M | MS | MV | [`eigmax()`](@ref), [`eigmin()`](@ref) | +| [`Tridiagonal`](@ref) | M | M | MS | MV |   | +| [`Bidiagonal`](@ref) | M | M | MS | MV |   | +| [`Diagonal`](@ref) | M | M | MV | MV | [`inv()`](@ref), [`det()`](@ref), [`logdet()`](@ref), [`/()`](@ref) | +| `UniformScaling` | M | M | MVS | MVS | [`/()`](@ref) | Legend: @@ -178,15 +178,15 @@ Legend: ### Matrix factorizations -| Matrix type | LAPACK | [`eig()`](@ref) | [`eigvals()`](@ref) | [`eigvecs()`](@ref) | [`svd()`](@ref) | [`svdvals()`](@ref) | -|:------------------------ |:------ |:--------------- |:------------------- |:------------------- |:--------------- |:------------------- | -| [`Hermitian`](@ref) | HE |   | ARI |   |   |   | -| `UpperTriangular` | TR | A | A | A |   |   | -| `LowerTriangular` | TR | A | A | A |   |   | -| [`SymTridiagonal`](@ref) | ST | A | ARI | AV |   |   | -| [`Tridiagonal`](@ref) | GT |   |   |   |   |   | -| [`Bidiagonal`](@ref) | BD |   |   |   | A | A | -| [`Diagonal`](@ref) | DI |   | A |   |   |   | +| Matrix type | LAPACK | [`eig()`](@ref) | [`eigvals()`](@ref) | [`eigvecs()`](@ref) | [`svd()`](@ref) | [`svdvals()`](@ref) | +|:------------------------- |:------ |:--------------- |:------------------- |:------------------- |:--------------- |:------------------- | +| [`Hermitian`](@ref) | HE |   | ARI |   |   |   | +| [`UpperTriangular`](@ref) | TR | A | A | A |   |   | +| [`LowerTriangular`](@ref) | TR | A | A | A |   |   | +| [`SymTridiagonal`](@ref) | ST | A | ARI | AV |   |   | +| [`Tridiagonal`](@ref) | GT |   |   |   |   |   | +| [`Bidiagonal`](@ref) | BD |   |   |   | A | A | +| [`Diagonal`](@ref) | DI |   | A |   |   |   | Legend: diff --git a/doc/src/stdlib/linalg.md b/doc/src/stdlib/linalg.md index 66dde6330d3e8..3e90cb5b2cafe 100644 --- a/doc/src/stdlib/linalg.md +++ b/doc/src/stdlib/linalg.md @@ -18,6 +18,8 @@ Base.LinAlg.SymTridiagonal Base.LinAlg.Tridiagonal Base.LinAlg.Symmetric Base.LinAlg.Hermitian +Base.LinAlg.LowerTriangular +Base.LinAlg.UpperTriangular Base.LinAlg.lu Base.LinAlg.lufact Base.LinAlg.lufact! From 7bbc17cb5d89ae472a75358889742276c0bb4960 Mon Sep 17 00:00:00 2001 From: Katharine Hyatt Date: Mon, 26 Jun 2017 20:56:41 -0500 Subject: [PATCH 23/88] More doctests and cleanup for intfuncs (#22515) * More doctests and cleanup for intfuncs * Also more doctests for arrays * More doctests and Example{s} inserting * Doctests for DAYS * Fix some failing doctests * "fix" failing OffsetArray test * Address more comments * fix dropstored! * Fix leading space * fix typo (cherry picked from commit de746144cfe76de27b08874b4e37da2f8d10935f) --- base/abstractarray.jl | 6 +- base/abstractarraymath.jl | 7 + base/array.jl | 102 +++++++- base/arraymath.jl | 7 + base/bitarray.jl | 3 + base/combinatorics.jl | 9 +- base/docs/helpdb/Base.jl | 280 ++++++++++++++++++++-- base/essentials.jl | 2 +- base/intfuncs.jl | 129 +++++++++- base/linalg/eigen.jl | 4 +- base/linalg/generic.jl | 29 ++- base/multidimensional.jl | 46 +++- base/permuteddimsarray.jl | 3 +- base/random.jl | 197 ++++++++++++++- base/reducedim.jl | 15 ++ base/sort.jl | 11 + base/sparse/sparsematrix.jl | 92 ++++++- base/sparse/sparsevector.jl | 16 ++ doc/src/manual/faq.md | 4 +- doc/src/manual/mathematical-operations.md | 6 +- doc/src/manual/types.md | 2 +- 21 files changed, 917 insertions(+), 53 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index e2e5749998e36..6360769c785c5 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -801,7 +801,7 @@ A[iter] = 0 If you supply more than one `AbstractArray` argument, `eachindex` will create an iterable object that is fast for all arguments (a `UnitRange` -if all inputs have fast linear indexing, a `CartesianRange` +if all inputs have fast linear indexing, a [`CartesianRange`](@ref) otherwise). If the arrays have different sizes and/or dimensionalities, `eachindex` returns an iterable that spans the largest range along each dimension. @@ -1718,6 +1718,7 @@ For multiple iterable arguments, `f` is called elementwise. `foreach` should be used instead of `map` when the results of `f` are not needed, for example in `foreach(println, array)`. +# Example ```jldoctest julia> a = 1:3:7; @@ -1745,6 +1746,7 @@ colons go in this expression. The results are concatenated along the remaining d For example, if `dims` is `[1,2]` and `A` is 4-dimensional, `f` is called on `A[:,:,i,j]` for all `i` and `j`. +# Examples ```jldoctest julia> a = reshape(collect(1:16),(2,2,2,2)) 2×2×2×2 Array{Int64,4}: @@ -1871,6 +1873,7 @@ map(f, A::Union{AbstractArray,AbstractSet,Associative}) = collect_similar(A, Gen Transform collection `c` by applying `f` to each element. For multiple collection arguments, apply `f` elementwise. +# Examples ```jldoctest julia> map(x -> x * 2, [1, 2, 3]) 3-element Array{Int64,1}: @@ -1913,6 +1916,7 @@ end Like [`map`](@ref), but stores the result in `destination` rather than a new collection. `destination` must be at least as large as the first collection. +# Example ```jldoctest julia> x = zeros(3); diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 058170e3d5041..0430293b46737 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -16,6 +16,7 @@ Reshape the array `a` as a one-dimensional column vector. The resulting array shares the same underlying data as `a`, so modifying one will also modify the other. +# Example ```jldoctest julia> a = [1 2 3; 4 5 6] 2×3 Array{Int64,2}: @@ -48,6 +49,7 @@ Remove the dimensions specified by `dims` from array `A`. Elements of `dims` must be unique and within the range `1:ndims(A)`. `size(A,i)` must equal 1 for all `i` in `dims`. +# Example ```jldoctest julia> a = reshape(collect(1:4),(2,2,1,1)) 2×2×1×1 Array{Int64,4}: @@ -101,6 +103,7 @@ imag(x::AbstractArray{<:Real}) = zero(x) Return all the data of `A` where the index for dimension `d` equals `i`. Equivalent to `A[:,:,...,i,:,:,...]` where `i` is in position `d`. +# Example ```jldoctest julia> A = [1 2 3 4; 5 6 7 8] 2×4 Array{Int64,2}: @@ -125,6 +128,7 @@ end Reverse `A` in dimension `d`. +# Example ```jldoctest julia> b = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -177,6 +181,7 @@ circshift(a::AbstractArray, shiftamt::DimsInteger) = circshift!(similar(a), a, s Circularly shift the data in an array. The second argument is a vector giving the amount to shift in each dimension. +# Example ```jldoctest julia> b = reshape(collect(1:16), (4,4)) 4×4 Array{Int64,2}: @@ -281,6 +286,7 @@ end Construct a matrix by repeating the given matrix (or vector) `m` times in dimension 1 and `n` times in dimension 2. +# Examples ```jldoctest julia> repmat([1, 2, 3], 2) 6-element Array{Int64,1}: @@ -337,6 +343,7 @@ repeated. The i-th element of `outer` specifies the number of times that a slice i-th dimension of `A` should be repeated. If `inner` or `outer` are omitted, no repetition is performed. +# Examples ```jldoctest julia> repeat(1:2, inner=2) 4-element Array{Int64,1}: diff --git a/base/array.jl b/base/array.jl index 2fe19b8f50f3f..633dfed5c1469 100644 --- a/base/array.jl +++ b/base/array.jl @@ -272,6 +272,26 @@ end `m`-by-`n` identity matrix. The default element type is [`Float64`](@ref). + +# Examples + +```jldoctest +julia> eye(3, 4) +3×4 Array{Float64,2}: + 1.0 0.0 0.0 0.0 + 0.0 1.0 0.0 0.0 + 0.0 0.0 1.0 0.0 + +julia> eye(2, 2) +2×2 Array{Float64,2}: + 1.0 0.0 + 0.0 1.0 + +julia> eye(Int, 2, 2) +2×2 Array{Int64,2}: + 1 0 + 0 1 +``` """ function eye(::Type{T}, m::Integer, n::Integer) where T a = zeros(T,m,n) @@ -293,6 +313,19 @@ eye(::Type{T}, n::Integer) where {T} = eye(T, n, n) `n`-by-`n` identity matrix. The default element type is [`Float64`](@ref). + +# Examples +```jldoctest +julia> eye(Int, 2) +2×2 Array{Int64,2}: + 1 0 + 0 1 + +julia> eye(2) +2×2 Array{Float64,2}: + 1.0 0.0 + 0.0 1.0 +``` """ eye(n::Integer) = eye(Float64, n) @@ -382,6 +415,7 @@ Return an `Array` of all items in a collection or iterator. For associative coll `Pair{KeyType, ValType}`. If the argument is array-like or is an iterator with the `HasShape()` trait, the result will have the same shape and number of dimensions as the argument. +# Example ```jldoctest julia> collect(1:2:13) 7-element Array{Int64,1}: @@ -658,6 +692,7 @@ end Insert the elements of `items` to the beginning of `a`. +# Example ```jldoctest julia> prepend!([3],[1,2]) 3-element Array{Int64,1}: @@ -710,25 +745,27 @@ Resize `a` to contain `n` elements. If `n` is smaller than the current collectio length, the first `n` elements will be retained. If `n` is larger, the new elements are not guaranteed to be initialized. +# Examples ```jldoctest julia> resize!([6, 5, 4, 3, 2, 1], 3) 3-element Array{Int64,1}: 6 5 4 -``` -```julia-repl -julia> resize!([6, 5, 4, 3, 2, 1], 8) -8-element Array{Int64,1}: +julia> a = resize!([6, 5, 4, 3, 2, 1], 8); + +julia> length(a) +8 + +julia> a[1:6] +6-element Array{Int64,1}: 6 5 4 3 2 1 - 0 - 0 ``` """ function resize!(a::Vector, nl::Integer) @@ -763,6 +800,7 @@ end Insert one or more `items` at the beginning of `collection`. +# Example ```jldoctest julia> unshift!([1, 2, 3, 4], 5, 6) 6-element Array{Int64,1}: @@ -796,6 +834,7 @@ end Insert an `item` into `a` at the given `index`. `index` is the index of `item` in the resulting `a`. +# Example ```jldoctest julia> insert!([6, 5, 4, 2, 1], 4, 3) 6-element Array{Int64,1}: @@ -822,6 +861,7 @@ end Remove the item at the given `i` and return the modified `a`. Subsequent items are shifted to fill the resulting gap. +# Example ```jldoctest julia> deleteat!([6, 5, 4, 3, 2, 1], 2) 5-element Array{Int64,1}: @@ -849,6 +889,7 @@ Subsequent items are shifted to fill the resulting gap. `inds` can be either an iterator or a collection of sorted and unique integer indices, or a boolean vector of the same length as `a` with `true` indicating entries to delete. +# Examples ```jldoctest julia> deleteat!([6, 5, 4, 3, 2, 1], 1:2:5) 3-element Array{Int64,1}: @@ -865,8 +906,8 @@ julia> deleteat!([6, 5, 4, 3, 2, 1], [true, false, true, false, true, false]) julia> deleteat!([6, 5, 4, 3, 2, 1], (2, 2)) ERROR: ArgumentError: indices must be unique and sorted Stacktrace: - [1] _deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:885 - [2] deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:872 + [1] _deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:926 + [2] deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:913 ``` """ deleteat!(a::Vector, inds) = _deleteat!(a, inds) @@ -924,6 +965,7 @@ Subsequent items are shifted left to fill the resulting gap. If specified, replacement values from an ordered collection will be spliced in place of the removed item. +# Examples ```jldoctest splice! julia> A = [6, 5, 4, 3, 2, 1]; splice!(A, 5) 2 @@ -994,6 +1036,7 @@ place of the removed items. To insert `replacement` before an index `n` without removing any items, use `splice!(collection, n:n-1, replacement)`. +# Example ```jldoctest splice! julia> splice!(A, 4:3, 2) 0-element Array{Int64,1} @@ -1150,6 +1193,7 @@ cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(x->1, n-1)..., length(x Find the next linear index >= `i` of a non-zero element of `A`, or `0` if not found. +# Examples ```jldoctest julia> A = [0 0; 1 0] 2×2 Array{Int64,2}: @@ -1178,6 +1222,7 @@ end Return the linear index of the first non-zero value in `A` (determined by `A[i]!=0`). Returns `0` if no such value is found. +# Examples ```jldoctest julia> A = [0 0; 1 0] 2×2 Array{Int64,2}: @@ -1186,6 +1231,9 @@ julia> A = [0 0; 1 0] julia> findfirst(A) 2 + +julia> findfirst(zeros(3)) +0 ``` """ findfirst(A) = findnext(A, 1) @@ -1195,6 +1243,7 @@ findfirst(A) = findnext(A, 1) Find the next linear index >= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found. +# Examples ```jldoctest julia> A = [1 4; 2 2] 2×2 Array{Int64,2}: @@ -1222,6 +1271,7 @@ end Return the linear index of the first element equal to `v` in `A`. Returns `0` if `v` is not found. +# Examples ```jldoctest julia> A = [4 6; 2 2] 2×2 Array{Int64,2}: @@ -1242,6 +1292,7 @@ findfirst(A, v) = findnext(A, v, 1) Find the next linear index >= `i` of an element of `A` for which `predicate` returns `true`, or `0` if not found. +# Examples ```jldoctest julia> A = [1 4; 2 2] 2×2 Array{Int64,2}: @@ -1270,6 +1321,7 @@ end Return the linear index of the first element of `A` for which `predicate` returns `true`. Returns `0` if there is no such element. +# Examples ```jldoctest julia> A = [1 4; 2 2] 2×2 Array{Int64,2}: @@ -1290,6 +1342,7 @@ findfirst(testf::Function, A) = findnext(testf, A, 1) Find the previous linear index <= `i` of a non-zero element of `A`, or `0` if not found. +# Examples ```jldoctest julia> A = [0 0; 1 2] 2×2 Array{Int64,2}: @@ -1316,6 +1369,7 @@ end Return the linear index of the last non-zero value in `A` (determined by `A[i]!=0`). Returns `0` if there is no non-zero value in `A`. +# Examples ```jldoctest julia> A = [1 0; 1 0] 2×2 Array{Int64,2}: @@ -1341,6 +1395,7 @@ findlast(A) = findprev(A, length(A)) Find the previous linear index <= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found. +# Examples ```jldoctest julia> A = [0 0; 1 2] 2×2 Array{Int64,2}: @@ -1367,6 +1422,7 @@ end Return the linear index of the last element equal to `v` in `A`. Returns `0` if there is no element of `A` equal to `v`. +# Examples ```jldoctest julia> A = [1 2; 2 1] 2×2 Array{Int64,2}: @@ -1391,6 +1447,7 @@ findlast(A, v) = findprev(A, v, length(A)) Find the previous linear index <= `i` of an element of `A` for which `predicate` returns `true`, or `0` if not found. +# Examples ```jldoctest julia> A = [4 6; 1 2] 2×2 Array{Int64,2}: @@ -1417,6 +1474,7 @@ end Return the linear index of the last element of `A` for which `predicate` returns `true`. Returns `0` if there is no such element. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -1438,6 +1496,7 @@ findlast(testf::Function, A) = findprev(testf, A, length(A)) Return a vector `I` of the linear indexes of `A` where `f(A[I])` returns `true`. If there are no such elements of `A`, find returns an empty array. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -1448,6 +1507,9 @@ julia> find(isodd,A) 2-element Array{Int64,1}: 1 2 + +julia> find(isodd, [2, 4]) +0-element Array{Int64,1} ``` """ function find(testf::Function, A) @@ -1474,6 +1536,7 @@ Return a vector of the linear indexes of the non-zeros in `A` (determined by `A[ common use of this is to convert a boolean array to an array of indexes of the `true` elements. If there are no non-zero elements of `A`, `find` returns an empty array. +# Examples ```jldoctest julia> A = [true false; false true] 2×2 Array{Bool,2}: @@ -1484,6 +1547,9 @@ julia> find(A) 2-element Array{Int64,1}: 1 4 + +julia> find(zeros(3)) +0-element Array{Int64,1} ``` """ function find(A) @@ -1512,6 +1578,7 @@ Return a vector of indexes for each dimension giving the locations of the non-ze (determined by `A[i]!=0`). If there are no non-zero elements of `A`, `findn` returns a 2-tuple of empty arrays. +# Examples ```jldoctest julia> A = [1 2 0; 0 0 3; 0 4 0] 3×3 Array{Int64,2}: @@ -1552,6 +1619,7 @@ end Return a tuple `(I, J, V)` where `I` and `J` are the row and column indexes of the non-zero values in matrix `A`, and `V` is a vector of the non-zero values. +# Example ```jldoctest julia> A = [1 2 0; 0 0 3; 0 4 0] 3×3 Array{Int64,2}: @@ -1592,6 +1660,7 @@ all elements are `NaN`. The collection must not be empty. +# Examples ```jldoctest julia> findmax([8,0.1,-9,pi]) (8.0, 1) @@ -1630,6 +1699,7 @@ all elements are `NaN`. The collection must not be empty. +# Examples ```jldoctest julia> findmin([8,0.1,-9,pi]) (-9.0, 3) @@ -1668,6 +1738,7 @@ elements are `NaN`. The collection must not be empty. +# Examples ```jldoctest julia> indmax([8,0.1,-9,pi]) 1 @@ -1690,6 +1761,7 @@ elements are `NaN`. The collection must not be empty. +# Examples ```jldoctest julia> indmin([8,0.1,-9,pi]) 3 @@ -1711,6 +1783,7 @@ Returns a vector containing the highest index in `b` for each value in `a` that is a member of `b` . The output vector contains 0 wherever `a` is not a member of `b`. +# Examples ```jldoctest julia> a = ['a', 'b', 'c', 'b', 'd', 'a']; @@ -1742,6 +1815,7 @@ end Returns the indices of elements in collection `a` that appear in collection `b`. +# Examples ```jldoctest julia> a = collect(1:3:15) 5-element Array{Int64,1}: @@ -1803,6 +1877,7 @@ end Return a copy of `collection`, removing elements for which `function` is `false`. For associative collections, the function is passed two arguments (key and value). +# Examples ```jldocttest julia> a = 1:10 1:10 @@ -1814,6 +1889,15 @@ julia> filter(isodd, a) 5 7 9 + +julia> d = Dict(1=>"a", 2=>"b") +Dict{Int64,String} with 2 entries: + 2 => "b" + 1 => "a" + +julia> filter((x,y)->isodd(x), d) +Dict{Int64,String} with 1 entry: + 1 => "a" ``` """ filter(f, As::AbstractArray) = As[map(f, As)::AbstractArray{Bool}] @@ -1889,6 +1973,7 @@ both arguments must be collections, and both will be iterated over. In particula `setdiff(set,element)` where `element` is a potential member of `set`, will not work in general. +# Example ```jldoctest julia> setdiff([1,2,3],[3,4,5]) 2-element Array{Int64,1}: @@ -1922,6 +2007,7 @@ symdiff(a, b) = union(setdiff(a,b), setdiff(b,a)) Construct the symmetric difference of elements in the passed in sets or arrays. Maintains order with arrays. +# Example ```jldoctest julia> symdiff([1,2,3],[3,4,5],[4,5,6]) 3-element Array{Int64,1}: diff --git a/base/arraymath.jl b/base/arraymath.jl index 54ac4418c5e45..020dd9f736fbc 100644 --- a/base/arraymath.jl +++ b/base/arraymath.jl @@ -9,6 +9,7 @@ Transform an array to its complex conjugate in-place. See also [`conj`](@ref). +# Example ```jldoctest julia> A = [1+im 2-im; 2+2im 3+im] 2×2 Array{Complex{Int64},2}: @@ -116,6 +117,7 @@ end Rotate matrix `A` left 90 degrees. +# Example ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -143,6 +145,7 @@ end Rotate matrix `A` right 90 degrees. +# Example ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -169,6 +172,7 @@ end Rotate matrix `A` 180 degrees. +# Example ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -196,6 +200,7 @@ end Rotate matrix `A` left 90 degrees an integer `k` number of times. If `k` is zero or a multiple of four, this is equivalent to a `copy`. +# Examples ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -235,6 +240,7 @@ end Rotate matrix `A` right 90 degrees an integer `k` number of times. If `k` is zero or a multiple of four, this is equivalent to a `copy`. +# Examples ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -269,6 +275,7 @@ rotr90(A::AbstractMatrix, k::Integer) = rotl90(A,-k) Rotate matrix `A` 180 degrees an integer `k` number of times. If `k` is even, this is equivalent to a `copy`. +# Examples ```jldoctest julia> a = [1 2; 3 4] 2×2 Array{Int64,2}: diff --git a/base/bitarray.jl b/base/bitarray.jl index 261853f02aa1c..7fd2ba6b65a0f 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -1145,6 +1145,7 @@ end Performs a bitwise not operation on `B`. See [`~`](@ref). +# Example ```jldoctest julia> A = trues(2,2) 2×2 BitArray{2}: @@ -1497,6 +1498,7 @@ Performs a left rotation operation, returning a new `BitVector`. `i` controls how far to rotate the bits. See also [`rol!`](@ref). +# Examples ```jldoctest julia> A = BitArray([true, true, false, false, true]) 5-element BitArray{1}: @@ -1566,6 +1568,7 @@ Performs a right rotation operation on `B`, returning a new `BitVector`. `i` controls how far to rotate the bits. See also [`ror!`](@ref). +# Examples ```jldoctest julia> A = BitArray([true, true, false, false, true]) 5-element BitArray{1}: diff --git a/base/combinatorics.jl b/base/combinatorics.jl index 920f6c23d944e..7cf2eccbbaef8 100644 --- a/base/combinatorics.jl +++ b/base/combinatorics.jl @@ -61,6 +61,7 @@ end Returns `true` if `v` is a valid permutation. +# Examples ```jldoctest julia> isperm([1; 2]) true @@ -112,8 +113,9 @@ to verify that `p` is a permutation. To return a new permutation, use `v[p]`. Note that this is generally faster than `permute!(v,p)` for large vectors. -See also [`ipermute!`](@ref) +See also [`ipermute!`](@ref). +# Example ```jldoctest julia> A = [1, 1, 3, 4]; @@ -157,8 +159,9 @@ end """ ipermute!(v, p) -Like `permute!`, but the inverse of the given permutation is applied. +Like [`permute!`](@ref), but the inverse of the given permutation is applied. +# Example ```jldoctest julia> A = [1, 1, 3, 4]; @@ -182,6 +185,7 @@ ipermute!(a, p::AbstractVector) = ipermute!!(a, copymutable(p)) Return the inverse permutation of `v`. If `B = A[v]`, then `A == B[invperm(v)]`. +# Example ```jldoctest julia> v = [2; 4; 3; 1]; @@ -233,6 +237,7 @@ invperm(a::Tuple) = (invperm([a...])...,) Next integer greater than or equal to `n` that can be written as ``\\prod k_i^{p_i}`` for integers ``p_1``, ``p_2``, etc. +# Example ```jldoctest julia> nextprod([2, 3], 105) 108 diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 4f67be21924dc..22d05c4aefeb2 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -9,6 +9,7 @@ Fill array `A` with the value `x`. If `x` is an object reference, all elements w the same object. `fill!(A, Foo())` will return `A` filled with the result of evaluating `Foo()` once. +# Examples ```jldoctest julia> A = zeros(2,3) 2×3 Array{Float64,2}: @@ -81,6 +82,7 @@ Subtraction operator. A string giving the literal bit representation of a number. +# Example ```jldoctest julia> bits(4) "0000000000000000000000000000000000000000000000000000000000000100" @@ -97,6 +99,7 @@ bits Construct a 1-d array of the specified type. This is usually called with the syntax `Type[]`. Element values can be specified using `Type[a,b,c,...]`. +# Example ```jldoctest julia> Int8[1, 2, 3] 3-element Array{Int8,1}: @@ -120,6 +123,7 @@ Returns a subset of array `A` as specified by `inds`, where each `ind` may be an `Int`, a `Range`, or a `Vector`. See the manual section on [array indexing](@ref man-array-indexing) for details. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -149,6 +153,7 @@ getindex(::AbstractArray, inds...) Retrieve the value(s) stored at the given key or index within a collection. The syntax `a[i,j,...]` is converted by the compiler to `getindex(a, i, j, ...)`. +# Example ```jldoctest julia> A = Dict("a" => 1, "b" => 2) Dict{String,Int64} with 2 entries: @@ -219,6 +224,7 @@ unsafe_copy!(dest::Array, d, src::Array, so, N) Create a Float32 from `x`. If `x` is not exactly representable then `mode` determines how `x` is rounded. +# Examples ```jldoctest julia> Float32(1/3, RoundDown) 0.3333333f0 @@ -310,6 +316,7 @@ Mmap.mmap(io, ::BitArray, dims = ?, offset = ?) Update `collection`, removing elements for which `function` is `false`. For associative collections, the function is passed two arguments (key and value). +# Example ```jldoctest julia> filter!(isodd, collect(1:10)) 5-element Array{Int64,1}: @@ -327,6 +334,7 @@ filter! Size, in bytes, of the canonical binary representation of the given DataType `T`, if any. +# Examples ```jldoctest julia> sizeof(Float32) 4 @@ -341,7 +349,7 @@ If `T` does not have a specific size, an error is thrown. julia> sizeof(Base.LinAlg.LU) ERROR: argument is an abstract type; size is indeterminate Stacktrace: - [1] sizeof(::Type{T} where T) at ./essentials.jl:159 + [1] sizeof(::Type{T} where T) at ./essentials.jl:150 ``` """ sizeof(::Type) @@ -378,6 +386,7 @@ oftype Insert one or more `items` at the end of `collection`. +# Example ```jldoctest julia> push!([1, 2, 3], 4, 5, 6) 6-element Array{Int64,1}: @@ -399,6 +408,12 @@ push! promote(xs...) Convert all arguments to their common promotion type (if any), and return them all (as a tuple). + +# Example +```jldoctest +julia> promote(Int8(1), Float16(4.5), Float32(4.1)) +(1.0f0, 4.5f0, 4.1f0) +``` """ promote @@ -418,6 +433,7 @@ Create an array of all ones with the same layout as `A`, element type `T` and si The `A` argument can be skipped, which behaves like `Array{Float64,0}()` was passed. For convenience `dims` may also be passed in variadic form. +# Examples ```jldoctest julia> ones(Complex128, 2, 3) 2×3 Array{Complex{Float64},2}: @@ -483,6 +499,23 @@ Returns the range of indices of `a` which compare as equal to `x` (using binary according to the order specified by the `by`, `lt` and `rev` keywords, assuming that `a` is already sorted in that order. Returns an empty range located at the insertion point if `a` does not contain values equal to `x`. + +# Examples + +```jldoctest +julia> a = [4, 3, 2, 1] +4-element Array{Int64,1}: + 4 + 3 + 2 + 1 + +julia> searchsorted(a, 4) +5:4 + +julia> searchsorted(a, 4, rev=true) +1:1 +``` """ searchsorted @@ -549,6 +582,7 @@ print_shortest Construct a tuple of the given objects. +# Example ```jldoctest julia> tuple(1, 'a', pi) (1, 'a', π = 3.1415926535897...) @@ -570,6 +604,7 @@ eachmatch Get a hexadecimal string of the binary representation of a floating point number. +# Example ```jldoctest julia> num2hex(2.2) "400199999999999a" @@ -590,6 +625,7 @@ truncate Compute ``10^x``. +# Examples ```jldoctest julia> exp10(2) 100.0 @@ -605,6 +641,7 @@ exp10 Bitwise and. +# Examples ```jldoctest julia> 4 & 10 0 @@ -618,7 +655,7 @@ julia> 4 & 12 """ select(v, k, [by=,] [lt=,] [rev=false]) -Variant of `select!` which copies `v` before partially sorting it, thereby returning the +Variant of [`select!`](@ref) which copies `v` before partially sorting it, thereby returning the same thing as `select!` but leaving `v` unmodified. """ select @@ -664,6 +701,41 @@ ErrorException reverse(v [, start=1 [, stop=length(v) ]] ) Return a copy of `v` reversed from start to stop. + +# Examples +```jldoctest +julia> A = collect(1:5) +5-element Array{Int64,1}: + 1 + 2 + 3 + 4 + 5 + +julia> reverse(A) +5-element Array{Int64,1}: + 5 + 4 + 3 + 2 + 1 + +julia> reverse(A, 1, 4) +5-element Array{Int64,1}: + 4 + 3 + 2 + 1 + 5 + +julia> reverse(A, 3, 5) +5-element Array{Int64,1}: + 1 + 2 + 5 + 4 + 3 +``` """ reverse @@ -686,15 +758,14 @@ UndefRefError Add the elements of `collection2` to the end of `collection`. +# Examples ```jldoctest julia> append!([1],[2,3]) 3-element Array{Int64,1}: 1 2 3 -``` -```jldoctest julia> append!([1, 2, 3], [4, 5, 6]) 6-element Array{Int64,1}: 1 @@ -730,6 +801,7 @@ setdiff! Return `z` which has the magnitude of `x` and the same sign as `y`. +# Examples ```jldoctest julia> copysign(1, -2) -1 @@ -767,6 +839,7 @@ showcompact Extract a named field from a `value` of composite type. The syntax `a.b` calls `getfield(a, :b)`. +# Example ```jldoctest julia> a = 1//2 1//2 @@ -786,6 +859,48 @@ at the position where it would appear if the array were fully sorted via a non-s algorithm. If `k` is a single index, that value is returned; if `k` is a range, an array of values at those indices is returned. Note that `select!` does not fully sort the input array. + +# Examples + +```jldoctest +julia> a = [1, 2, 4, 3, 4] +5-element Array{Int64,1}: + 1 + 2 + 4 + 3 + 4 + +julia> select!(a, 4) +4 + +julia> a +5-element Array{Int64,1}: + 1 + 2 + 3 + 4 + 4 + +julia> a = [1, 2, 4, 3, 4] +5-element Array{Int64,1}: + 1 + 2 + 4 + 3 + 4 + +julia> select!(a, 4, rev=true) +2 + +julia> a +5-element Array{Int64,1}: + 4 + 4 + 3 + 2 + 1 +``` """ select! @@ -795,6 +910,15 @@ select! Create a random ASCII string of length `len`, consisting of upper- and lower-case letters and the digits 0-9. The optional `rng` argument specifies a random number generator, see [Random Numbers](@ref). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randstring(rng, 4) +"mbDd" +``` """ randstring @@ -804,6 +928,7 @@ randstring Create a Float64 from `x`. If `x` is not exactly representable then `mode` determines how `x` is rounded. +# Examples ```jldoctest julia> Float64(pi, RoundDown) 3.141592653589793 @@ -821,6 +946,28 @@ Float64(x) ∪(s1,s2...) Construct the union of two or more sets. Maintains order with arrays. + +# Examples +```jldoctest +julia> union([1, 2], [3, 4]) +4-element Array{Int64,1}: + 1 + 2 + 3 + 4 + +julia> union([1, 2], [2, 4]) +3-element Array{Int64,1}: + 1 + 2 + 4 + +julia> union([4, 2], [1, 2]) +3-element Array{Int64,1}: + 4 + 2 + 1 +``` """ union @@ -829,6 +976,7 @@ union The highest finite value representable by the given floating-point DataType `T`. +# Examples ```jldoctest julia> realmax(Float16) Float16(6.55e4) @@ -855,6 +1003,7 @@ serialize The lowest value representable by the given (real) numeric DataType `T`. +# Examples ```jldoctest julia> typemin(Float16) -Inf16 @@ -938,6 +1087,7 @@ cglobal Returns the last index of the collection. +# Example ```jldoctest julia> endof([1,2,4]) 3 @@ -950,6 +1100,7 @@ endof For a given iterable object and iteration state, return the current item and the next iteration state. +# Examples ```jldoctest julia> next(1:5, 3) (3, 4) @@ -1085,9 +1236,9 @@ Return a partial permutation of the vector `v`, according to the order specified if `k` is a range) values of a fully sorted version of `v`. If `k` is a single index (Integer), an array of the first `k` indices is returned; if `k` is a range, an array of those indices is returned. Note that the handling of integer values for `k` is different -from `select` in that it returns a vector of `k` elements instead of just the `k` th +from [`select`](@ref) in that it returns a vector of `k` elements instead of just the `k` th element. Also note that this is equivalent to, but more efficient than, calling -`sortperm(...)[k]` +`sortperm(...)[k]`. """ selectperm @@ -1101,6 +1252,15 @@ For example, `reinterpret(Float32, UInt32(7))` interprets the 4 bytes corresponding to `UInt32(7)` as a [`Float32`](@ref). +!!! warning + + It is not allowed to `reinterpret` an array to an element type with a larger alignment then + the alignment of the array. For a normal `Array`, this is the alignment of its element type. + For a reinterpreted array, this is the alignment of the `Array` it was reinterpreted from. + For example, `reinterpret(UInt32, UInt8[0, 0, 0, 0])` is not allowed but + `reinterpret(UInt32, reinterpret(UInt8, Float32[1.0]))` is allowed. + +# Examples ```jldoctest julia> reinterpret(Float32, UInt32(7)) 1.0f-44 @@ -1117,6 +1277,7 @@ reinterpret Bitwise not. +# Examples ```jldoctest julia> ~4 -5 @@ -1135,6 +1296,7 @@ false Byte-swap an integer. Flip the bits of its binary representation. +# Examples ```jldoctest julia> a = bswap(4) 288230376151711744 @@ -1162,6 +1324,18 @@ maxintfloat delete!(collection, key) Delete the mapping for the given key in a collection, and return the collection. + +# Example +```jldoctest +julia> d = Dict("a"=>1, "b"=>2) +Dict{String,Int64} with 2 entries: + "b" => 2 + "a" => 1 + +julia> delete!(d, "b") +Dict{String,Int64} with 1 entry: + "a" => 1 +``` """ delete! @@ -1171,6 +1345,20 @@ delete! Returns the index of the first value in `a` greater than or equal to `x`, according to the specified order. Returns `length(a)+1` if `x` is greater than all values in `a`. +`a` is assumed to be sorted. + +# Examples + +```jldoctest +julia> searchsortedfirst([1, 2, 4, 5, 14], 4) +3 + +julia> searchsortedfirst([1, 2, 4, 5, 14], 4, rev=true) +1 + +julia> searchsortedfirst([1, 2, 4, 5, 14], 15) +6 +``` """ searchsortedfirst @@ -1200,7 +1388,7 @@ typejoin """ selectperm!(ix, v, k, [alg=,] [by=,] [lt=,] [rev=false,] [initialized=false]) -Like `selectperm`, but accepts a preallocated index vector `ix`. If `initialized` is `false` +Like [`selectperm`](@ref), but accepts a preallocated index vector `ix`. If `initialized` is `false` (the default), ix is initialized to contain the values `1:length(ix)`. """ selectperm! @@ -1224,6 +1412,17 @@ cot Return the value stored for the given key, or the given default value if no mapping for the key is present. + +# Examples +```jldoctest +julia> d = Dict("a"=>1, "b"=>2); + +julia> get(d, "a", 3) +1 + +julia> get(d, "c", 3) +3 +``` """ get(collection,key,default) @@ -1284,6 +1483,7 @@ read(stream, t) Remove the first `item` from `collection`. +# Example ```jldoctest julia> A = [1, 2, 3, 4, 5, 6] 6-element Array{Int64,1}: @@ -1380,6 +1580,7 @@ copy Determine whether a collection is empty (has no elements). +# Examples ```jldoctest julia> isempty([]) true @@ -1434,6 +1635,7 @@ IntSet Create a `Task` (i.e. coroutine) to execute the given function (which must be callable with no arguments). The task exits when this function returns. +# Example ```jldoctest julia> a() = det(rand(1000, 1000)); @@ -1535,7 +1737,7 @@ mean! Test whether `x` is less than `y`, according to a canonical total order. Values that are normally unordered, such as `NaN`, are ordered in an arbitrary but consistent fashion. This -is the default comparison used by `sort`. Non-numeric types with a canonical total order +is the default comparison used by [`sort`](@ref). Non-numeric types with a canonical total order should implement this function. Numeric types only need to implement it if they have special values such as `NaN`. """ @@ -1655,6 +1857,7 @@ show(x) Return `true` if and only if all values of `type1` are also of `type2`. Can also be written using the `<:` infix operator as `type1 <: type2`. +# Examples ```jldoctest julia> issubtype(Int8, Int32) false @@ -1739,6 +1942,7 @@ matchall Return the value stored for the given key, or if no mapping for the key is present, store `key => default`, and return `default`. +# Examples ```jldoctest julia> d = Dict("a"=>1, "b"=>2, "c"=>3); @@ -1765,11 +1969,12 @@ Return the value stored for the given key, or if no mapping for the key is prese `key => f()`, and return `f()`. This is intended to be called using `do` block syntax: - - get!(dict, key) do - # default value calculated here - time() - end +```julia +get!(dict, key) do + # default value calculated here + time() +end +``` """ get!(f::Function,collection,key) @@ -1799,6 +2004,7 @@ For ordered, indexable collections, returns the maximum index `i` for which `get is valid. For unordered collections, returns the number of elements. +# Examples ```jldoctest julia> length(1:5) 5 @@ -1813,7 +2019,21 @@ length(collection) searchsortedlast(a, x, [by=,] [lt=,] [rev=false]) Returns the index of the last value in `a` less than or equal to `x`, according to the -specified order. Returns `0` if `x` is less than all values in `a`. +specified order. Returns `0` if `x` is less than all values in `a`. `a` is assumed to +be sorted. + +# Examples + +```jldoctest +julia> searchsortedlast([1, 2, 4, 5, 14], 4) +3 + +julia> searchsortedlast([1, 2, 4, 5, 14], 4, rev=true) +5 + +julia> searchsortedlast([1, 2, 4, 5, 14], -1) +0 +``` """ searchsortedlast @@ -1912,6 +2132,7 @@ coth Get initial iteration state for an iterable object. +# Examples ```jldoctest julia> start(1:5) 1 @@ -1946,6 +2167,7 @@ isa Test whether we are done iterating. +# Examples ```jldoctest julia> done(1:5, 3) false @@ -1968,6 +2190,7 @@ If `T` is an [`Integer`](@ref) type, an [`InexactError`](@ref) will be raised if is not representable by `T`, for example if `x` is not integer-valued, or is outside the range supported by `T`. +# Examples ```jldoctest julia> convert(Int, 3.0) 3 @@ -2034,6 +2257,7 @@ convert Determine whether the given generic function has a method applicable to the given arguments. +# Examples ```jldoctest julia> function f(x, y) x + y @@ -2117,6 +2341,15 @@ throw ⊊(a,b) -> Bool Determine whether every element of `a` is also in `b`, using [`in`](@ref). + +# Examples +```jldoctest +julia> issubset([1, 2], [1, 2, 3]) +true + +julia> issubset([1, 2, 3], [1, 2]) +false +``` """ issubset(a,b) @@ -2135,7 +2368,7 @@ Create an array of all zeros with the same layout as `A`, element type `T` and s The `A` argument can be skipped, which behaves like `Array{Float64,0}()` was passed. For convenience `dims` may also be passed in variadic form. - +# Examples ```jldoctest julia> zeros(1) 1-element Array{Float64,1}: @@ -2200,6 +2433,18 @@ isvalid(T,value) Convert a number to an unsigned integer. If the argument is signed, it is reinterpreted as unsigned without checking for negative values. + +# Examples +```jldoctest +julia> unsigned(-2) +0xfffffffffffffffe + +julia> unsigned(2) +0x0000000000000002 + +julia> signed(unsigned(-2)) +-2 +``` """ unsigned @@ -2217,6 +2462,7 @@ reverseind Returns `true` if the value of the sign of `x` is negative, otherwise `false`. +# Examples ```jldoctest julia> signbit(-4) true @@ -2308,6 +2554,7 @@ If `x` is a type, return a "larger" type (for numeric types, this will be a type with at least as much range and precision as the argument, and usually more). Otherwise `x` is converted to `widen(typeof(x))`. +# Examples ```jldoctest julia> widen(Int32) Int64 @@ -2350,6 +2597,7 @@ Val Bitwise or. +# Examples ```jldoctest julia> 4 | 10 14 @@ -2366,6 +2614,7 @@ Base.:(|) Delete and return the mapping for `key` if it exists in `collection`, otherwise return `default`, or throw an error if `default` is not specified. +# Examples ```jldoctest julia> d = Dict("a"=>1, "b"=>2, "c"=>3); @@ -2388,6 +2637,7 @@ pop!(collection,key,?) Remove the last item in `collection` and return it. +# Examples ```jldoctest julia> A=[1, 2, 3, 4, 5, 6] 6-element Array{Int64,1}: diff --git a/base/essentials.jl b/base/essentials.jl index 6e06e23302d1d..7c522aaed415d 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -314,7 +314,7 @@ end Colons (:) are used to signify indexing entire objects or dimensions at once. Very few operations are defined on Colons directly; instead they are converted -by `to_indices` to an internal vector type (`Base.Slice`) to represent the +by [`to_indices`](@ref) to an internal vector type (`Base.Slice`) to represent the collection of indices they span before being used. """ struct Colon diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 4f34d7a7ace29..e25098f2d81b3 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -7,6 +7,7 @@ Greatest common (positive) divisor (or zero if `x` and `y` are both zero). +# Examples ```jldoctest julia> gcd(6,9) 3 @@ -51,6 +52,8 @@ end lcm(x,y) Least common (non-negative) multiple. + +# Examples ```jldoctest julia> lcm(2,3) 6 @@ -86,12 +89,11 @@ Computes the greatest common (positive) divisor of `x` and `y` and their Bézout coefficients, i.e. the integer coefficients `u` and `v` that satisfy ``ux+vy = d = gcd(x,y)``. ``gcdx(x,y)`` returns ``(d,u,v)``. +# Examples ```jldoctest julia> gcdx(12, 42) (6, -3, 1) -``` -```jldoctest julia> gcdx(240, 46) (2, -9, 47) ``` @@ -131,6 +133,7 @@ Take the inverse of `x` modulo `m`: `y` such that ``x y = 1 \\pmod m``, with ``div(x,y) = 0``. This is undefined for ``m = 0``, or if ``gcd(x,m) \\neq 1``. +# Examples ```jldoctest julia> invmod(2,5) 3 @@ -225,12 +228,22 @@ const HWNumber = Union{HWReal, Complex{<:HWReal}, Rational{<:HWReal}} Compute ``x^p \\pmod m``. +# Examples ```jldoctest julia> powermod(2, 6, 5) 4 julia> mod(2^6, 5) 4 + +julia> powermod(5, 2, 20) +5 + +julia> powermod(5, 2, 19) +6 + +julia> powermod(5, 3, 19) +11 ``` """ function powermod(x::Integer, p::Integer, m::T) where T<:Integer @@ -265,6 +278,7 @@ powermod(x::Integer, p::Integer, m::Union{Int128,UInt128}) = oftype(m, powermod( The smallest power of two not less than `n`. Returns 0 for `n==0`, and returns `-nextpow2(-n)` for negative arguments. +# Examples ```jldoctest julia> nextpow2(16) 16 @@ -282,9 +296,13 @@ nextpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -nextpow2(unsigned(-x)) : n The largest power of two not greater than `n`. Returns 0 for `n==0`, and returns `-prevpow2(-n)` for negative arguments. +# Examples ```jldoctest julia> prevpow2(5) 4 + +julia> prevpow2(0) +0 ``` """ prevpow2(x::Unsigned) = one(x) << unsigned((sizeof(x)<<3)-leading_zeros(x)-1) @@ -295,6 +313,7 @@ prevpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -prevpow2(unsigned(-x)) : p Test whether `n` is a power of two. +# Examples ```jldoctest julia> ispow2(4) true @@ -311,12 +330,19 @@ ispow2(x::Integer) = x > 0 && count_ones(x) == 1 The smallest `a^n` not less than `x`, where `n` is a non-negative integer. `a` must be greater than 1, and `x` must be greater than 0. +# Examples ```jldoctest julia> nextpow(2, 7) 8 julia> nextpow(2, 9) 16 + +julia> nextpow(5, 20) +25 + +julia> nextpow(4, 16) +16 ``` See also [`prevpow`](@ref). @@ -336,14 +362,20 @@ end The largest `a^n` not greater than `x`, where `n` is a non-negative integer. `a` must be greater than 1, and `x` must not be less than 1. +# Examples ```jldoctest julia> prevpow(2, 7) 4 julia> prevpow(2, 9) 8 -``` +julia> prevpow(5, 20) +5 + +julia> prevpow(4, 16) +16 +``` See also [`nextpow`](@ref). """ function prevpow(a::Real, x::Real) @@ -423,12 +455,22 @@ integer `n` written in base `b` (i.e. equal to `ndigits(n, b)` in this case). The base `b` must not be in `[-1, 0, 1]`. +# Examples ```jldoctest julia> Base.ndigits0z(0, 16) 0 julia> Base.ndigits(0, 16) 1 + +julia> Base.ndigits0z(0) +0 + +julia> Base.ndigits0z(10, 2) +4 + +julia> Base.ndigits0z(10) +2 ``` See also [`ndigits`](@ref). @@ -441,6 +483,7 @@ ndigits0z Compute the number of digits in integer `n` written in base `b`. The base `b` must not be in `[-1, 0, 1]`. +# Examples ```jldoctest julia> ndigits(12345) 5 @@ -572,21 +615,49 @@ bin """ hex(n, pad::Int=1) -Convert an integer to a hexadecimal string, optionally specifying a number of digits to pad to. +Convert an integer to a hexadecimal string, optionally specifying a number of +digits to pad to. + +```jldoctest +julia> hex(20) +"14" + +julia> hex(20, 3) +"014" +``` """ hex """ oct(n, pad::Int=1) -Convert an integer to an octal string, optionally specifying a number of digits to pad to. +Convert an integer to an octal string, optionally specifying a number of digits +to pad to. + +```jldoctest +julia> oct(20) +"24" + +julia> oct(20, 3) +"024" +``` """ oct """ dec(n, pad::Int=1) -Convert an integer to a decimal string, optionally specifying a number of digits to pad to. +Convert an integer to a decimal string, optionally specifying a number of digits +to pad to. + +# Examples +```jldoctest +julia> dec(20) +"20" + +julia> dec(20, 3) +"020" +``` """ dec @@ -602,6 +673,30 @@ bits(x::Union{Int128,UInt128}) = bin(reinterpret(UInt128,x),128) Returns an array with element type `T` (default `Int`) of the digits of `n` in the given base, optionally padded with zeros to a specified size. More significant digits are at higher indexes, such that `n == sum([digits[k]*base^(k-1) for k=1:length(digits)])`. + +# Examples +```jldoctest +julia> digits(10, 10) +2-element Array{Int64,1}: + 0 + 1 + +julia> digits(10, 2) +4-element Array{Int64,1}: + 0 + 1 + 0 + 1 + +julia> digits(10, 2, 6) +6-element Array{Int64,1}: + 0 + 1 + 0 + 1 + 0 + 0 +``` """ digits(n::Integer, base::T=10, pad::Integer=1) where {T<:Integer} = digits(T, n, base, pad) @@ -616,6 +711,25 @@ end Fills an array of the digits of `n` in the given base. More significant digits are at higher indexes. If the array length is insufficient, the least significant digits are filled up to the array length. If the array length is excessive, the excess portion is filled with zeros. + +# Examples +```jldoctest +julia> digits!([2,2,2,2], 10, 2) +4-element Array{Int64,1}: + 0 + 1 + 0 + 1 + +julia> digits!([2,2,2,2,2,2], 10, 2) +6-element Array{Int64,1}: + 0 + 1 + 0 + 1 + 0 + 0 +``` """ function digits!(a::AbstractArray{T,1}, n::Integer, base::Integer=10) where T<:Integer 2 <= base || throw(ArgumentError("base must be ≥ 2, got $base")) @@ -659,10 +773,11 @@ function factorial(n::Integer) end """ - binomial(n,k) + binomial(n, k) Number of ways to choose `k` out of `n` items. +# Example ```jldoctest julia> binomial(5, 3) 10 diff --git a/base/linalg/eigen.jl b/base/linalg/eigen.jl index 0ef75b84c2246..4280da7c2d196 100644 --- a/base/linalg/eigen.jl +++ b/base/linalg/eigen.jl @@ -228,7 +228,7 @@ julia> A = [0 im; -1 0] julia> eigmax(A) ERROR: DomainError: Stacktrace: - [1] #eigmax#46(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:238 + [1] #eigmax#52(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:238 [2] eigmax(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:236 ``` """ @@ -270,7 +270,7 @@ julia> A = [0 im; -1 0] julia> eigmin(A) ERROR: DomainError: Stacktrace: - [1] #eigmin#47(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:280 + [1] #eigmin#53(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:280 [2] eigmin(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:278 ``` """ diff --git a/base/linalg/generic.jl b/base/linalg/generic.jl index 6f44208621bd4..cfce003667412 100644 --- a/base/linalg/generic.jl +++ b/base/linalg/generic.jl @@ -702,6 +702,21 @@ values of `M` have magnitude greater than `tol`. By default, the value of `tol` is the largest dimension of `M` multiplied by the [`eps`](@ref) of the [`eltype`](@ref) of `M`. + +# Example +```jldoctest +julia> rank(eye(3)) +3 + +julia> rank(diagm([1, 0, 2])) +2 + +julia> rank(diagm([1, 0.001, 2]), 0.1) +2 + +julia> rank(diagm([1, 0.001, 2]), 0.00001) +3 +``` """ rank(A::AbstractMatrix, tol::Real) = mapreduce(x -> x > tol, +, 0, svdvals(A)) function rank(A::AbstractMatrix) @@ -852,7 +867,7 @@ condskeel(A::AbstractMatrix, x::AbstractVector, p::Real=Inf) = norm(abs.(inv(A)) Test whether a matrix is symmetric. -# Example +# Examples ```jldoctest julia> a = [1 2; 2 -1] @@ -892,7 +907,7 @@ issymmetric(x::Number) = x == x Test whether a matrix is Hermitian. -# Example +# Examples ```jldoctest julia> a = [1 2; 2 -1] @@ -932,7 +947,7 @@ ishermitian(x::Number) = (x == conj(x)) Test whether a matrix is upper triangular. -# Example +# Examples ```jldoctest julia> a = [1 2; 2 -1] @@ -967,7 +982,7 @@ end Test whether a matrix is lower triangular. -# Example +# Examples ```jldoctest julia> a = [1 2; 2 -1] @@ -1002,7 +1017,7 @@ end Test whether a matrix is diagonal. -# Example +# Examples ```jldoctest julia> a = [1 2; 2 -1] @@ -1224,7 +1239,7 @@ logabsdet(A::AbstractMatrix) = logabsdet(lufact(A)) Log of matrix determinant. Equivalent to `log(det(M))`, but may provide increased accuracy and/or speed. -# Example +# Examples ```jldoctest julia> M = [1 0; 2 2] @@ -1322,7 +1337,7 @@ Normalize the vector `v` so that its `p`-norm equals unity, i.e. `norm(v, p) == vecnorm(v, p) == 1`. See also [`normalize!`](@ref) and [`vecnorm`](@ref). -# Example +# Examples ```jldoctest julia> a = [1,2,4]; diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 129bb5fe224a7..5384f66020e40 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -27,6 +27,37 @@ module IteratorsMD A `CartesianIndex` is sometimes produced by [`eachindex`](@ref), and always when iterating with an explicit [`CartesianRange`](@ref). + + # Example + + ```jldoctest + julia> A = reshape(collect(1:16), (2, 2, 2, 2)) + 2×2×2×2 Array{Int64,4}: + [:, :, 1, 1] = + 1 3 + 2 4 + + [:, :, 2, 1] = + 5 7 + 6 8 + + [:, :, 1, 2] = + 9 11 + 10 12 + + [:, :, 2, 2] = + 13 15 + 14 16 + + julia> A[CartesianIndex((1, 1, 1, 1))] + 1 + + julia> A[CartesianIndex((1, 1, 1, 2))] + 9 + + julia> A[CartesianIndex((1, 1, 2, 1))] + 5 + ``` """ struct CartesianIndex{N} <: AbstractCartesianIndex{N} I::NTuple{N,Int} @@ -111,6 +142,18 @@ module IteratorsMD Consequently these can be useful for writing algorithms that work in arbitrary dimensions. + + ```jldoctest + julia> foreach(println, CartesianRange((2, 2, 2))) + CartesianIndex{3}((1, 1, 1)) + CartesianIndex{3}((2, 1, 1)) + CartesianIndex{3}((1, 2, 1)) + CartesianIndex{3}((2, 2, 1)) + CartesianIndex{3}((1, 1, 2)) + CartesianIndex{3}((2, 1, 2)) + CartesianIndex{3}((1, 2, 2)) + CartesianIndex{3}((2, 2, 2)) + ``` """ struct CartesianRange{I<:CartesianIndex} start::I @@ -850,7 +893,7 @@ Circularly shift the data in `src`, storing the result in The `dest` array must be distinct from the `src` array (they cannot alias each other). -See also `circshift`. +See also [`circshift`](@ref). """ @noinline function circshift!(dest::AbstractArray{T,N}, src, shiftamt::DimsInteger) where {T,N} dest === src && throw(ArgumentError("dest and src must be separate arrays")) @@ -903,6 +946,7 @@ their indices; any offset results in a (circular) wraparound. If the arrays have overlapping indices, then on the domain of the overlap `dest` agrees with `src`. +# Example ```julia-repl julia> src = reshape(collect(1:16), (4,4)) 4×4 Array{Int64,2}: diff --git a/base/permuteddimsarray.jl b/base/permuteddimsarray.jl index 8236a781f39c6..fee5d3af0b66b 100644 --- a/base/permuteddimsarray.jl +++ b/base/permuteddimsarray.jl @@ -89,6 +89,7 @@ equivalent to `permutedims(A, [2,1])`. See also: [`PermutedDimsArray`](@ref). +# Example ```jldoctest julia> A = reshape(collect(1:8), (2,2,2)) 2×2×2 Array{Int64,3}: @@ -125,7 +126,7 @@ have `size(dest) == size(src)[perm]` and is completely overwritten. No in-place is supported and unexpected results will happen if `src` and `dest` have overlapping memory regions. -See also [`permutedims`](@ref) +See also [`permutedims`](@ref). """ function Base.permutedims!(dest, src::AbstractArray, perm) Base.checkdims_perm(dest, src, perm) diff --git a/base/random.jl b/base/random.jl index ff8f9cccd39ba..6a46a71f4d591 100644 --- a/base/random.jl +++ b/base/random.jl @@ -93,6 +93,11 @@ MersenneTwister(seed::Vector{UInt32}, state::DSFMT_state) = Create a `MersenneTwister` RNG object. Different RNG objects can have their own seeds, which may be useful for generating different streams of random numbers. + +# Example +```jldoctest +julia> rng = MersenneTwister(1234); +``` """ MersenneTwister(seed) = srand(MersenneTwister(Vector{UInt32}(), DSFMT_state()), seed) @@ -290,6 +295,20 @@ rand(r::AbstractArray) = rand(GLOBAL_RNG, r) Populate the array `A` with random values. If the indexable collection `coll` is specified, the values are picked randomly from `coll`. This is equivalent to `copy!(A, rand(rng, coll, size(A)))` or `copy!(A, rand(rng, eltype(A), size(A)))` but without allocating a new array. + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> rand!(rng, zeros(5)) +5-element Array{Float64,1}: + 0.590845 + 0.766797 + 0.566237 + 0.460085 + 0.794026 +``` """ rand!(A::AbstractArray, r::AbstractArray) = rand!(GLOBAL_RNG, A, r) @@ -692,6 +711,25 @@ end bitrand([rng=GLOBAL_RNG], [dims...]) Generate a `BitArray` of random boolean values. + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> bitrand(rng, 10) +10-element BitArray{1}: + true + true + true + false + true + false + false + true + false + true +``` """ bitrand(r::AbstractRNG, dims::Dims) = rand!(r, BitArray(dims)) bitrand(r::AbstractRNG, dims::Int...) = rand!(r, BitArray(dims)) @@ -1199,7 +1237,23 @@ 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`](@ref), [`Float32`](@ref), and [`Float64`](@ref) (the default). +[`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. + +# Examples + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randn(rng, Complex128) +0.6133070881429037 - 0.6376291670853887im + +julia> randn(rng, Complex64, (2, 4)) +2×4 Array{Complex{Float32},2}: + -0.349649-0.638457im 0.376756-0.192146im -0.396334-0.0136413im -0.585317+0.0778497im + 0.611224+1.56403im 0.355204-0.365563im 0.0905552+1.31012im -0.177608+0.261427im +``` """ @inline function randn(rng::AbstractRNG=GLOBAL_RNG) @inbounds begin @@ -1234,6 +1288,21 @@ Generate a random number of type `T` according to the exponential distribution w Optionally generate an array of such random numbers. The `Base` module currently provides an implementation for the types [`Float16`](@ref), [`Float32`](@ref), and [`Float64`](@ref) (the default). + +# Examples + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randexp(rng, Float32) +2.4835055f0 + +julia> randexp(rng, 3, 3) +3×3 Array{Float64,2}: + 1.5167 1.30652 0.344435 + 0.604436 2.78029 0.418516 + 0.695867 0.693292 0.643644 +``` """ @inline function randexp(rng::AbstractRNG=GLOBAL_RNG) @inbounds begin @@ -1260,6 +1329,20 @@ end Fill the array `A` with normally-distributed (mean 0, standard deviation 1) random numbers. Also see the [`rand`](@ref) function. + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randn!(rng, zeros(5)) +5-element Array{Float64,1}: + 0.867347 + -0.901744 + -0.494479 + -0.902914 + 0.864401 +``` """ function randn! end @@ -1267,6 +1350,20 @@ function randn! end randexp!([rng=GLOBAL_RNG], A::AbstractArray) -> A Fill the array `A` with random numbers following the exponential distribution (with scale 1). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randexp!(rng, zeros(5)) +5-element Array{Float64,1}: + 2.48351 + 1.5167 + 0.604436 + 0.695867 + 1.30652 +``` """ function randexp! end @@ -1316,6 +1413,15 @@ end Generates a version 1 (time-based) universally unique identifier (UUID), as specified by RFC 4122. Note that the Node ID is randomly generated (does not identify the host) according to section 4.5 of the RFC. + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> Base.Random.uuid1(rng) +2cc938da-5937-11e7-196e-0f4ef71aa64b +``` """ function uuid1(rng::AbstractRNG=GLOBAL_RNG) u = rand(rng, UInt128) @@ -1345,6 +1451,14 @@ end Generates a version 4 (random or pseudo-random) universally unique identifier (UUID), as specified by RFC 4122. + +# Example +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> Base.Random.uuid4(rng) +82015f10-44cc-4827-996e-0f4ef71aa64b +``` """ function uuid4(rng::AbstractRNG=GLOBAL_RNG) u = rand(rng, UInt128) @@ -1357,6 +1471,15 @@ end uuid_version(u::UUID) -> Integer Inspects the given UUID and returns its version (see RFC 4122). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> Base.Random.uuid_version(Base.Random.uuid4(rng)) +4 +``` """ function uuid_version(u::UUID) Int((u.value >> 76) & 0xf) @@ -1472,6 +1595,31 @@ end In-place version of [`shuffle`](@ref): randomly permute the array `v` in-place, optionally supplying the random-number generator `rng`. + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> shuffle!(rng, collect(1:16)) +16-element Array{Int64,1}: + 2 + 15 + 5 + 14 + 1 + 9 + 10 + 6 + 11 + 3 + 16 + 7 + 4 + 12 + 8 + 13 +``` """ function shuffle!(r::AbstractRNG, a::AbstractVector) n = length(a) @@ -1494,6 +1642,25 @@ Return a randomly permuted copy of `v`. The optional `rng` argument specifies a number generator (see [Random Numbers](@ref)). To permute `v` in-place, see [`shuffle!`](@ref). To obtain randomly permuted indices, see [`randperm`](@ref). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> shuffle(rng, collect(1:10)) +10-element Array{Int64,1}: + 6 + 1 + 10 + 2 + 3 + 9 + 5 + 7 + 4 + 8 +``` """ shuffle(r::AbstractRNG, a::AbstractVector) = shuffle!(r, copymutable(a)) shuffle(a::AbstractVector) = shuffle(GLOBAL_RNG, a) @@ -1505,6 +1672,19 @@ Construct a random permutation of length `n`. The optional `rng` argument specif number generator (see [Random Numbers](@ref)). To randomly permute a arbitrary vector, see [`shuffle`](@ref) or [`shuffle!`](@ref). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randperm(rng, 4) +4-element Array{Int64,1}: + 2 + 1 + 4 + 3 +``` """ function randperm(r::AbstractRNG, n::Integer) a = Vector{typeof(n)}(n) @@ -1531,6 +1711,21 @@ randperm(n::Integer) = randperm(GLOBAL_RNG, n) Construct a random cyclic permutation of length `n`. The optional `rng` argument specifies a random number generator, see [Random Numbers](@ref). + +# Example + +```jldoctest +julia> rng = MersenneTwister(1234); + +julia> randcycle(rng, 6) +6-element Array{Int64,1}: + 3 + 5 + 4 + 6 + 1 + 2 +``` """ function randcycle(r::AbstractRNG, n::Integer) a = Vector{typeof(n)}(n) diff --git a/base/reducedim.jl b/base/reducedim.jl index a2ba674ee6d64..e857f579b3b55 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -219,6 +219,7 @@ reducedim!(op, R::AbstractArray{RT}, A::AbstractArray) where {RT} = Evaluates to the same as `reducedim(op, map(f, A), region, f(v0))`, but is generally faster because the intermediate array is avoided. +# Examples ```jldoctest julia> a = reshape(collect(1:16), (4,4)) 4×4 Array{Int64,2}: @@ -252,6 +253,7 @@ The associativity of the reduction is implementation-dependent; if you need a pa associativity, e.g. left-to-right, you should write your own loop. See documentation for [`reduce`](@ref). +# Examples ```jldoctest julia> a = reshape(collect(1:16), (4,4)) 4×4 Array{Int64,2}: @@ -282,6 +284,7 @@ reducedim(op, A::AbstractArray, region) = mapreducedim(identity, op, A, region) Sum elements of an array over the given dimensions. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -305,6 +308,7 @@ sum(A, dims) Sum elements of `A` over the singleton dimensions of `r`, and write results to `r`. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -328,6 +332,7 @@ sum!(r, A) Multiply elements of an array over the given dimensions. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -351,6 +356,7 @@ prod(A, dims) Multiply elements of `A` over the singleton dimensions of `r`, and write results to `r`. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -399,6 +405,7 @@ maximum(A, dims) Compute the maximum value of `A` over the singleton dimensions of `r`, and write results to `r`. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -424,6 +431,7 @@ Compute the minimum value of an array over the given dimensions. See also the [`min(a,b)`](@ref) function to take the minimum of two or more arguments, which can be applied elementwise to arrays via `min.(a,b)`. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -447,6 +455,7 @@ minimum(A, dims) Compute the minimum value of `A` over the singleton dimensions of `r`, and write results to `r`. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -470,6 +479,7 @@ minimum!(r, A) Test whether all values along the given dimensions of an array are `true`. +# Examples ```jldoctest julia> A = [true false; true true] 2×2 Array{Bool,2}: @@ -493,6 +503,7 @@ all(A::AbstractArray, dims) Test whether all values in `A` along the singleton dimensions of `r` are `true`, and write results to `r`. +# Examples ```jldoctest julia> A = [true false; true false] 2×2 Array{Bool,2}: @@ -516,6 +527,7 @@ all!(r, A) Test whether any values along the given dimensions of an array are `true`. +# Examples ```jldoctest julia> A = [true false; true false] 2×2 Array{Bool,2}: @@ -540,6 +552,7 @@ any(::AbstractArray,dims) Test whether any values in `A` along the singleton dimensions of `r` are `true`, and write results to `r`. +# Examples ```jldoctest julia> A = [true false; true false] 2×2 Array{Bool,2}: @@ -637,6 +650,7 @@ end For an array input, returns the value and index of the minimum over the given region. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: @@ -675,6 +689,7 @@ end For an array input, returns the value and index of the maximum over the given region. +# Examples ```jldoctest julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: diff --git a/base/sort.jl b/base/sort.jl index 846723518a9b7..cc71c26177f1f 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -63,6 +63,7 @@ end Test whether a vector is in sorted order. The `lt`, `by` and `rev` keywords modify what order is considered to be sorted just as they do for [`sort`](@ref). +# Examples ```jldoctest julia> issorted([1, 2, 3]) true @@ -447,6 +448,8 @@ options are independent and can be used together in all possible combinations: i and `lt` are specified, the `lt` function is applied to the result of the `by` function; `rev=true` reverses whatever ordering specified via the `by` and `lt` keywords. +# Examples + ```jldoctest julia> v = [3, 1, 2]; sort!(v); v 3-element Array{Int64,1}: @@ -522,6 +525,8 @@ end Variant of [`sort!`](@ref) that returns a sorted copy of `v` leaving `v` itself unmodified. +# Examples + ```jldoctest julia> v = [3, 1, 2]; @@ -578,6 +583,8 @@ specified using the same keywords as `sort!`. See also [`sortperm!`](@ref). +# Examples + ```jldoctest julia> v = [3, 1, 2]; @@ -626,6 +633,8 @@ end Like [`sortperm`](@ref), but accepts a preallocated index vector `ix`. If `initialized` is `false` (the default), `ix` is initialized to contain the values `1:length(v)`. +# Examples + ```jldoctest julia> v = [3, 1, 2]; p = zeros(Int, 3); @@ -691,6 +700,8 @@ Sort a multidimensional array `A` along the given dimension. See [`sort!`](@ref) for a description of possible keyword arguments. +# Examples + ```jldoctest julia> A = [4 3; 1 2] 2×2 Array{Int64,2}: diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 6fca07fa37682..e0db9edd6fe8e 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -32,6 +32,7 @@ size(S::SparseMatrixCSC) = (S.m, S.n) Returns the number of stored (filled) elements in a sparse array. +# Example ```jldoctest julia> A = speye(3) 3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: @@ -56,6 +57,7 @@ vector points directly to the internal nonzero storage of `A`, and any modifications to the returned vector will mutate `A` as well. See [`rowvals`](@ref) and [`nzrange`](@ref). +# Example ```jldoctest julia> A = speye(3) 3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: @@ -80,6 +82,7 @@ vector will mutate `A` as well. Providing access to how the row indices are stored internally can be useful in conjunction with iterating over structural nonzero values. See also [`nonzeros`](@ref) and [`nzrange`](@ref). +# Example ```jldoctest julia> A = speye(3) 3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: @@ -348,6 +351,7 @@ full(S::SparseMatrixCSC) = convert(Array, S) Convert a sparse matrix or vector `S` into a dense matrix or vector. +# Example ```jldoctest julia> A = speye(3) 3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: @@ -378,6 +382,7 @@ vec(S::SparseMatrixCSC) = S[:] Convert an AbstractMatrix `A` into a sparse matrix. +# Example ```jldoctest julia> A = eye(3) 3×3 Array{Float64,2}: @@ -458,6 +463,7 @@ retained as structural nonzeros; to drop numerical zeros, use [`dropzeros!`](@re For additional documentation and an expert driver, see `Base.SparseArrays.sparse!`. +# Example ```jldoctest julia> Is = [1; 2; 3]; @@ -1001,7 +1007,7 @@ For additional (algorithmic) information, and for versions of these methods that argument checking, see (unexported) parent methods `unchecked_noalias_permute!` and `unchecked_aliasing_permute!`. -See also: [`permute`](@ref) +See also: [`permute`](@ref). """ function permute!{Tv,Ti}(X::SparseMatrixCSC{Tv,Ti}, A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) @@ -1054,6 +1060,39 @@ match `A`'s column count (`length(q) == A.n`). Row-permutation `p`'s length must row count (`length(p) == A.m`). For expert drivers and additional information, see [`permute!`](@ref). + +# Example +```jldoctest +julia> A = spdiagm([1, 2, 3, 4], 0, 4, 4) + spdiagm([5, 6, 7], 1, 4, 4) +4×4 SparseMatrixCSC{Int64,Int64} with 7 stored entries: + [1, 1] = 1 + [1, 2] = 5 + [2, 2] = 2 + [2, 3] = 6 + [3, 3] = 3 + [3, 4] = 7 + [4, 4] = 4 + +julia> permute(A, [4, 3, 2, 1], [1, 2, 3, 4]) +4×4 SparseMatrixCSC{Int64,Int64} with 7 stored entries: + [4, 1] = 1 + [3, 2] = 2 + [4, 2] = 5 + [2, 3] = 3 + [3, 3] = 6 + [1, 4] = 4 + [2, 4] = 7 + +julia> permute(A, [1, 2, 3, 4], [4, 3, 2, 1]) +4×4 SparseMatrixCSC{Int64,Int64} with 7 stored entries: + [3, 1] = 7 + [4, 1] = 4 + [2, 2] = 6 + [3, 2] = 3 + [1, 3] = 5 + [2, 3] = 2 + [1, 4] = 1 +``` """ function permute{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) @@ -1078,6 +1117,21 @@ value. This method makes a single sweep through `A`, requiring `O(A.n, nnz(A))`-time for matrices and `O(nnz(A))`-time for vectors and no space beyond that passed in. If `trim` is `true`, this method trims `A.rowval` or `A.nzind` and `A.nzval` to length `nnz(A)` after dropping elements. + +# Example +```jldoctest +julia> A = spdiagm([1, 2, 3, 4]) +4×4 SparseMatrixCSC{Int64,Int64} with 4 stored entries: + [1, 1] = 1 + [2, 2] = 2 + [3, 3] = 3 + [4, 4] = 4 + +julia> Base.SparseArrays.fkeep!(A, (i, j, v) -> isodd(v)) +4×4 SparseMatrixCSC{Int64,Int64} with 2 stored entries: + [1, 1] = 1 + [3, 3] = 3 +``` """ function fkeep!(A::SparseMatrixCSC, f, trim::Bool = true) An = A.n @@ -1153,6 +1207,20 @@ Generates a copy of `A` and removes stored numerical zeros from that copy, optio trimming excess space from the result's `rowval` and `nzval` arrays when `trim` is `true`. For an in-place version and algorithmic information, see [`dropzeros!`](@ref). + +# Example +```jldoctest +julia> A = sparse([1, 2, 3], [1, 2, 3], [1.0, 0.0, 1.0]) +3×3 SparseMatrixCSC{Float64,Int64} with 3 stored entries: + [1, 1] = 1.0 + [2, 2] = 0.0 + [3, 3] = 1.0 + +julia> dropzeros(A) +3×3 SparseMatrixCSC{Float64,Int64} with 2 stored entries: + [1, 1] = 1.0 + [3, 3] = 1.0 +``` """ dropzeros(A::SparseMatrixCSC, trim::Bool = true) = dropzeros!(copy(A), trim) @@ -1263,6 +1331,7 @@ values are sampled from the distribution specified by `rfn` and have the type `t distribution is used in case `rfn` is not specified. The optional `rng` argument specifies a random number generator, see [Random Numbers](@ref). +# Example ```jldoctest julia> rng = MersenneTwister(1234); @@ -1314,6 +1383,7 @@ with the specified (independent) probability `p` of any entry being nonzero, where nonzero values are sampled from the normal distribution. The optional `rng` argument specifies a random number generator, see [Random Numbers](@ref). +# Example ```jldoctest julia> rng = MersenneTwister(1234); @@ -1334,6 +1404,7 @@ sprandn(m::Integer, n::Integer, density::AbstractFloat) = sprandn(GLOBAL_RNG,m,n Create a sparse array with the same structure as that of `S`, but with every nonzero element having the value `1.0`. +# Example ```jldoctest julia> A = sparse([1,2,3,4],[2,4,3,1],[5.,4.,3.,2.]) 4×4 SparseMatrixCSC{Float64,Int64} with 4 stored entries: @@ -1363,6 +1434,7 @@ sparse array will not contain any nonzero values. No storage will be allocated for nonzero values during construction. The type defaults to [`Float64`](@ref) if not specified. +# Examples ```jldoctest julia> spzeros(3, 3) 3×3 SparseMatrixCSC{Float64,Int64} with 0 stored entries @@ -1391,6 +1463,7 @@ speye(m::Integer, n::Integer) = speye(Float64, m, n) Create a sparse identity matrix with the same size as `S`. +# Example ```jldoctest julia> A = sparse([1,2,3,4],[2,4,3,1],[5.,4.,3.,2.]) 4×4 SparseMatrixCSC{Float64,Int64} with 4 stored entries: @@ -2817,6 +2890,22 @@ stored and otherwise do nothing. Derivative forms: dropstored!(A::SparseMatrixCSC, i::Integer, J::AbstractVector{<:Integer}) dropstored!(A::SparseMatrixCSC, I::AbstractVector{<:Integer}, j::Integer) + +# Example +```jldoctest +julia> A = spdiagm([1, 2, 3, 4]) +4×4 SparseMatrixCSC{Int64,Int64} with 4 stored entries: + [1, 1] = 1 + [2, 2] = 2 + [3, 3] = 3 + [4, 4] = 4 + +julia> Base.SparseArrays.dropstored!(A, [1, 2], [1, 1]) +4×4 SparseMatrixCSC{Int64,Int64} with 3 stored entries: + [2, 2] = 2 + [3, 3] = 3 + [4, 4] = 4 +``` """ function dropstored!(A::SparseMatrixCSC, I::AbstractVector{<:Integer}, J::AbstractVector{<:Integer}) @@ -3199,6 +3288,7 @@ one diagonal, `B` can be a vector (instead of a tuple) and `d` can be the diagon (instead of a tuple), defaulting to 0 (diagonal). Optionally, `m` and `n` specify the size of the resulting sparse matrix. +# Example ```jldoctest julia> spdiagm(([1,2,3,4],[4,3,2,1]),(-1,1)) 5×5 SparseMatrixCSC{Int64,Int64} with 8 stored entries: diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index 63daae89a130a..7922954c13248 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -253,6 +253,7 @@ setindex!(x::SparseVector{Tv,Ti}, v, i::Integer) where {Tv,Ti<:Integer} = Drop entry `x[i]` from `x` if `x[i]` is stored and otherwise do nothing. +# Examples ```jldoctest julia> x = sparsevec([1, 3], [1.0, 2.0]) 3-element SparseVector{Float64,Int64} with 2 stored entries: @@ -305,6 +306,7 @@ convert(::Type{SparseVector}, s::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = Convert a vector `A` into a sparse vector of length `m`. +# Example ```jldoctest julia> sparsevec([1.0, 2.0, 0.0, 0.0, 3.0, 0.0]) 6-element SparseVector{Float64,Int64} with 3 stored entries: @@ -1928,6 +1930,20 @@ Generates a copy of `x` and removes numerical zeros from that copy, optionally t excess space from the result's `nzind` and `nzval` arrays when `trim` is `true`. For an in-place version and algorithmic information, see [`dropzeros!`](@ref). + +# Example +```jldoctest +julia> A = sparsevec([1, 2, 3], [1.0, 0.0, 1.0]) +3-element SparseVector{Float64,Int64} with 3 stored entries: + [1] = 1.0 + [2] = 0.0 + [3] = 1.0 + +julia> dropzeros(A) +3-element SparseVector{Float64,Int64} with 2 stored entries: + [1] = 1.0 + [3] = 1.0 +``` """ dropzeros(x::SparseVector, trim::Bool = true) = dropzeros!(copy(x), trim) diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index 462eb8c3b72da..7c5263a2f27c6 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -235,8 +235,8 @@ ERROR: DomainError: Cannot raise an integer x to a negative power -n. Make x a float by adding a zero decimal (e.g. 2.0^-n instead of 2^-n), or write 1/x^n, float(x)^-n, or (x//1)^-n. Stacktrace: - [1] power_by_squaring(::Int64, ::Int64) at ./intfuncs.jl:170 - [2] literal_pow(::Base.#^, ::Int64, ::Type{Val{-5}}) at ./intfuncs.jl:205 + [1] power_by_squaring(::Int64, ::Int64) at ./intfuncs.jl:173 + [2] literal_pow(::Base.#^, ::Int64, ::Type{Val{-5}}) at ./intfuncs.jl:208 ``` This behavior is an inconvenient consequence of the requirement for type-stability. In the case diff --git a/doc/src/manual/mathematical-operations.md b/doc/src/manual/mathematical-operations.md index a6e8da1fff8f3..71ef3fa77c464 100644 --- a/doc/src/manual/mathematical-operations.md +++ b/doc/src/manual/mathematical-operations.md @@ -397,7 +397,7 @@ julia> Int8(127) julia> Int8(128) ERROR: InexactError() Stacktrace: - [1] Int8(::Int64) at ./sysimg.jl:24 + [1] Int8(::Int64) at ./sysimg.jl:102 julia> Int8(127.0) 127 @@ -411,8 +411,8 @@ Stacktrace: julia> Int8(128.0) ERROR: InexactError() Stacktrace: - [1] convert(::Type{Int8}, ::Float64) at ./float.jl:658 - [2] Int8(::Float64) at ./sysimg.jl:24 + [1] convert(::Type{Int8}, ::Float64) at ./float.jl:659 + [2] Int8(::Float64) at ./sysimg.jl:102 julia> 127 % Int8 127 diff --git a/doc/src/manual/types.md b/doc/src/manual/types.md index 97c59738623ec..e9cc055b3784c 100644 --- a/doc/src/manual/types.md +++ b/doc/src/manual/types.md @@ -651,7 +651,7 @@ ERROR: MethodError: Cannot `convert` an object of type Float64 to an object of t This may have arisen from a call to the constructor Point{Float64}(...), since type constructors fall back to convert methods. Stacktrace: - [1] Point{Float64}(::Float64) at ./sysimg.jl:24 + [1] Point{Float64}(::Float64) at ./sysimg.jl:102 julia> Point{Float64}(1.0,2.0,3.0) ERROR: MethodError: no method matching Point{Float64}(::Float64, ::Float64, ::Float64) From 8ff738e0c2313b2a8be80ace07b87ed858638d2a Mon Sep 17 00:00:00 2001 From: kshyatt Date: Sat, 24 Jun 2017 17:14:57 -0700 Subject: [PATCH 24/88] I love # Example Ref #22522 (cherry picked from commit 9c6466afd50c5ffa5ae1fa8ee5e9fd4ecb1749c1) --- base/iterators.jl | 20 +++++++++++++++++++- base/strings/basic.jl | 30 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/base/iterators.jl b/base/iterators.jl index 1c2ab13f8e113..ef4e7acf66f66 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -43,6 +43,8 @@ for indexing `iter`; it's also possible that `x != iter[i]`, if `iter` has indices that do not start at 1. See the `enumerate(IndexLinear(), iter)` method if you want to ensure that `i` is an index. +# Example + ```jldoctest julia> a = ["a", "b", "c"]; @@ -90,6 +92,8 @@ specifying `IndexCartesian()` ensures that `i` will be a `CartesianIndex`; specifying `IndexStyle(A)` chooses whichever has been defined as the native indexing style for array `A`. +# Examples + ```jldoctest julia> A = ["a" "d"; "b" "e"; "c" "f"]; @@ -202,6 +206,8 @@ the `i`th component of each input iterable. Note that [`zip`](@ref) is its own inverse: `collect(zip(zip(a...)...)) == collect(a)`. +# Example + ```jldoctest julia> a = 1:5 1:5 @@ -357,6 +363,8 @@ end An iterator that generates at most the first `n` elements of `iter`. +# Example + ```jldoctest julia> a = 1:2:11 1:2:11 @@ -412,6 +420,8 @@ end An iterator that generates all but the first `n` elements of `iter`. +# Example + ```jldoctest julia> a = 1:2:11 1:2:11 @@ -505,6 +515,8 @@ repeated(x) = Repeated(x) An iterator that generates the value `x` forever. If `n` is specified, generates `x` that many times (equivalent to `take(repeated(x), n)`). +# Example + ```jldoctest julia> a = Iterators.repeated([1 2], 4); @@ -594,6 +606,8 @@ Returns an iterator over the product of several iterators. Each generated elemen a tuple whose `i`th element comes from the `i`th argument iterator. The first iterator changes the fastest. Example: +# Example + ```jldoctest julia> collect(Iterators.product(1:2,3:5)) 2×3 Array{Tuple{Int64,Int64},2}: @@ -669,7 +683,9 @@ end Given an iterator that yields iterators, return an iterator that yields the elements of those iterators. -Put differently, the elements of the argument iterator are concatenated. Example: +Put differently, the elements of the argument iterator are concatenated. + +# Example ```jldoctest julia> collect(Iterators.flatten((1:2, 8:9))) @@ -724,6 +740,8 @@ end Iterate over a collection `n` elements at a time. +# Example + ```jldoctest julia> collect(Iterators.partition([1,2,3,4,5], 2)) 3-element Array{Array{Int64,1},1}: diff --git a/base/strings/basic.jl b/base/strings/basic.jl index df3e4bdf6db81..d46e490e50e84 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -46,6 +46,8 @@ Symbol(s::AbstractString) = Symbol(String(s)) The number of bytes in string `s`. +# Example + ```jldoctest julia> sizeof("❤") 3 @@ -62,6 +64,8 @@ eltype(::Type{<:AbstractString}) = Char Concatenate strings. The `*` operator is an alias to this function. +# Example + ```jldoctest julia> "Hello " * "world" "Hello world" @@ -78,6 +82,8 @@ length(s::DirectIndexString) = endof(s) The number of characters in string `s`. +# Example + ```jldoctest julia> length("jμΛIα") 5 @@ -138,6 +144,8 @@ isvalid(s::DirectIndexString, i::Integer) = (start(s) <= i <= endof(s)) Tells whether index `i` is valid for the given string. +# Examples + ```jldoctest julia> str = "αβγdef"; @@ -179,6 +187,8 @@ nextind(s::AbstractArray , i::Integer) = Int(i)+1 Get the previous valid string index before `i`. Returns a value less than `1` at the beginning of the string. +# Examples + ```jldoctest julia> prevind("αβγdef", 3) 1 @@ -208,6 +218,8 @@ end Get the next valid string index after `i`. Returns a value greater than `endof(str)` at or after the end of the string. +# Examples + ```jldoctest julia> str = "αβγdef"; @@ -255,6 +267,8 @@ respect to string `s`. See also [`chr2ind`](@ref). +# Example + ```jldoctest julia> str = "αβγdef"; @@ -286,6 +300,8 @@ Convert a character index `i` to a byte index. See also [`ind2chr`](@ref). +# Example + ```jldoctest julia> str = "αβγdef"; @@ -328,6 +344,8 @@ eltype(::Type{EachStringIndex}) = Int Gives the number of columns needed to print a string. +# Example + ```jldoctest julia> strwidth("March") 5 @@ -354,6 +372,8 @@ promote_rule(::Type{<:AbstractString}, ::Type{<:AbstractString}) = String Tests whether a character is a valid hexadecimal digit. Note that this does not include `x` (as in the standard `0x` prefix). +# Example + ```jldoctest julia> isxdigit('a') true @@ -371,6 +391,8 @@ isxdigit(c::Char) = '0'<=c<='9' || 'a'<=c<='f' || 'A'<=c<='F' Returns `s` with all characters converted to uppercase. +# Example + ```jldoctest julia> uppercase("Julia") "JULIA" @@ -383,6 +405,8 @@ uppercase(s::AbstractString) = map(uppercase, s) Returns `s` with all characters converted to lowercase. +# Example + ```jldoctest julia> lowercase("STRINGS AND THINGS") "strings and things" @@ -395,6 +419,8 @@ lowercase(s::AbstractString) = map(lowercase, s) Capitalizes the first character of each word in `s`. +# Example + ```jldoctest julia> titlecase("the julia programming language") "The Julia Programming Language" @@ -420,6 +446,8 @@ end Returns `string` with the first character converted to uppercase. +# Example + ```jldoctest julia> ucfirst("python") "Python" @@ -434,6 +462,8 @@ end Returns `string` with the first character converted to lowercase. +# Example + ```jldoctest julia> lcfirst("Julia") "julia" From 2a1b86e99f5801a14e8463a08eb248afbd3c3caf Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sun, 25 Jun 2017 11:14:15 -0700 Subject: [PATCH 25/88] test elementwise leftshift on BigInt by vector of ints (#22524) (cherry picked from commit 65784d73ac1c78410b40b7028584533e4ff3b2fd) --- test/int.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/int.jl b/test/int.jl index ad2e9a1e8f1f2..d89811e3fcf61 100644 --- a/test/int.jl +++ b/test/int.jl @@ -207,3 +207,10 @@ for T in [Base.BitInteger_types..., BigInt], U in [Base.BitInteger_types..., BigInt] @test typeof(rand(U(0):U(127)) % T) === T end + + +@testset "left shift with Vector{Int} on BigInt-scalar #13832" begin + x = BigInt(1) .<< [1:70;] + @test x[end] == 1180591620717411303424 + @test eltype(x) == BigInt +end From 60c1351b382e02744b7975a1810c407043f52217 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sun, 25 Jun 2017 05:51:44 +0200 Subject: [PATCH 26/88] fix not using type in argument list Ref #22526 (cherry picked from commit a7c0046c74b4c21411de1cffa3720bec470d3ce3) --- doc/src/manual/functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/functions.md b/doc/src/manual/functions.md index 1793befa0beed..a6bf9ed8c72e0 100644 --- a/doc/src/manual/functions.md +++ b/doc/src/manual/functions.md @@ -392,7 +392,7 @@ interprets a string as a number in some base. The `base` argument defaults to `1 can be expressed concisely as: ```julia -function parse(type, num, base=10) +function parse(T, num, base=10) ### end ``` From 5ac4706b66063b50a88675798f925872d6eea4b5 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Mon, 26 Jun 2017 23:54:58 +0200 Subject: [PATCH 27/88] use where syntax in deprecated.jl (#22527) (cherry picked from commit ab97a0dd4dcb8732da2d6178d3ac5424698bdb06) --- base/deprecated.jl | 90 +++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/base/deprecated.jl b/base/deprecated.jl index 12bb33fe3a527..9e8836a17fb20 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -217,7 +217,7 @@ macro dep_vectorize_1arg(S, f) T = esc(:T) x = esc(:x) AbsArr = esc(:AbstractArray) - :( @deprecate $f{$T<:$S}($x::$AbsArr{$T}) $f.($x) ) + :( @deprecate $f($x::$AbsArr{$T}) where {$T<:$S} $f.($x) ) end macro dep_vectorize_2arg(S, f) S = esc(S) @@ -228,9 +228,9 @@ macro dep_vectorize_2arg(S, f) y = esc(:y) AbsArr = esc(:AbstractArray) quote - @deprecate $f{$T1<:$S}($x::$S, $y::$AbsArr{$T1}) $f.($x,$y) - @deprecate $f{$T1<:$S}($x::$AbsArr{$T1}, $y::$S) $f.($x,$y) - @deprecate $f{$T1<:$S,$T2<:$S}($x::$AbsArr{$T1}, $y::$AbsArr{$T2}) $f.($x,$y) + @deprecate $f($x::$S, $y::$AbsArr{$T1}) where {$T1<:$S} $f.($x,$y) + @deprecate $f($x::$AbsArr{$T1}, $y::$S) where {$T1<:$S} $f.($x,$y) + @deprecate $f($x::$AbsArr{$T1}, $y::$AbsArr{$T2}) where {$T1<:$S,$T2<:$S} $f.($x,$y) end end @@ -481,7 +481,7 @@ Filesystem.stop_watching(stream::Filesystem._FDWatcher) = depwarn("stop_watching filter(fun, dr) end end - recur{T<:TimeType}(fun::Function, start::T, stop::T; step::Period=Day(1), negate::Bool=false, limit::Int=10000) = recur(fun, start:step:stop; negate=negate) + recur(fun::Function, start::T, stop::T; step::Period=Day(1), negate::Bool=false, limit::Int=10000) where {T<:TimeType} = recur(fun, start:step:stop; negate=negate) end # Index conversions revamp; #19730 @@ -708,19 +708,19 @@ export Collections @deprecate bitbroadcast broadcast # Deprecate two-argument map! (map!(f, A)) for a cycle in anticipation of semantic change -@deprecate map!{F}(f::F, A::AbstractArray) map!(f, A, A) +@deprecate map!(f::F, A::AbstractArray) where {F} map!(f, A, A) @deprecate asyncmap!(f, c; ntasks=0, batch_size=nothing) asyncmap!(f, c, c; ntasks=ntasks, batch_size=batch_size) # Not exported, but used outside Base _promote_array_type(F, ::Type, ::Type, T::Type) = T -_promote_array_type{A<:AbstractFloat}(F, ::Type{<:Real}, ::Type{A}, ::Type) = A -_promote_array_type{A<:Integer}(F, ::Type{<:Integer}, ::Type{A}, ::Type) = A +_promote_array_type(F, ::Type{<:Real}, ::Type{A}, ::Type) where {A<:AbstractFloat} = A +_promote_array_type(F, ::Type{<:Integer}, ::Type{A}, ::Type) where {A<:Integer} = A _promote_array_type(::typeof(/), ::Type{<:Integer}, ::Type{<:Integer}, T::Type) = T _promote_array_type(::typeof(\), ::Type{<:Integer}, ::Type{<:Integer}, T::Type) = T _promote_array_type(::typeof(/), ::Type{<:Integer}, ::Type{Bool}, T::Type) = T _promote_array_type(::typeof(\), ::Type{<:Integer}, ::Type{Bool}, T::Type) = T _promote_array_type(F, ::Type{<:Integer}, ::Type{Bool}, T::Type) = T -_promote_array_type{T<:AbstractFloat}(F, ::Type{<:Union{Complex, Real}}, ::Type{Complex{T}}, ::Type) = Complex{T} +_promote_array_type(F, ::Type{<:Union{Complex, Real}}, ::Type{Complex{T}}, ::Type) where {T<:AbstractFloat} = Complex{T} function promote_array_type(F, R, S, T) Base.depwarn("`promote_array_type` is deprecated as it is no longer needed " * "in Base. See https://github.com/JuliaLang/julia/issues/19669 " * @@ -753,8 +753,8 @@ end @deprecate round(M::Bidiagonal) round.(M) @deprecate round(M::Tridiagonal) round.(M) @deprecate round(M::SymTridiagonal) round.(M) -@deprecate round{T}(::Type{T}, x::AbstractArray) round.(T, x) -@deprecate round{T}(::Type{T}, x::AbstractArray, r::RoundingMode) round.(T, x, r) +@deprecate round(::Type{T}, x::AbstractArray) where {T} round.(T, x) +@deprecate round(::Type{T}, x::AbstractArray, r::RoundingMode) where {T} round.(T, x, r) @deprecate round(x::AbstractArray, r::RoundingMode) round.(x, r) @deprecate round(x::AbstractArray, digits::Integer, base::Integer = 10) round.(x, digits, base) @@ -762,21 +762,21 @@ end @deprecate trunc(M::Bidiagonal) trunc.(M) @deprecate trunc(M::Tridiagonal) trunc.(M) @deprecate trunc(M::SymTridiagonal) trunc.(M) -@deprecate trunc{T}(::Type{T}, x::AbstractArray) trunc.(T, x) +@deprecate trunc(::Type{T}, x::AbstractArray) where {T} trunc.(T, x) @deprecate trunc(x::AbstractArray, digits::Integer, base::Integer = 10) trunc.(x, digits, base) # Deprecate manually vectorized floor methods in favor of compact broadcast syntax @deprecate floor(M::Bidiagonal) floor.(M) @deprecate floor(M::Tridiagonal) floor.(M) @deprecate floor(M::SymTridiagonal) floor.(M) -@deprecate floor{T}(::Type{T}, A::AbstractArray) floor.(T, A) +@deprecate floor(::Type{T}, A::AbstractArray) where {T} floor.(T, A) @deprecate floor(A::AbstractArray, digits::Integer, base::Integer = 10) floor.(A, digits, base) # Deprecate manually vectorized ceil methods in favor of compact broadcast syntax @deprecate ceil(M::Bidiagonal) ceil.(M) @deprecate ceil(M::Tridiagonal) ceil.(M) @deprecate ceil(M::SymTridiagonal) ceil.(M) -@deprecate ceil{T}(::Type{T}, x::AbstractArray) ceil.(T, x) +@deprecate ceil(::Type{T}, x::AbstractArray) where {T} ceil.(T, x) @deprecate ceil(x::AbstractArray, digits::Integer, base::Integer = 10) ceil.(x, digits, base) # Deprecate manually vectorized `big` methods in favor of compact broadcast syntax @@ -805,10 +805,10 @@ end @deprecate rem(A::AbstractArray, B::Number) rem.(A, B) # Deprecate manually vectorized div, mod, and % methods for dates -@deprecate div{P<:Dates.Period}(X::StridedArray{P}, y::P) div.(X, y) +@deprecate div(X::StridedArray{P}, y::P) where {P<:Dates.Period} div.(X, y) @deprecate div(X::StridedArray{<:Dates.Period}, y::Integer) div.(X, y) -@deprecate (%){P<:Dates.Period}(X::StridedArray{P}, y::P) X .% y -@deprecate mod{P<:Dates.Period}(X::StridedArray{P}, y::P) mod.(X, y) +@deprecate (%)(X::StridedArray{P}, y::P) where {P<:Dates.Period} X .% y +@deprecate mod(X::StridedArray{P}, y::P) where {P<:Dates.Period} mod.(X, y) # Deprecate manually vectorized mod methods in favor of compact broadcast syntax @deprecate mod(B::BitArray, x::Bool) mod.(B, x) @@ -1023,7 +1023,7 @@ isempty(::Task) = error("isempty not defined for Tasks") end end - array_eps{T}(a::AbstractArray{Complex{T}}) = eps(float(maximum(x->(isfinite(x) ? abs(x) : T(NaN)), a))) + array_eps(a::AbstractArray{Complex{T}}) where {T} = eps(float(maximum(x->(isfinite(x) ? abs(x) : T(NaN)), a))) array_eps(a) = eps(float(maximum(x->(isfinite(x) ? abs(x) : oftype(x,NaN)), a))) test_approx_eq(va, vb, astr, bstr) = @@ -1097,22 +1097,22 @@ function partial_linear_indexing_warning(n) end # Deprecate Array(T, dims...) in favor of proper type constructors -@deprecate Array{T,N}(::Type{T}, d::NTuple{N,Int}) Array{T}(d) -@deprecate Array{T}(::Type{T}, d::Int...) Array{T}(d...) -@deprecate Array{T}(::Type{T}, m::Int) Array{T}(m) -@deprecate Array{T}(::Type{T}, m::Int,n::Int) Array{T}(m,n) -@deprecate Array{T}(::Type{T}, m::Int,n::Int,o::Int) Array{T}(m,n,o) -@deprecate Array{T}(::Type{T}, d::Integer...) Array{T}(convert(Tuple{Vararg{Int}}, d)) -@deprecate Array{T}(::Type{T}, m::Integer) Array{T}(Int(m)) -@deprecate Array{T}(::Type{T}, m::Integer,n::Integer) Array{T}(Int(m),Int(n)) -@deprecate Array{T}(::Type{T}, m::Integer,n::Integer,o::Integer) Array{T}(Int(m),Int(n),Int(o)) +@deprecate Array(::Type{T}, d::NTuple{N,Int}) where {T,N} Array{T}(d) +@deprecate Array(::Type{T}, d::Int...) where {T} Array{T}(d...) +@deprecate Array(::Type{T}, m::Int) where {T} Array{T}(m) +@deprecate Array(::Type{T}, m::Int,n::Int) where {T} Array{T}(m,n) +@deprecate Array(::Type{T}, m::Int,n::Int,o::Int) where {T} Array{T}(m,n,o) +@deprecate Array(::Type{T}, d::Integer...) where {T} Array{T}(convert(Tuple{Vararg{Int}}, d)) +@deprecate Array(::Type{T}, m::Integer) where {T} Array{T}(Int(m)) +@deprecate Array(::Type{T}, m::Integer,n::Integer) where {T} Array{T}(Int(m),Int(n)) +@deprecate Array(::Type{T}, m::Integer,n::Integer,o::Integer) where {T} Array{T}(Int(m),Int(n),Int(o)) # Likewise for SharedArrays -@deprecate SharedArray{T,N}(::Type{T}, dims::Dims{N}; kwargs...) SharedArray{T}(dims; kwargs...) -@deprecate SharedArray{T}(::Type{T}, dims::Int...; kwargs...) SharedArray{T}(dims...; kwargs...) -@deprecate(SharedArray{T,N}(filename::AbstractString, ::Type{T}, dims::NTuple{N,Int}, offset; kwargs...), +@deprecate SharedArray(::Type{T}, dims::Dims{N}; kwargs...) where {T,N} SharedArray{T}(dims; kwargs...) +@deprecate SharedArray(::Type{T}, dims::Int...; kwargs...) where {T} SharedArray{T}(dims...; kwargs...) +@deprecate(SharedArray(filename::AbstractString, ::Type{T}, dims::NTuple{N,Int}, offset; kwargs...) where {T,N}, SharedArray{T}(filename, dims, offset; kwargs...)) -@deprecate(SharedArray{T}(filename::AbstractString, ::Type{T}, dims::NTuple, offset; kwargs...), +@deprecate(SharedArray(filename::AbstractString, ::Type{T}, dims::NTuple, offset; kwargs...) where {T}, SharedArray{T}(filename, dims, offset; kwargs...)) @noinline function is_intrinsic_expr(x::ANY) @@ -1123,14 +1123,14 @@ end @deprecate EachLine(stream, ondone) EachLine(stream, ondone=ondone) # These conversions should not be defined, see #19896 -@deprecate convert{T<:Number}(::Type{T}, x::Dates.Period) convert(T, Dates.value(x)) -@deprecate convert{T<:Dates.Period}(::Type{T}, x::Real) T(x) -@deprecate convert{R<:Real}(::Type{R}, x::Dates.DateTime) R(Dates.value(x)) -@deprecate convert{R<:Real}(::Type{R}, x::Dates.Date) R(Dates.value(x)) -@deprecate convert(::Type{Dates.DateTime}, x::Real) Dates.DateTime(Dates.Millisecond(x)) -@deprecate convert(::Type{Dates.Date}, x::Real) Dates.Date(Dates.Day(x)) - -function colon{T<:Dates.Period}(start::T, stop::T) +@deprecate convert(::Type{T}, x::Dates.Period) where {T<:Number} convert(T, Dates.value(x)) +@deprecate convert(::Type{T}, x::Real) where {T<:Dates.Period} T(x) +@deprecate convert(::Type{R}, x::Dates.DateTime) where {R<:Real} R(Dates.value(x)) +@deprecate convert(::Type{R}, x::Dates.Date) where {R<:Real} R(Dates.value(x)) +@deprecate convert(::Type{Dates.DateTime}, x::Real) Dates.DateTime(Dates.Millisecond(x)) +@deprecate convert(::Type{Dates.Date}, x::Real) Dates.Date(Dates.Day(x)) + +function colon(start::T, stop::T) where T<:Dates.Period depwarn("$start:$stop is deprecated, use $start:$T(1):$stop instead.", :colon) colon(start, T(1), stop) end @@ -1141,13 +1141,13 @@ end Base.@deprecate_binding GitAnyObject GitUnknownObject @deprecate owner(x) repository(x) false - @deprecate get{T<:GitObject}(::Type{T}, repo::GitRepo, x) T(repo, x) false - @deprecate get{T<:GitObject}(::Type{T}, repo::GitRepo, oid::GitHash, oid_size::Int) T(repo, GitShortHash(oid, oid_size)) false + @deprecate get(::Type{T}, repo::GitRepo, x) where {T<:GitObject} T(repo, x) false + @deprecate get(::Type{T}, repo::GitRepo, oid::GitHash, oid_size::Int) where {T<:GitObject} T(repo, GitShortHash(oid, oid_size)) false @deprecate revparse(repo::GitRepo, objname::AbstractString) GitObject(repo, objname) false @deprecate object(repo::GitRepo, te::GitTreeEntry) GitObject(repo, te) false @deprecate commit(ann::GitAnnotated) GitHash(ann) false @deprecate lookup(repo::GitRepo, oid::GitHash) GitBlob(repo, oid) false - function Base.cat{T<:GitObject}(repo::GitRepo, ::Type{T}, spec::Union{AbstractString,AbstractGitHash}) + function Base.cat(repo::GitRepo, ::Type{T}, spec::Union{AbstractString,AbstractGitHash}) where T<:GitObject Base.depwarn("cat(repo::GitRepo, T, spec) is deprecated, use content(T(repo, spec))", :cat) try return content(GitBlob(repo, spec)) @@ -1198,9 +1198,9 @@ step(r::Use_StepRangeLen_Instead) = r.step/r.divisor length(r::Use_StepRangeLen_Instead) = Integer(r.len) -first{T}(r::Use_StepRangeLen_Instead{T}) = convert(T, r.start/r.divisor) +first(r::Use_StepRangeLen_Instead{T}) where {T} = convert(T, r.start/r.divisor) -last{T}(r::Use_StepRangeLen_Instead{T}) = convert(T, (r.start + (r.len-1)*r.step)/r.divisor) +last(r::Use_StepRangeLen_Instead{T}) where {T} = convert(T, (r.start + (r.len-1)*r.step)/r.divisor) start(r::Use_StepRangeLen_Instead) = 0 done(r::Use_StepRangeLen_Instead, i::Int) = length(r) <= i @@ -1322,7 +1322,7 @@ end for fname in (:ones, :zeros) @eval @deprecate ($fname)(T::Type, arr) ($fname)(T, size(arr)) @eval ($fname)(T::Type, i::Integer) = ($fname)(T, (i,)) - @eval function ($fname){T}(::Type{T}, arr::Array{T}) + @eval function ($fname)(::Type{T}, arr::Array{T}) where T msg = string("`", $fname, "{T}(::Type{T}, arr::Array{T})` is deprecated, use ", "`", $fname , "(T, size(arr))` instead. ", ) From 50c3588c7a6d4abd3c9005de61de350ee6ac7c0e Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sun, 25 Jun 2017 11:18:46 -0700 Subject: [PATCH 28/88] add test for filtering empty iterator (#22528) (cherry picked from commit 96fca0d796e922827091d638903a3db101b21925) --- test/iterators.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/iterators.jl b/test/iterators.jl index 5e8e368c33269..44538ba5058bc 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -406,3 +406,9 @@ end @testset "product iterator infinite loop" begin @test collect(product(1:1, (1, "2"))) == [(1, 1) (1, "2")] end + +@testset "filter empty iterable #16704" begin + arr = filter(n -> true, 1:0) + @test length(arr) == 0 + @test eltype(arr) == Int +end From e8ed71232b38a34635c0f84492b75872b622e305 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sun, 25 Jun 2017 09:55:11 -0700 Subject: [PATCH 29/88] test fixed inlining bug #18735 (#22530) (cherry picked from commit 6218a1f9260a3cc428ae79eee96dd38e77b6ce7b) --- test/misc.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/misc.jl b/test/misc.jl index 599aadf854064..572f720689b0a 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -742,3 +742,9 @@ end # module # @test @test_warn "A{T}(x::S) where {T, S} is deprecated, use f() instead." A{Int}(1.) # @test @test_nowarn A{Int}(1.) end + +@testset "inline bug #18735" begin + @noinline f(n) = n ? error() : Int + g() = Union{f(true)} + @test_throws ErrorException g() +end From 78831902cc412e298c5fcc94dae1e4382c8e7cd0 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Tue, 4 Jul 2017 12:53:50 +0200 Subject: [PATCH 30/88] document SparseVector and SparseMatrixCSC (#22541) rewrite manual chapter to include sparse vectors also some references to SparseVector/SparseMatrix (cherry picked from commit ee4c5bcf5864de5aad4e44222cb2990dd8d48dd7) --- base/sparse/cholmod.jl | 16 ++--- base/sparse/sparsematrix.jl | 22 ++++--- base/sparse/sparsevector.jl | 11 +++- doc/src/devdocs/subarrays.md | 7 ++- doc/src/manual/arrays.md | 116 ++++++++++++++++++++++++++--------- doc/src/manual/interfaces.md | 5 +- doc/src/stdlib/arrays.md | 4 +- 7 files changed, 128 insertions(+), 53 deletions(-) diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index 2d812d07bba85..9ea5bd3bd07cd 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -1365,8 +1365,8 @@ end cholfact!(F::Factor, A; shift = 0.0) -> CHOLMOD.Factor Compute the Cholesky (``LL'``) factorization of `A`, reusing the symbolic -factorization `F`. `A` must be a `SparseMatrixCSC`, `Symmetric{SparseMatrixCSC}`, -or `Hermitian{SparseMatrixCSC}`. Note that even if `A` doesn't +factorization `F`. `A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/ +[`Hermitian`](@ref) view of a `SparseMatrixCSC`. Note that even if `A` doesn't have the type tag, it must still be symmetric or Hermitian. See also [`cholfact`](@ref). @@ -1406,8 +1406,8 @@ end cholfact(A; shift = 0.0, perm = Int[]) -> CHOLMOD.Factor Compute the Cholesky factorization of a sparse positive definite matrix `A`. -`A` must be a `SparseMatrixCSC`, `Symmetric{SparseMatrixCSC}`, or -`Hermitian{SparseMatrixCSC}`. Note that even if `A` doesn't +`A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/[`Hermitian`](@ref) +view of a `SparseMatrixCSC`. Note that even if `A` doesn't have the type tag, it must still be symmetric or Hermitian. A fill-reducing permutation is used. `F = cholfact(A)` is most frequently used to solve systems of equations with `F\\b`, @@ -1457,8 +1457,8 @@ end ldltfact!(F::Factor, A; shift = 0.0) -> CHOLMOD.Factor Compute the ``LDL'`` factorization of `A`, reusing the symbolic factorization `F`. -`A` must be a `SparseMatrixCSC`, `Symmetric{SparseMatrixCSC}`, or -`Hermitian{SparseMatrixCSC}`. Note that even if `A` doesn't +`A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/[`Hermitian`](@ref) +view of a `SparseMatrixCSC`. Note that even if `A` doesn't have the type tag, it must still be symmetric or Hermitian. See also [`ldltfact`](@ref). @@ -1505,8 +1505,8 @@ end ldltfact(A; shift = 0.0, perm=Int[]) -> CHOLMOD.Factor Compute the ``LDL'`` factorization of a sparse matrix `A`. -`A` must be a `SparseMatrixCSC`, `Symmetric{SparseMatrixCSC}`, or -`Hermitian{SparseMatrixCSC}`. Note that even if `A` doesn't +`A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/[`Hermitian`](@ref) +view of a `SparseMatrixCSC`. Note that even if `A` doesn't have the type tag, it must still be symmetric or Hermitian. A fill-reducing permutation is used. `F = ldltfact(A)` is most frequently used to solve systems of equations `A*x = b` with `F\\b`. The returned diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index e0db9edd6fe8e..974c43da233c2 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -5,12 +5,18 @@ # Assumes that row values in rowval for each column are sorted # issorted(rowval[colptr[i]:(colptr[i+1]-1)]) == true +""" + SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti} + +Matrix type for storing sparse matrices in the +[Compressed Sparse Column](@ref man-csc) format. +""" struct SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti} m::Int # Number of rows n::Int # Number of columns colptr::Vector{Ti} # Column i is in colptr[i]:(colptr[i+1]-1) - rowval::Vector{Ti} # Row values of nonzeros - nzval::Vector{Tv} # Nonzero values + rowval::Vector{Ti} # Row indices of stored values + nzval::Vector{Tv} # Stored values, typically nonzeros function SparseMatrixCSC{Tv,Ti}(m::Integer, n::Integer, colptr::Vector{Ti}, rowval::Vector{Ti}, nzval::Vector{Tv}) where {Tv,Ti<:Integer} @@ -530,8 +536,8 @@ Parent of and expert driver for [`sparse`](@ref); see [`sparse`](@ref) for basic usage. This method allows the user to provide preallocated storage for `sparse`'s intermediate objects and result as described below. This capability enables more efficient successive construction -of `SparseMatrixCSC`s from coordinate representations, and also enables extraction of an -unsorted-column representation of the result's transpose at no additional cost. +of [`SparseMatrixCSC`](@ref)s from coordinate representations, and also enables extraction +of an unsorted-column representation of the result's transpose at no additional cost. This method consists of three major steps: (1) Counting-sort the provided coordinate representation into an unsorted-row CSR form including repeated entries. (2) Sweep through @@ -731,8 +737,8 @@ and `length(X.nzval) >= nnz(A)`). Column-permutation `q`'s length must match `A count (`length(q) == A.n`). This method is the parent of several methods performing transposition and permutation -operations on `SparseMatrixCSC`s. As this method performs no argument checking, prefer -the safer child methods (`[c]transpose[!]`, `permute[!]`) to direct use. +operations on [`SparseMatrixCSC`](@ref)s. As this method performs no argument checking, +prefer the safer child methods (`[c]transpose[!]`, `permute[!]`) to direct use. This method implements the `HALFPERM` algorithm described in F. Gustavson, "Two fast algorithms for sparse matrices: multiplication and permuted transposition," ACM TOMS 4(3), @@ -850,8 +856,8 @@ end C::SparseMatrixCSC{Tv,Ti}, workcolptr::Vector{Ti}) See [`permute!`](@ref) for basic usage. Parent of `permute!` -methods operating on `SparseMatrixCSC`s where the source and destination matrices are the -same. See `unchecked_noalias_permute!` +methods operating on [`SparseMatrixCSC`](@ref)s where the source and destination matrices +are the same. See `unchecked_noalias_permute!` for additional information; these methods are identical but for this method's requirement of the additional `workcolptr`, `length(workcolptr) >= A.n + 1`, which enables efficient handling of the source-destination aliasing. diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index 7922954c13248..cdb7f53f1c39b 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -9,10 +9,15 @@ import Base.LinAlg: promote_to_array_type, promote_to_arrays_ ### Types +""" + SparseVector{Tv,Ti<:Integer} <: AbstractSparseVector{Tv,Ti} + +Vector type for storing sparse vectors. +""" struct SparseVector{Tv,Ti<:Integer} <: AbstractSparseVector{Tv,Ti} - n::Int # the number of elements - nzind::Vector{Ti} # the indices of nonzeros - nzval::Vector{Tv} # the values of nonzeros + n::Int # Length of the sparse vector + nzind::Vector{Ti} # Indices of stored values + nzval::Vector{Tv} # Stored values, typically nonzeros function SparseVector{Tv,Ti}(n::Integer, nzind::Vector{Ti}, nzval::Vector{Tv}) where {Tv,Ti<:Integer} n >= 0 || throw(ArgumentError("The number of elements must be non-negative.")) diff --git a/doc/src/devdocs/subarrays.md b/doc/src/devdocs/subarrays.md index 16a11c39cf7e3..d77c7f68fb96b 100644 --- a/doc/src/devdocs/subarrays.md +++ b/doc/src/devdocs/subarrays.md @@ -17,9 +17,10 @@ allows you to combine these styles of indexing: for example, a 3d array `A3` can For `Array`s, linear indexing appeals to the underlying storage format: an array is laid out as a contiguous block of memory, and hence the linear index is just the offset (+1) of the corresponding entry relative to the beginning of the array. However, this is not true for many other `AbstractArray` -types: examples include `SparseMatrixCSC`, arrays that require some kind of computation (such -as interpolation), and the type under discussion here, `SubArray`. For these types, the underlying -information is more naturally described in terms of cartesian indexes. +types: examples include [`SparseMatrixCSC`](@ref), arrays that require some kind of +computation (such as interpolation), and the type under discussion here, `SubArray`. +For these types, the underlying information is more naturally described in terms of +cartesian indexes. You can manually convert from a cartesian index to a linear index with `sub2ind`, and vice versa using `ind2sub`. `getindex` and `setindex!` functions for `AbstractArray` types may include similar diff --git a/doc/src/manual/arrays.md b/doc/src/manual/arrays.md index b99ae2cb050df..755c66e9fc343 100644 --- a/doc/src/manual/arrays.md +++ b/doc/src/manual/arrays.md @@ -702,18 +702,19 @@ julia> r 0.0 0.866567 ``` -## Sparse Matrices +## Sparse Vectors and Matrices -[Sparse matrices](https://en.wikipedia.org/wiki/Sparse_matrix) are matrices that contain enough -zeros that storing them in a special data structure leads to savings in space and execution time. -Sparse matrices may be used when operations on the sparse representation of a matrix lead to considerable -gains in either time or space when compared to performing the same operations on a dense matrix. +Julia has built-in support for sparse vectors and +[sparse matrices](https://en.wikipedia.org/wiki/Sparse_matrix). Sparse arrays are arrays +that contain enough zeros that storing them in a special data structure leads to savings +in space and execution time, compared to dense arrays. -### Compressed Sparse Column (CSC) Storage +### [Compressed Sparse Column (CSC) Sparse Matrix Storage](@id man-csc) In Julia, sparse matrices are stored in the [Compressed Sparse Column (CSC) format](https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_column_.28CSC_or_CCS.29). -Julia sparse matrices have the type `SparseMatrixCSC{Tv,Ti}`, where `Tv` is the type of the stored -values, and `Ti` is the integer type for storing column pointers and row indices.: +Julia sparse matrices have the type [`SparseMatrixCSC{Tv,Ti}`](@ref), where `Tv` is the +type of the stored values, and `Ti` is the integer type for storing column pointers and +row indices. The internal representation of `SparseMatrixCSC` is as follows: ```julia struct SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti} @@ -743,19 +744,50 @@ In some applications, it is convenient to store explicit zero values in a `Spars *are* accepted by functions in `Base` (but there is no guarantee that they will be preserved in mutating operations). Such explicitly stored zeros are treated as structural nonzeros by many routines. The [`nnz()`](@ref) function returns the number of elements explicitly stored in the -sparse data structure, including structural nonzeros. In order to count the exact number of actual -values that are nonzero, use [`countnz()`](@ref), which inspects every stored element of a sparse -matrix. +sparse data structure, including structural nonzeros. In order to count the exact number of +numerical nonzeros, use [`countnz()`](@ref), which inspects every stored element of a sparse +matrix. [`dropzeros()`](@ref), and the in-place [`dropzeros!()`](@ref), can be used to +remove stored zeros from the sparse matrix. -### Sparse matrix constructors +```jldoctest +julia> A = sparse([1, 2, 3], [1, 2, 3], [0, 2, 0]) +3×3 SparseMatrixCSC{Int64,Int64} with 3 stored entries: + [1, 1] = 0 + [2, 2] = 2 + [3, 3] = 0 + +julia> dropzeros(A) +3×3 SparseMatrixCSC{Int64,Int64} with 1 stored entry: + [2, 2] = 2 +``` + +### Sparse Vector Storage + +Sparse vectors are stored in a close analog to compressed sparse column format for sparse +matrices. In Julia, sparse vectors have the type [`SparseVector{Tv,Ti}`](@ref) where `Tv` +is the type of the stored values and `Ti` the integer type for the indices. The internal +representation is as follows: + +```julia +struct SparseVector{Tv,Ti<:Integer} <: AbstractSparseVector{Tv,Ti} + n::Int # Length of the sparse vector + nzind::Vector{Ti} # Indices of stored values + nzval::Vector{Tv} # Stored values, typically nonzeros +end +``` + +As for [`SparseMatrixCSC`](@ref), the `SparseVector` type can also contain explicitly +stored zeros. (See [Sparse Matrix Storage](@ref man-csc).). -The simplest way to create sparse matrices is to use functions equivalent to the [`zeros()`](@ref) -and [`eye()`](@ref) functions that Julia provides for working with dense matrices. To produce -sparse matrices instead, you can use the same names with an `sp` prefix: +### Sparse Vector and Matrix Constructors + +The simplest way to create sparse arrays is to use functions equivalent to the [`zeros()`](@ref) +and [`eye()`](@ref) functions that Julia provides for working with dense arrays. To produce +sparse arrays instead, you can use the same names with an `sp` prefix: ```jldoctest -julia> spzeros(3,5) -3×5 SparseMatrixCSC{Float64,Int64} with 0 stored entries +julia> spzeros(3) +3-element SparseVector{Float64,Int64} with 0 stored entries julia> speye(3,5) 3×5 SparseMatrixCSC{Float64,Int64} with 3 stored entries: @@ -764,9 +796,14 @@ julia> speye(3,5) [3, 3] = 1.0 ``` -The [`sparse()`](@ref) function is often a handy way to construct sparse matrices. It takes as -its input a vector `I` of row indices, a vector `J` of column indices, and a vector `V` of stored -values. `sparse(I,J,V)` constructs a sparse matrix such that `S[I[k], J[k]] = V[k]`. +The [`sparse()`](@ref) function is often a handy way to construct sparse arrays. For +example, to construct a sparse matrix we can input a vector `I` of row indices, a vector +`J` of column indices, and a vector `V` of stored values (this is also known as the +[COO (coordinate) format](https://en.wikipedia.org/wiki/Sparse_matrix#Coordinate_list_.28COO.29)). +`sparse(I,J,V)` then constructs a sparse matrix such that `S[I[k], J[k]] = V[k]`. The +equivalent sparse vector constructor is [`sparsevec`](@ref), which takes the (row) index +vector `I` and the vector `V` with the stored values and constructs a sparse vector `R` +such that `R[I[k]] = V[k]`. ```jldoctest sparse_function julia> I = [1, 4, 3, 5]; J = [4, 7, 18, 9]; V = [1, 2, -5, 3]; @@ -777,20 +814,38 @@ julia> S = sparse(I,J,V) [4 , 7] = 2 [5 , 9] = 3 [3 , 18] = -5 + +julia> R = sparsevec(I,V) +5-element SparseVector{Int64,Int64} with 4 stored entries: + [1] = 1 + [3] = -5 + [4] = 2 + [5] = 3 ``` -The inverse of the [`sparse()`](@ref) function is [`findn()`](@ref), which retrieves the inputs -used to create the sparse matrix. +The inverse of the [`sparse()`](@ref) and [`sparsevec`](@ref) functions is +[`findnz()`](@ref), which retrieves the inputs used to create the sparse array. +There is also a [`findn`](@ref) function which only returns the index vectors. ```jldoctest sparse_function +julia> findnz(S) +([1, 4, 5, 3], [4, 7, 9, 18], [1, 2, 3, -5]) + julia> findn(S) ([1, 4, 5, 3], [4, 7, 9, 18]) -julia> findnz(S) -([1, 4, 5, 3], [4, 7, 9, 18], [1, 2, 3, -5]) +julia> findnz(R) +([1, 3, 4, 5], [1, -5, 2, 3]) + +julia> findn(R) +4-element Array{Int64,1}: + 1 + 3 + 4 + 5 ``` -Another way to create sparse matrices is to convert a dense matrix into a sparse matrix using +Another way to create a sparse array is to convert a dense array into a sparse array using the [`sparse()`](@ref) function: ```jldoctest @@ -801,9 +856,14 @@ julia> sparse(eye(5)) [3, 3] = 1.0 [4, 4] = 1.0 [5, 5] = 1.0 + +julia> sparse([1.0, 0.0, 1.0]) +3-element SparseVector{Float64,Int64} with 2 stored entries: + [1] = 1.0 + [3] = 1.0 ``` -You can go in the other direction using the [`full()`](@ref) function. The [`issparse()`](@ref) +You can go in the other direction using the [`Array`](@ref) constructor. The [`issparse()`](@ref) function can be used to query if a matrix is sparse. ```jldoctest @@ -828,8 +888,8 @@ differ from their dense counterparts in that the resulting matrix follows the sa as a given sparse matrix `S`, or that the resulting sparse matrix has density `d`, i.e. each matrix element has a probability `d` of being non-zero. -Details can be found in the [Sparse Vectors and Matrices](@ref) section of the standard library -reference. +Details can be found in the [Sparse Vectors and Matrices](@ref stdlib-sparse-arrays) +section of the standard library reference. | Sparse | Dense | Description | |:-------------------------- |:---------------------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 91ae4fbe21e57..3b679db3d8aa8 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -231,8 +231,9 @@ arrays are simple: just define `getindex(A::ArrayType, i::Int)`. When the array indexed with a multidimensional set of indices, the fallback `getindex(A::AbstractArray, I...)()` efficiently converts the indices into one linear index and then calls the above method. `IndexCartesian()` arrays, on the other hand, require methods to be defined for each supported dimensionality with -`ndims(A)``Int` indices. For example, the builtin `SparseMatrixCSC` type only supports two dimensions, -so it just defines `getindex(A::SparseMatrixCSC, i::Int, j::Int)()`. The same holds for `setindex!()`. +`ndims(A)` `Int` indices. For example, the built-in [`SparseMatrixCSC`](@ref) type only +supports two dimensions, so it just defines +`getindex(A::SparseMatrixCSC, i::Int, j::Int)`. The same holds for `setindex!()`. Returning to the sequence of squares from above, we could instead define it as a subtype of an `AbstractArray{Int, 1}`: diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index 2fc43f52bee53..9249b11925f47 100644 --- a/doc/src/stdlib/arrays.md +++ b/doc/src/stdlib/arrays.md @@ -172,12 +172,14 @@ Base.ror! Base.ror ``` -## Sparse Vectors and Matrices +## [Sparse Vectors and Matrices](@id stdlib-sparse-arrays) Sparse vectors and matrices largely support the same set of operations as their dense counterparts. The following functions are specific to sparse arrays. ```@docs +Base.SparseArrays.SparseVector +Base.SparseArrays.SparseMatrixCSC Base.SparseArrays.sparse Base.SparseArrays.sparsevec Base.SparseArrays.issparse From b51fce7a43d705e0c6e3df280a7e1473fb813bc5 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 27 Jun 2017 18:12:20 -0700 Subject: [PATCH 31/88] fix bug in HTML showing of method table of function with parameters Ref #22586 (cherry picked from commit 2f1d30d3640ed3bd574174cb1159e77176c7c2e4) --- base/methodshow.jl | 14 ++++++++------ test/show.jl | 10 ++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/base/methodshow.jl b/base/methodshow.jl index c9f304a509c9e..9db69228b0cae 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -97,15 +97,16 @@ end function show(io::IO, m::Method; kwtype::Nullable{DataType}=Nullable{DataType}()) tv, decls, file, line = arg_decl_parts(m) sig = unwrap_unionall(m.sig) - ft = unwrap_unionall(sig.parameters[1]) + ft0 = sig.parameters[1] + ft = unwrap_unionall(ft0) d1 = decls[1] if sig === Tuple print(io, m.name) decls = Any[(), ("...", "")] - elseif ft <: Function && + elseif ft <: Function && isa(ft, DataType) && isdefined(ft.name.module, ft.name.mt.name) && # TODO: more accurate test? (tn.name === "#" name) - ft == typeof(getfield(ft.name.module, ft.name.mt.name)) + ft0 === typeof(getfield(ft.name.module, ft.name.mt.name)) print(io, ft.name.mt.name) elseif isa(ft, DataType) && ft.name === Type.body.name && isleaftype(ft) f = ft.parameters[1] @@ -222,11 +223,12 @@ end function show(io::IO, ::MIME"text/html", m::Method; kwtype::Nullable{DataType}=Nullable{DataType}()) tv, decls, file, line = arg_decl_parts(m) sig = unwrap_unionall(m.sig) - ft = sig.parameters[1] + ft0 = sig.parameters[1] + ft = unwrap_unionall(ft0) d1 = decls[1] - if ft <: Function && + if ft <: Function && isa(ft, DataType) && isdefined(ft.name.module, ft.name.mt.name) && - ft == typeof(getfield(ft.name.module, ft.name.mt.name)) + ft0 === typeof(getfield(ft.name.module, ft.name.mt.name)) print(io, ft.name.mt.name) elseif isa(ft, DataType) && ft.name === Type.body.name && isleaftype(ft) f = ft.parameters[1] diff --git a/test/show.jl b/test/show.jl index a0f9fa3bd32c9..8e104277f8e50 100644 --- a/test/show.jl +++ b/test/show.jl @@ -669,3 +669,13 @@ let m = which(T20332{Int}(), (Int,)), end @test sprint(show, Main) == "Main" + +struct f_with_params{t} <: Function +end + +(::f_with_params)(x) = 2x + +let io = IOBuffer() + show(io, MIME"text/html"(), f_with_params.body.name.mt) + @test contains(String(take!(io)), "f_with_params") +end From eb8cbce05ea450260f2d4b9d81b95450259342d9 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 30 Jun 2017 01:03:33 -0600 Subject: [PATCH 32/88] fix #22624, crash in certain circular type definitions This was caused by expanding a type's field types in the wrong environment. Ref #22627 (cherry picked from commit 211e8d156c25a081ebfc1b415358126f54bc83f9) --- src/jltypes.c | 54 ++++++++++++++++++++++++++++----------------------- test/core.jl | 10 ++++++++++ 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/jltypes.c b/src/jltypes.c index f3a869236fc13..ae2d91574b5d8 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -827,11 +827,7 @@ JL_DLLEXPORT jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *v) } typedef struct _jl_typestack_t { - union { - jl_value_t *ua; - jl_datatype_t *tt; - }; - jl_value_t *ua_new; + jl_datatype_t *tt; struct _jl_typestack_t *prev; } jl_typestack_t; @@ -999,8 +995,8 @@ static jl_value_t *normalize_vararg(jl_value_t *va) return va; } -static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, - int cacheable, jl_typestack_t *stack, jl_typeenv_t *env) +static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, + int cacheable, jl_typestack_t *stack, jl_typeenv_t *env) { jl_ptls_t ptls = jl_get_ptls_states(); jl_typestack_t top; @@ -1198,6 +1194,25 @@ static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **i return (jl_value_t*)ndt; } +// Build an environment mapping a TypeName's parameters to parameter values. +// This is the environment needed for instantiating a type's supertype and field types. +static jl_value_t *inst_datatype_env(jl_value_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, + int cacheable, jl_typestack_t *stack, jl_typeenv_t *env, int c) +{ + if (jl_is_datatype(dt)) + return inst_datatype_inner((jl_datatype_t*)dt, p, iparams, ntp, cacheable, stack, env); + assert(jl_is_unionall(dt)); + jl_unionall_t *ua = (jl_unionall_t*)dt; + jl_typeenv_t e = { ua->var, iparams[c], env }; + return inst_datatype_env(ua->body, p, iparams, ntp, cacheable, stack, &e, c+1); +} + +static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, + int cacheable, jl_typestack_t *stack) +{ + return inst_datatype_env(dt->name->wrapper, p, iparams, ntp, cacheable, stack, NULL, 0); +} + static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params) { int cacheable = 1; @@ -1206,7 +1221,7 @@ static jl_tupletype_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec cacheable = 0; } jl_datatype_t *ndt = (jl_datatype_t*)inst_datatype(jl_anytuple_type, params, p, np, - cacheable, NULL, NULL); + cacheable, NULL); return ndt; } @@ -1222,12 +1237,12 @@ JL_DLLEXPORT jl_tupletype_t *jl_apply_tuple_type_v(jl_value_t **p, size_t np) jl_datatype_t *jl_inst_concrete_tupletype(jl_svec_t *p) { - return (jl_datatype_t*)inst_datatype(jl_anytuple_type, p, jl_svec_data(p), jl_svec_len(p), 1, NULL, NULL); + return (jl_datatype_t*)inst_datatype(jl_anytuple_type, p, jl_svec_data(p), jl_svec_len(p), 1, NULL); } jl_datatype_t *jl_inst_concrete_tupletype_v(jl_value_t **p, size_t np) { - return (jl_datatype_t*)inst_datatype(jl_anytuple_type, NULL, p, np, 1, NULL, NULL); + return (jl_datatype_t*)inst_datatype(jl_anytuple_type, NULL, p, np, 1, NULL); } static jl_svec_t *inst_all(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack, int check) @@ -1294,8 +1309,7 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ if (cacheable && !jl_is_leaf_type(pi)) cacheable = 0; } - jl_value_t *result = inst_datatype((jl_datatype_t*)tt, ip_heap, iparams, ntp, cacheable, - stack, env); + jl_value_t *result = inst_datatype((jl_datatype_t*)tt, ip_heap, iparams, ntp, cacheable, stack); JL_GC_POP(); return result; } @@ -1320,29 +1334,22 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t return (jl_value_t*)t; } if (jl_is_unionall(t)) { - jl_typestack_t *sp = stack; - while (sp != NULL) { - if (sp->ua == t) - return sp->ua_new; - sp = sp->prev; - } if (!jl_has_free_typevars(t)) return t; jl_unionall_t *ua = (jl_unionall_t*)t; jl_value_t *res=NULL, *lb=ua->var->lb, *ub=ua->var->ub; JL_GC_PUSH3(&lb, &ub, &res); res = jl_new_struct(jl_unionall_type, ua->var, NULL); - jl_typestack_t top = { {t}, res, stack }; if (jl_has_bound_typevars(ua->var->lb, env)) - lb = inst_type_w_(ua->var->lb, env, &top, check); + lb = inst_type_w_(ua->var->lb, env, stack, check); if (jl_has_bound_typevars(ua->var->ub, env)) - ub = inst_type_w_(ua->var->ub, env, &top, check); + ub = inst_type_w_(ua->var->ub, env, stack, check); if (lb != ua->var->lb || ub != ua->var->ub) { ((jl_unionall_t*)res)->var = jl_new_typevar(ua->var->name, lb, ub); jl_gc_wb(res, ((jl_unionall_t*)res)->var); } jl_typeenv_t newenv = { ua->var, (jl_value_t*)((jl_unionall_t*)res)->var, env }; - jl_value_t *newbody = inst_type_w_(ua->body, &newenv, &top, check); + jl_value_t *newbody = inst_type_w_(ua->body, &newenv, stack, check); if (newbody == (jl_value_t*)jl_emptytuple_type) { // NTuple{0} => Tuple{} can make a typevar disappear res = (jl_value_t*)jl_emptytuple_type; @@ -1394,8 +1401,7 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t // if t's parameters are not bound in the environment, return it uncopied (#9378) if (!bound) { JL_GC_POP(); return (jl_value_t*)t; } - jl_value_t *result = inst_datatype((jl_datatype_t*)tt, NULL, iparams, ntp, cacheable, - stack, env); + jl_value_t *result = inst_datatype((jl_datatype_t*)tt, NULL, iparams, ntp, cacheable, stack); JL_GC_POP(); return result; } diff --git a/test/core.jl b/test/core.jl index 427c00cb72996..968cbd42c1664 100644 --- a/test/core.jl +++ b/test/core.jl @@ -177,6 +177,16 @@ struct C21923{T,N}; v::C21923{T,M} where M; end struct D21923{T,N}; v::D21923{T}; end @test fieldtype(D21923, 1) == D21923 +# issue #22624, more circular definitions +struct T22624{A,B,C}; v::Vector{T22624{Int64,A}}; end +let elT = T22624.body.body.body.types[1].parameters[1] + @test elT == T22624{Int64, T22624.var, C} where C + elT2 = elT.body.types[1].parameters[1] + @test elT2 == T22624{Int64, Int64, C} where C + @test elT2.body.types[1].parameters[1] === elT2 + @test isleaftype(elT2.body.types[1]) +end + # issue #3890 mutable struct A3890{T1} x::Matrix{Complex{T1}} From 7da0638ec1208c2437392a1a70985e1619d67bec Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 30 Jun 2017 12:32:56 -0600 Subject: [PATCH 33/88] speed up common cases of type application. helps #22593 Ref #22593 (cherry picked from commit 7035cba1e91d56241edb8911ea6ea44051691471) --- src/jltypes.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/jltypes.c b/src/jltypes.c index ae2d91574b5d8..1489c4387faf9 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -748,15 +748,35 @@ static int within_typevar(jl_value_t *t, jl_value_t *vlb, jl_value_t *vub) return jl_subtype(vlb, lb) && jl_subtype(ub, vub); } +typedef struct _jl_typestack_t jl_typestack_t; + +static jl_value_t *inst_datatype(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, + int cacheable, jl_typestack_t *stack); + jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n) { if (tc == (jl_value_t*)jl_anytuple_type) return (jl_value_t*)jl_apply_tuple_type_v(params, n); if (tc == (jl_value_t*)jl_uniontype_type) return (jl_value_t*)jl_type_union(params, n); + size_t i; + if (n > 1) { + // detect common case of applying a wrapper, where we know that all parameters will + // end up as direct parameters of a certain datatype, which can be optimized. + jl_value_t *u = jl_unwrap_unionall(tc); + if (jl_is_datatype(u) && n == jl_nparams((jl_datatype_t*)u) && + ((jl_datatype_t*)u)->name->wrapper == tc) { + int cacheable = 1; + for(i=0; i < n; i++) { + if (jl_has_free_typevars(params[i])) { + cacheable = 0; break; + } + } + return inst_datatype((jl_datatype_t*)u, NULL, params, n, cacheable, NULL); + } + } JL_GC_PUSH1(&tc); jl_value_t *tc0 = tc; - size_t i; for (i=0; i < n; i++) { if (!jl_is_unionall(tc0)) jl_error("too many parameters for type"); From bb81ca38a117164283aba0df5f95e88278fdcacc Mon Sep 17 00:00:00 2001 From: angusmoore Date: Fri, 30 Jun 2017 13:34:02 +1000 Subject: [PATCH 34/88] Handle 32 bit architecture when creating float ranges Ref #22644 (cherry picked from commit b9034e7a92ee0d4991c29fdc8686d9f128b30334) (cherry picked from commit dd4d8eb6b8aee22b030f19a3012ca096f8903476) (cherry picked from commit a07f7676f5ac741d58a20d3cf9709ec8da7e9cda) (cherry picked from commit f502e1c0e3bd03e3542a0bbad0fc52a41e5af08f) (cherry picked from commit ca60ff5a6420554a5a88317119a171f5923c9b26) (cherry picked from commit 5018fd6af4fb183751ce33bb1c5c8bdd4937373e) (cherry picked from commit 8713fa3a51a3ad408509a2d131fbcb0420e72f80) (cherry picked from commit 7772517ea188440e7e1c5e64ff11908e14629dab) (cherry picked from commit 4de1a518d08c0cec1a79d118933ef41e42751011) (cherry picked from commit 7f163ba20ecbd4d7abf190d05927088bd73e28fc) --- base/docs/helpdb/Base.jl | 10 +++++++++- base/floatfuncs.jl | 1 + base/twiceprecision.jl | 10 +++++----- test/floatfuncs.jl | 10 +++++++--- test/ranges.jl | 7 +++++-- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 22d05c4aefeb2..5ea2cad7b1cfa 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -1318,7 +1318,15 @@ bswap The largest integer losslessly representable by the given floating-point DataType `T`. """ -maxintfloat +maxintfloat(T) + +""" + maxintfloat(T, S) + +The largest integer losslessly representable by the given floating-point DataType `T` that +also does not exceed the maximum integer representable by the integer DataType `S`. +""" +maxintfloat(T, S) """ delete!(collection, key) diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index a5973c7d99986..88f5723a9ebd0 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -20,6 +20,7 @@ maxintfloat(::Type{Float64}) = 9007199254740992. maxintfloat(::Type{Float32}) = Float32(16777216.) maxintfloat(::Type{Float16}) = Float16(2048f0) maxintfloat(x::T) where {T<:AbstractFloat} = maxintfloat(T) +maxintfloat(::Type{S}, ::Type{T}) where {S<:AbstractFloat, T<:Integer} = min(maxintfloat(S), S(typemax(T))) maxintfloat() = maxintfloat(Float64) isinteger(x::AbstractFloat) = (x - trunc(x) == 0) diff --git a/base/twiceprecision.jl b/base/twiceprecision.jl index 539afe54cee62..8c1ececfb45bc 100644 --- a/base/twiceprecision.jl +++ b/base/twiceprecision.jl @@ -106,7 +106,7 @@ end function floatrange(a::AbstractFloat, st::AbstractFloat, len::Real, divisor::AbstractFloat) T = promote_type(typeof(a), typeof(st), typeof(divisor)) - m = maxintfloat(T) + m = maxintfloat(T, Int) if abs(a) <= m && abs(st) <= m && abs(divisor) <= m ia, ist, idivisor = round(Int, a), round(Int, st), round(Int, divisor) if ia == a && ist == st && idivisor == divisor @@ -131,7 +131,7 @@ function colon(start::T, step::T, stop::T) where T<:Union{Float16,Float32,Float6 if start_d != 0 && stop_d != 0 && T(start_n/start_d) == start && T(stop_n/stop_d) == stop den = lcm(start_d, step_d) # use same denominator for start and step - m = maxintfloat(T) + m = maxintfloat(T, Int) if den != 0 && abs(start*den) <= m && abs(step*den) <= m && # will round succeed? rem(den, start_d) == 0 && rem(den, step_d) == 0 # check lcm overflow start_n = round(Int, start*den) @@ -167,7 +167,7 @@ function range(a::T, st::T, len::Integer) where T<:Union{Float16,Float32,Float64 if start_d != 0 && step_d != 0 && T(start_n/start_d) == a && T(step_n/step_d) == st den = lcm(start_d, step_d) - m = maxintfloat(T) + m = maxintfloat(T, Int) if abs(den*a) <= m && abs(den*st) <= m && rem(den, start_d) == 0 && rem(den, step_d) == 0 start_n = round(Int, den*a) @@ -257,7 +257,7 @@ function _convertSRL(::Type{StepRangeLen{T,R,S}}, r::Range{U}) where {T,R,S,U} if start_d != 0 && step_d != 0 && U(start_n/start_d) == f && U(step_n/step_d) == s den = lcm(start_d, step_d) - m = maxintfloat(T) + m = maxintfloat(T, Int) if den != 0 && abs(f*den) <= m && abs(s*den) <= m && rem(den, start_d) == 0 && rem(den, step_d) == 0 start_n = round(Int, f*den) @@ -326,7 +326,7 @@ function linspace(start::T, stop::T, len::Integer) where T<:Union{Float16,Float3 stop_n, stop_d = rat(stop) if start_d != 0 && stop_d != 0 den = lcm(start_d, stop_d) - m = maxintfloat(T) + m = maxintfloat(T, Int) if den != 0 && abs(den*start) <= m && abs(den*stop) <= m start_n = round(Int, den*start) stop_n = round(Int, den*stop) diff --git a/test/floatfuncs.jl b/test/floatfuncs.jl index 3fee77d56dbe3..30e189b372ae9 100644 --- a/test/floatfuncs.jl +++ b/test/floatfuncs.jl @@ -14,11 +14,15 @@ end # maxintfloat -@test maxintfloat(Float16) == Float16(2048f0) +@test maxintfloat(Float16) === Float16(2048f0) for elty in (Float16,Float32,Float64) - @test maxintfloat(rand(elty)) == maxintfloat(elty) + @test maxintfloat(rand(elty)) === maxintfloat(elty) end -@test maxintfloat() == maxintfloat(Float64) +@test maxintfloat() === maxintfloat(Float64) +@test maxintfloat(Float64, Int32) === 2147483647.0 +@test maxintfloat(Float32, Int32) === maxintfloat(Float32) +@test maxintfloat(Float64, Int16) === 32767.0 +@test maxintfloat(Float64, Int64) === maxintfloat(Float64) # isinteger for elty in (Float16,Float32,Float64) diff --git a/test/ranges.jl b/test/ranges.jl index 506c030db9a33..9cc49c5e51f3a 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -356,8 +356,6 @@ for T = (Float32, Float64,), i = 1:2^15, n = 1:5 # FIXME: these fail some small portion of the time @test_skip start == first(r) @test_skip stop == last(r) - # FIXME: linspace construction fails on 32-bit - Sys.WORD_SIZE == 64 || continue l = linspace(start,stop,n) @test n == length(l) # FIXME: these fail some small portion of the time @@ -365,6 +363,11 @@ for T = (Float32, Float64,), i = 1:2^15, n = 1:5 @test_skip stop == last(l) end +# Inexact errors on 32 bit architectures. #22613 +@test first(linspace(log(0.2), log(10.0), 10)) == log(0.2) +@test last(linspace(log(0.2), log(10.0), 10)) == log(10.0) +@test length(Base.floatrange(-3e9, 1.0, 1, 1.0)) == 1 + # linspace & ranges with very small endpoints for T = (Float32, Float64) z = zero(T) From 585f387700a34d98940fccd4a6619adb89e0f15d Mon Sep 17 00:00:00 2001 From: Animesh Kashyap Date: Mon, 3 Jul 2017 11:31:24 -0500 Subject: [PATCH 35/88] Add efficient hashing of CartesianIndex objects Ref #22657 (cherry picked from commit a18ffdb92a1bd277695de0f6894e2d2372e7ae67) --- base/multidimensional.jl | 10 ++++++++++ test/arrayops.jl | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 5384f66020e40..bb9bdafb519ef 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -123,6 +123,16 @@ module IteratorsMD _isless(ret, ::Tuple{}, ::Tuple{}) = ifelse(ret==1, true, false) icmp(a, b) = ifelse(isless(a,b), 1, ifelse(a==b, 0, -1)) + # hashing + const cartindexhash_seed = UInt == UInt64 ? 0xd60ca92f8284b8b0 : 0xf2ea7c2e + function Base.hash(ci::CartesianIndex, h::UInt) + h += cartindexhash_seed + for i in ci.I + h = hash(i, h) + end + return h + end + # Iteration """ CartesianRange(Istart::CartesianIndex, Istop::CartesianIndex) -> R diff --git a/test/arrayops.jl b/test/arrayops.jl index d9fd754199edc..dc4c60675ba45 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -1549,6 +1549,11 @@ end @test CartesianRange((3,-7:7)) == CartesianRange(CartesianIndex{2}(3,-7),CartesianIndex{2}(3,7)) end +# All we really care about is that we have an optimized +# implementation, but the seed is a useful way to check that. +@test hash(CartesianIndex()) == Base.IteratorsMD.cartindexhash_seed +@test hash(CartesianIndex(1, 2)) != hash((1, 2)) + @testset "itr, start, done, next" begin r = 2:3 itr = eachindex(r) From 875bfceddf8f922e748d118c3213ad03bc0f0359 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sun, 2 Jul 2017 17:06:23 -0600 Subject: [PATCH 36/88] small improvements to (de)serialize perf. helps #22593 also add a `sizehint!` method for `ObjectIdDict` Ref #22661 (cherry picked from commit 99fd74edce5a7849b9c710c0040a16afa3763bb1) --- base/associative.jl | 10 ++++++++++ base/serialize.jl | 12 +++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/base/associative.jl b/base/associative.jl index 8c276ee8dc078..564c3fd5578bd 100644 --- a/base/associative.jl +++ b/base/associative.jl @@ -412,6 +412,16 @@ function rehash!(t::ObjectIdDict, newsz = length(t.ht)) t end +function sizehint!(t::ObjectIdDict, newsz) + newsz = _tablesz(newsz*2) # *2 for keys and values in same array + oldsz = length(t.ht) + # grow at least 25% + if newsz < (oldsz*5)>>2 + return t + end + rehash!(t, newsz) +end + function setindex!(t::ObjectIdDict, v::ANY, k::ANY) if t.ndel >= ((3*length(t.ht))>>2) rehash!(t, max(length(t.ht)>>1, 32)) diff --git a/base/serialize.jl b/base/serialize.jl index d453e9e0a33f9..382f667f90712 100644 --- a/base/serialize.jl +++ b/base/serialize.jl @@ -130,7 +130,7 @@ end # cycle handling function serialize_cycle(s::AbstractSerializer, x) - offs = get(s.table, x, -1) + offs = get(s.table, x, -1)::Int if offs != -1 if offs <= typemax(UInt16) writetag(s.io, SHORTBACKREF_TAG) @@ -212,8 +212,8 @@ function serialize(s::AbstractSerializer, x::Symbol) end function serialize_array_data(s::IO, a) - elty = eltype(a) - if elty === Bool && !isempty(a) + isempty(a) && return 0 + if eltype(a) === Bool last = a[1] count = 1 for i = 2:length(a) @@ -246,7 +246,8 @@ function serialize(s::AbstractSerializer, a::Array) if isbits(elty) serialize_array_data(s.io, a) else - for i in eachindex(a) + sizehint!(s.table, div(length(a),4)) # prepare for lots of pointers + @inbounds for i in eachindex(a) if isassigned(a, i) serialize(s, a[i]) else @@ -865,10 +866,11 @@ function deserialize_array(s::AbstractSerializer) end A = Array{elty, length(dims)}(dims) s.table[slot] = A + sizehint!(s.table, s.counter + div(length(A),4)) for i = eachindex(A) tag = Int32(read(s.io, UInt8)::UInt8) if tag != UNDEFREF_TAG - A[i] = handle_deserialize(s, tag) + @inbounds A[i] = handle_deserialize(s, tag) end end return A From 656813da2ce44d24148649babe897be56d2ac4ee Mon Sep 17 00:00:00 2001 From: Amit Murthy Date: Fri, 7 Jul 2017 11:40:28 +0530 Subject: [PATCH 37/88] fix bug in serialization of nested anonymous functions across processes (#22675) (cherry picked from commit e90f29db30f81f340d4f36669b27ac5a281e2a7f) --- base/distributed/clusterserialize.jl | 5 +++-- base/serialize.jl | 4 +++- test/distributed_exec.jl | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/base/distributed/clusterserialize.jl b/base/distributed/clusterserialize.jl index 163d8d9636284..9fb256d1e261b 100644 --- a/base/distributed/clusterserialize.jl +++ b/base/distributed/clusterserialize.jl @@ -88,8 +88,9 @@ function serialize(s::ClusterSerializer, g::GlobalRef) # Record if required and then invoke the default GlobalRef serializer. sym = g.name if g.mod === Main && isdefined(g.mod, sym) - v = getfield(Main, sym) - if (binding_module(Main, sym) === Main) && (s.anonfunc_id != 0) + if (binding_module(Main, sym) === Main) && (s.anonfunc_id != 0) && + !startswith(string(sym), "#") # Anonymous functions are handled via FULL_GLOBALREF_TAG + push!(get!(s.glbs_in_tnobj, s.anonfunc_id, []), sym) end end diff --git a/base/serialize.jl b/base/serialize.jl index 382f667f90712..a1a688374dcdc 100644 --- a/base/serialize.jl +++ b/base/serialize.jl @@ -435,7 +435,9 @@ function serialize(s::AbstractSerializer, t::Task) end function serialize(s::AbstractSerializer, g::GlobalRef) - if g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name) + if (g.mod === __deserialized_types__ ) || + (g.mod === Main && isdefined(g.mod, g.name) && isconst(g.mod, g.name)) + v = getfield(g.mod, g.name) unw = unwrap_unionall(v) if isa(unw,DataType) && v === unw.name.wrapper && should_send_whole_type(s, unw) diff --git a/test/distributed_exec.jl b/test/distributed_exec.jl index 3f12f5cb15075..99d2157e26292 100644 --- a/test/distributed_exec.jl +++ b/test/distributed_exec.jl @@ -1590,6 +1590,20 @@ let thrown = false @test thrown end +#19463 +function foo19463() + w1 = workers()[1] + w2 = workers()[2] + w3 = workers()[3] + + b1 = () -> 1 + b2 = () -> fetch(@spawnat w1 b1()) + 1 + b3 = () -> fetch(@spawnat w2 b2()) + 1 + b4 = () -> fetch(@spawnat w3 b3()) + 1 + b4() +end +@test foo19463() == 4 + # Testing clear! function setup_syms(n, pids) syms = [] From 46e68a9ee4322c9e8f011bfafd752a125f20c653 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 6 Jul 2017 09:03:53 -0400 Subject: [PATCH 38/88] simplified a test Ref #22694 (cherry picked from commit 5bc6b9664b181a55901b76cdd6006feba13e72f4) --- test/unicode/utf8proc.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/unicode/utf8proc.jl b/test/unicode/utf8proc.jl index 403c2775f9897..b5623cc94d062 100644 --- a/test/unicode/utf8proc.jl +++ b/test/unicode/utf8proc.jl @@ -311,9 +311,6 @@ end h = hash(str) @test hash(g) == h @test convert(GenericString, g) == str - io = IOBuffer() - show(io, g) - check = "length-14 GraphemeIterator{String} for \"$str\"" - @test String(take!(io)) == check + @test repr(g) == "length-14 GraphemeIterator{String} for \"$str\"" end end From b2feda0dc4266994b69406cd739e8ba8cc1a927a Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 6 Jul 2017 09:03:08 -0400 Subject: [PATCH 39/88] fix graphemes eltype for substrings (fixes #22693) better grapheme-substring testset name test substring grapheme eltype Ref #22694 (cherry picked from commit b13e9d1cca137515a9cfcccbb1c3ec142bb1b6bf) --- base/strings/utf8proc.jl | 1 + test/unicode/utf8proc.jl | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/base/strings/utf8proc.jl b/base/strings/utf8proc.jl index 8b90af4d06c7c..a3ebd46ca0414 100644 --- a/base/strings/utf8proc.jl +++ b/base/strings/utf8proc.jl @@ -354,6 +354,7 @@ letter combined with an accent mark is a single grapheme.) graphemes(s::AbstractString) = GraphemeIterator{typeof(s)}(s) eltype(::Type{GraphemeIterator{S}}) where {S} = SubString{S} +eltype(::Type{GraphemeIterator{SubString{S}}}) where {S} = SubString{S} function length(g::GraphemeIterator) c0 = Char(0x00ad) # soft hyphen (grapheme break always allowed after this) diff --git a/test/unicode/utf8proc.jl b/test/unicode/utf8proc.jl index b5623cc94d062..d06106a9abefc 100644 --- a/test/unicode/utf8proc.jl +++ b/test/unicode/utf8proc.jl @@ -314,3 +314,9 @@ end @test repr(g) == "length-14 GraphemeIterator{String} for \"$str\"" end end + +@testset "#22693: substring graphemes" begin + g = graphemes(SubString("123α56789", 1, 6)) + @test eltype(g) == SubString{String} + @test collect(g) == ["1","2","3","α","5"] +end From 015cf6d9d78c59d7f01cc3495e0fb19e9d60c2eb Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 6 Jul 2017 22:15:38 -0600 Subject: [PATCH 40/88] fix and simplify subtyping rule for `x <: Type{T}` Ref #22701 (cherry picked from commit f0e3678d4cfa922341e26ceaf85dba5ce99f0c14) --- src/subtype.c | 16 ++-------------- test/subtype.jl | 4 +++- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/subtype.c b/src/subtype.c index b0a4a81e1705b..68aa745668fa9 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -883,21 +883,9 @@ static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param) } if (jl_is_type_type(y) && !jl_is_type_type(x) && x != (jl_value_t*)jl_typeofbottom_type) { jl_value_t *tp0 = jl_tparam0(yd); - if (!jl_is_typevar(tp0)) + if (!jl_is_typevar(tp0) || !jl_is_kind(x)) return 0; - if (!jl_is_kind(x)) return 0; - jl_varbinding_t *yy = lookup(e, (jl_tvar_t*)tp0); - jl_value_t *ub = yy ? yy->ub : ((jl_tvar_t*)tp0)->ub; - int ans; - if (ub == (jl_value_t*)jl_any_type) { - ans = subtype((jl_value_t*)jl_type_type, y, e, param); - } - else { - e->invdepth++; - ans = forall_exists_equal(x, tp0, e); - e->invdepth--; - } - return ans; + return subtype((jl_value_t*)jl_type_type, y, e, param); } while (xd != jl_any_type && xd->name != yd->name) { if (xd->super == NULL) diff --git a/test/subtype.jl b/test/subtype.jl index 4ca0b5b288566..56b0773fefa1f 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -446,7 +446,9 @@ function test_Type() @test isa(Int, @UnionAll T<:Number Type{T}) @test !isa(DataType, @UnionAll T<:Number Type{T}) - @test DataType <: (@UnionAll T<:Type Type{T}) + @test !(DataType <: (@UnionAll T<:Type Type{T})) + @test isa(DataType, (@UnionAll T<:Type Type{T})) + @test isa(Tuple{},Type{Tuple{}}) @test !(Tuple{Int,} <: (@UnionAll T<:Tuple Type{T})) @test isa(Tuple{Int}, (@UnionAll T<:Tuple Type{T})) From 48e850efcd67de7e48b8f4918f91b056ff902f0a Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Sun, 9 Jul 2017 22:31:48 -0400 Subject: [PATCH 41/88] Remove extra JL_GC_POP in emit_a_ccall error path Ref #22730 (cherry picked from commit 390efc081a8ace8934f57a56f785d8e950d656ea) --- src/ccall.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index 6edf5cd222532..f0553fb4d9ee6 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1977,7 +1977,6 @@ jl_cgval_t function_sig_t::emit_a_ccall( else { if (jl_is_abstract_ref_type(jargty)) { emit_error("ccall: & on a Ref{T} argument is invalid", ctx); - JL_GC_POP(); return jl_cgval_t(); } v = julia_to_address(largty, jargty_in_env, unionall_env, arg, @@ -1986,7 +1985,6 @@ jl_cgval_t function_sig_t::emit_a_ccall( } if (isa(v)) { - JL_GC_POP(); return jl_cgval_t(); } assert(v->getType() == pargty); From 524ec4abb0b42be1f5f3329242908dd22b69920d Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 10 Jul 2017 14:19:09 -0400 Subject: [PATCH 42/88] fix field types of Method type Ref #22743 (cherry picked from commit 93531aa856e6c25c967ddcf821277680639920a2) --- src/jltypes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jltypes.c b/src/jltypes.c index 1489c4387faf9..ea7418dfb19a9 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -2085,8 +2085,8 @@ void jl_init_types(void) jl_svecset(jl_methtable_type->types, 7, jl_int32_type); // DWORD #endif jl_svecset(jl_methtable_type->types, 8, jl_int32_type); // uint32_t + jl_svecset(jl_method_type->types, 10, jl_method_instance_type); jl_svecset(jl_method_type->types, 11, jl_method_instance_type); - jl_svecset(jl_method_type->types, 12, jl_method_instance_type); jl_svecset(jl_method_instance_type->types, 12, jl_voidpointer_type); jl_svecset(jl_method_instance_type->types, 13, jl_voidpointer_type); jl_svecset(jl_method_instance_type->types, 14, jl_voidpointer_type); From 5496bb28add44209b0a6ac56bc3dbaeb0d09a7cb Mon Sep 17 00:00:00 2001 From: Pablo Zubieta Date: Mon, 10 Jul 2017 18:52:40 -0500 Subject: [PATCH 43/88] Fix repeat for arrays of arrays Ref #22747 (cherry picked from commit e8e475e6651d43c3c46442fceee396e32cfd1ed7) --- base/abstractarraymath.jl | 2 +- test/arrayops.jl | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 0430293b46737..726c8c06ae851 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -415,7 +415,7 @@ _reperr(s, n, N) = throw(ArgumentError("number of " * s * " repetitions " * n = inner[i] inner_indices[i] = (1:n) + ((c[i] - 1) * n) end - R[inner_indices...] = A[c] + fill!(view(R, inner_indices...), A[c]) end end diff --git a/test/arrayops.jl b/test/arrayops.jl index dc4c60675ba45..cfe5a5c34c036 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -793,6 +793,11 @@ end R = repeat(1:2, inner=(3,), outer=(2,)) @test R == [1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2] + # Arrays of arrays + @test repeat([[1], [2]], inner=2) == [[1], [1], [2], [2]] + @test repeat([[1], [2]], outer=2) == [[1], [2], [1], [2]] + @test repeat([[1], [2]], inner=2, outer=2) == [[1], [1], [2], [2], [1], [1], [2], [2]] + @test size(repeat([1], inner=(0,))) == (0,) @test size(repeat([1], outer=(0,))) == (0,) @test size(repeat([1 1], inner=(0, 1))) == (0, 2) From 7347c57a77cc196560177e62390f637d86f65727 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 11 Jul 2017 18:26:36 -0400 Subject: [PATCH 44/88] look up constructors by type name in depwarn. fixes #21972 add deprecation_exec.jl for testing deprecations with other `--depwarn` settings Ref #22764 (cherry picked from commit b1c196e49ab108fad5b41722d3e4f9ff53a8e703) --- base/deprecated.jl | 9 ++++++ test/deprecation_exec.jl | 64 ++++++++++++++++++++++++++++++++++++++++ test/misc.jl | 51 +++++++------------------------- 3 files changed, 83 insertions(+), 41 deletions(-) create mode 100644 test/deprecation_exec.jl diff --git a/base/deprecated.jl b/base/deprecated.jl index 9e8836a17fb20..118e8039b23a5 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -96,6 +96,15 @@ function firstcaller(bt::Array{Ptr{Void},1}, funcsyms) end found && @goto found found = lkup.func in funcsyms + # look for constructor type name + if !found && !isnull(lkup.linfo) + li = get(lkup.linfo) + ft = ccall(:jl_first_argument_datatype, Any, (Any,), li.def.sig) + if isa(ft,DataType) && ft.name === Type.body.name + ft = unwrap_unionall(ft.parameters[1]) + found = (isa(ft,DataType) && ft.name.name in funcsyms) + end + end end end return StackTraces.UNKNOWN diff --git a/test/deprecation_exec.jl b/test/deprecation_exec.jl new file mode 100644 index 0000000000000..564740af45329 --- /dev/null +++ b/test/deprecation_exec.jl @@ -0,0 +1,64 @@ +using Base.Test + +module DeprecationTests # to test @deprecate + f() = true + + # test the Symbol path of @deprecate + @deprecate f1 f + @deprecate f2 f false # test that f2 is not exported + + # test the Expr path of @deprecate + @deprecate f3() f() + @deprecate f4() f() false # test that f4 is not exported + @deprecate f5(x::T) where T f() + + # test deprecation of a constructor + struct A{T} end + @deprecate A{T}(x::S) where {T, S} f() +end # module +module Foo1234 + export foo1234 + foo1234(x) = x+1 +end + +# issue #21972 +struct T21972 + @noinline function T21972() + Base.depwarn("something", :T21972) + new() + end +end + +@testset "@deprecate" begin + using .DeprecationTests + using .Foo1234 + @test foo1234(3) == 4 + + # enable when issue #22043 is fixed + # @test @test_warn "f1 is deprecated, use f instead." f1() + # @test @test_nowarn f1() + + # @test_throws UndefVarError f2() # not exported + # @test @test_warn "f2 is deprecated, use f instead." DeprecationTests.f2() + # @test @test_nowarn DeprecationTests.f2() + + # @test @test_warn "f3() is deprecated, use f() instead." f3() + # @test @test_nowarn f3() + + # @test_throws UndefVarError f4() # not exported + # @test @test_warn "f4() is deprecated, use f() instead." DeprecationTests.f4() + # @test @test_nowarn DeprecationTests.f4() + + # @test @test_warn "f5(x::T) where T is deprecated, use f() instead." f5(1) + # @test @test_nowarn f5(1) + + # @test @test_warn "A{T}(x::S) where {T, S} is deprecated, use f() instead." A{Int}(1.) + # @test @test_nowarn A{Int}(1.) + + # issue #21972 + @noinline function f21972() + T21972() + end + @test_warn "deprecated" f21972() + @test_nowarn f21972() +end diff --git a/test/misc.jl b/test/misc.jl index 572f720689b0a..ba6e20da774fb 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -702,49 +702,18 @@ end @test ltoh(0x102030405060708) == 0x102030405060708 @test htol(0x102030405060708) == 0x102030405060708 -module DeprecationTests # to test @deprecate - f() = true - - # test the Symbol path of @deprecate - @deprecate f1 f - @deprecate f2 f false # test that f2 is not exported - - # test the Expr path of @deprecate - @deprecate f3() f() - @deprecate f4() f() false # test that f4 is not exported - @deprecate f5(x::T) where T f() - - # test deprecation of a constructor - struct A{T} end - @deprecate A{T}(x::S) where {T, S} f() -end # module - -@testset "@deprecate" begin - using .DeprecationTests - # enable when issue #22043 is fixed - # @test @test_warn "f1 is deprecated, use f instead." f1() - # @test @test_nowarn f1() - - # @test_throws UndefVarError f2() # not exported - # @test @test_warn "f2 is deprecated, use f instead." DeprecationTests.f2() - # @test @test_nowarn DeprecationTests.f2() - - # @test @test_warn "f3() is deprecated, use f() instead." f3() - # @test @test_nowarn f3() - - # @test_throws UndefVarError f4() # not exported - # @test @test_warn "f4() is deprecated, use f() instead." DeprecationTests.f4() - # @test @test_nowarn DeprecationTests.f4() - - # @test @test_warn "f5(x::T) where T is deprecated, use f() instead." f5(1) - # @test @test_nowarn f5(1) - - # @test @test_warn "A{T}(x::S) where {T, S} is deprecated, use f() instead." A{Int}(1.) - # @test @test_nowarn A{Int}(1.) -end - @testset "inline bug #18735" begin @noinline f(n) = n ? error() : Int g() = Union{f(true)} @test_throws ErrorException g() end + +include("testenv.jl") + +let flags = Cmd(filter(a->!contains(a, "depwarn"), test_exeflags.exec)) + local cmd = `$test_exename $flags deprecation_exec.jl` + + if !success(pipeline(cmd; stdout=STDOUT, stderr=STDERR)) + error("Deprecation test failed, cmd : $cmd") + end +end From a5d70fe11ed6b4c7c79445a9bf8bfd61a58cefd4 Mon Sep 17 00:00:00 2001 From: Andreas Noack Date: Sun, 16 Jul 2017 22:31:22 -0400 Subject: [PATCH 45/88] Make var(Range) type stable (#22778) Fixes #22773 (cherry picked from commit e5ca3681ff8d18b11ea7c02c00d8723fb9fb417c) --- base/statistics.jl | 20 +++++++++++--------- test/statistics.jl | 12 ++++++++++++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/base/statistics.jl b/base/statistics.jl index 21124f3e0ec5e..2b9969afa95bd 100644 --- a/base/statistics.jl +++ b/base/statistics.jl @@ -210,22 +210,24 @@ varm(iterable, m::Number; corrected::Bool=true) = ## variances over ranges function varm(v::Range, m::Number) - f = first(v) - m - s = step(v) - l = length(v) + f = first(v) - m + s = step(v) + l = length(v) + vv = f^2 * l / (l - 1) + f * s * l + s^2 * l * (2 * l - 1) / 6 if l == 0 || l == 1 - return NaN + return typeof(vv)(NaN) end - return f^2 * l / (l - 1) + f * s * l + s^2 * l * (2 * l - 1) / 6 + return vv end function var(v::Range) - s = step(v) - l = length(v) + s = step(v) + l = length(v) + vv = abs2(s) * (l + 1) * l / 12 if l == 0 || l == 1 - return NaN + return typeof(vv)(NaN) end - return abs2(s) * (l + 1) * l / 12 + return vv end diff --git a/test/statistics.jl b/test/statistics.jl index 9e7dbf09f6374..d6ecc279a440a 100644 --- a/test/statistics.jl +++ b/test/statistics.jl @@ -113,6 +113,18 @@ X = [2 3 1 -1; 7 4 5 -4] @test isnan(var(1:1)) @test isnan(var(1:-1)) +@test @inferred(var(1.0:8.0)) == 6. +@test varm(1.0:8.0,1.0) == varm(collect(1.0:8.0),1) +@test isnan(varm(1.0:1.0,1.0)) +@test isnan(var(1.0:1.0)) +@test isnan(var(1.0:-1.0)) + +@test @inferred(var(1.0f0:8.0f0)) === 6.f0 +@test varm(1.0f0:8.0f0,1.0f0) == varm(collect(1.0f0:8.0f0),1) +@test isnan(varm(1.0f0:1.0f0,1.0f0)) +@test isnan(var(1.0f0:1.0f0)) +@test isnan(var(1.0f0:-1.0f0)) + @test varm([1,2,3], 2) ≈ 1. @test var([1,2,3]) ≈ 1. @test var([1,2,3]; corrected=false) ≈ 2.0/3 From 46e176d76a8594af1f704c7e0bb7c5bfdc0578f7 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 14 Jul 2017 18:57:56 -0400 Subject: [PATCH 46/88] fix `let` bound functions with `where` and return types Ref #22817 (cherry picked from commit a0f11e5f9adf31e07adbe674db0f699c15f40867) --- src/julia-syntax.scm | 29 ++++++++++++----------------- src/macroexpand.scm | 3 +-- test/parse.jl | 8 ++++++++ 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index ddf261da58c60..24b52a63a68c8 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1104,6 +1104,18 @@ (eq? (caar binds) '=)) ;; some kind of assignment (cond + ((eventually-call (cadar binds)) + ;; f()=c + (let ((asgn (butlast (expand-forms (car binds)))) + (name (assigned-name (cadar binds)))) + (if (not (symbol? name)) + (error "invalid let syntax")) + (loop (cdr binds) + `(scope-block + (block + (local-def ,name) + ,asgn + ,blk))))) ((or (symbol? (cadar binds)) (decl? (cadar binds))) (let ((vname (decl-var (cadar binds)))) @@ -1123,23 +1135,6 @@ (local-def ,(cadar binds)) (= ,vname ,(caddar binds)) ,blk)))))) - ((and (pair? (cadar binds)) - (or (eq? (caadar binds) 'call) - (and (eq? (caadar binds) 'comparison) - (length= (cadar binds) 4)))) - ;; f()=c - (let* ((asgn (butlast (expand-forms (car binds)))) - (name (cadr (cadar binds))) - (name (cond ((symbol? name) name) - ((and (pair? name) (eq? (car name) 'curly)) - (cadr name)) - (else (error "invalid let syntax"))))) - (loop (cdr binds) - `(scope-block - (block - (local-def ,name) - ,asgn - ,blk))))) ;; (a, b, c, ...) = rhs ((and (pair? (cadar binds)) (eq? (caadar binds) 'tuple)) diff --git a/src/macroexpand.scm b/src/macroexpand.scm index 8f2ad5784bb87..1832274e2e1e4 100644 --- a/src/macroexpand.scm +++ b/src/macroexpand.scm @@ -107,8 +107,7 @@ ;; a=b -> add argument (loop (cdr binds) (cons (decl-var (cadar binds)) vars))) - ((and (pair? (cadar binds)) - (eq? (caadar binds) 'call)) + ((eventually-call (cadar binds)) ;; f()=c (let ((asgn (cadr (julia-expand0 (car binds))))) (loop (cdr binds) diff --git a/test/parse.jl b/test/parse.jl index 91fb3fa163000..6cb27fd06ba4e 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -1204,6 +1204,14 @@ module Test21607 end === 1.0 end +# let-bound functions with `where` and static parameters +@test let f()::Int = 2.0 + f() +end === 2 +@test let (f(x::T)::Tuple{Int,Any}) where {T} = (3.0, T) + f("") +end === (3, String) + # issue #19351 # adding return type decl should not affect parse of function body @test :(t(abc) = 3).args[2] == :(t(abc)::Int = 3).args[2] From fb082ccd3a8d8b7ac3cb7deedc78867b3898c634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gunnar=20Farneb=C3=A4ck?= Date: Mon, 17 Jul 2017 16:12:15 +0200 Subject: [PATCH 47/88] Bugfix for zero matrix in A_ldiv_B! for QRPivoted (#22831) * Bugfix for zero matrix in A_ldiv_B! for QRPivoted. * Address review comments. (cherry picked from commit bf47fd90f50bfda87fad5a501829e91a60c7d0d0) --- base/linalg/qr.jl | 8 ++++++-- test/linalg/qr.jl | 8 ++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/base/linalg/qr.jl b/base/linalg/qr.jl index 13aa153575f1e..1e5941b60a1d6 100644 --- a/base/linalg/qr.jl +++ b/base/linalg/qr.jl @@ -694,9 +694,13 @@ function A_ldiv_B!(A::QRPivoted{T}, B::StridedMatrix{T}, rcond::Real) where T<:B mA, nA = size(A.factors) nr = min(mA,nA) nrhs = size(B, 2) - if nr == 0 return zeros(T, 0, nrhs), 0 end + if nr == 0 + return zeros(T, 0, nrhs), 0 + end ar = abs(A.factors[1]) - if ar == 0 return zeros(T, nr, nrhs), 0 end + if ar == 0 + return zeros(T, nA, nrhs), 0 + end rnk = 1 xmin = ones(T, 1) xmax = ones(T, 1) diff --git a/test/linalg/qr.jl b/test/linalg/qr.jl index 2de9f65fa774c..d7525732c1462 100644 --- a/test/linalg/qr.jl +++ b/test/linalg/qr.jl @@ -183,3 +183,11 @@ B = rand(7,2) # Issue 16520 @test_throws DimensionMismatch ones(3,2)\(1:5) + +# Issue 22810 +let + A = zeros(1, 2) + B = zeros(1, 1) + @test A \ B == zeros(2, 1) + @test qrfact(A, Val{true}) \ B == zeros(2, 1) +end From 20558e12f57f28a85f7656aab0d29d2474b43bf6 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Mon, 17 Jul 2017 11:54:15 +0200 Subject: [PATCH 48/88] Base.ndigits0z(0, b) must return 0 (fix #22837) Ref #22838 (cherry picked from commit 33ffc86c692153cd8c4b974721e66e97ee7984a1) --- base/intfuncs.jl | 1 + test/intfuncs.jl | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index e25098f2d81b3..9eea4a79081ba 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -418,6 +418,7 @@ function ndigits0znb(n::Signed, b::Int) end function ndigits0z(n::Unsigned, b::Int) + n == 0 && return 0 b < 0 && return ndigits0znb(signed(n), b) b == 2 && return sizeof(n)<<3 - leading_zeros(n) b == 8 && return (sizeof(n)<<3 - leading_zeros(n) + 2) ÷ 3 diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 547e826480c52..ed3469f906ffd 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -164,3 +164,8 @@ end # issue #15911 @inferred string(1) + +# issue #22837 +for b in [-100:-2; 2:100;] + @test Base.ndigits0z(0, b) == 0 +end From 856e413f3e42d4884985c540d7fcf5f724b2b401 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 21 Jul 2017 17:20:05 -0400 Subject: [PATCH 49/88] fix #22908, typemap ordering of `Union` vs. `Type{Union{...}}`. Ref #22909 (cherry picked from commit 7e37e5d4b319015355e19eb0eadd9cf66c6ede3b) --- src/typemap.c | 2 ++ test/specificity.jl | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/typemap.c b/src/typemap.c index b06be06415d76..3b99326620f31 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -1045,6 +1045,8 @@ jl_typemap_entry_t *jl_typemap_insert(union jl_typemap_t *cache, jl_value_t *par newrec->isleafsig = 0; // Type{} may have a higher priority than DataType else if (decl == (jl_value_t*)jl_unionall_type) newrec->isleafsig = 0; // Type{} may have a higher priority than UnionAll + else if (decl == (jl_value_t*)jl_uniontype_type) + newrec->isleafsig = 0; // Type{} may have a higher priority than Union else if (jl_is_type_type(decl)) newrec->isleafsig = 0; // Type{} may need special processing to compute the match else if (jl_is_vararg_type(decl)) diff --git a/test/specificity.jl b/test/specificity.jl index 6657f544b724b..46d7b543ecda3 100644 --- a/test/specificity.jl +++ b/test/specificity.jl @@ -172,3 +172,8 @@ let A = Tuple{T, Array{T, 1}} where T, @test args_morespecific(C, B) @test args_morespecific(C, A) end + +# issue #22908 +f22908(::Union) = 2 +f22908(::Type{Union{Int, Float32}}) = 1 +@test f22908(Union{Int, Float32}) == 1 From 776be41c26c46d4201c89f33d0d8bece13b4df8f Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 21 Jul 2017 18:24:58 -0400 Subject: [PATCH 50/88] fix `tuple_type_head` and `tuple_type_tail` on `UnionAll` Ref #22911 (cherry picked from commit 763d008bebbed1231d7ec0aed7d4d2cad40c62a5) --- base/essentials.jl | 4 ++-- test/tuple.jl | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/base/essentials.jl b/base/essentials.jl index 7c522aaed415d..cdeb952d83449 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -59,13 +59,13 @@ end argtail(x, rest...) = rest tail(x::Tuple) = argtail(x...) -tuple_type_head(T::UnionAll) = tuple_type_head(T.body) +tuple_type_head(T::UnionAll) = (@_pure_meta; UnionAll(T.var, tuple_type_head(T.body))) function tuple_type_head(T::DataType) @_pure_meta T.name === Tuple.name || throw(MethodError(tuple_type_head, (T,))) return unwrapva(T.parameters[1]) end -tuple_type_tail(T::UnionAll) = tuple_type_tail(T.body) +tuple_type_tail(T::UnionAll) = (@_pure_meta; UnionAll(T.var, tuple_type_tail(T.body))) function tuple_type_tail(T::DataType) @_pure_meta T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,))) diff --git a/test/tuple.jl b/test/tuple.jl index d59b0497cdc9f..bbf224ca0ebe2 100644 --- a/test/tuple.jl +++ b/test/tuple.jl @@ -258,3 +258,7 @@ end for n = 0:15 @test ntuple(identity, Val{n}) == ntuple(identity, n) end + +# https://github.com/JuliaLang/julia/issues/21026#issuecomment-317113307 +const VecTuple21026{T} = Tuple{VecElement{T}} +@test convert(VecTuple21026, (1,)) === (VecElement(1),) From 7994c640c14adbd4f696468f4bc8925560a29285 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 24 Jul 2017 22:43:40 -0400 Subject: [PATCH 51/88] fix codegen bug in `===` on two `SimpleVector`s Ref #22946 (cherry picked from commit 2fca4d3adf2284c8666ef65622c766f5fcf0460d) --- src/codegen.cpp | 2 ++ test/codegen.jl | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 test/codegen.jl diff --git a/src/codegen.cpp b/src/codegen.cpp index 66b7d73a6228c..1e08cfce6b336 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2620,6 +2620,8 @@ static Value *emit_f_is(const jl_cgval_t &arg1, const jl_cgval_t &arg2, jl_codec if ((jl_is_type_type(rt1) && jl_is_leaf_type(jl_tparam0(rt1))) || (jl_is_type_type(rt2) && jl_is_leaf_type(jl_tparam0(rt2)))) // can compare leaf types by pointer ptr_comparable = 1; + if (rt1 == (jl_value_t*)jl_simplevector_type && rt2 == (jl_value_t*)jl_simplevector_type) + ptr_comparable = 0; // technically mutable, but compared by contents if (ptr_comparable) { Value *varg1 = arg1.constant ? literal_pointer_val(arg1.constant) : arg1.V; Value *varg2 = arg2.constant ? literal_pointer_val(arg2.constant) : arg2.V; diff --git a/test/codegen.jl b/test/codegen.jl new file mode 100644 index 0000000000000..45e8e157e43e9 --- /dev/null +++ b/test/codegen.jl @@ -0,0 +1,9 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +function egal_svecs() + a = Core.svec(:a, :b) + b = Core.svec(:a, :b) + a === b +end +@test egal_svecs() +@test Core.svec(:a, :b) === Core.svec(:a, :b) From c1cbc9855bbb76bf3986998ded925d5e635e4fe0 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Thu, 27 Jul 2017 18:01:36 -0400 Subject: [PATCH 52/88] mark julia threads as initialized ensures that cfunction can see that Julia state is initialized on this thread also upgrades the embedding/examples test to handle exceptions better (e.g. to actually detect them) while testing for correctness Ref #22987 (cherry picked from commit 98a2d1d5734597c60f436fe3fd78f09ee735a183) --- examples/embedding/embedding-test.jl | 16 +++--- examples/embedding/embedding.c | 81 +++++++++++++++++++++++----- src/threading.c | 2 + 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/examples/embedding/embedding-test.jl b/examples/embedding/embedding-test.jl index 336169085db4c..8081bdc6d36bc 100644 --- a/examples/embedding/embedding-test.jl +++ b/examples/embedding/embedding-test.jl @@ -4,17 +4,19 @@ using Base.Test @test length(ARGS) == 1 -let +@testset "embedding example" begin stdout = Pipe() stderr = Pipe() p = spawn(pipeline(Cmd(ARGS), stdin=DevNull, stdout=stdout, stderr=stderr)) close(stdout.in) close(stderr.in) - stderr_task = @async readlines(stderr) - lines = readlines(stdout) - @test length(lines) == 6 - @test parse(Float64, lines[1]) ≈ sqrt(2) - lines = wait(stderr_task) - @test lines == ["UndefVarError(:this_function_does_not_exist)"] + stdout_task = @async readlines(stdout) + stderr = readstring(stderr) + @test stderr == "MethodError: no method matching this_function_has_no_methods()\n" @test success(p) + lines = wait(stdout_task) + @test length(lines) == 9 + @test parse(Float64, lines[1]) ≈ sqrt(2) + @test lines[8] == "called bar" + @test lines[9] == "calling new bar" end diff --git a/examples/embedding/embedding.c b/examples/embedding/embedding.c index 5bb70aadc04c2..a4172a1b18583 100644 --- a/examples/embedding/embedding.c +++ b/examples/embedding/embedding.c @@ -12,22 +12,39 @@ double my_c_sqrt(double x) return sqrt(x); } +jl_value_t *checked_eval_string(const char* code) +{ + jl_value_t *result = jl_eval_string(code); + if (jl_exception_occurred()) { + // none of these allocate, so a gc-root (JL_GC_PUSH) is not necessary + jl_call2(jl_get_function(jl_base_module, "showerror"), + jl_stderr_obj(), + jl_exception_occurred()); + jl_printf(jl_stderr_stream(), "\n"); + jl_atexit_hook(1); + exit(1); + } + assert(result && "Missing return value but no exception occurred!"); + return result; +} + int main() { jl_init(); { - // Simple running Julia code + // Simple running of Julia code - jl_eval_string("println(sqrt(2.0))"); + checked_eval_string("println(sqrt(2.0))"); } { // Accessing the return value - jl_value_t *ret = jl_eval_string("sqrt(2.0)"); + jl_value_t *ret = checked_eval_string("sqrt(2.0)"); double retDouble = jl_unbox_float64(ret); printf("sqrt(2.0) in C: %e\n", retDouble); + fflush(stdout); } { @@ -38,62 +55,98 @@ int main() jl_value_t* ret = jl_call1(func, argument); double retDouble = jl_unbox_float64(ret); printf("sqrt(2.0) in C: %e\n", retDouble); + fflush(stdout); } { // 1D arrays - jl_value_t* array_type = jl_apply_array_type( (jl_value_t*)jl_float64_type, 1 ); - jl_array_t* x = jl_alloc_array_1d(array_type , 10); + jl_value_t* array_type = jl_apply_array_type((jl_value_t*)jl_float64_type, 1); + jl_array_t* x = jl_alloc_array_1d(array_type, 10); + // JL_GC_PUSH* is required here to ensure that `x` is not deleted before + // (aka, is gc-rooted until) the program reaches the corresponding JL_GC_POP() JL_GC_PUSH1(&x); double* xData = jl_array_data(x); size_t i; - for(i=0; i println( ccall(my_c_sqrt, Float64, (Float64,), 2.0) )"); + jl_call1(call_by_ptr, jl_box_voidpointer(my_c_sqrt)); } { - // check for exceptions + // Handling exceptions gracefully - jl_eval_string("this_function_does_not_exist()"); + jl_value_t *f = checked_eval_string("function this_function_has_no_methods end"); + jl_call0(f); if (jl_exception_occurred()) { - jl_call2(jl_get_function(jl_base_module, "show"), jl_stderr_obj(), jl_exception_occurred()); + jl_call2(jl_get_function(jl_base_module, "showerror"), + jl_stderr_obj(), + jl_exception_occurred()); jl_printf(jl_stderr_stream(), "\n"); } } + { + // Creating and using a native C function handle + // to a Julia function signature + + checked_eval_string( + "function bar()\n" + " println(\"called bar\")\n" + " random_return_value = 42\n" + "end"); + checked_eval_string( + "function bar_from_c()\n" + " bar()\n" + " nothing\n" + "end"); + typedef void (*Func_VOID__VOID)(void); + jl_value_t *pbar = jl_eval_string("cfunction(bar_from_c, Void, ())"); + Func_VOID__VOID bar = (Func_VOID__VOID)jl_unbox_voidpointer(pbar); + bar(); + checked_eval_string("bar() = println(\"calling new bar\")"); + bar(); + } + int ret = 0; jl_atexit_hook(ret); return ret; diff --git a/src/threading.c b/src/threading.c index abf183ae3576d..c9958f9e69b03 100644 --- a/src/threading.c +++ b/src/threading.c @@ -263,6 +263,8 @@ static void ti_initthread(int16_t tid) #ifndef _OS_WINDOWS_ ptls->system_id = pthread_self(); #endif + assert(ptls->world_age == 0); + ptls->world_age = 1; // OK to run Julia code on this thread ptls->tid = tid; ptls->pgcstack = NULL; ptls->gc_state = 0; // GC unsafe From 25d23e41061245932b3f7bee3e14a025adb16005 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 28 Jul 2017 17:39:26 -0400 Subject: [PATCH 53/88] fix backedge restore list order in incremental serializer Ref #23012 (cherry picked from commit f1535ab1d70b7d2088a446af6a7adea17ed3e6ed) --- src/dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dump.c b/src/dump.c index baa4729c98be3..0b9d3e228da5e 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1277,8 +1277,8 @@ static void jl_collect_backedges_to(jl_method_instance_t *caller, jl_array_t *di jl_array_t **pcallees = (jl_array_t**)ptrhash_bp(&edges_map, (void*)caller), *callees = *pcallees; if (callees != HT_NOTFOUND) { - arraylist_push(to_restore, (void*)pcallees); arraylist_push(to_restore, (void*)callees); + arraylist_push(to_restore, (void*)pcallees); *pcallees = (jl_array_t*) HT_NOTFOUND; jl_array_ptr_1d_append(direct_callees, callees); size_t i, l = jl_array_len(callees); From 9db7fd942a0a33ff246d72d797554c848b8a7f27 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Mon, 31 Jul 2017 15:26:35 -0400 Subject: [PATCH 54/88] suppress warning for redefining docstrings if the symbol is in Main (#23019) suppress warning for redefining docstrings if the symbol is in Main (fixes #23011) (cherry picked from commit 4d4bdc1831ac0a9eba19b073bc36e7d4ffcb05d1) --- base/docs/Docs.jl | 6 +++--- test/docs.jl | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 23753f86f2625..3894e2635d526 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -232,9 +232,9 @@ function doc!(b::Binding, str::DocStr, sig::ANY = Union{}) m = get!(meta(), b, MultiDoc()) if haskey(m.docs, sig) # We allow for docstrings to be updated, but print a warning since it is possible - # that over-writing a docstring *may* have been accidental. - s = "replacing docs for '$b :: $sig' in module '$(current_module())'." - isdefined(Base, :STDERR) ? warn(s) : ccall(:jl_, Void, (Any,), "WARNING: $s") + # that over-writing a docstring *may* have been accidental. The warning + # is suppressed for symbols in Main, for interactive use (#23011). + current_module() == Main || warn("replacing docs for '$b :: $sig' in module '$(current_module())'.") else # The ordering of docstrings for each Binding is defined by the order in which they # are initially added. Replacing a specific docstring does not change it's ordering. diff --git a/test/docs.jl b/test/docs.jl index 18e0a21617530..dcb91d974594d 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -1010,3 +1010,10 @@ end """ ) +# issue #23011 +@test_nowarn @eval Main begin + @doc "first" f23011() = 1 + @doc "second" f23011() = 2 +end +@test Main.f23011() == 2 +@test docstrings_equal(@doc(Main.f23011), doc"second") From 5961643ae835e8a6fe63cc9739887c9c8c12d9d4 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Sat, 29 Jul 2017 09:11:21 +0200 Subject: [PATCH 55/88] Add a test for #22582/#22022. Ref #23021 (cherry picked from commit e55b1dbcb9a073d0e35e6c0aa62600437647d404) --- test/codegen.jl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/codegen.jl b/test/codegen.jl index 45e8e157e43e9..307ad38e66261 100644 --- a/test/codegen.jl +++ b/test/codegen.jl @@ -7,3 +7,17 @@ function egal_svecs() end @test egal_svecs() @test Core.svec(:a, :b) === Core.svec(:a, :b) + +# issue #22582 +function issue22582!(a::AbstractArray, b) + len = length(a) + if b + ccall(:jl_array_grow_end, Void, (Any, Csize_t), a, 1) + end + return len +end +let c = [1,2,3] + len1 = length(c) + len2 = issue22582!(c, true) + @test len1 == len2 +end From bd8ca6305b3364436d6a99676b7a2df15f2db0dd Mon Sep 17 00:00:00 2001 From: Mus M Date: Tue, 1 Aug 2017 00:26:05 -0400 Subject: [PATCH 56/88] Update deprecated tuple type call's in cfunction (#23046) Update deprecated tuple type call's in cfunction (cherry picked from commit 73ca642055ef0d54968626843212462025be7931) --- base/c.jl | 17 +++++++++++++++++ base/docs/helpdb/Base.jl | 19 ------------------- base/libdl.jl | 10 +++++----- base/libgit2/callbacks.jl | 6 +++--- base/libgit2/tree.jl | 2 +- base/libuv.jl | 22 +++++++++++----------- base/poll.jl | 6 +++--- base/threadcall.jl | 4 ++-- 8 files changed, 42 insertions(+), 44 deletions(-) diff --git a/base/c.jl b/base/c.jl index 3385e18b4e9d2..405c7e5819ca1 100644 --- a/base/c.jl +++ b/base/c.jl @@ -4,6 +4,23 @@ import Core.Intrinsics: cglobal, bitcast +""" + cfunction(function::Function, ReturnType::Type, ArgumentTypes::Type) + +Generate C-callable function pointer from Julia function. Type annotation of the return +value in the callback function is a must for situations where Julia cannot infer the return +type automatically. + +# Examples +```julia-repl +julia> function foo(x::Int, y::Int) + return x + y + end + +julia> cfunction(foo, Int, Tuple{Int,Int}) +Ptr{Void} @0x000000001b82fcd0 +``` +""" cfunction(f, r, a) = ccall(:jl_function_ptr, Ptr{Void}, (Any, Any, Any), f, r, a) if ccall(:jl_is_char_signed, Ref{Bool}, ()) diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 5ea2cad7b1cfa..4c779ddacded3 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -2066,25 +2066,6 @@ An attempted access to a [`Nullable`](@ref) with no defined value. """ NullException -""" - cfunction(function::Function, ReturnType::Type, (ArgumentTypes...)) - -Generate C-callable function pointer from Julia function. Type annotation of the return -value in the callback function is a must for situations where Julia cannot infer the return -type automatically. - -For example: - - function foo() - # body - - retval::Float64 - end - - bar = cfunction(foo, Float64, ()) -""" -cfunction - """ intersect(s1,s2...) ∩(s1,s2) diff --git a/base/libdl.jl b/base/libdl.jl index 439b10bb40410..c15ab2a4ffec6 100644 --- a/base/libdl.jl +++ b/base/libdl.jl @@ -221,7 +221,7 @@ if is_bsd() && !is_apple() phnum::Cshort end - function dl_phdr_info_callback(di::dl_phdr_info, size::Csize_t, dy_libs::Array{AbstractString,1}) + function dl_phdr_info_callback(di::dl_phdr_info, size::Csize_t, dy_libs::Vector{AbstractString}) name = unsafe_string(di.name) if !isempty(name) push!(dy_libs, name) @@ -235,8 +235,8 @@ function dllist() @static if is_linux() const callback = cfunction(dl_phdr_info_callback, Cint, - (Ref{dl_phdr_info}, Csize_t, Ref{Array{AbstractString,1}} )) - ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Array{AbstractString,1}}), callback, dynamic_libraries) + Tuple{Ref{dl_phdr_info}, Csize_t, Ref{Vector{AbstractString}}}) + ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Vector{AbstractString}}), callback, dynamic_libraries) end @static if is_apple() @@ -255,8 +255,8 @@ function dllist() @static if is_bsd() && !is_apple() const callback = cfunction(dl_phdr_info_callback, Cint, - (Ref{dl_phdr_info}, Csize_t, Ref{Array{AbstractString,1}} )) - ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Array{AbstractString,1}}), callback, dynamic_libraries) + Tuple{Ref{dl_phdr_info}, Csize_t, Ref{Vector{AbstractString}}}) + ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Vector{AbstractString}}), callback, dynamic_libraries) shift!(dynamic_libraries) end diff --git a/base/libgit2/callbacks.jl b/base/libgit2/callbacks.jl index 0a78f48949f47..639a874121bd2 100644 --- a/base/libgit2/callbacks.jl +++ b/base/libgit2/callbacks.jl @@ -258,8 +258,8 @@ function fetchhead_foreach_callback(ref_name::Cstring, remote_url::Cstring, end "C function pointer for `mirror_callback`" -mirror_cb() = cfunction(mirror_callback, Cint, (Ptr{Ptr{Void}}, Ptr{Void}, Cstring, Cstring, Ptr{Void})) +mirror_cb() = cfunction(mirror_callback, Cint, Tuple{Ptr{Ptr{Void}}, Ptr{Void}, Cstring, Cstring, Ptr{Void}}) "C function pointer for `credentials_callback`" -credentials_cb() = cfunction(credentials_callback, Cint, (Ptr{Ptr{Void}}, Cstring, Cstring, Cuint, Ptr{Void})) +credentials_cb() = cfunction(credentials_callback, Cint, Tuple{Ptr{Ptr{Void}}, Cstring, Cstring, Cuint, Ptr{Void}}) "C function pointer for `fetchhead_foreach_callback`" -fetchhead_foreach_cb() = cfunction(fetchhead_foreach_callback, Cint, (Cstring, Cstring, Ptr{GitHash}, Cuint, Ptr{Void})) +fetchhead_foreach_cb() = cfunction(fetchhead_foreach_callback, Cint, Tuple{Cstring, Cstring, Ptr{GitHash}, Cuint, Ptr{Void}}) diff --git a/base/libgit2/tree.jl b/base/libgit2/tree.jl index 3f9162f3823b9..60da6a821f0be 100644 --- a/base/libgit2/tree.jl +++ b/base/libgit2/tree.jl @@ -8,7 +8,7 @@ Function parameter should have following signature: (Cstring, Ptr{Void}, Ptr{Void}) -> Cint """ function treewalk(f::Function, tree::GitTree, payload=Any[], post::Bool = false) - cbf = cfunction(f, Cint, (Cstring, Ptr{Void}, Ptr{Void})) + cbf = cfunction(f, Cint, Tuple{Cstring, Ptr{Void}, Ptr{Void}}) cbf_payload = Ref{typeof(payload)}(payload) @check ccall((:git_tree_walk, :libgit2), Cint, (Ptr{Void}, Cint, Ptr{Void}, Ptr{Void}), diff --git a/base/libuv.jl b/base/libuv.jl index 702fad7392081..63894de44b087 100644 --- a/base/libuv.jl +++ b/base/libuv.jl @@ -86,17 +86,17 @@ function process_events(block::Bool) end function reinit_stdio() - global uv_jl_alloc_buf = cfunction(uv_alloc_buf, Void, (Ptr{Void}, Csize_t, Ptr{Void})) - global uv_jl_readcb = cfunction(uv_readcb, Void, (Ptr{Void}, Cssize_t, Ptr{Void})) - global uv_jl_connectioncb = cfunction(uv_connectioncb, Void, (Ptr{Void}, Cint)) - global uv_jl_connectcb = cfunction(uv_connectcb, Void, (Ptr{Void}, Cint)) - global uv_jl_writecb_task = cfunction(uv_writecb_task, Void, (Ptr{Void}, Cint)) - global uv_jl_getaddrinfocb = cfunction(uv_getaddrinfocb, Void, (Ptr{Void},Cint,Ptr{Void})) - global uv_jl_recvcb = cfunction(uv_recvcb, Void, (Ptr{Void}, Cssize_t, Ptr{Void}, Ptr{Void}, Cuint)) - global uv_jl_sendcb = cfunction(uv_sendcb, Void, (Ptr{Void}, Cint)) - global uv_jl_return_spawn = cfunction(uv_return_spawn, Void, (Ptr{Void}, Int64, Int32)) - global uv_jl_asynccb = cfunction(uv_asynccb, Void, (Ptr{Void},)) - global uv_jl_timercb = cfunction(uv_timercb, Void, (Ptr{Void},)) + global uv_jl_alloc_buf = cfunction(uv_alloc_buf, Void, Tuple{Ptr{Void}, Csize_t, Ptr{Void}}) + global uv_jl_readcb = cfunction(uv_readcb, Void, Tuple{Ptr{Void}, Cssize_t, Ptr{Void}}) + global uv_jl_connectioncb = cfunction(uv_connectioncb, Void, Tuple{Ptr{Void}, Cint}) + global uv_jl_connectcb = cfunction(uv_connectcb, Void, Tuple{Ptr{Void}, Cint}) + global uv_jl_writecb_task = cfunction(uv_writecb_task, Void, Tuple{Ptr{Void}, Cint}) + global uv_jl_getaddrinfocb = cfunction(uv_getaddrinfocb, Void, Tuple{Ptr{Void}, Cint, Ptr{Void}}) + global uv_jl_recvcb = cfunction(uv_recvcb, Void, Tuple{Ptr{Void}, Cssize_t, Ptr{Void}, Ptr{Void}, Cuint}) + global uv_jl_sendcb = cfunction(uv_sendcb, Void, Tuple{Ptr{Void}, Cint}) + global uv_jl_return_spawn = cfunction(uv_return_spawn, Void, Tuple{Ptr{Void}, Int64, Int32}) + global uv_jl_asynccb = cfunction(uv_asynccb, Void, Tuple{Ptr{Void}}) + global uv_jl_timercb = cfunction(uv_timercb, Void, Tuple{Ptr{Void}}) global uv_eventloop = ccall(:jl_global_event_loop, Ptr{Void}, ()) global STDIN = init_stdio(ccall(:jl_stdin_stream, Ptr{Void}, ())) diff --git a/base/poll.jl b/base/poll.jl index a670a10f0a979..af6b40fad375c 100644 --- a/base/poll.jl +++ b/base/poll.jl @@ -263,9 +263,9 @@ function _uv_hook_close(uv::FileMonitor) end function __init__() - global uv_jl_pollcb = cfunction(uv_pollcb, Void, (Ptr{Void}, Cint, Cint)) - global uv_jl_fspollcb = cfunction(uv_fspollcb, Void, (Ptr{Void}, Cint, Ptr{Void}, Ptr{Void})) - global uv_jl_fseventscb = cfunction(uv_fseventscb, Void, (Ptr{Void}, Ptr{Int8}, Int32, Int32)) + global uv_jl_pollcb = cfunction(uv_pollcb, Void, Tuple{Ptr{Void}, Cint, Cint}) + global uv_jl_fspollcb = cfunction(uv_fspollcb, Void, Tuple{Ptr{Void}, Cint, Ptr{Void}, Ptr{Void}}) + global uv_jl_fseventscb = cfunction(uv_fseventscb, Void, Tuple{Ptr{Void}, Ptr{Int8}, Int32, Int32}) end function uv_fseventscb(handle::Ptr{Void}, filename::Ptr, events::Int32, status::Int32) diff --git a/base/threadcall.jl b/base/threadcall.jl index d1e0b75e65f23..fee9ef8222700 100644 --- a/base/threadcall.jl +++ b/base/threadcall.jl @@ -11,7 +11,7 @@ function notify_fun(idx) end function init_threadcall() - global c_notify_fun = cfunction(notify_fun, Void, (Cint,)) + global c_notify_fun = cfunction(notify_fun, Void, Tuple{Cint}) end """ @@ -64,7 +64,7 @@ end function do_threadcall(wrapper::Function, rettype::Type, argtypes::Vector, argvals::Vector) # generate function pointer - fun_ptr = cfunction(wrapper, Int, (Ptr{Void}, Ptr{Void})) + fun_ptr = cfunction(wrapper, Int, Tuple{Ptr{Void}, Ptr{Void}}) # cconvert, root and unsafe_convert arguments roots = Any[] From 2a18f3383e436f507c80e5d1df79bc8725cf05ce Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 31 Jul 2017 11:42:45 -0400 Subject: [PATCH 57/88] fix method lookup intersection error fix #23024 and improve subtype test macro to always check for this Ref #23058 (cherry picked from commit fef53134177875fdfa020f46c0aa753faa571cd1) --- src/subtype.c | 15 ++------------- test/inference.jl | 9 +++++++++ test/subtype.jl | 25 ++++++++++++++++++++----- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/subtype.c b/src/subtype.c index 68aa745668fa9..98b44bc6d5498 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -2146,20 +2146,9 @@ jl_value_t *jl_type_intersection_env_s(jl_value_t *a, jl_value_t *b, jl_svec_t * else { sz = szb; // TODO: compute better `env` directly during intersection. - // we assume that if the intersection is a leaf type, we have - // full information in `env`. however the intersection algorithm - // does not yet provide that in all cases so use subtype. + // for now, we attempt to compute env by using subtype on the intersection result if (szb > 0 && !jl_types_equal(b, (jl_value_t*)jl_type_type)) { - if (jl_subtype_env(*ans, b, env, szb)) { - if (jl_is_leaf_type(*ans)) { - for(i=0; i < sz; i++) { - if (jl_is_typevar(env[i])) { - *ans = jl_bottom_type; goto bot; - } - } - } - } - else { + if (!jl_subtype_env(*ans, b, env, szb)) { sz = 0; } } diff --git a/test/inference.jl b/test/inference.jl index f6fb97e2fc477..8164f87534002 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -884,3 +884,12 @@ let isa_tfunc = Core.Inference.t_ffunc_val[ @test isa_tfunc(c, Type{Complex{T}} where T) === Const(false) end end + +function f23024(::Type{T}, ::Int) where T + 1 + 1 +end +v23024 = 0 +g23024(TT::Tuple{DataType}) = f23024(TT[1], v23024) +@test Base.return_types(f23024, (DataType, Any)) == Any[Int] +@test Base.return_types(g23024, (Tuple{DataType},)) == Any[Int] +@test g23024((UInt8,)) === 2 diff --git a/test/subtype.jl b/test/subtype.jl index 56b0773fefa1f..0f391208f9892 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -600,15 +600,25 @@ function test_properties() end macro testintersect(a, b, result) - if isa(result,Expr) && result.head === :call && length(result.args)==2 && result.args[1] === :! + if isa(result, Expr) && result.head === :call && length(result.args) == 2 && result.args[1] === :! result = result.args[2] - cmp = :notequal_type + cmp = :(!=) else - cmp = :isequal_type + cmp = :(==) end + cmp = esc(cmp) + a = esc(a) + b = esc(b) + result = esc(result) Base.remove_linenums!(quote - @test $(esc(cmp))(_type_intersect($(esc(a)), $(esc(b))), $(esc(result))) - @test $(esc(cmp))(_type_intersect($(esc(b)), $(esc(a))), $(esc(result))) + # test real intersect + @test $cmp(_type_intersect($a, $b), $result) + @test $cmp(_type_intersect($b, $a), $result) + # test simplified intersect + if !($result === Union{}) + @test typeintersect($a, $b) != Union{} + @test typeintersect($b, $a) != Union{} + end end) end @@ -1115,3 +1125,8 @@ end @testintersect(Val{Pair{T,T}} where T, Val{Pair{Int,T}} where T, Val{Pair{Int,Int}}) + +# issue #23024 +@testintersect(Tuple{DataType, Any}, + Tuple{Type{T}, Int} where T, + Tuple{DataType, Int}) From 2548c22d8dad7ad3531160fcfda1d3e0c038e18b Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Mon, 31 Jul 2017 14:28:11 -0400 Subject: [PATCH 58/88] inference: fix and improve instanceof_tfunc-based queries fix #23045 Ref #23059 (cherry picked from commit 32e3673d61584c5b7cc0f9434f5836d2467810e2) --- base/inference.jl | 83 +++++++++++++++++++++++++++-------------------- test/inference.jl | 69 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 112 insertions(+), 40 deletions(-) diff --git a/base/inference.jl b/base/inference.jl index 997d66a743df6..8455889e807b5 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -372,25 +372,30 @@ end add_tfunc(throw, 1, 1, (x::ANY) -> Bottom) # the inverse of typeof_tfunc +# returns (type, isexact) +# if isexact is false, the actual runtime type may (will) be a subtype of t function instanceof_tfunc(t::ANY) - # TODO improve - if t === Bottom - return t + if t === Bottom || t === typeof(Bottom) + return Bottom, true elseif isa(t, Const) if isa(t.val, Type) - return t.val + return t.val, true end elseif isType(t) - return t.parameters[1] - elseif isa(t,UnionAll) + tp = t.parameters[1] + return tp, !has_free_typevars(tp) + elseif isa(t, UnionAll) t′ = unwrap_unionall(t) - return rewrap_unionall(instanceof_tfunc(t′), t) - elseif isa(t,Union) - return Union{instanceof_tfunc(t.a), instanceof_tfunc(t.b)} + t′′, isexact = instanceof_tfunc(t′) + return rewrap_unionall(t′′, t), isexact + elseif isa(t, Union) + ta, isexact_a = instanceof_tfunc(t.a) + tb, isexact_b = instanceof_tfunc(t.b) + return Union{ta, tb}, false # at runtime, will be exactly one of these end - return Any + return Any, false end -bitcast_tfunc(t::ANY, x::ANY) = instanceof_tfunc(t) +bitcast_tfunc(t::ANY, x::ANY) = instanceof_tfunc(t)[1] math_tfunc(x::ANY) = widenconst(x) math_tfunc(x::ANY, y::ANY) = widenconst(x) math_tfunc(x::ANY, y::ANY, z::ANY) = widenconst(x) @@ -505,7 +510,7 @@ add_tfunc(checked_smul_int, 2, 2, chk_tfunc) add_tfunc(checked_umul_int, 2, 2, chk_tfunc) ## other, misc intrinsics ## add_tfunc(Core.Intrinsics.llvmcall, 3, IInf, - (fptr::ANY, rt::ANY, at::ANY, a...) -> instanceof_tfunc(rt)) + (fptr::ANY, rt::ANY, at::ANY, a...) -> instanceof_tfunc(rt)[1]) cglobal_tfunc(fptr::ANY) = Ptr{Void} cglobal_tfunc(fptr::ANY, t::ANY) = (isType(t) ? Ptr{t.parameters[1]} : Ptr) cglobal_tfunc(fptr::ANY, t::Const) = (isa(t.val, Type) ? Ptr{t.val} : Ptr) @@ -612,7 +617,7 @@ end add_tfunc(typeof, 1, 1, typeof_tfunc) add_tfunc(typeassert, 2, 2, function (v::ANY, t::ANY) - t = instanceof_tfunc(t) + t, isexact = instanceof_tfunc(t) t === Any && return v if isa(v, Const) if !has_free_typevars(t) && !isa(v.val, t) @@ -629,24 +634,38 @@ add_tfunc(typeassert, 2, 2, end) add_tfunc(isa, 2, 2, function (v::ANY, t::ANY) - t = instanceof_tfunc(t) - if t !== Any && !has_free_typevars(t) - if v ⊑ t - return Const(true) + t, isexact = instanceof_tfunc(t) + if !has_free_typevars(t) + if t === Bottom + return Const(false) + elseif v ⊑ t + if isexact + return Const(true) + end elseif isa(v, Const) || isa(v, Conditional) || (isleaftype(v) && !iskindtype(v)) return Const(false) + elseif isexact && typeintersect(v, t) === Bottom + if !iskindtype(v) #= subtyping currently intentionally answers this query incorrectly for kinds =# + return Const(false) + end end end # TODO: handle non-leaftype(t) by testing against lower and upper bounds return Bool end) -add_tfunc(issubtype, 2, 2, +add_tfunc(<:, 2, 2, function (a::ANY, b::ANY) - if (isa(a,Const) || isType(a)) && (isa(b,Const) || isType(b)) - a = instanceof_tfunc(a) - b = instanceof_tfunc(b) - if !has_free_typevars(a) && !has_free_typevars(b) - return Const(issubtype(a, b)) + a, isexact_a = instanceof_tfunc(a) + b, isexact_b = instanceof_tfunc(b) + if !has_free_typevars(a) && !has_free_typevars(b) + if a <: b + if isexact_b || a === Bottom + return Const(true) + end + else + if isexact_a || (b !== Bottom && typeintersect(a, b) === Union{}) + return Const(false) + end end end return Bool @@ -757,7 +776,6 @@ function const_datatype_getfield_tfunc(sv, fld) return nothing end -# returns (type, isexact) function getfield_tfunc(s00::ANY, name) if isa(s00, TypeVar) s00 = s00.ub @@ -892,7 +910,7 @@ function fieldtype_tfunc(s0::ANY, name::ANY) return Bottom end - s = instanceof_tfunc(s0) + s = instanceof_tfunc(s0)[1] u = unwrap_unionall(s) if isa(u,Union) @@ -1687,14 +1705,9 @@ function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vect a = fargs[2] if isa(a, fieldtype(Conditional, :var)) aty = widenconst(argtypes[2]) - tty = instanceof_tfunc(argtypes[3]) - if tty !== Any && tty !== Bottom - if isa(tty, TypeVar) - tty_ub = tty.ub - tty_lb = tty.lb - else - tty_ub = tty_lb = tty - end + tty_ub, isexact_tty = instanceof_tfunc(argtypes[3]) + if isexact_tty && !isa(tty_ub, TypeVar) + tty_lb = tty_ub # TODO: this would be wrong if !isexact_tty, but instanceof_tfunc doesn't preserve this info if !has_free_typevars(tty_lb) && !has_free_typevars(tty_ub) ifty = typeintersect(aty, tty_ub) elsety = typesubtract(aty, tty_lb) @@ -1729,7 +1742,7 @@ function abstract_call(f::ANY, fargs::Union{Tuple{},Vector{Any}}, argtypes::Vect elseif f === Core.kwfunc if length(fargs) == 2 ft = widenconst(argtypes[2]) - if isa(ft,DataType) && isdefined(ft.name, :mt) && isdefined(ft.name.mt, :kwsorter) + if isa(ft, DataType) && isdefined(ft.name, :mt) && isdefined(ft.name.mt, :kwsorter) return Const(ft.name.mt.kwsorter) end end @@ -1938,7 +1951,7 @@ function abstract_eval(e::ANY, vtypes::VarTable, sv::InferenceState) elseif e.head === :null t = Void elseif e.head === :new - t = instanceof_tfunc(abstract_eval(e.args[1], vtypes, sv)) + t = instanceof_tfunc(abstract_eval(e.args[1], vtypes, sv))[1] for i = 2:length(e.args) if abstract_eval(e.args[i], vtypes, sv) === Bottom rt = Bottom diff --git a/test/inference.jl b/test/inference.jl index 8164f87534002..d6111ac96dad9 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -858,7 +858,7 @@ let isa_tfunc = Core.Inference.t_ffunc_val[ @test isa_tfunc(Array, Const(AbstractArray)) === Const(true) @test isa_tfunc(Array, Type{AbstractArray}) === Const(true) @test isa_tfunc(Array, Type{AbstractArray{Int}}) == Bool - @test isa_tfunc(Array{Real}, Type{AbstractArray{Int}}) === Bool # could be improved + @test isa_tfunc(Array{Real}, Type{AbstractArray{Int}}) === Const(false) @test isa_tfunc(Array{Real, 2}, Const(AbstractArray{Real, 2})) === Const(true) @test isa_tfunc(Array{Real, 2}, Const(AbstractArray{Int, 2})) === Const(false) @test isa_tfunc(DataType, Int) === Bool # could be improved @@ -869,9 +869,9 @@ let isa_tfunc = Core.Inference.t_ffunc_val[ @test isa_tfunc(Union, Const(Union{Float32, Float64})) === Bool @test isa_tfunc(Union, Type{Union}) === Const(true) @test isa_tfunc(typeof(Union{}), Const(Int)) === Bool # any result is ok - @test isa_tfunc(typeof(Union{}), Const(Union{})) === Bool # could be improved - @test isa_tfunc(typeof(Union{}), typeof(Union{})) === Bool # could be improved - @test isa_tfunc(typeof(Union{}), Union{}) === Bool # could be improved + @test isa_tfunc(typeof(Union{}), Const(Union{})) === Const(false) + @test isa_tfunc(typeof(Union{}), typeof(Union{})) === Const(false) + @test isa_tfunc(typeof(Union{}), Union{}) === Const(false) # any result is ok @test isa_tfunc(typeof(Union{}), Type{typeof(Union{})}) === Const(true) @test isa_tfunc(typeof(Union{}), Const(typeof(Union{}))) === Const(true) let c = Conditional(Core.SlotNumber(0), Const(Union{}), Const(Union{})) @@ -882,7 +882,66 @@ let isa_tfunc = Core.Inference.t_ffunc_val[ @test isa_tfunc(c, Const(Signed)) === Const(false) @test isa_tfunc(c, Type{Complex}) === Const(false) @test isa_tfunc(c, Type{Complex{T}} where T) === Const(false) - end + end + @test isa_tfunc(Val{1}, Type{Val{T}} where T) === Bool + @test isa_tfunc(Val{1}, DataType) === Bool + @test isa_tfunc(Any, Const(Any)) === Const(true) + @test isa_tfunc(Any, Union{}) === Const(false) # any result is ok + @test isa_tfunc(Any, Type{Union{}}) === Const(false) + @test isa_tfunc(Union{Int64, Float64}, Type{Real}) === Const(true) + @test isa_tfunc(Union{Int64, Float64}, Type{Integer}) === Bool + @test isa_tfunc(Union{Int64, Float64}, Type{AbstractArray}) === Const(false) +end + +let subtype_tfunc = Core.Inference.t_ffunc_val[ + findfirst(Core.Inference.t_ffunc_key, <:)][3] + @test subtype_tfunc(Type{<:Array}, Const(AbstractArray)) === Const(true) + @test subtype_tfunc(Type{<:Array}, Type{AbstractArray}) === Const(true) + @test subtype_tfunc(Type{<:Array}, Type{AbstractArray{Int}}) == Bool + @test subtype_tfunc(Type{<:Array{Real}}, Type{AbstractArray{Int}}) === Const(false) + @test subtype_tfunc(Type{<:Array{Real, 2}}, Const(AbstractArray{Real, 2})) === Const(true) + @test subtype_tfunc(Type{Array{Real, 2}}, Const(AbstractArray{Int, 2})) === Const(false) + @test subtype_tfunc(DataType, Int) === Bool + @test subtype_tfunc(DataType, Const(Type{Int})) === Bool + @test subtype_tfunc(DataType, Const(Type{Array})) === Bool + @test subtype_tfunc(UnionAll, Const(Type{Int})) === Bool + @test subtype_tfunc(UnionAll, Const(Type{Array})) === Bool + @test subtype_tfunc(Union, Const(Union{Float32, Float64})) === Bool + @test subtype_tfunc(Union, Type{Union}) === Bool + @test subtype_tfunc(Union{}, Const(Int)) === Const(true) # any result is ok + @test subtype_tfunc(Union{}, Const(Union{})) === Const(true) # any result is ok + @test subtype_tfunc(Union{}, typeof(Union{})) === Const(true) # any result is ok + @test subtype_tfunc(Union{}, Union{}) === Const(true) # any result is ok + @test subtype_tfunc(Union{}, Type{typeof(Union{})}) === Const(true) # any result is ok + @test subtype_tfunc(Union{}, Const(typeof(Union{}))) === Const(true) # any result is ok + @test subtype_tfunc(typeof(Union{}), Const(typeof(Union{}))) === Const(true) # Union{} <: typeof(Union{}) + @test subtype_tfunc(typeof(Union{}), Const(Int)) === Const(true) # Union{} <: Int + @test subtype_tfunc(typeof(Union{}), Const(Union{})) === Const(true) # Union{} <: Union{} + @test subtype_tfunc(typeof(Union{}), Type{typeof(Union{})}) === Const(true) # Union{} <: Union{} + @test subtype_tfunc(typeof(Union{}), Type{typeof(Union{})}) === Const(true) # Union{} <: typeof(Union{}) + @test subtype_tfunc(typeof(Union{}), Type{Union{}}) === Const(true) # Union{} <: Union{} + @test subtype_tfunc(Type{Union{}}, typeof(Union{})) === Const(true) # Union{} <: Union{} + @test subtype_tfunc(Type{Union{}}, Const(typeof(Union{}))) === Const(true) # Union{} <: typeof(Union{}) + @test subtype_tfunc(Type{Union{}}, Const(Int)) === Const(true) # Union{} <: typeof(Union{}) + @test subtype_tfunc(Type{Union{}}, Any) === Const(true) # Union{} <: Any + @test subtype_tfunc(Type{Union{}}, Union{Type{Int64}, Type{Float64}}) === Const(true) + @test subtype_tfunc(Type{Union{}}, Union{Type{T}, Type{Float64}} where T) === Const(true) + let c = Conditional(Core.SlotNumber(0), Const(Union{}), Const(Union{})) + @test subtype_tfunc(c, Const(Bool)) === Bool # any result is ok + end + @test subtype_tfunc(Type{Val{1}}, Type{Val{T}} where T) === Bool + @test subtype_tfunc(Type{Val{1}}, DataType) === Bool + @test subtype_tfunc(Type, Type{Val{T}} where T) === Bool + @test subtype_tfunc(Type{Val{T}} where T, Type) === Bool + @test subtype_tfunc(Any, Const(Any)) === Const(true) + @test subtype_tfunc(Type{Any}, Const(Any)) === Const(true) + @test subtype_tfunc(Any, Union{}) === Bool # any result is ok + @test subtype_tfunc(Type{Any}, Union{}) === Const(false) # any result is ok + @test subtype_tfunc(Type, Union{}) === Bool # any result is ok + @test subtype_tfunc(Type, Type{Union{}}) === Bool + @test subtype_tfunc(Union{Type{Int64}, Type{Float64}}, Type{Real}) === Const(true) + @test subtype_tfunc(Union{Type{Int64}, Type{Float64}}, Type{Integer}) === Bool + @test subtype_tfunc(Union{Type{Int64}, Type{Float64}}, Type{AbstractArray}) === Const(false) end function f23024(::Type{T}, ::Int) where T From f01ad7f954b62fe2cb87e853b17c5bae75411920 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Wed, 2 Aug 2017 01:56:29 +0200 Subject: [PATCH 59/88] remove mentioning of internal .typ field in Expr objects Ref #23082 (cherry picked from commit a07d65d35fd00ec629088cfa57650b005ef885a3) --- doc/src/manual/metaprogramming.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index 1668bfe5a0260..e1a0118b6f658 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -33,7 +33,7 @@ julia> typeof(ex1) Expr ``` -`Expr` objects contain three parts: +`Expr` objects contain two parts: * a `Symbol` identifying the kind of expression. A symbol is an [interned string](https://en.wikipedia.org/wiki/String_interning) identifier (more discussion below). @@ -53,14 +53,6 @@ julia> ex1.args 1 ``` - * finally, the expression result type, which may be annotated by the user or inferred by the compiler - (and may be ignored completely for the purposes of this chapter): - -```jldoctest prog -julia> ex1.typ -Any -``` - Expressions may also be constructed directly in [prefix notation](https://en.wikipedia.org/wiki/Polish_notation): ```jldoctest prog From 9950d82fc67fd07b34be025b027b84697821f9e9 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Mon, 7 Aug 2017 21:44:36 +0200 Subject: [PATCH 60/88] fix math in condskeel docstring (#23083) (cherry picked from commit 0f4229d2e744375255fa1b27cb180f678ebf3e76) --- base/linalg/generic.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/base/linalg/generic.jl b/base/linalg/generic.jl index cfce003667412..01af43e527ecf 100644 --- a/base/linalg/generic.jl +++ b/base/linalg/generic.jl @@ -849,13 +849,15 @@ condskeel(A::AbstractMatrix, p::Real=Inf) = norm(abs.(inv(A))*abs.(A), p) condskeel(M, [x, p::Real=Inf]) ```math -\\kappa_S(M, p) & = \\left\\Vert \\left\\vert M \\right\\vert \\left\\vert M^{-1} \\right\\vert \\right\\Vert_p \\\\ -\\kappa_S(M, x, p) & = \\left\\Vert \\left\\vert M \\right\\vert \\left\\vert M^{-1} \\right\\vert \\left\\vert x \\right\\vert \\right\\Vert_p +\\kappa_S(M, p) = \\left\\Vert \\left\\vert M \\right\\vert \\left\\vert M^{-1} \\right\\vert \\right\\Vert_p \\\\ +\\kappa_S(M, x, p) = \\left\\Vert \\left\\vert M \\right\\vert \\left\\vert M^{-1} \\right\\vert \\left\\vert x \\right\\vert \\right\\Vert_p ``` Skeel condition number ``\\kappa_S`` of the matrix `M`, optionally with respect to the -vector `x`, as computed using the operator `p`-norm. -`p` is `Inf` by default, if not provided. Valid values for `p` are `1`, `2`, or `Inf`. +vector `x`, as computed using the operator `p`-norm. ``\\left\\vert M \\right\\vert`` +denotes the matrix of (entry wise) absolute values of ``M``; +``\\left\\vert M \\right\\vert_{ij} = \\left\\vert M_{ij} \\right\\vert``. +Valid values for `p` are `1`, `2` and `Inf` (default). This quantity is also known in the literature as the Bauer condition number, relative condition number, or componentwise relative condition number. From b5adafb224f390fa403cbbbcec96120957bbd0dd Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 2 Aug 2017 12:53:59 -0400 Subject: [PATCH 61/88] fix #23091, function in LHS of destructuring assignment Ref #23093 (cherry picked from commit 869f35fd3cf4431415d2c899ef1aa0bd99f18e60) --- src/julia-parser.scm | 8 +++----- src/julia-syntax.scm | 10 +++++----- src/macroexpand.scm | 4 ++-- test/core.jl | 6 ++++++ 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 56b12de1c3a21..96b5253902a76 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -673,16 +673,14 @@ (parse-assignment s parse-cond))))) (parse-assignment s parse-cond)))) -(define (eventually-call ex) +(define (eventually-call? ex) (and (pair? ex) (or (eq? (car ex) 'call) (and (or (eq? (car ex) 'where) (eq? (car ex) '|::|)) - (eventually-call (cadr ex)))))) + (eventually-call? (cadr ex)))))) (define (short-form-function-loc ex lno) - (if (and (pair? ex) - (eq? (car ex) '=) - (eventually-call (cadr ex))) + (if (eventually-call? (cadr ex)) `(= ,(cadr ex) (block (line ,lno ,current-filename) ,(caddr ex))) ex)) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 24b52a63a68c8..40410103a830e 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1104,7 +1104,7 @@ (eq? (caar binds) '=)) ;; some kind of assignment (cond - ((eventually-call (cadar binds)) + ((eventually-call? (cadar binds)) ;; f()=c (let ((asgn (butlast (expand-forms (car binds)))) (name (assigned-name (cadar binds)))) @@ -1327,7 +1327,7 @@ (define (assigned-name e) (cond ((atom? e) e) ((or (memq (car e) '(call curly where)) - (and (eq? (car e) '|::|) (eventually-call e))) + (and (eq? (car e) '|::|) (eventually-call? e))) (assigned-name (cadr e))) (else e))) @@ -1385,7 +1385,7 @@ (cons (make-assignment L R) stmts) after (cons R elts)) - (let ((temp (make-ssavalue))) + (let ((temp (if (eventually-call? L) (gensy) (make-ssavalue)))) (loop (cdr lhss) (cons L assigned) (cdr rhss) @@ -1401,7 +1401,7 @@ ,@(let loop ((lhs lhss) (i 1)) (if (null? lhs) '((null)) - (cons (if (eventually-call (car lhs)) + (cons (if (eventually-call? (car lhs)) ;; if this is a function assignment, avoid putting our ssavalue ;; inside the function and instead create a capture-able variable. ;; issue #22032 @@ -2428,7 +2428,7 @@ (else '()))) (define (all-decl-vars e) ;; map decl-var over every level of an assignment LHS - (cond ((eventually-call e) e) + (cond ((eventually-call? e) e) ((decl? e) (decl-var e)) ((and (pair? e) (eq? (car e) 'tuple)) (cons 'tuple (map all-decl-vars (cdr e)))) diff --git a/src/macroexpand.scm b/src/macroexpand.scm index 1832274e2e1e4..e0d55c3b99862 100644 --- a/src/macroexpand.scm +++ b/src/macroexpand.scm @@ -107,7 +107,7 @@ ;; a=b -> add argument (loop (cdr binds) (cons (decl-var (cadar binds)) vars))) - ((eventually-call (cadar binds)) + ((eventually-call? (cadar binds)) ;; f()=c (let ((asgn (cadr (julia-expand0 (car binds))))) (loop (cdr binds) @@ -389,7 +389,7 @@ (define (function-def? e) (and (pair? e) (or (eq? (car e) 'function) (eq? (car e) '->) (and (eq? (car e) '=) (length= e 3) - (eventually-call (cadr e)))))) + (eventually-call? (cadr e)))))) (define (find-declared-vars-in-expansion e decl (outer #t)) (cond ((or (not (pair? e)) (quoted? e)) '()) diff --git a/test/core.jl b/test/core.jl index 968cbd42c1664..2365d10758a9a 100644 --- a/test/core.jl +++ b/test/core.jl @@ -486,6 +486,12 @@ let t = (22,33) @test x == 33 end +# issue #23091 +let (f(), x) = (1, 2) + @test f() == 1 + @test x == 2 +end + # issue #21900 f21900_cnt = 0 function f21900() From d79a2ef8fa4954019321ba6c79de420b57ccfcb7 Mon Sep 17 00:00:00 2001 From: Moritz Schauer Date: Thu, 3 Aug 2017 01:12:24 +0200 Subject: [PATCH 62/88] Show in doc that thin is a keyword argument. (#23096) (cherry picked from commit 2700288b5b49bec0a557e367b3b906bda3c30ee7) --- base/linalg/svd.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/linalg/svd.jl b/base/linalg/svd.jl index 639d528a1b812..94b14247665e8 100644 --- a/base/linalg/svd.jl +++ b/base/linalg/svd.jl @@ -27,7 +27,7 @@ function svdfact!(A::StridedMatrix{T}; thin::Bool=true) where T<:BlasFloat end """ - svdfact(A, thin::Bool=true) -> SVD + svdfact(A; thin::Bool=true) -> SVD Compute the singular value decomposition (SVD) of `A` and return an `SVD` object. @@ -68,7 +68,7 @@ svdfact(x::Number; thin::Bool=true) = SVD(x == 0 ? fill(one(x), 1, 1) : fill(x/a svdfact(x::Integer; thin::Bool=true) = svdfact(float(x), thin=thin) """ - svd(A, thin::Bool=true) -> U, S, V + svd(A; thin::Bool=true) -> U, S, V Computes the SVD of `A`, returning `U`, vector `S`, and `V` such that `A == U*diagm(S)*V'`. The singular values in `S` are sorted in descending order. From 9c5f8e31c2537f0aa7f78c36d6e8483997e22c17 Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Thu, 3 Aug 2017 09:12:26 +0200 Subject: [PATCH 63/88] symdiff! on IntSet: fix too permissive bounds checking (#23099) (cherry picked from commit 0b095323ef582c4938f229ce3b0d31e55d91fc9f) --- base/intset.jl | 2 +- test/intset.jl | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/base/intset.jl b/base/intset.jl index 13b9fce6325d9..1e45f8076c903 100644 --- a/base/intset.jl +++ b/base/intset.jl @@ -140,7 +140,7 @@ symdiff!(s::IntSet, ns) = (for n in ns; symdiff!(s, n); end; s) The set `s` is destructively modified to toggle the inclusion of integer `n`. """ function symdiff!(s::IntSet, n::Integer) - 0 <= n < typemax(Int) || _throw_intset_bounds_err() + 0 < n < typemax(Int) || _throw_intset_bounds_err() val = !(n in s) _setint!(s, n, val) s diff --git a/test/intset.jl b/test/intset.jl index 1b8bab5557ec8..6d0afdaaba472 100644 --- a/test/intset.jl +++ b/test/intset.jl @@ -86,6 +86,10 @@ end i = IntSet(1:6) @test symdiff!(i, IntSet([6, 513])) == IntSet([1:5; 513]) + + # issue #23099 : these tests should not segfault + @test_throws ArgumentError symdiff!(IntSet(rand(1:100, 30)), 0) + @test_throws ArgumentError symdiff!(IntSet(rand(1:100, 30)), [0, 2, 4]) end @testset "copy, copy!, similar" begin From 262de92e24bd292b9018ba567fa7cfd6ded500f8 Mon Sep 17 00:00:00 2001 From: Matsumoto Date: Sun, 6 Aug 2017 03:12:38 +0900 Subject: [PATCH 64/88] Fix typo: subsitution -> substitution. (#23141) (cherry picked from commit 83007fb8c4c748fb23d38759daafd77fa1d56c2b) --- doc/src/manual/strings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index a1298af12de5b..206878a8becf3 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -712,7 +712,7 @@ julia> m[2] ``` Captures can be referenced in a substitution string when using [`replace()`](@ref) by using `\n` -to refer to the nth capture group and prefixing the subsitution string with `s`. Capture group +to refer to the nth capture group and prefixing the substitution string with `s`. Capture group 0 refers to the entire match object. Named capture groups can be referenced in the substitution with `g`. For example: From 2f580779f511a7e0d8e7cb450cdfe79627495a3a Mon Sep 17 00:00:00 2001 From: Amit Murthy Date: Wed, 9 Aug 2017 03:32:08 +0530 Subject: [PATCH 65/88] Release a Future only after it has been fetched locally by sending a del_msg. (#23172) (cherry picked from commit 60bc26e6fcfe134d32a77307a7832584234e7e2b) --- base/distributed/remotecall.jl | 9 ++------- base/precompile.jl | 4 ---- test/distributed_exec.jl | 31 +++++++++++++++++++++++++------ 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/base/distributed/remotecall.jl b/base/distributed/remotecall.jl index ff1de61be8222..ce1fd71bafef0 100644 --- a/base/distributed/remotecall.jl +++ b/base/distributed/remotecall.jl @@ -455,16 +455,11 @@ end wait(r::Future) = (!isnull(r.v) && return r; call_on_owner(wait_ref, r, myid()); r) wait(r::RemoteChannel, args...) = (call_on_owner(wait_ref, r, myid(), args...); r) -function fetch_future(rid, callee) - rv = lookup_ref(rid) - v = fetch(rv.c) - del_client(rid, callee) - v -end function fetch(r::Future) !isnull(r.v) && return get(r.v) - v=call_on_owner(fetch_future, r, myid()) + v=call_on_owner(fetch_ref, r) r.v=v + send_del_client(r) v end diff --git a/base/precompile.jl b/base/precompile.jl index 9bd0f90f30572..a604830733728 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -1669,7 +1669,6 @@ precompile(Tuple{typeof(Base.isempty), Base.IntSet}) precompile(Tuple{typeof(Base.any), Base.BitArray{1}}) precompile(Tuple{typeof(Base.uvfinalize), Base.PipeEndpoint}) precompile(Tuple{typeof(Base.uvfinalize), Base.Process}) -precompile(Tuple{getfield(Base.Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Base.Distributed.remotecall_fetch), typeof(Base.Distributed.fetch_future), Base.Distributed.Worker, Base.Distributed.RRID, Int64}) precompile(Tuple{getfield(Base.Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Base.Distributed.remotecall_fetch), typeof(Base.find_in_path), Base.Distributed.LocalProcess, String, Void}) precompile(Tuple{getfield(Base.Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Base.Distributed.remotecall_fetch), typeof(Base.find_in_path), Base.Distributed.Worker, String, Void}) precompile(Tuple{getfield(Base.Distributed, Symbol("#kw##remotecall_fetch")), Array{Any, 1}, typeof(Base.Distributed.remotecall_fetch), typeof(Base.open), Base.Distributed.LocalProcess, typeof(Base.read), String}) @@ -1702,10 +1701,7 @@ precompile(Tuple{typeof(Base.compilecache), String}) precompile(Tuple{typeof(Base.copy!), Array{Tuple{String, Float64}, 1}, Int64, Array{Tuple{String, Float64}, 1}, Int64, Int64}) precompile(Tuple{typeof(Base.create_expr_cache), String, String, Array{Any, 1}}) precompile(Tuple{typeof(Base._delete!), Base.Dict{Symbol, Base.Condition}, Int64}) -precompile(Tuple{typeof(Base.Distributed.call_on_owner), typeof(Base.Distributed.fetch_future), Base.Distributed.Future, Int64}) -precompile(Tuple{typeof(Base.Distributed.fetch_future), Base.Distributed.RRID, Int64}) precompile(Tuple{typeof(Base.Distributed.flush_gc_msgs), Base.Distributed.Worker}) -precompile(Tuple{typeof(Base.Distributed.remotecall_fetch), typeof(Base.Distributed.fetch_future), Base.Distributed.Worker, Base.Distributed.RRID, Int64}) precompile(Tuple{typeof(Base.Distributed.remotecall_fetch), typeof(Base.find_in_path), Base.Distributed.LocalProcess, String, Void}) precompile(Tuple{typeof(Base.Distributed.remotecall_fetch), typeof(Base.find_in_path), Base.Distributed.Worker, String, Void}) precompile(Tuple{typeof(Base.Distributed.remotecall_fetch), typeof(Base.open), Base.Distributed.LocalProcess, typeof(Base.read), String}) diff --git a/test/distributed_exec.jl b/test/distributed_exec.jl index 99d2157e26292..821f3c1a31eb0 100644 --- a/test/distributed_exec.jl +++ b/test/distributed_exec.jl @@ -149,6 +149,7 @@ function test_futures_dgc(id) @test isnull(f.v) == true @test fetch(f) == id @test isnull(f.v) == false + yield(); # flush gc msgs @test remotecall_fetch(k->(yield();haskey(Base.Distributed.PGRP.refs, k)), id, fid) == false @@ -158,14 +159,14 @@ function test_futures_dgc(id) @test remotecall_fetch(k->(yield();haskey(Base.Distributed.PGRP.refs, k)), id, fid) == true @test isnull(f.v) == true finalize(f) - Base.Distributed.flush_gc_msgs() + yield(); # flush gc msgs @test remotecall_fetch(k->(yield();haskey(Base.Distributed.PGRP.refs, k)), id, fid) == false end test_futures_dgc(id_me) test_futures_dgc(id_other) -# if sent to another worker, it should not be deleted till the other worker has fetched. +# if sent to another worker, it should not be deleted till all references are fetched. wid1 = workers()[1] wid2 = workers()[2] f = remotecall(myid, wid1) @@ -176,7 +177,8 @@ put!(fstore, f) @test fetch(f) == wid1 @test remotecall_fetch(k->haskey(Base.Distributed.PGRP.refs, k), wid1, fid) == true -remotecall_fetch(r->fetch(fetch(r)), wid2, fstore) +remotecall_fetch(r->(fetch(fetch(r)); yield()), wid2, fstore) +sleep(0.5) # to ensure that wid2 gc messages have been executed on wid1 @test remotecall_fetch(k->haskey(Base.Distributed.PGRP.refs, k), wid1, fid) == false # put! should release remote reference since it would have been cached locally @@ -228,7 +230,7 @@ function test_remoteref_dgc(id) @test fetch(rr) == :OK @test remotecall_fetch(k->(yield();haskey(Base.Distributed.PGRP.refs, k)), id, rrid) == true finalize(rr) - Base.Distributed.flush_gc_msgs() + yield(); # flush gc msgs @test remotecall_fetch(k->(yield();haskey(Base.Distributed.PGRP.refs, k)), id, rrid) == false end test_remoteref_dgc(id_me) @@ -244,12 +246,29 @@ fstore = RemoteChannel(wid2) put!(fstore, rr) @test remotecall_fetch(k->haskey(Base.Distributed.PGRP.refs, k), wid1, rrid) == true -finalize(rr); Base.Distributed.flush_gc_msgs() # finalize locally +finalize(rr) # finalize locally +yield(); # flush gc msgs @test remotecall_fetch(k->haskey(Base.Distributed.PGRP.refs, k), wid1, rrid) == true -remotecall_fetch(r->(finalize(take!(r)); Base.Distributed.flush_gc_msgs(); nothing), wid2, fstore) # finalize remotely +remotecall_fetch(r->(finalize(take!(r)); yield(); nothing), wid2, fstore) # finalize remotely sleep(0.5) # to ensure that wid2 messages have been executed on wid1 @test remotecall_fetch(k->haskey(Base.Distributed.PGRP.refs, k), wid1, rrid) == false +# Tests for issue #23109 - should not hang. +f = @spawn rand(1,1) +@sync begin + for _ in 1:10 + @async fetch(f) + end +end + +wid1,wid2 = workers()[1:2] +f = @spawnat wid1 rand(1,1) +@sync begin + @async fetch(f) + @async remotecall_fetch(()->fetch(f), wid2) +end + + @test fetch(@spawnat id_other myid()) == id_other @test (@fetchfrom id_other myid()) == id_other From dcf7ff337fda11e43c085e2b9af7bdc7f1464e51 Mon Sep 17 00:00:00 2001 From: Curtis Vogt Date: Thu, 10 Aug 2017 12:43:31 -0500 Subject: [PATCH 66/88] Fix style issues with manual METADATA publishing (#23184) (cherry picked from commit f87dea2d0075596a3548db1451db3594fdcd9422) --- doc/src/manual/packages.md | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/doc/src/manual/packages.md b/doc/src/manual/packages.md index 569806656811f..ea024571f6f32 100644 --- a/doc/src/manual/packages.md +++ b/doc/src/manual/packages.md @@ -978,25 +978,20 @@ By "forking" the main METADATA repository, you can create a personal copy (of ME your GitHub account. Once that copy exists, you can push your local changes to your copy (just like any other GitHub project). -1. go to [https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2FJuliaLang%2FMETADATA.jl%2Ffork](https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2FJuliaLang%2FMETADATA.jl%2Ffork) -and create your own fork. +1. Create a [fork of METADATA.jl](https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2FJuliaLang%2FMETADATA.jl%2Ffork). -2. add your fork as a remote repository for the METADATA repository on your local computer (in -the terminal where USERNAME is your github username): +2. Add your fork as a remote repository for the METADATA repository on your local computer (in + the terminal where USERNAME is your github username): -``` -cd ~/.julia/v0.6/METADATA -git remote add USERNAME https://github.com/USERNAME/METADATA.jl.git -``` + cd ~/.julia/v0.6/METADATA + git remote add USERNAME https://github.com/USERNAME/METADATA.jl.git -1. push your changes to your fork: +3. Push your changes to your fork: - ``` - git push USERNAME metadata-v2 - ``` + git push USERNAME metadata-v2 4. If all of that works, then go back to the GitHub page for your fork, and click the "pull request" -link. + link. ## Fixing Package Requirements From 21ba42ef2a16941eac8b510c58388d3c4a813acd Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Sat, 12 Aug 2017 15:47:22 +0200 Subject: [PATCH 67/88] remove .jl extension in Pkg.update (#23214) * remove .jl extension in Pkg.update * add test (cherry picked from commit 4c5cc04156ba074a8baa028c2a8a41b9e70d56ee) --- base/pkg/pkg.jl | 2 +- test/pkg.jl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/base/pkg/pkg.jl b/base/pkg/pkg.jl index 7d60ec9e6ce9d..2614c8d3d3939 100644 --- a/base/pkg/pkg.jl +++ b/base/pkg/pkg.jl @@ -225,7 +225,7 @@ optimal set of packages versions. Without arguments, updates all installed packages. When one or more package names are provided as arguments, only those packages and their dependencies are updated. """ -update(upkgs::AbstractString...) = cd(Entry.update,Dir.getmetabranch(),Set{String}([upkgs...])) +update(upkgs::AbstractString...) = cd(Entry.update,Dir.getmetabranch(),Set{String}(splitjl.([upkgs...]))) """ resolve() diff --git a/test/pkg.jl b/test/pkg.jl index 670d1dbcc42aa..c0012b49ed024 100644 --- a/test/pkg.jl +++ b/test/pkg.jl @@ -539,6 +539,7 @@ end Pkg.add("Example.jl") @test [keys(Pkg.installed())...] == ["Example"] iob = IOBuffer() + Pkg.update("Example.jl") Pkg.checkout("Example.jl") Pkg.status("Example.jl", iob) str = chomp(String(take!(iob))) From bd22138c369e0abc5d481727685f562b71bf2cc9 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 14 Aug 2017 11:49:45 -0400 Subject: [PATCH 68/88] fix #23218, lowering error in `(a,) = (b...,)` (#23242) (cherry picked from commit b5057f0e6593cc158bbe7d15a0f515004e6164bb) --- src/julia-syntax.scm | 55 ++++++++++++++++++++++++++++---------------- test/core.jl | 6 +++++ test/fastmath.jl | 6 +++++ 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 40410103a830e..8b93b2ee28ebb 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1374,24 +1374,32 @@ (unnecessary (tuple ,@(reverse elts)))) (let ((L (car lhss)) (R (car rhss))) - (if (and (symbol-like? L) - (or (not (pair? R)) (quoted? R) (equal? R '(null))) - ;; overwrite var immediately if it doesn't occur elsewhere - (not (contains (lambda (e) (eq-sym? e L)) (cdr rhss))) - (not (contains (lambda (e) (eq-sym? e R)) assigned))) - (loop (cdr lhss) - (cons L assigned) - (cdr rhss) - (cons (make-assignment L R) stmts) - after - (cons R elts)) - (let ((temp (if (eventually-call? L) (gensy) (make-ssavalue)))) - (loop (cdr lhss) - (cons L assigned) - (cdr rhss) - (cons (make-assignment temp R) stmts) - (cons (make-assignment L temp) after) - (cons temp elts)))))))) + (cond ((and (symbol-like? L) + (or (not (pair? R)) (quoted? R) (equal? R '(null))) + ;; overwrite var immediately if it doesn't occur elsewhere + (not (contains (lambda (e) (eq-sym? e L)) (cdr rhss))) + (not (contains (lambda (e) (eq-sym? e R)) assigned))) + (loop (cdr lhss) + (cons L assigned) + (cdr rhss) + (cons (make-assignment L R) stmts) + after + (cons R elts))) + ((vararg? R) + (let ((temp (make-ssavalue))) + `(block ,@(reverse stmts) + ,(make-assignment temp (cadr R)) + ,@(reverse after) + (= (tuple ,@lhss) ,temp) + (unnecessary (tuple ,@(reverse elts) (... ,temp)))))) + (else + (let ((temp (if (eventually-call? L) (gensy) (make-ssavalue)))) + (loop (cdr lhss) + (cons L assigned) + (cdr rhss) + (cons (make-assignment temp R) stmts) + (cons (make-assignment L temp) after) + (cons temp elts))))))))) ;; convert (lhss...) = x to tuple indexing (define (lower-tuple-assignment lhss x) @@ -1961,13 +1969,20 @@ ;; multiple assignment (let ((lhss (cdr lhs)) (x (caddr e))) + (define (sides-match? l r) + ;; l and r either have equal lengths, or r has a trailing ... + (cond ((null? l) (null? r)) + ((null? r) #f) + ((vararg? (car r)) (null? (cdr r))) + (else (sides-match? (cdr l) (cdr r))))) (if (and (pair? x) (pair? lhss) (eq? (car x) 'tuple) - (length= lhss (length (cdr x)))) + (sides-match? lhss (cdr x))) ;; (a, b, ...) = (x, y, ...) (expand-forms (tuple-to-assignments lhss x)) ;; (a, b, ...) = other - (let* ((xx (if (and (symbol? x) (not (memq x lhss))) + (let* ((xx (if (or (and (symbol? x) (not (memq x lhss))) + (ssavalue? x)) x (make-ssavalue))) (ini (if (eq? x xx) '() `((= ,xx ,(expand-forms x))))) (st (gensy))) diff --git a/test/core.jl b/test/core.jl index 2365d10758a9a..7ba768c6f7e10 100644 --- a/test/core.jl +++ b/test/core.jl @@ -4985,3 +4985,9 @@ end end @test M22026.foofunction(Int16) === Int16 @test M22026.foofunction2(3) === 6.0f0 + +# issue #23218 +let idx = (7,5,9) + (v,) = (idx...,) + @test v == 7 +end diff --git a/test/fastmath.jl b/test/fastmath.jl index 1a89a83503eda..0085d84b40e10 100644 --- a/test/fastmath.jl +++ b/test/fastmath.jl @@ -201,3 +201,9 @@ let a = ones(2,2), b = ones(2,2) local c = 0 @test @fastmath(c |= 1) == 1 end + +# issue #23218 +let a = zeros(1), b = ones(1), idx = (1,) + @fastmath a[idx...] += b[idx...] + @test a == b +end From dc839597735d5ee68fdd9c4d70e524954d677d99 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 14 Aug 2017 11:50:20 -0400 Subject: [PATCH 69/88] fix #23236 (#23243) comprehension eta-reduction needs to know that dot operators are not function names. (cherry picked from commit 37655e3f8fa4a2d2c89bcd51d3afb96feeea528e) --- src/julia-syntax.scm | 1 + test/broadcast.jl | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 8b93b2ee28ebb..81cf5d1588b0e 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1677,6 +1677,7 @@ (if (and (null? splat) (length= expr 3) (eq? (car expr) 'call) (eq? (caddr expr) argname) + (not (dotop? (cadr expr))) (not (expr-contains-eq argname (cadr expr)))) (cadr expr) ;; eta reduce `x->f(x)` => `f` `(-> ,argname (block ,@splat ,expr))))) diff --git a/test/broadcast.jl b/test/broadcast.jl index 8e89a12e65a89..ccb54599d6dbf 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -247,6 +247,11 @@ let x = [1:4;] @test sin.(f17300kw.(x, y=1)) == sin.(f17300kw.(x; y=1)) == sin.(x .+ 1) end +# issue #23236 +let X = [[true,false],[false,true]] + @test [.!x for x in X] == [[false,true],[true,false]] +end + # splice escaping of @. let x = [4, -9, 1, -16] @test [2, 3, 4, 5] == @.(1 + sqrt($sort(abs(x)))) From 01c61bbe7def730a47e083bc05baf831b1aea165 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 14 Aug 2017 21:47:07 -0400 Subject: [PATCH 70/88] fix #23234, parsing `function (x=0) ...` (#23258) (cherry picked from commit 771bae01cd5a9cce2daaed40d21f8606ef944a75) --- src/julia-parser.scm | 11 ++++++++--- test/parse.jl | 9 +++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 96b5253902a76..4c1803c4226f1 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -1170,6 +1170,11 @@ (and (eq? (car sig) 'where) (valid-func-sig? paren (cadr sig)))))) +(define (valid-1arg-func-sig? sig) + (or (symbol? sig) + (and (pair? sig) (eq? (car sig) '|::|) + (symbol? (cadr sig))))) + (define (unwrap-where x) (if (and (pair? x) (eq? (car x) 'where)) (unwrap-where (cadr x)) @@ -1302,9 +1307,9 @@ (take-token s) `(function ,sig)) (let* ((usig (unwrap-where sig)) - (def (if (or (symbol? usig) - (and (pair? usig) (eq? (car usig) '|::|) - (symbol? (cadr usig)))) + (def (if (or (valid-1arg-func-sig? usig) + (and (assignment? usig) + (valid-1arg-func-sig? (cadr usig)))) (if paren ;; in "function (x)" the (x) is a tuple (rewrap-where `(tuple ,usig) sig) diff --git a/test/parse.jl b/test/parse.jl index 6cb27fd06ba4e..052b0c272ef21 100644 --- a/test/parse.jl +++ b/test/parse.jl @@ -1215,3 +1215,12 @@ end === (3, String) # issue #19351 # adding return type decl should not affect parse of function body @test :(t(abc) = 3).args[2] == :(t(abc)::Int = 3).args[2] + +# issue #23234 +let + f = function (x=0) + x + end + @test f() == 0 + @test f(2) == 2 +end From 2f64bb0186a2ced6efb75daca2d66b4ca593246e Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Mon, 21 Aug 2017 21:30:14 +0200 Subject: [PATCH 71/88] no longer warn in code_warntype for unused variables (#23280) (cherry picked from commit 33fbfad3fd118cb89b63a241f35c92e20d466337) --- base/interactiveutil.jl | 25 +++++++++++++++++++++++-- test/reflection.jl | 5 +++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/base/interactiveutil.jl b/base/interactiveutil.jl index 8c949d1710706..c50c570014adb 100644 --- a/base/interactiveutil.jl +++ b/base/interactiveutil.jl @@ -324,14 +324,35 @@ problematic for performance, so the results need to be used judiciously. See [`@code_warntype`](@ref man-code-warntype) for more information. """ function code_warntype(io::IO, f, t::ANY) + function slots_used(ci, slotnames) + used = falses(length(slotnames)) + scan_exprs!(used, ci.code) + return used + end + + function scan_exprs!(used, exprs) + for ex in exprs + if isa(ex, Slot) + used[ex.id] = true + elseif isa(ex, Expr) + scan_exprs!(used, ex.args) + end + end + end + emph_io = IOContext(io, :TYPEEMPHASIZE => true) for (src, rettype) in code_typed(f, t) println(emph_io, "Variables:") slotnames = sourceinfo_slotnames(src) + used_slotids = slots_used(src, slotnames) for i = 1:length(slotnames) print(emph_io, " ", slotnames[i]) - if isa(src.slottypes, Array) - show_expr_type(emph_io, src.slottypes[i], true) + if used_slotids[i] + if isa(src.slottypes, Array) + show_expr_type(emph_io, src.slottypes[i], true) + end + else + print(emph_io, " ") end print(emph_io, '\n') end diff --git a/test/reflection.jl b/test/reflection.jl index d66098e3fde77..4af005d53a25b 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -92,6 +92,11 @@ show(iob, expand(:(x->x^2))) str = String(take!(iob)) @test isempty(search(str, tag)) +# Make sure non used variables are not emphasized +has_unused() = (a = rand(5)) +@test !warntype_hastag(has_unused, Tuple{}, tag) +@test warntype_hastag(has_unused, Tuple{}, "") + module ImportIntrinsics15819 # Make sure changing the lookup path of an intrinsic doesn't break # the heuristic for type instability warning. From 17c4a243444785f1d97377194a2586f9340ff104 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Tue, 22 Aug 2017 09:12:06 +0200 Subject: [PATCH 72/88] add RowVectors to to list of types included in sparse concatinations (#23297) (cherry picked from commit d00deb7ce962ae76f99e93b4ce97f6a1c4e27f18) --- base/sparse/sparsevector.jl | 8 ++++---- test/arrayops.jl | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index cdb7f53f1c39b..28b892125b6dd 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -934,7 +934,7 @@ vcat(X::Union{Vector,SparseVector}...) = vcat(map(sparse, X)...) # TODO: A definition similar to the third exists in base/linalg/bidiag.jl. These definitions # should be consolidated in a more appropriate location, e.g. base/linalg/special.jl. -const _SparseArrays = Union{SparseVector, SparseMatrixCSC} +const _SparseArrays = Union{SparseVector, SparseMatrixCSC, RowVector{<:Any, <:SparseVector}} const _SpecialArrays = Union{Diagonal, Bidiagonal, Tridiagonal, SymTridiagonal} const _SparseConcatArrays = Union{_SpecialArrays, _SparseArrays} @@ -949,9 +949,9 @@ const _Triangular_DenseArrays{T,A<:Matrix} = Base.LinAlg.AbstractTriangular{T,A} const _Annotated_DenseArrays = Union{_Triangular_DenseArrays, _Symmetric_DenseArrays, _Hermitian_DenseArrays} const _Annotated_Typed_DenseArrays{T} = Union{_Triangular_DenseArrays{T}, _Symmetric_DenseArrays{T}, _Hermitian_DenseArrays{T}} -const _SparseConcatGroup = Union{Vector, Matrix, _SparseConcatArrays, _Annotated_SparseConcatArrays, _Annotated_DenseArrays} -const _DenseConcatGroup = Union{Vector, Matrix, _Annotated_DenseArrays} -const _TypedDenseConcatGroup{T} = Union{Vector{T}, Matrix{T}, _Annotated_Typed_DenseArrays{T}} +const _SparseConcatGroup = Union{Vector, RowVector{<:Any, <:Vector}, Matrix, _SparseConcatArrays, _Annotated_SparseConcatArrays, _Annotated_DenseArrays} +const _DenseConcatGroup = Union{Vector, RowVector{<:Any, <:Vector}, Matrix, _Annotated_DenseArrays} +const _TypedDenseConcatGroup{T} = Union{Vector{T}, RowVector{T,Vector{T}}, Matrix{T}, _Annotated_Typed_DenseArrays{T}} # Concatenations involving un/annotated sparse/special matrices/vectors should yield sparse arrays function cat(catdims, Xin::_SparseConcatGroup...) diff --git a/test/arrayops.jl b/test/arrayops.jl index cfe5a5c34c036..36e6a3695f55e 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -1982,6 +1982,10 @@ end # module AutoRetType @test isa(hvcat((2,), densearray, densearray), Array) @test isa(cat((1,2), densearray, densearray), Array) end + @test isa([[1,2,3]'; [1,2,3]'], Matrix{Int}) + @test isa([[1,2,3]' [1,2,3]'], RowVector{Int, Vector{Int}}) + @test isa([Any[1.0, 2]'; Any[2.0, 2]'], Matrix{Any}) + @test isa([Any[1.0, 2]' Any[2.0, 2']'], RowVector{Any, Vector{Any}}) # Test that concatenations of heterogeneous Matrix-Vector pairs yield dense matrices @test isa(hcat(densemat, densevec), Array) @test isa(hcat(densevec, densemat), Array) From bb2a918f59b0a1cdd69044233775dec1584465bf Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 19 Aug 2017 09:14:24 -0500 Subject: [PATCH 73/88] Fix eltype conversion for StepRangeLen{BigFloat} (fixes #23300) Ref #23348 (cherry picked from commit 1c2e689dd476e507fca2e468c1de82e88cfc0808) --- base/twiceprecision.jl | 3 ++- test/ranges.jl | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/base/twiceprecision.jl b/base/twiceprecision.jl index 8c1ececfb45bc..afa39160bc85b 100644 --- a/base/twiceprecision.jl +++ b/base/twiceprecision.jl @@ -422,7 +422,7 @@ function rat(x) y = x a = d = 1 b = c = 0 - m = maxintfloat(narrow(typeof(x))) + m = maxintfloat(narrow(typeof(x)), Int) while abs(y) <= m f = trunc(Int,y) y -= f @@ -435,6 +435,7 @@ function rat(x) return a, b end +narrow(::Type{T}) where {T<:AbstractFloat} = Float64 narrow(::Type{Float64}) = Float32 narrow(::Type{Float32}) = Float16 narrow(::Type{Float16}) = Float16 diff --git a/test/ranges.jl b/test/ranges.jl index 9cc49c5e51f3a..82352cd1ff3bc 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -921,3 +921,10 @@ let linsp = linspace(1.0, 2.0, 10) @test Float32(linsp.ref) === convert(Float32, linsp.ref) @test Float32(linsp.ref) ≈ linsp.ref.hi + linsp.ref.lo end + +# Issue #23300 +x = -5:big(1.0):5 +@test map(Float64, x) === -5.0:1.0:5.0 +@test map(Float32, x) === -5.0f0:1.0f0:5.0f0 +@test map(Float16, x) === Float16(-5.0):Float16(1.0):Float16(5.0) +@test map(BigFloat, x) === x From 98158c10185bdee6b5bf431b9c0930c44cd91492 Mon Sep 17 00:00:00 2001 From: Andreas Noack Date: Mon, 21 Aug 2017 17:11:39 -0400 Subject: [PATCH 74/88] Fix Schur Factorization for 0x0 matrices (#23360) Fixes #23359 (cherry picked from commit db88dd1e906085c14d1cb9f0376c26f0fcf109c8) --- base/linalg/lapack.jl | 28 ++++++++++++++-------------- test/linalg/schur.jl | 6 ++++++ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/base/linalg/lapack.jl b/base/linalg/lapack.jl index 14d8f76df34ae..9810ad17bf054 100644 --- a/base/linalg/lapack.jl +++ b/base/linalg/lapack.jl @@ -5479,13 +5479,13 @@ for (gees, gges, elty) in # $ WR( * ) function gees!(jobvs::Char, A::StridedMatrix{$elty}) chkstride1(A) - n = checksquare(A) - sdim = Vector{BlasInt}(1) - wr = similar(A, $elty, n) - wi = similar(A, $elty, n) - ldvs = jobvs == 'V' ? n : 1 - vs = similar(A, $elty, ldvs, n) - work = Vector{$elty}(1) + n = checksquare(A) + sdim = Vector{BlasInt}(1) + wr = similar(A, $elty, n) + wi = similar(A, $elty, n) + vs = similar(A, $elty, jobvs == 'V' ? n : 0, n) + ldvs = max(size(vs, 1), 1) + work = Vector{$elty}(1) lwork = BlasInt(-1) info = Ref{BlasInt}() for i = 1:2 @@ -5572,13 +5572,13 @@ for (gees, gges, elty, relty) in # COMPLEX*16 A( LDA, * ), VS( LDVS, * ), W( * ), WORK( * ) function gees!(jobvs::Char, A::StridedMatrix{$elty}) chkstride1(A) - n = checksquare(A) - sort = 'N' - sdim = BlasInt(0) - w = similar(A, $elty, n) - ldvs = jobvs == 'V' ? n : 1 - vs = similar(A, $elty, ldvs, n) - work = Vector{$elty}(1) + n = checksquare(A) + sort = 'N' + sdim = BlasInt(0) + w = similar(A, $elty, n) + vs = similar(A, $elty, jobvs == 'V' ? n : 1, n) + ldvs = max(size(vs, 1), 1) + work = Vector{$elty}(1) lwork = BlasInt(-1) rwork = Vector{$relty}(n) info = Ref{BlasInt}() diff --git a/test/linalg/schur.jl b/test/linalg/schur.jl index 9b48443f278c7..3e9913d1ced96 100644 --- a/test/linalg/schur.jl +++ b/test/linalg/schur.jl @@ -100,4 +100,10 @@ aimg = randn(n,n)/2 @test NS[:Z] ≈ sZ end end + @testset "0x0 matrix" for A in (zeros(eltya, 0, 0), view(rand(eltya, 2, 2), 1:0, 1:0)) + T, Z, λ = Base.LinAlg.schur(A) + @test T == A + @test Z == A + @test λ == zeros(0) + end end From 8e610d5f5caa5bc52ba041b9e777a67a950748dc Mon Sep 17 00:00:00 2001 From: Rafael Fourquet Date: Mon, 21 Aug 2017 17:22:16 +0200 Subject: [PATCH 75/88] define Symbol(s::Symbol) = s for performance Before, `Symbol(:symbol)` was calling the generic `Symbo(x...)` method which in turns calls `string(x...)`; this is too slow for just returning the argument. Ref #23381 (cherry picked from commit 3cfd75b849ef60eeeb6b00c325cf40f17278cb77) --- base/boot.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/base/boot.jl b/base/boot.jl index d0a686e761bf5..13c6cc10c8153 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -332,6 +332,7 @@ function Symbol(a::Array{UInt8,1}) ccall(:jl_array_ptr, Ptr{UInt8}, (Any,), a), Intrinsics.arraylen(a)) end +Symbol(s::Symbol) = s # docsystem basics macro doc(x...) From 2780edb84ac175c70dbab869b8d60ac621802539 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 25 Aug 2017 10:54:04 -0400 Subject: [PATCH 76/88] fix #23430, counter overflow in subtyping Ref #23447 (cherry picked from commit 4d4b9ce06de296df3d51646c66192681ca1a8788) --- src/subtype.c | 5 +++-- test/subtype.jl | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/subtype.c b/src/subtype.c index 98b44bc6d5498..b636d77bba83d 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -420,9 +420,10 @@ static int subtype_ufirst(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) static void record_var_occurrence(jl_varbinding_t *vb, jl_stenv_t *e, int param) { if (vb != NULL && param) { - if (param == 2 && e->invdepth > vb->depth0) + // saturate counters at 2; we don't need values bigger than that + if (param == 2 && e->invdepth > vb->depth0 && vb->occurs_inv < 2) vb->occurs_inv++; - else + else if (vb->occurs_cov < 2) vb->occurs_cov++; } } diff --git a/test/subtype.jl b/test/subtype.jl index 0f391208f9892..3e2fcab5d01d1 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -1130,3 +1130,22 @@ end @testintersect(Tuple{DataType, Any}, Tuple{Type{T}, Int} where T, Tuple{DataType, Int}) + +# issue #23430 +@test [0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; + 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; + 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; + 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; + 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; 0 0.; + 0 0.; 0 0.; 0 0.; 0 0.] isa Matrix{Float64} +@test !(Tuple{Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64, + Int64,Float64,Int64,Float64,Int64,Float64,Int64,Float64} <: (Tuple{Vararg{T}} where T<:Number)) From 1aea74e97d55950d87ad08b912e44c23ae15805b Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sun, 27 Aug 2017 23:45:11 -0400 Subject: [PATCH 77/88] fix bug in printing generator expressions with n-d ranges Ref #23480 (cherry picked from commit f9527b7ee0cb07384312f32871cbcb960ed72c93) --- base/show.jl | 12 ++++-------- test/show.jl | 2 ++ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/base/show.jl b/base/show.jl index 37850aa17c5cc..76d8e42ff423c 100644 --- a/base/show.jl +++ b/base/show.jl @@ -671,23 +671,19 @@ function show_generator(io, ex, indent) fg = ex ranges = Any[] while isa(fg, Expr) && fg.head === :flatten - push!(ranges, fg.args[1].args[2]) + push!(ranges, fg.args[1].args[2:end]) fg = fg.args[1].args[1] end - push!(ranges, fg.args[2]) + push!(ranges, fg.args[2:end]) show_unquoted(io, fg.args[1], indent) for r in ranges print(io, " for ") - show_unquoted(io, r, indent) + show_list(io, r, ", ", indent) end else show_unquoted(io, ex.args[1], indent) print(io, " for ") - show_unquoted(io, ex.args[2], indent) - for i = 3:length(ex.args) - print(io, ", ") - show_unquoted(io, ex.args[i], indent) - end + show_list(io, ex.args[2:end], ", ", indent) end end diff --git a/test/show.jl b/test/show.jl index 8e104277f8e50..db221959b5930 100644 --- a/test/show.jl +++ b/test/show.jl @@ -618,6 +618,8 @@ end @test repr(:([x for x = y])) == ":([x for x = y])" @test repr(:([x for x = y if z])) == ":([x for x = y if z])" @test repr(:(z for z = 1:5, y = 1:5)) == ":((z for z = 1:5, y = 1:5))" +@test_repr "(x for i in a, b in c)" +@test_repr "(x for a in b, c in d for e in f)" for op in (:(.=), :(.+=), :(.&=)) @test repr(parse("x $op y")) == ":(x $op y)" From 2fe7cb97307605b7eebb913eea1b81f99bb0e552 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 29 Aug 2017 14:26:22 -0400 Subject: [PATCH 78/88] test-codegen: make jl_dump_compiles test more reliable (#23486) This was a flaky test, and it's not entirely clear what it was testing. Common failure was: FAILURE Error in testset codegen: Test Failed Expression: tempty == true Evaluated: false == true ERROR: LoadError: Test run finished with errors while loading C:\projects\julia\julia-a661736be5\share\julia\test\runtests.jl, in expression starting on line 29 Command exited with code 1 (cherry picked from commit 46bff1bf83f82107369b23c3163a53aed4f9801c) --- test/codegen.jl | 224 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) diff --git a/test/codegen.jl b/test/codegen.jl index 307ad38e66261..6925ef1266ff8 100644 --- a/test/codegen.jl +++ b/test/codegen.jl @@ -1,5 +1,229 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +# tests for codegen and optimizations + +const opt_level = Base.JLOptions().opt_level +const coverage = (Base.JLOptions().code_coverage > 0) || (Base.JLOptions().malloc_log > 0) +const Iptr = sizeof(Int) == 8 ? "i64" : "i32" + +# `_dump_function` might be more efficient but it doesn't really matter here... +get_llvm(@nospecialize(f), @nospecialize(t), strip_ir_metadata=true, dump_module=false) = + sprint(code_llvm, f, t, strip_ir_metadata, dump_module) + +if opt_level > 0 + # Make sure getptls call is removed at IR level with optimization on + @test !contains(get_llvm(identity, Tuple{String}), " call ") +end + +jl_string_ptr(s::String) = ccall(:jl_string_ptr, Ptr{UInt8}, (Any,), s) +core_sizeof(o) = Core.sizeof(o) +function test_loads_no_call(ir, load_types) + in_function = false + load_idx = 1 + for line in eachline(IOBuffer(ir)) + if !in_function + if startswith(line, "define ") + in_function = true + end + continue + end + @test !contains(line, " call ") + load_split = split(line, " load ", limit=2) + if !coverage && length(load_split) >= 2 + @test load_idx <= length(load_types) + if load_idx <= length(load_types) + @test startswith(load_split[2], "$(load_types[load_idx]),") + end + load_idx += 1 + end + if startswith(line, "}") + break + end + end + if !coverage + @test load_idx == length(load_types) + 1 + end +end + +# This function tests if functions are output when compiled if jl_dump_compiles is enabled. +# Have to go through pains with recursive function (eval probably not required) to make sure +# that inlining won't happen. +function test_jl_dump_compiles() + tfile = tempname() + io = open(tfile, "w") + @eval(test_jl_dump_compiles_internal(x) = x) + ccall(:jl_dump_compiles, Void, (Ptr{Void},), io.handle) + @eval test_jl_dump_compiles_internal(1) + ccall(:jl_dump_compiles, Void, (Ptr{Void},), C_NULL) + close(io) + tstats = stat(tfile) + tempty = tstats.size == 0 + rm(tfile) + @test tempty == false +end + +# This function tests if a toplevel thunk is output if jl_dump_compiles is enabled. +# The eval statement creates the toplevel thunk. +function test_jl_dump_compiles_toplevel_thunks() + tfile = tempname() + io = open(tfile, "w") + topthunk = expand(Main, :(for i in 1:10; end)) + ccall(:jl_dump_compiles, Void, (Ptr{Void},), io.handle) + Core.eval(Main, topthunk) + ccall(:jl_dump_compiles, Void, (Ptr{Void},), C_NULL) + close(io) + tstats = stat(tfile) + tempty = tstats.size == 0 + rm(tfile) + @test tempty == true +end + +if opt_level > 0 + # Make sure `jl_string_ptr` is inlined + @test !contains(get_llvm(jl_string_ptr, Tuple{String}), " call ") + s = "aaa" + @test jl_string_ptr(s) == pointer_from_objref(s) + sizeof(Int) + # String + test_loads_no_call(get_llvm(core_sizeof, Tuple{String}), [Iptr]) + # String + test_loads_no_call(get_llvm(core_sizeof, Tuple{SimpleVector}), [Iptr]) + # Array + test_loads_no_call(get_llvm(core_sizeof, Tuple{Vector{Int}}), [Iptr]) + # As long as the eltype is known we don't need to load the elsize + test_loads_no_call(get_llvm(core_sizeof, Tuple{Array{Any}}), [Iptr]) + # Check that we load the elsize + test_loads_no_call(get_llvm(core_sizeof, Tuple{Vector}), [Iptr, "i16"]) + + test_jl_dump_compiles() + test_jl_dump_compiles_toplevel_thunks() +end + +# Make sure we will not elide the allocation +@noinline create_ref1() = Ref(1) +function pointer_not_safepoint() + a = create_ref1() + unsafe_store!(Ptr{Int}(pointer_from_objref(a)), 3) + return a[] +end +@test pointer_not_safepoint() == 3 + +# The current memcmp threshold is 512bytes, make sure this struct has the same size on +# 32bits and 64bits +struct LargeStruct + x::NTuple{1024,Int8} + LargeStruct() = new() +end + +const large_struct = LargeStruct() +@noinline create_ref_struct() = Ref(large_struct) +function compare_large_struct(a) + b = create_ref_struct() + if a[] === b[] + b[].x[1] + else + a[].x[2] + end +end + +mutable struct MutableStruct + a::Int + MutableStruct() = new() +end + +breakpoint_mutable(a::MutableStruct) = ccall(:jl_breakpoint, Void, (Ref{MutableStruct},), a) + +# Allocation with uninitialized field as gcroot +mutable struct BadRef + x::MutableStruct + y::MutableStruct + BadRef(x) = new(x) +end +Base.cconvert(::Type{Ptr{BadRef}}, a::MutableStruct) = BadRef(a) +Base.unsafe_convert(::Type{Ptr{BadRef}}, ar::BadRef) = Ptr{BadRef}(pointer_from_objref(ar.x)) + +breakpoint_badref(a::MutableStruct) = ccall(:jl_breakpoint, Void, (Ptr{BadRef},), a) + +struct PtrStruct + a::Ptr{Void} + b::Int +end + +mutable struct RealStruct + a::Float64 + b::Int +end + +function Base.cconvert(::Type{Ref{PtrStruct}}, a::RealStruct) + (a, Ref(PtrStruct(pointer_from_objref(a), a.b))) +end +Base.unsafe_convert(::Type{Ref{PtrStruct}}, at::Tuple) = + Base.unsafe_convert(Ref{PtrStruct}, at[2]) + +breakpoint_ptrstruct(a::RealStruct) = + ccall(:jl_breakpoint, Void, (Ref{PtrStruct},), a) + +if opt_level > 0 + @test !contains(get_llvm(isequal, Tuple{Nullable{BigFloat}, Nullable{BigFloat}}), "%gcframe") + @test !contains(get_llvm(pointer_not_safepoint, Tuple{}), "%gcframe") + compare_large_struct_ir = get_llvm(compare_large_struct, Tuple{typeof(create_ref_struct())}) + @test contains(compare_large_struct_ir, "call i32 @memcmp") + @test !contains(compare_large_struct_ir, "%gcframe") + + @test contains(get_llvm(MutableStruct, Tuple{}), "jl_gc_pool_alloc") + breakpoint_mutable_ir = get_llvm(breakpoint_mutable, Tuple{MutableStruct}) + @test !contains(breakpoint_mutable_ir, "%gcframe") + @test !contains(breakpoint_mutable_ir, "jl_gc_pool_alloc") + + breakpoint_badref_ir = get_llvm(breakpoint_badref, Tuple{MutableStruct}) + @test !contains(breakpoint_badref_ir, "%gcframe") + @test !contains(breakpoint_badref_ir, "jl_gc_pool_alloc") + + breakpoint_ptrstruct_ir = get_llvm(breakpoint_ptrstruct, Tuple{RealStruct}) + @test !contains(breakpoint_ptrstruct_ir, "%gcframe") + @test !contains(breakpoint_ptrstruct_ir, "jl_gc_pool_alloc") +end + +function two_breakpoint(a::Float64) + ccall(:jl_breakpoint, Void, (Ref{Float64},), a) + ccall(:jl_breakpoint, Void, (Ref{Float64},), a) +end + +if opt_level > 0 + breakpoint_f64_ir = get_llvm((a)->ccall(:jl_breakpoint, Void, (Ref{Float64},), a), + Tuple{Float64}) + @test !contains(breakpoint_f64_ir, "jl_gc_pool_alloc") + breakpoint_any_ir = get_llvm((a)->ccall(:jl_breakpoint, Void, (Ref{Any},), a), + Tuple{Float64}) + @test contains(breakpoint_any_ir, "jl_gc_pool_alloc") + two_breakpoint_ir = get_llvm(two_breakpoint, Tuple{Float64}) + @test !contains(two_breakpoint_ir, "jl_gc_pool_alloc") + @test contains(two_breakpoint_ir, "llvm.lifetime.end") +end + +# Issue 22770 +let was_gced = false + @noinline make_tuple(x) = tuple(x) + @noinline use(x) = ccall(:jl_breakpoint, Void, ()) + @noinline assert_not_gced() = @test !was_gced + + function foo22770() + b = Ref(2) + finalizer(b, x -> was_gced = true) + y = make_tuple(b) + x = y[1] + a = Ref(1) + use(x); use(a); use(y) + c = Ref(3) + gc() + assert_not_gced() + use(x) + use(c) + end + foo22770() + gc() + @test was_gced +end + function egal_svecs() a = Core.svec(:a, :b) b = Core.svec(:a, :b) From 815a962f066fd4c1d24162a3ba8d0b0a6a3d1a16 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Thu, 31 Aug 2017 23:46:01 +0200 Subject: [PATCH 79/88] fix documentation for IOBuffer, close #23398 (#23514) (cherry picked from commit b729e58dff9c9cfa2640b8c4dcc71dbc91b29871) --- base/iobuffer.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/iobuffer.jl b/base/iobuffer.jl index c9d4226462dac..6441461b43383 100644 --- a/base/iobuffer.jl +++ b/base/iobuffer.jl @@ -36,8 +36,8 @@ StringVector(n::Integer) = Vector{UInt8}(_string_n(n)) Create an `IOBuffer`, which may optionally operate on a pre-existing array. If the readable/writable arguments are given, they restrict whether or not the buffer may be read -from or written to respectively. By default the buffer is readable but not writable. The -last argument optionally specifies a size beyond which the buffer may not be grown. +from or written to respectively. The last argument optionally specifies a size beyond which +the buffer may not be grown. """ IOBuffer(data::AbstractVector{UInt8}, readable::Bool=true, writable::Bool=false, maxsize::Int=typemax(Int)) = AbstractIOBuffer(data, readable, writable, true, false, maxsize) From 5b8476959c6702a6e4fc9b1d055391d3204f4a5f Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sat, 2 Sep 2017 13:14:53 -0400 Subject: [PATCH 80/88] fix #23558, bug in recursive let-bound functions Ref #23561 (cherry picked from commit aee1aab70f8521dcebb76ef91173c8c416a8611c) --- src/julia-syntax.scm | 9 +++++---- test/core.jl | 7 +++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 81cf5d1588b0e..18fab57cf4bc5 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1105,7 +1105,7 @@ ;; some kind of assignment (cond ((eventually-call? (cadar binds)) - ;; f()=c + ;; f() = c (let ((asgn (butlast (expand-forms (car binds)))) (name (assigned-name (cadar binds)))) (if (not (symbol? name)) @@ -1113,15 +1113,16 @@ (loop (cdr binds) `(scope-block (block - (local-def ,name) + ,(if (expr-contains-eq name (caddar binds)) + `(local ,name) ;; might need a Box for recursive functions + `(local-def ,name)) ,asgn ,blk))))) ((or (symbol? (cadar binds)) (decl? (cadar binds))) (let ((vname (decl-var (cadar binds)))) (loop (cdr binds) - (if (contains (lambda (x) (eq? x vname)) - (caddar binds)) + (if (expr-contains-eq vname (caddar binds)) (let ((tmp (make-ssavalue))) `(scope-block (block (= ,tmp ,(caddar binds)) diff --git a/test/core.jl b/test/core.jl index 7ba768c6f7e10..d3d7eafa26abd 100644 --- a/test/core.jl +++ b/test/core.jl @@ -343,6 +343,13 @@ let f = i18408() @test_throws UndefRefError f(0) end +# issue #23558 +c23558(n,k) = + let fact(n) = if (n == 0) 1 else n*fact(n-1) end + fact(n)/fact(k)/fact(n-k) + end +@test c23558(10, 5) == 252 + # variable scope, globals glob_x = 23 function glotest() From 2c2f577283c3cec86aea8c4394d012eaf72cf3e7 Mon Sep 17 00:00:00 2001 From: Curtis Vogt Date: Wed, 6 Sep 2017 09:31:28 -0500 Subject: [PATCH 81/88] Display STDOUT from Pkg.build Ref #23601 (cherry picked from commit 1ca3510baa14e0371fb53764276090f9108b1e9a) --- base/pkg/entry.jl | 2 +- test/pkg.jl | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/base/pkg/entry.jl b/base/pkg/entry.jl index 82bb1f5ab2fb9..bbf93962a8b9d 100644 --- a/base/pkg/entry.jl +++ b/base/pkg/entry.jl @@ -613,7 +613,7 @@ function build(pkg::AbstractString, build_file::AbstractString, errfile::Abstrac --eval $code ``` - success(pipeline(cmd, stderr=STDERR)) + success(pipeline(cmd, stdout=STDOUT, stderr=STDERR)) end function build!(pkgs::Vector, seen::Set, errfile::AbstractString) diff --git a/test/pkg.jl b/test/pkg.jl index c0012b49ed024..dd68d6cf773b1 100644 --- a/test/pkg.jl +++ b/test/pkg.jl @@ -531,6 +531,23 @@ temp_pkg_dir() do "redirect_stderr(STDOUT); using Example; Pkg.update(\"$package\")"`)) @test contains(msg, "- $package\nRestart Julia to use the updated versions.") end + + let package = "Output" + stdout_file = Pkg.dir(package, "stdout.txt") + stderr_file = Pkg.dir(package, "stderr.txt") + content = """ + println(STDOUT, "stdout") + println(STDERR, "stderr") + """ + write_build(package, content) + + code = "Pkg.build(\"$package\")" + msg = run(pipeline( + `$(Base.julia_cmd()) --startup-file=no -e $code`, + stdout=stdout_file, stderr=stderr_file)) + @test last(readlines(stdout_file)) == "stdout" + @test last(readlines(stderr_file)) == "stderr" + end end @testset "Pkg functions with .jl extension" begin From 269db8efd673b52da5b654fd7756057baa226a8c Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Fri, 15 Sep 2017 21:15:47 -0700 Subject: [PATCH 82/88] Adjust capitalization in LibGit2 test to be version agnostic --- test/libgit2.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/libgit2.jl b/test/libgit2.jl index 34db5d20b251a..0f09a6ff02d84 100644 --- a/test/libgit2.jl +++ b/test/libgit2.jl @@ -310,7 +310,9 @@ mktempdir() do dir error("unexpected") catch e @test typeof(e) == LibGit2.GitError - @test startswith(sprint(show,e),"GitError(Code:ENOTFOUND, Class:OS, Failed to resolve path") + @test startswith( + lowercase(sprint(show, e)), + lowercase("GitError(Code:ENOTFOUND, Class:OS, failed to resolve path")) end path = joinpath(dir, "Example.BareTwo") repo = LibGit2.init(path, true) From 7861fe817db6eac617fd46861c6501b44f4e287b Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Mon, 18 Sep 2017 13:05:45 -0500 Subject: [PATCH 83/88] Fix missing bounds checks for trailing zero dimensions (#23723) This fixes issue #23629 for 0.6. It is done independently from the fix for master (in #23628) due to all the deprecation changes. --- base/abstractarray.jl | 5 +++-- src/cgutils.cpp | 13 ++++++++++--- test/arrayops.jl | 5 +++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 6360769c785c5..8df9186d4ab07 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -407,9 +407,10 @@ function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple{Any}) end function checkbounds_linear_indices(::Type{Bool}, IA::Tuple{Vararg{OneTo}}, i) @_inline_meta - if checkindex(Bool, IA[1], i) + ts = trailingsize(IA) + if checkindex(Bool, IA[1], i) && ts > 0 return true - elseif checkindex(Bool, OneTo(trailingsize(IA)), i) # partial linear indexing + elseif checkindex(Bool, OneTo(ts), i) # partial linear indexing partial_linear_indexing_warning_lookup(length(IA)) return true # TODO: Return false after the above function is removed in deprecated.jl end diff --git a/src/cgutils.cpp b/src/cgutils.cpp index e9554702765fb..44f60c84f990a 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -1726,17 +1726,24 @@ static Value *emit_array_nd_index(const jl_cgval_t &ainfo, jl_value_t *ex, ssize // the accessed array, i.e. `if !(i < alen) goto error`. if (nidxs > 1) { // TODO: REMOVE DEPWARN AND RETURN FALSE AFTER 0.6. - // We need to check if this is inside the non-linearized size + // We need to check if this index is inside its non-linearized dimension BasicBlock *partidx = BasicBlock::Create(jl_LLVMContext, "partlinidx"); BasicBlock *partidxwarn = BasicBlock::Create(jl_LLVMContext, "partlinidxwarn"); + BasicBlock *trailingcheck = BasicBlock::Create(jl_LLVMContext, "trailingcheck"); Value *d = emit_arraysize_for_unsafe_dim(ainfo, ex, nidxs, nd, ctx); - builder.CreateCondBr(builder.CreateICmpULT(ii, d), endBB, partidx); + Value *alen = emit_arraylen(ainfo, ex, ctx); + builder.CreateCondBr(builder.CreateICmpULT(ii, d), trailingcheck, partidx); + + // If it is inside its own dimension, we still need to ensure all other + // dimensions are non-zero + ctx->f->getBasicBlockList().push_back(trailingcheck); + builder.SetInsertPoint(trailingcheck); + builder.CreateCondBr(builder.CreateICmpULT(ii, alen), endBB, failBB); // We failed the normal bounds check; check to see if we're // inside the linearized size (partial linear indexing): ctx->f->getBasicBlockList().push_back(partidx); builder.SetInsertPoint(partidx); - Value *alen = emit_arraylen(ainfo, ex, ctx); builder.CreateCondBr(builder.CreateICmpULT(i, alen), partidxwarn, failBB); // We passed the linearized bounds check; now throw the depwarn: diff --git a/test/arrayops.jl b/test/arrayops.jl index 36e6a3695f55e..e1a0a2497edac 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -2119,3 +2119,8 @@ Base.:(==)(a::T11053, b::T11053) = a.a == b.a #15907 @test typeof(Array{Int,0}()) == Array{Int,0} + +@testset "issue 23629" begin + @test_throws BoundsError zeros(2,3,0)[2,3] + @test_throws BoundsError checkbounds(zeros(2,3,0), 2, 3) +end From 65405cc41ae3a169ecd31b7d7f070e1c4ba2aa16 Mon Sep 17 00:00:00 2001 From: Alex Arslan Date: Mon, 18 Sep 2017 13:13:13 -0700 Subject: [PATCH 84/88] Move write_build to the outer scope --- test/pkg.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/pkg.jl b/test/pkg.jl index dd68d6cf773b1..16ce24d293c85 100644 --- a/test/pkg.jl +++ b/test/pkg.jl @@ -39,6 +39,12 @@ function temp_pkg_dir(fn::Function, tmp_dir=joinpath(tempdir(), randstring()), end end +function write_build(pkg, content) + build_filename = Pkg.dir(pkg, "deps", "build.jl") + mkpath(dirname(build_filename)) + write(build_filename, content) +end + # Test basic operations: adding or removing a package, status, free # Also test for the existence of REQUIRE and META_BRANCH temp_pkg_dir() do @@ -612,12 +618,6 @@ end end temp_pkg_dir(initialize=false) do - function write_build(pkg, content) - build_filename = Pkg.dir(pkg, "deps", "build.jl") - mkpath(dirname(build_filename)) - write(build_filename, content) - end - write_build("Normal", "") write_build("Error", "error(\"An error has occurred while building a package\")") write_build("Exit", "exit()") From 9b348ff635a1e59203236c83d3f287ce44439c56 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 22 Sep 2017 15:53:49 +0200 Subject: [PATCH 85/88] Add a small patch that allows us to generate code for PTX ISA 6.0. This is required for supporting newer NVIDIA GPUs, running under CUDA 9.0. Ref #23817 (cherry picked from commit 6626c1a153aba792dbc57bac614a64b1af692e71) --- deps/llvm.mk | 1 + .../llvm-3.9.0-D37576-NVPTX-sm_70.patch | 62 +++++++++++++++++++ .../llvm-4.0.0-D37576-NVPTX-sm_70.patch | 62 +++++++++++++++++++ 3 files changed, 125 insertions(+) create mode 100644 deps/patches/llvm-3.9.0-D37576-NVPTX-sm_70.patch create mode 100644 deps/patches/llvm-4.0.0-D37576-NVPTX-sm_70.patch diff --git a/deps/llvm.mk b/deps/llvm.mk index 5a2a0df4b9a17..f8cb58f36dc82 100644 --- a/deps/llvm.mk +++ b/deps/llvm.mk @@ -496,6 +496,7 @@ $(eval $(call LLVM_PATCH,llvm-rL293230-icc17-cmake)) # Remove for 4.0 $(eval $(call LLVM_PATCH,llvm-PR29010-i386-xmm)) # Remove for 4.0 $(eval $(call LLVM_PATCH,llvm-D32593)) $(eval $(call LLVM_PATCH,llvm-D33179)) +$(eval $(call LLVM_PATCH,llvm-3.9.0-D37576-NVPTX-sm_70)) # NVPTX, Remove for 6.0 endif # LLVM_VER ifeq ($(LLVM_VER),3.7.1) diff --git a/deps/patches/llvm-3.9.0-D37576-NVPTX-sm_70.patch b/deps/patches/llvm-3.9.0-D37576-NVPTX-sm_70.patch new file mode 100644 index 0000000000000..0ac8e44cc5c64 --- /dev/null +++ b/deps/patches/llvm-3.9.0-D37576-NVPTX-sm_70.patch @@ -0,0 +1,62 @@ +From 4059d374ce981827223ab6b1dae7af4ec5f8e74a Mon Sep 17 00:00:00 2001 +From: Artem Belevich +Date: Thu, 7 Sep 2017 18:14:32 +0000 +Subject: [PATCH] [CUDA] Added rudimentary support for CUDA-9 and sm_70. + +For now CUDA-9 is not included in the list of CUDA versions clang +searches for, so the path to CUDA-9 must be explicitly passed +via --cuda-path=. + +On LLVM side NVPTX added sm_70 GPU type which bumps required +PTX version to 6.0, but otherwise is equivalent to sm_62 at the moment. + +Differential Revision: https://reviews.llvm.org/D37576 + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@312734 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + lib/Target/NVPTX/NVPTX.td | 5 +++++ + test/CodeGen/NVPTX/sm-version-70.ll | 5 +++++ + 2 files changed, 10 insertions(+) + create mode 100644 test/CodeGen/NVPTX/sm-version-70.ll + +diff --git a/lib/Target/NVPTX/NVPTX.td b/lib/Target/NVPTX/NVPTX.td +index c77ddbc9978..aba37d36359 100644 +--- a/lib/Target/NVPTX/NVPTX.td ++++ b/lib/Target/NVPTX/NVPTX.td +@@ -50,6 +50,8 @@ def SM61 : SubtargetFeature<"sm_61", "SmVersion", "61", + "Target SM 6.1">; + def SM62 : SubtargetFeature<"sm_62", "SmVersion", "62", + "Target SM 6.2">; ++def SM70 : SubtargetFeature<"sm_70", "SmVersion", "70", ++ "Target SM 7.0">; + + def SATOM : SubtargetFeature<"satom", "HasAtomScope", "true", + "Atomic operations with scope">; +@@ -67,6 +69,8 @@ def PTX43 : SubtargetFeature<"ptx43", "PTXVersion", "43", + "Use PTX version 4.3">; + def PTX50 : SubtargetFeature<"ptx50", "PTXVersion", "50", + "Use PTX version 5.0">; ++def PTX60 : SubtargetFeature<"ptx60", "PTXVersion", "60", ++ "Use PTX version 6.0">; + + //===----------------------------------------------------------------------===// + // NVPTX supported processors. +@@ -87,6 +91,7 @@ def : Proc<"sm_53", [SM53, PTX42]>; + def : Proc<"sm_60", [SM60, PTX50]>; + def : Proc<"sm_61", [SM61, PTX50]>; + def : Proc<"sm_62", [SM62, PTX50]>; ++def : Proc<"sm_70", [SM70, PTX60]>; + + def NVPTXInstrInfo : InstrInfo { + } +diff --git a/test/CodeGen/NVPTX/sm-version-70.ll b/test/CodeGen/NVPTX/sm-version-70.ll +new file mode 100644 +index 00000000000..8b72d50747a +--- /dev/null ++++ b/test/CodeGen/NVPTX/sm-version-70.ll +@@ -0,0 +1,5 @@ ++; RUN: llc < %s -march=nvptx -mcpu=sm_70 | FileCheck %s ++; RUN: llc < %s -march=nvptx64 -mcpu=sm_70 | FileCheck %s ++ ++; CHECK: .version 6.0 ++; CHECK: .target sm_70 diff --git a/deps/patches/llvm-4.0.0-D37576-NVPTX-sm_70.patch b/deps/patches/llvm-4.0.0-D37576-NVPTX-sm_70.patch new file mode 100644 index 0000000000000..9fee1f36e2a95 --- /dev/null +++ b/deps/patches/llvm-4.0.0-D37576-NVPTX-sm_70.patch @@ -0,0 +1,62 @@ +From 4059d374ce981827223ab6b1dae7af4ec5f8e74a Mon Sep 17 00:00:00 2001 +From: Artem Belevich +Date: Thu, 7 Sep 2017 18:14:32 +0000 +Subject: [PATCH] [CUDA] Added rudimentary support for CUDA-9 and sm_70. + +For now CUDA-9 is not included in the list of CUDA versions clang +searches for, so the path to CUDA-9 must be explicitly passed +via --cuda-path=. + +On LLVM side NVPTX added sm_70 GPU type which bumps required +PTX version to 6.0, but otherwise is equivalent to sm_62 at the moment. + +Differential Revision: https://reviews.llvm.org/D37576 + +git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@312734 91177308-0d34-0410-b5e6-96231b3b80d8 +--- + lib/Target/NVPTX/NVPTX.td | 5 +++++ + test/CodeGen/NVPTX/sm-version-70.ll | 5 +++++ + 2 files changed, 10 insertions(+) + create mode 100644 test/CodeGen/NVPTX/sm-version-70.ll + +diff --git a/lib/Target/NVPTX/NVPTX.td b/lib/Target/NVPTX/NVPTX.td +index c77ddbc9978..aba37d36359 100644 +--- a/lib/Target/NVPTX/NVPTX.td ++++ b/lib/Target/NVPTX/NVPTX.td +@@ -50,6 +50,8 @@ def SM61 : SubtargetFeature<"sm_61", "SmVersion", "61", + "Target SM 6.1">; + def SM62 : SubtargetFeature<"sm_62", "SmVersion", "62", + "Target SM 6.2">; ++def SM70 : SubtargetFeature<"sm_70", "SmVersion", "70", ++ "Target SM 7.0">; + + def SATOM : SubtargetFeature<"satom", "HasAtomScope", "true", + "Atomic operations with scope">; +@@ -67,6 +69,8 @@ def PTX43 : SubtargetFeature<"ptx43", "PTXVersion", "43", + "Use PTX version 4.3">; + def PTX50 : SubtargetFeature<"ptx50", "PTXVersion", "50", + "Use PTX version 5.0">; ++def PTX60 : SubtargetFeature<"ptx60", "PTXVersion", "60", ++ "Use PTX version 6.0">; + + //===----------------------------------------------------------------------===// + // NVPTX supported processors. +@@ -87,6 +91,7 @@ def : Proc<"sm_53", [SM53, PTX42]>; + def : Proc<"sm_60", [SM60, PTX50, SATOM]>; + def : Proc<"sm_61", [SM61, PTX50, SATOM]>; + def : Proc<"sm_62", [SM62, PTX50, SATOM]>; ++def : Proc<"sm_70", [SM70, PTX60, SATOM]>; + + def NVPTXInstrInfo : InstrInfo { + } +diff --git a/test/CodeGen/NVPTX/sm-version-70.ll b/test/CodeGen/NVPTX/sm-version-70.ll +new file mode 100644 +index 00000000000..8b72d50747a +--- /dev/null ++++ b/test/CodeGen/NVPTX/sm-version-70.ll +@@ -0,0 +1,5 @@ ++; RUN: llc < %s -march=nvptx -mcpu=sm_70 | FileCheck %s ++; RUN: llc < %s -march=nvptx64 -mcpu=sm_70 | FileCheck %s ++ ++; CHECK: .version 6.0 ++; CHECK: .target sm_70 From 44a6ad3bc1ceed98bba967760ffdd14123cea659 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Sat, 30 Sep 2017 22:44:50 +0200 Subject: [PATCH 86/88] fix doctests for 0.6.1 (#23916) --- base/docs/helpdb/Base.jl | 4 ++-- base/linalg/eigen.jl | 4 ++-- base/random.jl | 16 +++++++--------- base/test.jl | 6 +++--- doc/src/manual/mathematical-operations.md | 8 ++++---- doc/src/manual/noteworthy-differences.md | 2 +- doc/src/manual/types.md | 2 +- 7 files changed, 20 insertions(+), 22 deletions(-) diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 4c779ddacded3..1328d5196d1fc 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -349,7 +349,7 @@ If `T` does not have a specific size, an error is thrown. julia> sizeof(Base.LinAlg.LU) ERROR: argument is an abstract type; size is indeterminate Stacktrace: - [1] sizeof(::Type{T} where T) at ./essentials.jl:150 + [1] sizeof(::Type{T} where T) at ./essentials.jl:159 ``` """ sizeof(::Type) @@ -1190,7 +1190,7 @@ julia> parse("x = ") julia> parse("1.0.2") ERROR: ParseError("invalid numeric constant \\\"1.0.\\\"") Stacktrace: - [...] +[...] julia> parse("1.0.2"; raise = false) :($(Expr(:error, "invalid numeric constant \"1.0.\""))) diff --git a/base/linalg/eigen.jl b/base/linalg/eigen.jl index 4280da7c2d196..0ef75b84c2246 100644 --- a/base/linalg/eigen.jl +++ b/base/linalg/eigen.jl @@ -228,7 +228,7 @@ julia> A = [0 im; -1 0] julia> eigmax(A) ERROR: DomainError: Stacktrace: - [1] #eigmax#52(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:238 + [1] #eigmax#46(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:238 [2] eigmax(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:236 ``` """ @@ -270,7 +270,7 @@ julia> A = [0 im; -1 0] julia> eigmin(A) ERROR: DomainError: Stacktrace: - [1] #eigmin#53(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:280 + [1] #eigmin#47(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:280 [2] eigmin(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:278 ``` """ diff --git a/base/random.jl b/base/random.jl index 6a46a71f4d591..80c276389c261 100644 --- a/base/random.jl +++ b/base/random.jl @@ -1237,22 +1237,20 @@ 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`](@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. +[`Float16`](@ref), [`Float32`](@ref), and [`Float64`](@ref) (the default). # Examples ```jldoctest julia> rng = MersenneTwister(1234); -julia> randn(rng, Complex128) -0.6133070881429037 - 0.6376291670853887im +julia> randn(rng, Float64) +0.8673472019512456 -julia> randn(rng, Complex64, (2, 4)) -2×4 Array{Complex{Float32},2}: - -0.349649-0.638457im 0.376756-0.192146im -0.396334-0.0136413im -0.585317+0.0778497im - 0.611224+1.56403im 0.355204-0.365563im 0.0905552+1.31012im -0.177608+0.261427im +julia> randn(rng, Float32, (2, 4)) +2×4 Array{Float32,2}: + -0.901744 -0.902914 2.21188 -0.271735 + -0.494479 0.864401 0.532813 0.502334 ``` """ @inline function randn(rng::AbstractRNG=GLOBAL_RNG) diff --git a/base/test.jl b/base/test.jl index 4454a213de998..aab681221480d 100644 --- a/base/test.jl +++ b/base/test.jl @@ -1041,10 +1041,10 @@ Int64 julia> @code_warntype f(1,2,3) Variables: - #self#::#f - a::Int64 + #self# + a b::Int64 - c::Int64 + c Body: begin diff --git a/doc/src/manual/mathematical-operations.md b/doc/src/manual/mathematical-operations.md index 71ef3fa77c464..4ec482ff36f64 100644 --- a/doc/src/manual/mathematical-operations.md +++ b/doc/src/manual/mathematical-operations.md @@ -397,7 +397,7 @@ julia> Int8(127) julia> Int8(128) ERROR: InexactError() Stacktrace: - [1] Int8(::Int64) at ./sysimg.jl:102 + [1] Int8(::Int64) at ./sysimg.jl:77 julia> Int8(127.0) 127 @@ -406,13 +406,13 @@ julia> Int8(3.14) ERROR: InexactError() Stacktrace: [1] convert(::Type{Int8}, ::Float64) at ./float.jl:658 - [2] Int8(::Float64) at ./sysimg.jl:24 + [2] Int8(::Float64) at ./sysimg.jl:77 julia> Int8(128.0) ERROR: InexactError() Stacktrace: - [1] convert(::Type{Int8}, ::Float64) at ./float.jl:659 - [2] Int8(::Float64) at ./sysimg.jl:102 + [1] convert(::Type{Int8}, ::Float64) at ./float.jl:658 + [2] Int8(::Float64) at ./sysimg.jl:77 julia> 127 % Int8 127 diff --git a/doc/src/manual/noteworthy-differences.md b/doc/src/manual/noteworthy-differences.md index 98740263fc364..ba2e1cae9cb34 100644 --- a/doc/src/manual/noteworthy-differences.md +++ b/doc/src/manual/noteworthy-differences.md @@ -146,7 +146,7 @@ For users coming to Julia from R, these are some noteworthy differences: For example: * Functions pertaining to probability distributions are provided by the [Distributions package](https://github.com/JuliaStats/Distributions.jl). - * The [DataFrames package](https://github.com/JuliaStats/DataFrames.jl) provides data frames. + * The [DataFrames package](https://github.com/JuliaData/DataFrames.jl) provides data frames. * Generalized linear models are provided by the [GLM package](https://github.com/JuliaStats/GLM.jl). * Julia provides tuples and real hash tables, but not R-style lists. When returning multiple items, you should typically use a tuple: instead of `list(a = 1, b = 2)`, use `(1, 2)`. diff --git a/doc/src/manual/types.md b/doc/src/manual/types.md index e9cc055b3784c..938a32e39f011 100644 --- a/doc/src/manual/types.md +++ b/doc/src/manual/types.md @@ -651,7 +651,7 @@ ERROR: MethodError: Cannot `convert` an object of type Float64 to an object of t This may have arisen from a call to the constructor Point{Float64}(...), since type constructors fall back to convert methods. Stacktrace: - [1] Point{Float64}(::Float64) at ./sysimg.jl:102 + [1] Point{Float64}(::Float64) at ./sysimg.jl:77 julia> Point{Float64}(1.0,2.0,3.0) ERROR: MethodError: no method matching Point{Float64}(::Float64, ::Float64, ::Float64) From 1a1ef7ac9c1b06eff10f5a2a83e6e48b22c770de Mon Sep 17 00:00:00 2001 From: Pablo Zubieta Date: Fri, 6 Oct 2017 16:40:37 -0500 Subject: [PATCH 87/88] Restore repeat preformance for arrays of scalars (#24022) (cherry picked from commit af5abb3516d5fb9262a33aafe25cc6f1ff1513bc) --- base/abstractarraymath.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 726c8c06ae851..7ccea62e60ed1 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -397,7 +397,11 @@ _rshps(shp, shp_i, sz, i, ::Tuple{}) = _reperr(s, n, N) = throw(ArgumentError("number of " * s * " repetitions " * "($n) cannot be less than number of dimensions of input ($N)")) -@propagate_inbounds function _repeat(A::AbstractArray, inner, outer) +# We need special handling when repeating arrays of arrays +cat_fill!(R, X, inds) = (R[inds...] = X) +cat_fill!(R, X::AbstractArray, inds) = fill!(view(R, inds...), X) + +@noinline function _repeat(A::AbstractArray, inner, outer) shape, inner_shape = rep_shapes(A, inner, outer) R = similar(A, shape) @@ -415,7 +419,7 @@ _reperr(s, n, N) = throw(ArgumentError("number of " * s * " repetitions " * n = inner[i] inner_indices[i] = (1:n) + ((c[i] - 1) * n) end - fill!(view(R, inner_indices...), A[c]) + cat_fill!(R, A[c], inner_indices) end end From f65127745b9a0e2aa8729048a45cae8cf7d461fc Mon Sep 17 00:00:00 2001 From: Eric Davies Date: Fri, 15 Sep 2017 15:12:16 -0500 Subject: [PATCH 88/88] Make print_matrix O(1) again (#23681) (cherry picked from commit c23d6bc0db0bddcc9d83a1d3609975a5dcc8fff8) --- base/show.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/base/show.jl b/base/show.jl index 76d8e42ff423c..b62e0d9acfc1f 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1463,9 +1463,8 @@ function print_matrix(io::IO, X::AbstractVecOrMat, postsp = "" @assert strwidth(hdots) == strwidth(ddots) sepsize = length(sep) - inds1, inds2 = indices(X,1), indices(X,2) - m, n = length(inds1), length(inds2) - rowsA, colsA = collect(inds1), collect(inds2) + rowsA, colsA = indices(X,1), indices(X,2) + m, n = length(rowsA), length(colsA) # To figure out alignments, only need to look at as many rows as could # fit down screen. If screen has at least as many rows as A, look at A. # If not, then we only need to look at the first and last chunks of A,