diff --git a/Make.inc b/Make.inc index 3fa153c7219c4..e1420dd5bac74 100644 --- a/Make.inc +++ b/Make.inc @@ -1225,6 +1225,9 @@ else NO_WHOLE_ARCHIVE := -Wl,--no-whole-archive endif +# Initialize these once, then add to them in OS-specific blocks +JLIBLDFLAGS := + ifeq ($(OS), Linux) OSLIBS += -Wl,--no-as-needed -ldl -lrt -lpthread -latomic -Wl,--export-dynamic,--as-needed,--no-whole-archive # Detect if ifunc is supported @@ -1238,12 +1241,12 @@ ifneq ($(SANITIZE),1) JLDFLAGS += -Wl,-no-undefined endif ifeq (-Bsymbolic-functions, $(shell $(LD) --help | grep -o -e "-Bsymbolic-functions")) -JLIBLDFLAGS := -Wl,-Bsymbolic-functions +JLIBLDFLAGS += -Wl,-Bsymbolic-functions else -JLIBLDFLAGS := endif -else ifneq ($(OS), Darwin) -JLIBLDFLAGS := +ifeq (--enable-new-dtags, $(shell $(LD) --help | grep -o -e "--enable-new-dtags")) +JLIBLDFLAGS += -Wl,--enable-new-dtags +endif endif ifeq ($(OS), FreeBSD) @@ -1266,7 +1269,7 @@ OSLIBS += -framework CoreFoundation WHOLE_ARCHIVE := -Xlinker -all_load NO_WHOLE_ARCHIVE := HAVE_SSP := 1 -JLIBLDFLAGS := -Wl,-compatibility_version,$(SOMAJOR) -Wl,-current_version,$(JULIA_MAJOR_VERSION).$(JULIA_MINOR_VERSION).$(JULIA_PATCH_VERSION) +JLIBLDFLAGS += -Wl,-compatibility_version,$(SOMAJOR) -Wl,-current_version,$(JULIA_MAJOR_VERSION).$(JULIA_MINOR_VERSION).$(JULIA_PATCH_VERSION) endif ifeq ($(OS), WINNT) diff --git a/Makefile b/Makefile index 952b9a00c1e63..d38311dce720a 100644 --- a/Makefile +++ b/Makefile @@ -365,8 +365,10 @@ endif # Set rpath for libjulia-internal, which is moving from `../lib` to `../lib/julia`. We only need to do this for Linux/FreeBSD ifneq (,$(findstring $(OS),Linux FreeBSD)) $(PATCHELF) --set-rpath '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-internal.$(SHLIB_EXT) + $(PATCHELF) --set-rpath '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-codegen.$(SHLIB_EXT) ifeq ($(BUNDLE_DEBUG_LIBS),1) $(PATCHELF) --set-rpath '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-internal-debug.$(SHLIB_EXT) + $(PATCHELF) --set-rpath '$$ORIGIN:$$ORIGIN/$(reverse_private_libdir_rel)' $(DESTDIR)$(private_libdir)/libjulia-codegen-debug.$(SHLIB_EXT) endif endif @@ -374,14 +376,22 @@ endif ifneq ($(LOADER_BUILD_DEP_LIBS),$(LOADER_INSTALL_DEP_LIBS)) # Next, overwrite relative path to libjulia-internal in our loader if $$(LOADER_BUILD_DEP_LIBS) != $$(LOADER_INSTALL_DEP_LIBS) $(call stringreplace,$(DESTDIR)$(shlibdir)/libjulia.$(JL_MAJOR_MINOR_SHLIB_EXT),$(LOADER_BUILD_DEP_LIBS)$$,$(LOADER_INSTALL_DEP_LIBS)) +ifeq ($(OS),Darwin) + # Codesign the libjulia we just modified + $(JULIAHOME)/contrib/codesign.sh "$(MACOS_CODESIGN_IDENTITY)" "$(DESTDIR)$(shlibdir)/libjulia.$(JL_MAJOR_MINOR_SHLIB_EXT)" +endif ifeq ($(BUNDLE_DEBUG_LIBS),1) $(call stringreplace,$(DESTDIR)$(shlibdir)/libjulia-debug.$(JL_MAJOR_MINOR_SHLIB_EXT),$(LOADER_DEBUG_BUILD_DEP_LIBS)$$,$(LOADER_DEBUG_INSTALL_DEP_LIBS)) +ifeq ($(OS),Darwin) + # Codesign the libjulia we just modified + $(JULIAHOME)/contrib/codesign.sh "$(MACOS_CODESIGN_IDENTITY)" "$(DESTDIR)$(shlibdir)/libjulia-debug.$(JL_MAJOR_MINOR_SHLIB_EXT)" +endif endif endif - # On FreeBSD, remove the build's libdir from each library's RPATH ifeq ($(OS),FreeBSD) + # On FreeBSD, remove the build's libdir from each library's RPATH $(JULIAHOME)/contrib/fixup-rpath.sh "$(PATCHELF)" $(DESTDIR)$(libdir) $(build_libdir) $(JULIAHOME)/contrib/fixup-rpath.sh "$(PATCHELF)" $(DESTDIR)$(private_libdir) $(build_libdir) $(JULIAHOME)/contrib/fixup-rpath.sh "$(PATCHELF)" $(DESTDIR)$(bindir) $(build_libdir) @@ -428,16 +438,9 @@ endif ifeq ($(OS), WINNT) cd $(BUILDROOT)/julia-$(JULIA_COMMIT)/bin && rm -f llvm* llc.exe lli.exe opt.exe LTO.dll bugpoint.exe macho-dump.exe endif - # If we're on macOS, and we have a codesigning identity, then codesign the binary-dist tarball! ifeq ($(OS),Darwin) -ifneq ($(MACOS_CODESIGN_IDENTITY),) - echo "Codesigning with identity $(MACOS_CODESIGN_IDENTITY)"; \ - MACHO_FILES=$$(find "$(BUILDROOT)/julia-$(JULIA_COMMIT)" -type f -perm -0111 | cut -d: -f1); \ - for f in $${MACHO_FILES}; do \ - echo "Codesigning $${f}..."; \ - codesign -s "$(MACOS_CODESIGN_IDENTITY)" --option=runtime --entitlements $(JULIAHOME)/contrib/mac/app/Entitlements.plist -vvv --timestamp --deep --force "$${f}"; \ - done -endif + # If we're on macOS, and we have a codesigning identity, then codesign the binary-dist tarball! + $(JULIAHOME)/contrib/codesign.sh "$(MACOS_CODESIGN_IDENTITY)" "$(BUILDROOT)/julia-$(JULIA_COMMIT)" endif cd $(BUILDROOT) && $(TAR) zcvf $(JULIA_BINARYDIST_FILENAME).tar.gz julia-$(JULIA_COMMIT) diff --git a/base/bitset.jl b/base/bitset.jl index 0abd9d4b782d2..22ff177695349 100644 --- a/base/bitset.jl +++ b/base/bitset.jl @@ -137,20 +137,10 @@ function union!(s::BitSet, r::AbstractUnitRange{<:Integer}) # grow s.bits as necessary if diffb >= len - _growend!(s.bits, diffb - len + 1) - # we set only some values to CHK0, those which will not be - # fully overwritten (i.e. only or'ed with `|`) - s.bits[end] = CHK0 # end == diffb + 1 - if diffa >= len - s.bits[diffa + 1] = CHK0 - end + _growend0!(s.bits, diffb - len + 1) end if diffa < 0 - _growbeg!(s.bits, -diffa) - s.bits[1] = CHK0 - if diffb < 0 - s.bits[diffb - diffa + 1] = CHK0 - end + _growbeg0!(s.bits, -diffa) s.offset = cidxa # s.offset += diffa diffb -= diffa diffa = 0 diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 5c1133b4d40ec..98bcfa4f18661 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -282,7 +282,7 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth if result === missing return FailedMethodMatch("For one of the union split cases, too many methods matched") end - matches, overlayed = result + (; matches, overlayed) = result nonoverlayed &= !overlayed push!(infos, MethodMatchInfo(matches)) for m in matches @@ -323,7 +323,7 @@ function find_matching_methods(argtypes::Vector{Any}, @nospecialize(atype), meth # (assume this will always be true, so we don't compute / update valid age in this case) return FailedMethodMatch("Too many methods matched") end - matches, overlayed = result + (; matches, overlayed) = result fullmatch = _any(match->(match::MethodMatch).fully_covers, matches) return MethodMatches(matches.matches, MethodMatchInfo(matches), diff --git a/base/compiler/compiler.jl b/base/compiler/compiler.jl index 6991e2d38437b..ed88e8c22178f 100644 --- a/base/compiler/compiler.jl +++ b/base/compiler/compiler.jl @@ -123,10 +123,10 @@ something(x::Any, y...) = x ############ include("compiler/cicache.jl") +include("compiler/methodtable.jl") include("compiler/types.jl") include("compiler/utilities.jl") include("compiler/validation.jl") -include("compiler/methodtable.jl") include("compiler/inferenceresult.jl") include("compiler/inferencestate.jl") diff --git a/base/compiler/methodtable.jl b/base/compiler/methodtable.jl index 7aa686009c1af..8b3968332e2e8 100644 --- a/base/compiler/methodtable.jl +++ b/base/compiler/methodtable.jl @@ -2,6 +2,27 @@ abstract type MethodTableView; end +struct MethodLookupResult + # Really Vector{Core.MethodMatch}, but it's easier to represent this as + # and work with Vector{Any} on the C side. + matches::Vector{Any} + valid_worlds::WorldRange + ambig::Bool +end +length(result::MethodLookupResult) = length(result.matches) +function iterate(result::MethodLookupResult, args...) + r = iterate(result.matches, args...) + r === nothing && return nothing + match, state = r + return (match::MethodMatch, state) +end +getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch + +struct MethodMatchResult + matches::MethodLookupResult + overlayed::Bool +end + """ struct InternalMethodTable <: MethodTableView @@ -23,25 +44,21 @@ struct OverlayMethodTable <: MethodTableView mt::Core.MethodTable end -struct MethodLookupResult - # Really Vector{Core.MethodMatch}, but it's easier to represent this as - # and work with Vector{Any} on the C side. - matches::Vector{Any} - valid_worlds::WorldRange - ambig::Bool -end -length(result::MethodLookupResult) = length(result.matches) -function iterate(result::MethodLookupResult, args...) - r = iterate(result.matches, args...) - r === nothing && return nothing - match, state = r - return (match::MethodMatch, state) +""" + struct CachedMethodTable <: MethodTableView + +Overlays another method table view with an additional local fast path cache that +can respond to repeated, identical queries faster than the original method table. +""" +struct CachedMethodTable{T} <: MethodTableView + cache::IdDict{Any, Union{Missing, MethodMatchResult}} + table::T end -getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch +CachedMethodTable(table::T) where T = CachedMethodTable{T}(IdDict{Any, Union{Missing, MethodMatchResult}}(), table) """ findall(sig::Type, view::MethodTableView; limit::Int=typemax(Int)) -> - (matches::MethodLookupResult, overlayed::Bool) or missing + MethodMatchResult(matches::MethodLookupResult, overlayed::Bool) or missing Find all methods in the given method table `view` that are applicable to the given signature `sig`. If no applicable methods are found, an empty result is returned. @@ -51,7 +68,7 @@ If the number of applicable methods exceeded the specified limit, `missing` is r function findall(@nospecialize(sig::Type), table::InternalMethodTable; limit::Int=Int(typemax(Int32))) result = _findall(sig, nothing, table.world, limit) result === missing && return missing - return result, false + return MethodMatchResult(result, false) end function findall(@nospecialize(sig::Type), table::OverlayMethodTable; limit::Int=Int(typemax(Int32))) @@ -60,18 +77,20 @@ function findall(@nospecialize(sig::Type), table::OverlayMethodTable; limit::Int nr = length(result) if nr ≥ 1 && result[nr].fully_covers # no need to fall back to the internal method table - return result, true + return MethodMatchResult(result, true) end # fall back to the internal method table fallback_result = _findall(sig, nothing, table.world, limit) fallback_result === missing && return missing # merge the fallback match results with the internal method table - return MethodLookupResult( - vcat(result.matches, fallback_result.matches), - WorldRange( - max(result.valid_worlds.min_world, fallback_result.valid_worlds.min_world), - min(result.valid_worlds.max_world, fallback_result.valid_worlds.max_world)), - result.ambig | fallback_result.ambig), !isempty(result) + return MethodMatchResult( + MethodLookupResult( + vcat(result.matches, fallback_result.matches), + WorldRange( + max(result.valid_worlds.min_world, fallback_result.valid_worlds.min_world), + min(result.valid_worlds.max_world, fallback_result.valid_worlds.max_world)), + result.ambig | fallback_result.ambig), + !isempty(result)) end function _findall(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, world::UInt, limit::Int) @@ -85,6 +104,17 @@ function _findall(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, return MethodLookupResult(ms::Vector{Any}, WorldRange(_min_val[], _max_val[]), _ambig[] != 0) end +function findall(@nospecialize(sig::Type), table::CachedMethodTable; limit::Int=typemax(Int)) + if isconcretetype(sig) + # as for concrete types, we cache result at on the next level + return findall(sig, table.table; limit) + end + box = Core.Box(sig) + return get!(table.cache, sig) do + findall(box.contents, table.table; limit) + end +end + """ findsup(sig::Type, view::MethodTableView) -> (match::MethodMatch, valid_worlds::WorldRange, overlayed::Bool) or nothing @@ -129,6 +159,10 @@ function _findsup(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, return match, valid_worlds end +# This query is not cached +findsup(@nospecialize(sig::Type), table::CachedMethodTable) = findsup(sig, table.table) + isoverlayed(::MethodTableView) = error("unsatisfied MethodTableView interface") isoverlayed(::InternalMethodTable) = false isoverlayed(::OverlayMethodTable) = true +isoverlayed(mt::CachedMethodTable) = isoverlayed(mt.table) diff --git a/base/compiler/ssair/legacy.jl b/base/compiler/ssair/legacy.jl index 3d91646fa05f7..15038f609c5f1 100644 --- a/base/compiler/ssair/legacy.jl +++ b/base/compiler/ssair/legacy.jl @@ -58,7 +58,7 @@ function replace_code_newstyle!(ci::CodeInfo, ir::IRCode, nargs::Int) elseif isa(stmt, GotoIfNot) stmt = GotoIfNot(stmt.cond, first(ir.cfg.blocks[stmt.dest].stmts)) elseif isa(stmt, PhiNode) - stmt = PhiNode(Int32[last(ir.cfg.blocks[edge].stmts) for edge in stmt.edges], stmt.values) + stmt = PhiNode(Int32[edge == 0 ? 0 : last(ir.cfg.blocks[edge].stmts) for edge in stmt.edges], stmt.values) elseif isa(stmt, Expr) && stmt.head === :enter stmt.args[1] = first(ir.cfg.blocks[stmt.args[1]::Int].stmts) end diff --git a/base/compiler/types.jl b/base/compiler/types.jl index a0884bd86d1d3..3652a15c3e7bd 100644 --- a/base/compiler/types.jl +++ b/base/compiler/types.jl @@ -318,6 +318,8 @@ struct NativeInterpreter <: AbstractInterpreter cache::Vector{InferenceResult} # The world age we're working inside of world::UInt + # method table to lookup for during inference on this world age + method_table::CachedMethodTable{InternalMethodTable} # Parameters for inference and optimization inf_params::InferenceParams @@ -327,27 +329,21 @@ struct NativeInterpreter <: AbstractInterpreter inf_params = InferenceParams(), opt_params = OptimizationParams(), ) + cache = Vector{InferenceResult}() # Initially empty cache + # Sometimes the caller is lazy and passes typemax(UInt). # we cap it to the current world age if world == typemax(UInt) world = get_world_counter() end + method_table = CachedMethodTable(InternalMethodTable(world)) + # If they didn't pass typemax(UInt) but passed something more subtly # incorrect, fail out loudly. @assert world <= get_world_counter() - return new( - # Initially empty cache - Vector{InferenceResult}(), - - # world age counter - world, - - # parameters for inference and optimization - inf_params, - opt_params, - ) + return new(cache, world, method_table, inf_params, opt_params) end end @@ -396,6 +392,7 @@ External `AbstractInterpreter` can optionally return `OverlayMethodTable` here to incorporate customized dispatches for the overridden methods. """ method_table(interp::AbstractInterpreter) = InternalMethodTable(get_world_counter(interp)) +method_table(interp::NativeInterpreter) = interp.method_table """ By default `AbstractInterpreter` implements the following inference bail out logic: diff --git a/base/deepcopy.jl b/base/deepcopy.jl index 317d999004c42..74c9d2b49c123 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -140,7 +140,7 @@ function deepcopy_internal(x::GenericCondition, stackdict::IdDict) if haskey(stackdict, x) return stackdict[x] end - y = typeof(x)(deepcopy_internal(x.lock)) + y = typeof(x)(deepcopy_internal(x.lock, stackdict)) stackdict[x] = y return y end diff --git a/base/dict.jl b/base/dict.jl index 220840ed0e5ea..a8dc20763c73e 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -372,7 +372,7 @@ end function setindex!(h::Dict{K,V}, v0, key0) where V where K key = convert(K, key0) - if !isequal(key, key0) + if !(isequal(key, key0)::Bool) throw(ArgumentError("$(limitrepr(key0)) is not a valid key for type $K")) end setindex!(h, v0, key) diff --git a/base/logging.jl b/base/logging.jl index 1b8e5e0f54192..db7ddf37c676d 100644 --- a/base/logging.jl +++ b/base/logging.jl @@ -669,7 +669,7 @@ function handle_message(logger::SimpleLogger, level::LogLevel, message, _module, end buf = IOBuffer() stream = logger.stream - if !isopen(stream) + if !(isopen(stream)::Bool) stream = stderr end iob = IOContext(buf, stream) diff --git a/base/math.jl b/base/math.jl index 1f194f73ca7f9..3b5465bc86e19 100644 --- a/base/math.jl +++ b/base/math.jl @@ -996,18 +996,22 @@ end # @constprop aggressive to help the compiler see the switch between the integer and float # variants for callers with constant `y` @constprop :aggressive function ^(x::Float64, y::Float64) - yint = unsafe_trunc(Int, y) # Note, this is actually safe since julia freezes the result - y == yint && return x^yint - #numbers greater than 2*inv(eps(T)) must be even, and the pow will overflow - y >= 2*inv(eps()) && return x^(typemax(Int64)-1) - x<0 && y > -4e18 && throw_exp_domainerror(x) # |y| is small enough that y isn't an integer x == 1 && return 1.0 + # Exponents greater than this will always overflow or underflow. + # Note that NaN can pass through this, but that will end up fine. + if !(abs(y)<0x1.8p62) + isnan(y) && return y + y = sign(y)*0x1.8p62 + end + yint = unsafe_trunc(Int64, y) # This is actually safe since julia freezes the result + y == yint && return x^yint + x<0 && throw_exp_domainerror(x) + !isfinite(x) && return x*(y>0 || isnan(x)) + x==0 && return abs(y)*Inf*(!(y>0)) return pow_body(x, y) end @inline function pow_body(x::Float64, y::Float64) - !isfinite(x) && return x*(y>0 || isnan(x)) - x==0 && return abs(y)*Inf*(!(y>0)) logxhi,logxlo = Base.Math._log_ext(x) xyhi, xylo = two_mul(logxhi,y) xylo = muladd(logxlo, y, xylo) @@ -1016,18 +1020,23 @@ end end @constprop :aggressive function ^(x::T, y::T) where T <: Union{Float16, Float32} - yint = unsafe_trunc(Int64, y) # Note, this is actually safe since julia freezes the result + x == 1 && return one(T) + # Exponents greater than this will always overflow or underflow. + # Note that NaN can pass through this, but that will end up fine. + max_exp = T == Float16 ? T(3<<14) : T(0x1.Ap30) + if !(abs(y)= 2*inv(eps(T)) && return x^(typemax(Int64)-1) - x < 0 && y > -4e18 && throw_exp_domainerror(x) # |y| is small enough that y isn't an integer + x < 0 && throw_exp_domainerror(x) + !isfinite(x) && return x*(y>0 || isnan(x)) + x==0 && return abs(y)*T(Inf)*(!(y>0)) return pow_body(x, y) end @inline function pow_body(x::T, y::T) where T <: Union{Float16, Float32} - x == 1 && return one(T) - !isfinite(x) && return x*(y>0 || isnan(x)) - x==0 && return abs(y)*T(Inf)*(!(y>0)) return T(exp2(log2(abs(widen(x))) * y)) end @@ -1059,8 +1068,8 @@ end xnlo += err n >>>= 1 end - !isfinite(x) && return x*y - return muladd(x, y, muladd(y, xnlo, x*ynlo)) + err = muladd(y, xnlo, x*ynlo) + return ifelse(isfinite(x) & isfinite(err), muladd(x, y, err), x*y) end function ^(x::Float32, n::Integer) diff --git a/base/operators.jl b/base/operators.jl index 9949f60bd597c..e42699062f016 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -910,6 +910,9 @@ julia> [1:5;] |> (x->x.^2) |> sum |> inv """ |>(x, f) = f(x) +_stable_typeof(x) = typeof(x) +_stable_typeof(::Type{T}) where {T} = @isdefined(T) ? Type{T} : DataType + """ f = Returns(value) @@ -936,7 +939,7 @@ julia> f.value struct Returns{V} <: Function value::V Returns{V}(value) where {V} = new{V}(value) - Returns(value) = new{Core.Typeof(value)}(value) + Returns(value) = new{_stable_typeof(value)}(value) end (obj::Returns)(args...; kw...) = obj.value @@ -1027,7 +1030,19 @@ struct ComposedFunction{O,I} <: Function ComposedFunction(outer, inner) = new{Core.Typeof(outer),Core.Typeof(inner)}(outer, inner) end -(c::ComposedFunction)(x...; kw...) = c.outer(c.inner(x...; kw...)) +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)...) +unwrap_composed(c) = (maybeconstructor(c),) +call_composed(x, f, fs...) = (@inline; call_composed(f(x), fs...)) +call_composed(x, f) = f(x) + +struct Constructor{F} <: Function end +(::Constructor{F})(args...; kw...) where {F} = (@inline; F(args...; kw...)) +maybeconstructor(::Type{F}) where {F} = Constructor{F}() +maybeconstructor(f) = f ∘(f) = f ∘(f, g) = ComposedFunction(f, g) @@ -1074,8 +1089,8 @@ struct Fix1{F,T} <: Function f::F x::T - Fix1(f::F, x::T) where {F,T} = new{F,T}(f, x) - Fix1(f::Type{F}, x::T) where {F,T} = new{Type{F},T}(f, x) + Fix1(f::F, x) where {F} = new{F,_stable_typeof(x)}(f, x) + Fix1(f::Type{F}, x) where {F} = new{Type{F},_stable_typeof(x)}(f, x) end (f::Fix1)(y) = f.f(f.x, y) @@ -1091,8 +1106,8 @@ struct Fix2{F,T} <: Function f::F x::T - Fix2(f::F, x::T) where {F,T} = new{F,T}(f, x) - Fix2(f::Type{F}, x::T) where {F,T} = new{Type{F},T}(f, x) + Fix2(f::F, x) where {F} = new{F,_stable_typeof(x)}(f, x) + Fix2(f::Type{F}, x) where {F} = new{Type{F},_stable_typeof(x)}(f, x) end (f::Fix2)(y) = f.f(y, f.x) diff --git a/base/promotion.jl b/base/promotion.jl index 24d0835a8b94a..8a89ce73d1788 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -476,7 +476,7 @@ xor(x::T, y::T) where {T<:Integer} = no_op_err("xor", T) (==)(x::T, y::T) where {T<:Number} = x === y (< )(x::T, y::T) where {T<:Real} = no_op_err("<" , T) -(<=)(x::T, y::T) where {T<:Real} = no_op_err("<=", T) +(<=)(x::T, y::T) where {T<:Real} = (x == y) | (x < y) rem(x::T, y::T) where {T<:Real} = no_op_err("rem", T) mod(x::T, y::T) where {T<:Real} = no_op_err("mod", T) diff --git a/base/reduce.jl b/base/reduce.jl index 13e1b69c79ede..587e34105d99e 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -140,17 +140,25 @@ what is returned is `itr′` and op′ = (xfₙ ∘ ... ∘ xf₂ ∘ xf₁)(op) """ -_xfadjoint(op, itr) = (op, itr) -_xfadjoint(op, itr::Generator) = - if itr.f === identity - _xfadjoint(op, itr.iter) - else - _xfadjoint(MappingRF(itr.f, op), itr.iter) - end -_xfadjoint(op, itr::Filter) = - _xfadjoint(FilteringRF(itr.flt, op), itr.itr) -_xfadjoint(op, itr::Flatten) = - _xfadjoint(FlatteningRF(op), itr.it) +function _xfadjoint(op, itr) + itr′, wrap = _xfadjoint_unwrap(itr) + wrap(op), itr′ +end + +_xfadjoint_unwrap(itr) = itr, identity +function _xfadjoint_unwrap(itr::Generator) + itr′, wrap = _xfadjoint_unwrap(itr.iter) + itr.f === identity && return itr′, wrap + return itr′, wrap ∘ Fix1(MappingRF, itr.f) +end +function _xfadjoint_unwrap(itr::Filter) + itr′, wrap = _xfadjoint_unwrap(itr.itr) + return itr′, wrap ∘ Fix1(FilteringRF, itr.flt) +end +function _xfadjoint_unwrap(itr::Flatten) + itr′, wrap = _xfadjoint_unwrap(itr.it) + return itr′, wrap ∘ FlatteningRF +end """ mapfoldl(f, op, itr; [init]) diff --git a/base/sort.jl b/base/sort.jl index 307a515dad050..b9c22e396db2c 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -501,7 +501,7 @@ function sort!(v::AbstractVector, lo::Integer, hi::Integer, ::InsertionSortAlg, x = v[i] while j > lo y = v[j-1] - if !lt(o, x, y) + if !(lt(o, x, y)::Bool) break end v[j] = y diff --git a/base/special/exp.jl b/base/special/exp.jl index 00a9c0c2d19c6..e955d182f29d3 100644 --- a/base/special/exp.jl +++ b/base/special/exp.jl @@ -70,31 +70,30 @@ LogB(::Val{:ℯ}, ::Type{Float16}) = -0.6931472f0 LogB(::Val{10}, ::Type{Float16}) = -0.30103f0 # Range reduced kernels -@inline function expm1b_kernel(::Val{2}, x::Float64) +function expm1b_kernel(::Val{2}, x::Float64) return x * evalpoly(x, (0.6931471805599393, 0.24022650695910058, 0.05550411502333161, 0.009618129548366803)) end -@inline function expm1b_kernel(::Val{:ℯ}, x::Float64) +function expm1b_kernel(::Val{:ℯ}, x::Float64) return x * evalpoly(x, (0.9999999999999912, 0.4999999999999997, 0.1666666857598779, 0.04166666857598777)) end - -@inline function expm1b_kernel(::Val{10}, x::Float64) +function expm1b_kernel(::Val{10}, x::Float64) return x * evalpoly(x, (2.3025850929940255, 2.6509490552391974, 2.034678825384765, 1.1712552025835192)) end -@inline function expb_kernel(::Val{2}, x::Float32) +function expb_kernel(::Val{2}, x::Float32) return evalpoly(x, (1.0f0, 0.6931472f0, 0.2402265f0, 0.05550411f0, 0.009618025f0, 0.0013333423f0, 0.00015469732f0, 1.5316464f-5)) end -@inline function expb_kernel(::Val{:ℯ}, x::Float32) +function expb_kernel(::Val{:ℯ}, x::Float32) return evalpoly(x, (1.0f0, 1.0f0, 0.5f0, 0.16666667f0, 0.041666217f0, 0.008333249f0, 0.001394858f0, 0.00019924171f0)) end -@inline function expb_kernel(::Val{10}, x::Float32) +function expb_kernel(::Val{10}, x::Float32) return evalpoly(x, (1.0f0, 2.3025851f0, 2.650949f0, 2.0346787f0, 1.1712426f0, 0.53937745f0, 0.20788547f0, 0.06837386f0)) @@ -178,7 +177,7 @@ const J_TABLE = (0x0000000000000000, 0xaac00b1afa5abcbe, 0x9b60163da9fb3335, 0xa # XXX we want to mark :consistent-cy here so that this function can be concrete-folded, # because the effect analysis currently can't prove it in the presence of `@inbounds` or # `:boundscheck`, but still the access to `J_TABLE` is really safe here -Base.@assume_effects :consistent @inline function table_unpack(ind::Int32) +@noinline Base.@assume_effects :consistent @inline function table_unpack(ind::Int32) ind = ind & 255 + 1 # 255 == length(J_TABLE) - 1 j = @inbounds J_TABLE[ind] jU = reinterpret(Float64, JU_CONST | (j&JU_MASK)) @@ -224,7 +223,7 @@ end if k <= -53 # The UInt64 forces promotion. (Only matters for 32 bit systems.) twopk = (k + UInt64(53)) << 52 - return reinterpret(T, twopk + reinterpret(UInt64, small_part))*(2.0^-53) + return reinterpret(T, twopk + reinterpret(UInt64, small_part))*0x1p-53 end #k == 1024 && return (small_part * 2.0) * 2.0^1023 end @@ -249,7 +248,7 @@ end if k <= -53 # The UInt64 forces promotion. (Only matters for 32 bit systems.) twopk = (k + UInt64(53)) << 52 - return reinterpret(T, twopk + reinterpret(UInt64, small_part))*(2.0^-53) + return reinterpret(T, twopk + reinterpret(UInt64, small_part))*0x1p-53 end #k == 1024 && return (small_part * 2.0) * 2.0^1023 end @@ -324,8 +323,8 @@ for (func, fast_func, base) in ((:exp2, :exp2_fast, Val(2)), (:exp, :exp_fast, Val(:ℯ)), (:exp10, :exp10_fast, Val(10))) @eval begin - $func(x::Union{Float16,Float32,Float64}) = exp_impl(x, $base) - $fast_func(x::Union{Float32,Float64}) = exp_impl_fast(x, $base) + @noinline $func(x::Union{Float16,Float32,Float64}) = exp_impl(x, $base) + @noinline $fast_func(x::Union{Float32,Float64}) = exp_impl_fast(x, $base) end end diff --git a/base/strings/string.jl b/base/strings/string.jl index c37e36594119e..17e05a93b7dc4 100644 --- a/base/strings/string.jl +++ b/base/strings/string.jl @@ -17,10 +17,12 @@ function Base.showerror(io::IO, exc::StringIndexError) if firstindex(s) <= exc.index <= ncodeunits(s) iprev = thisind(s, exc.index) inext = nextind(s, iprev) + escprev = escape_string(s[iprev:iprev]) if inext <= ncodeunits(s) - print(io, ", valid nearby indices [$iprev]=>'$(s[iprev])', [$inext]=>'$(s[inext])'") + escnext = escape_string(s[inext:inext]) + print(io, ", valid nearby indices [$iprev]=>'$escprev', [$inext]=>'$escnext'") else - print(io, ", valid nearby index [$iprev]=>'$(s[iprev])'") + print(io, ", valid nearby index [$iprev]=>'$escprev'") end end end diff --git a/base/strings/util.jl b/base/strings/util.jl index 91686f330849b..ee58c2df095e3 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -533,7 +533,7 @@ function iterate(iter::SplitIterator, (i, k, n)=(firstindex(iter.str), firstinde r = findnext(iter.splitter, iter.str, k)::Union{Nothing,Int,UnitRange{Int}} while r !== nothing && n != iter.limit - 1 && first(r) <= ncodeunits(iter.str) j, k = first(r), nextind(iter.str, last(r))::Int - k_ = k <= j ? nextind(iter.str, j) : k + k_ = k <= j ? nextind(iter.str, j)::Int : k if i < k substr = @inbounds SubString(iter.str, i, prevind(iter.str, j)::Int) (iter.keepempty || i < j) && return (substr, (k, k_, n + 1)) diff --git a/base/timing.jl b/base/timing.jl index a72f2980ca3b8..f924382a37a47 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -218,8 +218,7 @@ See also [`@showtime`](@ref), [`@timev`](@ref), [`@timed`](@ref), [`@elapsed`](@ !!! compat "Julia 1.8" The option to add a description was introduced in Julia 1.8. -!!! compat "Julia 1.9" - Recompilation time being shown separately from compilation time was introduced in Julia 1.9 + Recompilation time being shown separately from compilation time was introduced in Julia 1.8 ```julia-repl julia> x = rand(10,10); diff --git a/base/util.jl b/base/util.jl index df9e29790deb6..e55e834e690d3 100644 --- a/base/util.jl +++ b/base/util.jl @@ -527,7 +527,16 @@ function _kwdef!(blk, params_args, call_args) push!(params_args, ei) push!(call_args, ei) elseif ei isa Expr - if ei.head === :(=) + is_atomic = ei.head === :atomic + ei = is_atomic ? first(ei.args) : ei # strip "@atomic" and add it back later + is_const = ei.head === :const + ei = is_const ? first(ei.args) : ei # strip "const" and add it back later + # Note: `@atomic const ..` isn't valid, but reconstruct it anyway to serve a nice error + if ei isa Symbol + # const var + push!(params_args, ei) + push!(call_args, ei) + elseif ei.head === :(=) lhs = ei.args[1] if lhs isa Symbol # var = defexpr @@ -543,7 +552,9 @@ function _kwdef!(blk, params_args, call_args) defexpr = ei.args[2] # defexpr push!(params_args, Expr(:kw, var, esc(defexpr))) push!(call_args, var) - blk.args[i] = lhs + lhs = is_const ? Expr(:const, lhs) : lhs + lhs = is_atomic ? Expr(:atomic, lhs) : lhs + blk.args[i] = lhs # overrides arg elseif ei.head === :(::) && ei.args[1] isa Symbol # var::Typ var = ei.args[1] diff --git a/cli/loader.h b/cli/loader.h index 2d0b977f7142f..0620113048efe 100644 --- a/cli/loader.h +++ b/cli/loader.h @@ -22,8 +22,6 @@ #define realloc loader_realloc #endif -#include - #ifdef _OS_WINDOWS_ #define WIN32_LEAN_AND_MEAN @@ -49,6 +47,8 @@ #endif +#include + // Borrow definition from `support/dtypes.h` #ifdef _OS_WINDOWS_ # ifdef LIBRARY_EXPORTS diff --git a/contrib/codesign.sh b/contrib/codesign.sh new file mode 100755 index 0000000000000..03866c4bb1ac1 --- /dev/null +++ b/contrib/codesign.sh @@ -0,0 +1,38 @@ +#!/bin/sh +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# Codesign binary files for macOS. + +usage() { + echo "Usage: ${0} MACOS_CODESIGN_IDENTITY FILE-OR-DIRECTORY" + exit 0 +} + +# Default codesign identity to `-` if not provided +if [ -z "${1}" ]; then + MACOS_CODESIGN_IDENTITY="-" + ENTITLEMENTS="" +else + MACOS_CODESIGN_IDENTITY="${1}" + ENTITLEMENTS="--entitlements $(dirname "${0}")/mac/app/Entitlements.plist" +fi + +if [ "${#}" -eq 2 ]; then + if [ -f "${2}" ]; then + # Codesign only the given file + MACHO_FILES="${2}" + elif [ -d "${2}" ]; then + # Find all files in the given directory + MACHO_FILES=$(find "${2}" -type f -perm -0111 | cut -d: -f1) + else + usage + fi +else + usage +fi + +echo "Codesigning with identity ${MACOS_CODESIGN_IDENTITY}" +for f in ${MACHO_FILES}; do + echo "Codesigning ${f}..." + codesign -s "${MACOS_CODESIGN_IDENTITY}" --option=runtime ${ENTITLEMENTS} -vvv --timestamp --deep --force "${f}" +done diff --git a/deps/checksums/Pkg-03e3bad8ef894f5a8b0edcfb00e4025173652b2b.tar.gz/md5 b/deps/checksums/Pkg-03e3bad8ef894f5a8b0edcfb00e4025173652b2b.tar.gz/md5 new file mode 100644 index 0000000000000..5d95a7b01b6c7 --- /dev/null +++ b/deps/checksums/Pkg-03e3bad8ef894f5a8b0edcfb00e4025173652b2b.tar.gz/md5 @@ -0,0 +1 @@ +682606d3308f82eaca8c33fe1f0bd083 diff --git a/deps/checksums/Pkg-03e3bad8ef894f5a8b0edcfb00e4025173652b2b.tar.gz/sha512 b/deps/checksums/Pkg-03e3bad8ef894f5a8b0edcfb00e4025173652b2b.tar.gz/sha512 new file mode 100644 index 0000000000000..c4f3205f38150 --- /dev/null +++ b/deps/checksums/Pkg-03e3bad8ef894f5a8b0edcfb00e4025173652b2b.tar.gz/sha512 @@ -0,0 +1 @@ +9de41dced83f007cc425acde3ca1a8646d30dceb8f071381820fac0f5bf57ed58fe1aed0be09317084c5b8abb7a415921f2f22c9517dd610748de53cd5046baa diff --git a/deps/checksums/Pkg-63f4405d17e11decd2e5eb786cc491322b68c58c.tar.gz/md5 b/deps/checksums/Pkg-63f4405d17e11decd2e5eb786cc491322b68c58c.tar.gz/md5 deleted file mode 100644 index 267a11ce9e392..0000000000000 --- a/deps/checksums/Pkg-63f4405d17e11decd2e5eb786cc491322b68c58c.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -eb99c4458db02049e01122431211678a diff --git a/deps/checksums/Pkg-63f4405d17e11decd2e5eb786cc491322b68c58c.tar.gz/sha512 b/deps/checksums/Pkg-63f4405d17e11decd2e5eb786cc491322b68c58c.tar.gz/sha512 deleted file mode 100644 index de1835da35995..0000000000000 --- a/deps/checksums/Pkg-63f4405d17e11decd2e5eb786cc491322b68c58c.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -57fe5f9d897ff82ba64c6e4d8f102a2fc5d689340b41993c4f2cab3af0f516427d5e3696e0db75cedc49866ef19d4c87194e175f2a51391e1ae76546b10e997d diff --git a/doc/Manifest.toml b/doc/Manifest.toml index a1fc86f2e779b..9992d7b18ced2 100644 --- a/doc/Manifest.toml +++ b/doc/Manifest.toml @@ -18,15 +18,15 @@ uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" [[deps.DocStringExtensions]] deps = ["LibGit2"] -git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b" +git-tree-sha1 = "5158c2b41018c5f7eb1470d558127ac274eca0c9" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.8.6" +version = "0.9.1" [[deps.Documenter]] deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "e4967ebb9dce1328d582200b03bcc44c69372312" +git-tree-sha1 = "6030186b00a38e9d0434518627426570aac2ef95" uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.27.20" +version = "0.27.23" [[deps.IOCapture]] deps = ["Logging", "Random"] @@ -63,9 +63,9 @@ uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" [[deps.Parsers]] deps = ["Dates"] -git-tree-sha1 = "0044b23da09b5608b4ecacb4e5e6c6332f833a7e" +git-tree-sha1 = "3d5bf43e3e8b412656404ed9466f1dcbf7c50269" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.3.2" +version = "2.4.0" [[deps.Printf]] deps = ["Unicode"] diff --git a/doc/src/assets/custom.sty b/doc/src/assets/custom.sty index f257d2d3d2174..03e6ff805cd3f 100644 --- a/doc/src/assets/custom.sty +++ b/doc/src/assets/custom.sty @@ -40,6 +40,7 @@ contents={ }}% % ---- Heading font style -\DeclareFixedFont{\MainHeading}{T1}{phv}{b}{n}{1.5cm} -\DeclareFixedFont{\SecondaryHeading}{T1}{phv}{b}{n}{0.8cm} +\usepackage{anyfontsize} +\newcommand{\MainHeading}{\fontspec{DejaVu Sans}\fontsize{40}{40}\selectfont\bfseries} +\newcommand{\SecondaryHeading}{\fontspec{DejaVu Sans}\LARGE} %% cover page END ------------------------------------------------------------- diff --git a/doc/src/manual/multi-threading.md b/doc/src/manual/multi-threading.md index 14d42013ae2ff..55140c8938b8a 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -307,9 +307,6 @@ threads in Julia: multiple threads where at least one thread modifies the collection (common examples include `push!` on arrays, or inserting items into a `Dict`). - * `@threads` currently uses a static schedule, using all threads and assigning - equal iteration counts to each. In the future the default schedule is likely - to change to be dynamic. * The schedule used by `@spawn` is nondeterministic and should not be relied on. * Compute-bound, non-memory-allocating tasks can prevent garbage collection from running in other threads that are allocating memory. In these cases it may diff --git a/src/codegen.cpp b/src/codegen.cpp index cfd0e7154ce68..79b40513f453c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6709,7 +6709,7 @@ static std::pair, jl_llvm_functions_t> Type *vtype = julia_type_to_llvm(ctx, jt, &isboxed); assert(!isboxed); assert(!type_is_ghost(vtype) && "constants should already be handled"); - Value *lv = new AllocaInst(vtype, 0, jl_symbol_name(s), /*InsertBefore*/ctx.pgcstack); + Value *lv = new AllocaInst(vtype, 0, NULL, Align(jl_datatype_align(jt)), jl_symbol_name(s), /*InsertBefore*/ctx.pgcstack); if (CountTrackedPointers(vtype).count) { StoreInst *SI = new StoreInst(Constant::getNullValue(vtype), lv, false, Align(sizeof(void*))); SI->insertAfter(ctx.pgcstack); diff --git a/src/dump.c b/src/dump.c index 44f6262f37d5c..8cb2f901ee45b 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1202,9 +1202,10 @@ static void jl_collect_backedges_to(jl_method_instance_t *caller, htable_t *all_ { if (module_in_worklist(caller->def.method->module) || method_instance_in_queue(caller)) return; - jl_array_t **pcallees = (jl_array_t**)ptrhash_bp(&edges_map, (void*)caller), - *callees = *pcallees; - if (callees != HT_NOTFOUND) { + if (ptrhash_has(&edges_map, caller)) { + jl_array_t **pcallees = (jl_array_t**)ptrhash_bp(&edges_map, (void*)caller), + *callees = *pcallees; + assert(callees != HT_NOTFOUND); *pcallees = (jl_array_t*) HT_NOTFOUND; size_t i, l = jl_array_len(callees); for (i = 0; i < l; i++) { @@ -1227,7 +1228,10 @@ static void jl_collect_backedges( /* edges */ jl_array_t *s, /* ext_targets */ j htable_new(&all_callees, 0); size_t i; void **table = edges_map.table; // edges is caller => callees - for (i = 0; i < edges_map.size; i += 2) { + size_t table_size = edges_map.size; + for (i = 0; i < table_size; i += 2) { + assert(table == edges_map.table && table_size == edges_map.size && + "edges_map changed during iteration"); jl_method_instance_t *caller = (jl_method_instance_t*)table[i]; jl_array_t *callees = (jl_array_t*)table[i + 1]; if (callees == HT_NOTFOUND) diff --git a/src/subtype.c b/src/subtype.c index aea5b80a5cadf..c01ee54e683be 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -200,12 +200,9 @@ static void restore_env(jl_stenv_t *e, jl_value_t *root, jl_savedenv_t *se) JL_N jl_varbinding_t *v = e->vars; int i = 0, j = 0; while (v != NULL) { - if (root) v->lb = jl_svecref(root, i); - i++; - if (root) v->ub = jl_svecref(root, i); - i++; - if (root) v->innervars = (jl_array_t*)jl_svecref(root, i); - i++; + if (root) v->lb = jl_svecref(root, i++); + if (root) v->ub = jl_svecref(root, i++); + if (root) v->innervars = (jl_array_t*)jl_svecref(root, i++); v->occurs_inv = se->buf[j++]; v->occurs_cov = se->buf[j++]; v = v->prev; @@ -2323,6 +2320,11 @@ static jl_value_t *intersect_var(jl_tvar_t *b, jl_value_t *a, jl_stenv_t *e, int JL_GC_POP(); return jl_bottom_type; } + if (jl_is_uniontype(ub) && !jl_is_uniontype(a)) { + bb->ub = ub; + bb->lb = jl_bottom_type; + ub = (jl_value_t*)b; + } } if (ub != (jl_value_t*)b) { if (jl_has_free_typevars(ub)) { @@ -3166,26 +3168,50 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa return jl_bottom_type; } +static int merge_env(jl_stenv_t *e, jl_value_t **root, jl_savedenv_t *se, int count) +{ + if (!count) { + save_env(e, root, se); + return 1; + } + int n = 0; + jl_varbinding_t *v = e->vars; + jl_value_t *ub = NULL, *vub = NULL; + JL_GC_PUSH2(&ub, &vub); + while (v != NULL) { + if (v->ub != v->var->ub || v->lb != v->var->lb) { + jl_value_t *lb = jl_svecref(*root, n); + if (v->lb != lb) + jl_svecset(*root, n, lb ? jl_bottom_type : v->lb); + ub = jl_svecref(*root, n+1); + vub = v->ub; + if (vub != ub) + jl_svecset(*root, n+1, ub ? simple_join(ub, vub) : vub); + } + n = n + 3; + v = v->prev; + } + JL_GC_POP(); + return count + 1; +} + static jl_value_t *intersect_all(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) { e->Runions.depth = 0; e->Runions.more = 0; e->Runions.used = 0; jl_value_t **is; - JL_GC_PUSHARGS(is, 3); + JL_GC_PUSHARGS(is, 4); jl_value_t **saved = &is[2]; - jl_savedenv_t se; + jl_value_t **merged = &is[3]; + jl_savedenv_t se, me; save_env(e, saved, &se); int lastset = 0, niter = 0, total_iter = 0; jl_value_t *ii = intersect(x, y, e, 0); is[0] = ii; // root - if (ii == jl_bottom_type) { - restore_env(e, *saved, &se); - } - else { - free_env(&se); - save_env(e, saved, &se); - } + if (is[0] != jl_bottom_type) + niter = merge_env(e, merged, &me, niter); + restore_env(e, *saved, &se); while (e->Runions.more) { if (e->emptiness_only && ii != jl_bottom_type) break; @@ -3199,13 +3225,9 @@ static jl_value_t *intersect_all(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) is[0] = ii; is[1] = intersect(x, y, e, 0); - if (is[1] == jl_bottom_type) { - restore_env(e, *saved, &se); - } - else { - free_env(&se); - save_env(e, saved, &se); - } + if (is[1] != jl_bottom_type) + niter = merge_env(e, merged, &me, niter); + restore_env(e, *saved, &se); if (is[0] == jl_bottom_type) ii = is[1]; else if (is[1] == jl_bottom_type) @@ -3213,14 +3235,17 @@ static jl_value_t *intersect_all(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) else { // TODO: the repeated subtype checks in here can get expensive ii = jl_type_union(is, 2); - niter++; } total_iter++; - if (niter > 3 || total_iter > 400000) { + if (niter > 4 || total_iter > 400000) { ii = y; break; } } + if (niter){ + restore_env(e, *merged, &me); + free_env(&me); + } free_env(&se); JL_GC_POP(); return ii; diff --git a/stdlib/LinearAlgebra/src/bidiag.jl b/stdlib/LinearAlgebra/src/bidiag.jl index 317ed15af770c..fb29f9ae595b9 100644 --- a/stdlib/LinearAlgebra/src/bidiag.jl +++ b/stdlib/LinearAlgebra/src/bidiag.jl @@ -702,14 +702,15 @@ function dot(x::AbstractVector, B::Bidiagonal, y::AbstractVector) require_one_based_indexing(x, y) nx, ny = length(x), length(y) (nx == size(B, 1) == ny) || throw(DimensionMismatch()) - if iszero(nx) - return dot(zero(eltype(x)), zero(eltype(B)), zero(eltype(y))) + if nx ≤ 1 + nx == 0 && return dot(zero(eltype(x)), zero(eltype(B)), zero(eltype(y))) + return dot(x[1], B.dv[1], y[1]) end ev, dv = B.ev, B.dv - if B.uplo == 'U' + @inbounds if B.uplo == 'U' x₀ = x[1] r = dot(x[1], dv[1], y[1]) - @inbounds for j in 2:nx-1 + for j in 2:nx-1 x₋, x₀ = x₀, x[j] r += dot(adjoint(ev[j-1])*x₋ + adjoint(dv[j])*x₀, y[j]) end @@ -719,7 +720,7 @@ function dot(x::AbstractVector, B::Bidiagonal, y::AbstractVector) x₀ = x[1] x₊ = x[2] r = dot(adjoint(dv[1])*x₀ + adjoint(ev[1])*x₊, y[1]) - @inbounds for j in 2:nx-1 + for j in 2:nx-1 x₀, x₊ = x₊, x[j+1] r += dot(adjoint(dv[j])*x₀ + adjoint(ev[j])*x₊, y[j]) end diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index 1d6fb0ecda0bc..c415b151bf363 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -380,9 +380,9 @@ norm solution. Multiplication with respect to either full/square or non-full/square `Q` is allowed, i.e. both `F.Q*F.R` and `F.Q*A` are supported. A `Q` matrix can be converted into a regular matrix with -[`Matrix`](@ref). This operation returns the "thin" Q factor, i.e., if `A` is `m`×`n` with `m>=n`, then +[`Matrix`](@ref). This operation returns the "thin" Q factor, i.e., if `A` is `m`×`n` with `m>=n`, then `Matrix(F.Q)` yields an `m`×`n` matrix with orthonormal columns. To retrieve the "full" Q factor, an -`m`×`m` orthogonal matrix, use `F.Q*Matrix(I,m,m)`. If `m<=n`, then `Matrix(F.Q)` yields an `m`×`m` +`m`×`m` orthogonal matrix, use `F.Q*I`. If `m<=n`, then `Matrix(F.Q)` yields an `m`×`m` orthogonal matrix. The block size for QR decomposition can be specified by keyword argument diff --git a/stdlib/LinearAlgebra/src/special.jl b/stdlib/LinearAlgebra/src/special.jl index 1ead4826127c2..ad62fea13eadc 100644 --- a/stdlib/LinearAlgebra/src/special.jl +++ b/stdlib/LinearAlgebra/src/special.jl @@ -347,10 +347,10 @@ end *(A::Diagonal, Q::AbstractQ) = _qrmul(A, Q) *(A::Diagonal, Q::Adjoint{<:Any,<:AbstractQ}) = _qrmul(A, Q) -*(Q::AbstractQ, B::AbstractQ) = _qlmul(Q, B) -*(Q::Adjoint{<:Any,<:AbstractQ}, B::AbstractQ) = _qrmul(Q, B) -*(Q::AbstractQ, B::Adjoint{<:Any,<:AbstractQ}) = _qlmul(Q, B) -*(Q::Adjoint{<:Any,<:AbstractQ}, B::Adjoint{<:Any,<:AbstractQ}) = _qrmul(Q, B) +*(Q::AbstractQ, B::AbstractQ) = Q * (B * I) +*(Q::Adjoint{<:Any,<:AbstractQ}, B::AbstractQ) = Q * (B * I) +*(Q::AbstractQ, B::Adjoint{<:Any,<:AbstractQ}) = Q * (B * I) +*(Q::Adjoint{<:Any,<:AbstractQ}, B::Adjoint{<:Any,<:AbstractQ}) = Q * (B * I) # fill[stored]! methods fillstored!(A::Diagonal, x) = (fill!(A.diag, x); A) diff --git a/stdlib/LinearAlgebra/src/tridiag.jl b/stdlib/LinearAlgebra/src/tridiag.jl index e5c31856d3f0a..d6b44d85e68e9 100644 --- a/stdlib/LinearAlgebra/src/tridiag.jl +++ b/stdlib/LinearAlgebra/src/tridiag.jl @@ -256,21 +256,24 @@ end function dot(x::AbstractVector, S::SymTridiagonal, y::AbstractVector) require_one_based_indexing(x, y) nx, ny = length(x), length(y) - (nx == size(S, 1) == ny) || throw(DimensionMismatch()) - if iszero(nx) - return dot(zero(eltype(x)), zero(eltype(S)), zero(eltype(y))) + (nx == size(S, 1) == ny) || throw(DimensionMismatch("dot")) + if nx ≤ 1 + nx == 0 && return dot(zero(eltype(x)), zero(eltype(S)), zero(eltype(y))) + return dot(x[1], S.dv[1], y[1]) end dv, ev = S.dv, S.ev - x₀ = x[1] - x₊ = x[2] - sub = transpose(ev[1]) - r = dot(adjoint(dv[1])*x₀ + adjoint(sub)*x₊, y[1]) - @inbounds for j in 2:nx-1 - x₋, x₀, x₊ = x₀, x₊, x[j+1] - sup, sub = transpose(sub), transpose(ev[j]) - r += dot(adjoint(sup)*x₋ + adjoint(dv[j])*x₀ + adjoint(sub)*x₊, y[j]) - end - r += dot(adjoint(transpose(sub))*x₀ + adjoint(dv[nx])*x₊, y[nx]) + @inbounds begin + x₀ = x[1] + x₊ = x[2] + sub = transpose(ev[1]) + r = dot(adjoint(dv[1])*x₀ + adjoint(sub)*x₊, y[1]) + for j in 2:nx-1 + x₋, x₀, x₊ = x₀, x₊, x[j+1] + sup, sub = transpose(sub), transpose(ev[j]) + r += dot(adjoint(sup)*x₋ + adjoint(dv[j])*x₀ + adjoint(sub)*x₊, y[j]) + end + r += dot(adjoint(transpose(sub))*x₀ + adjoint(dv[nx])*x₊, y[nx]) + end return r end @@ -841,18 +844,21 @@ function dot(x::AbstractVector, A::Tridiagonal, y::AbstractVector) require_one_based_indexing(x, y) nx, ny = length(x), length(y) (nx == size(A, 1) == ny) || throw(DimensionMismatch()) - if iszero(nx) - return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y))) - end - x₀ = x[1] - x₊ = x[2] - dl, d, du = A.dl, A.d, A.du - r = dot(adjoint(d[1])*x₀ + adjoint(dl[1])*x₊, y[1]) - @inbounds for j in 2:nx-1 - x₋, x₀, x₊ = x₀, x₊, x[j+1] - r += dot(adjoint(du[j-1])*x₋ + adjoint(d[j])*x₀ + adjoint(dl[j])*x₊, y[j]) - end - r += dot(adjoint(du[nx-1])*x₀ + adjoint(d[nx])*x₊, y[nx]) + if nx ≤ 1 + nx == 0 && return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y))) + return dot(x[1], A.d[1], y[1]) + end + @inbounds begin + x₀ = x[1] + x₊ = x[2] + dl, d, du = A.dl, A.d, A.du + r = dot(adjoint(d[1])*x₀ + adjoint(dl[1])*x₊, y[1]) + for j in 2:nx-1 + x₋, x₀, x₊ = x₀, x₊, x[j+1] + r += dot(adjoint(du[j-1])*x₋ + adjoint(d[j])*x₀ + adjoint(dl[j])*x₊, y[j]) + end + r += dot(adjoint(du[nx-1])*x₀ + adjoint(d[nx])*x₊, y[nx]) + end return r end diff --git a/stdlib/LinearAlgebra/test/bidiag.jl b/stdlib/LinearAlgebra/test/bidiag.jl index 422984d84eb6b..c711bf3e1e1c1 100644 --- a/stdlib/LinearAlgebra/test/bidiag.jl +++ b/stdlib/LinearAlgebra/test/bidiag.jl @@ -623,14 +623,14 @@ end end @testset "generalized dot" begin - for elty in (Float64, ComplexF64) - dv = randn(elty, 5) - ev = randn(elty, 4) - x = randn(elty, 5) - y = randn(elty, 5) + for elty in (Float64, ComplexF64), n in (5, 1) + dv = randn(elty, n) + ev = randn(elty, n-1) + x = randn(elty, n) + y = randn(elty, n) for uplo in (:U, :L) B = Bidiagonal(dv, ev, uplo) - @test dot(x, B, y) ≈ dot(B'x, y) ≈ dot(x, Matrix(B), y) + @test dot(x, B, y) ≈ dot(B'x, y) ≈ dot(x, B*y) ≈ dot(x, Matrix(B), y) end dv = Vector{elty}(undef, 0) ev = Vector{elty}(undef, 0) @@ -638,7 +638,7 @@ end y = Vector{elty}(undef, 0) for uplo in (:U, :L) B = Bidiagonal(dv, ev, uplo) - @test dot(x, B, y) ≈ dot(zero(elty), zero(elty), zero(elty)) + @test dot(x, B, y) === zero(elty) end end end diff --git a/stdlib/LinearAlgebra/test/special.jl b/stdlib/LinearAlgebra/test/special.jl index 277c51bb9f7bb..ad2bda61d1d17 100644 --- a/stdlib/LinearAlgebra/test/special.jl +++ b/stdlib/LinearAlgebra/test/special.jl @@ -215,16 +215,29 @@ end atri = typ(a) matri = Matrix(atri) b = rand(n,n) - qrb = qr(b, ColumnNorm()) - @test atri * qrb.Q ≈ matri * qrb.Q ≈ rmul!(copy(atri), qrb.Q) - @test atri * qrb.Q' ≈ matri * qrb.Q' ≈ rmul!(copy(atri), qrb.Q') - @test qrb.Q * atri ≈ qrb.Q * matri ≈ lmul!(qrb.Q, copy(atri)) - @test qrb.Q' * atri ≈ qrb.Q' * matri ≈ lmul!(qrb.Q', copy(atri)) - qrb = qr(b, NoPivot()) - @test atri * qrb.Q ≈ matri * qrb.Q ≈ rmul!(copy(atri), qrb.Q) - @test atri * qrb.Q' ≈ matri * qrb.Q' ≈ rmul!(copy(atri), qrb.Q') - @test qrb.Q * atri ≈ qrb.Q * matri ≈ lmul!(qrb.Q, copy(atri)) - @test qrb.Q' * atri ≈ qrb.Q' * matri ≈ lmul!(qrb.Q', copy(atri)) + for pivot in (ColumnNorm(), NoPivot()) + qrb = qr(b, pivot) + @test atri * qrb.Q ≈ matri * qrb.Q ≈ rmul!(copy(atri), qrb.Q) + @test atri * qrb.Q' ≈ matri * qrb.Q' ≈ rmul!(copy(atri), qrb.Q') + @test qrb.Q * atri ≈ qrb.Q * matri ≈ lmul!(qrb.Q, copy(atri)) + @test qrb.Q' * atri ≈ qrb.Q' * matri ≈ lmul!(qrb.Q', copy(atri)) + end + end +end + +@testset "Multiplication of Qs" begin + for pivot in (ColumnNorm(), NoPivot()), A in (rand(5, 3), rand(5, 5), rand(3, 5)) + Q = qr(A, pivot).Q + m = size(A, 1) + C = Matrix{Float64}(undef, (m, m)) + @test Q*Q ≈ (Q*I) * (Q*I) ≈ mul!(C, Q, Q) + @test size(Q*Q) == (m, m) + @test Q'Q ≈ (Q'*I) * (Q*I) ≈ mul!(C, Q', Q) + @test size(Q'Q) == (m, m) + @test Q*Q' ≈ (Q*I) * (Q'*I) ≈ mul!(C, Q, Q') + @test size(Q*Q') == (m, m) + @test Q'Q' ≈ (Q'*I) * (Q'*I) ≈ mul!(C, Q', Q') + @test size(Q'Q') == (m, m) end end diff --git a/stdlib/LinearAlgebra/test/tridiag.jl b/stdlib/LinearAlgebra/test/tridiag.jl index ecdf6b416baa5..0698a583c8d45 100644 --- a/stdlib/LinearAlgebra/test/tridiag.jl +++ b/stdlib/LinearAlgebra/test/tridiag.jl @@ -434,7 +434,11 @@ end @testset "generalized dot" begin x = fill(convert(elty, 1), n) y = fill(convert(elty, 1), n) - @test dot(x, A, y) ≈ dot(A'x, y) + @test dot(x, A, y) ≈ dot(A'x, y) ≈ dot(x, A*y) + @test dot([1], SymTridiagonal([1], Int[]), [1]) == 1 + @test dot([1], Tridiagonal(Int[], [1], Int[]), [1]) == 1 + @test dot(Int[], SymTridiagonal(Int[], Int[]), Int[]) === 0 + @test dot(Int[], Tridiagonal(Int[], Int[], Int[]), Int[]) === 0 end end end diff --git a/stdlib/Logging/src/ConsoleLogger.jl b/stdlib/Logging/src/ConsoleLogger.jl index 86e3d587eb452..3d283e7a33456 100644 --- a/stdlib/Logging/src/ConsoleLogger.jl +++ b/stdlib/Logging/src/ConsoleLogger.jl @@ -118,7 +118,7 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module # split into lines. msglines = [(indent=0, msg=l) for l in split(chomp(convert(String, string(message))::String), '\n')] stream = logger.stream - if !isopen(stream) + if !(isopen(stream)::Bool) stream = stderr end dsize = displaysize(stream)::Tuple{Int,Int} diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 464e7fd2c45a4..cba86fbb03674 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.8 -PKG_SHA1 = 63f4405d17e11decd2e5eb786cc491322b68c58c +PKG_SHA1 = 03e3bad8ef894f5a8b0edcfb00e4025173652b2b 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/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index e3daa4677f077..a8beb58b4eb92 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -1380,7 +1380,7 @@ end end # returns the width of the written prompt -function write_prompt(terminal, s::Union{AbstractString,Function}, color::Bool) +function write_prompt(terminal::AbstractTerminal, s::Union{AbstractString,Function}, color::Bool) @static Sys.iswindows() && _reset_console_mode() promptstr = prompt_string(s)::String write(terminal, promptstr) @@ -1438,7 +1438,7 @@ function normalize_keys(keymap::Union{Dict{Char,Any},AnyDict}) return ret end -function add_nested_key!(keymap::Dict, key::Union{String, Char}, value; override = false) +function add_nested_key!(keymap::Dict{Char, Any}, key::Union{String, Char}, value; override::Bool = false) y = iterate(key) while y !== nothing c, i = y @@ -1453,7 +1453,7 @@ function add_nested_key!(keymap::Dict, key::Union{String, Char}, value; override elseif !(c in keys(keymap) && isa(keymap[c], Dict)) keymap[c] = Dict{Char,Any}() end - keymap = keymap[c] + keymap = keymap[c]::Dict{Char, Any} end end diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index 162d1184d18c3..07b904c6abb84 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -418,9 +418,9 @@ function get_value(sym::Expr, fn) end sym.head !== :. && return (nothing, false) for ex in sym.args - ex, found = get_value(ex, fn) + ex, found = get_value(ex, fn)::Tuple{Any, Bool} !found && return (nothing, false) - fn, found = get_value(ex, fn) + fn, found = get_value(ex, fn)::Tuple{Any, Bool} !found && return (nothing, false) end return (fn, true) diff --git a/stdlib/TOML/src/print.jl b/stdlib/TOML/src/print.jl index 059414152f727..46c5ecc357fbd 100644 --- a/stdlib/TOML/src/print.jl +++ b/stdlib/TOML/src/print.jl @@ -78,7 +78,7 @@ printvalue(f::MbyFunc, io::IO, value::Integer; _...) = Base.print(io, Int64(value)) # TOML specifies 64-bit signed long range for integer printvalue(f::MbyFunc, io::IO, value::AbstractFloat; _...) = Base.print(io, isnan(value) ? "nan" : - isinf(value) ? string(value > 0 ? "+" : "-", "inf") : + !(isfinite(value)::Bool) ? string(value > 0 ? "+" : "-", "inf") : Float64(value)) # TOML specifies IEEE 754 binary64 for float function printvalue(f::MbyFunc, io::IO, value::AbstractString; _...) Base.print(io, "\"") diff --git a/test/bitset.jl b/test/bitset.jl index 1919da4f3702a..6c7947ebc37af 100644 --- a/test/bitset.jl +++ b/test/bitset.jl @@ -351,3 +351,12 @@ end # union! with an empty range doesn't modify the BitSet @test union!(x, b:a) == y end + +@testset "union!(::BitSet, ::AbstractUnitRange) when two ranges do not overlap" begin + # see #45574 + a, b = rand(-10000:-5000), rand(5000:10000) + c, d = minmax(rand(20000:30000, 2)...) + @test length(union!(BitSet(a:b), c:d)) == length(a:b) + length(c:d) + c, d = minmax(rand(-30000:-20000, 2)...) + @test length(union!(BitSet(a:b), c:d)) == length(a:b) + length(c:d) +end diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 8ea3a55030fe3..70a720e53f209 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -4062,3 +4062,15 @@ end let t = Core.Compiler.tuple_tfunc(Any[Core.Const(42), Vararg{Any}]) @test Core.Compiler.issimplertype(t, t) end + +# issue #45600 +@test only(code_typed() do + while true + x = try finally end + end +end)[2] == Union{} +@test only(code_typed() do + while true + @time 1 + end +end)[2] == Union{} diff --git a/test/copy.jl b/test/copy.jl index c4fcff40f2b3f..633beee5f2af3 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -252,3 +252,19 @@ end a = [1:3;] @test copyto!(a, 2:3, 1:1, a, 1:2, 1:1) == [1;1:2;] end + +@testset "`deepcopy` a `GenericCondition`" begin + a = Base.GenericCondition(ReentrantLock()) + @test !islocked(a.lock) + lock(a.lock) + @test islocked(a.lock) + b = deepcopy(a) + @test typeof(a) === typeof(b) + @test a != b + @test a !== b + @test typeof(a.lock) === typeof(b.lock) + @test a.lock != b.lock + @test a.lock !== b.lock + @test islocked(a.lock) + @test !islocked(b.lock) +end diff --git a/test/math.jl b/test/math.jl index 5daf1ef465509..1946e73829eb6 100644 --- a/test/math.jl +++ b/test/math.jl @@ -1318,18 +1318,41 @@ end end @testset "pow" begin + # tolerance by type for regular powers + POW_TOLS = Dict(Float16=>[.51, .51, 2.0, 1.5], + Float32=>[.51, .51, 2.0, 1.5], + Float64=>[1.0, 1.5, 2.0, 1.5]) for T in (Float16, Float32, Float64) for x in (0.0, -0.0, 1.0, 10.0, 2.0, Inf, NaN, -Inf, -NaN) for y in (0.0, -0.0, 1.0, -3.0,-10.0 , Inf, NaN, -Inf, -NaN) - got, expected = T(x)^T(y), T(big(x))^T(y) - @test isnan_type(T, got) && isnan_type(T, expected) || (got === expected) + got, expected = T(x)^T(y), T(big(x)^T(y)) + if isnan(expected) + @test isnan_type(T, got) || T.((x,y)) + else + @test got == expected || T.((x,y)) + end end end for _ in 1:2^16 + # note x won't be subnormal here x=rand(T)*100; y=rand(T)*200-100 got, expected = x^y, widen(x)^y if isfinite(eps(T(expected))) - @test abs(expected-got) <= 1.3*eps(T(expected)) || (x,y) + if y == T(-2) # unfortunately x^-2 is less accurate for performance reasons. + @test abs(expected-got) <= POW_TOLS[T][3]*eps(T(expected)) || (x,y) + elseif y == T(3) # unfortunately x^3 is less accurate for performance reasons. + @test abs(expected-got) <= POW_TOLS[T][4]*eps(T(expected)) || (x,y) + else + @test abs(expected-got) <= POW_TOLS[T][1]*eps(T(expected)) || (x,y) + end + end + end + for _ in 1:2^14 + # test subnormal(x), y in -1.2, 1.8 since anything larger just overflows. + x=rand(T)*floatmin(T); y=rand(T)*3-T(1.2) + got, expected = x^y, widen(x)^y + if isfinite(eps(T(expected))) + @test abs(expected-got) <= POW_TOLS[T][2]*eps(T(expected)) || (x,y) end end # test (-x)^y for y larger than typemax(Int) @@ -1339,6 +1362,7 @@ end end # test for large negative exponent where error compensation matters @test 0.9999999955206014^-1.0e8 == 1.565084574870928 + @test 3e18^20 == Inf end # Test that sqrt behaves correctly and doesn't exhibit fp80 double rounding. diff --git a/test/misc.jl b/test/misc.jl index 9ad9b4e21acac..bda0566650170 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -1097,6 +1097,37 @@ const outsidevar = 7 end @test TestOutsideVar() == TestOutsideVar(7) +@kwdef mutable struct Test_kwdef_const_atomic + a + b::Int + c::Int = 1 + const d + const e::Int + const f = 1 + const g::Int = 1 + @atomic h::Int +end + +@testset "const and @atomic fields in @kwdef" begin + x = Test_kwdef_const_atomic(a = 1, b = 1, d = 1, e = 1, h = 1) + for f in fieldnames(Test_kwdef_const_atomic) + @test getfield(x, f) == 1 + end + @testset "const fields" begin + @test_throws ErrorException x.d = 2 + @test_throws ErrorException x.e = 2 + @test_throws MethodError x.e = "2" + @test_throws ErrorException x.f = 2 + @test_throws ErrorException x.g = 2 + end + @testset "atomic fields" begin + @test_throws ConcurrencyViolationError x.h = 1 + @atomic x.h = 1 + @test @atomic(x.h) == 1 + @atomic x.h = 2 + @test @atomic(x.h) == 2 + end +end @testset "exports of modules" begin for (_, mod) in Base.loaded_modules diff --git a/test/operators.jl b/test/operators.jl index 97edebc0ea6f3..1c5d2d33bf0f8 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -175,6 +175,15 @@ Base.promote_rule(::Type{T19714}, ::Type{Int}) = T19714 end +@testset "Nested ComposedFunction's stability" begin + f(x) = (1, 1, x...) + g = (f ∘ (f ∘ f)) ∘ (f ∘ f ∘ f) + @test (@inferred (g∘g)(1)) == ntuple(Returns(1), 25) + @test (@inferred g(1)) == ntuple(Returns(1), 13) + h = (-) ∘ (-) ∘ (-) ∘ (-) ∘ (-) ∘ (-) ∘ sum + @test (@inferred h((1, 2, 3); init = 0.0)) == 6.0 +end + @testset "function negation" begin str = randstring(20) @test filter(!isuppercase, str) == replace(str, r"[A-Z]" => "") @@ -302,4 +311,18 @@ end val = [1,2,3] @test Returns(val)(1) === val @test sprint(show, Returns(1.0)) == "Returns{Float64}(1.0)" + + illtype = Vector{Core._typevar(:T, Union{}, Any)} + @test Returns(illtype) == Returns{DataType}(illtype) +end + +@testset "<= (issue #46327)" begin + struct A46327 <: Real end + Base.:(==)(::A46327, ::A46327) = false + Base.:(<)(::A46327, ::A46327) = false + @test !(A46327() <= A46327()) + struct B46327 <: Real end + Base.:(==)(::B46327, ::B46327) = true + Base.:(<)(::B46327, ::B46327) = false + @test B46327() <= B46327() end diff --git a/test/reduce.jl b/test/reduce.jl index 0e1568b0af901..4bd0916c1702e 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -677,3 +677,16 @@ end @test mapreduce(+, +, oa, oa) == 2len end end + +# issue #45748 +@testset "foldl's stability for nested Iterators" begin + a = Iterators.flatten((1:3, 1:3)) + b = (2i for i in a if i > 0) + c = Base.Generator(Float64, b) + d = (sin(i) for i in c if i > 0) + @test @inferred(sum(d)) == sum(collect(d)) + @test @inferred(extrema(d)) == extrema(collect(d)) + @test @inferred(maximum(c)) == maximum(collect(c)) + @test @inferred(prod(b)) == prod(collect(b)) + @test @inferred(minimum(a)) == minimum(collect(a)) +end diff --git a/test/strings/basic.jl b/test/strings/basic.jl index b20c18e636db7..547a006cb7bd6 100644 --- a/test/strings/basic.jl +++ b/test/strings/basic.jl @@ -723,6 +723,11 @@ end @test_throws ArgumentError "abc"[BitArray([true, false, true])] end +@testset "issue #46039 enhance StringIndexError display" begin + @test sprint(showerror, StringIndexError("αn", 2)) == "StringIndexError: invalid index [2], valid nearby indices [1]=>'α', [3]=>'n'" + @test sprint(showerror, StringIndexError("α\n", 2)) == "StringIndexError: invalid index [2], valid nearby indices [1]=>'α', [3]=>'\\n'" +end + @testset "concatenation" begin @test "ab" * "cd" == "abcd" @test 'a' * "bc" == "abc" diff --git a/test/subtype.jl b/test/subtype.jl index b17f502bc2e00..70c8c0cb354b6 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -1928,12 +1928,24 @@ let A = Tuple{Ref{T}, Vararg{T}} where T, B = Tuple{Ref{U}, Union{Ref{S}, Ref{U}, Int}, Union{Ref{S}, S}} where S where U, C = Tuple{Ref{U}, Union{Ref{S}, Ref{U}, Ref{W}}, Union{Ref{S}, W, V}} where V<:AbstractArray where W where S where U I = typeintersect(A, B) + Ts = (Tuple{Ref{Int}, Int, Int}, Tuple{Ref{Ref{Int}}, Ref{Int}, Ref{Int}}) @test I != Union{} @test I <: A - @test I <: B - # avoid stack overflow + @test_broken I <: B + for T in Ts + if T <: A && T <: B + @test T <: I + end + end J = typeintersect(A, C) - @test_broken J != Union{} + @test J != Union{} + @test J <: A + @test_broken J <: C + for T in Ts + if T <: A && T <: C + @test T <: J + end + end end let A = Tuple{Dict{I,T}, I, T} where T where I, @@ -1964,8 +1976,9 @@ let A = Tuple{Any, Type{Ref{_A}} where _A}, B = Tuple{Type{T}, Type{<:Union{Ref{T}, T}}} where T, I = typeintersect(A, B) @test I != Union{} - # TODO: this intersection result is still too narrow - @test_broken Tuple{Type{Ref{Integer}}, Type{Ref{Integer}}} <: I + @test Tuple{Type{Ref{Integer}}, Type{Ref{Integer}}} <: I + # TODO: this intersection result seems too wide (I == B) ? + @test_broken !<:(Tuple{Type{Int}, Type{Int}}, I) end @testintersect(Tuple{Type{T}, T} where T<:(Tuple{Vararg{_A, _B}} where _B where _A), @@ -1996,3 +2009,14 @@ let T = TypeVar(:T, Real), @test !(UnionAll(T, UnionAll(V, UnionAll(T, Type{Pair{T, V}}))) <: UnionAll(T, UnionAll(V, Type{Pair{T, V}}))) @test !(UnionAll(T, UnionAll(V, UnionAll(T, S))) <: UnionAll(T, UnionAll(V, S))) end + +# issue #41096 +let C = Val{Val{B}} where {B} + @testintersect(Val{<:Union{Missing, Val{false}, Val{true}}}, C, Val{<:Union{Val{true}, Val{false}}}) + @testintersect(Val{<:Union{Nothing, Val{true}, Val{false}}}, C, Val{<:Union{Val{true}, Val{false}}}) + @testintersect(Val{<:Union{Nothing, Val{false}}}, C, Val{Val{false}}) +end + +#issue #43082 +struct X43082{A, I, B<:Union{Ref{I},I}}; end +@testintersect(Tuple{X43082{T}, Int} where T, Tuple{X43082{Int}, Any}, Tuple{X43082{Int}, Int})