diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d2da8839ddb39..bf1380f5a07bc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,5 +2,5 @@ CODEOWNERS @JuliaLang/github-actions /.github/ @JuliaLang/github-actions /.buildkite/ @JuliaLang/github-actions -/.github/workflows/retry.yml @DilumAluthge +/.github/workflows/rerun_failed.yml @DilumAluthge /.github/workflows/statuses.yml @DilumAluthge diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e409381da3754..0c5b6593f40f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -345,7 +345,6 @@ please remove the `backport-X.Y` tag from the originating pull request for the c - If you see any unrelated changes to submodules like `deps/libuv`, `deps/openlibm`, etc., try running `git submodule update` first. - Descriptive commit messages are good. - Using `git add -p` or `git add -i` can be useful to avoid accidentally committing unrelated changes. - - GitHub does not send notifications when you push a new commit to a pull request, so please add a comment to the pull request thread to let reviewers know when you've made changes. - When linking to specific lines of code in discussion of an issue or pull request, hit the `y` key while viewing code on GitHub to reload the page with a URL that includes the specific version that you're viewing. That way any lines of code that you refer to will still make sense in the future, even if the content of the file changes. - Whitespace can be automatically removed from existing commits with `git rebase`. - To remove whitespace for the previous commit, run diff --git a/Make.inc b/Make.inc index c9692fa00c7e7..1b223b245a56b 100644 --- a/Make.inc +++ b/Make.inc @@ -1279,7 +1279,13 @@ JLDFLAGS += -Wl,--large-address-aware endif JCPPFLAGS += -D_WIN32_WINNT=0x0502 UNTRUSTED_SYSTEM_LIBM := 1 -endif +# Use hard links for files on windows, rather than soft links +# https://stackoverflow.com/questions/3648819/how-to-make-a-symbolic-link-with-cygwin-in-windows-7 +# Usage: $(WIN_MAKE_HARD_LINK) +WIN_MAKE_HARD_LINK := cp --dereference --link --force +else +WIN_MAKE_HARD_LINK := true -ignore +endif # $(OS) == WINNT # Threads ifneq ($(JULIA_THREADS), 0) diff --git a/Makefile b/Makefile index 958024c9942d3..42774ef531eaa 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ JULIAHOME := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) include $(JULIAHOME)/Make.inc +# import LLVM_SHARED_LIB_NAME +include $(JULIAHOME)/deps/llvm-ver.make VERSDIR := v`cut -d. -f1-2 < $(JULIAHOME)/VERSION` @@ -197,7 +199,7 @@ else JL_PRIVATE_LIBS-$(USE_SYSTEM_ZLIB) += libz endif ifeq ($(USE_LLVM_SHLIB),1) -JL_PRIVATE_LIBS-$(USE_SYSTEM_LLVM) += libLLVM libLLVM-14jl +JL_PRIVATE_LIBS-$(USE_SYSTEM_LLVM) += libLLVM $(LLVM_SHARED_LIB_NAME) endif JL_PRIVATE_LIBS-$(USE_SYSTEM_LIBUNWIND) += libunwind diff --git a/NEWS.md b/NEWS.md index 434e38078b01c..57d729aa44257 100644 --- a/NEWS.md +++ b/NEWS.md @@ -111,6 +111,9 @@ Standard library changes #### Printf +* Error messages for bad format strings have been improved, to make it clearer what & where in the + format string is wrong. ([#45366]) + #### Random * `randn` and `randexp` now work for any `AbstractFloat` type defining `rand` ([#44714]). diff --git a/README.md b/README.md index 007704a3e67b6..442ec990e6e21 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ If you would rather not compile the latest Julia from source, platform-specific tarballs with pre-compiled binaries are also [available for download](https://julialang.org/downloads/). The downloads page also provides details on the -[different tiers of support](https://julialang.org/downloads/#support-tiers) +[different tiers of support](https://julialang.org/downloads/#supported_platforms) for OS and platform combinations. If everything works correctly, you will see a Julia banner and an @@ -120,10 +120,9 @@ are included in the [build documentation](https://github.com/JuliaLang/julia/blo ### Uninstalling Julia -Julia does not install anything outside the directory it was cloned -into. Julia can be completely uninstalled by deleting this -directory. Julia packages are installed in `~/.julia` by default, and -can be uninstalled by deleting `~/.julia`. +By default, Julia does not install anything outside the directory it was cloned +into and `~/.julia`. Julia and the vast majority of Julia packages can be +completely uninstalled by deleting these two directories. ## Source Code Organization diff --git a/base/Base.jl b/base/Base.jl index 843d5e6087b2c..aa29a6d08c943 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -130,6 +130,8 @@ const REPL_MODULE_REF = Ref{Module}() include("checked.jl") using .Checked +function cld end +function fld end # Lazy strings include("strings/lazy.jl") diff --git a/base/abstractarray.jl b/base/abstractarray.jl index b710c35a0876b..b5b74bd8446c0 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1076,7 +1076,7 @@ function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle: # Dual-iterator implementation ret = iterate(iterdest) @inbounds for a in src - idx, state = ret + idx, state = ret::NTuple{2,Any} dest[idx] = a ret = iterate(iterdest, state) end diff --git a/base/atomics.jl b/base/atomics.jl index e6d62c3fc807b..7312206c19896 100644 --- a/base/atomics.jl +++ b/base/atomics.jl @@ -20,7 +20,7 @@ export # - LLVM doesn't currently support atomics on floats for ppc64 # C++20 is adding limited support for atomics on float, but as of # now Clang does not support that yet. -if Sys.ARCH == :i686 || startswith(string(Sys.ARCH), "arm") || +if Sys.ARCH === :i686 || startswith(string(Sys.ARCH), "arm") || Sys.ARCH === :powerpc64le || Sys.ARCH === :ppc64le const inttypes = (Int8, Int16, Int32, Int64, UInt8, UInt16, UInt32, UInt64) diff --git a/base/boot.jl b/base/boot.jl index 057767db295fe..ddf82b9823453 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -453,6 +453,18 @@ convert(::Type{T}, x::T) where {T} = x cconvert(::Type{T}, x) where {T} = convert(T, x) unsafe_convert(::Type{T}, x::T) where {T} = x +_is_internal(__module__) = __module__ === Core +# can be used in place of `@assume_effects :foldable` (supposed to be used for bootstrapping) +macro _foldable_meta() + return _is_internal(__module__) && Expr(:meta, Expr(:purity, + #=:consistent=#true, + #=:effect_free=#true, + #=:nothrow=#false, + #=:terminates_globally=#true, + #=:terminates_locally=#false, + #=:notaskstate=#false)) +end + const NTuple{N,T} = Tuple{Vararg{T,N}} ## primitive Array constructors @@ -480,7 +492,6 @@ Array{T}(::UndefInitializer, d::NTuple{N,Int}) where {T,N} = Array{T,N}(undef, d # empty vector constructor Array{T,1}() where {T} = Array{T,1}(undef, 0) - (Array{T,N} where T)(x::AbstractArray{S,N}) where {S,N} = Array{S,N}(x) Array(A::AbstractArray{T,N}) where {T,N} = Array{T,N}(A) @@ -489,12 +500,12 @@ Array{T}(A::AbstractArray{S,N}) where {T,N,S} = Array{T,N}(A) AbstractArray{T}(A::AbstractArray{S,N}) where {T,S,N} = AbstractArray{T,N}(A) # primitive Symbol constructors -eval(Core, :(function Symbol(s::String) - $(Expr(:meta, :pure)) +function Symbol(s::String) + @_foldable_meta return ccall(:jl_symbol_n, Ref{Symbol}, (Ptr{UInt8}, Int), ccall(:jl_string_ptr, Ptr{UInt8}, (Any,), s), sizeof(s)) -end)) +end function Symbol(a::Array{UInt8,1}) return ccall(:jl_symbol_n, Ref{Symbol}, (Ptr{UInt8}, Int), ccall(:jl_array_ptr, Ptr{UInt8}, (Any,), a), diff --git a/base/broadcast.jl b/base/broadcast.jl index 1896e5edad105..a54016ad00917 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -1185,7 +1185,7 @@ Base.@propagate_inbounds dotview(B::BitArray, i::BitArray) = BitMaskedBitArray(B Base.show(io::IO, B::BitMaskedBitArray) = foreach(arg->show(io, arg), (typeof(B), (B.parent, B.mask))) # Override materialize! to prevent the BitMaskedBitArray from escaping to an overrideable method @inline materialize!(B::BitMaskedBitArray, bc::Broadcasted{<:Any,<:Any,typeof(identity),Tuple{Bool}}) = fill!(B, bc.args[1]) -@inline materialize!(B::BitMaskedBitArray, bc::Broadcasted{<:Any}) = materialize!(SubArray(B.parent, to_indices(B.parent, (B.mask,))), bc) +@inline materialize!(B::BitMaskedBitArray, bc::Broadcasted{<:Any}) = materialize!(@inbounds(view(B.parent, B.mask)), bc) function Base.fill!(B::BitMaskedBitArray, b::Bool) Bc = B.parent.chunks Ic = B.mask.chunks diff --git a/base/channels.jl b/base/channels.jl index da7b1d24583ca..0cf3b8d799926 100644 --- a/base/channels.jl +++ b/base/channels.jl @@ -493,14 +493,18 @@ function show(io::IO, ::MIME"text/plain", c::Channel) end function iterate(c::Channel, state=nothing) - try - return (take!(c), nothing) - catch e - if isa(e, InvalidStateException) && e.state === :closed - return nothing - else - rethrow() + if isopen(c) || isready(c) + try + return (take!(c), nothing) + catch e + if isa(e, InvalidStateException) && e.state === :closed + return nothing + else + rethrow() + end end + else + return nothing end end diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 5aa7669c3a3a9..b9daf48d9ba71 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -496,13 +496,13 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp add_remark!(interp, sv, "Refusing to infer into `depwarn`") return MethodCallResult(Any, false, false, nothing, Effects()) end - topmost = nothing + # Limit argument type tuple growth of functions: # look through the parents list to see if there's a call to the same method # and from the same method. # Returns the topmost occurrence of that repeated edge. - edgecycle = false - edgelimited = false + edgecycle = edgelimited = false + topmost = nothing for infstate in InfStackUnwind(sv) if method === infstate.linfo.def @@ -617,9 +617,13 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp # this edge is known to terminate effects = Effects(effects; terminates=ALWAYS_TRUE) elseif edgecycle - # Some sort of recursion was detected. Even if we did not limit types, - # we cannot guarantee that the call will terminate - effects = Effects(effects; terminates=ALWAYS_FALSE) + # Some sort of recursion was detected. + if edge !== nothing && !edgelimited && !is_edge_recursed(edge, sv) + # no `MethodInstance` cycles -- don't taint :terminate + else + # we cannot guarantee that the call will terminate + effects = Effects(effects; terminates=ALWAYS_FALSE) + end end return MethodCallResult(rt, edgecycle, edgelimited, edge, effects) @@ -691,6 +695,30 @@ function matches_sv(parent::InferenceState, sv::InferenceState) return parent.linfo.def === sv.linfo.def && sv_method2 === parent_method2 end +function is_edge_recursed(edge::MethodInstance, sv::InferenceState) + return any(InfStackUnwind(sv)) do infstate + return edge === infstate.linfo + end +end + +function is_method_recursed(method::Method, sv::InferenceState) + return any(InfStackUnwind(sv)) do infstate + return method === infstate.linfo.def + end +end + +function is_constprop_edge_recursed(edge::MethodInstance, sv::InferenceState) + return any(InfStackUnwind(sv)) do infstate + return edge === infstate.linfo && any(infstate.result.overridden_by_const) + end +end + +function is_constprop_method_recursed(method::Method, sv::InferenceState) + return any(InfStackUnwind(sv)) do infstate + return method === infstate.linfo.def && any(infstate.result.overridden_by_const) + end +end + # keeps result and context information of abstract_method_call, which will later be used for # backedge computation, and concrete evaluation or constant-propagation struct MethodCallResult @@ -799,8 +827,7 @@ function const_prop_enabled(interp::AbstractInterpreter, sv::InferenceState, mat add_remark!(interp, sv, "[constprop] Disabled by parameter") return false end - method = match.method - if method.constprop == 0x02 + if is_no_constprop(match.method) add_remark!(interp, sv, "[constprop] Disabled by method parameter") return false end @@ -836,17 +863,14 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, resul if inf_result === nothing # if there might be a cycle, check to make sure we don't end up # calling ourselves here. - let result = result # prevent capturing - if result.edgecycle && _any(InfStackUnwind(sv)) do infstate - # if the type complexity limiting didn't decide to limit the call signature (`result.edgelimited = false`) - # we can relax the cycle detection by comparing `MethodInstance`s and allow inference to - # propagate different constant elements if the recursion is finite over the lattice - return (result.edgelimited ? match.method === infstate.linfo.def : mi === infstate.linfo) && - any(infstate.result.overridden_by_const) - end - add_remark!(interp, sv, "[constprop] Edge cycle encountered") - return nothing - end + if result.edgecycle && (result.edgelimited ? + is_constprop_method_recursed(match.method, sv) : + # if the type complexity limiting didn't decide to limit the call signature (`result.edgelimited = false`) + # we can relax the cycle detection by comparing `MethodInstance`s and allow inference to + # propagate different constant elements if the recursion is finite over the lattice + is_constprop_edge_recursed(mi, sv)) + add_remark!(interp, sv, "[constprop] Edge cycle encountered") + return nothing end inf_result = InferenceResult(mi, (arginfo, sv)) if !any(inf_result.overridden_by_const) @@ -963,8 +987,8 @@ function is_const_prop_profitable_arg(@nospecialize(arg)) isa(arg, PartialOpaque) && return true isa(arg, Const) || return true val = arg.val - # don't consider mutable values or Strings useful constants - return isa(val, Symbol) || isa(val, Type) || (!isa(val, String) && !ismutable(val)) + # don't consider mutable values useful constants + return isa(val, Symbol) || isa(val, Type) || !ismutable(val) end function is_const_prop_profitable_conditional(cnd::Conditional, fargs::Vector{Any}, sv::InferenceState) @@ -1003,7 +1027,7 @@ function is_all_overridden((; fargs, argtypes)::ArgInfo, sv::InferenceState) end function force_const_prop(interp::AbstractInterpreter, @nospecialize(f), method::Method) - return method.constprop == 0x01 || + return is_aggressive_constprop(method) || InferenceParams(interp).aggressive_constant_propagation || istopfunction(f, :getproperty) || istopfunction(f, :setproperty!) @@ -1345,7 +1369,7 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv:: end cti = Any[Vararg{argt}] end - if _any(t -> t === Bottom, cti) + if any(@nospecialize(t) -> t === Bottom, cti) continue end for j = 1:length(ctypes) @@ -1654,7 +1678,8 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), return abstract_finalizer(interp, argtypes, sv) end rt = abstract_call_builtin(interp, f, arginfo, sv, max_methods) - return CallMeta(rt, builtin_effects(f, argtypes, rt), false) + effects = builtin_effects(f, argtypes[2:end], rt) + return CallMeta(rt, effects, false) elseif isa(f, Core.OpaqueClosure) # calling an OpaqueClosure about which we have no information returns no information return CallMeta(Any, Effects(), false) @@ -2031,23 +2056,23 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), for i = 3:length(e.args) if abstract_eval_value(interp, e.args[i], vtypes, sv) === Bottom t = Bottom + tristate_merge!(sv, EFFECTS_THROWS) + @goto t_computed end end + effects = EFFECTS_UNKNOWN cconv = e.args[5] if isa(cconv, QuoteNode) && (v = cconv.value; isa(v, Tuple{Symbol, UInt8})) - effects = v[2] - effects = decode_effects_override(effects) - tristate_merge!(sv, Effects( - effects.consistent ? ALWAYS_TRUE : ALWAYS_FALSE, - effects.effect_free ? ALWAYS_TRUE : ALWAYS_FALSE, - effects.nothrow ? ALWAYS_TRUE : ALWAYS_FALSE, - effects.terminates_globally ? ALWAYS_TRUE : ALWAYS_FALSE, - #=nonoverlayed=#true, - effects.notaskstate ? ALWAYS_TRUE : ALWAYS_FALSE - )) - else - tristate_merge!(sv, EFFECTS_UNKNOWN) - end + override = decode_effects_override(v[2]) + effects = Effects( + override.consistent ? ALWAYS_TRUE : effects.consistent, + override.effect_free ? ALWAYS_TRUE : effects.effect_free, + override.nothrow ? ALWAYS_TRUE : effects.nothrow, + override.terminates_globally ? ALWAYS_TRUE : effects.terminates_globally, + effects.nonoverlayed ? true : false, + override.notaskstate ? ALWAYS_TRUE : effects.notaskstate) + end + tristate_merge!(sv, effects) elseif ehead === :cfunction tristate_merge!(sv, EFFECTS_UNKNOWN) t = e.args[1] @@ -2311,9 +2336,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) @assert !frame.inferred frame.dont_work_on_me = true # mark that this function is currently on the stack W = frame.ip - def = frame.linfo.def - isva = isa(def, Method) && def.isva - nargs = length(frame.result.argtypes) - isva + nargs = narguments(frame) slottypes = frame.slottypes ssavaluetypes = frame.ssavaluetypes bbs = frame.cfg.blocks diff --git a/base/compiler/compiler.jl b/base/compiler/compiler.jl index 5bd0852e06e53..8b6da7902457a 100644 --- a/base/compiler/compiler.jl +++ b/base/compiler/compiler.jl @@ -67,6 +67,22 @@ include("refvalue.jl") # the same constructor as defined in float.jl, but with a different name to avoid redefinition _Bool(x::Real) = x==0 ? false : x==1 ? true : throw(InexactError(:Bool, Bool, x)) +# fld(x,y) == div(x,y) - ((x>=0) != (y>=0) && rem(x,y) != 0 ? 1 : 0) +fld(x::T, y::T) where {T<:Unsigned} = div(x, y) +function fld(x::T, y::T) where T<:Integer + d = div(x, y) + return d - (signbit(x ⊻ y) & (d * y != x)) +end +# cld(x,y) = div(x,y) + ((x>0) == (y>0) && rem(x,y) != 0 ? 1 : 0) +function cld(x::T, y::T) where T<:Unsigned + d = div(x, y) + return d + (d * y != x) +end +function cld(x::T, y::T) where T<:Integer + d = div(x, y) + return d + (((x > 0) == (y > 0)) & (d * y != x)) +end + # checked arithmetic const checked_add = + diff --git a/base/compiler/effects.jl b/base/compiler/effects.jl index 9e041dca3a733..3d4584d1bf58f 100644 --- a/base/compiler/effects.jl +++ b/base/compiler/effects.jl @@ -57,27 +57,28 @@ struct Effects # This effect is currently only tracked in inference and modified # :consistent before caching. We may want to track it in the future. inbounds_taints_consistency::Bool -end -function Effects( - consistent::TriState, - effect_free::TriState, - nothrow::TriState, - terminates::TriState, - nonoverlayed::Bool, - notaskstate::TriState) - return Effects( - consistent, - effect_free, - nothrow, - terminates, - nonoverlayed, - notaskstate, - false) + function Effects( + consistent::TriState, + effect_free::TriState, + nothrow::TriState, + terminates::TriState, + nonoverlayed::Bool, + notaskstate::TriState, + inbounds_taints_consistency::Bool = false) + return new( + consistent, + effect_free, + nothrow, + terminates, + nonoverlayed, + notaskstate, + inbounds_taints_consistency) + end end const EFFECTS_TOTAL = Effects(ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE, true, ALWAYS_TRUE) const EFFECTS_THROWS = Effects(ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_FALSE, ALWAYS_TRUE, true, ALWAYS_TRUE) -const EFFECTS_UNKNOWN = Effects(ALWAYS_FALSE, ALWAYS_FALSE, ALWAYS_FALSE, ALWAYS_FALSE, true, ALWAYS_FALSE) # mostly unknown, but it's not overlayed at least (e.g. it's not a call) +const EFFECTS_UNKNOWN = Effects(ALWAYS_FALSE, ALWAYS_FALSE, ALWAYS_FALSE, ALWAYS_FALSE, true, ALWAYS_FALSE) # mostly unknown, but it's not overlayed at least (e.g. it's not a call) const EFFECTS_UNKNOWN′ = Effects(ALWAYS_FALSE, ALWAYS_FALSE, ALWAYS_FALSE, ALWAYS_FALSE, false, ALWAYS_FALSE) # unknown, really function Effects(e::Effects = EFFECTS_UNKNOWN′; @@ -121,13 +122,14 @@ is_removable_if_unused(effects::Effects) = is_nothrow(effects) function encode_effects(e::Effects) - return (e.consistent.state << 0) | - (e.effect_free.state << 2) | - (e.nothrow.state << 4) | - (e.terminates.state << 6) | - (UInt32(e.nonoverlayed) << 8) | - (UInt32(e.notaskstate.state) << 9) + return ((e.consistent.state) << 0) | + ((e.effect_free.state) << 2) | + ((e.nothrow.state) << 4) | + ((e.terminates.state) << 6) | + ((e.nonoverlayed % UInt32) << 8) | + ((e.notaskstate.state % UInt32) << 9) end + function decode_effects(e::UInt32) return Effects( TriState((e >> 0) & 0x03), @@ -135,8 +137,7 @@ function decode_effects(e::UInt32) TriState((e >> 4) & 0x03), TriState((e >> 6) & 0x03), _Bool( (e >> 8) & 0x01), - TriState((e >> 9) & 0x03), - false) + TriState((e >> 9) & 0x03)) end function tristate_merge(old::Effects, new::Effects) @@ -166,21 +167,21 @@ end function encode_effects_override(eo::EffectsOverride) e = 0x00 - eo.consistent && (e |= 0x01) - eo.effect_free && (e |= 0x02) - eo.nothrow && (e |= 0x04) - eo.terminates_globally && (e |= 0x08) - eo.terminates_locally && (e |= 0x10) - eo.notaskstate && (e |= 0x20) + eo.consistent && (e |= (0x01 << 0)) + eo.effect_free && (e |= (0x01 << 1)) + eo.nothrow && (e |= (0x01 << 2)) + eo.terminates_globally && (e |= (0x01 << 3)) + eo.terminates_locally && (e |= (0x01 << 4)) + eo.notaskstate && (e |= (0x01 << 5)) return e end function decode_effects_override(e::UInt8) return EffectsOverride( - (e & 0x01) != 0x00, - (e & 0x02) != 0x00, - (e & 0x04) != 0x00, - (e & 0x08) != 0x00, - (e & 0x10) != 0x00, - (e & 0x20) != 0x00) + (e & (0x01 << 0)) != 0x00, + (e & (0x01 << 1)) != 0x00, + (e & (0x01 << 2)) != 0x00, + (e & (0x01 << 3)) != 0x00, + (e & (0x01 << 4)) != 0x00, + (e & (0x01 << 5)) != 0x00) end diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index 45e75ed05573a..a40f63c701200 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -521,3 +521,10 @@ function print_callstack(sv::InferenceState) end get_curr_ssaflag(sv::InferenceState) = sv.src.ssaflags[sv.currpc] + +function narguments(sv::InferenceState) + def = sv.linfo.def + isva = isa(def, Method) && def.isva + nargs = length(sv.result.argtypes) - isva + return nargs +end diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index 1e812db13c9eb..f2b56fc493788 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -30,7 +30,6 @@ const IR_FLAG_EFFECT_FREE = 0x01 << 4 # This statement was proven not to throw const IR_FLAG_NOTHROW = 0x01 << 5 - const TOP_TUPLE = GlobalRef(Core, :tuple) ##################### @@ -772,7 +771,7 @@ function statement_cost(ex::Expr, line::Int, src::Union{CodeInfo, IRCode}, sptyp return 0 end return error_path ? params.inline_error_path_cost : params.inline_nonleaf_penalty - elseif head === :foreigncall || head === :invoke || head == :invoke_modify + elseif head === :foreigncall || head === :invoke || head === :invoke_modify # Calls whose "return type" is Union{} do not actually return: # they are errors. Since these are not part of the typical # run-time of the function, we omit them from diff --git a/base/compiler/ssair/domtree.jl b/base/compiler/ssair/domtree.jl index fd49a7e118eb7..984de95a4b58d 100644 --- a/base/compiler/ssair/domtree.jl +++ b/base/compiler/ssair/domtree.jl @@ -227,6 +227,7 @@ function compute_domtree_nodes!(domtree::DomTree) (idx == 1 || idom == 0) && continue push!(domtree.nodes[idom].children, idx) end + # n.b. now issorted(domtree.nodes[*].children) since idx is sorted above # Recursively set level update_level!(domtree.nodes, 1, 1) return domtree.nodes diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index ca9eb818f0edb..3a6333470fabe 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -767,7 +767,7 @@ function rewrite_apply_exprargs!( elseif isa(new_info, MethodMatchInfo) || isa(new_info, UnionSplitInfo) new_infos = isa(new_info, MethodMatchInfo) ? MethodMatchInfo[new_info] : new_info.matches # See if we can inline this call to `iterate` - analyze_single_call!( + handle_call!( ir, state1.id, new_stmt, new_infos, flag, new_sig, istate, todo) end @@ -874,8 +874,7 @@ function validate_sparams(sparams::SimpleVector) end function analyze_method!(match::MethodMatch, argtypes::Vector{Any}, - flag::UInt8, state::InliningState, - do_resolve::Bool = true) + flag::UInt8, state::InliningState) method = match.method spec_types = match.spec_types @@ -909,7 +908,7 @@ function analyze_method!(match::MethodMatch, argtypes::Vector{Any}, todo = InliningTodo(mi, match, argtypes) # If we don't have caches here, delay resolving this MethodInstance # until the batch inlining step (or an external post-processing pass) - do_resolve && state.mi_cache === nothing && return todo + state.mi_cache === nothing && return todo return resolve_todo(todo, state, flag) end @@ -921,7 +920,7 @@ function retrieve_ir_for_inlining(mi::MethodInstance, src::Array{UInt8, 1}) src = ccall(:jl_uncompress_ir, Any, (Any, Ptr{Cvoid}, Any), mi.def, C_NULL, src::Vector{UInt8})::CodeInfo return inflate_ir!(src, mi) end -retrieve_ir_for_inlining(mi::MethodInstance, src::CodeInfo) = inflate_ir(src, mi)::IRCode +retrieve_ir_for_inlining(mi::MethodInstance, src::CodeInfo) = inflate_ir(src, mi) retrieve_ir_for_inlining(mi::MethodInstance, ir::IRCode) = copy(ir) function handle_single_case!( @@ -1225,10 +1224,8 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto end # TODO inline non-`isdispatchtuple`, union-split callsites? -function compute_inlining_cases( - infos::Vector{MethodMatchInfo}, flag::UInt8, - sig::Signature, state::InliningState, - do_resolve::Bool = true) +function compute_inlining_cases(infos::Vector{MethodMatchInfo}, + flag::UInt8, sig::Signature, state::InliningState) argtypes = sig.argtypes cases = InliningCase[] local any_fully_covered = false @@ -1245,7 +1242,7 @@ function compute_inlining_cases( continue end for match in meth - handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, true, do_resolve) + handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, #=allow_abstract=#true) any_fully_covered |= match.fully_covers end end @@ -1258,23 +1255,10 @@ function compute_inlining_cases( return cases, handled_all_cases & any_fully_covered end -function analyze_single_call!( - ir::IRCode, idx::Int, stmt::Expr, infos::Vector{MethodMatchInfo}, flag::UInt8, - sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}}) - - r = compute_inlining_cases(infos, flag, sig, state) - r === nothing && return nothing - cases, all_covered = r - handle_cases!(ir, idx, stmt, argtypes_to_type(sig.argtypes), cases, - all_covered, todo, state.params) -end - -# similar to `analyze_single_call!`, but with constant results -function handle_const_call!( - ir::IRCode, idx::Int, stmt::Expr, cinfo::ConstCallInfo, flag::UInt8, - sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}}) +function compute_inlining_cases(info::ConstCallInfo, + flag::UInt8, sig::Signature, state::InliningState) argtypes = sig.argtypes - (; call, results) = cinfo + (; call, results) = info infos = isa(call, MethodMatchInfo) ? MethodMatchInfo[call] : call.matches cases = InliningCase[] local any_fully_covered = false @@ -1302,7 +1286,7 @@ function handle_const_call!( handled_all_cases &= handle_const_prop_result!(result, argtypes, flag, state, cases, true) else @assert result === nothing - handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, true) + handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, #=allow_abstract=#true) end end end @@ -1312,21 +1296,39 @@ function handle_const_call!( filter!(case::InliningCase->isdispatchtuple(case.sig), cases) end - handle_cases!(ir, idx, stmt, argtypes_to_type(argtypes), cases, - handled_all_cases & any_fully_covered, todo, state.params) + return cases, handled_all_cases & any_fully_covered +end + +function handle_call!( + ir::IRCode, idx::Int, stmt::Expr, infos::Vector{MethodMatchInfo}, flag::UInt8, + sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}}) + cases = compute_inlining_cases(infos, flag, sig, state) + cases === nothing && return nothing + cases, all_covered = cases + handle_cases!(ir, idx, stmt, argtypes_to_type(sig.argtypes), cases, + all_covered, todo, state.params) +end + +function handle_const_call!( + ir::IRCode, idx::Int, stmt::Expr, info::ConstCallInfo, flag::UInt8, + sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}}) + cases = compute_inlining_cases(info, flag, sig, state) + cases === nothing && return nothing + cases, all_covered = cases + handle_cases!(ir, idx, stmt, argtypes_to_type(sig.argtypes), cases, + all_covered, todo, state.params) end function handle_match!( match::MethodMatch, argtypes::Vector{Any}, flag::UInt8, state::InliningState, - cases::Vector{InliningCase}, allow_abstract::Bool = false, - do_resolve::Bool = true) + cases::Vector{InliningCase}, allow_abstract::Bool = false) spec_types = match.spec_types allow_abstract || isdispatchtuple(spec_types) || return false # we may see duplicated dispatch signatures here when a signature gets widened # during abstract interpretation: for the purpose of inlining, we can just skip # processing this dispatch candidate _any(case->case.sig === spec_types, cases) && return true - item = analyze_method!(match, argtypes, flag, state, do_resolve) + item = analyze_method!(match, argtypes, flag, state) item === nothing && return false push!(cases, InliningCase(spec_types, item)) return true @@ -1384,6 +1386,54 @@ function handle_const_opaque_closure_call!( return nothing end +function handle_finalizer_call!( + ir::IRCode, stmt::Expr, info::FinalizerInfo, state::InliningState) + # Only inline finalizers that are known nothrow and notls. + # This avoids having to set up state for finalizer isolation + (is_nothrow(info.effects) && is_notaskstate(info.effects)) || return nothing + + info = info.info + if isa(info, MethodMatchInfo) + infos = MethodMatchInfo[info] + elseif isa(info, UnionSplitInfo) + infos = info.matches + # elseif isa(info, ConstCallInfo) + # # NOTE currently this code path isn't active as constant propagation won't happen + # # for `Core.finalizer` call because inference currently isn't able to fold a mutable + # # object as a constant + else + return nothing + end + + ft = argextype(stmt.args[2], ir) + has_free_typevars(ft) && return nothing + f = singleton_type(ft) + argtypes = Vector{Any}(undef, 2) + argtypes[1] = ft + argtypes[2] = argextype(stmt.args[3], ir) + sig = Signature(f, ft, argtypes) + + cases = compute_inlining_cases(infos, #=flag=#UInt8(0), sig, state) + cases === nothing && return nothing + cases, all_covered = cases + if all_covered && length(cases) == 1 + # NOTE we don't append `item1` to `stmt` here so that we don't serialize + # `Core.Compiler` data structure into the global cache + item1 = cases[1].item + if isa(item1, InliningTodo) + push!(stmt.args, true) + push!(stmt.args, item1.mi) + elseif isa(item1, InvokeCase) + push!(stmt.args, false) + push!(stmt.args, item1.invoke) + elseif isa(item1, ConstantCase) + push!(stmt.args, nothing) + push!(stmt.args, item1.val) + end + end + return nothing +end + function inline_const_if_inlineable!(inst::Instruction) rt = inst[:type] if rt isa Const && is_inlineable_constant(rt.val) @@ -1434,53 +1484,15 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState) end # Handle invoke - if sig.f === Core.invoke - if isa(info, InvokeCallInfo) - inline_invoke!(ir, idx, stmt, info, flag, sig, state, todo) - end + if isa(info, InvokeCallInfo) + inline_invoke!(ir, idx, stmt, info, flag, sig, state, todo) continue end # Handle finalizer - if sig.f === Core.finalizer - if isa(info, FinalizerInfo) - # Only inline finalizers that are known nothrow and notls. - # This avoids having to set up state for finalizer isolation - (is_nothrow(info.effects) && is_notaskstate(info.effects)) || continue - - info = info.info - if isa(info, MethodMatchInfo) - infos = MethodMatchInfo[info] - elseif isa(info, UnionSplitInfo) - infos = info.matches - else - continue - end - - ft = argextype(stmt.args[2], ir) - has_free_typevars(ft) && return nothing - f = singleton_type(ft) - argtypes = Vector{Any}(undef, 2) - argtypes[1] = ft - argtypes[2] = argextype(stmt.args[3], ir) - sig = Signature(f, ft, argtypes) - - cases, all_covered = compute_inlining_cases(infos, UInt8(0), sig, state, false) - length(cases) == 0 && continue - if all_covered && length(cases) == 1 - if isa(cases[1], InliningCase) - case1 = cases[1].item - if isa(case1, InliningTodo) - push!(stmt.args, true) - push!(stmt.args, case1.mi) - elseif isa(case1, InvokeCase) - push!(stmt.args, false) - push!(stmt.args, case1.invoke) - end - end - end - continue - end + if isa(info, FinalizerInfo) + handle_finalizer_call!(ir, stmt, info, state) + continue end # if inference arrived here with constant-prop'ed result(s), @@ -1501,7 +1513,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState) continue # isa(info, ReturnTypeCallInfo), etc. end - analyze_single_call!(ir, idx, stmt, infos, flag, sig, state, todo) + handle_call!(ir, idx, stmt, infos, flag, sig, state, todo) end return todo diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index 047d4577cc7bc..58626f5279dde 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -14,7 +14,7 @@ GetfieldUse(idx::Int) = SSAUse(:getfield, idx) PreserveUse(idx::Int) = SSAUse(:preserve, idx) NoPreserve() = SSAUse(:nopreserve, 0) IsdefinedUse(idx::Int) = SSAUse(:isdefined, idx) -AddFinalizerUse(idx::Int) = SSAUse(:add_finalizer, idx) +FinalizerUse(idx::Int) = SSAUse(:finalizer, idx) """ du::SSADefUse @@ -604,11 +604,14 @@ function get(x::LazyDomtree) end function perform_lifting!(compact::IncrementalCompact, - visited_phinodes::Vector{AnySSAValue}, @nospecialize(cache_key), - lifting_cache::IdDict{Pair{AnySSAValue, Any}, AnySSAValue}, - @nospecialize(result_t), lifted_leaves::LiftedLeaves, @nospecialize(stmt_val), - lazydomtree::Union{LazyDomtree,Nothing}) - reverse_mapping = IdDict{AnySSAValue, Int}(ssa => id for (id, ssa) in enumerate(visited_phinodes)) + visited_phinodes::Vector{AnySSAValue}, @nospecialize(cache_key), + lifting_cache::IdDict{Pair{AnySSAValue, Any}, AnySSAValue}, + @nospecialize(result_t), lifted_leaves::LiftedLeaves, @nospecialize(stmt_val), + lazydomtree::Union{LazyDomtree,Nothing}) + reverse_mapping = IdDict{AnySSAValue, Int}() + for id in 1:length(visited_phinodes) + reverse_mapping[visited_phinodes[id]] = id + end # Check if all the lifted leaves are the same local the_leaf @@ -645,25 +648,28 @@ function perform_lifting!(compact::IncrementalCompact, end # Insert PhiNodes - lifted_phis = LiftedPhi[] - for item in visited_phinodes + nphis = length(visited_phinodes) + lifted_phis = Vector{LiftedPhi}(undef, nphis) + for i = 1:nphis + item = visited_phinodes[i] # FIXME this cache is broken somehow # ckey = Pair{AnySSAValue, Any}(item, cache_key) # cached = ckey in keys(lifting_cache) cached = false if cached ssa = lifting_cache[ckey] - push!(lifted_phis, LiftedPhi(ssa, compact[ssa][:inst]::PhiNode, false)) + lifted_phis[i] = LiftedPhi(ssa, compact[ssa][:inst]::PhiNode, false) continue end n = PhiNode() ssa = insert_node!(compact, item, effect_free(NewInstruction(n, result_t))) # lifting_cache[ckey] = ssa - push!(lifted_phis, LiftedPhi(ssa, n, true)) + lifted_phis[i] = LiftedPhi(ssa, n, true) end # Fix up arguments - for (old_node_ssa, lf) in zip(visited_phinodes, lifted_phis) + for i = 1:nphis + (old_node_ssa, lf) = visited_phinodes[i], lifted_phis[i] old_node = compact[old_node_ssa][:inst]::PhiNode new_node = lf.node lf.need_argupdate || continue @@ -876,7 +882,7 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing, InliningState} = nothin elseif is_isdefined push!(defuse.uses, IsdefinedUse(idx)) elseif is_finalizer - push!(defuse.uses, AddFinalizerUse(idx)) + push!(defuse.uses, FinalizerUse(idx)) else push!(defuse.uses, GetfieldUse(idx)) end @@ -910,14 +916,11 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing, InliningState} = nothin visited_phinodes, field, lifting_cache, result_t, lifted_leaves, val, lazydomtree) # Insert the undef check if necessary - if any_undef - if val === nothing - insert_node!(compact, SSAValue(idx), - non_effect_free(NewInstruction(Expr(:throw_undef_if_not, Symbol("##getfield##"), false), Nothing))) - else - # val must be defined - end + if any_undef && val === nothing + insert_node!(compact, SSAValue(idx), non_effect_free(NewInstruction( + Expr(:throw_undef_if_not, Symbol("##getfield##"), false), Nothing))) else + # val must be defined @assert val !== nothing end @@ -942,12 +945,15 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing, InliningState} = nothin end end +# NOTE we resolve the inlining source here as we don't want to serialize `Core.Compiler` +# data structure into the global cache (see the comment in `handle_finalizer_call!`) function try_inline_finalizer!(ir::IRCode, argexprs::Vector{Any}, idx::Int, mi::MethodInstance, inlining::InliningState) code = get(inlining.mi_cache, mi, nothing) + et = inlining.et if code isa CodeInstance if use_const_api(code) # No code in the function - Nothing to do - inlining.et !== nothing && push!(inlining.et, mi) + et !== nothing && push!(et, mi) return true end src = code.inferred @@ -963,15 +969,14 @@ function try_inline_finalizer!(ir::IRCode, argexprs::Vector{Any}, idx::Int, mi:: length(src.cfg.blocks) == 1 || return false # Ok, we're committed to inlining the finalizer - inlining.et !== nothing && push!(inlining.et, mi) + et !== nothing && push!(et, mi) linetable_offset, extra_coverage_line = ir_inline_linetable!(ir.linetable, src, mi.def, ir[SSAValue(idx)][:line]) if extra_coverage_line != 0 insert_node!(ir, idx, NewInstruction(Expr(:code_coverage_effect), Nothing, extra_coverage_line)) end - # TODO: Use the actual inliner here rather than open coding this special - # purpose inliner. + # TODO: Use the actual inliner here rather than open coding this special purpose inliner. spvals = mi.sparam_vals ssa_rename = Vector{Any}(undef, length(src.stmts)) for idx′ = 1:length(src.stmts) @@ -995,6 +1000,58 @@ function try_inline_finalizer!(ir::IRCode, argexprs::Vector{Any}, idx::Int, mi:: end is_nothrow(ir::IRCode, pc::Int) = ir.stmts[pc][:flag] & (IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW) ≠ 0 + +function try_resolve_finalizer!(ir::IRCode, idx::Int, finalizer_idx::Int, defuse::SSADefUse, inlining::InliningState) + # For now: Require that all uses and defs are in the same basic block, + # so that live range calculations are easy. + bb = ir.cfg.blocks[block_for_inst(ir.cfg, first(defuse.uses).idx)] + minval::Int = typemax(Int) + maxval::Int = 0 + + function check_in_range(x::Union{Int,SSAUse}) + if isa(x, SSAUse) + didx = x.idx + else + didx = x + end + didx in bb.stmts || return false + if didx < minval + minval = didx + end + if didx > maxval + maxval = didx + end + return true + end + + check_in_range(idx) || return nothing + all(check_in_range, defuse.uses) || return nothing + all(check_in_range, defuse.defs) || return nothing + + # For now: Require all statements in the basic block range to be nothrow. + all(minval:maxval) do idx::Int + return is_nothrow(ir, idx) || idx == finalizer_idx + end || return nothing + + # Ok, `finalizer` rewrite is legal. + finalizer_stmt = ir[SSAValue(finalizer_idx)][:inst] + argexprs = Any[finalizer_stmt.args[2], finalizer_stmt.args[3]] + inline = finalizer_stmt.args[4] + if inline === nothing + # No code in the function - Nothing to do + else + mi = finalizer_stmt.args[5]::MethodInstance + if inline::Bool && try_inline_finalizer!(ir, argexprs, maxval, mi, inlining) + # the finalizer body has been inlined + else + insert_node!(ir, maxval, NewInstruction(Expr(:invoke, mi, argexprs...), Nothing), true) + end + end + # Erase the call to `finalizer` + ir[SSAValue(finalizer_idx)][:inst] = nothing + return nothing +end + function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse}}, used_ssas::Vector{Int}, lazydomtree::LazyDomtree, inlining::Union{Nothing, InliningState}) for (idx, (intermediaries, defuse)) in defuses intermediaries = collect(intermediaries) @@ -1018,72 +1075,22 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse # error at runtime, but is not illegal to have in the IR. ismutabletype(typ) || continue typ = typ::DataType - # First check for any add_finalizer calls - add_finalizer_idx = nothing + # First check for any finalizer calls + finalizer_idx = nothing for use in defuse.uses - if use.kind === :add_finalizer - # For now: Only allow one add_finalizer per allocation - add_finalizer_idx !== nothing && @goto skip - add_finalizer_idx = use.idx + if use.kind === :finalizer + # For now: Only allow one finalizer per allocation + finalizer_idx !== nothing && @goto skip + finalizer_idx = use.idx end end - if add_finalizer_idx !== nothing - # For now: Require that all uses and defs are in the same basic block, - # so that live range calculations are easy. - bb = ir.cfg.blocks[block_for_inst(ir.cfg, first(defuse.uses).idx)] - minval::Int = typemax(Int) - maxval::Int = 0 - - check_in_range(defuse) = check_in_range(defuse.idx) - function check_in_range(didx::Int) - didx in bb.stmts || return false - if didx < minval - minval = didx - end - if didx > maxval - maxval = didx - end - return true - end - - check_in_range(idx) || continue - _all(check_in_range, defuse.uses) || continue - _all(check_in_range, defuse.defs) || continue - - # For now: Require all statements in the basic block range to be - # nothrow. - all_nothrow = _all(idx->is_nothrow(ir, idx) || idx == add_finalizer_idx, minval:maxval) - all_nothrow || continue - - # Ok, finalizer rewrite is legal. - add_finalizer_stmt = ir[SSAValue(add_finalizer_idx)][:inst] - argexprs = Any[add_finalizer_stmt.args[2], add_finalizer_stmt.args[3]] - may_inline = add_finalizer_stmt.args[4]::Bool - mi = add_finalizer_stmt.args[5]::Union{MethodInstance, Nothing} - if may_inline && mi !== nothing - if try_inline_finalizer!(ir, argexprs, maxval, add_finalizer_stmt.args[5], inlining) - @goto done_finalizer - end - mi = compileable_specialization(inlining.et, mi, Effects()).invoke - end - if mi !== nothing - insert_node!(ir, maxval, - NewInstruction(Expr(:invoke, mi, argexprs...), Nothing), - true) - else - insert_node!(ir, maxval, - NewInstruction(Expr(:call, argexprs...), Nothing), - true) - end - @label done_finalizer - # Erase call to add_finalizer - ir[SSAValue(add_finalizer_idx)][:inst] = nothing + if finalizer_idx !== nothing && inlining !== nothing + try_resolve_finalizer!(ir, idx, finalizer_idx, defuse, inlining) continue end # Partition defuses by field fielddefuse = SSADefUse[SSADefUse() for _ = 1:fieldcount(typ)] all_eliminated = all_forwarded = true - has_finalizer = false for use in defuse.uses if use.kind === :preserve for du in fielddefuse @@ -1189,7 +1196,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse if preserve_uses === nothing preserve_uses = IdDict{Int, Vector{Any}}() end - push!(get!(()->Any[], preserve_uses, use.idx), newval) + push!(get!(Vector{Any}, preserve_uses, use.idx), newval) end else @assert false "sroa_mutables!: unexpected use" diff --git a/base/compiler/ssair/slot2ssa.jl b/base/compiler/ssair/slot2ssa.jl index 7d534e5bd647a..29a3b093c9abf 100644 --- a/base/compiler/ssair/slot2ssa.jl +++ b/base/compiler/ssair/slot2ssa.jl @@ -330,7 +330,7 @@ function iterated_dominance_frontier(cfg::CFG, liveness::BlockLiveness, domtree: phiblocks end -function rename_incoming_edge(old_edge, old_to, result_order, bb_rename) +function rename_incoming_edge(old_edge::Int, old_to::Int, result_order::Vector{Int}, bb_rename::Vector{Int}) new_edge_from = bb_rename[old_edge] if old_edge == old_to - 1 # Could have been a crit edge break @@ -341,7 +341,7 @@ function rename_incoming_edge(old_edge, old_to, result_order, bb_rename) new_edge_from end -function rename_outgoing_edge(old_to, old_from, result_order, bb_rename) +function rename_outgoing_edge(old_to::Int, old_from::Int, result_order::Vector{Int}, bb_rename::Vector{Int}) new_edge_to = bb_rename[old_to] if old_from == old_to - 1 # Could have been a crit edge break @@ -352,12 +352,12 @@ function rename_outgoing_edge(old_to, old_from, result_order, bb_rename) new_edge_to end -function rename_phinode_edges(node, bb, result_order, bb_rename) +function rename_phinode_edges(node::PhiNode, bb::Int, result_order::Vector{Int}, bb_rename::Vector{Int}) new_values = Any[] new_edges = Int32[] for (idx, edge) in pairs(node.edges) edge = Int(edge) - (edge == 0 || haskey(bb_rename, edge)) || continue + (edge == 0 || bb_rename[edge] != 0) || continue new_edge_from = edge == 0 ? 0 : rename_incoming_edge(edge, bb, result_order, bb_rename) push!(new_edges, new_edge_from) if isassigned(node.values, idx) @@ -380,47 +380,42 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree) # First compute the new order of basic blocks result_order = Int[] stack = Int[] + bb_rename = zeros(Int, length(ir.cfg.blocks)) node = 1 ncritbreaks = 0 nnewfallthroughs = 0 while node !== -1 push!(result_order, node) + bb_rename[node] = length(result_order) cs = domtree.nodes[node].children terminator = ir.stmts[last(ir.cfg.blocks[node].stmts)][:inst] - iscondbr = isa(terminator, GotoIfNot) - let old_node = node + 1 - if length(cs) >= 1 - # Adding the nodes in reverse sorted order attempts to retain - # the original source order of the nodes as much as possible. - # This is not required for correctness, but is easier on the humans - if old_node in cs - # Schedule the fall through node first, - # so we can retain the fall through - append!(stack, reverse(sort(filter(x -> (x != old_node), cs)))) - node = node + 1 - else - append!(stack, reverse(sort(cs))) - node = pop!(stack) - end + next_node = node + 1 + node = -1 + # Adding the nodes in reverse sorted order attempts to retain + # the original source order of the nodes as much as possible. + # This is not required for correctness, but is easier on the humans + for child in Iterators.Reverse(cs) + if child == next_node + # Schedule the fall through node first, + # so we can retain the fall through + node = next_node else - if isempty(stack) - node = -1 - else - node = pop!(stack) - end + push!(stack, child) end - if node != old_node && !isa(terminator, Union{GotoNode, ReturnNode}) - if isa(terminator, GotoIfNot) - # Need to break the critical edge - ncritbreaks += 1 - push!(result_order, 0) - else - nnewfallthroughs += 1 - end + end + if node == -1 && !isempty(stack) + node = pop!(stack) + end + if node != next_node && !isa(terminator, Union{GotoNode, ReturnNode}) + if isa(terminator, GotoIfNot) + # Need to break the critical edge + ncritbreaks += 1 + push!(result_order, 0) + else + nnewfallthroughs += 1 end end end - bb_rename = IdDict{Int,Int}(i=>x for (x, i) in pairs(result_order) if i !== 0) new_bbs = Vector{BasicBlock}(undef, length(result_order)) nstmts = 0 for i in result_order @@ -481,7 +476,7 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree) result[inst_range[end]][:inst] = GotoIfNot(terminator.cond, bb_rename[terminator.dest]) elseif !isa(terminator, ReturnNode) if isa(terminator, Expr) - if terminator.head == :enter + if terminator.head === :enter terminator.args[1] = bb_rename[terminator.args[1]] end end @@ -496,8 +491,8 @@ function domsort_ssa!(ir::IRCode, domtree::DomTree) bb_start_off += length(inst_range) local new_preds, new_succs let bb = bb, bb_rename = bb_rename, result_order = result_order - new_preds = Int[rename_incoming_edge(i, bb, result_order, bb_rename) for i in ir.cfg.blocks[bb].preds if haskey(bb_rename, i)] - new_succs = Int[rename_outgoing_edge(i, bb, result_order, bb_rename) for i in ir.cfg.blocks[bb].succs if haskey(bb_rename, i)] + new_preds = Int[i == 0 ? 0 : rename_incoming_edge(i, bb, result_order, bb_rename) for i in ir.cfg.blocks[bb].preds] + new_succs = Int[ rename_outgoing_edge(i, bb, result_order, bb_rename) for i in ir.cfg.blocks[bb].succs] end new_bbs[new_bb] = BasicBlock(inst_range, new_preds, new_succs) end diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 096e47c1e500d..915c3c9dc8f8b 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -803,7 +803,7 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), boundscheck:: elseif isa(s, DataType) # Can't say anything about abstract types isabstracttype(s) && return false - s.name.atomicfields == C_NULL || return false # TODO: currently we're only testing for ordering == :not_atomic + s.name.atomicfields == C_NULL || return false # TODO: currently we're only testing for ordering === :not_atomic # If all fields are always initialized, and bounds check is disabled, we can assume # we don't throw if !boundscheck && s.name.n_uninitialized == 0 @@ -1020,7 +1020,7 @@ function setfield!_nothrow(s00, name, v) # Can't say anything about abstract types isabstracttype(s) && return false ismutabletype(s) || return false - s.name.atomicfields == C_NULL || return false # TODO: currently we're only testing for ordering == :not_atomic + s.name.atomicfields == C_NULL || return false # TODO: currently we're only testing for ordering === :not_atomic isa(name, Const) || return false field = try_compute_fieldidx(s, name.val) field === nothing && return false @@ -1798,45 +1798,44 @@ const _SPECIAL_BUILTINS = Any[ Core._apply_iterate ] -function builtin_effects(f::Builtin, argtypes::Vector{Any}, @nospecialize rt) +function builtin_effects(f::Builtin, argtypes::Vector{Any}, @nospecialize(rt)) if isa(f, IntrinsicFunction) return intrinsic_effects(f, argtypes) end @assert !contains_is(_SPECIAL_BUILTINS, f) - argtypes′ = argtypes[2:end] - if (f === Core.getfield || f === Core.isdefined) && length(argtypes) >= 3 + if (f === Core.getfield || f === Core.isdefined) && length(argtypes) >= 2 # consistent if the argtype is immutable - if isvarargtype(argtypes[2]) + if isvarargtype(argtypes[1]) return Effects(; effect_free=ALWAYS_TRUE, terminates=ALWAYS_TRUE, nonoverlayed=true) end - s = widenconst(argtypes[2]) + s = widenconst(argtypes[1]) if isType(s) || !isa(s, DataType) || isabstracttype(s) return Effects(; effect_free=ALWAYS_TRUE, terminates=ALWAYS_TRUE, nonoverlayed=true) end s = s::DataType consistent = !ismutabletype(s) ? ALWAYS_TRUE : ALWAYS_FALSE - if f === Core.getfield && !isvarargtype(argtypes[end]) && getfield_boundscheck(argtypes′) !== true + if f === Core.getfield && !isvarargtype(argtypes[end]) && getfield_boundscheck(argtypes) !== true # If we cannot independently prove inboundsness, taint consistency. # The inbounds-ness assertion requires dynamic reachability, while # :consistent needs to be true for all input values. # N.B. We do not taint for `--check-bounds=no` here -that happens in # InferenceState. - if getfield_nothrow(argtypes[2], argtypes[3], true) + if getfield_nothrow(argtypes[1], argtypes[2], true) nothrow = ALWAYS_TRUE else consistent = nothrow = ALWAYS_FALSE end else - nothrow = (!isvarargtype(argtypes[end]) && builtin_nothrow(f, argtypes′, rt)) ? + nothrow = (!isvarargtype(argtypes[end]) && builtin_nothrow(f, argtypes, rt)) ? ALWAYS_TRUE : ALWAYS_FALSE end effect_free = ALWAYS_TRUE - elseif f === getglobal && length(argtypes) >= 3 - if getglobal_nothrow(argtypes′) + elseif f === getglobal + if getglobal_nothrow(argtypes) consistent = isconst( # types are already checked in `getglobal_nothrow` - (argtypes[2]::Const).val::Module, (argtypes[3]::Const).val::Symbol) ? + (argtypes[1]::Const).val::Module, (argtypes[2]::Const).val::Symbol) ? ALWAYS_TRUE : ALWAYS_FALSE nothrow = ALWAYS_TRUE else @@ -1847,20 +1846,20 @@ function builtin_effects(f::Builtin, argtypes::Vector{Any}, @nospecialize rt) consistent = contains_is(_CONSISTENT_BUILTINS, f) ? ALWAYS_TRUE : ALWAYS_FALSE effect_free = (contains_is(_EFFECT_FREE_BUILTINS, f) || contains_is(_PURE_BUILTINS, f)) ? ALWAYS_TRUE : ALWAYS_FALSE - nothrow = (!isvarargtype(argtypes[end]) && builtin_nothrow(f, argtypes′, rt)) ? + nothrow = (!(!isempty(argtypes) && isvarargtype(argtypes[end])) && builtin_nothrow(f, argtypes, rt)) ? ALWAYS_TRUE : ALWAYS_FALSE end return Effects(EFFECTS_TOTAL; consistent, effect_free, nothrow) end -function builtin_nothrow(@nospecialize(f), argtypes::Array{Any, 1}, @nospecialize(rt)) +function builtin_nothrow(@nospecialize(f), argtypes::Vector{Any}, @nospecialize(rt)) rt === Bottom && return false contains_is(_PURE_BUILTINS, f) && return true return _builtin_nothrow(f, argtypes, rt) end -function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtypes::Array{Any,1}, +function builtin_tfunction(interp::AbstractInterpreter, @nospecialize(f), argtypes::Vector{Any}, sv::Union{InferenceState,Nothing}) if f === tuple return tuple_tfunc(argtypes) @@ -2025,7 +2024,7 @@ function intrinsic_effects(f::IntrinsicFunction, argtypes::Vector{Any}) f === Intrinsics.cglobal # cglobal lookup answer changes at runtime ) ? ALWAYS_TRUE : ALWAYS_FALSE effect_free = !(f === Intrinsics.pointerset) ? ALWAYS_TRUE : ALWAYS_FALSE - nothrow = (!isvarargtype(argtypes[end]) && intrinsic_nothrow(f, argtypes[2:end])) ? + nothrow = (!(!isempty(argtypes) && isvarargtype(argtypes[end])) && intrinsic_nothrow(f, argtypes)) ? ALWAYS_TRUE : ALWAYS_FALSE return Effects(EFFECTS_TOTAL; consistent, effect_free, nothrow) diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index 7ef006f244aa6..82748669e4387 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -209,6 +209,20 @@ function specialize_method(match::MethodMatch; kwargs...) return specialize_method(match.method, match.spec_types, match.sparams; kwargs...) end +""" + is_aggressive_constprop(method::Union{Method,CodeInfo}) -> Bool + +Check if `method` is declared as `Base.@constprop :aggressive`. +""" +is_aggressive_constprop(method::Union{Method,CodeInfo}) = method.constprop == 0x01 + +""" + is_no_constprop(method::Union{Method,CodeInfo}) -> Bool + +Check if `method` is declared as `Base.@constprop :none`. +""" +is_no_constprop(method::Union{Method,CodeInfo}) = method.constprop == 0x02 + ######### # types # ######### diff --git a/base/complex.jl b/base/complex.jl index f68e519386d93..3af32e483bfaf 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -591,7 +591,7 @@ julia> cispi(10000) 1.0 + 0.0im julia> cispi(0.25 + 1im) -0.030556854645952924 + 0.030556854645952924im +0.030556854645954562 + 0.030556854645954562im ``` !!! compat "Julia 1.6" @@ -601,8 +601,9 @@ function cispi end cispi(theta::Real) = Complex(reverse(sincospi(theta))...) function cispi(z::Complex) - sipi, copi = sincospi(z) - return complex(real(copi) - imag(sipi), imag(copi) + real(sipi)) + v = exp(-(pi*imag(z))) + s, c = sincospi(real(z)) + Complex(v * c, v * s) end """ diff --git a/base/div.jl b/base/div.jl index 7b172ecc95a63..9c2187e662ee9 100644 --- a/base/div.jl +++ b/base/div.jl @@ -5,10 +5,10 @@ """ div(x, y, r::RoundingMode=RoundToZero) -The quotient from Euclidean (integer) division. Computes x/y, rounded to +The quotient from Euclidean (integer) division. Computes `x / y`, rounded to an integer according to the rounding mode `r`. In other words, the quantity - round(x/y,r) + round(x / y, r) without any intermediate rounding. @@ -52,12 +52,12 @@ div(a, b) = div(a, b, RoundToZero) Compute the remainder of `x` after integer division by `y`, with the quotient rounded according to the rounding mode `r`. In other words, the quantity - x - y*round(x/y,r) + x - y * round(x / y, r) without any intermediate rounding. - if `r == RoundNearest`, then the result is exact, and in the interval - ``[-|y|/2, |y|/2]``. See also [`RoundNearest`](@ref). + ``[-|y| / 2, |y| / 2]``. See also [`RoundNearest`](@ref). - if `r == RoundToZero` (default), then the result is exact, and in the interval ``[0, |y|)`` if `x` is positive, or ``(-|y|, 0]`` otherwise. See also [`RoundToZero`](@ref). @@ -66,12 +66,12 @@ without any intermediate rounding. ``(y, 0]`` otherwise. The result may not be exact if `x` and `y` have different signs, and `abs(x) < abs(y)`. See also [`RoundDown`](@ref). -- if `r == RoundUp`, then the result is in the interval `(-y,0]` if `y` is positive, or - `[0,-y)` otherwise. The result may not be exact if `x` and `y` have the same sign, and +- if `r == RoundUp`, then the result is in the interval ``(-y, 0]`` if `y` is positive, or + ``[0, -y)`` otherwise. The result may not be exact if `x` and `y` have the same sign, and `abs(x) < abs(y)`. See also [`RoundUp`](@ref). -- if `r == RoundFromZero`, then the result is in the interval `(-y, 0]` if `y` is positive, or - `[0, -y)` otherwise. The result may not be exact if `x` and `y` have the same sign, and +- if `r == RoundFromZero`, then the result is in the interval ``(-y, 0]`` if `y` is positive, or + ``[0, -y)`` otherwise. The result may not be exact if `x` and `y` have the same sign, and `abs(x) < abs(y)`. See also [`RoundFromZero`](@ref). !!! compat "Julia 1.9" @@ -97,7 +97,7 @@ rem(x, y, r::RoundingMode) rem(x, y, ::RoundingMode{:ToZero}) = rem(x, y) rem(x, y, ::RoundingMode{:Down}) = mod(x, y) rem(x, y, ::RoundingMode{:Up}) = mod(x, -y) -rem(x, y, r::RoundingMode{:Nearest}) = x - y*div(x, y, r) +rem(x, y, r::RoundingMode{:Nearest}) = x - y * div(x, y, r) rem(x::Integer, y::Integer, r::RoundingMode{:Nearest}) = divrem(x, y, r)[2] function rem(x, y, ::typeof(RoundFromZero)) @@ -107,13 +107,13 @@ end """ fld(x, y) -Largest integer less than or equal to `x/y`. Equivalent to `div(x, y, RoundDown)`. +Largest integer less than or equal to `x / y`. Equivalent to `div(x, y, RoundDown)`. See also [`div`](@ref), [`cld`](@ref), [`fld1`](@ref). # Examples ```jldoctest -julia> fld(7.3,5.5) +julia> fld(7.3, 5.5) 1.0 julia> fld.(-5:5, 3)' @@ -123,11 +123,11 @@ julia> fld.(-5:5, 3)' Because `fld(x, y)` implements strictly correct floored rounding based on the true value of floating-point numbers, unintuitive situations can arise. For example: ```jldoctest -julia> fld(6.0,0.1) +julia> fld(6.0, 0.1) 59.0 -julia> 6.0/0.1 +julia> 6.0 / 0.1 60.0 -julia> 6.0/big(0.1) +julia> 6.0 / big(0.1) 59.99999999999999666933092612453056361837965690217069245739573412231113406246995 ``` What is happening here is that the true value of the floating-point number written @@ -141,13 +141,13 @@ fld(a, b) = div(a, b, RoundDown) """ cld(x, y) -Smallest integer larger than or equal to `x/y`. Equivalent to `div(x, y, RoundUp)`. +Smallest integer larger than or equal to `x / y`. Equivalent to `div(x, y, RoundUp)`. See also [`div`](@ref), [`fld`](@ref). # Examples ```jldoctest -julia> cld(5.5,2.2) +julia> cld(5.5, 2.2) 3.0 julia> cld.(-5:5, 3)' @@ -162,17 +162,17 @@ cld(a, b) = div(a, b, RoundUp) divrem(x, y, r::RoundingMode=RoundToZero) The quotient and remainder from Euclidean division. -Equivalent to `(div(x,y,r), rem(x,y,r))`. Equivalently, with the default -value of `r`, this call is equivalent to `(x÷y, x%y)`. +Equivalent to `(div(x, y, r), rem(x, y, r))`. Equivalently, with the default +value of `r`, this call is equivalent to `(x ÷ y, x % y)`. See also: [`fldmod`](@ref), [`cld`](@ref). # Examples ```jldoctest -julia> divrem(3,7) +julia> divrem(3, 7) (0, 3) -julia> divrem(7,3) +julia> divrem(7, 3) (2, 1) ``` """ @@ -190,23 +190,24 @@ function divrem(a, b, r::RoundingMode) (div(a, b, r), rem(a, b, r)) end end -#avoids calling rem for Integers-Integers (all modes), -#a-d*b not precise for Floats - AbstractFloat, AbstractIrrational. Rationals are still slower +# avoids calling rem for Integers-Integers (all modes), +# a - d * b not precise for Floats - AbstractFloat, AbstractIrrational. +# Rationals are still slower function divrem(a::Integer, b::Integer, r::Union{typeof(RoundUp), typeof(RoundDown), typeof(RoundToZero)}) if r === RoundToZero # For compat. Remove in 2.0. d = div(a, b) - (d, a - d*b) + (d, a - d * b) elseif r === RoundDown # For compat. Remove in 2.0. d = fld(a, b) - (d, a - d*b) + (d, a - d * b) elseif r === RoundUp # For compat. Remove in 2.0. d = div(a, b, r) - (d, a - d*b) + (d, a - d * b) end end function divrem(x::Integer, y::Integer, rnd::typeof(RoundNearest)) @@ -266,11 +267,11 @@ end fldmod(x, y) The floored quotient and modulus after division. A convenience wrapper for -`divrem(x, y, RoundDown)`. Equivalent to `(fld(x,y), mod(x,y))`. +`divrem(x, y, RoundDown)`. Equivalent to `(fld(x, y), mod(x, y))`. See also: [`fld`](@ref), [`cld`](@ref), [`fldmod1`](@ref). """ -fldmod(x,y) = divrem(x, y, RoundDown) +fldmod(x, y) = divrem(x, y, RoundDown) # We definite generic rounding methods for other rounding modes in terms of # RoundToZero. @@ -322,11 +323,11 @@ div(a::UInt128, b::UInt128, ::typeof(RoundToZero)) = div(a, b) rem(a::Int128, b::Int128, ::typeof(RoundToZero)) = rem(a, b) rem(a::UInt128, b::UInt128, ::typeof(RoundToZero)) = rem(a, b) -# These are kept for compatibility with external packages overriding fld/cld. -# In 2.0, packages should extend div(a,b,r) instead, in which case, these can +# These are kept for compatibility with external packages overriding fld / cld. +# In 2.0, packages should extend div(a, b, r) instead, in which case, these can # be removed. -fld(x::Real, y::Real) = div(promote(x,y)..., RoundDown) -cld(x::Real, y::Real) = div(promote(x,y)..., RoundUp) +fld(x::Real, y::Real) = div(promote(x, y)..., RoundDown) +cld(x::Real, y::Real) = div(promote(x, y)..., RoundUp) fld(x::Signed, y::Unsigned) = div(x, y, RoundDown) fld(x::Unsigned, y::Signed) = div(x, y, RoundDown) cld(x::Signed, y::Unsigned) = div(x, y, RoundUp) @@ -346,14 +347,14 @@ function div(x::Real, y::Real, r::RoundingMode) end # Integers -# fld(x,y) == div(x,y) - ((x>=0) != (y>=0) && rem(x,y) != 0 ? 1 : 0) -div(x::T, y::T, ::typeof(RoundDown)) where {T<:Unsigned} = div(x,y) +# fld(x, y) == div(x, y) - ((x >= 0) != (y >= 0) && rem(x, y) != 0 ? 1 : 0) +div(x::T, y::T, ::typeof(RoundDown)) where {T<:Unsigned} = div(x, y) function div(x::T, y::T, ::typeof(RoundDown)) where T<:Integer d = div(x, y, RoundToZero) return d - (signbit(x ⊻ y) & (d * y != x)) end -# cld(x,y) = div(x,y) + ((x>0) == (y>0) && rem(x,y) != 0 ? 1 : 0) +# cld(x, y) = div(x, y) + ((x > 0) == (y > 0) && rem(x, y) != 0 ? 1 : 0) function div(x::T, y::T, ::typeof(RoundUp)) where T<:Unsigned d = div(x, y, RoundToZero) return d + (d * y != x) @@ -366,5 +367,4 @@ end # Real # NOTE: C89 fmod() and x87 FPREM implicitly provide truncating float division, # so it is used here as the basis of float div(). -div(x::T, y::T, r::RoundingMode) where {T<:AbstractFloat} = convert(T,round((x-rem(x,y,r))/y)) -rem(x::T, y::T, ::typeof(RoundUp)) where {T<:AbstractFloat} = convert(T,x-y*ceil(x/y)) +div(x::T, y::T, r::RoundingMode) where {T<:AbstractFloat} = convert(T, round((x - rem(x, y, r)) / y)) diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 2c52d8f921ef2..994d8077edc4d 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -299,9 +299,8 @@ function astname(x::Expr, ismacro::Bool) head = x.head if head === :. ismacro ? macroname(x) : x - # Call overloading, e.g. `(a::A)(b) = b` or `function (a::A)(b) b end` should document `A(b)` - elseif (head === :function || head === :(=)) && isexpr(x.args[1], :call) && isexpr((x.args[1]::Expr).args[1], :(::)) - return astname(((x.args[1]::Expr).args[1]::Expr).args[end], ismacro) + elseif head === :call && isexpr(x.args[1], :(::)) + return astname((x.args[1]::Expr).args[end], ismacro) else n = isexpr(x, (:module, :struct)) ? 2 : 1 astname(x.args[n], ismacro) diff --git a/base/experimental.jl b/base/experimental.jl index 174d532ad1f4d..cc8d368023b49 100644 --- a/base/experimental.jl +++ b/base/experimental.jl @@ -155,7 +155,7 @@ the MethodTable). """ macro max_methods(n::Int, fdef::Expr) 0 < n <= 255 || error("We must have that `1 <= max_methods <= 255`, but `max_methods = $n`.") - (fdef.head == :function && length(fdef.args) == 1) || error("Second argument must be a function forward declaration") + (fdef.head === :function && length(fdef.args) == 1) || error("Second argument must be a function forward declaration") return :(typeof($(esc(fdef))).name.max_methods = $(UInt8(n))) end diff --git a/base/expr.jl b/base/expr.jl index 8e83926a332f3..8916825bc0db4 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -649,7 +649,7 @@ macro assume_effects(args...) end ex = args[end] isa(ex, Expr) || throw(ArgumentError("Bad expression `$ex` in `@assume_effects [settings] ex`")) - if ex.head === :macrocall && ex.args[1] == Symbol("@ccall") + if ex.head === :macrocall && ex.args[1] === Symbol("@ccall") ex.args[1] = GlobalRef(Base, Symbol("@ccall_effects")) insert!(ex.args, 3, Core.Compiler.encode_effects_override(Core.Compiler.EffectsOverride( consistent, effect_free, nothrow, terminates_globally, terminates_locally, notaskstate diff --git a/base/float.jl b/base/float.jl index 60850b7e02f64..eb1cc36e6c215 100644 --- a/base/float.jl +++ b/base/float.jl @@ -393,8 +393,6 @@ muladd(x::T, y::T, z::T) where {T<:IEEEFloat} = muladd_float(x, y, z) rem(x::T, y::T) where {T<:IEEEFloat} = rem_float(x, y) -cld(x::T, y::T) where {T<:AbstractFloat} = -fld(-x,y) - function mod(x::T, y::T) where T<:AbstractFloat r = rem(x,y) if r == 0 diff --git a/base/io.jl b/base/io.jl index ca96075a1b11e..59bce5eb4de6d 100644 --- a/base/io.jl +++ b/base/io.jl @@ -173,6 +173,19 @@ function will block to wait for more data if necessary, and then return `false`. it is always safe to read one byte after seeing `eof` return `false`. `eof` will return `false` as long as buffered data is still available, even if the remote end of a connection is closed. + +# Examples +```jldoctest +julia> b = IOBuffer("my buffer"); + +julia> eof(b) +false + +julia> seekend(b); + +julia> eof(b) +true +``` """ function eof end diff --git a/base/iterators.jl b/base/iterators.jl index 40fad992958d5..0184ab51323b4 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -3,16 +3,25 @@ """ Methods for working with Iterators. """ -module Iterators +baremodule Iterators # small dance to make this work from Base or Intrinsics import ..@__MODULE__, ..parentmodule const Base = parentmodule(@__MODULE__) using .Base: - @inline, Pair, Pairs, AbstractDict, IndexLinear, IndexCartesian, IndexStyle, AbstractVector, Vector, - tail, SizeUnknown, HasLength, HasShape, IsInfinite, EltypeUnknown, HasEltype, OneTo, - @propagate_inbounds, @isdefined, @boundscheck, @inbounds, Generator, AbstractRange, - LinearIndices, (:), |, +, -, !==, !, <=, <, missing, any, _counttuple + @inline, Pair, Pairs, AbstractDict, IndexLinear, IndexStyle, AbstractVector, Vector, + SizeUnknown, HasLength, HasShape, IsInfinite, EltypeUnknown, HasEltype, OneTo, + @propagate_inbounds, @isdefined, @boundscheck, @inbounds, Generator, + AbstractRange, AbstractUnitRange, UnitRange, LinearIndices, + (:), |, +, -, *, !==, !, ==, !=, <=, <, >, >=, missing, + any, _counttuple, eachindex, ntuple, zero, prod, in, firstindex, lastindex, + tail, fieldtypes, min, max, minimum, zero, oneunit, promote, promote_shape +using Core: @doc + +if Base !== Core.Compiler +using .Base: + cld, fld, SubArray, view, resize!, IndexCartesian +end import .Base: first, last, @@ -20,9 +29,13 @@ import .Base: eltype, IteratorSize, IteratorEltype, haskey, keys, values, pairs, getindex, setindex!, get, iterate, - popfirst!, isdone, peek + popfirst!, isdone, peek, intersect -export enumerate, zip, rest, countfrom, take, drop, takewhile, dropwhile, cycle, repeated, product, flatten, partition, flatmap +export enumerate, zip, rest, countfrom, take, drop, takewhile, dropwhile, cycle, repeated, product, flatten, flatmap + +if Base !== Core.Compiler +export partition +end """ Iterators.map(f, iterators...) @@ -208,7 +221,7 @@ of `A`. Specifying [`IndexLinear()`](@ref) ensures that `i` will be an integer; specifying [`IndexCartesian()`](@ref) ensures that `i` will be a -[`CartesianIndex`](@ref); specifying `IndexStyle(A)` chooses whichever has +[`Base.CartesianIndex`](@ref); specifying `IndexStyle(A)` chooses whichever has been defined as the native indexing style for array `A`. Mutation of the bounds of the underlying array will invalidate this iterator. @@ -241,17 +254,20 @@ CartesianIndex(2, 2) e See also [`IndexStyle`](@ref), [`axes`](@ref). """ pairs(::IndexLinear, A::AbstractArray) = Pairs(A, LinearIndices(A)) -pairs(::IndexCartesian, A::AbstractArray) = Pairs(A, CartesianIndices(axes(A))) # preserve indexing capabilities for known indexable types # faster than zip(keys(a), values(a)) for arrays pairs(tuple::Tuple) = Pairs{Int}(tuple, keys(tuple)) pairs(nt::NamedTuple) = Pairs{Symbol}(nt, keys(nt)) pairs(v::Core.SimpleVector) = Pairs(v, LinearIndices(v)) -pairs(A::AbstractArray) = pairs(IndexCartesian(), A) pairs(A::AbstractVector) = pairs(IndexLinear(), A) # pairs(v::Pairs) = v # listed for reference, but already defined from being an AbstractDict +if Base !== Core.Compiler +pairs(::IndexCartesian, A::AbstractArray) = Pairs(A, Base.CartesianIndices(axes(A))) +pairs(A::AbstractArray) = pairs(IndexCartesian(), A) +end + length(v::Pairs) = length(getfield(v, :itr)) axes(v::Pairs) = axes(getfield(v, :itr)) size(v::Pairs) = size(getfield(v, :itr)) @@ -277,7 +293,7 @@ end @inline isdone(v::Pairs, state...) = isdone(getfield(v, :itr), state...) IteratorSize(::Type{<:Pairs{<:Any, <:Any, I}}) where {I} = IteratorSize(I) -IteratorSize(::Type{<:Pairs{<:Any, <:Any, <:Base.AbstractUnitRange, <:Tuple}}) = HasLength() +IteratorSize(::Type{<:Pairs{<:Any, <:Any, <:AbstractUnitRange, <:Tuple}}) = HasLength() function last(v::Pairs{K, V}) where {K, V} idx = last(getfield(v, :itr)) @@ -677,7 +693,7 @@ end An iterator that generates at most the first `n` elements of `iter`. -See also: [`drop`](@ref Iterators.drop), [`peel`](@ref Iterators.peel), [`first`](@ref), [`take!`](@ref). +See also: [`drop`](@ref Iterators.drop), [`peel`](@ref Iterators.peel), [`first`](@ref), [`Base.take!`](@ref). # Examples ```jldoctest @@ -890,7 +906,7 @@ end An iterator that cycles through `iter` forever. If `iter` is empty, so is `cycle(iter)`. -See also: [`Iterators.repeated`](@ref), [`repeat`](@ref). +See also: [`Iterators.repeated`](@ref), [`Base.repeat`](@ref). # Examples ```jldoctest @@ -932,7 +948,7 @@ 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)`). -See also: [`Iterators.cycle`](@ref), [`repeat`](@ref). +See also: [`Iterators.cycle`](@ref), [`Base.repeat`](@ref). # Examples ```jldoctest @@ -1089,6 +1105,7 @@ end reverse(p::ProductIterator) = ProductIterator(Base.map(reverse, p.iterators)) last(p::ProductIterator) = Base.map(last, p.iterators) +intersect(a::ProductIterator, b::ProductIterator) = ProductIterator(intersect.(a.iterators, b.iterators)) # flatten an iterator of iterators @@ -1197,7 +1214,8 @@ julia> Iterators.flatmap(n->-n:2:n, 1:3) |> collect """ flatmap(f, c...) = flatten(map(f, c...)) -""" +if Base !== Core.Compiler # views are not defined +@doc """ partition(collection, n) Iterate over a collection `n` elements at a time. @@ -1210,8 +1228,7 @@ julia> collect(Iterators.partition([1,2,3,4,5], 2)) [3, 4] [5] ``` -""" -function partition(c, n::Integer) +""" function partition(c, n::Integer) n < 1 && throw(ArgumentError("cannot create partitions of length $n")) return PartitionIterator(c, Int(n)) end @@ -1221,7 +1238,7 @@ struct PartitionIterator{T} n::Int end # Partitions are explicitly a linear indexing operation, so reshape to 1-d immediately -PartitionIterator(A::AbstractArray, n::Int) = PartitionIterator(vec(A), n) +PartitionIterator(A::AbstractArray, n::Int) = PartitionIterator(Base.vec(A), n) PartitionIterator(v::AbstractVector, n::Int) = PartitionIterator{typeof(v)}(v, n) eltype(::Type{PartitionIterator{T}}) where {T} = Vector{eltype(T)} @@ -1279,7 +1296,7 @@ function iterate(itr::PartitionIterator, state...) return resize!(v, i), y === nothing ? IterationCutShort() : y[2] end -""" +@doc """ Stateful(itr) There are several different ways to think about this iterator wrapper: @@ -1292,7 +1309,7 @@ There are several different ways to think about this iterator wrapper: whenever an item is produced. `Stateful` provides the regular iterator interface. Like other mutable iterators -(e.g. [`Channel`](@ref)), if iteration is stopped early (e.g. by a [`break`](@ref) in a [`for`](@ref) loop), +(e.g. [`Base.Channel`](@ref)), if iteration is stopped early (e.g. by a [`break`](@ref) in a [`for`](@ref) loop), iteration can be resumed from the same spot by continuing to iterate over the same iterator object (in contrast, an immutable iterator would restart from the beginning). @@ -1336,8 +1353,7 @@ julia> peek(a) julia> sum(a) # Sum the remaining elements 7 ``` -""" -mutable struct Stateful{T, VS} +""" mutable struct Stateful{T, VS} itr::T # A bit awkward right now, but adapted to the new iteration protocol nextvalstate::Union{VS, Nothing} @@ -1358,28 +1374,25 @@ function reset!(s::Stateful{T,VS}, itr::T=s.itr) where {T,VS} s end -if Base === Core.Compiler - approx_iter_type(a::Type) = Any -else - # Try to find an appropriate type for the (value, state tuple), - # by doing a recursive unrolling of the iteration protocol up to - # fixpoint. - approx_iter_type(itrT::Type) = _approx_iter_type(itrT, Base._return_type(iterate, Tuple{itrT})) - # Not actually called, just passed to return type to avoid - # having to typesplit on Nothing - function doiterate(itr, valstate::Union{Nothing, Tuple{Any, Any}}) - valstate === nothing && return nothing - val, st = valstate - return iterate(itr, st) - end - function _approx_iter_type(itrT::Type, vstate::Type) - vstate <: Union{Nothing, Tuple{Any, Any}} || return Any - vstate <: Union{} && return Union{} - nextvstate = Base._return_type(doiterate, Tuple{itrT, vstate}) - return (nextvstate <: vstate ? vstate : Any) - end +# Try to find an appropriate type for the (value, state tuple), +# by doing a recursive unrolling of the iteration protocol up to +# fixpoint. +approx_iter_type(itrT::Type) = _approx_iter_type(itrT, Base._return_type(iterate, Tuple{itrT})) +# Not actually called, just passed to return type to avoid +# having to typesplit on Nothing +function doiterate(itr, valstate::Union{Nothing, Tuple{Any, Any}}) + valstate === nothing && return nothing + val, st = valstate + return iterate(itr, st) +end +function _approx_iter_type(itrT::Type, vstate::Type) + vstate <: Union{Nothing, Tuple{Any, Any}} || return Any + vstate <: Union{} && return Union{} + nextvstate = Base._return_type(doiterate, Tuple{itrT, vstate}) + return (nextvstate <: vstate ? vstate : Any) end +Stateful(x::Stateful) = x convert(::Type{Stateful}, itr) = Stateful(itr) @inline isdone(s::Stateful, st=nothing) = s.nextvalstate === nothing @@ -1387,7 +1400,7 @@ convert(::Type{Stateful}, itr) = Stateful(itr) @inline function popfirst!(s::Stateful) vs = s.nextvalstate if vs === nothing - throw(EOFError()) + throw(Base.EOFError()) else val, state = vs Core.setfield!(s, :nextvalstate, iterate(s.itr, state)) @@ -1405,6 +1418,7 @@ IteratorSize(::Type{Stateful{T,VS}}) where {T,VS} = IteratorSize(T) isa HasShape eltype(::Type{Stateful{T, VS}} where VS) where {T} = eltype(T) IteratorEltype(::Type{Stateful{T,VS}}) where {T,VS} = IteratorEltype(T) length(s::Stateful) = length(s.itr) - s.taken +end """ only(x) @@ -1462,7 +1476,4 @@ only(x::NamedTuple) = throw( ArgumentError("NamedTuple contains $(length(x)) elements, must contain exactly 1 element") ) - -Base.intersect(a::ProductIterator, b::ProductIterator) = ProductIterator(intersect.(a.iterators, b.iterators)) - end diff --git a/base/loading.jl b/base/loading.jl index 187f1bee4eea0..b3c0ee639a206 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -167,7 +167,8 @@ function dummy_uuid(project_file::String) end project_path = try realpath(project_file) - catch + catch ex + ex isa IOError || rethrow() project_file end uuid = uuid5(ns_dummy_uuid, project_path) @@ -367,15 +368,15 @@ function locate_package(pkg::PkgId)::Union{Nothing,String} for env in load_path() # look for the toplevel pkg `pkg.name` in this entry found = project_deps_get(env, pkg.name) - found === nothing && continue - if pkg == found - # pkg.name is present in this directory or project file, - # return the path the entry point for the code, if it could be found - # otherwise, signal failure - return implicit_manifest_uuid_path(env, pkg) + if found !== nothing + @assert found.name == pkg.name + if found.uuid === nothing + # pkg.name is present in this directory or project file, + # return the path the entry point for the code, if it could be found + # otherwise, signal failure + return implicit_manifest_uuid_path(env, pkg) + end end - @assert found.uuid !== nothing - return locate_package(found) # restart search now that we know the uuid for pkg end else for env in load_path() @@ -459,7 +460,9 @@ the form `pkgversion(@__MODULE__)` can be used. function pkgversion(m::Module) rootmodule = moduleroot(m) pkg = PkgId(rootmodule) - pkgorigin = get(pkgorigins, pkg, nothing) + pkgorigin = @lock require_lock begin + get(pkgorigins, pkg, nothing) + end return pkgorigin === nothing ? nothing : pkgorigin.version end @@ -844,10 +847,23 @@ function find_all_in_cache_path(pkg::PkgId) end end +# use an Int counter so that nested @time_imports calls all remain open +const TIMING_IMPORTS = Threads.Atomic{Int}(0) + # these return either the array of modules loaded from the path / content given # or an Exception that describes why it couldn't be loaded # and it reconnects the Base.Docs.META function _include_from_serialized(pkg::PkgId, path::String, depmods::Vector{Any}) + assert_havelock(require_lock) + timing_imports = TIMING_IMPORTS[] > 0 + try + if timing_imports + t_before = time_ns() + cumulative_compile_timing(true) + t_comp_before = cumulative_compile_time_ns() + end + + @debug "Loading cache file $path for $pkg" sv = ccall(:jl_restore_incremental, Any, (Cstring, Any), path, depmods) if isa(sv, Exception) return sv @@ -877,10 +893,36 @@ function _include_from_serialized(pkg::PkgId, path::String, depmods::Vector{Any} lock(require_lock) end end - return restored + + for M in restored + M = M::Module + if parentmodule(M) === M && PkgId(M) == pkg + if timing_imports + elapsed = round((time_ns() - t_before) / 1e6, digits = 1) + comp_time, recomp_time = cumulative_compile_time_ns() .- t_comp_before + print(lpad(elapsed, 9), " ms ") + print(pkg.name) + if comp_time > 0 + printstyled(" ", Ryu.writefixed(Float64(100 * comp_time / (elapsed * 1e6)), 2), "% compilation time", color = Base.info_color()) + end + if recomp_time > 0 + perc = Float64(100 * recomp_time / comp_time) + printstyled(" (", perc < 1 ? "<1" : Ryu.writefixed(perc, 0), "% recompilation)", color = Base.warn_color()) + end + println() + end + return M + end + end + return ErrorException("Required dependency $pkg failed to load from a cache file.") + + finally + timing_imports && cumulative_compile_timing(false) + end end function run_package_callbacks(modkey::PkgId) + assert_havelock(require_lock) unlock(require_lock) try for callback in package_callbacks @@ -896,35 +938,83 @@ function run_package_callbacks(modkey::PkgId) nothing end -function _tryrequire_from_serialized(modkey::PkgId, build_id::UInt64, modpath::Union{Nothing, String}, depth::Int = 0) +# loads a precompile cache file, after checking stale_cachefile tests +function _tryrequire_from_serialized(modkey::PkgId, build_id::UInt64) + assert_havelock(require_lock) + loaded = nothing if root_module_exists(modkey) - M = root_module(modkey) - if PkgId(M) == modkey && module_build_id(M) === build_id - return M + loaded = root_module(modkey) + else + loading = get(package_locks, modkey, false) + if loading !== false + # load already in progress for this module + loaded = wait(loading) + else + package_locks[modkey] = Threads.Condition(require_lock) + try + modpath = locate_package(modkey) + modpath === nothing && return nothing + set_pkgorigin_version_path(modkey, String(modpath)) + loaded = _require_search_from_serialized(modkey, String(modpath), build_id) + finally + loading = pop!(package_locks, modkey) + notify(loading, loaded, all=true) + end + if loaded isa Module + run_package_callbacks(modkey) + end end + end + if !(loaded isa Module) || PkgId(loaded) != modkey + return ErrorException("Required dependency $modkey failed to load from a cache file.") + end + return loaded +end + +# loads a precompile cache file, ignoring stale_cachefile tests +# assuming all depmods are already loaded and everything is valid +function _tryrequire_from_serialized(modkey::PkgId, path::String, sourcepath::String, depmods::Vector{Any}) + assert_havelock(require_lock) + loaded = nothing + if root_module_exists(modkey) + loaded = root_module(modkey) else - if modpath === nothing - modpath = locate_package(modkey) - modpath === nothing && return nothing - end - mod = _require_search_from_serialized(modkey, String(modpath), depth) - get!(PkgOrigin, pkgorigins, modkey).path = modpath - if !isa(mod, Bool) - run_package_callbacks(modkey) - for M in mod::Vector{Any} - M = M::Module - if PkgId(M) == modkey && module_build_id(M) === build_id - return M - end + loading = get(package_locks, modkey, false) + if loading !== false + # load already in progress for this module + loaded = wait(loading) + else + for i in 1:length(depmods) + dep = depmods[i] + dep isa Module && continue + _, depkey, depbuild_id = dep::Tuple{String, PkgId, UInt64} + @assert root_module_exists(depkey) + dep = root_module(depkey) + depmods[i] = dep + end + package_locks[modkey] = Threads.Condition(require_lock) + try + set_pkgorigin_version_path(modkey, sourcepath) + loaded = _include_from_serialized(modkey, path, depmods) + finally + loading = pop!(package_locks, modkey) + notify(loading, loaded, all=true) + end + if loaded isa Module + run_package_callbacks(modkey) end end end - return nothing + if !(loaded isa Module) || PkgId(loaded) != modkey + return ErrorException("Required dependency $modkey failed to load from a cache file.") + end + return loaded end -function _require_from_serialized(pkg::PkgId, path::String) - # loads a precompile cache file, ignoring stale_cachfile tests - # load all of the dependent modules first +# loads a precompile cache file, ignoring stale_cachefile tests +# load the best available (non-stale) version of all dependent modules first +function _tryrequire_from_serialized(pkg::PkgId, path::String) + assert_havelock(require_lock) local depmodnames io = open(path, "r") try @@ -938,82 +1028,82 @@ function _require_from_serialized(pkg::PkgId, path::String) depmods = Vector{Any}(undef, ndeps) for i in 1:ndeps modkey, build_id = depmodnames[i] - dep = _tryrequire_from_serialized(modkey, build_id, nothing) - dep === nothing && return ErrorException("Required dependency $modkey failed to load from a cache file.") - depmods[i] = dep::Module + dep = _tryrequire_from_serialized(modkey, build_id) + if !isa(dep, Module) + return dep + end + depmods[i] = dep end # then load the file return _include_from_serialized(pkg, path, depmods) end -# use an Int counter so that nested @time_imports calls all remain open -const TIMING_IMPORTS = Threads.Atomic{Int}(0) - -# returns `true` if require found a precompile cache for this sourcepath, but couldn't load it -# returns `false` if the module isn't known to be precompilable +# returns `nothing` if require found a precompile cache for this sourcepath, but couldn't load it # returns the set of modules restored if the cache load succeeded -@constprop :none function _require_search_from_serialized(pkg::PkgId, sourcepath::String, depth::Int = 0) - timing_imports = TIMING_IMPORTS[] > 0 - try - if timing_imports - t_before = time_ns() - cumulative_compile_timing(true) - t_comp_before = cumulative_compile_time_ns() - end +@constprop :none function _require_search_from_serialized(pkg::PkgId, sourcepath::String, build_id::UInt64) + assert_havelock(require_lock) paths = find_all_in_cache_path(pkg) for path_to_try in paths::Vector{String} - staledeps = stale_cachefile(sourcepath, path_to_try) + staledeps = stale_cachefile(pkg, build_id, sourcepath, path_to_try) if staledeps === true continue end staledeps = staledeps::Vector{Any} + # finish checking staledeps module graph + for i in 1:length(staledeps) + dep = staledeps[i] + dep isa Module && continue + modpath, modkey, modbuild_id = dep::Tuple{String, PkgId, UInt64} + modpaths = find_all_in_cache_path(modkey) + modfound = false + for modpath_to_try in modpaths::Vector{String} + modstaledeps = stale_cachefile(modkey, modbuild_id, modpath, modpath_to_try) + if modstaledeps === true + continue + end + modstaledeps = modstaledeps::Vector{Any} + staledeps[i] = (modpath, modkey, modpath_to_try, modstaledeps) + modfound = true + break + end + if !modfound + @debug "Rejecting cache file $path_to_try because required dependency $modkey with build ID $modbuild_id is missing from the cache." + staledeps = true + break + end + end + if staledeps === true + continue + end try touch(path_to_try) # update timestamp of precompilation file - catch # file might be read-only and then we fail to update timestamp, which is fine + catch ex # file might be read-only and then we fail to update timestamp, which is fine + ex isa IOError || rethrow() end # finish loading module graph into staledeps for i in 1:length(staledeps) dep = staledeps[i] dep isa Module && continue - modpath, modkey, build_id = dep::Tuple{String, PkgId, UInt64} - dep = _tryrequire_from_serialized(modkey, build_id, modpath, depth + 1) - if dep === nothing - @debug "Required dependency $modkey failed to load from cache file for $modpath." + modpath, modkey, modpath_to_try, modstaledeps = dep::Tuple{String, PkgId, String, Vector{Any}} + dep = _tryrequire_from_serialized(modkey, modpath_to_try, modpath, modstaledeps) + if !isa(dep, Module) + @debug "Rejecting cache file $path_to_try because required dependency $modkey failed to load from cache file for $modpath." exception=dep staledeps = true break end - staledeps[i] = dep::Module + staledeps[i] = dep end if staledeps === true continue end restored = _include_from_serialized(pkg, path_to_try, staledeps) - if isa(restored, Exception) + if !isa(restored, Module) @debug "Deserialization checks failed while attempting to load cache from $path_to_try" exception=restored else - if timing_imports - elapsed = round((time_ns() - t_before) / 1e6, digits = 1) - comp_time, recomp_time = cumulative_compile_time_ns() .- t_comp_before - tree_prefix = depth == 0 ? "" : " "^(depth-1)*"┌ " - print(lpad(elapsed, 9), " ms ") - printstyled(tree_prefix, color = :light_black) - print(pkg.name) - if comp_time > 0 - printstyled(" ", Ryu.writefixed(Float64(100 * comp_time / (elapsed * 1e6)), 2), "% compilation time", color = Base.info_color()) - end - if recomp_time > 0 - perc = Float64(100 * recomp_time / comp_time) - printstyled(" (", perc < 1 ? "<1" : Ryu.writefixed(perc, 0), "% recompilation)", color = Base.warn_color()) - end - println() - end return restored end end - return !isempty(paths) - finally - timing_imports && cumulative_compile_timing(false) - end + return end # to synchronize multiple tasks trying to import/using something @@ -1165,21 +1255,23 @@ const pkgorigins = Dict{PkgId,PkgOrigin}() require(uuidkey::PkgId) = @lock require_lock _require_prelocked(uuidkey) function _require_prelocked(uuidkey::PkgId) - just_loaded_pkg = false + assert_havelock(require_lock) if !root_module_exists(uuidkey) - _require(uuidkey) + newm = _require(uuidkey) + if newm === nothing + error("package `$(uuidkey.name)` did not define the expected \ + module `$(uuidkey.name)`, check for typos in package module name") + end # After successfully loading, notify downstream consumers run_package_callbacks(uuidkey) - just_loaded_pkg = true - end - if just_loaded_pkg && !root_module_exists(uuidkey) - error("package `$(uuidkey.name)` did not define the expected \ - module `$(uuidkey.name)`, check for typos in package module name") + else + newm = root_module(uuidkey) end - return root_module(uuidkey) + return newm end const loaded_modules = Dict{PkgId,Module}() +const loaded_modules_order = Vector{Module}() const module_keys = IdDict{Module,PkgId}() # the reverse is_root_module(m::Module) = @lock require_lock haskey(module_keys, m) @@ -1193,9 +1285,14 @@ root_module_key(m::Module) = @lock require_lock module_keys[m] if haskey(loaded_modules, key) oldm = loaded_modules[key] if oldm !== m - @warn "Replacing module `$(key.name)`" + if (0 != ccall(:jl_generating_output, Cint, ())) && (JLOptions().incremental != 0) + error("Replacing module `$(key.name)`") + else + @warn "Replacing module `$(key.name)`" + end end end + push!(loaded_modules_order, m) loaded_modules[key] = m module_keys[m] = key end @@ -1220,7 +1317,7 @@ root_module(where::Module, name::Symbol) = maybe_root_module(key::PkgId) = @lock require_lock get(loaded_modules, key, nothing) root_module_exists(key::PkgId) = @lock require_lock haskey(loaded_modules, key) -loaded_modules_array() = @lock require_lock collect(values(loaded_modules)) +loaded_modules_array() = @lock require_lock copy(loaded_modules_order) function unreference_module(key::PkgId) if haskey(loaded_modules, key) @@ -1230,7 +1327,9 @@ function unreference_module(key::PkgId) end end -function set_pkgorigin_version_path(pkg, path) +# whoever takes the package_locks[pkg] must call this function immediately +function set_pkgorigin_version_path(pkg::PkgId, path::Union{String,Nothing}) + assert_havelock(require_lock) pkgorigin = get!(PkgOrigin, pkgorigins, pkg) if path !== nothing project_file = locate_project_file(joinpath(dirname(path), "..")) @@ -1243,37 +1342,39 @@ function set_pkgorigin_version_path(pkg, path) end end pkgorigin.path = path + nothing end -# Returns `nothing` or the name of the newly-created cachefile +# Returns `nothing` or the new(ish) module function _require(pkg::PkgId) + assert_havelock(require_lock) # handle recursive calls to require loading = get(package_locks, pkg, false) if loading !== false # load already in progress for this module - wait(loading) - return + return wait(loading) end package_locks[pkg] = Threads.Condition(require_lock) last = toplevel_load[] + loaded = nothing try toplevel_load[] = false # perform the search operation to select the module file require intends to load path = locate_package(pkg) - set_pkgorigin_version_path(pkg, path) if path === nothing throw(ArgumentError(""" Package $pkg is required but does not seem to be installed: - Run `Pkg.instantiate()` to install all recorded dependencies. """)) end + set_pkgorigin_version_path(pkg, path) # attempt to load the module file via the precompile cache locations if JLOptions().use_compiled_modules != 0 - m = _require_search_from_serialized(pkg, path) - if !isa(m, Bool) - return + m = _require_search_from_serialized(pkg, path, UInt64(0)) + if m isa Module + return m end end @@ -1293,7 +1394,6 @@ function _require(pkg::PkgId) if JLOptions().use_compiled_modules != 0 if (0 == ccall(:jl_generating_output, Cint, ())) || (JLOptions().incremental != 0) # spawn off a new incremental pre-compile task for recursive `require` calls - # or if the require search declared it was pre-compiled before (and therefore is expected to still be pre-compilable) cachefile = compilecache(pkg, path) if isa(cachefile, Exception) if precompilableerror(cachefile) @@ -1304,11 +1404,11 @@ function _require(pkg::PkgId) end # fall-through to loading the file locally else - m = _require_from_serialized(pkg, cachefile) - if isa(m, Exception) + m = _tryrequire_from_serialized(pkg, cachefile) + if !isa(m, Module) @warn "The call to compilecache failed to create a usable precompiled cache file for $pkg" exception=m else - return + return m end end end @@ -1325,7 +1425,7 @@ function _require(pkg::PkgId) unlock(require_lock) try include(__toplevel__, path) - return + loaded = get(loaded_modules, pkg, nothing) finally lock(require_lock) if uuid !== old_uuid @@ -1335,11 +1435,24 @@ function _require(pkg::PkgId) finally toplevel_load[] = last loading = pop!(package_locks, pkg) - notify(loading, all=true) + notify(loading, loaded, all=true) end - nothing + return loaded end +function _require_from_serialized(uuidkey::PkgId, path::String) + @lock require_lock begin + set_pkgorigin_version_path(uuidkey, nothing) + newm = _tryrequire_from_serialized(uuidkey, path) + newm isa Module || throw(newm) + # After successfully loading, notify downstream consumers + run_package_callbacks(uuidkey) + return newm + end +end + + + # relative-path load """ @@ -1589,7 +1702,7 @@ end const MAX_NUM_PRECOMPILE_FILES = Ref(10) function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, internal_stdout::IO = stdout, - ignore_loaded_modules::Bool = true) + keep_loaded_modules::Bool = true) @nospecialize internal_stderr internal_stdout # decide where to put the resulting cache file @@ -1597,10 +1710,10 @@ function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, in # build up the list of modules that we want the precompile process to preserve concrete_deps = copy(_concrete_dependencies) - if ignore_loaded_modules - for (key, mod) in loaded_modules + if keep_loaded_modules + for mod in loaded_modules_array() if !(mod === Main || mod === Core || mod === Base) - push!(concrete_deps, key => module_build_id(mod)) + push!(concrete_deps, PkgId(mod) => module_build_id(mod)) end end end @@ -2002,9 +2115,12 @@ get_compiletime_preferences(uuid::UUID) = collect(get(Vector{String}, COMPILETIM get_compiletime_preferences(m::Module) = get_compiletime_preferences(PkgId(m).uuid) get_compiletime_preferences(::Nothing) = String[] -# returns true if it "cachefile.ji" is stale relative to "modpath.jl" +# returns true if it "cachefile.ji" is stale relative to "modpath.jl" and build_id for modkey # otherwise returns the list of dependencies to also check @constprop :none function stale_cachefile(modpath::String, cachefile::String; ignore_loaded::Bool = false) + return stale_cachefile(PkgId(""), UInt64(0), modpath, cachefile; ignore_loaded) +end +@constprop :none function stale_cachefile(modkey::PkgId, build_id::UInt64, modpath::String, cachefile::String; ignore_loaded::Bool = false) io = open(cachefile, "r") try if !isvalid_cache_header(io) @@ -2012,7 +2128,19 @@ get_compiletime_preferences(::Nothing) = String[] return true # invalid cache file end modules, (includes, requires), required_modules, srctextpos, prefs, prefs_hash = parse_cache_header(io) - id = isempty(modules) ? nothing : first(modules).first + if isempty(modules) + return true # ignore empty file + end + id = first(modules) + if id.first != modkey && modkey != PkgId("") + @debug "Rejecting cache file $cachefile for $modkey since it is for $id instead" + return true + end + if build_id != UInt64(0) && id.second != build_id + @debug "Ignoring cache file $cachefile for $modkey since it is does not provide desired build_id" + return true + end + id = id.first modules = Dict{PkgId, UInt64}(modules) # Check if transitive dependencies can be fulfilled @@ -2039,7 +2167,6 @@ get_compiletime_preferences(::Nothing) = String[] @debug "Rejecting cache file $cachefile because dependency $req_key not found." return true # Won't be able to fulfill dependency end - set_pkgorigin_version_path(req_key, path) depmods[i] = (path, req_key, req_build_id) end end @@ -2055,7 +2182,7 @@ get_compiletime_preferences(::Nothing) = String[] skip_timecheck = true break end - @debug "Rejecting cache file $cachefile because it provides the wrong uuid (got $build_id) for $req_key (want $req_build_id)" + @debug "Rejecting cache file $cachefile because it provides the wrong build_id (got $build_id) for $req_key (want $req_build_id)" return true # cachefile doesn't provide the required version of the dependency end end @@ -2093,12 +2220,10 @@ get_compiletime_preferences(::Nothing) = String[] return true end - if isa(id, PkgId) - curr_prefs_hash = get_preferences_hash(id.uuid, prefs) - if prefs_hash != curr_prefs_hash - @debug "Rejecting cache file $cachefile because preferences hash does not match 0x$(string(prefs_hash, base=16)) != 0x$(string(curr_prefs_hash, base=16))" - return true - end + curr_prefs_hash = get_preferences_hash(id.uuid, prefs) + if prefs_hash != curr_prefs_hash + @debug "Rejecting cache file $cachefile because preferences hash does not match 0x$(string(prefs_hash, base=16)) != 0x$(string(curr_prefs_hash, base=16))" + return true end return depmods # fresh cachefile diff --git a/base/math.jl b/base/math.jl index 9550a0a54b496..af193f996dbf5 100644 --- a/base/math.jl +++ b/base/math.jl @@ -42,7 +42,7 @@ end # non-type specific math functions -@inline function two_mul(x::Float64, y::Float64) +@assume_effects :consistent @inline function two_mul(x::Float64, y::Float64) if Core.Intrinsics.have_fma(Float64) xy = x*y return xy, fma(x, y, -xy) @@ -50,7 +50,7 @@ end return Base.twomul(x,y) end -@inline function two_mul(x::T, y::T) where T<: Union{Float16, Float32} +@assume_effects :consistent @inline function two_mul(x::T, y::T) where T<: Union{Float16, Float32} if Core.Intrinsics.have_fma(T) xy = x*y return xy, fma(x, y, -xy) @@ -309,6 +309,8 @@ end Convert `x` from radians to degrees. +See also [`deg2rad`](@ref). + # Examples ```jldoctest julia> rad2deg(pi) @@ -322,7 +324,7 @@ rad2deg(z::AbstractFloat) = z * (180 / oftype(z, pi)) Convert `x` from degrees to radians. -See also: [`rad2deg`](@ref), [`sind`](@ref). +See also [`rad2deg`](@ref), [`sind`](@ref), [`pi`](@ref). # Examples ```jldoctest @@ -404,6 +406,28 @@ cosh(x::Number) tanh(x) Compute hyperbolic tangent of `x`. + +See also [`tan`](@ref), [`atanh`](@ref). + +# Examples + +```jldoctest +julia> tanh.(-3:3f0) # Here 3f0 isa Float32 +7-element Vector{Float32}: + -0.9950548 + -0.9640276 + -0.7615942 + 0.0 + 0.7615942 + 0.9640276 + 0.9950548 + +julia> tan.(im .* (1:3)) +3-element Vector{ComplexF64}: + 0.0 + 0.7615941559557649im + 0.0 + 0.9640275800758169im + 0.0 + 0.9950547536867306im +``` """ tanh(x::Number) @@ -420,6 +444,21 @@ For two arguments, this is the angle in radians between the positive *x*-axis an point (*x*, *y*), returning a value in the interval ``[-\\pi, \\pi]``. This corresponds to a standard [`atan2`](https://en.wikipedia.org/wiki/Atan2) function. Note that by convention `atan(0.0,x)` is defined as ``\\pi`` and `atan(-0.0,x)` is defined as ``-\\pi`` when `x < 0`. + +See also [`atand`](@ref) for degrees. + +# Examples + +```jldoctest +julia> rad2deg(atan(-1/√3)) +-30.000000000000004 + +julia> rad2deg(atan(-1, √3)) +-30.000000000000004 + +julia> rad2deg(atan(1, -√3)) +150.0 +``` """ atan(x::Number) @@ -442,7 +481,29 @@ asinh(x::Number) Compute sine of `x`, where `x` is in radians. -See also [`sind`](@ref), [`sinpi`](@ref), [`sincos`](@ref), [`cis`](@ref). +See also [`sind`](@ref), [`sinpi`](@ref), [`sincos`](@ref), [`cis`](@ref), [`asin`](@ref). + +# Examples +```jldoctest +julia> round.(sin.(range(0, 2pi, length=9)'), digits=3) +1×9 Matrix{Float64}: + 0.0 0.707 1.0 0.707 0.0 -0.707 -1.0 -0.707 -0.0 + +julia> sind(45) +0.7071067811865476 + +julia> sinpi(1/4) +0.7071067811865476 + +julia> round.(sincos(pi/6), digits=3) +(0.5, 0.866) + +julia> round(cis(pi/6), digits=3) +0.866 + 0.5im + +julia> round(exp(im*pi/6), digits=3) +0.866 + 0.5im +``` """ sin(x::Number) @@ -466,6 +527,17 @@ tan(x::Number) asin(x) Compute the inverse sine of `x`, where the output is in radians. + +See also [`asind`](@ref) for output in degrees. + +# Examples +```jldoctest +julia> asin.((0, 1/2, 1)) +(0.0, 0.5235987755982989, 1.5707963267948966) + +julia> asind.((0, 1/2, 1)) +(0.0, 30.000000000000004, 90.0) +``` """ asin(x::Number) @@ -496,7 +568,7 @@ atanh(x::Number) Compute the natural logarithm of `x`. Throws [`DomainError`](@ref) for negative [`Real`](@ref) arguments. Use complex negative arguments to obtain complex results. -See also [`log1p`](@ref), [`log2`](@ref), [`log10`](@ref). +See also [`ℯ`](@ref), [`log1p`](@ref), [`log2`](@ref), [`log10`](@ref). # Examples ```jldoctest; filter = r"Stacktrace:(\\n \\[[0-9]+\\].*)*" @@ -509,6 +581,12 @@ log will only return a complex result if called with a complex argument. Try log Stacktrace: [1] throw_complex_domainerror(::Symbol, ::Float64) at ./math.jl:31 [...] + +julia> log.(exp.(-1:1)) +3-element Vector{Float64}: + -1.0 + 0.0 + 1.0 ``` """ log(x::Number) @@ -535,6 +613,12 @@ log2 will only return a complex result if called with a complex argument. Try lo Stacktrace: [1] throw_complex_domainerror(f::Symbol, x::Float64) at ./math.jl:31 [...] + +julia> log2.(2.0 .^ (-1:1)) +3-element Vector{Float64}: + -1.0 + 0.0 + 1.0 ``` """ log2(x) @@ -758,17 +842,34 @@ end atan(y::Real, x::Real) = atan(promote(float(y),float(x))...) atan(y::T, x::T) where {T<:AbstractFloat} = Base.no_op_err("atan", T) -max(x::T, y::T) where {T<:AbstractFloat} = ifelse((y > x) | (signbit(y) < signbit(x)), - ifelse(isnan(x), x, y), ifelse(isnan(y), y, x)) +_isless(x::T, y::T) where {T<:AbstractFloat} = (x < y) || (signbit(x) > signbit(y)) +min(x::T, y::T) where {T<:AbstractFloat} = isnan(x) || ~isnan(y) && _isless(x, y) ? x : y +max(x::T, y::T) where {T<:AbstractFloat} = isnan(x) || ~isnan(y) && _isless(y, x) ? x : y +minmax(x::T, y::T) where {T<:AbstractFloat} = min(x, y), max(x, y) +_isless(x::Float16, y::Float16) = signbit(widen(x) - widen(y)) -min(x::T, y::T) where {T<:AbstractFloat} = ifelse((y < x) | (signbit(y) > signbit(x)), - ifelse(isnan(x), x, y), ifelse(isnan(y), y, x)) +function min(x::T, y::T) where {T<:Union{Float32,Float64}} + diff = x - y + argmin = ifelse(signbit(diff), x, y) + anynan = isnan(x)|isnan(y) + ifelse(anynan, diff, argmin) +end -minmax(x::T, y::T) where {T<:AbstractFloat} = - ifelse(isnan(x) | isnan(y), ifelse(isnan(x), (x,x), (y,y)), - ifelse((y > x) | (signbit(x) > signbit(y)), (x,y), (y,x))) +function max(x::T, y::T) where {T<:Union{Float32,Float64}} + diff = x - y + argmax = ifelse(signbit(diff), y, x) + anynan = isnan(x)|isnan(y) + ifelse(anynan, diff, argmax) +end +function minmax(x::T, y::T) where {T<:Union{Float32,Float64}} + diff = x - y + sdiff = signbit(diff) + min, max = ifelse(sdiff, x, y), ifelse(sdiff, y, x) + anynan = isnan(x)|isnan(y) + ifelse(anynan, diff, min), ifelse(anynan, diff, max) +end """ ldexp(x, n) diff --git a/base/meta.jl b/base/meta.jl index cf59d3fa3274e..c9bad2bb8a4a5 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -96,7 +96,7 @@ rather than line 2 where `@test` is used as an implementation detail. """ function replace_sourceloc!(sourceloc, @nospecialize(ex)) if ex isa Expr - if ex.head == :macrocall + if ex.head === :macrocall ex.args[2] = sourceloc end map!(e -> replace_sourceloc!(sourceloc, e), ex.args, ex.args) diff --git a/base/methodshow.jl b/base/methodshow.jl index 44f6ca0cc72f7..dc723f5c23e8a 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -292,7 +292,7 @@ function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=tru last_shown_line_infos = get(io, :last_shown_line_infos, nothing) last_shown_line_infos === nothing || empty!(last_shown_line_infos) - modul = if mt === _TYPE_NAME.mt # type constructor + modul = if mt === _TYPE_NAME.mt && length(ms) > 0 # type constructor which(ms.ms[1].module, ms.ms[1].name) else mt.module diff --git a/base/mpfr.jl b/base/mpfr.jl index 60f59cdb0af7e..97e4535c065d2 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -16,7 +16,7 @@ import cosh, sinh, tanh, sech, csch, coth, acosh, asinh, atanh, lerpi, cbrt, typemax, typemin, unsafe_trunc, floatmin, floatmax, rounding, setrounding, maxintfloat, widen, significand, frexp, tryparse, iszero, - isone, big, _string_n, decompose + isone, big, _string_n, decompose, minmax import ..Rounding: rounding_raw, setrounding_raw @@ -697,20 +697,21 @@ function log1p(x::BigFloat) return z end -function max(x::BigFloat, y::BigFloat) - isnan(x) && return x - isnan(y) && return y - z = BigFloat() - ccall((:mpfr_max, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) - return z +# For `min`/`max`, general fallback for `AbstractFloat` is good enough. +# Only implement `minmax` and `_extrema_rf` to avoid repeated calls. +function minmax(x::BigFloat, y::BigFloat) + isnan(x) && return x, x + isnan(y) && return y, y + Base.Math._isless(x, y) ? (x, y) : (y, x) end -function min(x::BigFloat, y::BigFloat) - isnan(x) && return x - isnan(y) && return y - z = BigFloat() - ccall((:mpfr_min, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Ref{BigFloat}, MPFRRoundingMode), z, x, y, ROUNDING_MODE[]) - return z +function Base._extrema_rf(x::NTuple{2,BigFloat}, y::NTuple{2,BigFloat}) + (x1, x2), (y1, y2) = x, y + isnan(x1) && return x + isnan(y1) && return y + z1 = Base.Math._isless(x1, y1) ? x1 : y1 + z2 = Base.Math._isless(x2, y2) ? y2 : x2 + z1, z2 end function modf(x::BigFloat) diff --git a/base/operators.jl b/base/operators.jl index 20e65707ad59d..8f11e3b574706 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -1017,14 +1017,11 @@ struct ComposedFunction{O,I} <: Function ComposedFunction(outer, inner) = new{Core.Typeof(outer),Core.Typeof(inner)}(outer, inner) end -function (c::ComposedFunction)(x...; kw...) - fs = unwrap_composed(c) - call_composed(fs[1](x...; kw...), tail(fs)...) -end -unwrap_composed(c::ComposedFunction) = (unwrap_composed(c.inner)..., unwrap_composed(c.outer)...) +(c::ComposedFunction)(x...; kw...) = call_composed(unwrap_composed(c), x, kw) +unwrap_composed(c::ComposedFunction) = (unwrap_composed(c.outer)..., unwrap_composed(c.inner)...) unwrap_composed(c) = (maybeconstructor(c),) -call_composed(x, f, fs...) = (@inline; call_composed(f(x), fs...)) -call_composed(x, f) = f(x) +call_composed(fs, x, kw) = (@inline; fs[1](call_composed(tail(fs), x, kw))) +call_composed(fs::Tuple{Any}, x, kw) = fs[1](x...; kw...) struct Constructor{F} <: Function end (::Constructor{F})(args...; kw...) where {F} = (@inline; F(args...; kw...)) diff --git a/base/promotion.jl b/base/promotion.jl index 39d01fcbbfb42..3dc49c8eaf1b6 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -320,12 +320,25 @@ promote_result(::Type{T},::Type{S},::Type{Bottom},::Type{Bottom}) where {T,S} = Convert all arguments to a common type, and return them all (as a tuple). If no arguments can be converted, an error is raised. -See also: [`promote_type`], [`promote_rule`]. +See also: [`promote_type`](@ref), [`promote_rule`](@ref). # Examples ```jldoctest julia> promote(Int8(1), Float16(4.5), Float32(4.1)) (1.0f0, 4.5f0, 4.1f0) + +julia> promote_type(Int8, Float16, Float32) +Float32 + +julia> reduce(Base.promote_typejoin, (Int8, Float16, Float32)) +Real + +julia> promote(1, "x") +ERROR: promotion of types Int64 and String failed to change any arguments +[...] + +julia> promote_type(Int, String) +Any ``` """ function promote end diff --git a/base/range.jl b/base/range.jl index 10fa753d7538a..be4d46f796ac2 100644 --- a/base/range.jl +++ b/base/range.jl @@ -467,6 +467,9 @@ value `r[1]`, but alternatively you can supply it as the value of `r[offset]` for some other index `1 <= offset <= len`. In conjunction with `TwicePrecision` this can be used to implement ranges that are free of roundoff error. + +!!! compat "Julia 1.7" + The 4th type parameter `L` requires at least Julia 1.7. """ struct StepRangeLen{T,R,S,L<:Integer} <: AbstractRange{T} ref::R # reference value (might be smallest-magnitude value in the range) diff --git a/base/reduce.jl b/base/reduce.jl index 7f0ee2382b68f..64ea4293c9893 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -855,8 +855,15 @@ end ExtremaMap(::Type{T}) where {T} = ExtremaMap{Type{T}}(T) @inline (f::ExtremaMap)(x) = (y = f.f(x); (y, y)) -# TODO: optimize for inputs <: AbstractFloat @inline _extrema_rf((min1, max1), (min2, max2)) = (min(min1, min2), max(max1, max2)) +# optimization for IEEEFloat +function _extrema_rf(x::NTuple{2,T}, y::NTuple{2,T}) where {T<:IEEEFloat} + (x1, x2), (y1, y2) = x, y + anynan = isnan(x1)|isnan(y1) + z1 = ifelse(anynan, x1-y1, ifelse(signbit(x1-y1), x1, y1)) + z2 = ifelse(anynan, x1-y1, ifelse(signbit(x2-y2), y2, x2)) + z1, z2 +end ## findmax, findmin, argmax & argmin diff --git a/base/reflection.jl b/base/reflection.jl index 644714c8440cb..e7c3d439d6dff 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -330,7 +330,9 @@ end """ objectid(x) -> UInt -Get a hash value for `x` based on object identity. `objectid(x)==objectid(y)` if `x === y`. +Get a hash value for `x` based on object identity. + +If `x === y` then `objectid(x) == objectid(y)`, and usually when `x !== y`, `objectid(x) != objectid(y)`. See also [`hash`](@ref), [`IdDict`](@ref). """ @@ -1317,7 +1319,7 @@ internals. One can put the argument types in a tuple to get the corresponding `code_ircode`. -```jldoctest +```julia julia> Base.code_ircode(+, (Float64, Int64)) 1-element Vector{Any}: 388 1 ─ %1 = Base.sitofp(Float64, _3)::Float64 @@ -1414,9 +1416,9 @@ function infer_effects(@nospecialize(f), @nospecialize(types=default_tt(f)); ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions") types = to_tuple_type(types) if isa(f, Core.Builtin) - args = Any[types.parameters...] - rt = Core.Compiler.builtin_tfunction(interp, f, args, nothing) - return Core.Compiler.builtin_effects(f, args, rt) + argtypes = Any[types.parameters...] + rt = Core.Compiler.builtin_tfunction(interp, f, argtypes, nothing) + return Core.Compiler.builtin_effects(f, argtypes, rt) else effects = Core.Compiler.EFFECTS_TOTAL matches = _methods(f, types, -1, world)::Vector @@ -1642,7 +1644,7 @@ function bodyfunction(basemethod::Method) f = nothing if isa(ast, Core.CodeInfo) && length(ast.code) >= 2 callexpr = ast.code[end-1] - if isa(callexpr, Expr) && callexpr.head == :call + if isa(callexpr, Expr) && callexpr.head === :call fsym = callexpr.args[1] if isa(fsym, Symbol) f = getfield(fmod, fsym) diff --git a/base/reinterpretarray.jl b/base/reinterpretarray.jl index e2253736e4fe7..cead321388a26 100644 --- a/base/reinterpretarray.jl +++ b/base/reinterpretarray.jl @@ -152,23 +152,15 @@ strides(a::Union{DenseArray,StridedReshapedArray,StridedReinterpretArray}) = siz stride(A::Union{DenseArray,StridedReshapedArray,StridedReinterpretArray}, k::Integer) = k ≤ ndims(A) ? strides(A)[k] : length(A) -function strides(a::ReshapedReinterpretArray) - ap = parent(a) - els, elp = elsize(a), elsize(ap) - stp = strides(ap) - els == elp && return stp - els < elp && return (1, _checked_strides(stp, els, elp)...) +function strides(a::ReinterpretArray{T,<:Any,S,<:AbstractArray{S},IsReshaped}) where {T,S,IsReshaped} + _checkcontiguous(Bool, a) && return size_to_strides(1, size(a)) + stp = strides(parent(a)) + els, elp = sizeof(T), sizeof(S) + els == elp && return stp # 0dim parent is also handled here. + IsReshaped && els < elp && return (1, _checked_strides(stp, els, elp)...) stp[1] == 1 || throw(ArgumentError("Parent must be contiguous in the 1st dimension!")) - return _checked_strides(tail(stp), els, elp) -end - -function strides(a::NonReshapedReinterpretArray) - ap = parent(a) - els, elp = elsize(a), elsize(ap) - stp = strides(ap) - els == elp && return stp - stp[1] == 1 || throw(ArgumentError("Parent must be contiguous in the 1st dimension!")) - return (1, _checked_strides(tail(stp), els, elp)...) + st′ = _checked_strides(tail(stp), els, elp) + return IsReshaped ? st′ : (1, st′...) end @inline function _checked_strides(stp::Tuple, els::Integer, elp::Integer) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index 060b831283970..4037aff246a81 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -295,14 +295,51 @@ unsafe_convert(::Type{Ptr{T}}, V::SubArray{T,N,P,<:Tuple{Vararg{Union{RangeIndex unsafe_convert(Ptr{T}, V.parent) + (first_index(V)-1)*sizeof(T) -_checkcontiguous(::Type{Bool}, A::AbstractArray) = size_to_strides(1, size(A)...) == strides(A) -_checkcontiguous(::Type{Bool}, A::Array) = true +_checkcontiguous(::Type{Bool}, A::AbstractArray) = false +# `strides(A::DenseArray)` calls `size_to_strides` by default. +# Thus it's OK to assume all `DenseArray`s are contiguously stored. +_checkcontiguous(::Type{Bool}, A::DenseArray) = true _checkcontiguous(::Type{Bool}, A::ReshapedArray) = _checkcontiguous(Bool, parent(A)) _checkcontiguous(::Type{Bool}, A::FastContiguousSubArray) = _checkcontiguous(Bool, parent(A)) function strides(a::ReshapedArray) - # We can handle non-contiguous parent if it's a StridedVector - ndims(parent(a)) == 1 && return size_to_strides(only(strides(parent(a))), size(a)...) - _checkcontiguous(Bool, a) || throw(ArgumentError("Parent must be contiguous.")) - size_to_strides(1, size(a)...) + _checkcontiguous(Bool, a) && return size_to_strides(1, size(a)...) + apsz::Dims = size(a.parent) + apst::Dims = strides(a.parent) + msz, mst, n = merge_adjacent_dim(apsz, apst) # Try to perform "lazy" reshape + n == ndims(a.parent) && return size_to_strides(mst, size(a)...) # Parent is stridevector like + return _reshaped_strides(size(a), 1, msz, mst, n, apsz, apst) +end + +function _reshaped_strides(::Dims{0}, reshaped::Int, msz::Int, ::Int, ::Int, ::Dims, ::Dims) + reshaped == msz && return () + throw(ArgumentError("Input is not strided.")) +end +function _reshaped_strides(sz::Dims, reshaped::Int, msz::Int, mst::Int, n::Int, apsz::Dims, apst::Dims) + st = reshaped * mst + reshaped = reshaped * sz[1] + if length(sz) > 1 && reshaped == msz && sz[2] != 1 + msz, mst, n = merge_adjacent_dim(apsz, apst, n + 1) + reshaped = 1 + end + sts = _reshaped_strides(tail(sz), reshaped, msz, mst, n, apsz, apst) + return (st, sts...) +end + +merge_adjacent_dim(::Dims{0}, ::Dims{0}) = 1, 1, 0 +merge_adjacent_dim(apsz::Dims{1}, apst::Dims{1}) = apsz[1], apst[1], 1 +function merge_adjacent_dim(apsz::Dims{N}, apst::Dims{N}, n::Int = 1) where {N} + sz, st = apsz[n], apst[n] + while n < N + szₙ, stₙ = apsz[n+1], apst[n+1] + if sz == 1 + sz, st = szₙ, stₙ + elseif stₙ == st * sz || szₙ == 1 + sz *= szₙ + else + break + end + n += 1 + end + return sz, st, n end diff --git a/base/show.jl b/base/show.jl index 9841d34efe88b..850f6a9bf5e2b 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1192,12 +1192,12 @@ function print_fullname(io::IO, m::Module) end end -function sourceinfo_slotnames(src::CodeInfo) - slotnames = src.slotnames +sourceinfo_slotnames(src::CodeInfo) = sourceinfo_slotnames(src.slotnames) +function sourceinfo_slotnames(slotnames::Vector{Symbol}) names = Dict{String,Int}() printnames = Vector{String}(undef, length(slotnames)) for i in eachindex(slotnames) - if slotnames[i] == :var"#unused#" + if slotnames[i] === :var"#unused#" printnames[i] = "_" continue end @@ -1562,8 +1562,6 @@ unquoted(ex::Expr) = ex.args[1] function printstyled end function with_output_color end -is_expected_union(u::Union) = u.a == Nothing || u.b == Nothing || u.a == Missing || u.b == Missing - emphasize(io, str::AbstractString, col = Base.error_color()) = get(io, :color, false) ? printstyled(io, str; color=col, bold=true) : print(io, uppercase(str)) @@ -2021,7 +2019,7 @@ function show_unquoted(io::IO, ex::Expr, indent::Int, prec::Int, quote_level::In # other call-like expressions ("A[1,2]", "T{X,Y}", "f.(X,Y)") elseif haskey(expr_calls, head) && nargs >= 1 # :ref/:curly/:calldecl/:(.) funcargslike = head === :(.) ? (args[2]::Expr).args : args[2:end] - show_call(head == :ref ? IOContext(io, beginsym=>true) : io, head, args[1], funcargslike, indent, quote_level, head !== :curly) + show_call(head === :ref ? IOContext(io, beginsym=>true) : io, head, args[1], funcargslike, indent, quote_level, head !== :curly) # comprehensions elseif head === :typed_comprehension && nargs == 2 diff --git a/base/slicearray.jl b/base/slicearray.jl index c9371622f6aff..85fcb56e4278d 100644 --- a/base/slicearray.jl +++ b/base/slicearray.jl @@ -51,7 +51,7 @@ function _slice_check_dims(N, dim, dims...) _slice_check_dims(N,dims...) end -@inline function _eachslice(A::AbstractArray{T,N}, dims::NTuple{M,Integer}, drop::Bool) where {T,N,M} +@constprop :aggressive function _eachslice(A::AbstractArray{T,N}, dims::NTuple{M,Integer}, drop::Bool) where {T,N,M} _slice_check_dims(N,dims...) if drop # if N = 4, dims = (3,1) then diff --git a/base/some.jl b/base/some.jl index 8be58739a4df4..8e4e1b5e07c3f 100644 --- a/base/some.jl +++ b/base/some.jl @@ -65,7 +65,7 @@ Return `true` if `x === nothing`, and return `false` if not. !!! compat "Julia 1.1" This function requires at least Julia 1.1. -See also [`something`](@ref), [`notnothing`](@ref), [`ismissing`](@ref). +See also [`something`](@ref), [`Base.notnothing`](@ref), [`ismissing`](@ref). """ isnothing(x) = x === nothing diff --git a/base/sort.jl b/base/sort.jl index acd7bd6f6dd62..0eb2ae8a5b4be 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -515,8 +515,12 @@ function sort!(v::AbstractVector, lo::Integer, hi::Integer, ::InsertionSortAlg, @inbounds for i = lo+1:hi j = i x = v[i] - while j > lo && lt(o, x, v[j-1]) - v[j] = v[j-1] + while j > lo + y = v[j-1] + if !lt(o, x, y) + break + end + v[j] = y j -= 1 end v[j] = x diff --git a/base/task.jl b/base/task.jl index c405deaf56423..5601fea70a112 100644 --- a/base/task.jl +++ b/base/task.jl @@ -424,19 +424,21 @@ function sync_end(c::Channel{Any}) # Capture all waitable objects scheduled after the end of `@sync` and # include them in the exception. This way, the user can check what was # scheduled by examining at the exception object. - local racy - for r in c - if !@isdefined(racy) - racy = [] + if isready(c) + local racy + for r in c + if !@isdefined(racy) + racy = [] + end + push!(racy, r) end - push!(racy, r) - end - if @isdefined(racy) - if !@isdefined(c_ex) - c_ex = CompositeException() + if @isdefined(racy) + if !@isdefined(c_ex) + c_ex = CompositeException() + end + # Since this is a clear programming error, show this exception first: + pushfirst!(c_ex, ScheduledAfterSyncException(racy)) end - # Since this is a clear programming error, show this exception first: - pushfirst!(c_ex, ScheduledAfterSyncException(racy)) end if @isdefined(c_ex) @@ -924,7 +926,7 @@ function trypoptask(W::StickyWorkqueue) # can't throw here, because it's probably not the fault of the caller to wait # and don't want to use print() here, because that may try to incur a task switch ccall(:jl_safe_printf, Cvoid, (Ptr{UInt8}, Int32...), - "\nWARNING: Workqueue inconsistency detected: popfirst!(Workqueue).state != :runnable\n") + "\nWARNING: Workqueue inconsistency detected: popfirst!(Workqueue).state !== :runnable\n") continue end return t diff --git a/base/threadingconstructs.jl b/base/threadingconstructs.jl index b00dfb389ce3b..0852fafe192ec 100644 --- a/base/threadingconstructs.jl +++ b/base/threadingconstructs.jl @@ -26,9 +26,9 @@ function nthreads end nthreads() = Int(unsafe_load(cglobal(:jl_n_threads, Cint))) function nthreads(pool::Symbol) - if pool == :default + if pool === :default tpid = Int8(0) - elseif pool == :interactive + elseif pool === :interactive tpid = Int8(1) else error("invalid threadpool specified") diff --git a/base/threads_overloads.jl b/base/threads_overloads.jl index a0d4bbeda2288..376c1af94f441 100644 --- a/base/threads_overloads.jl +++ b/base/threads_overloads.jl @@ -20,6 +20,21 @@ to load-balancing. This approach thus may be more suitable for fine-grained, uniform workloads, but may perform worse than `FairSchedule` in concurrence with other multithreaded workloads. +# Examples +```julia-repl +julia> n = 20 + +julia> c = Channel{Int}(ch -> foreach(i -> put!(ch, i), 1:n), 1) + +julia> d = Channel{Int}(n) do ch + f = i -> put!(ch, i^2) + Threads.foreach(f, c) + end + +julia> collect(d) +collect(d) = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400] +``` + !!! compat "Julia 1.6" This function requires Julia 1.6 or later. """ diff --git a/base/util.jl b/base/util.jl index 46e7f36475b98..1dc59e86d7043 100644 --- a/base/util.jl +++ b/base/util.jl @@ -257,26 +257,83 @@ graphical interface. """ function getpass end -_getch() = UInt8(ccall(:jl_getch, Cint, ())) +# Note, this helper only works within `with_raw_tty()` on POSIX platforms! +function _getch() + @static if Sys.iswindows() + return UInt8(ccall(:_getch, Cint, ())) + else + return read(stdin, UInt8) + end +end + +const termios_size = Int(ccall(:jl_termios_size, Cint, ())) +make_termios() = zeros(UInt8, termios_size) + +# These values seem to hold on all OSes we care about: +# glibc Linux, musl Linux, macOS, FreeBSD +@enum TCSETATTR_FLAGS TCSANOW=0 TCSADRAIN=1 TCSAFLUSH=2 + +function tcgetattr(fd::RawFD, termios) + ret = ccall(:tcgetattr, Cint, (Cint, Ptr{Cvoid}), fd, termios) + if ret != 0 + throw(IOError("tcgetattr failed", ret)) + end +end +function tcsetattr(fd::RawFD, termios, mode::TCSETATTR_FLAGS = TCSADRAIN) + ret = ccall(:tcsetattr, Cint, (Cint, Cint, Ptr{Cvoid}), fd, Cint(mode), termios) + if ret != 0 + throw(IOError("tcsetattr failed", ret)) + end +end +cfmakeraw(termios) = ccall(:cfmakeraw, Cvoid, (Ptr{Cvoid},), termios) + +function with_raw_tty(f::Function, input::TTY) + input === stdin || throw(ArgumentError("with_raw_tty only works for stdin")) + fd = RawFD(0) + + # If we're on windows, we do nothing, as we have access to `_getch()` quite easily + @static if Sys.iswindows() + return f() + end + + # Get the current terminal mode + old_termios = make_termios() + tcgetattr(fd, old_termios) + try + # Set a new, raw, terminal mode + new_termios = copy(old_termios) + cfmakeraw(new_termios) + tcsetattr(fd, new_termios) + + # Call the user-supplied callback + f() + finally + # Always restore the terminal mode + tcsetattr(fd, old_termios) + end +end + function getpass(input::TTY, output::IO, prompt::AbstractString) input === stdin || throw(ArgumentError("getpass only works for stdin")) - print(output, prompt, ": ") - flush(output) - s = SecretBuffer() - plen = 0 - while true - c = _getch() - if c == 0xff || c == UInt8('\n') || c == UInt8('\r') || c == 0x04 - break # EOF or return - elseif c == 0x00 || c == 0xe0 - _getch() # ignore function/arrow keys - elseif c == UInt8('\b') && plen > 0 - plen -= 1 # delete last character on backspace - elseif !iscntrl(Char(c)) && plen < 128 - write(s, c) + with_raw_tty(stdin) do + print(output, prompt, ": ") + flush(output) + s = SecretBuffer() + plen = 0 + while true + c = _getch() + if c == 0xff || c == UInt8('\n') || c == UInt8('\r') || c == 0x04 + break # EOF or return + elseif c == 0x00 || c == 0xe0 + _getch() # ignore function/arrow keys + elseif c == UInt8('\b') && plen > 0 + plen -= 1 # delete last character on backspace + elseif !iscntrl(Char(c)) && plen < 128 + write(s, c) + end end + return seekstart(s) end - return seekstart(s) end # allow new getpass methods to be defined if stdin has been diff --git a/base/version_git.sh b/base/version_git.sh index 2a3352d1066ef..39ebb1b8ec5ee 100644 --- a/base/version_git.sh +++ b/base/version_git.sh @@ -41,7 +41,15 @@ if [ -n "$(git status --porcelain)" ]; then # append dirty mark '*' if the repository has uncommitted changes commit_short="$commit_short"* fi -branch=$(git rev-parse --abbrev-ref HEAD) + +# Our CI system checks commits out as a detached head, and so we must +# use the provided branch name, as we cannot autodetect this commit as +# the tip of any such branch. +if [ -n "${BUILDKITE_BRANCH}" ]; then + branch="${BUILDKITE_BRANCH}" +else + branch=$(git rev-parse --abbrev-ref HEAD) +fi topdir=$(git rev-parse --show-toplevel) verchanged=$(git blame -L ,1 -sl -- "$topdir/VERSION" | cut -f 1 -d " ") diff --git a/deps/checksums/DelimitedFiles-495ebc81ef7fe2c083ca4c1d7e43a22cc1e49490.tar.gz/md5 b/deps/checksums/DelimitedFiles-495ebc81ef7fe2c083ca4c1d7e43a22cc1e49490.tar.gz/md5 new file mode 100644 index 0000000000000..b4cf9f1e83f38 --- /dev/null +++ b/deps/checksums/DelimitedFiles-495ebc81ef7fe2c083ca4c1d7e43a22cc1e49490.tar.gz/md5 @@ -0,0 +1 @@ +ae5ab9a7304cffb64614c49540259f62 diff --git a/deps/checksums/DelimitedFiles-495ebc81ef7fe2c083ca4c1d7e43a22cc1e49490.tar.gz/sha512 b/deps/checksums/DelimitedFiles-495ebc81ef7fe2c083ca4c1d7e43a22cc1e49490.tar.gz/sha512 new file mode 100644 index 0000000000000..38e84b1ae4e1f --- /dev/null +++ b/deps/checksums/DelimitedFiles-495ebc81ef7fe2c083ca4c1d7e43a22cc1e49490.tar.gz/sha512 @@ -0,0 +1 @@ +eff8c61190d180248a6bcd0a4d194df223a0471f9a8200a12afb41f8df2c4dfbfb292bbe0ca5ac940e4093a041832a89ad252cd1a7b89c250500662808a6abbf diff --git a/deps/checksums/DelimitedFiles-f520e069d2eb8282e8a07dcb384fe0e0c6293bc3.tar.gz/md5 b/deps/checksums/DelimitedFiles-f520e069d2eb8282e8a07dcb384fe0e0c6293bc3.tar.gz/md5 deleted file mode 100644 index 93a2d414cff7d..0000000000000 --- a/deps/checksums/DelimitedFiles-f520e069d2eb8282e8a07dcb384fe0e0c6293bc3.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -ba99caf3dbe9c1c40e67033898ccea2d diff --git a/deps/checksums/DelimitedFiles-f520e069d2eb8282e8a07dcb384fe0e0c6293bc3.tar.gz/sha512 b/deps/checksums/DelimitedFiles-f520e069d2eb8282e8a07dcb384fe0e0c6293bc3.tar.gz/sha512 deleted file mode 100644 index 99c68c413c411..0000000000000 --- a/deps/checksums/DelimitedFiles-f520e069d2eb8282e8a07dcb384fe0e0c6293bc3.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -c39a90233d3d47431ac7bcbcc47cea9502a9e3a778caf1a67d8bd8364e273ccbe34c9c53f01ba4cfec97ca87b5e7bf9b7901889385061f6dd609413192635b40 diff --git a/deps/checksums/Downloads-78255d4927312181542b29ec6f063b0d5880189e.tar.gz/md5 b/deps/checksums/Downloads-78255d4927312181542b29ec6f063b0d5880189e.tar.gz/md5 deleted file mode 100644 index 1e6941e0ba3d2..0000000000000 --- a/deps/checksums/Downloads-78255d4927312181542b29ec6f063b0d5880189e.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -fe3fd0496c74e3bac89ff726dc332215 diff --git a/deps/checksums/Downloads-78255d4927312181542b29ec6f063b0d5880189e.tar.gz/sha512 b/deps/checksums/Downloads-78255d4927312181542b29ec6f063b0d5880189e.tar.gz/sha512 deleted file mode 100644 index a76890917a129..0000000000000 --- a/deps/checksums/Downloads-78255d4927312181542b29ec6f063b0d5880189e.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -1be660af912922a79301fbe9a4d2dcfbcf3e9b0d7b6277ea8823e51771f1267c222e4b7c4e08b0496b2e735f6748f3f5aa3acb6b4bcc246ab76f4afbc45dc302 diff --git a/deps/checksums/Downloads-c34ec3e5b231b231a37c83a9737feca481a47e4b.tar.gz/md5 b/deps/checksums/Downloads-c34ec3e5b231b231a37c83a9737feca481a47e4b.tar.gz/md5 new file mode 100644 index 0000000000000..67fe5ddda27ad --- /dev/null +++ b/deps/checksums/Downloads-c34ec3e5b231b231a37c83a9737feca481a47e4b.tar.gz/md5 @@ -0,0 +1 @@ +683d87d65f1a1cb584079fa52d0e0a8c diff --git a/deps/checksums/Downloads-c34ec3e5b231b231a37c83a9737feca481a47e4b.tar.gz/sha512 b/deps/checksums/Downloads-c34ec3e5b231b231a37c83a9737feca481a47e4b.tar.gz/sha512 new file mode 100644 index 0000000000000..e8b9b57ade705 --- /dev/null +++ b/deps/checksums/Downloads-c34ec3e5b231b231a37c83a9737feca481a47e4b.tar.gz/sha512 @@ -0,0 +1 @@ +2a0d6f4205b1f5a2ac6eea5132513c7d7afb5ef39dddb7ba06fbee7d349e8c1938e98571932f1e1035680dfb3286df2b97926b1edb476276c388f3104631d64e diff --git a/deps/checksums/Pkg-56cd041ccdf648c7cf5d280bca1386910923c276.tar.gz/md5 b/deps/checksums/Pkg-56cd041ccdf648c7cf5d280bca1386910923c276.tar.gz/md5 new file mode 100644 index 0000000000000..b177fcb64172b --- /dev/null +++ b/deps/checksums/Pkg-56cd041ccdf648c7cf5d280bca1386910923c276.tar.gz/md5 @@ -0,0 +1 @@ +6c6a19da9e109dd4c74dc77c2236d9c1 diff --git a/deps/checksums/Pkg-56cd041ccdf648c7cf5d280bca1386910923c276.tar.gz/sha512 b/deps/checksums/Pkg-56cd041ccdf648c7cf5d280bca1386910923c276.tar.gz/sha512 new file mode 100644 index 0000000000000..987ad37e01262 --- /dev/null +++ b/deps/checksums/Pkg-56cd041ccdf648c7cf5d280bca1386910923c276.tar.gz/sha512 @@ -0,0 +1 @@ +dd6e290c4b32d7efb2db91ed86fb068a5da9dce5789fde21ac1bda4707eaca4bd93f0d5c2e1eb94f0133efdda9c1b64b01fcb85e2dca1a1f78bc2a6583b852fc diff --git a/deps/checksums/Pkg-98d0cc276cc59817eb9c2e18e747fe027d7282a2.tar.gz/md5 b/deps/checksums/Pkg-98d0cc276cc59817eb9c2e18e747fe027d7282a2.tar.gz/md5 deleted file mode 100644 index 927835aebd23b..0000000000000 --- a/deps/checksums/Pkg-98d0cc276cc59817eb9c2e18e747fe027d7282a2.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -8c6bc28980648ed4b7315544c79c8b75 diff --git a/deps/checksums/Pkg-98d0cc276cc59817eb9c2e18e747fe027d7282a2.tar.gz/sha512 b/deps/checksums/Pkg-98d0cc276cc59817eb9c2e18e747fe027d7282a2.tar.gz/sha512 deleted file mode 100644 index ec9e546ace65a..0000000000000 --- a/deps/checksums/Pkg-98d0cc276cc59817eb9c2e18e747fe027d7282a2.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -84b8345212bb08e8801e049f2b2678edcde05bba7223965f2d75c902381b842555ea737ab084af2faa3804a7047c4b2cf9be533b153941c3dc761ddd459b4c43 diff --git a/deps/checksums/SparseArrays-0759ceac6e89d03b9abcea27ba1b7bfa6d806721.tar.gz/md5 b/deps/checksums/SparseArrays-0759ceac6e89d03b9abcea27ba1b7bfa6d806721.tar.gz/md5 deleted file mode 100644 index cd2013946933b..0000000000000 --- a/deps/checksums/SparseArrays-0759ceac6e89d03b9abcea27ba1b7bfa6d806721.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -9e1b18aaaeee1ed2f1c6f5b26541a3c8 diff --git a/deps/checksums/SparseArrays-0759ceac6e89d03b9abcea27ba1b7bfa6d806721.tar.gz/sha512 b/deps/checksums/SparseArrays-0759ceac6e89d03b9abcea27ba1b7bfa6d806721.tar.gz/sha512 deleted file mode 100644 index cddb9ab51aa46..0000000000000 --- a/deps/checksums/SparseArrays-0759ceac6e89d03b9abcea27ba1b7bfa6d806721.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -e799c89d4b9079690ef129e61992f2294ad173cb9f9c9e8106220e11483986ff024cf65221a91d9e19e446eae836680f376ee8eeb66b2f2e971e5e055eac4668 diff --git a/deps/checksums/SparseArrays-2bbdd7a12ead8207593655c541ba347761a9c663.tar.gz/md5 b/deps/checksums/SparseArrays-2bbdd7a12ead8207593655c541ba347761a9c663.tar.gz/md5 deleted file mode 100644 index 6ade8ae4a3ded..0000000000000 --- a/deps/checksums/SparseArrays-2bbdd7a12ead8207593655c541ba347761a9c663.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -db4be14b084094a3a083160fce142b01 diff --git a/deps/checksums/SparseArrays-2bbdd7a12ead8207593655c541ba347761a9c663.tar.gz/sha512 b/deps/checksums/SparseArrays-2bbdd7a12ead8207593655c541ba347761a9c663.tar.gz/sha512 deleted file mode 100644 index a50b52aa22586..0000000000000 --- a/deps/checksums/SparseArrays-2bbdd7a12ead8207593655c541ba347761a9c663.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -886dbede7bbc484cb8aa4c5ac7d05940890f00bff32b31a489dcbb873c7f6d956d15ab92638d67b7ba3638f429371af57be76a4949a860efa52d457941ed7f47 diff --git a/deps/checksums/SparseArrays-e081db699e4bc99db6424dca8103ff111c9b9fcc.tar.gz/md5 b/deps/checksums/SparseArrays-e081db699e4bc99db6424dca8103ff111c9b9fcc.tar.gz/md5 new file mode 100644 index 0000000000000..2a194c20ef647 --- /dev/null +++ b/deps/checksums/SparseArrays-e081db699e4bc99db6424dca8103ff111c9b9fcc.tar.gz/md5 @@ -0,0 +1 @@ +57797b6da80f194ffeb63116e60da43c diff --git a/deps/checksums/SparseArrays-e081db699e4bc99db6424dca8103ff111c9b9fcc.tar.gz/sha512 b/deps/checksums/SparseArrays-e081db699e4bc99db6424dca8103ff111c9b9fcc.tar.gz/sha512 new file mode 100644 index 0000000000000..ecd8945b9c6f6 --- /dev/null +++ b/deps/checksums/SparseArrays-e081db699e4bc99db6424dca8103ff111c9b9fcc.tar.gz/sha512 @@ -0,0 +1 @@ +ce50a0e9ed1af71b5069d00d58a79dfd6d4fa6b660b720996198928371e884f38772b00fc08cb0538184ab7845423cc0c37fcefa5c6e60cd75924c3035b20451 diff --git a/deps/checksums/Statistics-0588f2cf9e43f9f72af5802feaf0af4b652c3257.tar.gz/md5 b/deps/checksums/Statistics-0588f2cf9e43f9f72af5802feaf0af4b652c3257.tar.gz/md5 new file mode 100644 index 0000000000000..f0bd8c2517b21 --- /dev/null +++ b/deps/checksums/Statistics-0588f2cf9e43f9f72af5802feaf0af4b652c3257.tar.gz/md5 @@ -0,0 +1 @@ +fb508e9a699fde0d7f85b208ae7a0f2b diff --git a/deps/checksums/Statistics-0588f2cf9e43f9f72af5802feaf0af4b652c3257.tar.gz/sha512 b/deps/checksums/Statistics-0588f2cf9e43f9f72af5802feaf0af4b652c3257.tar.gz/sha512 new file mode 100644 index 0000000000000..5f6512e8a7f16 --- /dev/null +++ b/deps/checksums/Statistics-0588f2cf9e43f9f72af5802feaf0af4b652c3257.tar.gz/sha512 @@ -0,0 +1 @@ +5ea116f2ed5b4709e33888a865d07bbc6cb49f7ddb43c315a4e95e020e77c5eb769baab3e784c1c03665ac6ed4bad933bc21fdf4121667f7760027483ccd0171 diff --git a/deps/checksums/Statistics-c38dd4418738bc595bd8229eb4ee91b717de64af.tar.gz/md5 b/deps/checksums/Statistics-c38dd4418738bc595bd8229eb4ee91b717de64af.tar.gz/md5 deleted file mode 100644 index 69ee3fd518626..0000000000000 --- a/deps/checksums/Statistics-c38dd4418738bc595bd8229eb4ee91b717de64af.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -20ea909b7e95726c2aec676501b28af2 diff --git a/deps/checksums/Statistics-c38dd4418738bc595bd8229eb4ee91b717de64af.tar.gz/sha512 b/deps/checksums/Statistics-c38dd4418738bc595bd8229eb4ee91b717de64af.tar.gz/sha512 deleted file mode 100644 index 7229c045089a6..0000000000000 --- a/deps/checksums/Statistics-c38dd4418738bc595bd8229eb4ee91b717de64af.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -fb102582b868571c2c8d95f723df54aee2fe5693badb6171296207e267c4fbe0bcc8003c9e01ce6d3245ae79f977cad86fe18c14ef2cf440a764c10d11941d1e diff --git a/deps/checksums/curl b/deps/checksums/curl index 77cb46923aefd..0f235d8238e8e 100644 --- a/deps/checksums/curl +++ b/deps/checksums/curl @@ -1,36 +1,36 @@ LibCURL-fd8af649b38ae20c3ff7f5dca53753512ca00376.tar.gz/md5/f082283e6a35fcba5b63c9a6219d8003 LibCURL-fd8af649b38ae20c3ff7f5dca53753512ca00376.tar.gz/sha512/3bea5fa3fb6d29651daa923ae6bcb8eeb356ab9f2a1f3e005a6b746b617b0cf609aed4cadda4181783959840873c04b18e34e45ab973549169d19775a05ea01e -LibCURL.v7.83.1+1.aarch64-apple-darwin.tar.gz/md5/de0048ffcd0cf779f648c58df4d87ea9 -LibCURL.v7.83.1+1.aarch64-apple-darwin.tar.gz/sha512/874d1f83e0ff21ff8a5e39f29ca03588142e5f292a7e3bfb36f6f6f4f3e5b518b76dc8c0272a2df1167daed108b92f0e620277e6f3e2c091aa60934d18c292e4 -LibCURL.v7.83.1+1.aarch64-linux-gnu.tar.gz/md5/55bb17c62f5cf9894770bbc6e9fcce45 -LibCURL.v7.83.1+1.aarch64-linux-gnu.tar.gz/sha512/bb1e2246bb169ad7cc36749d56cf4bf6d3bd57bb9d141c5d807be5048ecc3cb3adeef95438d52c6360b5e70ba0ec75efb134c381affc812d0f5e1d8e76ff9884 -LibCURL.v7.83.1+1.aarch64-linux-musl.tar.gz/md5/52ce54a88113140c7f7c57895054d68c -LibCURL.v7.83.1+1.aarch64-linux-musl.tar.gz/sha512/dbd385d28ba6cf9e7c0ca05e9b10bafc041320c307ea7571bb972ae90b71a29ffa50d7c934d358c9e35cb168d3a378589cf0de66d5f13fe69da8a44ba1712284 -LibCURL.v7.83.1+1.armv6l-linux-gnueabihf.tar.gz/md5/68150dd7d41938065f444a1fc162d8d0 -LibCURL.v7.83.1+1.armv6l-linux-gnueabihf.tar.gz/sha512/0d8eccd3fc30160899789b91ff12ae08d97f48c08c25dcbcf737ceb9a9388fb082b7abac53da6e4711f9a5ff40700ac735d748f13895ea5205f919449182711b -LibCURL.v7.83.1+1.armv6l-linux-musleabihf.tar.gz/md5/963de5f46421087fc4f0c0e3674d6a5b -LibCURL.v7.83.1+1.armv6l-linux-musleabihf.tar.gz/sha512/a9b491384a19d4cb26ab48a09dff8e58989b0e2ba8f143a0740daa582ddcf4a29c21216045baaeec5d121922a2dc38e9072174aa8f5deaf2d38ea1997a1c6ba5 -LibCURL.v7.83.1+1.armv7l-linux-gnueabihf.tar.gz/md5/b64791ed06518e53d5e0bc713bf82af4 -LibCURL.v7.83.1+1.armv7l-linux-gnueabihf.tar.gz/sha512/30dcbbb3f944da18a9764728850fe24ba7612d11fe0b81f6c56e7735479128b0a55bd43d29cb326db20dc8f1fc9a1407bb7f54da1526d5fa182ab223e11377d0 -LibCURL.v7.83.1+1.armv7l-linux-musleabihf.tar.gz/md5/fc64fc8de930b1f2deee6910706da54e -LibCURL.v7.83.1+1.armv7l-linux-musleabihf.tar.gz/sha512/04e9cfdf55403ce2c7077356f05a98fe6a94772b5846ceff0cc81f0ebac95df85e259ecf4ded2baa369f55580892d083c74460e436a33c0286a797db60497558 -LibCURL.v7.83.1+1.i686-linux-gnu.tar.gz/md5/44a4f66754105b24102135fe62691aab -LibCURL.v7.83.1+1.i686-linux-gnu.tar.gz/sha512/9200ec12725fbf93039e534625f8cb14607be820df27ac4bcabcf8332f2e5214604b6c1efd6f4d1ae6c554b8cdd0808a1dda0f9e1fba7764484c0b00e351db7b -LibCURL.v7.83.1+1.i686-linux-musl.tar.gz/md5/bf0a521a03bb216430e66d29e9bd597e -LibCURL.v7.83.1+1.i686-linux-musl.tar.gz/sha512/ef549d533d1a1d40a0e10ec68611f586878fd3a218a9d388ae3328e4fad3dc613ed700671bbbd1f62554555073a7ab224c122fb31e7bcc6c751a7d0ce6fba9f6 -LibCURL.v7.83.1+1.i686-w64-mingw32.tar.gz/md5/c48af4c27cecbc38694cce627412eceb -LibCURL.v7.83.1+1.i686-w64-mingw32.tar.gz/sha512/9dbdbc8cbeafa913debfeed88b0514355fec89a48945716a43baae94e9855cb84cb9ba794cd022958636858a5be9f671f92a40ad3cd3b5145245c94cb26112d7 -LibCURL.v7.83.1+1.powerpc64le-linux-gnu.tar.gz/md5/50256b715d014ef9a2b328668a71a5dd -LibCURL.v7.83.1+1.powerpc64le-linux-gnu.tar.gz/sha512/730eef536baa0be00fc9f1e87f82fb84a051141bab277f11873e7e2fdaeced3964e9a0e4343504e1cb7b89fbf92df8890fa33eaed9b3c6555171c8a8adbf9dcf -LibCURL.v7.83.1+1.x86_64-apple-darwin.tar.gz/md5/367d7944167a83ff2a8d4982c8504e47 -LibCURL.v7.83.1+1.x86_64-apple-darwin.tar.gz/sha512/591f268ecbb0f5c43266876e9e0f33235b5c2e96aae4386d22c50785a4466e4b3f14e5b48117f1751733492c4ccc54638bfcf10c904d12145db7881e07778a23 -LibCURL.v7.83.1+1.x86_64-linux-gnu.tar.gz/md5/57bf4c88945b3f83e336754b075b35f7 -LibCURL.v7.83.1+1.x86_64-linux-gnu.tar.gz/sha512/71984f5240c5962422cf69069b3f0d0529a64c9ccb9995b9f26742a19dc12ae9700e888fe8b79b17edfcaa1b13b24a56b4d776453d83cce233dfa9c3fdb79660 -LibCURL.v7.83.1+1.x86_64-linux-musl.tar.gz/md5/64f3026a24b6a7df77e8325a108e76db -LibCURL.v7.83.1+1.x86_64-linux-musl.tar.gz/sha512/bf0c16b90b7b6ef33ed7d4678df539f88d041f5a78942ca5549d9d0e7ce8cef38af8da1f68d9d3999f969805dd1da546da3d289b32dad442ec1b2b5e44d158cb -LibCURL.v7.83.1+1.x86_64-unknown-freebsd.tar.gz/md5/578ba7e5607ce2de16132ab8f7a213d9 -LibCURL.v7.83.1+1.x86_64-unknown-freebsd.tar.gz/sha512/42c5892038aaedbbb19e192fc867e00d354da7cdf11c90151124f3c9006883960107663eaa865ee482895ee5784b5c5f487ea8aeef2a8ebbbe51f59d693e0778 -LibCURL.v7.83.1+1.x86_64-w64-mingw32.tar.gz/md5/5e5bb662234dd4520f4e4f73f8536daa -LibCURL.v7.83.1+1.x86_64-w64-mingw32.tar.gz/sha512/4553dc10d464771166b8a53473e68a23baa6fb8f65f09a5a274826d313dafc3289348e0e8026abcec6fea98e461aca31001176387526afcf3966167b71ec2178 -curl-7.83.1.tar.bz2/md5/08626822d50cbef47503f220718b920b -curl-7.83.1.tar.bz2/sha512/c43ec2da9c8609a312f723c0b3eff7e171ed1258c6ed1af16020190d4253e6bea63ca3905f04d0ca46a97986a8bb79be1d532f8d68fcbdbacfa80cc42f134db1 +LibCURL.v7.84.0+0.aarch64-apple-darwin.tar.gz/md5/0e1d2884864419df574b61a6db15ef9d +LibCURL.v7.84.0+0.aarch64-apple-darwin.tar.gz/sha512/18986ce04a39a8935d3b2e595e9c7b6ecd38340f1f886cb5b16880ad72b9889a5bba8720c30c2775add115c0385ca1f98956df2cb89cd4ffa92d67e433a8f12b +LibCURL.v7.84.0+0.aarch64-linux-gnu.tar.gz/md5/e4d57ee8f1304b8fde272a373a13cdf6 +LibCURL.v7.84.0+0.aarch64-linux-gnu.tar.gz/sha512/88ee9129a3053b8221808f977561541be573068c5abf388a78b1c748b6c7cca2cd23f8bfcb779541fc83dff07a7a3c979194359f6cd4d0cb6d6696affac03c11 +LibCURL.v7.84.0+0.aarch64-linux-musl.tar.gz/md5/f40a48d02ee841d7393477ef63163c43 +LibCURL.v7.84.0+0.aarch64-linux-musl.tar.gz/sha512/9998db3a896fa46a51d2da2a07b48470a9719fe301fb0589f04e2bd0e1bd116c5c74ca8f03d4dff6529339fdf68a42788ed33c629794bc3886e5147f51c53eb7 +LibCURL.v7.84.0+0.armv6l-linux-gnueabihf.tar.gz/md5/223727927aff997175d1d8bdcea39c79 +LibCURL.v7.84.0+0.armv6l-linux-gnueabihf.tar.gz/sha512/f856ca8a63f55d455ae161e58cd5e195ffb80ceaeeaa7cf306a3d192ae51a1ebfb93e87e27aa90f513294e27beb8e1358c7a07eb5a3a85d434327b4331211426 +LibCURL.v7.84.0+0.armv6l-linux-musleabihf.tar.gz/md5/efc2bcc500edaaf59542f86119b9a090 +LibCURL.v7.84.0+0.armv6l-linux-musleabihf.tar.gz/sha512/297f2999f1544816e2edd1fb78aa5f8abf9dde9b782a62054b0f61974f3dbde7ae67cf4d8dd63c21082de5f89dfeb32aa099e2228851242c3379a811883f92e4 +LibCURL.v7.84.0+0.armv7l-linux-gnueabihf.tar.gz/md5/e5a0a5b7f1e664675bc2ac4970b39297 +LibCURL.v7.84.0+0.armv7l-linux-gnueabihf.tar.gz/sha512/bd9c602b69841dd1b8625627c774dbf99e7c3fcf951b00299dbe8007e8ea2bf5a312fa34f0be9e21a7ac947332652ffa55fdbcdf21096449a8ab982c9a7ce776 +LibCURL.v7.84.0+0.armv7l-linux-musleabihf.tar.gz/md5/05f04c53e4a04ced1d6aefc1e9493332 +LibCURL.v7.84.0+0.armv7l-linux-musleabihf.tar.gz/sha512/7ea517a048d8d7a940f5e32d1476366d9e63bf0103276c8208cd23e1ae7e4dd70e0acba4cdeafd1e9a5db90dfc213bd0895ebef755ea237cab3fc9d39808c325 +LibCURL.v7.84.0+0.i686-linux-gnu.tar.gz/md5/97cffa9e6e771e5b96d77a0acff157af +LibCURL.v7.84.0+0.i686-linux-gnu.tar.gz/sha512/84b81c69c021e8aad542c909c81ace41ea96650ef1dcd46b1ef29b683a870abddff96b8d2ecde593c8cea427256dfa194cf5bd4e5b610b0b8ce779e383aadb76 +LibCURL.v7.84.0+0.i686-linux-musl.tar.gz/md5/3dccdbc2cde661c7d868f2bd7d5c0316 +LibCURL.v7.84.0+0.i686-linux-musl.tar.gz/sha512/7625d1ba19e69cce185d61ef09374af4d433730f4908f1ce5da7d3352c96a58e1543dc66a0cb01000c4ced9033e2b2137877a4d7c9f8f0fa551613e436cb574c +LibCURL.v7.84.0+0.i686-w64-mingw32.tar.gz/md5/bd2b06eadacaf984cc25993c242517eb +LibCURL.v7.84.0+0.i686-w64-mingw32.tar.gz/sha512/21aee096ff42e3c4dfbf6b8c9e3cbdcc4cae234ac784e871d4ca55424263eb59cfd2b159287861a076373017ab5454d0c9f93c99d87e90f263563ddee28d737d +LibCURL.v7.84.0+0.powerpc64le-linux-gnu.tar.gz/md5/221f481553cdb28d97a7caa69a895b12 +LibCURL.v7.84.0+0.powerpc64le-linux-gnu.tar.gz/sha512/90caf2fe245a0e1f5816fadf2c0b8e7bda5df38d716c309aadb37721923f57919af09c6a7396ce2888dc02ae02670da9300c0e5814d5ad851bdb4e661c48bc48 +LibCURL.v7.84.0+0.x86_64-apple-darwin.tar.gz/md5/9f609374291fe24ec9bd752c967d3072 +LibCURL.v7.84.0+0.x86_64-apple-darwin.tar.gz/sha512/8a8461a8cf7591a798d7ed32423a33b38425d32e3a7fd4feda06095237ae6dc43c6737dcc55bb86e260080198d5295f11fee88883354425b132c8e04bfa9feaf +LibCURL.v7.84.0+0.x86_64-linux-gnu.tar.gz/md5/c1cc01bbc7aec5b272f7dbe803fda257 +LibCURL.v7.84.0+0.x86_64-linux-gnu.tar.gz/sha512/e6f9ff29a8ab46537054e1fa364ece163fd4376d16fe7e22dc94c0a640397b45659c143b8e170b1b01ef800ab7f53a9f4087197f2fae9002e061530cefe6157b +LibCURL.v7.84.0+0.x86_64-linux-musl.tar.gz/md5/20dec1cebca3b2ef188a31ae50a40b42 +LibCURL.v7.84.0+0.x86_64-linux-musl.tar.gz/sha512/9d5675f90eb348ecb637ee7ed31d68701504efa7871c9f55eacb331b6717eae893e88c63cb5abd6ca9d13d34a055d67d0cf36ca173f2bd58e19b65cabbd816e7 +LibCURL.v7.84.0+0.x86_64-unknown-freebsd.tar.gz/md5/a57884bfdcbca83c1f14ece9d501224f +LibCURL.v7.84.0+0.x86_64-unknown-freebsd.tar.gz/sha512/f8bf1755b3a758b351532ede8f19af6ace8cfcf59b656067ddfd1135533052b340ca35e9cb0e134e1f082cea19860af2029448fc1ca231a32bf03bd07698d4da +LibCURL.v7.84.0+0.x86_64-w64-mingw32.tar.gz/md5/71182295492b38bb419a71489f01fa54 +LibCURL.v7.84.0+0.x86_64-w64-mingw32.tar.gz/sha512/9d84bfad36ca69b3ed2519bef8845cece4d9b3e8c9e1e040f744c6163469c732cfd1301cf5e5c9e23c25420b1b17a844bcb43bde858a501eb6133dbc266f2f75 +curl-7.84.0.tar.bz2/md5/35fca80437f32dd7ef6c2e30b4916f06 +curl-7.84.0.tar.bz2/sha512/57823295e2c036355d9170b9409d698e1cece882b2cb55ce33fcf384dd30a75c00e68d6550f3b3faba4ef38443e2172c731ddfef6e508b99476f4e36d25bdd1c diff --git a/deps/checksums/llvm b/deps/checksums/llvm index c36710af3fffc..d9ddeffde0efc 100644 --- a/deps/checksums/llvm +++ b/deps/checksums/llvm @@ -262,7 +262,7 @@ libLLVM.v14.0.5+1.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/md5/b6 libLLVM.v14.0.5+1.x86_64-w64-mingw32-cxx11-llvm_version+14.asserts.tar.gz/sha512/f60d64488d8cd332c812b0fe393287419456face8a5ab543c257fb5e5d917189e438ec16ab8d04a66645b8dde7eeec5bad2d341926546df8caf66ffbae43abc5 libLLVM.v14.0.5+1.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/md5/ad2a9f52a8fb9e67859ac34e395f2328 libLLVM.v14.0.5+1.x86_64-w64-mingw32-cxx11-llvm_version+14.tar.gz/sha512/51d111cbdab11e2d598ae553a922565161b5a66333fc644a8a566040d177965ec0fa377b08e21d9a5836f71feb61d7c0194bade3d8c4b6cba028efb5a1ee03f3 -llvm-julia-14.0.5-0.tar.gz/md5/c7df1a3f2cc19201ece78996582f43ce -llvm-julia-14.0.5-0.tar.gz/sha512/51c61d842cb61dab74df6d7263caa8c91e7b5e832bd8665cf40b3c2d8191a8c9665eb8b5ea1499607b6fba9013260f6b087c90ac850dd7e66f5fd37ebc407d15 +llvm-julia-14.0.5-1.tar.gz/md5/7f540b9ffc21fbad6e6b349ab7dd1a41 +llvm-julia-14.0.5-1.tar.gz/sha512/9842821fd19af8b9f091d8e3b600d83b77794271074b86e9d6505ab0325a40a52e38029b65c349e368e8bd985521203df00f125f93462379ea2931e5c81f9793 llvmunwind-12.0.1.tar.xz/md5/4ec327cee517fdb1f6a20e83748e2c7b llvmunwind-12.0.1.tar.xz/sha512/847b6ba03010a43f4fdbfdc49bf16d18fd18474d01584712e651b11191814bf7c1cf53475021d9ee447ed78413202b4ed97973d7bdd851d3e49f8d06f55a7af4 diff --git a/deps/curl.mk b/deps/curl.mk index 3f90495c7c042..58f3e1f89c05d 100644 --- a/deps/curl.mk +++ b/deps/curl.mk @@ -33,6 +33,17 @@ $(SRCCACHE)/curl-$(CURL_VER)/source-extracted: $(SRCCACHE)/curl-$(CURL_VER).tar. checksum-curl: $(SRCCACHE)/curl-$(CURL_VER).tar.bz2 $(JLCHECKSUM) $< +## xref: https://github.com/JuliaPackaging/Yggdrasil/blob/master/L/LibCURL/common.jl +# Disable....almost everything +CURL_CONFIGURE_FLAGS := $(CONFIGURE_COMMON) \ + --without-ssl --without-gnutls --without-libidn2 --without-librtmp \ + --without-nss --without-libpsl --without-libgsasl --without-fish-functions-dir \ + --disable-ares --disable-manual --disable-ldap --disable-ldaps --disable-static +# A few things we actually enable +CURL_CONFIGURE_FLAGS += --enable-versioned-symbols \ + --with-libssh2=${build_prefix} --with-zlib=${build_prefix} --with-nghttp2=${build_prefix} +CURL_CONFIGURE_FLAGS += --without-gssapi + # We use different TLS libraries on different platforms. # On Windows, we use schannel # On MacOS, we use SecureTransport @@ -44,21 +55,17 @@ CURL_TLS_CONFIGURE_FLAGS := --with-secure-transport else CURL_TLS_CONFIGURE_FLAGS := --with-mbedtls=$(build_prefix) endif +CURL_CONFIGURE_FLAGS += $(CURL_TLS_CONFIGURE_FLAGS) $(BUILDDIR)/curl-$(CURL_VER)/build-configured: $(SRCCACHE)/curl-$(CURL_VER)/source-extracted mkdir -p $(dir $@) cd $(dir $@) && \ - $(dir $<)/configure $(CONFIGURE_COMMON) --includedir=$(build_includedir) \ - --without-ssl --without-gnutls --without-gssapi --disable-ares \ - --without-libidn2 --without-librtmp --without-nss --without-libpsl \ - --disable-ldap --disable-ldaps --without-zsh-functions-dir --disable-static \ - --with-libssh2=$(build_prefix) --with-zlib=$(build_prefix) --with-nghttp2=$(build_prefix) \ - $(CURL_TLS_CONFIGURE_FLAGS) \ + $(dir $<)/configure $(CURL_CONFIGURE_FLAGS) \ CFLAGS="$(CFLAGS) $(CURL_CFLAGS)" LDFLAGS="$(LDFLAGS) $(CURL_LDFLAGS)" echo 1 > $@ $(BUILDDIR)/curl-$(CURL_VER)/build-compiled: $(BUILDDIR)/curl-$(CURL_VER)/build-configured - $(MAKE) -C $(dir $<) $(LIBTOOL_CCLD) + $(MAKE) -C $(dir $<) $(MAKE_COMMON) echo 1 > $@ $(BUILDDIR)/curl-$(CURL_VER)/build-checked: $(BUILDDIR)/curl-$(CURL_VER)/build-compiled @@ -69,7 +76,7 @@ endif $(eval $(call staged-install, \ curl,curl-$$(CURL_VER), \ - MAKE_INSTALL,$$(LIBTOOL_CCLD),, \ + MAKE_INSTALL,,, \ $$(INSTALL_NAME_CMD)libcurl.$$(SHLIB_EXT) $$(build_shlibdir)/libcurl.$$(SHLIB_EXT))) clean-curl: diff --git a/deps/curl.version b/deps/curl.version index 65e60e16758f7..96bc09263156f 100644 --- a/deps/curl.version +++ b/deps/curl.version @@ -1,5 +1,6 @@ +# -*- makefile -*- ## jll artifact CURL_JLL_NAME := LibCURL ## source build -CURL_VER := 7.83.1 +CURL_VER := 7.84.0 diff --git a/deps/gmp.mk b/deps/gmp.mk index ccf76e12eef84..2354a6ca44a9f 100644 --- a/deps/gmp.mk +++ b/deps/gmp.mk @@ -1,6 +1,16 @@ ## GMP ## include $(SRCDIR)/gmp.version +ifneq ($(USE_BINARYBUILDER_GMP),1) + +GMP_CONFIGURE_OPTS := $(CONFIGURE_COMMON) +GMP_CONFIGURE_OPTS += --enable-cxx --enable-shared --disable-static +GMP_CONFIGURE_OPTS += CC_FOR_BUILD="$(HOSTCC)" + +ifeq ($(BUILD_ARCH),x86_64) +GMP_CONFIGURE_OPTS += --enable-fat +endif + ifeq ($(SANITIZE),1) GMP_CONFIGURE_OPTS += --disable-assembly endif @@ -9,7 +19,6 @@ ifeq ($(BUILD_OS),WINNT) GMP_CONFIGURE_OPTS += --srcdir="$(subst \,/,$(call mingw_to_dos,$(SRCCACHE)/gmp-$(GMP_VER)))" endif -ifneq ($(USE_BINARYBUILDER_GMP),1) $(SRCCACHE)/gmp-$(GMP_VER).tar.bz2: | $(SRCCACHE) $(JLDOWNLOAD) $@ https://gmplib.org/download/gmp/$(notdir $@) @@ -45,38 +54,30 @@ $(SRCCACHE)/gmp-$(GMP_VER)/gmp-CVE-2021-43618.patch-applied: $(SRCCACHE)/gmp-$(G patch -p1 < $(SRCDIR)/patches/gmp-CVE-2021-43618.patch echo 1 > $@ -$(SRCCACHE)/gmp-$(GMP_VER)/source-patched: \ - $(SRCCACHE)/gmp-$(GMP_VER)/gmp-HG-changeset.patch-applied \ - $(SRCCACHE)/gmp-$(GMP_VER)/gmp-exception.patch-applied \ - $(SRCCACHE)/gmp-$(GMP_VER)/gmp_alloc_overflow_func.patch-applied \ - $(SRCCACHE)/gmp-$(GMP_VER)/gmp-CVE-2021-43618.patch-applied +$(SRCCACHE)/gmp-$(GMP_VER)/source-patched: $(SRCCACHE)/gmp-$(GMP_VER)/gmp-CVE-2021-43618.patch-applied echo 1 > $@ -$(BUILDDIR)/gmp-$(GMP_VER)/build-configured: $(SRCCACHE)/gmp-$(GMP_VER)/source-extracted $(SRCCACHE)/gmp-$(GMP_VER)/source-patched +$(BUILDDIR)/gmp-$(GMP_VER)/build-configured: $(SRCCACHE)/gmp-$(GMP_VER)/source-patched mkdir -p $(dir $@) cd $(dir $@) && \ - $(dir $<)/configure $(CONFIGURE_COMMON) F77= --enable-cxx --enable-shared --disable-static $(GMP_CONFIGURE_OPTS) + $(dir $<)/configure $(GMP_CONFIGURE_OPTS) echo 1 > $@ $(BUILDDIR)/gmp-$(GMP_VER)/build-compiled: $(BUILDDIR)/gmp-$(GMP_VER)/build-configured - $(MAKE) -C $(dir $<) $(LIBTOOL_CCLD) + $(MAKE) -C $(dir $<) echo 1 > $@ $(BUILDDIR)/gmp-$(GMP_VER)/build-checked: $(BUILDDIR)/gmp-$(GMP_VER)/build-compiled ifeq ($(OS),$(BUILD_OS)) - $(MAKE) -C $(dir $@) $(LIBTOOL_CCLD) check + $(MAKE) -C $(dir $@) check endif echo 1 > $@ -define GMP_INSTALL - mkdir -p $2/$(build_shlibdir) $2/$(build_includedir) - $(INSTALL_M) $1/.libs/libgmp*$(SHLIB_EXT)* $2/$(build_shlibdir) - $(INSTALL_F) $1/gmp.h $2/$(build_includedir) -endef $(eval $(call staged-install, \ gmp,gmp-$(GMP_VER), \ - GMP_INSTALL,,, \ - $$(INSTALL_NAME_CMD)libgmp.$$(SHLIB_EXT) $$(build_shlibdir)/libgmp.$$(SHLIB_EXT))) + MAKE_INSTALL,,, \ + $$(WIN_MAKE_HARD_LINK) $(build_bindir)/libgmp-*.dll $(build_bindir)/libgmp.dll && \ + $$(INSTALL_NAME_CMD)libgmp.$$(SHLIB_EXT) $$(build_shlibdir)/libgmp.$$(SHLIB_EXT))) clean-gmp: -rm -f $(BUILDDIR)/gmp-$(GMP_VER)/build-configured $(BUILDDIR)/gmp-$(GMP_VER)/build-compiled @@ -97,4 +98,5 @@ check-gmp: $(BUILDDIR)/gmp-$(GMP_VER)/build-checked else # USE_BINARYBUILDER_GMP $(eval $(call bb-install,gmp,GMP,false,true)) + endif diff --git a/deps/llvm-ver.make b/deps/llvm-ver.make index c2c7f2bc56da7..3c498be6c2363 100644 --- a/deps/llvm-ver.make +++ b/deps/llvm-ver.make @@ -1,3 +1,5 @@ +include $(JULIAHOME)/deps/llvm.version + LLVM_VER_MAJ:=$(word 1, $(subst ., ,$(LLVM_VER))) LLVM_VER_MIN:=$(word 2, $(subst ., ,$(LLVM_VER))) # define a "short" LLVM version for easy comparisons @@ -10,3 +12,8 @@ LLVM_VER_PATCH:=$(word 3, $(subst ., ,$(LLVM_VER))) ifeq ($(LLVM_VER_PATCH),) LLVM_VER_PATCH := 0 endif + +LLVM_SHARED_LIB_VER_SUFFIX := $(LLVM_VER_MAJ)jl +# e.g.: "libLLVM-14jl" +LLVM_SHARED_LIB_NAME := libLLVM-$(LLVM_SHARED_LIB_VER_SUFFIX) +LLVM_SHARED_LINK_FLAG := -lLLVM-$(LLVM_SHARED_LIB_VER_SUFFIX) diff --git a/deps/llvm.mk b/deps/llvm.mk index 62c47d581393e..f1bdc02a60069 100644 --- a/deps/llvm.mk +++ b/deps/llvm.mk @@ -202,7 +202,7 @@ LLVM_CMAKE += -DCMAKE_EXE_LINKER_FLAGS="$(LLVM_LDFLAGS)" \ -DCMAKE_SHARED_LINKER_FLAGS="$(LLVM_LDFLAGS)" # change the SONAME of Julia's private LLVM -# i.e. libLLVM-6.0jl.so +# i.e. libLLVM-14jl.so # see #32462 LLVM_CMAKE += -DLLVM_VERSION_SUFFIX:STRING="jl" LLVM_CMAKE += -DLLVM_SHLIB_SYMBOL_VERSION:STRING="JL_LLVM_$(LLVM_VER_SHORT)" @@ -259,10 +259,10 @@ endif LLVM_INSTALL = \ cd $1 && mkdir -p $2$$(build_depsbindir) && \ - cp -r $$(SRCCACHE)/$$(LLVM_SRC_DIR)/llvm/utils/lit $2$$(build_depsbindir)/ && \ - $$(CMAKE) -DCMAKE_INSTALL_PREFIX="$2$$(build_prefix)" -P cmake_install.cmake + cp -r $$(SRCCACHE)/$$(LLVM_SRC_DIR)/llvm/utils/lit $2$$(build_depsbindir)/ && \ + $$(CMAKE) -DCMAKE_INSTALL_PREFIX="$2$$(build_prefix)" -P cmake_install.cmake ifeq ($(OS), WINNT) -LLVM_INSTALL += && cp $2$$(build_shlibdir)/libLLVM.dll $2$$(build_depsbindir) +LLVM_INSTALL += && cp $2$$(build_shlibdir)/$(LLVM_SHARED_LIB_NAME).dll $2$$(build_depsbindir) endif ifeq ($(OS),Darwin) # https://github.com/JuliaLang/julia/issues/29981 diff --git a/deps/llvm.version b/deps/llvm.version index b18610e09fdf8..7a35ee0512413 100644 --- a/deps/llvm.version +++ b/deps/llvm.version @@ -3,6 +3,6 @@ LLVM_JLL_NAME := libLLVM LLVM_ASSERT_JLL_VER := 14.0.5+1 ## source build -LLVM_VER := 14.0.2 -LLVM_BRANCH=julia-14.0.5-0 -LLVM_SHA1=julia-14.0.5-0 +LLVM_VER := 14.0.5 +LLVM_BRANCH=julia-14.0.5-1 +LLVM_SHA1=julia-14.0.5-1 diff --git a/deps/zlib.mk b/deps/zlib.mk index d43f829c13111..5548a0791f4d2 100644 --- a/deps/zlib.mk +++ b/deps/zlib.mk @@ -4,9 +4,13 @@ ZLIB_GIT_URL := https://github.com/madler/zlib.git ZLIB_TAR_URL = https://api.github.com/repos/madler/zlib/tarball/$1 $(eval $(call git-external,zlib,ZLIB,,,$(SRCCACHE))) +# use `-DUNIX=true` to ensure that it is always named `libz` +ZLIB_BUILD_OPTS := $(CMAKE_COMMON) -DCMAKE_BUILD_TYPE=Release -DUNIX=true +ZLIB_BUILD_OPTS += -DCMAKE_POSITION_INDEPENDENT_CODE=ON + $(BUILDDIR)/$(ZLIB_SRC_DIR)/build-configured: $(SRCCACHE)/$(ZLIB_SRC_DIR)/source-extracted mkdir -p $(dir $@) - cd $(dir $@) && $(CMAKE) -DCMAKE_INSTALL_PREFIX=$(abspath $(build_prefix)) -DCMAKE_BUILD_TYPE=Release -DUNIX=true $(dir $<) + cd $(dir $@) && $(CMAKE) $(ZLIB_BUILD_OPTS) $(dir $<) echo 1 > $@ $(BUILDDIR)/$(ZLIB_SRC_DIR)/build-compiled: $(BUILDDIR)/$(ZLIB_SRC_DIR)/build-configured @@ -19,12 +23,12 @@ $(eval $(call staged-install, \ $(INSTALL_NAME_CMD)libz.$(SHLIB_EXT) $(build_shlibdir)/libz.$(SHLIB_EXT))) clean-zlib: - -rm -f $(BUILDDIR)/$(ZLIB_SRC_DIR)/build-compiled $(build_libdir)/libz.a* $(build_libdir)/libz.so* $(build_includedir)/zlib.h $(build_includedir)/zconf.h - -$(MAKE) -C $(BUILDDIR)/$(ZLIB_SRC_DIR) distclean $(ZLIB_FLAGS) + -rm -f $(BUILDDIR)/$(ZLIB_SRC_DIR)/build-configured $(BUILDDIR)/$(ZLIB_SRC_DIR)/build-compiled + -$(MAKE) -C $(BUILDDIR)/$(ZLIB_SRC_DIR) clean get-zlib: $(ZLIB_SRC_FILE) extract-zlib: $(BUILDDIR)/$(ZLIB_SRC_DIR)/source-extracted -configure-zlib: extract-zlib +configure-zlib: $(BUILDDIR)/$(ZLIB_SRC_DIR)/build-configured compile-zlib: $(BUILDDIR)/$(ZLIB_SRC_DIR)/build-compiled fastcheck-zlib: check-zlib check-zlib: compile-zlib diff --git a/doc/Manifest.toml b/doc/Manifest.toml index e3d56b7594251..74081475bc96b 100644 --- a/doc/Manifest.toml +++ b/doc/Manifest.toml @@ -24,9 +24,9 @@ version = "0.8.6" [[deps.Documenter]] deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "122d031e8dcb2d3e767ed434bc4d1ae1788b5a7f" +git-tree-sha1 = "e4967ebb9dce1328d582200b03bcc44c69372312" uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.27.17" +version = "0.27.20" [[deps.IOCapture]] deps = ["Logging", "Random"] @@ -64,9 +64,9 @@ version = "1.2.0" [[deps.Parsers]] deps = ["Dates"] -git-tree-sha1 = "1285416549ccfcdf0c50d4997a94331e88d68413" +git-tree-sha1 = "0044b23da09b5608b4ecacb4e5e6c6332f833a7e" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.3.1" +version = "2.3.2" [[deps.Printf]] deps = ["Unicode"] diff --git a/doc/make.jl b/doc/make.jl index 5028b89093cc4..5f5986497c922 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -336,8 +336,13 @@ end # Define our own DeployConfig struct BuildBotConfig <: Documenter.DeployConfig end +Documenter.authentication_method(::BuildBotConfig) = Documenter.HTTPS +Documenter.authenticated_repo_url(::BuildBotConfig) = "https://github.com/JuliaLang/docs.julialang.org.git" function Documenter.deploy_folder(::BuildBotConfig; devurl, repo, branch, kwargs...) - haskey(ENV, "DOCUMENTER_KEY") || return Documenter.DeployDecision(; all_ok=false) + if !haskey(ENV, "DOCUMENTER_KEY") + @info "Unable to deploy the documentation: DOCUMENTER_KEY missing" + return Documenter.DeployDecision(; all_ok=false) + end if Base.GIT_VERSION_INFO.tagged_commit # Strip extra pre-release info (1.5.0-rc2.0 -> 1.5.0-rc2) ver = VersionNumber(VERSION.major, VERSION.minor, VERSION.patch, @@ -347,6 +352,11 @@ function Documenter.deploy_folder(::BuildBotConfig; devurl, repo, branch, kwargs elseif Base.GIT_VERSION_INFO.branch == "master" return Documenter.DeployDecision(; all_ok=true, repo, branch, subfolder=devurl) end + @info """ + Unable to deploy the documentation: invalid GIT_VERSION_INFO + GIT_VERSION_INFO.tagged_commit: $(Base.GIT_VERSION_INFO.tagged_commit) + GIT_VERSION_INFO.branch: $(Base.GIT_VERSION_INFO.branch) + """ return Documenter.DeployDecision(; all_ok=false) end @@ -374,11 +384,16 @@ function Documenter.Writers.HTMLWriter.expand_versions(dir::String, v::Versions) return Documenter.Writers.HTMLWriter.expand_versions(dir, v.versions) end -deploydocs( - repo = "github.com/JuliaLang/docs.julialang.org.git", - deploy_config = BuildBotConfig(), - target = joinpath(buildroot, "doc", "_build", "html", "en"), - dirname = "en", - devurl = devurl, - versions = Versions(["v#.#", devurl => devurl]), -) +if "deploy" in ARGS + deploydocs( + repo = "github.com/JuliaLang/docs.julialang.org.git", + deploy_config = BuildBotConfig(), + target = joinpath(buildroot, "doc", "_build", "html", "en"), + dirname = "en", + devurl = devurl, + versions = Versions(["v#.#", devurl => devurl]), + archive = get(ENV, "DOCUMENTER_ARCHIVE", nothing), + ) +else + @info "Skipping deployment ('deploy' not passed)" +end diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index 96475b6818a1a..af4185a0f1266 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -785,9 +785,9 @@ defined to add new functionality: julia> Base.propertynames(::Point, private::Bool=false) = private ? (:x, :y, :r, :ϕ) : (:x, :y) julia> function Base.getproperty(p::Point, s::Symbol) - if s == :x + if s === :x return getfield(p, :r) * cos(getfield(p, :ϕ)) - elseif s == :y + elseif s === :y return getfield(p, :r) * sin(getfield(p, :ϕ)) else # This allows accessing fields with p.r and p.ϕ @@ -796,12 +796,12 @@ julia> function Base.getproperty(p::Point, s::Symbol) end julia> function Base.setproperty!(p::Point, s::Symbol, f) - if s == :x + if s === :x y = p.y setfield!(p, :r, sqrt(f^2 + y^2)) setfield!(p, :ϕ, atan(y, f)) return f - elseif s == :y + elseif s === :y x = p.x setfield!(p, :r, sqrt(x^2 + f^2)) setfield!(p, :ϕ, atan(f, x)) diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index a374b9c879e6a..8fddb8868c7d4 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -116,7 +116,7 @@ The [`Symbol`](@ref) constructor takes any number of arguments and creates a new their string representations together: ```jldoctest -julia> :foo == Symbol("foo") +julia> :foo === Symbol("foo") true julia> Symbol("func",10) @@ -1353,7 +1353,8 @@ Both these implementations, although different, do essentially the same thing: a over the dimensions of the array, collecting the offset in each dimension into the final index. However, all the information we need for the loop is embedded in the type information of the arguments. -Thus, we can utilize generated functions to move the iteration to compile-time; in compiler parlance, +This allows the compiler to move the iteration to compile time and eliminate the runtime loops +altogether. We can utilize generated functions to achieve a simmilar effect; in compiler parlance, we use generated functions to manually unroll the loop. The body becomes almost identical, but instead of calculating the linear index, we build up an *expression* that calculates the index: diff --git a/doc/src/manual/performance-tips.md b/doc/src/manual/performance-tips.md index 7ae33f501655d..8a9f5ce842513 100644 --- a/doc/src/manual/performance-tips.md +++ b/doc/src/manual/performance-tips.md @@ -1048,11 +1048,10 @@ julia> @time f.(x); That is, `fdot(x)` is ten times faster and allocates 1/6 the memory of `f(x)`, because each `*` and `+` operation in `f(x)` allocates -a new temporary array and executes in a separate loop. (Of course, -if you just do `f.(x)` then it is as fast as `fdot(x)` in this -example, but in many contexts it is more convenient to just sprinkle -some dots in your expressions rather than defining a separate function -for each vectorized operation.) +a new temporary array and executes in a separate loop. In this example +`f.(x)` is as fast as `fdot(x)` but in many contexts it is more +convenient to sprinkle some dots in your expressions than to +define a separate function for each vectorized operation. ## [Consider using views for slices](@id man-performance-views) diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index be3f76bb99683..32f4c29af9311 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -770,9 +770,10 @@ are some examples of non-standard string literals. Users and packages may also d Further documentation is given in the [Metaprogramming](@ref meta-non-standard-string-literals) section. ## [Regular Expressions](@id man-regex-literals) +Sometimes you are not looking for an exact string, but a particular *pattern*. For example, suppose you are trying to extract a single date from a large text file. You don’t know what that date is (that’s why you are searching for it), but you do know it will look something like `YYYY-MM-DD`. Regular expressions allow you to specify these patterns and search for them. -Julia has Perl-compatible regular expressions (regexes), as provided by the [PCRE](https://www.pcre.org/) -library (a description of the syntax can be found [here](https://www.pcre.org/current/doc/html/pcre2syntax.html)). Regular expressions are related to strings in two ways: the obvious connection is that +Julia uses version 2 of Perl-compatible regular expressions (regexes), as provided by the [PCRE](https://www.pcre.org/) +library (see the [PCRE2 syntax description](https://www.pcre.org/current/doc/html/pcre2syntax.html) for more details). Regular expressions are related to strings in two ways: the obvious connection is that regular expressions are used to find regular patterns in strings; the other connection is that regular expressions are themselves input as strings, which are parsed into a state machine that can be used to efficiently search for patterns in strings. In Julia, regular expressions are input diff --git a/src/.gitignore b/src/.gitignore index 388e971d4f12d..4ddd75fbb5d62 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -21,6 +21,7 @@ /julia_version.h /flisp/host /support/host +/base/ # Clang compilation database /compile_commands*.json diff --git a/src/Makefile b/src/Makefile index b3165777d4208..90455d51e9345 100644 --- a/src/Makefile +++ b/src/Makefile @@ -116,24 +116,29 @@ endif ifeq ($(JULIACODEGEN),LLVM) ifneq ($(USE_SYSTEM_LLVM),0) +# USE_SYSTEM_LLVM != 0 CG_LLVMLINK += $(LLVM_LDFLAGS) $(shell $(LLVM_CONFIG_HOST) --libs --system-libs) # HACK: llvm-config doesn't correctly point to shared libs on all platforms # https://github.com/JuliaLang/julia/issues/29981 else +# USE_SYSTEM_LLVM == 0 ifneq ($(USE_LLVM_SHLIB),1) +# USE_LLVM_SHLIB != 1 CG_LLVMLINK += $(LLVM_LDFLAGS) $(shell $(LLVM_CONFIG_HOST) --libs $(CG_LLVM_LIBS) --link-static) $($(LLVM_LDFLAGS) $(shell $(LLVM_CONFIG_HOST) --system-libs 2> /dev/null) else +# USE_LLVM_SHLIB == 1 ifeq ($(OS), Darwin) CG_LLVMLINK += $(LLVM_LDFLAGS) -lLLVM else -CG_LLVMLINK += $(LLVM_LDFLAGS) -lLLVM-14jl -endif -endif -endif +CG_LLVMLINK += $(LLVM_LDFLAGS) $(LLVM_SHARED_LINK_FLAG) +endif # OS +endif # USE_LLVM_SHLIB +endif # USE_SYSTEM_LLVM + ifeq ($(USE_LLVM_SHLIB),1) FLAGS += -DLLVM_SHLIB endif # USE_LLVM_SHLIB == 1 -endif +endif # JULIACODEGEN == LLVM RT_LLVM_LINK_ARGS := $(shell $(LLVM_CONFIG_HOST) --libs $(RT_LLVM_LIBS) --system-libs --link-static) RT_LLVMLINK += $(LLVM_LDFLAGS) $(RT_LLVM_LINK_ARGS) diff --git a/src/ast.scm b/src/ast.scm index 0f69638fdb52e..bbb2180a8a92f 100644 --- a/src/ast.scm +++ b/src/ast.scm @@ -523,6 +523,21 @@ (and (if one (length= e 3) (length> e 2)) (eq? (car e) 'meta) (memq (cadr e) '(nospecialize specialize)))) +(define (meta? e) + (and (length> e 1) (eq? (car e) 'meta))) + +(define (method-meta-sym? x) + (memq x '(inline noinline aggressive_constprop no_constprop propagate_inbounds))) + +(define (propagate-method-meta e) + `(meta ,@(filter (lambda (x) + (or (method-meta-sym? x) + (and (pair? x) (eq? (car x) 'purity)))) + (cdr e)))) + +(define (argwide-nospecialize-meta? e) + (and (length= e 2) (eq? (car e) 'meta) (memq (cadr e) '(nospecialize specialize)))) + (define (if-generated? e) (and (length= e 4) (eq? (car e) 'if) (equal? (cadr e) '(generated)))) diff --git a/src/builtins.c b/src/builtins.c index 2e93a752c3d29..f4ed6b39e56bb 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1602,6 +1602,7 @@ JL_CALLABLE(jl_f_donotdelete) JL_CALLABLE(jl_f_finalizer) { + // NOTE the compiler may temporarily insert additional argument for the later inlining pass JL_NARGS(finalizer, 2, 4); jl_task_t *ct = jl_current_task; jl_gc_add_finalizer_(ct->ptls, args[1], args[0]); diff --git a/src/dump.c b/src/dump.c index 63c504d5813c7..6a1bd2ea582b8 100644 --- a/src/dump.c +++ b/src/dump.c @@ -37,21 +37,76 @@ extern "C" { // careful to match the sequence, if necessary reserving space for something that will // be updated later. -// It is also necessary to save & restore references to externally-defined objects, -// e.g., for package methods that call methods defined in Base or elsewhere. -// Consequently during deserialization there's a distinction between "reference" -// types, methods, and method instances (essentially like a GlobalRef), -// and "recached" version that refer to the actual entity in the running session. -// We complete deserialization before beginning the process of recaching, -// because we need the backreferences during deserialization and the actual -// objects during recaching. +// It is also necessary to save & restore references to externally-defined +// objects, e.g., for package methods that call methods defined in Base or +// elsewhere. Consequently during deserialization there's a distinction between +// "reference" types, methods, and method instances (essentially like a +// GlobalRef), and "recached" version that refer to the actual entity in the +// running session. As a concrete example, types have a module in which they are +// defined, but once defined those types can be used by any dependent package. +// We don't store the full type definition again in that dependent package, we +// just encode a reference to that type. In the running session, such references +// are merely pointers to the type-cache, but the specific address is obviously +// not likely to be reproducible across sessions (it will differ between the +// session in which you precompile and the session in which you're using the +// package). Hence, during serialization we recode them as "verbose" references +// (that follow Julia syntax to allow them to be reconstructed), but on +// deserialization we have to replace those verbose references with the +// appropriate pointer in the user's running session. We complete +// deserialization before beginning the process of recaching, because we need +// the backreferences during deserialization and the actual objects during +// recaching. // Finally, because our backedge graph is not bidirectional, special handling is // required to identify backedges from external methods that call internal methods. // These get set aside and restored at the end of deserialization. +// In broad terms, the major steps in serialization are: +// - starting from a "worklist" of modules, write the header. This stores things +// like the Julia build this was precompiled for, the package dependencies, +// the list of include files, file modification times, etc. +// - gather the collection of items to be written to this precompile file. This +// includes accessible from the module's binding table (if they are owned by a +// worklist module), but also includes things like methods added to external +// functions, instances of external methods that were newly type-inferred +// while precompiling a worklist module, and backedges of callees that were +// called by methods in this package. By and large, these latter items are not +// referenced by the module(s) in the package, and so these have to be +// extracted by traversing the entire system searching for things that do link +// back to a module in the worklist. +// - serialize all the items. The first time we encounter an item, we serialized +// it, and on future references (pointers) to that item we replace them with +// with a backreference. `jl_serialize_*` functions handle this work. +// - write source text for the files that defined the package. This is primarily +// to support Revise.jl. + +// Deserialization is the mirror image of serialization, but in some ways is +// trickier: +// - we have to merge items into the running session (recaching as described +// above) and handle cases like having two dependent packages caching the same +// MethodInstance of a dependency +// - we have to check for invalidation---the user might have loaded other +// packages that define methods that supersede some of the dispatches chosen +// when the package was precompiled, or this package might define methods that +// supercede dispatches for previously-loaded packages. These two +// possibilities are checked during backedge and method insertion, +// respectively. +// Both of these mean that deserialization requires one to look up a lot of +// things in the running session; for example, for invalidation checks we have +// to do type-intersection between signatures used for MethodInstances and the +// current session's full MethodTable. In practice, such steps dominate package +// loading time (it has very little to do with I/O or deserialization +// performance). Paradoxically, sometimes storing more code in a package can +// lead to faster performance: references to things in the same .ji file can be +// precomputed, but external references have to be looked up. You can see this +// effect in the benchmarks for #43990, where storing external MethodInstances +// and CodeInstances (more code than was stored previously) actually decreased +// load times for many packages. + // Note that one should prioritize deserialization performance over serialization performance, // since deserialization may be performed much more often than serialization. +// Certain items are preprocessed during serialization to save work when they are +// later deserialized. // TODO: put WeakRefs on the weak_refs list during deserialization @@ -69,9 +124,11 @@ static jl_value_t *deser_symbols[256]; // (the order in the serializer stream). the low // bit is reserved for flagging certain entries and pos is // left shift by 1 -static htable_t backref_table; +static htable_t backref_table; // pos = backref_table[obj] static int backref_table_numel; -static arraylist_t backref_list; +static arraylist_t backref_list; // obj = backref_list[pos] + +// set of all CodeInstances yet to be (in)validated static htable_t new_code_instance_validate; // list of (jl_value_t **loc, size_t pos) entries @@ -83,16 +140,20 @@ static arraylist_t flagref_list; // like types, methods, and method instances static htable_t uniquing_table; -// list of (size_t pos, (void *f)(jl_value_t*)) entries -// for the serializer to mark values in need of rework by function f +// list of (size_t pos, itemkey) entries +// for the serializer to mark values in need of rework // during deserialization later +// This includes items that need rehashing (IdDict, TypeMapLevels) +// and modules. static arraylist_t reinit_list; -// list of stuff that is being serialized +// list of modules being serialized // This is not quite globally rooted, but we take care to only // ever assigned rooted values here. static jl_array_t *serializer_worklist JL_GLOBALLY_ROOTED; -// external MethodInstances we want to serialize +// The set of external MethodInstances we want to serialize +// (methods owned by other modules that were first inferred for a +// module currently being serialized) static htable_t external_mis; // Inference tracks newly-inferred MethodInstances during precompilation // and registers them by calling jl_set_newly_inferred @@ -100,7 +161,14 @@ static jl_array_t *newly_inferred JL_GLOBALLY_ROOTED; // New roots to add to Methods. These can't be added until after // recaching is complete, so we have to hold on to them separately -// Stored as method => (worklist_key, roots) +// Stored as method => (worklist_key, newroots) +// The worklist_key is the uuid of the module that triggered addition +// of `newroots`. This is needed because CodeInstances reference +// their roots by "index", and we use a bipartite index +// (module_uuid, integer_index) to make indexes "relocatable" +// (meaning that users can load modules in different orders and +// so the absolute integer index of a root is not reproducible). +// See the "root blocks" section of method.c for more detail. static htable_t queued_method_roots; // inverse of backedges graph (caller=>callees hash) diff --git a/src/gc.c b/src/gc.c index 3d120cf47cccd..c45ff8206ca67 100644 --- a/src/gc.c +++ b/src/gc.c @@ -375,6 +375,15 @@ static void jl_gc_run_finalizers_in_list(jl_task_t *ct, arraylist_t *list) ct->sticky = sticky; } +static uint64_t finalizer_rngState[4]; + +void jl_rng_split(uint64_t to[4], uint64_t from[4]); + +JL_DLLEXPORT void jl_gc_init_finalizer_rng_state(void) +{ + jl_rng_split(finalizer_rngState, jl_current_task->rngState); +} + static void run_finalizers(jl_task_t *ct) { // Racy fast path: @@ -396,9 +405,16 @@ static void run_finalizers(jl_task_t *ct) } jl_atomic_store_relaxed(&jl_gc_have_pending_finalizers, 0); arraylist_new(&to_finalize, 0); + + uint64_t save_rngState[4]; + memcpy(&save_rngState[0], &ct->rngState[0], sizeof(save_rngState)); + jl_rng_split(ct->rngState, finalizer_rngState); + // This releases the finalizers lock. jl_gc_run_finalizers_in_list(ct, &copied_list); arraylist_free(&copied_list); + + memcpy(&ct->rngState[0], &save_rngState[0], sizeof(save_rngState)); } JL_DLLEXPORT void jl_gc_run_pending_finalizers(jl_task_t *ct) diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 72d385329ce49..f0cc94d22ba68 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -199,7 +199,6 @@ XX(jl_generic_function_def) \ XX(jl_gensym) \ XX(jl_getallocationgranularity) \ - XX(jl_getch) \ XX(jl_getnameinfo) \ XX(jl_getpagesize) \ XX(jl_get_ARCH) \ @@ -462,6 +461,7 @@ XX(jl_take_buffer) \ XX(jl_task_get_next) \ XX(jl_task_stack_buffer) \ + XX(jl_termios_size) \ XX(jl_test_cpu_feature) \ XX(jl_threadid) \ XX(jl_threadpoolid) \ diff --git a/src/jl_uv.c b/src/jl_uv.c index ab13056b7601f..a2f7fc43a5fca 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -60,6 +60,7 @@ void JL_UV_LOCK(void) } else { jl_atomic_fetch_add_relaxed(&jl_uv_n_waiters, 1); + jl_fence(); // [^store_buffering_2] jl_wake_libuv(); JL_LOCK(&jl_uv_mutex); jl_atomic_fetch_add_relaxed(&jl_uv_n_waiters, -1); diff --git a/src/jltypes.c b/src/jltypes.c index 911edb3c32af1..91e6cbcf41a98 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -420,10 +420,8 @@ static int datatype_name_cmp(jl_value_t *a, jl_value_t *b) JL_NOTSAFEPOINT // sort singletons first, then DataTypes, then UnionAlls, // ties broken alphabetically including module name & type parameters -static int union_sort_cmp(const void *ap, const void *bp) JL_NOTSAFEPOINT +static int union_sort_cmp(jl_value_t *a, jl_value_t *b) JL_NOTSAFEPOINT { - jl_value_t *a = *(jl_value_t**)ap; - jl_value_t *b = *(jl_value_t**)bp; if (a == NULL) return b == NULL ? 0 : 1; if (b == NULL) @@ -458,16 +456,33 @@ static int union_sort_cmp(const void *ap, const void *bp) JL_NOTSAFEPOINT } } +static void isort_union(jl_value_t **a, size_t len) JL_NOTSAFEPOINT +{ + size_t i, j; + for (i = 1; i < len; i++) { + jl_value_t *x = a[i]; + for (j = i; j > 0; j--) { + jl_value_t *y = a[j - 1]; + if (!(union_sort_cmp(x, y) < 0)) + break; + a[j] = y; + } + a[j] = x; + } +} + JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) { - if (n == 0) return (jl_value_t*)jl_bottom_type; + if (n == 0) + return (jl_value_t*)jl_bottom_type; size_t i; - for(i=0; i < n; i++) { + for (i = 0; i < n; i++) { jl_value_t *pi = ts[i]; if (!(jl_is_type(pi) || jl_is_typevar(pi))) jl_type_error("Union", (jl_value_t*)jl_type_type, pi); } - if (n == 1) return ts[0]; + if (n == 1) + return ts[0]; size_t nt = count_union_components(ts, n); jl_value_t **temp; @@ -476,9 +491,9 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) flatten_type_union(ts, n, temp, &count); assert(count == nt); size_t j; - for(i=0; i < nt; i++) { - int has_free = temp[i]!=NULL && jl_has_free_typevars(temp[i]); - for(j=0; j < nt; j++) { + for (i = 0; i < nt; i++) { + int has_free = temp[i] != NULL && jl_has_free_typevars(temp[i]); + for (j = 0; j < nt; j++) { if (j != i && temp[i] && temp[j]) { if (temp[i] == jl_bottom_type || temp[j] == (jl_value_t*)jl_any_type || @@ -490,7 +505,7 @@ JL_DLLEXPORT jl_value_t *jl_type_union(jl_value_t **ts, size_t n) } } } - qsort(temp, nt, sizeof(jl_value_t*), union_sort_cmp); + isort_union(temp, nt); jl_value_t **ptu = &temp[nt]; *ptu = jl_bottom_type; int k; diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 4024d25c2e9ec..8af1bc8b80d23 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -562,6 +562,9 @@ ,(if (any kwarg? pargl) (gensy) UNUSED) (call (core kwftype) ,ftype)) ,kw ,@pargl ,@vararg) `(block + ;; propagate method metadata to keyword sorter + ,@(map propagate-method-meta (filter meta? prologue)) + ,@(filter argwide-nospecialize-meta? prologue) ,@(let ((lnns (filter linenum? prologue))) (if (pair? lnns) (list (car lnns)) diff --git a/src/julia.h b/src/julia.h index ada09fe61fadd..278837a93e683 100644 --- a/src/julia.h +++ b/src/julia.h @@ -234,19 +234,19 @@ typedef struct _jl_line_info_node_t { intptr_t inlined_at; } jl_line_info_node_t; -// the following mirrors `struct EffectsOverride` in `base/compiler/types.jl` +// the following mirrors `struct EffectsOverride` in `base/compiler/effects.jl` typedef union __jl_purity_overrides_t { struct { - uint8_t ipo_consistent : 1; - uint8_t ipo_effect_free : 1; - uint8_t ipo_nothrow : 1; - uint8_t ipo_terminates : 1; + uint8_t ipo_consistent : 1; + uint8_t ipo_effect_free : 1; + uint8_t ipo_nothrow : 1; + uint8_t ipo_terminates_globally : 1; // Weaker form of `terminates` that asserts // that any control flow syntactically in the method // is guaranteed to terminate, but does not make // assertions about any called functions. - uint8_t ipo_terminates_locally : 1; - uint8_t ipo_notaskstate : 1; + uint8_t ipo_terminates_locally : 1; + uint8_t ipo_notaskstate : 1; } overrides; uint8_t bits; } _jl_purity_overrides_t; @@ -397,25 +397,27 @@ typedef struct _jl_code_instance_t { // purity results #ifdef JL_USE_ANON_UNIONS_FOR_PURITY_FLAGS - // see also encode_effects() and decode_effects() in `base/compiler/types.jl`, + // see also encode_effects() and decode_effects() in `base/compiler/effects.jl`, union { uint32_t ipo_purity_bits; struct { - uint8_t ipo_consistent:2; - uint8_t ipo_effect_free:2; - uint8_t ipo_nothrow:2; - uint8_t ipo_terminates:2; - uint8_t ipo_nonoverlayed:1; + uint8_t ipo_consistent : 2; + uint8_t ipo_effect_free : 2; + uint8_t ipo_nothrow : 2; + uint8_t ipo_terminates : 2; + uint8_t ipo_nonoverlayed : 1; + uint8_t ipo_notaskstate : 2; } ipo_purity_flags; }; union { uint32_t purity_bits; struct { - uint8_t consistent:2; - uint8_t effect_free:2; - uint8_t nothrow:2; - uint8_t terminates:2; - uint8_t nonoverlayed:1; + uint8_t consistent : 2; + uint8_t effect_free : 2; + uint8_t nothrow : 2; + uint8_t terminates : 2; + uint8_t nonoverlayed : 1; + uint8_t notaskstate : 2; } purity_flags; }; #else @@ -2058,7 +2060,7 @@ extern JL_DLLEXPORT JL_STREAM *JL_STDERR; JL_DLLEXPORT JL_STREAM *jl_stdout_stream(void); JL_DLLEXPORT JL_STREAM *jl_stdin_stream(void); JL_DLLEXPORT JL_STREAM *jl_stderr_stream(void); -JL_DLLEXPORT int jl_getch(void); +JL_DLLEXPORT int jl_termios_size(void); // showing and std streams JL_DLLEXPORT void jl_flush_cstdio(void) JL_NOTSAFEPOINT; diff --git a/src/julia_threads.h b/src/julia_threads.h index 6f1c4e50d4e95..6cca406eaafef 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -362,7 +362,6 @@ int8_t jl_gc_safe_leave(jl_ptls_t ptls, int8_t state); // Can be a safepoint #define jl_gc_safe_enter(ptls) jl_gc_state_save_and_set(ptls, JL_GC_STATE_SAFE) #define jl_gc_safe_leave(ptls, state) ((void)jl_gc_state_set(ptls, (state), JL_GC_STATE_SAFE)) #endif -JL_DLLEXPORT void (jl_gc_safepoint)(void); JL_DLLEXPORT void jl_gc_enable_finalizers(struct _jl_task_t *ct, int on); JL_DLLEXPORT void jl_gc_disable_finalizers_internal(void); diff --git a/src/method.c b/src/method.c index 33abedcfdb62e..c684ffbe7b969 100644 --- a/src/method.c +++ b/src/method.c @@ -326,7 +326,7 @@ static void jl_code_info_set_ir(jl_code_info_t *li, jl_expr_t *ir) li->purity.overrides.ipo_consistent = jl_unbox_bool(jl_exprarg(ma, 0)); li->purity.overrides.ipo_effect_free = jl_unbox_bool(jl_exprarg(ma, 1)); li->purity.overrides.ipo_nothrow = jl_unbox_bool(jl_exprarg(ma, 2)); - li->purity.overrides.ipo_terminates = jl_unbox_bool(jl_exprarg(ma, 3)); + li->purity.overrides.ipo_terminates_globally = jl_unbox_bool(jl_exprarg(ma, 3)); li->purity.overrides.ipo_terminates_locally = jl_unbox_bool(jl_exprarg(ma, 4)); li->purity.overrides.ipo_notaskstate = jl_unbox_bool(jl_exprarg(ma, 5)); } @@ -1016,6 +1016,46 @@ JL_DLLEXPORT jl_method_t* jl_method_def(jl_svec_t *argdata, // root blocks +// This section handles method roots. Roots are GC-preserved items needed to +// represent lowered, type-inferred, and/or compiled code. These items are +// stored in a flat list (`m.roots`), and during serialization and +// deserialization of code we replace C-pointers to these items with a +// relocatable reference. We use a bipartite reference, `(key, index)` pair, +// where `key` identifies the module that added the root and `index` numbers +// just those roots with the same `key`. +// +// During precompilation (serialization), we save roots that were added to +// methods that are tagged with this package's module-key, even for "external" +// methods not owned by a module currently being precompiled. During +// deserialization, we load the new roots and append them to the method. When +// code is deserialized (see ircode.c), we replace the bipartite reference with +// the pointer to the memory address in the current session. The bipartite +// reference allows us to cache both roots and references in precompilation .ji +// files using a naming scheme that is independent of which packages are loaded +// in arbitrary order. +// +// To track the module-of-origin for each root, methods also have a +// `root_blocks` field that uses run-length encoding (RLE) storing `key` and the +// (absolute) integer index within `roots` at which a block of roots with that +// key begins. This makes it possible to look up an individual `(key, index)` +// pair fairly efficiently. A given `key` may possess more than one block; the +// `index` continues to increment regardless of block boundaries. +// +// Roots with `key = 0` are considered to be of unknown origin, and +// CodeInstances referencing such roots will remain unserializable unless all +// such roots were added at the time of system image creation. To track this +// additional data, we use two fields: +// +// - methods have an `nroots_sysimg` field to count the number of roots defined +// at the time of writing the system image (such occur first in the list of +// roots). These are the cases with `key = 0` that do not prevent +// serialization. +// - CodeInstances have a `relocatability` field which when 1 indicates that +// every root is "safe," meaning it was either added at sysimg creation or is +// tagged with a non-zero `key`. Even a single unsafe root will cause this to +// have value 0. + +// Get the key of the current (final) block of roots static uint64_t current_root_id(jl_array_t *root_blocks) { if (!root_blocks) @@ -1028,6 +1068,7 @@ static uint64_t current_root_id(jl_array_t *root_blocks) return blocks[nx2-2]; } +// Add a new block of `len` roots with key `modid` (module id) static void add_root_block(jl_array_t *root_blocks, uint64_t modid, size_t len) { assert(jl_is_array(root_blocks)); @@ -1038,6 +1079,7 @@ static void add_root_block(jl_array_t *root_blocks, uint64_t modid, size_t len) blocks[nx2-1] = len; } +// Allocate storage for roots static void prepare_method_for_roots(jl_method_t *m, uint64_t modid) { if (!m->roots) { @@ -1050,6 +1092,7 @@ static void prepare_method_for_roots(jl_method_t *m, uint64_t modid) } } +// Add a single root with owner `mod` to a method JL_DLLEXPORT void jl_add_method_root(jl_method_t *m, jl_module_t *mod, jl_value_t* root) { JL_GC_PUSH2(&m, &root); @@ -1066,6 +1109,7 @@ JL_DLLEXPORT void jl_add_method_root(jl_method_t *m, jl_module_t *mod, jl_value_ JL_GC_POP(); } +// Add a list of roots with key `modid` to a method void jl_append_method_roots(jl_method_t *m, uint64_t modid, jl_array_t* roots) { JL_GC_PUSH2(&m, &roots); @@ -1105,6 +1149,7 @@ jl_value_t *lookup_root(jl_method_t *m, uint64_t key, int index) return jl_array_ptr_ref(m->roots, i); } +// Count the number of roots added by module with id `key` int nroots_with_key(jl_method_t *m, uint64_t key) { size_t nroots = 0; diff --git a/src/partr.c b/src/partr.c index e511fb8727bfb..eeb0d0f456d97 100644 --- a/src/partr.c +++ b/src/partr.c @@ -38,7 +38,14 @@ static const int16_t sleeping = 1; // * Enqueuer: // * 2: `jl_atomic_load_relaxed(&ptls->sleep_check_state)` in `jl_wakeup_thread` returns `not_sleeping` // i.e., the dequeuer misses the enqueue and enqueuer misses the sleep state transition. - +// [^store_buffering_2]: and also +// * Enqueuer: +// * 1a: `jl_atomic_store_relaxed(jl_uv_n_waiters, 1)` in `JL_UV_LOCK` +// * 1b: "cheap read" of `handle->pending` in `uv_async_send` (via `JL_UV_LOCK`) loads `0` +// * Dequeuer: +// * 2a: store `2` to `handle->pending` in `uv_async_send` (via `JL_UV_LOCK` in `jl_task_get_next`) +// * 2b: `jl_atomic_load_relaxed(jl_uv_n_waiters)` in `jl_task_get_next` returns `0` +// i.e., the dequeuer misses the `n_waiters` is set and enqueuer misses the `uv_stop` flag (in `signal_async`) transition to cleared JULIA_DEBUG_SLEEPWAKE( uint64_t wakeup_enter; @@ -276,7 +283,7 @@ static int may_sleep(jl_ptls_t ptls) JL_NOTSAFEPOINT // by the thread itself. As a result, if this returns false, it will // continue returning false. If it returns true, we know the total // modification order of the fences. - jl_fence(); // [^store_buffering_1] + jl_fence(); // [^store_buffering_1] [^store_buffering_2] return jl_atomic_load_relaxed(&ptls->sleep_check_state) == sleeping; } diff --git a/src/signal-handling.c b/src/signal-handling.c index fda1c9947c1b5..e941d0fd9548b 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -411,7 +411,7 @@ void jl_critical_error(int sig, bt_context_t *context, jl_task_t *ct) sigaddset(&sset, sig); pthread_sigmask(SIG_UNBLOCK, &sset, NULL); #endif - jl_safe_printf("\nsignal (%d): %s\n", sig, strsignal(sig)); + jl_safe_printf("\n[%d] signal (%d): %s\n", getpid(), sig, strsignal(sig)); } jl_safe_printf("in expression starting at %s:%d\n", jl_filename, jl_lineno); if (context && ct) { diff --git a/src/sys.c b/src/sys.c index 2f512888c1873..2de4bc61a20b8 100644 --- a/src/sys.c +++ b/src/sys.c @@ -517,28 +517,11 @@ JL_DLLEXPORT JL_STREAM *jl_stdin_stream(void) { return JL_STDIN; } JL_DLLEXPORT JL_STREAM *jl_stdout_stream(void) { return JL_STDOUT; } JL_DLLEXPORT JL_STREAM *jl_stderr_stream(void) { return JL_STDERR; } -// terminal workarounds -JL_DLLEXPORT int jl_getch(void) JL_NOTSAFEPOINT -{ +JL_DLLEXPORT int jl_termios_size(void) { #if defined(_OS_WINDOWS_) - // Windows has an actual `_getch()`, use that: - return _getch(); + return 0; #else - // On all other platforms, we do the POSIX terminal manipulation dance - char c; - int r; - struct termios old_termios = {0}; - struct termios new_termios = {0}; - if (tcgetattr(0, &old_termios) != 0) - return -1; - new_termios = old_termios; - cfmakeraw(&new_termios); - if (tcsetattr(0, TCSADRAIN, &new_termios) != 0) - return -1; - r = read(0, &c, 1); - if (tcsetattr(0, TCSADRAIN, &old_termios) != 0) - return -1; - return r == 1 ? c : -1; + return sizeof(struct termios); #endif } diff --git a/src/task.c b/src/task.c index c12cb5a522099..22a5ad214e0b8 100644 --- a/src/task.c +++ b/src/task.c @@ -729,7 +729,7 @@ uint64_t jl_genrandom(uint64_t rngState[4]) JL_NOTSAFEPOINT return res; } -static void rng_split(jl_task_t *from, jl_task_t *to) JL_NOTSAFEPOINT +void jl_rng_split(uint64_t to[4], uint64_t from[4]) JL_NOTSAFEPOINT { /* TODO: consider a less ad-hoc construction Ideally we could just use the output of the random stream to seed the initial @@ -747,10 +747,10 @@ static void rng_split(jl_task_t *from, jl_task_t *to) JL_NOTSAFEPOINT 0x3688cf5d48899fa7 == hash(UInt(3))|0x01 0x867b4bb4c42e5661 == hash(UInt(4))|0x01 */ - to->rngState[0] = 0x02011ce34bce797f * jl_genrandom(from->rngState); - to->rngState[1] = 0x5a94851fb48a6e05 * jl_genrandom(from->rngState); - to->rngState[2] = 0x3688cf5d48899fa7 * jl_genrandom(from->rngState); - to->rngState[3] = 0x867b4bb4c42e5661 * jl_genrandom(from->rngState); + to[0] = 0x02011ce34bce797f * jl_genrandom(from); + to[1] = 0x5a94851fb48a6e05 * jl_genrandom(from); + to[2] = 0x3688cf5d48899fa7 * jl_genrandom(from); + to[3] = 0x867b4bb4c42e5661 * jl_genrandom(from); } JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion_future, size_t ssize) @@ -790,7 +790,7 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion // Inherit logger state from parent task t->logstate = ct->logstate; // Fork task-local random state from parent - rng_split(ct, t); + jl_rng_split(t->rngState, ct->rngState); // there is no active exception handler available on this stack yet t->eh = NULL; t->sticky = 1; diff --git a/stdlib/Artifacts/src/Artifacts.jl b/stdlib/Artifacts/src/Artifacts.jl index cdd8ca2fb2da5..926a662a7399c 100644 --- a/stdlib/Artifacts/src/Artifacts.jl +++ b/stdlib/Artifacts/src/Artifacts.jl @@ -711,7 +711,7 @@ end with_artifacts_directory(f::Function, artifacts_dir::AbstractString) = with_artifacts_directory(f, String(artifacts_dir)::String) query_override(pkg::Base.UUID, artifact_name::AbstractString; overrides::Dict=load_overrides()) = - query_override(pkg, String(artifact_name)::String; overrides=convert(Dict{Symbol, Any}(overrides))) + query_override(pkg, String(artifact_name)::String; overrides=convert(Dict{Symbol, Any}, overrides)) unpack_platform(entry::Dict, name::AbstractString, artifacts_toml::AbstractString) = unpack_platform(convert(Dict{String, Any}, entry), String(name)::String, String(artifacts_toml)::String) load_artifacts_toml(artifacts_toml::AbstractString; kwargs...) = diff --git a/stdlib/Dates/src/Dates.jl b/stdlib/Dates/src/Dates.jl index 6164216cbd1af..a111ea24089c4 100644 --- a/stdlib/Dates/src/Dates.jl +++ b/stdlib/Dates/src/Dates.jl @@ -14,13 +14,13 @@ For time zone functionality, see the TimeZones.jl package. julia> dt = DateTime(2017,12,31,23,59,59,999) 2017-12-31T23:59:59.999 -julia> d1 = Date(Dates.Month(12), Dates.Year(2017)) +julia> d1 = Date(Month(12), Year(2017)) 2017-12-01 -julia> d2 = Date("2017-12-31", Dates.DateFormat("y-m-d")) +julia> d2 = Date("2017-12-31", DateFormat("y-m-d")) 2017-12-31 -julia> Dates.yearmonthday(d2) +julia> yearmonthday(d2) (2017, 12, 31) julia> d2-d1 diff --git a/stdlib/Dates/src/accessors.jl b/stdlib/Dates/src/accessors.jl index 10e0142c83f21..05e9017303ef1 100644 --- a/stdlib/Dates/src/accessors.jl +++ b/stdlib/Dates/src/accessors.jl @@ -97,13 +97,13 @@ week of 2004. # Examples ```jldoctest -julia> Dates.week(Date(1989, 6, 22)) +julia> week(Date(1989, 6, 22)) 25 -julia> Dates.week(Date(2005, 1, 1)) +julia> week(Date(2005, 1, 1)) 53 -julia> Dates.week(Date(2004, 12, 31)) +julia> week(Date(2004, 12, 31)) 53 ``` """ diff --git a/stdlib/Dates/src/adjusters.jl b/stdlib/Dates/src/adjusters.jl index d5617ba8cf93c..245e2678a9d77 100644 --- a/stdlib/Dates/src/adjusters.jl +++ b/stdlib/Dates/src/adjusters.jl @@ -29,7 +29,7 @@ Truncates the value of `dt` according to the provided `Period` type. # Examples ```jldoctest -julia> trunc(Dates.DateTime("1996-01-01T12:30:00"), Dates.Day) +julia> trunc(DateTime("1996-01-01T12:30:00"), Day) 1996-01-01T00:00:00 ``` """ @@ -43,7 +43,7 @@ Adjusts `dt` to the Monday of its week. # Examples ```jldoctest -julia> Dates.firstdayofweek(DateTime("1996-01-05T12:30:00")) +julia> firstdayofweek(DateTime("1996-01-05T12:30:00")) 1996-01-01T00:00:00 ``` """ @@ -59,7 +59,7 @@ Adjusts `dt` to the Sunday of its week. # Examples ```jldoctest -julia> Dates.lastdayofweek(DateTime("1996-01-05T12:30:00")) +julia> lastdayofweek(DateTime("1996-01-05T12:30:00")) 1996-01-07T00:00:00 ``` """ @@ -75,7 +75,7 @@ Adjusts `dt` to the first day of its month. # Examples ```jldoctest -julia> Dates.firstdayofmonth(DateTime("1996-05-20")) +julia> firstdayofmonth(DateTime("1996-05-20")) 1996-05-01T00:00:00 ``` """ @@ -91,7 +91,7 @@ Adjusts `dt` to the last day of its month. # Examples ```jldoctest -julia> Dates.lastdayofmonth(DateTime("1996-05-20")) +julia> lastdayofmonth(DateTime("1996-05-20")) 1996-05-31T00:00:00 ``` """ @@ -110,7 +110,7 @@ Adjusts `dt` to the first day of its year. # Examples ```jldoctest -julia> Dates.firstdayofyear(DateTime("1996-05-20")) +julia> firstdayofyear(DateTime("1996-05-20")) 1996-01-01T00:00:00 ``` """ @@ -126,7 +126,7 @@ Adjusts `dt` to the last day of its year. # Examples ```jldoctest -julia> Dates.lastdayofyear(DateTime("1996-05-20")) +julia> lastdayofyear(DateTime("1996-05-20")) 1996-12-31T00:00:00 ``` """ @@ -145,10 +145,10 @@ Adjusts `dt` to the first day of its quarter. # Examples ```jldoctest -julia> Dates.firstdayofquarter(DateTime("1996-05-20")) +julia> firstdayofquarter(DateTime("1996-05-20")) 1996-04-01T00:00:00 -julia> Dates.firstdayofquarter(DateTime("1996-08-20")) +julia> firstdayofquarter(DateTime("1996-08-20")) 1996-07-01T00:00:00 ``` """ @@ -168,10 +168,10 @@ Adjusts `dt` to the last day of its quarter. # Examples ```jldoctest -julia> Dates.lastdayofquarter(DateTime("1996-05-20")) +julia> lastdayofquarter(DateTime("1996-05-20")) 1996-06-30T00:00:00 -julia> Dates.lastdayofquarter(DateTime("1996-08-20")) +julia> lastdayofquarter(DateTime("1996-08-20")) 1996-09-30T00:00:00 ``` """ @@ -221,13 +221,13 @@ pursue before throwing an error (given that `f::Function` is never satisfied). # Examples ```jldoctest -julia> Date(date -> Dates.week(date) == 20, 2010, 01, 01) +julia> Date(date -> week(date) == 20, 2010, 01, 01) 2010-05-17 -julia> Date(date -> Dates.year(date) == 2010, 2000, 01, 01) +julia> Date(date -> year(date) == 2010, 2000, 01, 01) 2010-01-01 -julia> Date(date -> Dates.month(date) == 10, 2000, 01, 01; limit = 5) +julia> Date(date -> month(date) == 10, 2000, 01, 01; limit = 5) ERROR: ArgumentError: Adjustment limit reached: 5 iterations Stacktrace: [...] @@ -248,10 +248,10 @@ pursue before throwing an error (in the case that `f::Function` is never satisfi # Examples ```jldoctest -julia> DateTime(dt -> Dates.second(dt) == 40, 2010, 10, 20, 10; step = Dates.Second(1)) +julia> DateTime(dt -> second(dt) == 40, 2010, 10, 20, 10; step = Second(1)) 2010-10-20T10:00:40 -julia> DateTime(dt -> Dates.hour(dt) == 20, 2010, 10, 20, 10; step = Dates.Hour(1), limit = 5) +julia> DateTime(dt -> hour(dt) == 20, 2010, 10, 20, 10; step = Hour(1), limit = 5) ERROR: ArgumentError: Adjustment limit reached: 5 iterations Stacktrace: [...] @@ -291,13 +291,13 @@ arguments are provided, the default step will be `Millisecond(1)` instead of `Se # Examples ```jldoctest -julia> Dates.Time(t -> Dates.minute(t) == 30, 20) +julia> Time(t -> minute(t) == 30, 20) 20:30:00 -julia> Dates.Time(t -> Dates.minute(t) == 0, 20) +julia> Time(t -> minute(t) == 0, 20) 20:00:00 -julia> Dates.Time(t -> Dates.hour(t) == 10, 3; limit = 5) +julia> Time(t -> hour(t) == 10, 3; limit = 5) ERROR: ArgumentError: Adjustment limit reached: 5 iterations Stacktrace: [...] diff --git a/stdlib/Dates/src/io.jl b/stdlib/Dates/src/io.jl index 7e007ced0bbee..65d6f4a88735f 100644 --- a/stdlib/Dates/src/io.jl +++ b/stdlib/Dates/src/io.jl @@ -414,8 +414,6 @@ function DateFormat(f::AbstractString, locale::DateLocale=ENGLISH) if !isempty(prev) letter, width = prev - typ = CONVERSION_SPECIFIERS[letter] - push!(tokens, DatePart{letter}(width, isempty(tran))) end @@ -434,8 +432,6 @@ function DateFormat(f::AbstractString, locale::DateLocale=ENGLISH) if !isempty(prev) letter, width = prev - typ = CONVERSION_SPECIFIERS[letter] - push!(tokens, DatePart{letter}(width, false)) end diff --git a/stdlib/Dates/src/periods.jl b/stdlib/Dates/src/periods.jl index 021e91924ce59..441ba0c46c5b6 100644 --- a/stdlib/Dates/src/periods.jl +++ b/stdlib/Dates/src/periods.jl @@ -160,7 +160,7 @@ coarserperiod(::Type{Month}) = (Year, 12) CompoundPeriod A `CompoundPeriod` is useful for expressing time periods that are not a fixed multiple of -smaller periods. For example, \"a year and a day\" is not a fixed number of days, but can +smaller periods. For example, "a year and a day" is not a fixed number of days, but can be expressed using a `CompoundPeriod`. In fact, a `CompoundPeriod` is automatically generated by addition of different period types, e.g. `Year(1) + Day(1)` produces a `CompoundPeriod` result. @@ -250,16 +250,16 @@ Reduces the `CompoundPeriod` into its canonical form by applying the following r # Examples ```jldoctest -julia> Dates.canonicalize(Dates.CompoundPeriod(Dates.Hour(12), Dates.Hour(13))) +julia> canonicalize(Dates.CompoundPeriod(Dates.Hour(12), Dates.Hour(13))) 1 day, 1 hour -julia> Dates.canonicalize(Dates.CompoundPeriod(Dates.Hour(-1), Dates.Minute(1))) +julia> canonicalize(Dates.CompoundPeriod(Dates.Hour(-1), Dates.Minute(1))) -59 minutes -julia> Dates.canonicalize(Dates.CompoundPeriod(Dates.Month(1), Dates.Week(-2))) +julia> canonicalize(Dates.CompoundPeriod(Dates.Month(1), Dates.Week(-2))) 1 month, -2 weeks -julia> Dates.canonicalize(Dates.CompoundPeriod(Dates.Minute(50000))) +julia> canonicalize(Dates.CompoundPeriod(Dates.Minute(50000))) 4 weeks, 6 days, 17 hours, 20 minutes ``` """ @@ -482,7 +482,7 @@ const zero_or_fixedperiod_seed = UInt === UInt64 ? 0x5b7fc751bba97516 : 0xeae0fd const nonzero_otherperiod_seed = UInt === UInt64 ? 0xe1837356ff2d2ac9 : 0x170d1b00 otherperiod_seed(x::OtherPeriod) = iszero(value(x)) ? zero_or_fixedperiod_seed : nonzero_otherperiod_seed # tons() will overflow for periods longer than ~300,000 years, implying a hash collision -# which is relatively harmless given how infrequent such periods should appear +# which is relatively harmless given how infrequently such periods should appear Base.hash(x::FixedPeriod, h::UInt) = hash(tons(x), h + zero_or_fixedperiod_seed) # Overflow can also happen here for really long periods (~8e17 years) Base.hash(x::Year, h::UInt) = hash(12 * value(x), h + otherperiod_seed(x)) @@ -511,11 +511,7 @@ toms(c::Millisecond) = value(c) toms(c::Second) = 1000 * value(c) toms(c::Minute) = 60000 * value(c) toms(c::Hour) = 3600000 * value(c) -toms(c::Day) = 86400000 * value(c) -toms(c::Week) = 604800000 * value(c) -toms(c::Month) = 86400000.0 * 30.436875 * value(c) -toms(c::Quarter) = 86400000.0 * 91.310625 * value(c) -toms(c::Year) = 86400000.0 * 365.2425 * value(c) +toms(c::Period) = 86400000 * days(c) toms(c::CompoundPeriod) = isempty(c.periods) ? 0.0 : Float64(sum(toms, c.periods)) tons(x) = toms(x) * 1000000 tons(x::Microsecond) = value(x) * 1000 diff --git a/stdlib/Dates/src/query.jl b/stdlib/Dates/src/query.jl index c204f750f5de2..4f3b5a5c4b095 100644 --- a/stdlib/Dates/src/query.jl +++ b/stdlib/Dates/src/query.jl @@ -93,10 +93,10 @@ Return 366 if the year of `dt` is a leap year, otherwise return 365. # Examples ```jldoctest -julia> Dates.daysinyear(1999) +julia> daysinyear(1999) 365 -julia> Dates.daysinyear(2000) +julia> daysinyear(2000) 366 ``` """ @@ -114,7 +114,7 @@ Return the day of the week as an [`Int64`](@ref) with `1 = Monday, 2 = Tuesday, # Examples ```jldoctest -julia> Dates.dayofweek(Date("2000-01-01")) +julia> dayofweek(Date("2000-01-01")) 6 ``` """ @@ -159,10 +159,10 @@ the given `locale`. Also accepts `Integer`. # Examples ```jldoctest -julia> Dates.dayname(Date("2000-01-01")) +julia> dayname(Date("2000-01-01")) "Saturday" -julia> Dates.dayname(4) +julia> dayname(4) "Thursday" ``` """ @@ -179,10 +179,10 @@ in the given `locale`. Also accepts `Integer`. # Examples ```jldoctest -julia> Dates.dayabbr(Date("2000-01-01")) +julia> dayabbr(Date("2000-01-01")) "Sat" -julia> Dates.dayabbr(3) +julia> dayabbr(3) "Wed" ``` """ @@ -209,13 +209,13 @@ month, etc.` In the range 1:5. # Examples ```jldoctest -julia> Dates.dayofweekofmonth(Date("2000-02-01")) +julia> dayofweekofmonth(Date("2000-02-01")) 1 -julia> Dates.dayofweekofmonth(Date("2000-02-08")) +julia> dayofweekofmonth(Date("2000-02-08")) 2 -julia> Dates.dayofweekofmonth(Date("2000-02-15")) +julia> dayofweekofmonth(Date("2000-02-15")) 3 ``` """ @@ -240,10 +240,10 @@ function. # Examples ```jldoctest -julia> Dates.daysofweekinmonth(Date("2005-01-01")) +julia> daysofweekinmonth(Date("2005-01-01")) 5 -julia> Dates.daysofweekinmonth(Date("2005-01-04")) +julia> daysofweekinmonth(Date("2005-01-04")) 4 ``` """ @@ -569,10 +569,10 @@ Return the full name of the month of the `Date` or `DateTime` or `Integer` in th # Examples ```jldoctest -julia> Dates.monthname(Date("2005-01-04")) +julia> monthname(Date("2005-01-04")) "January" -julia> Dates.monthname(2) +julia> monthname(2) "February" ``` """ @@ -588,7 +588,7 @@ Return the abbreviated month name of the `Date` or `DateTime` or `Integer` in th # Examples ```jldoctest -julia> Dates.monthabbr(Date("2005-01-04")) +julia> monthabbr(Date("2005-01-04")) "Jan" julia> monthabbr(2) @@ -606,13 +606,13 @@ Return the number of days in the month of `dt`. Value will be 28, 29, 30, or 31. # Examples ```jldoctest -julia> Dates.daysinmonth(Date("2000-01")) +julia> daysinmonth(Date("2000-01")) 31 -julia> Dates.daysinmonth(Date("2001-02")) +julia> daysinmonth(Date("2001-02")) 28 -julia> Dates.daysinmonth(Date("2000-02")) +julia> daysinmonth(Date("2000-02")) 29 ``` """ @@ -626,10 +626,10 @@ Return `true` if the year of `dt` is a leap year. # Examples ```jldoctest -julia> Dates.isleapyear(Date("2004")) +julia> isleapyear(Date("2004")) true -julia> Dates.isleapyear(Date("2005")) +julia> isleapyear(Date("2005")) false ``` """ diff --git a/stdlib/Dates/src/rounding.jl b/stdlib/Dates/src/rounding.jl index 53e680a6bfd1b..b5b6e52decba8 100644 --- a/stdlib/Dates/src/rounding.jl +++ b/stdlib/Dates/src/rounding.jl @@ -94,13 +94,13 @@ For convenience, `precision` may be a type instead of a value: `floor(x, Dates.H shortcut for `floor(x, Dates.Hour(1))`. ```jldoctest -julia> floor(Dates.Day(16), Dates.Week) +julia> floor(Day(16), Week) 2 weeks -julia> floor(Dates.Minute(44), Dates.Minute(15)) +julia> floor(Minute(44), Minute(15)) 30 minutes -julia> floor(Dates.Hour(36), Dates.Day) +julia> floor(Hour(36), Day) 1 day ``` @@ -122,13 +122,13 @@ For convenience, `p` may be a type instead of a value: `floor(dt, Dates.Hour)` i for `floor(dt, Dates.Hour(1))`. ```jldoctest -julia> floor(Date(1985, 8, 16), Dates.Month) +julia> floor(Date(1985, 8, 16), Month) 1985-08-01 -julia> floor(DateTime(2013, 2, 13, 0, 31, 20), Dates.Minute(15)) +julia> floor(DateTime(2013, 2, 13, 0, 31, 20), Minute(15)) 2013-02-13T00:30:00 -julia> floor(DateTime(2016, 8, 6, 12, 0, 0), Dates.Day) +julia> floor(DateTime(2016, 8, 6, 12, 0, 0), Day) 2016-08-06T00:00:00 ``` """ @@ -143,13 +143,13 @@ For convenience, `p` may be a type instead of a value: `ceil(dt, Dates.Hour)` is for `ceil(dt, Dates.Hour(1))`. ```jldoctest -julia> ceil(Date(1985, 8, 16), Dates.Month) +julia> ceil(Date(1985, 8, 16), Month) 1985-09-01 -julia> ceil(DateTime(2013, 2, 13, 0, 31, 20), Dates.Minute(15)) +julia> ceil(DateTime(2013, 2, 13, 0, 31, 20), Minute(15)) 2013-02-13T00:45:00 -julia> ceil(DateTime(2016, 8, 6, 12, 0, 0), Dates.Day) +julia> ceil(DateTime(2016, 8, 6, 12, 0, 0), Day) 2016-08-07T00:00:00 ``` """ @@ -168,13 +168,13 @@ For convenience, `precision` may be a type instead of a value: `ceil(x, Dates.Ho shortcut for `ceil(x, Dates.Hour(1))`. ```jldoctest -julia> ceil(Dates.Day(16), Dates.Week) +julia> ceil(Day(16), Week) 3 weeks -julia> ceil(Dates.Minute(44), Dates.Minute(15)) +julia> ceil(Minute(44), Minute(15)) 45 minutes -julia> ceil(Dates.Hour(36), Dates.Day) +julia> ceil(Hour(36), Day) 2 days ``` @@ -218,13 +218,13 @@ For convenience, `p` may be a type instead of a value: `round(dt, Dates.Hour)` i for `round(dt, Dates.Hour(1))`. ```jldoctest -julia> round(Date(1985, 8, 16), Dates.Month) +julia> round(Date(1985, 8, 16), Month) 1985-08-01 -julia> round(DateTime(2013, 2, 13, 0, 31, 20), Dates.Minute(15)) +julia> round(DateTime(2013, 2, 13, 0, 31, 20), Minute(15)) 2013-02-13T00:30:00 -julia> round(DateTime(2016, 8, 6, 12, 0, 0), Dates.Day) +julia> round(DateTime(2016, 8, 6, 12, 0, 0), Day) 2016-08-07T00:00:00 ``` @@ -248,13 +248,13 @@ For convenience, `precision` may be a type instead of a value: `round(x, Dates.H shortcut for `round(x, Dates.Hour(1))`. ```jldoctest -julia> round(Dates.Day(16), Dates.Week) +julia> round(Day(16), Week) 2 weeks -julia> round(Dates.Minute(44), Dates.Minute(15)) +julia> round(Minute(44), Minute(15)) 45 minutes -julia> round(Dates.Hour(36), Dates.Day) +julia> round(Hour(36), Day) 2 days ``` diff --git a/stdlib/DelimitedFiles.version b/stdlib/DelimitedFiles.version index 972918a83b75e..220a1482822e0 100644 --- a/stdlib/DelimitedFiles.version +++ b/stdlib/DelimitedFiles.version @@ -1,4 +1,4 @@ DELIMITEDFILES_BRANCH = main -DELIMITEDFILES_SHA1 = f520e069d2eb8282e8a07dcb384fe0e0c6293bc3 +DELIMITEDFILES_SHA1 = 495ebc81ef7fe2c083ca4c1d7e43a22cc1e49490 DELIMITEDFILES_GIT_URL := https://github.com/JuliaData/DelimitedFiles.jl.git DELIMITEDFILES_TAR_URL = https://api.github.com/repos/JuliaData/DelimitedFiles.jl/tarball/$1 diff --git a/stdlib/Distributed/src/managers.jl b/stdlib/Distributed/src/managers.jl index 7b048807eddae..8dd833197c951 100644 --- a/stdlib/Distributed/src/managers.jl +++ b/stdlib/Distributed/src/managers.jl @@ -281,7 +281,7 @@ function launch_on_machine(manager::SSHManager, machine::AbstractString, cnt, pa end # Julia process with passed in command line flag arguments - if shell == :posix + if shell === :posix # ssh connects to a POSIX shell cmds = "exec $(shell_escape_posixly(exename)) $(shell_escape_posixly(exeflags))" @@ -297,7 +297,7 @@ function launch_on_machine(manager::SSHManager, machine::AbstractString, cnt, pa # shell login (-l) with string command (-c) to launch julia process remotecmd = shell_escape_posixly(`sh -l -c $cmds`) - elseif shell == :csh + elseif shell === :csh # ssh connects to (t)csh remotecmd = "exec $(shell_escape_csh(exename)) $(shell_escape_csh(exeflags))" @@ -313,7 +313,7 @@ function launch_on_machine(manager::SSHManager, machine::AbstractString, cnt, pa remotecmd = "cd $(shell_escape_csh(dir))\n$remotecmd" end - elseif shell == :wincmd + elseif shell === :wincmd # ssh connects to Windows cmd.exe any(c -> c == '"', exename) && throw(ArgumentError("invalid exename")) diff --git a/stdlib/Distributed/test/distributed_exec.jl b/stdlib/Distributed/test/distributed_exec.jl index 0be94b28e5da5..8ed55550e61b9 100644 --- a/stdlib/Distributed/test/distributed_exec.jl +++ b/stdlib/Distributed/test/distributed_exec.jl @@ -126,7 +126,7 @@ function testf(id) @test_throws ErrorException put!(f, :OK) # Cannot put! to a already set future @test_throws MethodError take!(f) # take! is unsupported on a Future - @test fetch(f) == :OK + @test fetch(f) === :OK end testf(id_me) @@ -218,7 +218,7 @@ isready(f) @test remotecall_fetch(k->haskey(Distributed.PGRP.refs, k), wid1, fid) == true put!(f, :OK) @test remotecall_fetch(k->haskey(Distributed.PGRP.refs, k), wid1, fid) == false -@test fetch(f) == :OK +@test fetch(f) === :OK # RemoteException should be thrown on a put! when another process has set the value f = Future(wid1) @@ -270,7 +270,7 @@ function test_remoteref_dgc(id) # remote value should be deleted after finalizing the ref @test remotecall_fetch(k->(yield();haskey(Distributed.PGRP.refs, k)), id, rrid) == true - @test fetch(rr) == :OK + @test fetch(rr) === :OK @test remotecall_fetch(k->(yield();haskey(Distributed.PGRP.refs, k)), id, rrid) == true finalize(rr) yield(); # flush gc msgs @@ -349,7 +349,7 @@ function test_regular_io_ser(ref::Distributed.AbstractRemoteRef) v = getfield(ref2, fld) if isa(v, Number) @test v === zero(typeof(v)) - elseif fld == :lock + elseif fld === :lock @test v isa ReentrantLock @test !islocked(v) elseif v !== nothing @@ -528,7 +528,7 @@ let ex bt = ex.captured.processed_bt::Array{Any,1} @test length(bt) > 1 frame, repeated = bt[1]::Tuple{Base.StackTraces.StackFrame, Int} - @test frame.func == :foo + @test frame.func === :foo @test frame.linfo === nothing @test repeated == 1 end @@ -815,11 +815,11 @@ function f13168(n) return val end let t = schedule(@task f13168(100)) - @test t.state == :runnable + @test t.state === :runnable @test t.queue !== nothing @test_throws ErrorException schedule(t) yield() - @test t.state == :done + @test t.state === :done @test t.queue === nothing @test_throws ErrorException schedule(t) @test isa(fetch(t), Float64) @@ -900,7 +900,7 @@ end take!(rc)[1] != float(i) && error("Failed") end return :OK - end, id_other, rc_unbuffered) == :OK + end, id_other, rc_unbuffered) === :OK # github issue 33972 rc_unbuffered_other = RemoteChannel(()->Channel{Int}(0), id_other) @@ -997,7 +997,7 @@ let @test_throws RemoteException remotecall_fetch(bad_thunk, 2) # Test that the stream is still usable - @test remotecall_fetch(()->:test,2) == :test + @test remotecall_fetch(()->:test,2) === :test ref = remotecall(bad_thunk, 2) @test_throws RemoteException fetch(ref) end @@ -1175,11 +1175,11 @@ function launch(manager::ErrorSimulator, params::Dict, launched::Array, c::Condi dir = params[:dir] cmd = `$(Base.julia_cmd(exename)) --startup-file=no` - if manager.mode == :timeout + if manager.mode === :timeout cmd = `$cmd -e "sleep(10)"` - elseif manager.mode == :ntries + elseif manager.mode === :ntries cmd = `$cmd -e "[println(x) for x in 1:1001]"` - elseif manager.mode == :exit + elseif manager.mode === :exit cmd = `$cmd -e "exit(-1)"` else error("Unknown mode") diff --git a/stdlib/Distributed/test/topology.jl b/stdlib/Distributed/test/topology.jl index 2a659931ed306..fc969323bc587 100644 --- a/stdlib/Distributed/test/topology.jl +++ b/stdlib/Distributed/test/topology.jl @@ -62,9 +62,9 @@ end const map_pid_ident=Dict() function manage(manager::TopoTestManager, id::Integer, config::WorkerConfig, op::Symbol) - if op == :register + if op === :register map_pid_ident[id] = config.ident - elseif op == :interrupt + elseif op === :interrupt kill(config.process, 2) end end diff --git a/stdlib/Downloads.version b/stdlib/Downloads.version index 4072369c387da..2f6b454423fae 100644 --- a/stdlib/Downloads.version +++ b/stdlib/Downloads.version @@ -1,4 +1,4 @@ DOWNLOADS_BRANCH = master -DOWNLOADS_SHA1 = 78255d4927312181542b29ec6f063b0d5880189e +DOWNLOADS_SHA1 = c34ec3e5b231b231a37c83a9737feca481a47e4b DOWNLOADS_GIT_URL := https://github.com/JuliaLang/Downloads.jl.git DOWNLOADS_TAR_URL = https://api.github.com/repos/JuliaLang/Downloads.jl/tarball/$1 diff --git a/stdlib/FileWatching/test/pidfile.jl b/stdlib/FileWatching/test/pidfile.jl index febc082518edf..fae745131bca3 100644 --- a/stdlib/FileWatching/test/pidfile.jl +++ b/stdlib/FileWatching/test/pidfile.jl @@ -272,7 +272,9 @@ end # Just for coverage's sake, run a test with do-block syntax lock_times = Float64[] + synchronizer = Base.Event() t_loop = @async begin + wait(synchronizer) for idx in 1:100 t = @elapsed mkpidlock("do_block_pidfile") do # nothing @@ -283,6 +285,7 @@ end end isdefined(Base, :errormonitor) && Base.errormonitor(t_loop) mkpidlock("do_block_pidfile") do + notify(synchronizer) sleep(3) end wait(t_loop) diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index ad295345fabfd..4621ed07ed124 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -60,11 +60,11 @@ function varinfo(m::Module=Base.active_module(), pattern::Regex=r""; all::Bool = end end end - let (col, rev) = if sortby == :name + let (col, rev) = if sortby === :name 1, false - elseif sortby == :size + elseif sortby === :size 4, true - elseif sortby == :summary + elseif sortby === :summary 3, false else @assert "unreachable" diff --git a/stdlib/InteractiveUtils/src/clipboard.jl b/stdlib/InteractiveUtils/src/clipboard.jl index 7bc718b91b2bd..ee4548315c6ce 100644 --- a/stdlib/InteractiveUtils/src/clipboard.jl +++ b/stdlib/InteractiveUtils/src/clipboard.jl @@ -51,7 +51,7 @@ elseif Sys.islinux() || Sys.KERNEL === :FreeBSD _clipboardcmd !== nothing && return _clipboardcmd for cmd in (:xclip, :xsel, :wlclipboard) # wl-clipboard ships wl-copy/paste individually - c = cmd == :wlclipboard ? Symbol("wl-copy") : cmd + c = cmd === :wlclipboard ? Symbol("wl-copy") : cmd success(pipeline(`which $c`, devnull)) && return _clipboardcmd = cmd end pkgs = @static if Sys.KERNEL === :FreeBSD @@ -83,14 +83,14 @@ elseif Sys.iswindows() x_u16 = Base.cwstring(x) pdata = Ptr{UInt16}(C_NULL) function cleanup(cause) - errno = cause == :success ? UInt32(0) : Libc.GetLastError() + errno = cause === :success ? UInt32(0) : Libc.GetLastError() if cause !== :OpenClipboard if cause !== :success && pdata != C_NULL ccall((:GlobalFree, "kernel32"), stdcall, Cint, (Ptr{UInt16},), pdata) end ccall((:CloseClipboard, "user32"), stdcall, Cint, ()) == 0 && Base.windowserror(:CloseClipboard) # this should never fail end - cause == :success || Base.windowserror(cause, errno) + cause === :success || Base.windowserror(cause, errno) nothing end ccall((:OpenClipboard, "user32"), stdcall, Cint, (Ptr{Cvoid},), C_NULL) == 0 && return Base.windowserror(:OpenClipboard) @@ -110,7 +110,7 @@ elseif Sys.iswindows() clipboard(x) = clipboard(sprint(print, x)::String) function clipboard() function cleanup(cause) - errno = cause == :success ? UInt32(0) : Libc.GetLastError() + errno = cause === :success ? UInt32(0) : Libc.GetLastError() if cause !== :OpenClipboard ccall((:CloseClipboard, "user32"), stdcall, Cint, ()) == 0 && Base.windowserror(:CloseClipboard) # this should never fail end diff --git a/stdlib/InteractiveUtils/src/codeview.jl b/stdlib/InteractiveUtils/src/codeview.jl index 8e66c881e415c..8f72bcd37885c 100644 --- a/stdlib/InteractiveUtils/src/codeview.jl +++ b/stdlib/InteractiveUtils/src/codeview.jl @@ -32,7 +32,7 @@ function warntype_type_printer(io::IO, @nospecialize(ty), used::Bool) str = "::$ty" if !highlighting[:warntype] print(io, str) - elseif ty isa Union && Base.is_expected_union(ty) + elseif ty isa Union && is_expected_union(ty) Base.emphasize(io, str, Base.warn_color()) # more mild user notification elseif ty isa Type && (!Base.isdispatchelem(ty) || ty == Core.Box) Base.emphasize(io, str) @@ -42,6 +42,18 @@ function warntype_type_printer(io::IO, @nospecialize(ty), used::Bool) nothing end +# True if one can be pretty certain that the compiler handles this union well, +# i.e. must be small with concrete types. +function is_expected_union(u::Union) + Base.unionlen(u) < 4 || return false + for x in Base.uniontypes(u) + if !Base.isdispatchelem(x) || x == Core.Box + return false + end + end + return true +end + """ code_warntype([io::IO], f, types; debuginfo=:default) diff --git a/stdlib/InteractiveUtils/src/macros.jl b/stdlib/InteractiveUtils/src/macros.jl index b0005e6d7d783..4a2740cb37163 100644 --- a/stdlib/InteractiveUtils/src/macros.jl +++ b/stdlib/InteractiveUtils/src/macros.jl @@ -44,7 +44,7 @@ function gen_call_with_extracted_types(__module__, fcn, ex0, kws=Expr[]) end if ex0.head === :. || (ex0.head === :call && ex0.args[1] !== :.. && string(ex0.args[1])[1] == '.') codemacro = startswith(string(fcn), "code_") - if codemacro && ex0.args[2] isa Expr + if codemacro && (ex0.head === :call || ex0.args[2] isa Expr) # Manually wrap a dot call in a function args = Any[] ex, i = recursive_dotcalls!(copy(ex0), args) diff --git a/stdlib/InteractiveUtils/test/runtests.jl b/stdlib/InteractiveUtils/test/runtests.jl index 50236e7c8cfc5..4d7fad2b387cc 100644 --- a/stdlib/InteractiveUtils/test/runtests.jl +++ b/stdlib/InteractiveUtils/test/runtests.jl @@ -51,6 +51,23 @@ tag = "UNION" @test warntype_hastag(pos_unstable, Tuple{Float64}, tag) @test !warntype_hastag(pos_stable, Tuple{Float64}, tag) +for u in Any[ + Union{Int, UInt}, + Union{Nothing, Vector{Tuple{String, Tuple{Char, Char}}}}, + Union{Char, UInt8, UInt}, + Union{Tuple{Int, Int}, Tuple{Char, Int}, Nothing}, + Union{Missing, Nothing} +] + @test InteractiveUtils.is_expected_union(u) +end + +for u in Any[ + Union{Nothing, Tuple{Vararg{Char}}}, + Union{Missing, Array}, + Union{Int, Tuple{Any, Int}} +] + @test !InteractiveUtils.is_expected_union(u) +end mutable struct Stable{T,N} A::Array{T,N} end @@ -245,7 +262,7 @@ const curmod_str = curmod === Main ? "Main" : join(curmod_name, ".") @test_throws ErrorException("\"this_is_not_defined\" is not defined in module $curmod_str") @which this_is_not_defined # issue #13264 -@test (@which vcat(1...)).name == :vcat +@test (@which vcat(1...)).name === :vcat # PR #28122, issue #25474 @test (@which [1][1]).name === :getindex @@ -373,7 +390,7 @@ struct A14637 x end a14637 = A14637(0) -@test (@which a14637.x).name == :getproperty +@test (@which a14637.x).name === :getproperty @test (@functionloc a14637.x)[2] isa Integer # Issue #28615 @@ -383,6 +400,13 @@ a14637 = A14637(0) @test (@code_typed max.(Ref(true).x))[2] == Bool @test !isempty(@code_typed optimize=false max.(Ref.([5, 6])...)) +# Issue # 45889 +@test !isempty(@code_typed 3 .+ 6) +@test !isempty(@code_typed 3 .+ 6 .+ 7) +@test !isempty(@code_typed optimize=false (.- [3,4])) +@test !isempty(@code_typed optimize=false (6 .- [3,4])) +@test !isempty(@code_typed optimize=false (.- 0.5)) + # Issue #36261 @test (@code_typed max.(1 .+ 3, 5 - 7))[2] == Int f36261(x,y) = 3x + 4y @@ -608,7 +632,7 @@ end export B41010 ms = methodswith(A41010, @__MODULE__) |> collect - @test ms[1].name == :B41010 + @test ms[1].name === :B41010 end # macro options should accept both literals and variables diff --git a/stdlib/LibCURL_jll/Project.toml b/stdlib/LibCURL_jll/Project.toml index 3719fcbf37bef..45dbb45830837 100644 --- a/stdlib/LibCURL_jll/Project.toml +++ b/stdlib/LibCURL_jll/Project.toml @@ -1,6 +1,6 @@ name = "LibCURL_jll" uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "7.83.1+1" +version = "7.84.0+0" [deps] LibSSH2_jll = "29816b5a-b9ab-546f-933c-edad1886dfa8" diff --git a/stdlib/LibGit2/src/LibGit2.jl b/stdlib/LibGit2/src/LibGit2.jl index ece246864e51f..c699e120584ae 100644 --- a/stdlib/LibGit2/src/LibGit2.jl +++ b/stdlib/LibGit2/src/LibGit2.jl @@ -87,7 +87,7 @@ is in the repository. # Examples ```julia-repl -julia> repo = LibGit2.GitRepo(repo_path); +julia> repo = GitRepo(repo_path); julia> LibGit2.add!(repo, test_file); @@ -230,7 +230,7 @@ Return `true` if `a`, a [`GitHash`](@ref) in string form, is an ancestor of # Examples ```julia-repl -julia> repo = LibGit2.GitRepo(repo_path); +julia> repo = GitRepo(repo_path); julia> LibGit2.add!(repo, test_file1); diff --git a/stdlib/LibGit2/src/reference.jl b/stdlib/LibGit2/src/reference.jl index 345c546946ee5..c05b09ddfc518 100644 --- a/stdlib/LibGit2/src/reference.jl +++ b/stdlib/LibGit2/src/reference.jl @@ -53,7 +53,7 @@ Return a shortened version of the name of `ref` that's "human-readable". ```julia-repl -julia> repo = LibGit2.GitRepo(path_to_repo); +julia> repo = GitRepo(path_to_repo); julia> branch_ref = LibGit2.head(repo); diff --git a/stdlib/LibGit2/test/libgit2.jl b/stdlib/LibGit2/test/libgit2.jl index af140fe97f6d1..2c15be9da41af 100644 --- a/stdlib/LibGit2/test/libgit2.jl +++ b/stdlib/LibGit2/test/libgit2.jl @@ -98,8 +98,8 @@ function challenge_prompt(cmd::Cmd, challenges; timeout::Integer=60, debug::Bool status = fetch(timer) close(ptm) - if status != :success - if status == :timeout + if status !== :success + if status === :timeout error("Process timed out possibly waiting for a response. ", format_output(out)) else @@ -3121,7 +3121,7 @@ mktempdir() do dir catch end - loopback = ip"127.0.0.1" + loopbacks = (ip"127.0.0.1", ip"::1") for hostname in hostnames local addr try @@ -3130,7 +3130,7 @@ mktempdir() do dir continue end - if addr == loopback + if addr ∈ loopbacks common_name = hostname break end @@ -3186,9 +3186,9 @@ mktempdir() do dir err = open(errfile, "r") do f deserialize(f) end - @test err.code == LibGit2.Error.ECERTIFICATE + @test err.code == LibGit2.Error.ERROR @test startswith(lowercase(err.msg), - lowercase("The SSL certificate is invalid")) + lowercase("user rejected certificate for localhost")) rm(errfile) diff --git a/stdlib/LinearAlgebra/docs/src/index.md b/stdlib/LinearAlgebra/docs/src/index.md index 88e700685a0d3..f86ebcd8806cb 100644 --- a/stdlib/LinearAlgebra/docs/src/index.md +++ b/stdlib/LinearAlgebra/docs/src/index.md @@ -492,7 +492,8 @@ linear algebra routines it is useful to call the BLAS functions directly. `LinearAlgebra.BLAS` provides wrappers for some of the BLAS functions. Those BLAS functions that overwrite one of the input arrays have names ending in `'!'`. Usually, a BLAS function has -four methods defined, for [`Float64`](@ref), [`Float32`](@ref), `ComplexF64`, and `ComplexF32` arrays. +four methods defined, for [`Float32`](@ref), [`Float64`](@ref), [`ComplexF32`](@ref Complex), +and [`ComplexF64`](@ref Complex) arrays. ### [BLAS character arguments](@id stdlib-blas-chars) Many BLAS functions accept arguments that determine whether to transpose an argument (`trans`), @@ -528,6 +529,7 @@ the input argument belongs on (`side`). The possibilities are: ```@docs LinearAlgebra.BLAS +LinearAlgebra.BLAS.rot! LinearAlgebra.BLAS.dot LinearAlgebra.BLAS.dotu LinearAlgebra.BLAS.dotc @@ -541,6 +543,7 @@ LinearAlgebra.BLAS.scal LinearAlgebra.BLAS.iamax LinearAlgebra.BLAS.ger! LinearAlgebra.BLAS.syr! +LinearAlgebra.BLAS.spr! LinearAlgebra.BLAS.syrk! LinearAlgebra.BLAS.syrk LinearAlgebra.BLAS.syr2k! @@ -567,12 +570,14 @@ LinearAlgebra.BLAS.symm(::Any, ::Any, ::Any, ::Any) LinearAlgebra.BLAS.symv! LinearAlgebra.BLAS.symv(::Any, ::Any, ::Any, ::Any) LinearAlgebra.BLAS.symv(::Any, ::Any, ::Any) +LinearAlgebra.BLAS.spmv! LinearAlgebra.BLAS.hemm! LinearAlgebra.BLAS.hemm(::Any, ::Any, ::Any, ::Any, ::Any) LinearAlgebra.BLAS.hemm(::Any, ::Any, ::Any, ::Any) LinearAlgebra.BLAS.hemv! LinearAlgebra.BLAS.hemv(::Any, ::Any, ::Any, ::Any) LinearAlgebra.BLAS.hemv(::Any, ::Any, ::Any) +LinearAlgebra.BLAS.hpmv! LinearAlgebra.BLAS.trmm! LinearAlgebra.BLAS.trmm LinearAlgebra.BLAS.trsm! diff --git a/stdlib/LinearAlgebra/src/blas.jl b/stdlib/LinearAlgebra/src/blas.jl index 2710559e57d6b..d6fc2d0e1fd1f 100644 --- a/stdlib/LinearAlgebra/src/blas.jl +++ b/stdlib/LinearAlgebra/src/blas.jl @@ -147,18 +147,19 @@ end # Level 1 # A help function to pick the pointer and inc for 1d like inputs. @inline function vec_pointer_stride(x::AbstractArray, stride0check = nothing) - isdense(x) && return pointer(x), 1 # simpify runtime check when possibe - ndims(x) == 1 || strides(x) == Base.size_to_strides(stride(x, 1), size(x)...) || - throw(ArgumentError("only support vector like inputs")) - st = stride(x, 1) + Base._checkcontiguous(Bool, x) && return pointer(x), 1 # simpify runtime check when possibe + st, ptr = checkedstride(x), pointer(x) isnothing(stride0check) || (st == 0 && throw(stride0check)) - ptr = st > 0 ? pointer(x) : pointer(x, lastindex(x)) + ptr += min(st, 0) * sizeof(eltype(x)) * (length(x) - 1) ptr, st end -isdense(x) = x isa DenseArray -isdense(x::Base.FastContiguousSubArray) = isdense(parent(x)) -isdense(x::Base.ReshapedArray) = isdense(parent(x)) -isdense(x::Base.ReinterpretArray) = isdense(parent(x)) +function checkedstride(x::AbstractArray) + szs::Dims = size(x) + sts::Dims = strides(x) + _, st, n = Base.merge_adjacent_dim(szs, sts) + n === ndims(x) && return st + throw(ArgumentError("only support vector like inputs")) +end ## copy """ @@ -968,6 +969,9 @@ The scalar inputs `α` and `β` must be complex or real numbers. The array inputs `x`, `y` and `AP` must all be of `ComplexF32` or `ComplexF64` type. Return the updated `y`. + +!!! compat "Julia 1.5" + `hpmv!` requires at least Julia 1.5. """ hpmv! @@ -1125,6 +1129,9 @@ The scalar inputs `α` and `β` must be real. The array inputs `x`, `y` and `AP` must all be of `Float32` or `Float64` type. Return the updated `y`. + +!!! compat "Julia 1.5" + `spmv!` requires at least Julia 1.5. """ spmv! @@ -1193,6 +1200,9 @@ The scalar input `α` must be real. The array inputs `x` and `AP` must all be of `Float32` or `Float64` type. Return the updated `AP`. + +!!! compat "Julia 1.8" + `spr!` requires at least Julia 1.8. """ spr! @@ -1539,11 +1549,27 @@ for (mfname, elty) in ((:dsymm_,:Float64), require_one_based_indexing(A, B, C) m, n = size(C) j = checksquare(A) - if j != (side == 'L' ? m : n) - throw(DimensionMismatch(lazy"A has size $(size(A)), C has size ($m,$n)")) - end - if size(B,2) != n - throw(DimensionMismatch(lazy"B has second dimension $(size(B,2)) but needs to match second dimension of C, $n")) + M, N = size(B) + if side == 'L' + if j != m + throw(DimensionMismatch(lazy"A has first dimension $j but needs to match first dimension of C, $m")) + end + if N != n + throw(DimensionMismatch(lazy"B has second dimension $N but needs to match second dimension of C, $n")) + end + if j != M + throw(DimensionMismatch(lazy"A has second dimension $j but needs to match first dimension of B, $M")) + end + else + if j != n + throw(DimensionMismatch(lazy"B has second dimension $j but needs to match second dimension of C, $n")) + end + if N != j + throw(DimensionMismatch(lazy"A has second dimension $N but needs to match first dimension of B, $j")) + end + if M != m + throw(DimensionMismatch(lazy"A has first dimension $M but needs to match first dimension of C, $m")) + end end chkstride1(A) chkstride1(B) @@ -1613,11 +1639,27 @@ for (mfname, elty) in ((:zhemm_,:ComplexF64), require_one_based_indexing(A, B, C) m, n = size(C) j = checksquare(A) - if j != (side == 'L' ? m : n) - throw(DimensionMismatch(lazy"A has size $(size(A)), C has size ($m,$n)")) - end - if size(B,2) != n - throw(DimensionMismatch(lazy"B has second dimension $(size(B,2)) but needs to match second dimension of C, $n")) + M, N = size(B) + if side == 'L' + if j != m + throw(DimensionMismatch(lazy"A has first dimension $j but needs to match first dimension of C, $m")) + end + if N != n + throw(DimensionMismatch(lazy"B has second dimension $N but needs to match second dimension of C, $n")) + end + if j != M + throw(DimensionMismatch(lazy"A has second dimension $j but needs to match first dimension of B, $M")) + end + else + if j != n + throw(DimensionMismatch(lazy"B has second dimension $j but needs to match second dimension of C, $n")) + end + if N != j + throw(DimensionMismatch(lazy"A has second dimension $N but needs to match first dimension of B, $j")) + end + if M != m + throw(DimensionMismatch(lazy"A has first dimension $M but needs to match first dimension of C, $m")) + end end chkstride1(A) chkstride1(B) diff --git a/stdlib/LinearAlgebra/src/bunchkaufman.jl b/stdlib/LinearAlgebra/src/bunchkaufman.jl index 7961f97e58299..e0502b6f6dcfd 100644 --- a/stdlib/LinearAlgebra/src/bunchkaufman.jl +++ b/stdlib/LinearAlgebra/src/bunchkaufman.jl @@ -81,7 +81,7 @@ BunchKaufman(A::AbstractMatrix{T}, ipiv::AbstractVector{<:Integer}, uplo::Abstra BunchKaufman{T,typeof(A),typeof(ipiv)}(A, ipiv, uplo, symmetric, rook, info) # backwards-compatible constructors (remove with Julia 2.0) @deprecate(BunchKaufman(LD, ipiv, uplo, symmetric, rook, info) where {T,S}, - BunchKaufman{T,S,typeof(ipiv)}(LD, ipiv, uplo, symmetric, rook, info)) + BunchKaufman{T,S,typeof(ipiv)}(LD, ipiv, uplo, symmetric, rook, info), false) # iteration for destructuring into components Base.iterate(S::BunchKaufman) = (S.D, Val(:UL)) diff --git a/stdlib/LinearAlgebra/src/cholesky.jl b/stdlib/LinearAlgebra/src/cholesky.jl index d11630fcb6a5f..917c32625adb5 100644 --- a/stdlib/LinearAlgebra/src/cholesky.jl +++ b/stdlib/LinearAlgebra/src/cholesky.jl @@ -168,7 +168,7 @@ CholeskyPivoted(A::AbstractMatrix{T}, uplo::AbstractChar, piv::AbstractVector{<: CholeskyPivoted{T,typeof(A),typeof(piv)}(A, uplo, piv, rank, tol, info) # backwards-compatible constructors (remove with Julia 2.0) @deprecate(CholeskyPivoted{T,S}(factors, uplo, piv, rank, tol, info) where {T,S<:AbstractMatrix}, - CholeskyPivoted{T,S,typeof(piv)}(factors, uplo, piv, rank, tol, info)) + CholeskyPivoted{T,S,typeof(piv)}(factors, uplo, piv, rank, tol, info), false) # iteration for destructuring into components diff --git a/stdlib/LinearAlgebra/src/factorization.jl b/stdlib/LinearAlgebra/src/factorization.jl index 83ec4e1187d40..82c593f9bd7c4 100644 --- a/stdlib/LinearAlgebra/src/factorization.jl +++ b/stdlib/LinearAlgebra/src/factorization.jl @@ -32,12 +32,12 @@ Test that a factorization of a matrix succeeded. ```jldoctest julia> F = cholesky([1 0; 0 1]); -julia> LinearAlgebra.issuccess(F) +julia> issuccess(F) true julia> F = lu([1 0; 0 0]; check = false); -julia> LinearAlgebra.issuccess(F) +julia> issuccess(F) false ``` """ diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index cd438f142a793..4ff2035c85f55 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -5455,7 +5455,7 @@ for (bdsdc, elty) in elseif compq == 'P' @warn "COMPQ='P' is not tested" #TODO turn this into an actual LAPACK call - #smlsiz=ilaenv(9, $elty==:Float64 ? 'dbdsqr' : 'sbdsqr', string(uplo, compq), n,n,n,n) + #smlsiz=ilaenv(9, $elty === :Float64 ? 'dbdsqr' : 'sbdsqr', string(uplo, compq), n,n,n,n) smlsiz=100 #For now, completely overkill ldq = n*(11+2*smlsiz+8*round(Int,log((n/(smlsiz+1)))/log(2))) ldiq = n*(3+3*round(Int,log(n/(smlsiz+1))/log(2))) diff --git a/stdlib/LinearAlgebra/src/lbt.jl b/stdlib/LinearAlgebra/src/lbt.jl index 7648157a01a7d..f8fbd7f526ccb 100644 --- a/stdlib/LinearAlgebra/src/lbt.jl +++ b/stdlib/LinearAlgebra/src/lbt.jl @@ -159,9 +159,9 @@ function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, lbt::LBTConfig) println(io, "Libraries: ") for (i,l) in enumerate(lbt.loaded_libs) char = i == length(lbt.loaded_libs) ? "└" : "├" - interface_str = if l.interface == :ilp64 + interface_str = if l.interface === :ilp64 "ILP64" - elseif l.interface == :lp64 + elseif l.interface === :lp64 " LP64" else "UNKWN" diff --git a/stdlib/LinearAlgebra/src/lq.jl b/stdlib/LinearAlgebra/src/lq.jl index 80933cf3c6f46..52d4f944f682f 100644 --- a/stdlib/LinearAlgebra/src/lq.jl +++ b/stdlib/LinearAlgebra/src/lq.jl @@ -58,7 +58,7 @@ LQ{T}(factors::AbstractMatrix, τ::AbstractVector) where {T} = LQ(convert(AbstractMatrix{T}, factors), convert(AbstractVector{T}, τ)) # backwards-compatible constructors (remove with Julia 2.0) @deprecate(LQ{T,S}(factors::AbstractMatrix{T}, τ::AbstractVector{T}) where {T,S}, - LQ{T,S,typeof(τ)}(factors, τ)) + LQ{T,S,typeof(τ)}(factors, τ), false) # iteration for destructuring into components Base.iterate(S::LQ) = (S.L, Val(:Q)) diff --git a/stdlib/LinearAlgebra/src/lu.jl b/stdlib/LinearAlgebra/src/lu.jl index 1948f5d18001f..ce7a21b8196b4 100644 --- a/stdlib/LinearAlgebra/src/lu.jl +++ b/stdlib/LinearAlgebra/src/lu.jl @@ -64,7 +64,7 @@ LU{T}(factors::AbstractMatrix, ipiv::AbstractVector{<:Integer}, info::Integer) w # backwards-compatible constructors (remove with Julia 2.0) @deprecate(LU{T,S}(factors::AbstractMatrix{T}, ipiv::AbstractVector{<:Integer}, info::BlasInt) where {T,S}, - LU{T,S,typeof(ipiv)}(factors, ipiv, info)) + LU{T,S,typeof(ipiv)}(factors, ipiv, info), false) # iteration for destructuring into components Base.iterate(S::LU) = (S.L, Val(:U)) diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 7646aae29d1b9..81eb9e3d3012a 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -315,9 +315,9 @@ see [`QR`](@ref). ```jldoctest julia> A = [0 1; 1 0]; -julia> B = LinearAlgebra.UpperTriangular([1 2; 0 3]); +julia> B = UpperTriangular([1 2; 0 3]); -julia> LinearAlgebra.rmul!(A, B); +julia> rmul!(A, B); julia> A 2×2 Matrix{Int64}: @@ -348,9 +348,9 @@ see [`QR`](@ref). ```jldoctest julia> B = [0 1; 1 0]; -julia> A = LinearAlgebra.UpperTriangular([1 2; 0 3]); +julia> A = UpperTriangular([1 2; 0 3]); -julia> LinearAlgebra.lmul!(A, B); +julia> lmul!(A, B); julia> B 2×2 Matrix{Int64}: diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index 61e3b092b2a38..d562adf935770 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -49,7 +49,7 @@ QR{T}(factors::AbstractMatrix, τ::AbstractVector) where {T} = QR(convert(AbstractMatrix{T}, factors), convert(AbstractVector{T}, τ)) # backwards-compatible constructors (remove with Julia 2.0) @deprecate(QR{T,S}(factors::AbstractMatrix{T}, τ::AbstractVector{T}) where {T,S}, - QR{T,S,typeof(τ)}(factors, τ)) + QR{T,S,typeof(τ)}(factors, τ), false) # iteration for destructuring into components Base.iterate(S::QR) = (S.Q, Val(:R)) @@ -126,7 +126,7 @@ QRCompactWY{S}(factors::AbstractMatrix, T::AbstractMatrix) where {S} = QRCompactWY(convert(AbstractMatrix{S}, factors), convert(AbstractMatrix{S}, T)) # backwards-compatible constructors (remove with Julia 2.0) @deprecate(QRCompactWY{S,M}(factors::AbstractMatrix{S}, T::AbstractMatrix{S}) where {S,M}, - QRCompactWY{S,M,typeof(T)}(factors, T)) + QRCompactWY{S,M,typeof(T)}(factors, T), false) # iteration for destructuring into components Base.iterate(S::QRCompactWY) = (S.Q, Val(:R)) @@ -219,7 +219,7 @@ QRPivoted{T}(factors::AbstractMatrix, τ::AbstractVector, # backwards-compatible constructors (remove with Julia 2.0) @deprecate(QRPivoted{T,S}(factors::AbstractMatrix{T}, τ::AbstractVector{T}, jpvt::AbstractVector{<:Integer}) where {T,S}, - QRPivoted{T,S,typeof(τ),typeof(jpvt)}(factors, τ, jpvt)) + QRPivoted{T,S,typeof(τ),typeof(jpvt)}(factors, τ, jpvt), false) # iteration for destructuring into components Base.iterate(S::QRPivoted) = (S.Q, Val(:R)) @@ -314,9 +314,9 @@ julia> a = [1. 2.; 3. 4.] 3.0 4.0 julia> qr!(a) -QRCompactWY{Float64, Matrix{Float64}, Matrix{Float64}} +LinearAlgebra.QRCompactWY{Float64, Matrix{Float64}, Matrix{Float64}} Q factor: -2×2 QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}}: +2×2 LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}}: -0.316228 -0.948683 -0.948683 0.316228 R factor: @@ -401,9 +401,9 @@ julia> A = [3.0 -6.0; 4.0 -8.0; 0.0 1.0] 0.0 1.0 julia> F = qr(A) -QRCompactWY{Float64, Matrix{Float64}, Matrix{Float64}} +LinearAlgebra.QRCompactWY{Float64, Matrix{Float64}, Matrix{Float64}} Q factor: -3×3 QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}}: +3×3 LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}, Matrix{Float64}}: -0.6 0.0 0.8 -0.8 0.0 -0.6 0.0 -1.0 0.0 @@ -541,7 +541,7 @@ QRPackedQ{T}(factors::AbstractMatrix, τ::AbstractVector) where {T} = QRPackedQ(convert(AbstractMatrix{T}, factors), convert(AbstractVector{T}, τ)) # backwards-compatible constructors (remove with Julia 2.0) @deprecate(QRPackedQ{T,S}(factors::AbstractMatrix{T}, τ::AbstractVector{T}) where {T,S}, - QRPackedQ{T,S,typeof(τ)}(factors, τ)) + QRPackedQ{T,S,typeof(τ)}(factors, τ), false) """ QRCompactWYQ <: AbstractMatrix @@ -564,7 +564,7 @@ QRCompactWYQ{S}(factors::AbstractMatrix, T::AbstractMatrix) where {S} = QRCompactWYQ(convert(AbstractMatrix{S}, factors), convert(AbstractMatrix{S}, T)) # backwards-compatible constructors (remove with Julia 2.0) @deprecate(QRCompactWYQ{S,M}(factors::AbstractMatrix{S}, T::AbstractMatrix{S}) where {S,M}, - QRCompactWYQ{S,M,typeof(T)}(factors, T)) + QRCompactWYQ{S,M,typeof(T)}(factors, T), false) QRPackedQ{T}(Q::QRPackedQ) where {T} = QRPackedQ(convert(AbstractMatrix{T}, Q.factors), convert(Vector{T}, Q.τ)) AbstractMatrix{T}(Q::QRPackedQ{T}) where {T} = Q diff --git a/stdlib/LinearAlgebra/src/special.jl b/stdlib/LinearAlgebra/src/special.jl index 098df785e557a..0f707a1b523bd 100644 --- a/stdlib/LinearAlgebra/src/special.jl +++ b/stdlib/LinearAlgebra/src/special.jl @@ -82,7 +82,7 @@ convert(T::Type{<:UpperTriangular}, m::PossibleTriangularMatrix) = m isa T ? m : # f(x::S, y::T) where {S,T} = x+y # f(y::T, x::S) where {S,T} = f(x, y) macro commutative(myexpr) - @assert myexpr.head===:(=) || myexpr.head===:function # Make sure it is a function definition + @assert Base.is_function_def(myexpr) # Make sure it is a function definition y = copy(myexpr.args[1].args[2:end]) reverse!(y) reversed_call = Expr(:(=), Expr(:call,myexpr.args[1].args[1],y...), myexpr.args[1]) diff --git a/stdlib/LinearAlgebra/test/bidiag.jl b/stdlib/LinearAlgebra/test/bidiag.jl index adaae98250ee4..ba2dd4274851a 100644 --- a/stdlib/LinearAlgebra/test/bidiag.jl +++ b/stdlib/LinearAlgebra/test/bidiag.jl @@ -126,12 +126,12 @@ Random.seed!(1) @testset "Constructor and basic properties" begin @test size(T, 1) == size(T, 2) == n @test size(T) == (n, n) - @test Array(T) == diagm(0 => dv, (uplo == :U ? 1 : -1) => ev) + @test Array(T) == diagm(0 => dv, (uplo === :U ? 1 : -1) => ev) @test Bidiagonal(Array(T), uplo) == T @test big.(T) == T - @test Array(abs.(T)) == abs.(diagm(0 => dv, (uplo == :U ? 1 : -1) => ev)) - @test Array(real(T)) == real(diagm(0 => dv, (uplo == :U ? 1 : -1) => ev)) - @test Array(imag(T)) == imag(diagm(0 => dv, (uplo == :U ? 1 : -1) => ev)) + @test Array(abs.(T)) == abs.(diagm(0 => dv, (uplo === :U ? 1 : -1) => ev)) + @test Array(real(T)) == real(diagm(0 => dv, (uplo === :U ? 1 : -1) => ev)) + @test Array(imag(T)) == imag(diagm(0 => dv, (uplo === :U ? 1 : -1) => ev)) end @testset for func in (conj, transpose, adjoint) @@ -356,7 +356,7 @@ Random.seed!(1) @testset "diag" begin @test (@inferred diag(T))::typeof(dv) == dv - @test (@inferred diag(T, uplo == :U ? 1 : -1))::typeof(dv) == ev + @test (@inferred diag(T, uplo === :U ? 1 : -1))::typeof(dv) == ev @test (@inferred diag(T,2))::typeof(dv) == zeros(elty, n-2) @test_throws ArgumentError diag(T, -n - 1) @test_throws ArgumentError diag(T, n + 1) @@ -364,7 +364,7 @@ Random.seed!(1) gdv, gev = GenericArray(dv), GenericArray(ev) G = Bidiagonal(gdv, gev, uplo) @test (@inferred diag(G))::typeof(gdv) == gdv - @test (@inferred diag(G, uplo == :U ? 1 : -1))::typeof(gdv) == gev + @test (@inferred diag(G, uplo === :U ? 1 : -1))::typeof(gdv) == gev @test (@inferred diag(G,2))::typeof(gdv) == GenericArray(zeros(elty, n-2)) end @@ -372,9 +372,9 @@ Random.seed!(1) if relty <: AbstractFloat d1, v1 = eigen(T) d2, v2 = eigen(map(elty<:Complex ? ComplexF64 : Float64,Tfull), sortby=nothing) - @test (uplo == :U ? d1 : reverse(d1)) ≈ d2 + @test (uplo === :U ? d1 : reverse(d1)) ≈ d2 if elty <: Real - test_approx_eq_modphase(v1, uplo == :U ? v2 : v2[:,n:-1:1]) + test_approx_eq_modphase(v1, uplo === :U ? v2 : v2[:,n:-1:1]) end end end diff --git a/stdlib/LinearAlgebra/test/blas.jl b/stdlib/LinearAlgebra/test/blas.jl index 0a2ac87c8026d..76cf166fdc10d 100644 --- a/stdlib/LinearAlgebra/test/blas.jl +++ b/stdlib/LinearAlgebra/test/blas.jl @@ -11,16 +11,21 @@ fabs(x::Complex) = abs(real(x)) + abs(imag(x)) function pack(A, uplo) AP = eltype(A)[] n = size(A, 1) - for j in 1:n, i in (uplo==:L ? (j:n) : (1:j)) + for j in 1:n, i in (uplo === :L ? (j:n) : (1:j)) push!(AP, A[i,j]) end return AP end @testset "vec_pointer_stride" begin - a = zeros(4,4,4) - @test BLAS.asum(view(a,1:2:4,:,:)) == 0 # vector like + a = float(rand(1:20,4,4,4)) + @test BLAS.asum(a) == sum(a) # dense case + @test BLAS.asum(view(a,1:2:4,:,:)) == sum(view(a,1:2:4,:,:)) # vector like + @test BLAS.asum(view(a,1:3,2:2,3:3)) == sum(view(a,1:3,2:2,3:3)) + @test BLAS.asum(view(a,1:1,1:3,1:1)) == sum(view(a,1:1,1:3,1:1)) + @test BLAS.asum(view(a,1:1,1:1,1:3)) == sum(view(a,1:1,1:1,1:3)) @test_throws ArgumentError BLAS.asum(view(a,1:3:4,:,:)) # non-vector like + @test_throws ArgumentError BLAS.asum(view(a,1:2,1:1,1:3)) end Random.seed!(100) ## BLAS tests - testing the interface code to BLAS routines @@ -222,11 +227,19 @@ Random.seed!(100) @test_throws DimensionMismatch BLAS.symm('R','U',Cmn,Cnn) @test_throws DimensionMismatch BLAS.symm!('L','U',one(elty),Asymm,Cnn,one(elty),Cmn) @test_throws DimensionMismatch BLAS.symm!('L','U',one(elty),Asymm,Cnn,one(elty),Cnm) + @test_throws DimensionMismatch BLAS.symm!('L','U',one(elty),Asymm,Cmn,one(elty),Cnn) + @test_throws DimensionMismatch BLAS.symm!('R','U',one(elty),Asymm,Cnm,one(elty),Cmn) + @test_throws DimensionMismatch BLAS.symm!('R','U',one(elty),Asymm,Cnn,one(elty),Cnm) + @test_throws DimensionMismatch BLAS.symm!('R','U',one(elty),Asymm,Cmn,one(elty),Cnn) if elty <: BlasComplex @test_throws DimensionMismatch BLAS.hemm('L','U',Cnm,Cnn) @test_throws DimensionMismatch BLAS.hemm('R','U',Cmn,Cnn) @test_throws DimensionMismatch BLAS.hemm!('L','U',one(elty),Aherm,Cnn,one(elty),Cmn) @test_throws DimensionMismatch BLAS.hemm!('L','U',one(elty),Aherm,Cnn,one(elty),Cnm) + @test_throws DimensionMismatch BLAS.hemm!('L','U',one(elty),Aherm,Cmn,one(elty),Cnn) + @test_throws DimensionMismatch BLAS.hemm!('R','U',one(elty),Aherm,Cnm,one(elty),Cmn) + @test_throws DimensionMismatch BLAS.hemm!('R','U',one(elty),Aherm,Cnn,one(elty),Cnm) + @test_throws DimensionMismatch BLAS.hemm!('R','U',one(elty),Aherm,Cmn,one(elty),Cnn) end end end diff --git a/stdlib/LinearAlgebra/test/bunchkaufman.jl b/stdlib/LinearAlgebra/test/bunchkaufman.jl index f1da22d8733e2..d9efa48c8766c 100644 --- a/stdlib/LinearAlgebra/test/bunchkaufman.jl +++ b/stdlib/LinearAlgebra/test/bunchkaufman.jl @@ -70,10 +70,10 @@ bimg = randn(n,2)/2 @test getproperty(bc1, uplo)*bc1.D*transpose(getproperty(bc1, uplo)) ≈ asym[bc1.p, bc1.p] @test getproperty(bc1, uplo)*bc1.D*transpose(getproperty(bc1, uplo)) ≈ bc1.P*asym*transpose(bc1.P) @test_throws ErrorException bc1.Z - @test_throws ArgumentError uplo == :L ? bc1.U : bc1.L + @test_throws ArgumentError uplo === :L ? bc1.U : bc1.L end # test Base.iterate - ref_objs = (bc1.D, uplo == :L ? bc1.L : bc1.U, bc1.p) + ref_objs = (bc1.D, uplo === :L ? bc1.L : bc1.U, bc1.p) for (bki, bkobj) in enumerate(bc1) @test bkobj == ref_objs[bki] end @@ -162,7 +162,7 @@ end @test B.D == Tridiagonal([], [], []) @test B.P == ones(0, 0) @test B.p == [] - if ul == :U + if ul === :U @test B.U == UnitUpperTriangular(ones(0, 0)) @test_throws ArgumentError B.L else diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index 47a36df5e7883..96759643716da 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -352,6 +352,9 @@ end C = zeros(eltya,n,n) @test Hermitian(aherm) * a ≈ aherm * a @test a * Hermitian(aherm) ≈ a * aherm + # rectangular multiplication + @test [a; a] * Hermitian(aherm) ≈ [a; a] * aherm + @test Hermitian(aherm) * [a a] ≈ aherm * [a a] @test Hermitian(aherm) * Hermitian(aherm) ≈ aherm*aherm @test_throws DimensionMismatch Hermitian(aherm) * Vector{eltya}(undef, n+1) LinearAlgebra.mul!(C,a,Hermitian(aherm)) @@ -360,6 +363,9 @@ end @test Symmetric(asym) * Symmetric(asym) ≈ asym*asym @test Symmetric(asym) * a ≈ asym * a @test a * Symmetric(asym) ≈ a * asym + # rectangular multiplication + @test Symmetric(asym) * [a a] ≈ asym * [a a] + @test [a; a] * Symmetric(asym) ≈ [a; a] * asym @test_throws DimensionMismatch Symmetric(asym) * Vector{eltya}(undef, n+1) LinearAlgebra.mul!(C,a,Symmetric(asym)) @test C ≈ a*asym @@ -574,13 +580,13 @@ end # Hermitian A = Hermitian(fill(1.0+0im, 2, 2), uplo) @test fill!(A, 2) == fill(2, 2, 2) - @test A.data == (uplo == :U ? [2 2; 1.0+0im 2] : [2 1.0+0im; 2 2]) + @test A.data == (uplo === :U ? [2 2; 1.0+0im 2] : [2 1.0+0im; 2 2]) @test_throws ArgumentError fill!(A, 2+im) # Symmetric A = Symmetric(fill(1.0+im, 2, 2), uplo) @test fill!(A, 2) == fill(2, 2, 2) - @test A.data == (uplo == :U ? [2 2; 1.0+im 2] : [2 1.0+im; 2 2]) + @test A.data == (uplo === :U ? [2 2; 1.0+im 2] : [2 1.0+im; 2 2]) end end diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index d3c2817f89463..4475dde1e543b 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -26,7 +26,7 @@ for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFlo (UnitLowerTriangular, :L)) # Construct test matrix - A1 = t1(elty1 == Int ? rand(1:7, n, n) : convert(Matrix{elty1}, (elty1 <: Complex ? complex.(randn(n, n), randn(n, n)) : randn(n, n)) |> t -> cholesky(t't).U |> t -> uplo1 == :U ? t : copy(t'))) + A1 = t1(elty1 == Int ? rand(1:7, n, n) : convert(Matrix{elty1}, (elty1 <: Complex ? complex.(randn(n, n), randn(n, n)) : randn(n, n)) |> t -> cholesky(t't).U |> t -> uplo1 === :U ? t : copy(t'))) @test t1(A1) === A1 @test t1{elty1}(A1) === A1 # test the ctor works for AbstractMatrix @@ -77,7 +77,7 @@ for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFlo A1c = copy(A1) for i = 1:size(A1, 1) for j = 1:size(A1, 2) - if uplo1 == :U + if uplo1 === :U if i > j A1c[i,j] = 0 @test_throws ArgumentError A1c[i,j] = 1 @@ -104,7 +104,7 @@ for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFlo end # istril/istriu - if uplo1 == :L + if uplo1 === :L @test istril(A1) @test !istriu(A1) @test istriu(A1') @@ -121,7 +121,7 @@ for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFlo end #tril/triu - if uplo1 == :L + if uplo1 === :L @test tril(A1,0) == A1 @test tril(A1,-1) == LowerTriangular(tril(Matrix(A1), -1)) @test tril(A1,1) == t1(tril(tril(Matrix(A1), 1))) @@ -319,7 +319,7 @@ for elty1 in (Float32, Float64, BigFloat, ComplexF32, ComplexF64, Complex{BigFlo debug && println("elty1: $elty1, A1: $t1, elty2: $elty2") - A2 = t2(elty2 == Int ? rand(1:7, n, n) : convert(Matrix{elty2}, (elty2 <: Complex ? complex.(randn(n, n), randn(n, n)) : randn(n, n)) |> t -> cholesky(t't).U |> t -> uplo2 == :U ? t : copy(t'))) + A2 = t2(elty2 == Int ? rand(1:7, n, n) : convert(Matrix{elty2}, (elty2 <: Complex ? complex.(randn(n, n), randn(n, n)) : randn(n, n)) |> t -> cholesky(t't).U |> t -> uplo2 === :U ? t : copy(t'))) # Convert if elty1 <: Real && !(elty2 <: Integer) diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 079244a98a4ae..0332aca5aaf86 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = 98d0cc276cc59817eb9c2e18e747fe027d7282a2 +PKG_SHA1 = 56cd041ccdf648c7cf5d280bca1386910923c276 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 diff --git a/stdlib/Printf/src/Printf.jl b/stdlib/Printf/src/Printf.jl index 1d04e7146e28b..ce52ed959971a 100644 --- a/stdlib/Printf/src/Printf.jl +++ b/stdlib/Printf/src/Printf.jl @@ -77,18 +77,50 @@ end base(T) = T <: HexBases ? 16 : T <: Val{'o'} ? 8 : 10 char(::Type{Val{c}}) where {c} = c +struct InvalidFormatStringError <: Exception + message::String + format::String + start_color::Int + end_color::Int +end + +function Base.showerror(io::IO, err::InvalidFormatStringError) + io_has_color = get(io, :color, false) + + println(io, "InvalidFormatStringError: ", err.message) + print(io, " \"", @view(err.format[begin:prevind(err.format, err.start_color)])) + invalid_text = @view err.format[err.start_color:err.end_color] + + printstyled(io, invalid_text, color=:red) + + # +1 is okay, since all format characters are single bytes + println(io, @view(err.format[err.end_color+1:end]), "\"") + + arrow_error = '-'^(length(invalid_text)-1) + arrow = " " * ' '^err.start_color * arrow_error * "^\n" + if io_has_color + printstyled(io, arrow, color=:red) + else + print(io, arrow) + end +end + # parse format string function Format(f::AbstractString) - isempty(f) && throw(ArgumentError("empty format string")) + isempty(f) && throw(InvalidFormatStringError("Format string must not be empty", f, 1, 1)) bytes = codeunits(f) len = length(bytes) pos = 1 b = 0x00 + local last_percent_pos + + # skip ahead to first format specifier while pos <= len b = bytes[pos] pos += 1 if b == UInt8('%') - pos > len && throw(ArgumentError("invalid format string: '$f'")) + last_percent_pos = pos-1 + pos > len && throw(InvalidFormatStringError("Format specifier is incomplete", f, last_percent_pos, last_percent_pos)) if bytes[pos] == UInt8('%') # escaped '%' b = bytes[pos] @@ -120,7 +152,7 @@ function Format(f::AbstractString) else break end - pos > len && throw(ArgumentError("incomplete format string: '$f'")) + pos > len && throw(InvalidFormatStringError("Format specifier is incomplete", f, last_percent_pos, pos-1)) b = bytes[pos] pos += 1 end @@ -139,7 +171,7 @@ function Format(f::AbstractString) precision = 0 parsedprecdigits = false if b == UInt8('.') - pos > len && throw(ArgumentError("incomplete format string: '$f'")) + pos > len && throw(InvalidFormatStringError("Precision specifier is missing precision", f, last_percent_pos, pos-1)) parsedprecdigits = true b = bytes[pos] pos += 1 @@ -155,19 +187,21 @@ function Format(f::AbstractString) # parse length modifier (ignored) if b == UInt8('h') || b == UInt8('l') prev = b + pos > len && throw(InvalidFormatStringError("Length modifier is missing type specifier", f, last_percent_pos, pos-1)) b = bytes[pos] pos += 1 if b == prev - pos > len && throw(ArgumentError("invalid format string: '$f'")) + pos > len && throw(InvalidFormatStringError("Length modifier is missing type specifier", f, last_percent_pos, pos-1)) b = bytes[pos] pos += 1 end - elseif b in b"Ljqtz" + elseif b in b"Ljqtz" # q was a synonym for ll above, see `man 3 printf`. Not to be used. + pos > len && throw(InvalidFormatStringError("Length modifier is missing type specifier", f, last_percent_pos, pos-1)) b = bytes[pos] pos += 1 end # parse type - !(b in b"diouxXDOUeEfFgGaAcCsSpn") && throw(ArgumentError("invalid format string: '$f', invalid type specifier: '$(Char(b))'")) + !(b in b"diouxXDOUeEfFgGaAcCsSpn") && throw(InvalidFormatStringError("'$(Char(b))' is not a valid type specifier", f, last_percent_pos, pos-1)) type = Val{Char(b)} if type <: Ints && precision > 0 zero = false @@ -184,7 +218,8 @@ function Format(f::AbstractString) b = bytes[pos] pos += 1 if b == UInt8('%') - pos > len && throw(ArgumentError("invalid format string: '$f'")) + last_percent_pos = pos-1 + pos > len && throw(InvalidFormatStringError("Format specifier is incomplete", f, last_percent_pos, last_percent_pos)) if bytes[pos] == UInt8('%') # escaped '%' b = bytes[pos] @@ -394,6 +429,10 @@ _snprintf(ptr, siz, str, arg) = @ccall "libmpfr".mpfr_snprintf(ptr::Ptr{UInt8}, siz::Csize_t, str::Ptr{UInt8}; arg::Ref{BigFloat})::Cint +# Arbitrary constant for a maximum number of bytes we want to output for a BigFloat. +# 8KiB seems like a reasonable default. Larger BigFloat representations should probably +# use a custom printing routine. Printing values with results larger than this ourselves +# seems like a dangerous thing to do. const __BIG_FLOAT_MAX__ = 8192 @inline function fmt(buf, pos, arg, spec::Spec{T}) where {T <: Floats} @@ -405,17 +444,15 @@ const __BIG_FLOAT_MAX__ = 8192 GC.@preserve buf begin siz = length(buf) - pos + 1 str = string(spec; modifier="R") - len = _snprintf(pointer(buf, pos), siz, str, x) - if len > siz - maxout = max(__BIG_FLOAT_MAX__, - ceil(Int, precision(x) * log(2) / log(10)) + 25) - len > maxout && - error("Over $maxout bytes $len needed to output BigFloat $x") - resize!(buf, len + 1) - len = _snprintf(pointer(buf, pos), len + 1, str, x) + required_length = _snprintf(pointer(buf, pos), siz, str, x) + if required_length > siz + required_length > __BIG_FLOAT_MAX__ && + throw(ArgumentError("The given BigFloat requires $required_length bytes to be printed, which is more than the maximum of $__BIG_FLOAT_MAX__ bytes supported.")) + resize!(buf, required_length + 1) + required_length = _snprintf(pointer(buf, pos), required_length + 1, str, x) end - len > 0 || throw(ArgumentError("invalid printf formatting $str for BigFloat")) - return pos + len + required_length > 0 || throw(ArgumentError("The given BigFloat would produce less than the maximum allowed number of bytes $__BIG_FLOAT_MAX__, but still couldn't be printed fully for an unknown reason.")) + return pos + required_length end end x = Float64(x) @@ -805,7 +842,7 @@ plength(::Spec{PositionCounter}, x) = 0 end @noinline argmismatch(a, b) = - throw(ArgumentError("mismatch between # of format specifiers and provided args: $a != $b")) + throw(ArgumentError("Number of format specifiers and number of provided args differ: $a != $b")) """ Printf.format(f::Printf.Format, args...) => String @@ -892,8 +929,10 @@ macro printf(io_or_fmt, args...) return esc(:($Printf.format(stdout, $fmt, $(args...)))) else io = io_or_fmt - isempty(args) && throw(ArgumentError("must provide required format string")) - fmt = Format(args[1]) + isempty(args) && throw(ArgumentError("No format string provided to `@printf` - use like `@printf [io] [].")) + fmt_str = first(args) + fmt_str isa String || throw(ArgumentError("First argument to `@printf` after `io` must be a format string")) + fmt = Format(fmt_str) return esc(:($Printf.format($io, $fmt, $(Base.tail(args)...)))) end end @@ -910,6 +949,7 @@ julia> @sprintf "this is a %s %15.1f" "test" 34.567 ``` """ macro sprintf(fmt, args...) + fmt isa String || throw(ArgumentError("First argument to `@sprintf` must be a format string.")) f = Format(fmt) return esc(:($Printf.format($f, $(args...)))) end diff --git a/stdlib/Printf/test/runtests.jl b/stdlib/Printf/test/runtests.jl index e80cbe9626823..40a6a763e4eac 100644 --- a/stdlib/Printf/test/runtests.jl +++ b/stdlib/Printf/test/runtests.jl @@ -339,10 +339,10 @@ end @test Printf.@sprintf("1%%2%%3") == "1%2%3" @test Printf.@sprintf("GAP[%%]") == "GAP[%]" @test Printf.@sprintf("hey there") == "hey there" - @test_throws ArgumentError Printf.Format("") - @test_throws ArgumentError Printf.Format("%+") - @test_throws ArgumentError Printf.Format("%.") - @test_throws ArgumentError Printf.Format("%.0") + @test_throws Printf.InvalidFormatStringError Printf.Format("") + @test_throws Printf.InvalidFormatStringError Printf.Format("%+") + @test_throws Printf.InvalidFormatStringError Printf.Format("%.") + @test_throws Printf.InvalidFormatStringError Printf.Format("%.0") @test isempty(Printf.Format("%%").formats) @test Printf.@sprintf("%d%d", 1, 2) == "12" @test (Printf.@sprintf "%d%d" [1 2]...) == "12" @@ -355,10 +355,10 @@ end @test (Printf.@sprintf("%d\u0f00%d", 1, 2)) == "1\u0f002" @test (Printf.@sprintf("%d\U0001ffff%d", 1, 2)) == "1\U0001ffff2" @test (Printf.@sprintf("%d\u2203%d\u0203", 1, 2)) == "1\u22032\u0203" - @test_throws ArgumentError Printf.Format("%y%d") - @test_throws ArgumentError Printf.Format("%\u00d0%d") - @test_throws ArgumentError Printf.Format("%\u0f00%d") - @test_throws ArgumentError Printf.Format("%\U0001ffff%d") + @test_throws Printf.InvalidFormatStringError Printf.Format("%y%d") + @test_throws Printf.InvalidFormatStringError Printf.Format("%\u00d0%d") + @test_throws Printf.InvalidFormatStringError Printf.Format("%\u0f00%d") + @test_throws Printf.InvalidFormatStringError Printf.Format("%\U0001ffff%d") @test Printf.@sprintf("%10.5d", 4) == " 00004" @test (Printf.@sprintf "%d" typemax(Int64)) == "9223372036854775807" @@ -444,8 +444,8 @@ end @test (Printf.@sprintf("%f", parse(BigFloat, "1e400"))) == "10000000000000000000000000000000000000000000000000000000000000000000000000000025262527574416492004687051900140830217136998040684679611623086405387447100385714565637522507383770691831689647535911648520404034824470543643098638520633064715221151920028135130764414460468236314621044034960475540018328999334468948008954289495190631358190153259681118693204411689043999084305348398480210026863210192871358464.000000" - # Check that does not attempt to output incredibly large amounts of digits - @test_throws ErrorException Printf.@sprintf("%f", parse(BigFloat, "1e99999")) + # Check that Printf does not attempt to output more than 8KiB worth of digits + @test_throws ArgumentError Printf.@sprintf("%f", parse(BigFloat, "1e99999")) # Check bug with precision > length of string @test Printf.@sprintf("%4.2s", "a") == " a" @@ -528,13 +528,13 @@ end @test Printf.@sprintf( "%0-5d", -42) == "-42 " @test Printf.@sprintf( "%0-15d", 42) == "42 " @test Printf.@sprintf( "%0-15d", -42) == "-42 " - @test_throws ArgumentError Printf.Format("%d %") + @test_throws Printf.InvalidFormatStringError Printf.Format("%d %") @test Printf.@sprintf("%lld", 18446744065119617025) == "18446744065119617025" @test Printf.@sprintf("%+8lld", 100) == " +100" @test Printf.@sprintf("%+.8lld", 100) == "+00000100" @test Printf.@sprintf("%+10.8lld", 100) == " +00000100" - @test_throws ArgumentError Printf.Format("%_1lld") + @test_throws Printf.InvalidFormatStringError Printf.Format("%_1lld") @test Printf.@sprintf("%-1.5lld", -100) == "-00100" @test Printf.@sprintf("%5lld", 100) == " 100" @test Printf.@sprintf("%5lld", -100) == " -100" @@ -782,4 +782,10 @@ end @test (Printf.@sprintf("%s%n", "1234", x); x[] == 4) end +@testset "length modifiers" begin + @test_throws Printf.InvalidFormatStringError Printf.Format("%h") + @test_throws Printf.InvalidFormatStringError Printf.Format("%hh") + @test_throws Printf.InvalidFormatStringError Printf.Format("%z") +end + end # @testset "Printf" diff --git a/stdlib/Profile/src/Profile.jl b/stdlib/Profile/src/Profile.jl index 593f265eba3fa..12a44b9acda9a 100644 --- a/stdlib/Profile/src/Profile.jl +++ b/stdlib/Profile/src/Profile.jl @@ -242,7 +242,7 @@ function print(io::IO, tasks::Union{UInt,AbstractVector{UInt}} = typemin(UInt):typemax(UInt)) pf = ProfileFormat(;C, combine, maxdepth, mincount, noisefloor, sortedby, recur) - if groupby == :none + if groupby === :none print(io, data, lidict, pf, format, threads, tasks, false) else if !in(groupby, [:thread, :task, [:task, :thread], [:thread, :task]]) @@ -285,7 +285,7 @@ function print(io::IO, end end end - elseif groupby == :task + elseif groupby === :task threads = 1:typemax(Int) for taskid in intersect(get_task_ids(data), tasks) printstyled(io, "Task $(Base.repr(taskid)) "; bold=true, color=Base.debug_color()) @@ -293,7 +293,7 @@ function print(io::IO, nosamples && (any_nosamples = true) println(io) end - elseif groupby == :thread + elseif groupby === :thread tasks = 1:typemax(UInt) for threadid in intersect(get_thread_ids(data), threads) printstyled(io, "Thread $threadid "; bold=true, color=Base.info_color()) diff --git a/stdlib/Profile/test/runtests.jl b/stdlib/Profile/test/runtests.jl index 058158023cd25..edd291f22e4a6 100644 --- a/stdlib/Profile/test/runtests.jl +++ b/stdlib/Profile/test/runtests.jl @@ -151,14 +151,14 @@ end @profile busywait(1, 20) _, fdict0 = Profile.flatten(Profile.retrieve()...) Base.update_stackframes_callback[] = function(list) - modify((sf, n)) = sf.func == :busywait ? (StackTraces.StackFrame(sf.func, sf.file, sf.line+2, sf.linfo, sf.from_c, sf.inlined, sf.pointer), n) : (sf, n) + modify((sf, n)) = sf.func === :busywait ? (StackTraces.StackFrame(sf.func, sf.file, sf.line+2, sf.linfo, sf.from_c, sf.inlined, sf.pointer), n) : (sf, n) map!(modify, list, list) end _, fdictc = Profile.flatten(Profile.retrieve()...) Base.update_stackframes_callback[] = identity function getline(sfs) for sf in sfs - sf.func == :busywait && return sf.line + sf.func === :busywait && return sf.line end nothing end @@ -263,7 +263,7 @@ end Profile.tree!(root, backtraces, lidict, #= C =# true, :off) @test length(root.down) == 2 for k in keys(root.down) - @test k.file == :file1 + @test k.file === :file1 @test k.line ∈ (1, 2) end node = root.down[stackframe(:f1, :file1, 2)] diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index b30a1d816a83f..0d00063b5c880 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -1323,9 +1323,9 @@ end function edit_input(s, f = (filename, line, column) -> InteractiveUtils.edit(filename, line, column)) mode_name = guess_current_mode_name(s) filename = tempname() - if mode_name == :julia + if mode_name === :julia filename *= ".jl" - elseif mode_name == :shell + elseif mode_name === :shell filename *= ".sh" end buf = buffer(s) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index d3d0c9bc98582..9ef9d6b8a6f26 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -179,8 +179,8 @@ function check_for_missing_packages_and_run_hooks(ast) end function modules_to_be_loaded(ast::Expr, mods::Vector{Symbol} = Symbol[]) - ast.head == :quote && return mods # don't search if it's not going to be run during this eval - if ast.head in [:using, :import] + ast.head === :quote && return mods # don't search if it's not going to be run during this eval + if ast.head === :using || ast.head === :import for arg in ast.args arg = arg::Expr arg1 = first(arg.args) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 295fd5ae64229..a06700fbcc591 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -819,14 +819,14 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif end #Latex symbols can be completed for strings - (success || inc_tag==:cmd) && return sort!(paths, by=p->p.path), r, success + (success || inc_tag === :cmd) && return sort!(paths, by=p->p.path), r, success end ok, ret = bslash_completions(string, pos) ok && return ret # Make sure that only bslash_completions is working on strings - inc_tag==:string && return Completion[], 0:-1, false + inc_tag === :string && return Completion[], 0:-1, false if inc_tag === :other && should_method_complete(partial) frange, method_name_end = find_start_brace(partial) # strip preceding ! operator diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index 9a82106118fc5..a7325a51c6ae0 100644 --- a/stdlib/REPL/src/docview.jl +++ b/stdlib/REPL/src/docview.jl @@ -230,7 +230,7 @@ function lookup_doc(ex) end end binding = esc(bindingexpr(namify(ex))) - if isexpr(ex, :call) || isexpr(ex, :macrocall) + if isexpr(ex, :call) || isexpr(ex, :macrocall) || isexpr(ex, :where) sig = esc(signature(ex)) :($(doc)($binding, $sig)) else diff --git a/stdlib/REPL/test/lineedit.jl b/stdlib/REPL/test/lineedit.jl index 87028e239d5b8..4b9ba05b2b1e6 100644 --- a/stdlib/REPL/test/lineedit.jl +++ b/stdlib/REPL/test/lineedit.jl @@ -29,7 +29,7 @@ function transform!(f, s, i = -1) # i is char-based (not bytes) buffer position # simulate what happens in LineEdit.set_action! s isa LineEdit.MIState && (s.current_action = :unknown) status = f(s) - if s isa LineEdit.MIState && status != :ignore + if s isa LineEdit.MIState && status !== :ignore # simulate what happens in LineEdit.prompt! s.last_action = s.current_action end diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 6e4132aaab1cd..fcc571d8a44ef 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -1323,7 +1323,7 @@ fake_repl() do stdin_write, stdout_read, repl # necessary to read at least some part of the buffer, # for the "region_active" to have time to be updated - @test LineEdit.state(repl.mistate).region_active == :off + @test LineEdit.state(repl.mistate).region_active === :off @test s4 == "anything" # no control characters between the last two occurrences of "anything" write(stdin_write, "\x15\x04") Base.wait(repltask) diff --git a/stdlib/Random/src/RNGs.jl b/stdlib/Random/src/RNGs.jl index 115034d3e3988..f79f113bc95eb 100644 --- a/stdlib/Random/src/RNGs.jl +++ b/stdlib/Random/src/RNGs.jl @@ -388,6 +388,7 @@ end function __init__() seed!(GLOBAL_RNG) + ccall(:jl_gc_init_finalizer_rng_state, Cvoid, ()) end diff --git a/stdlib/Random/test/runtests.jl b/stdlib/Random/test/runtests.jl index 616aa80a20dca..b7c6cb10b197d 100644 --- a/stdlib/Random/test/runtests.jl +++ b/stdlib/Random/test/runtests.jl @@ -994,3 +994,26 @@ end @test minimum(m) >= 0.094 @test maximum(m) <= 0.106 end + +# issue #42752 +# test that running finalizers that launch tasks doesn't change RNG stream +function f42752(do_gc::Bool, cell = (()->Any[[]])()) + a = rand() + if do_gc + finalizer(cell[1]) do _ + @async nothing + end + cell[1] = nothing + GC.gc() + end + b = rand() + (a, b) +end +guardseed() do + for _ in 1:4 + Random.seed!(1) + val = f42752(false) + Random.seed!(1) + @test f42752(true) === val + end +end diff --git a/stdlib/Serialization/test/runtests.jl b/stdlib/Serialization/test/runtests.jl index 104b3e97d6118..0d438040a4cd0 100644 --- a/stdlib/Serialization/test/runtests.jl +++ b/stdlib/Serialization/test/runtests.jl @@ -325,8 +325,8 @@ main_ex = quote local g2 = deserialize(ds) Base.invokelatest() do $Test.@test g2 !== g - $Test.@test g2() == :magic_token_anon_fun_test - $Test.@test g2() == :magic_token_anon_fun_test + $Test.@test g2() === :magic_token_anon_fun_test + $Test.@test g2() === :magic_token_anon_fun_test $Test.@test deserialize(ds) === g2 end @@ -354,7 +354,7 @@ create_serialization_stream() do s # user-defined type array seek(s, 0) r = deserialize(s) @test r.storage[:v] == 2 - @test r.state == :done + @test r.state === :done @test r.exception === nothing end @@ -366,7 +366,7 @@ create_serialization_stream() do s # user-defined type array serialize(s, t) seek(s, 0) r = deserialize(s) - @test r.state == :failed + @test r.state === :failed end # corner case: undefined inside immutable struct diff --git a/stdlib/Sockets/src/addrinfo.jl b/stdlib/Sockets/src/addrinfo.jl index 586463ba0fa21..dda9dac308f38 100644 --- a/stdlib/Sockets/src/addrinfo.jl +++ b/stdlib/Sockets/src/addrinfo.jl @@ -170,7 +170,7 @@ using the operating system's underlying `getnameinfo` implementation. # Examples ```julia-repl -julia> getnameinfo(Sockets.IPv4("8.8.8.8")) +julia> getnameinfo(IPv4("8.8.8.8")) "google-public-dns-a.google.com" ``` """ diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index 0862a4e2a458c..865ae967c9e99 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = main -SPARSEARRAYS_SHA1 = 2bbdd7a12ead8207593655c541ba347761a9c663 +SPARSEARRAYS_SHA1 = e081db699e4bc99db6424dca8103ff111c9b9fcc SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 diff --git a/stdlib/Statistics.version b/stdlib/Statistics.version index aba34b5423d99..a9830fcd8759b 100644 --- a/stdlib/Statistics.version +++ b/stdlib/Statistics.version @@ -1,4 +1,4 @@ STATISTICS_BRANCH = master -STATISTICS_SHA1 = c38dd4418738bc595bd8229eb4ee91b717de64af +STATISTICS_SHA1 = 0588f2cf9e43f9f72af5802feaf0af4b652c3257 STATISTICS_GIT_URL := https://github.com/JuliaStats/Statistics.jl.git STATISTICS_TAR_URL = https://api.github.com/repos/JuliaStats/Statistics.jl/tarball/$1 diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 9a080812dbc45..e73a53550c7f7 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -682,6 +682,9 @@ a matching function, or a value (which will be tested for equality by comparing fields). Note that `@test_throws` does not support a trailing keyword form. +!!! compat "Julia 1.8" + The ability to specify anything other than a type or a value as `exception` requires Julia v1.8 or later. + # Examples ```jldoctest julia> @test_throws BoundsError [1, 2, 3][4] @@ -1328,7 +1331,7 @@ macro testset(args...) tests = args[end] # Determine if a single block or for-loop style - if !isa(tests,Expr) || (tests.head !== :for && tests.head !== :block && tests.head != :call) + if !isa(tests,Expr) || (tests.head !== :for && tests.head !== :block && tests.head !== :call) error("Expected function call, begin/end block or for loop as argument to @testset") end diff --git a/stdlib/Test/test/runtests.jl b/stdlib/Test/test/runtests.jl index 38a4fb0031dd7..829ecde1f83c7 100644 --- a/stdlib/Test/test/runtests.jl +++ b/stdlib/Test/test/runtests.jl @@ -409,19 +409,19 @@ end @test true @test false @test 1 == 1 - @test 2 == :foo + @test 2 === :foo @test 3 == 3 @testset "d" begin @test 4 == 4 end @testset begin - @test :blank != :notblank + @test :blank !== :notblank end end @testset "inner1" begin @test 1 == 1 @test 2 == 2 - @test 3 == :bar + @test 3 === :bar @test 4 == 4 @test_throws ErrorException 1+1 @test_throws ErrorException error() @@ -1387,12 +1387,12 @@ Test.finish(ts::PassInformationTestSet) = ts end test_line_number = (@__LINE__) - 3 test_throws_line_number = (@__LINE__) - 3 - @test ts.results[1].test_type == :test + @test ts.results[1].test_type === :test @test ts.results[1].orig_expr == :(1 == 1) @test ts.results[1].data == Expr(:comparison, 1, :(==), 1) @test ts.results[1].value == true @test ts.results[1].source == LineNumberNode(test_line_number, @__FILE__) - @test ts.results[2].test_type == :test_throws + @test ts.results[2].test_type === :test_throws @test ts.results[2].orig_expr == :(throw(ErrorException("Msg"))) @test ts.results[2].data == ErrorException @test ts.results[2].value == ErrorException("Msg") diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 111e2cabbe7c2..88156e499616c 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -1575,22 +1575,54 @@ end @test length(rr) == length(r) end +struct FakeZeroDimArray <: AbstractArray{Int, 0} end +Base.strides(::FakeZeroDimArray) = () +Base.size(::FakeZeroDimArray) = () @testset "strides for ReshapedArray" begin # Type-based contiguous check is tested in test/compiler/inline.jl + function check_strides(A::AbstractArray) + # Make sure stride(A, i) is equivalent with strides(A)[i] (if 1 <= i <= ndims(A)) + dims = ntuple(identity, ndims(A)) + map(i -> stride(A, i), dims) == @inferred(strides(A)) || return false + # Test strides via value check. + for i in eachindex(IndexLinear(), A) + A[i] === Base.unsafe_load(pointer(A, i)) || return false + end + return true + end # General contiguous check a = view(rand(10,10), 1:10, 1:10) - @test strides(vec(a)) == (1,) + @test check_strides(vec(a)) b = view(parent(a), 1:9, 1:10) - @test_throws "Parent must be contiguous." strides(vec(b)) + @test_throws "Input is not strided." strides(vec(b)) # StridedVector parent for n in 1:3 a = view(collect(1:60n), 1:n:60n) - @test strides(reshape(a, 3, 4, 5)) == (n, 3n, 12n) - @test strides(reshape(a, 5, 6, 2)) == (n, 5n, 30n) + @test check_strides(reshape(a, 3, 4, 5)) + @test check_strides(reshape(a, 5, 6, 2)) b = view(parent(a), 60n:-n:1) - @test strides(reshape(b, 3, 4, 5)) == (-n, -3n, -12n) - @test strides(reshape(b, 5, 6, 2)) == (-n, -5n, -30n) + @test check_strides(reshape(b, 3, 4, 5)) + @test check_strides(reshape(b, 5, 6, 2)) end + # StridedVector like parent + a = randn(10, 10, 10) + b = view(a, 1:10, 1:1, 5:5) + @test check_strides(reshape(b, 2, 5)) + # Other StridedArray parent + a = view(randn(10,10), 1:9, 1:10) + @test check_strides(reshape(a,3,3,2,5)) + @test check_strides(reshape(a,3,3,5,2)) + @test check_strides(reshape(a,9,5,2)) + @test check_strides(reshape(a,3,3,10)) + @test check_strides(reshape(a,1,3,1,3,1,5,1,2)) + @test check_strides(reshape(a,3,3,5,1,1,2,1,1)) + @test_throws "Input is not strided." strides(reshape(a,3,6,5)) + @test_throws "Input is not strided." strides(reshape(a,3,2,3,5)) + @test_throws "Input is not strided." strides(reshape(a,3,5,3,2)) + @test_throws "Input is not strided." strides(reshape(a,5,3,3,2)) + # Zero dimensional parent + a = reshape(FakeZeroDimArray(),1,1,1) + @test @inferred(strides(a)) == (1, 1, 1) end @testset "stride for 0 dims array #44087" begin diff --git a/test/arrayops.jl b/test/arrayops.jl index b11731d394b65..d4634a393aa86 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -2269,6 +2269,14 @@ end @test S32K isa AbstractSlices{<:AbstractArray{Int, 2}, 4} @test size(S32K) == (1,2,2,1) @test S32K[1,2,1,1] == M[:,2,1,:] + + @testset "eachslice inference (#45923)" begin + a = [1 2; 3 4] + f1(a) = eachslice(a, dims=1) + @test (@inferred f1(a)) == eachrow(a) + f2(a) = eachslice(a, dims=2) + @test (@inferred f2(a)) == eachcol(a) + end end ### diff --git a/test/asyncmap.jl b/test/asyncmap.jl index ec49230dbce14..5dc79e612acda 100644 --- a/test/asyncmap.jl +++ b/test/asyncmap.jl @@ -64,7 +64,7 @@ let end @test e isa CapturedException @test e.ex == ErrorException("captured") - @test e.processed_bt[2][1].func == :f42105 + @test e.processed_bt[2][1].func === :f42105 end include("generic_map_tests.jl") diff --git a/test/backtrace.jl b/test/backtrace.jl index c0abad5146b39..38019880da35d 100644 --- a/test/backtrace.jl +++ b/test/backtrace.jl @@ -35,7 +35,7 @@ catch err @test endswith(string(lkup[2].file), "backtrace.jl") @test lkup[2].line == 42 # TODO: we don't support surface AST locations with inlined function names - @test_broken lkup[1].func == :inlfunc + @test_broken lkup[1].func === :inlfunc @test endswith(string(lkup[1].file), "backtrace.jl") @test lkup[1].line == 37 end @@ -106,10 +106,10 @@ lkup = map(lookup, bt()) hasbt = hasbt2 = false for sfs in lkup for sf in sfs - if sf.func == :bt + if sf.func === :bt global hasbt = true end - if sf.func == :bt2 + if sf.func === :bt2 global hasbt2 = true end end @@ -125,10 +125,10 @@ lkup = map(lookup, btmacro()) hasme = hasbtmacro = false for sfs in lkup for sf in sfs - if sf.func == Symbol("macro expansion") + if sf.func === Symbol("macro expansion") global hasme = true end - if sf.func == :btmacro + if sf.func === :btmacro global hasbtmacro = true end end @@ -175,7 +175,7 @@ let bt, found = false bt = backtrace() end for frame in map(lookup, bt) - if frame[1].line == @__LINE__() - 3 && frame[1].file == Symbol(@__FILE__) + if frame[1].line == @__LINE__() - 3 && frame[1].file === Symbol(@__FILE__) found = true; break end end @@ -187,7 +187,7 @@ let bt, found = false @debug "" bt = backtrace() for frame in map(lookup, bt) - if frame[1].line == @__LINE__() - 2 && frame[1].file == Symbol(@__FILE__) + if frame[1].line == @__LINE__() - 2 && frame[1].file === Symbol(@__FILE__) found = true; break end end @@ -205,8 +205,8 @@ let trace = try catch stacktrace(catch_backtrace()) end - @test trace[1].func == Symbol("top-level scope") - @test trace[1].file == :a_filename + @test trace[1].func === Symbol("top-level scope") + @test trace[1].file === :a_filename @test trace[1].line == 2 end let trace = try @@ -219,8 +219,8 @@ let trace = try catch stacktrace(catch_backtrace()) end - @test trace[1].func == Symbol("top-level scope") - @test trace[1].file == :a_filename + @test trace[1].func === Symbol("top-level scope") + @test trace[1].file === :a_filename @test trace[1].line == 2 end diff --git a/test/broadcast.jl b/test/broadcast.jl index 1fd1b02776b68..bd9cb9e8e8fa3 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -1116,6 +1116,14 @@ end @inferred(test(x, y)) == [0, 0] end +@testset "issue #45903, in place broadcast into a bit-masked bitmatrix" begin + A = BitArray(ones(3,3)) + pos = randn(3,3) + A[pos .< 0] .= false + @test all(>=(0), pos[A]) + @test count(A) == count(>=(0), pos) +end + # test that `Broadcast` definition is defined as total and eligible for concrete evaluation import Base.Broadcast: BroadcastStyle, DefaultArrayStyle @test Base.infer_effects(BroadcastStyle, (DefaultArrayStyle{1},DefaultArrayStyle{2},)) |> diff --git a/test/channels.jl b/test/channels.jl index 1b7f96ad528bf..5da028264f74f 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -359,7 +359,7 @@ end redirect_stderr(oldstderr) close(newstderr[2]) end - @test fetch(errstream) == "\nWARNING: Workqueue inconsistency detected: popfirst!(Workqueue).state != :runnable\n" + @test fetch(errstream) == "\nWARNING: Workqueue inconsistency detected: popfirst!(Workqueue).state !== :runnable\n" end @testset "throwto" begin diff --git a/test/choosetests.jl b/test/choosetests.jl index 099dfa18a71c5..f5775bbc00911 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -140,8 +140,8 @@ function choosetests(choices = []) "strings/io", "strings/types"]) # do subarray before sparse but after linalg filtertests!(tests, "subarray") - filtertests!(tests, "compiler", ["compiler/inference", "compiler/validation", - "compiler/ssair", "compiler/irpasses", "compiler/codegen", + filtertests!(tests, "compiler", ["compiler/inference", "compiler/effects", + "compiler/validation", "compiler/ssair", "compiler/irpasses", "compiler/codegen", "compiler/inline", "compiler/contextual", "compiler/AbstractInterpreter", "compiler/EscapeAnalysis/local", "compiler/EscapeAnalysis/interprocedural"]) filtertests!(tests, "compiler/EscapeAnalysis", [ diff --git a/test/compiler/EscapeAnalysis/EAUtils.jl b/test/compiler/EscapeAnalysis/EAUtils.jl index f71cc20387733..f8db1cb62f460 100644 --- a/test/compiler/EscapeAnalysis/EAUtils.jl +++ b/test/compiler/EscapeAnalysis/EAUtils.jl @@ -51,7 +51,7 @@ function code_escapes(@nospecialize(f), @nospecialize(types=Base.default_tt(f)); interp = EscapeAnalyzer(interp, tt, optimize) results = Base.code_typed_by_type(tt; optimize=true, world, interp) isone(length(results)) || throw(ArgumentError("`code_escapes` only supports single analysis result")) - return EscapeResult(interp.ir, interp.state, interp.linfo, debuginfo===:source) + return EscapeResult(interp.ir, interp.state, interp.linfo, debuginfo === :source) end # in order to run a whole analysis from ground zero (e.g. for benchmarking, etc.) diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index 97ecda14efde0..c13ac2ad5255b 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -713,9 +713,9 @@ struct A44921{T} x::T end function f44921(a) - if a == :x + if a === :x A44921(_f) # _f purposefully undefined - elseif a == :p + elseif a === :p g44921(a) end end diff --git a/test/compiler/effects.jl b/test/compiler/effects.jl new file mode 100644 index 0000000000000..d63b99bf81ace --- /dev/null +++ b/test/compiler/effects.jl @@ -0,0 +1,173 @@ +using Test +include("irutils.jl") + +# control flow backedge should taint `terminates` +@test Base.infer_effects((Int,)) do n + for i = 1:n; end +end |> !Core.Compiler.is_terminates + +# interprocedural-recursion should taint `terminates` **appropriately** +function sumrecur(a, x) + isempty(a) && return x + return sumrecur(Base.tail(a), x + first(a)) +end +@test Base.infer_effects(sumrecur, (Tuple{Int,Int,Int},Int)) |> Core.Compiler.is_terminates +@test Base.infer_effects(sumrecur, (Tuple{Int,Int,Int,Vararg{Int}},Int)) |> !Core.Compiler.is_terminates + +# https://github.com/JuliaLang/julia/issues/45781 +@test Base.infer_effects((Float32,)) do a + out1 = promote_type(Irrational{:π}, Bool) + out2 = sin(a) + out1, out2 +end |> Core.Compiler.is_terminates + +# refine :consistent-cy effect inference using the return type information +@test Base.infer_effects((Any,)) do x + taint = Ref{Any}(x) # taints :consistent-cy, but will be adjusted + throw(taint) +end |> Core.Compiler.is_consistent +@test Base.infer_effects((Int,)) do x + if x < 0 + taint = Ref(x) # taints :consistent-cy, but will be adjusted + throw(DomainError(x, taint)) + end + return nothing +end |> Core.Compiler.is_consistent +@test Base.infer_effects((Int,)) do x + if x < 0 + taint = Ref(x) # taints :consistent-cy, but will be adjusted + throw(DomainError(x, taint)) + end + return x == 0 ? nothing : x # should `Union` of isbitstype objects nicely +end |> Core.Compiler.is_consistent +@test Base.infer_effects((Symbol,Any)) do s, x + if s === :throw + taint = Ref{Any}(":throw option given") # taints :consistent-cy, but will be adjusted + throw(taint) + end + return s # should handle `Symbol` nicely +end |> Core.Compiler.is_consistent +@test Base.infer_effects((Int,)) do x + return Ref(x) +end |> !Core.Compiler.is_consistent +@test Base.infer_effects((Int,)) do x + return x < 0 ? Ref(x) : nothing +end |> !Core.Compiler.is_consistent +@test Base.infer_effects((Int,)) do x + if x < 0 + throw(DomainError(x, lazy"$x is negative")) + end + return nothing +end |> Core.Compiler.is_foldable + +# effects propagation for `Core.invoke` calls +# https://github.com/JuliaLang/julia/issues/44763 +global x44763::Int = 0 +increase_x44763!(n) = (global x44763; x44763 += n) +invoke44763(x) = @invoke increase_x44763!(x) +@test Base.return_types() do + invoke44763(42) +end |> only === Int +@test x44763 == 0 + +# Test that purity doesn't try to accidentally run unreachable code due to +# boundscheck elimination +function f_boundscheck_elim(n) + # Inbounds here assumes that this is only ever called with n==0, but of + # course the compiler has no way of knowing that, so it must not attempt + # to run the @inbounds `getfield(sin, 1)`` that ntuple generates. + ntuple(x->(@inbounds getfield(sin, x)), n) +end +@test Tuple{} <: code_typed(f_boundscheck_elim, Tuple{Int})[1][2] + +# Test that purity modeling doesn't accidentally introduce new world age issues +f_redefine_me(x) = x+1 +f_call_redefine() = f_redefine_me(0) +f_mk_opaque() = Base.Experimental.@opaque ()->Base.inferencebarrier(f_call_redefine)() +const op_capture_world = f_mk_opaque() +f_redefine_me(x) = x+2 +@test op_capture_world() == 1 +@test f_mk_opaque()() == 2 + +# backedge insertion for Any-typed, effect-free frame +const CONST_DICT = let d = Dict() + for c in 'A':'z' + push!(d, c => Int(c)) + end + d +end +Base.@assume_effects :foldable getcharid(c) = CONST_DICT[c] +@noinline callf(f, args...) = f(args...) +function entry_to_be_invalidated(c) + return callf(getcharid, c) +end +@test Base.infer_effects((Char,)) do x + entry_to_be_invalidated(x) +end |> Core.Compiler.is_foldable +@test fully_eliminated(; retval=97) do + entry_to_be_invalidated('a') +end +getcharid(c) = CONST_DICT[c] # now this is not eligible for concrete evaluation +@test Base.infer_effects((Char,)) do x + entry_to_be_invalidated(x) +end |> !Core.Compiler.is_foldable +@test !fully_eliminated() do + entry_to_be_invalidated('a') +end + +@test !Core.Compiler.builtin_nothrow(Core.get_binding_type, Any[Rational{Int}, Core.Const(:foo)], Any) + +# Nothrow for assignment to globals +global glob_assign_int::Int = 0 +f_glob_assign_int() = global glob_assign_int += 1 +let effects = Base.infer_effects(f_glob_assign_int, ()) + @test !Core.Compiler.is_effect_free(effects) + @test Core.Compiler.is_nothrow(effects) +end +# Nothrow for setglobal! +global SETGLOBAL!_NOTHROW::Int = 0 +let effects = Base.infer_effects() do + setglobal!(@__MODULE__, :SETGLOBAL!_NOTHROW, 42) + end + @test Core.Compiler.is_nothrow(effects) +end + +# we should taint `nothrow` if the binding doesn't exist and isn't fixed yet, +# as the cached effects can be easily wrong otherwise +# since the inference curently doesn't track "world-age" of global variables +@eval global_assignment_undefinedyet() = $(GlobalRef(@__MODULE__, :UNDEFINEDYET)) = 42 +setglobal!_nothrow_undefinedyet() = setglobal!(@__MODULE__, :UNDEFINEDYET, 42) +let effects = Base.infer_effects() do + global_assignment_undefinedyet() + end + @test !Core.Compiler.is_nothrow(effects) +end +let effects = Base.infer_effects() do + setglobal!_nothrow_undefinedyet() + end + @test !Core.Compiler.is_nothrow(effects) +end +global UNDEFINEDYET::String = "0" +let effects = Base.infer_effects() do + global_assignment_undefinedyet() + end + @test !Core.Compiler.is_nothrow(effects) +end +let effects = Base.infer_effects() do + setglobal!_nothrow_undefinedyet() + end + @test !Core.Compiler.is_nothrow(effects) +end +@test_throws ErrorException setglobal!_nothrow_undefinedyet() + +# Nothrow for setfield! +mutable struct SetfieldNothrow + x::Int +end +f_setfield_nothrow() = SetfieldNothrow(0).x = 1 +let effects = Base.infer_effects(f_setfield_nothrow, ()) + # Technically effect free even though we use the heap, since the + # object doesn't escape, but the compiler doesn't know that. + #@test Core.Compiler.is_effect_free(effects) + @test Core.Compiler.is_nothrow(effects) +end diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 8fc63f42ada87..3772ce0d2440e 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -1817,10 +1817,10 @@ function f24852_kernel_cinfo(fsig::Type) Meta.partially_inline!(code_info.code, Any[], match.spec_types, Any[match.sparams...], 1, 0, :propagate) if startswith(String(match.method.name), "f24852") for a in code_info.code - if a isa Expr && a.head == :(=) + if Meta.isexpr(a, :(=)) a = a.args[2] end - if a isa Expr && length(a.args) === 3 && a.head === :call + if Meta.isexpr(a, :call) && length(a.args) === 3 pushfirst!(a.args, Core.SlotNumber(1)) end end @@ -2801,7 +2801,7 @@ foo_inlining_apply(args...) = ccall(:jl_, Nothing, (Any,), args[1]) bar_inlining_apply() = Core._apply_iterate(iterate, Core._apply_iterate, (iterate,), (foo_inlining_apply,), ((1,),)) let ci = code_typed(bar_inlining_apply, Tuple{})[1].first @test length(ci.code) == 2 - @test ci.code[1].head == :foreigncall + @test ci.code[1].head === :foreigncall end # Test that inference can infer .instance of types @@ -4056,27 +4056,6 @@ end end |> only === Union{} end -# Test that purity modeling doesn't accidentally introduce new world age issues -f_redefine_me(x) = x+1 -f_call_redefine() = f_redefine_me(0) -f_mk_opaque() = @Base.Experimental.opaque ()->Base.inferencebarrier(f_call_redefine)() -const op_capture_world = f_mk_opaque() -f_redefine_me(x) = x+2 -@test op_capture_world() == 1 -@test f_mk_opaque()() == 2 - -# Test that purity doesn't try to accidentally run unreachable code due to -# boundscheck elimination -function f_boundscheck_elim(n) - # Inbounds here assumes that this is only ever called with n==0, but of - # course the compiler has no way of knowing that, so it must not attempt - # to run the @inbounds `getfield(sin, 1)`` that ntuple generates. - ntuple(x->(@inbounds getfield(sin, x)), n) -end -@test Tuple{} <: code_typed(f_boundscheck_elim, Tuple{Int})[1][2] - -@test !Core.Compiler.builtin_nothrow(Core.get_binding_type, Any[Rational{Int}, Core.Const(:foo)], Any) - # Test that max_methods works as expected @Base.Experimental.max_methods 1 function f_max_methods end f_max_methods(x::Int) = 1 @@ -4102,145 +4081,12 @@ end Core.Compiler.return_type(+, NTuple{2, Rational}) end == Rational +# vararg-tuple comparison within `PartialStruct` # https://github.com/JuliaLang/julia/issues/44965 let t = Core.Compiler.tuple_tfunc(Any[Core.Const(42), Vararg{Any}]) @test Core.Compiler.issimplertype(t, t) end -# https://github.com/JuliaLang/julia/issues/44763 -global x44763::Int = 0 -increase_x44763!(n) = (global x44763; x44763 += n) -invoke44763(x) = @invoke increase_x44763!(x) -@test Base.return_types() do - invoke44763(42) -end |> only === Int -@test x44763 == 0 - -# backedge insertion for Any-typed, effect-free frame -const CONST_DICT = let d = Dict() - for c in 'A':'z' - push!(d, c => Int(c)) - end - d -end -Base.@assume_effects :foldable getcharid(c) = CONST_DICT[c] -@noinline callf(f, args...) = f(args...) -function entry_to_be_invalidated(c) - return callf(getcharid, c) -end -@test Base.infer_effects((Char,)) do x - entry_to_be_invalidated(x) -end |> Core.Compiler.is_foldable -@test fully_eliminated(; retval=97) do - entry_to_be_invalidated('a') -end -getcharid(c) = CONST_DICT[c] # now this is not eligible for concrete evaluation -@test Base.infer_effects((Char,)) do x - entry_to_be_invalidated(x) -end |> !Core.Compiler.is_foldable -@test !fully_eliminated() do - entry_to_be_invalidated('a') -end - -# control flow backedge should taint `terminates` -@test Base.infer_effects((Int,)) do n - for i = 1:n; end -end |> !Core.Compiler.is_terminates - -# Nothrow for assignment to globals -global glob_assign_int::Int = 0 -f_glob_assign_int() = global glob_assign_int += 1 -let effects = Base.infer_effects(f_glob_assign_int, ()) - @test !Core.Compiler.is_effect_free(effects) - @test Core.Compiler.is_nothrow(effects) -end -# Nothrow for setglobal! -global SETGLOBAL!_NOTHROW::Int = 0 -let effects = Base.infer_effects() do - setglobal!(@__MODULE__, :SETGLOBAL!_NOTHROW, 42) - end - @test Core.Compiler.is_nothrow(effects) -end - -# we should taint `nothrow` if the binding doesn't exist and isn't fixed yet, -# as the cached effects can be easily wrong otherwise -# since the inference curently doesn't track "world-age" of global variables -@eval global_assignment_undefinedyet() = $(GlobalRef(@__MODULE__, :UNDEFINEDYET)) = 42 -setglobal!_nothrow_undefinedyet() = setglobal!(@__MODULE__, :UNDEFINEDYET, 42) -let effects = Base.infer_effects() do - global_assignment_undefinedyet() - end - @test !Core.Compiler.is_nothrow(effects) -end -let effects = Base.infer_effects() do - setglobal!_nothrow_undefinedyet() - end - @test !Core.Compiler.is_nothrow(effects) -end -global UNDEFINEDYET::String = "0" -let effects = Base.infer_effects() do - global_assignment_undefinedyet() - end - @test !Core.Compiler.is_nothrow(effects) -end -let effects = Base.infer_effects() do - setglobal!_nothrow_undefinedyet() - end - @test !Core.Compiler.is_nothrow(effects) -end -@test_throws ErrorException setglobal!_nothrow_undefinedyet() - -# Nothrow for setfield! -mutable struct SetfieldNothrow - x::Int -end -f_setfield_nothrow() = SetfieldNothrow(0).x = 1 -let effects = Base.infer_effects(f_setfield_nothrow, ()) - # Technically effect free even though we use the heap, since the - # object doesn't escape, but the compiler doesn't know that. - #@test Core.Compiler.is_effect_free(effects) - @test Core.Compiler.is_nothrow(effects) -end - -# refine :consistent-cy effect inference using the return type information -@test Base.infer_effects((Any,)) do x - taint = Ref{Any}(x) # taints :consistent-cy, but will be adjusted - throw(taint) -end |> Core.Compiler.is_consistent -@test Base.infer_effects((Int,)) do x - if x < 0 - taint = Ref(x) # taints :consistent-cy, but will be adjusted - throw(DomainError(x, taint)) - end - return nothing -end |> Core.Compiler.is_consistent -@test Base.infer_effects((Int,)) do x - if x < 0 - taint = Ref(x) # taints :consistent-cy, but will be adjusted - throw(DomainError(x, taint)) - end - return x == 0 ? nothing : x # should `Union` of isbitstype objects nicely -end |> Core.Compiler.is_consistent -@test Base.infer_effects((Symbol,Any)) do s, x - if s === :throw - taint = Ref{Any}(":throw option given") # taints :consistent-cy, but will be adjusted - throw(taint) - end - return s # should handle `Symbol` nicely -end |> Core.Compiler.is_consistent -@test Base.infer_effects((Int,)) do x - return Ref(x) -end |> !Core.Compiler.is_consistent -@test Base.infer_effects((Int,)) do x - return x < 0 ? Ref(x) : nothing -end |> !Core.Compiler.is_consistent -@test Base.infer_effects((Int,)) do x - if x < 0 - throw(DomainError(x, lazy"$x is negative")) - end - return nothing -end |> Core.Compiler.is_foldable - # check the inference convergence with an empty vartable: # the inference state for the toplevel chunk below will have an empty vartable, # and so we may fail to terminate (or optimize) it if we don't update vartables correctly diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index 044ba03bacf32..e7f00064ed2ba 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -128,8 +128,8 @@ end @testset "issue #19122: [no]inline of short func. def. with return type annotation" begin exf19122 = @macroexpand(@inline f19122()::Bool = true) exg19122 = @macroexpand(@noinline g19122()::Bool = true) - @test exf19122.args[2].args[1].args[1] == :inline - @test exg19122.args[2].args[1].args[1] == :noinline + @test exf19122.args[2].args[1].args[1] === :inline + @test exg19122.args[2].args[1].args[1] === :noinline @inline f19122()::Bool = true @noinline g19122()::Bool = true @@ -1300,7 +1300,6 @@ mutable struct DoAllocNoEscape end end end - let src = code_typed1() do for i = 1:1000 DoAllocNoEscape() @@ -1309,6 +1308,65 @@ let src = code_typed1() do @test count(isnew, src.code) == 0 end +# Test that a case when `Core.finalizer` is registered interprocedurally, +# but still eligible for SROA after inlining +mutable struct DoAllocNoEscapeInter end + +let src = code_typed1() do + for i = 1:1000 + obj = DoAllocNoEscapeInter() + finalizer(obj) do this + nothrow_side_effect(nothing) + end + end + end + @test count(isnew, src.code) == 0 +end + +function register_finalizer!(obj) + finalizer(obj) do this + nothrow_side_effect(nothing) + end +end +let src = code_typed1() do + for i = 1:1000 + obj = DoAllocNoEscapeInter() + register_finalizer!(obj) + end + end + @test count(isnew, src.code) == 0 +end + +function genfinalizer(val) + return function (this) + nothrow_side_effect(val) + end +end +let src = code_typed1() do + for i = 1:1000 + obj = DoAllocNoEscapeInter() + finalizer(genfinalizer(nothing), obj) + end + end + @test count(isnew, src.code) == 0 +end + +# Test that we can inline a finalizer that just returns a constant value +mutable struct DoAllocConst + function DoAllocConst() + finalizer(new()) do this + return nothing + end + end +end +let src = code_typed1() do + for i = 1:1000 + DoAllocConst() + end + end + @test count(isnew, src.code) == 0 +end + # Test that finalizer elision doesn't cause a throw to be inlined into a function # that shouldn't have it const finalizer_should_throw = Ref{Bool}(true) @@ -1334,7 +1392,6 @@ end @test f_finalizer_throws() # Test finalizers with static parameters -global last_finalizer_type::Type = Any mutable struct DoAllocNoEscapeSparam{T} x::T function finalizer_sparam(d::DoAllocNoEscapeSparam{T}) where {T} @@ -1346,7 +1403,6 @@ mutable struct DoAllocNoEscapeSparam{T} end end DoAllocNoEscapeSparam(x::T) where {T} = DoAllocNoEscapeSparam{T}(x) - let src = code_typed1(Tuple{Any}) do x for i = 1:1000 DoAllocNoEscapeSparam(x) @@ -1366,7 +1422,6 @@ mutable struct DoAllocNoEscapeNoInline finalizer(noinline_finalizer, new()) end end - let src = code_typed1() do for i = 1:1000 DoAllocNoEscapeNoInline() @@ -1376,6 +1431,28 @@ let src = code_typed1() do @test count(isinvoke(:noinline_finalizer), src.code) == 1 end +# Test that we resolve a `finalizer` call that we don't handle currently +mutable struct DoAllocNoEscapeBranch + val::Int + function DoAllocNoEscapeBranch(val::Int) + finalizer(new(val)) do this + if this.val > 500 + nothrow_side_effect(this.val) + else + nothrow_side_effect(nothing) + end + end + end +end +let src = code_typed1() do + for i = 1:1000 + DoAllocNoEscapeBranch(i) + end + end + @test !any(iscall((src, Core.finalizer)), src.code) + @test !any(isinvoke(:finalizer), src.code) +end + # optimize `[push!|pushfirst!](::Vector{Any}, x...)` @testset "optimize `$f(::Vector{Any}, x...)`" for f = Any[push!, pushfirst!] @eval begin @@ -1402,3 +1479,49 @@ end end end end + +# https://github.com/JuliaLang/julia/issues/45050 +@testset "propagate :meta annotations to keyword sorter methods" begin + # @inline, @noinline, @constprop + let @inline f(::Any; x::Int=1) = 2x + @test ccall(:jl_ir_flag_inlineable, Bool, (Any,), only(methods(f)).source) + @test ccall(:jl_ir_flag_inlineable, Bool, (Any,), only(methods(Core.kwfunc(f))).source) + end + let @noinline f(::Any; x::Int=1) = 2x + @test !ccall(:jl_ir_flag_inlineable, Bool, (Any,), only(methods(f)).source) + @test !ccall(:jl_ir_flag_inlineable, Bool, (Any,), only(methods(Core.kwfunc(f))).source) + end + let Base.@constprop :aggressive f(::Any; x::Int=1) = 2x + @test Core.Compiler.is_aggressive_constprop(only(methods(f))) + @test Core.Compiler.is_aggressive_constprop(only(methods(Core.kwfunc(f)))) + end + let Base.@constprop :none f(::Any; x::Int=1) = 2x + @test Core.Compiler.is_no_constprop(only(methods(f))) + @test Core.Compiler.is_no_constprop(only(methods(Core.kwfunc(f)))) + end + # @nospecialize + let f(@nospecialize(A::Any); x::Int=1) = 2x + @test only(methods(f)).nospecialize == 1 + @test only(methods(Core.kwfunc(f))).nospecialize == 4 + end + let f(::Any; x::Int=1) = (@nospecialize; 2x) + @test only(methods(f)).nospecialize == -1 + @test only(methods(Core.kwfunc(f))).nospecialize == -1 + end + # Base.@assume_effects + let Base.@assume_effects :notaskstate f(::Any; x::Int=1) = 2x + @test Core.Compiler.decode_effects_override(only(methods(f)).purity).notaskstate + @test Core.Compiler.decode_effects_override(only(methods(Core.kwfunc(f))).purity).notaskstate + end + # propagate multiple metadata also + let @inline Base.@assume_effects :notaskstate Base.@constprop :aggressive f(::Any; x::Int=1) = (@nospecialize; 2x) + @test ccall(:jl_ir_flag_inlineable, Bool, (Any,), only(methods(f)).source) + @test Core.Compiler.is_aggressive_constprop(only(methods(f))) + @test ccall(:jl_ir_flag_inlineable, Bool, (Any,), only(methods(Core.kwfunc(f))).source) + @test Core.Compiler.is_aggressive_constprop(only(methods(Core.kwfunc(f)))) + @test only(methods(f)).nospecialize == -1 + @test only(methods(Core.kwfunc(f))).nospecialize == -1 + @test Core.Compiler.decode_effects_override(only(methods(f)).purity).notaskstate + @test Core.Compiler.decode_effects_override(only(methods(Core.kwfunc(f))).purity).notaskstate + end +end diff --git a/test/compiler/irpasses.jl b/test/compiler/irpasses.jl index 48682b9af3b95..8211de9689fc0 100644 --- a/test/compiler/irpasses.jl +++ b/test/compiler/irpasses.jl @@ -933,8 +933,8 @@ let end |> only |> first end - refs = map(Core.SSAValue, findall(x->x isa Expr && x.head == :new, src.code)) - some_ccall = findfirst(x -> x isa Expr && x.head == :foreigncall && x.args[1] == :(:some_ccall), src.code) + refs = map(Core.SSAValue, findall(@nospecialize(x)->Meta.isexpr(x, :new), src.code)) + some_ccall = findfirst(@nospecialize(x) -> Meta.isexpr(x, :foreigncall) && x.args[1] == :(:some_ccall), src.code) @assert some_ccall !== nothing stmt = src.code[some_ccall] nccallargs = length(stmt.args[3]::Core.SimpleVector) diff --git a/test/compiler/ssair.jl b/test/compiler/ssair.jl index 86545c8d0088c..1acd490a47295 100644 --- a/test/compiler/ssair.jl +++ b/test/compiler/ssair.jl @@ -205,7 +205,7 @@ let ci = make_ci([ # come after it. for i in 1:length(ir.stmts) s = ir.stmts[i] - if isa(s, Expr) && s.head == :call && s.args[1] == :something + if Meta.isexpr(s, :call) && s.args[1] === :something if isa(s.args[2], SSAValue) @test s.args[2].id <= i end diff --git a/test/complex.jl b/test/complex.jl index 20470dd5617e7..40b45870feafc 100644 --- a/test/complex.jl +++ b/test/complex.jl @@ -935,6 +935,7 @@ end @test cispi(0.0+0.0im) == cispi(0) @test cispi(1.0+0.0im) == cispi(1) @test cispi(2.0+0.0im) == cispi(2) + @test cispi(5im) ≈ exp(-5pi) rtol=1e-10 # https://github.com/JuliaLang/julia/pull/45945 end @testset "exp2" begin diff --git a/test/core.jl b/test/core.jl index e5b1c231d39a8..dfb7414e034a8 100644 --- a/test/core.jl +++ b/test/core.jl @@ -2838,10 +2838,10 @@ let f end end for m in methods(f10373) - @test m.name == :f10373 + @test m.name === :f10373 end for m in methods(g10373) - @test m.name == :g10373 + @test m.name === :g10373 end # issue #7221 @@ -3607,7 +3607,7 @@ let @test false catch err @test isa(err, TypeError) - @test err.func == :Vararg + @test err.func === :Vararg @test err.expected == Int @test err.got == Int end @@ -3617,7 +3617,7 @@ let @test false catch err @test isa(err, TypeError) - @test err.func == :Vararg + @test err.func === :Vararg @test err.expected == Int @test err.got == 0x1 end @@ -4229,7 +4229,7 @@ end let ex = quote $(if true; :(test); end) end - @test ex.args[2] == :test + @test ex.args[2] === :test end # issue #15180 @@ -7808,3 +7808,7 @@ end import .Foo45350: x45350 f45350() = (global x45350 = 2) @test_throws ErrorException f45350() + +@testset "effect override on Symbol(::String)" begin + @test Core.Compiler.is_foldable(Base.infer_effects(Symbol, (String,))) +end diff --git a/test/corelogging.jl b/test/corelogging.jl index 1b1254e78b3d6..05a9ca378056d 100644 --- a/test/corelogging.jl +++ b/test/corelogging.jl @@ -120,8 +120,8 @@ end @test length(logger.logs) == 1 record = logger.logs[1] @test record._module == Base.Core - @test record.group == :somegroup - @test record.id == :asdf + @test record.group === :somegroup + @test record.id === :asdf @test record.file == "/a/file" @test record.line == -10 # Test consistency with shouldlog() function arguments @@ -435,7 +435,7 @@ end (record,), _ = collect_test_logs() do @info "test" end - @test record.group == :corelogging # name of this file + @test record.group === :corelogging # name of this file end @testset "complicated kwargs logging macro" begin diff --git a/test/deprecation_exec.jl b/test/deprecation_exec.jl index 5a120f8e2ee76..1f936329d1372 100644 --- a/test/deprecation_exec.jl +++ b/test/deprecation_exec.jl @@ -132,7 +132,7 @@ f25130() testlogs = testlogger.logs @test length(testlogs) == 2 @test testlogs[1].id != testlogs[2].id -@test testlogs[1].kwargs[:caller].func == Symbol("top-level scope") +@test testlogs[1].kwargs[:caller].func === Symbol("top-level scope") @test all(l.message == "f25130 message" for l in testlogs) global_logger(prev_logger) diff --git a/test/dict.jl b/test/dict.jl index 9695877f44028..de0ce88fb5a0f 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -196,7 +196,7 @@ end bestkey(d, key) = key bestkey(d::AbstractDict{K,V}, key) where {K<:AbstractString,V} = string(key) bar(x) = bestkey(x, :y) - @test bar(Dict(:x => [1,2,5])) == :y + @test bar(Dict(:x => [1,2,5])) === :y @test bar(Dict("x" => [1,2,5])) == "y" end @@ -1150,7 +1150,7 @@ end @test isempty(findall(isequal(1), Dict())) @test isempty(findall(isequal(1), Dict(:a=>2, :b=>3))) - @test findfirst(isequal(1), Dict(:a=>1, :b=>2)) == :a + @test findfirst(isequal(1), Dict(:a=>1, :b=>2)) === :a @test findfirst(isequal(1), Dict(:a=>1, :b=>1, :c=>3)) in (:a, :b) @test findfirst(isequal(1), Dict()) === nothing @test findfirst(isequal(1), Dict(:a=>2, :b=>3)) === nothing diff --git a/test/docs.jl b/test/docs.jl index 762a481ee4801..4399722e864c1 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -12,26 +12,19 @@ using InteractiveUtils: apropos include("testenv.jl") # Test helpers. -function docstrings_equal(d1, d2) +function docstrings_equal(d1, d2; debug=true) io1 = IOBuffer() io2 = IOBuffer() show(io1, MIME"text/markdown"(), d1) show(io2, MIME"text/markdown"(), d2) s1 = String(take!(io1)) s2 = String(take!(io2)) - #if s1 != s2 # for debugging - # e1 = eachline(IOBuffer(s1)) - # e2 = eachline(IOBuffer(s2)) - # for (l1, l2) in zip(e1, e2) - # l1 == l2 || println(l1, "\n", l2, "\n") - # end - # for l1 in e1 - # println(l1, "\n[missing]\n") - # end - # for l2 in e2 - # println("[missing]\n", l2, "\n") - # end - #end + if debug && s1 != s2 + print(s1) + println("--------------------------------------------------------------------------------") + print(s2) + println("================================================================================") + end return s1 == s2 end docstrings_equal(d1::DocStr, d2) = docstrings_equal(parsedoc(d1), d2) @@ -177,7 +170,7 @@ t(::AbstractString) "t-2" t(::Int, ::Any) "t-3" -t{S <: Integer}(::S) +t(::S) where {S <: Integer} # Docstrings to parametric methods after definition using where syntax (#32960): tw(x::T) where T = nothing @@ -357,7 +350,7 @@ let d1 = @doc(DocsTest.t(::Int, ::Any)), @test docstrings_equal(d1,d2) end -let d1 = @doc(DocsTest.t{S <: Integer}(::S)), +let d1 = @doc(DocsTest.t(::S) where {S <: Integer}), d2 = doc"t-3" @test docstrings_equal(d1,d2) end @@ -655,7 +648,7 @@ end @doc "This should document @m1... since its the result of expansion" @m2_11993 @test (@doc @m1_11993) !== nothing let d = (@doc :@m2_11993), - macro_doc = Markdown.parse("`$(curmod_prefix)@m2_11993` is a macro.") + macro_doc = Markdown.parse("`$(curmod_prefix == "Main." ? "" : curmod_prefix)@m2_11993` is a macro.") @test docstring_startswith(d, doc""" No documentation found. @@ -723,7 +716,7 @@ f12593_2() = 1 # crude test to make sure we sort docstring output by method specificity @test !docstrings_equal(Docs.doc(getindex, Tuple{Dict{Int,Int},Int}), - Docs.doc(getindex, Tuple{Type{Int64},Int})) + Docs.doc(getindex, Tuple{Type{Int64},Int}); debug=false) # test that macro documentation works @test (@repl :@assert) !== nothing @@ -794,7 +787,7 @@ end # Issue #13905. let err = try; @macroexpand(@doc "" f() = @x); false; catch ex; ex; end err::UndefVarError - @test err.var == Symbol("@x") + @test err.var === Symbol("@x") end @@ -1209,11 +1202,11 @@ end import Base.Docs: @var, Binding, defined -let x = Binding(Base, Symbol("@time")) +let x = Binding(Base, Symbol("@inline")) @test defined(x) == true - @test @var(@time) == x - @test @var(Base.@time) == x - @test @var(Base.Iterators.@time) == x + @test @var(@inline) == x + @test @var(Base.@inline) == x + @test @var(Base.Iterators.@inline) == x end let x = Binding(Iterators, :enumerate) @@ -1302,9 +1295,9 @@ dynamic_test.x = "test 2" function striptrimdocs(expr) if Meta.isexpr(expr, :call) fex = expr.args[1] - if Meta.isexpr(fex, :.) && fex.args[1] == :REPL + if Meta.isexpr(fex, :.) && fex.args[1] === :REPL fmex = fex.args[2] - if isa(fmex, QuoteNode) && fmex.value == :trimdocs + if isa(fmex, QuoteNode) && fmex.value === :trimdocs expr = expr.args[2] end end @@ -1316,28 +1309,28 @@ let dt1 = striptrimdocs(_repl(:(dynamic_test(1.0)))) @test dt1 isa Expr @test dt1.args[1] isa Expr @test dt1.args[1].head === :macrocall - @test dt1.args[1].args[1] == Symbol("@doc") + @test dt1.args[1].args[1] === Symbol("@doc") @test dt1.args[1].args[3] == :(dynamic_test(::typeof(1.0))) end let dt2 = striptrimdocs(_repl(:(dynamic_test(::String)))) @test dt2 isa Expr @test dt2.args[1] isa Expr @test dt2.args[1].head === :macrocall - @test dt2.args[1].args[1] == Symbol("@doc") + @test dt2.args[1].args[1] === Symbol("@doc") @test dt2.args[1].args[3] == :(dynamic_test(::String)) end let dt3 = striptrimdocs(_repl(:(dynamic_test(a)))) @test dt3 isa Expr @test dt3.args[1] isa Expr @test dt3.args[1].head === :macrocall - @test dt3.args[1].args[1] == Symbol("@doc") - @test dt3.args[1].args[3].args[2].head == :(::) # can't test equality due to line numbers + @test dt3.args[1].args[1] === Symbol("@doc") + @test dt3.args[1].args[3].args[2].head === :(::) # can't test equality due to line numbers end let dt4 = striptrimdocs(_repl(:(dynamic_test(1.0,u=2.0)))) @test dt4 isa Expr @test dt4.args[1] isa Expr @test dt4.args[1].head === :macrocall - @test dt4.args[1].args[1] == Symbol("@doc") + @test dt4.args[1].args[1] === Symbol("@doc") @test dt4.args[1].args[3] == :(dynamic_test(::typeof(1.0); u::typeof(2.0)=2.0)) end @@ -1441,27 +1434,36 @@ end struct t_docs_abc end @test "t_docs_abc" in accessible(@__MODULE__) -# Call overloading issue #20087 +# Call overloading issues #20087 and #44889 """ Docs for `MyFunc` struct. """ -mutable struct MyFunc - x -end +mutable struct MyFunc x end +""" +Docs for `MyParametricFunc{T}` struct. +""" +struct MyParametricFunc{T} end """ Docs for calling `f::MyFunc`. """ -function (f::MyFunc)(x) - f.x = x - return f -end +(f::MyFunc)(x) = f -@test docstrings_equal(@doc(MyFunc(2)), +""" +Docs for calling `f::MyParametricFunc{T}`. +""" +(f::MyParametricFunc{T})(x) where T = f + +@test docstrings_equal(@doc((::MyFunc)(2)), doc""" Docs for calling `f::MyFunc`. """) +@test docstrings_equal(@doc((::MyParametricFunc{Int})(44889)), +doc""" +Docs for calling `f::MyParametricFunc{T}`. +""") + struct A_20087 end """a""" diff --git a/test/errorshow.jl b/test/errorshow.jl index b578c5025e98e..a05a86a797234 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -680,7 +680,7 @@ end getbt() = backtrace() bt = getbt() Base.update_stackframes_callback[] = function(list) - modify((sf, n)) = sf.func == :getbt ? (StackTraces.StackFrame(sf.func, sf.file, sf.line+2, sf.linfo, sf.from_c, sf.inlined, sf.pointer), n) : (sf, n) + modify((sf, n)) = sf.func === :getbt ? (StackTraces.StackFrame(sf.func, sf.file, sf.line+2, sf.linfo, sf.from_c, sf.inlined, sf.pointer), n) : (sf, n) map!(modify, list, list) end io = IOBuffer() diff --git a/test/exceptions.jl b/test/exceptions.jl index d8d1e7b45b8b5..eb0bbaec35090 100644 --- a/test/exceptions.jl +++ b/test/exceptions.jl @@ -276,7 +276,7 @@ end exc end yield(t) - @test t.state == :done + @test t.state === :done @test t.result == ErrorException("B") # Task exception state is preserved around task switches @test length(current_exceptions()) == 1 @@ -296,7 +296,7 @@ end exc end yield(t) - @test t.state == :done + @test t.state === :done @test t.result == ErrorException("B") @test bt == catch_backtrace() rethrow() @@ -318,7 +318,7 @@ end exc end yield(t) - @test t.state == :done + @test t.state === :done @test t.result == ErrorException("B") bt = catch_backtrace() rethrow(ErrorException("C")) @@ -335,7 +335,7 @@ end error("B") end yield(t) - @test t.state == :failed + @test t.state === :failed @test t.result == ErrorException("B") @test current_exceptions(t, backtrace=false) == [ (exception=ErrorException("A"),backtrace=nothing), diff --git a/test/iterators.jl b/test/iterators.jl index 453f27ca8885c..0258de116caa3 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -326,6 +326,8 @@ let itr @test collect(itr) == Int[] # Stateful do not preserve shape itr = (i-1 for i in Base.Stateful(zeros(Int, 0, 0))) @test collect(itr) == Int[] # Stateful do not preserve shape + itr = Iterators.Stateful(Iterators.Stateful(1:1)) + @test collect(itr) == [1] end # with 1D inputs diff --git a/test/keywordargs.jl b/test/keywordargs.jl index 9cbae2b1a0b19..0e651cf7f4531 100644 --- a/test/keywordargs.jl +++ b/test/keywordargs.jl @@ -288,7 +288,7 @@ end end @testset "issue #21510" begin f21510(; @nospecialize a = 2) = a - @test f21510(a=:b) == :b + @test f21510(a=:b) === :b @test f21510() == 2 end @testset "issue #34516" begin diff --git a/test/math.jl b/test/math.jl index 8938b6a8864ab..d788e0c939a05 100644 --- a/test/math.jl +++ b/test/math.jl @@ -1468,4 +1468,6 @@ for fn in (:sin, :cos, :tan, :log, :log2, :log10, :log1p, :exponent, :sqrt, :cbr end end end -@test Core.Compiler.is_foldable(Base.infer_effects(^, (Float32,Int))) +for T in (Float32, Float64) + @test Core.Compiler.is_foldable(Base.infer_effects(^, (T,Int))) +end diff --git a/test/meta.jl b/test/meta.jl index 5bdb988f41b6d..fd984cc837e4c 100644 --- a/test/meta.jl +++ b/test/meta.jl @@ -221,8 +221,8 @@ let a = 1 @test @macroexpand @is_dollar_expr $a end -@test Meta.parseatom("@foo", 1, filename=:bar)[1].args[2].file == :bar -@test Meta.parseall("@foo", filename=:bar).args[1].file == :bar +@test Meta.parseatom("@foo", 1, filename=:bar)[1].args[2].file === :bar +@test Meta.parseall("@foo", filename=:bar).args[1].file === :bar _lower(m::Module, ex, world::UInt) = ccall(:jl_expand_in_world, Any, (Any, Ref{Module}, Cstring, Cint, Csize_t), ex, m, "none", 0, world) diff --git a/test/misc.jl b/test/misc.jl index 0e93660b2bd2e..be5c8593351ff 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -191,7 +191,7 @@ end sleep(rand(0:0.01:0.1)) history[Threads.atomic_add!(clock, 1)] = Threads.atomic_sub!(occupied, 1) - 1 return :resultvalue - end == :resultvalue + end === :resultvalue end end @test all(<=(sem_size), history) diff --git a/test/namedtuple.jl b/test/namedtuple.jl index 3b571b3c7d612..94eb14008dc52 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -257,10 +257,10 @@ abstr_nt_22194_3() @test findall(isequal(1), (a=1, b=1)) == [:a, :b] @test isempty(findall(isequal(1), NamedTuple())) @test isempty(findall(isequal(1), (a=2, b=3))) -@test findfirst(isequal(1), (a=1, b=2)) == :a -@test findlast(isequal(1), (a=1, b=2)) == :a -@test findfirst(isequal(1), (a=1, b=1)) == :a -@test findlast(isequal(1), (a=1, b=1)) == :b +@test findfirst(isequal(1), (a=1, b=2)) === :a +@test findlast(isequal(1), (a=1, b=2)) === :a +@test findfirst(isequal(1), (a=1, b=1)) === :a +@test findlast(isequal(1), (a=1, b=1)) === :b @test findfirst(isequal(1), ()) === nothing @test findlast(isequal(1), ()) === nothing @test findfirst(isequal(1), (a=2, b=3)) === nothing diff --git a/test/numbers.jl b/test/numbers.jl index ad521d7382713..11b54191d3d6a 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -95,34 +95,68 @@ end @test max(1) === 1 @test minmax(1) === (1, 1) @test minmax(5, 3) == (3, 5) - @test minmax(3., 5.) == (3., 5.) - @test minmax(5., 3.) == (3., 5.) - @test minmax(3., NaN) ≣ (NaN, NaN) - @test minmax(NaN, 3) ≣ (NaN, NaN) - @test minmax(Inf, NaN) ≣ (NaN, NaN) - @test minmax(NaN, Inf) ≣ (NaN, NaN) - @test minmax(-Inf, NaN) ≣ (NaN, NaN) - @test minmax(NaN, -Inf) ≣ (NaN, NaN) - @test minmax(NaN, NaN) ≣ (NaN, NaN) - @test min(-0.0,0.0) === min(0.0,-0.0) - @test max(-0.0,0.0) === max(0.0,-0.0) - @test minmax(-0.0,0.0) === minmax(0.0,-0.0) - @test max(-3.2, 5.1) == max(5.1, -3.2) == 5.1 - @test min(-3.2, 5.1) == min(5.1, -3.2) == -3.2 - @test max(-3.2, Inf) == max(Inf, -3.2) == Inf - @test max(-3.2, NaN) ≣ max(NaN, -3.2) ≣ NaN - @test min(5.1, Inf) == min(Inf, 5.1) == 5.1 - @test min(5.1, -Inf) == min(-Inf, 5.1) == -Inf - @test min(5.1, NaN) ≣ min(NaN, 5.1) ≣ NaN - @test min(5.1, -NaN) ≣ min(-NaN, 5.1) ≣ NaN - @test minmax(-3.2, 5.1) == (min(-3.2, 5.1), max(-3.2, 5.1)) - @test minmax(-3.2, Inf) == (min(-3.2, Inf), max(-3.2, Inf)) - @test minmax(-3.2, NaN) ≣ (min(-3.2, NaN), max(-3.2, NaN)) - @test (max(Inf,NaN), max(-Inf,NaN), max(Inf,-NaN), max(-Inf,-NaN)) ≣ (NaN,NaN,NaN,NaN) - @test (max(NaN,Inf), max(NaN,-Inf), max(-NaN,Inf), max(-NaN,-Inf)) ≣ (NaN,NaN,NaN,NaN) - @test (min(Inf,NaN), min(-Inf,NaN), min(Inf,-NaN), min(-Inf,-NaN)) ≣ (NaN,NaN,NaN,NaN) - @test (min(NaN,Inf), min(NaN,-Inf), min(-NaN,Inf), min(-NaN,-Inf)) ≣ (NaN,NaN,NaN,NaN) - @test minmax(-Inf,NaN) ≣ (min(-Inf,NaN), max(-Inf,NaN)) + Top(T, op, x, y) = op(T.(x), T.(y)) + Top(T, op) = (x, y) -> Top(T, op, x, y) + _compare(x, y) = x == y + for T in (Float16, Float32, Float64, BigFloat) + minmax = Top(T,Base.minmax) + min = Top(T,Base.min) + max = Top(T,Base.max) + (==) = Top(T,_compare) + (===) = Top(T,Base.isequal) # we only use === to compare -0.0/0.0, `isequal` should be equalvient + @test minmax(3., 5.) == (3., 5.) + @test minmax(5., 3.) == (3., 5.) + @test minmax(3., NaN) ≣ (NaN, NaN) + @test minmax(NaN, 3) ≣ (NaN, NaN) + @test minmax(Inf, NaN) ≣ (NaN, NaN) + @test minmax(NaN, Inf) ≣ (NaN, NaN) + @test minmax(-Inf, NaN) ≣ (NaN, NaN) + @test minmax(NaN, -Inf) ≣ (NaN, NaN) + @test minmax(NaN, NaN) ≣ (NaN, NaN) + @test min(-0.0,0.0) === min(0.0,-0.0) + @test max(-0.0,0.0) === max(0.0,-0.0) + @test minmax(-0.0,0.0) === minmax(0.0,-0.0) + @test max(-3.2, 5.1) == max(5.1, -3.2) == 5.1 + @test min(-3.2, 5.1) == min(5.1, -3.2) == -3.2 + @test max(-3.2, Inf) == max(Inf, -3.2) == Inf + @test max(-3.2, NaN) ≣ max(NaN, -3.2) ≣ NaN + @test min(5.1, Inf) == min(Inf, 5.1) == 5.1 + @test min(5.1, -Inf) == min(-Inf, 5.1) == -Inf + @test min(5.1, NaN) ≣ min(NaN, 5.1) ≣ NaN + @test min(5.1, -NaN) ≣ min(-NaN, 5.1) ≣ NaN + @test minmax(-3.2, 5.1) == (min(-3.2, 5.1), max(-3.2, 5.1)) + @test minmax(-3.2, Inf) == (min(-3.2, Inf), max(-3.2, Inf)) + @test minmax(-3.2, NaN) ≣ (min(-3.2, NaN), max(-3.2, NaN)) + @test (max(Inf,NaN), max(-Inf,NaN), max(Inf,-NaN), max(-Inf,-NaN)) ≣ (NaN,NaN,NaN,NaN) + @test (max(NaN,Inf), max(NaN,-Inf), max(-NaN,Inf), max(-NaN,-Inf)) ≣ (NaN,NaN,NaN,NaN) + @test (min(Inf,NaN), min(-Inf,NaN), min(Inf,-NaN), min(-Inf,-NaN)) ≣ (NaN,NaN,NaN,NaN) + @test (min(NaN,Inf), min(NaN,-Inf), min(-NaN,Inf), min(-NaN,-Inf)) ≣ (NaN,NaN,NaN,NaN) + @test minmax(-Inf,NaN) ≣ (min(-Inf,NaN), max(-Inf,NaN)) + end +end +@testset "Base._extrema_rf for float" begin + for T in (Float16, Float32, Float64, BigFloat) + ordered = T[-Inf, -5, -0.0, 0.0, 3, Inf] + unorded = T[NaN, -NaN] + for i1 in 1:6, i2 in 1:6, j1 in 1:6, j2 in 1:6 + x = ordered[i1], ordered[i2] + y = ordered[j1], ordered[j2] + z = ordered[min(i1,j1)], ordered[max(i2,j2)] + @test Base._extrema_rf(x, y) === z + end + for i in 1:2, j1 in 1:6, j2 in 1:6 # unordered test (only 1 NaN) + x = unorded[i] , unorded[i] + y = ordered[j1], ordered[j2] + @test Base._extrema_rf(x, y) === x + @test Base._extrema_rf(y, x) === x + end + for i in 1:2, j in 1:2 # unordered test (2 NaNs) + x = unorded[i], unorded[i] + y = unorded[j], unorded[j] + z = Base._extrema_rf(x, y) + @test z === x || z === y + end + end end @testset "fma" begin let x = Int64(7)^7 @@ -1650,8 +1684,13 @@ end @test rem(prevfloat(1.0),1.0) == prevfloat(1.0) @test mod(prevfloat(1.0),1.0) == prevfloat(1.0) end - # issue #3046 - @test mod(Int64(2),typemax(Int64)) == 2 + @test mod(Int64(2), typemax(Int64)) == 2 # issue #3046 + @testset "issue #45875" begin + @test cld(+1.1, 0.1) == div(+1.1, 0.1, RoundUp) == ceil(big(+1.1)/big(0.1)) == +12.0 + @test fld(+1.1, 0.1) == div(+1.1, 0.1, RoundDown) == floor(big(+1.1)/big(0.1)) == +11.0 + @test cld(-1.1, 0.1) == div(-1.1, 0.1, RoundUp) == ceil(big(-1.1)/big(0.1)) == -11.0 + @test fld(-1.1, 0.1) == div(-1.1, 0.1, RoundDown) == floor(big(-1.1)/big(0.1)) == -12.0 + end end @testset "return types" begin for T in (Int8,Int16,Int32,Int64,Int128, UInt8,UInt16,UInt32,UInt64,UInt128) @@ -2550,13 +2589,12 @@ end @test isnan(rem(T(1), T(0), mode)) @test isnan(rem(T(Inf), T(2), mode)) @test isnan(rem(T(1), T(NaN), mode)) - # FIXME: The broken case erroneously returns -Inf - @test rem(T(4), floatmin(T) * 2, mode) == 0 broken=(T == BigFloat && mode in (RoundUp,RoundFromZero)) + @test rem(T(4), floatmin(T) * 2, mode) == 0 end @test isequal(rem(nextfloat(typemin(T)), T(2), RoundToZero), -0.0) @test isequal(rem(nextfloat(typemin(T)), T(2), RoundNearest), -0.0) @test isequal(rem(nextfloat(typemin(T)), T(2), RoundDown), 0.0) - @test isequal(rem(nextfloat(typemin(T)), T(2), RoundUp), 0.0) + @test isequal(rem(nextfloat(typemin(T)), T(2), RoundUp), -0.0) @test isequal(rem(nextfloat(typemin(T)), T(2), RoundFromZero), 0.0) end @@ -2816,7 +2854,7 @@ end @testset "constructor inferability for BigFloat" begin T = BigFloat @test_broken all(R -> R<:T, Base.return_types(T)) - @test all(m -> m.file == Symbol("deprecated.jl"), + @test all(m -> m.file === Symbol("deprecated.jl"), collect(methods(T))[findall(R -> !(R<:T), Base.return_types(T))]) end diff --git a/test/operators.jl b/test/operators.jl index 5e505391afd5a..65d5e5726b312 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -2,6 +2,8 @@ using Random: randstring +include("compiler/irutils.jl") + @testset "ifelse" begin @test ifelse(true, 1, 2) == 1 @test ifelse(false, 1, 2) == 2 @@ -44,11 +46,11 @@ end p = 1=>:foo @test first(p) == 1 - @test last(p) == :foo - @test first(reverse(p)) == :foo + @test last(p) === :foo + @test first(reverse(p)) === :foo @test last(reverse(p)) == 1 @test lastindex(p) == 2 - @test p[lastindex(p)] == p[end] == p[2] == :foo + @test p[lastindex(p)] == p[end] == p[2] === :foo end # Infix `isa` @@ -182,6 +184,11 @@ end @test (@inferred g(1)) == ntuple(Returns(1), 13) h = (-) ∘ (-) ∘ (-) ∘ (-) ∘ (-) ∘ (-) ∘ sum @test (@inferred h((1, 2, 3); init = 0.0)) == 6.0 + issue_45877 = reduce(∘, fill(sin,500)) + @test Core.Compiler.is_foldable(Base.infer_effects(Base.unwrap_composed, (typeof(issue_45877),))) + @test fully_eliminated() do + issue_45877(1.0) + end end @testset "function negation" begin diff --git a/test/precompile.jl b/test/precompile.jl index f7e3e93acd27e..c23fffb663088 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -313,8 +313,8 @@ precompile_test_harness(false) do dir # the module doesn't reload from the image: @test_warn "@ccallable was already defined for this method name" begin @test_logs (:warn, "Replacing module `$Foo_module`") begin - ms = Base._require_from_serialized(Base.PkgId(Foo), cachefile) - @test isa(ms, Array{Any,1}) + m = Base._require_from_serialized(Base.PkgId(Foo), cachefile) + @test isa(m, Module) end end diff --git a/test/reflection.jl b/test/reflection.jl index 5fd1be83ce01e..3f3f394ed71b5 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -147,7 +147,7 @@ module TestModSub9475 let @test Base.binding_module(@__MODULE__, :a9475) == @__MODULE__ @test Base.binding_module(@__MODULE__, :c7648) == TestMod7648 - @test Base.nameof(@__MODULE__) == :TestModSub9475 + @test Base.nameof(@__MODULE__) === :TestModSub9475 @test Base.fullname(@__MODULE__) == (curmod_name..., :TestMod7648, :TestModSub9475) @test Base.parentmodule(@__MODULE__) == TestMod7648 end @@ -158,7 +158,7 @@ using .TestModSub9475 let @test Base.binding_module(@__MODULE__, :d7648) == @__MODULE__ @test Base.binding_module(@__MODULE__, :a9475) == TestModSub9475 - @test Base.nameof(@__MODULE__) == :TestMod7648 + @test Base.nameof(@__MODULE__) === :TestMod7648 @test Base.parentmodule(@__MODULE__) == curmod end end # module TestMod7648 @@ -183,14 +183,14 @@ let using .TestMod7648 @test Base.binding_module(@__MODULE__, :a9475) == TestMod7648.TestModSub9475 @test Base.binding_module(@__MODULE__, :c7648) == TestMod7648 - @test nameof(foo7648) == :foo7648 + @test nameof(foo7648) === :foo7648 @test parentmodule(foo7648, (Any,)) == TestMod7648 @test parentmodule(foo7648) == TestMod7648 @test parentmodule(foo7648_nomethods) == TestMod7648 @test parentmodule(foo9475, (Any,)) == TestMod7648.TestModSub9475 @test parentmodule(foo9475) == TestMod7648.TestModSub9475 @test parentmodule(Foo7648) == TestMod7648 - @test nameof(Foo7648) == :Foo7648 + @test nameof(Foo7648) === :Foo7648 @test basename(functionloc(foo7648, (Any,))[1]) == "reflection.jl" @test first(methods(TestMod7648.TestModSub9475.foo7648)) == which(foo7648, (Int,)) @test TestMod7648 == which(@__MODULE__, :foo7648) @@ -724,7 +724,7 @@ Base.delete_method(m) # Methods with keyword arguments fookw(x; direction=:up) = direction fookw(y::Int) = 2 -@test fookw("string") == :up +@test fookw("string") === :up @test fookw(1) == 2 m = collect(methods(fookw))[2] Base.delete_method(m) @@ -995,4 +995,6 @@ function f_no_methods end # builtins @test Base.infer_effects(typeof, (Any,)) |> Core.Compiler.is_total @test Base.infer_effects(===, (Any,Any)) |> Core.Compiler.is_total + @test (Base.infer_effects(setfield!, ()); true) # `builtin_effects` shouldn't throw on empty `argtypes` + @test (Base.infer_effects(Core.Intrinsics.arraylen, ()); true) # `intrinsic_effects` shouldn't throw on empty `argtypes` end diff --git a/test/regex.jl b/test/regex.jl index 1cc377d9cfdbf..37bed00ef0b97 100644 --- a/test/regex.jl +++ b/test/regex.jl @@ -74,6 +74,10 @@ @test findall([0x01, 0x01], [0x01, 0x01, 0x01, 0x01]) == [1:2, 3:4] @test findall([0x01, 0x01], [0x01, 0x01, 0x01, 0x01]; overlap=true) == [1:2, 2:3, 3:4] + # findnext + @test findnext(r"z", "zabcz", 2) == 5:5 + @test_throws BoundsError findnext(r"z", "zabcz", 7) + # count @test count(r"\w+", "foo bar") == 2 @test count(r"\w+", "foo bar", overlap=true) == 6 @@ -119,6 +123,10 @@ # Backcapture reference in substitution string @test replace("abcde", r"(..)(?Pd)" => s"\gxy\\\1") == "adxy\\bce" @test_throws ErrorException replace("a", r"(?P)" => s"\g") + # test replace with invalid substitution group pattern + @test_throws ErrorException replace("s", r"(?.)" => s"\gg1>") + # test replace with 2-digit substitution group + @test replace(("0" ^ 9) * "1", Regex(("(0)" ^ 9) * "(1)") => s"10th group: \10") == "10th group: 1" # Proper unicode handling @test match(r"∀∀", "∀x∀∀∀").match == "∀∀" @@ -141,6 +149,8 @@ @test startswith("abc", r"A"i) @test !endswith("abc", r"C") @test endswith("abc", r"C"i) + # test with substring + @test endswith((@views "abc"[2:3]), r"C"i) @testset "multiplication & exponentiation" begin @test *(r"a") == r"a" @@ -206,4 +216,11 @@ # test that we can get the error message of negative error codes @test Base.PCRE.err_message(Base.PCRE.ERROR_NOMEMORY) isa String + + # test failure cases for invalid integer flags + @test_throws ArgumentError Regex("test", typemax(Int32), 0) + @test_throws ArgumentError Regex("test", 0, typemax(Int32)) + + # hash + @test hash(r"123"i, zero(UInt)) == hash(Regex("123", "i"), zero(UInt)) end diff --git a/test/sets.jl b/test/sets.jl index 9410739596486..1a86b5abd746f 100644 --- a/test/sets.jl +++ b/test/sets.jl @@ -115,7 +115,7 @@ end @test in(2,s) @test length(s) == 2 @test_throws KeyError pop!(s,1) - @test pop!(s,1,:foo) == :foo + @test pop!(s,1,:foo) === :foo @test length(delete!(s,2)) == 1 @test !in(1,s) @test !in(2,s) diff --git a/test/show.jl b/test/show.jl index 5aff7b1b3d6b0..a0352540e2d9d 100644 --- a/test/show.jl +++ b/test/show.jl @@ -603,7 +603,7 @@ let q1 = Meta.parse(repr(:("$(a)b"))), @test q1.args[1].args == [:a, "b"] @test isa(q2, Expr) - @test q2.args[1].head == :string + @test q2.args[1].head === :string @test q2.args[1].args == [:ab,] end @@ -775,6 +775,13 @@ let repr = sprint(show, "text/plain", methods(triangular_methodshow)) @test occursin("where {T2<:Integer, T1<:T2}", repr) end +struct S45879{P} end +let ms = methods(S45879) + @test ms isa Base.MethodList + @test length(ms) == 0 + @test sprint(show, Base.MethodList(Method[], typeof(S45879).name.mt)) isa String +end + if isempty(Base.GIT_VERSION_INFO.commit) @test occursin("https://github.com/JuliaLang/julia/tree/v$VERSION/base/special/trig.jl#L", Base.url(which(sin, (Float64,)))) else diff --git a/test/strings/basic.jl b/test/strings/basic.jl index b7021e3a2c2cb..c1f1473daa236 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -418,7 +418,7 @@ end end @test nextind("fóobar", 0, 3) == 4 - @test Symbol(gstr) == Symbol("12") + @test Symbol(gstr) === Symbol("12") @test sizeof(gstr) == 2 @test ncodeunits(gstr) == 2 diff --git a/test/syntax.jl b/test/syntax.jl index 3d306e8c2d780..f7bb2dd6fdbb6 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -649,7 +649,7 @@ function get_expr_list(ex::Core.CodeInfo) return ex.code::Array{Any,1} end function get_expr_list(ex::Expr) - if ex.head == :thunk + if ex.head === :thunk return get_expr_list(ex.args[1]) else return ex.args @@ -755,7 +755,7 @@ end if test + test == test println(test) end -```.head == :if +```.head === :if end @@ -853,7 +853,7 @@ end # Check that the body of a `where`-qualified short form function definition gets # a :block for its body short_where_call = :(f(x::T) where T = T) -@test short_where_call.args[2].head == :block +@test short_where_call.args[2].head === :block # `where` with multi-line anonymous functions let f = function (x::T) where T @@ -2212,7 +2212,7 @@ end # only allow certain characters after interpolated vars (#25231) @test Meta.parse("\"\$x෴ \"",raise=false) == Expr(:error, "interpolated variable \$x ends with invalid character \"෴\"; use \"\$(x)\" instead.") -@test Base.incomplete_tag(Meta.parse("\"\$foo", raise=false)) == :string +@test Base.incomplete_tag(Meta.parse("\"\$foo", raise=false)) === :string @testset "issue #30341" begin @test Meta.parse("x .~ y") == Expr(:call, :.~, :x, :y) @@ -3039,10 +3039,10 @@ end end # issue #19012 -@test Meta.parse("\U2200", raise=false) == Symbol("∀") -@test Meta.parse("\U2203", raise=false) == Symbol("∃") -@test Meta.parse("a\U2203", raise=false) == Symbol("a∃") -@test Meta.parse("\U2204", raise=false) == Symbol("∄") +@test Meta.parse("\U2200", raise=false) === Symbol("∀") +@test Meta.parse("\U2203", raise=false) === Symbol("∃") +@test Meta.parse("a\U2203", raise=false) === Symbol("a∃") +@test Meta.parse("\U2204", raise=false) === Symbol("∄") # issue 42220 macro m42220() diff --git a/test/threadpool_use.jl b/test/threadpool_use.jl index 92a4458ee8076..47c45bdd71eb8 100644 --- a/test/threadpool_use.jl +++ b/test/threadpool_use.jl @@ -4,10 +4,10 @@ using Test using Base.Threads @test nthreadpools() == 2 -@test threadpool() == :default -@test threadpool(2) == :interactive -dtask() = @test threadpool(current_task()) == :default -itask() = @test threadpool(current_task()) == :interactive +@test threadpool() === :default +@test threadpool(2) === :interactive +dtask() = @test threadpool(current_task()) === :default +itask() = @test threadpool(current_task()) === :interactive dt1 = @spawn dtask() dt2 = @spawn :default dtask() it = @spawn :interactive itask() diff --git a/test/threads_exec.jl b/test/threads_exec.jl index a5e7ba6d7e21b..4bce3ebd71b41 100644 --- a/test/threads_exec.jl +++ b/test/threads_exec.jl @@ -265,7 +265,7 @@ end @test_throws TypeError Atomic{BigInt} @test_throws TypeError Atomic{ComplexF64} -if Sys.ARCH == :i686 || startswith(string(Sys.ARCH), "arm") || +if Sys.ARCH === :i686 || startswith(string(Sys.ARCH), "arm") || Sys.ARCH === :powerpc64le || Sys.ARCH === :ppc64le @test_throws TypeError Atomic{Int128}() diff --git a/test/tuple.jl b/test/tuple.jl index 055fd47a55cff..81b5b374fb28e 100644 --- a/test/tuple.jl +++ b/test/tuple.jl @@ -617,7 +617,7 @@ end @testset "properties" begin ttest = (:a, :b, :c) @test propertynames(ttest) == (1, 2, 3) - @test getproperty(ttest, 2) == :b + @test getproperty(ttest, 2) === :b @test map(p->getproperty(ttest, p), propertynames(ttest)) == ttest @test_throws ErrorException setproperty!(ttest, 1, :d) end