diff --git a/Makefile b/Makefile index d7d25998688c5..2d4116147693d 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,10 @@ $(foreach link,base $(JULIAHOME)/test,$(eval $(call symlink_target,$(link),$$(bu julia_flisp.boot.inc.phony: julia-deps @$(MAKE) $(QUIET_MAKE) -C $(BUILDROOT)/src julia_flisp.boot.inc.phony +# Build the HTML docs (skipped if already exists, notably in tarballs) +$(BUILDROOT)/doc/_build/html/en/index.html: $(shell find $(BUILDROOT)/base $(BUILDROOT)/doc \( -path $(BUILDROOT)/doc/_build -o -path $(BUILDROOT)/doc/deps -o -name *_constants.jl -o -name *_h.jl -o -name version_git.jl \) -prune -o -type f -print) + @$(MAKE) docs + julia-symlink: julia-cli-$(JULIA_BUILD_MODE) ifeq ($(OS),WINNT) echo '@"%~dp0/'"$$(echo '$(call rel_path,$(BUILDROOT),$(JULIA_EXECUTABLE))')"'" %*' | tr / '\\' > $(BUILDROOT)/julia.bat @@ -272,7 +276,7 @@ define stringreplace endef -install: $(build_depsbindir)/stringreplace docs +install: $(build_depsbindir)/stringreplace $(BUILDROOT)/doc/_build/html/en/index.html @$(MAKE) $(QUIET_MAKE) $(JULIA_BUILD_MODE) @for subdir in $(bindir) $(datarootdir)/julia/stdlib/$(VERSDIR) $(docdir) $(man1dir) $(includedir)/julia $(libdir) $(private_libdir) $(sysconfdir) $(private_libexecdir); do \ mkdir -p $(DESTDIR)$$subdir; \ @@ -530,7 +534,7 @@ app: darwinframework: $(MAKE) -C $(JULIAHOME)/contrib/mac/framework -light-source-dist.tmp: docs +light-source-dist.tmp: $(BUILDROOT)/doc/_build/html/en/index.html ifneq ($(BUILDROOT),$(JULIAHOME)) $(error make light-source-dist does not work in out-of-tree builds) endif diff --git a/NEWS.md b/NEWS.md index 2e2d8a8a1a17b..1279f46df609e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -47,7 +47,7 @@ Compiler/Runtime improvements Command-line option changes --------------------------- -* The entry point for Julia has been standardized to `Main.main(ARGS)`. This must be explicitly opted into using the `@main` macro +* The entry point for Julia has been standardized to `Main.main(args)`. This must be explicitly opted into using the `@main` macro (see the docstring for further details). When opted-in, and `julia` is invoked to run a script or expression (i.e. using `julia script.jl` or `julia -e expr`), `julia` will subsequently run the `Main.main` function automatically. This is intended to unify script and compilation workflows, where code loading may happen diff --git a/base/Base.jl b/base/Base.jl index 491725b29f853..e192fd3f48cf6 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -401,8 +401,11 @@ include("weakkeydict.jl") include("scopedvalues.jl") using .ScopedValues +# metaprogramming +include("meta.jl") + # Logging -include("logging.jl") +include("logging/logging.jl") using .CoreLogging include("env.jl") @@ -494,9 +497,6 @@ include("irrationals.jl") include("mathconstants.jl") using .MathConstants: ℯ, π, pi -# metaprogramming -include("meta.jl") - # Stack frames and traces include("stacktraces.jl") using .StackTraces @@ -633,6 +633,8 @@ function __init__() if get_bool_env("JULIA_USE_FLISP_PARSER", false) === false JuliaSyntax.enable_in_core!() end + + CoreLogging.global_logger(CoreLogging.ConsoleLogger()) nothing end diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 9042e5f81e462..56390de1eb5d3 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1078,45 +1078,28 @@ function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle: if srcstyle isa IndexLinear # Single-index implementation @inbounds for i in srcinds - if isassigned(src, i) - dest[i + Δi] = src[i] - else - _unsetindex!(dest, i + Δi) - end + dest[i + Δi] = src[i] end else # Dual-index implementation i = idf - 1 - @inbounds for a in eachindex(src) - i += 1 - if isassigned(src, a) - dest[i] = src[a] - else - _unsetindex!(dest, i) - end + @inbounds for a in src + dest[i+=1] = a end end else iterdest, itersrc = eachindex(dest), eachindex(src) if iterdest == itersrc # Shared-iterator implementation - @inbounds for I in iterdest - if isassigned(src, I) - dest[I] = src[I] - else - _unsetindex!(dest, I) - end + for I in iterdest + @inbounds dest[I] = src[I] end else # Dual-iterator implementation ret = iterate(iterdest) - @inbounds for a in itersrc + @inbounds for a in src idx, state = ret::NTuple{2,Any} - if isassigned(src, a) - dest[idx] = src[a] - else - _unsetindex!(dest, idx) - end + dest[idx] = a ret = iterate(iterdest, state) end end @@ -1145,11 +1128,7 @@ function copyto!(dest::AbstractArray, dstart::Integer, (checkbounds(Bool, srcinds, sstart) && checkbounds(Bool, srcinds, sstart+n-1)) || throw(BoundsError(src, sstart:sstart+n-1)) src′ = unalias(dest, src) @inbounds for i = 0:n-1 - if isassigned(src′, sstart+i) - dest[dstart+i] = src′[sstart+i] - else - _unsetindex!(dest, dstart+i) - end + dest[dstart+i] = src′[sstart+i] end return dest end @@ -1160,7 +1139,7 @@ function copy(a::AbstractArray) end function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int}, - A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S} + A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S} if length(ir_dest) != length(ir_src) throw(ArgumentError(LazyString("source and destination must have same size (got ", length(ir_src)," and ",length(ir_dest),")"))) @@ -1473,20 +1452,7 @@ function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) whe r end -function _unsetindex!(A::AbstractArray, i::Integer...) - @_propagate_inbounds_meta - _unsetindex!(A, map(to_index, i)...) -end - -function _unsetindex!(A::AbstractArray{T}, i::Int...) where T - # this provides a fallback method which is a no-op if the element is already unassigned - # such that copying into an uninitialized object generally always will work, - # even if the specific custom array type has not implemented `_unsetindex!` - @inline - @boundscheck checkbounds(A, i...) - allocatedinline(T) || @inbounds(!isassigned(A, i...)) || throw(MethodError(_unsetindex!, (A, i...))) - return A -end +_unsetindex!(A::AbstractArray, i::Integer) = _unsetindex!(A, to_index(i)) """ parent(A) @@ -1650,13 +1616,15 @@ eltypeof(x::AbstractArray) = eltype(x) promote_eltypeof() = error() promote_eltypeof(v1) = eltypeof(v1) -promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...)) +promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2)) +promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...)) promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1) promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T promote_eltype() = error() promote_eltype(v1) = eltype(v1) -promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...)) +promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2)) +promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...)) promote_eltype(v1::T, vs::T...) where {T} = eltype(T) promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T diff --git a/base/array.jl b/base/array.jl index 83ca35714c244..19d79479bef39 100644 --- a/base/array.jl +++ b/base/array.jl @@ -219,12 +219,7 @@ function _unsetindex!(A::Array, i::Int) @inbounds _unsetindex!(GenericMemoryRef(A.ref, i)) return A end -function _unsetindex!(A::Array, i::Int...) - @inline - @boundscheck checkbounds(A, i...) - @inbounds _unsetindex!(A, _to_linear_index(A, i...)) - return A -end + # TODO: deprecate this (aligned_sizeof and/or elsize and/or sizeof(Some{T}) are more correct) elsize(::Type{A}) where {T,A<:Array{T}} = aligned_sizeof(T) diff --git a/base/boot.jl b/base/boot.jl index 5980818a2047b..bfee3c17336bc 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -547,19 +547,22 @@ function _checked_mul_dims(m::Int, n::Int) return a, ovflw end function _checked_mul_dims(m::Int, d::Int...) - @_foldable_meta # the compiler needs to know this loop terminates - a = m - i = 1 - ovflw = false - while Intrinsics.sle_int(i, nfields(d)) - di = getfield(d, i) - b = Intrinsics.checked_smul_int(a, di) - ovflw = Intrinsics.or_int(ovflw, getfield(b, 2)) - ovflw = Intrinsics.or_int(ovflw, Intrinsics.ule_int(typemax_Int, di)) - a = getfield(b, 1) - i = Intrinsics.add_int(i, 1) + @_foldable_meta # the compiler needs to know this loop terminates + a = m + i = 1 + ovflw = false + neg = Intrinsics.ule_int(typemax_Int, m) + zero = false # if m==0 we won't have overflow since we go left to right + while Intrinsics.sle_int(i, nfields(d)) + di = getfield(d, i) + b = Intrinsics.checked_smul_int(a, di) + zero = Intrinsics.or_int(zero, di === 0) + ovflw = Intrinsics.or_int(ovflw, getfield(b, 2)) + neg = Intrinsics.or_int(neg, Intrinsics.ule_int(typemax_Int, di)) + a = getfield(b, 1) + i = Intrinsics.add_int(i, 1) end - return a, ovflw + return a, Intrinsics.or_int(neg, Intrinsics.and_int(ovflw, Intrinsics.not_int(zero))) end # convert a set of dims to a length, with overflow checking diff --git a/base/client.jl b/base/client.jl index 31a3016489dcd..a0d3951391d5f 100644 --- a/base/client.jl +++ b/base/client.jl @@ -260,7 +260,7 @@ function exec_options(opts) # Load Distributed module only if any of the Distributed options have been specified. distributed_mode = (opts.worker == 1) || (opts.nprocs > 0) || (opts.machine_file != C_NULL) if distributed_mode - let Distributed = require_stdlib(PkgId(UUID((0x8ba89e20_285c_5b6f, 0x9357_94700520ee1b)), "Distributed")) + let Distributed = require(PkgId(UUID((0x8ba89e20_285c_5b6f, 0x9357_94700520ee1b)), "Distributed")) Core.eval(MainInclude, :(const Distributed = $Distributed)) Core.eval(Main, :(using Base.MainInclude.Distributed)) end @@ -575,7 +575,7 @@ The `@main` macro may be used standalone or as part of the function definition, case, parentheses are required. In particular, the following are equivalent: ``` -function (@main)(ARGS) +function (@main)(args) println("Hello World") end ``` @@ -594,7 +594,7 @@ imported into `Main`, it will be treated as an entrypoint in `Main`: ``` module MyApp export main - (@main)(ARGS) = println("Hello World") + (@main)(args) = println("Hello World") end using .MyApp # `julia` Will execute MyApp.main at the conclusion of script execution @@ -604,7 +604,7 @@ Note that in particular, the semantics do not attach to the method or the name: ``` module MyApp - (@main)(ARGS) = println("Hello World") + (@main)(args) = println("Hello World") end const main = MyApp.main # `julia` Will *NOT* execute MyApp.main unless there is a separate `@main` annotation in `Main` diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index e79c7188da868..b13df848ce605 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -2574,6 +2574,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp t = Bool effects = EFFECTS_TOTAL exct = Union{} + isa(sym, Symbol) && (sym = GlobalRef(frame_module(sv), sym)) if isa(sym, SlotNumber) && vtypes !== nothing vtyp = vtypes[slot_id(sym)] if vtyp.typ === Bottom @@ -2581,19 +2582,11 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp elseif !vtyp.undef t = Const(true) # definitely assigned previously end - elseif isa(sym, Symbol) - if isdefined(frame_module(sv), sym) - t = Const(true) - elseif InferenceParams(interp).assume_bindings_static - t = Const(false) - else - effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE) - end elseif isa(sym, GlobalRef) - if isdefined(sym.mod, sym.name) + if InferenceParams(interp).assume_bindings_static + t = Const(isdefined_globalref(sym)) + elseif isdefinedconst_globalref(sym) t = Const(true) - elseif InferenceParams(interp).assume_bindings_static - t = Const(false) else effects = Effects(EFFECTS_TOTAL; consistent=ALWAYS_FALSE) end @@ -2782,9 +2775,10 @@ function override_effects(effects::Effects, override::EffectsOverride) end isdefined_globalref(g::GlobalRef) = !iszero(ccall(:jl_globalref_boundp, Cint, (Any,), g)) +isdefinedconst_globalref(g::GlobalRef) = isconst(g) && isdefined_globalref(g) function abstract_eval_globalref_type(g::GlobalRef) - if isdefined_globalref(g) && isconst(g) + if isdefinedconst_globalref(g) return Const(ccall(:jl_get_globalref_value, Any, (Any,), g)) end ty = ccall(:jl_get_binding_type, Any, (Any, Any), g.mod, g.name) @@ -2803,18 +2797,22 @@ function abstract_eval_globalref(interp::AbstractInterpreter, g::GlobalRef, sv:: if is_mutation_free_argtype(rt) inaccessiblememonly = ALWAYS_TRUE end - elseif isdefined_globalref(g) - nothrow = true elseif InferenceParams(interp).assume_bindings_static consistent = inaccessiblememonly = ALWAYS_TRUE - rt = Union{} + if isdefined_globalref(g) + nothrow = true + else + rt = Union{} + end + elseif isdefinedconst_globalref(g) + nothrow = true end return RTEffects(rt, nothrow ? Union{} : UndefVarError, Effects(EFFECTS_TOTAL; consistent, nothrow, inaccessiblememonly)) end function handle_global_assignment!(interp::AbstractInterpreter, frame::InferenceState, lhs::GlobalRef, @nospecialize(newty)) effect_free = ALWAYS_FALSE - nothrow = global_assignment_nothrow(lhs.mod, lhs.name, newty) + nothrow = global_assignment_nothrow(lhs.mod, lhs.name, ignorelimited(newty)) inaccessiblememonly = ALWAYS_FALSE if !nothrow sub_curr_ssaflag!(frame, IR_FLAG_NOTHROW) @@ -3019,7 +3017,6 @@ end return BasicStmtChange(nothing, rt, exct) end changes = nothing - stmt = stmt::Expr hd = stmt.head if hd === :(=) (; rt, exct) = abstract_eval_statement(interp, stmt.args[2], pc_vartable, frame) diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index 9b6fcb760adb4..7d9e612491415 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -305,8 +305,7 @@ function stmt_effect_flags(𝕃ₒ::AbstractLattice, @nospecialize(stmt), @nospe isa(stmt, GotoNode) && return (true, false, true) isa(stmt, GotoIfNot) && return (true, false, ⊑(𝕃ₒ, argextype(stmt.cond, src), Bool)) if isa(stmt, GlobalRef) - nothrow = isdefined(stmt.mod, stmt.name) - consistent = nothrow && isconst(stmt.mod, stmt.name) + nothrow = consistent = isdefinedconst_globalref(stmt) return (consistent, nothrow, nothrow) elseif isa(stmt, Expr) (; head, args) = stmt @@ -534,6 +533,8 @@ function any_stmt_may_throw(ir::IRCode, bb::Int) return false end +visit_conditional_successors(callback, ir::IRCode, bb::Int) = # used for test + visit_conditional_successors(callback, LazyPostDomtree(ir), ir, bb) function visit_conditional_successors(callback, lazypostdomtree::LazyPostDomtree, ir::IRCode, bb::Int) visited = BitSet((bb,)) worklist = Int[bb] @@ -831,31 +832,38 @@ function ((; sv)::ScanStmt)(inst::Instruction, lstmt::Int, bb::Int) stmt_inconsistent = scan_inconsistency!(inst, sv) - if stmt_inconsistent && inst.idx == lstmt - if isa(stmt, ReturnNode) && isdefined(stmt, :val) + if stmt_inconsistent + if !has_flag(inst[:flag], IR_FLAG_NOTHROW) + # Taint :consistent if this statement may raise since :consistent requires + # consistent termination. TODO: Separate :consistent_return and :consistent_termination from :consistent. sv.all_retpaths_consistent = false - elseif isa(stmt, GotoIfNot) - # Conditional Branch with inconsistent condition. - # If we do not know this function terminates, taint consistency, now, - # :consistent requires consistent termination. TODO: Just look at the - # inconsistent region. - if !sv.result.ipo_effects.terminates - sv.all_retpaths_consistent = false - elseif visit_conditional_successors(sv.lazypostdomtree, sv.ir, bb) do succ::Int - return any_stmt_may_throw(sv.ir, succ) - end - # check if this `GotoIfNot` leads to conditional throws, which taints consistency + end + if inst.idx == lstmt + if isa(stmt, ReturnNode) && isdefined(stmt, :val) sv.all_retpaths_consistent = false - else - (; cfg, domtree) = get!(sv.lazyagdomtree) - for succ in iterated_dominance_frontier(cfg, BlockLiveness(sv.ir.cfg.blocks[bb].succs, nothing), domtree) - if succ == length(cfg.blocks) - # Phi node in the virtual exit -> We have a conditional - # return. TODO: Check if all the retvals are egal. - sv.all_retpaths_consistent = false - else - visit_bb_phis!(sv.ir, succ) do phiidx::Int - push!(sv.inconsistent, phiidx) + elseif isa(stmt, GotoIfNot) + # Conditional Branch with inconsistent condition. + # If we do not know this function terminates, taint consistency, now, + # :consistent requires consistent termination. TODO: Just look at the + # inconsistent region. + if !sv.result.ipo_effects.terminates + sv.all_retpaths_consistent = false + elseif visit_conditional_successors(sv.lazypostdomtree, sv.ir, bb) do succ::Int + return any_stmt_may_throw(sv.ir, succ) + end + # check if this `GotoIfNot` leads to conditional throws, which taints consistency + sv.all_retpaths_consistent = false + else + (; cfg, domtree) = get!(sv.lazyagdomtree) + for succ in iterated_dominance_frontier(cfg, BlockLiveness(sv.ir.cfg.blocks[bb].succs, nothing), domtree) + if succ == length(cfg.blocks) + # Phi node in the virtual exit -> We have a conditional + # return. TODO: Check if all the retvals are egal. + sv.all_retpaths_consistent = false + else + visit_bb_phis!(sv.ir, succ) do phiidx::Int + push!(sv.inconsistent, phiidx) + end end end end diff --git a/base/compiler/ssair/domtree.jl b/base/compiler/ssair/domtree.jl index dfe0550d7a06d..bbae3a4d8c0fc 100644 --- a/base/compiler/ssair/domtree.jl +++ b/base/compiler/ssair/domtree.jl @@ -345,10 +345,7 @@ function SNCA!(domtree::GenericDomTree{IsPostDom}, blocks::Vector{BasicBlock}, m ancestors = copy(D.to_parent_pre) relevant_blocks = IsPostDom ? (1:max_pre) : (2:max_pre) for w::PreNumber in reverse(relevant_blocks) - # LLVM initializes this to the parent, the paper initializes this to - # `w`, but it doesn't really matter (the parent is a predecessor, so at - # worst we'll discover it below). Save a memory reference here. - semi_w = typemax(PreNumber) + semi_w = ancestors[w] last_linked = PreNumber(w + 1) for v ∈ dom_edges(domtree, blocks, D.from_pre[w]) # For the purpose of the domtree, ignore virtual predecessors into diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index b817c2af9c49c..6979d1cffe217 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -394,20 +394,13 @@ end return isdefined_tfunc(𝕃, arg1, sym) end @nospecs function isdefined_tfunc(𝕃::AbstractLattice, arg1, sym) - if isa(arg1, Const) - arg1t = typeof(arg1.val) - else - arg1t = widenconst(arg1) - end - if isType(arg1t) - return Bool - end + arg1t = arg1 isa Const ? typeof(arg1.val) : isconstType(arg1) ? typeof(arg1.parameters[1]) : widenconst(arg1) a1 = unwrap_unionall(arg1t) if isa(a1, DataType) && !isabstracttype(a1) if a1 === Module hasintersect(widenconst(sym), Symbol) || return Bottom if isa(sym, Const) && isa(sym.val, Symbol) && isa(arg1, Const) && - isdefined(arg1.val::Module, sym.val::Symbol) + isdefinedconst_globalref(GlobalRef(arg1.val::Module, sym.val::Symbol)) return Const(true) end elseif isa(sym, Const) @@ -433,9 +426,8 @@ end elseif idx <= 0 || (!isvatuple(a1) && idx > fieldcount(a1)) return Const(false) elseif isa(arg1, Const) - arg1v = (arg1::Const).val - if !ismutable(arg1v) || isdefined(arg1v, idx) || isconst(typeof(arg1v), idx) - return Const(isdefined(arg1v, idx)) + if !ismutabletype(a1) || isconst(a1, idx) + return Const(isdefined(arg1.val, idx)) end elseif !isvatuple(a1) fieldT = fieldtype(a1, idx) @@ -987,7 +979,7 @@ end # If we have s00 being a const, we can potentially refine our type-based analysis above if isa(s00, Const) || isconstType(s00) if !isa(s00, Const) - sv = s00.parameters[1] + sv = (s00::DataType).parameters[1] else sv = s00.val end @@ -997,15 +989,16 @@ end isa(sv, Module) && return false isa(nval, Int) || return false end - return isdefined(sv, nval) + return isdefined_tfunc(𝕃, s00, name) === Const(true) end boundscheck && return false # If bounds checking is disabled and all fields are assigned, # we may assume that we don't throw isa(sv, Module) && return false name ⊑ Int || name ⊑ Symbol || return false - for i = 1:fieldcount(typeof(sv)) - isdefined(sv, i) || return false + typeof(sv).name.n_uninitialized == 0 && return true + for i = (datatype_min_ninitialized(typeof(sv)) + 1):nfields(sv) + isdefined_tfunc(𝕃, s00, Const(i)) === Const(true) || return false end return true end @@ -1244,27 +1237,22 @@ end return rewrap_unionall(R, s00) end -@nospecs function getfield_notundefined(typ0, name) - if isa(typ0, Const) && isa(name, Const) - typv = typ0.val - namev = name.val - isa(typv, Module) && return true - if isa(namev, Symbol) || isa(namev, Int) - # Fields are not allowed to transition from defined to undefined, so - # even if the field is not const, all we need to check here is that - # it is defined here. - return isdefined(typv, namev) - end +@nospecs function getfield_notuninit(typ0, name) + if isa(typ0, Const) + # If the object is Const, then we know exactly the bit patterns that + # must be returned by getfield if not an error + return true end typ0 = widenconst(typ0) typ = unwrap_unionall(typ0) if isa(typ, Union) - return getfield_notundefined(rewrap_unionall(typ.a, typ0), name) && - getfield_notundefined(rewrap_unionall(typ.b, typ0), name) + return getfield_notuninit(rewrap_unionall(typ.a, typ0), name) && + getfield_notuninit(rewrap_unionall(typ.b, typ0), name) end isa(typ, DataType) || return false - if typ.name === Tuple.name || typ.name === _NAMEDTUPLE_NAME - # tuples and named tuples can't be instantiated with undefined fields, + isabstracttype(typ) && !isconstType(typ) && return false # cannot say anything about abstract types + if typ.name.n_uninitialized == 0 + # Types such as tuples and named tuples that can't be instantiated with undefined fields, # so we don't need to be conservative here return true end @@ -2436,25 +2424,16 @@ function isdefined_effects(𝕃::AbstractLattice, argtypes::Vector{Any}) # consistent if the first arg is immutable na = length(argtypes) 2 ≤ na ≤ 3 || return EFFECTS_THROWS - obj, sym = argtypes - wobj = unwrapva(obj) + wobj, sym = argtypes + wobj = unwrapva(wobj) + sym = unwrapva(sym) consistent = CONSISTENT_IF_INACCESSIBLEMEMONLY if is_immutable_argtype(wobj) consistent = ALWAYS_TRUE - else - # Bindings/fields are not allowed to transition from defined to undefined, so even - # if the object is not immutable, we can prove `:consistent`-cy if it is defined: - if isa(wobj, Const) && isa(sym, Const) - objval = wobj.val - symval = sym.val - if isa(objval, Module) - if isa(symval, Symbol) && isdefined(objval, symval) - consistent = ALWAYS_TRUE - end - elseif (isa(symval, Symbol) || isa(symval, Int)) && isdefined(objval, symval) - consistent = ALWAYS_TRUE - end - end + elseif isdefined_tfunc(𝕃, wobj, sym) isa Const + # Some bindings/fields are not allowed to transition from defined to undefined or the reverse, so even + # if the object is not immutable, we can prove `:consistent`-cy of this: + consistent = ALWAYS_TRUE end nothrow = isdefined_nothrow(𝕃, argtypes) if hasintersect(widenconst(wobj), Module) @@ -2483,11 +2462,11 @@ function getfield_effects(𝕃::AbstractLattice, argtypes::Vector{Any}, @nospeci # taint `:consistent` if accessing `isbitstype`-type object field that may be initialized # with undefined value: note that we don't need to taint `:consistent` if accessing # uninitialized non-`isbitstype` field since it will simply throw `UndefRefError` - # NOTE `getfield_notundefined` conservatively checks if this field is never initialized + # NOTE `getfield_notuninit` conservatively checks if this field is never initialized # with undefined value to avoid tainting `:consistent` too aggressively # TODO this should probably taint `:noub`, however, it would hinder concrete eval for # `REPLInterpreter` that can ignore `:consistent-cy`, causing worse completions - if !(length(argtypes) ≥ 2 && getfield_notundefined(obj, argtypes[2])) + if !(length(argtypes) ≥ 2 && getfield_notuninit(obj, argtypes[2])) consistent = ALWAYS_FALSE end noub = ALWAYS_TRUE @@ -3123,7 +3102,7 @@ end if M isa Const && s isa Const M, s = M.val, s.val if M isa Module && s isa Symbol - return isdefined(M, s) + return isdefinedconst_globalref(GlobalRef(M, s)) end end return false @@ -3196,9 +3175,9 @@ end end function global_assignment_nothrow(M::Module, s::Symbol, @nospecialize(newty)) - if isdefined(M, s) && !isconst(M, s) + if !isconst(M, s) ty = ccall(:jl_get_binding_type, Any, (Any, Any), M, s) - return ty === nothing || newty ⊑ ty + return ty isa Type && widenconst(newty) <: ty end return false end @@ -3214,7 +3193,7 @@ end end @nospecs function get_binding_type_tfunc(𝕃::AbstractLattice, M, s) if get_binding_type_effect_free(M, s) - return Const(Core.get_binding_type((M::Const).val, (s::Const).val)) + return Const(Core.get_binding_type((M::Const).val::Module, (s::Const).val::Symbol)) end return Type end diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index 747fd6e3ef705..fc1c537f740cd 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -204,9 +204,8 @@ If set to `true`, record per-method-instance timings within type inference in th __set_measure_typeinf(onoff::Bool) = __measure_typeinf__[] = onoff const __measure_typeinf__ = fill(false) -# Wrapper around `_typeinf` that optionally records the exclusive time for -# each inference performed by `NativeInterpreter`. -function typeinf(interp::NativeInterpreter, frame::InferenceState) +# Wrapper around `_typeinf` that optionally records the exclusive time for each invocation. +function typeinf(interp::AbstractInterpreter, frame::InferenceState) if __measure_typeinf__[] Timings.enter_new_timer(frame) v = _typeinf(interp, frame) @@ -216,7 +215,6 @@ function typeinf(interp::NativeInterpreter, frame::InferenceState) return _typeinf(interp, frame) end end -typeinf(interp::AbstractInterpreter, frame::InferenceState) = _typeinf(interp, frame) function finish!(interp::AbstractInterpreter, caller::InferenceState) result = caller.result diff --git a/base/deepcopy.jl b/base/deepcopy.jl index bee1f7994a150..6256773423497 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -37,7 +37,7 @@ deepcopy_internal(x::Module, stackdict::IdDict) = error("deepcopy of Modules not function deepcopy_internal(x::SimpleVector, stackdict::IdDict) if haskey(stackdict, x) - return stackdict[x] + return stackdict[x]::typeof(x) end y = Core.svec(Any[deepcopy_internal(x[i], stackdict) for i = 1:length(x)]...) stackdict[x] = y @@ -46,7 +46,7 @@ end function deepcopy_internal(x::String, stackdict::IdDict) if haskey(stackdict, x) - return stackdict[x] + return stackdict[x]::typeof(x) end y = GC.@preserve x unsafe_string(pointer(x), sizeof(x)) stackdict[x] = y @@ -58,7 +58,7 @@ function deepcopy_internal(@nospecialize(x), stackdict::IdDict) nf = nfields(x) if ismutable(x) if haskey(stackdict, x) - return stackdict[x] + return stackdict[x]::typeof(x) end y = ccall(:jl_new_struct_uninit, Any, (Any,), T) stackdict[x] = y @@ -157,7 +157,7 @@ end function deepcopy_internal(x::AbstractLock, stackdict::IdDict) if haskey(stackdict, x) - return stackdict[x] + return stackdict[x]::typeof(x) end y = typeof(x)() stackdict[x] = y @@ -166,7 +166,7 @@ end function deepcopy_internal(x::GenericCondition, stackdict::IdDict) if haskey(stackdict, x) - return stackdict[x] + return stackdict[x]::typeof(x) end y = typeof(x)(deepcopy_internal(x.lock, stackdict)) stackdict[x] = y diff --git a/base/docs/Docs.jl b/base/docs/Docs.jl index 637a8e1a50bd9..6be96cd8b1799 100644 --- a/base/docs/Docs.jl +++ b/base/docs/Docs.jl @@ -505,6 +505,49 @@ isquotedmacrocall(@nospecialize x) = isbasicdoc(@nospecialize x) = isexpr(x, :.) || isa(x, Union{QuoteNode, Symbol}) is_signature(@nospecialize x) = isexpr(x, :call) || (isexpr(x, :(::), 2) && isexpr(x.args[1], :call)) || isexpr(x, :where) +function _doc(binding::Binding, sig::Type = Union{}) + if defined(binding) + result = getdoc(resolve(binding), sig) + result === nothing || return result + end + # Lookup first match for `binding` and `sig` in all modules of the docsystem. + for mod in modules + dict = meta(mod; autoinit=false) + isnothing(dict) && continue + if haskey(dict, binding) + multidoc = dict[binding] + for msig in multidoc.order + sig <: msig && return multidoc.docs[msig] + end + end + end + return nothing +end + +# Some additional convenience `doc` methods that take objects rather than `Binding`s. +_doc(obj::UnionAll) = _doc(Base.unwrap_unionall(obj)) +_doc(object, sig::Type = Union{}) = _doc(aliasof(object, typeof(object)), sig) +_doc(object, sig...) = _doc(object, Tuple{sig...}) + +function simple_lookup_doc(ex) + if isa(ex, Expr) && ex.head !== :(.) && Base.isoperator(ex.head) + # handle syntactic operators, e.g. +=, ::, .= + ex = ex.head + end + if haskey(keywords, ex) + return keywords[ex] + elseif !isa(ex, Expr) && !isa(ex, Symbol) + return :($(_doc)($(typeof)($(esc(ex))))) + end + binding = esc(bindingexpr(namify(ex))) + if isexpr(ex, :call) || isexpr(ex, :macrocall) || isexpr(ex, :where) + sig = esc(signature(ex)) + :($(_doc)($binding, $sig)) + else + :($(_doc)($binding)) + end +end + function docm(source::LineNumberNode, mod::Module, ex) @nospecialize ex if isexpr(ex, :->) && length(ex.args) > 1 @@ -513,6 +556,8 @@ function docm(source::LineNumberNode, mod::Module, ex) # TODO: this is a shim to continue to allow `@doc` for looking up docstrings REPL = Base.REPL_MODULE_REF[] return invokelatest(REPL.lookup_doc, ex) + else + return simple_lookup_doc(ex) end return nothing end diff --git a/base/essentials.jl b/base/essentials.jl index fdc66e94d1a00..5fdc718085df0 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -397,8 +397,9 @@ Stacktrace: [...] ``` -If `T` is a [`AbstractFloat`](@ref) type, -then it will return the closest value to `x` representable by `T`. +If `T` is a [`AbstractFloat`](@ref) type, then it will return the +closest value to `x` representable by `T`. Inf is treated as one +ulp greater than `floatmax(T)` for purposes of determining nearest. ```jldoctest julia> x = 1/3 diff --git a/base/float.jl b/base/float.jl index 64dcb8b807550..ff628f0ac7126 100644 --- a/base/float.jl +++ b/base/float.jl @@ -464,6 +464,19 @@ round(x::IEEEFloat, ::RoundingMode{:Down}) = floor_llvm(x) round(x::IEEEFloat, ::RoundingMode{:Up}) = ceil_llvm(x) round(x::IEEEFloat, ::RoundingMode{:Nearest}) = rint_llvm(x) +rounds_up(x, ::RoundingMode{:Down}) = false +rounds_up(x, ::RoundingMode{:Up}) = true +rounds_up(x, ::RoundingMode{:ToZero}) = signbit(x) +rounds_up(x, ::RoundingMode{:FromZero}) = !signbit(x) +function _round_convert(::Type{T}, x_integer, x, r::Union{RoundingMode{:ToZero}, RoundingMode{:FromZero}, RoundingMode{:Up}, RoundingMode{:Down}}) where {T<:AbstractFloat} + x_t = convert(T, x_integer) + if rounds_up(x, r) + x_t < x ? nextfloat(x_t) : x_t + else + x_t > x ? prevfloat(x_t) : x_t + end +end + ## floating point promotions ## promote_rule(::Type{Float32}, ::Type{Float16}) = Float32 promote_rule(::Type{Float64}, ::Type{Float16}) = Float64 diff --git a/base/gcutils.jl b/base/gcutils.jl index 3b8c4cf4ede10..7aea7f222d7fd 100644 --- a/base/gcutils.jl +++ b/base/gcutils.jl @@ -109,6 +109,8 @@ Module with garbage collection utilities. """ module GC +public gc, enable, @preserve, safepoint, enable_logging, logging_enabled + # mirrored from julia.h const GC_AUTO = 0 const GC_FULL = 1 diff --git a/base/genericmemory.jl b/base/genericmemory.jl index 3463be456ea59..c1dc215a68d33 100644 --- a/base/genericmemory.jl +++ b/base/genericmemory.jl @@ -312,3 +312,4 @@ end $(Expr(:new, :(Array{T, 1}), :ref, :dims)) end end +view(m::GenericMemory, inds::Colon) = view(m, eachindex(m)) diff --git a/base/gmp.jl b/base/gmp.jl index a7caa8dfcdafd..c476d12aa1307 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -834,7 +834,7 @@ Base.add_with_overflow(a::BigInt, b::BigInt) = a + b, false Base.sub_with_overflow(a::BigInt, b::BigInt) = a - b, false Base.mul_with_overflow(a::BigInt, b::BigInt) = a * b, false -Base.deepcopy_internal(x::BigInt, stackdict::IdDict) = get!(() -> MPZ.set(x), stackdict, x) +Base.deepcopy_internal(x::BigInt, stackdict::IdDict) = get!(() -> MPZ.set(x), stackdict, x)::BigInt ## streamlined hashing for BigInt, by avoiding allocation from shifts ## diff --git a/base/idset.jl b/base/idset.jl index 23f9ca009af0c..c46d49968ff73 100644 --- a/base/idset.jl +++ b/base/idset.jl @@ -5,14 +5,13 @@ IdSet() IdSet{T}() constructs a set (see [`Set`](@ref)) using -`===` as equality with values of type `V`. +`===` as equality with values of type `T`. -In the example below, the values are all `isequal` so they get overwritten. -The `IdSet` compares by `===` so preserves the 3 different keys. - -Examples -≡≡≡≡≡≡≡≡ +In the example below, the values are all `isequal` so they get overwritten in the ordinary `Set`. +The `IdSet` compares by `===` and so preserves the 3 different values. +# Examples +```jldoctest; filter = r"\\n\\s*(1|1\\.0|true)" julia> Set(Any[true, 1, 1.0]) Set{Any} with 1 element: 1.0 @@ -22,6 +21,7 @@ IdSet{Any} with 3 elements: 1.0 1 true +``` """ mutable struct IdSet{K} <: AbstractSet{K} list::Memory{Any} diff --git a/base/iobuffer.jl b/base/iobuffer.jl index 109eaa96a3de4..f9585b0599919 100644 --- a/base/iobuffer.jl +++ b/base/iobuffer.jl @@ -260,22 +260,32 @@ bytesavailable(io::GenericIOBuffer) = io.size - io.ptr + 1 position(io::GenericIOBuffer) = io.ptr - io.offset - 1 function skip(io::GenericIOBuffer, n::Integer) - seekto = io.ptr + n - n < 0 && return seek(io, seekto-1) # Does error checking - io.ptr = min(seekto, io.size+1) - return io + skip(io, clamp(n, Int)) +end +function skip(io::GenericIOBuffer, n::Int) + if signbit(n) + seekto = clamp(widen(position(io)) + widen(n), Int) + seek(io, seekto) # Does error checking + else + n_max = io.size + 1 - io.ptr + io.ptr += min(n, n_max) + io + end end function seek(io::GenericIOBuffer, n::Integer) + seek(io, clamp(n, Int)) +end +function seek(io::GenericIOBuffer, n::Int) if !io.seekable ismarked(io) || throw(ArgumentError("seek failed, IOBuffer is not seekable and is not marked")) n == io.mark || throw(ArgumentError("seek failed, IOBuffer is not seekable and n != mark")) end # TODO: REPL.jl relies on the fact that this does not throw (by seeking past the beginning or end # of an GenericIOBuffer), so that would need to be fixed in order to throw an error here - #(n < 0 || n > io.size) && throw(ArgumentError("Attempted to seek outside IOBuffer boundaries.")) - #io.ptr = n+1 - io.ptr = min(max(0, n)+io.offset, io.size)+1 + #(n < 0 || n > io.size - io.offset) && throw(ArgumentError("Attempted to seek outside IOBuffer boundaries.")) + #io.ptr = n + io.offset + 1 + io.ptr = clamp(n, 0, io.size - io.offset) + io.offset + 1 return io end @@ -458,7 +468,7 @@ function take!(io::IOBuffer) elseif io.writable data = view(io.data, io.offset+1:nbytes+io.offset) else - data = copyto!(StringVector(io.size), 1, io.data, io.offset + 1, nbytes) + data = copyto!(StringVector(nbytes), 1, io.data, io.offset + 1, nbytes) end else nbytes = bytesavailable(io) diff --git a/base/iostream.jl b/base/iostream.jl index 5d972945e00e0..7ca1db9c30c85 100644 --- a/base/iostream.jl +++ b/base/iostream.jl @@ -446,8 +446,8 @@ function readuntil_string(s::IOStream, delim::UInt8, keep::Bool) @_lock_ios s ccall(:jl_readuntil, Ref{String}, (Ptr{Cvoid}, UInt8, UInt8, UInt8), s.ios, delim, 1, !keep) end readuntil(s::IOStream, delim::AbstractChar; keep::Bool=false) = - delim ≤ '\x7f' ? readuntil_string(s, delim % UInt8, keep) : - String(unsafe_take!(copyuntil(IOBuffer(sizehint=70), s, delim; keep))) + isascii(delim) ? readuntil_string(s, delim % UInt8, keep) : + String(_unsafe_take!(copyuntil(IOBuffer(sizehint=70), s, delim; keep))) function readline(s::IOStream; keep::Bool=false) @_lock_ios s ccall(:jl_readuntil, Ref{String}, (Ptr{Cvoid}, UInt8, UInt8, UInt8), s.ios, '\n', 1, keep ? 0 : 2) diff --git a/base/loading.jl b/base/loading.jl index 6c4541296f269..8c5767df811d6 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2224,7 +2224,7 @@ function __require_prelocked(uuidkey::PkgId, env=nothing) run_package_callbacks(uuidkey) else m = get(loaded_modules, uuidkey, nothing) - if m !== nothing + if m !== nothing && !haskey(explicit_loaded_modules, uuidkey) explicit_loaded_modules[uuidkey] = m run_package_callbacks(uuidkey) end @@ -2499,7 +2499,7 @@ function require_stdlib(uuidkey::PkgId, ext::Union{Nothing, String}=nothing) run_package_callbacks(uuidkey) else # if the user deleted their bundled depot, next try to load it completely normally - newm = _require(uuidkey) + newm = _require_prelocked(uuidkey) end return newm end diff --git a/stdlib/Logging/src/ConsoleLogger.jl b/base/logging/ConsoleLogger.jl similarity index 86% rename from stdlib/Logging/src/ConsoleLogger.jl rename to base/logging/ConsoleLogger.jl index 08e4a8c6b2efe..c4596dd86c3f5 100644 --- a/stdlib/Logging/src/ConsoleLogger.jl +++ b/base/logging/ConsoleLogger.jl @@ -12,10 +12,10 @@ Log levels less than `min_level` are filtered out. Message formatting can be controlled by setting keyword arguments: * `meta_formatter` is a function which takes the log event metadata - `(level, _module, group, id, file, line)` and returns a face name (used in - the constructed [`AnnotatedString`](@ref Base.AnnotatedString)), prefix and - suffix for the log message. The default is to prefix with the log level and - a suffix containing the module, file and line location. + `(level, _module, group, id, file, line)` and returns a color (as would be + passed to printstyled), prefix and suffix for the log message. The + default is to prefix with the log level and a suffix containing the module, + file and line location. * `show_limited` limits the printing of large data structures to something which can fit on the screen by setting the `:limit` `IOContext` key during formatting. @@ -58,10 +58,10 @@ end showvalue(io, ex::Exception) = showerror(io, ex) function default_logcolor(level::LogLevel) - level < Info ? :log_debug : - level < Warn ? :log_info : - level < Error ? :log_warn : - :log_error + level < Info ? Base.debug_color() : + level < Warn ? Base.info_color() : + level < Error ? Base.warn_color() : + Base.error_color() end function default_metafmt(level::LogLevel, _module, group, id, file, line) @@ -103,8 +103,6 @@ function termlength(str) return N end -termlength(str::Base.AnnotatedString) = textwidth(str) - function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module, group, id, filepath, line; kwargs...) @nospecialize @@ -156,10 +154,6 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module # Format lines as text with appropriate indentation and with a box # decoration on the left. color, prefix, suffix = logger.meta_formatter(level, _module, group, id, filepath, line)::Tuple{Union{Symbol,Int},String,String} - lcolor = StyledStrings.Legacy.legacy_color(color) - if !isnothing(lcolor) - color = StyledStrings.Face(foreground=lcolor) - end minsuffixpad = 2 buf = IOBuffer() iob = IOContext(buf, stream) @@ -173,19 +167,19 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module nonpadwidth = 2 + length(suffix) end for (i, (indent, msg)) in enumerate(msglines) - boxstr = length(msglines) == 1 ? "[" : - i == 1 ? "┌" : - i < length(msglines) ? "│" : - "└" - print(iob, styled"{$color,bold:$boxstr} ") + boxstr = length(msglines) == 1 ? "[ " : + i == 1 ? "┌ " : + i < length(msglines) ? "│ " : + "└ " + printstyled(iob, boxstr, bold=true, color=color) if i == 1 && !isempty(prefix) - print(iob, styled"{$color,bold:$prefix} ") + printstyled(iob, prefix, " ", bold=true, color=color) end print(iob, " "^indent, msg) if i == length(msglines) && !isempty(suffix) npad = max(0, justify_width - nonpadwidth) + minsuffixpad print(iob, " "^npad) - print(iob, styled"{shadow:$suffix}") + printstyled(iob, suffix, color=:light_black) end println(iob) end diff --git a/base/logging.jl b/base/logging/logging.jl similarity index 99% rename from base/logging.jl rename to base/logging/logging.jl index 75b8eea5051d2..7124ffe25abf2 100644 --- a/base/logging.jl +++ b/base/logging/logging.jl @@ -700,4 +700,6 @@ end _global_logstate = LogState(SimpleLogger()) +include("logging/ConsoleLogger.jl") + end # CoreLogging diff --git a/base/math.jl b/base/math.jl index 6ed69188371dd..4626a684d5f0e 100644 --- a/base/math.jl +++ b/base/math.jl @@ -95,11 +95,10 @@ julia> clamp.([11, 8, 5], 10, 6) # an example where lo > hi 10 ``` """ -clamp(x::X, lo::L, hi::H) where {X,L,H} = - ifelse(x > hi, convert(promote_type(X,L,H), hi), - ifelse(x < lo, - convert(promote_type(X,L,H), lo), - convert(promote_type(X,L,H), x))) +function clamp(x::X, lo::L, hi::H) where {X,L,H} + T = promote_type(X, L, H) + return (x > hi) ? convert(T, hi) : (x < lo) ? convert(T, lo) : convert(T, x) +end """ clamp(x, T)::T @@ -120,7 +119,14 @@ julia> trunc(Int, 4pi^2) 39 ``` """ -clamp(x, ::Type{T}) where {T<:Integer} = clamp(x, typemin(T), typemax(T)) % T +function clamp(x, ::Type{T}) where {T<:Integer} + # delegating to clamp(x, typemin(T), typemax(T)) would promote types + # this way, we avoid unnecessary conversions + # think of, e.g., clamp(big(2) ^ 200, Int16) + lo = typemin(T) + hi = typemax(T) + return (x > hi) ? hi : (x < lo) ? lo : convert(T, x) +end """ diff --git a/base/meta.jl b/base/meta.jl index bc07a7efa6c74..e648df29c12f9 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -5,8 +5,6 @@ Convenience functions for metaprogramming. """ module Meta -using ..CoreLogging - export quot, isexpr, isidentifier, diff --git a/base/mpfr.jl b/base/mpfr.jl index c12154fa517c3..7972564f19de8 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -1193,7 +1193,7 @@ function Base.deepcopy_internal(x::BigFloat, stackdict::IdDict) y = _BigFloat(x.prec, x.sign, x.exp, d′) #ccall((:mpfr_custom_move,libmpfr), Cvoid, (Ref{BigFloat}, Ptr{Limb}), y, d) # unnecessary return y - end + end::BigFloat end function decompose(x::BigFloat)::Tuple{BigInt, Int, Int} diff --git a/base/multidimensional.jl b/base/multidimensional.jl index fe29e5c1d8e5f..146f8c160e8e9 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -1610,12 +1610,6 @@ end end end -# _unsetindex -@propagate_inbounds function Base._unsetindex!(A::AbstractArray, i::CartesianIndex) - Base._unsetindex!(A, to_indices(A, (i,))...) - return A -end - ## permutedims ## Permute array dims ## diff --git a/base/precompilation.jl b/base/precompilation.jl index 375fed35ae646..76f9748198955 100644 --- a/base/precompilation.jl +++ b/base/precompilation.jl @@ -399,7 +399,6 @@ function precompilepkgs(pkgs::Vector{String}=String[]; depsmap[pkg] = filter!(!Base.in_sysimage, deps) # add any extensions pkg_exts = Dict{Base.PkgId, Vector{Base.PkgId}}() - prev_ext = nothing for (ext_name, extdep_uuids) in env.extensions[dep] ext_deps = Base.PkgId[] push!(ext_deps, pkg) # depends on parent package @@ -414,13 +413,8 @@ function precompilepkgs(pkgs::Vector{String}=String[]; end end all_extdeps_available || continue - if prev_ext isa Base.PkgId - # also make the exts depend on eachother sequentially to avoid race - push!(ext_deps, prev_ext) - end ext_uuid = Base.uuid5(pkg.uuid, ext_name) ext = Base.PkgId(ext_uuid, ext_name) - prev_ext = ext filter!(!Base.in_sysimage, ext_deps) depsmap[ext] = ext_deps exts[ext] = pkg.name @@ -431,6 +425,51 @@ function precompilepkgs(pkgs::Vector{String}=String[]; end end + # An extension effectively depends on another extension if it has all the the + # dependencies of that other extension + function expand_dependencies(depsmap) + function visit!(visited, node, all_deps) + if node in visited + return + end + push!(visited, node) + for dep in get(Set{Base.PkgId}, depsmap, node) + if !(dep in all_deps) + push!(all_deps, dep) + visit!(visited, dep, all_deps) + end + end + end + + depsmap_transitive = Dict{Base.PkgId, Set{Base.PkgId}}() + for package in keys(depsmap) + # Initialize a set to keep track of all dependencies for 'package' + all_deps = Set{Base.PkgId}() + visited = Set{Base.PkgId}() + visit!(visited, package, all_deps) + # Update depsmap with the complete set of dependencies for 'package' + depsmap_transitive[package] = all_deps + end + return depsmap_transitive + end + + depsmap_transitive = expand_dependencies(depsmap) + + for (_, extensions_1) in pkg_exts_map + for extension_1 in extensions_1 + deps_ext_1 = depsmap_transitive[extension_1] + for (_, extensions_2) in pkg_exts_map + for extension_2 in extensions_2 + extension_1 == extension_2 && continue + deps_ext_2 = depsmap_transitive[extension_2] + if issubset(deps_ext_2, deps_ext_1) + push!(depsmap[extension_1], extension_2) + end + end + end + end + end + @debug "precompile: deps collected" # this loop must be run after the full depsmap has been populated for (pkg, pkg_exts) in pkg_exts_map @@ -739,6 +778,7 @@ function precompilepkgs(pkgs::Vector{String}=String[]; end @debug "precompile: starting precompilation loop" depsmap direct_deps ## precompilation loop + for (pkg, deps) in depsmap cachepaths = Base.find_all_in_cache_path(pkg) sourcepath = Base.locate_package(pkg) @@ -811,6 +851,7 @@ function precompilepkgs(pkgs::Vector{String}=String[]; end loaded && (n_loaded += 1) catch err + # @show err close(std_pipe.in) # close pipe to end the std output monitor wait(t_monitor) if err isa ErrorException || (err isa ArgumentError && startswith(err.msg, "Invalid header in cache file")) @@ -834,7 +875,8 @@ function precompilepkgs(pkgs::Vector{String}=String[]; notify(was_processed[pkg_config]) catch err_outer # For debugging: - # println("Task failed $err_outer") # logging doesn't show here + # println("Task failed $err_outer") + # Base.display_error(ErrorException(""), Base.catch_backtrace())# logging doesn't show here handle_interrupt(err_outer) || rethrow() notify(was_processed[pkg_config]) finally diff --git a/base/promotion.jl b/base/promotion.jl index 1d4fea8c404eb..689a4e4be8f39 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -19,7 +19,8 @@ Number """ typejoin() = Bottom typejoin(@nospecialize(t)) = (@_nospecializeinfer_meta; t) -typejoin(@nospecialize(t), ts...) = (@_foldable_meta; @_nospecializeinfer_meta; typejoin(t, typejoin(ts...))) +typejoin(@nospecialize(t), @nospecialize(s), @nospecialize(u)) = (@_foldable_meta; @_nospecializeinfer_meta; typejoin(typejoin(t, s), u)) +typejoin(@nospecialize(t), @nospecialize(s), @nospecialize(u), ts...) = (@_foldable_meta; @_nospecializeinfer_meta; afoldl(typejoin, typejoin(t, s, u), ts...)) function typejoin(@nospecialize(a), @nospecialize(b)) @_foldable_meta @_nospecializeinfer_meta @@ -299,7 +300,8 @@ function promote_type end promote_type() = Bottom promote_type(T) = T -promote_type(T, S, U, V...) = (@inline; promote_type(T, promote_type(S, U, V...))) +promote_type(T, S, U) = (@inline; promote_type(promote_type(T, S), U)) +promote_type(T, S, U, V...) = (@inline; afoldl(promote_type, promote_type(T, S, U), V...)) promote_type(::Type{Bottom}, ::Type{Bottom}) = Bottom promote_type(::Type{T}, ::Type{T}) where {T} = T @@ -373,7 +375,9 @@ function _promote(x::T, y::S) where {T,S} return (convert(R, x), convert(R, y)) end promote_typeof(x) = typeof(x) -promote_typeof(x, xs...) = (@inline; promote_type(typeof(x), promote_typeof(xs...))) +promote_typeof(x, y) = (@inline; promote_type(typeof(x), typeof(y))) +promote_typeof(x, y, z) = (@inline; promote_type(typeof(x), typeof(y), typeof(z))) +promote_typeof(x, y, z, a...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, typeof(y)), promote_typeof(x, y, z), a...)) function _promote(x, y, z) @inline R = promote_typeof(x, y, z) diff --git a/base/reflection.jl b/base/reflection.jl index 65a46242c389d..550f9cf0bceaf 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -1000,12 +1000,15 @@ function datatype_fieldcount(t::DataType) return fieldcount(types) end return nothing - elseif isabstracttype(t) || (t.name === Tuple.name && isvatuple(t)) + elseif isabstracttype(t) return nothing end - if isdefined(t, :types) + if t.name === Tuple.name + isvatuple(t) && return nothing return length(t.types) end + # Equivalent to length(t.types), but `t.types` is lazy and we do not want + # to be forced to compute it. return length(t.name.names) end diff --git a/base/rounding.jl b/base/rounding.jl index d80edda1e418f..98b4c30822245 100644 --- a/base/rounding.jl +++ b/base/rounding.jl @@ -338,6 +338,10 @@ The [`RoundingMode`](@ref) `r` controls the direction of the rounding; the defau of 0.5) being rounded to the nearest even integer. Note that `round` may give incorrect results if the global rounding mode is changed (see [`rounding`](@ref)). +When rounding to a floating point type, will round to integers representable by that type +(and Inf) rather than true integers. Inf is treated as one ulp greater than the +`floatmax(T)` for purposes of determining "nearest", similar to [`convert`](@ref). + # Examples ```jldoctest julia> round(1.7) @@ -363,6 +367,12 @@ julia> round(123.456; sigdigits=2) julia> round(357.913; sigdigits=4, base=2) 352.0 + +julia> round(Float16, typemax(UInt128)) +Inf16 + +julia> floor(Float16, typemax(UInt128)) +Float16(6.55e4) ``` !!! note @@ -466,6 +476,7 @@ floor(::Type{T}, x) where T = round(T, x, RoundDown) ceil(::Type{T}, x) where T = round(T, x, RoundUp) round(::Type{T}, x) where T = round(T, x, RoundNearest) -round(::Type{T}, x, r::RoundingMode) where T = convert(T, round(x, r)) +round(::Type{T}, x, r::RoundingMode) where T = _round_convert(T, round(x, r), x, r) +_round_convert(::Type{T}, x_integer, x, r) where T = convert(T, x_integer) round(x::Integer, r::RoundingMode) = x diff --git a/base/sort.jl b/base/sort.jl index eb57da376f4ab..fc27d30499cfb 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -1722,7 +1722,7 @@ sort(v::AbstractVector; kws...) = sort!(copymutable(v); kws...) ## partialsortperm: the permutation to sort the first k elements of an array ## """ - partialsortperm(v, k; by=ientity, lt=isless, rev=false) + partialsortperm(v, k; by=identity, lt=isless, rev=false) Return a partial permutation `I` of the vector `v`, so that `v[I]` returns values of a fully sorted version of `v` at index `k`. If `k` is a range, a vector of indices is returned; if diff --git a/base/stream.jl b/base/stream.jl index d53f3a2957a36..fdb19f7fec45b 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -122,7 +122,7 @@ const DEFAULT_READ_BUFFER_SZ = 10485760 # 10 MB if Sys.iswindows() const MAX_OS_WRITE = UInt(0x1FF0_0000) # 511 MB (determined semi-empirically, limited to 31 MB on XP) else - const MAX_OS_WRITE = UInt(typemax(Csize_t)) + const MAX_OS_WRITE = UInt(0x7FFF_0000) # almost 2 GB (both macOS and linux have this kernel restriction, although only macOS documents it) end diff --git a/base/strings/annotated.jl b/base/strings/annotated.jl index a85cdf1b08bbb..4f2caa107b5f1 100644 --- a/base/strings/annotated.jl +++ b/base/strings/annotated.jl @@ -25,6 +25,17 @@ and a value (`Any`), paired together as a `Pair{Symbol, <:Any}`. Labels do not need to be unique, the same region can hold multiple annotations with the same label. +Code written for `AnnotatedString`s in general should conserve the following +properties: +- Which characters an annotation is applied to +- The order in which annotations are applied to each character + +Additional semantics may be introduced by specific uses of `AnnotatedString`s. + +A corollary of these rules is that adjacent, consecutively placed, annotations +with identical labels and values are equivalent to a single annotation spanning +the combined range. + See also [`AnnotatedChar`](@ref), [`annotatedstring`](@ref), [`annotations`](@ref), and [`annotate!`](@ref). @@ -159,6 +170,22 @@ function getindex(s::AnnotatedString, i::Integer) end end +# To make `AnnotatedString`s repr-evaluable, we need to override +# the generic `AbstractString` 2-arg show method. + +function show(io::IO, s::A) where {A <: AnnotatedString} + show(io, A) + print(io, '(') + show(io, s.string) + print(io, ", ") + show(IOContext(io, :typeinfo => typeof(annotations(s))), annotations(s)) + print(io, ')') +end + +# But still use the generic `AbstractString` fallback for the 3-arg show. +show(io::IO, ::MIME"text/plain", s::AnnotatedString) = + invoke(show, Tuple{IO, AbstractString}, io, s) + ## AbstractChar interface ## ncodeunits(c::AnnotatedChar) = ncodeunits(c.char) @@ -176,6 +203,24 @@ cmp(a::AnnotatedString, b::AnnotatedString) = cmp(a.string, b.string) ==(a::AnnotatedString, b::AbstractString) = isempty(a.annotations) && a.string == b ==(a::AbstractString, b::AnnotatedString) = isempty(b.annotations) && a == b.string +# To prevent substring equality from hitting the generic fallback + +function ==(a::SubString{<:AnnotatedString}, b::SubString{<:AnnotatedString}) + SubString(a.string.string, a.offset, a.ncodeunits, Val(:noshift)) == + SubString(b.string.string, b.offset, b.ncodeunits, Val(:noshift)) && + annotations(a) == annotations(b) +end + +==(a::SubString{<:AnnotatedString}, b::AnnotatedString) = + annotations(a) == annotations(b) && SubString(a.string.string, a.offset, a.ncodeunits, Val(:noshift)) == b.string + +==(a::SubString{<:AnnotatedString}, b::AbstractString) = + isempty(annotations(a)) && SubString(a.string.string, a.offset, a.ncodeunits, Val(:noshift)) == b + +==(a::AbstractString, b::SubString{<:AnnotatedString}) = b == a + +==(a::AnnotatedString, b::SubString{<:AnnotatedString}) = b == a + """ annotatedstring(values...) @@ -239,36 +284,6 @@ annotatedstring(c::AnnotatedChar) = AnnotatedString(s::SubString{<:AnnotatedString}) = annotatedstring(s) -""" - annotatedstring_optimize!(str::AnnotatedString) - -Merge contiguous identical annotations in `str`. -""" -function annotatedstring_optimize!(s::AnnotatedString) - last_seen = Dict{Pair{Symbol, Any}, Int}() - i = 1 - while i <= length(s.annotations) - region, keyval = s.annotations[i] - prev = get(last_seen, keyval, 0) - if prev > 0 - lregion, _ = s.annotations[prev] - if last(lregion) + 1 == first(region) - s.annotations[prev] = - setindex(s.annotations[prev], - first(lregion):last(region), - 1) - deleteat!(s.annotations, i) - else - delete!(last_seen, keyval) - end - else - last_seen[keyval] = i - i += 1 - end - end - s -end - function repeat(str::AnnotatedString, r::Integer) r == 0 && return one(AnnotatedString) r == 1 && return str @@ -276,19 +291,19 @@ function repeat(str::AnnotatedString, r::Integer) annotations = Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}() len = ncodeunits(str) fullregion = firstindex(str):lastindex(str) - for (region, annot) in str.annotations - if region == fullregion - push!(annotations, (firstindex(unannot):lastindex(unannot), annot)) + if allequal(first, str.annotations) && first(first(str.annotations)) == fullregion + newfullregion = firstindex(unannot):lastindex(unannot) + for (_, annot) in str.annotations + push!(annotations, (newfullregion, annot)) end - end - for offset in 0:len:(r-1)*len - for (region, annot) in str.annotations - if region != fullregion + else + for offset in 0:len:(r-1)*len + for (region, annot) in str.annotations push!(annotations, (region .+ offset, annot)) end end end - AnnotatedString(unannot, annotations) |> annotatedstring_optimize! + AnnotatedString(unannot, annotations) end repeat(str::SubString{<:AnnotatedString}, r::Integer) = @@ -319,14 +334,9 @@ reverse(s::SubString{<:AnnotatedString}) = reverse(AnnotatedString(s)) function _annotate!(annlist::Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}, range::UnitRange{Int}, @nospecialize(labelval::Pair{Symbol, <:Any})) label, val = labelval if val === nothing - indices = searchsorted(annlist, (range,), by=first) - labelindex = filter(i -> first(annlist[i][2]) === label, indices) - for index in Iterators.reverse(labelindex) - deleteat!(annlist, index) - end + deleteat!(annlist, findall(ann -> ann[1] == range && first(ann[2]) === label, annlist)) else - sortedindex = searchsortedlast(annlist, (range,), by=first) + 1 - insert!(annlist, sortedindex, (range, Pair{Symbol, Any}(label, val))) + push!(annlist, (range, Pair{Symbol, Any}(label, val))) end end @@ -336,6 +346,9 @@ end Annotate a `range` of `str` (or the entire string) with a labeled value (`label` => `value`). To remove existing `label` annotations, use a value of `nothing`. + +The order in which annotations are applied to `str` is semantically meaningful, +as described in [`AnnotatedString`](@ref). """ annotate!(s::AnnotatedString, range::UnitRange{Int}, @nospecialize(labelval::Pair{Symbol, <:Any})) = (_annotate!(s.annotations, range, labelval); s) @@ -368,6 +381,9 @@ annotations that overlap with `position` will be returned. Annotations are provided together with the regions they apply to, in the form of a vector of region–annotation tuples. +In accordance with the semantics documented in [`AnnotatedString`](@ref), the +order of annotations returned matches the order in which they were applied. + See also: `annotate!`. """ annotations(s::AnnotatedString) = s.annotations @@ -399,6 +415,51 @@ Get all annotations of `chr`, in the form of a vector of annotation pairs. """ annotations(c::AnnotatedChar) = c.annotations +## Character transformation helper function, c.f. `unicode.jl`. + +""" + annotated_chartransform(f::Function, str::AnnotatedString, state=nothing) + +Transform every character in `str` with `f`, adjusting annotation regions as +appropriate. `f` must take one of two forms, either: +- `f(c::Char) -> Char`, or +- `f(c::Char, state) -> (Char, state)`. + +This works by comparing the number of code units of each character before and +after transforming with `f`, recording and aggregating any differences, then +applying them to the annotation regions. + +Returns an `AnnotatedString{String}` (regardless of the original underling +string type of `str`). +""" +function annotated_chartransform(f::Function, str::AnnotatedString, state=nothing) + outstr = IOBuffer() + annots = Tuple{UnitRange{Int}, Pair{Symbol, Any}}[] + bytepos = firstindex(str) - 1 + offsets = [bytepos => 0] + for c in str.string + oldnb = ncodeunits(c) + bytepos += oldnb + if isnothing(state) + c = f(c) + else + c, state = f(c, state) + end + nb = write(outstr, c) + if nb != oldnb + push!(offsets, bytepos => last(last(offsets)) + nb - oldnb) + end + end + for annot in str.annotations + region, value = annot + start, stop = first(region), last(region) + start_offset = last(offsets[findlast(<=(start) ∘ first, offsets)::Int]) + stop_offset = last(offsets[findlast(<=(stop) ∘ first, offsets)::Int]) + push!(annots, ((start + start_offset):(stop + stop_offset), value)) + end + AnnotatedString(String(take!(outstr)), annots) +end + ## AnnotatedIOBuffer struct AnnotatedIOBuffer <: AbstractPipe @@ -439,7 +500,8 @@ function write(io::AnnotatedIOBuffer, astr::Union{AnnotatedString, SubString{<:A write(io.io, String(astr)) end -write(io::AnnotatedIOBuffer, c::AnnotatedChar) = write(io, AnnotatedString(c)) +write(io::AnnotatedIOBuffer, c::AnnotatedChar) = + write(io, AnnotatedString(string(c), map(a -> (1:ncodeunits(c), a), annotations(c)))) write(io::AnnotatedIOBuffer, x::AbstractString) = write(io.io, x) write(io::AnnotatedIOBuffer, s::Union{SubString{String}, String}) = write(io.io, s) write(io::AnnotatedIOBuffer, b::UInt8) = write(io.io, b) @@ -456,10 +518,37 @@ function write(dest::AnnotatedIOBuffer, src::AnnotatedIOBuffer) nb end +# So that read/writes with `IOContext` (and any similar `AbstractPipe` wrappers) +# work as expected. +function write(io::AbstractPipe, s::Union{AnnotatedString, SubString{<:AnnotatedString}}) + if pipe_writer(io) isa AnnotatedIOBuffer + write(pipe_writer(io), s) + else + invoke(write, Tuple{IO, typeof(s)}, io, s) + end::Int +end +# Can't be part of the `Union` above because it introduces method ambiguities +function write(io::AbstractPipe, c::AnnotatedChar) + if pipe_writer(io) isa AnnotatedIOBuffer + write(pipe_writer(io), c) + else + invoke(write, Tuple{IO, typeof(c)}, io, c) + end::Int +end + +""" + _clear_annotations_in_region!(annotations::Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}, span::UnitRange{Int}) + +Erase the presence of `annotations` within a certain `span`. + +This operates by removing all elements of `annotations` that are entirely +contained in `span`, truncating ranges that partially overlap, and splitting +annotations that subsume `span` to just exist either side of `span`. +""" function _clear_annotations_in_region!(annotations::Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}, span::UnitRange{Int}) # Clear out any overlapping pre-existing annotations. filter!(((region, _),) -> first(region) < first(span) || last(region) > last(span), annotations) - extras = Tuple{UnitRange{Int}, Pair{Symbol, Any}}[] + extras = Tuple{Int, Tuple{UnitRange{Int}, Pair{Symbol, Any}}}[] for i in eachindex(annotations) region, annot = annotations[i] # Test for partial overlap @@ -470,31 +559,68 @@ function _clear_annotations_in_region!(annotations::Vector{Tuple{UnitRange{Int}, # If `span` fits exactly within `region`, then we've only copied over # the beginning overhang, but also need to conserve the end overhang. if first(region) < first(span) && last(span) < last(region) - push!(extras, (last(span)+1:last(region), annot)) + push!(extras, (i, (last(span)+1:last(region), annot))) end end - # Insert any extra entries in the appropriate position - for entry in extras - sortedindex = searchsortedlast(annotations, (first(entry),), by=first) + 1 - insert!(annotations, sortedindex, entry) - end + end + # Insert any extra entries in the appropriate position + for (offset, (i, entry)) in enumerate(extras) + insert!(annotations, i + offset, entry) end annotations end +""" + _insert_annotations!(io::AnnotatedIOBuffer, annotations::Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}, offset::Int = position(io)) + +Register new `annotations` in `io`, applying an `offset` to their regions. + +The largely consists of simply shifting the regions of `annotations` by `offset` +and pushing them onto `io`'s annotations. However, when it is possible to merge +the new annotations with recent annotations in accordance with the semantics +outlined in [`AnnotatedString`](@ref), we do so. More specifically, when there +is a run of the most recent annotations that are also present as the first +`annotations`, with the same value and adjacent regions, the new annotations are +merged into the existing recent annotations by simply extending their range. + +This is implemented so that one can say write an `AnnotatedString` to an +`AnnotatedIOBuffer` one character at a time without needlessly producing a +new annotation for each character. +""" function _insert_annotations!(io::AnnotatedIOBuffer, annotations::Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}, offset::Int = position(io)) - if !eof(io) - for (region, annot) in annotations - region = first(region)+offset:last(region)+offset - sortedindex = searchsortedlast(io.annotations, (region,), by=first) + 1 - insert!(io.annotations, sortedindex, (region, annot)) - end - else - for (region, annot) in annotations - region = first(region)+offset:last(region)+offset - push!(io.annotations, (region, annot)) + run = 0 + if !isempty(io.annotations) && last(first(last(io.annotations))) == offset + for i in reverse(axes(annotations, 1)) + annot = annotations[i] + first(first(annot)) == 1 || continue + if last(annot) == last(last(io.annotations)) + valid_run = true + for runlen in 1:i + new_range, new_annot = annotations[begin+runlen-1] + old_range, old_annot = io.annotations[end-i+runlen] + if last(old_range) != offset || first(new_range) != 1 || old_annot != new_annot + valid_run = false + break + end + end + if valid_run + run = i + break + end + end end end + for runindex in 0:run-1 + old_index = lastindex(io.annotations) - run + 1 + runindex + old_region, annot = io.annotations[old_index] + new_region, _ = annotations[begin+runindex] + io.annotations[old_index] = (first(old_region):last(new_region)+offset, annot) + end + for index in run+1:lastindex(annotations) + region, annot = annotations[index] + start, stop = first(region), last(region) + push!(io.annotations, (start+offset:stop+offset, annot)) + end end function read(io::AnnotatedIOBuffer, ::Type{AnnotatedString{T}}) where {T <: AbstractString} diff --git a/base/strings/unicode.jl b/base/strings/unicode.jl index 2e04633b87487..a3b06063b98ac 100644 --- a/base/strings/unicode.jl +++ b/base/strings/unicode.jl @@ -4,7 +4,8 @@ module Unicode import Base: show, ==, hash, string, Symbol, isless, length, eltype, - convert, isvalid, ismalformed, isoverlong, iterate + convert, isvalid, ismalformed, isoverlong, iterate, + AnnotatedString, AnnotatedChar, annotated_chartransform # whether codepoints are valid Unicode scalar values, i.e. 0-0xd7ff, 0xe000-0x10ffff @@ -271,6 +272,8 @@ julia> textwidth("March") """ textwidth(s::AbstractString) = mapreduce(textwidth, +, s; init=0) +textwidth(s::AnnotatedString) = textwidth(s.string) + """ lowercase(c::AbstractChar) @@ -290,6 +293,8 @@ julia> lowercase('Ö') lowercase(c::T) where {T<:AbstractChar} = isascii(c) ? ('A' <= c <= 'Z' ? c + 0x20 : c) : T(ccall(:utf8proc_tolower, UInt32, (UInt32,), c)) +lowercase(c::AnnotatedChar) = AnnotatedChar(lowercase(c.char), annotations(c)) + """ uppercase(c::AbstractChar) @@ -309,6 +314,8 @@ julia> uppercase('ê') uppercase(c::T) where {T<:AbstractChar} = isascii(c) ? ('a' <= c <= 'z' ? c - 0x20 : c) : T(ccall(:utf8proc_toupper, UInt32, (UInt32,), c)) +uppercase(c::AnnotatedChar) = AnnotatedChar(uppercase(c.char), annotations(c)) + """ titlecase(c::AbstractChar) @@ -332,6 +339,8 @@ julia> uppercase('dž') titlecase(c::T) where {T<:AbstractChar} = isascii(c) ? ('a' <= c <= 'z' ? c - 0x20 : c) : T(ccall(:utf8proc_totitle, UInt32, (UInt32,), c)) +titlecase(c::AnnotatedChar) = AnnotatedChar(titlecase(c.char), annotations(c)) + ############################################################################ # returns UTF8PROC_CATEGORY code in 0:30 giving Unicode category @@ -606,6 +615,7 @@ julia> uppercase("Julia") ``` """ uppercase(s::AbstractString) = map(uppercase, s) +uppercase(s::AnnotatedString) = annotated_chartransform(uppercase, s) """ lowercase(s::AbstractString) @@ -621,6 +631,7 @@ julia> lowercase("STRINGS AND THINGS") ``` """ lowercase(s::AbstractString) = map(lowercase, s) +lowercase(s::AnnotatedString) = annotated_chartransform(lowercase, s) """ titlecase(s::AbstractString; [wordsep::Function], strict::Bool=true) -> String @@ -669,6 +680,23 @@ function titlecase(s::AbstractString; wordsep::Function = !isletter, strict::Boo return String(take!(b)) end +# TODO: improve performance characteristics, room for a ~10x improvement. +function titlecase(s::AnnotatedString; wordsep::Function = !isletter, strict::Bool=true) + initial_state = (; startword = true, state = Ref{Int32}(0), + c0 = eltype(s)(zero(UInt32)), wordsep, strict) + annotated_chartransform(s, initial_state) do c, state + if isgraphemebreak!(state.state, state.c0, c) && state.wordsep(c) + state = Base.setindex(state, true, :startword) + cnew = c + else + cnew = state.startword ? titlecase(c) : state.strict ? lowercase(c) : c + state = Base.setindex(state, false, :startword) + end + state = Base.setindex(state, c, :c0) + cnew, state + end +end + """ uppercasefirst(s::AbstractString) -> String @@ -693,6 +721,17 @@ function uppercasefirst(s::AbstractString) string(c′, SubString(s, nextind(s, 1))) end +# TODO: improve performance characteristics, room for a ~5x improvement. +function uppercasefirst(s::AnnotatedString) + annotated_chartransform(s, true) do c, state + if state + (titlecase(c), false) + else + (c, state) + end + end +end + """ lowercasefirst(s::AbstractString) @@ -715,6 +754,17 @@ function lowercasefirst(s::AbstractString) string(c′, SubString(s, nextind(s, 1))) end +# TODO: improve performance characteristics, room for a ~5x improvement. +function lowercasefirst(s::AnnotatedString) + annotated_chartransform(s, true) do c, state + if state + (lowercase(c), false) + else + (c, state) + end + end +end + ############################################################################ # iterators for grapheme segmentation diff --git a/base/subarray.jl b/base/subarray.jl index 2b8545c2cc226..b67b917a478b3 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -115,11 +115,14 @@ function unaliascopy(V::SubArray{T,N,A,I,LD}) where {T,N,A<:Array,I<:Tuple{Varar trimmedpind = _trimmedpind(V.indices...) vdest = trimmedpind isa Tuple{Vararg{Union{Slice,Colon}}} ? dest : view(dest, trimmedpind...) copyto!(vdest, view(V, _trimmedvind(V.indices...)...)) - SubArray{T,N,A,I,LD}(dest, map(_trimmedindex, V.indices), 0, Int(LD)) + indices = map(_trimmedindex, V.indices) + stride1 = LD ? compute_stride1(dest, indices) : 0 + offset1 = LD ? compute_offset1(dest, stride1, indices) : 0 + SubArray{T,N,A,I,LD}(dest, indices, offset1, stride1) end # Get the proper trimmed shape _trimmedshape(::ScalarIndex, rest...) = (1, _trimmedshape(rest...)...) -_trimmedshape(i::AbstractRange, rest...) = (maximum(i), _trimmedshape(rest...)...) +_trimmedshape(i::AbstractRange, rest...) = (isempty(i) ? zero(eltype(i)) : maximum(i), _trimmedshape(rest...)...) _trimmedshape(i::Union{UnitRange,StepRange,OneTo}, rest...) = (length(i), _trimmedshape(rest...)...) _trimmedshape(i::AbstractArray{<:ScalarIndex}, rest...) = (length(i), _trimmedshape(rest...)...) _trimmedshape(i::AbstractArray{<:AbstractCartesianIndex{0}}, rest...) = _trimmedshape(rest...) @@ -410,25 +413,6 @@ function isassigned(V::FastSubArray{<:Any, 1}, i::Int) r end -function _unsetindex!(V::FastSubArray, i::Int) - @inline - @boundscheck checkbounds(V, i) - @inbounds _unsetindex!(V.parent, _reindexlinear(V, i)) - return V -end -function _unsetindex!(V::FastSubArray{<:Any,1}, i::Int) - @inline - @boundscheck checkbounds(V, i) - @inbounds _unsetindex!(V.parent, _reindexlinear(V, i)) - return V -end -function _unsetindex!(V::SubArray{T,N}, i::Vararg{Int,N}) where {T,N} - @inline - @boundscheck checkbounds(V, i...) - @inbounds _unsetindex!(V.parent, reindex(V.indices, i)...) - return V -end - IndexStyle(::Type{<:FastSubArray}) = IndexLinear() IndexStyle(::Type{<:SubArray}) = IndexCartesian() diff --git a/deps/checksums/Pkg-bd787952e6ceab2d3e8fec98429d954860ecfd9f.tar.gz/md5 b/deps/checksums/Pkg-bd787952e6ceab2d3e8fec98429d954860ecfd9f.tar.gz/md5 deleted file mode 100644 index 09eba0d1a7f51..0000000000000 --- a/deps/checksums/Pkg-bd787952e6ceab2d3e8fec98429d954860ecfd9f.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -3b2aa3606351309b2e5ca8b489c88c94 diff --git a/deps/checksums/Pkg-bd787952e6ceab2d3e8fec98429d954860ecfd9f.tar.gz/sha512 b/deps/checksums/Pkg-bd787952e6ceab2d3e8fec98429d954860ecfd9f.tar.gz/sha512 deleted file mode 100644 index 8f802b6c54f1a..0000000000000 --- a/deps/checksums/Pkg-bd787952e6ceab2d3e8fec98429d954860ecfd9f.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -9a58efdaf279b857fff3d446325e66547b0971adcdf3499764561235a32d30af72db8f3e11ebb4161ad1d502c4e59b6d6f0b0da48f941a04a0c333cda505b7ba diff --git a/deps/checksums/Pkg-f112626414a4f666306adb84936ea85aec77c89d.tar.gz/md5 b/deps/checksums/Pkg-f112626414a4f666306adb84936ea85aec77c89d.tar.gz/md5 new file mode 100644 index 0000000000000..423607f56c6dc --- /dev/null +++ b/deps/checksums/Pkg-f112626414a4f666306adb84936ea85aec77c89d.tar.gz/md5 @@ -0,0 +1 @@ +1f7791c24085bfbe03e2ec6df9e3e095 diff --git a/deps/checksums/Pkg-f112626414a4f666306adb84936ea85aec77c89d.tar.gz/sha512 b/deps/checksums/Pkg-f112626414a4f666306adb84936ea85aec77c89d.tar.gz/sha512 new file mode 100644 index 0000000000000..8b0db150dfff8 --- /dev/null +++ b/deps/checksums/Pkg-f112626414a4f666306adb84936ea85aec77c89d.tar.gz/sha512 @@ -0,0 +1 @@ +0541b8a46366022dddc54fba199619178cd297243ae56b3334b434c22aa8390fd0f50013b0549fb102a9895e091942736bd63b9967aff63d6f02b29d60ec83b0 diff --git a/deps/checksums/StyledStrings-ac472083359dde956aed8c61d43b8158ac84d9ce.tar.gz/md5 b/deps/checksums/StyledStrings-ac472083359dde956aed8c61d43b8158ac84d9ce.tar.gz/md5 new file mode 100644 index 0000000000000..758a74bce9dae --- /dev/null +++ b/deps/checksums/StyledStrings-ac472083359dde956aed8c61d43b8158ac84d9ce.tar.gz/md5 @@ -0,0 +1 @@ +6969fb6d2e8585d26beef865910ec8ef diff --git a/deps/checksums/StyledStrings-ac472083359dde956aed8c61d43b8158ac84d9ce.tar.gz/sha512 b/deps/checksums/StyledStrings-ac472083359dde956aed8c61d43b8158ac84d9ce.tar.gz/sha512 new file mode 100644 index 0000000000000..3d1ac8791e14d --- /dev/null +++ b/deps/checksums/StyledStrings-ac472083359dde956aed8c61d43b8158ac84d9ce.tar.gz/sha512 @@ -0,0 +1 @@ +281292e8478d72ab66b84cbd4f42e5dc2dd5054e8c54a79de8f0c0537d28962b460e67fe71230ead6b02386b87d0423879d51ce53a2b2427ce55866d62d6ebde diff --git a/deps/checksums/StyledStrings-e0ca0f85412ea5cafabfeaaec4d62ca26c3959d2.tar.gz/md5 b/deps/checksums/StyledStrings-e0ca0f85412ea5cafabfeaaec4d62ca26c3959d2.tar.gz/md5 deleted file mode 100644 index 2ab79799cca0e..0000000000000 --- a/deps/checksums/StyledStrings-e0ca0f85412ea5cafabfeaaec4d62ca26c3959d2.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -fc3a846400107c432d20da6cfdd19ccf diff --git a/deps/checksums/StyledStrings-e0ca0f85412ea5cafabfeaaec4d62ca26c3959d2.tar.gz/sha512 b/deps/checksums/StyledStrings-e0ca0f85412ea5cafabfeaaec4d62ca26c3959d2.tar.gz/sha512 deleted file mode 100644 index 70b0ef6f5cb3a..0000000000000 --- a/deps/checksums/StyledStrings-e0ca0f85412ea5cafabfeaaec4d62ca26c3959d2.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -22da8964cc4c09f7c7a3da44be14c953f520ce6d395cf0f9ccf9c17777d6d968b0a874b35c072801ef7a1f4eee40f96ea0e2fc5ed5b3a63ad0b6b776a9c14ebb diff --git a/deps/checksums/openblas b/deps/checksums/openblas index 34eca34c4ec2c..ad6b38dc075fa 100644 --- a/deps/checksums/openblas +++ b/deps/checksums/openblas @@ -1,94 +1,94 @@ -OpenBLAS.v0.3.26+2.aarch64-apple-darwin-libgfortran5.tar.gz/md5/62b6e0f8591668113a4985d88f386a16 -OpenBLAS.v0.3.26+2.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/fa5a15d853701818604c48bd152b599438eeeb1da67db552beb21b284027c313a9c7d8779b7236831a5f2631912baf881b0d2165aa77cb7ffec975a5c113a631 -OpenBLAS.v0.3.26+2.aarch64-linux-gnu-libgfortran3.tar.gz/md5/bc83bc702eb292c4491229cd6142fe06 -OpenBLAS.v0.3.26+2.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/d4e872be87cc450e1547e51ba15540f5f0082a874788c6ba414cab839147e69f7f37b2c4080a79bdcd411efec829e3510b83df8a9c319a3b132a117614d205cc -OpenBLAS.v0.3.26+2.aarch64-linux-gnu-libgfortran4.tar.gz/md5/436ae51ef0b2f7a053ed8fb19fd55fd1 -OpenBLAS.v0.3.26+2.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/686c9c04a11d2f8a4879876ae34c410ad9e5cb0fddecd44aea9d642e662af9766a07bf4846405685835968253f2cda004a7d7ca1a0a04b2799984489294ed4c5 -OpenBLAS.v0.3.26+2.aarch64-linux-gnu-libgfortran5.tar.gz/md5/fa57f3598b2c24ec3111c60f84bb6ed9 -OpenBLAS.v0.3.26+2.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/d6111ab03a8940892e8023af548de52da7b8c3c76ad2cfcf98a78cadf11b95ef4c39830dedc5a3c6a20e8d95c64fb24a4ed655971ea83ba11f69ff7a3ba34292 -OpenBLAS.v0.3.26+2.aarch64-linux-musl-libgfortran3.tar.gz/md5/184444acaf2f975b4bf5168a32577863 -OpenBLAS.v0.3.26+2.aarch64-linux-musl-libgfortran3.tar.gz/sha512/419da1e017208596e89482ac42005ed2adebfc917419cf900fad3b45ec40f7da46acffc3e6461f46862e3c4642588cd629f6dde151fd02edd6642c8d98d77ea6 -OpenBLAS.v0.3.26+2.aarch64-linux-musl-libgfortran4.tar.gz/md5/2aef4330a9995541bae287a3c2583ea6 -OpenBLAS.v0.3.26+2.aarch64-linux-musl-libgfortran4.tar.gz/sha512/caf7ae4ec0c4fddfe522409d1a5c3be5a376620baa9ddce63f62e4856cea4b1ab2818ef54f3fb5ffbcc4ae73247459d0de2ac7b93eba4bcc1ca744f4fe69695e -OpenBLAS.v0.3.26+2.aarch64-linux-musl-libgfortran5.tar.gz/md5/308471abda2c5eba60976d227f6d1c1e -OpenBLAS.v0.3.26+2.aarch64-linux-musl-libgfortran5.tar.gz/sha512/225242f309d343994176664f590471ec2e56254ebec877d97291c1334517993510422954774749d23da4c52f32a41e06aaba072bf2e3cbb3b2a8dac6c01dba8c -OpenBLAS.v0.3.26+2.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/69618373222d15ede34de1f913a93dac -OpenBLAS.v0.3.26+2.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/585fa3233d6c88c7ee5571da4dce7b83c53643937a0077d816c24c556b471926c808bcbd46c9ddddafbe24567f91039525b3a260505854e62e9b9b09acaede54 -OpenBLAS.v0.3.26+2.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/874b639fcce8fb077d1a9cdecc916a6c -OpenBLAS.v0.3.26+2.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/0a065ccd197822b028da36e157aed19fbe440d7eedc94fe1955cd8980423d477bdb73db7e0f99a6ea683701a2c8fc649e3967a781694a7219d82915d1c22767c -OpenBLAS.v0.3.26+2.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/03683c3d2310870905bc386c5fc89eb5 -OpenBLAS.v0.3.26+2.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/2e0f4ae61623cf094cb8396522dfb6e2a7cf7de23a4dd25fb3fb2f0a414fd0b8d6397ce1c74d3a88296fe4fe76d1a61e1df87b2814bf87852564c097aa1f45e2 -OpenBLAS.v0.3.26+2.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/9c9dbe9afb8fc5d1f2fae971e1dfce1d -OpenBLAS.v0.3.26+2.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/e592f91a2c0a303a059a9694565555247b76ab20ecfcf9c9f7235e0b67b458d530b35e9a2263f3c37b7ecc884c02124fac134f6061788348475fe1d546e07f1e -OpenBLAS.v0.3.26+2.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/ede329cb3e37e7c9008fec5273e38ce2 -OpenBLAS.v0.3.26+2.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/bbb081f217c977e77d77c2091918aeff99855dbe99f4396059954e057edf41c63e926769afc3a2360eb87cef5612a2c0de519852182dba51d9306be10c4508fe -OpenBLAS.v0.3.26+2.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/c884cc9c752857a6a020891040c1bbd4 -OpenBLAS.v0.3.26+2.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/67e671c05964b2a1456b9bddfe300cf29f88f4712cbe0c11cae01955abb31e70d9ad9a31175d2e29e4c5dd02d22febcafac8abe47d78dc179aa1e40776c51883 -OpenBLAS.v0.3.26+2.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/69618373222d15ede34de1f913a93dac -OpenBLAS.v0.3.26+2.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/585fa3233d6c88c7ee5571da4dce7b83c53643937a0077d816c24c556b471926c808bcbd46c9ddddafbe24567f91039525b3a260505854e62e9b9b09acaede54 -OpenBLAS.v0.3.26+2.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/874b639fcce8fb077d1a9cdecc916a6c -OpenBLAS.v0.3.26+2.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/0a065ccd197822b028da36e157aed19fbe440d7eedc94fe1955cd8980423d477bdb73db7e0f99a6ea683701a2c8fc649e3967a781694a7219d82915d1c22767c -OpenBLAS.v0.3.26+2.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/03683c3d2310870905bc386c5fc89eb5 -OpenBLAS.v0.3.26+2.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/2e0f4ae61623cf094cb8396522dfb6e2a7cf7de23a4dd25fb3fb2f0a414fd0b8d6397ce1c74d3a88296fe4fe76d1a61e1df87b2814bf87852564c097aa1f45e2 -OpenBLAS.v0.3.26+2.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/9c9dbe9afb8fc5d1f2fae971e1dfce1d -OpenBLAS.v0.3.26+2.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/e592f91a2c0a303a059a9694565555247b76ab20ecfcf9c9f7235e0b67b458d530b35e9a2263f3c37b7ecc884c02124fac134f6061788348475fe1d546e07f1e -OpenBLAS.v0.3.26+2.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/ede329cb3e37e7c9008fec5273e38ce2 -OpenBLAS.v0.3.26+2.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/bbb081f217c977e77d77c2091918aeff99855dbe99f4396059954e057edf41c63e926769afc3a2360eb87cef5612a2c0de519852182dba51d9306be10c4508fe -OpenBLAS.v0.3.26+2.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/c884cc9c752857a6a020891040c1bbd4 -OpenBLAS.v0.3.26+2.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/67e671c05964b2a1456b9bddfe300cf29f88f4712cbe0c11cae01955abb31e70d9ad9a31175d2e29e4c5dd02d22febcafac8abe47d78dc179aa1e40776c51883 -OpenBLAS.v0.3.26+2.i686-linux-gnu-libgfortran3.tar.gz/md5/030e3714c2544175861a411fc2520dc2 -OpenBLAS.v0.3.26+2.i686-linux-gnu-libgfortran3.tar.gz/sha512/5ea2318d786b423770e77cd820fef4bd995da7f6aaea70f73f55eb9210508e89f61fb0c6a728421c6fd3859ab11774f3111979c53a6c48ddf7a528a04295c4ba -OpenBLAS.v0.3.26+2.i686-linux-gnu-libgfortran4.tar.gz/md5/ef935e9cf567efa381de917a0cf66fbc -OpenBLAS.v0.3.26+2.i686-linux-gnu-libgfortran4.tar.gz/sha512/81a463ca756d4d363fd32f735d32d7b6e8c6f325401e943a8210fcf258ecd25507beac17b9b24ecddef0eb8521a58fdfcf6633794724f86e6977b162e099c70e -OpenBLAS.v0.3.26+2.i686-linux-gnu-libgfortran5.tar.gz/md5/ce1a4b1dc5e3c001b5c12f9cd81cb3fb -OpenBLAS.v0.3.26+2.i686-linux-gnu-libgfortran5.tar.gz/sha512/8f82012c0e9f955be2ab87551742a334f865cbdec95f0a62103c5127d6176838653884a6790234c5548940cec63e73ce95095bfcfaf241dc445020ab449c6687 -OpenBLAS.v0.3.26+2.i686-linux-musl-libgfortran3.tar.gz/md5/acfe348c1c1f33376469dd9106603222 -OpenBLAS.v0.3.26+2.i686-linux-musl-libgfortran3.tar.gz/sha512/2048723ce88ef28b2b7fa42cc73eccae8b663466a496709931ccecf06b4f4a9455fdfa3b5bd05bba4d847d3c0489251ecc3a34e7e3fb49bcdb40aacd4b53c140 -OpenBLAS.v0.3.26+2.i686-linux-musl-libgfortran4.tar.gz/md5/d82eb058ea705286058230f68b43c9fe -OpenBLAS.v0.3.26+2.i686-linux-musl-libgfortran4.tar.gz/sha512/c97ca8dd352c3067ec437b1a8b2b9ee06bd92157f0806dca55fcc3107a94e784cdf8f6d5986aae93ccb608fb90ba2ab9bba4acf7562c1fd519804897ab158c10 -OpenBLAS.v0.3.26+2.i686-linux-musl-libgfortran5.tar.gz/md5/014aa93d275d56e6176ab50f4040ede2 -OpenBLAS.v0.3.26+2.i686-linux-musl-libgfortran5.tar.gz/sha512/cd3d1dd1aab373fe4e1135042dee3fc959371fcbebe70f6c60327df35e389442a2f47351757db84cdc1d181b659ce2d6a0892508de6af27b01324e3119d9dabb -OpenBLAS.v0.3.26+2.i686-w64-mingw32-libgfortran3.tar.gz/md5/0b3f11710883a3cac2551cac0d72aad5 -OpenBLAS.v0.3.26+2.i686-w64-mingw32-libgfortran3.tar.gz/sha512/7d86f74c585dff33ed9384dc1c77b600a6893ceca335340232536f6e2cec1bbc86e85763c932c4b81c4012f12d68d7f37634e2f685aff6a999b875eae596cd9c -OpenBLAS.v0.3.26+2.i686-w64-mingw32-libgfortran4.tar.gz/md5/64d7806e859c804161a59641db744f7f -OpenBLAS.v0.3.26+2.i686-w64-mingw32-libgfortran4.tar.gz/sha512/7ebefd3ee2abd284c82e15d2497fd08bd4eccb264af7aacc1378c75d4b1dffb11ab95eafd98029c513ee7c667749a4917e26e4d57c65ccb77c5ba52cd8770009 -OpenBLAS.v0.3.26+2.i686-w64-mingw32-libgfortran5.tar.gz/md5/2a91e979a37722549d95cbd607e822fa -OpenBLAS.v0.3.26+2.i686-w64-mingw32-libgfortran5.tar.gz/sha512/f08880e18e6a361458a495c8860382a00001fe5d2989852b034ff9623b4517c8b75cd3f03986f62d72222e3cf07f8f2eb123785577500c7cf0e79109b9eed960 -OpenBLAS.v0.3.26+2.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/a417db847b1d610e3f52a891f98ae2e0 -OpenBLAS.v0.3.26+2.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/16da5454b0987ecae76b6fe547d28f699684aa5fbf05a0e579960b71b3ab75dc1f3602fc60182fea3556eda8d905a870f03dd976009ea1972e9693a584e584f3 -OpenBLAS.v0.3.26+2.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/c63388278f7e037c232d9e7b29d3c725 -OpenBLAS.v0.3.26+2.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/bedbb30539530e16314c97b87df59caf38c75de7b68616cdca78d27e241dce06527d7265924902d557394a14a6348dc2b5e45c4a006158a6b9182382183bd0ff -OpenBLAS.v0.3.26+2.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/5785f320f43600a791b543fb0bd8b00b -OpenBLAS.v0.3.26+2.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/37ae82c2f57ec7c6ce0cd3f93b33870602f44bffdbeb2cb9bceef4515f5851aba73214d4a1fd24606fe4fa9bf0bf0a5552e1aebd65027ae57f76f3379a04344e -OpenBLAS.v0.3.26+2.x86_64-apple-darwin-libgfortran3.tar.gz/md5/ebd368ef0d4fd4f39534bb52b506e109 -OpenBLAS.v0.3.26+2.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/a81bf2244b160786530ae449be1e81981d17146ccf833ea5afcea84eb24644002d5824591c96b7e89fe9642911a865a292be062d325ff2307d850b4cfbd0e7d6 -OpenBLAS.v0.3.26+2.x86_64-apple-darwin-libgfortran4.tar.gz/md5/f453ba9786d0916c9fc8c46281588c5d -OpenBLAS.v0.3.26+2.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/7dea0549e3fec7e18043b8b4f93491ddbb4e041325330a2e6e28d137c25431c12371b534bae5170b22c5077d285ee23fda1579bae54c894a46a885b4571daf84 -OpenBLAS.v0.3.26+2.x86_64-apple-darwin-libgfortran5.tar.gz/md5/3be8449cb3046322f21b1d17be41bd1f -OpenBLAS.v0.3.26+2.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/89bb94d645879bd2daa8e83fc9b391b84f32b8bc1f633caacc5eda138c8034b726bc5c7ddb931040f24b77482743cd2038fed6d1d17698f287c09f176a6085c8 -OpenBLAS.v0.3.26+2.x86_64-linux-gnu-libgfortran3.tar.gz/md5/2410734a7fc47705361267023c001272 -OpenBLAS.v0.3.26+2.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/e9b239a75ee7521145f30caa52ec4e8b42d99f5246df47c8e203497c577f161ec4f3e7df7d7fa8135b4f947f941314bbbb00fa56ed813bbbefd6f887af1a768b -OpenBLAS.v0.3.26+2.x86_64-linux-gnu-libgfortran4.tar.gz/md5/06212c9081e7d355bce7e7960e17371d -OpenBLAS.v0.3.26+2.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/aeb9913167f6e860c4f2082dc15310fa4fb2a0edcf70a6aa31626c59e132d2af9265544f1b18161d994405649f2923abd4cb21521466768f1ed4fe0ef8243bcd -OpenBLAS.v0.3.26+2.x86_64-linux-gnu-libgfortran5.tar.gz/md5/e21eb44972f00ff7c054e3fade50602d -OpenBLAS.v0.3.26+2.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/8d9c1bb8c300e2523fd7a42ef4d4bcfbaba94e29e69c630008a194a62e575648c9f89a42301d1cbd0e74613ba41e5282d69bd8e24376c64fedb1d2657dd1e4a4 -OpenBLAS.v0.3.26+2.x86_64-linux-musl-libgfortran3.tar.gz/md5/aa1501555419f9bc6c243e77d1a413c8 -OpenBLAS.v0.3.26+2.x86_64-linux-musl-libgfortran3.tar.gz/sha512/8a4c5166e76c14bf6c65953bdcb8a4b222dee61123cfdb243876ee5af2d5d04e3125149936ce71c25cd90b0af5208d733ed9a1944b3134634de6a2ddfd1796a8 -OpenBLAS.v0.3.26+2.x86_64-linux-musl-libgfortran4.tar.gz/md5/597ff5c5a516278129a3077daeb4ffd0 -OpenBLAS.v0.3.26+2.x86_64-linux-musl-libgfortran4.tar.gz/sha512/0b4b3e58d046e7a5f3eac36e967025983575df1979c5bdc73330481982e229f832735d1a7bce373009e666b9094ba5877d290bd06d9baf5f8a9efef0d3b0b4ac -OpenBLAS.v0.3.26+2.x86_64-linux-musl-libgfortran5.tar.gz/md5/410507ba0176c16180163556294d359e -OpenBLAS.v0.3.26+2.x86_64-linux-musl-libgfortran5.tar.gz/sha512/659167ca4b307c00afbfbc08a8bade4c144a0567c13354c81ef17dbd210f2a98b40289bb9f166a70cd447193c236561c7a6df2603ebcd0dec501529d4e976508 -OpenBLAS.v0.3.26+2.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/e12abdd6fa5a9211cdf3472ec9e2bf2c -OpenBLAS.v0.3.26+2.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/cc68370a2e2c76303272e0d91a71ae1a9408233d7f39292682fc901b8474d8272ac42f233c2d0c3cdc07c481968bee2486831e8df48d9f34877b45e3af694b62 -OpenBLAS.v0.3.26+2.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/a02fcf5127ae14a00204c1b43b1c6807 -OpenBLAS.v0.3.26+2.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/e502418902d1af01efa1c9d6db94659b1472db8af812cd2507fb324836e5bab3364e54bca9a2ee809114947b4210f5fe3ec640d7bb741114a66e110d2668ddab -OpenBLAS.v0.3.26+2.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/f4d49963b37686671d1d6f1f5b4b680e -OpenBLAS.v0.3.26+2.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/0c395e956243b40bc29a820ac755740efd932f56eaba85a554041c223238300f0370ef2d051cb67357bf9a740950bbc78de1fba52522bd53a9d3a8f24799f975 -OpenBLAS.v0.3.26+2.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/fecab0026d2b7b7e0261ccf1f9aeb282 -OpenBLAS.v0.3.26+2.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/a9032b79cbc18448b141bc61b404e156af2ccaccd3919f0d38d5f2963e9e89c93f4992ed58217f969a7f5201b4489e0bdb91761fe507ee7f07e65e712f9ed584 -OpenBLAS.v0.3.26+2.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/28d440488310d3730db018612078bad7 -OpenBLAS.v0.3.26+2.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/a24e5e8f8da4734ce10b6d959b566df0ece3f3ba30737584ad3e7795d07b950e2bd57fb13d4a4f21eb92b29c38cf40fd846b5f771eb820a769e50f4074e36142 -OpenBLAS.v0.3.26+2.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/7202113787553198c32b0b6964630b5a -OpenBLAS.v0.3.26+2.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/9553d90d0580bd6f1e6676be85029db615564bbada470ee8751619b5888e79ee23e1e699f1aba1e770a29c5ef1e4d13eb8c24cfa787ef22167c9100ed6af478e +OpenBLAS.v0.3.27+1.aarch64-apple-darwin-libgfortran5.tar.gz/md5/7bb5c7a169ec7660ec38fe73c74a89d7 +OpenBLAS.v0.3.27+1.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/97266fa0d786bac50f37d82e66da645dfa1b811975045d4aaad1f49361caf7945c06203cb728bf92e9071ec805dff2c75f2b45b346ae4f9cfe289d8f2215e68b +OpenBLAS.v0.3.27+1.aarch64-linux-gnu-libgfortran3.tar.gz/md5/ea42c557a49aa58172ea0e0f0f93c628 +OpenBLAS.v0.3.27+1.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/baade18c9d8d91f3fb32e44609277a7a6cd827a6c9554e5b21f88d492a0c34e93d29041f691f6b0cd03ab609d5470b1a06e95121781e9622cce301812d6613de +OpenBLAS.v0.3.27+1.aarch64-linux-gnu-libgfortran4.tar.gz/md5/85a9cbbbf9fff65927a9ff96f17d0792 +OpenBLAS.v0.3.27+1.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/7a0024c509a50c87c9318d209465e0d57fc2e0a8401740666f09d236678eb9d5a1b2fbbfd12c0c409006607a408f03f11c1465841417533010a7843c4af654c1 +OpenBLAS.v0.3.27+1.aarch64-linux-gnu-libgfortran5.tar.gz/md5/4e3c6a68a61b9749ebb55b20728bf0f1 +OpenBLAS.v0.3.27+1.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/dbf9fc5465f60a35849c391069c0a9d6d6fc8685b734d00088e297cf7a6c92fbed67f4264f2b2c164d3c6694d9c8f64b750faa248aa1fd44867d18a94211dc87 +OpenBLAS.v0.3.27+1.aarch64-linux-musl-libgfortran3.tar.gz/md5/c25b607a4df84f9aeb112f24520cabb3 +OpenBLAS.v0.3.27+1.aarch64-linux-musl-libgfortran3.tar.gz/sha512/a99fa75a3cfea19c84a4d455585e53f124e956dd5d4ee7ce0c38c0922b0bebb8b2c996079c3bc63e95444b531ddf9d1f003a22d7f6b55cf99db2334bb1c618ae +OpenBLAS.v0.3.27+1.aarch64-linux-musl-libgfortran4.tar.gz/md5/3473d20c26f6ad50f3a0b635415858a5 +OpenBLAS.v0.3.27+1.aarch64-linux-musl-libgfortran4.tar.gz/sha512/6e9100e0fcbe1b91c5a4461118739af9d4eca7edd7b8e6ee07a2052c0aaad0ea84c048f0e507ff88da81f47b10c102faf9fe735d13ae1cd35f44396d9a51a864 +OpenBLAS.v0.3.27+1.aarch64-linux-musl-libgfortran5.tar.gz/md5/9ad49254a2827987e622a58a1b8c7b98 +OpenBLAS.v0.3.27+1.aarch64-linux-musl-libgfortran5.tar.gz/sha512/f8a3b9aa52920ce76f5d9550407aeefed5e2596d05b9f8f0643e1da221cf533a09de7a0454a04a2d59a3a2a2fb899a538a5e03b133746415a81415ff926826ba +OpenBLAS.v0.3.27+1.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/c130634237846672f3a672f1d0e346d9 +OpenBLAS.v0.3.27+1.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/c174d00870ce3944c553122606cba7b78312342a02dc4833a91ae105f05d85d06e665e86a79452bdb7d2b31c18936582d79427ec3976048cf09497011d8c77c8 +OpenBLAS.v0.3.27+1.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/07c58a9399552e3b8362d9c1dd155693 +OpenBLAS.v0.3.27+1.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/98570a4dae80f9b4366c08994911efc87bf6967e63e20b486240a3b2d7637fabbfcca3fe8340ae4d9bae7702be400f5976fc5aa0020f984157b097b02e08d23c +OpenBLAS.v0.3.27+1.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/25a9af724bb8a5ca42be6277a726583e +OpenBLAS.v0.3.27+1.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/7afbc7453d1f22171523476e90882f67611374b03a3481bdb588722bc4816d081304b811a0dd452288ca972bea95bd2d2286644bda309dbe25fe721321298e85 +OpenBLAS.v0.3.27+1.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/2f9494f7600729bfa00a0db96bd9349d +OpenBLAS.v0.3.27+1.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/eae895a7ef4d9922bf9f6c454f56b2881fd5549e6c6a825e0e4d5b84defe9a97719a9f1e62f996dd545afdf372c1ab18bbee0a6cce8474d9adb2522b16678d35 +OpenBLAS.v0.3.27+1.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/8f30a26bd56ced5d6edc88b1fae57beb +OpenBLAS.v0.3.27+1.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/ad849216c9655dc160a0cd756904442a80d693121e60a2b33876ac347c79fe6e3e602faad0c64a45599f5a5e203c3d9e8316c6b20c41d81e666b7650dccfaa5c +OpenBLAS.v0.3.27+1.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/272facb48c295ccfea2a291869e1817e +OpenBLAS.v0.3.27+1.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/7fd5c23046fa548f0bed6e7ce4f6fa809e56909b5595d2a4f348189ee99f234dc84989219ee63cdc004ce303b50fee2aa1fcb93589ff116a2191f8ef520d24be +OpenBLAS.v0.3.27+1.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/c130634237846672f3a672f1d0e346d9 +OpenBLAS.v0.3.27+1.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/c174d00870ce3944c553122606cba7b78312342a02dc4833a91ae105f05d85d06e665e86a79452bdb7d2b31c18936582d79427ec3976048cf09497011d8c77c8 +OpenBLAS.v0.3.27+1.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/07c58a9399552e3b8362d9c1dd155693 +OpenBLAS.v0.3.27+1.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/98570a4dae80f9b4366c08994911efc87bf6967e63e20b486240a3b2d7637fabbfcca3fe8340ae4d9bae7702be400f5976fc5aa0020f984157b097b02e08d23c +OpenBLAS.v0.3.27+1.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/25a9af724bb8a5ca42be6277a726583e +OpenBLAS.v0.3.27+1.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/7afbc7453d1f22171523476e90882f67611374b03a3481bdb588722bc4816d081304b811a0dd452288ca972bea95bd2d2286644bda309dbe25fe721321298e85 +OpenBLAS.v0.3.27+1.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/2f9494f7600729bfa00a0db96bd9349d +OpenBLAS.v0.3.27+1.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/eae895a7ef4d9922bf9f6c454f56b2881fd5549e6c6a825e0e4d5b84defe9a97719a9f1e62f996dd545afdf372c1ab18bbee0a6cce8474d9adb2522b16678d35 +OpenBLAS.v0.3.27+1.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/8f30a26bd56ced5d6edc88b1fae57beb +OpenBLAS.v0.3.27+1.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/ad849216c9655dc160a0cd756904442a80d693121e60a2b33876ac347c79fe6e3e602faad0c64a45599f5a5e203c3d9e8316c6b20c41d81e666b7650dccfaa5c +OpenBLAS.v0.3.27+1.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/272facb48c295ccfea2a291869e1817e +OpenBLAS.v0.3.27+1.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/7fd5c23046fa548f0bed6e7ce4f6fa809e56909b5595d2a4f348189ee99f234dc84989219ee63cdc004ce303b50fee2aa1fcb93589ff116a2191f8ef520d24be +OpenBLAS.v0.3.27+1.i686-linux-gnu-libgfortran3.tar.gz/md5/14cee2ac2cff0d9d8b614278e3f7a4ed +OpenBLAS.v0.3.27+1.i686-linux-gnu-libgfortran3.tar.gz/sha512/d81aa1c8ff70d8d24d2cf88adc568dbf6a77f191332aa0298fbc0faad1fda855c9a6c278d0556003cca315ef75e47cf7caa6963b4e16f4d883ba7c1b13a298bb +OpenBLAS.v0.3.27+1.i686-linux-gnu-libgfortran4.tar.gz/md5/559f96fb8a2a03df6689200173f2c1df +OpenBLAS.v0.3.27+1.i686-linux-gnu-libgfortran4.tar.gz/sha512/cc1e987b2ad7d47b474d39b0f93ee6f6e46a4e5d0760cea9e31a0d3c5336e6cfc88401122ab278c0b745c9e60b290f9c05edf39bef9e7e97c70f33dc7afac341 +OpenBLAS.v0.3.27+1.i686-linux-gnu-libgfortran5.tar.gz/md5/c572b06af06609e5e84dc8aee61babc1 +OpenBLAS.v0.3.27+1.i686-linux-gnu-libgfortran5.tar.gz/sha512/d799e280600970697701098f76e79d0bb72bf55cbe8d6c131bd26f6a67bdcb5ed307b26eae89bc6b7cc6b6eb25d2622f952b315f7850b7f231148f14cc09b769 +OpenBLAS.v0.3.27+1.i686-linux-musl-libgfortran3.tar.gz/md5/4aa9f25b39088f79ea13aab1097c0c1f +OpenBLAS.v0.3.27+1.i686-linux-musl-libgfortran3.tar.gz/sha512/126876d9de1c67302dc1b9b71a96fd2f5eb45745ebbcea6d4b7d4bdfac93088ef6b89e75a2bfcd83f1b32dc798b7ef824bb225e24e88e6443571d0576939bb05 +OpenBLAS.v0.3.27+1.i686-linux-musl-libgfortran4.tar.gz/md5/4ffd9c16cd3c6535457dd654f95c62e6 +OpenBLAS.v0.3.27+1.i686-linux-musl-libgfortran4.tar.gz/sha512/cc7fbe4949b5b51e5f1f5fdae537bbcc68ef4a59a02c290df2f6723bdeb52d98e699e4b23a879372d56279196295d8c938ba2221fe3a73cd1ef953059cdf694f +OpenBLAS.v0.3.27+1.i686-linux-musl-libgfortran5.tar.gz/md5/7d6855b9a879259216c243dcfc75a2cc +OpenBLAS.v0.3.27+1.i686-linux-musl-libgfortran5.tar.gz/sha512/221d1ba0250802ae88daac384fd1b2c911c49f8e141efbf3c2668260f4018c5e5f1e21c459a1595652ca48ebc446fe43e54fbf732b47d68f20ecb1e280862570 +OpenBLAS.v0.3.27+1.i686-w64-mingw32-libgfortran3.tar.gz/md5/646fdfccf16f12f23441723e13c12f58 +OpenBLAS.v0.3.27+1.i686-w64-mingw32-libgfortran3.tar.gz/sha512/2692aae16acba199584da71275eb609071d6f7a6d644239f9b6307fe12fc875d6267b11d387b2cace1d5866bf50ab0db619510d02acd3c90696bfb0dfe958037 +OpenBLAS.v0.3.27+1.i686-w64-mingw32-libgfortran4.tar.gz/md5/257e35006373e43fedb211c56b73315a +OpenBLAS.v0.3.27+1.i686-w64-mingw32-libgfortran4.tar.gz/sha512/e4d8049a6e30763dbacba7646805bb72abad021f8810fb084a287d389137e30b96f12f04ad625c5ef322d127f7b603f388fee18a516e101761391d405ec58d2e +OpenBLAS.v0.3.27+1.i686-w64-mingw32-libgfortran5.tar.gz/md5/68245d8b061c60f97f48fd4fde4492dd +OpenBLAS.v0.3.27+1.i686-w64-mingw32-libgfortran5.tar.gz/sha512/511f5fcb538067c04742ad578d2584ebb3cc54bd7c43b84b14d3597bcb84d303a729a48c79018afa119ef12e084bed5ce6fe3591774a1cd6a5b6bbe5df4a8753 +OpenBLAS.v0.3.27+1.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/883728fe99e27d1f066032e1465880b2 +OpenBLAS.v0.3.27+1.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/3363ad953d1d7b5ba233b5d6ff65411e51189adcc6e7a9b68e45388132b38701eba53745f826f896820a98bc5015a8787ab1257f1a25c0a55f0437707c451d20 +OpenBLAS.v0.3.27+1.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/672fb00c47939bfc1893c7bf630b6904 +OpenBLAS.v0.3.27+1.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/e1beb8be0b58402df60b14a81d4fefe13cb0a30450717c80f2670b3a7947a89574848e858f90e0efd5474c47cdb86ce5623645988f05f105df206abd888c2f58 +OpenBLAS.v0.3.27+1.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/32eeeeeb57ed38bb4123ea793faf6685 +OpenBLAS.v0.3.27+1.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/bc505de8d8378e5c0fd6b3092b7093ecae0cacd9d5f6fa94e6e01ead03ffd7abad31c8d75fa84cf6da4f4fd33dde33df968595ecdc818f5b891b82db1be2d1a1 +OpenBLAS.v0.3.27+1.x86_64-apple-darwin-libgfortran3.tar.gz/md5/e49f4562399b5d45d987e9820774f7c8 +OpenBLAS.v0.3.27+1.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/0e5ade0c2112f01b3bde14ddb0fe500085d75fc86117d54bc66cc2da30f7251233387a90daca6203ebe457bc68e8bf3cff62c011b424a971ff9f7932974eaba4 +OpenBLAS.v0.3.27+1.x86_64-apple-darwin-libgfortran4.tar.gz/md5/26c9067086aa013de9c3b4001cd3f78a +OpenBLAS.v0.3.27+1.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/e641bc045b96cb011183e26541730b46b8dfb401ef1223f10f19450de206d9971f3181d37c7687477d782238e580bbba4fddbcb2094a45761b55dcc93a9cacd4 +OpenBLAS.v0.3.27+1.x86_64-apple-darwin-libgfortran5.tar.gz/md5/a2cf4ac08dc296f6aaf109e8d1fff491 +OpenBLAS.v0.3.27+1.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/2210bc1dfa32b0b9b86ec84943b6673bc540a0822652274ececa0f394ed406d9f23f02909f2b8f97dd2a2bc114df2d0e9a6d868d29bc2d08a3da7176743a6d10 +OpenBLAS.v0.3.27+1.x86_64-linux-gnu-libgfortran3.tar.gz/md5/1b501f18b00d1e051b4af955da81b3c9 +OpenBLAS.v0.3.27+1.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/1b5615dc63efd0166b206bbdc90801d0c623f93f537c320bac1af8bf41f9e3ae8ec33eb6b43a7bd9dc2d9ba526bc7bb200ff828f33ef36da920f9290fa4ff252 +OpenBLAS.v0.3.27+1.x86_64-linux-gnu-libgfortran4.tar.gz/md5/079cebb72efd39454275a8199fc78c17 +OpenBLAS.v0.3.27+1.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/94bdd5db2546381e3cd15bb60b382c11d8ba879f8b88771a15d0d7cbf5a399f46aec60fc01e07258614ec039bf9bf73cbeffc9d2f29b03c9885e63704f0d2ab0 +OpenBLAS.v0.3.27+1.x86_64-linux-gnu-libgfortran5.tar.gz/md5/cef6229311f1616c0db95cef84725cd4 +OpenBLAS.v0.3.27+1.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/297eda815134d5de59d1614b39f06a512f4ef544dc5abaffa015075a8bcba1506aa4825109213e54e94401cbf16d4292a1ec2b9b71b278cc8536379d80d96e46 +OpenBLAS.v0.3.27+1.x86_64-linux-musl-libgfortran3.tar.gz/md5/b410edbbc651fd9f6589fda153b410da +OpenBLAS.v0.3.27+1.x86_64-linux-musl-libgfortran3.tar.gz/sha512/718c22a940d998dcd8c754994f5a7d9bd3e3131d51beb1d8071ca0005e5c562bb2368924b0c4951839df0bc85a272962f87891b366a1bce1f735cc2b3495b834 +OpenBLAS.v0.3.27+1.x86_64-linux-musl-libgfortran4.tar.gz/md5/af8f2dc642041d5e4eff98d6b20e7596 +OpenBLAS.v0.3.27+1.x86_64-linux-musl-libgfortran4.tar.gz/sha512/48b88f703cc0e35d8f3b3bf7f395481a3225f5c3d1a4277a7b477815feab71df5c6b662313f4762bc8002f43c0f1bece0f383bc3920c09d383303b3927925ddf +OpenBLAS.v0.3.27+1.x86_64-linux-musl-libgfortran5.tar.gz/md5/eba3e9322d39993d81d78486306b301f +OpenBLAS.v0.3.27+1.x86_64-linux-musl-libgfortran5.tar.gz/sha512/dc11716e4f7a53a396b8b8cd3e506bd66272e9e8c5533199dc972c91fed0cea5067ec8e14abf67da2b53af7f3189eafc5c188657d617eea3f55ed248d7ed38e4 +OpenBLAS.v0.3.27+1.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/03f45c7c0276f58719235e5da3bcdc85 +OpenBLAS.v0.3.27+1.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/836fbbdae1065393de8ad1410301afbecfb0bf60256322b754e17aa5b4edb20e409eeca2f66f9a2b9ffb5872479cd3cab9b721bd2fc9c3544f5e90e78c7e59c7 +OpenBLAS.v0.3.27+1.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/dc6bc577a3ccd78364e9fcb98fec03dd +OpenBLAS.v0.3.27+1.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/2c52880b287b0c4f48ed3539e4e0b24b6a05b46d47d7586eea7ca06ebc19c7f0d018fdd24e8da94249fa3b7dc54b85b27ebc530fc5cefb2d9b5457e00dee3529 +OpenBLAS.v0.3.27+1.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/30a6a329d4d37dea7199dfcf264a2641 +OpenBLAS.v0.3.27+1.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/53be21e7a94033cd44b8e2d375b38606446800344698e4f365527d807f736b7b2b9a897138b5de5bd62ba9da104cd6f86bf59caebc18299c0abd98899c527988 +OpenBLAS.v0.3.27+1.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/290a8fc0d1580aeed8cb7b793ff991bf +OpenBLAS.v0.3.27+1.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/e30e4f666255982c1adbf73020bf88e2d499d2d26216a16c34b4a6b7ed0dc5b7d5374a978a7d0ef5735a82394b4ef06bd82491e2ddf7ec5775953b9183e9f601 +OpenBLAS.v0.3.27+1.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/1b46471021b6914fc60401e3e1ffe78b +OpenBLAS.v0.3.27+1.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/509d5138d8cd9621937f840b7f73949facec2f047676069403d3d7c482ea183766dc84536d9c2a291b18a2b89902e6f714665fa0b7a920727635530a3aa4aa17 +OpenBLAS.v0.3.27+1.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/ae28948c5d496a3d0bba649c72822b2b +OpenBLAS.v0.3.27+1.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/8d66a65040e973947a8a7d4f4b1d47d63a77b75c0d5e04843de9188256aeec5a1c7e0d59bf5e1d5c262c4f1a4ff2aa36599840337e9d828fb77724c38c1fff4e openblas-6c77e5e314474773a7749357b153caba4ec3817d.tar.gz/md5/4971eeb7adadee085d7c991db416fe7a openblas-6c77e5e314474773a7749357b153caba4ec3817d.tar.gz/sha512/7b85c9fb7be54407ba627d77897f40de4395d6d307230aa7df83cf8e0a41f545e4af4ae0576abb40cc9e0c385e1c6a488100dff292ea307439a89587c07ba66f diff --git a/deps/openblas.mk b/deps/openblas.mk index d1e0c03aabb1c..1bc068d2859d9 100644 --- a/deps/openblas.mk +++ b/deps/openblas.mk @@ -95,22 +95,7 @@ $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-ofast-power.patch-applied: $(BUILDDIR)/ patch -p1 -f < $(SRCDIR)/patches/openblas-ofast-power.patch echo 1 > $@ -$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-avx512bf-kernels.patch-applied: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-ofast-power.patch-applied - cd $(BUILDDIR)/$(OPENBLAS_SRC_DIR) && \ - patch -p1 -f < $(SRCDIR)/patches/openblas-avx512bf-kernels.patch - echo 1 > $@ - -$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-gemv-multithreading.patch-applied: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-avx512bf-kernels.patch-applied - cd $(BUILDDIR)/$(OPENBLAS_SRC_DIR) && \ - patch -p1 -f < $(SRCDIR)/patches/openblas-gemv-multithreading.patch - echo 1 > $@ - -$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-darwin-sve.patch-applied: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-gemv-multithreading.patch-applied - cd $(BUILDDIR)/$(OPENBLAS_SRC_DIR) && \ - patch -p1 -f < $(SRCDIR)/patches/openblas-darwin-sve.patch - echo 1 > $@ - -$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/build-configured: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-darwin-sve.patch-applied +$(BUILDDIR)/$(OPENBLAS_SRC_DIR)/build-configured: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/openblas-ofast-power.patch-applied echo 1 > $@ $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/build-compiled: $(BUILDDIR)/$(OPENBLAS_SRC_DIR)/build-configured diff --git a/deps/openblas.version b/deps/openblas.version index f62282b7ea8cc..527764e3f8603 100644 --- a/deps/openblas.version +++ b/deps/openblas.version @@ -3,8 +3,8 @@ OPENBLAS_JLL_NAME := OpenBLAS ## source build -OPENBLAS_VER := 0.3.26 -OPENBLAS_BRANCH=v0.3.26 +OPENBLAS_VER := 0.3.27 +OPENBLAS_BRANCH=v0.3.27 OPENBLAS_SHA1=6c77e5e314474773a7749357b153caba4ec3817d # LAPACK, source-only diff --git a/deps/patches/openblas-avx512bf-kernels.patch b/deps/patches/openblas-avx512bf-kernels.patch deleted file mode 100644 index 7e99cdf7c53ee..0000000000000 --- a/deps/patches/openblas-avx512bf-kernels.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 1dada6d65d89d19b2cf89b12169f6b2196c90f1d Mon Sep 17 00:00:00 2001 -From: Martin Kroeker -Date: Fri, 12 Jan 2024 00:10:56 +0100 -Subject: [PATCH 1/2] Add compiler test and flag for AVX512BF16 capability - ---- - c_check | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/c_check b/c_check -index b5e4a9ad00..3e507be818 100755 ---- a/c_check -+++ b/c_check -@@ -244,6 +244,7 @@ case "$data" in - esac - - no_avx512=0 -+no_avx512bf=0 - if [ "$architecture" = "x86" ] || [ "$architecture" = "x86_64" ]; then - tmpd=$(mktemp -d 2>/dev/null || mktemp -d -t 'OBC') - tmpf="$tmpd/a.c" -@@ -262,6 +263,25 @@ if [ "$architecture" = "x86" ] || [ "$architecture" = "x86_64" ]; then - } - - rm -rf "$tmpd" -+ if [ "$no_avx512" -eq 0 ]; then -+ tmpd=$(mktemp -d 2>/dev/null || mktemp -d -t 'OBC') -+ tmpf="$tmpd/a.c" -+ code='"__m512 a= _mm512_dpbf16_ps(a, (__m512bh) _mm512_loadu_si512(%1]), (__m512bh) _mm512_loadu_si512(%2]));"' -+ printf "#include \n\nint main(void){ %s; }\n" "$code" >> "$tmpf" -+ if [ "$compiler" = "PGI" ]; then -+ args=" -tp cooperlake -c -o $tmpf.o $tmpf" -+ else -+ args=" -march=cooperlake -c -o $tmpf.o $tmpf" -+ fi -+ no_avx512bf=0 -+ { -+ $compiler_name $flags $args >/dev/null 2>&1 -+ } || { -+ no_avx512bf=1 -+ } -+ -+ rm -rf "$tmpd" -+ fi - fi - - no_rv64gv=0 -@@ -409,6 +429,7 @@ done - [ "$makefile" = "-" ] && { - [ "$no_rv64gv" -eq 1 ] && printf "NO_RV64GV=1\n" - [ "$no_avx512" -eq 1 ] && printf "NO_AVX512=1\n" -+ [ "$no_avx512bf" -eq 1 ] && printf "NO_AVX512BF16=1\n" - [ "$no_avx2" -eq 1 ] && printf "NO_AVX2=1\n" - [ "$oldgcc" -eq 1 ] && printf "OLDGCC=1\n" - exit 0 -@@ -437,6 +458,7 @@ done - [ "$no_sve" -eq 1 ] && printf "NO_SVE=1\n" - [ "$no_rv64gv" -eq 1 ] && printf "NO_RV64GV=1\n" - [ "$no_avx512" -eq 1 ] && printf "NO_AVX512=1\n" -+ [ "$no_avx512bf" -eq 1 ] && printf "NO_AVX512BF16=1\n" - [ "$no_avx2" -eq 1 ] && printf "NO_AVX2=1\n" - [ "$oldgcc" -eq 1 ] && printf "OLDGCC=1\n" - [ "$no_lsx" -eq 1 ] && printf "NO_LSX=1\n" - -From 995a990e24fdcc8080128a8abc17b4ccc66bd4fd Mon Sep 17 00:00:00 2001 -From: Martin Kroeker -Date: Fri, 12 Jan 2024 00:12:46 +0100 -Subject: [PATCH 2/2] Make AVX512 BFLOAT16 kernels conditional on compiler - capability - ---- - kernel/x86_64/KERNEL.COOPERLAKE | 3 ++- - kernel/x86_64/KERNEL.SAPPHIRERAPIDS | 2 ++ - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/kernel/x86_64/KERNEL.COOPERLAKE b/kernel/x86_64/KERNEL.COOPERLAKE -index dba94aea86..22b042029f 100644 ---- a/kernel/x86_64/KERNEL.COOPERLAKE -+++ b/kernel/x86_64/KERNEL.COOPERLAKE -@@ -1,5 +1,5 @@ - include $(KERNELDIR)/KERNEL.SKYLAKEX -- -+ifneq ($(NO_AVX512BF16), 1) - SBGEMM_SMALL_M_PERMIT = sbgemm_small_kernel_permit_cooperlake.c - SBGEMM_SMALL_K_NN = sbgemm_small_kernel_nn_cooperlake.c - SBGEMM_SMALL_K_B0_NN = sbgemm_small_kernel_nn_cooperlake.c -@@ -20,3 +20,4 @@ SBGEMMINCOPYOBJ = sbgemm_incopy$(TSUFFIX).$(SUFFIX) - SBGEMMITCOPYOBJ = sbgemm_itcopy$(TSUFFIX).$(SUFFIX) - SBGEMMONCOPYOBJ = sbgemm_oncopy$(TSUFFIX).$(SUFFIX) - SBGEMMOTCOPYOBJ = sbgemm_otcopy$(TSUFFIX).$(SUFFIX) -+endif -diff --git a/kernel/x86_64/KERNEL.SAPPHIRERAPIDS b/kernel/x86_64/KERNEL.SAPPHIRERAPIDS -index 3a832e9174..0ab2b4ddcf 100644 ---- a/kernel/x86_64/KERNEL.SAPPHIRERAPIDS -+++ b/kernel/x86_64/KERNEL.SAPPHIRERAPIDS -@@ -1,5 +1,6 @@ - include $(KERNELDIR)/KERNEL.COOPERLAKE - -+ifneq ($(NO_AVX512BF16), 1) - SBGEMM_SMALL_M_PERMIT = - SBGEMM_SMALL_K_NN = - SBGEMM_SMALL_K_B0_NN = -@@ -20,3 +21,4 @@ SBGEMMINCOPYOBJ = sbgemm_incopy$(TSUFFIX).$(SUFFIX) - SBGEMMITCOPYOBJ = sbgemm_itcopy$(TSUFFIX).$(SUFFIX) - SBGEMMONCOPYOBJ = sbgemm_oncopy$(TSUFFIX).$(SUFFIX) - SBGEMMOTCOPYOBJ = sbgemm_otcopy$(TSUFFIX).$(SUFFIX) -+endif diff --git a/deps/patches/openblas-darwin-sve.patch b/deps/patches/openblas-darwin-sve.patch deleted file mode 100644 index a2166db9379f1..0000000000000 --- a/deps/patches/openblas-darwin-sve.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 03688a42622cf76e696859ce384e45aa26d927fc Mon Sep 17 00:00:00 2001 -From: Ian McInerney -Date: Tue, 23 Jan 2024 10:29:57 +0000 -Subject: [PATCH] Build with proper aarch64 flags on Neoverse Darwin - -We aren't affected by the problems in AppleClang that prompted this -fallback to an older architecture. ---- - Makefile.arm64 | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/Makefile.arm64 b/Makefile.arm64 -index ed52a9424..a8f3cb0f0 100644 ---- a/Makefile.arm64 -+++ b/Makefile.arm64 -@@ -135,11 +135,11 @@ ifeq ($(CORE), NEOVERSEN2) - ifeq (1, $(filter 1,$(GCCVERSIONGTEQ7) $(ISCLANG))) - ifeq (1, $(filter 1,$(GCCVERSIONGTEQ10) $(ISCLANG))) - ifeq (1, $(filter 1,$(GCCMINORVERSIONGTEQ4) $(GCCVERSIONGTEQ11) $(ISCLANG))) --ifneq ($(OSNAME), Darwin) -+#ifneq ($(OSNAME), Darwin) - CCOMMON_OPT += -march=armv8.5-a+sve+sve2+bf16 -mtune=neoverse-n2 --else --CCOMMON_OPT += -march=armv8.2-a -mtune=cortex-a72 --endif -+#else -+#CCOMMON_OPT += -march=armv8.2-a -mtune=cortex-a72 -+#endif - ifneq ($(F_COMPILER), NAG) - FCOMMON_OPT += -march=armv8.5-a+sve+sve2+bf16 -mtune=neoverse-n2 - endif --- -2.43.0 - diff --git a/deps/patches/openblas-gemv-multithreading.patch b/deps/patches/openblas-gemv-multithreading.patch deleted file mode 100644 index 827c72fa48b1a..0000000000000 --- a/deps/patches/openblas-gemv-multithreading.patch +++ /dev/null @@ -1,22 +0,0 @@ -From d2fc4f3b4d7f41527bc7dc8f62e9aa6229cfac89 Mon Sep 17 00:00:00 2001 -From: Martin Kroeker -Date: Wed, 17 Jan 2024 20:59:24 +0100 -Subject: [PATCH] Increase multithreading threshold by a factor of 50 - ---- - interface/gemv.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/interface/gemv.c b/interface/gemv.c -index 1f07635799..2c121f1308 100644 ---- a/interface/gemv.c -+++ b/interface/gemv.c -@@ -226,7 +226,7 @@ void CNAME(enum CBLAS_ORDER order, - - #ifdef SMP - -- if ( 1L * m * n < 2304L * GEMM_MULTITHREAD_THRESHOLD ) -+ if ( 1L * m * n < 115200L * GEMM_MULTITHREAD_THRESHOLD ) - nthreads = 1; - else - nthreads = num_cpu_avail(2); diff --git a/doc/Manifest.toml b/doc/Manifest.toml index c55c983402830..5aedbbd7eec38 100644 --- a/doc/Manifest.toml +++ b/doc/Manifest.toml @@ -140,7 +140,6 @@ uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" version = "1.17.0+0" [[deps.Logging]] -deps = ["StyledStrings"] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" version = "1.11.0" diff --git a/doc/make.jl b/doc/make.jl index e06fa1deb8f42..e8ccbad85c468 100644 --- a/doc/make.jl +++ b/doc/make.jl @@ -157,6 +157,7 @@ Manual = [ "manual/environment-variables.md", "manual/embedding.md", "manual/code-loading.md", + "manual/profile.md", "manual/stacktraces.md", "manual/performance-tips.md", "manual/workflow-tips.md", @@ -192,12 +193,6 @@ BaseDocs = [ StdlibDocs = [stdlib.targetfile for stdlib in STDLIB_DOCS] -Tutorials = [ - "tutorials/creating-packages.md", - "tutorials/profile.md", - "tutorials/external.md", -] - DevDocs = [ "Documentation of Julia's Internals" => [ "devdocs/init.md", @@ -256,7 +251,6 @@ const PAGES = [ "Manual" => ["index.md", Manual...], "Base" => BaseDocs, "Standard Library" => StdlibDocs, - "Tutorials" => Tutorials, # Add "Release Notes" to devdocs "Developer Documentation" => [DevDocs..., hide("NEWS.md")], ] @@ -267,7 +261,6 @@ const PAGES = [ "Manual" => Manual, "Base" => BaseDocs, "Standard Library" => StdlibDocs, - "Tutorials" => Tutorials, "Developer Documentation" => DevDocs, ] end diff --git a/doc/man/julia.1 b/doc/man/julia.1 index afde0326e4952..45ddf45412c32 100644 --- a/doc/man/julia.1 +++ b/doc/man/julia.1 @@ -59,7 +59,7 @@ Display version information .TP -h, --help -Print help message +Print command-line options (this message) .TP --help-hidden @@ -77,7 +77,7 @@ Start up with the given system image file .TP -H, --home -Set location of julia executable +Set location of `julia` executable .TP --startup-file={yes*|no} @@ -95,12 +95,14 @@ Use native code from system image if available .TP --compiled-modules={yes*|no|existing|strict} Enable or disable incremental precompilation of modules. -The "existing" option allows use of existing compiled modules that were previously precompiled, but disallows creation of new precompile files. -The "strict" option is similar, but will error if no precompile file is found. +The `existing` option allows use of existing compiled modules that were +previously precompiled, but disallows creation of new precompile files. +The `strict` option is similar, but will error if no precompile file is found. .TP --pkgimages={yes*|no|existing} Enable or disable usage of native code caching in the form of pkgimages +The `existing` option allows use of existing pkgimages but disallows creation of new ones .TP -e, --eval @@ -110,19 +112,25 @@ Evaluate -E, --print Evaluate and display the result +.TP +-m, --module [args] +Run entry point of `Package` (`@main` function) with `args' + .TP -L, --load Load immediately on all processors .TP --t, --threads -Enable n threads; "auto" tries to infer a useful default number -of threads to use but the exact behavior might change in the future. -Currently, "auto" uses the number of CPUs assigned to this julia -process based on the OS-specific affinity assignment interface, if -supported (Linux and Windows). If this is not supported (macOS) or -process affinity is not configured, it uses the number of CPU -threads. +-t, --threads {auto|N[,auto|M]} +Enable N[+M] threads; N threads are assigned to the `default` +threadpool, and if M is specified, M threads are assigned to the +`interactive` threadpool; `auto` tries to infer a useful +default number of threads to use but the exact behavior might change +in the future. Currently sets N to the number of CPUs assigned to +this Julia process based on the OS-specific affinity assignment +interface if supported (Linux and Windows) or to the number of CPU +threads if not supported (MacOS) or if process affinity is not +configured, and sets M to 1. .TP --gcthreads=N[,M] @@ -139,7 +147,7 @@ as the number of local CPU threads (logical cores) Run processes on hosts listed in .TP --i +-i, --interactive Interactive mode; REPL runs and `isinteractive()` is true .TP @@ -147,7 +155,7 @@ Interactive mode; REPL runs and `isinteractive()` is true Quiet startup: no banner, suppress REPL warnings .TP ---banner={yes|no|auto*} +--banner={yes|no|short|auto*} Enable or disable startup banner .TP @@ -175,15 +183,15 @@ Enable or disable warning for ambiguous top-level scope Limit usage of CPU features up to ; set to `help` to see the available options .TP --O, --optimize={0,1,2*,3} +-O, --optimize={0|1|2*|3} Set the optimization level (level 3 if `-O` is used without a level) .TP ---min-optlevel={0*,1,2,3} +--min-optlevel={0*|1|2|3} Set a lower bound on the optimization level .TP --g {0,1*,2} +-g, --debug-info={0|1*|2} Set the level of debug info generation (level 2 if `-g` is used without a level) .TP @@ -198,6 +206,10 @@ Emit bounds checks always, never, or respect @inbounds declarations --math-mode={ieee|user} Disallow or enable unsafe floating point optimizations (overrides @fastmath declaration) +.TP +--polly={yes*|no} +Enable or disable the polyhedral optimizer Polly (overrides @polly declaration) + .TP --code-coverage[={none*|user|all}] Count executions of source lines (omitting setting is equivalent to `user`) @@ -208,8 +220,8 @@ Count executions of source lines in a file or files under a given directory. A ` be placed before the path to indicate this option. A `@` with no path will track the current directory. .TP - --code-coverage=tracefile.info - Append coverage information to the LCOV tracefile (filename supports format tokens) +--code-coverage=tracefile.info +Append coverage information to the LCOV tracefile (filename supports format tokens) .TP --track-allocation[={none*|user|all}] @@ -217,8 +229,8 @@ Count bytes allocated by each source line (omitting setting is equivalent to `us .TP --track-allocation=@ -Count bytes allocated by each source line in a file or files under a given directory. A `@` -must be placed before the path to indicate this option. A `@` with no path will track the current directory. +Count bytes but only in files that fall under the given file path/directory. +The `@` prefix is required to select this option. A `@` with no path will track the current directory. .TP --bug-report=KIND @@ -228,7 +240,7 @@ fallbacks to the latest compatible BugReporting.jl if not. For more information, --bug-report=help. .TP ---heap-size-hint= +--heap-size-hint= Forces garbage collection if memory usage is higher than the given value. The value may be specified as a number of bytes, optionally in units of KB, MB, GB, or TB, or as a percentage of physical memory with %. @@ -270,13 +282,17 @@ Generate an assembly file (.s) Generate an incremental output file (rather than complete) .TP ---trace-compile={stderr,name} +--trace-compile={stderr|name} Print precompile statements for methods compiled during execution or save to a path .TP -image-codegen Force generate code in imaging mode +.TP +--permalloc-pkgimg={yes|no*} +Copy the data section of package images into memory + .SH FILES AND ENVIRONMENT See https://docs.julialang.org/en/v1/manual/environment-variables/ diff --git a/doc/src/base/math.md b/doc/src/base/math.md index c1b18c0b66d86..7091aa6f1aa87 100644 --- a/doc/src/base/math.md +++ b/doc/src/base/math.md @@ -74,6 +74,7 @@ Base.Math.tand Base.Math.sincosd Base.Math.sinpi Base.Math.cospi +Base.Math.tanpi Base.Math.sincospi Base.sinh(::Number) Base.cosh(::Number) diff --git a/doc/src/manual/command-line-interface.md b/doc/src/manual/command-line-interface.md index 448964bf1ef8a..f528dca86edd5 100644 --- a/doc/src/manual/command-line-interface.md +++ b/doc/src/manual/command-line-interface.md @@ -59,7 +59,7 @@ expression. To see this feature in action, consider the following definition, which will execute the print function despite there being no explicit call to `main`: ``` -$ julia -e '(@main)(ARGS) = println("Hello World!")' +$ julia -e '(@main)(args) = println("Hello World!")' Hello World! $ ``` @@ -93,7 +93,7 @@ The `main` binding may be imported from a package. A *hello world* package defin module Hello export main -(@main)(ARGS) = println("Hello from the package!") +(@main)(args) = println("Hello from the package!") end ``` @@ -164,44 +164,47 @@ The following is a complete list of command-line switches available when launchi |Switch |Description| |:--- |:---| |`-v`, `--version` |Display version information| -|`-h`, `--help` |Print command-line options (this message).| -|`--help-hidden` |Uncommon options not shown by `-h`| +|`-h`, `--help` |Print command-line options (this message)| +|`--help-hidden` |Print uncommon options not shown by `-h`| |`--project[={\|@.}]` |Set `` as the active project/environment. The default `@.` option will search through parent directories until a `Project.toml` or `JuliaProject.toml` file is found.| |`-J`, `--sysimage ` |Start up with the given system image file| |`-H`, `--home ` |Set location of `julia` executable| |`--startup-file={yes*\|no}` |Load `JULIA_DEPOT_PATH/config/startup.jl`; if [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH) environment variable is unset, load `~/.julia/config/startup.jl`| |`--handle-signals={yes*\|no}` |Enable or disable Julia's default signal handlers| |`--sysimage-native-code={yes*\|no}` |Use native code from system image if available| -|`--compiled-modules={yes*\|no\|existing|strict}` |Enable or disable incremental precompilation of modules. The `existing` option allows use of existing compiled modules that were previously precompiled, but disallows creation of new precompile files. The `strict` option is similar, but will error if no precompile file is found. | -|`--pkgimages={yes*\|no|existing}` |Enable or disable usage of native code caching in the form of pkgimages. The `existing` option allows use of existing pkgimages but disallows creation of new ones| +|`--compiled-modules={yes*\|no\|existing\|strict}` |Enable or disable incremental precompilation of modules. The `existing` option allows use of existing compiled modules that were previously precompiled, but disallows creation of new precompile files. The `strict` option is similar, but will error if no precompile file is found. | +|`--pkgimages={yes*\|no\|existing}` |Enable or disable usage of native code caching in the form of pkgimages. The `existing` option allows use of existing pkgimages but disallows creation of new ones| |`-e`, `--eval ` |Evaluate ``| |`-E`, `--print ` |Evaluate `` and display the result| +|`-m`, `--module [args]` |Run entry point of `Package` (`@main` function) with `args'| |`-L`, `--load ` |Load `` immediately on all processors| -|`-t`, `--threads {N\|auto}` |Enable N threads; `auto` tries to infer a useful default number of threads to use but the exact behavior might change in the future. Currently, `auto` uses the number of CPUs assigned to this julia process based on the OS-specific affinity assignment interface, if supported (Linux and Windows). If this is not supported (macOS) or process affinity is not configured, it uses the number of CPU threads.| +|`-t`, `--threads {auto\|N[,auto\|M]}` |Enable N[+M] threads; N threads are assigned to the `default` threadpool, and if M is specified, M threads are assigned to the `interactive` threadpool; `auto` tries to infer a useful default number of threads to use but the exact behavior might change in the future. Currently sets N to the number of CPUs assigned to this Julia process based on the OS-specific affinity assignment interface if supported (Linux and Windows) or to the number of CPU threads if not supported (MacOS) or if process affinity is not configured, and sets M to 1.| | `--gcthreads=N[,M]` |Use N threads for the mark phase of GC and M (0 or 1) threads for the concurrent sweeping phase of GC. N is set to half of the number of compute threads and M is set to 0 if unspecified.| |`-p`, `--procs {N\|auto}` |Integer value N launches N additional local worker processes; `auto` launches as many workers as the number of local CPU threads (logical cores)| |`--machine-file ` |Run processes on hosts listed in ``| -|`-i` |Interactive mode; REPL runs and `isinteractive()` is true| +|`-i`, `--interactive` |Interactive mode; REPL runs and `isinteractive()` is true| |`-q`, `--quiet` |Quiet startup: no banner, suppress REPL warnings| -|`--banner={yes\|no\|auto*}` |Enable or disable startup banner| +|`--banner={yes\|no\|short\|auto*}` |Enable or disable startup banner| |`--color={yes\|no\|auto*}` |Enable or disable color text| |`--history-file={yes*\|no}` |Load or save history| |`--depwarn={yes\|no*\|error}` |Enable or disable syntax and method deprecation warnings (`error` turns warnings into errors)| |`--warn-overwrite={yes\|no*}` |Enable or disable method overwrite warnings| |`--warn-scope={yes*\|no}` |Enable or disable warning for ambiguous top-level scope| |`-C`, `--cpu-target ` |Limit usage of CPU features up to ``; set to `help` to see the available options| -|`-O`, `--optimize={0,1,2*,3}` |Set the optimization level (level is 3 if `-O` is used without a level) ($)| -|`--min-optlevel={0*,1,2,3}` |Set the lower bound on per-module optimization| -|`-g`, `--debug-info={0,1*,2}` |Set the level of debug info generation (level is 2 if `-g` is used without a level) ($)| +|`-O`, `--optimize={0\|1\|2*\|3}` |Set the optimization level (level is 3 if `-O` is used without a level) ($)| +|`--min-optlevel={0*\|1\|2\|3}` |Set the lower bound on per-module optimization| +|`-g`, `--debug-info={0\|1*\|2}` |Set the level of debug info generation (level is 2 if `-g` is used without a level) ($)| |`--inline={yes\|no}` |Control whether inlining is permitted, including overriding `@inline` declarations| |`--check-bounds={yes\|no\|auto*}` |Emit bounds checks always, never, or respect `@inbounds` declarations ($)| |`--math-mode={ieee,fast}` |Disallow or enable unsafe floating point optimizations (overrides `@fastmath` declaration)| +|`--polly={yes*\|no}` |Enable or disable the polyhedral optimizer Polly (overrides @polly declaration)| |`--code-coverage[={none*\|user\|all}]` |Count executions of source lines (omitting setting is equivalent to `user`)| |`--code-coverage=@` |Count executions but only in files that fall under the given file path/directory. The `@` prefix is required to select this option. A `@` with no path will track the current directory.| |`--code-coverage=tracefile.info` |Append coverage information to the LCOV tracefile (filename supports format tokens).| |`--track-allocation[={none*\|user\|all}]` |Count bytes allocated by each source line (omitting setting is equivalent to "user")| |`--track-allocation=@` |Count bytes but only in files that fall under the given file path/directory. The `@` prefix is required to select this option. A `@` with no path will track the current directory.| |`--bug-report=KIND` |Launch a bug report session. It can be used to start a REPL, run a script, or evaluate expressions. It first tries to use BugReporting.jl installed in current environment and falls back to the latest compatible BugReporting.jl if not. For more information, see `--bug-report=help`.| +|`--heap-size-hint=` |Forces garbage collection if memory usage is higher than the given value. The value may be specified as a number of bytes, optionally in units of KB, MB, GB, or TB, or as a percentage of physical memory with %.| |`--compile={yes*\|no\|all\|min}` |Enable or disable JIT compiler, or request exhaustive or minimal compilation| |`--output-o ` |Generate an object file (including system image data)| |`--output-ji ` |Generate a system image data file (.ji)| @@ -211,9 +214,9 @@ The following is a complete list of command-line switches available when launchi |`--output-bc ` |Generate LLVM bitcode (.bc)| |`--output-asm ` |Generate an assembly file (.s)| |`--output-incremental={yes\|no*}` |Generate an incremental output file (rather than complete)| -|`--trace-compile={stderr,name}` |Print precompile statements for methods compiled during execution or save to a path| +|`--trace-compile={stderr\|name}` |Print precompile statements for methods compiled during execution or save to a path| |`--image-codegen` |Force generate code in imaging mode| -|`--heap-size-hint=` |Forces garbage collection if memory usage is higher than the given value. The value may be specified as a number of bytes, optionally in units of KB, MB, GB, or TB, or as a percentage of physical memory with %.| +|`--permalloc-pkgimg={yes\|no*}` |Copy the data section of package images into memory| !!! compat "Julia 1.1" diff --git a/doc/src/tutorials/profile.md b/doc/src/manual/profile.md similarity index 100% rename from doc/src/tutorials/profile.md rename to doc/src/manual/profile.md diff --git a/doc/src/tutorials/creating-packages.md b/doc/src/tutorials/creating-packages.md deleted file mode 100644 index d1f79e8c88a9d..0000000000000 --- a/doc/src/tutorials/creating-packages.md +++ /dev/null @@ -1,634 +0,0 @@ -# [Creating Packages](@id creating-packages-tutorial) - -## Generating files for a package - -!!! note - The [PkgTemplates](https://github.com/invenia/PkgTemplates.jl) package offers an easy, repeatable, and - customizable way to generate the files for a new package. It can also generate files needed for Documentation, CI, etc. - We recommend that you use PkgTemplates for creating - new packages instead of using the minimal `pkg> generate` functionality described below. - -To generate the bare minimum files for a new package, use `pkg> generate`. - -```julia-repl -(@v1.8) pkg> generate HelloWorld -``` - -This creates a new project `HelloWorld` in a subdirectory by the same name, with the following files (visualized with the external [`tree` command](https://linux.die.net/man/1/tree)): - -```julia-repl -shell> tree HelloWorld/ -HelloWorld/ -├── Project.toml -└── src - └── HelloWorld.jl - -2 directories, 2 files -``` - -The `Project.toml` file contains the name of the package, its unique UUID, its version, the authors and potential dependencies: - -```toml -name = "HelloWorld" -uuid = "b4cd1eb8-1e24-11e8-3319-93036a3eb9f3" -version = "0.1.0" -authors = ["Some One "] - -[deps] -``` - -The content of `src/HelloWorld.jl` is: - -```julia -module HelloWorld - -greet() = print("Hello World!") - -end # module -``` - -We can now activate the project by using the path to the directory where it is installed, and load the package: - -```julia-repl -pkg> activate ./HelloWorld - -julia> import HelloWorld - -julia> HelloWorld.greet() -Hello World! -``` - -For the rest of the tutorial we enter inside the directory of the project, for convenience: - -```julia-repl -julia> cd("HelloWorld") -``` - -## Adding dependencies to the project - -Let’s say we want to use the standard library package `Random` and the registered package `JSON` in our project. -We simply `add` these packages (note how the prompt now shows the name of the newly generated project, -since we `activate`d it): - -```julia-repl -(HelloWorld) pkg> add Random JSON - Resolving package versions... - Updating `~/HelloWorld/Project.toml` - [682c06a0] + JSON v0.21.3 - [9a3f8284] + Random - Updating `~/HelloWorld/Manifest.toml` - [682c06a0] + JSON v0.21.3 - [69de0a69] + Parsers v2.4.0 - [ade2ca70] + Dates - ... -``` - -Both `Random` and `JSON` got added to the project’s `Project.toml` file, and the resulting dependencies got added to the `Manifest.toml` file. -The resolver has installed each package with the highest possible version, while still respecting the compatibility that each package enforces on its dependencies. - -We can now use both `Random` and `JSON` in our project. Changing `src/HelloWorld.jl` to - -```julia -module HelloWorld - -import Random -import JSON - -greet() = print("Hello World!") -greet_alien() = print("Hello ", Random.randstring(8)) - -end # module -``` - -and reloading the package, the new `greet_alien` function that uses `Random` can be called: - -```julia-repl -julia> HelloWorld.greet_alien() -Hello aT157rHV -``` - -## Defining a public API - -If you want your package to be useful to other packages and you want folks to be able to -easily update to newer version of your package when they come out, it is important to -document what behavior will stay consistent across updates. - -Unless you note otherwise, the public API of your package is defined as all the behavior you -describe about public symbols. A public symbol is a symbol that is exported from your -package with the `export` keyword or marked as public with the `public` keyword. When you -change the behavior of something that was previously public so that the new -version no longer conforms to the specifications provided in the old version, you should -adjust your package version number according to [Julia's variant on SemVer](#Version-specifier-format). -If you would like to include a symbol in your public API without exporting it into the -global namespace of folks who call `using YourPackage`, you should mark that symbol as -public with `public that_symbol`. Symbols marked as public with the `public` keyword are -just as public as those marked as public with the `export` keyword, but when folks call -`using YourPackage`, they will still have to qualify access to those symbols with -`YourPackage.that_symbol`. - -Let's say we would like our `greet` function to be part of the public API, but not the -`greet_alien` function. We could the write the following and release it as version `1.0.0`. - -```julia -module HelloWorld - -export greet - -import Random -import JSON - -"Writes a friendly message." -greet() = print("Hello World!") - -"Greet an alien by a randomly generated name." -greet_alien() = print("Hello ", Random.randstring(8)) - -end # module -``` - -Then, if we change `greet` to - -```julia -"Writes a friendly message that is exactly three words long." -greet() = print("Hello Lovely World!") -``` - -We would release the new version as `1.1.0`. This is not breaking -because the new implementation conforms to the old documentation, but -it does add a new feature, that the message must be three words long. - -Later, we may wish to change `greet_alien` to - -```julia -"Greet an alien by the name of \"Zork\"." -greet_alien() = print("Hello Zork") -``` - -And also export it by changing - -```julia -export greet -``` - -to - -```julia -export greet, greet_alien -``` - -We should release this new version as `1.2.0` because it adds a new feature -`greet_alien` to the public API. Even though `greet_alien` was documented before -and the new version does not conform to the old documentation, this is not breaking -because the old documentation was not attached to a symbol that was exported -at the time so that documentation does not apply across released versions. - -However, if we now wish to change `greet` to - -```julia -"Writes a friendly message that is exactly four words long." -greet() = print("Hello very lovely world") -``` - -we would need to release the new version as `2.0.0`. In version `1.1.0`, we specified that -the greeting would be three words long, and because `greet` was exported, that description -also applies to all future versions until the next breaking release. Because this new -version does not conform to the old specification, it must be tagged as a breaking change. - -Please note that version numbers are free and unlimited. It is okay to use lots of them -(e.g. version `6.62.8`). - -## Adding a build step to the package - -The build step is executed the first time a package is installed or when explicitly invoked with `build`. -A package is built by executing the file `deps/build.jl`. - -```julia-repl -julia> mkpath("deps"); - -julia> write("deps/build.jl", - """ - println("I am being built...") - """); - -(HelloWorld) pkg> build - Building HelloWorld → `deps/build.log` - Resolving package versions... - -julia> print(readchomp("deps/build.log")) -I am being built... -``` - -If the build step fails, the output of the build step is printed to the console - -```julia-repl -julia> write("deps/build.jl", - """ - error("Ooops") - """); - -(HelloWorld) pkg> build - Building HelloWorld → `~/HelloWorld/deps/build.log` -ERROR: Error building `HelloWorld`: -ERROR: LoadError: Ooops -Stacktrace: - [1] error(s::String) - @ Base ./error.jl:35 - [2] top-level scope - @ ~/HelloWorld/deps/build.jl:1 - [3] include(fname::String) - @ Base.MainInclude ./client.jl:476 - [4] top-level scope - @ none:5 -in expression starting at /home/kc/HelloWorld/deps/build.jl:1 -``` - -!!! warning - A build step should generally not create or modify any files in the package directory. If you need to store some files - from the build step, use the [Scratch.jl](https://github.com/JuliaPackaging/Scratch.jl) package. - -## [Adding tests to the package](@id adding-tests-to-packages) - -When a package is tested the file `test/runtests.jl` is executed: - -```julia-repl -julia> mkpath("test"); - -julia> write("test/runtests.jl", - """ - println("Testing...") - """); - -(HelloWorld) pkg> test - Testing HelloWorld - Resolving package versions... -Testing... - Testing HelloWorld tests passed -``` - -Tests are run in a new Julia process, where the package itself, and any -test-specific dependencies, are available, see below. - - -!!! warning - Tests should generally not create or modify any files in the package directory. If you need to store some files - from the build step, use the [Scratch.jl](https://github.com/JuliaPackaging/Scratch.jl) package. - -### Test-specific dependencies - -There are two ways of adding test-specific dependencies (dependencies that are not dependencies of the package but will still be available to -load when the package is tested). - -#### `target` based test specific dependencies - -Using this method of adding test-specific dependencies, the packages are added under an `[extras]` section and to a test target, -e.g. to add `Markdown` and `Test` as test dependencies, add the following to the `Project.toml` file: - -```toml -[extras] -Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[targets] -test = ["Markdown", "Test"] -``` - -Note that the only supported targets are `test` and `build`, the latter of which (not recommended) can be used -for any `deps/build.jl` scripts. - -#### Alternative approach: `test/Project.toml` file test specific dependencies - -!!! note - The exact interaction between `Project.toml`, `test/Project.toml` and their corresponding - `Manifest.toml`s are not fully worked out and may be subject to change in future versions. - The older method of adding test-specific dependencies, described in the previous section, - will therefore be supported throughout all Julia 1.X releases. - -In Julia 1.2 and later test dependencies can be declared in `test/Project.toml`. When running -tests, Pkg will automatically merge this and the package Projects to create the test environment. - -!!! note - If no `test/Project.toml` exists Pkg will use the `target` based test specific dependencies. - -To add a test-specific dependency, i.e. a dependency that is available only when testing, -it is thus enough to add this dependency to the `test/Project.toml` project. This can be -done from the Pkg REPL by activating this environment, and then use `add` as one normally -does. Let's add the `Test` standard library as a test dependency: - -```julia-repl -(HelloWorld) pkg> activate ./test -[ Info: activating environment at `~/HelloWorld/test/Project.toml`. - -(test) pkg> add Test - Resolving package versions... - Updating `~/HelloWorld/test/Project.toml` - [8dfed614] + Test - Updating `~/HelloWorld/test/Manifest.toml` - [...] -``` - -We can now use `Test` in the test script and we can see that it gets installed when testing: - -```julia-repl -julia> write("test/runtests.jl", - """ - using Test - @test 1 == 1 - """); - -(test) pkg> activate . - -(HelloWorld) pkg> test - Testing HelloWorld - Resolving package versions... - Updating `/var/folders/64/76tk_g152sg6c6t0b4nkn1vw0000gn/T/tmpPzUPPw/Project.toml` - [d8327f2a] + HelloWorld v0.1.0 [`~/.julia/dev/Pkg/HelloWorld`] - [8dfed614] + Test - Updating `/var/folders/64/76tk_g152sg6c6t0b4nkn1vw0000gn/T/tmpPzUPPw/Manifest.toml` - [d8327f2a] + HelloWorld v0.1.0 [`~/.julia/dev/Pkg/HelloWorld`] - Testing HelloWorld tests passed``` -``` - -## Compatibility on dependencies - -Every dependency should in general have a compatibility constraint on it. -This is an important topic so there is a chapter in the package docs about it: -[Compatibility](https://pkgdocs.julialang.org/v1/compatibility). - -## Weak dependencies - -!!! note - This is a somewhat advanced usage of Pkg which can be skipped for people new to Julia and Julia packages. - -!!! compat - The described feature requires Julia 1.9+. - -A weak dependency is a dependency that will not automatically install when the package is installed but -you can still control what versions of that package are allowed to be installed by setting compatibility on it. -These are listed in the project file under the `[weakdeps]` section: - -```toml -[weakdeps] -SomePackage = "b3785f31-9d33-4cdf-bc73-f646780f1739" - -[compat] -SomePackage = "1.2" -``` - -The current usage of this is almost solely limited to "extensions" which is described in the next section. - -## Conditional loading of code in packages (Extensions) - -!!! note - This is a somewhat advanced usage of Pkg which can be skipped for people new to Julia and Julia packages. - -!!! compat - The described feature requires Julia 1.9+. - -Sometimes one wants to make two or more packages work well together, but may be reluctant (perhaps due to increased load times) to make one an unconditional dependency of the other. -A package *extension* is a module in a file (similar to a package) that is automatically loaded when *some other set of packages* are -loaded into the Julia session. This is very similar to functionality that the external package -[Requires.jl](https://github.com/JuliaPackaging/Requires.jl) provides, but which is now available directly through Julia, -and provides added benefits such as being able to precompile the extension. - -### Code structure - -A useful application of extensions could be for a plotting package that should be able to plot -objects from a wide variety of different Julia packages. -Adding all those different Julia packages as dependencies of the plotting package -could be expensive since they would end up getting loaded even if they were never used. -Instead, the code required to plot objects for specific packages can be put into separate files -(extensions) and these are loaded only when the packages that define the type(s) we want to plot -are loaded. - -Below is an example of how the code can be structured for a use case in which a -`Plotting` package wants to be able to display objects defined in the external package `Contour`. -The file and folder structure shown below is found in the `Plotting` package. - - `Project.toml`: - ```toml -name = "Plotting" -version = "0.1.0" -uuid = "..." - -[weakdeps] -Contour = "d38c429a-6771-53c6-b99e-75d170b6e991" - -[extensions] -# name of extension to the left -# extension dependencies required to load the extension to the right -# use a list for multiple extension dependencies -PlottingContourExt = "Contour" - -[compat] -Contour = "0.6.2" -``` - -`src/Plotting.jl`: -```julia -module Plotting - -function plot(x::Vector) - # Some functionality for plotting a vector here -end - -end # module -``` - -`ext/PlottingContourExt.jl` (can also be in `ext/PlottingContourExt/PlottingContourExt.jl`): -```julia -module PlottingContourExt # Should be same name as the file (just like a normal package) - -using Plotting, Contour - -function Plotting.plot(c::Contour.ContourCollection) - # Some functionality for plotting a contour here -end - -end # module -``` - -Extensions can have any arbitrary name (here `PlottingContourExt`), but using something similar to the format of -this example that makes the extended functionality and dependency of the extension clear is likely a good idea. - -!!! compat - Often you will put the extension dependencies into the `test` target so they are loaded when running e.g. `Pkg.test()`. On earlier Julia versions - this requires you to also put the package in the `[extras]` section. This is unfortunate but the project verifier on older Julia versions will - complain if this is not done. - -!!! note - If you use a manifest generated by a Julia version that does not know about extensions with a Julia version that does - know about them, the extensions will not load. This is because the manifest lacks some information that tells Julia - when it should load these packages. So make sure you use a manifest generated at least the Julia version you are using. - -### Behavior of extensions - -A user that depends only on `Plotting` will not pay the cost of the "extension" inside the `PlottingContourExt` module. -It is only when the `Contour` package actually gets loaded that the `PlottingContourExt` extension is loaded too -and provides the new functionality. - -In our example, the new functionality is an additional _method_, which we add to an existing _function_ from the parent package `Plotting`. -Implementing such methods is among the most standard use cases of package extensions. -Within the parent package, the function to extend can even be defined with zero methods, as follows: - -```julia -function plot end -``` - -!!! note - If one considers `PlottingContourExt` as a completely separate package, it could be argued that defining `Plotting.plot(c::Contour.ContourCollection)` is - [type piracy](@ref avoid-type-piracy) since `PlottingContourExt` _owns_ neither the function `Plotting.plot` nor the type `Contour.ContourCollection`. - However, for extensions, it is ok to assume that the extension owns the functions in its parent package. - -In other situations, one may need to define new symbols in the extension (types, structs, functions, etc.) instead of reusing those from the parent package. -Such symbols are created in a separate module corresponding to the extension, namely `PlottingContourExt`, and thus not in `Plotting` itself. -If extension symbols are needed in the parent package, one must call `Base.get_extension` to retrieve them. -Here is an example showing how a custom type defined in `PlottingContourExt` can be accessed in `Plotting`: - -```julia -ext = Base.get_extension(@__MODULE__, :PlottingContourExt) -if !isnothing(ext) - ContourPlotType = ext.ContourPlotType -end -``` - -On the other hand, accessing extension symbols from a third-party package (i.e. not the parent) is not a recommended practice at the moment. - -### Backwards compatibility - -This section discusses various methods for using extensions on Julia versions that support them, -while simultaneously providing similar functionality on older Julia versions. - -#### Requires.jl - -This section is relevant if you are currently using Requires.jl but want to transition to using extensions (while still having Requires be used on Julia versions that do not support extensions). -This is done by making the following changes (using the example above): - -- Add the following to the package file. This makes it so that Requires.jl loads and inserts the - callback only when extensions are not supported - ```julia - # This symbol is only defined on Julia versions that support extensions - if !isdefined(Base, :get_extension) - using Requires - end - - @static if !isdefined(Base, :get_extension) - function __init__() - @require Contour = "d38c429a-6771-53c6-b99e-75d170b6e991" include("../ext/PlottingContourExt.jl") - end - end - ``` - or if you have other things in your `__init__()` function: - ```julia - if !isdefined(Base, :get_extension) - using Requires - end - - function __init__() - # Other init functionality here - - @static if !isdefined(Base, :get_extension) - @require Contour = "d38c429a-6771-53c6-b99e-75d170b6e991" include("../ext/PlottingContourExt.jl") - end - end - ``` -- Make the following change in the conditionally-loaded code: - ```julia - isdefined(Base, :get_extension) ? (using Contour) : (using ..Contour) - ``` -- Add `Requires` to `[weakdeps]` in your `Project.toml` file, so that it is listed in both `[deps]` and `[weakdeps]`. - Julia 1.9+ knows to not install it as a regular dependency, whereas earlier versions will consider it a dependency. - -The package should now work with Requires.jl on Julia versions before extensions were introduced -and with extensions on more recent Julia versions. - -#### Transition from normal dependency to extension - -This section is relevant if you have a normal dependency that you want to transition be an extension (while still having the dependency be a normal dependency on Julia versions that do not support extensions). -This is done by making the following changes (using the example above): - -- Make sure that the package is **both** in the `[deps]` and `[weakdeps]` section. Newer Julia versions will ignore dependencies in `[deps]` that are also in `[weakdeps]`. -- Add the following to your main package file (typically at the bottom): - ```julia - if !isdefined(Base, :get_extension) - include("../ext/PlottingContourExt.jl") - end - ``` - -#### Using an extension while supporting older Julia versions - -In the case where one wants to use an extension (without worrying about the -feature of the extension being available on older Julia versions) while still -supporting older Julia versions the packages under `[weakdeps]` should be -duplicated into `[extras]`. This is an unfortunate duplication, but without -doing this the project verifier under older Julia versions will throw an error -if it finds packages under `[compat]` that is not listed in `[extras]`. - -## Package naming guidelines - -Package names should be sensible to most Julia users, *even to those who are not domain experts*. -The following guidelines apply to the `General` registry but may be useful for other package -registries as well. - -Since the `General` registry belongs to the entire community, people may have opinions about -your package name when you publish it, especially if it's ambiguous or can be confused with -something other than what it is. Usually, you will then get suggestions for a new name that -may fit your package better. - -1. Avoid jargon. In particular, avoid acronyms unless there is minimal possibility of confusion. - - * It's ok to say `USA` if you're talking about the USA. - * It's not ok to say `PMA`, even if you're talking about positive mental attitude. -2. Avoid using `Julia` in your package name or prefixing it with `Ju`. - - * It is usually clear from context and to your users that the package is a Julia package. - * Package names already have a `.jl` extension, which communicates to users that `Package.jl` is a Julia package. - * Having Julia in the name can imply that the package is connected to, or endorsed by, contributors - to the Julia language itself. -3. Packages that provide most of their functionality in association with a new type should have pluralized - names. - - * `DataFrames` provides the `DataFrame` type. - * `BloomFilters` provides the `BloomFilter` type. - * In contrast, `JuliaParser` provides no new type, but instead new functionality in the `JuliaParser.parse()` - function. -4. Err on the side of clarity, even if clarity seems long-winded to you. - - * `RandomMatrices` is a less ambiguous name than `RndMat` or `RMT`, even though the latter are shorter. -5. A less systematic name may suit a package that implements one of several possible approaches to - its domain. - - * Julia does not have a single comprehensive plotting package. Instead, `Gadfly`, `PyPlot`, `Winston` - and other packages each implement a unique approach based on a particular design philosophy. - * In contrast, `SortingAlgorithms` provides a consistent interface to use many well-established - sorting algorithms. -6. Packages that wrap external libraries or programs should be named after those libraries or programs. - - * `CPLEX.jl` wraps the `CPLEX` library, which can be identified easily in a web search. - * `MATLAB.jl` provides an interface to call the MATLAB engine from within Julia. -7. Avoid naming a package closely to an existing package - * `Websocket` is too close to `WebSockets` and can be confusing to users. Rather use a new name such as `SimpleWebsockets`. - -## Registering packages - -Once a package is ready it can be registered with the [General Registry](https://github.com/JuliaRegistries/General#registering-a-package-in-general) (see also the [FAQ](https://github.com/JuliaRegistries/General#faq)). -Currently, packages are submitted via [`Registrator`](https://juliaregistrator.github.io/). -In addition to `Registrator`, [`TagBot`](https://github.com/marketplace/actions/julia-tagbot) helps manage the process of tagging releases. - -## Best Practices - -Packages should avoid mutating their own state (writing to files within their package directory). -Packages should, in general, not assume that they are located in a writable location (e.g. if installed as part of a system-wide depot) or even a stable one (e.g. if they are bundled into a system image by [PackageCompiler.jl](https://github.com/JuliaLang/PackageCompiler.jl)). -To support the various use cases in the Julia package ecosystem, the Pkg developers have created a number of auxiliary packages and techniques to help package authors create self-contained, immutable, and relocatable packages: - -* [`Artifacts`](https://pkgdocs.julialang.org/v1/artifacts/) can be used to bundle chunks of data alongside your package, or even allow them to be downloaded on-demand. - Prefer artifacts over attempting to open a file via a path such as `joinpath(@__DIR__, "data", "my_dataset.csv")` as this is non-relocatable. - Once your package has been precompiled, the result of `@__DIR__` will have been baked into your precompiled package data, and if you attempt to distribute this package, it will attempt to load files at the wrong location. - Artifacts can be bundled and accessed easily using the `artifact"name"` string macro. - -* [`Scratch.jl`](https://github.com/JuliaPackaging/Scratch.jl) provides the notion of "scratch spaces", mutable containers of data for packages. - Scratch spaces are designed for data caches that are completely managed by a package and should be removed when the package itself is uninstalled. - For important user-generated data, packages should continue to write out to a user-specified path that is not managed by Julia or Pkg. - -* [`Preferences.jl`](https://github.com/JuliaPackaging/Preferences.jl) allows packages to read and write preferences to the top-level `Project.toml`. - These preferences can be read at runtime or compile-time, to enable or disable different aspects of package behavior. - Packages previously would write out files to their own package directories to record options set by the user or environment, but this is highly discouraged now that `Preferences` is available. diff --git a/doc/src/tutorials/external.md b/doc/src/tutorials/external.md deleted file mode 100644 index 0211db3d63a5e..0000000000000 --- a/doc/src/tutorials/external.md +++ /dev/null @@ -1,4 +0,0 @@ -# External Tutorials - -We have created a non-exhaustive list of community provided Julia tutorials. -[Check them out to learn Julia through the lens of someone from the community](https://julialang.org/learning/tutorials/). diff --git a/src/builtins.c b/src/builtins.c index c26d528cb3ee4..85f5ec206d795 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -1564,11 +1564,11 @@ JL_CALLABLE(jl_f_apply_type) jl_vararg_t *vm = (jl_vararg_t*)args[0]; if (!vm->T) { JL_NARGS(apply_type, 2, 3); - return (jl_value_t*)jl_wrap_vararg(args[1], nargs == 3 ? args[2] : NULL, 1); + return (jl_value_t*)jl_wrap_vararg(args[1], nargs == 3 ? args[2] : NULL, 1, 0); } else if (!vm->N) { JL_NARGS(apply_type, 2, 2); - return (jl_value_t*)jl_wrap_vararg(vm->T, args[1], 1); + return (jl_value_t*)jl_wrap_vararg(vm->T, args[1], 1, 0); } } else if (jl_is_unionall(args[0])) { @@ -2474,7 +2474,7 @@ void jl_init_primitives(void) JL_GC_DISABLED add_builtin("Tuple", (jl_value_t*)jl_anytuple_type); add_builtin("TypeofVararg", (jl_value_t*)jl_vararg_type); add_builtin("SimpleVector", (jl_value_t*)jl_simplevector_type); - add_builtin("Vararg", (jl_value_t*)jl_wrap_vararg(NULL, NULL, 0)); + add_builtin("Vararg", (jl_value_t*)jl_wrap_vararg(NULL, NULL, 0, 0)); add_builtin("Module", (jl_value_t*)jl_module_type); add_builtin("MethodTable", (jl_value_t*)jl_methtable_type); diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 007e4c5936a4f..998a8421c79f0 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -2915,6 +2915,7 @@ static Value *emit_genericmemoryptr(jl_codectx_t &ctx, Value *mem, const jl_data PointerType *PT = cast(mem->getType()); assert(PT == ctx.types().T_prjlvalue); Value *addr = emit_bitcast(ctx, mem, ctx.types().T_jlgenericmemory->getPointerTo(PT->getAddressSpace())); + addr = decay_derived(ctx, addr); addr = ctx.builder.CreateStructGEP(ctx.types().T_jlgenericmemory, addr, 1); setName(ctx.emission_context, addr, ".data_ptr"); PointerType *PPT = cast(ctx.types().T_jlgenericmemory->getElementType(1)); @@ -3625,7 +3626,7 @@ static void emit_write_multibarrier(jl_codectx_t &ctx, Value *parent, Value *agg static jl_cgval_t union_store(jl_codectx_t &ctx, Value *ptr, Value *ptindex, jl_cgval_t rhs, jl_cgval_t cmp, - jl_value_t *jltype, MDNode *tbaa, MDNode *aliasscope, MDNode *tbaa_tindex, + jl_value_t *jltype, MDNode *tbaa, MDNode *tbaa_tindex, AtomicOrdering Order, AtomicOrdering FailOrder, Value *needlock, bool issetfield, bool isreplacefield, bool isswapfield, bool ismodifyfield, bool issetfieldonce, const jl_cgval_t *modifyop, const Twine &fname) @@ -3683,7 +3684,7 @@ static jl_cgval_t union_store(jl_codectx_t &ctx, } Value *tindex = compute_tindex_unboxed(ctx, rhs_union, jltype); tindex = ctx.builder.CreateNUWSub(tindex, ConstantInt::get(getInt8Ty(ctx.builder.getContext()), 1)); - jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_unionselbyte); + jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, tbaa_tindex); ai.decorateInst(ctx.builder.CreateAlignedStore(tindex, ptindex, Align(1))); // copy data if (!rhs.isghost) { @@ -3739,7 +3740,7 @@ static jl_cgval_t emit_setfield(jl_codectx_t &ctx, emit_bitcast(ctx, addr, getInt8PtrTy(ctx.builder.getContext())), ConstantInt::get(ctx.types().T_size, fsz1)); setNameWithField(ctx.emission_context, ptindex, get_objname, sty, idx0, Twine(".tindex_ptr")); - return union_store(ctx, addr, ptindex, rhs, cmp, jfty, tbaa, nullptr, ctx.tbaa().tbaa_unionselbyte, + return union_store(ctx, addr, ptindex, rhs, cmp, jfty, tbaa, ctx.tbaa().tbaa_unionselbyte, Order, FailOrder, needlock, issetfield, isreplacefield, isswapfield, ismodifyfield, issetfieldonce, modifyop, fname); diff --git a/src/clangsa/GCChecker.cpp b/src/clangsa/GCChecker.cpp index 97def0fac59f2..9d6bd2e6a9b4b 100644 --- a/src/clangsa/GCChecker.cpp +++ b/src/clangsa/GCChecker.cpp @@ -795,56 +795,53 @@ static bool isMutexUnlock(StringRef name) { false; } -#if LLVM_VERSION_MAJOR >= 13 -#define endswith_lower endswith_insensitive -#endif bool GCChecker::isGCTrackedType(QualType QT) { return isJuliaType( [](StringRef Name) { - if (Name.endswith_lower("jl_value_t") || - Name.endswith_lower("jl_svec_t") || - Name.endswith_lower("jl_sym_t") || - Name.endswith_lower("jl_expr_t") || - Name.endswith_lower("jl_code_info_t") || - Name.endswith_lower("jl_array_t") || - Name.endswith_lower("jl_genericmemory_t") || - //Name.endswith_lower("jl_genericmemoryref_t") || - Name.endswith_lower("jl_method_t") || - Name.endswith_lower("jl_method_instance_t") || - Name.endswith_lower("jl_tupletype_t") || - Name.endswith_lower("jl_datatype_t") || - Name.endswith_lower("jl_typemap_entry_t") || - Name.endswith_lower("jl_typemap_level_t") || - Name.endswith_lower("jl_typename_t") || - Name.endswith_lower("jl_module_t") || - Name.endswith_lower("jl_tupletype_t") || - Name.endswith_lower("jl_gc_tracked_buffer_t") || - Name.endswith_lower("jl_binding_t") || - Name.endswith_lower("jl_ordereddict_t") || - Name.endswith_lower("jl_tvar_t") || - Name.endswith_lower("jl_typemap_t") || - Name.endswith_lower("jl_unionall_t") || - Name.endswith_lower("jl_methtable_t") || - Name.endswith_lower("jl_cgval_t") || - Name.endswith_lower("jl_codectx_t") || - Name.endswith_lower("jl_ast_context_t") || - Name.endswith_lower("jl_code_instance_t") || - Name.endswith_lower("jl_excstack_t") || - Name.endswith_lower("jl_task_t") || - Name.endswith_lower("jl_uniontype_t") || - Name.endswith_lower("jl_method_match_t") || - Name.endswith_lower("jl_vararg_t") || - Name.endswith_lower("jl_opaque_closure_t") || - Name.endswith_lower("jl_globalref_t") || + if (Name.ends_with_insensitive("jl_value_t") || + Name.ends_with_insensitive("jl_svec_t") || + Name.ends_with_insensitive("jl_sym_t") || + Name.ends_with_insensitive("jl_expr_t") || + Name.ends_with_insensitive("jl_code_info_t") || + Name.ends_with_insensitive("jl_array_t") || + Name.ends_with_insensitive("jl_genericmemory_t") || + //Name.ends_with_insensitive("jl_genericmemoryref_t") || + Name.ends_with_insensitive("jl_method_t") || + Name.ends_with_insensitive("jl_method_instance_t") || + Name.ends_with_insensitive("jl_tupletype_t") || + Name.ends_with_insensitive("jl_datatype_t") || + Name.ends_with_insensitive("jl_typemap_entry_t") || + Name.ends_with_insensitive("jl_typemap_level_t") || + Name.ends_with_insensitive("jl_typename_t") || + Name.ends_with_insensitive("jl_module_t") || + Name.ends_with_insensitive("jl_tupletype_t") || + Name.ends_with_insensitive("jl_gc_tracked_buffer_t") || + Name.ends_with_insensitive("jl_binding_t") || + Name.ends_with_insensitive("jl_ordereddict_t") || + Name.ends_with_insensitive("jl_tvar_t") || + Name.ends_with_insensitive("jl_typemap_t") || + Name.ends_with_insensitive("jl_unionall_t") || + Name.ends_with_insensitive("jl_methtable_t") || + Name.ends_with_insensitive("jl_cgval_t") || + Name.ends_with_insensitive("jl_codectx_t") || + Name.ends_with_insensitive("jl_ast_context_t") || + Name.ends_with_insensitive("jl_code_instance_t") || + Name.ends_with_insensitive("jl_excstack_t") || + Name.ends_with_insensitive("jl_task_t") || + Name.ends_with_insensitive("jl_uniontype_t") || + Name.ends_with_insensitive("jl_method_match_t") || + Name.ends_with_insensitive("jl_vararg_t") || + Name.ends_with_insensitive("jl_opaque_closure_t") || + Name.ends_with_insensitive("jl_globalref_t") || // Probably not technically true for these, but let's allow it - Name.endswith_lower("typemap_intersection_env") || - Name.endswith_lower("interpreter_state") || - Name.endswith_lower("jl_typeenv_t") || - Name.endswith_lower("jl_stenv_t") || - Name.endswith_lower("jl_varbinding_t") || - Name.endswith_lower("set_world") || - Name.endswith_lower("jl_codectx_t")) { + Name.ends_with_insensitive("typemap_intersection_env") || + Name.ends_with_insensitive("interpreter_state") || + Name.ends_with_insensitive("jl_typeenv_t") || + Name.ends_with_insensitive("jl_stenv_t") || + Name.ends_with_insensitive("jl_varbinding_t") || + Name.ends_with_insensitive("set_world") || + Name.ends_with_insensitive("jl_codectx_t")) { return true; } return false; diff --git a/src/codegen.cpp b/src/codegen.cpp index 09a2d635737cf..cb1957abf9e04 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3180,22 +3180,16 @@ static jl_cgval_t emit_globalref(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t * if (bp == NULL) return jl_cgval_t(); bp = julia_binding_pvalue(ctx, bp); + jl_value_t *ty = nullptr; if (bnd) { jl_value_t *v = jl_atomic_load_acquire(&bnd->value); // acquire value for ty - if (v != NULL) { - if (bnd->constp) - return mark_julia_const(ctx, v); - LoadInst *v = ctx.builder.CreateAlignedLoad(ctx.types().T_prjlvalue, bp, Align(sizeof(void*))); - setName(ctx.emission_context, v, jl_symbol_name(name)); - v->setOrdering(order); - jl_aliasinfo_t ai = jl_aliasinfo_t::fromTBAA(ctx, ctx.tbaa().tbaa_binding); - ai.decorateInst(v); - jl_value_t *ty = jl_atomic_load_relaxed(&bnd->ty); - return mark_julia_type(ctx, v, true, ty); - } + if (v != NULL && bnd->constp) + return mark_julia_const(ctx, v); + ty = jl_atomic_load_relaxed(&bnd->ty); } - // todo: use type info to avoid undef check - return emit_checked_var(ctx, bp, name, (jl_value_t*)mod, false, ctx.tbaa().tbaa_binding); + if (ty == nullptr) + ty = (jl_value_t*)jl_any_type; + return update_julia_type(ctx, emit_checked_var(ctx, bp, name, (jl_value_t*)mod, false, ctx.tbaa().tbaa_binding), ty); } static jl_cgval_t emit_globalop(jl_codectx_t &ctx, jl_module_t *mod, jl_sym_t *sym, jl_cgval_t rval, const jl_cgval_t &cmp, @@ -3799,6 +3793,8 @@ static bool emit_f_opmemory(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, bool needlock = isatomic && layout->size > MAX_ATOMIC_SIZE; size_t elsz = layout->size; size_t al = layout->alignment; + if (al > JL_HEAP_ALIGNMENT) + al = JL_HEAP_ALIGNMENT; if (isatomic == (order == jl_memory_order_notatomic)) { emit_atomic_error(ctx, issetmemory ? @@ -3876,7 +3872,7 @@ static bool emit_f_opmemory(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, ptindex = emit_bitcast(ctx, ptindex, getInt8PtrTy(ctx.builder.getContext())); ptindex = ctx.builder.CreateInBoundsGEP(getInt8Ty(ctx.builder.getContext()), ptindex, idx0); *ret = union_store(ctx, data, ptindex, val, cmp, ety, - ctx.tbaa().tbaa_arraybuf, nullptr, ctx.tbaa().tbaa_arrayselbyte, + ctx.tbaa().tbaa_arraybuf, ctx.tbaa().tbaa_arrayselbyte, Order, FailOrder, nullptr, issetmemory, isreplacememory, isswapmemory, ismodifymemory, issetmemoryonce, modifyop, fname); @@ -4126,6 +4122,8 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, bool isunion = layout->flags.arrayelem_isunion; size_t elsz = layout->size; size_t al = layout->alignment; + if (al > JL_HEAP_ALIGNMENT) + al = JL_HEAP_ALIGNMENT; bool needlock = isatomic && !isboxed && elsz > MAX_ATOMIC_SIZE; AtomicOrdering Order = (needlock || order <= jl_memory_order_notatomic) ? (isboxed ? AtomicOrdering::Unordered : AtomicOrdering::NotAtomic) @@ -5455,7 +5453,7 @@ static jl_cgval_t emit_isdefined(jl_codectx_t &ctx, jl_value_t *sym) } jl_binding_t *bnd = jl_get_binding(modu, name); if (bnd) { - if (jl_atomic_load_relaxed(&bnd->value) != NULL) + if (jl_atomic_load_acquire(&bnd->value) != NULL && bnd->constp) return mark_julia_const(ctx, jl_true); Value *bp = julia_binding_gv(ctx, bnd); bp = julia_binding_pvalue(ctx, bp); diff --git a/src/gc.c b/src/gc.c index d57bf05145e74..bb63a1725af2e 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1139,6 +1139,12 @@ void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT jl_atomic_load_relaxed(&ptls->gc_num.allocd) + sz); jl_batch_accum_heap_size(ptls, sz); } + +void jl_gc_count_freed(size_t sz) JL_NOTSAFEPOINT +{ + jl_batch_accum_free_size(jl_current_task->ptls, sz); +} + // Only safe to update the heap inside the GC static void combine_thread_gc_counts(jl_gc_num_t *dest, int update_heap) JL_NOTSAFEPOINT { @@ -2311,7 +2317,7 @@ STATIC_INLINE void gc_mark_memory8(jl_ptls_t ptls, jl_value_t *ary8_parent, jl_v pushed_chunk = 1; } } - for (; ary8_begin < ary8_end; ary8_begin += elsize) { + for (; ary8_begin < scan_end; ary8_begin += elsize) { for (uint8_t *pindex = elem_begin; pindex < elem_end; pindex++) { jl_value_t **slot = &ary8_begin[*pindex]; new_obj = *slot; diff --git a/src/gc.h b/src/gc.h index 4bb8828910e6c..4df6aceb80734 100644 --- a/src/gc.h +++ b/src/gc.h @@ -723,8 +723,6 @@ void gc_stats_big_obj(void); // For debugging void gc_count_pool(void); -size_t jl_genericmemory_nbytes(jl_genericmemory_t *a) JL_NOTSAFEPOINT; - JL_DLLEXPORT void jl_enable_gc_logging(int enable); JL_DLLEXPORT int jl_is_gc_logging_enabled(void); JL_DLLEXPORT uint32_t jl_get_num_stack_mappings(void); diff --git a/src/genericmemory.c b/src/genericmemory.c index f0e7b695f1122..ea52fca66ba48 100644 --- a/src/genericmemory.c +++ b/src/genericmemory.c @@ -161,9 +161,9 @@ JL_DLLEXPORT jl_genericmemory_t *jl_ptr_to_genericmemory(jl_value_t *mtype, void m = (jl_genericmemory_t*)jl_gc_alloc(ct->ptls, tsz, mtype); m->ptr = data; m->length = nel; - jl_genericmemory_data_owner_field(m) = NULL; - int isaligned = 0; // TODO: allow passing memalign'd buffers + jl_genericmemory_data_owner_field(m) = own_buffer ? (jl_value_t*)m : NULL; if (own_buffer) { + int isaligned = 0; // TODO: allow passing memalign'd buffers jl_gc_track_malloced_genericmemory(ct->ptls, m, isaligned); jl_gc_count_allocd(nel*elsz); } @@ -208,8 +208,11 @@ JL_DLLEXPORT jl_value_t *jl_genericmemory_to_string(jl_genericmemory_t *m, size_ JL_GC_PUSH1(&o); jl_value_t *str = jl_pchar_to_string((const char*)m->ptr, len); JL_GC_POP(); + if (how == 1) // TODO: we might like to early-call jl_gc_free_memory here instead actually, but hopefully `m` will die soon + jl_gc_count_freed(mlength); return str; } + // n.b. how == 0 is always pool-allocated, so the freed bytes are computed from the pool not the object return jl_pchar_to_string((const char*)m->ptr, len); } diff --git a/src/gf.c b/src/gf.c index d0ed5bdfc2f19..29501883dc041 100644 --- a/src/gf.c +++ b/src/gf.c @@ -767,7 +767,7 @@ static jl_value_t *inst_varargp_in_env(jl_value_t *decl, jl_svec_t *sparams) vm = T_has_tv ? jl_type_unionall(v, T) : T; if (N_has_tv) N = NULL; - vm = (jl_value_t*)jl_wrap_vararg(vm, N, 1); // this cannot throw for these inputs + vm = (jl_value_t*)jl_wrap_vararg(vm, N, 1, 0); // this cannot throw for these inputs } sp++; decl = ((jl_unionall_t*)decl)->body; @@ -1016,7 +1016,7 @@ static void jl_compilation_sig( // avoid Vararg{Type{Type{...}}} if (jl_is_type_type(type_i) && jl_is_type_type(jl_tparam0(type_i))) type_i = (jl_value_t*)jl_type_type; - type_i = (jl_value_t*)jl_wrap_vararg(type_i, (jl_value_t*)NULL, 1); // this cannot throw for these inputs + type_i = (jl_value_t*)jl_wrap_vararg(type_i, (jl_value_t*)NULL, 1, 0); // this cannot throw for these inputs } else { type_i = inst_varargp_in_env(decl, sparams); diff --git a/src/interpreter.c b/src/interpreter.c index 2fb4b91927496..c80986cd7ded0 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -135,10 +135,10 @@ static jl_value_t *do_invoke(jl_value_t **args, size_t nargs, interpreter_state JL_GC_PUSHARGS(argv, nargs - 1); size_t i; for (i = 1; i < nargs; i++) - argv[i] = eval_value(args[i], s); + argv[i-1] = eval_value(args[i], s); jl_method_instance_t *meth = (jl_method_instance_t*)args[0]; assert(jl_is_method_instance(meth)); - jl_value_t *result = jl_invoke(argv[1], &argv[2], nargs - 2, meth); + jl_value_t *result = jl_invoke(argv[0], nargs == 2 ? NULL : &argv[1], nargs - 2, meth); JL_GC_POP(); return result; } diff --git a/src/jloptions.c b/src/jloptions.c index c26c4e26cedd7..634099c66864b 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -108,11 +108,13 @@ static const char usage[] = "\n julia [switches] -- [programfile] [args...]\n static const char opts[] = "Switches (a '*' marks the default value, if applicable; settings marked '($)' may trigger package precompilation):\n\n" " -v, --version Display version information\n" - " -h, --help Print this message (--help-hidden for more)\n" - " --help-hidden Uncommon options not shown by `-h`\n\n" + " -h, --help Print command-line options (this message)\n" + " --help-hidden Print uncommon options not shown by `-h`\n\n" // startup options - " --project[={|@.}] Set as the active project/environment\n" + " --project[={|@.}] Set as the active project/environment.\n" + " The default @. option will search through parent directories\n" + " until a Project.toml or JuliaProject.toml file is found.\n" " -J, --sysimage Start up with the given system image file\n" " -H, --home Set location of `julia` executable\n" " --startup-file={yes*|no} Load `JULIA_DEPOT_PATH/config/startup.jl`; if `JULIA_DEPOT_PATH`\n" @@ -122,8 +124,12 @@ static const char opts[] = " Use native code from system image if available\n" " --compiled-modules={yes*|no|existing|strict}\n" " Enable or disable incremental precompilation of modules\n" + " The `existing` option allows use of existing compiled modules that were\n" + " previously precompiled, but disallows creation of new precompile files.\n" + " The `strict` option is similar, but will error if no precompile file is found.\n" " --pkgimages={yes*|no|existing}\n" - " Enable or disable usage of native code caching in the form of pkgimages ($)\n\n" + " Enable or disable usage of native code caching in the form of pkgimages\n" + " The `existing` option allows use of existing pkgimages but disallows creation of new ones ($)\n\n" // actions " -e, --eval Evaluate \n" @@ -134,7 +140,7 @@ static const char opts[] = " -t, --threads {auto|N[,auto|M]}\n" " Enable N[+M] threads; N threads are assigned to the `default`\n" " threadpool, and if M is specified, M threads are assigned to the\n" - " `interactive` threadpool; \"auto\" tries to infer a useful\n" + " `interactive` threadpool; `auto` tries to infer a useful\n" " default number of threads to use but the exact behavior might change\n" " in the future. Currently sets N to the number of CPUs assigned to\n" " this Julia process based on the OS-specific affinity assignment\n" @@ -144,7 +150,7 @@ static const char opts[] = " --gcthreads=N[,M] Use N threads for the mark phase of GC and M (0 or 1) threads for the concurrent sweeping phase of GC.\n" " N is set to half of the number of compute threads and M is set to 0 if unspecified.\n" " -p, --procs {N|auto} Integer value N launches N additional local worker processes\n" - " \"auto\" launches as many workers as the number of local CPU threads (logical cores)\n" + " `auto` launches as many workers as the number of local CPU threads (logical cores)\n" " --machine-file Run processes on hosts listed in \n\n" // interactive options @@ -162,16 +168,17 @@ static const char opts[] = // code generation options " -C, --cpu-target Limit usage of CPU features up to ; set to `help` to see the available options\n" - " -O, --optimize={0,1,2*,3} Set the optimization level (level 3 if `-O` is used without a level) ($)\n" - " --min-optlevel={0*,1,2,3} Set a lower bound on the optimization level\n" + " -O, --optimize={0|1|2*|3} Set the optimization level (level 3 if `-O` is used without a level) ($)\n" + " --min-optlevel={0*|1|2|3} Set a lower bound on the optimization level\n" #ifdef JL_DEBUG_BUILD - " -g, --debug-info=[{0,1,2*}] Set the level of debug info generation in the julia-debug build ($)\n" + " -g, --debug-info=[{0|1|2*}] Set the level of debug info generation in the julia-debug build ($)\n" #else - " -g, --debug-info=[{0,1*,2}] Set the level of debug info generation (level 2 if `-g` is used without a level) ($)\n" + " -g, --debug-info=[{0|1*|2}] Set the level of debug info generation (level 2 if `-g` is used without a level) ($)\n" #endif " --inline={yes*|no} Control whether inlining is permitted, including overriding @inline declarations\n" " --check-bounds={yes|no|auto*}\n" " Emit bounds checks always, never, or respect @inbounds declarations ($)\n" + " --math-mode={ieee|user*} Always follow `ieee` floating point semantics or respect `@fastmath` declarations\n\n" #ifdef USE_POLLY " --polly={yes*|no} Enable or disable the polyhedral optimizer Polly (overrides @polly declaration)\n" #endif @@ -220,7 +227,7 @@ static const char opts_hidden[] = " --output-asm Generate an assembly file (.s)\n" " --output-incremental={yes|no*}\n" " Generate an incremental output file (rather than complete)\n" - " --trace-compile={stderr,name}\n" + " --trace-compile={stderr|name}\n" " Print precompile statements for methods compiled during execution or save to a path\n" " --image-codegen Force generate code in imaging mode\n" " --permalloc-pkgimg={yes|no*} Copy the data section of package images into memory\n" diff --git a/src/jltypes.c b/src/jltypes.c index 9d238dc27b010..b357172606f30 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -876,14 +876,14 @@ JL_DLLEXPORT jl_value_t *jl_type_unionall(jl_tvar_t *v, jl_value_t *body) if (T_has_tv) { jl_value_t *wrapped = jl_type_unionall(v, vm->T); JL_GC_PUSH1(&wrapped); - wrapped = (jl_value_t*)jl_wrap_vararg(wrapped, vm->N, 1); + wrapped = (jl_value_t*)jl_wrap_vararg(wrapped, vm->N, 1, 0); JL_GC_POP(); return wrapped; } else { assert(N_has_tv); assert(vm->N == (jl_value_t*)v); - return (jl_value_t*)jl_wrap_vararg(vm->T, NULL, 1); + return (jl_value_t*)jl_wrap_vararg(vm->T, NULL, 1, 0); } } if (!jl_is_type(body) && !jl_is_typevar(body)) @@ -1346,7 +1346,7 @@ struct _jl_typestack_t; typedef struct _jl_typestack_t jl_typestack_t; static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, - jl_typestack_t *stack, jl_typeenv_t *env, int check); + jl_typestack_t *stack, jl_typeenv_t *env, int check, int nothrow); // Build an environment mapping a TypeName's parameters to parameter values. // This is the environment needed for instantiating a type's supertype and field types. @@ -1354,7 +1354,7 @@ static jl_value_t *inst_datatype_env(jl_value_t *dt, jl_svec_t *p, jl_value_t ** jl_typestack_t *stack, jl_typeenv_t *env, int c) { if (jl_is_datatype(dt)) - return inst_datatype_inner((jl_datatype_t*)dt, p, iparams, ntp, stack, env, 1); + return inst_datatype_inner((jl_datatype_t*)dt, p, iparams, ntp, stack, env, 1, 0); assert(jl_is_unionall(dt)); jl_unionall_t *ua = (jl_unionall_t*)dt; jl_typeenv_t e = { ua->var, iparams[c], env }; @@ -1478,13 +1478,13 @@ JL_EXTENSION struct _jl_typestack_t { struct _jl_typestack_t *prev; }; -static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check); +static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow); static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *stack, int cacheable); JL_DLLEXPORT jl_value_t *jl_instantiate_unionall(jl_unionall_t *u, jl_value_t *p) { jl_typeenv_t env = { u->var, p, NULL }; - return inst_type_w_(u->body, &env, NULL, 1); + return inst_type_w_(u->body, &env, NULL, 1, 0); } jl_unionall_t *jl_rename_unionall(jl_unionall_t *u) @@ -1493,18 +1493,27 @@ jl_unionall_t *jl_rename_unionall(jl_unionall_t *u) jl_value_t *t = NULL; JL_GC_PUSH2(&v, &t); jl_typeenv_t env = { u->var, (jl_value_t *)v, NULL }; - t = inst_type_w_(u->body, &env, NULL, 0); + t = inst_type_w_(u->body, &env, NULL, 0, 0); t = jl_new_struct(jl_unionall_type, v, t); JL_GC_POP(); return (jl_unionall_t*)t; } +jl_value_t *jl_substitute_var_nothrow(jl_value_t *t, jl_tvar_t *var, jl_value_t *val, int nothrow) +{ + if (val == (jl_value_t*)var) + return t; + nothrow = jl_is_typevar(val) ? 0 : nothrow; + jl_typeenv_t env = { var, val, NULL }; + return inst_type_w_(t, &env, NULL, 1, nothrow); +} + jl_value_t *jl_substitute_var(jl_value_t *t, jl_tvar_t *var, jl_value_t *val) { if (val == (jl_value_t*)var) return t; jl_typeenv_t env = { var, val, NULL }; - return inst_type_w_(t, &env, NULL, 1); + return inst_type_w_(t, &env, NULL, 1, 0); } jl_value_t *jl_unwrap_unionall(jl_value_t *v) @@ -1716,7 +1725,7 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable) dt->hash = typekey_hash(dt->name, jl_svec_data(dt->parameters), l, cacheable); } -static void check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, size_t np) +static int check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, size_t np, int nothrow) { jl_value_t *wrapper = tn->wrapper; jl_value_t **bounds; @@ -1734,6 +1743,10 @@ static void check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, si assert(jl_is_unionall(wrapper)); jl_tvar_t *tv = ((jl_unionall_t*)wrapper)->var; if (!within_typevar(params[i], bounds[2*i], bounds[2*i+1])) { + if (nothrow) { + JL_GC_POP(); + return 1; + } if (tv->lb != bounds[2*i] || tv->ub != bounds[2*i+1]) // pass a new version of `tv` containing the instantiated bounds tv = jl_new_typevar(tv->name, bounds[2*i], bounds[2*i+1]); @@ -1743,12 +1756,26 @@ static void check_datatype_parameters(jl_typename_t *tn, jl_value_t **params, si int j; for (j = 2*i + 2; j < 2*np; j++) { jl_value_t *bj = bounds[j]; - if (bj != (jl_value_t*)jl_any_type && bj != jl_bottom_type) - bounds[j] = jl_substitute_var(bj, tv, params[i]); + if (bj != (jl_value_t*)jl_any_type && bj != jl_bottom_type) { + int isub = j & 1; + // use different nothrow level for lb and ub substitution. + // TODO: This assuming the top instantiation could only start with + // `nothrow == 2` or `nothrow == 0`. If `nothrow` is initially set to 1 + // then we might miss some inner error, perhaps the normal path should + // also follow this rule? + jl_value_t *nb = jl_substitute_var_nothrow(bj, tv, params[i], nothrow ? (isub ? 2 : 1) : 0 ); + if (nb == NULL) { + assert(nothrow); + JL_GC_POP(); + return 1; + } + bounds[j] = nb; + } } wrapper = ((jl_unionall_t*)wrapper)->body; } JL_GC_POP(); + return 0; } static jl_value_t *extract_wrapper(jl_value_t *t JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT JL_GLOBALLY_ROOTED @@ -1868,15 +1895,20 @@ static jl_value_t *normalize_unionalls(jl_value_t *t) } // used to expand an NTuple to a flat representation -static jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *t, int check) +static jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *t, int check, int nothrow) { jl_value_t *p = NULL; JL_GC_PUSH1(&p); if (check) { // Since we are skipping making the Vararg and skipping checks later, // we inline the checks from jl_wrap_vararg here now - if (!jl_valid_type_param(t)) + if (!jl_valid_type_param(t)) { + if (nothrow) { + JL_GC_POP(); + return NULL; + } jl_type_error_rt("Vararg", "type", (jl_value_t*)jl_type_type, t); + } // jl_wrap_vararg sometimes simplifies the type, so we only do this 1 time, instead of for each n later t = normalize_unionalls(t); p = t; @@ -1895,7 +1927,7 @@ static jl_value_t *jl_tupletype_fill(size_t n, jl_value_t *t, int check) static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals, jl_typeenv_t *prev, jl_typestack_t *stack); static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, - jl_typestack_t *stack, jl_typeenv_t *env, int check) + jl_typestack_t *stack, jl_typeenv_t *env, int check, int nothrow) { jl_typestack_t top; jl_typename_t *tn = dt->name; @@ -1926,8 +1958,11 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value break; } } - if (pi == jl_bottom_type) + if (pi == jl_bottom_type) { + if (nothrow) + return NULL; jl_errorf("Tuple field type cannot be Union{}"); + } if (cacheable && !jl_is_concrete_type(pi)) cacheable = 0; } @@ -1987,7 +2022,8 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value // for whether this is even valid if (check && !istuple) { assert(ntp > 0); - check_datatype_parameters(tn, iparams, ntp); + if (check_datatype_parameters(tn, iparams, ntp, nothrow)) + return NULL; } else if (ntp == 0 && jl_emptytuple_type != NULL) { // empty tuple type case @@ -2014,7 +2050,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value if (nt == 0 || !jl_has_free_typevars(va0)) { if (ntp == 1) { JL_GC_POP(); - return jl_tupletype_fill(nt, va0, 0); + return jl_tupletype_fill(nt, va0, 0, 0); } size_t i, l; p = jl_alloc_svec(ntp - 1 + nt); @@ -2023,7 +2059,9 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value l = ntp - 1 + nt; for (; i < l; i++) jl_svecset(p, i, va0); - jl_value_t *ndt = jl_apply_tuple_type(p, check); + size_t np = jl_svec_len(p); + jl_value_t **pp = jl_svec_data(p); + jl_value_t *ndt = inst_datatype_inner(jl_anytuple_type, p, pp, np, NULL, NULL, check, nothrow); JL_GC_POP(); return ndt; } @@ -2122,6 +2160,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value ndt->parameters = p; jl_gc_wb(ndt, ndt->parameters); ndt->types = NULL; // to be filled in below + int invalid = 0; if (istuple) { ndt->types = p; // TODO: this may need to filter out certain types } @@ -2129,26 +2168,41 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value jl_value_t *names_tup = jl_svecref(p, 0); jl_value_t *values_tt = jl_svecref(p, 1); if (!jl_has_free_typevars(names_tup) && !jl_has_free_typevars(values_tt)) { - if (!jl_is_tuple(names_tup)) - jl_type_error_rt("NamedTuple", "names", (jl_value_t*)jl_anytuple_type, names_tup); + if (!jl_is_tuple(names_tup)) { + if (!nothrow) + jl_type_error_rt("NamedTuple", "names", (jl_value_t*)jl_anytuple_type, names_tup); + invalid = 1; + } size_t nf = jl_nfields(names_tup); for (size_t i = 0; i < nf; i++) { jl_value_t *ni = jl_fieldref(names_tup, i); - if (!jl_is_symbol(ni)) - jl_type_error_rt("NamedTuple", "name", (jl_value_t*)jl_symbol_type, ni); + if (!jl_is_symbol(ni)) { + if (!nothrow) + jl_type_error_rt("NamedTuple", "name", (jl_value_t*)jl_symbol_type, ni); + invalid = 1; break; + } for (size_t j = 0; j < i; j++) { - if (ni == jl_fieldref_noalloc(names_tup, j)) - jl_errorf("duplicate field name in NamedTuple: \"%s\" is not unique", jl_symbol_name((jl_sym_t*)ni)); + if (ni == jl_fieldref_noalloc(names_tup, j)) { + if (!nothrow) + jl_errorf("duplicate field name in NamedTuple: \"%s\" is not unique", jl_symbol_name((jl_sym_t*)ni)); + invalid = 1; break; + } } + if (invalid) break; } if (values_tt == jl_bottom_type && nf > 0) { ndt->types = jl_svec_fill(nf, jl_bottom_type); } else { - if (!jl_is_datatype(values_tt)) + if (!jl_is_datatype(values_tt)) { + // should have been checked within `check_datatype_parameters`. jl_error("NamedTuple field type must be a tuple datatype"); - if (jl_is_va_tuple((jl_datatype_t*)values_tt) || jl_nparams(values_tt) != nf) - jl_error("NamedTuple names and field types must have matching lengths"); + } + if (jl_is_va_tuple((jl_datatype_t*)values_tt) || jl_nparams(values_tt) != nf) { + if (!nothrow) + jl_error("NamedTuple names and field types must have matching lengths"); + invalid = 1; + } ndt->types = ((jl_datatype_t*)values_tt)->parameters; } jl_gc_wb(ndt, ndt->types); @@ -2159,13 +2213,25 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value } else if (tn == jl_genericmemoryref_typename || tn == jl_genericmemory_typename) { jl_value_t *isatomic = jl_svecref(p, 0); - if (!jl_is_typevar(isatomic) && !jl_is_symbol(isatomic)) - jl_type_error_rt("GenericMemory", "isatomic parameter", (jl_value_t*)jl_symbol_type, isatomic); + if (!jl_is_typevar(isatomic) && !jl_is_symbol(isatomic)) { + if (!nothrow) + jl_type_error_rt("GenericMemory", "isatomic parameter", (jl_value_t*)jl_symbol_type, isatomic); + invalid = 1; + } jl_value_t *addrspace = jl_svecref(p, 2); - if (!jl_is_typevar(addrspace) && !jl_is_addrspace(addrspace)) - jl_type_error_rt("GenericMemory", "addrspace parameter", (jl_value_t*)jl_addrspace_type, addrspace); + if (!jl_is_typevar(addrspace) && !jl_is_addrspace(addrspace)) { + if (!nothrow) + jl_type_error_rt("GenericMemory", "addrspace parameter", (jl_value_t*)jl_addrspace_type, addrspace); + invalid = 1; + } } + if (nothrow && invalid) { + if (cacheable) + JL_UNLOCK(&typecache_lock); + JL_GC_POP(); + return NULL; + } jl_datatype_t *primarydt = ((jl_datatype_t*)jl_unwrap_unionall(tn->wrapper)); jl_precompute_memoized_dt(ndt, cacheable); if (primarydt->layout) @@ -2175,7 +2241,14 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value ndt->super = jl_any_type; } else if (dt->super) { - ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)dt->super, env, stack, check); + jl_value_t *super = inst_type_w_((jl_value_t*)dt->super, env, stack, check, nothrow); + if (nothrow && super == NULL) { + if (cacheable) + JL_UNLOCK(&typecache_lock); + JL_GC_POP(); + return NULL; + } + ndt->super = (jl_datatype_t *)super; jl_gc_wb(ndt, ndt->super); } jl_svec_t *ftypes = dt->types; @@ -2223,7 +2296,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value static jl_value_t *jl_apply_tuple_type_v_(jl_value_t **p, size_t np, jl_svec_t *params, int check) { - return inst_datatype_inner(jl_anytuple_type, params, p, np, NULL, NULL, check); + return inst_datatype_inner(jl_anytuple_type, params, p, np, NULL, NULL, check, 0); } JL_DLLEXPORT jl_value_t *jl_apply_tuple_type(jl_svec_t *params, int check) @@ -2262,7 +2335,7 @@ jl_tupletype_t *jl_inst_arg_tuple_type(jl_value_t *arg1, jl_value_t **args, size } jl_svecset(params, i, ai); } - tt = (jl_datatype_t*)inst_datatype_inner(jl_anytuple_type, params, jl_svec_data(params), nargs, NULL, NULL, 1); + tt = (jl_datatype_t*)inst_datatype_inner(jl_anytuple_type, params, jl_svec_data(params), nargs, NULL, NULL, 1, 0); JL_GC_POP(); } return tt; @@ -2278,7 +2351,7 @@ static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *s for (i = 0; i < lp; i++) { pi = jl_svecref(p, i); JL_TRY { - pi = inst_type_w_(pi, env, stack, 1); + pi = inst_type_w_(pi, env, stack, 1, 0); if (!jl_is_type(pi) && !jl_is_typevar(pi)) { pi = jl_bottom_type; } @@ -2293,7 +2366,7 @@ static jl_svec_t *inst_ftypes(jl_svec_t *p, jl_typeenv_t *env, jl_typestack_t *s return np; } -static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check) +static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow) { jl_datatype_t *tt = (jl_datatype_t*)t; jl_svec_t *tp = tt->parameters; @@ -2320,9 +2393,11 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ if (T != NULL && N != NULL && jl_is_long(N)) { // TODO: && !jl_has_free_typevars(T) to match inst_datatype_inner, or even && jl_is_concrete_type(T) // Since this is skipping jl_wrap_vararg, we inline the checks from it here ssize_t nt = jl_unbox_long(N); - if (nt < 0) - jl_errorf("Vararg length is negative: %zd", nt); - return jl_tupletype_fill(nt, T, check); + if (nt >= 0) + return jl_tupletype_fill(nt, T, check, nothrow); + if (nothrow) + return NULL; + jl_errorf("Vararg length is negative: %zd", nt); } } jl_value_t **iparams; @@ -2334,23 +2409,36 @@ static jl_value_t *inst_tuple_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_ iparams[0] = (jl_value_t*)ip_heap; iparams = jl_svec_data(ip_heap); } - int bound = 0; - int i; + int i, bound = 0; for (i = 0; i < ntp; i++) { jl_value_t *elt = jl_svecref(tp, i); - jl_value_t *pi = inst_type_w_(elt, env, stack, check); + jl_value_t *pi = inst_type_w_(elt, env, stack, check, nothrow); + if (pi == NULL) { + assert(nothrow); + if (nothrow == 1 || (i == ntp-1 && jl_is_vararg(elt))) { + t = NULL; + break; + } + else { + pi = jl_bottom_type; + } + } iparams[i] = pi; if (ip_heap) jl_gc_wb(ip_heap, pi); bound |= (pi != elt); } - if (bound) - t = inst_datatype_inner(tt, ip_heap, iparams, ntp, stack, env, check); + if (t != NULL && bound) + t = inst_datatype_inner(tt, ip_heap, iparams, ntp, stack, env, check, nothrow); JL_GC_POP(); return t; } -static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check) +// `nothrow` means that when type checking fails, the type instantiation should +// return `NULL` instead of immediately throwing an error. If `nothrow` == 2 then +// we further assume that the imprecise instantiation for non invariant parameters +// is acceptable, and inner error (`NULL`) would be ignored. +static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t *stack, int check, int nothrow) { size_t i; if (jl_is_typevar(t)) { @@ -2370,42 +2458,73 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t jl_value_t *var = NULL; jl_value_t *newbody = NULL; JL_GC_PUSH3(&lb, &var, &newbody); - lb = inst_type_w_(ua->var->lb, env, stack, check); - var = inst_type_w_(ua->var->ub, env, stack, check); - if (lb != ua->var->lb || var != ua->var->ub) { - var = (jl_value_t*)jl_new_typevar(ua->var->name, lb, var); - } - else { - var = (jl_value_t*)ua->var; - } - jl_typeenv_t newenv = { ua->var, var, env }; - newbody = inst_type_w_(ua->body, &newenv, stack, check); - if (newbody == (jl_value_t*)jl_emptytuple_type) { - // NTuple{0} => Tuple{} can make a typevar disappear - t = (jl_value_t*)jl_emptytuple_type; + // set nothrow <= 1 to ensure lb's accuracy. + lb = inst_type_w_(ua->var->lb, env, stack, check, nothrow ? 1 : 0); + if (lb == NULL) { + assert(nothrow); + t = NULL; + } + if (t != NULL) { + var = inst_type_w_(ua->var->ub, env, stack, check, nothrow); + if (var == NULL) { + if (lb == jl_bottom_type) + var = jl_bottom_type; + else + t = NULL; + } + else if (lb != ua->var->lb || var != ua->var->ub) { + var = (jl_value_t*)jl_new_typevar(ua->var->name, lb, var); + } + else { + var = (jl_value_t*)ua->var; + } } - else if (newbody != ua->body || var != (jl_value_t*)ua->var) { - // if t's parameters are not bound in the environment, return it uncopied (#9378) - t = jl_new_struct(jl_unionall_type, var, newbody); + if (t != NULL) { + jl_typeenv_t newenv = { ua->var, var, env }; + newbody = inst_type_w_(ua->body, &newenv, stack, check, nothrow); + if (newbody == NULL) { + t = NULL; + } + else if (!jl_has_typevar(newbody, (jl_tvar_t *)var)) { + // inner instantiation might make a typevar disappear, e.g. + // NTuple{0,T} => Tuple{} + t = newbody; + } + else if (newbody != ua->body || var != (jl_value_t*)ua->var) { + // if t's parameters are not bound in the environment, return it uncopied (#9378) + t = jl_new_struct(jl_unionall_type, var, newbody); + } } JL_GC_POP(); return t; } if (jl_is_uniontype(t)) { jl_uniontype_t *u = (jl_uniontype_t*)t; - jl_value_t *a = inst_type_w_(u->a, env, stack, check); + jl_value_t *a = inst_type_w_(u->a, env, stack, check, nothrow); jl_value_t *b = NULL; JL_GC_PUSH2(&a, &b); - b = inst_type_w_(u->b, env, stack, check); + b = inst_type_w_(u->b, env, stack, check, nothrow); + if (nothrow) { + // ensure jl_type_union nothrow. + if (a && !(jl_is_typevar(a) || jl_is_type(a))) + a = NULL; + if (b && !(jl_is_typevar(b) || jl_is_type(b))) + b = NULL; + } if (a != u->a || b != u->b) { - if (check) { - jl_value_t *uargs[2] = {a, b}; - t = jl_type_union(uargs, 2); - } - else { + if (!check) { // fast path for `jl_rename_unionall`. t = jl_new_struct(jl_uniontype_type, a, b); } + else if (a == NULL || b == NULL) { + assert(nothrow); + t = nothrow == 1 ? NULL : a == NULL ? b : a; + } + else { + assert(a != NULL && b != NULL); + jl_value_t *uargs[2] = {a, b}; + t = jl_type_union(uargs, 2); + } } JL_GC_POP(); return t; @@ -2416,13 +2535,22 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t jl_value_t *N = NULL; JL_GC_PUSH2(&T, &N); if (v->T) { - T = inst_type_w_(v->T, env, stack, check); - if (v->N) - N = inst_type_w_(v->N, env, stack, check); - } - if (T != v->T || N != v->N) { - t = (jl_value_t*)jl_wrap_vararg(T, N, check); + T = inst_type_w_(v->T, env, stack, check, nothrow); + if (T == NULL) { + if (nothrow == 2) + T = jl_bottom_type; + else + t = NULL; + } + if (t && v->N) { + // set nothrow <= 1 to ensure invariant parameter's accuracy. + N = inst_type_w_(v->N, env, stack, check, nothrow ? 1 : 0); + if (N == NULL) + t = NULL; + } } + if (t && (T != v->T || N != v->N)) + t = (jl_value_t*)jl_wrap_vararg(T, N, check, nothrow); JL_GC_POP(); return t; } @@ -2434,20 +2562,26 @@ static jl_value_t *inst_type_w_(jl_value_t *t, jl_typeenv_t *env, jl_typestack_t return t; jl_typename_t *tn = tt->name; if (tn == jl_tuple_typename) - return inst_tuple_w_(t, env, stack, check); + return inst_tuple_w_(t, env, stack, check, nothrow); size_t ntp = jl_svec_len(tp); jl_value_t **iparams; JL_GC_PUSHARGS(iparams, ntp); int bound = 0; for (i = 0; i < ntp; i++) { jl_value_t *elt = jl_svecref(tp, i); - jl_value_t *pi = inst_type_w_(elt, env, stack, check); + // set nothrow <= 1 to ensure invariant parameter's accuracy. + jl_value_t *pi = inst_type_w_(elt, env, stack, check, nothrow ? 1 : 0); + if (pi == NULL) { + assert(nothrow); + t = NULL; + break; + } iparams[i] = pi; bound |= (pi != elt); } // if t's parameters are not bound in the environment, return it uncopied (#9378) - if (bound) - t = inst_datatype_inner(tt, NULL, iparams, ntp, stack, env, check); + if (t != NULL && bound) + t = inst_datatype_inner(tt, NULL, iparams, ntp, stack, env, check, nothrow); JL_GC_POP(); return t; } @@ -2458,7 +2592,7 @@ static jl_value_t *instantiate_with(jl_value_t *t, jl_value_t **env, size_t n, j jl_typeenv_t en = { (jl_tvar_t*)env[0], env[1], te }; return instantiate_with(t, &env[2], n-1, &en ); } - return inst_type_w_(t, te, NULL, 1); + return inst_type_w_(t, te, NULL, 1, 0); } jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n) @@ -2472,7 +2606,7 @@ static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *en if (jl_is_unionall(env->body)) return _jl_instantiate_type_in_env(ty, (jl_unionall_t*)env->body, vals + 1, &en, stack); else - return inst_type_w_(ty, &en, stack, 1); + return inst_type_w_(ty, &en, stack, 1, 0); } JL_DLLEXPORT jl_value_t *jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals) @@ -2494,8 +2628,10 @@ jl_datatype_t *jl_wrap_Type(jl_value_t *t) return (jl_datatype_t*)jl_instantiate_unionall(jl_type_type, t); } -jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check) +jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check, int nothrow) { + int valid = 1; + jl_vararg_t *vm = NULL; jl_task_t *ct = jl_current_task; JL_GC_PUSH1(&t); if (check) { @@ -2506,30 +2642,44 @@ jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check) // values and not the bounds of variables. /* jl_tvar_t *N = (jl_tvar_t*)n; - if (!(N->lb == jl_bottom_type && N->ub == (jl_value_t*)jl_any_type)) - jl_error("TypeVar in Vararg length must have bounds Union{} and Any"); + if (valid && !(N->lb == jl_bottom_type && N->ub == (jl_value_t*)jl_any_type)) { + if (!nothrow) + jl_error("TypeVar in Vararg length must have bounds Union{} and Any"); + invalid = 1; + } */ } - else if (!jl_is_long(n)) { - jl_type_error_rt("Vararg", "count", (jl_value_t*)jl_long_type, n); + else if (valid && !jl_is_long(n)) { + if (!nothrow) + jl_type_error_rt("Vararg", "count", (jl_value_t*)jl_long_type, n); + valid = 0; } - else if (jl_unbox_long(n) < 0) { - jl_errorf("Vararg length is negative: %zd", jl_unbox_long(n)); + else if (valid && jl_unbox_long(n) < 0) { + if (!nothrow) + jl_errorf("Vararg length is negative: %zd", jl_unbox_long(n)); + valid = 0; } } if (t) { - if (!jl_valid_type_param(t)) - jl_type_error_rt("Vararg", "type", (jl_value_t*)jl_type_type, t); - t = normalize_unionalls(t); - jl_value_t *tw = extract_wrapper(t); - if (tw && t != tw && jl_types_equal(t, tw)) - t = tw; - } - } - jl_vararg_t *vm = (jl_vararg_t *)jl_gc_alloc(ct->ptls, sizeof(jl_vararg_t), jl_vararg_type); - jl_set_typetagof(vm, jl_vararg_tag, 0); - vm->T = t; - vm->N = n; + if (valid && !jl_valid_type_param(t)) { + if (!nothrow) + jl_type_error_rt("Vararg", "type", (jl_value_t*)jl_type_type, t); + valid = 0; + } + if (valid) { + t = normalize_unionalls(t); + jl_value_t *tw = extract_wrapper(t); + if (tw && t != tw && jl_types_equal(t, tw)) + t = tw; + } + } + } + if (valid) { + vm = (jl_vararg_t *)jl_gc_alloc(ct->ptls, sizeof(jl_vararg_t), jl_vararg_type); + jl_set_typetagof(vm, jl_vararg_tag, 0); + vm->T = t; + vm->N = n; + } JL_GC_POP(); return vm; } @@ -2590,7 +2740,7 @@ void jl_reinstantiate_inner_types(jl_datatype_t *t) // can throw! for (i = 0; i < n; i++) env[i].val = jl_svecref(ndt->parameters, i); - ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)t->super, &env[n - 1], &top, 1); + ndt->super = (jl_datatype_t*)inst_type_w_((jl_value_t*)t->super, &env[n - 1], &top, 1, 0); jl_gc_wb(ndt, ndt->super); } @@ -2814,7 +2964,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_vararg_type->name->mayinlinealloc = 0; jl_vararg_type->ismutationfree = 1; - jl_svec_t *anytuple_params = jl_svec(1, jl_wrap_vararg((jl_value_t*)jl_any_type, (jl_value_t*)NULL, 0)); + jl_svec_t *anytuple_params = jl_svec(1, jl_wrap_vararg((jl_value_t*)jl_any_type, (jl_value_t*)NULL, 0, 0)); jl_anytuple_type = jl_new_datatype(jl_symbol("Tuple"), core, jl_any_type, anytuple_params, jl_emptysvec, anytuple_params, jl_emptysvec, 0, 0, 0); jl_tuple_typename = jl_anytuple_type->name; @@ -3040,7 +3190,7 @@ void jl_init_types(void) JL_GC_DISABLED jl_perm_symsvec(2, "ref", "size"), jl_svec(2, jl_apply_type3((jl_value_t*)jl_genericmemoryref_type, (jl_value_t*)jl_not_atomic_sym, jl_svecref(tv, 0), cpumem), - jl_apply_type1((jl_value_t*)jl_tuple_type, (jl_value_t*)jl_wrap_vararg((jl_value_t*)jl_long_type, jl_svecref(tv, 1), 0))), + jl_apply_type1((jl_value_t*)jl_tuple_type, (jl_value_t*)jl_wrap_vararg((jl_value_t*)jl_long_type, jl_svecref(tv, 1), 0, 0))), jl_emptysvec, 0, 1, 2)->name; jl_array_type = (jl_unionall_t*)jl_array_typename->wrapper; diff --git a/src/julia.h b/src/julia.h index 602d7e5c4318d..c6b685733ea30 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1148,8 +1148,8 @@ STATIC_INLINE jl_value_t *jl_svecset( /* how - allocation style 0 = data is inlined - 1 = owns the gc-managed data, exclusively - 2 = malloc-allocated pointer (may or may not own it) + 1 = owns the gc-managed data, exclusively (will free it) + 2 = malloc-allocated pointer (does not own it) 3 = has a pointer to the object that owns the data pointer */ STATIC_INLINE int jl_genericmemory_how(jl_genericmemory_t *m) JL_NOTSAFEPOINT diff --git a/src/julia_internal.h b/src/julia_internal.h index 67324299bfb1e..81888f01cc95e 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -615,7 +615,9 @@ JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void) JL_NOTSAFEPOINT; JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset) JL_NOTSAFEPOINT; void jl_gc_track_malloced_array(jl_ptls_t ptls, jl_array_t *a) JL_NOTSAFEPOINT; void jl_gc_track_malloced_genericmemory(jl_ptls_t ptls, jl_genericmemory_t *m, int isaligned) JL_NOTSAFEPOINT; +size_t jl_genericmemory_nbytes(jl_genericmemory_t *a) JL_NOTSAFEPOINT; void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT; +void jl_gc_count_freed(size_t sz) JL_NOTSAFEPOINT; void jl_gc_run_all_finalizers(jl_task_t *ct); void jl_release_task_stack(jl_ptls_t ptls, jl_task_t *task); void jl_gc_add_finalizer_(jl_ptls_t ptls, void *v, void *f) JL_NOTSAFEPOINT; @@ -759,6 +761,7 @@ JL_DLLEXPORT int jl_type_morespecific_no_subtype(jl_value_t *a, jl_value_t *b); jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n); JL_DLLEXPORT jl_value_t *jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals); jl_value_t *jl_substitute_var(jl_value_t *t, jl_tvar_t *var, jl_value_t *val); +jl_value_t *jl_substitute_var_nothrow(jl_value_t *t, jl_tvar_t *var, jl_value_t *val, int nothrow); jl_unionall_t *jl_rename_unionall(jl_unionall_t *u); JL_DLLEXPORT jl_value_t *jl_unwrap_unionall(jl_value_t *v JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_rewrap_unionall(jl_value_t *t, jl_value_t *u); @@ -771,7 +774,7 @@ jl_datatype_t *jl_new_abstracttype(jl_value_t *name, jl_module_t *module, jl_datatype_t *jl_new_uninitialized_datatype(void); void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable); JL_DLLEXPORT jl_datatype_t *jl_wrap_Type(jl_value_t *t); // x -> Type{x} -jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check); +jl_vararg_t *jl_wrap_vararg(jl_value_t *t, jl_value_t *n, int check, int nothrow); void jl_reinstantiate_inner_types(jl_datatype_t *t); jl_datatype_t *jl_lookup_cache_type_(jl_datatype_t *type); void jl_cache_type_(jl_datatype_t *type); diff --git a/src/passes.h b/src/passes.h index 9c3b0421670b5..6557a5813063d 100644 --- a/src/passes.h +++ b/src/passes.h @@ -64,7 +64,7 @@ struct RemoveNIPass : PassInfoMixin { struct MultiVersioningPass : PassInfoMixin { bool external_use; - MultiVersioningPass(bool external_use = false) : external_use(external_use) {} + MultiVersioningPass(bool external_use = false) JL_NOTSAFEPOINT : external_use(external_use) {} PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) JL_NOTSAFEPOINT; static bool isRequired() { return true; } }; diff --git a/src/pipeline.cpp b/src/pipeline.cpp index aafce01856634..8fbc6be6026c4 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -189,10 +189,11 @@ namespace { // } } -#ifdef JL_DEBUG_BUILD +#ifdef JL_VERIFY_PASSES static inline void addVerificationPasses(ModulePassManager &MPM, bool llvm_only) JL_NOTSAFEPOINT { - if (!llvm_only) - MPM.addPass(llvm::createModuleToFunctionPassAdaptor(GCInvariantVerifierPass())); + if (!llvm_only){ + MPM.addPass(llvm::createModuleToFunctionPassAdaptor(GCInvariantVerifierPass(true))); + } MPM.addPass(VerifierPass()); } #endif @@ -332,7 +333,7 @@ namespace { static void buildEarlySimplificationPipeline(ModulePassManager &MPM, PassBuilder *PB, OptimizationLevel O, const OptimizationOptions &options) JL_NOTSAFEPOINT { MPM.addPass(BeforeEarlySimplificationMarkerPass()); -#ifdef JL_DEBUG_BUILD +#ifdef JL_VERIFY_PASSES addVerificationPasses(MPM, options.llvm_only); #endif if (options.enable_early_simplifications) { diff --git a/src/scheduler.c b/src/scheduler.c index 8b778b877e025..e95c221548f9e 100644 --- a/src/scheduler.c +++ b/src/scheduler.c @@ -129,7 +129,12 @@ void jl_parallel_gc_threadfun(void *arg) // initialize this thread (set tid and create heap) jl_ptls_t ptls = jl_init_threadtls(targ->tid); - + void *stack_lo, *stack_hi; + jl_init_stack_limits(0, &stack_lo, &stack_hi); + // warning: this changes `jl_current_task`, so be careful not to call that from this function + jl_task_t *ct = jl_init_root_task(ptls, stack_lo, stack_hi); + JL_GC_PROMISE_ROOTED(ct); + (void)jl_atomic_fetch_add_relaxed(&nrunning, -1); // wait for all threads jl_gc_state_set(ptls, JL_GC_STATE_WAITING, JL_GC_STATE_UNSAFE); uv_barrier_wait(targ->barrier); @@ -158,7 +163,12 @@ void jl_concurrent_gc_threadfun(void *arg) // initialize this thread (set tid and create heap) jl_ptls_t ptls = jl_init_threadtls(targ->tid); - + void *stack_lo, *stack_hi; + jl_init_stack_limits(0, &stack_lo, &stack_hi); + // warning: this changes `jl_current_task`, so be careful not to call that from this function + jl_task_t *ct = jl_init_root_task(ptls, stack_lo, stack_hi); + JL_GC_PROMISE_ROOTED(ct); + (void)jl_atomic_fetch_add_relaxed(&nrunning, -1); // wait for all threads jl_gc_state_set(ptls, JL_GC_STATE_WAITING, JL_GC_STATE_UNSAFE); uv_barrier_wait(targ->barrier); diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 9542e54182644..05fce7cfc4630 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -1255,7 +1255,8 @@ static void jl_insert_backedges(jl_array_t *edges, jl_array_t *ext_targets, jl_a JL_GC_PROMISE_ROOTED(owner); assert(jl_atomic_load_relaxed(&codeinst->min_world) == minworld); - assert(jl_atomic_load_relaxed(&codeinst->max_world) == WORLD_AGE_REVALIDATION_SENTINEL); + // See #53586, #53109 + // assert(jl_atomic_load_relaxed(&codeinst->max_world) == WORLD_AGE_REVALIDATION_SENTINEL); assert(jl_atomic_load_relaxed(&codeinst->inferred)); jl_atomic_store_relaxed(&codeinst->max_world, maxvalid); diff --git a/src/subtype.c b/src/subtype.c index 8b2c696476061..688a39ca87ef0 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -87,6 +87,14 @@ typedef struct jl_varbinding_t { struct jl_varbinding_t *prev; } jl_varbinding_t; +typedef struct jl_ivarbinding_t { + jl_tvar_t **var; + jl_value_t **lb; + jl_value_t **ub; + jl_varbinding_t *root; + struct jl_ivarbinding_t *next; +} jl_ivarbinding_t; + // subtype algorithm state typedef struct jl_stenv_t { // N.B.: varbindings are created on the stack and rooted there @@ -972,7 +980,7 @@ static int subtype_unionall(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8 if (R && ans && e->envidx < e->envsz) { jl_value_t *val; if (vb.intvalued && vb.lb == (jl_value_t*)jl_any_type) - val = (jl_value_t*)jl_wrap_vararg(NULL, NULL, 0); // special token result that represents N::Int in the envout + val = (jl_value_t*)jl_wrap_vararg(NULL, NULL, 0, 0); // special token result that represents N::Int in the envout else if (!vb.occurs_inv && vb.lb != jl_bottom_type) val = is_leaf_bound(vb.lb) ? vb.lb : (jl_value_t*)jl_new_typevar(u->var->name, jl_bottom_type, vb.lb); else if (vb.lb == vb.ub) @@ -1307,6 +1315,8 @@ static int subtype_tuple(jl_datatype_t *xd, jl_datatype_t *yd, jl_stenv_t *e, in return ans; } +static int try_subtype_by_bounds(jl_value_t *a, jl_value_t *b, jl_stenv_t *e); + // `param` means we are currently looking at a parameter of a type constructor // (as opposed to being outside any type constructor, or comparing variable bounds). // this is used to record the positions where type variables occur for the @@ -1357,7 +1367,8 @@ static int subtype(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int param) if (yy) record_var_occurrence(yy, e, param); if (yr) { record_var_occurrence(xx, e, param); - return subtype(xx->lb, yy->ub, e, 0); + int trysub = e->intersection ? try_subtype_by_bounds(xx->lb, yy->ub, e) : 0; + return trysub || subtype(xx->lb, yy->ub, e, 0); } return var_lt((jl_tvar_t*)x, y, e, param); } @@ -2489,7 +2500,7 @@ static jl_value_t *bound_var_below(jl_tvar_t *tv, jl_varbinding_t *bb, jl_stenv_ static int subtype_by_bounds(jl_value_t *x, jl_value_t *y, jl_stenv_t *e) JL_NOTSAFEPOINT; -// similar to `subtype_by_bounds`, used to avoid stack-overflow caused by circulation constraints. +// similar to `subtype_by_bounds`, used to avoid stack-overflow caused by circular constraints. static int try_subtype_by_bounds(jl_value_t *a, jl_value_t *b, jl_stenv_t *e) { if (jl_is_uniontype(a)) @@ -2498,22 +2509,21 @@ static int try_subtype_by_bounds(jl_value_t *a, jl_value_t *b, jl_stenv_t *e) else if (jl_is_uniontype(b)) return try_subtype_by_bounds(a, ((jl_uniontype_t *)b)->a, e) || try_subtype_by_bounds(a, ((jl_uniontype_t *)b)->b, e); - else if (jl_egal(a, b)) + else if (a == jl_bottom_type || b == (jl_value_t *)jl_any_type || obviously_egal(a, b)) return 1; else if (!jl_is_typevar(b)) return 0; - jl_varbinding_t *vb = e->vars; - while (vb != NULL) { - if (subtype_by_bounds(b, (jl_value_t *)vb->var, e) && obviously_in_union(a, vb->ub)) - return 1; - vb = vb->prev; - } - return 0; + else if (jl_is_typevar(a) && subtype_by_bounds(a, b, e)) + return 1; + // check if `Union{a, ...} <: b`. + jl_varbinding_t *vb = lookup(e, (jl_tvar_t *)b); + jl_value_t *blb = vb ? vb->lb : ((jl_tvar_t *)b)->lb; + return obviously_in_union(a, blb); } static int try_subtype_in_env(jl_value_t *a, jl_value_t *b, jl_stenv_t *e) { - if (a == jl_bottom_type || b == (jl_value_t *)jl_any_type || try_subtype_by_bounds(a, b, e)) + if (try_subtype_by_bounds(a, b, e)) return 1; jl_savedenv_t se; save_env(e, &se, 1); @@ -2774,12 +2784,9 @@ static jl_value_t *omit_bad_union(jl_value_t *u, jl_tvar_t *t) res = jl_bottom_type; } else if (obviously_egal(var->lb, ub)) { - JL_TRY { - res = jl_substitute_var(body, var, ub); - } - JL_CATCH { + res = jl_substitute_var_nothrow(body, var, ub, 2); + if (res == NULL) res = jl_bottom_type; - } } else { if (ub != var->ub) { @@ -2811,8 +2818,8 @@ static jl_value_t *omit_bad_union(jl_value_t *u, jl_tvar_t *t) static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbinding_t *vb, jl_unionall_t *u, jl_stenv_t *e) { jl_value_t *varval = NULL, *ilb = NULL, *iub = NULL, *nivar = NULL; - jl_tvar_t *newvar = vb->var; - JL_GC_PUSH5(&res, &newvar, &ilb, &iub, &nivar); + jl_tvar_t *newvar = vb->var, *ivar = NULL; + JL_GC_PUSH6(&res, &newvar, &ivar, &nivar, &ilb, &iub); // try to reduce var to a single value if (jl_is_long(vb->ub) && jl_is_typevar(vb->lb)) { varval = vb->ub; @@ -2845,245 +2852,270 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind if (!varval && (vb->lb != vb->var->lb || vb->ub != vb->var->ub)) newvar = jl_new_typevar(vb->var->name, vb->lb, vb->ub); - // remove/replace/rewrap free occurrences of this var in the environment - - // I. Handle indirect innervars (make them behave like direct innervars). - // 1) record if btemp->lb/ub has indirect innervars. - // 2) substitute `vb->var` with `varval`/`newvar` - // note: We only store the innervar in the outmost `varbinding`, - // thus we must check all inner env to ensure the recording/substitution - // is complete - int len = current_env_length(e); - int8_t *blinding_has_innerdep = (int8_t *)alloca(len); - memset(blinding_has_innerdep, 0, len); + // flatten all innervar into a (revered) list + size_t icount = 0; + if (vb->innervars) + icount += jl_array_nrows(vb->innervars); for (jl_varbinding_t *btemp = e->vars; btemp != NULL; btemp = btemp->prev) { - if (btemp->innervars != NULL) { - for (size_t i = 0; i < jl_array_len(btemp->innervars); i++) { - jl_tvar_t *ivar = (jl_tvar_t*)jl_array_ptr_ref(btemp->innervars, i); - ilb = ivar->lb; iub = ivar->ub; - int has_innerdep = 0; - if (jl_has_typevar(ilb, vb->var)) { - has_innerdep = 1; - if (varval) { - JL_TRY { - ilb = jl_substitute_var(ilb, vb->var, varval); - } - JL_CATCH { - res = jl_bottom_type; - } - } - else if (newvar != vb->var) { - ilb = jl_substitute_var(ilb, vb->var, (jl_value_t*)newvar); - } - } - if (jl_has_typevar(iub, vb->var)) { - has_innerdep = 1; - if (varval) { - JL_TRY { - iub = jl_substitute_var(iub, vb->var, varval); - } - JL_CATCH { - res = jl_bottom_type; - } - } - else if (newvar != vb->var) { - iub = jl_substitute_var(iub, vb->var, (jl_value_t*)newvar); - } - } - if (!has_innerdep) continue; - int need_substitution = 0; - if (ilb != ivar->lb || iub != ivar->ub) { - need_substitution = 1; - nivar = (jl_value_t *)jl_new_typevar(ivar->name, ilb, iub); - jl_array_ptr_set(btemp->innervars, i, nivar); - if (jl_has_typevar(res, ivar)) - res = jl_substitute_var(res, ivar, nivar); - } - int envind = 0; - for (jl_varbinding_t *btemp2 = e->vars; btemp2 != btemp->prev; btemp2 = btemp2->prev) { - if (jl_has_typevar(btemp2->lb, ivar)) { - if (need_substitution) - btemp2->lb = jl_substitute_var(btemp2->lb, ivar, nivar); - blinding_has_innerdep[envind] |= 1; - } - if (jl_has_typevar(btemp2->ub, ivar)) { - if (need_substitution) - btemp2->ub = jl_substitute_var(btemp2->ub, ivar, nivar); - blinding_has_innerdep[envind] |= 2; - } - envind++; - } - // FIXME: innervar that depend on `ivar` should also be updated. - } + if (btemp->innervars != NULL) + icount += jl_array_nrows(btemp->innervars); + } + jl_svec_t *p = NULL; + jl_value_t **iparams; + jl_value_t **roots; + JL_GC_PUSHARGS(roots, icount < 22 ? 3*icount : 1); + if (icount < 22) { + iparams = roots; + } + else { + p = jl_alloc_svec(3*icount); + roots[0] = (jl_value_t*)p; + iparams = jl_svec_data(p); + } + jl_ivarbinding_t *allvars = NULL; + size_t niparams = 0; + if (vb->innervars) { + for (size_t i = 0; i < jl_array_nrows(vb->innervars); i++) { + jl_tvar_t *ivar = (jl_tvar_t *)jl_array_ptr_ref(vb->innervars, i); + jl_ivarbinding_t *inew = (jl_ivarbinding_t *)alloca(sizeof(jl_ivarbinding_t)); + inew->var = (jl_tvar_t **)&iparams[niparams++]; *inew->var = ivar; + inew->lb = &iparams[niparams++]; *inew->lb = ivar->lb; + inew->ub = &iparams[niparams++]; *inew->ub = ivar->ub; + inew->root = vb; + inew->next = allvars; + allvars = inew; } } - // II. Handle direct innervars. - jl_varbinding_t *wrap = NULL; - int envind = 0; for (jl_varbinding_t *btemp = e->vars; btemp != NULL; btemp = btemp->prev) { - int has_innerdep = blinding_has_innerdep[envind++]; - int lb_has_innerdep = has_innerdep & 1; - int ub_has_innerdep = has_innerdep & 2; - assert(!has_innerdep || btemp->depth0 == vb->depth0); - int lb_has_dep = jl_has_typevar(btemp->lb, vb->var); - int ub_has_dep = jl_has_typevar(btemp->ub, vb->var); - if (lb_has_innerdep || lb_has_dep) { - if (vb->lb == (jl_value_t*)btemp->var) { + jl_ivarbinding_t *inew = (jl_ivarbinding_t *)alloca(sizeof(jl_ivarbinding_t)); + inew->var = &btemp->var; + inew->lb = &btemp->lb; + inew->ub = &btemp->ub; + inew->root = btemp; + inew->next = allvars; + allvars = inew; + if (btemp->innervars) { + for (size_t i = 0; i < jl_array_nrows(btemp->innervars); i++) { + jl_tvar_t *ivar = (jl_tvar_t *)jl_array_ptr_ref(btemp->innervars, i); + jl_ivarbinding_t *inew = (jl_ivarbinding_t *)alloca(sizeof(jl_ivarbinding_t)); + inew->var = (jl_tvar_t **)&iparams[niparams++]; *inew->var = ivar; + inew->lb = &iparams[niparams++]; *inew->lb = ivar->lb; + inew->ub = &iparams[niparams++]; *inew->ub = ivar->ub; + inew->root = btemp; + inew->next = allvars; + allvars = inew; + } + } + } + + // remove/replace/rewrap free occurrences of this var in the environment + int wrapped = 0; + jl_ivarbinding_t *pwrap = NULL; + for (jl_ivarbinding_t *btemp = allvars, *pbtemp = NULL; btemp != NULL; btemp = btemp->next) { + int bdepth0 = btemp->root->depth0; + ivar = *btemp->var; + ilb = *btemp->lb; + iub = *btemp->ub; + if (jl_has_typevar(ilb, vb->var)) { + assert(btemp->root->var == ivar || bdepth0 == vb->depth0); + if (vb->lb == (jl_value_t*)ivar) { + JL_GC_POP(); JL_GC_POP(); return jl_bottom_type; } if (varval) { - if (lb_has_dep) { // inner substitution has been handled - JL_TRY { - btemp->lb = jl_substitute_var(btemp->lb, vb->var, varval); - } - JL_CATCH { - res = jl_bottom_type; - } + JL_TRY { + *btemp->lb = jl_substitute_var(ilb, vb->var, varval); + } + JL_CATCH { + res = jl_bottom_type; } } - else if (btemp->lb == (jl_value_t*)vb->var) { - btemp->lb = vb->lb; + else if (ilb == (jl_value_t*)vb->var) { + *btemp->lb = vb->lb; } - else if (btemp->depth0 == vb->depth0 && !jl_has_typevar(vb->lb, btemp->var) && !jl_has_typevar(vb->ub, btemp->var)) { + else if (bdepth0 == vb->depth0 && !jl_has_typevar(vb->lb, ivar) && !jl_has_typevar(vb->ub, ivar)) { // if our variable is T, and some outer variable has constraint S = Ref{T}, // move the `where T` outside `where S` instead of putting it here. issue #21243. - if (newvar != vb->var && lb_has_dep) // inner substitution has been handled - btemp->lb = jl_substitute_var(btemp->lb, vb->var, (jl_value_t*)newvar); - wrap = btemp; + if (newvar != vb->var) + *btemp->lb = jl_substitute_var(ilb, vb->var, (jl_value_t*)newvar); + if (!wrapped) pwrap = pbtemp; + wrapped = 1; } else { - btemp->lb = jl_new_struct(jl_unionall_type, vb->var, btemp->lb); + *btemp->lb = jl_new_struct(jl_unionall_type, vb->var, ilb); } - assert((jl_value_t*)btemp->var != btemp->lb); + assert((jl_value_t*)ivar != *btemp->lb); } - if (ub_has_innerdep || ub_has_dep) { - if (vb->ub == (jl_value_t*)btemp->var) { - // TODO: handle `omit_bad_union` correctly if `ub_has_innerdep` - btemp->ub = omit_bad_union(btemp->ub, vb->var); - if (btemp->ub == jl_bottom_type && btemp->ub != btemp->lb) { + if (jl_has_typevar(iub, vb->var)) { + assert(btemp->root->var == ivar || bdepth0 == vb->depth0); + if (vb->ub == (jl_value_t*)ivar) { + *btemp->ub = omit_bad_union(iub, vb->var); + if (*btemp->ub == jl_bottom_type && *btemp->ub != *btemp->lb) { + JL_GC_POP(); JL_GC_POP(); return jl_bottom_type; } } if (varval) { - if (ub_has_dep) { // inner substitution has been handled - JL_TRY { - btemp->ub = jl_substitute_var(btemp->ub, vb->var, varval); - } - JL_CATCH { - res = jl_bottom_type; - } - } + iub = jl_substitute_var_nothrow(iub, vb->var, varval, 2); + if (iub == NULL) + res = jl_bottom_type; + else + *btemp->ub = iub; } - else if (btemp->ub == (jl_value_t*)vb->var) { + else if (iub == (jl_value_t*)vb->var) { // TODO: this loses some constraints, such as in this test, where we replace T4<:S3 (e.g. T4==S3 since T4 only appears covariantly once) with T4<:Any // a = Tuple{Float64,T3,T4} where T4 where T3 // b = Tuple{S2,Tuple{S3},S3} where S2 where S3 // Tuple{Float64, T3, T4} where {S3, T3<:Tuple{S3}, T4<:S3} - btemp->ub = vb->ub; + *btemp->ub = vb->ub; } - else if (btemp->depth0 == vb->depth0 && !jl_has_typevar(vb->lb, btemp->var) && !jl_has_typevar(vb->ub, btemp->var)) { - if (newvar != vb->var && ub_has_dep) // inner substitution has been handled - btemp->ub = jl_substitute_var(btemp->ub, vb->var, (jl_value_t*)newvar); - wrap = btemp; + else if (bdepth0 == vb->depth0 && !jl_has_typevar(vb->lb, ivar) && !jl_has_typevar(vb->ub, ivar)) { + if (newvar != vb->var) + *btemp->ub = jl_substitute_var(iub, vb->var, (jl_value_t*)newvar); + if (!wrapped) pwrap = pbtemp; + wrapped = 1; } else - btemp->ub = jl_new_struct(jl_unionall_type, vb->var, btemp->ub); - assert((jl_value_t*)btemp->var != btemp->ub); + *btemp->ub = jl_new_struct(jl_unionall_type, vb->var, iub); + assert((jl_value_t*)ivar != *btemp->ub); + } + pbtemp = btemp; + } + + // Insert the newvar into the (reversed) var list if needed. + if (wrapped) { + jl_ivarbinding_t *wrap = pwrap == NULL ? allvars : pwrap->next; + jl_ivarbinding_t *inew = (jl_ivarbinding_t *)alloca(sizeof(jl_ivarbinding_t)); + inew->var = &newvar; + inew->lb = &newvar->lb; + inew->ub = &newvar->ub;; + inew->root = wrap->root; + inew->next = wrap; + if (pwrap != NULL) + pwrap->next = inew; + else + allvars = inew; + } + + // Re-sort the innervar inside the (reversed) var list. + // `jl_has_typevar` is used as the partial-ordering predicate. + // If this is slow, we could possibly switch to a simpler graph sort, such as Tarjan's SCC. + if (icount > 0) { + jl_ivarbinding_t *pib1 = NULL; + while (1) { + jl_ivarbinding_t *ib1 = pib1 == NULL ? allvars : pib1->next; + if (ib1 == NULL) break; + if (jl_has_free_typevars(*ib1->lb) || jl_has_free_typevars(*ib1->ub)) { + int changed = 0; + jl_ivarbinding_t *pib2 = ib1, *ib2 = ib1->next; + while (ib2 != NULL) { + int isinnervar = ib2->root->var != *ib2->var; + if (isinnervar && ib1->root->depth0 == ib2->root->depth0 && + (jl_has_typevar(*ib1->lb, *ib2->var) || + jl_has_typevar(*ib1->ub, *ib2->var))) { + pib2->next = ib2->next; + ib2->next = ib1; + ib2->root = ib1->root; + if (pib1) + pib1->next = ib2; + else + allvars = ib2; + changed = 1; + break; + } + pib2 = ib2; + ib2 = ib2->next; + } + if (changed) continue; + } + pib1 = ib1; + } + } + + // Freeze the innervars' lb/ub and perform substitution if needed. + for (jl_ivarbinding_t *btemp1 = allvars; btemp1 != NULL; btemp1 = btemp1->next) { + ivar = *btemp1->var; + ilb = *btemp1->lb; + iub = *btemp1->ub; + int isinnervar = btemp1->root->var != ivar; + if (isinnervar && (ivar->lb != ilb || ivar->ub != iub)) { + nivar = (jl_value_t *)jl_new_typevar(ivar->name, ilb, iub); + if (jl_has_typevar(res, ivar)) + res = jl_substitute_var(res, ivar, nivar); + for (jl_ivarbinding_t *btemp2 = btemp1->next; btemp2 != NULL; btemp2 = btemp2->next) { + ilb = *btemp2->lb; + iub = *btemp2->ub; + if (jl_has_typevar(ilb, ivar)) + *btemp2->lb = jl_substitute_var(ilb, ivar, nivar); + if (jl_has_typevar(iub, ivar)) + *btemp2->ub = jl_substitute_var(iub, ivar, nivar); + } + *btemp1->var = (jl_tvar_t *)nivar; } } - if (wrap) { - // We only assign the newvar with the outmost var. - // This make sure we never create a UnionAll with 2 identical vars. - if (wrap->innervars == NULL) - wrap->innervars = jl_alloc_array_1d(jl_array_any_type, 0); - jl_array_ptr_1d_push(wrap->innervars, (jl_value_t*)newvar); - // TODO: should we move all the innervars here too? + // Switch back the innervars' storage. + while (1) { + jl_ivarbinding_t *btemp = allvars; + jl_varbinding_t *root = btemp ? btemp->root : vb; + size_t icount = 0; + while (btemp && btemp->root == root) { + btemp = btemp->next; + icount++; + } + if (root != vb) icount--; + if (root->innervars != NULL) { + size_t len = jl_array_nrows(root->innervars); + if (icount > len) + jl_array_grow_end(root->innervars, icount - len); + if (icount < len) + jl_array_del_end(root->innervars, len - icount); + } + else if (icount > 0) { + root->innervars = jl_alloc_array_1d(jl_array_any_type, icount); + } + btemp = allvars; + for (size_t i = icount; i > 0; i--) { + jl_array_ptr_set(root->innervars, i - 1, (jl_value_t*)*btemp->var); + btemp = btemp->next; + } + if (root == vb) break; + assert(*btemp->var == root->var); + allvars = btemp->next; + assert(allvars == NULL || allvars->root != root); } + JL_GC_POP(); // if `v` still occurs, re-wrap body in `UnionAll v` or eliminate the UnionAll if (jl_has_typevar(res, vb->var)) { if (varval) { - JL_TRY { - // you can construct `T{x} where x` even if T's parameter is actually - // limited. in that case we might get an invalid instantiation here. - res = jl_substitute_var(res, vb->var, varval); - // simplify chains of UnionAlls where bounds become equal - while (jl_is_unionall(res) && obviously_egal(((jl_unionall_t*)res)->var->lb, - ((jl_unionall_t*)res)->var->ub)) - res = jl_instantiate_unionall((jl_unionall_t*)res, ((jl_unionall_t*)res)->var->lb); + // you can construct `T{x} where x` even if T's parameter is actually + // limited. in that case we might get an invalid instantiation here. + res = jl_substitute_var_nothrow(res, vb->var, varval, 2); + // simplify chains of UnionAlls where bounds become equal + while (res != NULL && jl_is_unionall(res) && obviously_egal(((jl_unionall_t*)res)->var->lb, + ((jl_unionall_t*)res)->var->ub)) { + jl_unionall_t * ures = (jl_unionall_t *)res; + res = jl_substitute_var_nothrow(ures->body, ures->var, ures->var->lb, 2); } - JL_CATCH { + if (res == NULL) res = jl_bottom_type; - } } else { if (newvar != vb->var) res = jl_substitute_var(res, vb->var, (jl_value_t*)newvar); varval = (jl_value_t*)newvar; - if (!wrap) + if (!wrapped) res = jl_type_unionall((jl_tvar_t*)newvar, res); } } if (vb->innervars != NULL) { - size_t len = jl_array_nrows(vb->innervars), count = 0; - for (size_t i = 0; i < len; i++) { + for (size_t i = 0; i < jl_array_nrows(vb->innervars); i++) { jl_tvar_t *var = (jl_tvar_t*)jl_array_ptr_ref(vb->innervars, i); - // the `btemp->prev` walk is only giving a sort of post-order guarantee (since we are - // iterating 2 trees at once), so once we set `wrap`, there might remain other branches - // of the type walk that now still may have incomplete bounds: finish those now too - jl_varbinding_t *wrap = NULL; - for (jl_varbinding_t *btemp = e->vars; btemp != NULL; btemp = btemp->prev) { - if (btemp->depth0 == vb->depth0 && (jl_has_typevar(btemp->lb, var) || jl_has_typevar(btemp->ub, var))) { - wrap = btemp; - } - } - if (wrap) { - if (wrap->innervars == NULL) - wrap->innervars = jl_alloc_array_1d(jl_array_any_type, 0); - // FIXME: `var`'s dependence should also be pushed into `wrap->innervars`. - jl_array_ptr_1d_push(wrap->innervars, (jl_value_t*)var); - jl_array_ptr_set(vb->innervars, i, (jl_value_t*)NULL); - } - } - for (size_t i = 0; i < len; i++) { - jl_tvar_t *var = (jl_tvar_t*)jl_array_ptr_ref(vb->innervars, i); - if (var) { - if (count < i) - jl_array_ptr_set(vb->innervars, count, (jl_value_t*)var); - count++; - } - } - if (count != len) - jl_array_del_end(vb->innervars, len - count); - if (res != jl_bottom_type) { - while (count > 1) { - int changed = 0; - // Now need to re-sort the vb->innervars using the partial-ordering predicate `jl_has_typevar`. - // If this is slow, we could possibly switch to a simpler graph sort than this triple loop, such as Tarjan's SCC. - // But for now we use a variant on selection sort for partial-orders. - for (size_t i = 0; i < count - 1; i++) { - jl_tvar_t *vari = (jl_tvar_t*)jl_array_ptr_ref(vb->innervars, i); - for (size_t j = i+1; j < count; j++) { - jl_tvar_t *varj = (jl_tvar_t*)jl_array_ptr_ref(vb->innervars, j); - if (jl_has_typevar(varj->lb, vari) || jl_has_typevar(varj->ub, vari)) { - jl_array_ptr_set(vb->innervars, j, (jl_value_t*)vari); - jl_array_ptr_set(vb->innervars, i, (jl_value_t*)varj); - changed = 1; - break; - } - } - if (changed) break; - } - if (!changed) break; - } - for (size_t i = 0; i < count; i++) { - jl_tvar_t *var = (jl_tvar_t*)jl_array_ptr_ref(vb->innervars, i); - res = jl_type_unionall(var, res); - } + res = jl_type_unionall(var, res); } } @@ -3278,7 +3310,7 @@ static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, ssize_t ii = (jl_value_t*)vmy; else { JL_GC_PUSH1(&ii); - ii = (jl_value_t*)jl_wrap_vararg(ii, NULL, 1); + ii = (jl_value_t*)jl_wrap_vararg(ii, NULL, 1, 0); JL_GC_POP(); } return ii; @@ -3334,7 +3366,7 @@ static jl_value_t *intersect_varargs(jl_vararg_t *vmx, jl_vararg_t *vmy, ssize_t else if (yp2 && obviously_egal(yp1, ii) && obviously_egal(yp2, i2)) ii = (jl_value_t*)vmy; else - ii = (jl_value_t*)jl_wrap_vararg(ii, i2, 1); + ii = (jl_value_t*)jl_wrap_vararg(ii, i2, 1, 0); } JL_GC_POP(); return ii; @@ -3958,9 +3990,9 @@ static int merge_env(jl_stenv_t *e, jl_savedenv_t *se, int count) se->buf[m+2] = 0; se->buf[m+3] = v->max_offset; } + jl_value_t *b1, *b2; if (v->occurs) { - // only merge lb/ub/innervars if this var occurs. - jl_value_t *b1, *b2; + // only merge lb/ub if this var occurs. b1 = roots[n]; JL_GC_PROMISE_ROOTED(b1); // clang-sagc doesn't know this came from our GC frame b2 = v->lb; @@ -3971,19 +4003,21 @@ static int merge_env(jl_stenv_t *e, jl_savedenv_t *se, int count) b2 = v->ub; JL_GC_PROMISE_ROOTED(b2); // clang-sagc doesn't know the fields of this are stack GC roots roots[n+1] = b1 ? simple_join(b1, b2) : b2; - b1 = roots[n+2]; - JL_GC_PROMISE_ROOTED(b1); // clang-sagc doesn't know this came from our GC frame - b2 = (jl_value_t*)v->innervars; - JL_GC_PROMISE_ROOTED(b2); // clang-sagc doesn't know the fields of this are stack GC roots - if (b2 && b1 != b2) { - if (b1) - jl_array_ptr_1d_append((jl_array_t*)b1, (jl_array_t*)b2); - else - roots[n+2] = b2; - } // record the meeted vars. se->buf[m] = 1; } + // `innervars` might be re-sorted inside `finish_unionall`. + // We'd better always merge it. + b1 = roots[n+2]; + JL_GC_PROMISE_ROOTED(b1); // clang-sagc doesn't know this came from our GC frame + b2 = (jl_value_t*)v->innervars; + JL_GC_PROMISE_ROOTED(b2); // clang-sagc doesn't know the fields of this are stack GC roots + if (b2 && b1 != b2) { + if (b1) + jl_array_ptr_1d_append((jl_array_t*)b1, (jl_array_t*)b2); + else + roots[n+2] = b2; + } // always merge occurs_inv/cov by max (never decrease) if (v->occurs_inv > se->buf[m+1]) se->buf[m+1] = v->occurs_inv; @@ -4558,7 +4592,7 @@ static jl_value_t *insert_nondiagonal(jl_value_t *type, jl_varbinding_t *troot, JL_GC_PUSH2(&newt, &n); newt = insert_nondiagonal(t, troot, widen2ub); if (t != newt) - type = (jl_value_t *)jl_wrap_vararg(newt, n, 0); + type = (jl_value_t *)jl_wrap_vararg(newt, n, 0, 0); JL_GC_POP(); } else if (jl_is_datatype(type)) { diff --git a/src/task.c b/src/task.c index d6563888c1663..0934f83e20a88 100644 --- a/src/task.c +++ b/src/task.c @@ -1649,6 +1649,7 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) JL_GC_PROMISE_ROOTED(ct); jl_set_pgcstack(&ct->gcstack); assert(jl_current_task == ct); + assert(jl_current_task->ptls == ptls); #ifdef _COMPILER_TSAN_ENABLED_ ct->ctx.tsan_state = __tsan_get_current_fiber(); diff --git a/stdlib/Artifacts/src/Artifacts.jl b/stdlib/Artifacts/src/Artifacts.jl index 968d190c2b443..e8a40c76b9e49 100644 --- a/stdlib/Artifacts/src/Artifacts.jl +++ b/stdlib/Artifacts/src/Artifacts.jl @@ -693,7 +693,7 @@ macro artifact_str(name, platform=nothing) local artifact_dict = load_artifacts_toml(artifacts_toml) # Invalidate calling .ji file if Artifacts.toml file changes - Base.include_dependency(artifacts_toml) + Base.include_dependency(artifacts_toml, track_content = true) # Check if the user has provided `LazyArtifacts`, and thus supports lazy artifacts # If not, check to see if `Pkg` or `Pkg.Artifacts` has been imported. @@ -759,6 +759,6 @@ precompile(NamedTuple{(:pkg_uuid,)}, (Tuple{Base.UUID},)) precompile(Core.kwfunc(load_artifacts_toml), (NamedTuple{(:pkg_uuid,), Tuple{Base.UUID}}, typeof(load_artifacts_toml), String)) precompile(parse_mapping, (String, String, String)) precompile(parse_mapping, (Dict{String, Any}, String, String)) - +precompile(Tuple{typeof(Artifacts._artifact_str), Module, String, Base.SubString{String}, String, Base.Dict{String, Any}, Base.SHA1, Base.BinaryPlatforms.Platform, Any}) end # module Artifacts diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index a42ca934e17a6..9262c2fddca45 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -516,32 +516,56 @@ const ⋅ = dot const × = cross export ⋅, × +# Separate the char corresponding to the wrapper from that corresponding to the uplo +# In most cases, the former may be constant-propagated, while the latter usually can't be. +# This improves type-inference in wrap for Symmetric/Hermitian matrices +# A WrapperChar is equivalent to `isuppertri ? uppercase(wrapperchar) : lowercase(wrapperchar)` +struct WrapperChar <: AbstractChar + wrapperchar :: Char + isuppertri :: Bool +end +function Base.Char(w::WrapperChar) + T = w.wrapperchar + if T ∈ ('N', 'T', 'C') # known cases where isuppertri is true + T + else + _isuppertri(w) ? uppercase(T) : lowercase(T) + end +end +Base.codepoint(w::WrapperChar) = codepoint(Char(w)) +WrapperChar(n::UInt32) = WrapperChar(Char(n)) +WrapperChar(c::Char) = WrapperChar(c, isuppercase(c)) +# We extract the wrapperchar so that the result may be constant-propagated +# This doesn't return a value of the same type on purpose +Base.uppercase(w::WrapperChar) = uppercase(w.wrapperchar) +Base.lowercase(w::WrapperChar) = lowercase(w.wrapperchar) +_isuppertri(w::WrapperChar) = w.isuppertri +_isuppertri(x::AbstractChar) = isuppercase(x) # compatibility with earlier Char-based implementation +_uplosym(x) = _isuppertri(x) ? (:U) : (:L) + wrapper_char(::AbstractArray) = 'N' wrapper_char(::Adjoint) = 'C' wrapper_char(::Adjoint{<:Real}) = 'T' wrapper_char(::Transpose) = 'T' -wrapper_char(A::Hermitian) = A.uplo == 'U' ? 'H' : 'h' -wrapper_char(A::Hermitian{<:Real}) = A.uplo == 'U' ? 'S' : 's' -wrapper_char(A::Symmetric) = A.uplo == 'U' ? 'S' : 's' +wrapper_char(A::Hermitian) = WrapperChar('H', A.uplo == 'U') +wrapper_char(A::Hermitian{<:Real}) = WrapperChar('S', A.uplo == 'U') +wrapper_char(A::Symmetric) = WrapperChar('S', A.uplo == 'U') Base.@constprop :aggressive function wrap(A::AbstractVecOrMat, tA::AbstractChar) # merge the result of this before return, so that we can type-assert the return such # that even if the tmerge is inaccurate, inference can still identify that the # `_generic_matmatmul` signature still matches and doesn't require missing backedges - B = if tA == 'N' + tA_uc = uppercase(tA) + B = if tA_uc == 'N' A - elseif tA == 'T' + elseif tA_uc == 'T' transpose(A) - elseif tA == 'C' + elseif tA_uc == 'C' adjoint(A) - elseif tA == 'H' - Hermitian(A, :U) - elseif tA == 'h' - Hermitian(A, :L) - elseif tA == 'S' - Symmetric(A, :U) - else # tA == 's' - Symmetric(A, :L) + elseif tA_uc == 'H' + Hermitian(A, _uplosym(tA)) + elseif tA_uc == 'S' + Symmetric(A, _uplosym(tA)) end return B::AbstractVecOrMat end @@ -693,7 +717,7 @@ function peakflops(n::Integer=4096; eltype::DataType=Float64, ntrials::Integer=3 end if parallel - let Distributed = Base.require_stdlib(Base.PkgId( + let Distributed = Base.require(Base.PkgId( Base.UUID((0x8ba89e20_285c_5b6f, 0x9357_94700520ee1b)), "Distributed")) nworkers = @invokelatest Distributed.nworkers() results = @invokelatest Distributed.pmap(peakflops, fill(n, nworkers)) diff --git a/stdlib/LinearAlgebra/src/abstractq.jl b/stdlib/LinearAlgebra/src/abstractq.jl index b0d53320f4aa3..bf4064c907a2d 100644 --- a/stdlib/LinearAlgebra/src/abstractq.jl +++ b/stdlib/LinearAlgebra/src/abstractq.jl @@ -18,6 +18,10 @@ transpose(Q::AbstractQ{<:Real}) = AdjointQ(Q) transpose(Q::AbstractQ) = error("transpose not implemented for $(typeof(Q)). Consider using adjoint instead of transpose.") adjoint(adjQ::AdjointQ) = adjQ.Q +(^)(Q::AbstractQ, p::Integer) = p < 0 ? power_by_squaring(inv(Q), -p) : power_by_squaring(Q, p) +@inline Base.literal_pow(::typeof(^), Q::AbstractQ, ::Val{1}) = Q +@inline Base.literal_pow(::typeof(^), Q::AbstractQ, ::Val{-1}) = inv(Q) + # promotion with AbstractMatrix, at least for equal eltypes promote_rule(::Type{<:AbstractMatrix{T}}, ::Type{<:AbstractQ{T}}) where {T} = (@inline; Union{AbstractMatrix{T},AbstractQ{T}}) @@ -149,13 +153,13 @@ end # generically, treat AbstractQ like a matrix with its definite size qsize_check(Q::AbstractQ, B::AbstractVecOrMat) = size(Q, 2) == size(B, 1) || - throw(DimensionMismatch("second dimension of Q, $(size(Q,2)), must coincide with first dimension of B, $(size(B,1))")) + throw(DimensionMismatch(lazy"second dimension of Q, $(size(Q,2)), must coincide with first dimension of B, $(size(B,1))")) qsize_check(A::AbstractVecOrMat, Q::AbstractQ) = size(A, 2) == size(Q, 1) || - throw(DimensionMismatch("second dimension of A, $(size(A,2)), must coincide with first dimension of Q, $(size(Q,1))")) + throw(DimensionMismatch(lazy"second dimension of A, $(size(A,2)), must coincide with first dimension of Q, $(size(Q,1))")) qsize_check(Q::AbstractQ, P::AbstractQ) = size(Q, 2) == size(P, 1) || - throw(DimensionMismatch("second dimension of A, $(size(Q,2)), must coincide with first dimension of B, $(size(P,1))")) + throw(DimensionMismatch(lazy"second dimension of A, $(size(Q,2)), must coincide with first dimension of B, $(size(P,1))")) # mimic the AbstractArray fallback *(Q::AbstractQ{<:Number}) = Q @@ -317,7 +321,7 @@ function lmul!(A::QRPackedQ, B::AbstractVecOrMat) mA, nA = size(A.factors) mB, nB = size(B,1), size(B,2) if mA != mB - throw(DimensionMismatch("matrix A has dimensions ($mA,$nA) but B has dimensions ($mB, $nB)")) + throw(DimensionMismatch(lazy"matrix A has dimensions ($mA,$nA) but B has dimensions ($mB, $nB)")) end Afactors = A.factors @inbounds begin @@ -353,7 +357,7 @@ function lmul!(adjA::AdjointQ{<:Any,<:QRPackedQ}, B::AbstractVecOrMat) mA, nA = size(A.factors) mB, nB = size(B,1), size(B,2) if mA != mB - throw(DimensionMismatch("matrix A has dimensions ($mA,$nA) but B has dimensions ($mB, $nB)")) + throw(DimensionMismatch(lazy"matrix A has dimensions ($mA,$nA) but B has dimensions ($mB, $nB)")) end Afactors = A.factors @inbounds begin @@ -384,7 +388,7 @@ function rmul!(A::AbstractVecOrMat, Q::QRPackedQ) mQ, nQ = size(Q.factors) mA, nA = size(A,1), size(A,2) if nA != mQ - throw(DimensionMismatch("matrix A has dimensions ($mA,$nA) but matrix Q has dimensions ($mQ, $nQ)")) + throw(DimensionMismatch(lazy"matrix A has dimensions ($mA,$nA) but matrix Q has dimensions ($mQ, $nQ)")) end Qfactors = Q.factors @inbounds begin @@ -420,7 +424,7 @@ function rmul!(A::AbstractVecOrMat, adjQ::AdjointQ{<:Any,<:QRPackedQ}) mQ, nQ = size(Q.factors) mA, nA = size(A,1), size(A,2) if nA != mQ - throw(DimensionMismatch("matrix A has dimensions ($mA,$nA) but matrix Q has dimensions ($mQ, $nQ)")) + throw(DimensionMismatch(lazy"matrix A has dimensions ($mA,$nA) but matrix Q has dimensions ($mQ, $nQ)")) end Qfactors = Q.factors @inbounds begin @@ -521,10 +525,10 @@ rmul!(X::Adjoint{T,<:StridedVecOrMat{T}}, adjQ::AdjointQ{<:Any,<:HessenbergQ{T}} # flexible left-multiplication (and adjoint right-multiplication) qsize_check(Q::Union{QRPackedQ,QRCompactWYQ,HessenbergQ}, B::AbstractVecOrMat) = size(B, 1) in size(Q.factors) || - throw(DimensionMismatch("first dimension of B, $(size(B,1)), must equal one of the dimensions of Q, $(size(Q.factors))")) + throw(DimensionMismatch(lazy"first dimension of B, $(size(B,1)), must equal one of the dimensions of Q, $(size(Q.factors))")) qsize_check(A::AbstractVecOrMat, adjQ::AdjointQ{<:Any,<:Union{QRPackedQ,QRCompactWYQ,HessenbergQ}}) = (Q = adjQ.Q; size(A, 2) in size(Q.factors) || - throw(DimensionMismatch("second dimension of A, $(size(A,2)), must equal one of the dimensions of Q, $(size(Q.factors))"))) + throw(DimensionMismatch(lazy"second dimension of A, $(size(A,2)), must equal one of the dimensions of Q, $(size(Q.factors))"))) det(Q::HessenbergQ) = _det_tau(Q.τ) @@ -560,10 +564,10 @@ size(Q::LQPackedQ) = (n = size(Q.factors, 2); return n, n) qsize_check(adjQ::AdjointQ{<:Any,<:LQPackedQ}, B::AbstractVecOrMat) = size(B, 1) in size(adjQ.Q.factors) || - throw(DimensionMismatch("first dimension of B, $(size(B,1)), must equal one of the dimensions of Q, $(size(adjQ.Q.factors))")) + throw(DimensionMismatch(lazy"first dimension of B, $(size(B,1)), must equal one of the dimensions of Q, $(size(adjQ.Q.factors))")) qsize_check(A::AbstractVecOrMat, Q::LQPackedQ) = size(A, 2) in size(Q.factors) || - throw(DimensionMismatch("second dimension of A, $(size(A,2)), must equal one of the dimensions of Q, $(size(Q.factors))")) + throw(DimensionMismatch(lazy"second dimension of A, $(size(A,2)), must equal one of the dimensions of Q, $(size(Q.factors))")) # in-place right-application of LQPackedQs # these methods require that the applied-to matrix's (A's) number of columns diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index 24ad7960f00b4..f52460a870ca0 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -465,7 +465,7 @@ tr(A::Transpose) = transpose(tr(parent(A))) function _dot_nonrecursive(u, v) lu = length(u) if lu != length(v) - throw(DimensionMismatch("first array has length $(lu) which does not match the length of the second, $(length(v)).")) + throw(DimensionMismatch(lazy"first array has length $(lu) which does not match the length of the second, $(length(v)).")) end if lu == 0 zero(eltype(u)) * zero(eltype(v)) diff --git a/stdlib/LinearAlgebra/src/bidiag.jl b/stdlib/LinearAlgebra/src/bidiag.jl index 00c972f7f990b..d356379f34dff 100644 --- a/stdlib/LinearAlgebra/src/bidiag.jl +++ b/stdlib/LinearAlgebra/src/bidiag.jl @@ -8,7 +8,7 @@ struct Bidiagonal{T,V<:AbstractVector{T}} <: AbstractMatrix{T} function Bidiagonal{T,V}(dv, ev, uplo::AbstractChar) where {T,V<:AbstractVector{T}} require_one_based_indexing(dv, ev) if length(ev) != max(length(dv)-1, 0) - throw(DimensionMismatch("length of diagonal vector is $(length(dv)), length of off-diagonal vector is $(length(ev))")) + throw(DimensionMismatch(lazy"length of diagonal vector is $(length(dv)), length of off-diagonal vector is $(length(ev))")) end (uplo != 'U' && uplo != 'L') && throw_uplo() new{T,V}(dv, ev, uplo) @@ -443,11 +443,11 @@ function check_A_mul_B!_sizes(C, A, B) mB, nB = size(B) mC, nC = size(C) if mA != mC - throw(DimensionMismatch("first dimension of A, $mA, and first dimension of output C, $mC, must match")) + throw(DimensionMismatch(lazy"first dimension of A, $mA, and first dimension of output C, $mC, must match")) elseif nA != mB - throw(DimensionMismatch("second dimension of A, $nA, and first dimension of B, $mB, must match")) + throw(DimensionMismatch(lazy"second dimension of A, $nA, and first dimension of B, $mB, must match")) elseif nB != nC - throw(DimensionMismatch("second dimension of output C, $nC, and second dimension of B, $nB, must match")) + throw(DimensionMismatch(lazy"second dimension of output C, $nC, and second dimension of B, $nB, must match")) end end @@ -567,10 +567,10 @@ function _mul!(C::AbstractVecOrMat, A::BiTriSym, B::AbstractVecOrMat, _add::MulA nA = size(A,1) nB = size(B,2) if !(size(C,1) == size(B,1) == nA) - throw(DimensionMismatch("A has first dimension $nA, B has $(size(B,1)), C has $(size(C,1)) but all must match")) + throw(DimensionMismatch(lazy"A has first dimension $nA, B has $(size(B,1)), C has $(size(C,1)) but all must match")) end if size(C,2) != nB - throw(DimensionMismatch("A has second dimension $nA, B has $(size(B,2)), C has $(size(C,2)) but all must match")) + throw(DimensionMismatch(lazy"A has second dimension $nA, B has $(size(B,2)), C has $(size(C,2)) but all must match")) end iszero(nA) && return C iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta) @@ -768,11 +768,11 @@ function ldiv!(c::AbstractVecOrMat, A::Bidiagonal, b::AbstractVecOrMat) N = size(A, 2) mb, nb = size(b, 1), size(b, 2) if N != mb - throw(DimensionMismatch("second dimension of A, $N, does not match first dimension of b, $mb")) + throw(DimensionMismatch(lazy"second dimension of A, $N, does not match first dimension of b, $mb")) end mc, nc = size(c, 1), size(c, 2) if mc != mb || nc != nb - throw(DimensionMismatch("size of result, ($mc, $nc), does not match the size of b, ($mb, $nb)")) + throw(DimensionMismatch(lazy"size of result, ($mc, $nc), does not match the size of b, ($mb, $nb)")) end if N == 0 @@ -838,11 +838,11 @@ function _rdiv!(C::AbstractMatrix, A::AbstractMatrix, B::Bidiagonal) require_one_based_indexing(C, A, B) m, n = size(A) if size(B, 1) != n - throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) + throw(DimensionMismatch(lazy"right hand side B needs first dimension of size $n, has size $(size(B,1))")) end mc, nc = size(C) if mc != m || nc != n - throw(DimensionMismatch("expect output to have size ($m, $n), but got ($mc, $nc)")) + throw(DimensionMismatch(lazy"expect output to have size ($m, $n), but got ($mc, $nc)")) end zi = findfirst(iszero, B.dv) diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index 72c3792d7867c..97a64aee3e721 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -336,7 +336,7 @@ function diagm_size(size::Tuple{Int,Int}, kv::Pair{<:Integer,<:AbstractVector}.. mmax = mapreduce(x -> length(x.second) - min(0,Int(x.first)), max, kv; init=0) nmax = mapreduce(x -> length(x.second) + max(0,Int(x.first)), max, kv; init=0) m, n = size - (m ≥ mmax && n ≥ nmax) || throw(DimensionMismatch("invalid size=$size")) + (m ≥ mmax && n ≥ nmax) || throw(DimensionMismatch(lazy"invalid size=$size")) return m, n end function diagm_container(size, kv::Pair{<:Integer,<:AbstractVector}...) @@ -1645,7 +1645,7 @@ function cond(A::AbstractMatrix, p::Real=2) end end end - throw(ArgumentError("p-norm must be 1, 2 or Inf, got $p")) + throw(ArgumentError(lazy"p-norm must be 1, 2 or Inf, got $p")) end ## Lyapunov and Sylvester equation diff --git a/stdlib/LinearAlgebra/src/diagonal.jl b/stdlib/LinearAlgebra/src/diagonal.jl index 063dde619bd1a..f07e0fba17f53 100644 --- a/stdlib/LinearAlgebra/src/diagonal.jl +++ b/stdlib/LinearAlgebra/src/diagonal.jl @@ -190,7 +190,7 @@ function setindex!(D::Diagonal, v, i::Int, j::Int) if i == j @inbounds D.diag[i] = v elseif !iszero(v) - throw(ArgumentError("cannot set off-diagonal entry ($i, $j) to a nonzero value ($v)")) + throw(ArgumentError(lazy"cannot set off-diagonal entry ($i, $j) to a nonzero value ($v)")) end return v end @@ -279,13 +279,13 @@ Base.literal_pow(::typeof(^), D::Diagonal, ::Val{-1}) = inv(D) # for disambiguat function _muldiag_size_check(A, B) nA = size(A, 2) mB = size(B, 1) - @noinline throw_dimerr(::AbstractMatrix, nA, mB) = throw(DimensionMismatch("second dimension of A, $nA, does not match first dimension of B, $mB")) - @noinline throw_dimerr(::AbstractVector, nA, mB) = throw(DimensionMismatch("second dimension of D, $nA, does not match length of V, $mB")) + @noinline throw_dimerr(::AbstractMatrix, nA, mB) = throw(DimensionMismatch(lazy"second dimension of A, $nA, does not match first dimension of B, $mB")) + @noinline throw_dimerr(::AbstractVector, nA, mB) = throw(DimensionMismatch(lazy"second dimension of D, $nA, does not match length of V, $mB")) nA == mB || throw_dimerr(B, nA, mB) return nothing end # the output matrix should have the same size as the non-diagonal input matrix or vector -@noinline throw_dimerr(szC, szA) = throw(DimensionMismatch("output matrix has size: $szC, but should have size $szA")) +@noinline throw_dimerr(szC, szA) = throw(DimensionMismatch(lazy"output matrix has size: $szC, but should have size $szA")) _size_check_out(C, ::Diagonal, A) = _size_check_out(C, A) _size_check_out(C, A, ::Diagonal) = _size_check_out(C, A) _size_check_out(C, A::Diagonal, ::Diagonal) = _size_check_out(C, A) @@ -432,7 +432,7 @@ function _rdiv!(B::AbstractVecOrMat, A::AbstractVecOrMat, D::Diagonal) dd = D.diag m, n = size(A, 1), size(A, 2) if (k = length(dd)) != n - throw(DimensionMismatch("left hand side has $n columns but D is $k by $k")) + throw(DimensionMismatch(lazy"left hand side has $n columns but D is $k by $k")) end @inbounds for j in 1:n ddj = dd[j] @@ -459,8 +459,8 @@ function ldiv!(B::AbstractVecOrMat, D::Diagonal, A::AbstractVecOrMat) d = length(dd) m, n = size(A, 1), size(A, 2) m′, n′ = size(B, 1), size(B, 2) - m == d || throw(DimensionMismatch("right hand side has $m rows but D is $d by $d")) - (m, n) == (m′, n′) || throw(DimensionMismatch("expect output to be $m by $n, but got $m′ by $n′")) + m == d || throw(DimensionMismatch(lazy"right hand side has $m rows but D is $d by $d")) + (m, n) == (m′, n′) || throw(DimensionMismatch(lazy"expect output to be $m by $n, but got $m′ by $n′")) j = findfirst(iszero, D.diag) isnothing(j) || throw(SingularException(j)) @inbounds for j = 1:n, i = 1:m @@ -474,7 +474,7 @@ end /(A::Diagonal, D::Diagonal) = _rdiv!(matprod_dest(A, D, promote_op(/, eltype(A), eltype(D))), A, D) function _rdiv!(Dc::Diagonal, Db::Diagonal, Da::Diagonal) n, k = length(Db.diag), length(Da.diag) - n == k || throw(DimensionMismatch("left hand side has $n columns but D is $k by $k")) + n == k || throw(DimensionMismatch(lazy"left hand side has $n columns but D is $k by $k")) j = findfirst(iszero, Da.diag) isnothing(j) || throw(SingularException(j)) Dc.diag .= Db.diag ./ Da.diag @@ -502,10 +502,10 @@ function ldiv!(T::Tridiagonal, D::Diagonal, S::Union{SymTridiagonal,Tridiagonal} m = size(S, 1) dd = D.diag if (k = length(dd)) != m - throw(DimensionMismatch("diagonal matrix is $k by $k but right hand side has $m rows")) + throw(DimensionMismatch(lazy"diagonal matrix is $k by $k but right hand side has $m rows")) end if length(T.d) != m - throw(DimensionMismatch("target matrix size $(size(T)) does not match input matrix size $(size(S))")) + throw(DimensionMismatch(lazy"target matrix size $(size(T)) does not match input matrix size $(size(S))")) end m == 0 && return T j = findfirst(iszero, dd) @@ -539,10 +539,10 @@ function _rdiv!(T::Tridiagonal, S::Union{SymTridiagonal,Tridiagonal}, D::Diagona n = size(S, 2) dd = D.diag if (k = length(dd)) != n - throw(DimensionMismatch("left hand side has $n columns but D is $k by $k")) + throw(DimensionMismatch(lazy"left hand side has $n columns but D is $k by $k")) end if length(T.d) != n - throw(DimensionMismatch("target matrix size $(size(T)) does not match input matrix size $(size(S))")) + throw(DimensionMismatch(lazy"target matrix size $(size(T)) does not match input matrix size $(size(S))")) end n == 0 && return T j = findfirst(iszero, dd) @@ -612,7 +612,7 @@ end valB = B.diag; nB = length(valB) nC = checksquare(C) @boundscheck nC == nA*nB || - throw(DimensionMismatch("expect C to be a $(nA*nB)x$(nA*nB) matrix, got size $(nC)x$(nC)")) + throw(DimensionMismatch(lazy"expect C to be a $(nA*nB)x$(nA*nB) matrix, got size $(nC)x$(nC)")) isempty(A) || isempty(B) || fill!(C, zero(A[1,1] * B[1,1])) @inbounds for i = 1:nA, j = 1:nB idx = (i-1)*nB+j @@ -643,7 +643,7 @@ end (mB, nB) = size(B) (mC, nC) = size(C) @boundscheck (mC, nC) == (mA * mB, nA * nB) || - throw(DimensionMismatch("expect C to be a $(mA * mB)x$(nA * nB) matrix, got size $(mC)x$(nC)")) + throw(DimensionMismatch(lazy"expect C to be a $(mA * mB)x$(nA * nB) matrix, got size $(mC)x$(nC)")) isempty(A) || isempty(B) || fill!(C, zero(A[1,1] * B[1,1])) m = 1 @inbounds for j = 1:nA @@ -666,7 +666,7 @@ end (mB, nB) = size(B) (mC, nC) = size(C) @boundscheck (mC, nC) == (mA * mB, nA * nB) || - throw(DimensionMismatch("expect C to be a $(mA * mB)x$(nA * nB) matrix, got size $(mC)x$(nC)")) + throw(DimensionMismatch(lazy"expect C to be a $(mA * mB)x$(nA * nB) matrix, got size $(mC)x$(nC)")) isempty(A) || isempty(B) || fill!(C, zero(A[1,1] * B[1,1])) m = 1 @inbounds for j = 1:nA @@ -879,7 +879,7 @@ dot(x::AbstractVector, D::Diagonal, y::AbstractVector) = _mapreduce_prod(dot, x, dot(A::Diagonal, B::Diagonal) = dot(A.diag, B.diag) function dot(D::Diagonal, B::AbstractMatrix) - size(D) == size(B) || throw(DimensionMismatch("Matrix sizes $(size(D)) and $(size(B)) differ")) + size(D) == size(B) || throw(DimensionMismatch(lazy"Matrix sizes $(size(D)) and $(size(B)) differ")) return dot(D.diag, view(B, diagind(B, IndexStyle(B)))) end @@ -887,7 +887,7 @@ dot(A::AbstractMatrix, B::Diagonal) = conj(dot(B, A)) function _mapreduce_prod(f, x, D::Diagonal, y) if !(length(x) == length(D.diag) == length(y)) - throw(DimensionMismatch("x has length $(length(x)), D has size $(size(D)), and y has $(length(y))")) + throw(DimensionMismatch(lazy"x has length $(length(x)), D has size $(size(D)), and y has $(length(y))")) end if isempty(x) && isempty(D) && isempty(y) return zero(promote_op(f, eltype(x), eltype(D), eltype(y))) diff --git a/stdlib/LinearAlgebra/src/generic.jl b/stdlib/LinearAlgebra/src/generic.jl index d0a985f3b6e51..f3d39824ad72c 100644 --- a/stdlib/LinearAlgebra/src/generic.jl +++ b/stdlib/LinearAlgebra/src/generic.jl @@ -110,7 +110,7 @@ end function generic_mul!(C::AbstractArray, X::AbstractArray, s::Number, _add::MulAddMul) if length(C) != length(X) - throw(DimensionMismatch("first array has length $(length(C)) which does not match the length of the second, $(length(X)).")) + throw(DimensionMismatch(lazy"first array has length $(length(C)) which does not match the length of the second, $(length(X)).")) end for (IC, IX) in zip(eachindex(C), eachindex(X)) @inbounds _modify!(_add, X[IX] * s, C, IC) @@ -120,7 +120,7 @@ end function generic_mul!(C::AbstractArray, s::Number, X::AbstractArray, _add::MulAddMul) if length(C) != length(X) - throw(DimensionMismatch("first array has length $(length(C)) which does not + throw(DimensionMismatch(lazy"first array has length $(length(C)) which does not match the length of the second, $(length(X)).")) end for (IC, IX) in zip(eachindex(C), eachindex(X)) @@ -748,7 +748,7 @@ function opnorm(A::AbstractMatrix, p::Real=2) elseif p == Inf return opnormInf(A) else - throw(ArgumentError("invalid p-norm p=$p. Valid: 1, 2, Inf")) + throw(ArgumentError(lazy"invalid p-norm p=$p. Valid: 1, 2, Inf")) end end @@ -886,7 +886,7 @@ dot(x::Number, y::Number) = conj(x) * y function dot(x::AbstractArray, y::AbstractArray) lx = length(x) if lx != length(y) - throw(DimensionMismatch("first array has length $(lx) which does not match the length of the second, $(length(y)).")) + throw(DimensionMismatch(lazy"first array has length $(lx) which does not match the length of the second, $(length(y)).")) end if lx == 0 return dot(zero(eltype(x)), zero(eltype(y))) @@ -1464,7 +1464,7 @@ julia> axpy!(2, x, y) function axpy!(α, x::AbstractArray, y::AbstractArray) n = length(x) if n != length(y) - throw(DimensionMismatch("x has length $n, but y has length $(length(y))")) + throw(DimensionMismatch(lazy"x has length $n, but y has length $(length(y))")) end iszero(α) && return y for (IY, IX) in zip(eachindex(y), eachindex(x)) @@ -1475,7 +1475,7 @@ end function axpy!(α, x::AbstractArray, rx::AbstractArray{<:Integer}, y::AbstractArray, ry::AbstractArray{<:Integer}) if length(rx) != length(ry) - throw(DimensionMismatch("rx has length $(length(rx)), but ry has length $(length(ry))")) + throw(DimensionMismatch(lazy"rx has length $(length(rx)), but ry has length $(length(ry))")) elseif !checkindex(Bool, eachindex(IndexLinear(), x), rx) throw(BoundsError(x, rx)) elseif !checkindex(Bool, eachindex(IndexLinear(), y), ry) @@ -1509,7 +1509,7 @@ julia> axpby!(2, x, 2, y) """ function axpby!(α, x::AbstractArray, β, y::AbstractArray) if length(x) != length(y) - throw(DimensionMismatch("x has length $(length(x)), but y has length $(length(y))")) + throw(DimensionMismatch(lazy"x has length $(length(x)), but y has length $(length(y))")) end iszero(α) && isone(β) && return y for (IX, IY) in zip(eachindex(x), eachindex(y)) @@ -1549,7 +1549,7 @@ function rotate!(x::AbstractVector, y::AbstractVector, c, s) require_one_based_indexing(x, y) n = length(x) if n != length(y) - throw(DimensionMismatch("x has length $(length(x)), but y has length $(length(y))")) + throw(DimensionMismatch(lazy"x has length $(length(x)), but y has length $(length(y))")) end @inbounds for i = 1:n xi, yi = x[i], y[i] @@ -1572,7 +1572,7 @@ function reflect!(x::AbstractVector, y::AbstractVector, c, s) require_one_based_indexing(x, y) n = length(x) if n != length(y) - throw(DimensionMismatch("x has length $(length(x)), but y has length $(length(y))")) + throw(DimensionMismatch(lazy"x has length $(length(x)), but y has length $(length(y))")) end @inbounds for i = 1:n xi, yi = x[i], y[i] @@ -1613,7 +1613,7 @@ Multiplies `A` in-place by a Householder reflection on the left. It is equivalen require_one_based_indexing(x) m, n = size(A, 1), size(A, 2) if length(x) != m - throw(DimensionMismatch("reflector has length $(length(x)), which must match the first dimension of matrix A, $m")) + throw(DimensionMismatch(lazy"reflector has length $(length(x)), which must match the first dimension of matrix A, $m")) end m == 0 && return A @inbounds for j = 1:n @@ -1934,7 +1934,7 @@ function copytrito!(B::AbstractMatrix, A::AbstractMatrix, uplo::AbstractChar) BLAS.chkuplo(uplo) m,n = size(A) m1,n1 = size(B) - (m1 < m || n1 < n) && throw(DimensionMismatch("B of size ($m1,$n1) should have at least the same number of rows and columns than A of size ($m,$n)")) + (m1 < m || n1 < n) && throw(DimensionMismatch(lazy"B of size ($m1,$n1) should have at least the same number of rows and columns than A of size ($m,$n)")) if uplo == 'U' for j=1:n for i=1:min(j,m) diff --git a/stdlib/LinearAlgebra/src/hessenberg.jl b/stdlib/LinearAlgebra/src/hessenberg.jl index 3be41baf24b24..f20d76e727b34 100644 --- a/stdlib/LinearAlgebra/src/hessenberg.jl +++ b/stdlib/LinearAlgebra/src/hessenberg.jl @@ -90,7 +90,7 @@ Base.@propagate_inbounds getindex(H::UpperHessenberg{T}, i::Integer, j::Integer) Base.@propagate_inbounds function setindex!(A::UpperHessenberg, x, i::Integer, j::Integer) if i > j+1 x == 0 || throw(ArgumentError("cannot set index in the lower triangular part " * - "($i, $j) of an UpperHessenberg matrix to a nonzero value ($x)")) + lazy"($i, $j) of an UpperHessenberg matrix to a nonzero value ($x)")) else A.data[i,j] = x end @@ -180,7 +180,7 @@ end function ldiv!(F::UpperHessenberg, B::AbstractVecOrMat; shift::Number=false) checksquare(F) m = size(F,1) - m != size(B,1) && throw(DimensionMismatch("wrong right-hand-side # rows != $m")) + m != size(B,1) && throw(DimensionMismatch(lazy"wrong right-hand-side # rows != $m")) require_one_based_indexing(B) n = size(B,2) H = F.data @@ -230,7 +230,7 @@ end function rdiv!(B::AbstractMatrix, F::UpperHessenberg; shift::Number=false) checksquare(F) m = size(F,1) - m != size(B,2) && throw(DimensionMismatch("wrong right-hand-side # cols != $m")) + m != size(B,2) && throw(DimensionMismatch(lazy"wrong right-hand-side # cols != $m")) require_one_based_indexing(B) n = size(B,1) H = F.data diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index 02dfa0079038b..fc8d8d67e07b4 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -26,7 +26,7 @@ Handle only negative LAPACK error codes """ function chkargsok(ret::BlasInt) if ret < 0 - throw(ArgumentError("invalid argument #$(-ret) to LAPACK call")) + throw(ArgumentError(lazy"invalid argument #$(-ret) to LAPACK call")) end end @@ -35,7 +35,7 @@ function chklapackerror(ret::BlasInt, f...) if ret == 0 return elseif ret < 0 - throw(ArgumentError("invalid argument #$(-ret) to LAPACK call")) + throw(ArgumentError(lazy"invalid argument #$(-ret) to LAPACK call")) else # ret > 0 chklapackerror_positive(ret, f...) end @@ -63,7 +63,7 @@ end function chkvalidparam(position::Int, var::String, val, validvals) if val ∉ validvals throw(ArgumentError( - "argument #$position: $var must be one of $validvals, but $(repr(val)) was passed")) + lazy"argument #$position: $var must be one of $validvals, but $(repr(val)) was passed")) end return val end @@ -71,7 +71,7 @@ end "Check that {c}transpose is correctly specified" function chktrans(trans::AbstractChar) if !(trans == 'N' || trans == 'C' || trans == 'T') - throw(ArgumentError("trans argument must be 'N' (no transpose), 'T' (transpose), or 'C' (conjugate transpose), got '$trans'")) + throw(ArgumentError(lazy"trans argument must be 'N' (no transpose), 'T' (transpose), or 'C' (conjugate transpose), got '$trans'")) end trans end @@ -79,7 +79,7 @@ end "Check that left/right hand side multiply is correctly specified" function chkside(side::AbstractChar) if !(side == 'L' || side == 'R') - throw(ArgumentError("side argument must be 'L' (left hand multiply) or 'R' (right hand multiply), got '$side'")) + throw(ArgumentError(lazy"side argument must be 'L' (left hand multiply) or 'R' (right hand multiply), got '$side'")) end side end @@ -87,7 +87,7 @@ end "Check that unit diagonal flag is correctly specified" function chkdiag(diag::AbstractChar) if !(diag == 'U' || diag =='N') - throw(ArgumentError("diag argument must be 'U' (unit diagonal) or 'N' (non-unit diagonal), got '$diag'")) + throw(ArgumentError(lazy"diag argument must be 'U' (unit diagonal) or 'N' (non-unit diagonal), got '$diag'")) end diag end @@ -178,7 +178,7 @@ for (gbtrf, gbtrs, elty) in info = Ref{BlasInt}() n = size(AB,2) if m != n || m != size(B,1) - throw(DimensionMismatch("matrix AB has dimensions $(size(AB)), but right hand side matrix B has dimensions $(size(B))")) + throw(DimensionMismatch(lazy"matrix AB has dimensions $(size(AB)), but right hand side matrix B has dimensions $(size(B))")) end ccall((@blasfunc($gbtrs), libblastrampoline), Cvoid, (Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, Ref{BlasInt}, Ref{BlasInt}, @@ -355,7 +355,7 @@ for (gebrd, gelqf, geqlf, geqrf, geqp3, geqrt, geqrt3, gerqf, getrf, elty, relty n = BlasInt(size(A, 2)) lda = BlasInt(max(1,stride(A, 2))) if length(tau) != min(m,n) - throw(DimensionMismatch("tau has length $(length(tau)), but needs length $(min(m,n))")) + throw(DimensionMismatch(lazy"tau has length $(length(tau)), but needs length $(min(m,n))")) end lwork = BlasInt(-1) work = Vector{$elty}(undef, 1) @@ -386,7 +386,7 @@ for (gebrd, gelqf, geqlf, geqrf, geqp3, geqrt, geqrt3, gerqf, getrf, elty, relty n = BlasInt(size(A, 2)) lda = BlasInt(max(1,stride(A, 2))) if length(tau) != min(m,n) - throw(DimensionMismatch("tau has length $(length(tau)), but needs length $(min(m,n))")) + throw(DimensionMismatch(lazy"tau has length $(length(tau)), but needs length $(min(m,n))")) end lwork = BlasInt(-1) work = Vector{$elty}(undef, 1) @@ -416,10 +416,10 @@ for (gebrd, gelqf, geqlf, geqrf, geqp3, geqrt, geqrt3, gerqf, getrf, elty, relty chkstride1(A,jpvt,tau) m,n = size(A) if length(tau) != min(m,n) - throw(DimensionMismatch("tau has length $(length(tau)), but needs length $(min(m,n))")) + throw(DimensionMismatch(lazy"tau has length $(length(tau)), but needs length $(min(m,n))")) end if length(jpvt) != n - throw(DimensionMismatch("jpvt has length $(length(jpvt)), but needs length $n")) + throw(DimensionMismatch(lazy"jpvt has length $(length(jpvt)), but needs length $n")) end lda = stride(A,2) if lda == 0 @@ -466,7 +466,7 @@ for (gebrd, gelqf, geqlf, geqrf, geqp3, geqrt, geqrt3, gerqf, getrf, elty, relty minmn = min(m, n) nb = size(T, 1) if nb > minmn - throw(ArgumentError("block size $nb > $minmn too large")) + throw(ArgumentError(lazy"block size $nb > $minmn too large")) end lda = max(1, stride(A,2)) work = Vector{$elty}(undef, nb*n) @@ -491,10 +491,10 @@ for (gebrd, gelqf, geqlf, geqrf, geqp3, geqrt, geqrt3, gerqf, getrf, elty, relty m, n = size(A) p, q = size(T) if m < n - throw(DimensionMismatch("input matrix A has dimensions ($m,$n), but should have more rows than columns")) + throw(DimensionMismatch(lazy"input matrix A has dimensions ($m,$n), but should have more rows than columns")) end if p != n || q != n - throw(DimensionMismatch("block reflector T has dimensions ($p,$q), but should have dimensions ($n,$n)")) + throw(DimensionMismatch(lazy"block reflector T has dimensions ($p,$q), but should have dimensions ($n,$n)")) end if n > 0 info = Ref{BlasInt}() @@ -519,7 +519,7 @@ for (gebrd, gelqf, geqlf, geqrf, geqp3, geqrt, geqrt3, gerqf, getrf, elty, relty chkstride1(A,tau) m, n = size(A) if length(tau) != min(m,n) - throw(DimensionMismatch("tau has length $(length(tau)), but needs length $(min(m,n))")) + throw(DimensionMismatch(lazy"tau has length $(length(tau)), but needs length $(min(m,n))")) end work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -548,7 +548,7 @@ for (gebrd, gelqf, geqlf, geqrf, geqp3, geqrt, geqrt3, gerqf, getrf, elty, relty chkstride1(A,tau) m, n = size(A) if length(tau) != min(m,n) - throw(DimensionMismatch("tau has length $(length(tau)), but needs length $(min(m,n))")) + throw(DimensionMismatch(lazy"tau has length $(length(tau)), but needs length $(min(m,n))")) end lwork = BlasInt(-1) work = Vector{$elty}(undef, 1) @@ -869,7 +869,7 @@ for (tzrzf, ormrz, elty) in chkstride1(A) m, n = size(A) if n < m - throw(DimensionMismatch("input matrix A has dimensions ($m,$n), but cannot have fewer columns than rows")) + throw(DimensionMismatch(lazy"input matrix A has dimensions ($m,$n), but cannot have fewer columns than rows")) end lda = max(1, stride(A,2)) tau = similar(A, $elty, m) @@ -974,7 +974,7 @@ for (gels, gesv, getrs, getri, elty) in btrn = trans == 'T' m, n = size(A) if size(B,1) != (btrn ? n : m) - throw(DimensionMismatch("matrix A has dimensions ($m,$n), transposed: $btrn, but leading dimension of B is $(size(B,1))")) + throw(DimensionMismatch(lazy"matrix A has dimensions ($m,$n), transposed: $btrn, but leading dimension of B is $(size(B,1))")) end info = Ref{BlasInt}() work = Vector{$elty}(undef, 1) @@ -1017,7 +1017,7 @@ for (gels, gesv, getrs, getri, elty) in chkstride1(A, B) n = checksquare(A) if size(B,1) != n - throw(DimensionMismatch("B has leading dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has leading dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) info = Ref{BlasInt}() @@ -1042,10 +1042,10 @@ for (gels, gesv, getrs, getri, elty) in chkstride1(A, B, ipiv) n = checksquare(A) if n != size(B, 1) - throw(DimensionMismatch("B has leading dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has leading dimension $(size(B,1)), but needs $n")) end if n != length(ipiv) - throw(DimensionMismatch("ipiv has length $(length(ipiv)), but needs to be $n")) + throw(DimensionMismatch(lazy"ipiv has length $(length(ipiv)), but needs to be $n")) end nrhs = size(B, 2) info = Ref{BlasInt}() @@ -1068,7 +1068,7 @@ for (gels, gesv, getrs, getri, elty) in chkstride1(A, ipiv) n = checksquare(A) if n != length(ipiv) - throw(DimensionMismatch("ipiv has length $(length(ipiv)), but needs $n")) + throw(DimensionMismatch(lazy"ipiv has length $(length(ipiv)), but needs $n")) end lda = max(1,stride(A, 2)) lwork = BlasInt(-1) @@ -1331,7 +1331,7 @@ for (gelsd, gelsy, elty) in chkstride1(A, B) m, n = size(A) if size(B, 1) != m - throw(DimensionMismatch("B has leading dimension $(size(B,1)) but needs $m")) + throw(DimensionMismatch(lazy"B has leading dimension $(size(B,1)) but needs $m")) end newB = [B; zeros($elty, max(0, n - size(B, 1)), size(B, 2))] s = similar(A, $elty, min(m, n)) @@ -1376,7 +1376,7 @@ for (gelsd, gelsy, elty) in n = size(A, 2) nrhs = size(B, 2) if size(B, 1) != m - throw(DimensionMismatch("B has leading dimension $(size(B,1)) but needs $m")) + throw(DimensionMismatch(lazy"B has leading dimension $(size(B,1)) but needs $m")) end newB = [B; zeros($elty, max(0, n - size(B, 1)), size(B, 2))] lda = max(1, stride(A,2)) @@ -1426,7 +1426,7 @@ for (gelsd, gelsy, elty, relty) in chkstride1(A, B) m, n = size(A) if size(B, 1) != m - throw(DimensionMismatch("B has leading dimension $(size(B,1)) but needs $m")) + throw(DimensionMismatch(lazy"B has leading dimension $(size(B,1)) but needs $m")) end newB = [B; zeros($elty, max(0, n - size(B, 1)), size(B, 2))] s = similar(A, $relty, min(m, n)) @@ -1473,7 +1473,7 @@ for (gelsd, gelsy, elty, relty) in m, n = size(A) nrhs = size(B, 2) if size(B, 1) != m - throw(DimensionMismatch("B has leading dimension $(size(B,1)) but needs $m")) + throw(DimensionMismatch(lazy"B has leading dimension $(size(B,1)) but needs $m")) end newB = [B; zeros($elty, max(0, n - size(B, 1)), size(B, 2))] lda = max(1, m) @@ -1547,13 +1547,13 @@ for (gglse, elty) in ((:dgglse_, :Float64), m, n = size(A) p = size(B, 1) if size(B, 2) != n - throw(DimensionMismatch("B has second dimension $(size(B,2)), needs $n")) + throw(DimensionMismatch(lazy"B has second dimension $(size(B,2)), needs $n")) end if length(c) != m - throw(DimensionMismatch("c has length $(length(c)), needs $m")) + throw(DimensionMismatch(lazy"c has length $(length(c)), needs $m")) end if length(d) != p - throw(DimensionMismatch("d has length $(length(d)), needs $p")) + throw(DimensionMismatch(lazy"d has length $(length(d)), needs $p")) end X = zeros($elty, n) info = Ref{BlasInt}() @@ -1823,7 +1823,7 @@ for (geev, gesvd, gesdd, ggsvd, elty, relty) in @chkvalidparam 3 jobq ('Q', 'N') m, n = size(A) if size(B, 2) != n - throw(DimensionMismatch("B has second dimension $(size(B,2)) but needs $n")) + throw(DimensionMismatch(lazy"B has second dimension $(size(B,2)) but needs $n")) end p = size(B, 1) k = Vector{BlasInt}(undef, 1) @@ -1953,7 +1953,7 @@ for (f, elty) in ((:dggsvd3_, :Float64), @chkvalidparam 3 jobq ('Q', 'N') m, n = size(A) if size(B, 2) != n - throw(DimensionMismatch("B has second dimension $(size(B,2)) but needs $n")) + throw(DimensionMismatch(lazy"B has second dimension $(size(B,2)) but needs $n")) end p = size(B, 1) k = Ref{BlasInt}() @@ -2015,7 +2015,7 @@ for (f, elty, relty) in ((:zggsvd3_, :ComplexF64, :Float64), @chkvalidparam 3 jobq ('Q', 'N') m, n = size(A) if size(B, 2) != n - throw(DimensionMismatch("B has second dimension $(size(B,2)) but needs $n")) + throw(DimensionMismatch(lazy"B has second dimension $(size(B,2)) but needs $n")) end p = size(B, 1) k = Vector{BlasInt}(undef, 1) @@ -2103,7 +2103,7 @@ for (geevx, ggev, ggev3, elty) in @chkvalidparam 1 balanc ('N', 'P', 'S', 'B') @chkvalidparam 4 sense ('N', 'E', 'V', 'B') if sense ∈ ('E', 'B') && !(jobvl == jobvr == 'V') - throw(ArgumentError("sense = '$sense' requires jobvl = 'V' and jobvr = 'V'")) + throw(ArgumentError(lazy"sense = '$sense' requires jobvl = 'V' and jobvr = 'V'")) end n = checksquare(A) ldvl = 0 @@ -2112,7 +2112,7 @@ for (geevx, ggev, ggev3, elty) in elseif jobvl == 'N' ldvl = 0 else - throw(ArgumentError("jobvl must be 'V' or 'N', but $jobvl was passed")) + throw(ArgumentError(lazy"jobvl must be 'V' or 'N', but $jobvl was passed")) end ldvr = 0 if jobvr == 'V' @@ -2120,7 +2120,7 @@ for (geevx, ggev, ggev3, elty) in elseif jobvr == 'N' ldvr = 0 else - throw(ArgumentError("jobvr must be 'V' or 'N', but $jobvr was passed")) + throw(ArgumentError(lazy"jobvr must be 'V' or 'N', but $jobvr was passed")) end chkfinite(A) # balancing routines don't support NaNs and Infs lda = max(1,stride(A,2)) @@ -2142,7 +2142,7 @@ for (geevx, ggev, ggev3, elty) in elseif sense == 'V' || sense == 'B' iworksize = 2*n - 2 else - throw(ArgumentError("sense must be 'N', 'E', 'V' or 'B', but $sense was passed")) + throw(ArgumentError(lazy"sense must be 'N', 'E', 'V' or 'B', but $sense was passed")) end iwork = Vector{BlasInt}(undef, iworksize) info = Ref{BlasInt}() @@ -2186,7 +2186,7 @@ for (geevx, ggev, ggev3, elty) in chkstride1(A,B) n, m = checksquare(A,B) if n != m - throw(DimensionMismatch("A has dimensions $(size(A)), and B has dimensions $(size(B)), but A and B must have the same size")) + throw(DimensionMismatch(lazy"A has dimensions $(size(A)), and B has dimensions $(size(B)), but A and B must have the same size")) end ldvl = 0 if jobvl == 'V' @@ -2194,7 +2194,7 @@ for (geevx, ggev, ggev3, elty) in elseif jobvl == 'N' ldvl = 1 else - throw(ArgumentError("jobvl must be 'V' or 'N', but $jobvl was passed")) + throw(ArgumentError(lazy"jobvl must be 'V' or 'N', but $jobvl was passed")) end ldvr = 0 if jobvr == 'V' @@ -2202,7 +2202,7 @@ for (geevx, ggev, ggev3, elty) in elseif jobvr == 'N' ldvr = 1 else - throw(ArgumentError("jobvr must be 'V' or 'N', but $jobvr was passed")) + throw(ArgumentError(lazy"jobvr must be 'V' or 'N', but $jobvr was passed")) end lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) @@ -2250,7 +2250,7 @@ for (geevx, ggev, ggev3, elty) in chkstride1(A,B) n, m = checksquare(A,B) if n != m - throw(DimensionMismatch("A has dimensions $(size(A)), and B has dimensions $(size(B)), but A and B must have the same size")) + throw(DimensionMismatch(lazy"A has dimensions $(size(A)), and B has dimensions $(size(B)), but A and B must have the same size")) end ldvl = 0 if jobvl == 'V' @@ -2258,7 +2258,7 @@ for (geevx, ggev, ggev3, elty) in elseif jobvl == 'N' ldvl = 1 else - throw(ArgumentError("jobvl must be 'V' or 'N', but $jobvl was passed")) + throw(ArgumentError(lazy"jobvl must be 'V' or 'N', but $jobvl was passed")) end ldvr = 0 if jobvr == 'V' @@ -2266,7 +2266,7 @@ for (geevx, ggev, ggev3, elty) in elseif jobvr == 'N' ldvr = 1 else - throw(ArgumentError("jobvr must be 'V' or 'N', but $jobvr was passed")) + throw(ArgumentError(lazy"jobvr must be 'V' or 'N', but $jobvr was passed")) end lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) @@ -2322,13 +2322,13 @@ for (geevx, ggev, ggev3, elty, relty) in function geevx!(balanc::AbstractChar, jobvl::AbstractChar, jobvr::AbstractChar, sense::AbstractChar, A::AbstractMatrix{$elty}) require_one_based_indexing(A) if balanc ∉ ('N', 'P', 'S', 'B') - throw(ArgumentError("balanc must be 'N', 'P', 'S', or 'B', but $balanc was passed")) + throw(ArgumentError(lazy"balanc must be 'N', 'P', 'S', or 'B', but $balanc was passed")) end if sense ∉ ('N','E','V','B') - throw(ArgumentError("sense must be 'N', 'E', 'V' or 'B', but $sense was passed")) + throw(ArgumentError(lazy"sense must be 'N', 'E', 'V' or 'B', but $sense was passed")) end if sense ∈ ('E', 'B') && !(jobvl == jobvr == 'V') - throw(ArgumentError("sense = '$sense' requires jobvl = 'V' and jobvr = 'V'")) + throw(ArgumentError(lazy"sense = '$sense' requires jobvl = 'V' and jobvr = 'V'")) end n = checksquare(A) ldvl = 0 @@ -2337,7 +2337,7 @@ for (geevx, ggev, ggev3, elty, relty) in elseif jobvl == 'N' ldvl = 0 else - throw(ArgumentError("jobvl must be 'V' or 'N', but $jobvl was passed")) + throw(ArgumentError(lazy"jobvl must be 'V' or 'N', but $jobvl was passed")) end ldvr = 0 if jobvr == 'V' @@ -2345,7 +2345,7 @@ for (geevx, ggev, ggev3, elty, relty) in elseif jobvr == 'N' ldvr = 0 else - throw(ArgumentError("jobvr must be 'V' or 'N', but $jobvr was passed")) + throw(ArgumentError(lazy"jobvr must be 'V' or 'N', but $jobvr was passed")) end chkfinite(A) # balancing routines don't support NaNs and Infs lda = max(1,stride(A,2)) @@ -2401,7 +2401,7 @@ for (geevx, ggev, ggev3, elty, relty) in chkstride1(A, B) n, m = checksquare(A, B) if n != m - throw(DimensionMismatch("A has dimensions $(size(A)), and B has dimensions $(size(B)), but A and B must have the same size")) + throw(DimensionMismatch(lazy"A has dimensions $(size(A)), and B has dimensions $(size(B)), but A and B must have the same size")) end ldvl = 0 if jobvl == 'V' @@ -2409,7 +2409,7 @@ for (geevx, ggev, ggev3, elty, relty) in elseif jobvl == 'N' ldvl = 1 else - throw(ArgumentError("jobvl must be 'V' or 'N', but $jobvl was passed")) + throw(ArgumentError(lazy"jobvl must be 'V' or 'N', but $jobvl was passed")) end ldvr = 0 if jobvr == 'V' @@ -2417,7 +2417,7 @@ for (geevx, ggev, ggev3, elty, relty) in elseif jobvr == 'N' ldvr = 1 else - throw(ArgumentError("jobvr must be 'V' or 'N', but $jobvr was passed")) + throw(ArgumentError(lazy"jobvr must be 'V' or 'N', but $jobvr was passed")) end lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) @@ -2466,7 +2466,7 @@ for (geevx, ggev, ggev3, elty, relty) in chkstride1(A, B) n, m = checksquare(A, B) if n != m - throw(DimensionMismatch("A has dimensions $(size(A)), and B has dimensions $(size(B)), but A and B must have the same size")) + throw(DimensionMismatch(lazy"A has dimensions $(size(A)), and B has dimensions $(size(B)), but A and B must have the same size")) end ldvl = 0 if jobvl == 'V' @@ -2474,7 +2474,7 @@ for (geevx, ggev, ggev3, elty, relty) in elseif jobvl == 'N' ldvl = 1 else - throw(ArgumentError("jobvl must be 'V' or 'N', but $jobvl was passed")) + throw(ArgumentError(lazy"jobvl must be 'V' or 'N', but $jobvl was passed")) end ldvr = 0 if jobvr == 'V' @@ -2482,7 +2482,7 @@ for (geevx, ggev, ggev3, elty, relty) in elseif jobvr == 'N' ldvr = 1 else - throw(ArgumentError("jobvr must be 'V' or 'N', but $jobvr was passed")) + throw(ArgumentError(lazy"jobvr must be 'V' or 'N', but $jobvr was passed")) end lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) @@ -2576,7 +2576,7 @@ for (laic1, elty) in @chkvalidparam 1 job (1,2) j = length(x) if j != length(w) - throw(DimensionMismatch("vectors must have same length, but length of x is $j and length of w is $(length(w))")) + throw(DimensionMismatch(lazy"vectors must have same length, but length of x is $j and length of w is $(length(w))")) end sestpr = Ref{$elty}() s = Ref{$elty}() @@ -2611,7 +2611,7 @@ for (laic1, elty, relty) in @chkvalidparam 1 job (1,2) j = length(x) if j != length(w) - throw(DimensionMismatch("vectors must have same length, but length of x is $j and length of w is $(length(w))")) + throw(DimensionMismatch(lazy"vectors must have same length, but length of x is $j and length of w is $(length(w))")) end sestpr = Ref{$relty}() s = Ref{$elty}() @@ -2646,13 +2646,13 @@ for (gtsv, gttrf, gttrs, elty) in chkstride1(B, dl, d, du) n = length(d) if !(n >= length(dl) >= n - 1) - throw(DimensionMismatch("subdiagonal has length $(length(dl)), but should be $n or $(n - 1)")) + throw(DimensionMismatch(lazy"subdiagonal has length $(length(dl)), but should be $n or $(n - 1)")) end if !(n >= length(du) >= n - 1) - throw(DimensionMismatch("superdiagonal has length $(length(du)), but should be $n or $(n - 1)")) + throw(DimensionMismatch(lazy"superdiagonal has length $(length(du)), but should be $n or $(n - 1)")) end if n != size(B,1) - throw(DimensionMismatch("B has leading dimension $(size(B,1)), but should have $n")) + throw(DimensionMismatch(lazy"B has leading dimension $(size(B,1)), but should have $n")) end if n == 0 return B # Early exit if possible @@ -2677,10 +2677,10 @@ for (gtsv, gttrf, gttrs, elty) in chkstride1(dl,d,du) n = length(d) if length(dl) != n - 1 - throw(DimensionMismatch("subdiagonal has length $(length(dl)), but should be $(n - 1)")) + throw(DimensionMismatch(lazy"subdiagonal has length $(length(dl)), but should be $(n - 1)")) end if length(du) != n - 1 - throw(DimensionMismatch("superdiagonal has length $(length(du)), but should be $(n - 1)")) + throw(DimensionMismatch(lazy"superdiagonal has length $(length(du)), but should be $(n - 1)")) end du2 = similar(d, $elty, n-2) ipiv = similar(d, BlasInt, n) @@ -2708,13 +2708,13 @@ for (gtsv, gttrf, gttrs, elty) in chkstride1(B, ipiv, dl, d, du, du2) n = length(d) if length(dl) != n - 1 - throw(DimensionMismatch("subdiagonal has length $(length(dl)), but should be $(n - 1)")) + throw(DimensionMismatch(lazy"subdiagonal has length $(length(dl)), but should be $(n - 1)")) end if length(du) != n - 1 - throw(DimensionMismatch("superdiagonal has length $(length(du)), but should be $(n - 1)")) + throw(DimensionMismatch(lazy"superdiagonal has length $(length(du)), but should be $(n - 1)")) end if n != size(B,1) - throw(DimensionMismatch("B has leading dimension $(size(B,1)), but should have $n")) + throw(DimensionMismatch(lazy"B has leading dimension $(size(B,1)), but should have $n")) end info = Ref{BlasInt}() ccall((@blasfunc($gttrs), libblastrampoline), Cvoid, @@ -2778,7 +2778,7 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in n = size(A, 2) m = min(n, size(A, 1)) if k > m - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= m = $m")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= m = $m")) end work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -2812,7 +2812,7 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in m = size(A, 1) n = min(m, size(A, 2)) if k > n - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -2848,7 +2848,7 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in m = size(A, 1) n = min(m, size(A, 2)) if k > n - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -2883,10 +2883,10 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in chkstride1(A,tau) m, n = size(A) if n < m - throw(DimensionMismatch("input matrix A has dimensions ($m,$n), but cannot have fewer columns than rows")) + throw(DimensionMismatch(lazy"input matrix A has dimensions ($m,$n), but cannot have fewer columns than rows")) end if k > n - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -2924,16 +2924,16 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in nA = size(A, 2) k = length(tau) if side == 'L' && m != nA - throw(DimensionMismatch("for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $nA")) + throw(DimensionMismatch(lazy"for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $nA")) end if side == 'R' && n != nA - throw(DimensionMismatch("for a right-sided multiplication, the second dimension of C, $n, must equal the second dimension of A, $nA")) + throw(DimensionMismatch(lazy"for a right-sided multiplication, the second dimension of C, $n, must equal the second dimension of A, $nA")) end if side == 'L' && k > m - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= m = $m")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= m = $m")) end if side == 'R' && k > n - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -2971,16 +2971,16 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in mA = size(A, 1) k = length(tau) if side == 'L' && m != mA - throw(DimensionMismatch("for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $mA")) + throw(DimensionMismatch(lazy"for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $mA")) end if side == 'R' && n != mA - throw(DimensionMismatch("for a right-sided multiplication, the second dimension of C, $m, must equal the second dimension of A, $mA")) + throw(DimensionMismatch(lazy"for a right-sided multiplication, the second dimension of C, $m, must equal the second dimension of A, $mA")) end if side == 'L' && k > m - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= m = $m")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= m = $m")) end if side == 'R' && k > n - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -3021,16 +3021,16 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in mA = size(A, 1) k = length(tau) if side == 'L' && m != mA - throw(DimensionMismatch("for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $mA")) + throw(DimensionMismatch(lazy"for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $mA")) end if side == 'R' && n != mA - throw(DimensionMismatch("for a right-sided multiplication, the second dimension of C, $m, must equal the second dimension of A, $mA")) + throw(DimensionMismatch(lazy"for a right-sided multiplication, the second dimension of C, $m, must equal the second dimension of A, $mA")) end if side == 'L' && k > m - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= m = $m")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= m = $m")) end if side == 'R' && k > n - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -3071,16 +3071,16 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in nA = size(A, 2) k = length(tau) if side == 'L' && m != nA - throw(DimensionMismatch("for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $nA")) + throw(DimensionMismatch(lazy"for a left-sided multiplication, the first dimension of C, $m, must equal the second dimension of A, $nA")) end if side == 'R' && n != nA - throw(DimensionMismatch("for a right-sided multiplication, the second dimension of C, $m, must equal the second dimension of A, $nA")) + throw(DimensionMismatch(lazy"for a right-sided multiplication, the second dimension of C, $m, must equal the second dimension of A, $nA")) end if side == 'L' && k > m - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= m = $m")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= m = $m")) end if side == 'R' && k > n - throw(DimensionMismatch("invalid number of reflectors: k = $k should be <= n = $n")) + throw(DimensionMismatch(lazy"invalid number of reflectors: k = $k should be <= n = $n")) end work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -3113,31 +3113,31 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in end if side == 'L' if !(0 <= k <= m) - throw(DimensionMismatch("wrong value for k = $k: must be between 0 and $m")) + throw(DimensionMismatch(lazy"wrong value for k = $k: must be between 0 and $m")) end if m != size(V,1) - throw(DimensionMismatch("first dimensions of C, $m, and V, $(size(V,1)) must match")) + throw(DimensionMismatch(lazy"first dimensions of C, $m, and V, $(size(V,1)) must match")) end ldv = stride(V,2) if ldv < max(1, m) - throw(DimensionMismatch("Q and C don't fit! The stride of V, $ldv, is too small")) + throw(DimensionMismatch(lazy"Q and C don't fit! The stride of V, $ldv, is too small")) end wss = n*k elseif side == 'R' if !(0 <= k <= n) - throw(DimensionMismatch("wrong value for k = $k: must be between 0 and $n")) + throw(DimensionMismatch(lazy"wrong value for k = $k: must be between 0 and $n")) end if n != size(V,1) - throw(DimensionMismatch("second dimension of C, $n, and first dimension of V, $(size(V,1)) must match")) + throw(DimensionMismatch(lazy"second dimension of C, $n, and first dimension of V, $(size(V,1)) must match")) end ldv = stride(V,2) if ldv < max(1, n) - throw(DimensionMismatch("Q and C don't fit! The stride of V, $ldv, is too small")) + throw(DimensionMismatch(lazy"Q and C don't fit! The stride of V, $ldv, is too small")) end wss = m*k end if !(1 <= nb <= k) - throw(DimensionMismatch("wrong value for nb = $nb, which must be between 1 and $k")) + throw(DimensionMismatch(lazy"wrong value for nb = $nb, which must be between 1 and $k")) end ldc = stride(C, 2) work = Vector{$elty}(undef, wss) @@ -3258,7 +3258,7 @@ for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in n = checksquare(A) chkuplo(uplo) if size(B,1) != n - throw(DimensionMismatch("first dimension of B, $(size(B,1)), and size of A, ($n,$n), must match!")) + throw(DimensionMismatch(lazy"first dimension of B, $(size(B,1)), and size of A, ($n,$n), must match!")) end info = Ref{BlasInt}() ccall((@blasfunc($posv), libblastrampoline), Cvoid, @@ -3328,7 +3328,7 @@ for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in chkuplo(uplo) nrhs = size(B,2) if size(B,1) != n - throw(DimensionMismatch("first dimension of B, $(size(B,1)), and size of A, ($n,$n), must match!")) + throw(DimensionMismatch(lazy"first dimension of B, $(size(B,1)), and size of A, ($n,$n), must match!")) end lda = max(1,stride(A,2)) if lda == 0 || nrhs == 0 @@ -3445,10 +3445,10 @@ for (ptsv, pttrf, elty, relty) in chkstride1(B, D, E) n = length(D) if length(E) != n - 1 - throw(DimensionMismatch("E has length $(length(E)), but needs $(n - 1)")) + throw(DimensionMismatch(lazy"E has length $(length(E)), but needs $(n - 1)")) end if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)) but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)) but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($ptsv), libblastrampoline), Cvoid, @@ -3469,7 +3469,7 @@ for (ptsv, pttrf, elty, relty) in chkstride1(D, E) n = length(D) if length(E) != n - 1 - throw(DimensionMismatch("E has length $(length(E)), but needs $(n - 1)")) + throw(DimensionMismatch(lazy"E has length $(length(E)), but needs $(n - 1)")) end info = Ref{BlasInt}() ccall((@blasfunc($pttrf), libblastrampoline), Cvoid, @@ -3513,10 +3513,10 @@ for (pttrs, elty, relty) in chkstride1(B, D, E) n = length(D) if length(E) != n - 1 - throw(DimensionMismatch("E has length $(length(E)), but needs $(n - 1)")) + throw(DimensionMismatch(lazy"E has length $(length(E)), but needs $(n - 1)")) end if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)) but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)) but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($pttrs), libblastrampoline), Cvoid, @@ -3547,10 +3547,10 @@ for (pttrs, elty, relty) in chkuplo(uplo) n = length(D) if length(E) != n - 1 - throw(DimensionMismatch("E has length $(length(E)), but needs $(n - 1)")) + throw(DimensionMismatch(lazy"E has length $(length(E)), but needs $(n - 1)")) end if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)) but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)) but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($pttrs), libblastrampoline), Cvoid, @@ -3616,7 +3616,7 @@ for (trtri, trtrs, elty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)) but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)) but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($trtrs), libblastrampoline), Cvoid, @@ -3707,7 +3707,7 @@ for (trcon, trevc, trrfs, elty) in require_one_based_indexing(select, T, VL, VR) # Extract if side ∉ ('L','R','B') - throw(ArgumentError("side argument must be 'L' (left eigenvectors), 'R' (right eigenvectors), or 'B' (both), got $side")) + throw(ArgumentError(lazy"side argument must be 'L' (left eigenvectors), 'R' (right eigenvectors), or 'B' (both), got $side")) end @chkvalidparam 2 howmny ('A', 'B', 'S') n, mm = checksquare(T), size(VL, 2) @@ -3773,7 +3773,7 @@ for (trcon, trevc, trrfs, elty) in n = size(A,2) nrhs = size(B,2) if nrhs != size(X,2) - throw(DimensionMismatch("second dimensions of B, $nrhs, and X, $(size(X,2)), must match")) + throw(DimensionMismatch(lazy"second dimensions of B, $nrhs, and X, $(size(X,2)), must match")) end work = Vector{$elty}(undef, 3n) iwork = Vector{BlasInt}(undef, n) @@ -3849,7 +3849,7 @@ for (trcon, trevc, trrfs, elty, relty) in # Check chkstride1(T, select, VL, VR) if side ∉ ('L','R','B') - throw(ArgumentError("side argument must be 'L' (left eigenvectors), 'R' (right eigenvectors), or 'B' (both), got $side")) + throw(ArgumentError(lazy"side argument must be 'L' (left eigenvectors), 'R' (right eigenvectors), or 'B' (both), got $side")) end @chkvalidparam 2 howmny ('A', 'B', 'S') @@ -3910,7 +3910,7 @@ for (trcon, trevc, trrfs, elty, relty) in n = size(A,2) nrhs = size(B,2) if nrhs != size(X,2) - throw(DimensionMismatch("second dimensions of B, $nrhs, and X, $(size(X,2)), must match")) + throw(DimensionMismatch(lazy"second dimensions of B, $nrhs, and X, $(size(X,2)), must match")) end work = Vector{$elty}(undef, 2n) rwork = Vector{$relty}(undef, n) @@ -3982,7 +3982,7 @@ for (stev, stebz, stegr, stein, elty) in chkstride1(dv, ev) n = length(dv) if length(ev) != n - 1 && length(ev) != n - throw(DimensionMismatch("ev has length $(length(ev)) but needs one less than or equal to dv's length, $n)")) + throw(DimensionMismatch(lazy"ev has length $(length(ev)) but needs one less than or equal to dv's length, $n)")) end Zmat = similar(dv, $elty, (n, job != 'N' ? n : 0)) work = Vector{$elty}(undef, max(1, 2n-2)) @@ -4006,7 +4006,7 @@ for (stev, stebz, stegr, stein, elty) in chkstride1(dv, ev) n = length(dv) if length(ev) != n - 1 - throw(DimensionMismatch("ev has length $(length(ev)) but needs one less than dv's length, $n)")) + throw(DimensionMismatch(lazy"ev has length $(length(ev)) but needs one less than dv's length, $n)")) end m = Ref{BlasInt}() nsplit = Vector{BlasInt}(undef, 1) @@ -4045,7 +4045,7 @@ for (stev, stebz, stegr, stein, elty) in eev = copy(ev) eev[n] = zero($elty) else - throw(DimensionMismatch("ev has length $ne but needs one less than or equal to dv's length, $n)")) + throw(DimensionMismatch(lazy"ev has length $ne but needs one less than or equal to dv's length, $n)")) end abstol = Vector{$elty}(undef, 1) @@ -4095,12 +4095,12 @@ for (stev, stebz, stegr, stein, elty) in ev = copy(ev_in) ev[n] = zero($elty) else - throw(DimensionMismatch("ev_in has length $ne but needs one less than or equal to dv's length, $n)")) + throw(DimensionMismatch(lazy"ev_in has length $ne but needs one less than or equal to dv's length, $n)")) end ldz = n #Leading dimension #Number of eigenvalues to find if !(1 <= length(w_in) <= n) - throw(DimensionMismatch("w_in has length $(length(w_in)), but needs to be between 1 and $n")) + throw(DimensionMismatch(lazy"w_in has length $(length(w_in)), but needs to be between 1 and $n")) end m = length(w_in) #If iblock and isplit are invalid input, assume worst-case block partitioning, @@ -4236,7 +4236,7 @@ for (syconv, sysv, sytrf, sytri, sytrs, elty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(undef, 1) @@ -4365,7 +4365,7 @@ for (syconv, sysv, sytrf, sytri, sytrs, elty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($sytrs), libblastrampoline), Cvoid, @@ -4397,7 +4397,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(undef, 1) @@ -4490,7 +4490,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($sytrs), libblastrampoline), Cvoid, @@ -4524,10 +4524,10 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty) in throw(ArgumentError("way must be C or R")) end if length(ipiv) != n - throw(ArgumentError("length of pivot vector was $(length(ipiv)) but should have been $n")) + throw(ArgumentError(lazy"length of pivot vector was $(length(ipiv)) but should have been $n")) end if length(e) != n - throw(ArgumentError("length of e vector was $(length(e)) but should have been $n")) + throw(ArgumentError(lazy"length of e vector was $(length(e)) but should have been $n")) end # allocate @@ -4591,7 +4591,7 @@ for (syconv, hesv, hetrf, hetri, hetrs, elty, relty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(undef, 1) @@ -4718,7 +4718,7 @@ for (syconv, hesv, hetrf, hetri, hetrs, elty, relty) in chkstride1(A,B,ipiv) n = checksquare(A) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($hetrs), libblastrampoline), Cvoid, @@ -4749,7 +4749,7 @@ for (hesv, hetrf, hetri, hetrs, elty, relty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(undef, 1) @@ -4839,7 +4839,7 @@ for (hesv, hetrf, hetri, hetrs, elty, relty) in chkuplo(uplo) n = checksquare(A) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($hetrs), libblastrampoline), Cvoid, @@ -4871,7 +4871,7 @@ for (sysv, sytrf, sytri, sytrs, elty, relty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(undef, 1) @@ -5001,7 +5001,7 @@ for (sysv, sytrf, sytri, sytrs, elty, relty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($sytrs), libblastrampoline), Cvoid, @@ -5033,7 +5033,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty, relty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end ipiv = similar(A, BlasInt, n) work = Vector{$elty}(undef, 1) @@ -5127,7 +5127,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty, relty) in n = checksquare(A) chkuplo(uplo) if n != size(B,1) - throw(DimensionMismatch("B has first dimension $(size(B,1)), but needs $n")) + throw(DimensionMismatch(lazy"B has first dimension $(size(B,1)), but needs $n")) end info = Ref{BlasInt}() ccall((@blasfunc($sytrs), libblastrampoline), Cvoid, @@ -5160,13 +5160,13 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty, relty) in # check chkuplo(uplo) if way != 'C' && way != 'R' - throw(ArgumentError("way must be 'C' or 'R'")) + throw(ArgumentError(lazy"way must be 'C' or 'R'")) end if length(ipiv) != n - throw(ArgumentError("length of pivot vector was $(length(ipiv)) but should have been $n")) + throw(ArgumentError(lazy"length of pivot vector was $(length(ipiv)) but should have been $n")) end if length(e) != n - throw(ArgumentError("length of e vector was $(length(e)) but should have been $n")) + throw(ArgumentError(lazy"length of e vector was $(length(e)) but should have been $n")) end # allocate @@ -5368,10 +5368,10 @@ for (syev, syevr, syevd, sygvd, elty) in chkstride1(A) n = checksquare(A) if range == 'I' && !(1 <= il <= iu <= n) - throw(ArgumentError("illegal choice of eigenvalue indices (il = $il, iu = $iu), which must be between 1 and n = $n")) + throw(ArgumentError(lazy"illegal choice of eigenvalue indices (il = $il, iu = $iu), which must be between 1 and n = $n")) end if range == 'V' && vl >= vu - throw(ArgumentError("lower boundary, $vl, must be less than upper boundary, $vu")) + throw(ArgumentError(lazy"lower boundary, $vl, must be less than upper boundary, $vu")) end chkuplofinite(A, uplo) lda = stride(A,2) @@ -5476,7 +5476,7 @@ for (syev, syevr, syevd, sygvd, elty) in chkstride1(A, B) n, m = checksquare(A, B) if n != m - throw(DimensionMismatch("dimensions of A, ($n,$n), and B, ($m,$m), must match")) + throw(DimensionMismatch(lazy"dimensions of A, ($n,$n), and B, ($m,$m), must match")) end lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) @@ -5571,10 +5571,10 @@ for (syev, syevr, syevd, sygvd, elty, relty) in chkuplofinite(A, uplo) n = checksquare(A) if range == 'I' && !(1 <= il <= iu <= n) - throw(ArgumentError("illegal choice of eigenvalue indices (il = $il, iu=$iu), which must be between 1 and n = $n")) + throw(ArgumentError(lazy"illegal choice of eigenvalue indices (il = $il, iu=$iu), which must be between 1 and n = $n")) end if range == 'V' && vl >= vu - throw(ArgumentError("lower boundary, $vl, must be less than upper boundary, $vu")) + throw(ArgumentError(lazy"lower boundary, $vl, must be less than upper boundary, $vu")) end lda = max(1,stride(A,2)) m = Ref{BlasInt}() @@ -5691,7 +5691,7 @@ for (syev, syevr, syevd, sygvd, elty, relty) in chkuplofinite(B, uplo) n, m = checksquare(A, B) if n != m - throw(DimensionMismatch("dimensions of A, ($n,$n), and B, ($m,$m), must match")) + throw(DimensionMismatch(lazy"dimensions of A, ($n,$n), and B, ($m,$m), must match")) end lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) @@ -5802,19 +5802,19 @@ for (bdsqr, relty, elty) in # Do checks chkuplo(uplo) if length(e_) != n - 1 - throw(DimensionMismatch("off-diagonal has length $(length(e_)) but should have length $(n - 1)")) + throw(DimensionMismatch(lazy"off-diagonal has length $(length(e_)) but should have length $(n - 1)")) end if ncvt > 0 && ldvt < n - throw(DimensionMismatch("leading dimension of Vt, $ldvt, must be at least $n")) + throw(DimensionMismatch(lazy"leading dimension of Vt, $ldvt, must be at least $n")) end if ldu < nru - throw(DimensionMismatch("leading dimension of U, $ldu, must be at least $nru")) + throw(DimensionMismatch(lazy"leading dimension of U, $ldu, must be at least $nru")) end if size(U, 2) != n - throw(DimensionMismatch("U must have $n columns but has $(size(U, 2))")) + throw(DimensionMismatch(lazy"U must have $n columns but has $(size(U, 2))")) end if ncc > 0 && ldc < n - throw(DimensionMismatch("leading dimension of C, $ldc, must be at least $n")) + throw(DimensionMismatch(lazy"leading dimension of C, $ldc, must be at least $n")) end # Allocate work = Vector{$relty}(undef, 4n) @@ -5881,7 +5881,7 @@ for (bdsdc, elty) in ldvt=ldu=max(1, n) lwork=3*n^2 + 4*n else - throw(ArgumentError("COMPQ argument must be 'N', 'P' or 'I', got $(repr(compq))")) + throw(ArgumentError(lazy"COMPQ argument must be 'N', 'P' or 'I', got $(repr(compq))")) end u = similar(d, $elty, (ldu, n)) vt = similar(d, $elty, (ldvt, n)) @@ -6069,7 +6069,7 @@ for (orghr, elty) in chkstride1(A, tau) n = checksquare(A) if n - length(tau) != 1 - throw(DimensionMismatch("tau has length $(length(tau)), needs $(n - 1)")) + throw(DimensionMismatch(lazy"tau has length $(length(tau)), needs $(n - 1)")) end work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -6124,7 +6124,7 @@ for (ormhr, elty) in mC, nC = size(C, 1), size(C, 2) if n - length(tau) != 1 - throw(DimensionMismatch("tau has length $(length(tau)), needs $(n - 1)")) + throw(DimensionMismatch(lazy"tau has length $(length(tau)), needs $(n - 1)")) end if (side == 'L' && mC != n) || (side == 'R' && nC != n) throw(DimensionMismatch("A and C matrices are not conformable")) @@ -6326,7 +6326,7 @@ for (orgtr, elty) in chkstride1(A, tau) n = checksquare(A) if n - length(tau) != 1 - throw(DimensionMismatch("tau has length $(length(tau)), needs $(n - 1)")) + throw(DimensionMismatch(lazy"tau has length $(length(tau)), needs $(n - 1)")) end chkuplo(uplo) work = Vector{$elty}(undef, 1) @@ -6383,10 +6383,10 @@ for (ormtr, elty) in mC, nC = size(C, 1), size(C, 2) if n - length(tau) != 1 - throw(DimensionMismatch("tau has length $(length(tau)), needs $(n - 1)")) + throw(DimensionMismatch(lazy"tau has length $(length(tau)), needs $(n - 1)")) end if (side == 'L' && mC != n) || (side == 'R' && nC != n) - throw(DimensionMismatch("A and C matrices are not conformable")) + throw(DimensionMismatch(lazy"A and C matrices are not conformable")) end work = Vector{$elty}(undef, 1) @@ -6473,7 +6473,7 @@ for (gees, gges, gges3, elty) in chkstride1(A, B) n, m = checksquare(A, B) if n != m - throw(DimensionMismatch("dimensions of A, ($n,$n), and B, ($m,$m), must match")) + throw(DimensionMismatch(lazy"dimensions of A, ($n,$n), and B, ($m,$m), must match")) end sdim = BlasInt(0) alphar = similar(A, $elty, n) @@ -6525,7 +6525,7 @@ for (gees, gges, gges3, elty) in chkstride1(A, B) n, m = checksquare(A, B) if n != m - throw(DimensionMismatch("dimensions of A, ($n,$n), and B, ($m,$m), must match")) + throw(DimensionMismatch(lazy"dimensions of A, ($n,$n), and B, ($m,$m), must match")) end sdim = BlasInt(0) alphar = similar(A, $elty, n) @@ -6625,7 +6625,7 @@ for (gees, gges, gges3, elty, relty) in chkstride1(A, B) n, m = checksquare(A, B) if n != m - throw(DimensionMismatch("dimensions of A, ($n,$n), and B, ($m,$m), must match")) + throw(DimensionMismatch(lazy"dimensions of A, ($n,$n), and B, ($m,$m), must match")) end sdim = BlasInt(0) alpha = similar(A, $elty, n) @@ -6678,7 +6678,7 @@ for (gees, gges, gges3, elty, relty) in chkstride1(A, B) n, m = checksquare(A, B) if n != m - throw(DimensionMismatch("dimensions of A, ($n,$n), and B, ($m,$m), must match")) + throw(DimensionMismatch(lazy"dimensions of A, ($n,$n), and B, ($m,$m), must match")) end sdim = BlasInt(0) alpha = similar(A, $elty, n) @@ -6859,13 +6859,13 @@ for (trexc, trsen, tgsen, elty) in chkstride1(select, S, T, Q, Z) n, nt, nq, nz = checksquare(S, T, Q, Z) if n != nt - throw(DimensionMismatch("dimensions of S, ($n,$n), and T, ($nt,$nt), must match")) + throw(DimensionMismatch(lazy"dimensions of S, ($n,$n), and T, ($nt,$nt), must match")) end if n != nq - throw(DimensionMismatch("dimensions of S, ($n,$n), and Q, ($nq,$nq), must match")) + throw(DimensionMismatch(lazy"dimensions of S, ($n,$n), and Q, ($nq,$nq), must match")) end if n != nz - throw(DimensionMismatch("dimensions of S, ($n,$n), and Z, ($nz,$nz), must match")) + throw(DimensionMismatch(lazy"dimensions of S, ($n,$n), and Z, ($nz,$nz), must match")) end lds = max(1, stride(S, 2)) ldt = max(1, stride(T, 2)) @@ -7010,13 +7010,13 @@ for (trexc, trsen, tgsen, elty, relty) in chkstride1(select, S, T, Q, Z) n, nt, nq, nz = checksquare(S, T, Q, Z) if n != nt - throw(DimensionMismatch("dimensions of S, ($n,$n), and T, ($nt,$nt), must match")) + throw(DimensionMismatch(lazy"dimensions of S, ($n,$n), and T, ($nt,$nt), must match")) end if n != nq - throw(DimensionMismatch("dimensions of S, ($n,$n), and Q, ($nq,$nq), must match")) + throw(DimensionMismatch(lazy"dimensions of S, ($n,$n), and Q, ($nq,$nq), must match")) end if n != nz - throw(DimensionMismatch("dimensions of S, ($n,$n), and Z, ($nz,$nz), must match")) + throw(DimensionMismatch(lazy"dimensions of S, ($n,$n), and Z, ($nz,$nz), must match")) end lds = max(1, stride(S, 2)) ldt = max(1, stride(T, 2)) @@ -7115,7 +7115,7 @@ for (fn, elty, relty) in ((:dtrsyl_, :Float64, :Float64), ldb = max(1, stride(B, 2)) m1, n1 = size(C) if m != m1 || n != n1 - throw(DimensionMismatch("dimensions of A, ($m,$n), and C, ($m1,$n1), must match")) + throw(DimensionMismatch(lazy"dimensions of A, ($m,$n), and C, ($m1,$n1), must match")) end ldc = max(1, stride(C, 2)) scale = Ref{$relty}() @@ -7165,7 +7165,7 @@ for (fn, elty) in ((:dlacpy_, :Float64), chkstride1(A, B) m,n = size(A) m1,n1 = size(B) - (m1 < m || n1 < n) && throw(DimensionMismatch("B of size ($m1,$n1) should have at least the same number of rows and columns than A of size ($m,$n)")) + (m1 < m || n1 < n) && throw(DimensionMismatch(lazy"B of size ($m1,$n1) should have at least the same number of rows and columns than A of size ($m,$n)")) lda = max(1, stride(A, 2)) ldb = max(1, stride(B, 2)) ccall((@blasfunc($fn), libblastrampoline), Cvoid, diff --git a/stdlib/LinearAlgebra/src/lbt.jl b/stdlib/LinearAlgebra/src/lbt.jl index b133741611adc..aadcb45d606a3 100644 --- a/stdlib/LinearAlgebra/src/lbt.jl +++ b/stdlib/LinearAlgebra/src/lbt.jl @@ -247,11 +247,11 @@ If the given `symbol_name` is not contained within the list of exported symbols, function lbt_find_backing_library(symbol_name, interface::Symbol; config::LBTConfig = lbt_get_config()) if interface ∉ (:ilp64, :lp64) - throw(ArgumentError("Invalid interface specification: '$(interface)'")) + throw(ArgumentError(lazy"Invalid interface specification: '$(interface)'")) end symbol_idx = findfirst(s -> s == symbol_name, config.exported_symbols) if symbol_idx === nothing - throw(ArgumentError("Invalid exported symbol name '$(symbol_name)'")) + throw(ArgumentError(lazy"Invalid exported symbol name '$(symbol_name)'")) end # Convert to zero-indexed symbol_idx -= 1 diff --git a/stdlib/LinearAlgebra/src/ldlt.jl b/stdlib/LinearAlgebra/src/ldlt.jl index d3d6234961c44..89e57d0dd27eb 100644 --- a/stdlib/LinearAlgebra/src/ldlt.jl +++ b/stdlib/LinearAlgebra/src/ldlt.jl @@ -175,7 +175,7 @@ function ldiv!(S::LDLt{<:Any,<:SymTridiagonal}, B::AbstractVecOrMat) require_one_based_indexing(B) n, nrhs = size(B, 1), size(B, 2) if size(S,1) != n - throw(DimensionMismatch("Matrix has dimensions $(size(S)) but right hand side has first dimension $n")) + throw(DimensionMismatch(lazy"Matrix has dimensions $(size(S)) but right hand side has first dimension $n")) end d = S.data.dv l = S.data.ev diff --git a/stdlib/LinearAlgebra/src/lu.jl b/stdlib/LinearAlgebra/src/lu.jl index be32f1e863ff1..d2e82af5d6409 100644 --- a/stdlib/LinearAlgebra/src/lu.jl +++ b/stdlib/LinearAlgebra/src/lu.jl @@ -95,6 +95,11 @@ end function lu!(A::HermOrSym{T}, pivot::Union{RowMaximum,NoPivot,RowNonZero} = lupivottype(T); check::Bool = true, allowsingular::Bool = false) where {T} copytri!(A.data, A.uplo, isa(A, Hermitian)) + @inbounds if isa(A, Hermitian) # realify diagonal + for i in axes(A, 1) + A.data[i,i] = A[i,i] + end + end lu!(A.data, pivot; check, allowsingular) end # for backward compatibility @@ -680,7 +685,7 @@ function ldiv!(A::LU{T,Tridiagonal{T,V}}, B::AbstractVecOrMat) where {T,V} require_one_based_indexing(B) n = size(A,1) if n != size(B,1) - throw(DimensionMismatch("matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) + throw(DimensionMismatch(lazy"matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) end nrhs = size(B,2) dl = A.factors.dl @@ -713,7 +718,7 @@ function ldiv!(transA::TransposeFactorization{<:Any,<:LU{T,Tridiagonal{T,V}}}, B A = transA.parent n = size(A,1) if n != size(B,1) - throw(DimensionMismatch("matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) + throw(DimensionMismatch(lazy"matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) end nrhs = size(B,2) dl = A.factors.dl @@ -750,7 +755,7 @@ function ldiv!(adjA::AdjointFactorization{<:Any,<:LU{T,Tridiagonal{T,V}}}, B::Ab A = adjA.parent n = size(A,1) if n != size(B,1) - throw(DimensionMismatch("matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) + throw(DimensionMismatch(lazy"matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) end nrhs = size(B,2) dl = A.factors.dl diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 95a24b0d798ea..9c74addd6b69c 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -364,14 +364,18 @@ lmul!(A, B) # aggressive constant propagation makes mul!(C, A, B) invoke gemm_wrapper! directly Base.@constprop :aggressive function generic_matmatmul!(C::StridedMatrix{T}, tA, tB, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}, _add::MulAddMul=MulAddMul()) where {T<:BlasFloat} - if all(in(('N', 'T', 'C')), (tA, tB)) - if tA == 'T' && tB == 'N' && A === B + # We convert the chars to uppercase to potentially unwrap a WrapperChar, + # and extract the char corresponding to the wrapper type + tA_uc, tB_uc = uppercase(tA), uppercase(tB) + # the map in all ensures constprop by acting on tA and tB individually, instead of looping over them. + if all(map(in(('N', 'T', 'C')), (tA_uc, tB_uc))) + if tA_uc == 'T' && tB_uc == 'N' && A === B return syrk_wrapper!(C, 'T', A, _add) - elseif tA == 'N' && tB == 'T' && A === B + elseif tA_uc == 'N' && tB_uc == 'T' && A === B return syrk_wrapper!(C, 'N', A, _add) - elseif tA == 'C' && tB == 'N' && A === B + elseif tA_uc == 'C' && tB_uc == 'N' && A === B return herk_wrapper!(C, 'C', A, _add) - elseif tA == 'N' && tB == 'C' && A === B + elseif tA_uc == 'N' && tB_uc == 'C' && A === B return herk_wrapper!(C, 'N', A, _add) else return gemm_wrapper!(C, tA, tB, A, B, _add) @@ -379,13 +383,13 @@ Base.@constprop :aggressive function generic_matmatmul!(C::StridedMatrix{T}, tA, end alpha, beta = promote(_add.alpha, _add.beta, zero(T)) if alpha isa Union{Bool,T} && beta isa Union{Bool,T} - if (tA == 'S' || tA == 's') && tB == 'N' + if tA_uc == 'S' && tB_uc == 'N' return BLAS.symm!('L', tA == 'S' ? 'U' : 'L', alpha, A, B, beta, C) - elseif (tB == 'S' || tB == 's') && tA == 'N' + elseif tA_uc == 'N' && tB_uc == 'S' return BLAS.symm!('R', tB == 'S' ? 'U' : 'L', alpha, B, A, beta, C) - elseif (tA == 'H' || tA == 'h') && tB == 'N' + elseif tA_uc == 'H' && tB_uc == 'N' return BLAS.hemm!('L', tA == 'H' ? 'U' : 'L', alpha, A, B, beta, C) - elseif (tB == 'H' || tB == 'h') && tA == 'N' + elseif tA_uc == 'N' && tB_uc == 'H' return BLAS.hemm!('R', tB == 'H' ? 'U' : 'L', alpha, B, A, beta, C) end end @@ -395,7 +399,11 @@ end # Complex matrix times (transposed) real matrix. Reinterpret the first matrix to real for efficiency. Base.@constprop :aggressive function generic_matmatmul!(C::StridedVecOrMat{Complex{T}}, tA, tB, A::StridedVecOrMat{Complex{T}}, B::StridedVecOrMat{T}, _add::MulAddMul=MulAddMul()) where {T<:BlasReal} - if all(in(('N', 'T', 'C')), (tA, tB)) + # We convert the chars to uppercase to potentially unwrap a WrapperChar, + # and extract the char corresponding to the wrapper type + tA_uc, tB_uc = uppercase(tA), uppercase(tB) + # the map in all ensures constprop by acting on tA and tB individually, instead of looping over them. + if all(map(in(('N', 'T', 'C')), (tA_uc, tB_uc))) gemm_wrapper!(C, tA, tB, A, B, _add) else _generic_matmatmul!(C, wrap(A, tA), wrap(B, tB), _add) @@ -434,18 +442,19 @@ Base.@constprop :aggressive function gemv!(y::StridedVector{T}, tA::AbstractChar mA == 0 && return y nA == 0 && return _rmul_or_fill!(y, β) alpha, beta = promote(α, β, zero(T)) + tA_uc = uppercase(tA) # potentially convert a WrapperChar to a Char if alpha isa Union{Bool,T} && beta isa Union{Bool,T} && stride(A, 1) == 1 && abs(stride(A, 2)) >= size(A, 1) && !iszero(stride(x, 1)) && # We only check input's stride here. - if tA in ('N', 'T', 'C') + if tA_uc in ('N', 'T', 'C') return BLAS.gemv!(tA, alpha, A, x, beta, y) - elseif tA in ('S', 's') + elseif tA_uc == 'S' return BLAS.symv!(tA == 'S' ? 'U' : 'L', alpha, A, x, beta, y) - elseif tA in ('H', 'h') + elseif tA_uc == 'H' return BLAS.hemv!(tA == 'H' ? 'U' : 'L', alpha, A, x, beta, y) end end - if tA in ('S', 's', 'H', 'h') + if tA_uc in ('S', 'H') # re-wrap again and use plain ('N') matvec mul algorithm, # because _generic_matvecmul! can't handle the HermOrSym cases specifically return _generic_matvecmul!(y, 'N', wrap(A, tA), x, MulAddMul(α, β)) @@ -464,14 +473,15 @@ Base.@constprop :aggressive function gemv!(y::StridedVector{Complex{T}}, tA::Abs mA == 0 && return y nA == 0 && return _rmul_or_fill!(y, β) alpha, beta = promote(α, β, zero(T)) + tA_uc = uppercase(tA) # potentially convert a WrapperChar to a Char if alpha isa Union{Bool,T} && beta isa Union{Bool,T} && stride(A, 1) == 1 && abs(stride(A, 2)) >= size(A, 1) && - stride(y, 1) == 1 && tA == 'N' && # reinterpret-based optimization is valid only for contiguous `y` + stride(y, 1) == 1 && tA_uc == 'N' && # reinterpret-based optimization is valid only for contiguous `y` !iszero(stride(x, 1)) BLAS.gemv!(tA, alpha, reinterpret(T, A), x, beta, reinterpret(T, y)) return y else - Anew, ta = tA in ('S', 's', 'H', 'h') ? (wrap(A, tA), 'N') : (A, tA) + Anew, ta = tA_uc in ('S', 'H') ? (wrap(A, tA), oftype(tA, 'N')) : (A, tA) return _generic_matvecmul!(y, ta, Anew, x, MulAddMul(α, β)) end end @@ -487,15 +497,16 @@ Base.@constprop :aggressive function gemv!(y::StridedVector{Complex{T}}, tA::Abs mA == 0 && return y nA == 0 && return _rmul_or_fill!(y, β) alpha, beta = promote(α, β, zero(T)) + tA_uc = uppercase(tA) # potentially convert a WrapperChar to a Char @views if alpha isa Union{Bool,T} && beta isa Union{Bool,T} && stride(A, 1) == 1 && abs(stride(A, 2)) >= size(A, 1) && - !iszero(stride(x, 1)) && tA in ('N', 'T', 'C') + !iszero(stride(x, 1)) && tA_uc in ('N', 'T', 'C') xfl = reinterpret(reshape, T, x) # Use reshape here. yfl = reinterpret(reshape, T, y) BLAS.gemv!(tA, alpha, A, xfl[1, :], beta, yfl[1, :]) BLAS.gemv!(tA, alpha, A, xfl[2, :], beta, yfl[2, :]) return y - elseif tA in ('S', 's', 'H', 'h') + elseif tA_uc in ('S', 'H') # re-wrap again and use plain ('N') matvec mul algorithm, # because _generic_matvecmul! can't handle the HermOrSym cases specifically return _generic_matvecmul!(y, 'N', wrap(A, tA), x, MulAddMul(α, β)) @@ -504,10 +515,13 @@ Base.@constprop :aggressive function gemv!(y::StridedVector{Complex{T}}, tA::Abs end end -function syrk_wrapper!(C::StridedMatrix{T}, tA::AbstractChar, A::StridedVecOrMat{T}, +# the aggressive constprop pushes tA and tB into gemm_wrapper!, which is needed for wrap calls within it +# to be concretely inferred +Base.@constprop :aggressive function syrk_wrapper!(C::StridedMatrix{T}, tA::AbstractChar, A::StridedVecOrMat{T}, _add = MulAddMul()) where {T<:BlasFloat} nC = checksquare(C) - if tA == 'T' + tA_uc = uppercase(tA) # potentially convert a WrapperChar to a Char + if tA_uc == 'T' (nA, mA) = size(A,1), size(A,2) tAt = 'N' else @@ -542,10 +556,13 @@ function syrk_wrapper!(C::StridedMatrix{T}, tA::AbstractChar, A::StridedVecOrMat return gemm_wrapper!(C, tA, tAt, A, A, _add) end -function herk_wrapper!(C::Union{StridedMatrix{T}, StridedMatrix{Complex{T}}}, tA::AbstractChar, A::Union{StridedVecOrMat{T}, StridedVecOrMat{Complex{T}}}, +# the aggressive constprop pushes tA and tB into gemm_wrapper!, which is needed for wrap calls within it +# to be concretely inferred +Base.@constprop :aggressive function herk_wrapper!(C::Union{StridedMatrix{T}, StridedMatrix{Complex{T}}}, tA::AbstractChar, A::Union{StridedVecOrMat{T}, StridedVecOrMat{Complex{T}}}, _add = MulAddMul()) where {T<:BlasReal} nC = checksquare(C) - if tA == 'C' + tA_uc = uppercase(tA) # potentially convert a WrapperChar to a Char + if tA_uc == 'C' (nA, mA) = size(A,1), size(A,2) tAt = 'N' else @@ -581,20 +598,28 @@ function herk_wrapper!(C::Union{StridedMatrix{T}, StridedMatrix{Complex{T}}}, tA return gemm_wrapper!(C, tA, tAt, A, A, _add) end -function gemm_wrapper(tA::AbstractChar, tB::AbstractChar, +# Aggressive constprop helps propagate the values of tA and tB into wrap, which +# makes the calls concretely inferred +Base.@constprop :aggressive function gemm_wrapper(tA::AbstractChar, tB::AbstractChar, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} mA, nA = lapack_size(tA, A) mB, nB = lapack_size(tB, B) C = similar(B, T, mA, nB) - if all(in(('N', 'T', 'C')), (tA, tB)) + # We convert the chars to uppercase to potentially unwrap a WrapperChar, + # and extract the char corresponding to the wrapper type + tA_uc, tB_uc = uppercase(tA), uppercase(tB) + # the map in all ensures constprop by acting on tA and tB individually, instead of looping over them. + if all(map(in(('N', 'T', 'C')), (tA_uc, tB_uc))) gemm_wrapper!(C, tA, tB, A, B) else _generic_matmatmul!(C, wrap(A, tA), wrap(B, tB), _add) end end -function gemm_wrapper!(C::StridedVecOrMat{T}, tA::AbstractChar, tB::AbstractChar, +# Aggressive constprop helps propagate the values of tA and tB into wrap, which +# makes the calls concretely inferred +Base.@constprop :aggressive function gemm_wrapper!(C::StridedVecOrMat{T}, tA::AbstractChar, tB::AbstractChar, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}, _add = MulAddMul()) where {T<:BlasFloat} mA, nA = lapack_size(tA, A) @@ -634,7 +659,9 @@ function gemm_wrapper!(C::StridedVecOrMat{T}, tA::AbstractChar, tB::AbstractChar _generic_matmatmul!(C, wrap(A, tA), wrap(B, tB), _add) end -function gemm_wrapper!(C::StridedVecOrMat{Complex{T}}, tA::AbstractChar, tB::AbstractChar, +# Aggressive constprop helps propagate the values of tA and tB into wrap, which +# makes the calls concretely inferred +Base.@constprop :aggressive function gemm_wrapper!(C::StridedVecOrMat{Complex{T}}, tA::AbstractChar, tB::AbstractChar, A::StridedVecOrMat{Complex{T}}, B::StridedVecOrMat{T}, _add = MulAddMul()) where {T<:BlasReal} mA, nA = lapack_size(tA, A) @@ -664,13 +691,15 @@ function gemm_wrapper!(C::StridedVecOrMat{Complex{T}}, tA::AbstractChar, tB::Abs alpha, beta = promote(_add.alpha, _add.beta, zero(T)) + tA_uc = uppercase(tA) # potentially convert a WrapperChar to a Char + # Make-sure reinterpret-based optimization is BLAS-compatible. if (alpha isa Union{Bool,T} && beta isa Union{Bool,T} && stride(A, 1) == stride(B, 1) == stride(C, 1) == 1 && stride(A, 2) >= size(A, 1) && stride(B, 2) >= size(B, 1) && - stride(C, 2) >= size(C, 1) && tA == 'N') + stride(C, 2) >= size(C, 1) && tA_uc == 'N') BLAS.gemm!(tA, tB, alpha, reinterpret(T, A), B, beta, reinterpret(T, C)) return C end @@ -703,9 +732,10 @@ parameters must satisfy `length(ir_dest) == length(ir_src)` and See also [`copy_transpose!`](@ref) and [`copy_adjoint!`](@ref). """ function copyto!(B::AbstractVecOrMat, ir_dest::AbstractUnitRange{Int}, jr_dest::AbstractUnitRange{Int}, tM::AbstractChar, M::AbstractVecOrMat, ir_src::AbstractUnitRange{Int}, jr_src::AbstractUnitRange{Int}) - if tM == 'N' + tM_uc = uppercase(tM) # potentially convert a WrapperChar to a Char + if tM_uc == 'N' copyto!(B, ir_dest, jr_dest, M, ir_src, jr_src) - elseif tM == 'T' + elseif tM_uc == 'T' copy_transpose!(B, ir_dest, jr_dest, M, jr_src, ir_src) else copy_adjoint!(B, ir_dest, jr_dest, M, jr_src, ir_src) @@ -734,11 +764,12 @@ range parameters must satisfy `length(ir_dest) == length(jr_src)` and See also [`copyto!`](@ref) and [`copy_adjoint!`](@ref). """ function copy_transpose!(B::AbstractMatrix, ir_dest::AbstractUnitRange{Int}, jr_dest::AbstractUnitRange{Int}, tM::AbstractChar, M::AbstractVecOrMat, ir_src::AbstractUnitRange{Int}, jr_src::AbstractUnitRange{Int}) - if tM == 'N' + tM_uc = uppercase(tM) # potentially convert a WrapperChar to a Char + if tM_uc == 'N' copy_transpose!(B, ir_dest, jr_dest, M, ir_src, jr_src) else copyto!(B, ir_dest, jr_dest, M, jr_src, ir_src) - tM == 'C' && conj!(@view B[ir_dest, jr_dest]) + tM_uc == 'C' && conj!(@view B[ir_dest, jr_dest]) end B end @@ -751,7 +782,8 @@ end @inline function generic_matvecmul!(C::AbstractVector, tA, A::AbstractVecOrMat, B::AbstractVector, _add::MulAddMul = MulAddMul()) - Anew, ta = tA in ('S', 's', 'H', 'h') ? (wrap(A, tA), 'N') : (A, tA) + tA_uc = uppercase(tA) # potentially convert a WrapperChar to a Char + Anew, ta = tA_uc in ('S', 'H') ? (wrap(A, tA), oftype(tA, 'N')) : (A, tA) return _generic_matvecmul!(C, ta, Anew, B, _add) end @@ -779,7 +811,8 @@ function _generic_matvecmul!(C::AbstractVector, tA, A::AbstractVecOrMat, B::Abst else for k = 1:mA aoffs = (k-1)*Astride - s = zero(A[aoffs + 1]*B[1] + A[aoffs + 1]*B[1]) + firstterm = transpose(A[aoffs + 1])*B[1] + s = zero(firstterm + firstterm) for i = 1:nA s += transpose(A[aoffs+i]) * B[i] end @@ -794,7 +827,8 @@ function _generic_matvecmul!(C::AbstractVector, tA, A::AbstractVecOrMat, B::Abst else for k = 1:mA aoffs = (k-1)*Astride - s = zero(A[aoffs + 1]*B[1] + A[aoffs + 1]*B[1]) + firstterm = A[aoffs + 1]'B[1] + s = zero(firstterm + firstterm) for i = 1:nA s += A[aoffs + i]'B[i] end diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index 782e4778c56c9..06c2fba2932f5 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -541,7 +541,7 @@ function ldiv!(A::QRPivoted{T,<:StridedMatrix}, B::AbstractMatrix{T}, rcond::Rea m, n = size(A) if m > size(B, 1) || n > size(B, 1) - throw(DimensionMismatch("B has leading dimension $(size(B, 1)) but needs at least $(max(m, n))")) + throw(DimensionMismatch(lazy"B has leading dimension $(size(B, 1)) but needs at least $(max(m, n))")) end if length(A.factors) == 0 || length(B) == 0 @@ -734,7 +734,7 @@ _ret_size(A::Factorization, B::AbstractMatrix) = (max(size(A, 2), size(B, 1)), s function (\)(A::Union{QR{T},QRCompactWY{T},QRPivoted{T}}, BIn::VecOrMat{Complex{T}}) where T<:BlasReal require_one_based_indexing(BIn) m, n = size(A) - m == size(BIn, 1) || throw(DimensionMismatch("left hand side has $m rows, but right hand side has $(size(BIn,1)) rows")) + m == size(BIn, 1) || throw(DimensionMismatch(lazy"left hand side has $m rows, but right hand side has $(size(BIn,1)) rows")) # |z1|z3| reinterpret |x1|x2|x3|x4| transpose |x1|y1| reshape |x1|y1|x3|y3| # |z2|z4| -> |y1|y2|y3|y4| -> |x2|y2| -> |x2|y2|x4|y4| diff --git a/stdlib/LinearAlgebra/src/special.jl b/stdlib/LinearAlgebra/src/special.jl index 136f566f68447..1363708fb515f 100644 --- a/stdlib/LinearAlgebra/src/special.jl +++ b/stdlib/LinearAlgebra/src/special.jl @@ -287,7 +287,7 @@ _small_enough(A::SymTridiagonal) = size(A, 1) <= 2 function fill!(A::Union{Diagonal,Bidiagonal,Tridiagonal,SymTridiagonal}, x) xT = convert(eltype(A), x) (iszero(xT) || _small_enough(A)) && return fillstored!(A, xT) - throw(ArgumentError("array of type $(typeof(A)) and size $(size(A)) can + throw(ArgumentError(lazy"array of type $(typeof(A)) and size $(size(A)) can not be filled with $x, since some of its entries are constrained.")) end diff --git a/stdlib/LinearAlgebra/src/structuredbroadcast.jl b/stdlib/LinearAlgebra/src/structuredbroadcast.jl index a227b678c9934..e7804f8733c58 100644 --- a/stdlib/LinearAlgebra/src/structuredbroadcast.jl +++ b/stdlib/LinearAlgebra/src/structuredbroadcast.jl @@ -78,7 +78,7 @@ find_uplo(bc::Broadcasted) = mapfoldl(find_uplo, merge_uplos, Broadcast.cat_nest function structured_broadcast_alloc(bc, ::Type{Bidiagonal}, ::Type{ElType}, n) where {ElType} uplo = n > 0 ? find_uplo(bc) : 'U' n1 = max(n - 1, 0) - if uplo == 'T' + if count_structedmatrix(Bidiagonal, bc) > 1 && uplo == 'T' return Tridiagonal(Array{ElType}(undef, n1), Array{ElType}(undef, n), Array{ElType}(undef, n1)) end return Bidiagonal(Array{ElType}(undef, n),Array{ElType}(undef, n1), uplo) @@ -134,6 +134,8 @@ iszerodefined(::Type) = false iszerodefined(::Type{<:Number}) = true iszerodefined(::Type{<:AbstractArray{T}}) where T = iszerodefined(T) +count_structedmatrix(T, bc::Broadcasted) = sum(Base.Fix2(isa, T), Broadcast.cat_nested(bc); init = 0) + fzeropreserving(bc) = (v = fzero(bc); !ismissing(v) && (iszerodefined(typeof(v)) ? iszero(v) : v == 0)) # Like sparse matrices, we assume that the zero-preservation property of a broadcasted # expression is stable. We can test the zero-preservability by applying the function @@ -204,7 +206,7 @@ function copyto!(dest::SymTridiagonal, bc::Broadcasted{<:StructuredMatrixStyle}) end for i = 1:size(dest, 1)-1 v = @inbounds Broadcast._broadcast_getindex(bc, CartesianIndex(i, i+1)) - v == (@inbounds Broadcast._broadcast_getindex(bc, CartesianIndex(i+1, i))) || throw(ArgumentError("broadcasted assignment breaks symmetry between locations ($i, $(i+1)) and ($(i+1), $i)")) + v == (@inbounds Broadcast._broadcast_getindex(bc, CartesianIndex(i+1, i))) || throw(ArgumentError(lazy"broadcasted assignment breaks symmetry between locations ($i, $(i+1)) and ($(i+1), $i)")) dest.ev[i] = v end return dest diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index 21047dad8fcd9..07240fb9afb22 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -483,7 +483,7 @@ for (T, trans, real) in [(:Symmetric, :transpose, :identity), (:(Hermitian{<:Uni function dot(A::$T, B::$T) n = size(A, 2) if n != size(B, 2) - throw(DimensionMismatch("A has dimensions $(size(A)) but B has dimensions $(size(B))")) + throw(DimensionMismatch(lazy"A has dimensions $(size(A)) but B has dimensions $(size(B))")) end dotprod = $real(zero(dot(first(A), first(B)))) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index aff87e3ae50ba..e782c0929f09f 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -272,7 +272,7 @@ Base.isstored(A::UpperTriangular, i::Int, j::Int) = @propagate_inbounds function setindex!(A::UpperTriangular, x, i::Integer, j::Integer) if i > j iszero(x) || throw(ArgumentError("cannot set index in the lower triangular part " * - "($i, $j) of an UpperTriangular matrix to a nonzero value ($x)")) + lazy"($i, $j) of an UpperTriangular matrix to a nonzero value ($x)")) else A.data[i,j] = x end @@ -282,10 +282,10 @@ end @propagate_inbounds function setindex!(A::UnitUpperTriangular, x, i::Integer, j::Integer) if i > j iszero(x) || throw(ArgumentError("cannot set index in the lower triangular part " * - "($i, $j) of a UnitUpperTriangular matrix to a nonzero value ($x)")) + lazy"($i, $j) of a UnitUpperTriangular matrix to a nonzero value ($x)")) elseif i == j - x == oneunit(x) || throw(ArgumentError("cannot set index on the diagonal ($i, $j) " * - "of a UnitUpperTriangular matrix to a non-unit value ($x)")) + x == oneunit(x) || throw(ArgumentError(lazy"cannot set index on the diagonal ($i, $j) " * + lazy"of a UnitUpperTriangular matrix to a non-unit value ($x)")) else A.data[i,j] = x end @@ -295,7 +295,7 @@ end @propagate_inbounds function setindex!(A::LowerTriangular, x, i::Integer, j::Integer) if i < j iszero(x) || throw(ArgumentError("cannot set index in the upper triangular part " * - "($i, $j) of a LowerTriangular matrix to a nonzero value ($x)")) + lazy"($i, $j) of a LowerTriangular matrix to a nonzero value ($x)")) else A.data[i,j] = x end @@ -305,10 +305,10 @@ end @propagate_inbounds function setindex!(A::UnitLowerTriangular, x, i::Integer, j::Integer) if i < j iszero(x) || throw(ArgumentError("cannot set index in the upper triangular part " * - "($i, $j) of a UnitLowerTriangular matrix to a nonzero value ($x)")) + lazy"($i, $j) of a UnitLowerTriangular matrix to a nonzero value ($x)")) elseif i == j - x == oneunit(x) || throw(ArgumentError("cannot set index on the diagonal ($i, $j) " * - "of a UnitLowerTriangular matrix to a non-unit value ($x)")) + x == oneunit(x) || throw(ArgumentError(lazy"cannot set index on the diagonal ($i, $j) " * + lazy"of a UnitLowerTriangular matrix to a non-unit value ($x)")) else A.data[i,j] = x end @@ -317,7 +317,7 @@ end @inline function fill!(A::UpperTriangular, x) iszero(x) || throw(ArgumentError("cannot set indices in the lower triangular part " * - "of an UpperTriangular matrix to a nonzero value ($x)")) + lazy"of an UpperTriangular matrix to a nonzero value ($x)")) for col in axes(A,2), row in firstindex(A,1):col @inbounds A.data[row, col] = x end @@ -325,7 +325,7 @@ end end @inline function fill!(A::LowerTriangular, x) iszero(x) || throw(ArgumentError("cannot set indices in the upper triangular part " * - "of a LowerTriangular matrix to a nonzero value ($x)")) + lazy"of a LowerTriangular matrix to a nonzero value ($x)")) for col in axes(A,2), row in col:lastindex(A,1) @inbounds A.data[row, col] = x end @@ -540,7 +540,7 @@ end function checksize1(A, B) szA, szB = size(A), size(B) - szA == szB || throw(DimensionMismatch("size of A, $szA, does not match size of B, $szB")) + szA == szB || throw(DimensionMismatch(lazy"size of A, $szA, does not match size of B, $szB")) checksquare(B) end @@ -1003,11 +1003,11 @@ function generic_trimatmul!(C::AbstractVecOrMat, uploc, isunitc, tfun::Function, m, n = size(B, 1), size(B, 2) N = size(A, 1) if m != N - throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) + throw(DimensionMismatch(lazy"right hand side B needs first dimension of size $(size(A,1)), has size $m")) end mc, nc = size(C, 1), size(C, 2) if mc != N || nc != n - throw(DimensionMismatch("output has dimensions ($mc,$nc), should have ($N,$n)")) + throw(DimensionMismatch(lazy"output has dimensions ($mc,$nc), should have ($N,$n)")) end oA = oneunit(eltype(A)) unit = isunitc == 'U' @@ -1065,11 +1065,11 @@ function generic_trimatmul!(C::AbstractVecOrMat, uploc, isunitc, ::Function, xA: m, n = size(B, 1), size(B, 2) N = size(A, 1) if m != N - throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m")) + throw(DimensionMismatch(lazy"right hand side B needs first dimension of size $(size(A,1)), has size $m")) end mc, nc = size(C, 1), size(C, 2) if mc != N || nc != n - throw(DimensionMismatch("output has dimensions ($mc,$nc), should have ($N,$n)")) + throw(DimensionMismatch(lazy"output has dimensions ($mc,$nc), should have ($N,$n)")) end oA = oneunit(eltype(A)) unit = isunitc == 'U' @@ -1102,11 +1102,11 @@ function generic_mattrimul!(C::AbstractMatrix, uploc, isunitc, tfun::Function, A m, n = size(A, 1), size(A, 2) N = size(B, 1) if n != N - throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $N")) + throw(DimensionMismatch(lazy"right hand side B needs first dimension of size $n, has size $N")) end mc, nc = size(C, 1), size(C, 2) if mc != m || nc != N - throw(DimensionMismatch("output has dimensions ($mc,$nc), should have ($m,$N)")) + throw(DimensionMismatch(lazy"output has dimensions ($mc,$nc), should have ($m,$N)")) end oB = oneunit(eltype(B)) unit = isunitc == 'U' @@ -1164,11 +1164,11 @@ function generic_mattrimul!(C::AbstractMatrix, uploc, isunitc, ::Function, A::Ab m, n = size(A, 1), size(A, 2) N = size(B, 1) if n != N - throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $N")) + throw(DimensionMismatch(lazy"right hand side B needs first dimension of size $n, has size $N")) end mc, nc = size(C, 1), size(C, 2) if mc != m || nc != N - throw(DimensionMismatch("output has dimensions ($mc,$nc), should have ($m,$N)")) + throw(DimensionMismatch(lazy"output has dimensions ($mc,$nc), should have ($m,$N)")) end oB = oneunit(eltype(B)) unit = isunitc == 'U' @@ -1212,10 +1212,10 @@ function generic_trimatdiv!(C::AbstractVecOrMat, uploc, isunitc, tfun::Function, mA, nA = size(A) m, n = size(B, 1), size(B,2) if nA != m - throw(DimensionMismatch("second dimension of left hand side A, $nA, and first dimension of right hand side B, $m, must be equal")) + throw(DimensionMismatch(lazy"second dimension of left hand side A, $nA, and first dimension of right hand side B, $m, must be equal")) end if size(C) != size(B) - throw(DimensionMismatch("size of output, $(size(C)), does not match size of right hand side, $(size(B))")) + throw(DimensionMismatch(lazy"size of output, $(size(C)), does not match size of right hand side, $(size(B))")) end oA = oneunit(eltype(A)) @inbounds if uploc == 'U' @@ -1348,10 +1348,10 @@ function generic_trimatdiv!(C::AbstractVecOrMat, uploc, isunitc, ::Function, xA: mA, nA = size(A) m, n = size(B, 1), size(B,2) if nA != m - throw(DimensionMismatch("second dimension of left hand side A, $nA, and first dimension of right hand side B, $m, must be equal")) + throw(DimensionMismatch(lazy"second dimension of left hand side A, $nA, and first dimension of right hand side B, $m, must be equal")) end if size(C) != size(B) - throw(DimensionMismatch("size of output, $(size(C)), does not match size of right hand side, $(size(B))")) + throw(DimensionMismatch(lazy"size of output, $(size(C)), does not match size of right hand side, $(size(B))")) end oA = oneunit(eltype(A)) @inbounds if uploc == 'U' @@ -1430,10 +1430,10 @@ function generic_mattridiv!(C::AbstractMatrix, uploc, isunitc, tfun::Function, A require_one_based_indexing(C, A, B) m, n = size(A) if size(B, 1) != n - throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) + throw(DimensionMismatch(lazy"right hand side B needs first dimension of size $n, has size $(size(B,1))")) end if size(C) != size(A) - throw(DimensionMismatch("size of output, $(size(C)), does not match size of left hand side, $(size(A))")) + throw(DimensionMismatch(lazy"size of output, $(size(C)), does not match size of left hand side, $(size(A))")) end oB = oneunit(eltype(B)) unit = isunitc == 'U' @@ -1493,10 +1493,10 @@ function generic_mattridiv!(C::AbstractMatrix, uploc, isunitc, ::Function, A::Ab require_one_based_indexing(C, A, B) m, n = size(A) if size(B, 1) != n - throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))")) + throw(DimensionMismatch(lazy"right hand side B needs first dimension of size $n, has size $(size(B,1))")) end if size(C) != size(A) - throw(DimensionMismatch("size of output, $(size(C)), does not match size of left hand side, $(size(A))")) + throw(DimensionMismatch(lazy"size of output, $(size(C)), does not match size of left hand side, $(size(A))")) end oB = oneunit(eltype(B)) unit = isunitc == 'U' @@ -1618,7 +1618,7 @@ end # 34(3), (2013) 1341–1360. function powm!(A0::UpperTriangular, p::Real) if abs(p) >= 1 - throw(ArgumentError("p must be a real number in (-1,1), got $p")) + throw(ArgumentError(lazy"p must be a real number in (-1,1), got $p")) end normA0 = opnorm(A0, 1) @@ -2548,7 +2548,7 @@ function eigvecs(A::AbstractTriangular{T}) where T if TT <: BlasFloat return eigvecs(convert(AbstractMatrix{TT}, A)) else - throw(ArgumentError("eigvecs type $(typeof(A)) not supported. Please submit a pull request.")) + throw(ArgumentError(lazy"eigvecs type $(typeof(A)) not supported. Please submit a pull request.")) end end det(A::UnitUpperTriangular{T}) where {T} = one(T) diff --git a/stdlib/LinearAlgebra/src/tridiag.jl b/stdlib/LinearAlgebra/src/tridiag.jl index 07c2fe410769d..447d87f1c5efc 100644 --- a/stdlib/LinearAlgebra/src/tridiag.jl +++ b/stdlib/LinearAlgebra/src/tridiag.jl @@ -9,7 +9,7 @@ struct SymTridiagonal{T, V<:AbstractVector{T}} <: AbstractMatrix{T} function SymTridiagonal{T, V}(dv, ev) where {T, V<:AbstractVector{T}} require_one_based_indexing(dv, ev) if !(length(dv) - 1 <= length(ev) <= length(dv)) - throw(DimensionMismatch("subdiagonal has wrong length. Has length $(length(ev)), but should be either $(length(dv) - 1) or $(length(dv)).")) + throw(DimensionMismatch(lazy"subdiagonal has wrong length. Has length $(length(ev)), but should be either $(length(dv) - 1) or $(length(dv)).")) end new{T, V}(dv, ev) end @@ -187,8 +187,8 @@ function diag(M::SymTridiagonal{T}, n::Integer=0) where T<:Number elseif absn <= size(M,1) return fill!(similar(M.dv, size(M,1)-absn), zero(T)) else - throw(ArgumentError(string("requested diagonal, $n, must be at least $(-size(M, 1)) ", - "and at most $(size(M, 2)) for an $(size(M, 1))-by-$(size(M, 2)) matrix"))) + throw(ArgumentError(string(lazy"requested diagonal, $n, must be at least $(-size(M, 1)) ", + lazy"and at most $(size(M, 2)) for an $(size(M, 1))-by-$(size(M, 2)) matrix"))) end end function diag(M::SymTridiagonal, n::Integer=0) @@ -203,8 +203,8 @@ function diag(M::SymTridiagonal, n::Integer=0) elseif n <= size(M,1) throw(ArgumentError("requested diagonal contains undefined zeros of an array type")) else - throw(ArgumentError(string("requested diagonal, $n, must be at least $(-size(M, 1)) ", - "and at most $(size(M, 2)) for an $(size(M, 1))-by-$(size(M, 2)) matrix"))) + throw(ArgumentError(string(lazy"requested diagonal, $n, must be at least $(-size(M, 1)) ", + lazy"and at most $(size(M, 2)) for an $(size(M, 1))-by-$(size(M, 2)) matrix"))) end end @@ -346,8 +346,8 @@ isdiag(M::SymTridiagonal) = iszero(_evview(M)) function tril!(M::SymTridiagonal{T}, k::Integer=0) where T n = length(M.dv) if !(-n - 1 <= k <= n - 1) - throw(ArgumentError(string("the requested diagonal, $k, must be at least ", - "$(-n - 1) and at most $(n - 1) in an $n-by-$n matrix"))) + throw(ArgumentError(string(lazy"the requested diagonal, $k, must be at least ", + lazy"$(-n - 1) and at most $(n - 1) in an $n-by-$n matrix"))) elseif k < -1 fill!(M.ev, zero(T)) fill!(M.dv, zero(T)) @@ -365,8 +365,8 @@ end function triu!(M::SymTridiagonal{T}, k::Integer=0) where T n = length(M.dv) if !(-n + 1 <= k <= n + 1) - throw(ArgumentError(string("the requested diagonal, $k, must be at least ", - "$(-n + 1) and at most $(n + 1) in an $n-by-$n matrix"))) + throw(ArgumentError(string(lazy"the requested diagonal, $k, must be at least ", + lazy"$(-n + 1) and at most $(n + 1) in an $n-by-$n matrix"))) elseif k > 1 fill!(M.ev, zero(T)) fill!(M.dv, zero(T)) @@ -459,7 +459,7 @@ end if i == j @inbounds A.dv[i] = x else - throw(ArgumentError("cannot set off-diagonal entry ($i, $j)")) + throw(ArgumentError(lazy"cannot set off-diagonal entry ($i, $j)")) end return x end @@ -476,7 +476,7 @@ struct Tridiagonal{T,V<:AbstractVector{T}} <: AbstractMatrix{T} if (length(dl) != n-1 || length(du) != n-1) && !(length(d) == 0 && length(dl) == 0 && length(du) == 0) throw(ArgumentError(string("cannot construct Tridiagonal from incompatible ", "lengths of subdiagonal, diagonal and superdiagonal: ", - "($(length(dl)), $(length(d)), $(length(du)))"))) + lazy"($(length(dl)), $(length(d)), $(length(du)))"))) end new{T,V}(dl, d, Base.unalias(dl, du)) end @@ -642,8 +642,8 @@ function diag(M::Tridiagonal{T}, n::Integer=0) where T elseif abs(n) <= size(M,1) return fill!(similar(M.d, size(M,1)-abs(n)), zero(T)) else - throw(ArgumentError(string("requested diagonal, $n, must be at least $(-size(M, 1)) ", - "and at most $(size(M, 2)) for an $(size(M, 1))-by-$(size(M, 2)) matrix"))) + throw(ArgumentError(string(lazy"requested diagonal, $n, must be at least $(-size(M, 1)) ", + lazy"and at most $(size(M, 2)) for an $(size(M, 1))-by-$(size(M, 2)) matrix"))) end end @@ -695,8 +695,8 @@ end elseif j - i == 1 @inbounds A.du[i] = x elseif !iszero(x) - throw(ArgumentError(string("cannot set entry ($i, $j) off ", - "the tridiagonal band to a nonzero value ($x)"))) + throw(ArgumentError(string(lazy"cannot set entry ($i, $j) off ", + lazy"the tridiagonal band to a nonzero value ($x)"))) end return x end @@ -738,8 +738,8 @@ isdiag(M::Tridiagonal) = iszero(M.dl) && iszero(M.du) function tril!(M::Tridiagonal{T}, k::Integer=0) where T n = length(M.d) if !(-n - 1 <= k <= n - 1) - throw(ArgumentError(string("the requested diagonal, $k, must be at least ", - "$(-n - 1) and at most $(n - 1) in an $n-by-$n matrix"))) + throw(ArgumentError(string(lazy"the requested diagonal, $k, must be at least ", + lazy"$(-n - 1) and at most $(n - 1) in an $n-by-$n matrix"))) elseif k < -1 fill!(M.dl, zero(T)) fill!(M.d, zero(T)) @@ -756,8 +756,8 @@ end function triu!(M::Tridiagonal{T}, k::Integer=0) where T n = length(M.d) if !(-n + 1 <= k <= n + 1) - throw(ArgumentError(string("the requested diagonal, $k, must be at least ", - "$(-n + 1) and at most $(n + 1) in an $n-by-$n matrix"))) + throw(ArgumentError(string(lazy"the requested diagonal, $k, must be at least ", + lazy"$(-n + 1) and at most $(n + 1) in an $n-by-$n matrix"))) elseif k > 1 fill!(M.dl, zero(T)) fill!(M.d, zero(T)) @@ -925,7 +925,7 @@ function ldiv!(A::Tridiagonal, B::AbstractVecOrMat) LinearAlgebra.require_one_based_indexing(B) n = size(A, 1) if n != size(B,1) - throw(DimensionMismatch("matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) + throw(DimensionMismatch(lazy"matrix has dimensions ($n,$n) but right hand side has $(size(B,1)) rows")) end nrhs = size(B, 2) diff --git a/stdlib/LinearAlgebra/test/abstractq.jl b/stdlib/LinearAlgebra/test/abstractq.jl index 19b872d685668..0eb88324e8c20 100644 --- a/stdlib/LinearAlgebra/test/abstractq.jl +++ b/stdlib/LinearAlgebra/test/abstractq.jl @@ -39,6 +39,12 @@ n = 5 @test Q'*I ≈ Q.Q'*I rtol=2eps(real(T)) @test I*Q ≈ Q.Q*I rtol=2eps(real(T)) @test I*Q' ≈ I*Q.Q' rtol=2eps(real(T)) + @test Q^3 ≈ Q*Q*Q + @test Q^2 ≈ Q*Q + @test Q^1 == Q + @test Q^(-1) == Q' + @test (Q')^(-1) == Q + @test (Q')^2 ≈ Q'*Q' @test abs(det(Q)) ≈ 1 @test logabsdet(Q)[1] ≈ 0 atol=2n*eps(real(T)) y = rand(T, n) diff --git a/stdlib/LinearAlgebra/test/matmul.jl b/stdlib/LinearAlgebra/test/matmul.jl index 5bcbb99a314fd..db61fbe0ab45a 100644 --- a/stdlib/LinearAlgebra/test/matmul.jl +++ b/stdlib/LinearAlgebra/test/matmul.jl @@ -30,6 +30,30 @@ mul_wrappers = [ h(A) = LinearAlgebra.wrap(LinearAlgebra._unwrap(A), LinearAlgebra.wrapper_char(A)) @test @inferred(h(transpose(A))) === transpose(A) @test @inferred(h(adjoint(A))) === transpose(A) + + M = rand(2,2) + for S in (Symmetric(M), Hermitian(M)) + @test @inferred((A -> LinearAlgebra.wrap(parent(A), LinearAlgebra.wrapper_char(A)))(S)) === Symmetric(M) + end + M = rand(ComplexF64,2,2) + for S in (Symmetric(M), Hermitian(M)) + @test @inferred((A -> LinearAlgebra.wrap(parent(A), LinearAlgebra.wrapper_char(A)))(S)) === S + end + + @testset "WrapperChar" begin + @test LinearAlgebra.WrapperChar('c') == 'c' + @test LinearAlgebra.WrapperChar('C') == 'C' + @testset "constant propagation in uppercase/lowercase" begin + v = @inferred (() -> Val(uppercase(LinearAlgebra.WrapperChar('C'))))() + @test v isa Val{'C'} + v = @inferred (() -> Val(uppercase(LinearAlgebra.WrapperChar('s'))))() + @test v isa Val{'S'} + v = @inferred (() -> Val(lowercase(LinearAlgebra.WrapperChar('C'))))() + @test v isa Val{'c'} + v = @inferred (() -> Val(lowercase(LinearAlgebra.WrapperChar('s'))))() + @test v isa Val{'s'} + end + end end @testset "matrices with zero dimensions" begin @@ -216,6 +240,18 @@ end end end +@testset "generic_matvecmul for vectors of matrices" begin + x = [1 2 3; 4 5 6] + A = reshape([x,2x,3x,4x],2,2) + b = [x, 2x] + for f in (adjoint, transpose) + c = f(A) * b + for i in eachindex(c) + @test c[i] == sum(f(A)[i, j] * b[j] for j in eachindex(b)) + end + end +end + @testset "generic_matmatmul for matrices of vectors" begin B = Matrix{Vector{Int}}(undef, 2, 2) B[1, 1] = [1, 2] diff --git a/stdlib/LinearAlgebra/test/structuredbroadcast.jl b/stdlib/LinearAlgebra/test/structuredbroadcast.jl index fab6cd80141b2..316729c0b21b7 100644 --- a/stdlib/LinearAlgebra/test/structuredbroadcast.jl +++ b/stdlib/LinearAlgebra/test/structuredbroadcast.jl @@ -59,6 +59,24 @@ using Test, LinearAlgebra @test broadcast!(*, Z, X, Y) == broadcast(*, fX, fY) end end + + @testset "type-stability in Bidiagonal" begin + B2 = @inferred (B -> .- B)(B) + @test B2 isa Bidiagonal + @test B2 == -1 * B + B2 = @inferred (B -> B .* 2)(B) + @test B2 isa Bidiagonal + @test B2 == B + B + B2 = @inferred (B -> 2 .* B)(B) + @test B2 isa Bidiagonal + @test B2 == B + B + B2 = @inferred (B -> B ./ 1)(B) + @test B2 isa Bidiagonal + @test B2 == B + B2 = @inferred (B -> 1 .\ B)(B) + @test B2 isa Bidiagonal + @test B2 == B + end end @testset "broadcast! where the destination is a structured matrix" begin diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index d3b24ccf78b0b..4d9fce18cf5a6 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -264,8 +264,11 @@ end @testset "inverse edge case with complex Hermitian" begin # Hermitian matrix, where inv(lu(A)) generates non-real diagonal elements for T in (ComplexF32, ComplexF64) - A = T[0.650488+0.0im 0.826686+0.667447im; 0.826686-0.667447im 1.81707+0.0im] - H = Hermitian(A) + # data should have nonvanishing imaginary parts on the diagonal + M = T[0.279982+0.988074im 0.770011+0.870555im + 0.138001+0.889728im 0.177242+0.701413im] + H = Hermitian(M) + A = Matrix(H) @test inv(H) ≈ inv(A) @test ishermitian(Matrix(inv(H))) end diff --git a/stdlib/Logging/Project.toml b/stdlib/Logging/Project.toml index 3fc288e25f0b7..ce69112733d5e 100644 --- a/stdlib/Logging/Project.toml +++ b/stdlib/Logging/Project.toml @@ -2,9 +2,6 @@ name = "Logging" uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" version = "1.11.0" -[deps] -StyledStrings = "f489334b-da3d-4c2e-b8f0-e476e12c162b" - [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/Logging/src/Logging.jl b/stdlib/Logging/src/Logging.jl index 3822bde2e630b..192885f2f94b7 100644 --- a/stdlib/Logging/src/Logging.jl +++ b/stdlib/Logging/src/Logging.jl @@ -8,8 +8,6 @@ and available by default. """ module Logging -using StyledStrings - # Import the CoreLogging implementation into Logging as new const bindings. # Doing it this way (rather than with import) makes these symbols accessible to # tab completion. @@ -70,7 +68,10 @@ Alias for [`LogLevel(1_000_001)`](@ref LogLevel). const AboveMaxLevel = Base.CoreLogging.AboveMaxLevel using Base.CoreLogging: - closed_stream + closed_stream, ConsoleLogger, default_metafmt + +# Some packages use `Logging.default_logcolor` +const default_logcolor = Base.CoreLogging.default_logcolor export AbstractLogger, @@ -94,8 +95,6 @@ export Error, AboveMaxLevel -include("ConsoleLogger.jl") - # The following are also part of the public API, but not exported: # # 1. Log levels: @@ -104,8 +103,4 @@ include("ConsoleLogger.jl") # 2. AbstractLogger message related functions: # handle_message, shouldlog, min_enabled_level, catch_exceptions, -function __init__() - global_logger(ConsoleLogger()) -end - end diff --git a/stdlib/Logging/test/runtests.jl b/stdlib/Logging/test/runtests.jl index a244facee3468..176860fcdec63 100644 --- a/stdlib/Logging/test/runtests.jl +++ b/stdlib/Logging/test/runtests.jl @@ -63,24 +63,24 @@ end @testset "Default metadata formatting" begin @test Logging.default_metafmt(Logging.Debug, Base, :g, :i, expanduser("~/somefile.jl"), 42) == - (:log_debug, "Debug:", "@ Base ~/somefile.jl:42") + (:blue, "Debug:", "@ Base ~/somefile.jl:42") @test Logging.default_metafmt(Logging.Info, Main, :g, :i, "a.jl", 1) == - (:log_info, "Info:", "") + (:cyan, "Info:", "") @test Logging.default_metafmt(Logging.Warn, Main, :g, :i, "b.jl", 2) == - (:log_warn, "Warning:", "@ Main b.jl:2") + (:yellow, "Warning:", "@ Main b.jl:2") @test Logging.default_metafmt(Logging.Error, Main, :g, :i, "", 0) == - (:log_error, "Error:", "@ Main :0") + (:light_red, "Error:", "@ Main :0") # formatting of nothing @test Logging.default_metafmt(Logging.Warn, nothing, :g, :i, "b.jl", 2) == - (:log_warn, "Warning:", "@ b.jl:2") + (:yellow, "Warning:", "@ b.jl:2") @test Logging.default_metafmt(Logging.Warn, Main, :g, :i, nothing, 2) == - (:log_warn, "Warning:", "@ Main") + (:yellow, "Warning:", "@ Main") @test Logging.default_metafmt(Logging.Warn, Main, :g, :i, "b.jl", nothing) == - (:log_warn, "Warning:", "@ Main b.jl") + (:yellow, "Warning:", "@ Main b.jl") @test Logging.default_metafmt(Logging.Warn, nothing, :g, :i, nothing, 2) == - (:log_warn, "Warning:", "") + (:yellow, "Warning:", "") @test Logging.default_metafmt(Logging.Warn, Main, :g, :i, "b.jl", 2:5) == - (:log_warn, "Warning:", "@ Main b.jl:2-5") + (:yellow, "Warning:", "@ Main b.jl:2-5") end function dummy_metafmt(level, _module, group, id, file, line) @@ -265,9 +265,9 @@ end # Basic colorization test @test genmsg("line1\nline2", color=true) == """ - \e[36m\e[1m┌\e[39m\e[22m \e[36m\e[1mPREFIX\e[39m\e[22m line1 - \e[36m\e[1m│\e[39m\e[22m line2 - \e[36m\e[1m└\e[39m\e[22m \e[90mSUFFIX\e[39m + \e[36m\e[1m┌ \e[22m\e[39m\e[36m\e[1mPREFIX \e[22m\e[39mline1 + \e[36m\e[1m│ \e[22m\e[39mline2 + \e[36m\e[1m└ \e[22m\e[39m\e[90mSUFFIX\e[39m """ end diff --git a/stdlib/Manifest.toml b/stdlib/Manifest.toml index 80ecce3883490..e3d57ccb020a8 100644 --- a/stdlib/Manifest.toml +++ b/stdlib/Manifest.toml @@ -130,7 +130,6 @@ uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" version = "1.11.0" [[deps.Logging]] -deps = ["StyledStrings"] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" version = "1.11.0" @@ -191,7 +190,6 @@ uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" version = "1.11.0" [[deps.Profile]] -deps = ["Unicode"] uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" version = "1.11.0" diff --git a/stdlib/Mmap/src/Mmap.jl b/stdlib/Mmap/src/Mmap.jl index 6d328c40cd7b3..e6987582bf511 100644 --- a/stdlib/Mmap/src/Mmap.jl +++ b/stdlib/Mmap/src/Mmap.jl @@ -256,7 +256,7 @@ function mmap(io::IO, end # os-test # convert mmapped region to Julia Array at `ptr + (offset - offset_page)` since file was mapped at offset_page A = unsafe_wrap(Array, convert(Ptr{T}, UInt(ptr) + UInt(offset - offset_page)), dims) - finalizer(A) do x + finalizer(A.ref.mem) do x @static if Sys.isunix() systemerror("munmap", ccall(:munmap, Cint, (Ptr{Cvoid}, Int), ptr, mmaplen) != 0) else diff --git a/stdlib/Mmap/test/runtests.jl b/stdlib/Mmap/test/runtests.jl index ebd16a45ba0ed..03e4b48d95f7a 100644 --- a/stdlib/Mmap/test/runtests.jl +++ b/stdlib/Mmap/test/runtests.jl @@ -100,9 +100,9 @@ if !(Sys.ARCH === :powerpc64le || Sys.ARCH === :ppc64le) s = open(file, "r") m = mmap(s) @test_throws ReadOnlyMemoryError m[5] = UInt8('x') # tries to setindex! on read-only array - finalize(m); m=nothing; GC.gc() + finalize(m); m=nothing; end - +GC.gc() write(file, "Hello World\n") s = open(file, "r") @@ -336,8 +336,9 @@ open(file, "r+") do s finalize(A); A = nothing; GC.gc() A = mmap(s, Vector{UInt8}, (10,), 1) Mmap.sync!(A) - finalize(A); A = nothing; GC.gc() + finalize(A); A = nothing; end +GC.gc() rm(file) @testset "Docstrings" begin diff --git a/stdlib/OpenBLAS_jll/Project.toml b/stdlib/OpenBLAS_jll/Project.toml index 10e8285027d42..95dc40e6a0c2b 100644 --- a/stdlib/OpenBLAS_jll/Project.toml +++ b/stdlib/OpenBLAS_jll/Project.toml @@ -1,6 +1,6 @@ name = "OpenBLAS_jll" uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.26+2" +version = "0.3.27+1" [deps] # See note in `src/OpenBLAS_jll.jl` about this dependency. diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 986b0b16e0b76..0d9ae50e19a8f 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = release-1.11 -PKG_SHA1 = bd787952e6ceab2d3e8fec98429d954860ecfd9f +PKG_SHA1 = f112626414a4f666306adb84936ea85aec77c89d 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/Profile/Project.toml b/stdlib/Profile/Project.toml index ede7ccd66bc8e..ad0107ecf9404 100644 --- a/stdlib/Profile/Project.toml +++ b/stdlib/Profile/Project.toml @@ -2,12 +2,6 @@ name = "Profile" uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" version = "1.11.0" -[deps] -Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" - -[compat] -Unicode = "1.11.0" - [extras] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" diff --git a/stdlib/Profile/src/heapsnapshot_reassemble.jl b/stdlib/Profile/src/heapsnapshot_reassemble.jl index 27d7d12318ed1..50da13e550d82 100644 --- a/stdlib/Profile/src/heapsnapshot_reassemble.jl +++ b/stdlib/Profile/src/heapsnapshot_reassemble.jl @@ -2,8 +2,6 @@ module HeapSnapshot -using Unicode - """ assemble_snapshot(filepath::AbstractString, out_file::AbstractString) @@ -236,7 +234,7 @@ function print_str_escape_json(stream::IO, s::AbstractString) print(stream, "\\t") elseif '\x00' <= c <= '\x1f' print(stream, "\\u", lpad(string(UInt16(c), base=16), 4, '0')) - elseif !Unicode.isassigned(c) + elseif !isvalid(c) # we have to do this because vscode's viewer doesn't like the replace character print(stream, "[invalid unicode character]") else diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 4c95d4264dbcb..9888654dc21c5 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -180,11 +180,11 @@ struct EmptyHistoryProvider <: HistoryProvider end reset_state(::EmptyHistoryProvider) = nothing -complete_line(c::EmptyCompletionProvider, s) = String[], "", true +complete_line(c::EmptyCompletionProvider, s; hint::Bool=false) = String[], "", true # complete_line can be specialized for only two arguments, when the active module # doesn't matter (e.g. Pkg does this) -complete_line(c::CompletionProvider, s, ::Module) = complete_line(c, s) +complete_line(c::CompletionProvider, s, ::Module; hint::Bool=false) = complete_line(c, s; hint) terminal(s::IO) = s terminal(s::PromptState) = s.terminal @@ -381,7 +381,7 @@ function check_for_hint(s::MIState) # Requires making space for them earlier in refresh_multi_line return clear_hint(st) end - completions, partial, should_complete = complete_line(st.p.complete, st, s.active_module)::Tuple{Vector{String},String,Bool} + completions, partial, should_complete = complete_line(st.p.complete, st, s.active_module; hint = true)::Tuple{Vector{String},String,Bool} isempty(completions) && return clear_hint(st) # Don't complete for single chars, given e.g. `x` completes to `xor` if length(partial) > 1 && should_complete @@ -417,8 +417,8 @@ function clear_hint(s::ModeState) end end -function complete_line(s::PromptState, repeats::Int, mod::Module) - completions, partial, should_complete = complete_line(s.p.complete, s, mod)::Tuple{Vector{String},String,Bool} +function complete_line(s::PromptState, repeats::Int, mod::Module; hint::Bool=false) + completions, partial, should_complete = complete_line(s.p.complete, s, mod; hint)::Tuple{Vector{String},String,Bool} isempty(completions) && return false if !should_complete # should_complete is false for cases where we only want to show @@ -2150,8 +2150,8 @@ setmodifiers!(p::Prompt, m::Modifiers) = setmodifiers!(p.complete, m) setmodifiers!(c) = nothing # Search Mode completions -function complete_line(s::SearchState, repeats, mod::Module) - completions, partial, should_complete = complete_line(s.histprompt.complete, s, mod) +function complete_line(s::SearchState, repeats, mod::Module; hint::Bool=false) + completions, partial, should_complete = complete_line(s.histprompt.complete, s, mod; hint) # For now only allow exact completions in search mode if length(completions) == 1 prev_pos = position(s) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 5e92ea920b640..8b540f0220a30 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -610,26 +610,26 @@ end beforecursor(buf::IOBuffer) = String(buf.data[1:buf.ptr-1]) -function complete_line(c::REPLCompletionProvider, s::PromptState, mod::Module) +function complete_line(c::REPLCompletionProvider, s::PromptState, mod::Module; hint::Bool=false) partial = beforecursor(s.input_buffer) full = LineEdit.input_string(s) - ret, range, should_complete = completions(full, lastindex(partial), mod, c.modifiers.shift) + ret, range, should_complete = completions(full, lastindex(partial), mod, c.modifiers.shift, hint) c.modifiers = LineEdit.Modifiers() return unique!(map(completion_text, ret)), partial[range], should_complete end -function complete_line(c::ShellCompletionProvider, s::PromptState) +function complete_line(c::ShellCompletionProvider, s::PromptState; hint::Bool=false) # First parse everything up to the current position partial = beforecursor(s.input_buffer) full = LineEdit.input_string(s) - ret, range, should_complete = shell_completions(full, lastindex(partial)) + ret, range, should_complete = shell_completions(full, lastindex(partial), hint) return unique!(map(completion_text, ret)), partial[range], should_complete end -function complete_line(c::LatexCompletions, s) +function complete_line(c::LatexCompletions, s; hint::Bool=false) partial = beforecursor(LineEdit.buffer(s)) full = LineEdit.input_string(s)::String - ret, range, should_complete = bslash_completions(full, lastindex(partial))[2] + ret, range, should_complete = bslash_completions(full, lastindex(partial), hint)[2] return unique!(map(completion_text, ret)), partial[range], should_complete end @@ -1041,6 +1041,9 @@ setup_interface( extra_repl_keymap::Any = repl.options.extra_keymap ) = setup_interface(repl, hascolor, extra_repl_keymap) +# we have to grab this after Pkg is loaded so cache it +pkg_mode::Union{Nothing,LineEdit.Prompt} = nothing + # This non keyword method can be precompiled which is important function setup_interface( repl::LineEditREPL, @@ -1186,18 +1189,20 @@ function setup_interface( end, ']' => function (s::MIState,o...) if isempty(s) || position(LineEdit.buffer(s)) == 0 - pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg") - REPLExt = Base.require_stdlib(pkgid, "REPLExt") - pkg_mode = nothing - if REPLExt isa Module && isdefined(REPLExt, :PkgCompletionProvider) - for mode in repl.interface.modes - if mode isa LineEdit.Prompt && mode.complete isa REPLExt.PkgCompletionProvider - pkg_mode = mode - break + global pkg_mode + if pkg_mode === nothing + pkgid = Base.PkgId(Base.UUID("44cfe95a-1eb2-52ea-b672-e2afdf69b78f"), "Pkg") + REPLExt = Base.require_stdlib(pkgid, "REPLExt") + pkg_mode = nothing + if REPLExt isa Module && isdefined(REPLExt, :PkgCompletionProvider) + for mode in repl.interface.modes + if mode isa LineEdit.Prompt && mode.complete isa REPLExt.PkgCompletionProvider + pkg_mode = mode + break + end end end end - # TODO: Cache the `pkg_mode`? if pkg_mode !== nothing buf = copy(LineEdit.buffer(s)) transition(s, pkg_mode) do diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index f5ef8e6bff53c..46d6fc7b62dd3 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -367,7 +367,8 @@ function complete_path(path::AbstractString; use_envpath=false, shell_escape=false, raw_escape=false, - string_escape=false) + string_escape=false, + contract_user=false) @assert !(shell_escape && string_escape) if Base.Sys.isunix() && occursin(r"^~(?:/|$)", path) # if the path is just "~", don't consider the expanded username as a prefix @@ -413,7 +414,7 @@ function complete_path(path::AbstractString; matches = ((shell_escape ? do_shell_escape(s) : string_escape ? do_string_escape(s) : s) for s in matches) matches = ((raw_escape ? do_raw_escape(s) : s) for s in matches) - matches = Completion[PathCompletion(s) for s in matches] + matches = Completion[PathCompletion(contract_user ? contractuser(s) : s) for s in matches] return matches, dir, !isempty(matches) end @@ -421,7 +422,8 @@ function complete_path(path::AbstractString, pos::Int; use_envpath=false, shell_escape=false, - string_escape=false) + string_escape=false, + contract_user=false) ## TODO: enable this depwarn once Pkg is fixed #Base.depwarn("complete_path with pos argument is deprecated because the return value [2] is incorrect to use", :complete_path) paths, dir, success = complete_path(path; use_envpath, shell_escape, string_escape) @@ -909,7 +911,7 @@ function close_path_completion(dir, paths, str, pos) return lastindex(str) <= pos || str[nextind(str, pos)] != '"' end -function bslash_completions(string::String, pos::Int) +function bslash_completions(string::String, pos::Int, hint::Bool=false) slashpos = something(findprev(isequal('\\'), string, pos), 0) if (something(findprev(in(bslash_separators), string, pos), 0) < slashpos && !(1 < slashpos && (string[prevind(string, slashpos)]=='\\'))) @@ -1166,7 +1168,7 @@ function complete_identifiers!(suggestions::Vector{Completion}, @nospecialize(ff return sort!(unique(suggestions), by=completion_text), (dotpos+1):pos, true end -function completions(string::String, pos::Int, context_module::Module=Main, shift::Bool=true) +function completions(string::String, pos::Int, context_module::Module=Main, shift::Bool=true, hint::Bool=false) # First parse everything up to the current position partial = string[1:pos] inc_tag = Base.incomplete_tag(Meta.parse(partial, raise=false, depwarn=false)) @@ -1219,6 +1221,9 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif # its invocation. varrange = findprev("var\"", string, pos) + expanded = nothing + was_expanded = false + if varrange !== nothing ok, ret = bslash_completions(string, pos) ok && return ret @@ -1235,7 +1240,13 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif scs::String = string[r] expanded = complete_expanduser(scs, r) - expanded[3] && return expanded # If user expansion available, return it + was_expanded = expanded[3] + if was_expanded + scs = (only(expanded[1])::PathCompletion).path + # If tab press, ispath and user expansion available, return it now + # otherwise see if we can complete the path further before returning with expanded ~ + !hint && ispath(scs) && return expanded::Completions + end path::String = replace(scs, r"(\\+)\g1(\\?)`" => "\1\2`") # fuzzy unescape_raw_string: match an even number of \ before ` and replace with half as many # This expansion with "\\ "=>' ' replacement and shell_escape=true @@ -1253,12 +1264,19 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif r = nextind(string, startpos + sizeof(dir)):pos else map!(paths, paths) do c::PathCompletion - return PathCompletion(dir * "/" * c.path) + p = dir * "/" * c.path + was_expanded && (p = contractuser(p)) + return PathCompletion(p) end end end end - return sort!(paths, by=p->p.path), r, success + if isempty(paths) && !hint && was_expanded + # if not able to provide completions, not hinting, and ~ expansion was possible, return ~ expansion + return expanded::Completions + else + return sort!(paths, by=p->p.path), r::UnitRange{Int}, success + end end elseif inc_tag === :string # Find first non-escaped quote @@ -1268,7 +1286,13 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif scs::String = string[r] expanded = complete_expanduser(scs, r) - expanded[3] && return expanded # If user expansion available, return it + was_expanded = expanded[3] + if was_expanded + scs = (only(expanded[1])::PathCompletion).path + # If tab press, ispath and user expansion available, return it now + # otherwise see if we can complete the path further before returning with expanded ~ + !hint && ispath(scs) && return expanded::Completions + end path = try unescape_string(replace(scs, "\\\$"=>"\$")) @@ -1280,7 +1304,9 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif paths, dir, success = complete_path(path::String, string_escape=true) if close_path_completion(dir, paths, path, pos) - paths[1] = PathCompletion((paths[1]::PathCompletion).path * "\"") + p = (paths[1]::PathCompletion).path * "\"" + hint && was_expanded && (p = contractuser(p)) + paths[1] = PathCompletion(p) end if success && !isempty(dir) @@ -1289,21 +1315,31 @@ function completions(string::String, pos::Int, context_module::Module=Main, shif # otherwise make it the whole completion if endswith(dir, "/") && startswith(scs, dir) r = (startpos + sizeof(dir)):pos - elseif startswith(scs, dir * "/") + elseif startswith(scs, dir * "/") && dir != dirname(homedir()) + was_expanded && (dir = contractuser(dir)) r = nextind(string, startpos + sizeof(dir)):pos else map!(paths, paths) do c::PathCompletion - return PathCompletion(dir * "/" * c.path) + p = dir * "/" * c.path + hint && was_expanded && (p = contractuser(p)) + return PathCompletion(p) end end end end # Fallthrough allowed so that Latex symbols can be completed in strings - success && return sort!(paths, by=p->p.path), r, success + if success + return sort!(paths, by=p->p.path), r::UnitRange{Int}, success + elseif !hint && was_expanded + # if not able to provide completions, not hinting, and ~ expansion was possible, return ~ expansion + return expanded::Completions + end end end end + # if path has ~ and we didn't find any paths to complete just return the expanded path + was_expanded && return expanded::Completions ok, ret = bslash_completions(string, pos) ok && return ret @@ -1389,7 +1425,7 @@ end module_filter(mod::Module, x::Symbol) = Base.isbindingresolved(mod, x) && isdefined(mod, x) && isa(getglobal(mod, x), Module) -function shell_completions(string, pos) +function shell_completions(string, pos, hint::Bool=false) # First parse everything up to the current position scs = string[1:pos] args, last_arg_start = try @@ -1407,7 +1443,7 @@ function shell_completions(string, pos) # If the last char was a space, but shell_parse ignored it search on "". if isexpr(lastarg, :incomplete) || isexpr(lastarg, :error) partial = string[last_arg_start:pos] - ret, range = completions(partial, lastindex(partial)) + ret, range = completions(partial, lastindex(partial), Main, true, hint) range = range .+ (last_arg_start - 1) return ret, range, true elseif endswith(scs, ' ') && !endswith(scs, "\\ ") @@ -1422,9 +1458,16 @@ function shell_completions(string, pos) # Also try looking into the env path if the user wants to complete the first argument use_envpath = length(args.args) < 2 - # TODO: call complete_expanduser here? + expanded = complete_expanduser(path, r) + was_expanded = expanded[3] + if was_expanded + path = (only(expanded[1])::PathCompletion).path + # If tab press, ispath and user expansion available, return it now + # otherwise see if we can complete the path further before returning with expanded ~ + !hint && ispath(path) && return expanded::Completions + end - paths, dir, success = complete_path(path, use_envpath=use_envpath, shell_escape=true) + paths, dir, success = complete_path(path, use_envpath=use_envpath, shell_escape=true, contract_user=was_expanded) if success && !isempty(dir) let dir = do_shell_escape(dir) @@ -1442,7 +1485,14 @@ function shell_completions(string, pos) end end end - + # if ~ was expanded earlier and the incomplete string isn't a path + # return the path with contracted user to match what the hint shows. Otherwise expand ~ + # i.e. require two tab presses to expand user + if was_expanded && !ispath(path) + map!(paths, paths) do c::PathCompletion + PathCompletion(contractuser(c.path)) + end + end return paths, r, success end return Completion[], 0:-1, false diff --git a/stdlib/StyledStrings.version b/stdlib/StyledStrings.version index 19a5a24514f2f..81a599f125406 100644 --- a/stdlib/StyledStrings.version +++ b/stdlib/StyledStrings.version @@ -1,4 +1,4 @@ STYLEDSTRINGS_BRANCH = main -STYLEDSTRINGS_SHA1 = e0ca0f85412ea5cafabfeaaec4d62ca26c3959d2 +STYLEDSTRINGS_SHA1 = ac472083359dde956aed8c61d43b8158ac84d9ce STYLEDSTRINGS_GIT_URL := https://github.com/JuliaLang/StyledStrings.jl.git STYLEDSTRINGS_TAR_URL = https://api.github.com/repos/JuliaLang/StyledStrings.jl/tarball/$1 diff --git a/stdlib/Test/docs/src/index.md b/stdlib/Test/docs/src/index.md index e68efdfb6ebf5..949c2591474a6 100644 --- a/stdlib/Test/docs/src/index.md +++ b/stdlib/Test/docs/src/index.md @@ -24,7 +24,7 @@ The `Test` module provides simple *unit testing* functionality. Unit testing is see if your code is correct by checking that the results are what you expect. It can be helpful to ensure your code still works after you make changes, and can be used when developing as a way of specifying the behaviors your code should have when complete. You may also want to look at the -documentation for [adding tests to your Julia Package](@ref adding-tests-to-packages). +documentation for [adding tests to your Julia Package](https://pkgdocs.julialang.org/dev/creating-packages/#Adding-tests-to-the-package). Simple unit testing can be performed with the `@test` and `@test_throws` macros: @@ -469,7 +469,7 @@ end We will need to create those two included files, `math_tests.jl` and `greeting_tests.jl`, and add some tests to them. > **Note:** Notice how we did not have to specify add `Example` into the `test` environment's `Project.toml`. -> This is a benefit of Julia's testing system that you could [read about more here](@ref adding-tests-to-packages). +> This is a benefit of Julia's testing system that you could [read about more here](https://pkgdocs.julialang.org/dev/creating-packages/). #### Writing Tests for `math_tests.jl` diff --git a/stdlib/Test/src/logging.jl b/stdlib/Test/src/logging.jl index 42d3eaf8eaa48..b224d79e47cd9 100644 --- a/stdlib/Test/src/logging.jl +++ b/stdlib/Test/src/logging.jl @@ -2,6 +2,7 @@ using Logging: Logging, AbstractLogger, LogLevel, Info, with_logger import Base: occursin +using Base: @lock #------------------------------------------------------------------------------- """ @@ -35,11 +36,15 @@ struct Ignored ; end #------------------------------------------------------------------------------- # Logger with extra test-related state mutable struct TestLogger <: AbstractLogger - logs::Vector{LogRecord} + lock::ReentrantLock + logs::Vector{LogRecord} # Guarded by lock. min_level::LogLevel catch_exceptions::Bool - shouldlog_args - message_limits::Dict{Any,Int} + # Note: shouldlog_args only maintains the info for the most recent log message, which + # may not be meaningful in a multithreaded program. See: + # https://github.com/JuliaLang/julia/pull/54497#discussion_r1603691606 + shouldlog_args # Guarded by lock. + message_limits::Dict{Any,Int} # Guarded by lock. respect_maxlog::Bool end @@ -80,15 +85,17 @@ Test Passed ``` """ TestLogger(; min_level=Info, catch_exceptions=false, respect_maxlog=true) = - TestLogger(LogRecord[], min_level, catch_exceptions, nothing, Dict{Any, Int}(), respect_maxlog) + TestLogger(ReentrantLock(), LogRecord[], min_level, catch_exceptions, nothing, Dict{Any, Int}(), respect_maxlog) Logging.min_enabled_level(logger::TestLogger) = logger.min_level function Logging.shouldlog(logger::TestLogger, level, _module, group, id) - if get(logger.message_limits, id, 1) > 0 - logger.shouldlog_args = (level, _module, group, id) - true - else - false + @lock logger.lock begin + if get(logger.message_limits, id, 1) > 0 + logger.shouldlog_args = (level, _module, group, id) + return true + else + return false + end end end @@ -98,12 +105,17 @@ function Logging.handle_message(logger::TestLogger, level, msg, _module, if logger.respect_maxlog maxlog = get(kwargs, :maxlog, nothing) if maxlog isa Core.BuiltinInts - remaining = get!(logger.message_limits, id, Int(maxlog)::Int) - logger.message_limits[id] = remaining - 1 - remaining > 0 || return + @lock logger.lock begin + remaining = get!(logger.message_limits, id, Int(maxlog)::Int) + logger.message_limits[id] = remaining - 1 + remaining > 0 || return + end end end - push!(logger.logs, LogRecord(level, msg, _module, group, id, file, line, kwargs)) + r = LogRecord(level, msg, _module, group, id, file, line, kwargs) + @lock logger.lock begin + push!(logger.logs, r) + end end # Catch exceptions for the test logger only if specified @@ -112,7 +124,9 @@ Logging.catch_exceptions(logger::TestLogger) = logger.catch_exceptions function collect_test_logs(f; kwargs...) logger = TestLogger(; kwargs...) value = with_logger(f, logger) - logger.logs, value + @lock logger.lock begin + return copy(logger.logs), value + end end diff --git a/test/abstractarray.jl b/test/abstractarray.jl index a156953476c43..732ffba85ae84 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -2059,34 +2059,3 @@ end @test r2[i] == z[j] end end - -@testset "_unsetindex!" begin - struct MyMatrixUnsetIndexCartInds{T,A<:AbstractMatrix{T}} <: AbstractMatrix{T} - data :: A - end - Base.size(A::MyMatrixUnsetIndexCartInds) = size(A.data) - Base.getindex(M::MyMatrixUnsetIndexCartInds, i::Int, j::Int) = M.data[i,j] - Base.setindex!(M::MyMatrixUnsetIndexCartInds, v, i::Int, j::Int) = setindex!(M.data, v, i, j) - struct MyMatrixUnsetIndexLinInds{T,A<:AbstractMatrix{T}} <: AbstractMatrix{T} - data :: A - end - Base.size(A::MyMatrixUnsetIndexLinInds) = size(A.data) - Base.getindex(M::MyMatrixUnsetIndexLinInds, i::Int) = M.data[i] - Base.setindex!(M::MyMatrixUnsetIndexLinInds, v, i::Int) = setindex!(M.data, v, i) - Base.IndexStyle(::Type{<:MyMatrixUnsetIndexLinInds}) = IndexLinear() - - function test_unsetindex(MT) - M = MT(ones(2,2)) - M2 = MT(Matrix{BigFloat}(undef, 2,2)) - copyto!(M, M2) - @test all(==(1), M) - M3 = MT(Matrix{BigFloat}(undef, 2,2)) - for i in eachindex(M3) - @test !isassigned(M3, i) - end - M3 .= 1 - @test_throws MethodError copyto!(M3, M2) - end - test_unsetindex(MyMatrixUnsetIndexCartInds) - test_unsetindex(MyMatrixUnsetIndexLinInds) -end diff --git a/test/arrayops.jl b/test/arrayops.jl index a31d373a65a38..1c36453a6adae 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -3203,6 +3203,7 @@ end @test @inferred(view(mem, 3:8))::Vector{Int} == 13:18 @test @inferred(view(mem, 20:19))::Vector{Int} == [] @test @inferred(view(mem, -5:-7))::Vector{Int} == [] + @test @inferred(view(mem, :))::Vector{Int} == mem @test @inferred(reshape(mem, 5, 2))::Matrix{Int} == reshape(11:20, 5, 2) # 53990 @@ -3217,6 +3218,7 @@ end @test @inferred(view(empty_mem, 1:0))::Vector{Module} == [] @test @inferred(view(empty_mem, 10:3))::Vector{Module} == [] + @test @inferred(view(empty_mem, :))::Vector{Module} == empty_mem @test isempty(@inferred(reshape(empty_mem, 0, 7, 1))::Array{Module, 3}) offset_inds = OffsetArrays.IdOffsetRange(values=3:6, indices=53:56) diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 7cc51520fb0f2..47537b1cc9a5d 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -1135,14 +1135,14 @@ end ## `Main.main` entrypoint # Basic usage -@test readchomp(`$(Base.julia_cmd()) -e '(@main)(ARGS) = println("hello")'`) == "hello" +@test readchomp(`$(Base.julia_cmd()) -e '(@main)(args) = println("hello")'`) == "hello" # Test ARGS with -e -@test readchomp(`$(Base.julia_cmd()) -e '(@main)(ARGS) = println(ARGS)' a b`) == repr(["a", "b"]) +@test readchomp(`$(Base.julia_cmd()) -e '(@main)(args) = println(ARGS)' a b`) == repr(["a", "b"]) # Test import from module -@test readchomp(`$(Base.julia_cmd()) -e 'module Hello; export main; (@main)(ARGS) = println("hello"); end; using .Hello'`) == "hello" -@test readchomp(`$(Base.julia_cmd()) -e 'module Hello; export main; (@main)(ARGS) = println("hello"); end; import .Hello'`) == "" +@test readchomp(`$(Base.julia_cmd()) -e 'module Hello; export main; (@main)(args) = println("hello"); end; using .Hello'`) == "hello" +@test readchomp(`$(Base.julia_cmd()) -e 'module Hello; export main; (@main)(args) = println("hello"); end; import .Hello'`) == "" # test --bug-report=rr if Sys.islinux() && Sys.ARCH in (:i686, :x86_64) # rr is only available on these platforms diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index 805e5c7acc817..a95ef3225c3f3 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -873,3 +873,17 @@ if Sys.ARCH === :x86_64 end end end + +#Check if we aren't emitting the store with the wrong TBAA metadata + +foo54166(x,i,y) = x[i] = y +let io = IOBuffer() + code_llvm(io,foo54166, (Vector{Union{Missing,Int}}, Int, Int), dump_module=true, raw=true) + str = String(take!(io)) + @test !occursin("jtbaa_unionselbyte", str) + @test occursin("jtbaa_arrayselbyte", str) +end + +ex54166 = Union{Missing, Int64}[missing -2; missing -2]; +dims54166 = (1,2) +@test (minimum(ex54166; dims=dims54166)[1] === missing) diff --git a/test/compiler/effects.jl b/test/compiler/effects.jl index fa70c8de9d853..36c28b6c844bf 100644 --- a/test/compiler/effects.jl +++ b/test/compiler/effects.jl @@ -249,52 +249,52 @@ struct SyntacticallyDefined{T} x::T end -import Core.Compiler: Const, getfield_notundefined +import Core.Compiler: Const, getfield_notuninit for T = (Base.RefValue, Maybe) # both mutable and immutable for name = (Const(1), Const(:x)) - @test getfield_notundefined(T{String}, name) - @test getfield_notundefined(T{Integer}, name) - @test getfield_notundefined(T{Union{String,Integer}}, name) - @test getfield_notundefined(Union{T{String},T{Integer}}, name) - @test !getfield_notundefined(T{Int}, name) - @test !getfield_notundefined(T{<:Integer}, name) - @test !getfield_notundefined(T{Union{Int32,Int64}}, name) - @test !getfield_notundefined(T, name) + @test getfield_notuninit(T{String}, name) + @test getfield_notuninit(T{Integer}, name) + @test getfield_notuninit(T{Union{String,Integer}}, name) + @test getfield_notuninit(Union{T{String},T{Integer}}, name) + @test !getfield_notuninit(T{Int}, name) + @test !getfield_notuninit(T{<:Integer}, name) + @test !getfield_notuninit(T{Union{Int32,Int64}}, name) + @test !getfield_notuninit(T, name) end # throw doesn't account for undefined behavior for name = (Const(0), Const(2), Const(1.0), Const(:y), Const("x"), Float64, String, Nothing) - @test getfield_notundefined(T{String}, name) - @test getfield_notundefined(T{Int}, name) - @test getfield_notundefined(T{Integer}, name) - @test getfield_notundefined(T{<:Integer}, name) - @test getfield_notundefined(T{Union{Int32,Int64}}, name) - @test getfield_notundefined(T, name) + @test getfield_notuninit(T{String}, name) + @test getfield_notuninit(T{Int}, name) + @test getfield_notuninit(T{Integer}, name) + @test getfield_notuninit(T{<:Integer}, name) + @test getfield_notuninit(T{Union{Int32,Int64}}, name) + @test getfield_notuninit(T, name) end # should not be too conservative when field isn't known very well but object information is accurate - @test getfield_notundefined(T{String}, Int) - @test getfield_notundefined(T{String}, Symbol) - @test getfield_notundefined(T{Integer}, Int) - @test getfield_notundefined(T{Integer}, Symbol) - @test !getfield_notundefined(T{Int}, Int) - @test !getfield_notundefined(T{Int}, Symbol) - @test !getfield_notundefined(T{<:Integer}, Int) - @test !getfield_notundefined(T{<:Integer}, Symbol) + @test getfield_notuninit(T{String}, Int) + @test getfield_notuninit(T{String}, Symbol) + @test getfield_notuninit(T{Integer}, Int) + @test getfield_notuninit(T{Integer}, Symbol) + @test !getfield_notuninit(T{Int}, Int) + @test !getfield_notuninit(T{Int}, Symbol) + @test !getfield_notuninit(T{<:Integer}, Int) + @test !getfield_notuninit(T{<:Integer}, Symbol) end # should be conservative when object information isn't accurate -@test !getfield_notundefined(Any, Const(1)) -@test !getfield_notundefined(Any, Const(:x)) +@test !getfield_notuninit(Any, Const(1)) +@test !getfield_notuninit(Any, Const(:x)) # tuples and namedtuples should be okay if not given accurate information for TupleType = Any[Tuple{Int,Int,Int}, Tuple{Int,Vararg{Int}}, Tuple{Any}, Tuple, NamedTuple{(:a, :b), Tuple{Int,Int}}, NamedTuple{(:x,),Tuple{Any}}, NamedTuple], FieldType = Any[Int, Symbol, Any] - @test getfield_notundefined(TupleType, FieldType) + @test getfield_notuninit(TupleType, FieldType) end # skip analysis on fields that are known to be defined syntactically -@test Core.Compiler.getfield_notundefined(SyntacticallyDefined{Float64}, Symbol) -@test Core.Compiler.getfield_notundefined(Const(Main), Const(:var)) -@test Core.Compiler.getfield_notundefined(Const(Main), Const(42)) -# high-level tests for `getfield_notundefined` +@test Core.Compiler.getfield_notuninit(SyntacticallyDefined{Float64}, Symbol) +@test Core.Compiler.getfield_notuninit(Const(Main), Const(:var)) +@test Core.Compiler.getfield_notuninit(Const(Main), Const(42)) +# high-level tests for `getfield_notuninit` @test Base.infer_effects() do Maybe{Int}() end |> !Core.Compiler.is_consistent @@ -904,7 +904,7 @@ end |> Core.Compiler.is_foldable_nothrow @test Base.infer_effects(Tuple{WrapperOneField{Float64}, Symbol}) do w, s getfield(w, s) end |> Core.Compiler.is_foldable -@test Core.Compiler.getfield_notundefined(WrapperOneField{Float64}, Symbol) +@test Core.Compiler.getfield_notuninit(WrapperOneField{Float64}, Symbol) @test Base.infer_effects(Tuple{WrapperOneField{Symbol}, Symbol}) do w, s getfield(w, s) end |> Core.Compiler.is_foldable @@ -996,7 +996,7 @@ end let effects = Base.infer_effects() do isdefined(defined_ref, :x) end - @test Core.Compiler.is_consistent(effects) + @test !Core.Compiler.is_consistent(effects) @test Core.Compiler.is_nothrow(effects) end let effects = Base.infer_effects() do @@ -1102,7 +1102,7 @@ function f3_optrefine(x) @fastmath sqrt(x) return x end -@test Core.Compiler.is_consistent(Base.infer_effects(f3_optrefine)) +@test Core.Compiler.is_consistent(Base.infer_effects(f3_optrefine, (Float64,))) # Check that :consistent is properly modeled for throwing statements const GLOBAL_MUTABLE_SWITCH = Ref{Bool}(false) @@ -1387,3 +1387,16 @@ let; Base.Experimental.@force_compile; func52843(); end # https://github.com/JuliaLang/julia/issues/53508 @test !Core.Compiler.is_consistent(Base.infer_effects(getindex, (UnitRange{Int},Int))) @test !Core.Compiler.is_consistent(Base.infer_effects(getindex, (Base.OneTo{Int},Int))) + +@noinline f53613() = @assert isdefined(@__MODULE__, :v53613) +g53613() = f53613() +h53613() = g53613() +@test !Core.Compiler.is_consistent(Base.infer_effects(f53613)) +@test !Core.Compiler.is_consistent(Base.infer_effects(g53613)) +@test_throws AssertionError f53613() +@test_throws AssertionError g53613() +@test_throws AssertionError h53613() +global v53613 = nothing +@test f53613() === nothing +@test g53613() === nothing +@test h53613() === nothing diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 243566596954e..d546e70d7d749 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -5645,3 +5645,12 @@ end @test issue53590(true, false) == Real @test issue53590(false, false) == Float64 @test issue53590(false, true) == Real + +# issue #53585 +let t = ntuple(i -> i % 8 == 1 ? Int64 : Float64, 4000) + @test only(Base.return_types(Base.promote_typeof, t)) == Type{Float64} + @test only(Base.return_types(vcat, t)) == Vector{Float64} +end + +# fieldcount on `Tuple` should constant fold, even though `.fields` not const +@test fully_eliminated(Base.fieldcount, Tuple{Type{Tuple{Nothing, Int, Int}}}) diff --git a/test/compiler/ssair.jl b/test/compiler/ssair.jl index e237ab732ef57..9250a5d46989f 100644 --- a/test/compiler/ssair.jl +++ b/test/compiler/ssair.jl @@ -233,35 +233,79 @@ let code = Any[ end # issue #37919 -let ci = code_lowered(()->@isdefined(_not_def_37919_), ())[1] +let ci = only(code_lowered(()->@isdefined(_not_def_37919_), ())) ir = Core.Compiler.inflate_ir(ci) @test Core.Compiler.verify_ir(ir) === nothing end let code = Any[ # block 1 - GotoIfNot(Argument(2), 4), + GotoIfNot(Argument(2), 4) # block 2 - GotoNode(3), + Expr(:call, throw, "potential throw") + ReturnNode() # unreachable # block 3 - Expr(:call, throw, "potential throw"), + ReturnNode(Argument(3)) + ] + ir = make_ircode(code; slottypes=Any[Any,Bool,Int]) + visited = BitSet() + @test !Core.Compiler.visit_conditional_successors(ir, #=bb=#1) do succ::Int + push!(visited, succ) + return false + end + @test 2 ∈ visited + @test 3 ∈ visited + oc = Core.OpaqueClosure(ir) + @test oc(false, 1) == 1 + @test_throws "potential throw" oc(true, 1) +end + +let code = Any[ + # block 1 + GotoIfNot(Argument(2), 3) + # block 2 + ReturnNode(Argument(3)) + # block 3 + Expr(:call, throw, "potential throw") + ReturnNode() # unreachable + ] + ir = make_ircode(code; slottypes=Any[Any,Bool,Int]) + visited = BitSet() + @test !Core.Compiler.visit_conditional_successors(ir, #=bb=#1) do succ::Int + push!(visited, succ) + return false + end + @test 2 ∈ visited + @test 3 ∈ visited + oc = Core.OpaqueClosure(ir) + @test oc(true, 1) == 1 + @test_throws "potential throw" oc(false, 1) +end + +let code = Any[ + # block 1 + GotoIfNot(Argument(2), 5) + # block 2 + GotoNode(3) + # block 3 + Expr(:call, throw, "potential throw") + ReturnNode() # block 4 - Expr(:call, Core.Intrinsics.add_int, Argument(3), Argument(4)), - GotoNode(6), + Expr(:call, Core.Intrinsics.add_int, Argument(3), Argument(4)) + GotoNode(7) # block 5 - ReturnNode(SSAValue(4)) + ReturnNode(SSAValue(5)) ] ir = make_ircode(code; slottypes=Any[Any,Bool,Int,Int]) - lazypostdomtree = Core.Compiler.LazyPostDomtree(ir) visited = BitSet() - @test !Core.Compiler.visit_conditional_successors(lazypostdomtree, ir, #=bb=#1) do succ::Int + @test !Core.Compiler.visit_conditional_successors(ir, #=bb=#1) do succ::Int push!(visited, succ) return false end @test 2 ∈ visited @test 3 ∈ visited - @test 4 ∉ visited - @test 5 ∉ visited + @test 4 ∈ visited + @test 5 ∈ visited oc = Core.OpaqueClosure(ir) @test oc(false, 1, 1) == 2 @test_throws "potential throw" oc(true, 1, 1) diff --git a/test/copy.jl b/test/copy.jl index 633beee5f2af3..14a8adadccab9 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -246,6 +246,22 @@ end @test (@inferred Base.deepcopy_internal(zeros(), IdDict())) == zeros() end +@testset "deepcopy_internal inference" begin + @inferred Base.deepcopy_internal(1, IdDict()) + @inferred Base.deepcopy_internal(1.0, IdDict()) + @inferred Base.deepcopy_internal(big(1), IdDict()) + @inferred Base.deepcopy_internal(big(1.0), IdDict()) + @inferred Base.deepcopy_internal('a', IdDict()) + @inferred Base.deepcopy_internal("abc", IdDict()) + @inferred Base.deepcopy_internal([1,2,3], IdDict()) + + # structs without custom deepcopy_internal method + struct Immutable2; x::Int; end + mutable struct Mutable2; x::Int; end + @inferred Base.deepcopy_internal(Immutable2(1), IdDict()) + @inferred Base.deepcopy_internal(Mutable2(1), IdDict()) +end + @testset "`copyto!`'s unaliasing" begin a = view([1:3;], :) @test copyto!(a, 2, a, 1, 2) == [1;1:2;] @@ -267,4 +283,6 @@ end @test a.lock !== b.lock @test islocked(a.lock) @test !islocked(b.lock) + @inferred deepcopy(a) + @inferred deepcopy(a.lock) end diff --git a/test/core.jl b/test/core.jl index b1af565c07d6a..9950056aa8b32 100644 --- a/test/core.jl +++ b/test/core.jl @@ -7213,6 +7213,20 @@ end @test_throws ArgumentError Array{Int, 2}(undef, -10, 0) @test_throws ArgumentError Array{Int, 2}(undef, -1, -1) +# issue #54244 +# test that zero sized array doesn't throw even with large axes +bignum = Int==Int64 ? 2^32 : 2^16 +Array{Int}(undef, 0, bignum, bignum) +Array{Int}(undef, bignum, bignum, 0) +Array{Int}(undef, bignum, bignum, 0, bignum, bignum) +# but also test that it does throw if the axes multiply to a multiple of typemax(UInt) +@test_throws ArgumentError Array{Int}(undef, bignum, bignum) +@test_throws ArgumentError Array{Int}(undef, 1, bignum, bignum) +# also test that we always throw erros for negative dims even if other dims are 0 or the product is positive +@test_throws ArgumentError Array{Int}(undef, 0, -4, -4) +@test_throws ArgumentError Array{Int}(undef, -4, 1, 0) +@test_throws ArgumentError Array{Int}(undef, -4, -4, 1) + # issue #28812 @test Tuple{Vararg{Array{T} where T,3}} === Tuple{Array,Array,Array} diff --git a/test/docs.jl b/test/docs.jl index 36893b8614170..8e6023b6b385d 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -2,6 +2,9 @@ import Base.Docs: meta, @var, DocStr, parsedoc +# check that @doc can work before REPL is loaded +@test !startswith(read(`$(Base.julia_cmd()) -E '@doc sin'`, String), "nothing") + using Markdown using REPL diff --git a/test/iobuffer.jl b/test/iobuffer.jl index 6151f90f297ee..d82a68c61f780 100644 --- a/test/iobuffer.jl +++ b/test/iobuffer.jl @@ -196,6 +196,31 @@ end @test position(skip(io, -3)) == 0 end +@testset "issue #53908" begin + @testset "offset $first" for first in (false, true) + b = collect(0x01:0x05) + sizehint!(b, 100; first) # make offset non zero + io = IOBuffer(b) + @test position(skip(io, 4)) == 4 + @test position(skip(io, typemax(Int))) == 5 + @test position(skip(io, typemax(Int128))) == 5 + @test position(skip(io, typemax(Int32))) == 5 + @test position(skip(io, typemin(Int))) == 0 + @test position(skip(io, typemin(Int128))) == 0 + @test position(skip(io, typemin(Int32))) == 0 + @test position(skip(io, 4)) == 4 + @test position(skip(io, -2)) == 2 + @test position(skip(io, -2)) == 0 + @test position(seek(io, -2)) == 0 + @test position(seek(io, typemax(Int))) == 5 + @test position(seek(io, typemax(Int128))) == 5 + @test position(seek(io, typemax(Int32))) == 5 + @test position(seek(io, typemin(Int))) == 0 + @test position(seek(io, typemin(Int128))) == 0 + @test position(seek(io, typemin(Int32))) == 0 + end +end + @testset "pr #11554" begin io = IOBuffer(SubString("***αhelloworldω***", 4, 16)) io2 = IOBuffer(Vector{UInt8}(b"goodnightmoon"), read=true, write=true) @@ -358,3 +383,8 @@ end seek(io,0) @test Base.read_sub(io,v,1,1) == [1,0] end + +@testset "with offset" begin + b = pushfirst!([0x02], 0x01) + @test take!(IOBuffer(b)) == [0x01, 0x02] +end diff --git a/test/math.jl b/test/math.jl index f3c6dc5bb103f..c88905018fb3a 100644 --- a/test/math.jl +++ b/test/math.jl @@ -47,6 +47,17 @@ has_fma = Dict( clamp!(x, 1, 3) @test x == [1.0, 1.0, 2.0, 3.0, 3.0] end + + @test clamp(typemax(UInt64), Int64) === typemax(Int64) + @test clamp(typemin(Int), UInt64) === typemin(UInt64) + @test clamp(Int16(-1), UInt16) === UInt16(0) + @test clamp(-1, 2, UInt(0)) === UInt(2) + @test clamp(typemax(UInt16), Int16) === Int16(32767) + + # clamp should not allocate a BigInt for typemax(Int16) + x = big(2) ^ 100 + @test (@allocated clamp(x, Int16)) == 0 + end @testset "constants" begin diff --git a/test/precompile.jl b/test/precompile.jl index 527be616a5448..d8471120051db 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -469,7 +469,7 @@ precompile_test_harness(false) do dir # and their dependencies Dict(Base.PkgId(Base.root_module(Base, :SHA)) => Base.module_build_id(Base.root_module(Base, :SHA))), Dict(Base.PkgId(Base.root_module(Base, :Markdown)) => Base.module_build_id(Base.root_module(Base, :Markdown))), - Dict(Base.PkgId(Base.root_module(Base, :StyledStrings)) => Base.module_build_id(Base.root_module(Base, :StyledStrings))), + # and their dependencies Dict(Base.PkgId(Base.root_module(Base, :Base64)) => Base.module_build_id(Base.root_module(Base, :Base64))), ) @@ -1355,6 +1355,25 @@ precompile_test_harness("package_callbacks") do dir finally pop!(Base.package_callbacks) end + Test5_module = :Teste4095a85 + write(joinpath(dir, "$(Test5_module).jl"), + """ + module $(Test5_module) + end + """) + Base.compilecache(Base.PkgId("$(Test5_module)")) + cnt = 0 + push!(Base.package_callbacks, _->(cnt += 1)) + try + @eval using $(Symbol(Test5_module)) + @eval using $(Symbol(Test5_module)) + @eval using $(Symbol(Test5_module)) + @eval using $(Symbol(Test5_module)) + @eval using $(Symbol(Test5_module)) + @test cnt == 1 + finally + pop!(Base.package_callbacks) + end end # Issue #19960 diff --git a/test/read.jl b/test/read.jl index 283381668c28a..34224c146864e 100644 --- a/test/read.jl +++ b/test/read.jl @@ -170,6 +170,10 @@ for (name, f) in l local t, s, m, kept @test readuntil(io(t), s) == m @test readuntil(io(t), s, keep=true) == kept + if isone(length(s)) + @test readuntil(io(t), first(s)) == m + @test readuntil(io(t), first(s), keep=true) == kept + end @test readuntil(io(t), SubString(s, firstindex(s))) == m @test readuntil(io(t), SubString(s, firstindex(s)), keep=true) == kept @test readuntil(io(t), GenericString(s)) == m diff --git a/test/rounding.jl b/test/rounding.jl index 045c834e63013..76b15ec1d9118 100644 --- a/test/rounding.jl +++ b/test/rounding.jl @@ -458,3 +458,15 @@ end @test_throws InexactError round(Int128, -Inf16) # More comprehensive testing is present in test/floatfuncs.jl end + +@testset "floor(<:AbstractFloat, large_number) (#52355)" begin + @test floor(Float32, 0xffff_ffff) == prevfloat(2f0^32) <= 0xffff_ffff + @test trunc(Float16, typemax(UInt128)) == floatmax(Float16) + @test round(Float16, typemax(UInt128)) == Inf16 + for i in [-BigInt(floatmax(Float64)), -BigInt(floatmax(Float64))*100, BigInt(floatmax(Float64)), BigInt(floatmax(Float64))*100] + f = ceil(Float64, i) + @test f >= i + @test isinteger(f) || isinf(f) + @test prevfloat(f) < i + end +end diff --git a/test/strings/annotated.jl b/test/strings/annotated.jl index fda583bf7f778..222d9addc910c 100644 --- a/test/strings/annotated.jl +++ b/test/strings/annotated.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +using StyledStrings # see https://github.com/JuliaLang/StyledStrings.jl/issues/61 + @testset "AnnotatedString" begin str = Base.AnnotatedString("some string") @test str == Base.AnnotatedString(str.string, Tuple{UnitRange{Int}, Pair{Symbol, Any}}[]) @@ -12,6 +14,8 @@ @test "a" * str == Base.AnnotatedString("asome string") @test str * "a" == Base.AnnotatedString("some stringa") @test str * str == Base.AnnotatedString("some stringsome string") + @test str[3:4] == SubString("me") + @test SubString("me") == str[3:4] Base.annotate!(str, 1:4, :thing => 0x01) Base.annotate!(str, 6:11, :other => 0x02) Base.annotate!(str, 1:11, :all => 0x03) @@ -21,13 +25,15 @@ # └───┰─────┘ # :all @test str[3:4] == SubString(str, 3, 4) + @test str[3:4] != SubString("me") + @test SubString("me") != str[3:4] @test Base.AnnotatedString(str[3:4]) == Base.AnnotatedString("me", [(1:2, :thing => 0x01), (1:2, :all => 0x03)]) @test Base.AnnotatedString(str[3:6]) == - Base.AnnotatedString("me s", [(1:2, :thing => 0x01), (1:4, :all => 0x03), (4:4, :other => 0x02)]) - @test str == Base.AnnotatedString("some string", [(1:4, :thing => 0x01), (1:11, :all => 0x03), (6:11, :other => 0x02)]) + Base.AnnotatedString("me s", [(1:2, :thing => 0x01), (4:4, :other => 0x02), (1:4, :all => 0x03)]) + @test str == Base.AnnotatedString("some string", [(1:4, :thing => 0x01), (6:11, :other => 0x02), (1:11, :all => 0x03)]) @test str != Base.AnnotatedString("some string") - @test str != Base.AnnotatedString("some string", [(1:1, :thing => 0x01), (6:6, :other => 0x02), (11:11, :all => 0x03)]) + @test str != Base.AnnotatedString("some string", [(1:1, :thing => 0x01), (1:11, :all => 0x03), (6:6, :other => 0x02)]) @test str != Base.AnnotatedString("some string", [(1:4, :thing => 0x11), (1:11, :all => 0x13), (6:11, :other => 0x12)]) @test str != Base.AnnotatedString("some thingg", [(1:4, :thing => 0x01), (1:11, :all => 0x03), (6:11, :other => 0x02)]) @test Base.AnnotatedString([Base.AnnotatedChar('a', [:a => 1]), Base.AnnotatedChar('b', [:b => 2])]) == @@ -51,13 +57,10 @@ # @test collect(Base.eachstyle(str)) == # [("some", [:thing => 0x01, :all => 0x03]), # (" string", [:all => 0x03, :other => 0x02])] - @test ==(Base.annotatedstring_optimize!( - Base.AnnotatedString("abc", [(1:1, :val => 1), - (2:2, :val => 2), - (2:2, :val => 1), - (3:3, :val => 2)])), - Base.AnnotatedString("abc", [(1:2, :val => 1), - (2:3, :val => 2)])) + @test chopprefix(sprint(show, str), "Base.") == + "AnnotatedString{String}(\"some string\", [(1:4, :thing => 0x01), (6:11, :other => 0x02), (1:11, :all => 0x03)])" + @test eval(Meta.parse(repr(str))) == str + @test sprint(show, MIME("text/plain"), str) == "\"some string\"" end @testset "AnnotatedChar" begin @@ -108,6 +111,33 @@ end @test reverse(str2) == Base.AnnotatedString("esac", [(2:3, :label => "oomph")]) end +@testset "Unicode" begin + for words in (["ᲃase", "cɦɒnɡeȿ", "can", "CHⱯNGE", "Сodeunıts"], + ["Сodeunıts", "ᲃase", "cɦɒnɡeȿ", "can", "CHⱯNGE"]) + ann_words = [Base.AnnotatedString(w, [(1:ncodeunits(w), :i => i)]) + for (i, w) in enumerate(words)] + ann_str = join(ann_words, '-') + for transform in (lowercase, uppercase, titlecase) + t_words = map(transform, words) + ann_t_words = [Base.AnnotatedString(w, [(1:ncodeunits(w), :i => i)]) + for (i, w) in enumerate(t_words)] + ann_t_str = join(ann_t_words, '-') + t_ann_str = transform(ann_str) + @test String(ann_t_str) == String(t_ann_str) + @test Base.annotations(ann_t_str) == Base.annotations(t_ann_str) + end + for transform in (uppercasefirst, lowercasefirst) + t_words = vcat(transform(first(words)), words[2:end]) + ann_t_words = [Base.AnnotatedString(w, [(1:ncodeunits(w), :i => i)]) + for (i, w) in enumerate(t_words)] + ann_t_str = join(ann_t_words, '-') + t_ann_str = transform(ann_str) + @test String(ann_t_str) == String(t_ann_str) + @test Base.annotations(ann_t_str) == Base.annotations(t_ann_str) + end + end +end + @testset "AnnotatedIOBuffer" begin aio = Base.AnnotatedIOBuffer() # Append-only writing @@ -118,8 +148,8 @@ end # Check `annotate!`, including region sorting @test truncate(aio, 0).io.size == 0 @test write(aio, "hello world") == ncodeunits("hello world") - @test Base.annotate!(aio, 7:11, :tag => 2) === aio @test Base.annotate!(aio, 1:5, :tag => 1) === aio + @test Base.annotate!(aio, 7:11, :tag => 2) === aio @test Base.annotations(aio) == [(1:5, :tag => 1), (7:11, :tag => 2)] # Reading @test read(seekstart(deepcopy(aio.io)), String) == "hello world" @@ -147,24 +177,49 @@ end @test Base.annotations(aio) == [(1:5, :tag => 1), (7:11, :tag => 2)] # Should be unchanged @test write(seek(aio, 0), Base.AnnotatedString("hey-o", [(1:5, :hey => 'o')])) == 5 @test read(seekstart(aio), String) == "hey-o alice" - @test Base.annotations(aio) == [(1:5, :hey => 'o'), (7:11, :tag => 2)] # First annotation should have been entirely replaced + @test Base.annotations(aio) == [(7:11, :tag => 2), (1:5, :hey => 'o')] # First annotation should have been entirely replaced @test write(seek(aio, 7), Base.AnnotatedString("bbi", [(1:3, :hey => 'a')])) == 3 # a[lic => bbi]e ('alice' => 'abbie') @test read(seekstart(aio), String) == "hey-o abbie" - @test Base.annotations(aio) == [(1:5, :hey => 'o'), (7:7, :tag => 2), (8:10, :hey => 'a'), (11:11, :tag => 2)] + @test Base.annotations(aio) == [(7:7, :tag => 2), (11:11, :tag => 2), (1:5, :hey => 'o'), (8:10, :hey => 'a')] @test write(seek(aio, 0), Base.AnnotatedString("ab")) == 2 # Check first annotation's region is adjusted correctly @test read(seekstart(aio), String) == "aby-o abbie" - @test Base.annotations(aio) == [(3:5, :hey => 'o'), (7:7, :tag => 2), (8:10, :hey => 'a'), (11:11, :tag => 2)] + @test Base.annotations(aio) == [(7:7, :tag => 2), (11:11, :tag => 2), (3:5, :hey => 'o'), (8:10, :hey => 'a')] @test write(seek(aio, 3), Base.AnnotatedString("ss")) == 2 @test read(seekstart(aio), String) == "abyss abbie" - @test Base.annotations(aio) == [(3:3, :hey => 'o'), (7:7, :tag => 2), (8:10, :hey => 'a'), (11:11, :tag => 2)] + @test Base.annotations(aio) == [(7:7, :tag => 2), (11:11, :tag => 2), (3:3, :hey => 'o'), (8:10, :hey => 'a')] # Writing one buffer to another newaio = Base.AnnotatedIOBuffer() @test write(newaio, seekstart(aio)) == 11 @test read(seekstart(newaio), String) == "abyss abbie" @test Base.annotations(newaio) == Base.annotations(aio) @test write(seek(newaio, 5), seek(aio, 5)) == 6 - @test Base.annotations(newaio) == Base.annotations(aio) + @test sort(Base.annotations(newaio)) == sort(Base.annotations(aio)) @test write(newaio, seek(aio, 5)) == 6 @test read(seekstart(newaio), String) == "abyss abbie abbie" - @test Base.annotations(newaio) == vcat(Base.annotations(aio), [(13:13, :tag => 2), (14:16, :hey => 'a'), (17:17, :tag => 2)]) + @test sort(Base.annotations(newaio)) == sort(vcat(Base.annotations(aio), [(13:13, :tag => 2), (14:16, :hey => 'a'), (17:17, :tag => 2)])) + # The `_insert_annotations!` cautious-merging optimisation + aio = Base.AnnotatedIOBuffer() + @test write(aio, Base.AnnotatedChar('a', [:a => 1, :b => 2])) == 1 + @test Base.annotations(aio) == [(1:1, :a => 1), (1:1, :b => 2)] + @test write(aio, Base.AnnotatedChar('b', [:a => 1, :b => 2])) == 1 + @test Base.annotations(aio) == [(1:2, :a => 1), (1:2, :b => 2)] + let aio2 = copy(aio) # A different start makes merging too risky to do. + @test write(aio2, Base.AnnotatedChar('c', [:a => 0, :b => 2])) == 1 + @test Base.annotations(aio2) == [(1:2, :a => 1), (1:2, :b => 2), (3:3, :a => 0), (3:3, :b => 2)] + end + let aio2 = copy(aio) # Merging some run of the most recent annotations is fine though. + @test write(aio2, Base.AnnotatedChar('c', [:b => 2])) == 1 + @test Base.annotations(aio2) == [(1:2, :a => 1), (1:3, :b => 2)] + end + let aio2 = copy(aio) # ...and any subsequent annotations after a matching run can just be copied over. + @test write(aio2, Base.AnnotatedChar('c', [:b => 2, :c => 3, :d => 4])) == 1 + @test Base.annotations(aio2) == [(1:2, :a => 1), (1:3, :b => 2), (3:3, :c => 3), (3:3, :d => 4)] + end + # Working through an IOContext + aio = Base.AnnotatedIOBuffer() + wrapio = IOContext(aio) + @test write(wrapio, Base.AnnotatedString("hey", [(1:3, :x => 1)])) == 3 + @test write(wrapio, Base.AnnotatedChar('a', [:y => 2])) == 1 + @test read(seekstart(aio), Base.AnnotatedString) == + Base.AnnotatedString("heya", [(1:3, :x => 1), (4:4, :y => 2)]) end diff --git a/test/subarray.jl b/test/subarray.jl index 31bd69cccb5ae..9fd59ef5a4156 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -826,6 +826,25 @@ end @test @inferred(Base.unaliascopy(V))::typeof(V) == V == A[i1, 1:5, i2, i3] V = view(A, i1, 1:5, i3, i2) @test @inferred(Base.unaliascopy(V))::typeof(V) == V == A[i1, 1:5, i3, i2] + + @testset "custom ranges" begin + struct MyStepRange{T} <: OrdinalRange{T,T} + r::StepRange{T,T} + end + + for f in (:first, :last, :step, :length, :size) + @eval Base.$f(r::MyStepRange) = $f(r.r) + end + Base.getindex(r::MyStepRange, i::Int) = r.r[i] + + a = rand(6) + V = view(a, MyStepRange(2:2:4)) + @test @inferred(Base.unaliascopy(V))::typeof(V) == V + + # empty range + V = view(a, MyStepRange(2:2:1)) + @test @inferred(Base.unaliascopy(V))::typeof(V) == V + end end @testset "issue #27632" begin @@ -1055,48 +1074,4 @@ end @test !isassigned(v, 1, 2) # inbounds but not assigned @test !isassigned(v, 3, 3) # out-of-bounds end - - @testset "_unsetindex!" begin - function test_unsetindex(A, B) - copyto!(A, B) - for i in eachindex(A) - @test !isassigned(A, i) - end - inds = eachindex(A) - @test_throws BoundsError Base._unsetindex!(A, last(inds) + oneunit(eltype(inds))) - end - @testset "dest IndexLinear, src IndexLinear" begin - for p in (fill(BigInt(2)), BigInt[1, 2], BigInt[1 2; 3 4]) - A = view(copy(p), ntuple(_->:, ndims(p))...) - B = view(similar(A), ntuple(_->:, ndims(p))...) - test_unsetindex(A, B) - test_unsetindex(p, B) - end - end - - @testset "dest IndexLinear, src IndexCartesian" begin - for p in (fill(BigInt(2)), BigInt[1, 2], BigInt[1 2; 3 4]) - A = view(copy(p), ntuple(_->:, ndims(p))...) - B = view(similar(A), axes(A)...) - test_unsetindex(A, B) - test_unsetindex(p, B) - end - end - - @testset "dest IndexCartesian, src IndexLinear" begin - for p in (fill(BigInt(2)), BigInt[1, 2], BigInt[1 2; 3 4]) - A = view(p, axes(p)...) - B = similar(A) - test_unsetindex(A, B) - end - end - - @testset "dest IndexCartesian, src IndexCartesian" begin - for p in (fill(BigInt(2)), BigInt[1, 2], BigInt[1 2; 3 4]) - A = view(p, axes(p)...) - B = view(similar(A), axes(A)...) - test_unsetindex(A, B) - end - end - end end diff --git a/test/subtype.jl b/test/subtype.jl index 7805c232bd050..c65521d44ac5a 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -2336,9 +2336,10 @@ T46784{B<:Val, M<:AbstractMatrix} = Tuple{<:Union{B, <:Val{<:B}}, M, Union{Abstr #issue 36185 let S = Tuple{Type{T},Array{Union{T,Missing},N}} where {T,N}, T = Tuple{Type{T},Array{Union{T,Nothing},N}} where {T,N} - @testintersect(S, T, !Union{}) - @test_broken typeintersect(S, T) != S - @test_broken typeintersect(T, S) != T + I = typeintersect(S, T) + @test I == typeintersect(T, S) != Union{} + @test_broken I <: S + @test_broken I <: T end #issue 46736 @@ -2606,3 +2607,46 @@ let S = Type{T53371{A, B, C, D, E}} where {A, B<:R53371{A}, C<:R53371{A}, D<:R53 T = Type{T53371{A, B, C, D, E} where {A, B<:R53371{A}, C<:R53371{A}, D<:R53371{A}, E<:R53371{A}}} @test !(S <: T) end + +#issue 54356 +let S = Tuple{Val{Val{Union{Val{A2}, A2}}}, Val{Val{Union{Val{A2}, Val{A4}, A4}}}} where {A2, A4<:Union{Val{A2}, A2}}, + T = Tuple{Vararg{Val{V}}} where {V} + @testintersect(S, T, !Union{}) +end + +#issue 54356 +abstract type A54356{T<:Real} end +struct B54356{T} <: A54356{T} end +struct C54356{S,T<:Union{S,Complex{S}}} end +struct D54356{S<:Real,T} end +let S = Tuple{Val, Val{T}} where {T}, R = Tuple{Val{Val{T}}, Val{T}} where {T}, + SS = Tuple{Val, Val{T}, Val{T}} where {T}, RR = Tuple{Val{Val{T}}, Val{T}, Val{T}} where {T} + # parameters check for self + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, Complex{B}}}, S{1}, R{1}) + # parameters check for supertype (B54356 -> A54356) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, B54356{B}}}, S{1}, R{1}) + # enure unused TypeVar skips the `UnionAll` wrapping + @testintersect(Tuple{Val{A}, A} where {B, A<:(Union{Val{B}, D54356{B,C}} where {C})}, S{1}, R{1}) + # invariant parameter should not get narrowed + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, Val{Union{Int,Complex{B}}}}}, S{1}, R{1}) + # bit value could not be `Union` element + @testintersect(Tuple{Val{A}, A, Val{B}} where {B, A<:Union{B, Val{B}}}, SS{1}, RR{1}) + @testintersect(Tuple{Val{A}, A, Val{B}} where {B, A<:Union{B, Complex{B}}}, SS{1}, Union{}) + # `check_datatype_parameters` should ignore bad `Union` elements in constraint's ub + T = Tuple{Val{Union{Val{Nothing}, Val{C54356{V,V}}}}, Val{Nothing}} where {Nothing<:V<:Nothing} + @test T <: S{Nothing} + @test T <: Tuple{Val{A}, A} where {B, C, A<:Union{Val{B}, Val{C54356{B,C}}}} + @test T <: typeintersect(Tuple{Val{A}, A} where {B, C, A<:Union{Val{B}, Val{C54356{B,C}}}}, S{Nothing}) + # extra check for Vararg + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NTuple{B,Any}}}, S{-1}, R{-1}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, Tuple{Any,Vararg{Any,B}}}}, S{-1}, R{-1}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, Tuple{Vararg{Int,Union{Int,Complex{B}}}}}}, S{1}, R{1}) + # extra check for NamedTuple + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NamedTuple{B,Tuple{Int}}}}, S{1}, R{1}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NamedTuple{B,Tuple{Int}}}}, S{(1,)}, R{(1,)}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NamedTuple{(:a),B}}}, S{NTuple{2,Int}}, R{NTuple{2,Int}}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, NamedTuple{B,Tuple{Int,Int}}}}, S{(:a,:a)}, R{(:a,:a)}) + # extra check for GenericMemory/GenericMemoryRef + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, GenericMemory{B}}}, S{1}, R{1}) + @testintersect(Tuple{Val{A}, A} where {B, A<:Union{Val{B}, GenericMemory{:not_atomic,Int,B}}}, S{1}, R{1}) +end diff --git a/test/vecelement.jl b/test/vecelement.jl index 6638f06f4f358..b89eb097ee560 100644 --- a/test/vecelement.jl +++ b/test/vecelement.jl @@ -1,5 +1,5 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license - +using InteractiveUtils make_value(::Type{T}, i::Integer) where {T<:Integer} = 3*i%T make_value(::Type{T},i::Integer) where {T<:AbstractFloat} = T(3*i) @@ -120,3 +120,9 @@ for T in (Float64, Float32, Int64, Int32) @test b == result end end +@testset "vecelement overalignment" begin + io = IOBuffer() + code_llvm(io,getindex, (Array{NTuple{5, VecElement{Float64}}, 1}, Int64), optimize=false) + ir = String(take!(io)) + @test match(r"align 64", ir) === nothing +end