From b1e711e5aeb8f0c8c16ec16efb12852812db3ac2 Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Sun, 15 Oct 2023 21:56:22 +0800 Subject: [PATCH 0001/1315] Avoid `Style()` during broadcast whenever possible. (#51708) On master, `combine_styles(bc::Broadcasted)` calls `BroadcastStyle(typeof(bc))`, which seems bad after #49395 as it has a `Style()` call by default. --- base/broadcast.jl | 4 ++++ test/broadcast.jl | 3 +++ 2 files changed, 7 insertions(+) diff --git a/base/broadcast.jl b/base/broadcast.jl index 43044f9b7d6ed..145be717cbd58 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -419,6 +419,10 @@ function combine_styles end combine_styles() = DefaultArrayStyle{0}() combine_styles(c) = result_style(BroadcastStyle(typeof(c))) +function combine_styles(bc::Broadcasted) + bc.style isa Union{Nothing,Unknown} || return bc.style + throw(ArgumentError("Broadcasted{Unknown} wrappers do not have a style assigned")) +end combine_styles(c1, c2) = result_style(combine_styles(c1), combine_styles(c2)) @inline combine_styles(c1, c2, cs...) = result_style(combine_styles(c1), combine_styles(c2, cs...)) diff --git a/test/broadcast.jl b/test/broadcast.jl index 269adc9f7276d..0a111f9523d60 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -1153,6 +1153,9 @@ Base.BroadcastStyle(a::MyBroadcastStyleWithField, b::MyBroadcastStyleWithField) MyBroadcastStyleWithField(1) @test_throws ErrorException Broadcast.result_style(MyBroadcastStyleWithField(1), MyBroadcastStyleWithField(2)) + dest = [0, 0] + dest .= Broadcast.Broadcasted(MyBroadcastStyleWithField(1), +, (1:2, 2:3)) + @test dest == [3, 5] end # test that `Broadcast` definition is defined as total and eligible for concrete evaluation From 4a1d74edc509efc1aec4ace991d86a04fb1d75fc Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Sun, 15 Oct 2023 10:45:26 -0400 Subject: [PATCH 0002/1315] Add versions to all stdlibs (#51696) For upgradeable stdlibs we need versions numbers, let's add them now instead of after excision. --- stdlib/Artifacts/Project.toml | 1 + stdlib/Base64/Project.toml | 1 + stdlib/CRC32c/Project.toml | 1 + stdlib/Dates/Project.toml | 1 + stdlib/FileWatching/Project.toml | 1 + stdlib/Future/Project.toml | 1 + stdlib/InteractiveUtils/Project.toml | 1 + stdlib/LibGit2/Project.toml | 1 + stdlib/Libdl/Project.toml | 1 + stdlib/LinearAlgebra/Project.toml | 1 + stdlib/Logging/Project.toml | 1 + stdlib/Markdown/Project.toml | 1 + stdlib/Mmap/Project.toml | 1 + stdlib/Printf/Project.toml | 1 + stdlib/Profile/Project.toml | 1 + stdlib/REPL/Project.toml | 1 + stdlib/Random/Project.toml | 1 + stdlib/Serialization/Project.toml | 1 + stdlib/SharedArrays/Project.toml | 1 + stdlib/Sockets/Project.toml | 1 + stdlib/Test/Project.toml | 1 + stdlib/UUIDs/Project.toml | 1 + stdlib/Unicode/Project.toml | 2 +- 23 files changed, 23 insertions(+), 1 deletion(-) diff --git a/stdlib/Artifacts/Project.toml b/stdlib/Artifacts/Project.toml index 7251b79cea8c1..c4e5cc031375c 100644 --- a/stdlib/Artifacts/Project.toml +++ b/stdlib/Artifacts/Project.toml @@ -1,5 +1,6 @@ name = "Artifacts" uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" +version = "1.11.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/Base64/Project.toml b/stdlib/Base64/Project.toml index 68d63837fc385..14796beb7e21a 100644 --- a/stdlib/Base64/Project.toml +++ b/stdlib/Base64/Project.toml @@ -1,5 +1,6 @@ name = "Base64" uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" +version = "1.11.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/CRC32c/Project.toml b/stdlib/CRC32c/Project.toml index c1de88cbc7c52..d3ab5ff019503 100644 --- a/stdlib/CRC32c/Project.toml +++ b/stdlib/CRC32c/Project.toml @@ -1,5 +1,6 @@ name = "CRC32c" uuid = "8bf52ea8-c179-5cab-976a-9e18b702a9bc" +version = "1.11.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/Dates/Project.toml b/stdlib/Dates/Project.toml index fe225055bad98..45da6ad1a0152 100644 --- a/stdlib/Dates/Project.toml +++ b/stdlib/Dates/Project.toml @@ -1,5 +1,6 @@ name = "Dates" uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" +version = "1.11.0" [deps] Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" diff --git a/stdlib/FileWatching/Project.toml b/stdlib/FileWatching/Project.toml index 1da637fd4259d..5edcfdadd085d 100644 --- a/stdlib/FileWatching/Project.toml +++ b/stdlib/FileWatching/Project.toml @@ -1,5 +1,6 @@ name = "FileWatching" uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" +version = "1.11.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/Future/Project.toml b/stdlib/Future/Project.toml index ffdbaf94b9853..c09489812ce01 100644 --- a/stdlib/Future/Project.toml +++ b/stdlib/Future/Project.toml @@ -1,5 +1,6 @@ name = "Future" uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" +version = "1.11.0" [deps] Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" diff --git a/stdlib/InteractiveUtils/Project.toml b/stdlib/InteractiveUtils/Project.toml index e13902375e005..53cc9218eff5d 100644 --- a/stdlib/InteractiveUtils/Project.toml +++ b/stdlib/InteractiveUtils/Project.toml @@ -1,5 +1,6 @@ name = "InteractiveUtils" uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +version = "1.11.0" [deps] Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" diff --git a/stdlib/LibGit2/Project.toml b/stdlib/LibGit2/Project.toml index 1205716369e09..83d359d6a4f1a 100644 --- a/stdlib/LibGit2/Project.toml +++ b/stdlib/LibGit2/Project.toml @@ -1,5 +1,6 @@ name = "LibGit2" uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" +version = "1.11.0" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" diff --git a/stdlib/Libdl/Project.toml b/stdlib/Libdl/Project.toml index 26e5bf0cdefd7..7fab4b9334260 100644 --- a/stdlib/Libdl/Project.toml +++ b/stdlib/Libdl/Project.toml @@ -1,5 +1,6 @@ name = "Libdl" uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" +version = "1.11.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/LinearAlgebra/Project.toml b/stdlib/LinearAlgebra/Project.toml index 46653aa795209..892de0397c219 100644 --- a/stdlib/LinearAlgebra/Project.toml +++ b/stdlib/LinearAlgebra/Project.toml @@ -1,5 +1,6 @@ name = "LinearAlgebra" uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +version = "1.11.0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/Logging/Project.toml b/stdlib/Logging/Project.toml index af931e68e07d1..ce69112733d5e 100644 --- a/stdlib/Logging/Project.toml +++ b/stdlib/Logging/Project.toml @@ -1,5 +1,6 @@ name = "Logging" uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" +version = "1.11.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/Markdown/Project.toml b/stdlib/Markdown/Project.toml index 229e58749d233..b40de17b9422d 100644 --- a/stdlib/Markdown/Project.toml +++ b/stdlib/Markdown/Project.toml @@ -1,5 +1,6 @@ name = "Markdown" uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" +version = "1.11.0" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" diff --git a/stdlib/Mmap/Project.toml b/stdlib/Mmap/Project.toml index f3dab686d2eaa..ce4b65ccbb06a 100644 --- a/stdlib/Mmap/Project.toml +++ b/stdlib/Mmap/Project.toml @@ -1,5 +1,6 @@ name = "Mmap" uuid = "a63ad114-7e13-5084-954f-fe012c677804" +version = "1.11.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/Printf/Project.toml b/stdlib/Printf/Project.toml index 9fa4e3633cae1..019b7e94ef9bd 100644 --- a/stdlib/Printf/Project.toml +++ b/stdlib/Printf/Project.toml @@ -1,5 +1,6 @@ name = "Printf" uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" +version = "1.11.0" [deps] Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" diff --git a/stdlib/Profile/Project.toml b/stdlib/Profile/Project.toml index 334d475832b6d..8e50b474f1cd3 100644 --- a/stdlib/Profile/Project.toml +++ b/stdlib/Profile/Project.toml @@ -1,5 +1,6 @@ name = "Profile" uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" +version = "1.11.0" [deps] Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" diff --git a/stdlib/REPL/Project.toml b/stdlib/REPL/Project.toml index 2c3ab32fdc327..77eca2bfe4240 100644 --- a/stdlib/REPL/Project.toml +++ b/stdlib/REPL/Project.toml @@ -1,5 +1,6 @@ name = "REPL" uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" +version = "1.11.0" [deps] InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" diff --git a/stdlib/Random/Project.toml b/stdlib/Random/Project.toml index f86f0a54f8ba4..5a9cc2dfc4cb7 100644 --- a/stdlib/Random/Project.toml +++ b/stdlib/Random/Project.toml @@ -1,5 +1,6 @@ name = "Random" uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +version = "1.11.0" [deps] SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce" diff --git a/stdlib/Serialization/Project.toml b/stdlib/Serialization/Project.toml index 4a2f7874e3124..97e898d731c7d 100644 --- a/stdlib/Serialization/Project.toml +++ b/stdlib/Serialization/Project.toml @@ -1,5 +1,6 @@ name = "Serialization" uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" +version = "1.11.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/SharedArrays/Project.toml b/stdlib/SharedArrays/Project.toml index 588785347c73d..46e5332f8d89d 100644 --- a/stdlib/SharedArrays/Project.toml +++ b/stdlib/SharedArrays/Project.toml @@ -1,5 +1,6 @@ name = "SharedArrays" uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" +version = "1.11.0" [deps] Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b" diff --git a/stdlib/Sockets/Project.toml b/stdlib/Sockets/Project.toml index 5afb89b29f126..6a395465722f2 100644 --- a/stdlib/Sockets/Project.toml +++ b/stdlib/Sockets/Project.toml @@ -1,5 +1,6 @@ name = "Sockets" uuid = "6462fe0b-24de-5631-8697-dd941f90decc" +version = "1.11.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/stdlib/Test/Project.toml b/stdlib/Test/Project.toml index ee1ae15fd7154..f04b4f976196f 100644 --- a/stdlib/Test/Project.toml +++ b/stdlib/Test/Project.toml @@ -1,5 +1,6 @@ name = "Test" uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +version = "1.11.0" [deps] InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" diff --git a/stdlib/UUIDs/Project.toml b/stdlib/UUIDs/Project.toml index 11dbcda5c4944..4eb31dc9572c0 100644 --- a/stdlib/UUIDs/Project.toml +++ b/stdlib/UUIDs/Project.toml @@ -1,5 +1,6 @@ name = "UUIDs" uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" +version = "1.11.0" [deps] Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" diff --git a/stdlib/Unicode/Project.toml b/stdlib/Unicode/Project.toml index 5e3040ce9e3db..a01833870644e 100644 --- a/stdlib/Unicode/Project.toml +++ b/stdlib/Unicode/Project.toml @@ -1,6 +1,6 @@ name = "Unicode" uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" - +version = "1.11.0" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From 0acca3c35524cff5c3dd65c25d1b104e62db22cb Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Sun, 15 Oct 2023 15:21:33 -0400 Subject: [PATCH 0003/1315] Optimize away try/catch blocks that are known not to trigger (#51674) This leverages the support from #51590 to delete any try catch block that is known not to be triggered (either because the try-body is empty to because we have proven `:nothrow` for all contained statements). --- base/compiler/abstractinterpretation.jl | 41 ++++++++------- base/compiler/optimize.jl | 55 ++++++++++++-------- base/compiler/ssair/ir.jl | 15 ++++++ base/compiler/ssair/slot2ssa.jl | 3 +- base/compiler/typelattice.jl | 18 ------- src/codegen.cpp | 11 ++-- test/compiler/inference.jl | 69 +++++++++++++++++++++++++ 7 files changed, 149 insertions(+), 63 deletions(-) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index bfddc2d6927b3..00e9ef48d9fe2 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -2981,6 +2981,20 @@ function update_bestguess!(interp::AbstractInterpreter, frame::InferenceState, end end +function propagate_to_error_handler!(frame::InferenceState, currpc::Int, W::BitSet, ๐•ƒแตข::AbstractLattice, currstate::VarTable) + # If this statement potentially threw, propagate the currstate to the + # exception handler, BEFORE applying any state changes. + cur_hand = frame.handler_at[currpc] + if cur_hand != 0 + enter = frame.src.code[cur_hand]::Expr + l = enter.args[1]::Int + exceptbb = block_for_inst(frame.cfg, l) + if update_bbstate!(๐•ƒแตข, frame, exceptbb, currstate) + push!(W, exceptbb) + end + end +end + # make as much progress on `frame` as possible (without handling cycles) function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) @assert !is_inferred(frame) @@ -3037,6 +3051,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) if nothrow add_curr_ssaflag!(frame, IR_FLAG_NOTHROW) else + propagate_to_error_handler!(frame, currpc, W, ๐•ƒแตข, currstate) merge_effects!(interp, frame, EFFECTS_THROWS) end @@ -3107,12 +3122,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) ssavaluetypes[frame.currpc] = Any @goto find_next_bb elseif isexpr(stmt, :enter) - # Propagate entry info to exception handler - l = stmt.args[1]::Int - catchbb = block_for_inst(frame.cfg, l) - if update_bbstate!(๐•ƒแตข, frame, catchbb, currstate) - push!(W, catchbb) - end + ssavaluetypes[currpc] = Any + @goto fallthrough + elseif isexpr(stmt, :leave) ssavaluetypes[currpc] = Any @goto fallthrough end @@ -3121,26 +3133,15 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) # Process non control-flow statements (; changes, type) = abstract_eval_basic_statement(interp, stmt, currstate, frame) + if (get_curr_ssaflag(frame) & IR_FLAG_NOTHROW) != IR_FLAG_NOTHROW + propagate_to_error_handler!(frame, currpc, W, ๐•ƒแตข, currstate) + end if type === Bottom ssavaluetypes[currpc] = Bottom @goto find_next_bb end if changes !== nothing stoverwrite1!(currstate, changes) - let cur_hand = frame.handler_at[currpc], l, enter - while cur_hand != 0 - enter = frame.src.code[cur_hand]::Expr - l = enter.args[1]::Int - exceptbb = block_for_inst(frame.cfg, l) - # propagate new type info to exception handler - # the handling for Expr(:enter) propagates all changes from before the try/catch - # so this only needs to propagate any changes - if stupdate1!(๐•ƒแตข, states[exceptbb]::VarTable, changes) - push!(W, exceptbb) - end - cur_hand = frame.handler_at[cur_hand] - end - end end if type === nothing ssavaluetypes[currpc] = Any diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index 4a0f7d8071553..a1ff740b5b83d 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -839,27 +839,35 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState) code = copy_exprargs(ci.code) for i = 1:length(code) expr = code[i] - if !(i in sv.unreachable) && isa(expr, GotoIfNot) - # Replace this live GotoIfNot with: - # - no-op if :nothrow and the branch target is unreachable - # - cond if :nothrow and both targets are unreachable - # - typeassert if must-throw - block = block_for_inst(sv.cfg, i) - if ssavaluetypes[i] === Bottom - destblock = block_for_inst(sv.cfg, expr.dest) - cfg_delete_edge!(sv.cfg, block, block + 1) - ((block + 1) != destblock) && cfg_delete_edge!(sv.cfg, block, destblock) - expr = Expr(:call, Core.typeassert, expr.cond, Bool) - elseif i + 1 in sv.unreachable - @assert (ci.ssaflags[i] & IR_FLAG_NOTHROW) != 0 - cfg_delete_edge!(sv.cfg, block, block + 1) - expr = GotoNode(expr.dest) - elseif expr.dest in sv.unreachable - @assert (ci.ssaflags[i] & IR_FLAG_NOTHROW) != 0 - cfg_delete_edge!(sv.cfg, block, block_for_inst(sv.cfg, expr.dest)) - expr = nothing + if !(i in sv.unreachable) + if isa(expr, GotoIfNot) + # Replace this live GotoIfNot with: + # - no-op if :nothrow and the branch target is unreachable + # - cond if :nothrow and both targets are unreachable + # - typeassert if must-throw + block = block_for_inst(sv.cfg, i) + if ssavaluetypes[i] === Bottom + destblock = block_for_inst(sv.cfg, expr.dest) + cfg_delete_edge!(sv.cfg, block, block + 1) + ((block + 1) != destblock) && cfg_delete_edge!(sv.cfg, block, destblock) + expr = Expr(:call, Core.typeassert, expr.cond, Bool) + elseif i + 1 in sv.unreachable + @assert (ci.ssaflags[i] & IR_FLAG_NOTHROW) != 0 + cfg_delete_edge!(sv.cfg, block, block + 1) + expr = GotoNode(expr.dest) + elseif expr.dest in sv.unreachable + @assert (ci.ssaflags[i] & IR_FLAG_NOTHROW) != 0 + cfg_delete_edge!(sv.cfg, block, block_for_inst(sv.cfg, expr.dest)) + expr = nothing + end + code[i] = expr + elseif isexpr(expr, :enter) + catchdest = expr.args[1]::Int + if catchdest in sv.unreachable + cfg_delete_edge!(sv.cfg, block_for_inst(sv.cfg, i), block_for_inst(sv.cfg, catchdest)) + code[i] = nothing + end end - code[i] = expr end end @@ -1239,7 +1247,12 @@ function renumber_ir_elements!(body::Vector{Any}, ssachangemap::Vector{Int}, lab end if el.head === :enter tgt = el.args[1]::Int - el.args[1] = tgt + labelchangemap[tgt] + was_deleted = labelchangemap[tgt] == typemin(Int) + if was_deleted + body[i] = nothing + else + el.args[1] = tgt + labelchangemap[tgt] + end elseif !is_meta_expr_head(el.head) args = el.args for i = 1:length(args) diff --git a/base/compiler/ssair/ir.jl b/base/compiler/ssair/ir.jl index 1e01e0f476daa..3f8160a088e8d 100644 --- a/base/compiler/ssair/ir.jl +++ b/base/compiler/ssair/ir.jl @@ -1364,6 +1364,21 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr ssa_rename[idx] = nothing return result_idx end + elseif isexpr(stmt, :leave) + let i = 1 + while i <= length(stmt.args) + if stmt.args[i] === nothing + deleteat!(stmt.args, i) + else + i += 1 + end + end + end + if isempty(stmt.args) + # This :leave is dead + ssa_rename[idx] = nothing + return result_idx + end end typ = inst[:type] if isa(typ, Const) && is_inlineable_constant(typ.val) diff --git a/base/compiler/ssair/slot2ssa.jl b/base/compiler/ssair/slot2ssa.jl index 39e092332aae6..1f682d9168413 100644 --- a/base/compiler/ssair/slot2ssa.jl +++ b/base/compiler/ssair/slot2ssa.jl @@ -875,7 +875,8 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, sv::OptimizationState, new_code[idx] = GotoIfNot(stmt.cond, new_dest) end elseif isexpr(stmt, :enter) - new_code[idx] = Expr(:enter, block_for_inst(cfg, stmt.args[1]::Int)) + except_bb = block_for_inst(cfg, stmt.args[1]::Int) + new_code[idx] = Expr(:enter, except_bb) ssavalmap[idx] = SSAValue(idx) # Slot to store token for pop_exception elseif isexpr(stmt, :leave) || isexpr(stmt, :(=)) || isa(stmt, ReturnNode) || isexpr(stmt, :meta) || isa(stmt, NewvarNode) diff --git a/base/compiler/typelattice.jl b/base/compiler/typelattice.jl index df6022609d612..0c44a610f8f95 100644 --- a/base/compiler/typelattice.jl +++ b/base/compiler/typelattice.jl @@ -759,24 +759,6 @@ function stupdate!(lattice::AbstractLattice, state::VarTable, changes::VarTable) return changed end -function stupdate1!(lattice::AbstractLattice, state::VarTable, change::StateUpdate) - changeid = slot_id(change.var) - for i = 1:length(state) - invalidated = invalidate_slotwrapper(state[i], changeid, change.conditional) - if invalidated !== nothing - state[i] = invalidated - end - end - # and update the type of it - newtype = change.vtype - oldtype = state[changeid] - if schanged(lattice, newtype, oldtype) - state[changeid] = smerge(lattice, oldtype, newtype) - return true - end - return false -end - function stoverwrite!(state::VarTable, newstate::VarTable) for i = 1:length(state) state[i] = newstate[i] diff --git a/src/codegen.cpp b/src/codegen.cpp index 940f235bf59fc..402924c4b778b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5180,14 +5180,19 @@ static void emit_ssaval_assign(jl_codectx_t &ctx, ssize_t ssaidx_0based, jl_valu ctx.ssavalue_assigned[ssaidx_0based] = true; } -static void emit_varinfo_assign(jl_codectx_t &ctx, jl_varinfo_t &vi, jl_cgval_t rval_info, jl_value_t *l=NULL) +static void emit_varinfo_assign(jl_codectx_t &ctx, jl_varinfo_t &vi, jl_cgval_t rval_info, jl_value_t *l=NULL, bool allow_mismatch=false) { if (!vi.used || vi.value.typ == jl_bottom_type) return; // convert rval-type to lval-type jl_value_t *slot_type = vi.value.typ; - rval_info = convert_julia_type(ctx, rval_info, slot_type); + // If allow_mismatch is set, type mismatches will not result in traps. + // This is used for upsilon nodes, where the destination can have a narrower + // type than the store, if inference determines that the store is never read. + Value *dummy = NULL; + Value **skip = allow_mismatch ? &dummy : NULL; + rval_info = convert_julia_type(ctx, rval_info, slot_type, skip); if (rval_info.typ == jl_bottom_type) return; @@ -5284,7 +5289,7 @@ static void emit_upsilonnode(jl_codectx_t &ctx, ssize_t phic, jl_value_t *val) // was unreachable and dead val = NULL; else - emit_varinfo_assign(ctx, vi, rval_info); + emit_varinfo_assign(ctx, vi, rval_info, NULL, true); } if (!val) { if (vi.boxroot) { diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 619e6f6f87a53..afda3c1793031 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -5284,3 +5284,72 @@ end @test only(Base.return_types((x,f) -> getfield(x, f), (An51317, Symbol))) === Int @test only(Base.return_types(x -> getfield(x, :b), (A51317,))) === Union{} @test only(Base.return_types(x -> getfield(x, :b), (An51317,))) === Union{} + +# Don't visit the catch block for empty try/catch +function completely_dead_try_catch() + try + catch + return 2.0 + end + return 1 +end +@test Base.return_types(completely_dead_try_catch) |> only === Int +@test fully_eliminated(completely_dead_try_catch) + +function nothrow_try_catch() + try + 1+1 + catch + return 2.0 + end + return 1 +end +@test Base.return_types(nothrow_try_catch) |> only === Int +@test fully_eliminated(nothrow_try_catch) + +may_error(b) = Base.inferencebarrier(b) && error() +function phic_type1() + a = 1 + try + may_error(false) + a = 1.0 + catch + return a + end + return 2 +end +@test Base.return_types(phic_type1) |> only === Int +@test phic_type1() === 2 + +function phic_type2() + a = 1 + try + may_error(false) + a = 1.0 + may_error(false) + catch + return a + end + return 2 +end +@test Base.return_types(phic_type2) |> only === Union{Int, Float64} +@test phic_type2() === 2 + +function phic_type3() + a = 1 + try + may_error(false) + a = 1.0 + may_error(false) + if Base.inferencebarrier(false) + a = Ref(1) + elseif Base.inferencebarrier(false) + a = nothing + end + catch + return a + end + return 2 +end +@test Base.return_types(phic_type3) |> only === Union{Int, Float64} +@test phic_type3() === 2 From ff03e5116d452d0e6e5970a50c187d468febf594 Mon Sep 17 00:00:00 2001 From: Paul Berg Date: Mon, 16 Oct 2023 02:41:46 +0200 Subject: [PATCH 0004/1315] Allow using `ReturnNode()` in `@generated` code (#51715) IRTools.jl currently tries to use `ReturnNode()` to model unreachable block terminators but it fails in `find_ssavalue_uses`. This PR adds a check to enable using `ReturnNode()` in untyped code. One other alternative for frontends is to use an instruction known to terminate (`Core.throw`) instead. See https://github.com/FluxML/IRTools.jl/pull/115 for more context. --- base/compiler/utilities.jl | 1 + test/staged.jl | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index bdc0156efd824..78079e6174f29 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -390,6 +390,7 @@ function find_ssavalue_uses(body::Vector{Any}, nvals::Int) for line in 1:length(body) e = body[line] if isa(e, ReturnNode) + isdefined(e, :val) || continue e = e.val elseif isa(e, GotoIfNot) e = e.cond diff --git a/test/staged.jl b/test/staged.jl index 5204f5f6ca777..76d02c1938e4d 100644 --- a/test/staged.jl +++ b/test/staged.jl @@ -346,3 +346,32 @@ let world = Base.get_world_counter() @test all(lin->lin.method === :sin, src.linetable) @test sin_generated(42) == sin(42) end + +# Allow passing unreachable insts in generated codeinfo +let + dummy() = return + dummy_m = which(dummy, Tuple{}) + + src = Base.uncompressed_ir(dummy_m) + src.code = Any[ + # block 1 + Core.ReturnNode(nothing), + # block 2 + Core.ReturnNode(), + ] + nstmts = length(src.code) + nslots = 1 + src.ssavaluetypes = nstmts + src.codelocs = fill(Int32(1), nstmts) + src.ssaflags = fill(Int32(0), nstmts) + src.slotflags = fill(0, nslots) + src.slottypes = Any[Any] + + @eval function f_unreachable() + $(Expr(:meta, :generated, Returns(src))) + $(Expr(:meta, :generated_only)) + end + + ir, _ = Base.code_ircode(f_unreachable, ()) |> only + @test length(ir.cfg.blocks) == 1 +end From 0c4af3288e8a4aab71c39b6ee5174964101e0704 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Sun, 15 Oct 2023 20:34:52 -0500 Subject: [PATCH 0005/1315] Fix typos [nfc] (#51709) --- HISTORY.md | 2 +- NEWS.md | 2 +- base/broadcast.jl | 2 +- base/client.jl | 2 +- base/compiler/abstractinterpretation.jl | 6 +- base/compiler/abstractlattice.jl | 2 +- base/compiler/inferencestate.jl | 4 +- base/compiler/ssair/show.jl | 2 +- base/compiler/tfuncs.jl | 2 +- base/dict.jl | 2 +- base/hamt.jl | 4 +- base/libc.jl | 2 +- base/reflection.jl | 2 +- base/reinterpretarray.jl | 2 +- base/sort.jl | 4 +- base/strings/string.jl | 2 +- base/toml_parser.jl | 6 +- base/version.jl | 2 +- contrib/generate_precompile.jl | 2 +- .../frameworkapp/JuliaLauncher/AppDelegate.m | 2 +- deps/valgrind/valgrind.h | 2 +- doc/src/base/scopedvalues.md | 6 +- doc/src/devdocs/pkgimg.md | 2 +- doc/src/index.md | 2 +- doc/src/manual/command-line-interface.md | 2 +- doc/src/manual/modules.md | 2 +- doc/src/manual/noteworthy-differences.md | 2 +- doc/src/manual/strings.md | 2 +- src/aotcompile.cpp | 2 +- src/cgutils.cpp | 2 +- src/codegen.cpp | 2 +- src/flisp/read.c | 2 +- src/gc-heap-snapshot.cpp | 2 +- src/gc.c | 4 +- src/intrinsics.cpp | 2 +- src/jitlayers.cpp | 2 +- src/julia_internal.h | 4 +- src/llvm-alloc-helpers.cpp | 2 +- src/llvm-late-gc-lowering.cpp | 6 +- src/llvm-lower-handlers.cpp | 2 +- src/signal-handling.c | 2 +- src/stackwalk.c | 2 +- src/subtype.c | 14 +- stdlib/Dates/docs/src/index.md | 4 +- stdlib/InteractiveUtils/test/highlighting.jl | 184 +++++++++--------- stdlib/LibGit2/src/callbacks.jl | 4 +- stdlib/LinearAlgebra/src/generic.jl | 4 +- stdlib/LinearAlgebra/src/lu.jl | 2 +- stdlib/LinearAlgebra/test/dense.jl | 2 +- stdlib/LinearAlgebra/test/triangular.jl | 2 +- stdlib/Printf/src/Printf.jl | 2 +- stdlib/REPL/src/latex_symbols.jl | 8 +- stdlib/REPL/src/precompile.jl | 4 +- stdlib/REPL/test/replcompletions.jl | 2 +- stdlib/Random/docs/src/index.md | 2 +- stdlib/SuiteSparse_jll/test/runtests.jl | 2 +- stdlib/TOML/test/toml_test.jl | 2 +- stdlib/Test/src/Test.jl | 2 +- stdlib/Test/test/runtests.jl | 30 +-- test/clangsa/GCPushPop.cpp | 2 +- test/cmdlineargs.jl | 2 +- test/compiler/inference.jl | 22 +-- test/compiler/inline.jl | 2 +- test/compiler/invalidation.jl | 20 +- test/core.jl | 2 +- test/gcext/gcext.c | 2 +- test/intrinsics.jl | 2 +- test/misc.jl | 4 +- test/operators.jl | 2 +- test/testhelpers/DualNumbers.jl | 2 +- 70 files changed, 221 insertions(+), 221 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 6a4373cdbf337..1d46189c74c51 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -98,7 +98,7 @@ Standard library changes ([#46196]). * Adjoints and transposes of `Factorization` objects are no longer wrapped in `Adjoint` and `Transpose` wrappers, respectively. Instead, they are wrapped in - `AdjointFactorization` and `TranposeFactorization` types, which themselves subtype + `AdjointFactorization` and `TransposeFactorization` types, which themselves subtype `Factorization` ([#46874]). * New functions `hermitianpart` and `hermitianpart!` for extracting the Hermitian (real symmetric) part of a matrix ([#31836]). diff --git a/NEWS.md b/NEWS.md index c8ed757ef3fd7..bab64a2d195ac 100644 --- a/NEWS.md +++ b/NEWS.md @@ -22,7 +22,7 @@ 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 -(see the docstring for futher details). When opted-in, and julia is invoked to run a script or expression +(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 in the compiler and execution of `Main.main` may happen in the resulting executable. For interactive use, there is no semantic diff --git a/base/broadcast.jl b/base/broadcast.jl index 145be717cbd58..97e69cc680358 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -379,7 +379,7 @@ make_makeargs(args::Tuple) = _make_makeargs(args, 1)[1] end _make_makeargs(::Tuple{}, n::Int) = (), n -# A help struct to store the flattened index staticly +# A help struct to store the flattened index statically struct Pick{N} <: Function end (::Pick{N})(@nospecialize(args::Tuple)) where {N} = args[N] diff --git a/base/client.jl b/base/client.jl index 79541f2c106b1..69f35d3fdd4fc 100644 --- a/base/client.jl +++ b/base/client.jl @@ -613,7 +613,7 @@ In the `julia` driver, if `Main.main` is marked as an entrypoint, it will be aut the completion of script execution. The `@main` macro may be used standalone or as part of the function definition, though in the latter -case, parenthese are required. In particular, the following are equivalent: +case, parentheses are required. In particular, the following are equivalent: ``` function (@main)(ARGS) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 00e9ef48d9fe2..bbbff8e250e8b 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -1150,7 +1150,7 @@ function semi_concrete_eval_call(interp::AbstractInterpreter, if !(isa(rt, Type) && hasintersect(rt, Bool)) ir = irsv.ir # TODO (#48913) enable double inlining pass when there are any calls - # that are newly resovled by irinterp + # that are newly resolved by irinterp # state = InliningState(interp) # ir = ssa_inlining_pass!(irsv.ir, state, propagate_inbounds(irsv)) effects = result.effects @@ -1219,7 +1219,7 @@ end conditional_argtypes::ConditionalArgtypes) The implementation is able to forward `Conditional` of `conditional_argtypes`, -as well as the other general extended lattice inforamtion. +as well as the other general extended lattice information. """ function matching_cache_argtypes(๐•ƒ::AbstractLattice, linfo::MethodInstance, conditional_argtypes::ConditionalArgtypes) @@ -2309,7 +2309,7 @@ function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, sv::Infere si = StmtInfo(!call_result_unused(sv, sv.currpc)) (; rt, effects, info) = abstract_call(interp, arginfo, si, sv) sv.stmt_info[sv.currpc] = info - # mark this call statement as DCE-elgible + # mark this call statement as DCE-eligible # TODO better to do this in a single pass based on the `info` object at the end of abstractinterpret? return RTEffects(rt, effects) end diff --git a/base/compiler/abstractlattice.jl b/base/compiler/abstractlattice.jl index c1229124d1cec..18b6a5473abd0 100644 --- a/base/compiler/abstractlattice.jl +++ b/base/compiler/abstractlattice.jl @@ -260,7 +260,7 @@ end Appropriately converts inferred type of a return value `rt` to such a type that we know we can store in the cache and is valid and good inter-procedurally, E.g. if `rt isa Conditional` then `rt` should be converted to `InterConditional` -or the other cachable lattice element. +or the other cacheable lattice element. External lattice `๐•ƒแตข::ExternalLattice` may overload: - `widenreturn(๐•ƒแตข::ExternalLattice, @nospecialize(rt), info::BestguessInfo)` diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index 9546d9ef79184..6a6aba1076449 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -338,8 +338,8 @@ function compute_trycatch(code::Vector{Any}, ip::BitSet) # 3: (expr) # == 1 # 3: (leave %1) # == 1 # 4: (expr) # == 0 - # then we can find all trys by walking backwards from :enter statements, - # and all catches by looking at the statement after the :enter + # then we can find all `try`s by walking backwards from :enter statements, + # and all `catch`es by looking at the statement after the :enter n = length(code) empty!(ip) ip.offset = 0 # for _bits_findnext diff --git a/base/compiler/ssair/show.jl b/base/compiler/ssair/show.jl index e9e2aa75f755e..67698fbc89aaa 100644 --- a/base/compiler/ssair/show.jl +++ b/base/compiler/ssair/show.jl @@ -250,7 +250,7 @@ We get: โ””โ”€โ”€ return %3 โ”‚ ``` -Even though we were in the `f` scope since the first statement, it tooks us two statements +Even though we were in the `f` scope since the first statement, it took us two statements to catch up and print the intermediate scopes. Which scope is printed is indicated both by the indentation of the method name and by an increased thickness of the appropriate line for the scope. diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 7f7766e44a164..d332c88bd240c 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -1655,7 +1655,7 @@ function apply_type_nothrow(๐•ƒ::AbstractLattice, argtypes::Vector{Any}, @nospe (headtype === Union) && return true isa(rt, Const) && return true u = headtype - # TODO: implement optimization for isvarargtype(u) and istuple occurences (which are valid but are not UnionAll) + # TODO: implement optimization for isvarargtype(u) and istuple occurrences (which are valid but are not UnionAll) for i = 2:length(argtypes) isa(u, UnionAll) || return false ai = widenconditional(argtypes[i]) diff --git a/base/dict.jl b/base/dict.jl index d4efe268f641a..b2797db8dc059 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -896,7 +896,7 @@ end `PersistentDict` is a dictionary implemented as an hash array mapped trie, which is optimal for situations where you need persistence, each operation -returns a new dictonary separate from the previous one, but the underlying +returns a new dictionary separate from the previous one, but the underlying implementation is space-efficient and may share storage across multiple separate dictionaries. diff --git a/base/hamt.jl b/base/hamt.jl index 3c95d974800fa..d801352fce6c5 100644 --- a/base/hamt.jl +++ b/base/hamt.jl @@ -29,11 +29,11 @@ export HAMT # # At each level we use a 32bit bitmap to store which elements are occupied. # Since our storage is "sparse" we need to map from index in [0,31] to -# the actual storage index. We mask the bitmap wiht (1 << i) - 1 and count +# the actual storage index. We mask the bitmap with (1 << i) - 1 and count # the ones in the result. The number of set ones (+1) gives us the index # into the storage array. # -# HAMT can be both persitent and non-persistent. +# HAMT can be both persistent and non-persistent. # The `path` function searches for a matching entries, and for persistency # optionally copies the path so that it can be safely mutated. diff --git a/base/libc.jl b/base/libc.jl index 25d1e4c495804..f74f7b4ca5230 100644 --- a/base/libc.jl +++ b/base/libc.jl @@ -6,7 +6,7 @@ Interface to libc, the C standard library. """ Libc import Base: transcode, windowserror, show -# these need to be defined seperately for bootstrapping but belong to Libc +# these need to be defined separately for bootstrapping but belong to Libc import Base: memcpy, memmove, memset, memcmp import Core.Intrinsics: bitcast diff --git a/base/reflection.jl b/base/reflection.jl index 6204a4cb44482..469bd8e1b40a3 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -1354,7 +1354,7 @@ struct CodegenParams using the `swiftself` convention, which in the ordinary case means that the pointer is kept in a register and accesses are thus very fast. If this option is disabled, the task local state pointer must be loaded from thread local - stroage, which incurs a small amount of additional overhead. The option is enabled by + storage, which incurs a small amount of additional overhead. The option is enabled by default. """ gcstack_arg::Cint diff --git a/base/reinterpretarray.jl b/base/reinterpretarray.jl index 3844edc331c7c..a4aa66c7f3533 100644 --- a/base/reinterpretarray.jl +++ b/base/reinterpretarray.jl @@ -672,7 +672,7 @@ end """ CyclePadding(padding, total_size) -Cylces an iterator of `Padding` structs, restarting the padding at `total_size`. +Cycles an iterator of `Padding` structs, restarting the padding at `total_size`. E.g. if `padding` is all the padding in a struct and `total_size` is the total aligned size of that array, `CyclePadding` will correspond to the padding in an infinite vector of such structs. diff --git a/base/sort.jl b/base/sort.jl index ceea7365a08b2..95909f90ad8e5 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -1299,7 +1299,7 @@ Next, we [`ConsiderCountingSort`](@ref). If the range the input is small compare length, we apply [`CountingSort`](@ref). Next, we [`ConsiderRadixSort`](@ref). This is similar to the dispatch to counting sort, -but we conside rthe number of _bits_ in the range, rather than the range itself. +but we consider the number of _bits_ in the range, rather than the range itself. Consequently, we apply [`RadixSort`](@ref) for any reasonably long inputs that reach this stage. @@ -1367,7 +1367,7 @@ algorithms). Elements are first transformed with the function `by` and then compared according to either the function `lt` or the ordering `order`. Finally, the resulting order is reversed if `rev=true` (this preserves forward stability: -elements that compare equal are not reversed). The current implemention applies +elements that compare equal are not reversed). The current implementation applies the `by` transformation before each comparison rather than once per element. Passing an `lt` other than `isless` along with an `order` other than diff --git a/base/strings/string.jl b/base/strings/string.jl index fefaf5d79ea3a..bb3a292c26b1d 100644 --- a/base/strings/string.jl +++ b/base/strings/string.jl @@ -247,7 +247,7 @@ end Shifts | 0 4 10 14 18 24 8 20 12 26 - The shifts that represent each state were derived using teh SMT solver Z3, to ensure when encoded into + The shifts that represent each state were derived using the SMT solver Z3, to ensure when encoded into the rows the correct shift was a result. Each character class row is encoding 10 states with shifts as defined above. By shifting the bitsof a row by diff --git a/base/toml_parser.jl b/base/toml_parser.jl index 18166b03e23b3..086b7d99580c0 100644 --- a/base/toml_parser.jl +++ b/base/toml_parser.jl @@ -80,7 +80,7 @@ mutable struct Parser # Filled in in case we are parsing a file to improve error messages filepath::Union{String, Nothing} - # Get's populated with the Dates stdlib if it exists + # Gets populated with the Dates stdlib if it exists Dates::Union{Module, Nothing} end @@ -367,7 +367,7 @@ end @inline peek(l::Parser) = l.current_char # Return true if the character was accepted. When a character -# is accepted it get's eaten and we move to the next character +# is accepted it gets eaten and we move to the next character @inline function accept(l::Parser, f::Union{Function, Char})::Bool c = peek(l) c == EOF_CHAR && return false @@ -665,7 +665,7 @@ end ######### function push!!(v::Vector, el) - # Since these types are typically non-inferrable, they are a big invalidation risk, + # Since these types are typically non-inferable, they are a big invalidation risk, # and since it's used by the package-loading infrastructure the cost of invalidation # is high. Therefore, this is written to reduce the "exposed surface area": e.g., rather # than writing `T[el]` we write it as `push!(Vector{T}(undef, 1), el)` so that there diff --git a/base/version.jl b/base/version.jl index a966135a071e2..730ae47a27363 100644 --- a/base/version.jl +++ b/base/version.jl @@ -11,7 +11,7 @@ const VInt = UInt32 Version number type which follows the specifications of [semantic versioning (semver)](https://semver.org/), composed of major, minor and patch numeric values, followed by pre-release and build -alpha-numeric annotations. +alphanumeric annotations. `VersionNumber` objects can be compared with all of the standard comparison operators (`==`, `<`, `<=`, etc.), with the result following semver rules. diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 582e5410a4b3d..4ba93483730ac 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -1,6 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -# Prevent this from putting anyting into the Main namespace +# Prevent this from putting anything into the Main namespace @eval Module() begin if Threads.maxthreadid() != 1 diff --git a/contrib/mac/frameworkapp/JuliaLauncher/AppDelegate.m b/contrib/mac/frameworkapp/JuliaLauncher/AppDelegate.m index db2f13b485189..1d20d6ed3efa1 100644 --- a/contrib/mac/frameworkapp/JuliaLauncher/AppDelegate.m +++ b/contrib/mac/frameworkapp/JuliaLauncher/AppDelegate.m @@ -51,7 +51,7 @@ + (ExecSandboxController *)sharedController { @end -/// Location of an installed variant of Julia (frameowrk or nix hier). +/// Location of an installed variant of Julia (framework or nix hier). @interface JuliaVariant : NSObject @property(readonly, nullable) NSBundle *bundle; @property(readonly, nonnull) NSURL *juliaexe; diff --git a/deps/valgrind/valgrind.h b/deps/valgrind/valgrind.h index 2e07a49d91dfa..b33fd70fab672 100644 --- a/deps/valgrind/valgrind.h +++ b/deps/valgrind/valgrind.h @@ -1065,7 +1065,7 @@ typedef /* Use these to write the name of your wrapper. NOTE: duplicates VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. NOTE also: inserts - the default behaviour equivalance class tag "0000" into the name. + the default behaviour equivalence class tag "0000" into the name. See pub_tool_redir.h for details -- normally you don't need to think about this, though. */ diff --git a/doc/src/base/scopedvalues.md b/doc/src/base/scopedvalues.md index 5c3318259ca55..0de29308c5df8 100644 --- a/doc/src/base/scopedvalues.md +++ b/doc/src/base/scopedvalues.md @@ -140,7 +140,7 @@ end @sync begin # If we instead pass a unique dictionary to each - # task we can access the dictonaries race free. + # task we can access the dictionaries race free. with(sval_dict => Dict()) do @spawn (sval_dict[][:a] = 3) end @@ -166,7 +166,7 @@ const LEVEL = ScopedValue(:GUEST) function serve(request, response) level = isAdmin(request) ? :ADMIN : :GUEST with(LEVEL => level) do - Threads.@spawn handle(request, respone) + Threads.@spawn handle(request, response) end end @@ -194,7 +194,7 @@ const sval_dict = ScopedValue(Dict()) # If you want to add new values to the dict, instead of replacing # it, unshare the values explicitly. In this example we use `merge` -# to unshare the state of the dictonary in parent scope. +# to unshare the state of the dictionary in parent scope. @sync begin with(sval_dict => merge(sval_dict[], Dict(:a => 10))) do @spawn @show sval_dict[][:a] diff --git a/doc/src/devdocs/pkgimg.md b/doc/src/devdocs/pkgimg.md index 0e2cffd91a26f..64f4e640b7c19 100644 --- a/doc/src/devdocs/pkgimg.md +++ b/doc/src/devdocs/pkgimg.md @@ -33,7 +33,7 @@ Dynamic libraries on macOS need to link against `-lSystem`. On recent macOS vers To that effect we link with `-undefined dynamic_lookup`. ## [Package images optimized for multiple microarchitectures](@id pkgimgs-multi-versioning) -Similar to [multi-versioning](@ref sysimg-multi-versioning) for system images, package images support multi-versioning. If you are in a heterogenous environment, with a unified cache, +Similar to [multi-versioning](@ref sysimg-multi-versioning) for system images, package images support multi-versioning. If you are in a heterogeneous environment, with a unified cache, you can set the environment variable `JULIA_CPU_TARGET=generic` to multi-version the object caches. ## Flags that impact package image creation and selection diff --git a/doc/src/index.md b/doc/src/index.md index bb758d14b4cf2..8c88af424e8e3 100644 --- a/doc/src/index.md +++ b/doc/src/index.md @@ -34,7 +34,7 @@ Markdown.parse(""" ## [Important Links](@id man-important-links) -Below is a non-exhasutive list of links that will be useful as you learn and use the Julia programming language. +Below is a non-exhaustive list of links that will be useful as you learn and use the Julia programming language. - [Julia Homepage](https://julialang.org) - [Download Julia](https://julialang.org/downloads/) diff --git a/doc/src/manual/command-line-interface.md b/doc/src/manual/command-line-interface.md index 7427cfc4a950a..c69d221a80f2e 100644 --- a/doc/src/manual/command-line-interface.md +++ b/doc/src/manual/command-line-interface.md @@ -104,7 +104,7 @@ $ ``` However, note that the current best practice recommendation is to not mix application and reusable library -code in the same package. Helper applications may be distributed as separate pacakges or as scripts with +code in the same package. Helper applications may be distributed as separate packages or as scripts with separate `main` entry points in a package's `bin` folder. ## Parallel mode diff --git a/doc/src/manual/modules.md b/doc/src/manual/modules.md index 6ed8e3c8bc8e0..b329dbc91b923 100644 --- a/doc/src/manual/modules.md +++ b/doc/src/manual/modules.md @@ -106,7 +106,7 @@ modules. We will see how to manage name clashes below. To mark a name as public without exporting it into the namespace of folks who call `using NiceStuff`, one can use `public` instead of `export`. This marks the public name(s) as part of the public API, -but does not have any namespace implications. The `public` keyword is only availiable in Julia 1.11 +but does not have any namespace implications. The `public` keyword is only available in Julia 1.11 and above. To maintain compatibility with Julia 1.10 and below, use the `@compat` macro from the [Compat](https://github.com/JuliaLang/Compat.jl) package. diff --git a/doc/src/manual/noteworthy-differences.md b/doc/src/manual/noteworthy-differences.md index 6c55bee59cadf..12dc4fdfddd24 100644 --- a/doc/src/manual/noteworthy-differences.md +++ b/doc/src/manual/noteworthy-differences.md @@ -392,7 +392,7 @@ For users coming to Julia from R, these are some noteworthy differences: paths to the `Base.LOAD_PATH` array. * Packages from directory-based repositories do not require the `Pkg.add()` tool prior to being loaded with `import` or `using`. They are simply available to the project. - * Directory-based package repositories are the **quickest solution** to developping local + * Directory-based package repositories are the **quickest solution** to developing local libraries of "software modules". ### Julia ⇔ C/C++: Assembling modules diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index fca4fc75d9e0f..9c4fde5b8a701 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -1144,7 +1144,7 @@ Version numbers can easily be expressed with non-standard string literals of the Version number literals create [`VersionNumber`](@ref) objects which follow the specifications of [semantic versioning](https://semver.org/), and therefore are composed of major, minor and patch numeric values, followed by pre-release and -build alpha-numeric annotations. For example, `v"0.2.1-rc1+win64"` is broken into major version +build alphanumeric annotations. For example, `v"0.2.1-rc1+win64"` is broken into major version `0`, minor version `2`, patch version `1`, pre-release `rc1` and build `win64`. When entering a version literal, everything except the major version number is optional, therefore e.g. `v"0.2"` is equivalent to `v"0.2.0"` (with empty pre-release/build annotations), `v"2"` is equivalent to diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index ae9ebca7a8b7a..fab53fa4de14c 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -1124,7 +1124,7 @@ static auto serializeModule(const Module &M) { // Modules are deserialized lazily by LLVM, to avoid deserializing // unnecessary functions. We take advantage of this by serializing // the entire module once, then deleting the bodies of functions -// that are not in this partition. Once unnecesary functions are +// that are not in this partition. Once unnecessary functions are // deleted, we then materialize the entire module to make use-lists // consistent. static void materializePreserved(Module &M, Partition &partition) { diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 63f5e2be5ddbb..f086c7fd0b0bd 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -3167,7 +3167,7 @@ static jl_value_t *static_constant_instance(const llvm::DataLayout &DL, Constant if (const auto *CC = dyn_cast(constant)) nargs = CC->getNumOperands(); else if (const auto *CAZ = dyn_cast(constant)) { - // SVE: Elsewhere we use `getMinKownValue` + // SVE: Elsewhere we use `getMinKnownValue` nargs = CAZ->getElementCount().getFixedValue(); } else if (const auto *CDS = dyn_cast(constant)) diff --git a/src/codegen.cpp b/src/codegen.cpp index 402924c4b778b..33730ad9cf74b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6354,7 +6354,7 @@ static Function* gen_cfun_wrapper( BasicBlock *unboxedBB = BasicBlock::Create(ctx.builder.getContext(), "maybe-unboxed", cw); BasicBlock *isanyBB = BasicBlock::Create(ctx.builder.getContext(), "any", cw); BasicBlock *afterBB = BasicBlock::Create(ctx.builder.getContext(), "after", cw); - Value *isrtboxed = ctx.builder.CreateIsNull(val); // XXX: this is the wrong condition and should be inspecting runtime_dt intead + Value *isrtboxed = ctx.builder.CreateIsNull(val); // XXX: this is the wrong condition and should be inspecting runtime_dt instead ctx.builder.CreateCondBr(isrtboxed, boxedBB, loadBB); ctx.builder.SetInsertPoint(boxedBB); Value *p1 = ctx.builder.CreateBitCast(val, ctx.types().T_pjlvalue); diff --git a/src/flisp/read.c b/src/flisp/read.c index 9a480e0536c7a..7a6039323a988 100644 --- a/src/flisp/read.c +++ b/src/flisp/read.c @@ -303,7 +303,7 @@ static uint32_t peek(fl_context_t *fl_ctx) fl_ctx->readtokval = fixnum(x); } else if (c == '!') { - // #! single line comment for shbang script support + // #! single line comment for shebang script support do { ch = ios_getc(readF(fl_ctx)); } while (ch != IOS_EOF && (char)ch != '\n'); diff --git a/src/gc-heap-snapshot.cpp b/src/gc-heap-snapshot.cpp index 51bc5ab61610e..1875a22f64ff6 100644 --- a/src/gc-heap-snapshot.cpp +++ b/src/gc-heap-snapshot.cpp @@ -71,7 +71,7 @@ struct Node { size_t id; // This should be a globally-unique counter, but we use the memory address size_t self_size; size_t trace_node_id; // This is ALWAYS 0 in Javascript heap-snapshots. - // whether the from_node is attached or dettached from the main application state + // whether the from_node is attached or detached from the main application state // https://github.com/nodejs/node/blob/5fd7a72e1c4fbaf37d3723c4c81dce35c149dc84/deps/v8/include/v8-profiler.h#L739-L745 int detachedness; // 0 - unknown, 1 - attached, 2 - detached SmallVector edges; diff --git a/src/gc.c b/src/gc.c index 42a9daa01a747..b030be9848f0b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -2811,7 +2811,7 @@ void gc_drain_own_chunkqueue(jl_ptls_t ptls, jl_gc_markqueue_t *mq) } // Main mark loop. Stack (allocated on the heap) of `jl_value_t *` -// is used to keep track of processed items. Maintaning this stack (instead of +// is used to keep track of processed items. Maintaining this stack (instead of // native one) avoids stack overflow when marking deep objects and // makes it easier to implement parallel marking via work-stealing JL_EXTENSION NOINLINE void gc_mark_loop_serial(jl_ptls_t ptls) @@ -2846,7 +2846,7 @@ void gc_mark_and_steal(jl_ptls_t ptls) goto pop; } // Note that for the stealing heuristics, we try to - // steal chunks much more agressively than pointers, + // steal chunks much more aggressively than pointers, // since we know chunks will likely expand into a lot // of work for the mark loop steal : { diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index e8a7c0f333c12..57eacd141744a 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -1197,7 +1197,7 @@ static jl_cgval_t emit_intrinsic(jl_codectx_t &ctx, intrinsic f, jl_value_t **ar for (size_t i = 0; i < nargs; ++i) { jl_cgval_t arg = emit_expr(ctx, args[i + 1]); if (arg.typ == jl_bottom_type) { - // intrinsics generally don't handle buttom values, so bail out early + // intrinsics generally don't handle bottom values, so bail out early return jl_cgval_t(); } argv[i] = arg; diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 62d1a8612ce60..42239ecf2de3c 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -794,7 +794,7 @@ struct JITObjectInfo { class JLDebuginfoPlugin : public ObjectLinkingLayer::Plugin { std::mutex PluginMutex; std::map> PendingObjs; - // Resources from distinct MaterializationResponsibilitys can get merged + // Resources from distinct `MaterializationResponsibility`s can get merged // after emission, so we can have multiple debug objects per resource key. std::map, 0>> RegisteredObjs; diff --git a/src/julia_internal.h b/src/julia_internal.h index 7883844d908f8..204674c6d495a 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -211,13 +211,13 @@ void jl_unlock_stackwalk(int lockret) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; static inline uint64_t cycleclock(void) JL_NOTSAFEPOINT { #if defined(_CPU_X86_64_) - // This is nopl 0(%rax, %rax, 1), but assembler are incosistent about whether + // This is nopl 0(%rax, %rax, 1), but assembler are inconsistent about whether // they emit that as a 4 or 5 byte sequence and we need to be guaranteed to use // the 5 byte one. #define NOP5_OVERRIDE_NOP ".byte 0x0f, 0x1f, 0x44, 0x00, 0x00\n\t" uint64_t low, high; // This instruction sequence is promised by rr to be patchable. rr can usually - // also patch `rdtsc` in regular code, but without the preceeding nop, there could + // also patch `rdtsc` in regular code, but without the preceding nop, there could // be an interfering branch into the middle of rr's patch region. Using this // sequence prevents a massive rr-induced slowdown if the compiler happens to emit // an unlucky pattern. See https://github.com/rr-debugger/rr/pull/3580. diff --git a/src/llvm-alloc-helpers.cpp b/src/llvm-alloc-helpers.cpp index d24c08b4b4930..665c0b1d2e00e 100644 --- a/src/llvm-alloc-helpers.cpp +++ b/src/llvm-alloc-helpers.cpp @@ -325,7 +325,7 @@ void jl_alloc::runEscapeAnalysis(llvm::Instruction *I, EscapeAnalysisRequiredArg else { next_offset = apoffset.getLimitedValue(); if (next_offset > UINT32_MAX) { - LLVM_DEBUG(dbgs() << "GEP inst exceeeds 32-bit offset\n"); + LLVM_DEBUG(dbgs() << "GEP inst exceeds 32-bit offset\n"); next_offset = UINT32_MAX; } } diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index fa666ad464cda..10b2209945081 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -140,7 +140,7 @@ using namespace llvm; not sunk into the gc frame. Nevertheless performing such sinking can still be profitable. Since all arguments to a jlcall are guaranteed to be live at that call in some gc slot, we can attempt to rearrange the slots within - the gc-frame, or re-use slots not assigned at that particular location + the gc-frame, or reuse slots not assigned at that particular location for the gcframe. However, even without this optimization, stack frames are at most two times larger than optimal (because regular stack coloring can merge the jlcall allocas). @@ -2117,7 +2117,7 @@ struct PEOIterator { } if (NextElement == -1) return NextElement; - // Make sure not to try to re-use this later. + // Make sure not to try to reuse this later. Elements[NextElement].weight = (unsigned)-1; // Raise neighbors for (int Neighbor : Neighbors[NextElement]) { @@ -2395,7 +2395,7 @@ bool LateLowerGCFrame::CleanupIR(Function &F, State *S, bool *CFGModified) { // Now, finally, set the tag. We do this in IR instead of in the C alloc // function, to provide possible optimization opportunities. (I think? TBH // the most recent editor of this code is not entirely clear on why we - // prefer to set the tag in the generated code. Providing optimziation + // prefer to set the tag in the generated code. Providing optimization // opportunities is the most likely reason; the tradeoff is slightly // larger code size and increased compilation time, compiling this // instruction at every allocation site, rather than once in the C alloc diff --git a/src/llvm-lower-handlers.cpp b/src/llvm-lower-handlers.cpp index 2e2b5955fcf67..15866d0855fc1 100644 --- a/src/llvm-lower-handlers.cpp +++ b/src/llvm-lower-handlers.cpp @@ -60,7 +60,7 @@ using namespace llvm; * \ / * br i1 %cond, %left2, %right2 * / \ - * jl_pop_hander ret + * jl_pop_handler ret * ret * * The frontend doesn't emit structures like this. However, the optimizer diff --git a/src/signal-handling.c b/src/signal-handling.c index 284ad359f3799..6c2702a5604d6 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -429,7 +429,7 @@ void jl_task_frame_noreturn(jl_task_t *ct) JL_NOTSAFEPOINT ct->ptls->in_pure_callback = 0; ct->ptls->in_finalizer = 0; ct->ptls->defer_signal = 0; - jl_atomic_store_release(&ct->ptls->gc_state, 0); // forceably exit GC (if we were in it) or safe into unsafe, without the mandatory safepoint + jl_atomic_store_release(&ct->ptls->gc_state, 0); // forcibly exit GC (if we were in it) or safe into unsafe, without the mandatory safepoint } } diff --git a/src/stackwalk.c b/src/stackwalk.c index 1289e7d08657e..dc963094853d2 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -1022,7 +1022,7 @@ static void jl_rec_backtrace(jl_task_t *t) JL_NOTSAFEPOINT mc->__r14 = ((uint64_t*)mctx)[5]; mc->__r15 = ((uint64_t*)mctx)[6]; mc->__rip = ((uint64_t*)mctx)[7]; - // added in libsystem_plaform 177.200.16 (macOS Mojave 10.14.3) + // added in libsystem_platform 177.200.16 (macOS Mojave 10.14.3) // prior to that _os_ptr_munge_token was (hopefully) typically 0, // so x ^ 0 == x and this is a no-op mc->__rbp = _OS_PTR_UNMUNGE(mc->__rbp); diff --git a/src/subtype.c b/src/subtype.c index d8177f0fd21ff..766e0e703f480 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -2810,9 +2810,9 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind // I. Handle indirect innervars (make them behave like direct innervars). // 1) record if btemp->lb/ub has indirect innervars. - // 2) subtitute `vb->var` with `varval`/`varval` + // 2) substitute `vb->var` with `varval`/`varval` // note: We only store the innervar in the outmost `varbinding`, - // thus we must check all inner env to ensure the recording/subtitution + // 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); @@ -2852,9 +2852,9 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind } } if (!has_innerdep) continue; - int need_subtitution = 0; + int need_substitution = 0; if (ilb != ivar->lb || iub != ivar->ub) { - need_subtitution = 1; + 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)) @@ -2863,12 +2863,12 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind 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_subtitution) + 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_subtitution) + if (need_substitution) btemp2->ub = jl_substitute_var(btemp2->ub, ivar, nivar); blinding_has_innerdep[envind] |= 2; } @@ -3637,7 +3637,7 @@ static jl_value_t *intersect(jl_value_t *x, jl_value_t *y, jl_stenv_t *e, int pa if (xlb == xub && ylb == yub && jl_has_typevar(xlb, (jl_tvar_t *)y) && jl_has_typevar(ylb, (jl_tvar_t *)x)) { - // specical case for e.g. + // special case for e.g. // 1) Val{Y}<:X<:Val{Y} && Val{X}<:Y<:Val{X} // 2) Y<:X<:Y && Val{X}<:Y<:Val{X} => Val{Y}<:Y<:Val{Y} ccheck = 0; diff --git a/stdlib/Dates/docs/src/index.md b/stdlib/Dates/docs/src/index.md index aa46f7b827f10..5d3fe4fd50f00 100644 --- a/stdlib/Dates/docs/src/index.md +++ b/stdlib/Dates/docs/src/index.md @@ -343,12 +343,12 @@ First the mapping is loaded into the `LOCALES` variable: julia> french_months = ["janvier", "fรฉvrier", "mars", "avril", "mai", "juin", "juillet", "aoรปt", "septembre", "octobre", "novembre", "dรฉcembre"]; -julia> french_monts_abbrev = ["janv","fรฉvr","mars","avril","mai","juin", +julia> french_months_abbrev = ["janv","fรฉvr","mars","avril","mai","juin", "juil","aoรปt","sept","oct","nov","dรฉc"]; julia> french_days = ["lundi","mardi","mercredi","jeudi","vendredi","samedi","dimanche"]; -julia> Dates.LOCALES["french"] = Dates.DateLocale(french_months, french_monts_abbrev, french_days, [""]); +julia> Dates.LOCALES["french"] = Dates.DateLocale(french_months, french_months_abbrev, french_days, [""]); ``` The above mentioned functions can then be used to perform the queries: diff --git a/stdlib/InteractiveUtils/test/highlighting.jl b/stdlib/InteractiveUtils/test/highlighting.jl index bac52e2945b5e..b72c9dbe72795 100644 --- a/stdlib/InteractiveUtils/test/highlighting.jl +++ b/stdlib/InteractiveUtils/test/highlighting.jl @@ -72,7 +72,7 @@ end @test occursin("\e", String(take!(io))) end -function hilight_llvm(s) +function highlight_llvm(s) io = IOBuffer() InteractiveUtils.print_llvm(IOContext(io, :color=>true), s) r = String(take!(io)) @@ -82,7 +82,7 @@ function hilight_llvm(s) flush(stdout) r end -function hilight_native(s, arch) +function highlight_native(s, arch) io = IOBuffer() InteractiveUtils.print_native(IOContext(io, :color=>true), s, arch) r = String(take!(io)) @@ -92,8 +92,8 @@ function hilight_native(s, arch) flush(stdout) r end -hilight_x86(s) = hilight_native(s, :x86) -hilight_arm(s) = hilight_native(s, :arm) +highlight_x86(s) = highlight_native(s, :x86) +highlight_arm(s) = highlight_native(s, :arm) function esc_code(s) io = IOBuffer() @@ -124,41 +124,41 @@ const XU = B * "}" * XB @testset "LLVM IR" begin @testset "comment" begin - @test hilight_llvm("; comment ; // # ") == "$(C); comment ; // # $(XC)\n" + @test highlight_llvm("; comment ; // # ") == "$(C); comment ; // # $(XC)\n" end - @testset "lavel" begin - @test hilight_llvm("top:") == "$(L)top:$(XL)\n" + @testset "label" begin + @test highlight_llvm("top:") == "$(L)top:$(XL)\n" - @test hilight_llvm("L7:\t\t; preds = %top") == + @test highlight_llvm("L7:\t\t; preds = %top") == "$(L)L7:$(XL)\t\t$(C); preds = %top$(XC)\n" end @testset "define" begin - @test hilight_llvm("define double @julia_func_1234(float) {") == + @test highlight_llvm("define double @julia_func_1234(float) {") == "$(K)define$(XK) $(T)double$(XT) " * "$(F)@julia_func_1234$(XF)$P$(T)float$(XT)$XP $U\n" - @test hilight_llvm("}") == "$XU\n" + @test highlight_llvm("}") == "$XU\n" end @testset "declare" begin - @test hilight_llvm("declare i32 @jl_setjmp(i8*) #2") == + @test highlight_llvm("declare i32 @jl_setjmp(i8*) #2") == "$(K)declare$(XK) $(T)i32$(XT) " * "$(F)@jl_setjmp$(XF)$P$(T)i8$(XT)$(D)*$(XD)$XP $(D)#2$(XD)\n" end @testset "type" begin - @test hilight_llvm("%jl_value_t = type opaque") == + @test highlight_llvm("%jl_value_t = type opaque") == "$(V)%jl_value_t$(XV) $EQU $(K)type$(XK) $(T)opaque$(XT)\n" end @testset "target" begin datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:10:11:12:13" - @test hilight_llvm("target datalayout = \"$datalayout\"") == + @test highlight_llvm("target datalayout = \"$datalayout\"") == "$(K)target$(XK) $(K)datalayout$(XK) $EQU $(V)\"$datalayout\"$(XV)\n" end @testset "attributes" begin - @test hilight_llvm( + @test highlight_llvm( """attributes #1 = { uwtable "frame-pointer"="all" }""") == "$(K)attributes$(XK) $(D)#1$(XD) $EQU " * "$U $(K)uwtable$(XK) $(V)\"frame-pointer\"$(XV)$EQU" * @@ -166,57 +166,57 @@ const XU = B * "}" * XB end @testset "terminator" begin - @test hilight_llvm(" ret i8 %12") == + @test highlight_llvm(" ret i8 %12") == " $(I)ret$(XI) $(T)i8$(XT) $(V)%12$(XV)\n" - @test hilight_llvm(" br i1 %2, label %L6, label %L4") == + @test highlight_llvm(" br i1 %2, label %L6, label %L4") == " $(I)br$(XI) $(T)i1$(XT) $(V)%2$(XV)$COM " * "$(T)label$(XT) $(L)%L6$(XL)$COM $(T)label$(XT) $(L)%L4$(XL)\n" - @test hilight_llvm(" br label %L5") == + @test highlight_llvm(" br label %L5") == " $(I)br$(XI) $(T)label$(XT) $(L)%L5$(XL)\n" - @test hilight_llvm(" unreachable") == " $(I)unreachable$(XI)\n" + @test highlight_llvm(" unreachable") == " $(I)unreachable$(XI)\n" end @testset "arithmetic" begin - @test hilight_llvm(" %11 = add nuw nsw i64 %value_phi10, 1") == + @test highlight_llvm(" %11 = add nuw nsw i64 %value_phi10, 1") == " $(V)%11$(XV) $EQU $(I)add$(XI) $(K)nuw$(XK) $(K)nsw$(XK) " * "$(T)i64$(XT) $(V)%value_phi10$(XV)$COM $(N)1$(XN)\n" - @test hilight_llvm(" %13 = fadd double %12, -2.000000e+00") == + @test highlight_llvm(" %13 = fadd double %12, -2.000000e+00") == " $(V)%13$(XV) $EQU $(I)fadd$(XI) " * "$(T)double$(XT) $(V)%12$(XV)$COM $(N)-2.000000e+00$(XN)\n" - @test hilight_llvm(" %21 = fmul contract double %20, 0x0123456789ABCDEF") == + @test highlight_llvm(" %21 = fmul contract double %20, 0x0123456789ABCDEF") == " $(V)%21$(XV) $EQU $(I)fmul$(XI) $(K)contract$(XK) " * "$(T)double$(XT) $(V)%20$(XV)$COM $(N)0x0123456789ABCDEF$(XN)\n" end @testset "bitwise" begin - @test hilight_llvm(" %31 = shl i64 %value_phi4, 52") == + @test highlight_llvm(" %31 = shl i64 %value_phi4, 52") == " $(V)%31$(XV) $EQU " * "$(I)shl$(XI) $(T)i64$(XT) $(V)%value_phi4$(XV)$COM $(N)52$(XN)\n" end @testset "aggregate" begin - @test hilight_llvm(" %4 = extractvalue { i64, i1 } %1, 0") == + @test highlight_llvm(" %4 = extractvalue { i64, i1 } %1, 0") == " $(V)%4$(XV) $EQU $(I)extractvalue$(XI) " * "$U $(T)i64$(XT)$COM $(T)i1$(XT) $XU $(V)%1$(XV)$COM $(N)0$(XN)\n" end @testset "memory access" begin - @test hilight_llvm(" %dims = alloca [1 x i64], align 8") == + @test highlight_llvm(" %dims = alloca [1 x i64], align 8") == " $(V)%dims$(XV) $EQU $(I)alloca$(XI) " * "$S$(N)1$(XN) $(D)x$(XD) $(T)i64$(XT)$XS$COM $(K)align$(XK) $(N)8$(XN)\n" - @test hilight_llvm(" %51 = load i32," * + @test highlight_llvm(" %51 = load i32," * " i32* inttoptr (i64 226995504 to i32*), align 16") == " $(V)%51$(XV) $EQU $(I)load$(XI) $(T)i32$(XT)$COM " * "$(T)i32$(XT)$(D)*$(XD) $(K)inttoptr$(XK) $P$(T)i64$(XT) $(N)226995504$(XN) " * "$(K)to$(XK) $(T)i32$(XT)$(D)*$(XD)$XP$COM $(K)align$(XK) $(N)16$(XN)\n" - @test hilight_llvm(" %53 = load %jl_value_t addrspace(10)*, " * + @test highlight_llvm(" %53 = load %jl_value_t addrspace(10)*, " * "%jl_value_t addrspace(10)* addrspace(11)* %52, align 8") == " $(V)%53$(XV) $EQU $(I)load$(XI) $(V)%jl_value_t$(XV) " * "$(K)addrspace$(XK)$P$(N)10$(XN)$XP$(D)*$(XD)$COM " * @@ -224,37 +224,37 @@ const XU = B * "}" * XB "$(K)addrspace$(XK)$P$(N)11$(XN)$XP$(D)*$(XD) " * "$(V)%52$(XV)$COM $(K)align$(XK) $(N)8$(XN)\n" - @test hilight_llvm(" store i64 %61, i64 addrspace(11)* %60, align 8") == + @test highlight_llvm(" store i64 %61, i64 addrspace(11)* %60, align 8") == " $(I)store$(XI) $(T)i64$(XT) $(V)%61$(XV)$COM " * "$(T)i64$(XT) $(K)addrspace$(XK)$P$(N)11$(XN)$XP$(D)*$(XD) " * "$(V)%60$(XV)$COM $(K)align$(XK) $(N)8$(XN)\n" - @test hilight_llvm(" store volatile %jl_value_t addrspace(10)** %62, " * + @test highlight_llvm(" store volatile %jl_value_t addrspace(10)** %62, " * "%jl_value_t addrspace(10)*** %63, align 8") == " $(I)store$(XI) $(K)volatile$(XK) $(V)%jl_value_t$(XV) " * "$(K)addrspace$(XK)$P$(N)10$(XN)$XP$(D)**$(XD) $(V)%62$(XV)$COM " * "$(V)%jl_value_t$(XV) $(K)addrspace$(XK)$P$(N)10$(XN)$XP$(D)***$(XD) " * "$(V)%63$(XV)$COM $(K)align$(XK) $(N)8$(XN)\n" - @test hilight_llvm(" %71 = getelementptr i8, i8* %70, i64 8") == + @test highlight_llvm(" %71 = getelementptr i8, i8* %70, i64 8") == " $(V)%71$(XV) $EQU $(I)getelementptr$(XI) $(T)i8$(XT)$COM " * "$(T)i8$(XT)$(D)*$(XD) $(V)%70$(XV)$COM $(T)i64$(XT) $(N)8$(XN)\n" end @testset "conversion" begin - @test hilight_llvm(" %22 = zext i1 %21 to i8") == + @test highlight_llvm(" %22 = zext i1 %21 to i8") == " $(V)%22$(XV) $EQU $(I)zext$(XI) $(T)i1$(XT) $(V)%21$(XV) " * "$(K)to$(XK) $(T)i8$(XT)\n" - @test hilight_llvm(" %24 = sitofp i64 %23 to double") == + @test highlight_llvm(" %24 = sitofp i64 %23 to double") == " $(V)%24$(XV) $EQU $(I)sitofp$(XI) $(T)i64$(XT) $(V)%23$(XV) " * "$(K)to$(XK) $(T)double$(XT)\n" - @test hilight_llvm(" %26 = ptrtoint i8* %25 to i64") == + @test highlight_llvm(" %26 = ptrtoint i8* %25 to i64") == " $(V)%26$(XV) $EQU $(I)ptrtoint$(XI) $(T)i8$(XT)$(D)*$(XD) " * "$(V)%25$(XV) $(K)to$(XK) $(T)i64$(XT)\n" - @test hilight_llvm(" %28 = bitcast %jl_value_t addrspace(10)* %27 " * + @test highlight_llvm(" %28 = bitcast %jl_value_t addrspace(10)* %27 " * "to [2 x i16] addrspace(10)*") == " $(V)%28$(XV) $EQU $(I)bitcast$(XI) $(V)%jl_value_t$(XV) " * "$(K)addrspace$(XK)$P$(N)10$(XN)$XP$(D)*$(XD) $(V)%27$(XV) " * @@ -263,20 +263,20 @@ const XU = B * "}" * XB end @testset "other" begin - @test hilight_llvm(" %31 = icmp slt i64 %30, 0") == + @test highlight_llvm(" %31 = icmp slt i64 %30, 0") == " $(V)%31$(XV) $EQU $(I)icmp$(XI) $(I)slt$(XI) " * "$(T)i64$(XT) $(V)%30$(XV)$COM $(N)0$(XN)\n" - @test hilight_llvm(" %value_phi34 = phi double [ %33, %L50 ], [ %32, %L60 ]") == + @test highlight_llvm(" %value_phi34 = phi double [ %33, %L50 ], [ %32, %L60 ]") == " $(V)%value_phi34$(XV) $EQU $(I)phi$(XI) $(T)double$(XT) " * "$S $(V)%33$(XV)$COM $(L)%L50$(XL) $XS$COM " * "$S $(V)%32$(XV)$COM $(L)%L60$(XL) $XS\n" - @test hilight_llvm(" %.v = select i1 %35, i64 %36, i64 63") == + @test highlight_llvm(" %.v = select i1 %35, i64 %36, i64 63") == " $(V)%.v$(XV) $EQU $(I)select$(XI) $(T)i1$(XT) $(V)%35$(XV)$COM " * "$(T)i64$(XT) $(V)%36$(XV)$COM $(T)i64$(XT) $(N)63$(XN)\n" - @test hilight_llvm(" %38 = call i64 @llvm.cttz.i64(i64 %37, i1 false)") == + @test highlight_llvm(" %38 = call i64 @llvm.cttz.i64(i64 %37, i1 false)") == " $(V)%38$(XV) $EQU $(I)call$(XI) $(T)i64$(XT) " * "$(F)@llvm.cttz.i64$(XF)$P$(T)i64$(XT) $(V)%37$(XV)$COM " * "$(T)i1$(XT) $(K)false$(XK)$XP\n" @@ -285,133 +285,133 @@ end @testset "x86 ASM" begin @testset "comment" begin - @test hilight_x86("; comment ; // # ") == "$(C); comment ; // # $(XC)\n" + @test highlight_x86("; comment ; // # ") == "$(C); comment ; // # $(XC)\n" end @testset "label" begin - @test hilight_x86("L123:") == "$(L)L123:$(XL)\n" + @test highlight_x86("L123:") == "$(L)L123:$(XL)\n" end @testset "directive" begin - @test hilight_x86("\t.text") == "\t$(D).text$(XD)\n" + @test highlight_x86("\t.text") == "\t$(D).text$(XD)\n" end @testset "0-operand" begin # AT&T - @test hilight_x86("\tretq") == "\t$(I)retq$(XI)\n" + @test highlight_x86("\tretq") == "\t$(I)retq$(XI)\n" # Intel - @test hilight_x86("\tret") == "\t$(I)ret$(XI)\n" + @test highlight_x86("\tret") == "\t$(I)ret$(XI)\n" end @testset "1-operand" begin # AT&T - @test hilight_x86("\tpopq\t%rax") == "\t$(I)popq$(XI)\t$(V)%rax$(XV)\n" + @test highlight_x86("\tpopq\t%rax") == "\t$(I)popq$(XI)\t$(V)%rax$(XV)\n" - @test hilight_x86("\tpushl\t\$4294967295\t# imm = 0xFFFFFFFF") == + @test highlight_x86("\tpushl\t\$4294967295\t# imm = 0xFFFFFFFF") == "\t$(I)pushl$(XI)\t$(N)\$4294967295$(XN)\t$(C)# imm = 0xFFFFFFFF$(XC)\n" - @test hilight_x86("\tja\tL234") == "\t$(I)ja$(XI)\t$(L)L234$(XL)\n" + @test highlight_x86("\tja\tL234") == "\t$(I)ja$(XI)\t$(L)L234$(XL)\n" - @test hilight_x86("\tnopw\t%cs:(%rax,%rax)") == + @test highlight_x86("\tnopw\t%cs:(%rax,%rax)") == "\t$(I)nopw$(XI)\t$(V)%cs$(XV)$COL$P$(V)%rax$(XV)$COM$(V)%rax$(XV)$XP\n" # Intel - @test hilight_x86("\tpop\trax") == "\t$(I)pop$(XI)\t$(V)rax$(XV)\n" + @test highlight_x86("\tpop\trax") == "\t$(I)pop$(XI)\t$(V)rax$(XV)\n" - @test hilight_x86("\tpush\t4294967295") == + @test highlight_x86("\tpush\t4294967295") == "\t$(I)push$(XI)\t$(N)4294967295$(XN)\n" - @test hilight_x86("\tja\tL234") == "\t$(I)ja$(XI)\t$(L)L234$(XL)\n" + @test highlight_x86("\tja\tL234") == "\t$(I)ja$(XI)\t$(L)L234$(XL)\n" - @test hilight_x86("\tnop\tword ptr cs:[rax + rax]") == + @test highlight_x86("\tnop\tword ptr cs:[rax + rax]") == "\t$(I)nop$(XI)\t$(K)word$(XK) $(K)ptr$(XK) " * "$(V)cs$(XV)$COL$S$(V)rax$(XV) $(D)+$(XD) $(V)rax$(XV)$XS\n" end @testset "2-operand" begin # AT&T - @test hilight_x86("\tshrq\t\$63, %rcx") == + @test highlight_x86("\tshrq\t\$63, %rcx") == "\t$(I)shrq$(XI)\t$(N)\$63$(XN)$COM $(V)%rcx$(XV)\n" - @test hilight_x86("\tvmovsd\t(%rsi,%rdx,8), %xmm1\t# xmm1 = mem[0],zero") == + @test highlight_x86("\tvmovsd\t(%rsi,%rdx,8), %xmm1\t# xmm1 = mem[0],zero") == "\t$(I)vmovsd$(XI)\t$P$(V)%rsi$(XV)$COM$(V)%rdx$(XV)$COM$(N)8$(XN)$XP" * "$COM $(V)%xmm1$(XV)\t$(C)# xmm1 = mem[0],zero$(XC)\n" - @test hilight_x86("\tmovabsq\t\$\"#string#338\", %rax") == + @test highlight_x86("\tmovabsq\t\$\"#string#338\", %rax") == "\t$(I)movabsq$(XI)\t$(F)\$\"#string#338\"$(XF)$COM $(V)%rax$(XV)\n" # Intel - @test hilight_x86("\tshr\trcx, 63") == + @test highlight_x86("\tshr\trcx, 63") == "\t$(I)shr$(XI)\t$(V)rcx$(XV)$COM $(N)63$(XN)\n" - @test hilight_x86( + @test highlight_x86( "\tvmovsd\txmm1, dword ptr [rsi + 8*rdx]\t# xmm1 = mem[0],zero") == "\t$(I)vmovsd$(XI)\t$(V)xmm1$(XV)$COM $(K)dword$(XK) $(K)ptr$(XK) " * "$S$(V)rsi$(XV) $(D)+$(XD) $(N)8$(XN)$(D)*$(XD)$(V)rdx$(XV)$XS" * "\t$(C)# xmm1 = mem[0],zero$(XC)\n" - @test hilight_x86("\tmovabs\trax, offset \"#string#338\"") == + @test highlight_x86("\tmovabs\trax, offset \"#string#338\"") == "\t$(I)movabs$(XI)\t$(V)rax$(XV)$COM " * "$(K)offset$(XK) $(F)\"#string#338\"$(XF)\n" end @testset "3-operand" begin # AT&T - @test hilight_x86("\tvaddsd\t(%rax), %xmm0, %xmm0") == + @test highlight_x86("\tvaddsd\t(%rax), %xmm0, %xmm0") == "\t$(I)vaddsd$(XI)\t$P$(V)%rax$(XV)$XP$COM " * "$(V)%xmm0$(XV)$COM $(V)%xmm0$(XV)\n" # Intel - @test hilight_x86("\tvaddsd\txmm0, xmm0, qword ptr [rax]") == + @test highlight_x86("\tvaddsd\txmm0, xmm0, qword ptr [rax]") == "\t$(I)vaddsd$(XI)\t$(V)xmm0$(XV)$COM $(V)xmm0$(XV)$COM " * "$(K)qword$(XK) $(K)ptr$(XK) $S$(V)rax$(XV)$XS\n" end @testset "4-operand" begin # AT&T - @test hilight_x86("\tvroundsd\t\$4, %xmm1, %xmm1, %xmm1") == + @test highlight_x86("\tvroundsd\t\$4, %xmm1, %xmm1, %xmm1") == "\t$(I)vroundsd$(XI)\t$(N)\$4$(XN)$COM " * "$(V)%xmm1$(XV)$COM $(V)%xmm1$(XV)$COM $(V)%xmm1$(XV)\n" # Intel - @test hilight_x86("\tvroundsd\txmm1, xmm1, xmm1, 4") == + @test highlight_x86("\tvroundsd\txmm1, xmm1, xmm1, 4") == "\t$(I)vroundsd$(XI)\t" * "$(V)xmm1$(XV)$COM $(V)xmm1$(XV)$COM $(V)xmm1$(XV)$COM $(N)4$(XN)\n" end @testset "AVX-512" begin # AT&T - @test hilight_x86("\tvmovaps\t(%eax), %zmm0") == + @test highlight_x86("\tvmovaps\t(%eax), %zmm0") == "\t$(I)vmovaps$(XI)\t$P$(V)%eax$(XV)$XP$COM $(V)%zmm0$(XV)\n" - @test hilight_x86("\tvpaddd\t%zmm3, %zmm1, %zmm1 {%k1}") == + @test highlight_x86("\tvpaddd\t%zmm3, %zmm1, %zmm1 {%k1}") == "\t$(I)vpaddd$(XI)\t$(V)%zmm3$(XV)$COM $(V)%zmm1$(XV)$COM " * "$(V)%zmm1$(XV) $U$(V)%k1$(XV)$XU\n" - @test hilight_x86("\tvdivpd\t%zmm3, %zmm1, %zmm0 {%k1} {z}") == + @test highlight_x86("\tvdivpd\t%zmm3, %zmm1, %zmm0 {%k1} {z}") == "\t$(I)vdivpd$(XI)\t$(V)%zmm3$(XV)$COM $(V)%zmm1$(XV)$COM " * "$(V)%zmm0$(XV) $U$(V)%k1$(XV)$XU $U$(K)z$(XK)$XU\n" - @test hilight_x86("\tvdivps\t(%ebx){1to16}, %zmm5, %zmm4") == + @test highlight_x86("\tvdivps\t(%ebx){1to16}, %zmm5, %zmm4") == "\t$(I)vdivps$(XI)\t$P$(V)%ebx$(XV)$XP$U$(K)1to16$(XK)$XU$COM " * "$(V)%zmm5$(XV)$COM $(V)%zmm4$(XV)\n" - @test hilight_x86("\tvcvtsd2si\t{rn-sae}, %xmm0, %eax") == + @test highlight_x86("\tvcvtsd2si\t{rn-sae}, %xmm0, %eax") == "\t$(I)vcvtsd2si$(XI)\t$U$(K)rn-sae$(XK)$XU$COM " * "$(V)%xmm0$(XV)$COM $(V)%eax$(XV)\n" # Intel - @test hilight_x86("\tvmovaps\tzmm0, zmmword ptr [eax]") == + @test highlight_x86("\tvmovaps\tzmm0, zmmword ptr [eax]") == "\t$(I)vmovaps$(XI)\t$(V)zmm0$(XV)$COM " * "$(K)zmmword$(XK) $(K)ptr$(XK) $S$(V)eax$(XV)$XS\n" - @test hilight_x86("\tvpaddd\tzmm1 {k1}, zmm1, zmm3") == + @test highlight_x86("\tvpaddd\tzmm1 {k1}, zmm1, zmm3") == "\t$(I)vpaddd$(XI)\t$(V)zmm1$(XV) $U$(V)k1$(XV)$XU$COM " * "$(V)zmm1$(XV)$COM $(V)zmm3$(XV)\n" - @test hilight_x86("\tvdivpd\tzmm0 {k1} {z}, zmm1, zmm3") == + @test highlight_x86("\tvdivpd\tzmm0 {k1} {z}, zmm1, zmm3") == "\t$(I)vdivpd$(XI)\t$(V)zmm0$(XV) $U$(V)k1$(XV)$XU $U$(K)z$(XK)$XU$COM " * "$(V)zmm1$(XV)$COM $(V)zmm3$(XV)\n" - @test hilight_x86("\tvdivps\tzmm4, zmm5, dword ptr [ebx]{1to16}") == + @test highlight_x86("\tvdivps\tzmm4, zmm5, dword ptr [ebx]{1to16}") == "\t$(I)vdivps$(XI)\t$(V)zmm4$(XV)$COM $(V)zmm5$(XV)$COM " * "$(K)dword$(XK) $(K)ptr$(XK) $S$(V)ebx$(XV)$XS$U$(K)1to16$(XK)$XU\n" - @test hilight_x86("\tvcvtsd2si\teax, xmm0$(XV), {rn-sae}") == + @test highlight_x86("\tvcvtsd2si\teax, xmm0$(XV), {rn-sae}") == "\t$(I)vcvtsd2si$(XI)\t$(V)eax$(XV)$COM " * "$(V)xmm0$(XV)$COM $U$(K)rn-sae$(XK)$XU\n" end @@ -419,74 +419,74 @@ end @testset "ARM ASM" begin @testset "comment" begin - @test hilight_arm("; comment ; // # ") == "$(C); comment ; // # $(XC)\n" + @test highlight_arm("; comment ; // # ") == "$(C); comment ; // # $(XC)\n" end @testset "label" begin - @test hilight_arm("L45:") == "$(L)L45:$(XL)\n" + @test highlight_arm("L45:") == "$(L)L45:$(XL)\n" end @testset "directive" begin - @test hilight_arm("\t.text") == "\t$(D).text$(XD)\n" + @test highlight_arm("\t.text") == "\t$(D).text$(XD)\n" end @testset "0-operand" begin - @test hilight_arm("\tret") == "\t$(I)ret$(XI)\n" + @test highlight_arm("\tret") == "\t$(I)ret$(XI)\n" end @testset "1-operand" begin - @test hilight_arm("\tbl\t0x12") == "\t$(I)bl$(XI)\t$(N)0x12$(XN)\n" + @test highlight_arm("\tbl\t0x12") == "\t$(I)bl$(XI)\t$(N)0x12$(XN)\n" - @test hilight_arm("\tb\tL345") == "\t$(I)b$(XI)\t$(L)L345$(XL)\n" + @test highlight_arm("\tb\tL345") == "\t$(I)b$(XI)\t$(L)L345$(XL)\n" - @test hilight_arm("\tb.gt\tL67") == "\t$(I)b.gt$(XI)\t$(L)L67$(XL)\n" + @test highlight_arm("\tb.gt\tL67") == "\t$(I)b.gt$(XI)\t$(L)L67$(XL)\n" - @test hilight_arm("\tpop\t{r11, pc}") == + @test highlight_arm("\tpop\t{r11, pc}") == "\t$(I)pop$(XI)\t$U$(V)r11$(XV)$COM $(V)pc$(XV)$XU\n" end @testset "2-operand" begin - @test hilight_arm("\tcmp\tx10, #2047\t// =2047") == + @test highlight_arm("\tcmp\tx10, #2047\t// =2047") == "\t$(I)cmp$(XI)\t$(V)x10$(XV)$COM $(N)#2047$(XN)\t$(C)// =2047$(XC)\n" - @test hilight_arm("\tldr\td1, [x10]") == + @test highlight_arm("\tldr\td1, [x10]") == "\t$(I)ldr$(XI)\t$(V)d1$(XV)$COM $S$(V)x10$(XV)$XS\n" - @test hilight_arm("\tstr\tx30, [sp, #-16]!") == + @test highlight_arm("\tstr\tx30, [sp, #-16]!") == "\t$(I)str$(XI)\t$(V)x30$(XV)$COM " * "$S$(V)sp$(XV)$COM $(N)#-16$(XN)$XS$(K)!$(XK)\n" - @test hilight_arm("\tmov\tv0.16b, v1.16b") == + @test highlight_arm("\tmov\tv0.16b, v1.16b") == "\t$(I)mov$(XI)\t$(V)v0.16b$(XV)$COM $(V)v1.16b$(XV)\n" end @testset "3-operand" begin - @test hilight_arm("\tfmul\td2, d0, d2") == + @test highlight_arm("\tfmul\td2, d0, d2") == "\t$(I)fmul$(XI)\t$(V)d2$(XV)$COM $(V)d0$(XV)$COM $(V)d2$(XV)\n" - @test hilight_arm("\tmovk\tx10, #65535, lsl #32") == + @test highlight_arm("\tmovk\tx10, #65535, lsl #32") == "\t$(I)movk$(XI)\t$(V)x10$COM $(N)#65535$(XN)$COM $(K)lsl$(XK) $(N)#32$(XN)\n" - @test hilight_arm("\tcneg\tx8, x8, ge") == + @test highlight_arm("\tcneg\tx8, x8, ge") == "\t$(I)cneg$(XI)\t$(V)x8$(XV)$COM $(V)x8$(XV)$COM $(K)ge$(XK)\n" end @testset "4-operand" begin - @test hilight_arm("\tadd\tx8, x9, x8, lsl #52") == + @test highlight_arm("\tadd\tx8, x9, x8, lsl #52") == "\t$(I)add$(XI)\t$(V)x8$(XV)$COM $(V)x9$(XV)$COM $(V)x8$(XV)$COM " * "$(K)lsl$(XK) $(N)#52$(XN)\n" - @test hilight_arm("\tfcsel\td1, d0, d1, eq") == + @test highlight_arm("\tfcsel\td1, d0, d1, eq") == "\t$(I)fcsel$(XI)\t" * "$(V)d1$(XV)$COM $(V)d0$(XV)$COM $(V)d1$(XV)$COM $(K)eq$(XK)\n" end @testset "NEON" begin - hilight_arm("\tvmul.f32\tq8, q9, q8") == + highlight_arm("\tvmul.f32\tq8, q9, q8") == "\t$(I)vmul.f32$(XI)\t$(V)q8$(XV)$COM $(V)q9$(XV)$COM $(V)q8$(XV)\n" - hilight_arm("\tvcvt.s32.f64\ts2, d20") == + highlight_arm("\tvcvt.s32.f64\ts2, d20") == "\t$(I)vcvt.s32.f64$(XI)\t$(V)s2$(XV)$COM $(V)d20$(XV)\n" - hilight_arm("\tvld1.32\t{d18, d19}, [r1]") == + highlight_arm("\tvld1.32\t{d18, d19}, [r1]") == "\t$(I)vld1.32$(XI)\t$U$(V)d18$(XV)$COM $(V)d19$(XV)$XU$COM $S$(V)r1$(XV)$XS\n" end @testset "SVE" begin - hilight_arm("\tld1d\tz1.d, p0/z, [x0, x4, lsl #3]") == + highlight_arm("\tld1d\tz1.d, p0/z, [x0, x4, lsl #3]") == "\t$(I)ld1d$(XI)\t$(V)z1.d$(XV)$COM " * "$(V)p0$(XV)$(K)/z$(XK)$COM " * "$S$(V)x0$(XV)$COM $(V)x4$(XV)$COM $(K)lsl$(XK) $(N)#3$(XN)$XS\n" - hilight_arm("\tb.first\tL123") == "\t$(I)b.first$(XI)\t$(L)L123$(XL)" + highlight_arm("\tb.first\tL123") == "\t$(I)b.first$(XI)\t$(L)L123$(XL)" end end diff --git a/stdlib/LibGit2/src/callbacks.jl b/stdlib/LibGit2/src/callbacks.jl index f4df26cdc30d8..b4fb29716e609 100644 --- a/stdlib/LibGit2/src/callbacks.jl +++ b/stdlib/LibGit2/src/callbacks.jl @@ -292,7 +292,7 @@ function credentials_callback(libgit2credptr::Ptr{Ptr{Cvoid}}, url_ptr::Cstring, cred = explicit # Copy explicit credentials to avoid mutating approved credentials. - # invalidation fix from cred being non-inferrable + # invalidation fix from cred being non-inferable p.credential = Base.invokelatest(deepcopy, cred) if isa(cred, SSHCredential) @@ -307,7 +307,7 @@ function credentials_callback(libgit2credptr::Ptr{Ptr{Cvoid}}, url_ptr::Cstring, # Perform a deepcopy as we do not want to mutate approved cached credentials if haskey(cache, cred_id) - # invalidation fix from cache[cred_id] being non-inferrable + # invalidation fix from cache[cred_id] being non-inferable p.credential = Base.invokelatest(deepcopy, cache[cred_id]) end end diff --git a/stdlib/LinearAlgebra/src/generic.jl b/stdlib/LinearAlgebra/src/generic.jl index 8fb79354c5656..9ab961461e76f 100644 --- a/stdlib/LinearAlgebra/src/generic.jl +++ b/stdlib/LinearAlgebra/src/generic.jl @@ -755,8 +755,8 @@ This is equivalent to [`norm`](@ref). @inline opnorm(x::Number, p::Real=2) = norm(x, p) """ - opnorm(A::Adjoint{<:Any,<:AbstracVector}, q::Real=2) - opnorm(A::Transpose{<:Any,<:AbstracVector}, q::Real=2) + opnorm(A::Adjoint{<:Any,<:AbstractVector}, q::Real=2) + opnorm(A::Transpose{<:Any,<:AbstractVector}, q::Real=2) For Adjoint/Transpose-wrapped vectors, return the operator ``q``-norm of `A`, which is equivalent to the `p`-norm with value `p = q/(q-1)`. They coincide at `p = q = 2`. diff --git a/stdlib/LinearAlgebra/src/lu.jl b/stdlib/LinearAlgebra/src/lu.jl index 109def9fddb2c..4afb855117c14 100644 --- a/stdlib/LinearAlgebra/src/lu.jl +++ b/stdlib/LinearAlgebra/src/lu.jl @@ -76,7 +76,7 @@ Base.iterate(S::LU, ::Val{:done}) = nothing adjoint(F::LU{<:Real}) = TransposeFactorization(F) transpose(F::LU{<:Real}) = TransposeFactorization(F) -# the following method is meant to catch calls to lu!(A::LAPACKArray) without a pivoting stategy +# the following method is meant to catch calls to lu!(A::LAPACKArray) without a pivoting strategy lu!(A::StridedMatrix{<:BlasFloat}; check::Bool = true) = lu!(A, RowMaximum(); check=check) function lu!(A::StridedMatrix{T}, ::RowMaximum; check::Bool = true) where {T<:BlasFloat} lpt = LAPACK.getrf!(A; check) diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index c2ab5df107527..b11ab5ece9c21 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -878,7 +878,7 @@ end end end -@testset "matrix logarithm is type-inferrable" for elty in (Float32,Float64,ComplexF32,ComplexF64) +@testset "matrix logarithm is type-inferable" for elty in (Float32,Float64,ComplexF32,ComplexF64) A1 = randn(elty, 4, 4) @inferred Union{Matrix{elty},Matrix{complex(elty)}} log(A1) end diff --git a/stdlib/LinearAlgebra/test/triangular.jl b/stdlib/LinearAlgebra/test/triangular.jl index aaf433c95b7b0..e0ba443ece7df 100644 --- a/stdlib/LinearAlgebra/test/triangular.jl +++ b/stdlib/LinearAlgebra/test/triangular.jl @@ -564,7 +564,7 @@ end end end -@testset "check matrix logarithm type-inferrable" for elty in (Float32,Float64,ComplexF32,ComplexF64) +@testset "check matrix logarithm type-inferable" for elty in (Float32,Float64,ComplexF32,ComplexF64) A = UpperTriangular(exp(triu(randn(elty, n, n)))) @inferred Union{typeof(A),typeof(complex(A))} log(A) @test exp(Matrix(log(A))) โ‰ˆ A diff --git a/stdlib/Printf/src/Printf.jl b/stdlib/Printf/src/Printf.jl index cb336a8d9c18b..8d2d97ddd6b32 100644 --- a/stdlib/Printf/src/Printf.jl +++ b/stdlib/Printf/src/Printf.jl @@ -237,7 +237,7 @@ function Format(f::AbstractString) !(b in b"diouxXDOUeEfFgGaAcCsSpn") && throw(InvalidFormatStringError("'$(Char(b))' is not a valid type specifier", f, last_percent_pos, pos-1)) type = Val{Char(b)} if type <: Ints && precision > 0 - # note - we should also set zero to false if dynamic precison > 0 + # note - we should also set zero to false if dynamic precision > 0 # this is taken care of in fmt() for Ints zero = false elseif (type <: Strings || type <: Chars) && !parsedprecdigits diff --git a/stdlib/REPL/src/latex_symbols.jl b/stdlib/REPL/src/latex_symbols.jl index 9e71819f6562b..ddd110de8b714 100644 --- a/stdlib/REPL/src/latex_symbols.jl +++ b/stdlib/REPL/src/latex_symbols.jl @@ -2623,10 +2623,10 @@ const latex_symbols = Dict( "\\4/5" => "โ…˜", # vulgar fraction four fifths "\\1/6" => "โ…™", # vulgar fraction one sixth "\\5/6" => "โ…š", # vulgar fraction five sixths - "\\1/8" => "โ…›", # vulgar fraction one eigth - "\\3/8" => "โ…œ", # vulgar fraction three eigths - "\\5/8" => "โ…", # vulgar fraction five eigths - "\\7/8" => "โ…ž", # vulgar fraction seventh eigths + "\\1/8" => "โ…›", # vulgar fraction one eighth + "\\3/8" => "โ…œ", # vulgar fraction three eighths + "\\5/8" => "โ…", # vulgar fraction five eighths + "\\7/8" => "โ…ž", # vulgar fraction seventh eighths "\\1/" => "โ…Ÿ", # fraction numerator one "\\0/3" => "โ†‰", # vulgar fraction zero thirds "\\1/4" => "ยผ", # vulgar fraction one quarter diff --git a/stdlib/REPL/src/precompile.jl b/stdlib/REPL/src/precompile.jl index 2e75bd69e197b..1b22eb77953a3 100644 --- a/stdlib/REPL/src/precompile.jl +++ b/stdlib/REPL/src/precompile.jl @@ -51,7 +51,7 @@ $UP_ARROW$DOWN_ARROW$CTRL_C f(x) = x03 f(1,2) [][1] -cd("complet_path\t\t$CTRL_C +cd("complete_path\t\t$CTRL_C """ julia_exepath() = joinpath(Sys.BINDIR, Base.julia_exename()) @@ -148,7 +148,7 @@ generate_precompile_statements() = try open(precompile_file, "r") do io while true - # We need to allways call eof(io) for bytesavailable(io) to work + # We need to always call eof(io) for bytesavailable(io) to work eof(io) && istaskdone(repl_inputter) && eof(io) && break if bytesavailable(io) == 0 sleep(0.1) diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index ef1cf8814af74..96a190e9f41ea 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -1980,7 +1980,7 @@ let (c, r, res) = test_complete_context("getkeyelem(mutable_const_prop).value.") end # JuliaLang/julia/#51548 -# don't return wrong result due to mutable inconsistentcy +# don't return wrong result due to mutable inconsistency function issue51548(T, a) # if we fold `xs = getindex(T)` to `xs::Const(Vector{T}())`, then we may wrongly # constant-fold `isempty(xs)::Const(true)` and return wrong result diff --git a/stdlib/Random/docs/src/index.md b/stdlib/Random/docs/src/index.md index fbf0b60fc6a24..70d27dc021875 100644 --- a/stdlib/Random/docs/src/index.md +++ b/stdlib/Random/docs/src/index.md @@ -215,7 +215,7 @@ and that we *always* want to build an alias table, regardless of the number of v Random.eltype(::Type{<:DiscreteDistribution}) = Int function Random.Sampler(::Type{<:AbstractRNG}, distribution::DiscreteDistribution, ::Repetition) - SamplerSimple(disribution, make_alias_table(distribution.probabilities)) + SamplerSimple(distribution, make_alias_table(distribution.probabilities)) end ``` should be defined to return a sampler with pre-computed data, then diff --git a/stdlib/SuiteSparse_jll/test/runtests.jl b/stdlib/SuiteSparse_jll/test/runtests.jl index d6d82a73e4a57..922da55fa1881 100644 --- a/stdlib/SuiteSparse_jll/test/runtests.jl +++ b/stdlib/SuiteSparse_jll/test/runtests.jl @@ -5,7 +5,7 @@ using Test, SuiteSparse_jll # SuiteSparse only uses SUITESPARSE_MAIN_VERSION and SUITESPARSE_SUB_VERSION to compute its version # The SUITESPARSE_SUBSUB_VERSION is not used # TODO before release: update to 7020 or above when upstreamed. -# This should be safe and unecessary since we specify exact version of the BB JLL. +# This should be safe and unnecessary since we specify exact version of the BB JLL. @testset "SuiteSparse_jll" begin @test ccall((:SuiteSparse_version, libsuitesparseconfig), Cint, (Ptr{Cint},), C_NULL) > 7000 end diff --git a/stdlib/TOML/test/toml_test.jl b/stdlib/TOML/test/toml_test.jl index f4670058223a1..c22c01acf1870 100644 --- a/stdlib/TOML/test/toml_test.jl +++ b/stdlib/TOML/test/toml_test.jl @@ -36,7 +36,7 @@ end function check_valid(f) jsn = try jsn2data(@eval include($f * ".jl")) - # Some files cannot be reprsented with julias DateTime (timezones) + # Some files cannot be represented with julias DateTime (timezones) catch return false end diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 0844aa9807bb1..7e416df91864e 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -1459,7 +1459,7 @@ parent test set (with the context object appended to any failing tests.) `@testset let` requires at least Julia 1.9. !!! compat "Julia 1.10" - Multiple `let` assignements are supported since Julia 1.10. + Multiple `let` assignments are supported since Julia 1.10. ## Examples ```jldoctest diff --git a/stdlib/Test/test/runtests.jl b/stdlib/Test/test/runtests.jl index 7c4edc4b9d93b..92ca8900882ce 100644 --- a/stdlib/Test/test/runtests.jl +++ b/stdlib/Test/test/runtests.jl @@ -659,15 +659,15 @@ end @test tss.foo == 3 # test @inferred -uninferrable_function(i) = (1, "1")[i] -uninferrable_small_union(i) = (1, nothing)[i] -@test_throws ErrorException @inferred(uninferrable_function(1)) +uninferable_function(i) = (1, "1")[i] +uninferable_small_union(i) = (1, nothing)[i] +@test_throws ErrorException @inferred(uninferable_function(1)) @test @inferred(identity(1)) == 1 -@test @inferred(Nothing, uninferrable_small_union(1)) === 1 -@test @inferred(Nothing, uninferrable_small_union(2)) === nothing -@test_throws ErrorException @inferred(Missing, uninferrable_small_union(1)) -@test_throws ErrorException @inferred(Missing, uninferrable_small_union(2)) -@test_throws ArgumentError @inferred(nothing, uninferrable_small_union(1)) +@test @inferred(Nothing, uninferable_small_union(1)) === 1 +@test @inferred(Nothing, uninferable_small_union(2)) === nothing +@test_throws ErrorException @inferred(Missing, uninferable_small_union(1)) +@test_throws ErrorException @inferred(Missing, uninferable_small_union(2)) +@test_throws ArgumentError @inferred(nothing, uninferable_small_union(1)) # Ensure @inferred only evaluates the arguments once inferred_test_global = 0 @@ -692,12 +692,12 @@ end # Issue #17105 # @inferred with kwargs -inferrable_kwtest(x; y=1) = 2x -uninferrable_kwtest(x; y=1) = 2x+y -@test (@inferred inferrable_kwtest(1)) == 2 -@test (@inferred inferrable_kwtest(1; y=1)) == 2 -@test (@inferred uninferrable_kwtest(1)) == 3 -@test (@inferred uninferrable_kwtest(1; y=2)) == 4 +inferable_kwtest(x; y=1) = 2x +uninferable_kwtest(x; y=1) = 2x+y +@test (@inferred inferable_kwtest(1)) == 2 +@test (@inferred inferable_kwtest(1; y=1)) == 2 +@test (@inferred uninferable_kwtest(1)) == 3 +@test (@inferred uninferable_kwtest(1; y=2)) == 4 @test_throws ErrorException @testset "$(error())" for i in 1:10 end @@ -1193,7 +1193,7 @@ h25835(;x=1,y=1) = x isa Int ? x*y : (rand(Bool) ? 1.0 : 1) @test @inferred(f25835(x=nothing)) == () @test @inferred(f25835(x=1)) == (1,) - # A global argument should make this uninferrable + # A global argument should make this uninferable global y25835 = 1 @test f25835(x=y25835) == (1,) @test_throws ErrorException @inferred((()->f25835(x=y25835))()) == (1,) diff --git a/test/clangsa/GCPushPop.cpp b/test/clangsa/GCPushPop.cpp index a62c1501bf323..72e0494a7d936 100644 --- a/test/clangsa/GCPushPop.cpp +++ b/test/clangsa/GCPushPop.cpp @@ -18,7 +18,7 @@ void missingPop2() { } // expected-warning{{Non-popped GC frame present at end of function}} // expected-note@-1{{Non-popped GC frame present at end of function}} -void superflousPop() { +void superfluousPop() { JL_GC_POP(); // expected-warning{{JL_GC_POP without corresponding push}} } // expected-note@-1{{JL_GC_POP without corresponding push}} diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 2e3598d0a1597..95d65de0c01f2 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -148,7 +148,7 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` "JULIA_LOAD_PATH" => ";;;:::", "JULIA_DEPOT_PATH" => ";;;:::", "HOME" => homedir())) - # TODO: ideally, `@which`, etc. would still work, but Julia can't handle `using $InterativeUtils` + # TODO: ideally, `@which`, etc. would still work, but Julia can't handle `using $InteractiveUtils` @test v == ("REPL: 3\n", true) end @testset let v = readchomperrors(`$exename -i -e ' diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index afda3c1793031..8ed034b391b5e 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -236,7 +236,7 @@ tuplemerge_test(Tuple{}, Tuple{Complex, Vararg{Union{ComplexF32, ComplexF64}}}, @test Core.Compiler.tmerge(Union{Nothing, AbstractFloat}, Integer) == Union{Nothing, AbstractFloat, Integer} # test that recursively more complicated types don't widen all the way to Any when there is a useful valid type upper bound -# Specificially test with base types of a trivial type, a simple union, a complicated union, and a tuple. +# Specifically test with base types of a trivial type, a simple union, a complicated union, and a tuple. for T in (Nothing, Base.BitInteger, Union{Int, Int32, Int16, Int8}, Tuple{Int, Int}) Ta, Tb = T, T for i in 1:10 @@ -2403,7 +2403,7 @@ isaint(a) = isa(a, Int) end return 0 end |> only === Int -# handle multiple call-site refinment targets +# handle multiple call-site refinement targets isasome(_) = true isasome(::Nothing) = false @test_broken Base.return_types((AliasableField{Union{Int,Nothing}},); interp=MustAliasInterpreter()) do a @@ -5129,7 +5129,7 @@ let ๐•ƒ = Core.Compiler.SimpleInferenceLattice.instance end isa Vector end -# `getindex(::SimpleVector, ::Int)` shuold be concrete-evaluated +# `getindex(::SimpleVector, ::Int)` should be concrete-evaluated @eval Base.return_types() do $(Core.svec(1,Int,nothing))[2] end |> only == Type{Int} @@ -5255,14 +5255,14 @@ let TV = TypeVar(:T) end # use `Vararg` type constraints -use_vararg_constrant1(args::Vararg{T,N}) where {T,N} = Val(T), Val(N) -@test only(Base.return_types(use_vararg_constrant1, Tuple{Int,Int})) == Tuple{Val{Int},Val{2}} -use_vararg_constrant2(args::Vararg{T,N}) where {T,N} = Val(T), N -@test only(Base.return_types(use_vararg_constrant2, Tuple{Vararg{Int}})) == Tuple{Val{Int},Int} -use_vararg_constrant3(args::NTuple{N,T}) where {T,N} = Val(T), Val(N) -@test only(Base.return_types(use_vararg_constrant3, Tuple{Tuple{Int,Int}})) == Tuple{Val{Int},Val{2}} -use_vararg_constrant4(args::NTuple{N,T}) where {T,N} = Val(T), N -@test only(Base.return_types(use_vararg_constrant4, Tuple{NTuple{N,Int}} where N)) == Tuple{Val{Int},Int} +use_vararg_constraint1(args::Vararg{T,N}) where {T,N} = Val(T), Val(N) +@test only(Base.return_types(use_vararg_constraint1, Tuple{Int,Int})) == Tuple{Val{Int},Val{2}} +use_vararg_constraint2(args::Vararg{T,N}) where {T,N} = Val(T), N +@test only(Base.return_types(use_vararg_constraint2, Tuple{Vararg{Int}})) == Tuple{Val{Int},Int} +use_vararg_constraint3(args::NTuple{N,T}) where {T,N} = Val(T), Val(N) +@test only(Base.return_types(use_vararg_constraint3, Tuple{Tuple{Int,Int}})) == Tuple{Val{Int},Val{2}} +use_vararg_constraint4(args::NTuple{N,T}) where {T,N} = Val(T), N +@test only(Base.return_types(use_vararg_constraint4, Tuple{NTuple{N,Int}} where N)) == Tuple{Val{Int},Int} # issue 51228 global whatever_unknown_value51228 diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index 07d4c7bf363a8..0fce3e1b6f0d8 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -1710,7 +1710,7 @@ let getfield_tfunc(@nospecialize xs...) = end @test fully_eliminated(Base.ismutable, Tuple{Base.RefValue}) -# TODO: Remove compute sparams for vararg_retrival +# TODO: Remove compute sparams for vararg_retrieval fvarargN_inline(x::Tuple{Vararg{Int, N}}) where {N} = N fvarargN_inline(args...) = fvarargN_inline(args) let src = code_typed1(fvarargN_inline, (Tuple{Vararg{Int}},)) diff --git a/test/compiler/invalidation.jl b/test/compiler/invalidation.jl index 848d475b85b69..10e239cfc363f 100644 --- a/test/compiler/invalidation.jl +++ b/test/compiler/invalidation.jl @@ -173,13 +173,13 @@ end # we can avoid adding backedge even if the callee's return type is not the top # when the return value is not used within the caller begin take!(GLOBAL_BUFFER) - pr48932_callee_inferrable(x) = (print(GLOBAL_BUFFER, x); Base.inferencebarrier(1)::Int) - pr48932_caller_unuse(x) = (pr48932_callee_inferrable(Base.inferencebarrier(x)); nothing) + pr48932_callee_inferable(x) = (print(GLOBAL_BUFFER, x); Base.inferencebarrier(1)::Int) + pr48932_caller_unuse(x) = (pr48932_callee_inferable(Base.inferencebarrier(x)); nothing) # assert that type and effects information inferred from `pr48932_callee(::Any)` are the top - let rt = only(Base.return_types(pr48932_callee_inferrable, (Any,))) + let rt = only(Base.return_types(pr48932_callee_inferable, (Any,))) @test rt === Int - effects = Base.infer_effects(pr48932_callee_inferrable, (Any,)) + effects = Base.infer_effects(pr48932_callee_inferable, (Any,)) @test Core.Compiler.Effects(effects) == Core.Compiler.Effects() end @@ -190,10 +190,10 @@ begin take!(GLOBAL_BUFFER) @inline pr48932_caller_unuse(x) end |> only @test rt === Nothing - @test any(iscall((src, pr48932_callee_inferrable)), src.code) + @test any(iscall((src, pr48932_callee_inferable)), src.code) end @test any(INVALIDATION_TESTER_CACHE.dict) do (mi, ci) - mi.def.name === :pr48932_callee_inferrable + mi.def.name === :pr48932_callee_inferable end @test any(INVALIDATION_TESTER_CACHE.dict) do (mi, ci) mi.def.name === :pr48932_caller_unuse @@ -201,11 +201,11 @@ begin take!(GLOBAL_BUFFER) @test isnothing(pr48932_caller_unuse(42)) @test "42" == String(take!(GLOBAL_BUFFER)) - # test that we didn't add the backedge from `pr48932_callee_inferrable` to `pr48932_caller_unuse`: - # this redefinition below should invalidate the cache of `pr48932_callee_inferrable` but not that of `pr48932_caller_unuse` - pr48932_callee_inferrable(x) = (print(GLOBAL_BUFFER, "foo"); x) + # test that we didn't add the backedge from `pr48932_callee_inferable` to `pr48932_caller_unuse`: + # this redefinition below should invalidate the cache of `pr48932_callee_inferable` but not that of `pr48932_caller_unuse` + pr48932_callee_inferable(x) = (print(GLOBAL_BUFFER, "foo"); x) @test !any(INVALIDATION_TESTER_CACHE.dict) do (mi, ci) - mi.def.name === :pr48932_callee_inferrable + mi.def.name === :pr48932_callee_inferable end @test any(INVALIDATION_TESTER_CACHE.dict) do (mi, ci) mi.def.name === :pr48932_caller_unuse diff --git a/test/core.jl b/test/core.jl index af9a896de59f8..c552678b19603 100644 --- a/test/core.jl +++ b/test/core.jl @@ -8023,7 +8023,7 @@ for T in (Int, String, Symbol, Module) end @test !Core.Compiler.is_consistent(Base.infer_effects(objectid, (Ref{Int},))) @test !Core.Compiler.is_consistent(Base.infer_effects(objectid, (Tuple{Ref{Int}},))) -# objectid for datatypes is inconsistant for types that have unbound type parameters. +# objectid for datatypes is inconsistent for types that have unbound type parameters. @test !Core.Compiler.is_consistent(Base.infer_effects(objectid, (DataType,))) @test !Core.Compiler.is_consistent(Base.infer_effects(objectid, (Tuple{Vector{Int}},))) diff --git a/test/gcext/gcext.c b/test/gcext/gcext.c index 90b5ee82d80b5..d5bf91ec8c9ab 100644 --- a/test/gcext/gcext.c +++ b/test/gcext/gcext.c @@ -32,7 +32,7 @@ static inline int lt_ptr(void *a, void *b) return (uintptr_t)a < (uintptr_t)b; } -/* align pointer to full word if mis-aligned */ +/* align pointer to full word if misaligned */ static inline void *align_ptr(void *p) { uintptr_t u = (uintptr_t)p; diff --git a/test/intrinsics.jl b/test/intrinsics.jl index 3c49afe2c4d7e..d67dad33e60cc 100644 --- a/test/intrinsics.jl +++ b/test/intrinsics.jl @@ -182,7 +182,7 @@ end if Sys.ARCH == :aarch64 || Sys.ARCH === :powerpc64le || Sys.ARCH === :ppc64le # On AArch64 we are following the `_Float16` ABI. Buthe these functions expect `Int16`. - # TODO: SHould we have `Chalf == Int16` and `Cfloat16 == Float16`? + # TODO: Should we have `Chalf == Int16` and `Cfloat16 == Float16`? extendhfsf2(x::Float16) = ccall("extern __extendhfsf2", llvmcall, Float32, (UInt16,), reinterpret(UInt16, x)) gnu_h2f_ieee(x::Float16) = ccall("extern __gnu_h2f_ieee", llvmcall, Float32, (UInt16,), reinterpret(UInt16, x)) truncsfhf2(x::Float32) = reinterpret(Float16, ccall("extern __truncsfhf2", llvmcall, UInt16, (Float32,), x)) diff --git a/test/misc.jl b/test/misc.jl index 79b684badf1e0..249175a0ed1d3 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -1058,7 +1058,7 @@ Base.setindex!(xs::InvokeXs2, @nospecialize(v::Any), idx::Int) = xs.xs[idx] = v @test @invoke(f2(1::Real)) === Integer end - # when argment's type annotation is omitted, it should be specified as `Core.Typeof(x)` + # when argument's type annotation is omitted, it should be specified as `Core.Typeof(x)` let f(_) = Any f(x::Integer) = Integer @test f(1) === Integer @@ -1353,7 +1353,7 @@ end end # Test that read fault on a prot-none region does not incorrectly give -# ReadOnlyMemoryEror, but rather crashes the program +# ReadOnlyMemoryError, but rather crashes the program const MAP_ANONYMOUS_PRIVATE = Sys.isbsd() ? 0x1002 : 0x22 let script = :( let ptr = Ptr{Cint}(ccall(:jl_mmap, Ptr{Cvoid}, diff --git a/test/operators.jl b/test/operators.jl index cf72d83ab0076..95006235692a0 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -195,7 +195,7 @@ end @test repr(uppercase โˆ˜ first) == "uppercase โˆ˜ first" @test sprint(show, "text/plain", uppercase โˆ˜ first) == "uppercase โˆ˜ first" - # test keyword ags in composition + # test keyword args in composition function kwf(a;b,c); a + b + c; end @test (abs2 โˆ˜ kwf)(1,b=2,c=3) == 36 diff --git a/test/testhelpers/DualNumbers.jl b/test/testhelpers/DualNumbers.jl index 9f62e3bf0d429..5c481aef47f76 100644 --- a/test/testhelpers/DualNumbers.jl +++ b/test/testhelpers/DualNumbers.jl @@ -41,6 +41,6 @@ Base.sqrt(x::Dual) = Dual(sqrt(x.val), x.eps/(2sqrt(x.val))) Base.isless(x::Dual, y::Dual) = x.val < y.val Base.isless(x::Real, y::Dual) = x < y.val Base.isinf(x::Dual) = isinf(x.val) & isfinite(x.eps) -Base.real(x::Dual) = x # since we curently only consider Dual{<:Real} +Base.real(x::Dual) = x # since we currently only consider Dual{<:Real} end # module From 258ac4614f589cb46436c12b2fa12030efd0cca3 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Sun, 15 Oct 2023 19:09:11 -0700 Subject: [PATCH 0006/1315] Add note about sysimage `__init__`s running before startup.jl (#51623) What caught me out in https://github.com/JuliaLang/julia/issues/51620 --- doc/src/manual/environment-variables.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/src/manual/environment-variables.md b/doc/src/manual/environment-variables.md index 344c272fd80a5..2fc1dcbb2f32b 100644 --- a/doc/src/manual/environment-variables.md +++ b/doc/src/manual/environment-variables.md @@ -16,8 +16,19 @@ including those which include `JULIA` in their names. !!! note - Some variables, such as [`JULIA_NUM_THREADS`](@ref JULIA_NUM_THREADS) and [`JULIA_PROJECT`](@ref JULIA_PROJECT), need to be set before Julia - starts, therefore adding these to `~/.julia/config/startup.jl` is too late in the startup process. + It is recommended to avoid changing environment variables during runtime, + such as within a `~/.julia/config/startup.jl`. + + One reason is that some julia language variables, such as [`JULIA_NUM_THREADS`](@ref JULIA_NUM_THREADS) + and [`JULIA_PROJECT`](@ref JULIA_PROJECT), need to be set before Julia starts. + + Similarly, `__init__()` functions of user modules in the sysimage (via PackageCompiler) are + run before `startup.jl`, so setting environment variables in a `startup.jl` may be too late for + user code. + + Further, changing environment variables during runtime can introduce data races into + otherwise benign code. + In Bash, environment variables can either be set manually by running, e.g., `export JULIA_NUM_THREADS=4` before starting Julia, or by adding the same command to `~/.bashrc` or `~/.bash_profile` to set the variable each time Bash is started. From b0c6781676f08bc0150018cd5ed54d71bb0c49c2 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Mon, 16 Oct 2023 08:09:42 -0400 Subject: [PATCH 0007/1315] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the?= =?UTF-8?q?=20SparseArrays=20stdlib=20from=204e6776a=20to=200f8bbda=20(#51?= =?UTF-8?q?678)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: SparseArrays URL: https://github.com/JuliaSparse/SparseArrays.jl.git Stdlib branch: main Julia branch: master Old commit: 4e6776a New commit: 0f8bbda Julia version: 1.11.0-DEV SparseArrays version: 1.11.0 Bump invoked by: @ViralBShah Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaSparse/SparseArrays.jl/compare/4e6776a825f2a26c3c580f9b77ba230a6598d7dd...0f8bbdac9c2d805f32faed90f4d8b8c8514aa478 ``` $ git log --oneline 4e6776a..0f8bbda 0f8bbda Interpolate SparseVector in display test (#455) d884072 Merge pull request #427 from JuliaSparse/jishnub/sparsevecshow 9e68b7e Merge branch 'main' into jishnub/sparsevecshow 12a1c30 remove unnecessary inequality change 4217641 don't set Documenter compat e86b148 Adapt to Documenter v1 (#444) 8c72535 Merge branch 'main' into jishnub/sparsevecshow 8c20ba1 Test for truncation 8f925f8 Interpolate Int in expected string c53e1f2 interpolate struct in display test 33d4bf5 Undef show with MIME text/plain 034d234 Hook into new factorization dispatch mechanisms (#437) 248d0e6 Merge branch 'main' into jishnub/sparsevecshow 713ab9b Fix documentation of `findall` behaviour (#452) cb9b31f rowvals instead of nonzeroinds 05ac950 Add example for UMFPACK control vector (#449) 605237e Add JL_UMFPACK_PIVOT_TOLERANCE to umfpack.jl (#447) 5dac134 Use a single header wrapper for all platforms. (#446) 47e26dd Explicit types in test RHS c123952 Interpolate vectors in show test b309da7 Explicit types d21fc79 Add test for showing a vector of sparsevec 3e918e4 Restore unfilled sparsevec display b533818 Don't add SparseArrays to docs/Project.toml 4449100 Remove commented out method 728e116 ignore docs/build 99a0db2 Merge show methods ac5c8ed Switch from internal 5-arg `searchsorted*` methods to views (#440) ada9edd sparse vector views remain sparse (#416) c93065c Improved the dot product between two vectors and a sparse matrix (#410) 2fae1a1 Correctly set zeros with `fill!(::SubArray)` and fix its return value (#433) 03ed9e3 Code quality cleanup (#438) 559a74e Merge branch 'main' into jishnub/sparsevecshow 8944160 fix empty show e72223d One-line show for SparseVector ``` Co-authored-by: Dilum Aluthge --- .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 - .../sha512 | 1 - stdlib/SparseArrays.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/md5 create mode 100644 deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/sha512 delete mode 100644 deps/checksums/SparseArrays-4e6776a825f2a26c3c580f9b77ba230a6598d7dd.tar.gz/md5 delete mode 100644 deps/checksums/SparseArrays-4e6776a825f2a26c3c580f9b77ba230a6598d7dd.tar.gz/sha512 diff --git a/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/md5 b/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/md5 new file mode 100644 index 0000000000000..91cf02d3d1d50 --- /dev/null +++ b/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/md5 @@ -0,0 +1 @@ +69978c0844e0b4e780ae98c491e2fef4 diff --git a/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/sha512 b/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/sha512 new file mode 100644 index 0000000000000..45782edfc0689 --- /dev/null +++ b/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/sha512 @@ -0,0 +1 @@ +96391c3e79cc7eb580c7f61814c808110b5b1f5f65135509bf55fcd93c007257a126c6511fa97975d88cacec1d2c0722c2cc66b43f974278375ef976870af63c diff --git a/deps/checksums/SparseArrays-4e6776a825f2a26c3c580f9b77ba230a6598d7dd.tar.gz/md5 b/deps/checksums/SparseArrays-4e6776a825f2a26c3c580f9b77ba230a6598d7dd.tar.gz/md5 deleted file mode 100644 index fe0a7d8a02a91..0000000000000 --- a/deps/checksums/SparseArrays-4e6776a825f2a26c3c580f9b77ba230a6598d7dd.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -610ecdfc1624f4dba575d1ca78c02f01 diff --git a/deps/checksums/SparseArrays-4e6776a825f2a26c3c580f9b77ba230a6598d7dd.tar.gz/sha512 b/deps/checksums/SparseArrays-4e6776a825f2a26c3c580f9b77ba230a6598d7dd.tar.gz/sha512 deleted file mode 100644 index 5626ac97ada1f..0000000000000 --- a/deps/checksums/SparseArrays-4e6776a825f2a26c3c580f9b77ba230a6598d7dd.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -fb6fc223f2bc0abfdc082805100351a46fb1c56d16079ea1d608d114f86a701243f5aa448b7e251f735125389baed94e632385f3e560c789136a6848e5f39c81 diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index 96024ba41da82..91a67c5bddc9f 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = main -SPARSEARRAYS_SHA1 = 4e6776a825f2a26c3c580f9b77ba230a6598d7dd +SPARSEARRAYS_SHA1 = 0f8bbdac9c2d805f32faed90f4d8b8c8514aa478 SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 From 4d36da7768ea403284cb7364366a941cfba40642 Mon Sep 17 00:00:00 2001 From: KronosTheLate <61620837+KronosTheLate@users.noreply.github.com> Date: Mon, 16 Oct 2023 17:01:46 +0200 Subject: [PATCH 0008/1315] Improve dostring for error(msg...) (#51721) This PR slightly modifies the docstring for the second method defined for `error`, as the docstring for this method a) seems quite imprecise, and b) is identical to that of `error(::AbstractString)`. --- base/error.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/error.jl b/base/error.jl index 4e9be0e172d61..fa020f4823cbd 100644 --- a/base/error.jl +++ b/base/error.jl @@ -37,7 +37,7 @@ error(s::AbstractString) = throw(ErrorException(s)) """ error(msg...) -Raise an `ErrorException` with the given message. +Raise an `ErrorException` with a message constructed by `string(msg...)`. """ function error(s::Vararg{Any,N}) where {N} @noinline From 6ec149f3b19a0d1ba597ee20780856cd5ae31867 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Mon, 16 Oct 2023 09:53:47 -0700 Subject: [PATCH 0009/1315] Lower Pidfile stale_age multiplier. Add pidfile to cache log message. (#51714) --- base/loading.jl | 19 +++++++++------- stdlib/FileWatching/src/pidfile.jl | 21 +++++++++-------- stdlib/FileWatching/test/pidfile.jl | 35 ++++++++++++++++++++--------- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index a10c7b35d0e18..4eca0ea0e1200 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -3053,14 +3053,17 @@ global parse_pidfile_hook # the same package cannot be precompiled from different projects and/or different preferences at the same time. compilecache_pidfile_path(pkg::PkgId) = compilecache_path(pkg, UInt64(0); project="") * ".pidfile" +const compilecache_pidlock_stale_age = 10 + # Allows processes to wait if another process is precompiling a given source already. -# The lock file mtime will be updated when held every `stale_age/2` seconds. +# The lock file mtime will be updated when held at most every `stale_age/2` seconds, with expected +# variance of 10 seconds or more being infrequent but not unusual. # After `stale_age` seconds beyond the mtime of the lock file, the lock file is deleted and -# precompilation will proceed if -# - the locking process no longer exists -# - the lock is held by another host, since processes cannot be checked remotely -# or after `stale_age * 25` seconds if the process does still exist. -function maybe_cachefile_lock(f, pkg::PkgId, srcpath::String; stale_age=10) +# precompilation will proceed if the locking process no longer exists or after `stale_age * 5` +# seconds if the process does still exist. +# If the lock is held by another host, it will conservatively wait `stale_age * 5` +# seconds since processes cannot be checked remotely +function maybe_cachefile_lock(f, pkg::PkgId, srcpath::String; stale_age=compilecache_pidlock_stale_age) if @isdefined(mkpidlock_hook) && @isdefined(trymkpidlock_hook) && @isdefined(parse_pidfile_hook) pidfile = compilecache_pidfile_path(pkg) cachefile = invokelatest(trymkpidlock_hook, f, pidfile; stale_age) @@ -3068,9 +3071,9 @@ function maybe_cachefile_lock(f, pkg::PkgId, srcpath::String; stale_age=10) pid, hostname, age = invokelatest(parse_pidfile_hook, pidfile) verbosity = isinteractive() ? CoreLogging.Info : CoreLogging.Debug if isempty(hostname) || hostname == gethostname() - @logmsg verbosity "Waiting for another process (pid: $pid) to finish precompiling $pkg" + @logmsg verbosity "Waiting for another process (pid: $pid) to finish precompiling $pkg. Pidfile: $pidfile" else - @logmsg verbosity "Waiting for another machine (hostname: $hostname, pid: $pid) to finish precompiling $pkg" + @logmsg verbosity "Waiting for another machine (hostname: $hostname, pid: $pid) to finish precompiling $pkg. Pidfile: $pidfile" end # wait until the lock is available, but don't actually acquire it # returning nothing indicates a process waited for another diff --git a/stdlib/FileWatching/src/pidfile.jl b/stdlib/FileWatching/src/pidfile.jl index 93217311c3183..ada725e63094b 100644 --- a/stdlib/FileWatching/src/pidfile.jl +++ b/stdlib/FileWatching/src/pidfile.jl @@ -33,7 +33,8 @@ Optional keyword arguments: - `mode`: file access mode (modified by the process umask). Defaults to world-readable. - `poll_interval`: Specify the maximum time to between attempts (if `watch_file` doesn't work) - `stale_age`: Delete an existing pidfile (ignoring the lock) if it is older than this many seconds, based on its mtime. - The file won't be deleted until 25x longer than this if the pid in the file appears that it may be valid. + The file won't be deleted until 5x longer than this if the pid in the file appears that it may be valid. + Or 25x longer if `refresh` is overridden to 0 to disable lock refreshing. By default this is disabled (`stale_age` = 0), but a typical recommended value would be about 3-5x an estimated normal completion time. - `refresh`: Keeps a lock from becoming stale by updating the mtime every interval of time that passes. @@ -64,7 +65,7 @@ mutable struct LockMonitor atdir, atname = splitdir(at) isempty(atdir) && (atdir = pwd()) at = realpath(atdir) * path_separator * atname - fd = open_exclusive(at; stale_age=stale_age, kwopts...) + fd = open_exclusive(at; stale_age, refresh, kwopts...) update = nothing try write_pidfile(fd, pid) @@ -185,15 +186,16 @@ function isvalidpid(hostname::AbstractString, pid::Cuint) end """ - stale_pidfile(path::String, stale_age::Real) :: Bool + stale_pidfile(path::String, stale_age::Real, refresh::Real) :: Bool Helper function for `open_exclusive` for deciding if a pidfile is stale. """ -function stale_pidfile(path::String, stale_age::Real) +function stale_pidfile(path::String, stale_age::Real, refresh::Real) pid, hostname, age = parse_pidfile(path) age < -stale_age && @warn "filesystem time skew detected" path=path + longer_factor = refresh == 0 ? 25 : 5 if age > stale_age - if (age > stale_age * 25) || !isvalidpid(hostname, pid) + if (age > stale_age * longer_factor) || !isvalidpid(hostname, pid) return true end end @@ -220,7 +222,7 @@ struct PidlockedError <: Exception end """ - open_exclusive(path::String; mode, poll_interval, wait, stale_age) :: File + open_exclusive(path::String; mode, poll_interval, wait, stale_age, refresh) :: File Create a new a file for read-write advisory-exclusive access. If `wait` is `false` then error out if the lock files exist @@ -232,13 +234,14 @@ function open_exclusive(path::String; mode::Integer = 0o444 #= read-only =#, poll_interval::Real = 10 #= seconds =#, wait::Bool = true #= return on failure if false =#, - stale_age::Real = 0 #= disabled =#) + stale_age::Real = 0 #= disabled =#, + refresh::Real = stale_age/2) # fast-path: just try to open it file = tryopen_exclusive(path, mode) file === nothing || return file if !wait if file === nothing && stale_age > 0 - if stale_age > 0 && stale_pidfile(path, stale_age) + if stale_age > 0 && stale_pidfile(path, stale_age, refresh) @warn "attempting to remove probably stale pidfile" path=path tryrmopenfile(path) end @@ -264,7 +267,7 @@ function open_exclusive(path::String; file = tryopen_exclusive(path, mode) file === nothing || return file Base.wait(t) # sleep for a bit before trying again - if stale_age > 0 && stale_pidfile(path, stale_age) + if stale_age > 0 && stale_pidfile(path, stale_age, refresh) # if the file seems stale, try to remove it before attempting again # set stale_age to zero so we won't attempt again, even if the attempt fails stale_age -= stale_age diff --git a/stdlib/FileWatching/test/pidfile.jl b/stdlib/FileWatching/test/pidfile.jl index c2cb0c88a1b1e..3464a24175632 100644 --- a/stdlib/FileWatching/test/pidfile.jl +++ b/stdlib/FileWatching/test/pidfile.jl @@ -203,18 +203,33 @@ end @assert !ispath("pidfile") @testset "open_exclusive: break lock" begin - # test for stale_age - t = @elapsed f = open_exclusive("pidfile", poll_interval=3, stale_age=10)::File - try - write_pidfile(f, getpid()) - finally + @testset "using stale_age without lock refreshing" begin + t = @elapsed f = open_exclusive("pidfile", poll_interval=3, stale_age=10, refresh=0)::File + try + write_pidfile(f, getpid()) + finally + close(f) + end + @test t < 2 + t = @elapsed f = open_exclusive("pidfile", poll_interval=3, stale_age=1, refresh=0)::File close(f) + @test 20 < t < 50 + rm("pidfile") + end + + @testset "using stale_age with lock refreshing on (default)" begin + t = @elapsed f = open_exclusive("pidfile", poll_interval=3, stale_age=10)::File + try + write_pidfile(f, getpid()) + finally + close(f) + end + @test t < 2 + t = @elapsed f = open_exclusive("pidfile", poll_interval=3, stale_age=5)::File + close(f) + @test 20 < t < 50 + rm("pidfile") end - @test t < 2 - t = @elapsed f = open_exclusive("pidfile", poll_interval=3, stale_age=1)::File - close(f) - @test 20 < t < 50 - rm("pidfile") t = @elapsed f = open_exclusive("pidfile", poll_interval=3, stale_age=10)::File close(f) From d5cde522e2274ea8dddd93c3ee224a1e5d7cfe96 Mon Sep 17 00:00:00 2001 From: "Viral B. Shah" Date: Mon, 16 Oct 2023 16:16:08 -0400 Subject: [PATCH 0010/1315] Bump SparseArrays to pull in SuiteSparse 7.2.1 (#51725) Upgrade SuiteSparse to 7.2.1 Upgrade SparseArrays.jl to the latest master --------- Co-authored-by: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Co-authored-by: Dilum Aluthge --- .../md5 | 1 - .../sha512 | 1 - .../md5 | 1 + .../sha512 | 1 + .../md5 | 1 + .../sha512 | 1 + deps/checksums/suitesparse | 70 +++++++++---------- deps/libsuitesparse.mk | 2 +- deps/libsuitesparse.version | 5 +- stdlib/SparseArrays.version | 2 +- stdlib/SuiteSparse_jll/Project.toml | 4 +- 11 files changed, 44 insertions(+), 45 deletions(-) delete mode 100644 deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/md5 delete mode 100644 deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/sha512 create mode 100644 deps/checksums/SparseArrays-3582898a4efd3f504d39076f5a162b9ed1ebcdb2.tar.gz/md5 create mode 100644 deps/checksums/SparseArrays-3582898a4efd3f504d39076f5a162b9ed1ebcdb2.tar.gz/sha512 create mode 100644 deps/checksums/SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/md5 create mode 100644 deps/checksums/SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/sha512 diff --git a/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/md5 b/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/md5 deleted file mode 100644 index 91cf02d3d1d50..0000000000000 --- a/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -69978c0844e0b4e780ae98c491e2fef4 diff --git a/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/sha512 b/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/sha512 deleted file mode 100644 index 45782edfc0689..0000000000000 --- a/deps/checksums/SparseArrays-0f8bbdac9c2d805f32faed90f4d8b8c8514aa478.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -96391c3e79cc7eb580c7f61814c808110b5b1f5f65135509bf55fcd93c007257a126c6511fa97975d88cacec1d2c0722c2cc66b43f974278375ef976870af63c diff --git a/deps/checksums/SparseArrays-3582898a4efd3f504d39076f5a162b9ed1ebcdb2.tar.gz/md5 b/deps/checksums/SparseArrays-3582898a4efd3f504d39076f5a162b9ed1ebcdb2.tar.gz/md5 new file mode 100644 index 0000000000000..12314ebe27beb --- /dev/null +++ b/deps/checksums/SparseArrays-3582898a4efd3f504d39076f5a162b9ed1ebcdb2.tar.gz/md5 @@ -0,0 +1 @@ +6427ffc68076c0555b0d3a02eaf88160 diff --git a/deps/checksums/SparseArrays-3582898a4efd3f504d39076f5a162b9ed1ebcdb2.tar.gz/sha512 b/deps/checksums/SparseArrays-3582898a4efd3f504d39076f5a162b9ed1ebcdb2.tar.gz/sha512 new file mode 100644 index 0000000000000..5c7602b6707cc --- /dev/null +++ b/deps/checksums/SparseArrays-3582898a4efd3f504d39076f5a162b9ed1ebcdb2.tar.gz/sha512 @@ -0,0 +1 @@ +7a4c6dae45b739bb1b22c53c8b2b32fc765995767580338218a99f671749bbd5c5d9b61f45718c3b80e153b524737501141481ede2a6f24856de1c028f07ad3a diff --git a/deps/checksums/SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/md5 b/deps/checksums/SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/md5 new file mode 100644 index 0000000000000..2f81a0d9191b5 --- /dev/null +++ b/deps/checksums/SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/md5 @@ -0,0 +1 @@ +46541001073d1c3c85e18d910f8308f3 diff --git a/deps/checksums/SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/sha512 b/deps/checksums/SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/sha512 new file mode 100644 index 0000000000000..e2eb44845e276 --- /dev/null +++ b/deps/checksums/SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/sha512 @@ -0,0 +1 @@ +f7470a447b934ca9315e216a07b97e363f11bc93186f9aa057b20b2d05092c58ae4f1b733de362de4a0730861c00be4ca5588d0b3ba65f018c1798b9122b9672 diff --git a/deps/checksums/suitesparse b/deps/checksums/suitesparse index ad571d8be1f28..7578826fe3f0e 100644 --- a/deps/checksums/suitesparse +++ b/deps/checksums/suitesparse @@ -1,36 +1,34 @@ -SuiteSparse-7.2.0.tar.gz/md5/a751b1161f03eb6bd8bd7b9c9be74b67 -SuiteSparse-7.2.0.tar.gz/sha512/62fc796a77f2a8c95cd688a4fa0e39c19d7ccfafde7a6623d62ca6928cee68ac9863a0f721959a1d5a07e62888ab621a4b1cb4f63371f4ac10f4ffe513241340 -SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/md5/46541001073d1c3c85e18d910f8308f3 -SuiteSparse-e8285dd13a6d5b5cf52d8124793fc4d622d07554.tar.gz/sha512/f7470a447b934ca9315e216a07b97e363f11bc93186f9aa057b20b2d05092c58ae4f1b733de362de4a0730861c00be4ca5588d0b3ba65f018c1798b9122b9672 -SuiteSparse.v7.2.0+1.aarch64-apple-darwin.tar.gz/md5/1a10261e5bed293a66849c7a50605a1c -SuiteSparse.v7.2.0+1.aarch64-apple-darwin.tar.gz/sha512/11ecce872aac1f30a3d4ce870920ebb03c7828d0fd740c3789d3f65c3f91ed3682372e9807b0593e2850ae9024450306451ee2e03866afee16b4169e4b5de1c6 -SuiteSparse.v7.2.0+1.aarch64-linux-gnu.tar.gz/md5/65e2e7ae54e94e00b306d17a1d08ed34 -SuiteSparse.v7.2.0+1.aarch64-linux-gnu.tar.gz/sha512/7714598448c6f98a7d931822f9ddb661a903342d4c8384648c1b7457511794ff95ad64266c9377a4a5856dcb1fb8864cb05eab1c7787fca58802473270313570 -SuiteSparse.v7.2.0+1.aarch64-linux-musl.tar.gz/md5/95eb68e02c04d075d6ecc974c3b44457 -SuiteSparse.v7.2.0+1.aarch64-linux-musl.tar.gz/sha512/1d7835106cd5baef701a3b670778a757d97ab9933f7da909e1e5521150f7e44bee30cf4dc7c1e9f57731366db0fca1b91d1cdfddbc53b7cc7457ca11534be6d7 -SuiteSparse.v7.2.0+1.armv6l-linux-gnueabihf.tar.gz/md5/5f627cc9c9d4d70e2f0d749e09926b1a -SuiteSparse.v7.2.0+1.armv6l-linux-gnueabihf.tar.gz/sha512/5ae4b79b418b45d954bfb578ac384afd6fff10a602d16d8b503997ba15251a7db0e12da66061ffd27c23b7459ff56b4a5d200c7c8aaa4a33c608a88752535c15 -SuiteSparse.v7.2.0+1.armv6l-linux-musleabihf.tar.gz/md5/61b5ee7e2b50665caf15e7c4f7353048 -SuiteSparse.v7.2.0+1.armv6l-linux-musleabihf.tar.gz/sha512/854c0165bceeb8202aeeaa16e6ba1f643e8cb9bf0561816cf2c44d1c7334ba7c376ee9e9085316439ca7e27dd4e37814f4916382096a5889c6bb656d22a7fb8d -SuiteSparse.v7.2.0+1.armv7l-linux-gnueabihf.tar.gz/md5/618b9687ce30e630a52f72a8f34cfb9f -SuiteSparse.v7.2.0+1.armv7l-linux-gnueabihf.tar.gz/sha512/add77a8842faf6515d94dc1d000784247d13f0211a9bb3f98edbc65b5f8994c0101940875fa050ca7a4605aaf33ec14daeaaf6b837673b3b4c600d4c5c0f4876 -SuiteSparse.v7.2.0+1.armv7l-linux-musleabihf.tar.gz/md5/b84d7f98b953772517689478d6bfc121 -SuiteSparse.v7.2.0+1.armv7l-linux-musleabihf.tar.gz/sha512/2c461eb23194bf61d3166abd8eb308dc643d865ff07466a88a580aa5a040f3c4fbfeadf7c78e1a3ce737fe0602909ff2b25be439741d36a780a260ccfdc6ed83 -SuiteSparse.v7.2.0+1.i686-linux-gnu.tar.gz/md5/3a38deddb5c1952584782378892d9579 -SuiteSparse.v7.2.0+1.i686-linux-gnu.tar.gz/sha512/5d6a9090c1c275c2bdcdc8d510c6372913109c1a775819354922c0d0afc2bc13a27950ed0e8cb8e05bc94d245220e322d93879054e5082814b7796b305981987 -SuiteSparse.v7.2.0+1.i686-linux-musl.tar.gz/md5/8076c50a73ab08ce0b9374956c2dbf29 -SuiteSparse.v7.2.0+1.i686-linux-musl.tar.gz/sha512/e54bcfe7eb9b266514a35a3c48676b7a792b59830e44bfcd5dfcf35be790f534cc31bd2e63ce4da1a22fcb3b0afb0ebebcc94f0e596806d6e832c3f68195cc5b -SuiteSparse.v7.2.0+1.i686-w64-mingw32.tar.gz/md5/45ac2448ac7a1a9c67114ea58e8ceacf -SuiteSparse.v7.2.0+1.i686-w64-mingw32.tar.gz/sha512/ed65a4071144c0096dfa768f26fd6216d4554c606a981658675d42f201865032972d9ce252dca5dc8a4a7ab0e33411c77bba9287e8013bdb0907ed6cb63d576f -SuiteSparse.v7.2.0+1.powerpc64le-linux-gnu.tar.gz/md5/64845ee8bb2f3f44a0837297e47e412d -SuiteSparse.v7.2.0+1.powerpc64le-linux-gnu.tar.gz/sha512/5f935e497db4ebbcdfb96603a7ee9c6c520d7f4df04f65952305ceff4271ab637079e9144b98044c5f159b4bed0963df8c95ed1578d2828f1a2356e6d34d7042 -SuiteSparse.v7.2.0+1.x86_64-apple-darwin.tar.gz/md5/fb8b00d4ca63004fe8ab8c159128e01f -SuiteSparse.v7.2.0+1.x86_64-apple-darwin.tar.gz/sha512/bcfb18c11be4b1147ff857e2ad0c881c9fc4ae16db8e88fb6e7e0448418c1fc4bff9ea8f1e6aa7202c277273c44c1afb3cc6c2bfcaa0735c7c09052f033248c7 -SuiteSparse.v7.2.0+1.x86_64-linux-gnu.tar.gz/md5/043594ee1cb90fd47b36acfa829fffb8 -SuiteSparse.v7.2.0+1.x86_64-linux-gnu.tar.gz/sha512/6a5bb3c85bb7e97b915f7dd40e8be1ed1bbbd5c756ef510deaecc8505b95bd42f3662f82e25c80055947060e0429e2ce427d4ff67b434acbe28d46b88279c65f -SuiteSparse.v7.2.0+1.x86_64-linux-musl.tar.gz/md5/67c6d3a7fd8635a43bd86b2b1e986978 -SuiteSparse.v7.2.0+1.x86_64-linux-musl.tar.gz/sha512/d46be3f60102fc69707c3e7cc3d693c7ecb4d4307c636afde61e5fab3c46fcf32564716a11d2cfe47b4e541422d5b6e13fbcc3e8749764527b4f4132e8ce17fc -SuiteSparse.v7.2.0+1.x86_64-unknown-freebsd.tar.gz/md5/124057f8455c9710fd1e6b4b4b469fb0 -SuiteSparse.v7.2.0+1.x86_64-unknown-freebsd.tar.gz/sha512/da0e56a8b1cf3967275cb64aea0b939d8982392f9ca1c3b268607e37c0b9bebbd456172c507c6dc2293989a0fe8df04ba1fea67442a4bb738cc8d894bea457a5 -SuiteSparse.v7.2.0+1.x86_64-w64-mingw32.tar.gz/md5/0f99c67d25c0fdd0f3c3e11f18925c43 -SuiteSparse.v7.2.0+1.x86_64-w64-mingw32.tar.gz/sha512/32fcd894cb4197970aa311f7bd12ccb91df7bbe27e389e793a2d3565c9c5c36c751f6dfa37e155cd2c2245be52f0a872dba032b78dc45c45d3fd7d7f2eeb773e +SuiteSparse-7.2.1.tar.gz/md5/c341b4b2943b6d99ec147dc36ae64d51 +SuiteSparse-7.2.1.tar.gz/sha512/6385b699d2f109e8473bb58e95705671b8a5c2f1b281d17bba9f396a94b2e783700c4c64f4ab9495a4a64e23ba279052616054045783b4b8c8eb28a8f4f6be28 +SuiteSparse.v7.2.1+1.aarch64-apple-darwin.tar.gz/md5/1bd9c850b5bb6de56f4dfd0633ce7a6c +SuiteSparse.v7.2.1+1.aarch64-apple-darwin.tar.gz/sha512/f0e932fa2b6d2843fd75c1e151b8304ed2521b679c732301877495d9a2437ec693ba0ebaaf52cb3a4f5c01bcd8c972a27b1080071c9c77462901fa4dec7de787 +SuiteSparse.v7.2.1+1.aarch64-linux-gnu.tar.gz/md5/ff52a5ef6546bbea2ce2d73db2821522 +SuiteSparse.v7.2.1+1.aarch64-linux-gnu.tar.gz/sha512/f5c2a54e40b36fc0489140397e6324bbd1050a87949fd9be3837012825c3becbef66258d28c286d0c45b0447361b2ddf736370402ed928b909e0fb7c5f4ee69c +SuiteSparse.v7.2.1+1.aarch64-linux-musl.tar.gz/md5/2baa4103f4070f66d6278fc001317372 +SuiteSparse.v7.2.1+1.aarch64-linux-musl.tar.gz/sha512/17bc9b020850d9cc652d49987c3faa57204ed3beecd04ea812fd03b4f60f541ba7b250fa70c801a8ec3c440f3562a4771a3742299f0d4eb770e58010c43a3823 +SuiteSparse.v7.2.1+1.armv6l-linux-gnueabihf.tar.gz/md5/cdc1c60e50f6551a52e57ac71440564a +SuiteSparse.v7.2.1+1.armv6l-linux-gnueabihf.tar.gz/sha512/9209f86ac97c061755169412565055847be4890140a389a92468297507cee240219d910bbcef94c52926771a4152762cfa05cfa33c26d31351d68265e5719bd3 +SuiteSparse.v7.2.1+1.armv6l-linux-musleabihf.tar.gz/md5/cd5e177e660d793426e4c4aeb2f9269c +SuiteSparse.v7.2.1+1.armv6l-linux-musleabihf.tar.gz/sha512/a8a5ca739999a16336b2c98ec88873e00349720b5d966d643d5665338b1f9c8077352d87fac41a165cb65793ae5fb686e954b3eaa3f751aa8d002388a0ce6a13 +SuiteSparse.v7.2.1+1.armv7l-linux-gnueabihf.tar.gz/md5/eb43136009b370e93c6ab4c1b0eec40c +SuiteSparse.v7.2.1+1.armv7l-linux-gnueabihf.tar.gz/sha512/e20a308911a36037c9b6da3c060f8624b1ff84b0e23cbd62189f62e989f6a5307b07a6286d95459e0886a8d16fd59ad5a34607dd2c644f7bedc786dd6567670c +SuiteSparse.v7.2.1+1.armv7l-linux-musleabihf.tar.gz/md5/19f9246fc6c8bd2c7a4d2df498725abe +SuiteSparse.v7.2.1+1.armv7l-linux-musleabihf.tar.gz/sha512/d2cba310fe33ddb11d9ada37ce04905dfc3f058a1cbf7b53ca1dc31c2c51bcf930a4976c39d55bfdacb19195ff772acb1c6876238640a6ed6277777934a8b53f +SuiteSparse.v7.2.1+1.i686-linux-gnu.tar.gz/md5/8ff91e530528c8761411b8d9be56d1f0 +SuiteSparse.v7.2.1+1.i686-linux-gnu.tar.gz/sha512/42bd937fb1c476164b923b5093d3df3fc3cdd4e3bc148616ba48027d4616479d674a4c8f7291cf7004a43834508b459630f4cafbd90850d10402d53faa34e714 +SuiteSparse.v7.2.1+1.i686-linux-musl.tar.gz/md5/49bc8f22a227748680734d89f64a4cf7 +SuiteSparse.v7.2.1+1.i686-linux-musl.tar.gz/sha512/b78b84d330a8f22e7d9fdd72fe621e9830c1afd908946d4101705f05546aa892b2f5ef87988dec39ccd81cbe4dbeb95adc277d096d60e106485c5b6f81cf4403 +SuiteSparse.v7.2.1+1.i686-w64-mingw32.tar.gz/md5/cd593a3c801ba72bf6d77788c7ca06b9 +SuiteSparse.v7.2.1+1.i686-w64-mingw32.tar.gz/sha512/0b49795ed5cb773a5930d305e65d53ff35ff1d1ee0a84e8762f56ca442c2421752b50b667646fd6a977c0684c2214996011f405ff1c7fd6eeaf16d08262d7d05 +SuiteSparse.v7.2.1+1.powerpc64le-linux-gnu.tar.gz/md5/3858c87b8f62844520ff61c72d7b5a25 +SuiteSparse.v7.2.1+1.powerpc64le-linux-gnu.tar.gz/sha512/ea505fe14155ee69a715339fe7075603c04458d5c7f65fecb92bea69a86117b1d21da75dab832ac0f6cc9aa64bfa6d7f50cb679fefa9ec5b4d4d8826d3137ff9 +SuiteSparse.v7.2.1+1.x86_64-apple-darwin.tar.gz/md5/241dec5338e04fbf6084cec90bbd2f76 +SuiteSparse.v7.2.1+1.x86_64-apple-darwin.tar.gz/sha512/8477d2102be709aa2f74325df91aab4f9c894c8f516cd17d3780aab66bcbf920fa5771fa7e130a63793f94b99c6cfc4db6ab22e6a33a55670e25e36472770d59 +SuiteSparse.v7.2.1+1.x86_64-linux-gnu.tar.gz/md5/c6b6fa99a21a9000892d51b821f304a7 +SuiteSparse.v7.2.1+1.x86_64-linux-gnu.tar.gz/sha512/ad2e1200d0418c531758672b64e849c81cfe74ca73cff0e1a47797e73dbc4675c9a2ec855af628dddef58b135412d06fa18c15565c94de5e1e6d15e3b150ecbd +SuiteSparse.v7.2.1+1.x86_64-linux-musl.tar.gz/md5/6c14129471a9c92464d36ae00f4c5a08 +SuiteSparse.v7.2.1+1.x86_64-linux-musl.tar.gz/sha512/e9051ceb7d551019deb16480b493d1ac5b622fe86c7e19b1023eb12af28d42f25e911e1e44870c35849d8f95d78e8e28c38699cde1fab250dac32818ebc58a2b +SuiteSparse.v7.2.1+1.x86_64-unknown-freebsd.tar.gz/md5/ab0f6a9b7789f21aba5ea10659b03ed3 +SuiteSparse.v7.2.1+1.x86_64-unknown-freebsd.tar.gz/sha512/cc9136bfda474914107e68f97a200d46f81a1f36ea51c4e482ef04e818d3ac10d14b2895eef59b2570f6115261e987bd076dd8f9be0e6d2dc77931d3257db142 +SuiteSparse.v7.2.1+1.x86_64-w64-mingw32.tar.gz/md5/e804d9ed593d739326865dc1f60d5800 +SuiteSparse.v7.2.1+1.x86_64-w64-mingw32.tar.gz/sha512/20c9ac62cd41b19e0b9605c8f9a8bece9089f7f69e2cf57ace3058215acefe8cf9ce39d3c05010223443bfc45b1efb8391be677a1b5e9a59bbdfe89f89553f71 diff --git a/deps/libsuitesparse.mk b/deps/libsuitesparse.mk index 10161f08ecf5b..fa1eda94b5c4f 100644 --- a/deps/libsuitesparse.mk +++ b/deps/libsuitesparse.mk @@ -29,7 +29,7 @@ LIBSUITESPARSE_CMAKE_FLAGS += -DCMAKE_INSTALL_RPATH="\$$ORIGIN" endif $(SRCCACHE)/SuiteSparse-$(LIBSUITESPARSE_VER).tar.gz: | $(SRCCACHE) - $(JLDOWNLOAD) $@ https://github.com/Wimmerer/SuiteSparse/archive/v$(LIBSUITESPARSE_VER).tar.gz + $(JLDOWNLOAD) $@ https://github.com/DrTimothyAldenDavis/SuiteSparse/archive/v$(LIBSUITESPARSE_VER).tar.gz $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/source-extracted: $(SRCCACHE)/SuiteSparse-$(LIBSUITESPARSE_VER).tar.gz $(JLCHECKSUM) $< diff --git a/deps/libsuitesparse.version b/deps/libsuitesparse.version index 867e52304477c..eea10d4f2beb8 100644 --- a/deps/libsuitesparse.version +++ b/deps/libsuitesparse.version @@ -2,6 +2,5 @@ LIBSUITESPARSE_JLL_NAME := SuiteSparse ## source build -LIBSUITESPARSE_VER := 7.2.0 -LIBSUITESPARSE_BRANCH=guard-CXX_Standard -LIBSUITESPARSE_SHA1=1b4edf467637dbf33a26eee9a6c20afa40c7c5ea +LIBSUITESPARSE_VER := 7.2.1 +LIBSUITESPARSE_SHA1=d6c84f7416eaee0d23d61c6c49ad1b73235d2ea2 diff --git a/stdlib/SparseArrays.version b/stdlib/SparseArrays.version index 91a67c5bddc9f..10357d46ab030 100644 --- a/stdlib/SparseArrays.version +++ b/stdlib/SparseArrays.version @@ -1,4 +1,4 @@ SPARSEARRAYS_BRANCH = main -SPARSEARRAYS_SHA1 = 0f8bbdac9c2d805f32faed90f4d8b8c8514aa478 +SPARSEARRAYS_SHA1 = 3582898a4efd3f504d39076f5a162b9ed1ebcdb2 SPARSEARRAYS_GIT_URL := https://github.com/JuliaSparse/SparseArrays.jl.git SPARSEARRAYS_TAR_URL = https://api.github.com/repos/JuliaSparse/SparseArrays.jl/tarball/$1 diff --git a/stdlib/SuiteSparse_jll/Project.toml b/stdlib/SuiteSparse_jll/Project.toml index 6c23952e5c6b6..ccd1d06d9a7bb 100644 --- a/stdlib/SuiteSparse_jll/Project.toml +++ b/stdlib/SuiteSparse_jll/Project.toml @@ -1,6 +1,6 @@ name = "SuiteSparse_jll" uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" -version = "7.2.0+1" +version = "7.2.1+1" [deps] libblastrampoline_jll = "8e850b90-86db-534c-a0d3-1478176c7d93" @@ -9,7 +9,7 @@ Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [compat] -julia = "1.9" +julia = "1.10" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From ab94a242f6e56438f86a1babab7721db45b7feed Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 16 Oct 2023 17:15:25 -0400 Subject: [PATCH 0011/1315] clean up identifiers defined in `Main` (#51411) Loaded packages do not need explicit bindings, and the name `MainInclude` does not need to be visible. I noticed that `Main` tab completes to `MainInclude`, which is not great since it's an implementation detail. It's also a bit messy that `InteractiveUtils` appears in `varinfo()`. This is not necessary to access its functionality. The only behavior change from this is that adding a method to `include` or `eval` in Main used to work since these were explicitly imported. This now gives the "must be explicitly imported to be extended" error, which I consider a big improvement. Nobody should be doing that anyway. --- base/client.jl | 19 +++++++------------ base/sysimg.jl | 7 +++---- stdlib/REPL/src/REPL.jl | 2 +- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/base/client.jl b/base/client.jl index 69f35d3fdd4fc..5e7cd19ea480f 100644 --- a/base/client.jl +++ b/base/client.jl @@ -261,8 +261,8 @@ function exec_options(opts) distributed_mode = (opts.worker == 1) || (opts.nprocs > 0) || (opts.machine_file != C_NULL) if distributed_mode let Distributed = require(PkgId(UUID((0x8ba89e20_285c_5b6f, 0x9357_94700520ee1b)), "Distributed")) - Core.eval(Main, :(const Distributed = $Distributed)) - Core.eval(Main, :(using .Distributed)) + Core.eval(MainInclude, :(const Distributed = $Distributed)) + Core.eval(Main, :(using Base.MainInclude.Distributed)) end invokelatest(Main.Distributed.process_opts, opts) @@ -380,19 +380,18 @@ _atreplinit(repl) = invokelatest(__atreplinit, repl) function load_InteractiveUtils(mod::Module=Main) # load interactive-only libraries - if !isdefined(mod, :InteractiveUtils) + if !isdefined(MainInclude, :InteractiveUtils) try let InteractiveUtils = require(PkgId(UUID(0xb77e0a4c_d291_57a0_90e8_8db25a27a240), "InteractiveUtils")) - Core.eval(mod, :(const InteractiveUtils = $InteractiveUtils)) - Core.eval(mod, :(using .InteractiveUtils)) - return InteractiveUtils + Core.eval(MainInclude, :(const InteractiveUtils = $InteractiveUtils)) end catch ex @warn "Failed to import InteractiveUtils into module $mod" exception=(ex, catch_backtrace()) + return nothing end - return nothing end - return getfield(mod, :InteractiveUtils) + Core.eval(mod, :(using Base.MainInclude.InteractiveUtils)) + return MainInclude.InteractiveUtils end function load_REPL() @@ -511,10 +510,6 @@ A variable referring to the last thrown errors, automatically imported to the in The thrown errors are collected in a stack of exceptions. """ global err = nothing - -# weakly exposes ans and err variables to Main -export ans, err - end """ diff --git a/base/sysimg.jl b/base/sysimg.jl index 1bdbe60479e91..bf8de0bc3f75e 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -4,10 +4,6 @@ Core.include(Main, "Base.jl") using .Base -# Set up Main module -using Base.MainInclude # ans, err, and sometimes Out -import Base.MainInclude: eval, include - # Ensure this file is also tracked pushfirst!(Base._included_files, (@__MODULE__, abspath(@__FILE__))) @@ -78,7 +74,10 @@ let empty!(LOAD_PATH) Base.init_load_path() # want to be able to find external packages in userimg.jl + # Set up Main module ccall(:jl_clear_implicit_imports, Cvoid, (Any,), Main) + eval(Main, :(using Base.MainInclude: eval, include, ans, err)) + tot_time_userimg = @elapsed (isfile("userimg.jl") && Base.include(Main, "userimg.jl")) tot_time_base = (Base.end_base_include - Base.start_base_include) * 10.0^(-9) diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 25b2ff00602d6..fe324345a3e17 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -1490,8 +1490,8 @@ function capture_result(n::Ref{Int}, @nospecialize(x)) mod = Base.MainInclude if !isdefined(mod, :Out) @eval mod global Out - @eval mod export Out setglobal!(mod, :Out, Dict{Int, Any}()) + @eval Main using Base.MainInclude: Out end if x !== getglobal(mod, :Out) && x !== nothing # remove this? getglobal(mod, :Out)[n] = x From bbcbac9752ad54faf960fa26d2f105fc8ae7771e Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Mon, 16 Oct 2023 17:16:45 -0400 Subject: [PATCH 0012/1315] support `public` in fallback/legacy parser (#51575) --- base/exports.jl | 117 +++++++++++++++++++++---------------------- src/ast.scm | 2 +- src/jlfrontend.scm | 2 +- src/julia-parser.scm | 21 ++++++-- test/syntax.jl | 23 +++++++++ 5 files changed, 99 insertions(+), 66 deletions(-) diff --git a/base/exports.jl b/base/exports.jl index de9e2b8cf1b93..81296f7d34b18 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1072,83 +1072,82 @@ export @main -# TODO: use normal syntax once JuliaSyntax.jl becomes available at this point in bootstrapping -eval(Expr(:public, +public # Modules - :Checked, - :Filesystem, - :Order, - :Sort, + Checked, + Filesystem, + Order, + Sort, # Types - :AbstractLock, - :AsyncCondition, - :CodeUnits, - :Event, - :Fix1, - :Fix2, - :Generator, - :ImmutableDict, - :OneTo, - :UUID, + AbstractLock, + AsyncCondition, + CodeUnits, + Event, + Fix1, + Fix2, + Generator, + ImmutableDict, + OneTo, + UUID, # Semaphores - :Semaphore, - :acquire, - :release, + Semaphore, + acquire, + release, # collections - :IteratorEltype, - :IteratorSize, - :to_index, - :vect, - :isdone, - :front, - :rest, - :split_rest, - :tail, - :checked_length, + IteratorEltype, + IteratorSize, + to_index, + vect, + isdone, + front, + rest, + split_rest, + tail, + checked_length, # Loading - :DL_LOAD_PATH, - :load_path, - :active_project, + DL_LOAD_PATH, + load_path, + active_project, # Reflection and introspection - :isambiguous, - :isexpr, - :isidentifier, - :issingletontype, - :identify_package, - :locate_package, - :moduleroot, - :jit_total_bytes, - :summarysize, - :isexported, - :ispublic, + isambiguous, + isexpr, + isidentifier, + issingletontype, + identify_package, + locate_package, + moduleroot, + jit_total_bytes, + summarysize, + isexported, + ispublic, # Opperators - :operator_associativity, - :operator_precedence, - :isbinaryoperator, - :isoperator, - :isunaryoperator, + operator_associativity, + operator_precedence, + isbinaryoperator, + isoperator, + isunaryoperator, # C interface - :cconvert, - :unsafe_convert, + cconvert, + unsafe_convert, # Error handling - :exit_on_sigint, - :windowserror, + exit_on_sigint, + windowserror, # Macros - Symbol("@assume_effects"), - Symbol("@constprop"), - Symbol("@locals"), - Symbol("@propagate_inbounds"), + @assume_effects, + @constprop, + @locals, + @propagate_inbounds, # misc - :notnothing, - :runtests, - :text_colors)) + notnothing, + runtests, + text_colors diff --git a/src/ast.scm b/src/ast.scm index 87db8449b3992..abfce314fc569 100644 --- a/src/ast.scm +++ b/src/ast.scm @@ -249,7 +249,7 @@ ;; misc syntax forms ((import using) (string (car e) " " (string.join (map deparse-import-path (cdr e)) ", "))) - ((global local export) (string (car e) " " (string.join (map deparse (cdr e)) ", "))) + ((global local export public) (string (car e) " " (string.join (map deparse (cdr e)) ", "))) ((const) (string "const " (deparse (cadr e)))) ((top) (deparse (cadr e))) ((core) (string "Core." (deparse (cadr e)))) diff --git a/src/jlfrontend.scm b/src/jlfrontend.scm index 23c3acf7973c7..34a8f5405676a 100644 --- a/src/jlfrontend.scm +++ b/src/jlfrontend.scm @@ -140,7 +140,7 @@ (define (toplevel-only-expr? e) (and (pair? e) - (or (memq (car e) '(toplevel line module import using export + (or (memq (car e) '(toplevel line module import using export public error incomplete)) (and (memq (car e) '(global const)) (every symbol? (cdr e)))))) diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 210ba8f0ae07b..fb20717add65d 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -716,7 +716,7 @@ ;; ";" at the top level produces a sequence of top level expressions (define (parse-stmts s) - (let ((ex (parse-Nary s (lambda (s) (parse-docstring s parse-eq)) + (let ((ex (parse-Nary s (lambda (s) (parse-public s parse-eq)) '(#\;) 'toplevel (lambda (x) (eqv? x #\newline)) #f))) ;; check for unparsed junk after an expression (let ((t (peek-token s))) @@ -1608,18 +1608,18 @@ ((module baremodule) (let* ((name (parse-unary-prefix s)) (loc (line-number-node s)) - (body (parse-block s (lambda (s) (parse-docstring s parse-eq))))) + (body (parse-block s (lambda (s) (parse-public s parse-eq))))) (if (reserved-word? name) (error (string "invalid module name \"" name "\""))) (expect-end s word) (list 'module (if (eq? word 'module) '(true) '(false)) name `(block ,loc ,@(cdr body))))) - ((export) + ((export public) (let ((es (map macrocall-to-atsym (parse-comma-separated s parse-unary-prefix)))) (if (not (every symbol-or-interpolate? es)) - (error "invalid \"export\" statement")) - `(export ,@es))) + (error (string "invalid \"" word "\" statement"))) + `(,word ,@es))) ((import using) (parse-imports s word)) ((do) @@ -2664,6 +2664,17 @@ ;; string interpolation (eq? (car e) 'string)))) +(define (parse-public s production) + (if (eq? (peek-token s) 'public) + (let ((spc (ts:space? s))) + (take-token s) + (if (memv (peek-token s) '(#\( = #\[)) + (begin ;; TODO: deprecation warning here + (ts:put-back! s 'public spc) + (parse-docstring s production)) + (parse-resword s 'public))) + (parse-docstring s production))) + (define (parse-docstring s production) (let ((startloc (line-number-node s)) ; be sure to use the line number from the head of the docstring (ex (production s))) diff --git a/test/syntax.jl b/test/syntax.jl index 17ade72112ec0..f6b66d4882021 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -3536,3 +3536,26 @@ end @test_throws ErrorException("syntax: Attempted to use slot marked unused") @eval function funused50518(::Float64) $(Symbol("#unused#")) end + +@testset "public keyword" begin + p(str) = Base.remove_linenums!(Meta.parse(str)) + # tests ported from JuliaSyntax.jl + @test p("function f(public)\n public + 3\nend") == Expr(:function, Expr(:call, :f, :public), Expr(:block, Expr(:call, :+, :public, 3))) + @test p("public A, B") == Expr(:public, :A, :B) + @test p("if true \n public *= 4 \n end") == Expr(:if, true, Expr(:block, Expr(:*=, :public, 4))) + @test p("module Mod\n public A, B \n end") == Expr(:module, true, :Mod, Expr(:block, Expr(:public, :A, :B))) + @test p("module Mod2\n a = 3; b = 6; public a, b\n end") == Expr(:module, true, :Mod2, Expr(:block, Expr(:(=), :a, 3), Expr(:(=), :b, 6), Expr(:public, :a, :b))) + @test p("a = 3; b = 6; public a, b") == Expr(:toplevel, Expr(:(=), :a, 3), Expr(:(=), :b, 6), Expr(:public, :a, :b)) + @test_throws Meta.ParseError p("begin \n public A, B \n end") + @test_throws Meta.ParseError p("if true \n public A, B \n end") + @test_throws Meta.ParseError p("public export=true foo, bar") + @test_throws Meta.ParseError p("public experimental=true foo, bar") + @test p("public(x::String) = false") == Expr(:(=), Expr(:call, :public, Expr(:(::), :x, :String)), Expr(:block, false)) + @test p("module M; export @a; end") == Expr(:module, true, :M, Expr(:block, Expr(:export, :var"@a"))) + @test p("module M; public @a; end") == Expr(:module, true, :M, Expr(:block, Expr(:public, :var"@a"))) + @test p("module M; export โคˆ; end") == Expr(:module, true, :M, Expr(:block, Expr(:export, :โคˆ))) + @test p("module M; public โคˆ; end") == Expr(:module, true, :M, Expr(:block, Expr(:public, :โคˆ))) + @test p("public = 4") == Expr(:(=), :public, 4) + @test p("public[7] = 5") == Expr(:(=), Expr(:ref, :public, 7), 5) + @test p("public() = 6") == Expr(:(=), Expr(:call, :public), Expr(:block, 6)) +end From d42415ae79613970ca366c207d478988b31332e6 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Tue, 17 Oct 2023 04:40:01 -0400 Subject: [PATCH 0013/1315] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the?= =?UTF-8?q?=20Pkg=20stdlib=20from=20b02fb9597=20to=20ffb6edf03=20(#51732)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: Pkg URL: https://github.com/JuliaLang/Pkg.jl.git Stdlib branch: master Julia branch: master Old commit: b02fb9597 New commit: ffb6edf03 Julia version: 1.11.0-DEV Pkg version: 1.11.0 Bump invoked by: @IanButterworth Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/Pkg.jl/compare/b02fb95979c71dc5834aad739ad61622cccf4a16...ffb6edf0306a651240b71641fb4aa5ab8cc7659b ``` $ git log --oneline b02fb9597..ffb6edf03 ffb6edf03 cache pidlock tweaks (#3654) 550eadd7e Pin registry for MetaGraph tests (#3666) ee39026b8 Remove test that depends on Random being in the sysimg (#3656) 561508db2 CI: Increase the CI timeout. Update actions. Fix double precompilation. (#3665) 7c7ed63b1 Remove change UUID script it should be uncessary on Julia v1.11-dev (#3655) a8648f7c8 Precompile: Fix algorithmic complexity of cycle detection (#3651) 0e0cf4514 Switch datastructure Vector -> Set for algorithmic complexity (#3652) 894cc3f78 respect if load-time precompile is disabled (#3648) 3ffd1cf73 Make auto GC message use printpkgstyle (#3633) ``` Co-authored-by: Dilum Aluthge --- .../Pkg-b02fb95979c71dc5834aad739ad61622cccf4a16.tar.gz/md5 | 1 - .../Pkg-b02fb95979c71dc5834aad739ad61622cccf4a16.tar.gz/sha512 | 1 - .../Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/md5 | 1 + .../Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-b02fb95979c71dc5834aad739ad61622cccf4a16.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-b02fb95979c71dc5834aad739ad61622cccf4a16.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/md5 create mode 100644 deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/sha512 diff --git a/deps/checksums/Pkg-b02fb95979c71dc5834aad739ad61622cccf4a16.tar.gz/md5 b/deps/checksums/Pkg-b02fb95979c71dc5834aad739ad61622cccf4a16.tar.gz/md5 deleted file mode 100644 index 141318a4aa0eb..0000000000000 --- a/deps/checksums/Pkg-b02fb95979c71dc5834aad739ad61622cccf4a16.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -540f9de36245fc3d52ff40a97b4d73d9 diff --git a/deps/checksums/Pkg-b02fb95979c71dc5834aad739ad61622cccf4a16.tar.gz/sha512 b/deps/checksums/Pkg-b02fb95979c71dc5834aad739ad61622cccf4a16.tar.gz/sha512 deleted file mode 100644 index 4b2a864ef3951..0000000000000 --- a/deps/checksums/Pkg-b02fb95979c71dc5834aad739ad61622cccf4a16.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -207d82ea9f376c30e5d8680dfaf82f3a9f8f40789313e46fcedf3f6911608be2b6e7cb63ab115eb45549413ba03e2da0d08d5fadd47ed1b46d0a544877a67ce9 diff --git a/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/md5 b/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/md5 new file mode 100644 index 0000000000000..d0689b2900b94 --- /dev/null +++ b/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/md5 @@ -0,0 +1 @@ +7debd8f3b98285c9837b6715fe2e1802 diff --git a/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/sha512 b/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/sha512 new file mode 100644 index 0000000000000..6b45b3b24cd68 --- /dev/null +++ b/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/sha512 @@ -0,0 +1 @@ +6f3b71ac68899c265d59edf3376f224f8a64b63ac0a9a08f05652789f9bc8e670365e0f0758c357b8a8bdf08a08c75c27f1d1a63d062795ae67793a686d4acfe diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index c39a6c331a37f..b5928ddf64786 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = b02fb95979c71dc5834aad739ad61622cccf4a16 +PKG_SHA1 = ffb6edf0306a651240b71641fb4aa5ab8cc7659b PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From ac7eecb24a3f7ed952ecd5274d18e9d2407c0701 Mon Sep 17 00:00:00 2001 From: Florian Date: Tue, 17 Oct 2023 12:46:23 +0200 Subject: [PATCH 0014/1315] Fix LinearAlgebra/diagonal test (#51733) --- stdlib/LinearAlgebra/test/diagonal.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/LinearAlgebra/test/diagonal.jl b/stdlib/LinearAlgebra/test/diagonal.jl index 11d506cf64bf8..1b1aa37af2d31 100644 --- a/stdlib/LinearAlgebra/test/diagonal.jl +++ b/stdlib/LinearAlgebra/test/diagonal.jl @@ -792,7 +792,7 @@ end evecs = [ [[ 1/sqrt(2)+0im, 1/sqrt(2)*im ]] [[ 1/sqrt(2)+0im, -1/sqrt(2)*im ]] [[ 0.0, 0.0 ]] [[ 0.0, 0.0 ]] [[ 0.0, 0.0]]; [[ 0.0, 0.0, 0.0 ]] [[ 0.0, 0.0, 0.0 ]] [[ 1.0, 0.0, 0.0 ]] [[ 0.0, 1.0, 0.0 ]] [[ 0.0, 0.0, 1.0]] ] @test eigD.values == evals - @test eigD.vectors == evecs + @test eigD.vectors โ‰ˆ evecs @test D * eigD.vectors โ‰ˆ eigD.vectors * Diagonal(eigD.values) end From a0f16291a6d265437cad4e3a5a674b7b52999d9d Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Tue, 17 Oct 2023 13:30:24 +0200 Subject: [PATCH 0015/1315] docs: `Base.Order.Ordering`: consistency with #48363 and #48387 (#51683) "Total order" -> "strict weak order". --- base/ordering.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/base/ordering.jl b/base/ordering.jl index 13f5eceb2d4dc..36d8e90064eba 100644 --- a/base/ordering.jl +++ b/base/ordering.jl @@ -21,7 +21,8 @@ export # not exported by Base """ Base.Order.Ordering -Abstract type which represents a total order on some set of elements. +Abstract type which represents a strict weak order on some set of elements. See +[`sort!`](@ref) for more. Use [`Base.Order.lt`](@ref) to compare two elements according to the ordering. """ From 2e54092e0ebda81422d1a8239ad6dc9a9516b0d5 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 17 Oct 2023 08:31:23 -0300 Subject: [PATCH 0016/1315] Use currently unused LLVM statistics (#51685) These variables missed being incremented --- src/jitlayers.cpp | 1 + src/llvm-simdloop.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 42239ecf2de3c..e3f30f7d22d58 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -1324,6 +1324,7 @@ namespace { } } } + ++ModulesOptimized; switch (PoolIdx) { case 0: ++OptO0; diff --git a/src/llvm-simdloop.cpp b/src/llvm-simdloop.cpp index 62fb26ac163a4..c4981c33f088d 100644 --- a/src/llvm-simdloop.cpp +++ b/src/llvm-simdloop.cpp @@ -191,7 +191,7 @@ static bool processLoop(Loop &L, OptimizationRemarkEmitter &ORE, ScalarEvolution LLVM_DEBUG(dbgs() << "LSL: simd: " << simd << " ivdep: " << ivdep << "\n"); if (!simd && !ivdep) return false; - + ++TotalMarkedLoops; LLVMContext &Context = L.getHeader()->getContext(); LoopID = MDNode::get(Context, MDs); // Set operand 0 to refer to the loop id itself From 214ac5185f5f6eb489fa6dbb0118508670f70d42 Mon Sep 17 00:00:00 2001 From: Eric Hanson <5846501+ericphanson@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:40:33 +0200 Subject: [PATCH 0017/1315] add `Printf.Format` and `Printf.format` to manual (#51723) --- stdlib/Printf/docs/src/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stdlib/Printf/docs/src/index.md b/stdlib/Printf/docs/src/index.md index 48e38e2b2ce5b..7a5bae778ea36 100644 --- a/stdlib/Printf/docs/src/index.md +++ b/stdlib/Printf/docs/src/index.md @@ -3,4 +3,6 @@ ```@docs Printf.@printf Printf.@sprintf +Printf.Format +Printf.format ``` From 66cdf15f26a0dcd1dc0c4880e6491ccb9b95796c Mon Sep 17 00:00:00 2001 From: Justin Walker <2695841+just-walk@users.noreply.github.com> Date: Tue, 17 Oct 2023 06:41:38 -0500 Subject: [PATCH 0018/1315] Add note in constructor doc about infix notation (#51610) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When reading the documentation---and later, when I was doing an Exercism example implementing the complex numbers---it wasn't clear to me how certain symbols could work as infix operators. The Julia documentation uses โŠ˜ for rational division in its example, but it doesn't say why this works for `1 โŠ˜ 2`. I just added a note to clarify this. --- doc/src/manual/constructors.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/manual/constructors.md b/doc/src/manual/constructors.md index 6ec206dade335..27e2c9396c437 100644 --- a/doc/src/manual/constructors.md +++ b/doc/src/manual/constructors.md @@ -491,6 +491,7 @@ operator, which provides a syntax for writing rationals (e.g. `1 โŠ˜ 2`). Julia' type uses the [`//`](@ref) operator for this purpose. Before these definitions, `โŠ˜` is a completely undefined operator with only syntax and no meaning. Afterwards, it behaves just as described in [Rational Numbers](@ref) -- its entire behavior is defined in these few lines. +Note that the infix use of `โŠ˜` works because Julia has a set of symbols that are recognized to be infix operators. The first and most basic definition just makes `a โŠ˜ b` construct a `OurRational` by applying the `OurRational` constructor to `a` and `b` when they are integers. When one of the operands of `โŠ˜` is already a rational number, we construct a new rational for the resulting ratio slightly differently; From 09dd7d7d0bd0e39d68acba9e2b86a84ddff02565 Mon Sep 17 00:00:00 2001 From: Benjamin Lorenz Date: Tue, 17 Oct 2023 14:44:29 +0200 Subject: [PATCH 0019/1315] REPL: remove 'oops.' for non Markdown help strings (#51734) This was added in https://github.com/JuliaLang/julia/pull/50105/files#diff-625b68d89f9d5b3eaa175971271a3cce315a0d1e0597d03c9ab0bd7a0b020648R196 --- stdlib/REPL/src/docview.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index cc3a7fe980190..84323f2072b1e 100644 --- a/stdlib/REPL/src/docview.jl +++ b/stdlib/REPL/src/docview.jl @@ -193,7 +193,6 @@ function insert_internal_warning(md::Markdown.MD, internal_access::Set{Pair{Modu md end function insert_internal_warning(other, internal_access::Set{Pair{Module,Symbol}}) - println("oops.") other end From 4d2d8490bdee8f457948b949441e95a69a775217 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 17 Oct 2023 19:03:23 +0530 Subject: [PATCH 0020/1315] Dots in displaying views of sparse/structured arrays (#51679) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this, views of sparse/structured arrays are printed with dots as well: ```julia julia> D = Diagonal(1:4) 4ร—4 Diagonal{Int64, UnitRange{Int64}}: 1 โ‹… โ‹… โ‹… โ‹… 2 โ‹… โ‹… โ‹… โ‹… 3 โ‹… โ‹… โ‹… โ‹… 4 julia> view(D, 1:3, 1:3) 3ร—3 view(::Diagonal{Int64, UnitRange{Int64}}, 1:3, 1:3) with eltype Int64: 1 โ‹… โ‹… โ‹… 2 โ‹… โ‹… โ‹… 3 julia> S = sparse([1,2,2,2,3], [1,1,2,2,4], [5, -19, 73, 12, -7]) 3ร—4 SparseMatrixCSC{Int64, Int64} with 4 stored entries: 5 โ‹… โ‹… โ‹… -19 85 โ‹… โ‹… โ‹… โ‹… โ‹… -7 julia> view(S, 1:3, 1:3) 3ร—3 view(::SparseMatrixCSC{Int64, Int64}, 1:3, 1:3) with eltype Int64: 5 โ‹… โ‹… -19 85 โ‹… โ‹… โ‹… โ‹… ``` --- base/subarray.jl | 7 +++++++ test/subarray.jl | 31 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/base/subarray.jl b/base/subarray.jl index 901410e908d1e..57014d5c86856 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -494,3 +494,10 @@ function _indices_sub(i1::AbstractArray, I...) end has_offset_axes(S::SubArray) = has_offset_axes(S.indices...) + +function replace_in_print_matrix(S::SubArray{<:Any,2,<:AbstractMatrix}, i::Integer, j::Integer, s::AbstractString) + replace_in_print_matrix(S.parent, reindex(S.indices, (i,j))..., s) +end +function replace_in_print_matrix(S::SubArray{<:Any,1,<:AbstractVector}, i::Integer, j::Integer, s::AbstractString) + replace_in_print_matrix(S.parent, reindex(S.indices, (i,))..., j, s) +end diff --git a/test/subarray.jl b/test/subarray.jl index 1137c265fa126..442e6f485f5b1 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -769,3 +769,34 @@ end @test view(m, 1:2, 3, 1, 1) == m[1:2, 3] @test parent(view(m, 1:2, 3, 1, 1)) === m end + +@testset "replace_in_print_matrix" begin + struct MyIdentity <: AbstractMatrix{Bool} + n :: Int + end + Base.size(M::MyIdentity) = (M.n, M.n) + function Base.getindex(M::MyIdentity, i::Int, j::Int) + checkbounds(M, i, j) + i == j + end + function Base.replace_in_print_matrix(M::MyIdentity, i::Integer, j::Integer, s::AbstractString) + i == j ? s : Base.replace_with_centered_mark(s) + end + V = view(MyIdentity(3), 1:2, 1:3) + @test sprint(show, "text/plain", V) == "$(summary(V)):\n 1 โ‹… โ‹…\n โ‹… 1 โ‹…" + + struct OneElVec <: AbstractVector{Bool} + n :: Int + ind :: Int + end + Base.size(M::OneElVec) = (M.n,) + function Base.getindex(M::OneElVec, i::Int) + checkbounds(M, i) + i == M.ind + end + function Base.replace_in_print_matrix(M::OneElVec, i::Integer, j::Integer, s::AbstractString) + i == M.ind ? s : Base.replace_with_centered_mark(s) + end + V = view(OneElVec(6, 2), 1:5) + @test sprint(show, "text/plain", V) == "$(summary(V)):\n โ‹…\n 1\n โ‹…\n โ‹…\n โ‹…" +end From 86cbb604f853acef34b84416735e1c2640a45d4e Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 18 Oct 2023 06:19:01 +0900 Subject: [PATCH 0021/1315] inference: use `jl_method_get_table` for `get_nospecializeinfer_sig` (#51735) This allows `@nospecializeinfer` to be functional for `@overlay`ed methods, making it more aligned with `get_compileable_sig` too. --- base/compiler/utilities.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index 78079e6174f29..bce430b055bed 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -164,7 +164,7 @@ end function get_nospecializeinfer_sig(method::Method, @nospecialize(atype), sparams::SimpleVector) isa(atype, DataType) || return method.sig - mt = ccall(:jl_method_table_for, Any, (Any,), atype) + mt = ccall(:jl_method_get_table, Any, (Any,), method) mt === nothing && return method.sig return ccall(:jl_normalize_to_compilable_sig, Any, (Any, Any, Any, Any, Cint), mt, atype, sparams, method, #=int return_if_compileable=#0) From 0b31e8b9e9c9093e88cc6610765cfccb21cde499 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 18 Oct 2023 17:56:27 +0900 Subject: [PATCH 0022/1315] EA: allow tests to run for out-of-tree build (#51752) --- test/compiler/EscapeAnalysis/EscapeAnalysis.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/compiler/EscapeAnalysis/EscapeAnalysis.jl b/test/compiler/EscapeAnalysis/EscapeAnalysis.jl index b598388a3d138..04729ab818420 100644 --- a/test/compiler/EscapeAnalysis/EscapeAnalysis.jl +++ b/test/compiler/EscapeAnalysis/EscapeAnalysis.jl @@ -1,6 +1,6 @@ module test_EA -const use_core_compiler = false +const use_core_compiler = true if use_core_compiler const EscapeAnalysis = Core.Compiler.EscapeAnalysis From e36f65f0f66c1306574f7ec577479bf381fa088c Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 18 Oct 2023 09:54:22 -0400 Subject: [PATCH 0023/1315] codegen: fix gc rooting bug (#51744) ccall was not creating roots for the contents of struct values which contained roots on the stack, as expected to align with `GC.@preserve`, and causing many segfaults for #51319 --- src/ccall.cpp | 2 +- src/cgutils.cpp | 30 +++++++++++++++++++++--------- src/codegen.cpp | 20 ++++++++------------ test/compiler/codegen.jl | 6 +++--- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index fafb71efaf52d..9eb672e3047fb 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -1393,7 +1393,7 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) if (jl_is_long(argi_root)) continue; jl_cgval_t arg_root = emit_expr(ctx, argi_root); - Value *gc_root = get_gc_root_for(arg_root); + Value *gc_root = get_gc_root_for(ctx, arg_root); if (gc_root) gc_uses.push_back(gc_root); } diff --git a/src/cgutils.cpp b/src/cgutils.cpp index f086c7fd0b0bd..c71c78da4c829 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -314,19 +314,34 @@ static Value *emit_pointer_from_objref(jl_codectx_t &ctx, Value *V) return Call; } -static Value *get_gc_root_for(const jl_cgval_t &x) +static Value *emit_unbox(jl_codectx_t &ctx, Type *to, const jl_cgval_t &x, jl_value_t *jt); +static void emit_unbox_store(jl_codectx_t &ctx, const jl_cgval_t &x, Value* dest, MDNode *tbaa_dest, unsigned alignment, bool isVolatile=false); + +static Value *get_gc_root_for(jl_codectx_t &ctx, const jl_cgval_t &x) { - if (x.Vboxed) + if (x.constant || x.typ == jl_bottom_type) + return nullptr; + if (x.Vboxed) // superset of x.isboxed return x.Vboxed; - if (x.ispointer() && !x.constant) { + assert(!x.isboxed); +#ifndef NDEBUG + if (x.ispointer()) { assert(x.V); if (PointerType *T = dyn_cast(x.V->getType())) { - if (T->getAddressSpace() == AddressSpace::Tracked || - T->getAddressSpace() == AddressSpace::Derived) { - return x.V; + assert(T->getAddressSpace() != AddressSpace::Tracked); + if (T->getAddressSpace() == AddressSpace::Derived) { + // n.b. this IR would not be valid after LLVM-level inlining, + // since codegen does not have a way to determine the whether + // this argument value needs to be re-rooted } } } +#endif + if (jl_is_concrete_immutable(x.typ) && !jl_is_pointerfree(x.typ)) { + Type *T = julia_type_to_llvm(ctx, x.typ); + return emit_unbox(ctx, T, x, x.typ); + } + // nothing here to root, move along return nullptr; } @@ -1786,9 +1801,6 @@ static Value *emit_bounds_check(jl_codectx_t &ctx, const jl_cgval_t &ainfo, jl_v return im1; } -static Value *emit_unbox(jl_codectx_t &ctx, Type *to, const jl_cgval_t &x, jl_value_t *jt); -static void emit_unbox_store(jl_codectx_t &ctx, const jl_cgval_t &x, Value* dest, MDNode *tbaa_dest, unsigned alignment, bool isVolatile=false); - static void emit_write_barrier(jl_codectx_t&, Value*, ArrayRef); static void emit_write_barrier(jl_codectx_t&, Value*, Value*); static void emit_write_multibarrier(jl_codectx_t&, Value*, Value*, jl_value_t*); diff --git a/src/codegen.cpp b/src/codegen.cpp index 33730ad9cf74b..e37de75b7c5bc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3064,9 +3064,12 @@ static Value *emit_bits_compare(jl_codectx_t &ctx, jl_cgval_t arg1, jl_cgval_t a varg2 = emit_pointer_from_objref(ctx, varg2); Value *gc_uses[2]; int nroots = 0; - if ((gc_uses[nroots] = get_gc_root_for(arg1))) + // these roots may seem a bit overkill, but we want to make sure + // that a!=b implies (a,)!=(b,) even if a and b are unused and + // therefore could be freed and then the memory for a reused for b + if ((gc_uses[nroots] = get_gc_root_for(ctx, arg1))) nroots++; - if ((gc_uses[nroots] = get_gc_root_for(arg2))) + if ((gc_uses[nroots] = get_gc_root_for(ctx, arg2))) nroots++; OperandBundleDef OpBundle("jl_roots", makeArrayRef(gc_uses, nroots)); auto answer = ctx.builder.CreateCall(prepare_call(memcmp_func), { @@ -5863,16 +5866,9 @@ static jl_cgval_t emit_expr(jl_codectx_t &ctx, jl_value_t *expr, ssize_t ssaidx_ } SmallVector vals; for (size_t i = 0; i < nargs; ++i) { - const jl_cgval_t &ai = argv[i]; - if (ai.constant || ai.typ == jl_bottom_type) - continue; - if (ai.isboxed) { - vals.push_back(ai.Vboxed); - } - else if (jl_is_concrete_immutable(ai.typ) && !jl_is_pointerfree(ai.typ)) { - Type *at = julia_type_to_llvm(ctx, ai.typ); - vals.push_back(emit_unbox(ctx, at, ai, ai.typ)); - } + Value *gc_root = get_gc_root_for(ctx, argv[i]); + if (gc_root) + vals.push_back(gc_root); } Value *token = vals.empty() ? (Value*)ConstantTokenNone::get(ctx.builder.getContext()) diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index bb0592c86c654..3b517201ce67d 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -581,13 +581,13 @@ end end @test occursin("llvm.julia.gc_preserve_begin", get_llvm(f3, Tuple{Bool}, true, false, false)) - # unions of immutables (JuliaLang/julia#39501) + # PhiNode of unions of immutables (JuliaLang/julia#39501) function f2(cond) - val = cond ? 1 : 1f0 + val = cond ? 1 : "" GC.@preserve val begin end return cond end - @test !occursin("llvm.julia.gc_preserve_begin", get_llvm(f2, Tuple{Bool}, true, false, false)) + @test occursin("llvm.julia.gc_preserve_begin", get_llvm(f2, Tuple{Bool}, true, false, false)) # make sure the fix for the above doesn't regress #34241 function f4(cond) val = cond ? ([1],) : ([1f0],) From 3cc4fdc7a11b99a253fb1d4b1b420bb52ac95b69 Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:05:54 -0400 Subject: [PATCH 0024/1315] =?UTF-8?q?=F0=9F=A4=96=20[master]=20Bump=20the?= =?UTF-8?q?=20Pkg=20stdlib=20from=20ffb6edf03=20to=20af5392db5=20(#51749)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stdlib: Pkg URL: https://github.com/JuliaLang/Pkg.jl.git Stdlib branch: master Julia branch: master Old commit: ffb6edf03 New commit: af5392db5 Julia version: 1.11.0-DEV Pkg version: 1.11.0 Bump invoked by: @DilumAluthge Powered by: [BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl) Diff: https://github.com/JuliaLang/Pkg.jl/compare/ffb6edf0306a651240b71641fb4aa5ab8cc7659b...af5392db53e1a45aa31bd93b507e163fc0205893 ``` $ git log --oneline ffb6edf03..af5392db5 af5392db5 Precompilation workload: restore the original depot and load paths (#3668) b39ba05f3 Precompilation workload: set `"JULIA_PKG_UNPACK_REGISTRY" => nothing` (#3662) ``` Co-authored-by: Dilum Aluthge --- .../Pkg-af5392db53e1a45aa31bd93b507e163fc0205893.tar.gz/md5 | 1 + .../Pkg-af5392db53e1a45aa31bd93b507e163fc0205893.tar.gz/sha512 | 1 + .../Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/md5 | 1 - .../Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/sha512 | 1 - stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 deps/checksums/Pkg-af5392db53e1a45aa31bd93b507e163fc0205893.tar.gz/md5 create mode 100644 deps/checksums/Pkg-af5392db53e1a45aa31bd93b507e163fc0205893.tar.gz/sha512 delete mode 100644 deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/sha512 diff --git a/deps/checksums/Pkg-af5392db53e1a45aa31bd93b507e163fc0205893.tar.gz/md5 b/deps/checksums/Pkg-af5392db53e1a45aa31bd93b507e163fc0205893.tar.gz/md5 new file mode 100644 index 0000000000000..b10919c082900 --- /dev/null +++ b/deps/checksums/Pkg-af5392db53e1a45aa31bd93b507e163fc0205893.tar.gz/md5 @@ -0,0 +1 @@ +65413e890729029a25b147ffc242a23f diff --git a/deps/checksums/Pkg-af5392db53e1a45aa31bd93b507e163fc0205893.tar.gz/sha512 b/deps/checksums/Pkg-af5392db53e1a45aa31bd93b507e163fc0205893.tar.gz/sha512 new file mode 100644 index 0000000000000..20ee4dcd235d8 --- /dev/null +++ b/deps/checksums/Pkg-af5392db53e1a45aa31bd93b507e163fc0205893.tar.gz/sha512 @@ -0,0 +1 @@ +f8ddfd14a1f1124a08cb8334ab58caf9f628e561b4523ea6e27880da191f359fa1e5c46db09cf8ad0c62736b241085b448314e6af243a34df3901b85fc8fe89f diff --git a/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/md5 b/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/md5 deleted file mode 100644 index d0689b2900b94..0000000000000 --- a/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -7debd8f3b98285c9837b6715fe2e1802 diff --git a/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/sha512 b/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/sha512 deleted file mode 100644 index 6b45b3b24cd68..0000000000000 --- a/deps/checksums/Pkg-ffb6edf0306a651240b71641fb4aa5ab8cc7659b.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -6f3b71ac68899c265d59edf3376f224f8a64b63ac0a9a08f05652789f9bc8e670365e0f0758c357b8a8bdf08a08c75c27f1d1a63d062795ae67793a686d4acfe diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index b5928ddf64786..1d900ed01c9f0 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,4 +1,4 @@ PKG_BRANCH = master -PKG_SHA1 = ffb6edf0306a651240b71641fb4aa5ab8cc7659b +PKG_SHA1 = af5392db53e1a45aa31bd93b507e163fc0205893 PKG_GIT_URL := https://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 From 101e475645df961c904ef5ed9995fb3268e468d5 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Wed, 18 Oct 2023 15:57:05 -0400 Subject: [PATCH 0025/1315] ignore mightalias for empty objects (#51761) There is no bytes that overlap, so it is safe to use these without needing to make an explicit copy of nothing. --- base/abstractarray.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 0171c38bc9c0b..f2329478fbe74 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1507,7 +1507,7 @@ Perform a conservative test to check if arrays `A` and `B` might share the same By default, this simply checks if either of the arrays reference the same memory regions, as identified by their [`Base.dataids`](@ref). """ -mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !_isdisjoint(dataids(A), dataids(B)) +mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !isempty(A) && !isempty(B) && !_isdisjoint(dataids(A), dataids(B)) mightalias(x, y) = false _isdisjoint(as::Tuple{}, bs::Tuple{}) = true From 8a889ffcd235ac75720205b0cd7446c9b66eb664 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 18 Oct 2023 16:32:39 -0400 Subject: [PATCH 0026/1315] limit TimeType subtraction (#51743) Disallow some type combinations that don't make sense. --------- Co-authored-by: Ben Baumgold <4933671+baumgold@users.noreply.github.com> --- stdlib/Dates/src/arithmetic.jl | 6 ++++-- stdlib/Dates/test/arithmetic.jl | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/stdlib/Dates/src/arithmetic.jl b/stdlib/Dates/src/arithmetic.jl index a847f749d0154..23a76f5ed75d6 100644 --- a/stdlib/Dates/src/arithmetic.jl +++ b/stdlib/Dates/src/arithmetic.jl @@ -6,8 +6,10 @@ # TimeType arithmetic (+)(x::TimeType) = x -(-)(x::T, y::T) where {T<:TimeType} = x.instant - y.instant -(-)(x::TimeType, y::TimeType) = -(promote(x, y)...) +(-)(x::Date, y::Date) = x.instant - y.instant +(-)(x::Time, y::Time) = x.instant - y.instant +(-)(x::DateTime, y::DateTime) = x.instant - y.instant +(-)(x::AbstractDateTime, y::AbstractDateTime) = -(promote(x, y)...) # Date-Time arithmetic """ diff --git a/stdlib/Dates/test/arithmetic.jl b/stdlib/Dates/test/arithmetic.jl index 110eea6d00235..129e9a60bf490 100644 --- a/stdlib/Dates/test/arithmetic.jl +++ b/stdlib/Dates/test/arithmetic.jl @@ -12,9 +12,7 @@ using Dates end @testset "TimeType arithmetic" begin - a = Date(2023, 5, 1) - b = DateTime(2023, 5, 2) - @test b - a == Day(1) + @test_throws MethodError DateTime(2023, 5, 2) - Date(2023, 5, 1) end @testset "Wrapping arithmetic for Months" begin From 47d5c021539d4d3bd305d7104b40720217022827 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Thu, 19 Oct 2023 01:34:31 -0400 Subject: [PATCH 0027/1315] Fix inlining logic for :invoke exprs (#51766) This code path isn't currently used in Base, but is reached in external abstract interpreters and wasn't correctly handling ConstantCase returns from `resolve_todo`. --- base/compiler/ssair/inlining.jl | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index 0a5b5c6580595..ed46c4aafbdbf 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -1008,8 +1008,12 @@ function handle_single_case!(todo::Vector{Pair{Int,Any}}, elseif isa(case, InvokeCase) is_foldable_nothrow(case.effects) && inline_const_if_inlineable!(ir[SSAValue(idx)]) && return nothing isinvoke && rewrite_invoke_exprargs!(stmt) - stmt.head = :invoke - pushfirst!(stmt.args, case.invoke) + if stmt.head === :invoke + stmt.args[1] = case.invoke + else + stmt.head = :invoke + pushfirst!(stmt.args, case.invoke) + end ir[SSAValue(idx)][:flag] |= flags_for_effects(case.effects) elseif case === nothing # Do, well, nothing @@ -1643,13 +1647,11 @@ function handle_finalizer_call!(ir::IRCode, idx::Int, stmt::Expr, info::Finalize return nothing end -function handle_invoke_expr!(todo::Vector{Pair{Int,Any}}, +function handle_invoke_expr!(todo::Vector{Pair{Int,Any}}, ir::IRCode, idx::Int, stmt::Expr, @nospecialize(info::CallInfo), flag::UInt32, sig::Signature, state::InliningState) mi = stmt.args[1]::MethodInstance case = resolve_todo(mi, sig.argtypes, info, flag, state) - if case !== nothing - push!(todo, idx=>(case::InliningTodo)) - end + handle_single_case!(todo, ir, idx, stmt, case, false) return nothing end @@ -1677,7 +1679,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState) # `NativeInterpreter` won't need this, but provide a support for `:invoke` exprs here # for external `AbstractInterpreter`s that may run the inlining pass multiple times if isexpr(stmt, :invoke) - handle_invoke_expr!(todo, idx, stmt, info, flag, sig, state) + handle_invoke_expr!(todo, ir, idx, stmt, info, flag, sig, state) continue end From 4ef353c6e4ad5156ad65cb40c3a2a61fbd324b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= Date: Thu, 19 Oct 2023 09:37:16 +0100 Subject: [PATCH 0028/1315] Put mingw32 `*.a` files in `private_libdir` (#51698) This avoid that these files are picked up during julia's build process, and are instead only used to link pkgimages, as intended. Co-authored-by: Tim Besard --- Make.inc | 2 +- Makefile | 9 +- base/linking.jl | 6 +- deps/checksums/compilersupportlibraries | 184 +++++++++--------- deps/csl.mk | 16 ++ .../CompilerSupportLibraries_jll/Project.toml | 4 +- 6 files changed, 117 insertions(+), 104 deletions(-) diff --git a/Make.inc b/Make.inc index 0f170734127ed..8d5aa5ce86dfe 100644 --- a/Make.inc +++ b/Make.inc @@ -1248,7 +1248,7 @@ LIBGFORTRAN_VERSION := $(subst libgfortran,,$(filter libgfortran%,$(subst -,$(SP # shipped with CSL. Although we do not depend on any of the symbols, it is entirely # possible that a user might choose to install a library which depends on symbols provided # by a newer libstdc++. Without runtime detection, those libraries would break. -CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.31|GLIBCXX_3\.5\.|GLIBCXX_4\. +CSL_NEXT_GLIBCXX_VERSION=GLIBCXX_3\.4\.33|GLIBCXX_3\.5\.|GLIBCXX_4\. # This is the set of projects that BinaryBuilder dependencies are hooked up for. diff --git a/Makefile b/Makefile index d205a4cf8deb8..68a316b0a32ae 100644 --- a/Makefile +++ b/Makefile @@ -288,16 +288,13 @@ else ifeq ($(JULIA_BUILD_MODE),debug) -$(INSTALL_M) $(build_libdir)/libjulia-debug.dll.a $(DESTDIR)$(libdir)/ -$(INSTALL_M) $(build_libdir)/libjulia-internal-debug.dll.a $(DESTDIR)$(libdir)/ endif + -$(INSTALL_M) $(wildcard $(build_private_libdir)/*.a) $(DESTDIR)$(private_libdir)/ - # We have a single exception; we want 7z.dll to live in private_libexecdir, not bindir, so that 7z.exe can find it. + # We have a single exception; we want 7z.dll to live in private_libexecdir, + # not bindir, so that 7z.exe can find it. -mv $(DESTDIR)$(bindir)/7z.dll $(DESTDIR)$(private_libexecdir)/ -$(INSTALL_M) $(build_bindir)/libopenlibm.dll.a $(DESTDIR)$(libdir)/ -$(INSTALL_M) $(build_libdir)/libssp.dll.a $(DESTDIR)$(libdir)/ - # The rest are compiler dependencies, as an example memcpy is exported by msvcrt - # These are files from mingw32 and required for creating shared libraries like our caches. - -$(INSTALL_M) $(build_libdir)/libgcc_s.a $(DESTDIR)$(libdir)/ - -$(INSTALL_M) $(build_libdir)/libgcc.a $(DESTDIR)$(libdir)/ - -$(INSTALL_M) $(build_libdir)/libmsvcrt.a $(DESTDIR)$(libdir)/ else # Copy over .dSYM directories directly for Darwin diff --git a/base/linking.jl b/base/linking.jl index fd21ce74c9268..2d68ea730c0fb 100644 --- a/base/linking.jl +++ b/base/linking.jl @@ -150,16 +150,16 @@ else end function link_image_cmd(path, out) - LIBDIR = "-L$(libdir())" PRIVATE_LIBDIR = "-L$(private_libdir())" SHLIBDIR = "-L$(shlibdir())" - LIBS = is_debug() ? ("-ljulia-debug", "-ljulia-internal-debug") : ("-ljulia", "-ljulia-internal") + LIBS = is_debug() ? ("-ljulia-debug", "-ljulia-internal-debug") : + ("-ljulia", "-ljulia-internal") @static if Sys.iswindows() LIBS = (LIBS..., "-lopenlibm", "-lssp", "-lgcc_s", "-lgcc", "-lmsvcrt") end V = VERBOSE[] ? "--verbose" : "" - `$(ld()) $V $SHARED -o $out $WHOLE_ARCHIVE $path $NO_WHOLE_ARCHIVE $LIBDIR $PRIVATE_LIBDIR $SHLIBDIR $LIBS` + `$(ld()) $V $SHARED -o $out $WHOLE_ARCHIVE $path $NO_WHOLE_ARCHIVE $PRIVATE_LIBDIR $SHLIBDIR $LIBS` end function link_image(path, out, internal_stderr::IO=stderr, internal_stdout::IO=stdout) diff --git a/deps/checksums/compilersupportlibraries b/deps/checksums/compilersupportlibraries index 0908c34e13a58..2dcfecfb56b26 100644 --- a/deps/checksums/compilersupportlibraries +++ b/deps/checksums/compilersupportlibraries @@ -1,92 +1,92 @@ -CompilerSupportLibraries.v1.0.5+1.aarch64-apple-darwin-libgfortran5.tar.gz/md5/20ebaad57850393b6ac9fa924e511fe4 -CompilerSupportLibraries.v1.0.5+1.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/020de4d8b0ff6bedbadaa305ff8445e6849f12053762ea4aa68412d1ec763dbd86f479587a2fbb862487f1feb04d976c38099ddf3887817a3d32b3f029cf85b1 -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-gnu-libgfortran3.tar.gz/md5/3908fa1a2f739b330e787468c9bfb5c8 -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/1741e3403ac7aa99e7cfd9a01222c4153ed300f47cc1b347e1af1a6cd07a82caaa54b9cfbebae8751440420551621cc6524504413446d104f9493dff2c081853 -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-gnu-libgfortran4.tar.gz/md5/2444dbb7637b32cf543675cc12330878 -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/8537f0b243df8544350c884021b21c585fd302e8dd462a30a6ee84c7a36a049133262e5d1bc362f972066b8e8d6a091c32c3b746bab1feb9fccf2e7cca65756c -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-gnu-libgfortran5.tar.gz/md5/d79c1434594c0c5e7d6be798bf52c99e -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/7e71accc401a45b51b298702fb4c79a2fc856c7b28f0935f6ad3a0db5381c55fe5432daff371842930d718024b7c6c1d80e2bd09d397145203673bebbe3496ae -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-musl-libgfortran3.tar.gz/md5/f212059053d99558a9b0bf54b20180e1 -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-musl-libgfortran3.tar.gz/sha512/5c104b1282cec8a944e5d008f44a4d60f4394fd5d797fec7d1f487d13e7328cd9c88ec4916dabf18596d87160756bda914e4f8c5a356b5577f9349d0d9e976d6 -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-musl-libgfortran4.tar.gz/md5/3e3b3795ee93ef317223050e803a9875 -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-musl-libgfortran4.tar.gz/sha512/85d3c955e15f66bfe8bfec2f28c9160bc03d4d531ea4ffe6bc6b51e0d69ccea3ab67a16ca752dabc870861c407381c4519d75c6be3832e8dccd6122ec8c6ed75 -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-musl-libgfortran5.tar.gz/md5/cf2d1315f6a348af2e6c065e2a286e7a -CompilerSupportLibraries.v1.0.5+1.aarch64-linux-musl-libgfortran5.tar.gz/sha512/58420377bc77aa7678034ee5f708eb6be7db359faef2c2638869765453633da9bf455512bd88e95b38ae0428ecc4053561517b176b2371129bdaef9d8d5dadfd -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/f5c09ed7e0eeb8d345d328f950582f26 -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/9c657f55c8fcdeb404be168a3a63a5e84304730fe34f25673d92cdae4b0a1fcc6a877ee1433f060e1be854c7811d66632e32510a2ed591d88330f1340b9c20de -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/c685518aca4721cd8621d510e2039683 -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/b760468c6377dcd2b8dd50200daaabe604006afc070984d78152b2becd0680b59036c9a6e91dea490121bd85b58d285bfc1e1cf696d29af236528400101de36c -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/8faf5c8ad62ab10f71dd2ec9683053e2 -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/921239f241a5c89710cf07272d7f6c3f10201a7533068ed1e9643f9fb2f439e1bb765a4966d913829866ee0ce4f1589d30d06e4b5c1361e3c016a9473f087177 -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/b38fcb70691ac2621379d298eef8c79e -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/06c7f64257ce721f5941f6e50a0d2717cdc9394fc532ded19ce3eaacd5e92a416969534227562e4fee04d2b6340c650d8bc9779e14519b90038bc41e8d1f5ce3 -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/cdfab2c7bc41765caf4441c3caeed761 -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/7109d4a7b32c00309c42685f54a86fc2cc63c0c00f65584ad296b6e44ad3320eed1aaf49684a8831841cdffa5555d72f89272fb722a780596e27ef020528026b -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/441980ebd23d72772cbe603f1c275336 -CompilerSupportLibraries.v1.0.5+1.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/e273d9f1af259a3080df8f173e1808a1ade976a943aba97216bf59a96178e7c052e7a048b0ceee53ab486ed577a2ecb92579857be2f7b29e76322ee1f13c9d76 -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/f5c09ed7e0eeb8d345d328f950582f26 -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/9c657f55c8fcdeb404be168a3a63a5e84304730fe34f25673d92cdae4b0a1fcc6a877ee1433f060e1be854c7811d66632e32510a2ed591d88330f1340b9c20de -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/c685518aca4721cd8621d510e2039683 -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/b760468c6377dcd2b8dd50200daaabe604006afc070984d78152b2becd0680b59036c9a6e91dea490121bd85b58d285bfc1e1cf696d29af236528400101de36c -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/8faf5c8ad62ab10f71dd2ec9683053e2 -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/921239f241a5c89710cf07272d7f6c3f10201a7533068ed1e9643f9fb2f439e1bb765a4966d913829866ee0ce4f1589d30d06e4b5c1361e3c016a9473f087177 -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/b38fcb70691ac2621379d298eef8c79e -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/06c7f64257ce721f5941f6e50a0d2717cdc9394fc532ded19ce3eaacd5e92a416969534227562e4fee04d2b6340c650d8bc9779e14519b90038bc41e8d1f5ce3 -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/cdfab2c7bc41765caf4441c3caeed761 -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/7109d4a7b32c00309c42685f54a86fc2cc63c0c00f65584ad296b6e44ad3320eed1aaf49684a8831841cdffa5555d72f89272fb722a780596e27ef020528026b -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/441980ebd23d72772cbe603f1c275336 -CompilerSupportLibraries.v1.0.5+1.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/e273d9f1af259a3080df8f173e1808a1ade976a943aba97216bf59a96178e7c052e7a048b0ceee53ab486ed577a2ecb92579857be2f7b29e76322ee1f13c9d76 -CompilerSupportLibraries.v1.0.5+1.i686-linux-gnu-libgfortran3.tar.gz/md5/6decf8fd5afb50451771c761e63a8917 -CompilerSupportLibraries.v1.0.5+1.i686-linux-gnu-libgfortran3.tar.gz/sha512/4984724bcc847724b1bc005b6f760a18b68147f7d5402d0faf4e28fc0d14fa10975368a951f9caf2a8856500046dec8343043274557d58269e77492b929a9e4b -CompilerSupportLibraries.v1.0.5+1.i686-linux-gnu-libgfortran4.tar.gz/md5/39d1e8a3baa144c018d3eaf7f3806482 -CompilerSupportLibraries.v1.0.5+1.i686-linux-gnu-libgfortran4.tar.gz/sha512/fc4d429279c5a93b6c28b6e911b1e7cfd1c1cfe46f11f2e901b3832ce90d45f49d3d29f0ef18518a94af6cc8651f67c4ed81672680f9281ada390440b172a2af -CompilerSupportLibraries.v1.0.5+1.i686-linux-gnu-libgfortran5.tar.gz/md5/37dabd9cd224c9fed9633dedccb6c565 -CompilerSupportLibraries.v1.0.5+1.i686-linux-gnu-libgfortran5.tar.gz/sha512/b253149e72eef9486888fbaace66e9b6945f4477f6b818f64f3047331165b0e2bc17aa6e3fc8c88686a72e478eb62c8f53883415d5419db448d8016fa3a1da5e -CompilerSupportLibraries.v1.0.5+1.i686-linux-musl-libgfortran3.tar.gz/md5/afdd32bfadd465848e6be458817a44ae -CompilerSupportLibraries.v1.0.5+1.i686-linux-musl-libgfortran3.tar.gz/sha512/eebd679c499143014514c7c9d1875dedbbab9e3af51526c4dd445a9e3dbade95d24522da8bbad0a50ab400755e47b018828b324c4ad7705e212ccd990e34439a -CompilerSupportLibraries.v1.0.5+1.i686-linux-musl-libgfortran4.tar.gz/md5/bc4a0f0b7cea328f7e8850583774496b -CompilerSupportLibraries.v1.0.5+1.i686-linux-musl-libgfortran4.tar.gz/sha512/82285b67946212b49cddf6259f2c60ff5469f8c5263ccefe44f1d93ace98ab68e2c152e1b54434b2f075fd8d192c06d5451bc8cca26d951ad15f3453102f02b5 -CompilerSupportLibraries.v1.0.5+1.i686-linux-musl-libgfortran5.tar.gz/md5/177f0232abce8d523882530ed7a93092 -CompilerSupportLibraries.v1.0.5+1.i686-linux-musl-libgfortran5.tar.gz/sha512/db80acf0f2434f28ee7680e1beb34f564940071815d1ad89fb5913cbd9ac24da528e826d0d54be6265a7340ebd661b6d308ed79d96b67fa5d8c98dc3f1bee8d6 -CompilerSupportLibraries.v1.0.5+1.i686-w64-mingw32-libgfortran3.tar.gz/md5/f5795dada5360eb8422f45150b13bae9 -CompilerSupportLibraries.v1.0.5+1.i686-w64-mingw32-libgfortran3.tar.gz/sha512/6acd1bf7c81631cef9b8b0576ccece08723c5ae2f49de2487d3aefd25f9a0ad49df09e3782735267997d40687b04b85c89e00f6889b026af599bf1bbe91803a1 -CompilerSupportLibraries.v1.0.5+1.i686-w64-mingw32-libgfortran4.tar.gz/md5/5e590f83161913f0145ba8d496b2504b -CompilerSupportLibraries.v1.0.5+1.i686-w64-mingw32-libgfortran4.tar.gz/sha512/4a3f36588afcdef26173764597054068e26f2376e6126a9a94c46b258b5d7a29951d47b5e1ba24df6c3d139bbc4decc5c501a266811692d7fadadc7bd7b6960d -CompilerSupportLibraries.v1.0.5+1.i686-w64-mingw32-libgfortran5.tar.gz/md5/27da4a7c890fe1427c33fe214cc5feaf -CompilerSupportLibraries.v1.0.5+1.i686-w64-mingw32-libgfortran5.tar.gz/sha512/310ad00f053f9f3ec715ce2e8d20446f397728dff5acc787ea9c9332346607a3d42b678099c424e6d6e5294acddf2aa26051de657b48d34abfd04486951bf241 -CompilerSupportLibraries.v1.0.5+1.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/4e5e4b23dc87450738da33926a07511d -CompilerSupportLibraries.v1.0.5+1.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/fc09879d94b750e75775d8b64a41ab9924d675fb53c5700467604412928fe7f5cb21911da0f64898d2463fa77ffbaf4c96c397b9060f4746eec152747930cddc -CompilerSupportLibraries.v1.0.5+1.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/9a92138ed69aa317a932a615c6e62d69 -CompilerSupportLibraries.v1.0.5+1.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/0b7785379936a2a209b074177b1424dd7e00b29b5165f564e799b0aa4e06a582e9d616525d97274ba2507cb88192028f1ac485d3f99bdc7ee53fc63c1a7e85de -CompilerSupportLibraries.v1.0.5+1.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/8ffee3d6de5197c7a1f354d72c8238fa -CompilerSupportLibraries.v1.0.5+1.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/deadc4d7224c84f9b82dc956b69e815c44ae036802838365d870ab9f58c8bcf8ce0645f2f387c8ff344ac2108fc8e7e1ee907fa55e93c91aa5d9fd921bf3fdcb -CompilerSupportLibraries.v1.0.5+1.x86_64-apple-darwin-libgfortran3.tar.gz/md5/87449e72e3f33dbb69b7053cdc2649d4 -CompilerSupportLibraries.v1.0.5+1.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/5ce02ad10c6f4686a476eb2a5de2988cd8b482f5e693db2880c84ad1c82f468ef03fe01b9d0feefe5d4ee741d1d16643d36b144e6261ed32311b3b6f312fac2f -CompilerSupportLibraries.v1.0.5+1.x86_64-apple-darwin-libgfortran4.tar.gz/md5/0407cde92cfa42fa89ac83217ca0ec16 -CompilerSupportLibraries.v1.0.5+1.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/032c831f1166a336551138939ac40eb2c68a048ce786c0c1403b879a20c1b706caac16d22560b2c7f2b3d6373986c347188675674116005ca251336ee048d09f -CompilerSupportLibraries.v1.0.5+1.x86_64-apple-darwin-libgfortran5.tar.gz/md5/23418763b808371ee94772a90d501f4d -CompilerSupportLibraries.v1.0.5+1.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/7867b843551457b11bda7821dd384c1c1cf23b80a308b2058a693de7b7da099f0b37eb0a6de2b84c04b625a68c60eea55138e200d5d6ec6f6af09bd7ce406a96 -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-gnu-libgfortran3.tar.gz/md5/e3d33ae03c18affea74699bdc1fabb68 -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/42013f4921de5a69ad857195ce5c19ad1bca3c920d79699e5501f1f4534ab132fabd422362b2b5056f5d182215d6c069db5df460bafa700903faf962cc00f77b -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-gnu-libgfortran4.tar.gz/md5/d40c1e8c0393213c6057c53a12f44175 -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/fe7baa4de7490065ab7b953cc12f41462a24bcb49d0a4a64b23249e98e7569b19bb1cb455af2f76090e34066a7d3cdd7a48cae6515ce6c7a5c8486b0cacc5106 -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-gnu-libgfortran5.tar.gz/md5/48541b90f715c4c86ee4da0570275947 -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/7f2683fb98e80f12629f4ed3bea9fd59d32b7e7a9ed1699e782d8e238ff0915ecc61bf00adaf4597cfe41caf82cdca0f9be250f595f5f0bea6d8f77dba99eaf4 -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-musl-libgfortran3.tar.gz/md5/4547059eb905995667be48bf85d49911 -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-musl-libgfortran3.tar.gz/sha512/7400fdabc924434ab4a4949248c3603887ac06ffd2f205ae33e14495d86cd4f816bbd1999eeafa0257f518df1e7f7c522f596e847a71dbfbfccff4859f50acc7 -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-musl-libgfortran4.tar.gz/md5/46267543cad6584d7b7b9fcc8f18f21d -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-musl-libgfortran4.tar.gz/sha512/0353d7d724be48d4185d3c181692970b7996f53f6a01723072aa5c94b53a8c5055faeed30df51659c252a46f4b941dec0cb24569323e3c85c166f14c5b7c8e9e -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-musl-libgfortran5.tar.gz/md5/14dba2897a6e9d370fa9091c045375fc -CompilerSupportLibraries.v1.0.5+1.x86_64-linux-musl-libgfortran5.tar.gz/sha512/10b79f9c059839f5b57fa8d2a381a034c4067262c4088bd354d14ea56bec097878069383aa9cfadaa09d73bd20fc348fb61662d863a8d62cb25d7af6b8e29858 -CompilerSupportLibraries.v1.0.5+1.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/1f069e9c832fa1e9c7c8d51e3e841f5c -CompilerSupportLibraries.v1.0.5+1.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/877ed9953bc167ade224fc503a2b639c7c333d420804ccf0d3b1637e29bdaf8c608a8f7accb3ec7983d6881c4b00729a1327a121c741022aff1e627cdffb52ce -CompilerSupportLibraries.v1.0.5+1.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/3e542990ca4192dcecf2e8b8b17e8580 -CompilerSupportLibraries.v1.0.5+1.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/0b9cf0f431a5de28bc11af31d965beaf6774d4e83cb3877fdca630d0327312eb966485d6a99d62b0212f505a6714c23fc7ac1ed17ec619baff13941f6ce7519c -CompilerSupportLibraries.v1.0.5+1.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/b09302632fda815a1248884a82a6f95a -CompilerSupportLibraries.v1.0.5+1.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/7a64ae14e40d285bbcd27a0f54ba6ad0a108ee4f4fed7c99d3a876a70578445e0c7108fa945f3f5a0b202cf95e533b96eedaf7641ded6e9869af77db98075709 -CompilerSupportLibraries.v1.0.5+1.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/0c2fc6fae4ebe293a7f0dc1e91f6531a -CompilerSupportLibraries.v1.0.5+1.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/fdb0ad061cacad0557fde3ec216fd3666284f24ad6a86f4a4b6f946dccb112c9704f52edba86f3b17d84c824affbcfef740720348ef227380cf6017811bda80b -CompilerSupportLibraries.v1.0.5+1.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/005e608dbef2b5cdb7624702ccc426be -CompilerSupportLibraries.v1.0.5+1.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/8bb2bcd0a6b1901e8a9be20f505bead5c78ecafbe5a8271cd13385553e5744e0c7bff62976ac9e7d74b8f3bd467603d4c0f5658e6b120bb23066c15e0a644ed4 -CompilerSupportLibraries.v1.0.5+1.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/d6c2c7ad72bff7f7e5c43678d716a57a -CompilerSupportLibraries.v1.0.5+1.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/36f5eba1b0be440797467cb7104652b74709913d2bad1b08ee2dc70f450fb8eab81b28f2b0bc8dfc238b3c46982c69aac831b4fad5bcee4e9dd114852fcb4a0b +CompilerSupportLibraries.v1.1.0+0.aarch64-apple-darwin-libgfortran5.tar.gz/md5/20ebaad57850393b6ac9fa924e511fe4 +CompilerSupportLibraries.v1.1.0+0.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/020de4d8b0ff6bedbadaa305ff8445e6849f12053762ea4aa68412d1ec763dbd86f479587a2fbb862487f1feb04d976c38099ddf3887817a3d32b3f029cf85b1 +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-gnu-libgfortran3.tar.gz/md5/e084a4374be45ba52279682c640449bc +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/d4aedf5c08e13fd9596476330f69e374af64373f7bca0e4df6cbb4d1710d695dce23f2655ee368c3df2049b7b0ca1848c9e01a437fadc0eb08937c6a7cdf2a27 +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-gnu-libgfortran4.tar.gz/md5/6b3975f25be16ea1370ef0bf353ac752 +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/d6298517be1ce350a61d1c1a1bf9b27a541382aa8ccf3e86eeadd7c47e2fe88facd17139a3878adb939df869a330264a942d280e3468d53b61325df7e31daaad +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-gnu-libgfortran5.tar.gz/md5/7134b79b71059d4da79224df1ca0853e +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/e66590a37e756ff33a84514a7ca2bbe2e1517f3e901bc66e40139e8a318d6cd8e329e0c2a7c557ea39e6db2f56802d485ab81b87be1373717b78474b1c7bf7d7 +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-musl-libgfortran3.tar.gz/md5/fd37789f5745a17cc9a85902cebf4698 +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-musl-libgfortran3.tar.gz/sha512/9ff4e9be39f115af2e5bb6a5c88b3940f15a010952cebf39da22e7a5c6744be2f905bebccba092db0a89cf82e8c0e1a3e61b74d4204d2a6648b5469f3ccb0d12 +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-musl-libgfortran4.tar.gz/md5/e9286ae9299c57d5df7b795997b4adf5 +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-musl-libgfortran4.tar.gz/sha512/ea64858481095e0374be330aa2ac84b394bc3e5351b9326137c9cd5d15e6bec47d6e5f672a216572dcb80c3aa6fcb08950cc10157c264f429a93c235028d79a4 +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-musl-libgfortran5.tar.gz/md5/b19c6cbc5b2a62ea76dea64b0f8ae488 +CompilerSupportLibraries.v1.1.0+0.aarch64-linux-musl-libgfortran5.tar.gz/sha512/090d659f7e4a7034117e2bb2dcad0ef544cdca898bf032222cdb81d32af6e6528be842d2cf55839fe397c2ace05dd4ce920cf98cc96324ae18832016516e6cc3 +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/26fb41031e1b797373aea7a7c4d7be3c +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/8fd0b6c990681789caec528067b4bcb9661f9c0a5e0268927d4e88565fa7005db3b592fb8e7830cf32b3fb4ce54d6db747dfde896f93bd38f65b7a1290a2399a +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/6ed3f3e94f662177c3cf3c3734a5c1ec +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/b8165630cced0f7880cb6fd6263cf39bbbbda668eccc94219720078a85a641c3b1b20648960041aa3a51108ab6df087b909c572d0690aacf8b99dc5496ff7db6 +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/86060cbbe966a59f18f92a9b2fab95d4 +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/0aa0ca0ff3a4d541c7a9599ca1adae7391fdd3fa841f3055ecb8635096d0d95a0763758d7533c887b38a655af55174dfcb63f470147b28a256b75a85c8e47801 +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/4acf6f8929fb8ec9fdb8a0f1af06260d +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/3b2e0a5f62bd93434d07848c3045479a1a05bd8589dc976a5680e13805db5adcd9abdcca82edee7b28b4c4a9413ce795784a8a0f0a8fb7346a439322c27c96d9 +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/a75a927c3e14bee6dca29b4907def681 +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/7853fd187f9289a8282d34112b5277bad13abe9dd9b6c796498db2f1a080b2c81faa6119df9ececd09725a019bf99706894765c9c20f618e359adc153c3181a2 +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/ba8545cc20e6c602a0526a3b1fc1d2f1 +CompilerSupportLibraries.v1.1.0+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/7a7f3a7761deb068efc00ffc5d4bf4df365cb27674ce73abbe2305b678285161f1526f4facbe27fc11076d99b2079976507f78f5b463bd9057ed008e9d52f9cf +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/26fb41031e1b797373aea7a7c4d7be3c +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/8fd0b6c990681789caec528067b4bcb9661f9c0a5e0268927d4e88565fa7005db3b592fb8e7830cf32b3fb4ce54d6db747dfde896f93bd38f65b7a1290a2399a +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/6ed3f3e94f662177c3cf3c3734a5c1ec +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/b8165630cced0f7880cb6fd6263cf39bbbbda668eccc94219720078a85a641c3b1b20648960041aa3a51108ab6df087b909c572d0690aacf8b99dc5496ff7db6 +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/86060cbbe966a59f18f92a9b2fab95d4 +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/0aa0ca0ff3a4d541c7a9599ca1adae7391fdd3fa841f3055ecb8635096d0d95a0763758d7533c887b38a655af55174dfcb63f470147b28a256b75a85c8e47801 +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/4acf6f8929fb8ec9fdb8a0f1af06260d +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/3b2e0a5f62bd93434d07848c3045479a1a05bd8589dc976a5680e13805db5adcd9abdcca82edee7b28b4c4a9413ce795784a8a0f0a8fb7346a439322c27c96d9 +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/a75a927c3e14bee6dca29b4907def681 +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/7853fd187f9289a8282d34112b5277bad13abe9dd9b6c796498db2f1a080b2c81faa6119df9ececd09725a019bf99706894765c9c20f618e359adc153c3181a2 +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/ba8545cc20e6c602a0526a3b1fc1d2f1 +CompilerSupportLibraries.v1.1.0+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/7a7f3a7761deb068efc00ffc5d4bf4df365cb27674ce73abbe2305b678285161f1526f4facbe27fc11076d99b2079976507f78f5b463bd9057ed008e9d52f9cf +CompilerSupportLibraries.v1.1.0+0.i686-linux-gnu-libgfortran3.tar.gz/md5/39dc387fd58ef02c461c7906ceb110e3 +CompilerSupportLibraries.v1.1.0+0.i686-linux-gnu-libgfortran3.tar.gz/sha512/1296ac707fdad620c65256686523f2b027c8359f54d1f8354ef5d1ba514992c7269aad26b706575509b5e29d0ad3dec1c7d32fe3bcff0d723d6a4890819eca46 +CompilerSupportLibraries.v1.1.0+0.i686-linux-gnu-libgfortran4.tar.gz/md5/21a76d54d875ef09db2cdce77d328c2e +CompilerSupportLibraries.v1.1.0+0.i686-linux-gnu-libgfortran4.tar.gz/sha512/9c6bf15338ffbc7113c536e145e53bfaa693007b971f83ee2db820d7d54018bd1cfdbedb6bbce000ee7aaadad1561e91f5ac0e0519bbfccbc3bc57fdfc0eb7e7 +CompilerSupportLibraries.v1.1.0+0.i686-linux-gnu-libgfortran5.tar.gz/md5/f028f2c94f28201701ef6ba4fec9abc9 +CompilerSupportLibraries.v1.1.0+0.i686-linux-gnu-libgfortran5.tar.gz/sha512/c231af1bb0fd4f733278f883837fddf574689bbd7c4dd46cfcd1478d784cbeae1fd785d7cf9f4b0f98cda08819b63a20d5026c6beb892a188fc979b7893697bc +CompilerSupportLibraries.v1.1.0+0.i686-linux-musl-libgfortran3.tar.gz/md5/184436dc05207a653f13aae3d82a2e1b +CompilerSupportLibraries.v1.1.0+0.i686-linux-musl-libgfortran3.tar.gz/sha512/b6e1f969528a168de087f472eebd23a4daf907aa48f7c5b42c35960b1cae3e6ca8f512982d69b757f39d6dc07b46f74c84e549cb22354a2f55d1265cba7b7013 +CompilerSupportLibraries.v1.1.0+0.i686-linux-musl-libgfortran4.tar.gz/md5/545bee22cb35d1c4c1381009e72eebca +CompilerSupportLibraries.v1.1.0+0.i686-linux-musl-libgfortran4.tar.gz/sha512/78a65b9e7cda79cd648a1ae09daea970eba9d04fd5ea41bc1e37b065cf5c53974f759590292876f57c7f65139be66a6c381aa6756cdda7b36845cfed1bb7fddc +CompilerSupportLibraries.v1.1.0+0.i686-linux-musl-libgfortran5.tar.gz/md5/3f1a08601a6a7bbd4ecfa36c8f6abbd9 +CompilerSupportLibraries.v1.1.0+0.i686-linux-musl-libgfortran5.tar.gz/sha512/0e225e0a7b651f6b3fbccf760d08d66f2d8af1e329d14ef67fd3968a46905e062edcf75f60d7540f0cd7dabcd3ac9130fa0f63e198869bdc6a9aabd391652805 +CompilerSupportLibraries.v1.1.0+0.i686-w64-mingw32-libgfortran3.tar.gz/md5/9cfea65fa6c1b587d9b4b84ee64af166 +CompilerSupportLibraries.v1.1.0+0.i686-w64-mingw32-libgfortran3.tar.gz/sha512/b30e24982d4140c312759b8c26d4b72845fc1fa4d7fdf49ccfe9994f7bbf1815ed006a228f6a2185c5b8f9d596d0b04debd1d8392e705c530e5177a22c7c081d +CompilerSupportLibraries.v1.1.0+0.i686-w64-mingw32-libgfortran4.tar.gz/md5/af99905c4f054fe13842559f7201b3ad +CompilerSupportLibraries.v1.1.0+0.i686-w64-mingw32-libgfortran4.tar.gz/sha512/96513ff22dc16cc259ad392862f1765218474bff24e561f14c1e0d349a6bc433952d9b7b73236b56722fd971e0b864b178d8a9f8d9499de4595bc9857ef17a95 +CompilerSupportLibraries.v1.1.0+0.i686-w64-mingw32-libgfortran5.tar.gz/md5/1be078cd374d3b501b20d9ce679009ee +CompilerSupportLibraries.v1.1.0+0.i686-w64-mingw32-libgfortran5.tar.gz/sha512/63097283c987dc439f02d72a6f70423acd962e4da25acc04185e654c7f16a617e34ad7efabd624fd2e70119e79e4d4806f76286d36d56c353f9e53814e75d3e4 +CompilerSupportLibraries.v1.1.0+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/156ae44ab4172903ad40932ca78a57ed +CompilerSupportLibraries.v1.1.0+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/e800c20342dd9886c4c3f57e92278d6d41c544adba202ef3f5a6a4f8211fbbd8fab65f169adf7320b7be8a2ea02c0aa1afedbaf0b3f9afbfb691759aaaaccc4c +CompilerSupportLibraries.v1.1.0+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/cb01c02fdcbd319784034744172e1eb9 +CompilerSupportLibraries.v1.1.0+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/0ba635d39958672a0a55069521e20ca6c0f9c81a9f55c360f6043acb415709edb72bfe8d0e83c25cdf9ace8a9e9ba10e39457e234e3905c988eb95e0e0ecff3d +CompilerSupportLibraries.v1.1.0+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/f9592263c6e72228c492ed2ed216f29e +CompilerSupportLibraries.v1.1.0+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/cbe29742959906e3fe9a356991ca1f09d4d8cc2a02a9af8624b3e02b4ab59e33bc05082826f7c67c73c6b91cc8e1e5c4a0c275c21c5f8eab8b58ed942cdcb55c +CompilerSupportLibraries.v1.1.0+0.x86_64-apple-darwin-libgfortran3.tar.gz/md5/8f0db2ff4688c3f9e1337a28976d833a +CompilerSupportLibraries.v1.1.0+0.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/98502e07499ad9e22147a977b1fe55320e75b6229c3993f1cd1b71e47a09ae6bf78e2341ce978ea72d33b111d09b813a332bfe8f4f6dfb669509c300fcec2561 +CompilerSupportLibraries.v1.1.0+0.x86_64-apple-darwin-libgfortran4.tar.gz/md5/980a1b8e6262c4a7b8f86b84f7234043 +CompilerSupportLibraries.v1.1.0+0.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/c0755d4fbb1b6fd7755d7508d7df929feabe7e5778661397ef0205e21aa3be565b39ccc2a08ed0d958e812c0c759be68ef52de09fe92ebab6da342b309a0810d +CompilerSupportLibraries.v1.1.0+0.x86_64-apple-darwin-libgfortran5.tar.gz/md5/4b3cdb65e6114c77fd1e51da69e41afa +CompilerSupportLibraries.v1.1.0+0.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/803cb771875d94eda554bade8197b31aab988ab0c957a2f8853d82d01418be9fee7d9d4b7ef6f5b7fc8d1825ab22083a71d467eb976d5076fc5d73a9a7a30440 +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-gnu-libgfortran3.tar.gz/md5/36638a444b185954bf12169edace1914 +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/33f657775258d0da1a57fc03c5e8ed203946944581ebf70af7b0205f9bff7fcd4f2bde5b6fa3b01659c51f106d0e6df5c7533ab8d3372c4895675854688e01dc +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-gnu-libgfortran4.tar.gz/md5/36ac52a361fd0f4be5c66572345af7a4 +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/802bd8089bb2a3b5959a47dbade2199b46c247d0a793cbf6fcbc97b9a1dccd6d8585ac7694ae4bef1dc3ba21796ae5b53f995c8793ccd7316e8fde68ac121f83 +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-gnu-libgfortran5.tar.gz/md5/5911da90a0fc86d665aa86cba12e9d61 +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/c966936dfd272d9706aa51ed44abcb8cded899b0caa8b12ee787a0fb1569fa90a1cba89c9a9b83e05c0993facc615feb851399f4799c06956ae3064d172c964d +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-musl-libgfortran3.tar.gz/md5/5f42a52e72f0e79530d71733a93811bf +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-musl-libgfortran3.tar.gz/sha512/51078ef0e447bb181003a50b899b39a9d1ee8ecc92fc293f5a358d836ddf21d03dc44433ae28aa21fdf756c2912b2d3f1e374a5ba108c8c34552fcf32f93fd0b +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-musl-libgfortran4.tar.gz/md5/f3bbee1114cb85c266a45f64632c6911 +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-musl-libgfortran4.tar.gz/sha512/102e638f49ff0f62644f15a931c71a16b96f02f4c90d1b8bd378e0d7c54f4e8a150cdb5ffdbc3dcbafb83131bef84f9071cb77e8debdd98d8929c7b65401fc54 +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-musl-libgfortran5.tar.gz/md5/ff2b0ebdc7ef83cf8b48bd2ae76c6430 +CompilerSupportLibraries.v1.1.0+0.x86_64-linux-musl-libgfortran5.tar.gz/sha512/0730ecf1b9476612cadc3f3e7c1b227a1967edc091c88cd0cc19477079d1739fd5e7b1022ff686c0c6a2404edaebfb02c810dcfc1aa4187e7ecddb54998ad96c +CompilerSupportLibraries.v1.1.0+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/35642304a9a2f435cf5214b2715198fe +CompilerSupportLibraries.v1.1.0+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/a67f41ba31c99a064f504f508711537f9e90089ca5352bfc2698c3fcd3e499ca716f07ffeac4fb1b88c2c934f7f380f262af8c863d3b16ac7e805d5c805ab358 +CompilerSupportLibraries.v1.1.0+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/01df0fbb265e5ff1a480a7a5e23b0835 +CompilerSupportLibraries.v1.1.0+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/57a79f2b8e846c1514dcb18420f26ae2889962040f410b746836cab4395749155fa9cd9d00d4c25954c0ffa72f9f3823b1b50688a20ddf675301f64e0d4b5c7e +CompilerSupportLibraries.v1.1.0+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/1f1f6380ce8815cc9cedcea0b40860e7 +CompilerSupportLibraries.v1.1.0+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/a88ea8af8c8df792861812bfdf7f1bcaae31582ab78ce78b47a0dc6fd57b93441c0471f529ce23877131ac9701c6eed72ce89241746e18271f3686fbd718138c +CompilerSupportLibraries.v1.1.0+0.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/5eab740e86bfa7656f6a08038fe2fa63 +CompilerSupportLibraries.v1.1.0+0.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/3dc6b7ec39ff7dcb71478376c86ce34a35a62f049f6203722c5414b7b635ff1b412e02d8d24c13c123d18b2e914780da4639538676694e342a1a6b507691ef25 +CompilerSupportLibraries.v1.1.0+0.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/9718c79244ed31c367e715f1f563b8cd +CompilerSupportLibraries.v1.1.0+0.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/eec2380c4e182f4e923142736a2c4aaf11a525a5f966fed7e4ec4b431ee28f3842a4e73495df116604f74b419e6d398576ee3dd21d3c0c53b92167dcfd0f6b84 +CompilerSupportLibraries.v1.1.0+0.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/58d7b0b79a22f3aade7e4f39eec898e7 +CompilerSupportLibraries.v1.1.0+0.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/efecc0ca09ec6b7b8898c2ffd333c7e0a6a44706d72ac0e5010409aba92ee70a88b6fd77434bedafe0e013561f8d0c74b5a274808a6c9499f6a3005a7691785f diff --git a/deps/csl.mk b/deps/csl.mk index 37956ba5c3505..aaebc8f50c053 100644 --- a/deps/csl.mk +++ b/deps/csl.mk @@ -104,4 +104,20 @@ distclean-csl: clean-csl else $(eval $(call bb-install,csl,CSL,true)) +ifeq ($(OS),WINNT) +install-csl: + mkdir -p $(build_private_libdir)/ + cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/13/libgcc_s.a $(build_private_libdir)/ + cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/13/libgcc.a $(build_private_libdir)/ + cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/13/libmsvcrt.a $(build_private_libdir)/ + cp -a $(build_libdir)/gcc/$(BB_TRIPLET)/13/libssp.dll.a $(build_private_libdir)/ +endif +endif +ifeq ($(OS),WINNT) +uninstall-csl: uninstall-gcc-libraries +uninstall-gcc-libraries: + -rm -f $(build_private_libdir)/libgcc_s.a + -rm -f $(build_private_libdir)/libgcc.a + -rm -f $(build_private_libdir)/libmsvcrt.a + -rm -f $(build_private_libdir)/libssp.dll.a endif diff --git a/stdlib/CompilerSupportLibraries_jll/Project.toml b/stdlib/CompilerSupportLibraries_jll/Project.toml index 6256c69d9bc10..3e15ff6b87b71 100644 --- a/stdlib/CompilerSupportLibraries_jll/Project.toml +++ b/stdlib/CompilerSupportLibraries_jll/Project.toml @@ -2,9 +2,9 @@ name = "CompilerSupportLibraries_jll" uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" # NOTE: When updating this, also make sure to update the value -# `CSL_NEXT_GLIBCXX_VERSION` in `deps/csl.mk`, to properly disable +# `CSL_NEXT_GLIBCXX_VERSION` in `Make.inc`, to properly disable # automatic usage of BB-built CSLs on extremely up-to-date systems! -version = "1.0.5+1" +version = "1.1.0+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" From 86305e3423b33ac80f186090a838d5ce22a01075 Mon Sep 17 00:00:00 2001 From: Ian Butterworth Date: Thu, 19 Oct 2023 10:38:01 -0400 Subject: [PATCH 0029/1315] allow more module declaration formats in module check (#51689) --- base/loading.jl | 4 ++-- test/loading.jl | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/base/loading.jl b/base/loading.jl index 4eca0ea0e1200..25fe8144b71d6 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2252,7 +2252,7 @@ end Checks that a package entry file `srcpath` has a module declaration, and that it is before any using/import statements. """ function check_src_module_wrap(pkg::PkgId, srcpath::String) - module_rgx = r"^\s*(?:@\w*\s*)*(?:bare)?module\s" + module_rgx = r"^(|end |\"\"\" )\s*(?:@)*(?:bare)?module\s" load_rgx = r"\b(?:using|import)\s" load_seen = false inside_string = false @@ -2262,7 +2262,7 @@ function check_src_module_wrap(pkg::PkgId, srcpath::String) inside_string = !inside_string end inside_string && continue - if startswith(s, module_rgx) + if contains(s, module_rgx) if load_seen throw(ErrorException("Package $pkg source file $srcpath has a using/import before a module declaration.")) end diff --git a/test/loading.jl b/test/loading.jl index d7e967f209eaa..0ee3e3985cc84 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -1223,8 +1223,18 @@ end @test Base.check_src_module_wrap(p, fpath) write(fpath, """ - # using foo - module Foo + \"\"\" + Foo + \"\"\" module Foo + using Bar + end + """) + @test Base.check_src_module_wrap(p, fpath) + + write(fpath, """ + @doc let x = 1 + x + end module Foo using Bar end """) From cd8298400ff12c3a8b77d4eeb9415c9336c7305b Mon Sep 17 00:00:00 2001 From: Simeon Schaub Date: Thu, 19 Oct 2023 17:12:15 +0200 Subject: [PATCH 0030/1315] fix `--bug-report=rr` (#51750) This option is currently broken on nightly due to world age errors --- base/client.jl | 2 +- test/cmdlineargs.jl | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/base/client.jl b/base/client.jl index 5e7cd19ea480f..d66933e27e4d1 100644 --- a/base/client.jl +++ b/base/client.jl @@ -246,7 +246,7 @@ function exec_options(opts) # If we're doing a bug report, don't load anything else. We will # spawn a child in which to execute these options. let InteractiveUtils = load_InteractiveUtils() - InteractiveUtils.report_bug(arg) + invokelatest(InteractiveUtils.report_bug, arg) end return nothing else diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 95d65de0c01f2..fc6016da960c4 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -994,3 +994,9 @@ end # 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 --bug-report=rr +if Sys.islinux() && Sys.ARCH in (:i686, :x86_64, :aarch64) # rr is only available on these platforms + # TODO: get this to work on CI + @test_skip success(setenv(`$(Base.julia_cmd()) --bug-report=rr-local -e 'exit()'`, "JULIA_RR_RECORD_ARGS" => "-n")) +end From d432821e0b869cae47e59d2541eee1243ee75630 Mon Sep 17 00:00:00 2001 From: Simeon Schaub Date: Fri, 20 Oct 2023 02:16:42 +0200 Subject: [PATCH 0031/1315] fix return type of `exec_options` (#51787) Should fix the failures observed in JuliaLang/BugReporting.jl#141. Test for this is in #51776 which depends on afromentioned PR which depends on this fix. --- base/client.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/client.jl b/base/client.jl index d66933e27e4d1..7339bf0870990 100644 --- a/base/client.jl +++ b/base/client.jl @@ -248,7 +248,7 @@ function exec_options(opts) let InteractiveUtils = load_InteractiveUtils() invokelatest(InteractiveUtils.report_bug, arg) end - return nothing + return false else @warn "Unexpected command -$cmd'$arg'" end From f2df1b41b85843120a9715449eb5ff555a4a172d Mon Sep 17 00:00:00 2001 From: Florian Date: Fri, 20 Oct 2023 02:56:22 +0200 Subject: [PATCH 0032/1315] Make precompile files relocatable (#49866) String replacement with `@depot` when serializing out happens with any paths that are located inside a `DEPOT_PATH` (first match wins). If no match, then we emit the absolute file path as before. Right now we only emit one token `@depot`. String replacement of `@depot` when loading happens now on a `.ji` file basis and only if all the listed include dependencies can be resolved to files located in one and the same depot on `DEPOT_PATH` (again, first match wins). If we can't resolve, then the cache is invalided with `stale_cachefile`. --- base/loading.jl | 200 ++++++++++++------ base/sysimg.jl | 5 +- doc/src/manual/modules.md | 10 +- src/precompile.c | 34 ++- src/staticdata.c | 5 +- src/staticdata_utils.c | 26 ++- test/.gitignore | 2 + test/Makefile | 26 ++- test/RelocationTestPkg1/Project.toml | 4 + .../src/RelocationTestPkg1.jl | 5 + test/RelocationTestPkg1/src/foo.txt | 0 test/RelocationTestPkg2/Project.toml | 4 + .../src/RelocationTestPkg2.jl | 6 + test/RelocationTestPkg2/src/foo.txt | 0 test/choosetests.jl | 2 +- test/precompile.jl | 16 +- test/relocatedepot.jl | 104 +++++++++ test/testenv.jl | 2 + 18 files changed, 360 insertions(+), 91 deletions(-) create mode 100644 test/RelocationTestPkg1/Project.toml create mode 100644 test/RelocationTestPkg1/src/RelocationTestPkg1.jl create mode 100644 test/RelocationTestPkg1/src/foo.txt create mode 100644 test/RelocationTestPkg2/Project.toml create mode 100644 test/RelocationTestPkg2/src/RelocationTestPkg2.jl create mode 100644 test/RelocationTestPkg2/src/foo.txt create mode 100644 test/relocatedepot.jl diff --git a/base/loading.jl b/base/loading.jl index 25fe8144b71d6..1f6bb5442540a 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -371,7 +371,7 @@ its `PkgId`, or `nothing` if it cannot be found. If only the `name` argument is provided, it searches each environment in the stack and its named direct dependencies. -There `where` argument provides the context from where to search for the +The `where` argument provides the context from where to search for the package: in this case it first checks if the name matches the context itself, otherwise it searches all recursive dependencies (from the resolved manifest of each environment) until it locates the context `where`, and from there @@ -1503,7 +1503,7 @@ function _tryrequire_from_serialized(pkg::PkgId, path::String, ocachepath::Union io = open(path, "r") try iszero(isvalid_cache_header(io)) && return ArgumentError("Invalid header in cache file $path.") - _, _, depmodnames, _, _, _, clone_targets, _ = parse_cache_header(io) + _, _, depmodnames, _, _, _, clone_targets, _ = parse_cache_header(io, path) pkgimage = !isempty(clone_targets) if pkgimage ocachepath !== nothing || return ArgumentError("Expected ocachepath to be provided") @@ -1660,9 +1660,9 @@ const include_callbacks = Any[] # used to optionally track dependencies when requiring a module: const _concrete_dependencies = Pair{PkgId,UInt128}[] # these dependency versions are "set in stone", and the process should try to avoid invalidating them -const _require_dependencies = Any[] # a list of (mod, path, mtime) tuples that are the file dependencies of the module currently being precompiled +const _require_dependencies = Any[] # a list of (mod, abspath, fsize, hash, mtime) tuples that are the file dependencies of the module currently being precompiled const _track_dependencies = Ref(false) # set this to true to track the list of file dependencies -function _include_dependency(mod::Module, _path::AbstractString) +function _include_dependency(mod::Module, _path::AbstractString; track_content=true) prev = source_path(nothing) if prev === nothing path = abspath(_path) @@ -1671,7 +1671,15 @@ function _include_dependency(mod::Module, _path::AbstractString) end if _track_dependencies[] @lock require_lock begin - push!(_require_dependencies, (mod, path, mtime(path))) + if track_content + @assert isfile(path) "can only hash files" + # use mtime=-1.0 here so that fsize==0 && mtime==0.0 corresponds to a missing include_dependency + push!(_require_dependencies, + (mod, path, filesize(path), open(_crc32c, path, "r"), -1.0)) + else + push!(_require_dependencies, + (mod, path, UInt64(0), UInt32(0), mtime(path))) + end end end return path, prev @@ -1688,7 +1696,7 @@ This is only needed if your module depends on a path that is not used via [`incl no effect outside of compilation. """ function include_dependency(path::AbstractString) - _include_dependency(Main, path) + _include_dependency(Main, path, track_content=false) return nothing end @@ -1787,7 +1795,8 @@ function __require(into::Module, mod::Symbol) end uuidkey, env = uuidkey_env if _track_dependencies[] - push!(_require_dependencies, (into, binpack(uuidkey), 0.0)) + path = binpack(uuidkey) + push!(_require_dependencies, (into, path, UInt64(0), UInt32(0), 0.0)) end return _require_prelocked(uuidkey, env) finally @@ -2580,14 +2589,46 @@ function isvalid_pkgimage_crc(f::IOStream, ocachefile::String) expected_crc_so == crc_so end -struct CacheHeaderIncludes - id::PkgId +mutable struct CacheHeaderIncludes + const id::PkgId filename::String - mtime::Float64 - modpath::Vector{String} # seemingly not needed in Base, but used by Revise + const fsize::UInt64 + const hash::UInt32 + const mtime::Float64 + const modpath::Vector{String} # seemingly not needed in Base, but used by Revise +end + +function replace_depot_path(path::AbstractString) + for depot in DEPOT_PATH + if startswith(path, depot) + path = replace(path, depot => "@depot") + break + end + end + return path +end + +# Find depot in DEPOT_PATH for which all @depot tags from the `includes` +# can be replaced so that they point to a file on disk each. +# Return nothing when no depot matched. +function resolve_depot(includes) + if any(includes) do inc + !startswith(inc, "@depot") + end + return :missing_depot_tag + end + for depot in DEPOT_PATH + if all(includes) do inc + isfile(replace(inc, r"^@depot" => depot)) + end + return depot + end + end + return :no_depot_found end -function parse_cache_header(f::IO) + +function parse_cache_header(f::IO, cachefile::AbstractString) flags = read(f, UInt8) modules = Vector{Pair{PkgId, UInt64}}() while true @@ -2598,7 +2639,7 @@ function parse_cache_header(f::IO) build_id = read(f, UInt64) # build UUID (mostly just a timestamp) push!(modules, PkgId(uuid, sym) => build_id) end - totbytes = read(f, Int64) # total bytes for file dependencies + preferences + totbytes = Int64(read(f, UInt64)) # total bytes for file dependencies + preferences # read the list of requirements # and split the list into include and requires statements includes = CacheHeaderIncludes[] @@ -2611,6 +2652,10 @@ function parse_cache_header(f::IO) end depname = String(read(f, n2)) totbytes -= n2 + fsize = read(f, UInt64) + totbytes -= 8 + hash = read(f, UInt32) + totbytes -= 4 mtime = read(f, Float64) totbytes -= 8 n1 = read(f, Int32) @@ -2633,7 +2678,7 @@ function parse_cache_header(f::IO) if depname[1] == '\0' push!(requires, modkey => binunpack(depname)) else - push!(includes, CacheHeaderIncludes(modkey, depname, mtime, modpath)) + push!(includes, CacheHeaderIncludes(modkey, depname, fsize, hash, mtime, modpath)) end end prefs = String[] @@ -2665,69 +2710,90 @@ function parse_cache_header(f::IO) l = read(f, Int32) clone_targets = read(f, l) - return modules, (includes, requires), required_modules, srctextpos, prefs, prefs_hash, clone_targets, flags + # determine path for @depot replacement from srctext files only, e.g. ignore any include_dependency files + srcfiles = srctext_files(f, srctextpos, includes) + depot = resolve_depot(srcfiles) + keepidx = Int[] + for (i, chi) in enumerate(includes) + chi.filename โˆˆ srcfiles && push!(keepidx, i) + end + if depot === :no_depot_found + throw(ArgumentError(""" + Failed to determine depot from srctext files in cache file $cachefile. + - Make sure you have adjusted DEPOT_PATH in case you relocated depots.""")) + elseif depot === :missing_depot_tag + @debug "Missing @depot tag for include dependencies in cache file $cachefile." + else + for inc in includes + inc.filename = replace(inc.filename, r"^@depot" => depot) + end + end + includes_srcfiles_only = includes[keepidx] + + return modules, (includes, includes_srcfiles_only, requires), required_modules, srctextpos, prefs, prefs_hash, clone_targets, flags end -function parse_cache_header(cachefile::String; srcfiles_only::Bool=false) +function parse_cache_header(cachefile::String) io = open(cachefile, "r") try iszero(isvalid_cache_header(io)) && throw(ArgumentError("Invalid header in cache file $cachefile.")) - ret = parse_cache_header(io) - srcfiles_only || return ret - _, (includes, _), _, srctextpos, _... = ret - srcfiles = srctext_files(io, srctextpos) - delidx = Int[] - for (i, chi) in enumerate(includes) - chi.filename โˆˆ srcfiles || push!(delidx, i) - end - deleteat!(includes, delidx) + ret = parse_cache_header(io, cachefile) return ret finally close(io) end end -preferences_hash(f::IO) = parse_cache_header(f)[6] +preferences_hash(f::IO, cachefile::AbstractString) = parse_cache_header(f, cachefile)[6] function preferences_hash(cachefile::String) io = open(cachefile, "r") try if iszero(isvalid_cache_header(io)) throw(ArgumentError("Invalid header in cache file $cachefile.")) end - return preferences_hash(io) + return preferences_hash(io, cachefile) finally close(io) end end -function cache_dependencies(f::IO) - _, (includes, _), modules, _... = parse_cache_header(f) - return modules, map(chi -> (chi.filename, chi.mtime), includes) # return just filename and mtime +function cache_dependencies(f::IO, cachefile::AbstractString) + _, (includes, _, _), modules, _... = parse_cache_header(f, cachefile) + return modules, map(chi -> chi.filename, includes) # return just filename end function cache_dependencies(cachefile::String) io = open(cachefile, "r") try iszero(isvalid_cache_header(io)) && throw(ArgumentError("Invalid header in cache file $cachefile.")) - return cache_dependencies(io) + return cache_dependencies(io, cachefile) finally close(io) end end -function read_dependency_src(io::IO, filename::AbstractString) - srctextpos = parse_cache_header(io)[4] +function read_dependency_src(io::IO, cachefile::AbstractString, filename::AbstractString) + _, (includes, _, _), _, srctextpos, _, _, _, _ = parse_cache_header(io, cachefile) srctextpos == 0 && error("no source-text stored in cache file") seek(io, srctextpos) - return _read_dependency_src(io, filename) + return _read_dependency_src(io, filename, includes) end -function _read_dependency_src(io::IO, filename::AbstractString) +function _read_dependency_src(io::IO, filename::AbstractString, includes::Vector{CacheHeaderIncludes}=CacheHeaderIncludes[]) while !eof(io) filenamelen = read(io, Int32) filenamelen == 0 && break - fn = String(read(io, filenamelen)) + depotfn = String(read(io, filenamelen)) len = read(io, UInt64) + fn = if !startswith(depotfn, "@depot") + depotfn + else + basefn = replace(depotfn, r"^@depot" => "") + idx = findfirst(includes) do inc + endswith(inc.filename, basefn) + end + isnothing(idx) ? depotfn : includes[idx].filename + end if fn == filename return String(read(io, len)) end @@ -2740,22 +2806,22 @@ function read_dependency_src(cachefile::String, filename::AbstractString) io = open(cachefile, "r") try iszero(isvalid_cache_header(io)) && throw(ArgumentError("Invalid header in cache file $cachefile.")) - return read_dependency_src(io, filename) + return read_dependency_src(io, cachefile, filename) finally close(io) end end -function srctext_files(f::IO, srctextpos::Int64) +function srctext_files(f::IO, srctextpos::Int64, includes::Vector{CacheHeaderIncludes}) files = Set{String}() srctextpos == 0 && return files seek(f, srctextpos) while !eof(f) filenamelen = read(f, Int32) filenamelen == 0 && break - fn = String(read(f, filenamelen)) + filename = String(read(f, filenamelen)) len = read(f, UInt64) - push!(files, fn) + push!(files, filename) seek(f, position(f) + len) end return files @@ -3098,7 +3164,7 @@ end @debug "Rejecting cache file $cachefile due to it containing an invalid cache header" return true # invalid cache file end - modules, (includes, requires), required_modules, srctextpos, prefs, prefs_hash, clone_targets, flags = parse_cache_header(io) + modules, (includes, _, requires), required_modules, srctextpos, prefs, prefs_hash, clone_targets, flags = parse_cache_header(io, cachefile) if isempty(modules) return true # ignore empty file end @@ -3141,7 +3207,7 @@ end if build_id != UInt128(0) id_build = (UInt128(checksum) << 64) | id.second if id_build != build_id - @debug "Ignoring cache file $cachefile for $modkey ($((UUID(id_build)))) since it is does not provide desired build_id ($((UUID(build_id))))" + @debug "Ignoring cache file $cachefile for $modkey ($((UUID(id_build)))) since it does not provide desired build_id ($((UUID(build_id))))" return true end end @@ -3179,13 +3245,13 @@ end # check if this file is going to provide one of our concrete dependencies # or if it provides a version that conflicts with our concrete dependencies # or neither - skip_timecheck = false + skip_check = false for (req_key, req_build_id) in _concrete_dependencies build_id = get(modules, req_key, UInt64(0)) if build_id !== UInt64(0) build_id |= UInt128(checksum) << 64 if build_id === req_build_id - skip_timecheck = true + skip_check = true break end @debug "Rejecting cache file $cachefile because it provides the wrong build_id (got $((UUID(build_id)))) for $req_key (want $(UUID(req_build_id)))" @@ -3193,40 +3259,54 @@ end end end - # now check if this file is fresh relative to its source files - if !skip_timecheck + # now check if this file's content hash has changed relative to its source files + if !skip_check if !samefile(includes[1].filename, modpath) && !samefile(fixup_stdlib_path(includes[1].filename), modpath) @debug "Rejecting cache file $cachefile because it is for file $(includes[1].filename) not file $modpath" return true # cache file was compiled from a different path end for (modkey, req_modkey) in requires # verify that `require(modkey, name(req_modkey))` ==> `req_modkey` - if identify_package(modkey, req_modkey.name) != req_modkey - @debug "Rejecting cache file $cachefile because uuid mapping for $modkey => $req_modkey has changed" + pkg = identify_package(modkey, req_modkey.name) + if pkg != req_modkey + @debug "Rejecting cache file $cachefile because uuid mapping for $modkey => $req_modkey has changed, expected $modkey => $pkg" return true end end for chi in includes - f, ftime_req = chi.filename, chi.mtime + f, fsize_req, hash_req, ftime_req = chi.filename, chi.fsize, chi.hash, chi.mtime if !ispath(f) _f = fixup_stdlib_path(f) if isfile(_f) && startswith(_f, Sys.STDLIB) - # mtime is changed by extraction continue end @debug "Rejecting stale cache file $cachefile because file $f does not exist" return true end - ftime = mtime(f) - is_stale = ( ftime != ftime_req ) && - ( ftime != floor(ftime_req) ) && # Issue #13606, PR #13613: compensate for Docker images rounding mtimes - ( ftime != ceil(ftime_req) ) && # PR: #47433 Compensate for CirceCI's truncating of timestamps in its caching - ( ftime != trunc(ftime_req, digits=6) ) && # Issue #20837, PR #20840: compensate for GlusterFS truncating mtimes to microseconds - ( ftime != 1.0 ) && # PR #43090: provide compatibility with Nix mtime. - !( 0 < (ftime_req - ftime) < 1e-6 ) # PR #45552: Compensate for Windows tar giving mtimes that may be incorrect by up to one microsecond - if is_stale - @debug "Rejecting stale cache file $cachefile (mtime $ftime_req) because file $f (mtime $ftime) has changed" - return true + if ftime_req >= 0.0 + # this is an include_dependency for which we only recorded the mtime + ftime = mtime(f) + is_stale = ( ftime != ftime_req ) && + ( ftime != floor(ftime_req) ) && # Issue #13606, PR #13613: compensate for Docker images rounding mtimes + ( ftime != ceil(ftime_req) ) && # PR: #47433 Compensate for CirceCI's truncating of timestamps in its caching + ( ftime != trunc(ftime_req, digits=6) ) && # Issue #20837, PR #20840: compensate for GlusterFS truncating mtimes to microseconds + ( ftime != 1.0 ) && # PR #43090: provide compatibility with Nix mtime. + !( 0 < (ftime_req - ftime) < 1e-6 ) # PR #45552: Compensate for Windows tar giving mtimes that may be incorrect by up to one microsecond + if is_stale + @debug "Rejecting stale cache file $cachefile because mtime of include_dependency $f has changed (mtime $ftime, before $ftime_req)" + return true + end + else + fsize = filesize(f) + if fsize != fsize_req + @debug "Rejecting stale cache file $cachefile because file size of $f has changed (file size $fsize, before $fsize_req)" + return true + end + hash = open(_crc32c, f, "r") + if hash != hash_req + @debug "Rejecting stale cache file $cachefile because hash of $f has changed (hash $hash, before $hash_req)" + return true + end end end end diff --git a/base/sysimg.jl b/base/sysimg.jl index bf8de0bc3f75e..a4bf21786c633 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -59,8 +59,9 @@ let print_time(stdlib, tt) end for dep in Base._require_dependencies - dep[3] == 0.0 && continue - push!(Base._included_files, dep[1:2]) + mod, path, fsize, mtime = dep[1], dep[2], dep[3], dep[5] + (fsize == 0 || mtime == 0.0) && continue + push!(Base._included_files, (mod, path)) end empty!(Base._require_dependencies) Base._track_dependencies[] = false diff --git a/doc/src/manual/modules.md b/doc/src/manual/modules.md index b329dbc91b923..4be08edc56f38 100644 --- a/doc/src/manual/modules.md +++ b/doc/src/manual/modules.md @@ -447,10 +447,12 @@ recompiled upon `using` or `import`. Dependencies are modules it imports, the Julia build, files it includes, or explicit dependencies declared by [`include_dependency(path)`](@ref) in the module file(s). -For file dependencies, a change is determined by examining whether the modification time (`mtime`) -of each file loaded by `include` or added explicitly by `include_dependency` is unchanged, or equal -to the modification time truncated to the nearest second (to accommodate systems that can't copy -mtime with sub-second accuracy). It also takes into account whether the path to the file chosen +For file dependencies loaded by `include`, a change is determined by examining whether the +file size (`fsize`) or content (condensed into a hash) is unchanged. +For file dependencies loaded by `include_dependency` a change is determined by examining whether the modification time (`mtime`) +is unchanged, or equal to the modification time truncated to the nearest second +(to accommodate systems that can't copy mtime with sub-second accuracy). +It also takes into account whether the path to the file chosen by the search logic in `require` matches the path that had created the precompile file. It also takes into account the set of dependencies already loaded into the current process and won't recompile those modules, even if their files change or disappear, in order to avoid creating incompatibilities between diff --git a/src/precompile.c b/src/precompile.c index f6266e252f609..ad33dcd9b6d65 100644 --- a/src/precompile.c +++ b/src/precompile.c @@ -36,26 +36,43 @@ void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) { // char*: src text // At the end we write int32(0) as a terminal sentinel. size_t len = jl_array_len(udeps); + static jl_value_t *replace_depot_func = NULL; + if (!replace_depot_func) + replace_depot_func = jl_get_global(jl_base_module, jl_symbol("replace_depot_path")); ios_t srctext; + jl_value_t *deptuple = NULL; + JL_GC_PUSH2(&deptuple, &udeps); for (size_t i = 0; i < len; i++) { - jl_value_t *deptuple = jl_array_ptr_ref(udeps, i); + deptuple = jl_array_ptr_ref(udeps, i); jl_value_t *depmod = jl_fieldref(deptuple, 0); // module // Dependencies declared with `include_dependency` are excluded // because these may not be Julia code (and could be huge) if (depmod != (jl_value_t*)jl_main_module) { - jl_value_t *dep = jl_fieldref(deptuple, 1); // file abspath - const char *depstr = jl_string_data(dep); - if (!depstr[0]) + jl_value_t *abspath = jl_fieldref(deptuple, 1); // file abspath + const char *abspathstr = jl_string_data(abspath); + if (!abspathstr[0]) continue; - ios_t *srctp = ios_file(&srctext, depstr, 1, 0, 0, 0); + ios_t *srctp = ios_file(&srctext, abspathstr, 1, 0, 0, 0); if (!srctp) { jl_printf(JL_STDERR, "WARNING: could not cache source text for \"%s\".\n", - jl_string_data(dep)); + abspathstr); continue; } - size_t slen = jl_string_len(dep); + + jl_value_t **replace_depot_args; + JL_GC_PUSHARGS(replace_depot_args, 2); + replace_depot_args[0] = replace_depot_func; + replace_depot_args[1] = abspath; + jl_task_t *ct = jl_current_task; + size_t last_age = ct->world_age; + ct->world_age = jl_atomic_load_acquire(&jl_world_counter); + jl_value_t *depalias = (jl_value_t*)jl_apply(replace_depot_args, 2); + ct->world_age = last_age; + JL_GC_POP(); + + size_t slen = jl_string_len(depalias); write_int32(f, slen); - ios_write(f, depstr, slen); + ios_write(f, jl_string_data(depalias), slen); posfile = ios_pos(f); write_uint64(f, 0); // placeholder for length of this file in bytes uint64_t filelen = (uint64_t) ios_copyall(f, &srctext); @@ -65,6 +82,7 @@ void write_srctext(ios_t *f, jl_array_t *udeps, int64_t srctextpos) { ios_seek_end(f); } } + JL_GC_POP(); } write_int32(f, 0); // mark the end of the source text } diff --git a/src/staticdata.c b/src/staticdata.c index c684bee4c485b..69226408f711b 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -2691,8 +2691,9 @@ static void jl_write_header_for_incremental(ios_t *f, jl_array_t *worklist, jl_a write_uint8(f, jl_cache_flags()); // write description of contents (name, uuid, buildid) write_worklist_for_header(f, worklist); - // Determine unique (module, abspath, mtime) dependencies for the files defining modules in the worklist - // (see Base._require_dependencies). These get stored in `udeps` and written to the ji-file header. + // Determine unique (module, abspath, fsize, hash, mtime) dependencies for the files defining modules in the worklist + // (see Base._require_dependencies). These get stored in `udeps` and written to the ji-file header + // (abspath will be converted to a relocateable @depot path before writing, cf. Base.replace_depot_path). // Also write Preferences. // last word of the dependency list is the end of the data / start of the srctextpos *srctextpos = write_dependency_list(f, worklist, udeps); // srctextpos: position of srctext entry in header index (update later) diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index a4cbc3fd5ebc4..047042795d128 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -706,6 +706,10 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t jl_array_t *udeps = (*udepsp = deps && unique_func ? (jl_array_t*)jl_apply(uniqargs, 2) : NULL); ct->world_age = last_age; + static jl_value_t *replace_depot_func = NULL; + if (!replace_depot_func) + replace_depot_func = jl_get_global(jl_base_module, jl_symbol("replace_depot_path")); + // write a placeholder for total size so that we can quickly seek past all of the // dependencies if we don't need them initial_pos = ios_pos(s); @@ -713,11 +717,25 @@ static int64_t write_dependency_list(ios_t *s, jl_array_t* worklist, jl_array_t size_t i, l = udeps ? jl_array_len(udeps) : 0; for (i = 0; i < l; i++) { jl_value_t *deptuple = jl_array_ptr_ref(udeps, i); - jl_value_t *dep = jl_fieldref(deptuple, 1); // file abspath - size_t slen = jl_string_len(dep); + jl_value_t *abspath = jl_fieldref(deptuple, 1); + + jl_value_t **replace_depot_args; + JL_GC_PUSHARGS(replace_depot_args, 2); + replace_depot_args[0] = replace_depot_func; + replace_depot_args[1] = abspath; + ct = jl_current_task; + size_t last_age = ct->world_age; + ct->world_age = jl_atomic_load_acquire(&jl_world_counter); + jl_value_t *depalias = (jl_value_t*)jl_apply(replace_depot_args, 2); + ct->world_age = last_age; + JL_GC_POP(); + + size_t slen = jl_string_len(depalias); write_int32(s, slen); - ios_write(s, jl_string_data(dep), slen); - write_float64(s, jl_unbox_float64(jl_fieldref(deptuple, 2))); // mtime + ios_write(s, jl_string_data(depalias), slen); + write_uint64(s, jl_unbox_uint64(jl_fieldref(deptuple, 2))); // fsize + write_uint32(s, jl_unbox_uint32(jl_fieldref(deptuple, 3))); // hash + write_float64(s, jl_unbox_float64(jl_fieldref(deptuple, 4))); // mtime jl_module_t *depmod = (jl_module_t*)jl_fieldref(deptuple, 0); // evaluating module jl_module_t *depmod_top = depmod; while (depmod_top->parent != jl_main_module && depmod_top->parent != depmod_top) diff --git a/test/.gitignore b/test/.gitignore index a1af9ae3d44bf..fc55a0df3a173 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -2,3 +2,5 @@ /ccalltest /ccalltest.s /libccalltest.* +/relocatedepot +/RelocationTestPkg2/src/foo.txt diff --git a/test/Makefile b/test/Makefile index 88dbe5b2b4ed6..d8605341ff9b9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -14,7 +14,7 @@ unexport JULIA_BINDIR := TESTGROUPS = unicode strings compiler TESTS = all default stdlib $(TESTGROUPS) \ $(patsubst $(STDLIBDIR)/%/,%,$(dir $(wildcard $(STDLIBDIR)/*/.))) \ - $(filter-out runtests testdefs, \ + $(filter-out runtests testdefs relocatedepot, \ $(patsubst $(SRCDIR)/%.jl,%,$(wildcard $(SRCDIR)/*.jl))) \ $(foreach group,$(TESTGROUPS), \ $(patsubst $(SRCDIR)/%.jl,%,$(wildcard $(SRCDIR)/$(group)/*.jl))) @@ -34,6 +34,28 @@ $(addprefix revise-, $(TESTS)): revise-% : @cd $(SRCDIR) && \ $(call PRINT_JULIA, $(call spawn,$(JULIA_EXECUTABLE)) --check-bounds=yes --startup-file=no --depwarn=error ./runtests.jl --revise $*) +relocatedepot: + @rm -rf $(SRCDIR)/relocatedepot + @cd $(SRCDIR) && \ + $(call PRINT_JULIA, $(call spawn,JULIA_DEBUG=loading $(JULIA_EXECUTABLE)) --check-bounds=yes --startup-file=no --depwarn=error ./runtests.jl $@) + @mkdir $(SRCDIR)/relocatedepot + @cp -R $(build_datarootdir)/julia $(SRCDIR)/relocatedepot + @cp -R $(SRCDIR)/RelocationTestPkg1 $(SRCDIR)/relocatedepot + @cp -R $(SRCDIR)/RelocationTestPkg2 $(SRCDIR)/relocatedepot + @cd $(SRCDIR) && \ + $(call PRINT_JULIA, $(call spawn,JULIA_DEBUG=loading RELOCATEDEPOT="" JULIA_DEPOT_PATH=$(SRCDIR)/relocatedepot/julia $(JULIA_EXECUTABLE)) --check-bounds=yes --startup-file=no --depwarn=error ./runtests.jl $@) + +revise-relocatedepot: revise-% : + @rm -rf $(SRCDIR)/relocatedepot + @cd $(SRCDIR) && \ + $(call PRINT_JULIA, $(call spawn,JULIA_DEBUG=loading $(JULIA_EXECUTABLE)) --check-bounds=yes --startup-file=no --depwarn=error ./runtests.jl --revise $*) + @mkdir $(SRCDIR)/relocatedepot + @cp -R $(build_datarootdir)/julia $(SRCDIR)/relocatedepot + @cp -R $(SRCDIR)/RelocationTestPkg1 $(SRCDIR)/relocatedepot + @cp -R $(SRCDIR)/RelocationTestPkg2 $(SRCDIR)/relocatedepot + @cd $(SRCDIR) && \ + $(call PRINT_JULIA, $(call spawn,JULIA_DEBUG=loading RELOCATEDEPOT="" JULIA_DEPOT_PATH=$(SRCDIR)/relocatedepot/julia $(JULIA_EXECUTABLE)) --check-bounds=yes --startup-file=no --depwarn=error ./runtests.jl --revise $*) + embedding: @$(MAKE) -C $(SRCDIR)/$@ check $(EMBEDDING_ARGS) @@ -47,4 +69,4 @@ clean: @$(MAKE) -C embedding $@ $(EMBEDDING_ARGS) @$(MAKE) -C gcext $@ $(GCEXT_ARGS) -.PHONY: $(TESTS) $(addprefix revise-, $(TESTS)) embedding gcext clangsa clean +.PHONY: $(TESTS) $(addprefix revise-, $(TESTS)) relocatedepot revise-relocatedepot embedding gcext clangsa clean diff --git a/test/RelocationTestPkg1/Project.toml b/test/RelocationTestPkg1/Project.toml new file mode 100644 index 0000000000000..826980207d508 --- /dev/null +++ b/test/RelocationTestPkg1/Project.toml @@ -0,0 +1,4 @@ +name = "RelocationTestPkg1" +uuid = "854e1adb-5a97-46bf-a391-1cfe05ac726d" +authors = ["flo "] +version = "0.1.0" diff --git a/test/RelocationTestPkg1/src/RelocationTestPkg1.jl b/test/RelocationTestPkg1/src/RelocationTestPkg1.jl new file mode 100644 index 0000000000000..a86543a61b3f8 --- /dev/null +++ b/test/RelocationTestPkg1/src/RelocationTestPkg1.jl @@ -0,0 +1,5 @@ +module RelocationTestPkg1 + +greet() = print("Hello World!") + +end # module RelocationTestPkg1 diff --git a/test/RelocationTestPkg1/src/foo.txt b/test/RelocationTestPkg1/src/foo.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test/RelocationTestPkg2/Project.toml b/test/RelocationTestPkg2/Project.toml new file mode 100644 index 0000000000000..68da889785215 --- /dev/null +++ b/test/RelocationTestPkg2/Project.toml @@ -0,0 +1,4 @@ +name = "RelocationTestPkg2" +uuid = "8d933983-b090-4b0b-a37e-c34793f459d1" +authors = ["flo "] +version = "0.1.0" diff --git a/test/RelocationTestPkg2/src/RelocationTestPkg2.jl b/test/RelocationTestPkg2/src/RelocationTestPkg2.jl new file mode 100644 index 0000000000000..0d8b5e15edf06 --- /dev/null +++ b/test/RelocationTestPkg2/src/RelocationTestPkg2.jl @@ -0,0 +1,6 @@ +module RelocationTestPkg2 + +include_dependency("foo.txt") +greet() = print("Hello World!") + +end # module RelocationTestPkg2 diff --git a/test/RelocationTestPkg2/src/foo.txt b/test/RelocationTestPkg2/src/foo.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test/choosetests.jl b/test/choosetests.jl index 2f77b11767dee..221a49b710d8b 100644 --- a/test/choosetests.jl +++ b/test/choosetests.jl @@ -24,7 +24,7 @@ const TESTNAMES = [ "some", "meta", "stacktraces", "docs", "gc", "misc", "threads", "stress", "binaryplatforms", "atexit", "enums", "cmdlineargs", "int", "interpreter", - "checked", "bitset", "floatfuncs", "precompile", + "checked", "bitset", "floatfuncs", "precompile", "relocatedepot", "boundscheck", "error", "ambiguous", "cartesian", "osutils", "channels", "iostream", "secretbuffer", "specificity", "reinterpretarray", "syntax", "corelogging", "missing", "asyncmap", diff --git a/test/precompile.jl b/test/precompile.jl index 671535c360625..fc4ab2490c4a8 100644 --- a/test/precompile.jl +++ b/test/precompile.jl @@ -381,8 +381,8 @@ precompile_test_harness(false) do dir @test string(Base.Docs.doc(Foo.Bar.bar)) == "bar function\n" @test string(Base.Docs.doc(Foo.Bar)) == "Bar module\n" - modules, (deps, requires), required_modules, _... = Base.parse_cache_header(cachefile) - discard_module = mod_fl_mt -> (mod_fl_mt.filename, mod_fl_mt.mtime) + modules, (deps, _, requires), required_modules, _... = Base.parse_cache_header(cachefile) + discard_module = mod_fl_mt -> mod_fl_mt.filename @test modules == [ Base.PkgId(Foo) => Base.module_build_id(Foo) % UInt64 ] @test map(x -> x.filename, deps) == [ Foo_file, joinpath(dir, "foo.jl"), joinpath(dir, "bar.jl") ] @test requires == [ Base.PkgId(Foo) => Base.PkgId(string(FooBase_module)), @@ -422,7 +422,7 @@ precompile_test_harness(false) do dir @test Dict(modules) == modules_ok @test discard_module.(deps) == deps1 - modules, (deps, requires), required_modules, _... = Base.parse_cache_header(cachefile; srcfiles_only=true) + modules, (_, deps, requires), required_modules, _... = Base.parse_cache_header(cachefile) @test map(x -> x.filename, deps) == [Foo_file] @test current_task()(0x01, 0x4000, 0x30031234) == 2 @@ -485,7 +485,7 @@ precompile_test_harness(false) do dir """) Nest = Base.require(Main, Nest_module) cachefile = joinpath(cachedir, "$Nest_module.ji") - modules, (deps, requires), required_modules, _... = Base.parse_cache_header(cachefile) + modules, (deps, _, requires), required_modules, _... = Base.parse_cache_header(cachefile) @test last(deps).modpath == ["NestInner"] UsesB_module = :UsesB4b3a94a1a081a8cb @@ -507,7 +507,7 @@ precompile_test_harness(false) do dir """) UsesB = Base.require(Main, UsesB_module) cachefile = joinpath(cachedir, "$UsesB_module.ji") - modules, (deps, requires), required_modules, _... = Base.parse_cache_header(cachefile) + modules, (deps, _, requires), required_modules, _... = Base.parse_cache_header(cachefile) id1, id2 = only(requires) @test Base.pkgorigins[id1].cachepath == cachefile @test Base.pkgorigins[id2].cachepath == joinpath(cachedir, "$B_module.ji") @@ -584,12 +584,12 @@ precompile_test_harness(false) do dir fb_uuid = Base.module_build_id(FooBar) sleep(2); touch(FooBar_file) insert!(DEPOT_PATH, 1, dir2) - @test Base.stale_cachefile(FooBar_file, joinpath(cachedir, "FooBar.ji")) === true + @test Base.stale_cachefile(FooBar_file, joinpath(cachedir, "FooBar.ji")) isa Tsc @eval using FooBar1 @test !isfile(joinpath(cachedir2, "FooBar.ji")) @test !isfile(joinpath(cachedir, "FooBar1.ji")) @test isfile(joinpath(cachedir2, "FooBar1.ji")) - @test Base.stale_cachefile(FooBar_file, joinpath(cachedir, "FooBar.ji")) === true + @test Base.stale_cachefile(FooBar_file, joinpath(cachedir, "FooBar.ji")) isa Tsc @test Base.stale_cachefile(FooBar1_file, joinpath(cachedir2, "FooBar1.ji")) isa Tsc @test fb_uuid == Base.module_build_id(FooBar) fb_uuid1 = Base.module_build_id(FooBar1) @@ -1712,7 +1712,7 @@ precompile_test_harness("PkgCacheInspector") do load_path try # isvalid_cache_header returns checksum id or zero Base.isvalid_cache_header(io) == 0 && throw(ArgumentError("Invalid header in cache file $cachefile.")) - depmodnames = Base.parse_cache_header(io)[3] + depmodnames = Base.parse_cache_header(io, cachefile)[3] Base.isvalid_file_crc(io) || throw(ArgumentError("Invalid checksum in cache file $cachefile.")) finally close(io) diff --git a/test/relocatedepot.jl b/test/relocatedepot.jl new file mode 100644 index 0000000000000..91f03d59cc168 --- /dev/null +++ b/test/relocatedepot.jl @@ -0,0 +1,104 @@ +using Test +using Logging + + +include("testenv.jl") + + +function test_harness(@nospecialize(fn)) + load_path = copy(LOAD_PATH) + depot_path = copy(DEPOT_PATH) + try + fn() + finally + copy!(LOAD_PATH, load_path) + copy!(DEPOT_PATH, depot_path) + end +end + + +if !test_relocated_depot + + @testset "precompile RelocationTestPkg1" begin + pkgname = "RelocationTestPkg1" + test_harness() do + push!(LOAD_PATH, @__DIR__) + push!(DEPOT_PATH, @__DIR__) + pkg = Base.identify_package(pkgname) + cachefiles = Base.find_all_in_cache_path(pkg) + rm.(cachefiles, force=true) + @test Base.isprecompiled(pkg) == false + Base.require(pkg) # precompile + @test Base.isprecompiled(pkg, ignore_loaded=true) == true + end + end + + @testset "precompile RelocationTestPkg2 (contains include_dependency)" begin + pkgname = "RelocationTestPkg2" + test_harness() do + push!(LOAD_PATH, @__DIR__) + push!(DEPOT_PATH, @__DIR__) + pkg = Base.identify_package(pkgname) + cachefiles = Base.find_all_in_cache_path(pkg) + rm.(cachefiles, force=true) + @test Base.isprecompiled(pkg) == false + touch(joinpath(@__DIR__, pkgname, "src", "foo.txt")) + Base.require(pkg) # precompile + @info "SERS OIDA" + @test Base.isprecompiled(pkg, ignore_loaded=true) == true + end + end + +else + + # must come before any of the load tests, because the will recompile and generate new cache files + @testset "attempt loading precompiled pkgs when depot is missing" begin + test_harness() do + empty!(LOAD_PATH) + push!(LOAD_PATH, joinpath(@__DIR__, "relocatedepot")) + for pkgname in ("RelocationTestPkg1", "RelocationTestPkg2") + pkg = Base.identify_package(pkgname) + cachefile = only(Base.find_all_in_cache_path(pkg)) + @info cachefile + @test_throws ArgumentError(""" + Failed to determine depot from srctext files in cache file $cachefile. + - Make sure you have adjusted DEPOT_PATH in case you relocated depots.""") Base.isprecompiled(pkg) + end + end + end + + @testset "load stdlib from test/relocatedepot" begin + test_harness() do + push!(LOAD_PATH, joinpath(@__DIR__, "relocatedepot")) + push!(DEPOT_PATH, joinpath(@__DIR__, "relocatedepot")) + # stdlib should be already precompiled + pkg = Base.identify_package("DelimitedFiles") + @test Base.isprecompiled(pkg) == true + end + end + + @testset "load RelocationTestPkg1 from test/relocatedepot" begin + pkgname = "RelocationTestPkg1" + test_harness() do + push!(LOAD_PATH, joinpath(@__DIR__, "relocatedepot")) + push!(DEPOT_PATH, joinpath(@__DIR__, "relocatedepot")) + pkg = Base.identify_package(pkgname) + @test Base.isprecompiled(pkg) == true + Base.require(pkg) # re-precompile + @test Base.isprecompiled(pkg) == true + end + end + + @testset "load RelocationTestPkg2 (contains include_dependency) from test/relocatedepot" begin + pkgname = "RelocationTestPkg2" + test_harness() do + push!(LOAD_PATH, joinpath(@__DIR__, "relocatedepot")) + push!(DEPOT_PATH, joinpath(@__DIR__, "relocatedepot")) + pkg = Base.identify_package(pkgname) + @test Base.isprecompiled(pkg) == false # moving depot changes mtime of include_dependency + Base.require(pkg) # re-precompile + @test Base.isprecompiled(pkg) == true + end + end + +end diff --git a/test/testenv.jl b/test/testenv.jl index 6f99291e01138..3ef1126e0e927 100644 --- a/test/testenv.jl +++ b/test/testenv.jl @@ -35,6 +35,8 @@ if !@isdefined(testenv_defined) const rr_exename = `` end + const test_relocated_depot = haskey(ENV, "RELOCATEDEPOT") + function addprocs_with_testenv(X; rr_allowed=true, kwargs...) exename = rr_allowed ? `$rr_exename $test_exename` : test_exename if X isa Integer From 795d8d7a033cb711f5914b0da7587ab55edb0f39 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Fri, 20 Oct 2023 07:26:06 +0200 Subject: [PATCH 0033/1315] fix parallel peakflop usage (#51757) This is required now once Distributed is not in the sysimage. Fixes https://github.com/JuliaLang/julia/issues/51756 --- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index ca95214b1bbd1..b372ef26a46d4 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -619,7 +619,9 @@ function peakflops(n::Integer=4096; eltype::DataType=Float64, ntrials::Integer=3 if parallel let Distributed = Base.require(Base.PkgId( Base.UUID((0x8ba89e20_285c_5b6f, 0x9357_94700520ee1b)), "Distributed")) - return sum(Distributed.pmap(peakflops, fill(n, Distributed.nworkers()))) + nworkers = @invokelatest Distributed.nworkers() + results = @invokelatest Distributed.pmap(peakflops, fill(n, nworkers)) + return sum(results) end else return 2*Float64(n)^3 / minimum(t) From f8f573dc0ddb10a9ca33d3e624f6e806fb68afb3 Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Fri, 20 Oct 2023 00:31:14 -0500 Subject: [PATCH 0034/1315] Fix reference in manual (#51741) --- doc/src/manual/multi-threading.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/src/manual/multi-threading.md b/doc/src/manual/multi-threading.md index f3b65c74b31d3..b1495192e752c 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -450,7 +450,8 @@ threads in Julia: method, and module definitions in parallel. * Be aware that finalizers registered by a library may break if threads are enabled. This may require some transitional work across the ecosystem before threading - can be widely adopted with confidence. See the next section for further details. + can be widely adopted with confidence. See the section on + [the safe use of finalizers](@ref man-finalizers) for further details. ## [Task Migration](@id man-task-migration) @@ -466,7 +467,7 @@ and therefore should not be used to index into a vector of buffers or stateful o Task migration was introduced in Julia 1.7. Before this tasks always remained on the same thread that they were started on. -## Safe use of Finalizers +## [Safe use of Finalizers](@id man-finalizers) Because finalizers can interrupt any code, they must be very careful in how they interact with any global state. Unfortunately, the main reason that From ef3bf66d5e1d60c9b604eb6e01539eb1c3aced90 Mon Sep 17 00:00:00 2001 From: Tim Besard Date: Fri, 20 Oct 2023 10:21:56 +0200 Subject: [PATCH 0035/1315] Use a single Float16 ABI. (#51666) Currently, Julia uses 2 different Float16 ABIs, depending on the host compiler used to compile Julia: either pass as integer, or pass as LLVM's native `half`. Since the runtime intrinsics are implemented in C using `uint16`, this necessitated conversions around the runtime functions (`gnu_h2f_ieee`, `truncdfhf2`, etc) that the compiler may emit calls to. This PR switches to always using the 'native' ABIs that platforms have for Float16, by removing the conversions around runtime calls, and defining our runtime intrinsics using the native `_Float16` type. Availability of this type depends on the platform, and the compiler version, so we also define fallbacks that mimick the platform-specific calling convention. --- base/ctypes.jl | 4 + src/APInt-C.cpp | 9 +- src/abi_ppc64le.cpp | 8 +- src/abi_x86_64.cpp | 3 +- src/aotcompile.cpp | 9 +- src/codegen.cpp | 55 --------- src/jitlayers.cpp | 5 +- src/julia_internal.h | 20 +--- src/llvm-version.h | 9 -- src/runtime_intrinsics.c | 253 ++++++++++++++++++++++++++------------- test/intrinsics.jl | 22 +--- 11 files changed, 207 insertions(+), 190 deletions(-) diff --git a/base/ctypes.jl b/base/ctypes.jl index 26640ed82bef5..45f01b684902f 100644 --- a/base/ctypes.jl +++ b/base/ctypes.jl @@ -113,3 +113,7 @@ const Cfloat = Float32 Equivalent to the native `double` c-type ([`Float64`](@ref)). """ const Cdouble = Float64 + + +# we have no `Float16` alias, because C does not define a standard fp16 type. Julia follows +# the _Float16 C ABI; if that becomes standard, we can add an appropriate alias here. diff --git a/src/APInt-C.cpp b/src/APInt-C.cpp index f06d4362bf958..7ff68edb0868c 100644 --- a/src/APInt-C.cpp +++ b/src/APInt-C.cpp @@ -313,10 +313,13 @@ void LLVMByteSwap(unsigned numbits, integerPart *pa, integerPart *pr) { ASSIGN(r, a) } +extern "C" float julia_half_to_float(uint16_t ival) JL_NOTSAFEPOINT; +extern "C" uint16_t julia_float_to_half(float param) JL_NOTSAFEPOINT; + void LLVMFPtoInt(unsigned numbits, void *pa, unsigned onumbits, integerPart *pr, bool isSigned, bool *isExact) { double Val; if (numbits == 16) - Val = julia__gnu_h2f_ieee(*(uint16_t*)pa); + Val = julia_half_to_float(*(uint16_t*)pa); else if (numbits == 32) Val = *(float*)pa; else if (numbits == 64) @@ -391,7 +394,7 @@ void LLVMSItoFP(unsigned numbits, integerPart *pa, unsigned onumbits, integerPar val = a.roundToDouble(true); } if (onumbits == 16) - *(uint16_t*)pr = julia__gnu_f2h_ieee(val); + *(uint16_t*)pr = julia_float_to_half(val); else if (onumbits == 32) *(float*)pr = val; else if (onumbits == 64) @@ -408,7 +411,7 @@ void LLVMUItoFP(unsigned numbits, integerPart *pa, unsigned onumbits, integerPar val = a.roundToDouble(false); } if (onumbits == 16) - *(uint16_t*)pr = julia__gnu_f2h_ieee(val); + *(uint16_t*)pr = julia_float_to_half(val); else if (onumbits == 32) *(float*)pr = val; else if (onumbits == 64) diff --git a/src/abi_ppc64le.cpp b/src/abi_ppc64le.cpp index 2e18acdbd4f4b..44d110422a099 100644 --- a/src/abi_ppc64le.cpp +++ b/src/abi_ppc64le.cpp @@ -118,7 +118,12 @@ bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab, LLVMContext &ctx, Type *T Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const override { // Arguments are either scalar or passed by value - size_t size = jl_datatype_size(dt); + + // LLVM passes Float16 in floating-point registers, but this doesn't match the ABI. + // No C compiler seems to support _Float16 yet, so in the meantime, pass as i16 + if (dt == jl_float16_type || dt == jl_bfloat16_type) + return Type::getInt16Ty(ctx); + // don't need to change bitstypes if (!jl_datatype_nfields(dt)) return NULL; @@ -143,6 +148,7 @@ Type *preferred_llvm_type(jl_datatype_t *dt, bool isret, LLVMContext &ctx) const } // rewrite integer-sized (non-HFA) struct to an array // the bitsize of the integer gives the desired alignment + size_t size = jl_datatype_size(dt); if (size > 8) { if (jl_datatype_align(dt) <= 8) { Type *T_int64 = Type::getInt64Ty(ctx); diff --git a/src/abi_x86_64.cpp b/src/abi_x86_64.cpp index 7800c44b4d3ae..5938e1e5778a2 100644 --- a/src/abi_x86_64.cpp +++ b/src/abi_x86_64.cpp @@ -118,7 +118,8 @@ struct Classification { void classifyType(Classification& accum, jl_datatype_t *dt, uint64_t offset) const { // Floating point types - if (dt == jl_float64_type || dt == jl_float32_type || dt == jl_bfloat16_type) { + if (dt == jl_float64_type || dt == jl_float32_type || dt == jl_float16_type || + dt == jl_bfloat16_type) { accum.addField(offset, Sse); } // Misc types diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index fab53fa4de14c..2e1a9d2418eaa 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -986,8 +986,6 @@ struct ShardTimers { } }; -void emitFloat16Wrappers(Module &M, bool external); - struct AOTOutputs { SmallVector unopt, opt, obj, asm_; }; @@ -1047,11 +1045,12 @@ static AOTOutputs add_output_impl(Module &M, TargetMachine &SourceTM, ShardTimer // no need to inject aliases if we have no functions if (inject_aliases) { -#if JULIA_FLOAT16_ABI == 1 // We would like to emit an alias or an weakref alias to redirect these symbols // but LLVM doesn't let us emit a GlobalAlias to a declaration... // So for now we inject a definition of these functions that calls our runtime // functions. We do so after optimization to avoid cloning these functions. + + // Float16 conversion routines injectCRTAlias(M, "__gnu_h2f_ieee", "julia__gnu_h2f_ieee", FunctionType::get(Type::getFloatTy(M.getContext()), { Type::getHalfTy(M.getContext()) }, false)); injectCRTAlias(M, "__extendhfsf2", "julia__gnu_h2f_ieee", @@ -1062,10 +1061,8 @@ static AOTOutputs add_output_impl(Module &M, TargetMachine &SourceTM, ShardTimer FunctionType::get(Type::getHalfTy(M.getContext()), { Type::getFloatTy(M.getContext()) }, false)); injectCRTAlias(M, "__truncdfhf2", "julia__truncdfhf2", FunctionType::get(Type::getHalfTy(M.getContext()), { Type::getDoubleTy(M.getContext()) }, false)); -#else - emitFloat16Wrappers(M, false); -#endif + // BFloat16 conversion routines injectCRTAlias(M, "__truncsfbf2", "julia__truncsfbf2", FunctionType::get(Type::getBFloatTy(M.getContext()), { Type::getFloatTy(M.getContext()) }, false)); injectCRTAlias(M, "__truncsdbf2", "julia__truncdfbf2", diff --git a/src/codegen.cpp b/src/codegen.cpp index e37de75b7c5bc..dbb7d5aa498dc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9144,58 +9144,6 @@ static JuliaVariable *julia_const_gv(jl_value_t *val) return nullptr; } -// Handle FLOAT16 ABI v2 -#if JULIA_FLOAT16_ABI == 2 -static void makeCastCall(Module &M, StringRef wrapperName, StringRef calledName, FunctionType *FTwrapper, FunctionType *FTcalled, bool external) -{ - Function *calledFun = M.getFunction(calledName); - if (!calledFun) { - calledFun = Function::Create(FTcalled, Function::ExternalLinkage, calledName, M); - } - auto linkage = external ? Function::ExternalLinkage : Function::InternalLinkage; - auto wrapperFun = Function::Create(FTwrapper, linkage, wrapperName, M); - wrapperFun->addFnAttr(Attribute::AlwaysInline); - llvm::IRBuilder<> builder(BasicBlock::Create(M.getContext(), "top", wrapperFun)); - SmallVector CallArgs; - if (wrapperFun->arg_size() != calledFun->arg_size()){ - llvm::errs() << "FATAL ERROR: Can't match wrapper to called function"; - abort(); - } - for (auto wrapperArg = wrapperFun->arg_begin(), calledArg = calledFun->arg_begin(); - wrapperArg != wrapperFun->arg_end() && calledArg != calledFun->arg_end(); ++wrapperArg, ++calledArg) - { - CallArgs.push_back(builder.CreateBitCast(wrapperArg, calledArg->getType())); - } - auto val = builder.CreateCall(calledFun, CallArgs); - auto retval = builder.CreateBitCast(val,wrapperFun->getReturnType()); - builder.CreateRet(retval); -} - -void emitFloat16Wrappers(Module &M, bool external) -{ - auto &ctx = M.getContext(); - makeCastCall(M, "__gnu_h2f_ieee", "julia__gnu_h2f_ieee", FunctionType::get(Type::getFloatTy(ctx), { Type::getHalfTy(ctx) }, false), - FunctionType::get(Type::getFloatTy(ctx), { Type::getInt16Ty(ctx) }, false), external); - makeCastCall(M, "__extendhfsf2", "julia__gnu_h2f_ieee", FunctionType::get(Type::getFloatTy(ctx), { Type::getHalfTy(ctx) }, false), - FunctionType::get(Type::getFloatTy(ctx), { Type::getInt16Ty(ctx) }, false), external); - makeCastCall(M, "__gnu_f2h_ieee", "julia__gnu_f2h_ieee", FunctionType::get(Type::getHalfTy(ctx), { Type::getFloatTy(ctx) }, false), - FunctionType::get(Type::getInt16Ty(ctx), { Type::getFloatTy(ctx) }, false), external); - makeCastCall(M, "__truncsfhf2", "julia__gnu_f2h_ieee", FunctionType::get(Type::getHalfTy(ctx), { Type::getFloatTy(ctx) }, false), - FunctionType::get(Type::getInt16Ty(ctx), { Type::getFloatTy(ctx) }, false), external); - makeCastCall(M, "__truncdfhf2", "julia__truncdfhf2", FunctionType::get(Type::getHalfTy(ctx), { Type::getDoubleTy(ctx) }, false), - FunctionType::get(Type::getInt16Ty(ctx), { Type::getDoubleTy(ctx) }, false), external); -} - -static void init_f16_funcs(void) -{ - auto ctx = jl_ExecutionEngine->acquireContext(); - auto TSM = jl_create_ts_module("F16Wrappers", ctx); - auto aliasM = TSM.getModuleUnlocked(); - emitFloat16Wrappers(*aliasM, true); - jl_ExecutionEngine->addModule(std::move(TSM)); -} -#endif - static void init_jit_functions(void) { add_named_global(jl_small_typeof_var, &jl_small_typeof); @@ -9438,9 +9386,6 @@ extern "C" JL_DLLEXPORT_CODEGEN void jl_init_codegen_impl(void) jl_init_llvm(); // Now that the execution engine exists, initialize all modules init_jit_functions(); -#if JULIA_FLOAT16_ABI == 2 - init_f16_funcs(); -#endif } extern "C" JL_DLLEXPORT_CODEGEN void jl_teardown_codegen_impl() JL_NOTSAFEPOINT diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index e3f30f7d22d58..7eed240529e20 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -1729,13 +1729,14 @@ JuliaOJIT::JuliaOJIT() ExternalJD.addToLinkOrder(JD, orc::JITDylibLookupFlags::MatchExportedSymbolsOnly); orc::SymbolAliasMap jl_crt = { -#if JULIA_FLOAT16_ABI == 1 + // Float16 conversion routines { mangle("__gnu_h2f_ieee"), { mangle("julia__gnu_h2f_ieee"), JITSymbolFlags::Exported } }, { mangle("__extendhfsf2"), { mangle("julia__gnu_h2f_ieee"), JITSymbolFlags::Exported } }, { mangle("__gnu_f2h_ieee"), { mangle("julia__gnu_f2h_ieee"), JITSymbolFlags::Exported } }, { mangle("__truncsfhf2"), { mangle("julia__gnu_f2h_ieee"), JITSymbolFlags::Exported } }, { mangle("__truncdfhf2"), { mangle("julia__truncdfhf2"), JITSymbolFlags::Exported } }, -#endif + + // BFloat16 conversion routines { mangle("__truncsfbf2"), { mangle("julia__truncsfbf2"), JITSymbolFlags::Exported } }, { mangle("__truncdfbf2"), { mangle("julia__truncdfbf2"), JITSymbolFlags::Exported } }, }; diff --git a/src/julia_internal.h b/src/julia_internal.h index 204674c6d495a..4f326216d8daf 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1661,20 +1661,12 @@ jl_sym_t *_jl_symbol(const char *str, size_t len) JL_NOTSAFEPOINT; #define JL_WEAK_SYMBOL_DEFAULT(sym) NULL #endif -JL_DLLEXPORT float julia__gnu_h2f_ieee(uint16_t param) JL_NOTSAFEPOINT; -JL_DLLEXPORT uint16_t julia__gnu_f2h_ieee(float param) JL_NOTSAFEPOINT; -JL_DLLEXPORT uint16_t julia__truncdfhf2(double param) JL_NOTSAFEPOINT; -JL_DLLEXPORT float julia__truncsfbf2(float param) JL_NOTSAFEPOINT; -JL_DLLEXPORT float julia__truncdfbf2(double param) JL_NOTSAFEPOINT; -//JL_DLLEXPORT double julia__extendhfdf2(uint16_t n) JL_NOTSAFEPOINT; -//JL_DLLEXPORT int32_t julia__fixhfsi(uint16_t n) JL_NOTSAFEPOINT; -//JL_DLLEXPORT int64_t julia__fixhfdi(uint16_t n) JL_NOTSAFEPOINT; -//JL_DLLEXPORT uint32_t julia__fixunshfsi(uint16_t n) JL_NOTSAFEPOINT; -//JL_DLLEXPORT uint64_t julia__fixunshfdi(uint16_t n) JL_NOTSAFEPOINT; -//JL_DLLEXPORT uint16_t julia__floatsihf(int32_t n) JL_NOTSAFEPOINT; -//JL_DLLEXPORT uint16_t julia__floatdihf(int64_t n) JL_NOTSAFEPOINT; -//JL_DLLEXPORT uint16_t julia__floatunsihf(uint32_t n) JL_NOTSAFEPOINT; -//JL_DLLEXPORT uint16_t julia__floatundihf(uint64_t n) JL_NOTSAFEPOINT; +//JL_DLLEXPORT float julia__gnu_h2f_ieee(half param) JL_NOTSAFEPOINT; +//JL_DLLEXPORT half julia__gnu_f2h_ieee(float param) JL_NOTSAFEPOINT; +//JL_DLLEXPORT half julia__truncdfhf2(double param) JL_NOTSAFEPOINT; +//JL_DLLEXPORT float julia__truncsfbf2(float param) JL_NOTSAFEPOINT; +//JL_DLLEXPORT float julia__truncdfbf2(double param) JL_NOTSAFEPOINT; +//JL_DLLEXPORT double julia__extendhfdf2(half n) JL_NOTSAFEPOINT; JL_DLLEXPORT uint32_t jl_crc32c(uint32_t crc, const char *buf, size_t len); diff --git a/src/llvm-version.h b/src/llvm-version.h index 01638b8d44a6e..7b8dfbbae92d6 100644 --- a/src/llvm-version.h +++ b/src/llvm-version.h @@ -18,15 +18,6 @@ #define JL_LLVM_OPAQUE_POINTERS 1 #endif -// Pre GCC 12 libgcc defined the ABI for Float16->Float32 -// to take an i16. GCC 12 silently changed the ABI to now pass -// Float16 in Float32 registers. -#if JL_LLVM_VERSION < 150000 || defined(_CPU_PPC64_) || defined(_CPU_PPC_) -#define JULIA_FLOAT16_ABI 1 -#else -#define JULIA_FLOAT16_ABI 2 -#endif - #ifdef __cplusplus #if defined(__GNUC__) && (__GNUC__ >= 9) // Added in GCC 9, this warning is annoying diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index b42b7d9832383..588c0359f70be 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -5,8 +5,6 @@ // // this file assumes a little-endian processor, although that isn't too hard to fix // it also assumes two's complement negative numbers, which might be a bit harder to fix -// -// TODO: add half-float support #include "APInt-C.h" #include "julia.h" @@ -14,7 +12,7 @@ const unsigned int host_char_bit = 8; -// float16 intrinsics +// float16 conversion helpers static inline float half_to_float(uint16_t ival) JL_NOTSAFEPOINT { @@ -185,94 +183,189 @@ static inline uint16_t float_to_half(float param) JL_NOTSAFEPOINT return h; } -JL_DLLEXPORT float julia__gnu_h2f_ieee(uint16_t param) +static inline uint16_t double_to_half(double param) JL_NOTSAFEPOINT { + float temp = (float)param; + uint32_t tempi; + memcpy(&tempi, &temp, sizeof(temp)); + + // if Float16(res) is subnormal + if ((tempi&0x7fffffffu) < 0x38800000u) { + // shift so that the mantissa lines up where it would for normal Float16 + uint32_t shift = 113u-((tempi & 0x7f800000u)>>23u); + if (shift<23u) { + tempi |= 0x00800000; // set implicit bit + tempi >>= shift; + } + } + + // if we are halfway between 2 Float16 values + if ((tempi & 0x1fffu) == 0x1000u) { + memcpy(&tempi, &temp, sizeof(temp)); + // adjust the value by 1 ULP in the direction that will make Float16(temp) give the right answer + tempi += (fabs(temp) < fabs(param)) - (fabs(param) < fabs(temp)); + memcpy(&temp, &tempi, sizeof(temp)); + } + + return float_to_half(temp); +} + +// x86-specific helpers for emulating the (B)Float16 ABI +#if defined(_CPU_X86_) || defined(_CPU_X86_64_) +#include +static inline __m128 return_in_xmm(uint16_t input) JL_NOTSAFEPOINT { + __m128 xmm_output; + asm ( + "movd %[input], %%xmm0\n\t" + "movss %%xmm0, %[xmm_output]\n\t" + : [xmm_output] "=x" (xmm_output) + : [input] "r" ((uint32_t)input) + : "xmm0" + ); + return xmm_output; +} +static inline uint16_t take_from_xmm(__m128 xmm_input) JL_NOTSAFEPOINT { + uint32_t output; + asm ( + "movss %[xmm_input], %%xmm0\n\t" + "movd %%xmm0, %[output]\n\t" + : [output] "=r" (output) + : [xmm_input] "x" (xmm_input) + : "xmm0" + ); + return (uint16_t)output; +} +#endif + +// float16 conversion API + +// for use in APInt (without the ABI shenanigans from below) +uint16_t julia_float_to_half(float param) { + return float_to_half(param); +} +float julia_half_to_float(uint16_t param) { return half_to_float(param); } -JL_DLLEXPORT uint16_t julia__gnu_f2h_ieee(float param) +// starting with GCC 12 and Clang 15, we have _Float16 on most platforms +// (but not on Windows; this may be a bug in the MSYS2 GCC compilers) +#if ((defined(__GNUC__) && __GNUC__ > 11) || \ + (defined(__clang__) && __clang_major__ > 14)) && \ + !defined(_CPU_PPC64_) && !defined(_CPU_PPC_) && \ + !defined(_OS_WINDOWS_) + #define FLOAT16_TYPE _Float16 + #define FLOAT16_TO_UINT16(x) (*(uint16_t*)&(x)) + #define FLOAT16_FROM_UINT16(x) (*(_Float16*)&(x)) +// on older compilers, we need to emulate the platform-specific ABI +#elif defined(_CPU_X86_) || (defined(_CPU_X86_64_) && !defined(_OS_WINDOWS_)) + // on x86, we can use __m128; except on Windows where x64 calling + // conventions expect to pass __m128 by reference. + #define FLOAT16_TYPE __m128 + #define FLOAT16_TO_UINT16(x) take_from_xmm(x) + #define FLOAT16_FROM_UINT16(x) return_in_xmm(x) +#elif defined(_CPU_PPC64_) || defined(_CPU_PPC_) + // on PPC, pass Float16 as if it were an integer, similar to the old x86 ABI + // before _Float16 + #define FLOAT16_TYPE uint16_t + #define FLOAT16_TO_UINT16(x) (x) + #define FLOAT16_FROM_UINT16(x) (x) +#else + // otherwise, pass using floating-point calling conventions + #define FLOAT16_TYPE float + #define FLOAT16_TO_UINT16(x) ((uint16_t)*(uint32_t*)&(x)) + #define FLOAT16_FROM_UINT16(x) ({ uint32_t tmp = (uint32_t)(x); *(float*)&tmp; }) +#endif + +JL_DLLEXPORT float julia__gnu_h2f_ieee(FLOAT16_TYPE param) { - return float_to_half(param); + uint16_t param16 = FLOAT16_TO_UINT16(param); + return half_to_float(param16); } -JL_DLLEXPORT uint16_t julia__truncdfhf2(double param) +JL_DLLEXPORT FLOAT16_TYPE julia__gnu_f2h_ieee(float param) { - float res = (float)param; - uint32_t resi; - memcpy(&resi, &res, sizeof(res)); - if ((resi&0x7fffffffu) < 0x38800000u){ // if Float16(res) is subnormal - // shift so that the mantissa lines up where it would for normal Float16 - uint32_t shift = 113u-((resi & 0x7f800000u)>>23u); - if (shift<23u) { - resi |= 0x00800000; // set implicit bit - resi >>= shift; - } - } - if ((resi & 0x1fffu) == 0x1000u) { // if we are halfway between 2 Float16 values - memcpy(&resi, &res, sizeof(res)); - // adjust the value by 1 ULP in the direction that will make Float16(res) give the right answer - resi += (fabs(res) < fabs(param)) - (fabs(param) < fabs(res)); - memcpy(&res, &resi, sizeof(res)); - } - return float_to_half(res); + uint16_t res = float_to_half(param); + return FLOAT16_FROM_UINT16(res); } -JL_DLLEXPORT float julia__truncsfbf2(float param) JL_NOTSAFEPOINT +JL_DLLEXPORT FLOAT16_TYPE julia__truncdfhf2(double param) { - uint16_t result; + uint16_t res = double_to_half(param); + return FLOAT16_FROM_UINT16(res); +} + +// bfloat16 conversion helpers + +static inline uint16_t float_to_bfloat(float param) JL_NOTSAFEPOINT +{ if (isnan(param)) - result = 0x7fc0; - else { - uint32_t bits = *((uint32_t*) ¶m); + return 0x7fc0; - // round to nearest even - bits += 0x7fff + ((bits >> 16) & 1); - result = (uint16_t)(bits >> 16); - } + uint32_t bits = *((uint32_t*) ¶m); - // on x86, bfloat16 needs to be returned in XMM. only GCC 13 provides the necessary ABI - // support in the form of the __bf16 type; older versions only provide __bfloat16 which - // is simply a typedef for short (i16). so use float, which is passed in XMM too. - uint32_t result_32bit = (uint32_t)result; - return *(float*)&result_32bit; + // round to nearest even + bits += 0x7fff + ((bits >> 16) & 1); + return (uint16_t)(bits >> 16); } -JL_DLLEXPORT float julia__truncdfbf2(double param) JL_NOTSAFEPOINT +static inline uint16_t double_to_bfloat(double param) JL_NOTSAFEPOINT { - float res = (float)param; - uint32_t resi; - memcpy(&resi, &res, sizeof(res)); + float temp = (float)param; + uint32_t tempi; + memcpy(&tempi, &temp, sizeof(temp)); // bfloat16 uses the same exponent as float32, so we don't need special handling // for subnormals when truncating float64 to bfloat16. - if ((resi & 0x1ffu) == 0x100u) { // if we are halfway between 2 bfloat16 values - // adjust the value by 1 ULP in the direction that will make bfloat16(res) give the right answer - resi += (fabs(res) < fabs(param)) - (fabs(param) < fabs(res)); - memcpy(&res, &resi, sizeof(res)); + // if we are halfway between 2 bfloat16 values + if ((tempi & 0x1ffu) == 0x100u) { + // adjust the value by 1 ULP in the direction that will make bfloat16(temp) give the right answer + tempi += (fabs(temp) < fabs(param)) - (fabs(param) < fabs(temp)); + memcpy(&temp, &tempi, sizeof(temp)); } - return julia__truncsfbf2(res); -} - -//JL_DLLEXPORT double julia__extendhfdf2(uint16_t n) { return (double)julia__gnu_h2f_ieee(n); } -//JL_DLLEXPORT int32_t julia__fixhfsi(uint16_t n) { return (int32_t)julia__gnu_h2f_ieee(n); } -//JL_DLLEXPORT int64_t julia__fixhfdi(uint16_t n) { return (int64_t)julia__gnu_h2f_ieee(n); } -//JL_DLLEXPORT uint32_t julia__fixunshfsi(uint16_t n) { return (uint32_t)julia__gnu_h2f_ieee(n); } -//JL_DLLEXPORT uint64_t julia__fixunshfdi(uint16_t n) { return (uint64_t)julia__gnu_h2f_ieee(n); } -//JL_DLLEXPORT uint16_t julia__floatsihf(int32_t n) { return julia__gnu_f2h_ieee((float)n); } -//JL_DLLEXPORT uint16_t julia__floatdihf(int64_t n) { return julia__gnu_f2h_ieee((float)n); } -//JL_DLLEXPORT uint16_t julia__floatunsihf(uint32_t n) { return julia__gnu_f2h_ieee((float)n); } -//JL_DLLEXPORT uint16_t julia__floatundihf(uint64_t n) { return julia__gnu_f2h_ieee((float)n); } -//HANDLE_LIBCALL(F16, F128, __extendhftf2) -//HANDLE_LIBCALL(F16, F80, __extendhfxf2) -//HANDLE_LIBCALL(F80, F16, __truncxfhf2) -//HANDLE_LIBCALL(F128, F16, __trunctfhf2) -//HANDLE_LIBCALL(PPCF128, F16, __trunctfhf2) -//HANDLE_LIBCALL(F16, I128, __fixhfti) -//HANDLE_LIBCALL(F16, I128, __fixunshfti) -//HANDLE_LIBCALL(I128, F16, __floattihf) -//HANDLE_LIBCALL(I128, F16, __floatuntihf) + + return float_to_bfloat(temp); +} + +// bfloat16 conversion API + +// starting with GCC 13 and Clang 17, we have __bf16 on most platforms +// (but not on Windows; this may be a bug in the MSYS2 GCC compilers) +#if ((defined(__GNUC__) && __GNUC__ > 12) || \ + (defined(__clang__) && __clang_major__ > 16)) && \ + !defined(_CPU_PPC64_) && !defined(_CPU_PPC_) && \ + !defined(_OS_WINDOWS_) + #define BFLOAT16_TYPE __bf16 + #define BFLOAT16_TO_UINT16(x) (*(uint16_t*)&(x)) + #define BFLOAT16_FROM_UINT16(x) (*(__bf16*)&(x)) +// on older compilers, we need to emulate the platform-specific ABI. +// for more details, see similar code above that deals with Float16. +#elif defined(_CPU_X86_) || (defined(_CPU_X86_64_) && !defined(_OS_WINDOWS_)) + #define BFLOAT16_TYPE __m128 + #define BFLOAT16_TO_UINT16(x) take_from_xmm(x) + #define BFLOAT16_FROM_UINT16(x) return_in_xmm(x) +#elif defined(_CPU_PPC64_) || defined(_CPU_PPC_) + #define BFLOAT16_TYPE uint16_t + #define BFLOAT16_TO_UINT16(x) (x) + #define BFLOAT16_FROM_UINT16(x) (x) +#else + #define BFLOAT16_TYPE float + #define BFLOAT16_TO_UINT16(x) ((uint16_t)*(uint32_t*)&(x)) + #define BFLOAT16_FROM_UINT16(x) ({ uint32_t tmp = (uint32_t)(x); *(float*)&tmp; }) +#endif + +JL_DLLEXPORT BFLOAT16_TYPE julia__truncsfbf2(float param) JL_NOTSAFEPOINT +{ + uint16_t res = float_to_bfloat(param); + return BFLOAT16_FROM_UINT16(res); +} + +JL_DLLEXPORT BFLOAT16_TYPE julia__truncdfbf2(double param) JL_NOTSAFEPOINT +{ + uint16_t res = double_to_bfloat(param); + return BFLOAT16_FROM_UINT16(res); +} // run time version of bitcast intrinsic @@ -643,11 +736,11 @@ static inline void name(unsigned osize, void *pa, void *pr) JL_NOTSAFEPOINT \ static inline void name(unsigned osize, void *pa, void *pr) JL_NOTSAFEPOINT \ { \ uint16_t a = *(uint16_t*)pa; \ - float A = julia__gnu_h2f_ieee(a); \ + float A = half_to_float(a); \ if (osize == 16) { \ float R; \ OP(&R, A); \ - *(uint16_t*)pr = julia__gnu_f2h_ieee(R); \ + *(uint16_t*)pr = float_to_half(R); \ } else { \ OP((uint16_t*)pr, A); \ } \ @@ -671,11 +764,11 @@ static void jl_##name##16(unsigned runtime_nbits, void *pa, void *pb, void *pr) { \ uint16_t a = *(uint16_t*)pa; \ uint16_t b = *(uint16_t*)pb; \ - float A = julia__gnu_h2f_ieee(a); \ - float B = julia__gnu_h2f_ieee(b); \ + float A = half_to_float(a); \ + float B = half_to_float(b); \ runtime_nbits = 16; \ float R = OP(A, B); \ - *(uint16_t*)pr = julia__gnu_f2h_ieee(R); \ + *(uint16_t*)pr = float_to_half(R); \ } // float or integer inputs, bool output @@ -696,8 +789,8 @@ static int jl_##name##16(unsigned runtime_nbits, void *pa, void *pb) JL_NOTSAFEP { \ uint16_t a = *(uint16_t*)pa; \ uint16_t b = *(uint16_t*)pb; \ - float A = julia__gnu_h2f_ieee(a); \ - float B = julia__gnu_h2f_ieee(b); \ + float A = half_to_float(a); \ + float B = half_to_float(b); \ runtime_nbits = 16; \ return OP(A, B); \ } @@ -737,12 +830,12 @@ static void jl_##name##16(unsigned runtime_nbits, void *pa, void *pb, void *pc, uint16_t a = *(uint16_t*)pa; \ uint16_t b = *(uint16_t*)pb; \ uint16_t c = *(uint16_t*)pc; \ - float A = julia__gnu_h2f_ieee(a); \ - float B = julia__gnu_h2f_ieee(b); \ - float C = julia__gnu_h2f_ieee(c); \ + float A = half_to_float(a); \ + float B = half_to_float(b); \ + float C = half_to_float(c); \ runtime_nbits = 16; \ float R = OP(A, B, C); \ - *(uint16_t*)pr = julia__gnu_f2h_ieee(R); \ + *(uint16_t*)pr = float_to_half(R); \ } @@ -1412,7 +1505,7 @@ cvt_iintrinsic(LLVMFPtoUI, fptoui) if (!(osize < 8 * sizeof(a))) \ jl_error("fptrunc: output bitsize must be < input bitsize"); \ else if (osize == 16) \ - *(uint16_t*)pr = julia__gnu_f2h_ieee(a); \ + *(uint16_t*)pr = float_to_half(a); \ else if (osize == 32) \ *(float*)pr = a; \ else if (osize == 64) \ diff --git a/test/intrinsics.jl b/test/intrinsics.jl index d67dad33e60cc..8e4ab932f5eb6 100644 --- a/test/intrinsics.jl +++ b/test/intrinsics.jl @@ -180,28 +180,12 @@ end @test_intrinsic Core.Intrinsics.fptoui UInt Float16(3.3) UInt(3) end -if Sys.ARCH == :aarch64 || Sys.ARCH === :powerpc64le || Sys.ARCH === :ppc64le - # On AArch64 we are following the `_Float16` ABI. Buthe these functions expect `Int16`. - # TODO: Should we have `Chalf == Int16` and `Cfloat16 == Float16`? - extendhfsf2(x::Float16) = ccall("extern __extendhfsf2", llvmcall, Float32, (UInt16,), reinterpret(UInt16, x)) - gnu_h2f_ieee(x::Float16) = ccall("extern __gnu_h2f_ieee", llvmcall, Float32, (UInt16,), reinterpret(UInt16, x)) - truncsfhf2(x::Float32) = reinterpret(Float16, ccall("extern __truncsfhf2", llvmcall, UInt16, (Float32,), x)) - gnu_f2h_ieee(x::Float32) = reinterpret(Float16, ccall("extern __gnu_f2h_ieee", llvmcall, UInt16, (Float32,), x)) - truncdfhf2(x::Float64) = reinterpret(Float16, ccall("extern __truncdfhf2", llvmcall, UInt16, (Float64,), x)) -else - extendhfsf2(x::Float16) = ccall("extern __extendhfsf2", llvmcall, Float32, (Float16,), x) - gnu_h2f_ieee(x::Float16) = ccall("extern __gnu_h2f_ieee", llvmcall, Float32, (Float16,), x) - truncsfhf2(x::Float32) = ccall("extern __truncsfhf2", llvmcall, Float16, (Float32,), x) - gnu_f2h_ieee(x::Float32) = ccall("extern __gnu_f2h_ieee", llvmcall, Float16, (Float32,), x) - truncdfhf2(x::Float64) = ccall("extern __truncdfhf2", llvmcall, Float16, (Float64,), x) -end - @testset "Float16 intrinsics (crt)" begin - @test extendhfsf2(Float16(3.3)) == 3.3007812f0 + gnu_h2f_ieee(x::Float16) = ccall("julia__gnu_h2f_ieee", Float32, (Float16,), x) + gnu_f2h_ieee(x::Float32) = ccall("julia__gnu_f2h_ieee", Float16, (Float32,), x) + @test gnu_h2f_ieee(Float16(3.3)) == 3.3007812f0 - @test truncsfhf2(3.3f0) == Float16(3.3) @test gnu_f2h_ieee(3.3f0) == Float16(3.3) - @test truncdfhf2(3.3) == Float16(3.3) end using Base.Experimental: @force_compile From 01f6c4c8b86f62af923a600327f9b6be1a905193 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Fri, 20 Oct 2023 10:08:35 -0300 Subject: [PATCH 0036/1315] Fix remove-addrspaces pass in the presence of globals with addrspaces (#51782) This fixes an assertion that might trigger if we run this pass on sysimg modules. --- src/llvm-remove-addrspaces.cpp | 4 ++-- test/llvmpasses/remove-addrspaces.ll | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/llvm-remove-addrspaces.cpp b/src/llvm-remove-addrspaces.cpp index b0a68ade4c42b..4b25821f43efb 100644 --- a/src/llvm-remove-addrspaces.cpp +++ b/src/llvm-remove-addrspaces.cpp @@ -335,7 +335,7 @@ bool removeAddrspaces(Module &M, AddrspaceRemapFunction ASRemapper) GlobalVariable *NGV = cast(VMap[GV]); if (GV->hasInitializer()) - NGV->setInitializer(MapValue(GV->getInitializer(), VMap)); + NGV->setInitializer(MapValue(GV->getInitializer(), VMap, RF_None, &TypeRemapper, &Materializer)); SmallVector, 1> MDs; GV->getAllMetadata(MDs); @@ -400,7 +400,7 @@ bool removeAddrspaces(Module &M, AddrspaceRemapFunction ASRemapper) for (GlobalAlias *GA : Aliases) { GlobalAlias *NGA = cast(VMap[GA]); if (const Constant *C = GA->getAliasee()) - NGA->setAliasee(MapValue(C, VMap)); + NGA->setAliasee(MapValue(C, VMap, RF_None, &TypeRemapper, &Materializer)); GA->setAliasee(nullptr); } diff --git a/test/llvmpasses/remove-addrspaces.ll b/test/llvmpasses/remove-addrspaces.ll index b0415671e2d93..90043a7d85cf4 100644 --- a/test/llvmpasses/remove-addrspaces.ll +++ b/test/llvmpasses/remove-addrspaces.ll @@ -5,6 +5,12 @@ ; RUN: opt -enable-new-pm=1 --opaque-pointers=1 --load-pass-plugin=libjulia-codegen%shlibext -passes='RemoveJuliaAddrspaces' -S %s | FileCheck %s --check-prefixes=CHECK,OPAQUE +; COM: check that package image fptrs work +@pjlsys_BoundsError_32 = internal global {} addrspace(10)* ({}***, {} addrspace(10)*, [1 x i64] addrspace(11)*)* null +; CHECK: @pjlsys_BoundsError_32 = internal global +; TYPED-SAME: {}* ({}***, {}*, [1 x i64]*)* null +; OPAQUE-SAME: ptr null + define i64 @getindex({} addrspace(10)* nonnull align 16 dereferenceable(40)) { ; CHECK-LABEL: @getindex top: From 7489a3190432d0a9e77372dd6b6801c3e1589238 Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 29 Apr 2023 17:09:05 +0800 Subject: [PATCH 0037/1315] Allow SubString construction without index shift --- base/strings/substring.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/base/strings/substring.jl b/base/strings/substring.jl index 792925f24b12b..dfd8770b08d47 100644 --- a/base/strings/substring.jl +++ b/base/strings/substring.jl @@ -36,9 +36,18 @@ struct SubString{T<:AbstractString} <: AbstractString end return new(s, i-1, nextind(s,j)-i) end + function SubString{T}(s::T, i::Int, j::Int, ::Val{:noshift}) where T<:AbstractString + @boundscheck begin + si, sj = i + 1, prevind(s, j + i + 1) + @inbounds isvalid(s, si) || string_index_err(s, si) + @inbounds isvalid(s, sj) || string_index_err(s, sj) + end + new(s, i, j) + end end @propagate_inbounds SubString(s::T, i::Int, j::Int) where {T<:AbstractString} = SubString{T}(s, i, j) +@propagate_inbounds SubString(s::T, i::Int, j::Int, v::Val{:noshift}) where {T<:AbstractString} = SubString{T}(s, i, j, v) @propagate_inbounds SubString(s::AbstractString, i::Integer, j::Integer=lastindex(s)) = SubString(s, Int(i), Int(j)) @propagate_inbounds SubString(s::AbstractString, r::AbstractUnitRange{<:Integer}) = SubString(s, first(r), last(r)) From 7bf226bf8a3c4a99a01e596a6a4c2de6b21ffd40 Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 29 Apr 2023 17:10:36 +0800 Subject: [PATCH 0038/1315] Parametrize RegexMatch string type This allows for the construction of matches built on non-String AbstractStrings. --- base/regex.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base/regex.jl b/base/regex.jl index 3e161806c50ea..88f43629bd084 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -212,9 +212,9 @@ julia> hr "11" ``` """ -struct RegexMatch <: AbstractMatch - match::SubString{String} - captures::Vector{Union{Nothing,SubString{String}}} +struct RegexMatch{S<:AbstractString} <: AbstractMatch + match::SubString{S} + captures::Vector{Union{Nothing,SubString{S}}} offset::Int offsets::Vector{Int} regex::Regex @@ -418,7 +418,7 @@ function match(re::Regex, str::Union{SubString{String}, String}, idx::Integer, SubString(str, unsafe_load(p,2i+1)+1, prevind(str, unsafe_load(p,2i+2)+1)) for i=1:n] off = Int[ unsafe_load(p,2i+1)+1 for i=1:n ] - result = RegexMatch(mat, cap, unsafe_load(p,1)+1, off, re) + result = RegexMatch{String}(mat, cap, unsafe_load(p,1)+1, off, re) PCRE.free_match_data(data) return result end From 6113e1c338b23c16424b8f077b8f3b31f828067b Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 29 Apr 2023 17:53:44 +0800 Subject: [PATCH 0039/1315] Introduce Styled{String,Char} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These new types allow for arbitrary properties to be attached to regions of an AbstractString or AbstractChar. The most common expected use of this is for styled content, where the styling is attached as special properties. This has the major benefit of separating styling from content, allowing both to be treated better โ€” functions that operate on the content won't need variants that work around styling, and operations that interact with the styling will have many less edge cases (e.g. printing a substring and having to work around unterminated ANSI styling codes). Other use cases are also enabled by this, such as text links and the preserving of line information in string processing. --- base/exports.jl | 3 + base/regex.jl | 49 ++++- base/strings/basic.jl | 20 +- base/strings/io.jl | 23 +++ base/strings/strings.jl | 1 + base/strings/styled.jl | 432 ++++++++++++++++++++++++++++++++++++++++ base/strings/util.jl | 16 +- 7 files changed, 524 insertions(+), 20 deletions(-) create mode 100644 base/strings/styled.jl diff --git a/base/exports.jl b/base/exports.jl index 81296f7d34b18..87b52189983ad 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -92,6 +92,8 @@ export StridedMatrix, StridedVecOrMat, StridedVector, + StyledChar, + StyledString, SubArray, SubString, SubstitutionString, @@ -629,6 +631,7 @@ export split, string, strip, + styledstring, textwidth, thisind, titlecase, diff --git a/base/regex.jl b/base/regex.jl index 88f43629bd084..61a138de1ee78 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -220,6 +220,10 @@ struct RegexMatch{S<:AbstractString} <: AbstractMatch regex::Regex end +RegexMatch(match::SubString{S}, captures::Vector{Union{Nothing,SubString{S}}}, + offset::Union{Int, UInt}, offsets::Vector{Int}, regex::Regex) where {S<:AbstractString} = + RegexMatch{S}(match, captures, offset, offsets, regex) + """ keys(m::RegexMatch) -> Vector @@ -418,11 +422,37 @@ function match(re::Regex, str::Union{SubString{String}, String}, idx::Integer, SubString(str, unsafe_load(p,2i+1)+1, prevind(str, unsafe_load(p,2i+2)+1)) for i=1:n] off = Int[ unsafe_load(p,2i+1)+1 for i=1:n ] - result = RegexMatch{String}(mat, cap, unsafe_load(p,1)+1, off, re) + result = RegexMatch(mat, cap, unsafe_load(p,1)+1, off, re) PCRE.free_match_data(data) return result end +function _styledmatch(m::RegexMatch{S}, str::StyledString{S}) where {S<:AbstractString} + RegexMatch{StyledString{S}}( + (@inbounds SubString{StyledString{S}}( + str, m.match.offset, m.match.ncodeunits, Val(:noshift))), + Union{Nothing,SubString{StyledString{S}}}[ + if !isnothing(cap) + (@inbounds SubString{StyledString{S}}( + str, cap.offset, cap.ncodeunits, Val(:noshift))) + end for cap in m.captures], + m.offset, m.offsets, m.regex) +end + +function match(re::Regex, str::StyledString) + m = match(re, str.string) + if !isnothing(m) + _styledmatch(m, str) + end +end + +function match(re::Regex, str::StyledString, idx::Integer, add_opts::UInt32=UInt32(0)) + m = match(re, str.string, idx, add_opts) + if !isnothing(m) + _styledmatch(m, str) + end +end + match(r::Regex, s::AbstractString) = match(r, s, firstindex(s)) match(r::Regex, s::AbstractString, i::Integer) = throw(ArgumentError( "regex matching is only available for the String type; use String(s) to convert" @@ -671,18 +701,19 @@ function _replace(io, repl_s::SubstitutionString, str, r, re) end end -struct RegexMatchIterator +struct RegexMatchIterator{S <: AbstractString} regex::Regex - string::String + string::S overlap::Bool - function RegexMatchIterator(regex::Regex, string::AbstractString, ovr::Bool=false) - new(regex, string, ovr) - end + RegexMatchIterator(regex::Regex, string::AbstractString, ovr::Bool=false) = + new{String}(regex, String(string), ovr) + RegexMatchIterator(regex::Regex, string::StyledString, ovr::Bool=false) = + new{StyledString{String}}(regex, StyledString(String(string.string), string.properties), ovr) end compile(itr::RegexMatchIterator) = (compile(itr.regex); itr) -eltype(::Type{RegexMatchIterator}) = RegexMatch -IteratorSize(::Type{RegexMatchIterator}) = SizeUnknown() +eltype(::Type{<:RegexMatchIterator}) = RegexMatch +IteratorSize(::Type{<:RegexMatchIterator}) = SizeUnknown() function iterate(itr::RegexMatchIterator, (offset,prevempty)=(1,false)) opts_nonempty = UInt32(PCRE.ANCHORED | PCRE.NOTEMPTY_ATSTART) @@ -727,7 +758,7 @@ julia> rx = r"a.a" r"a.a" julia> m = eachmatch(rx, "a1a2a3a") -Base.RegexMatchIterator(r"a.a", "a1a2a3a", false) +Base.RegexMatchIterator{String}(r"a.a", "a1a2a3a", false) julia> collect(m) 2-element Vector{RegexMatch}: diff --git a/base/strings/basic.jl b/base/strings/basic.jl index d2bc157aefd94..468ee4476da7e 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -241,9 +241,10 @@ end """ *(s::Union{AbstractString, AbstractChar}, t::Union{AbstractString, AbstractChar}...) -> AbstractString -Concatenate strings and/or characters, producing a [`String`](@ref). This is equivalent -to calling the [`string`](@ref) function on the arguments. Concatenation of built-in -string types always produces a value of type `String` but other string types may choose +Concatenate strings and/or characters, producing a [`String`](@ref) or +[`StyledString`](@ref) (as appropriate). This is equivalent to calling the +[`string`](@ref) or [`styledstring`](@ref) function on the arguments. Concatenation of built-in string +types always produces a value of type `String` but other string types may choose to return a string of a different type as appropriate. # Examples @@ -255,7 +256,15 @@ julia> 'j' * "ulia" "julia" ``` """ -(*)(s1::Union{AbstractChar, AbstractString}, ss::Union{AbstractChar, AbstractString}...) = string(s1, ss...) +function (*)(s1::Union{AbstractChar, AbstractString}, ss::Union{AbstractChar, AbstractString}...) + isstyled = s1 isa StyledString || s1 isa StyledChar || + any(s -> s isa StyledString || s isa StyledChar, ss) + if isstyled + styledstring(s1, ss...) + else + string(s1, ss...) + end +end one(::Union{T,Type{T}}) where {T<:AbstractString} = convert(T, "") @@ -309,7 +318,8 @@ end ==(a::AbstractString, b::AbstractString) -> Bool Test whether two strings are equal character by character (technically, Unicode -code point by code point). +code point by code point). Should either string be a [`StyledString`](@ref) the +string properties must match too. # Examples ```jldoctest diff --git a/base/strings/io.jl b/base/strings/io.jl index 987a64798d3da..d15bcf412f121 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -764,3 +764,26 @@ function String(chars::AbstractVector{<:AbstractChar}) end end end + +function StyledString(chars::AbstractVector{C}) where {C<:AbstractChar} + str = if C <: StyledChar + String(getfield.(chars, :char)) + else + sprint(sizehint=length(chars)) do io + for c in chars + print(io, c) + end + end + end + props = Tuple{UnitRange{Int}, Pair{Symbol, Any}}[] + point = 1 + for c in chars + if c isa StyledChar + for prop in c.properties + push!(props, (point:point, prop)) + end + end + point += ncodeunits(c) + end + StyledString(str, props) +end diff --git a/base/strings/strings.jl b/base/strings/strings.jl index d995d8535e24b..17f329bedb208 100644 --- a/base/strings/strings.jl +++ b/base/strings/strings.jl @@ -1,5 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +include("strings/styled.jl") include("strings/search.jl") include("strings/unicode.jl") diff --git a/base/strings/styled.jl b/base/strings/styled.jl new file mode 100644 index 0000000000000..d1a6e58ece3c4 --- /dev/null +++ b/base/strings/styled.jl @@ -0,0 +1,432 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +""" + StyledString{S <: AbstractString} <: AbstractString + +A string with annotated regions (often styling information). + +More specifically, this is a thin wrapper around any other [`AbstractString`](@ref), +which adds arbitrary named annotations to regions of the wrapped string. + +See also [`StyledChar`](@ref), [`styledstring`](@ref), [`S""`](@ref @S_str), and [`Face`](@ref). + +# Constructors + +In most cases the easiest way to construct a `StyledString` is via the +[`S""`](@ref @S_str) string macro (which see), however a number of constructors +are also availible. + +```julia +StyledString(s::S<:AbstractString) -> StyledString{S} +StyledString(s::S<:AbstractString, props::Pair{Symbol, <:Any}...) +StyledString(s::S<:AbstractString, properties::Vector{Tuple{UnitRange{Int}, Pair{Symbol, <:Any}}}) +``` + +A StyledString can also be created with [`styledstring`](@ref), which acts much +like [`string`](@ref) but preserves any styling present in the arguments. + +# Examples + +```jldoctest +julia> StyledString("hello there", :face => :italic) +"hello there" + +julia> StyledString("more text", :tag => 1) +"more text" +``` +""" +struct StyledString{S <: AbstractString} <: AbstractString + string::S + properties::Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}} +end + +""" + StyledChar{S <: AbstractChar} <: AbstractChar + +A Char annotated by properties (often styling information). + +More specifically, this is a thin wrapper around any other [`AbstractChar`](@ref), +which adds arbitrary named annotations to the wrapped character. + +# Constructors + +```julia +StyledChar(s::S) -> StyledChar{S} +StyledChar(s::S, props::Pair{Symbol, <:Any}...) +StyledChar(s::S, properties::Vector{Pair{Symbol, <:Any}}) +``` + +# Examples + +```jldoctest +julia> StyledChar('j', :face => :blue) +'j': ASCII/Unicode U+006A (category Ll: Letter, lowercase) + +julia> StyledChar('j', :tag => :1) +'j': ASCII/Unicode U+006A (category Ll: Letter, lowercase) +``` +""" +struct StyledChar{C <: AbstractChar} <: AbstractChar + char::C + properties::Vector{Pair{Symbol, Any}} +end + +## Constructors ## + +StyledString(s::AbstractString, prop::Pair{Symbol, <:Any}, props::Pair{Symbol, <:Any}...) = + StyledString(s, firstindex(s):lastindex(s), prop, props...) + +StyledString(s::AbstractString, region::UnitRange{Int}, props::Pair{Symbol, <:Any}...) = + StyledString(s, [(region, Pair{Symbol, Any}(first(p), last(p))) + for p in props]) + +StyledString(s::AbstractString, props::Vector{<:Pair{Symbol, <:Any}}) = + StyledString(s, [(firstindex(s):lastindex(s), p) for p in props]) + +# Constructors called with overly-specialised arguments + +StyledString(s::AbstractString, props::Vector{<:Tuple{UnitRange{Int}, <:Pair{Symbol, <:Any}}}) = + StyledString(s, Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}(props)) + +StyledChar(c::AbstractChar, prop::Pair{Symbol, <:Any}, props::Pair{Symbol, <:Any}...) = + StyledChar(c, Vector{Pair{Symbol, Any}}(vcat(prop, props...))) + +# Constructors to avoid recursive wrapping + +StyledString(s::StyledString, props::Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}) = + StyledString(s.string, vcat(s.properties, props)) + +StyledChar(c::StyledChar, props::Vector{Pair{Symbol, Any}}) = + StyledChar(c.char, vcat(s.properties, props)) + +# To avoid pointless overhead +String(s::StyledString{String}) = s.string + +## Conversion/promotion ## + +convert(::Type{StyledString}, s::StyledString) = s +convert(::Type{StyledString{S}}, s::S) where {S <: AbstractString} = + StyledString(s, Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}()) +convert(::Type{StyledString}, s::S) where {S <: AbstractString} = + convert(StyledString{S}, s) +StyledString(s::S) where {S <: AbstractString} = convert(StyledString{S}, s) + +convert(::Type{StyledChar}, c::StyledChar) = c +convert(::Type{StyledChar{C}}, c::C) where { C <: AbstractChar } = + StyledChar{C}(c, Vector{Pair{Symbol, Any}}()) +convert(::Type{StyledChar}, c::C) where { C <: AbstractChar } = + convert(StyledChar{C}, c) + +StyledChar(c::AbstractChar) = convert(StyledChar, c) +StyledChar(c::UInt32) = convert(StyledChar, Char(c)) +StyledChar{C}(c::UInt32) where {C <: AbstractChar} = convert(StyledChar, C(c)) + +promote_rule(::Type{<:StyledString}, ::Type{<:AbstractString}) = StyledString + +## AbstractString interface ## + +ncodeunits(s::StyledString) = ncodeunits(s.string) +codeunits(s::StyledString) = codeunits(s.string) +codeunit(s::StyledString) = codeunit(s.string) +codeunit(s::StyledString, i::Integer) = codeunit(s.string, i) +isvalid(s::StyledString, i::Integer) = isvalid(s.string, i) +@propagate_inbounds iterate(s::StyledString, i::Integer=firstindex(s)) = + if i <= lastindex(s.string); (s[i], nextind(s, i)) end +eltype(::Type{<:StyledString{S}}) where {S} = StyledChar{eltype(S)} +firstindex(s::StyledString) = firstindex(s.string) +lastindex(s::StyledString) = lastindex(s.string) + +function getindex(s::StyledString, i::Integer) + @boundscheck checkbounds(s, i) + @inbounds if isvalid(s, i) + StyledChar(s.string[i], textproperties(s, i)) + else + string_index_err(s, i) + end +end + +## AbstractChar interface ## + +ncodeunits(c::StyledChar) = ncodeunits(c.char) +codepoint(c::StyledChar) = codepoint(c.char) + +# Avoid the iteration fallback with comparison +cmp(a::StyledString, b::AbstractString) = cmp(a.string, b) +cmp(a::AbstractString, b::StyledString) = cmp(a, b.string) +# To avoid method ambiguity +cmp(a::StyledString, b::StyledString) = cmp(a.string, b.string) + +==(a::StyledString, b::StyledString) = + a.string == b.string && a.properties == b.properties + +==(a::StyledString, b::AbstractString) = isempty(a.properties) && a.string == b +==(a::AbstractString, b::StyledString) = isempty(b.properties) && a == b.string + +""" + styledstring(values...) + +Create a `StyledString` from any number of `values` using their +[`print`](@ref)ed representation. + +This acts like [`string`](@ref), but takes care to preserve any properties +present (in the form of [`StyledString`](@ref) or [`StyledChar`](@ref) values). + +See also [`StyledString`](@ref), [`StyledChar`](@ref), and [`S""`](@ref @S_str). + +## Examples + +``` +julia> styledstring("now a StyledString") +"now a StyledString" + +julia> styledstring(S"{yellow:styled text}", ", and unstyled") +"styled text, and unstyled" +``` +""" +function styledstring(xs...) + isempty(xs) && return StyledString("") + size = mapreduce(_str_sizehint, +, xs) + s = IOContext(IOBuffer(sizehint=size), :color => true) + properties = Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}() + for x in xs + if x isa StyledString + for (region, prop) in x.properties + push!(properties, (s.io.size .+ (region), prop)) + end + print(s, x.string) + elseif x isa SubString{<:StyledString} + for (substr, props) in eachstyle(x) + region = s.io.size .+ (1+substr.offset:prevind(substr.string, 1+substr.offset+substr.ncodeunits)) .- x.offset + for prop in props + push!(properties, (region, prop)) + end + end + print(s, SubString(x.string.string, x.offset, x.ncodeunits, Val(:noshift))) + elseif x isa StyledChar + for prop in x.properties + push!(properties, (1+s.io.size:1+s.io.size, prop)) + end + print(s, x.char) + else + print(s, x) + end + end + str = String(resize!(s.io.data, s.io.size)) + StyledString(str, properties) +end + +""" + styledstring_optimize!(str::StyledString) + +Merge contiguous identical properties in `str`. +""" +function styledstring_optimize!(s::StyledString) + last_seen = Dict{Pair{Symbol, Any}, Int}() + i = 1 + while i <= length(s.properties) + region, keyval = s.properties[i] + prev = get(last_seen, keyval, 0) + if prev > 0 + lregion, _ = s.properties[prev] + if last(lregion) + 1 == first(region) + s.properties[prev] = + setindex(s.properties[prev], + first(lregion):last(region), + 1) + deleteat!(s.properties, i) + else + delete!(last_seen, keyval) + end + else + last_seen[keyval] = i + i += 1 + end + end + s +end + +styledstring(s::StyledString) = s +styledstring(c::StyledChar) = StyledString(string(c.char), c.properties) + +StyledString(s::SubString{<:StyledString}) = styledstring(s) + +function join(iterator, delim::StyledString, last=delim) + xs = zip(iterator, Iterators.repeated(delim)) |> Iterators.flatten |> collect + xs = xs[1:end-1] + if length(xs) > 1 + xs[end-1] = last + end + styledstring(xs...) +end + +function repeat(str::StyledString, r::Integer) + r == 0 && return one(StyledString) + r == 1 && return str + unstyled = repeat(str.string, r) + properties = Vector{Tuple{UnitRange{Int}, Pair{Symbol, Any}}}() + len = ncodeunits(str) + fullregion = firstindex(str):lastindex(str) + for (region, prop) in str.properties + if region == fullregion + push!(properties, (firstindex(unstyled):lastindex(unstyled), prop)) + end + end + for offset in 0:len:(r-1)*len + for (region, prop) in str.properties + if region != fullregion + push!(properties, (region .+ offset, prop)) + end + end + end + StyledString(unstyled, properties) |> styledstring_optimize! +end + +repeat(str::SubString{<:StyledString}, r::Integer) = + repeat(StyledString(str), r) + +function repeat(c::StyledChar, r::Integer) + str = repeat(c.char, r) + fullregion = firstindex(str):lastindex(str) + StyledString(str, [(fullregion, prop) for prop in c.properties]) +end + +function reverse(s::StyledString) + StyledString(reverse(s.string), + [(UnitRange(1 + lastindex(s) - last(region), + 1 + lastindex(s) - first(region)), + prop) + for (region, prop) in s.properties]) +end + +# TODO optimise? +reverse(s::SubString{<:StyledString}) = reverse(StyledString(s)) + +# TODO implement `replace(::StyledString, ...)` + +## End AbstractString interface ## + +""" + textproperty!(s::StyledString, [range::UnitRange{Int}], prop::Symbol, val) + textproperty!(s::SubString{StyledString}, [range::UnitRange{Int}], prop::Symbol, val) + +Set `prop` to `val` in `s`, over either `range` if specified or the whole string. +""" +function textproperty!(s::StyledString, range::UnitRange{Int}, prop::Symbol, val) + indices = searchsorted(s.properties, (range,), by=first) + propindex = filter(i -> first(s.properties[i][2]) === prop, indices) + if length(propindex) == 1 + if val === nothing + deleteat!(s.properties, first(propindex)) + else + s.properties[first(propindex)] = (range, Pair{Symbol, Any}(prop, val)) + end + else + splice!(s.properties, indices, [(range, Pair{Symbol, Any}(prop, val))]) + end + s +end + +textproperty!(ss::StyledString, prop::Symbol, value) = + textproperty!(ss, firstindex(ss):lastindex(ss), prop, value) + +textproperty!(s::SubString{<:StyledString}, range::UnitRange{Int}, prop::Symbol, value) = + (textproperty!(s.string, s.offset .+ (range), prop, value); s) + +textproperty!(s::SubString{<:StyledString}, prop::Symbol, value) = + (textproperty!(s.string, s.offset .+ (1:s.ncodeunits), prop, value); s) + +# TODO optimise +""" + textproperties(s::StyledString, i::Integer) + textproperties(s::SubString{StyledString}, i::Integer) + +Get the text properties that apply to `s` at index `i`. +""" +function textproperties(s::StyledString, i::Integer) + props = filter(prop -> !isempty(intersect(i:i, first(prop))), + s.properties) + last.(props) +end + +textproperties(s::SubString{<:StyledString}, i::Integer) = + textproperties(s.string, s.offset + i) + +""" + textproperties(c::StyledChar) + +Get the properties that apply to `c`. +""" +textproperties(c::StyledChar) = c.properties + +## Iterating over styles ## + +struct StyleIterator{S <: AbstractString} + str::S + regions::Vector{UnitRange{Int}} + styles::Vector{Vector{Pair{Symbol, Any}}} +end + +length(si::StyleIterator) = length(si.regions) + +@propagate_inbounds function iterate(si::StyleIterator, i::Integer=1) + if i <= length(si.regions) + @inbounds ((SubString(si.str, si.regions[i]), si.styles[i]), i+1) + end +end + +eltype(::StyleIterator{S}) where { S <: AbstractString} = + Tuple{SubString{S}, Vector{Pair{Symbol, Any}}} + +""" + eachstyle(s::StyledString{S}) + eachstyle(s::SubString{StyledString{S}}) + +Identify the contiguous substrings of `s` with a constant style, and return +an iterator which provides each substring and the applicable styles as a +`Tuple{SubString{S}, Vector{Pair{Symbol, Any}}}`. + +# Examples + +```jldoctest +julia> eachstyle(StyledString("hey there", [(1:3, :face => :bold), + (5:9, :face => :italic)])) |> collect +3-element Vector{Tuple{SubString{String}, Vector{Pair{Symbol, Any}}}}: + ("hey", [:face => :bold]) + (" ", []) + ("there", [:face => :italic]) +``` +""" +function eachstyle(s::StyledString, region::UnitRange{Int}=firstindex(s):lastindex(s)) + isempty(s) || isempty(region) && + return StyleIterator(s, Vector{UnitRange{Int}}(), Vector{Vector{Pair{Symbol, Any}}}()) + regions = Vector{UnitRange{Int}}() + styles = Vector{Vector{Pair{Symbol, Any}}}() + changepoints = filter(c -> c in region, + Iterators.flatten((first(region), nextind(s, last(region))) + for region in first.(s.properties)) |> + unique |> sort) + isempty(changepoints) && + return StyleIterator(s.string, [region], [textproperties(s, first(region))]) + function registerchange!(start, stop) + push!(regions, start:stop) + push!(styles, textproperties(s, start)) + end + if first(region) < first(changepoints) + registerchange!(first(region), prevind(s, first(changepoints))) + end + for (start, stop) in zip(changepoints, changepoints[2:end]) + registerchange!(start, prevind(s, stop)) + end + if last(changepoints) <= last(region) + registerchange!(last(changepoints), last(region)) + end + StyleIterator(s.string, regions, styles) +end + +function eachstyle(s::SubString{<:StyledString}, region::UnitRange{Int}=firstindex(s):lastindex(s)) + if isempty(s) + StyleIterator(s, Vector{UnitRange{Int}}(), Vector{Vector{Pair{Symbol, Any}}}()) + else + eachstyle(s.string, first(region)+s.offset:last(region)+s.offset) + end +end diff --git a/base/strings/util.jl b/base/strings/util.jl index 890afaf62b2ee..337131d823824 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -458,13 +458,15 @@ function lpad( s::Union{AbstractChar,AbstractString}, n::Integer, p::Union{AbstractChar,AbstractString}=' ', -) :: String +) + stringfn = if any(isa.((s, p), Union{StyledString, StyledChar, SubString{<:StyledString}})) + styledstring else string end n = Int(n)::Int m = signed(n) - Int(textwidth(s))::Int - m โ‰ค 0 && return string(s) + m โ‰ค 0 && return stringfn(s) l = textwidth(p) q, r = divrem(m, l) - r == 0 ? string(p^q, s) : string(p^q, first(p, r), s) + r == 0 ? stringfn(p^q, s) : stringfn(p^q, first(p, r), s) end """ @@ -488,13 +490,15 @@ function rpad( s::Union{AbstractChar,AbstractString}, n::Integer, p::Union{AbstractChar,AbstractString}=' ', -) :: String +) + stringfn = if any(isa.((s, p), Union{StyledString, StyledChar, SubString{<:StyledString}})) + styledstring else string end n = Int(n)::Int m = signed(n) - Int(textwidth(s))::Int - m โ‰ค 0 && return string(s) + m โ‰ค 0 && return stringfn(s) l = textwidth(p) q, r = divrem(m, l) - r == 0 ? string(s, p^q) : string(s, p^q, first(p, r)) + r == 0 ? stringfn(s, p^q) : stringfn(s, p^q, first(p, r)) end """ From c505b047ac44b2bbd4e536bef6b84cb11531abff Mon Sep 17 00:00:00 2001 From: TEC Date: Tue, 2 May 2023 00:24:06 +0800 Subject: [PATCH 0040/1315] Introduce text faces To easy text styling, a "Face" type is introduced which bundles a collection of stylistic attributes together (essentially constituting a typeface). This builds on the recently added Styled{String,Char} types, and together allow for an ergonomic way of handling styled text. --- base/client.jl | 15 ++ base/exports.jl | 3 + base/strings/faces.jl | 561 ++++++++++++++++++++++++++++++++++++++++ base/strings/strings.jl | 1 + 4 files changed, 580 insertions(+) create mode 100644 base/strings/faces.jl diff --git a/base/client.jl b/base/client.jl index 7339bf0870990..ac7fabe19a458 100644 --- a/base/client.jl +++ b/base/client.jl @@ -394,6 +394,19 @@ function load_InteractiveUtils(mod::Module=Main) return MainInclude.InteractiveUtils end +""" + loadfaces!(facetoml::IO) + +Parse `facetoml` as TOML, and load all faces described. +The loading is done with `loadfaces!`, which see. + +Face entries should be of the following form: +```toml +[face_name] +property = "value" +""" +loadfaces!(facetoml::IO) = loadfaces!(TOML.parse(TOML.Parser(facetoml))) + function load_REPL() # load interactive-only libraries try @@ -416,6 +429,8 @@ function run_main_repl(interactive::Bool, quiet::Bool, banner::Symbol, history_f end end # TODO cleanup REPL_MODULE_REF + userfaces = joinpath(first(DEPOT_PATH), "config", "faces.toml") + isfile(userfaces) && open(loadfaces!, userfaces) if !fallback_repl && interactive && isassigned(REPL_MODULE_REF) invokelatest(REPL_MODULE_REF[]) do REPL diff --git a/base/exports.jl b/base/exports.jl index 87b52189983ad..93b7ee8181065 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -50,6 +50,7 @@ export Dims, Enum, ExponentialBackOff, + Face, IndexCartesian, IndexLinear, IndexStyle, @@ -582,6 +583,7 @@ export โˆช, # strings + addface!, ascii, bitstring, bytes2hex, @@ -610,6 +612,7 @@ export isspace, isuppercase, isxdigit, + loadfaces!, lowercase, lowercasefirst, isvalid, diff --git a/base/strings/faces.jl b/base/strings/faces.jl new file mode 100644 index 0000000000000..c5b82bb7da1d7 --- /dev/null +++ b/base/strings/faces.jl @@ -0,0 +1,561 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +const RGBTuple = NamedTuple{(:r, :g, :b), NTuple{3, UInt8}} + +""" + struct SimpleColor + +A basic representation of a color, intended for string styling purposes. +It can either contain a named color (like `:red`), or an `RGBTuple` which +is a NamedTuple specifying an `r`, `g`, `b` color with a bit-depth of 8. + +# Constructors + +```julia +SimpleColor(name::Symbol) # e.g. :red +SimpleColor(rgb::RGBTuple) # e.g. (r=1, b=2, g=3) +SimpleColor(r::Integer, b::Integer, b::Integer) +SimpleColor(rgb::UInt32) # e.g. 0x123456 +``` + +Also see `tryparse(SimpleColor, rgb::String)`. +""" +struct SimpleColor + value::Union{Symbol, RGBTuple} +end + +SimpleColor(r::Integer, g::Integer, b::Integer) = SimpleColor((; r=UInt8(r), g=UInt8(g), b=UInt8(b))) +SimpleColor(rgb::UInt32) = SimpleColor(reverse(reinterpret(UInt8, [rgb]))[2:end]...) + +""" + tryparse(::Type{SimpleColor}, rgb::String) + +Attempt to parse `rgb` as a `SimpleColor`. If `rgb` starts with +`#` and has a length of 7, it is converted into a `RGBTuple`-backed `SimpleColor`. +If `rgb` starts with `a`-`z`, `rgb` is interpreted as a color name +and converted to a `Symbol`-backed `SimpleColor`. + +Otherwise, `nothing` is returned. + +# Examples + +```jldoctest +julia> tryparse(SimpleColor, "blue") +SimpleColor(:blue) + +julia> tryparse(SimpleColor, "#9558b2") +SimpleColor((r = 0x95, g = 0x58, b = 0xb2)) + +julia> tryparse(SimpleColor, "#nocolor") +``` +""" +function tryparse(::Type{SimpleColor}, rgb::String) + if ncodeunits(rgb) == 7 && first(rgb) == '#' && + all(โˆˆ(('#',) โˆช ('0':'9') โˆช ('a':'f') โˆช ('A':'F')), rgb) + SimpleColor(parse(UInt8, rgb[2:3], base=16), + parse(UInt8, rgb[4:5], base=16), + parse(UInt8, rgb[6:7], base=16)) + elseif startswith(rgb, 'a':'z') || startswith(rgb, 'A':'Z') + SimpleColor(Symbol(rgb)) + else + nothing + end +end + +""" + parse(::Type{SimpleColor}, rgb::String) + +An analogue of `tryparse(SimpleColor, rgb::String)` (which see), +that raises an error instead of returning `nothing`. +""" +function parse(::Type{SimpleColor}, rgb::String) + color = tryparse(SimpleColor, rgb) + !isnothing(color) || + throw(ArgumentError("invalid color \"$rgb\"")) + color +end + +""" +A [`Face`](@ref) is a collection of graphical attributes for displaying text. +Faces control how text is displayed in the terminal, and possibly other +places too. + +Most of the time, a [`Face`](@ref) will be stored in the global faces dicts as a +unique association with a *face name* Symbol, and will be most often referred to +by this name instead of the [`Face`](@ref) object itself. + +# Attributes + +All attributes can be set via the keyword constructor, and default to `nothing`. + +- `height` (an `Int` or `Float64`): The height in either deci-pt (when an `Int`), + or as a factor of the base size (when a `Float64`). +- `weight` (a `Symbol`): One of the symbols (from faintest to densest) + `:thin`, `:extralight`, `:light`, `:semilight`, `:normal`, + `:medium`, `:semibold`, `:bold`, `:extrabold`, or `:black`. + In terminals any weight greater than `:normal` is displayed as bold, + and in terminals that support variable-brightness text, any weight + less than `:normal` is displayed as faint. +- `slant` (a `Symbol`): One of the symbols `:italic`, `:oblique`, or `:normal`. +- `foreground` (a `SimpleColor`): The text foreground color. +- `background` (a `SimpleColor`): The text background color. +- `underline`, the text underline, which takes one of the following forms: + - a `Bool`: Whether the text should be underlined or not.\\ + - a `SimpleColor`: The text should be underlined with this color.\\ + - a `Tuple{Nothing, Symbol}`: The text should be underlined using the style + set by the Symbol, one of `:straight`, `:double`, `:curly`, `:dotted`, + or `:dashed`.\\ + - a `Tuple{SimpleColor, Symbol}`: The text should be underlined in the specified + SimpleColor, and using the style specified by the Symbol, as before. +- `strikethrough` (a `Bool`): Whether the text should be struck through. +- `inverse` (a `Bool`): Whether the foreground and background colors should be + inverted. +- `inherit` (a `Vector{Symbol}`): Names of faces to inherit from, + with earlier faces taking priority. All faces inherit from the `:default` face. +""" +struct Face + font::Union{Nothing, String} + height::Union{Nothing, Int, Float64} + weight::Union{Nothing, Symbol} + slant::Union{Nothing, Symbol} + foreground::Union{Nothing, SimpleColor} + background::Union{Nothing, SimpleColor} + underline::Union{Nothing, Bool, SimpleColor, + Tuple{<:Union{Nothing, SimpleColor}, Symbol}} + strikethrough::Union{Nothing, Bool} + inverse::Union{Nothing, Bool} + inherit::Vector{Symbol} +end + +function Face(; font::Union{Nothing, String} = nothing, + height::Union{Nothing, Int, Float64} = nothing, + weight::Union{Nothing, Symbol} = nothing, + slant::Union{Nothing, Symbol} = nothing, + foreground::Union{Nothing, SimpleColor, Symbol, RGBTuple, UInt32} = nothing, + background::Union{Nothing, SimpleColor, Symbol, RGBTuple, UInt32} = nothing, + underline::Union{Nothing, Bool, SimpleColor, + Symbol, RGBTuple, UInt32, + Tuple{<:Union{Nothing, SimpleColor, Symbol, RGBTuple, UInt32}, Symbol} + } = nothing, + strikethrough::Union{Nothing, Bool} = nothing, + inverse::Union{Nothing, Bool} = nothing, + inherit::Union{Symbol, Vector{Symbol}} = Symbol[], + _...) # Simply ignore unrecognised keyword arguments. + ascolor(::Nothing) = nothing + ascolor(c::SimpleColor) = c + ascolor(c::Union{Symbol, RGBTuple, UInt32}) = SimpleColor(c) + Face(font, height, weight, slant, + ascolor(foreground), ascolor(background), + if underline isa Tuple + (ascolor(underline[1]), underline[2]) + elseif underline isa Symbol || underline isa RGBTuple || underline isa UInt32 + ascolor(underline) + else + underline + end, + strikethrough, + inverse, + if inherit isa Symbol + [inherit] + else inherit end) +end + +==(a::Face, b::Face) = + getfield.(Ref(a), fieldnames(Face)) == + getfield.(Ref(b), fieldnames(Face)) + +""" +Globally named [`Face`](@ref)s. + +`default` gives the initial values of the faces, and `current` holds the active +(potentially modified) set of faces. This two-set system allows for any +modifications to the active faces to be undone. +""" +const FACES = let default = Dict{Symbol, Face}( + # Default is special, it must be completely specified + # and everything inherits from it. + :default => Face( + "monospace", 120, # font, height + :normal, :normal, # weight, slant + SimpleColor(:default), # foreground + SimpleColor(:default), # background + false, false, false, # underline, strikethrough, overline + Symbol[]), # inherit + # Property faces + :bold => Face(weight=:bold), + :italic => Face(slant=:italic), + :underline => Face(underline=true), + :strikethrough => Face(strikethrough=true), + :inverse => Face(inverse=true), + # Basic color faces + :black => Face(foreground=:black), + :red => Face(foreground=:red), + :green => Face(foreground=:green), + :yellow => Face(foreground=:yellow), + :blue => Face(foreground=:blue), + :magenta => Face(foreground=:magenta), + :cyan => Face(foreground=:cyan), + :white => Face(foreground=:white), + :bright_black => Face(foreground=:bright_black), + :grey => Face(foreground=:bright_black), + :gray => Face(foreground=:bright_black), + :bright_red => Face(foreground=:bright_red), + :bright_green => Face(foreground=:bright_green), + :bright_yellow => Face(foreground=:bright_yellow), + :bright_blue => Face(foreground=:bright_blue), + :bright_magenta => Face(foreground=:bright_magenta), + :bright_cyan => Face(foreground=:bright_cyan), + :bright_white => Face(foreground=:bright_white), + # Useful common faces + :shadow => Face(foreground=:bright_black), + :region => Face(background=0x3a3a3a), + :emphasis => Face(foreground=:blue), + :highlight => Face(inherit=:emphasis, inverse=true), + :code => Face(foreground=:cyan), + # Styles of generic content categories + :error => Face(foreground=:bright_red), + :warning => Face(foreground=:yellow), + :success => Face(foreground=:green), + :info => Face(foreground=:bright_cyan), + :note => Face(foreground=:grey), + :tip => Face(foreground=:bright_green)) + (; default, current=Ref(copy(default))) +end + +## Adding and resetting faces ## + +""" + addface!(name::Symbol => default::Face) + +Create a new face by the name `name`. So long as no face already exists by this +name, `default` is added to both `FACES``.default` and (a copy of) to +`FACES`.`current`, with the current value returned. + +Should the face `name` already exist, `nothing` is returned. + +# Examples + +```jldoctest +julia> addface!(:mypkg_myface => Face(slant=:italic, underline=true)) +Face (sample) + slant: italic + underline: true +``` +""" +function addface!((name, default)::Pair{Symbol, Face}) + if !haskey(FACES.default, name) + FACES.default[name] = default + FACES.current[][name] = if haskey(FACES.current[], name) + merge(deepcopy(default), FACES.current[][name]) + else + deepcopy(default) + end + end +end + +""" + resetfaces!() + +Reset the current global face dictionary to the default value. +""" +function resetfaces!() + FACES.current[] = copy(FACES.default) +end + +""" + resetfaces!(name::Symbol) + +Reset the face `name` to its default value, which is returned. + +If the face `name` does not exist, nothing is done and `nothing` returned. +In the unlikely event that the face `name` does not have a default value, +it is deleted, a warning message is printed, and `nothing` returned. +""" +function resetfaces!(name::Symbol) + if !haskey(FACES.current[], name) + elseif haskey(FACES.current[], name) + FACES.current[][name] = copy(FACES.default[name]) + else # This shouldn't happen + delete!(FACES.current[], name) + println(stderr, + """! The face $name was reset, but it had no default value, and so has been deleted instead!", + This should not have happened, perhaps the face was added without using `addface!`?""") + end +end + +""" + withfaces(f, kv::Pair...) + +Execute `f` with `FACES``.current` temporarily modified by zero or more +`:name => val` arguments `kv`. `withfaces` is generally used via the +`withfaces(kv...) do ... end` syntax. A value of `nothing` can be used to +temporarily unset an face (if if has been set). When `withfaces` returns, the +original `FACES``.current` has been restored. + + !!! warning + Changing faces is not thread-safe. + +# Examples + +```jldoctest +julia> withfaces(:yellow => Face(foreground=:red), :green => :blue) do + println(S"{yellow:red} and {green:blue} mixed make {magenta:purple}") + end +"red and blue mixed make purple" +``` +""" +function withfaces(f, keyvals::Pair{Symbol, <:Union{Face, Symbol, Nothing}}...) + old = Dict{Symbol, Union{Face, Nothing}}() + for (name, face) in keyvals + old[name] = get(FACES.current[], name, nothing) + if face isa Face + FACES.current[][name] = face + elseif face isa Symbol + FACES.current[][name] = + @something(get(old, face, nothing), get(FACES.current[], face, Face())) + elseif haskey(FACES.current[], name) + delete!(FACES.current[], name) + end + end + try f() + finally + for (name, face) in old + if isnothing(face) + delete!(FACES.current[], name) + else + FACES.current[][name] = face + end + end + end +end + +""" + withfaces(f, altfaces::Dict{Symbol, Face}) + +Execute `f` with `FACES``.current` temporarily swapped out with `altfaces` +When `withfaces` returns, the original `FACES``.current` has been restored. + + !!! warning + Changing faces is not thread-safe. +""" +function withfaces(f, altfaces::Dict{Symbol, Face}) + oldfaces, FACES.current[] = FACES.current[], altfaces + try f() + finally + FACES.current[] = oldfaces + end +end + +withfaces(f) = f() + +## Face combination and inheritance ## + +""" + merge(initial::Face, others::Face...) + +Merge the properties of the `initial` face and `others`, with +later faces taking priority. +""" +function merge(a::Face, b::Face) + if isempty(a.inherit) + Face(ifelse(isnothing(b.font), a.font, b.font), + if isnothing(b.height) a.height + elseif isnothing(a.height) b.height + elseif b.height isa Int b.height + elseif a.height isa Int round(Int, a.height * b.height) + else a.height * b.height end, + ifelse(isnothing(b.weight), a.weight, b.weight), + ifelse(isnothing(b.slant), a.slant, b.slant), + ifelse(isnothing(b.foreground), a.foreground, b.foreground), + ifelse(isnothing(b.background), a.background, b.background), + ifelse(isnothing(b.underline), a.underline, b.underline), + ifelse(isnothing(b.strikethrough), a.strikethrough, b.strikethrough), + ifelse(isnothing(b.inverse), a.inverse, b.inverse), + b.inherit) + else + a_noinherit = Face( + a.font, a.height, a.weight, a.slant, a.foreground, a.background, + a.underline, a.strikethrough, a.inverse, Symbol[]) + a_inheritance = map(fname -> get(FACES.current[], fname, Face()), Iterators.reverse(a.inherit)) + a_resolved = merge(foldl(merge, a_inheritance), a_noinherit) + merge(a_resolved, b) + end +end + +merge(a::Face, b::Face, others::Face...) = merge(merge(a, b), others...) + +## Getting the combined face from a set of properties ## + +""" + getface(faces) + +Obtain the final merged face from `faces`, an iterator of +[`Face`](@ref)s, face name `Symbol`s, and lists thereof. +""" +function getface(faces) + isempty(faces) && return FACES.current[][:default] + mergedface(face::Face) = face + mergedface(face::Symbol) = get(FACES.current[], face, Face()) + mergedface(faces::Vector) = mapfoldl(mergedface, merge, Iterators.reverse(faces)) + combined = mapfoldl(mergedface, merge, Iterators.reverse(faces))::Face + if !isempty(combined.inherit) + combined = merge(combined, Face()) + end + merge(FACES.current[][:default], combined) +end + +""" + getface(styles::Vector{Pair{Symbol, Any}}) + +Combine all of the `:face` styles with `getfaces`. +""" +function getface(styles::Vector{Pair{Symbol, Any}}) + faces = (last(prop) for prop in styles if first(prop) === :face) + getface(faces) +end + +getface(face::Face) = merge(FACES.current[][:default], merge(face, Face())) +getface(face::Symbol) = getface(get(FACES.current[], face, Face())) + +""" + getface() + +Obtain the default face. +""" +getface() = FACES.current[][:default] + +## Face/StyledString integration ## + +""" + getface(s::StyledString, i::Integer) + +Get the merged [`Face`](@ref) that applies to `s` at index `i`. +""" +getface(s::StyledString, i::Integer) = + getface(textproperties(s, i)) + +""" + getface(c::StyledChar) + +Get the merged [`Face`](@ref) that applies to `c`. +""" +getface(c::StyledChar) = getface(c.properties) + +""" + face!(s::Union{<:StyledString, <:SubString{<:StyledString}}, + [range::UnitRange{Int},] face::Union{Symbol, Face}) + +Apply `face` to `s`, along `range` if specified, or the whole of `s`. +""" +face!(s::Union{<:StyledString, <:SubString{<:StyledString}}, + range::UnitRange{Int}, face::Union{Symbol, Face}) = + textproperty!(s, range, :face, face) + +face!(s::Union{<:StyledString, <:SubString{<:StyledString}}, + face::Union{Symbol, Face}) = + textproperty!(s, firstindex(s):lastindex(s), :face, face) + +## Reading face definitions from a dictionary ## + +""" + loadfaces!(name::Symbol => update::Face) + +Merge the face `name` in `FACES``.current` with `update`. If the face `name` does +not already exist in `FACES``.current`, then it is set to `update.` + +# Examples + +```jldoctest +julia> loadfaces!(:red => Face(foreground=0xff0000)) +Face (sample) + foreground: โ–  #ff0000 +``` +""" +function loadfaces!((name, update)::Pair{Symbol, Face}) + if haskey(FACES.current[], name) + FACES.current[][name] = merge(FACES.current[][name], update) + else + FACES.current[][name] = update + end +end + +function loadfaces!((name, _)::Pair{Symbol, Nothing}) + if haskey(FACES.current[], name) + resetfaces!(name) + end +end + +""" + loadfaces!(faces::Dict{String, Any}) + +For each face specified in `Dict`, load it to `FACES``.current`. +""" +function loadfaces!(faces::Dict{String, Any}, prefix::Union{String, Nothing}=nothing) + for (name, spec) in faces + fullname = if isnothing(prefix) + name + else + string(prefix, '_', name) + end + fspec = filter((_, v)::Pair -> !(v isa Dict), spec) + fnest = filter((_, v)::Pair -> v isa Dict, spec) + !isempty(fspec) && + loadfaces!(Symbol(fullname) => convert(Face, fspec)) + !isempty(fnest) && + loadfaces!(fnest, fullname) + end +end + +function convert(::Type{Face}, spec::Dict) + Face(if haskey(spec, "font") && spec["font"] isa String + spec["font"] end, + if haskey(spec, "height") && (spec["height"] isa Int || spec["height"] isa Float64) + spec["height"] + end, + if haskey(spec, "weight") && spec["weight"] isa String + Symbol(spec["weight"]) + elseif haskey(spec, "bold") && spec["bold"] isa Bool + ifelse(spec["bold"], :bold, :normal) + end, + if haskey(spec, "slant") && spec["slant"] isa String + Symbol(spec["slant"]) + elseif haskey(spec, "italic") && spec["italic"] isa Bool + ifelse(spec["italic"], :italic, :normal) + end, + if haskey(spec, "foreground") && spec["foreground"] isa String + tryparse(SimpleColor, spec["foreground"]) + elseif haskey(spec, "fg") && spec["fg"] isa String + tryparse(SimpleColor, spec["fg"]) + end, + if haskey(spec, "background") && spec["background"] isa String + tryparse(SimpleColor, spec["background"]) + elseif haskey(spec, "bg") && spec["bg"] isa String + tryparse(SimpleColor, spec["bg"]) + end, + if !haskey(spec, "underline") + elseif spec["underline"] isa Bool + spec["underline"] + elseif spec["underline"] isa String + tryparse(SimpleColor, spec["underline"]) + elseif spec["underline"] isa Vector && length(spec["underline"]) == 2 + color = tryparse(SimpleColor, spec["underline"][1]) + (color, Symbol(spec["underline"][2])) + end, + if !haskey(spec, "strikethrough") + elseif spec["strikethrough"] isa Bool + spec["strikethrough"] + elseif spec["strikethrough"] isa String + tryparse(SimpleColor, spec["strikethrough"]) + end, + if haskey(spec, "inverse") && spec["inverse"] isa Bool + spec["inverse"] end, + if !haskey(spec, "inherit") + Symbol[] + elseif spec["inherit"] isa String + [Symbol(spec["inherit"])] + elseif spec["inherit"] isa Vector{String} + Symbol.(spec["inherit"]) + else + Symbol[] + end) +end diff --git a/base/strings/strings.jl b/base/strings/strings.jl index 17f329bedb208..5e1e91b319b17 100644 --- a/base/strings/strings.jl +++ b/base/strings/strings.jl @@ -1,6 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license include("strings/styled.jl") +include("strings/faces.jl") include("strings/search.jl") include("strings/unicode.jl") From eada39b4e162b32454f967333b3557ece60293ee Mon Sep 17 00:00:00 2001 From: TEC Date: Tue, 2 May 2023 00:29:46 +0800 Subject: [PATCH 0041/1315] Introduce a styled string macro (@S_str) To make specifying StyledStrings easier, the @S_str macro is added to convert a minimalistic style markup to either a constant StyledString or a StyledString-generating expression. This macro was not easy to write, but seems to work well in practice. --- base/exports.jl | 1 + base/strings/faces.jl | 254 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 255 insertions(+) diff --git a/base/exports.jl b/base/exports.jl index 93b7ee8181065..d2b6995318789 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -1018,6 +1018,7 @@ export @b_str, # byte vector @r_str, # regex @s_str, # regex substitution string + @S_str, # styled string @v_str, # version number @raw_str, # raw string with no interpolation/unescaping @NamedTuple, diff --git a/base/strings/faces.jl b/base/strings/faces.jl index c5b82bb7da1d7..69f5d43a6aa8e 100644 --- a/base/strings/faces.jl +++ b/base/strings/faces.jl @@ -559,3 +559,257 @@ function convert(::Type{Face}, spec::Dict) Symbol[] end) end + +## Style macro ## + +""" + @S_str -> StyledString + +Construct a styled string. Within the string, `{:}` structures +apply the formatting to ``, according to the list of comma-separated +specifications ``. Each spec can either take the form of a face name, +an inline face specification, or a `key=value` pair. The value must be wrapped +by `{...}` should it contain any of the characters `,=:{}`. + +String interpolation with `\$` functions in the same way as regular strings, +except quotes need to be escaped. Faces, keys, and values can also be +interpolated with `\$`. + +# Example + +```julia +S"The {bold:{italic:quick} {(foreground=#cd853f):brown} fox} jumped over \ +the {link={https://en.wikipedia.org/wiki/Laziness}:lazy} dog" +``` +""" +macro S_str(raw_content::String) + parts = Any[] + content = unescape_string(raw_content, ('{', '}', '$', '\n')) + content_bytes = Vector{UInt8}(content) + s = Iterators.Stateful(zip(eachindex(content), content)) + offset = 0 + point = 1 + escape = false + active_styles = Vector{Vector{Tuple{Int, Union{Symbol, Expr, Pair{Symbol, Any}}}}}() + pending_styles = Vector{Tuple{UnitRange{Int}, Union{Symbol, Expr, Pair{Symbol, Any}}}}() + interpolated = false + function addpart(stop::Int) + str = String(content_bytes[point:stop+offset+ncodeunits(content[stop])-1]) + push!(parts, + if isempty(pending_styles) && isempty(active_styles) + str + else + styles = Expr[] + relevant_styles = Iterators.filter( + (start, _)::Tuple -> start <= stop + offset + 1, + Iterators.flatten(active_styles)) + for (start, prop) in relevant_styles + range = (start - point):(stop - point + offset + 1) + push!(styles, Expr(:tuple, range, prop)) + end + for (range, prop) in pending_styles + if !isempty(range) + push!(styles, Expr(:tuple, range .- point, prop)) + end + end + empty!(pending_styles) + if isempty(styles) + str + else + :(StyledString($str, $(Expr(:vect, styles...)))) + end + end) + point = nextind(content, stop) + offset + end + function addpart(start::Int, expr, stop::Int) + if point < start + addpart(start) + end + if isempty(active_styles) + push!(parts, expr) + else + push!(parts, + :(StyledString(string($expr), + $(last.(Iterators.flatten(active_styles))...)))) + map!.((_, prop)::Tuple -> (nextind(content, stop + offset), prop), active_styles, active_styles) + end + end + for (i, char) in s + if char == '\\' + escape = true + elseif escape + if char in ('{', '}', '$') + deleteat!(content_bytes, i + offset - 1) + offset -= 1 + elseif char == '\n' + deleteat!(content_bytes, i+offset-1:i+offset) + offset -= 2 + end + escape = false + elseif char == '$' + # Interpolation + expr, nexti = Meta.parseatom(content, i + 1) + deleteat!(content_bytes, i + offset) + offset -= 1 + nchars = length(content[i:prevind(content, nexti)]) + for _ in 1:min(length(s), nchars-1) + popfirst!(s) + end + addpart(i, expr, nexti) + point = nexti + offset + interpolated = true + elseif char == '{' + # Property declaration parsing and application + properties = true + hasvalue = false + newstyles = Vector{Tuple{Int, Union{Symbol, Expr, Pair{Symbol, Any}}}}() + while properties + if !isnothing(peek(s)) && last(peek(s)) == '(' + # Inline face + popfirst!(s) + specstr = Iterators.takewhile(c -> last(c) != ')', s) |> + collect .|> last |> String + spec = map(split(specstr, ',')) do spec + spec = rstrip(spec) + kv = split(spec, '=', limit=2) + if length(kv) == 2 + kv[1] => @something(tryparse(Bool, kv[2]), + String(kv[2])) + else "" => "" end + end |> Dict + push!(newstyles, + (nextind(content, i + offset), + Pair{Symbol, Any}(:face, convert(Face, spec)))) + if isnothing(peek(s)) || last(popfirst!(s)) != ',' + properties = false + end + else + # Face symbol or key=value pair + key = if isempty(s) + break + elseif last(peek(s)) == '$' + interpolated = true + j, _ = popfirst!(s) + expr, nextj = Meta.parseatom(content, j + 1) + nchars = length(content[j:prevind(content, nextj)]) + for _ in 1:min(length(s), nchars-1) + popfirst!(s) + end + if !isempty(s) + _, c = popfirst!(s) + if c == ':' + properties = false + elseif c == '=' + hasvalue = true + end + end + expr + else + Iterators.takewhile( + function(c) + if last(c) == ':' # Start of content + properties = false + elseif last(c) == '=' # Start of value + hasvalue = true + false + elseif last(c) == ',' # Next key + false + else true end + end, s) |> collect .|> last |> String + end + if hasvalue + hasvalue = false + value = if !isnothing(peek(s)) + if last(peek(s)) == '{' + # Grab {}-wrapped value + popfirst!(s) + isescaped = false + val = Vector{Char}() + while (next = popfirst!(s)) |> !isnothing + (_, c) = next + if isescaped && c โˆˆ ('\\', '}') + push!(val, c) + elseif isescaped + push!(val, '\\', c) + elseif c == '}' + break + else + push!(val, c) + end + end + String(val) + elseif last(peek(s)) == '$' + j, _ = popfirst!(s) + expr, nextj = Meta.parseatom(content, j + 1) + nchars = length(content[j:prevind(content, nextj)]) + for _ in 1:min(length(s), nchars-1) + popfirst!(s) + end + interpolated = true + expr + else + # Grab up to next value, or start of content. + Iterators.takewhile( + function (c) + if last(c) == ':' + properties = false + elseif last(c) == ',' + false + else true end + end, s) |> collect .|> last |> String + end + end + push!(newstyles, + (nextind(content, i + offset), + if key isa String && !(value isa Symbol || value isa Expr) + Pair{Symbol, Any}(Symbol(key), value) + elseif key isa Expr || key isa Symbol + :(Pair{Symbol, Any}($key, $value)) + else + :(Pair{Symbol, Any}( + $(QuoteNode(Symbol(key))), $value)) + end)) + elseif key !== "" # No value, hence a Face property + push!(newstyles, + (nextind(content, i + offset), + if key isa Symbol || key isa Expr + :(Pair{Symbol, Any}(:face, $key)) + else # Face symbol + Pair{Symbol, Any}(:face, Symbol(key)) + end)) + end + end + end + push!(active_styles, newstyles) + # Adjust content_bytes/offset based on how much the index + # has been incremented in the processing of the + # style declaration(s). + if !isnothing(peek(s)) + nexti = first(peek(s)) + deleteat!(content_bytes, i+offset:nexti+offset-1) + offset -= nexti - i + end + elseif char == '}' && !isempty(active_styles) + # Close off most recent active style + for (start, prop) in pop!(active_styles) + push!(pending_styles, (start:i+offset, prop)) + end + deleteat!(content_bytes, i + offset) + offset -= 1 + end + end + # Ensure that any trailing unstyled content is added + if point <= lastindex(content) + offset + addpart(lastindex(content)) + end + if !isempty(active_styles) + println(stderr, "WARNING: Styled string macro in module ", __module__, + " at ", something(__source__.file, ""), ':', string(__source__.line), + " contains unterminated styled constructs.") + end + if interpolated + :(styledstring($(parts...))) |> esc + else + styledstring(map(eval, parts)...) + end +end From 13f32f1510d659abff9254c3f50876823cd7993d Mon Sep 17 00:00:00 2001 From: TEC Date: Tue, 2 May 2023 00:45:44 +0800 Subject: [PATCH 0042/1315] Implement styled printing of StyledStrings Printing StyledStrings is more complicated than using the printstyled function as a Face supports a much richer set of attributes, and StyledString allows for attributes to be nested and overlapping. With the aid of and the newly added terminfo, we can now print a StyledString in all it's glory, up to the capabilities of the current terminal, gracefully degrading italic to underline, and 24-bit colors to 8-bit. --- base/strings/io.jl | 269 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) diff --git a/base/strings/io.jl b/base/strings/io.jl index d15bcf412f121..57c1ab1c3dd4e 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -787,3 +787,272 @@ function StyledString(chars::AbstractVector{C}) where {C<:AbstractChar} end StyledString(str, props) end + +## Styled printing ## + +""" +A mapping between ANSI named colours and indices in the standard 256-color +table. The standard colors are 0-7, and high intensity colors 8-15. + +The high intensity colors are prefixed by "bright_". The "bright_black" color is +given two aliases: "grey" and "gray". +""" +const ANSI_4BIT_COLORS = Dict{Symbol, Int}( + :black => 0, + :red => 1, + :green => 2, + :yellow => 3, + :blue => 4, + :magenta => 5, + :cyan => 6, + :white => 7, + :bright_black => 8, + :grey => 8, + :gray => 8, + :bright_red => 9, + :bright_green => 10, + :bright_yellow => 11, + :bright_blue => 12, + :bright_magenta => 13, + :bright_cyan => 14, + :bright_white => 15) + +""" + ansi_4bit_color_code(color::Symbol, background::Bool=false) + +Provide the color code (30-37, 40-47, 90-97, 100-107) for `color`, as a string. +When `background` is set the background variant will be provided, otherwise +the provided code is for setting the foreground color. +""" +function ansi_4bit_color_code(color::Symbol, background::Bool=false) + if haskey(ANSI_4BIT_COLORS, color) + code = ANSI_4BIT_COLORS[color] + code >= 8 && (code += 52) + background && (code += 10) + string(code + 30) + else + ifelse(background, "49", "39") + end +end + +""" + termcolor8bit(io::IO, color::RGBTuple, category::Char) + +Print to `io` the best 8-bit SGR color code that sets the `category` color to +be close to `color`. +""" +function termcolor8bit(io::IO, (; r, g, b)::RGBTuple, category::Char) + # Magic numbers? Lots. + cdistsq(r1, g1, b1) = (r1 - r)^2 + (g1 - g)^2 + (b1 - b)^2 + to6cube(value) = if value < 48; 1 + elseif value < 114; 2 + else 1 + (value - 35) รท 40 end + r6cube, g6cube, b6cube = to6cube(r), to6cube(g), to6cube(b) + sixcube = (0, 95, 135, 175, 215, 255) + rnear, gnear, bnear = sixcube[r6cube], sixcube[g6cube], sixcube[b6cube] + colorcode = if r == rnear && g == gnear && b == bnear + 16 + 35 * r6cube + 6 * g6cube + b6cube + else + grey_avg = Int(r + g + b) รท 3 + grey_index = if grey_avg > 238 23 else (grey_avg - 3) รท 10 end + grey = 8 + 10 * grey_index + if cdistsq(grey, grey, grey) <= cdistsq(rnear, gnear, bnear) + 232 + grey + else + 16 + 35 * r6cube + 6 * g6cube + b6cube + end + end + print(io, "\e[", category, "8;5;", string(colorcode), 'm') +end + +""" + termcolor24bit(io::IO, color::RGBTuple, category::Char) + +Print to `io` the 24-bit SGR color code to set the `category`8 slot to `color`. +""" +function termcolor24bit(io::IO, color::RGBTuple, category::Char) + print(io, "\e[", category, "8;2;", + string(color.r), ';', + string(color.g), ';', + string(color.b), 'm') +end + +""" + termcolor(io::IO, color::SimpleColor, category::Char) + +Print to `io` the SGR code to set the `category`'s slot to `color`, +where `category` is set as follows: +- `'3'` sets the foreground color +- `'4'` sets the background color +- `'5'` sets the underline color + +If `color` is a `SimpleColor{Symbol}`, the value should be a a member of +`ANSI_4BIT_COLORS`. Any other value will cause the color to be reset. + +If `color` is a `SimpleColor{RGBTuple}` and `get_have_truecolor()` returns true, +24-bit color is used. Otherwise, an 8-bit approximation of `color` is used. +""" +function termcolor(io::IO, color::SimpleColor, category::Char) + if color.value isa RGBTuple + if get_have_truecolor() + termcolor24bit(io, color.value, category) + else + termcolor8bit(io, color.value, category) + end + elseif (fg = get(FACES.current[], color.value, getface()).foreground) != SimpleColor(color.value) + termcolor(io, fg, category) + else + print(io, "\e[", + if category == '3' || category == '4' + ansi_4bit_color_code(color.value, category == '4') + elseif category == '5' + if haskey(ANSI_4BIT_COLORS, color.value) + string("58;5;", ANSI_4BIT_COLORS[color.value]) + else "59" end + end, + 'm') + end +end + +""" + termcolor(io::IO, ::Nothing, category::Char) + +Print to `io` the SGR code to reset the color for `category`. +""" +termcolor(io::IO, ::Nothing, category::Char) = + print(io, "\e[", category, '9', 'm') + +const ANSI_STYLE_CODES = ( + bold_weight = "\e[1m", + dim_weight = "\e[2m", + normal_weight = "\e[22m", + start_italics = "\e[3m", + end_italics = "\e[23m", + start_underline = "\e[4m", + end_underline = "\e[24m", + start_reverse = "\e[7m", + end_reverse = "\e[27m", + start_strikethrough = "\e[9m", + end_strikethrough = "\e[29m" +) + +function termstyle(io::IO, face::Face, lastface::Face=getface()) + face.foreground == lastface.foreground || + termcolor(io, face.foreground, '3') + face.background == lastface.background || + termcolor(io, face.background, '4') + face.weight == lastface.weight || + print(io, if face.weight โˆˆ (:medium, :semibold, :bold, :extrabold, :black) + get(current_terminfo, :bold, "\e[1m") + elseif face.weight โˆˆ (:semilight, :light, :extralight, :thin) + get(current_terminfo, :dim, "") + else # :normal + ANSI_STYLE_CODES.normal_weight + end) + face.slant == lastface.slant || + if haskey(current_terminfo, :enter_italics_mode) + print(io, ifelse(face.slant โˆˆ (:italic, :oblique), + ANSI_STYLE_CODES.start_italics, + ANSI_STYLE_CODES.end_italics)) + elseif face.slant โˆˆ (:italic, :oblique) && face.underline โˆˆ (nothing, false) + print(io, ANSI_STYLE_CODES.start_underline) + elseif face.slant โˆ‰ (:italic, :oblique) && lastface.underline โˆˆ (nothing, false) + print(io, ANSI_STYLE_CODES.end_underline) + end + # Kitty fancy underlines, see + # Supported in Kitty, VTE, iTerm2, Alacritty, and Wezterm. + face.underline == lastface.underline || + if get(current_terminfo, :Su, false) # Color/style capabilities + if face.underline isa Tuple # Color and style + color, style = face.underline + print(io, "\e[4:", + if style == :straight; '1' + elseif style == :double; '2' + elseif style == :curly; '3' + elseif style == :dotted; '4' + elseif style == :dashed; '5' + else '0' end, 'm') + !isnothing(color) && termcolor(io, color, '5') + elseif face.underline isa SimpleColor + if !(lastface.underline isa SimpleColor || lastface.underline == true) + print(io, ANSI_STYLE_CODES.start_underline) + end + termcolor(io, face.underline, '5') + else + if lastface.underline isa SimpleColor || lastface.underline isa Tuple && first(lastface.underline) isa SimpleColor + termcolor(io, SimpleColor(:none), '5') + end + print(io, ifelse(face.underline == true, + ANSI_STYLE_CODES.start_underline, + ANSI_STYLE_CODES.end_underline)) + end + else + print(io, ifelse(face.underline !== false, + ANSI_STYLE_CODES.start_underline, + ANSI_STYLE_CODES.end_underline)) + end + face.strikethrough == lastface.strikethrough || !haskey(current_terminfo, :smxx) || + print(io, ifelse(face.strikethrough === true, + ANSI_STYLE_CODES.start_strikethrough, + ANSI_STYLE_CODES.end_strikethrough)) + face.inverse == lastface.inverse || !haskey(current_terminfo, :enter_reverse_mode) || + print(io, ifelse(face.inverse === true, + ANSI_STYLE_CODES.start_reverse, + ANSI_STYLE_CODES.end_reverse)) +end + +function _ansi_writer(io::IO, s::Union{<:StyledString, SubString{<:StyledString}}, + string_writer::Function) + if get(io, :color, false)::Bool + for (str, styles) in eachstyle(s) + face = getface(styles) + link = let idx=findfirst(==(:link) โˆ˜ first, styles) + if !isnothing(idx) + string(last(styles[idx]))::String + end end + !isnothing(link) && write(io, "\e]8;;", link, "\e\\") + termstyle(io, face, lastface) + string_writer(io, str) + !isnothing(link) && write(io, "\e]8;;\e\\") + lastface = face + end + termstyle(io, getface(), lastface) + elseif s isa StyledString + string_writer(io, s.string) + elseif s isa SubString + string_writer( + io, SubString(s.string.string, s.offset, s.ncodeunits, Val(:noshift))) + end +end + +write(io::IO, s::Union{<:StyledString, SubString{<:StyledString}}) = + _ansi_writer(io, s, write) + +print(io::IO, s::Union{<:StyledString, SubString{<:StyledString}}) = + (write(io, s); nothing) + +escape_string(io::IO, s::Union{<:StyledString, SubString{<:StyledString}}, + esc = ""; keep = ()) = + (_ansi_writer(io, s, (io, s) -> escape_string(io, s, esc; keep)); nothing) + +function write(io::IO, c::StyledChar) + if get(io, :color, false) == true + termstyle(io, getface(c), getface()) + print(io, c.char) + termstyle(io, getface(), getface(c)) + else + print(io, c.char) + end +end + +print(io::IO, c::StyledChar) = (write(io, c); nothing) + +function show(io::IO, c::StyledChar) + if get(io, :color, false) == true + out = IOBuffer() + show(out, c.char) + print(io, ''', StyledString(String(take!(out)[2:end-1]), c.properties), ''') + else + show(io, c.char) + end +end From ea24b5371368047dcaa11ebbcbdf64cd6eee6174 Mon Sep 17 00:00:00 2001 From: TEC Date: Tue, 2 May 2023 18:28:13 +0800 Subject: [PATCH 0043/1315] Buffer styled printing When printing directly to stdout, there is a non-negligible overhead compared to simply printing to an IOBuffer. Testing indicates 3 allocations per print argument, and benchmarks reveal a ~2x increase in allocations overall and much as a 10x increase in execution time. Thus, it seems worthwhile to use a temporary buffer in all cases. --- base/strings/io.jl | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/base/strings/io.jl b/base/strings/io.jl index 57c1ab1c3dd4e..446d44398128a 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -1004,19 +1004,22 @@ end function _ansi_writer(io::IO, s::Union{<:StyledString, SubString{<:StyledString}}, string_writer::Function) if get(io, :color, false)::Bool + buf = IOBuffer() # Avoid the overhead in repeatadly printing to `stdout` + lastface::Face = FACES.current[][:default] for (str, styles) in eachstyle(s) face = getface(styles) link = let idx=findfirst(==(:link) โˆ˜ first, styles) if !isnothing(idx) string(last(styles[idx]))::String end end - !isnothing(link) && write(io, "\e]8;;", link, "\e\\") - termstyle(io, face, lastface) - string_writer(io, str) - !isnothing(link) && write(io, "\e]8;;\e\\") + !isnothing(link) && write(buf, "\e]8;;", link, "\e\\") + termstyle(buf, face, lastface) + string_writer(buf, str) + !isnothing(link) && write(buf, "\e]8;;\e\\") lastface = face end - termstyle(io, getface(), lastface) + termstyle(buf, getface(), lastface) + write(io, take!(buf)) elseif s isa StyledString string_writer(io, s.string) elseif s isa SubString From 98e9af49325ce27560fbb50c607e27b06d192f23 Mon Sep 17 00:00:00 2001 From: TEC Date: Thu, 18 May 2023 19:07:57 +0800 Subject: [PATCH 0044/1315] Add text/html show method for styled strings --- base/strings/io.jl | 175 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/base/strings/io.jl b/base/strings/io.jl index 446d44398128a..8f1ae565243dd 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -1059,3 +1059,178 @@ function show(io::IO, c::StyledChar) show(io, c.char) end end + +""" +A mapping between ANSI named colors and 8-bit colors for use in HTML +representations. +""" +const HTML_BASIC_COLORS = Dict{Symbol, SimpleColor}( + :black => SimpleColor(0x00, 0x00, 0x00), + :red => SimpleColor(0x80, 0x00, 0x00), + :green => SimpleColor(0x00, 0x80, 0x00), + :yellow => SimpleColor(0x80, 0x80, 0x00), + :blue => SimpleColor(0x00, 0x00, 0x80), + :magenta => SimpleColor(0x80, 0x00, 0x80), + :cyan => SimpleColor(0x00, 0x80, 0x80), + :white => SimpleColor(0xc0, 0xc0, 0xc0), + :bright_black => SimpleColor(0x80, 0x80, 0x80), + :grey => SimpleColor(0x80, 0x80, 0x80), + :gray => SimpleColor(0x80, 0x80, 0x80), + :bright_red => SimpleColor(0xff, 0x00, 0x00), + :bright_green => SimpleColor(0x00, 0xff, 0x00), + :bright_yellow => SimpleColor(0xff, 0xff, 0x00), + :bright_blue => SimpleColor(0x00, 0x00, 0xff), + :bright_magenta => SimpleColor(0xff, 0x00, 0xff), + :bright_cyan => SimpleColor(0x00, 0xff, 0xff), + :bright_white => SimpleColor(0xff, 0xff, 0xff)) + +function htmlcolor(io::IO, color::SimpleColor) + if color.value isa Symbol + if color.value === :default + print(io, "initial") + elseif (fg = get(FACES.current[], color.value, getface()).foreground) != SimpleColor(color.value) + htmlcolor(io, fg) + else + htmlcolor(io, get(HTML_BASIC_COLORS, color.value, SimpleColor(:default))) + end + else + (; r, g, b) = color.value + print(io, '#') + r < 0x10 && print(io, '0') + print(io, string(r, base=16)) + g < 0x10 && print(io, '0') + print(io, string(g, base=16)) + b < 0x10 && print(io, '0') + print(io, string(b, base=16)) + end +end + +const HTML_WEIGHT_MAP = Dict{Symbol, Int}( + :thin => 100, + :extralight => 200, + :light => 300, + :semilight => 300, + :normal => 400, + :medium => 500, + :semibold => 600, + :bold => 700, + :extrabold => 800, + :black => 900) + +function htmlstyle(io::IO, face::Face, lastface::Face=getface()) + print(io, " """, ''' => "'"), '"') + face.height == lastface.height || + print(io, "font-size: ", string(face.height รท 10), "pt;") + face.weight == lastface.weight || + print(io, "font-weight: ", get(HTML_WEIGHT_MAP, face.weight, 400), ';') + face.slant == lastface.slant || + print(io, "font-style: ", String(face.slant), ';') + foreground, background = + ifelse(face.inverse === true, + (face.background, face.foreground), + (face.foreground, face.background)) + lastforeground, lastbackground = + ifelse(lastface.inverse === true, + (lastface.background, lastface.foreground), + (lastface.foreground, lastface.background)) + if foreground != lastforeground + print(io, "color: ") + htmlcolor(io, foreground) + print(io, ';') + end + if background != lastbackground + print(io, "background-color: ") + htmlcolor(io, background) + print(io, ';') + end + face.underline == lastface.underline || + if face.underline isa Tuple # Color and style + color, style = face.underline + print(io, "text-decoration: ") + if !isnothing(color) + htmlcolor(io, color) + print(io, ' ') + end + print(io, if style == :straight "solid " + elseif style == :double "double " + elseif style == :curly "wavy " + elseif style == :dotted "dotted " + elseif style == :dashed "dashed " + else "" end) + print(io, "underline;") + elseif face.underline isa SimpleColor + print(io, "text-decoration: ") + htmlcolor(io, face.underline) + if lastface.underline isa Tuple && last(lastface.underline) != :straight + print(io, " solid") + end + print(io, " underline;") + else # must be a Bool + print(io, "text-decoration: ") + if lastface.underline isa SimpleColor + print(io, "currentcolor ") + elseif lastface.underline isa Tuple + first(lastface.underline) isa SimpleColor && + print(io, "currentcolor ") + last(lastface.underline) != :straight && + print(io, "straight ") + end + print(io, ifelse(face.underline, "underline;", "none;")) + end + face.strikethrough == lastface.strikethrough || + print(io, ifelse(face.strikethrough, + "text-decoration: line-through", + ifelse(face.underline === false, + "text-decoration: none", ""))) + print(io, "\">") +end + +function show(io::IO, ::MIME"text/html", s::Union{<:StyledString, SubString{<:StyledString}}; wrap::Symbol=:pre) + htmlescape(str) = replace(str, '&' => "&", '<' => "<", '>' => ">") + buf = IOBuffer() # Avoid potential overhead in repeatadly printing a more complex IO + wrap == :none || + print(buf, '<', String(wrap), '>') + lastface::Face = getface() + stylestackdepth = 0 + for (str, styles) in eachstyle(s) + face = getface(styles) + link = let idx=findfirst(==(:link) โˆ˜ first, styles) + if !isnothing(idx) + string(last(styles[idx]))::String + end end + !isnothing(link) && print(buf, "") + if face == getface() + print(buf, "" ^ stylestackdepth) + stylestackdepth = 0 + elseif (lastface.inverse, lastface.foreground, lastface.background) != + (face.inverse, face.foreground, face.background) + # We can't un-inherit colors well, so we just need to reset and apply + print(buf, "" ^ stylestackdepth) + htmlstyle(buf, face, getface()) + stylestackdepth = 1 + else + htmlstyle(buf, face, lastface) + stylestackdepth += 1 + end + if wrap == :p + newpara = false + for para in eachsplit(str, "\n\n") + newpara && print(buf, "

\n

") + print(buf, htmlescape(para)) + newpara = true + end + else + print(buf, htmlescape(str)) + end + !isnothing(link) && print(buf, "") + lastface = face + end + print(buf, "" ^ stylestackdepth) + wrap == :none || + print(buf, "') + write(io, take!(buf)) + nothing +end From c214350944bfdb1e1dc9048cce8a3b1e393b28f4 Mon Sep 17 00:00:00 2001 From: TEC Date: Sun, 3 Sep 2023 17:19:03 +0800 Subject: [PATCH 0045/1315] Custom show methods for faces and simplecolor This is just nicer to look at in the REPL --- base/strings/faces.jl | 93 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/base/strings/faces.jl b/base/strings/faces.jl index 69f5d43a6aa8e..2ca44a05ec85e 100644 --- a/base/strings/faces.jl +++ b/base/strings/faces.jl @@ -164,6 +164,99 @@ end getfield.(Ref(a), fieldnames(Face)) == getfield.(Ref(b), fieldnames(Face)) +function show(io::IO, ::MIME"text/plain", color::SimpleColor) + skiptype = get(io, :typeinfo, nothing) === SimpleColor + skiptype || show(io, SimpleColor) + skiptype || print(io, '(') + if get(io, :color, false)::Bool + print(io, StyledString("โ– ", :face => Face(foreground=color)), ' ') + end + if color.value isa Symbol + print(io, color.value) + else # rgb tuple + print(io, '#', join(lpad.(string.(values(color.value), base=16), 2, '0'))) + end + skiptype || print(io, ')') + nothing +end + +function show(io::IO, ::MIME"text/plain", face::Face) + if get(io, :compact, false)::Bool + show(io, Face) + if get(io, :color, false)::Bool + # Could do S"({$face:sample})", but S_str isn't defined yet + print(io, StyledString("(sample)", [(2:7, :face => face)])) + else + print(io, '(') + isfirst = true + for field in setdiff(fieldnames(Face), (:inherit,)) + if !isnothing(getfield(face, field)) + if isfirst; isfirst = false else print(io, ", ") end + print(io, field, '=') + show(io, getfield(face, field)) + end + end + if !isempty(face.inherit) + if isfirst; isfirst = false else print(io, ", ") end + print(io, "inherit=") + show(IOContext(io, :typeinfo => Vector{Symbol}), face.inherit) + end + print(io, ')') + end + else + show(io, Face) + print(io, StyledString(" (sample)", [(3:8, :face => face)])) + showcolor(io, color) = show(IOContext(io, :typeinfo => SimpleColor), + MIME("text/plain"), color) + setfields = Pair{Symbol, Any}[] + isempty(setfields) || print(io, ":") + fieldnamepad = 14 + for field in (:font, :height, :weight, :slant) + if !isnothing(getfield(face, field)) + print(io, '\n', lpad(String(field), fieldnamepad, ' '), ": ", + getfield(face, field)) + end + end + for field in (:foreground, :background) + if !isnothing(getfield(face, field)) + print(io, '\n', lpad(String(field), fieldnamepad, ' '), ": ") + showcolor(io, getfield(face, field)) + end + end + if !isnothing(face.underline) + print(io, '\n', lpad("underline", fieldnamepad, ' '), ": ") + if face.underline isa Bool + print(io, face.underline) + elseif face.underline isa SimpleColor + showcolor(io, face.underline) + elseif face.underline isa Tuple{Nothing, Symbol} + print(io, last(face.underline)) + elseif face.underline isa Tuple{SimpleColor, Symbol} + showcolor(io, first(face.underline)) + print(io, ", ", last(face.underline)) + end + end + for field in (:strikethrough, :inverse) + if !isnothing(getfield(face, field)) + print(io, '\n', lpad(String(field), fieldnamepad, ' '), ": ", + getfield(face, field)) + end + end + if !isempty(face.inherit) + print(io, '\n', lpad("inherit", fieldnamepad, ' '), ": ") + isfirst = true + for iface in face.inherit + if isfirst; isfirst = false else print(io, ", ") end + print(io, iface, '(', StyledString("*", :face => iface), ')') + end + end + end +end + +function show(io::IO, face::Face) + show(IOContext(io, :compact => true), MIME("text/plain"), face) +end + """ Globally named [`Face`](@ref)s. From 96e3d6bbab80eaaef8ec087d6b962bc522c2b5cc Mon Sep 17 00:00:00 2001 From: TEC Date: Mon, 4 Sep 2023 21:59:54 +0800 Subject: [PATCH 0046/1315] Load terminfo during exec_options This way should any styled printing occur, regardless of whether a REPL session is started, it will be handled correctly based on the current terminal. --- base/client.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/base/client.jl b/base/client.jl index ac7fabe19a458..aa02e48cd47d8 100644 --- a/base/client.jl +++ b/base/client.jl @@ -271,6 +271,10 @@ function exec_options(opts) interactiveinput = (repl || is_interactive::Bool) && isa(stdin, TTY) is_interactive::Bool |= interactiveinput + # load terminfo in for styled printing + term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb") + global current_terminfo = load_terminfo(term_env) + # load ~/.julia/config/startup.jl file if startup try @@ -435,7 +439,6 @@ function run_main_repl(interactive::Bool, quiet::Bool, banner::Symbol, history_f if !fallback_repl && interactive && isassigned(REPL_MODULE_REF) invokelatest(REPL_MODULE_REF[]) do REPL term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb") - global current_terminfo = load_terminfo(term_env) term = REPL.Terminals.TTYTerminal(term_env, stdin, stdout, stderr) banner == :no || Base.banner(term, short=banner==:short) if term.term_type == "dumb" From 4a9128d6b8db5fe4473d3d422e76f25068df5b4d Mon Sep 17 00:00:00 2001 From: TEC Date: Sat, 9 Sep 2023 20:25:44 +0800 Subject: [PATCH 0047/1315] Overhaul S"" macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous S"" macro was essentially one giant for loop with a helper function. When adding support for inline face value interpolation, it was clear that that approach was unmaintainable. As a result, the implementation has been completely rewritten. The new S"" macro is more maintainable, featureful, and correct โ€” now with a documented EBNF grammar and more validation during expansion. --- base/strings/faces.jl | 720 +++++++++++++++++++++++++++++++----------- 1 file changed, 528 insertions(+), 192 deletions(-) diff --git a/base/strings/faces.jl b/base/strings/faces.jl index 2ca44a05ec85e..c48fbca7f68fb 100644 --- a/base/strings/faces.jl +++ b/base/strings/faces.jl @@ -674,235 +674,571 @@ interpolated with `\$`. S"The {bold:{italic:quick} {(foreground=#cd853f):brown} fox} jumped over \ the {link={https://en.wikipedia.org/wiki/Laziness}:lazy} dog" ``` + +# Extended help + +This macro can be described by the following EBNF grammar: + +```ebnf +styledstring = { styled | interpolated | escaped | plain } ; + +specialchar = '{' | '}' | '\$' | '\\\"' ; +anychar = [\u0-\u1fffff] ; +plain = { anychar - specialchar } ; +escaped = '\\\\', specialchar ; + +interpolated = '\$', ? expr ? | '\$(', ? expr ?, ')' ; + +styled = '{', ws, properties, ':', content, '}' ; +content = { interpolated | escaped | plain | styled } ; +properties = property | properties, ws, ',', ws, property +property = face | inlineface | keyvalue ; +ws = { ' ' | '\\t' | '\\n' } ; (* whitespace *) + +face = facename | interpolated ; +facename = [A-Za-z0-9_]+ ; + +inlineface = '(', ws, [ faceprop ], { ws, ',', faceprop }, ws, ')' ; +faceprop = [a-z]+, ws, '=', ws, ( [^,)]+ | interpolated) ; + +keyvalue = key, ws, '=', ws, value ; +key = ( [^\${}=,:], [^=,:]* ) | interpolated ; +value = simplevalue | curlybraced | interpolated ; +curlybraced = '{' { escaped | plain } '}' ; +simplevalue = [^\${},:], [^,:]* ; +``` + +The above grammar for `inlineface` is simplified, as the actual implementation +is a bit more sophisticated. The full behaviour is given below. + +```ebnf +faceprop = ( 'face', ws, '=', ws, ( ? string ? | interpolated ) ) | + ( 'height', ws, '=', ws, ( ? number ? | interpolated ) ) | + ( 'weight', ws, '=', ws, ( symbol | interpolated ) ) | + ( 'slant', ws, '=', ws, ( symbol | interpolated ) ) | + ( ( 'foreground' | 'fg' | 'background' | 'bg' ), + ws, '=', ws, ( simplecolor | interpolated ) ) | + ( 'underline', ws, '=', ws, ( underline | interpolated ) ) | + ( 'strikethrough', ws, '=', ws, ( bool | interpolated ) ) | + ( 'inverse', ws, '=', ws, ( bool | interpolated ) ) | + ( 'inherit', ws, '=', ws, ( inherit | interpolated ) ) ; + +nothing = 'nothing' ; +bool = 'true' | 'false' ; +symbol = [^ ,)]+ ; +hexcolor = ('#' | '0x'), [0-9a-f]{6} ; +simplecolor = hexcolor | symbol | nothing ; + +underline = nothing | bool | simplecolor | underlinestyled; +underlinestyled = '(', whitespace, ('' | nothing | simplecolor), whitespace, + ',', whitespace, symbol, whitespace ')' ; + +inherit = ( '[', inheritval, { ',', inheritval }, ']' ) | inheritval; +inheritval = whitespace, ':'?, symbol ; +``` """ macro S_str(raw_content::String) - parts = Any[] - content = unescape_string(raw_content, ('{', '}', '$', '\n')) - content_bytes = Vector{UInt8}(content) - s = Iterators.Stateful(zip(eachindex(content), content)) - offset = 0 - point = 1 - escape = false - active_styles = Vector{Vector{Tuple{Int, Union{Symbol, Expr, Pair{Symbol, Any}}}}}() - pending_styles = Vector{Tuple{UnitRange{Int}, Union{Symbol, Expr, Pair{Symbol, Any}}}}() - interpolated = false - function addpart(stop::Int) - str = String(content_bytes[point:stop+offset+ncodeunits(content[stop])-1]) - push!(parts, - if isempty(pending_styles) && isempty(active_styles) + #------------------ + # Helper functions + #------------------ + + # If this were a module, I'd define the following struct. + + #= struct State + content::String # the (unescaped) input string + bytes::Vector{UInt8} # bytes of `content` + s::Iterators.Stateful # (index, char) interator of `content` + parts::Vector{Any} # the final result + active_styles::Vector{ # unterminated batches of styles + Vector{Tuple{Int, Union{Symbol, Expr, Pair{Symbol, Any}}}}} + pending_styles::Vector{ # terminated styles that have yet to be applied + Tuple{UnitRange{Int}, Union{Symbol, Expr, Pair{Symbol, Any}}}} + offset::Ref{Int} # drift in the `content` index as structures are absorbed + point::Ref{Int} # current index in `content` + escape::Ref{Bool} # whether the last char was an escape char + interpolated::Ref{Bool} # whether any string interpolation occurs + end =# + + # Instead we'll just use a `NamedTuple` + state = let content = unescape_string(raw_content, ('{', '}', '$', '\n')) + (; content, bytes = Vector{UInt8}(content), + s = Iterators.Stateful(zip(eachindex(content), content)), + parts = Any[], + active_styles = Vector{Tuple{Int, Union{Symbol, Expr, Pair{Symbol, Any}}}}[], + pending_styles = Tuple{UnitRange{Int}, Union{Symbol, Expr, Pair{Symbol, Any}}}[], + offset = Ref(0), point = Ref(1), escape = Ref(false), interpolated = Ref(false)) + end + + # Value restrictions we can check against + valid_weights = ("thin", "extralight", "light", "semilight", "normal", + "medium", "semibold", "bold", "extrabold", "black") + valid_slants = ("italic", "oblique", "normal") + valid_underline_styles = ("straight", "double", "curly", "dotted", "dashed") + valid_colornames = + ("black", "red", "green", "yellow", "blue", "magenta", "cyan", "white", + "grey", "gray", "bright_black", "bright_red", "bright_green", "bright_yellow", + "bright_blue", "bright_magenta", "bright_cyan", "bright_white") + + function stywarn(state, message::String) + println(stderr, "WARNING: Styled string macro in module ", __module__, + " at ", something(__source__.file, ""), + ':', string(__source__.line), + something(if !isempty(state.s) + i, chr = peek(state.s) + " (just before '$chr' [$i])" + end, ""), + ", ", message, '.') + end + + function addpart!(state, stop::Int) + if state.point[] > stop+state.offset[]+ncodeunits(state.content[stop])-1 + return state.point[] = nextind(state.content, stop) + state.offset[] + end + str = String(state.bytes[ + state.point[]:stop+state.offset[]+ncodeunits(state.content[stop])-1]) + push!(state.parts, + if isempty(state.pending_styles) && isempty(state.active_styles) str else styles = Expr[] relevant_styles = Iterators.filter( - (start, _)::Tuple -> start <= stop + offset + 1, - Iterators.flatten(active_styles)) + (start, _)::Tuple -> start <= stop + state.offset[] + 1, + Iterators.flatten(state.active_styles)) for (start, prop) in relevant_styles - range = (start - point):(stop - point + offset + 1) + range = (start - state.point[]):(stop - state.point[] + state.offset[] + 1) push!(styles, Expr(:tuple, range, prop)) end - for (range, prop) in pending_styles + sort!(state.pending_styles, by = first) + for (range, prop) in state.pending_styles if !isempty(range) - push!(styles, Expr(:tuple, range .- point, prop)) + push!(styles, Expr(:tuple, range .- state.point[], prop)) end end - empty!(pending_styles) + empty!(state.pending_styles) if isempty(styles) str else - :(StyledString($str, $(Expr(:vect, styles...)))) + :($StyledString($str, $(Expr(:vect, styles...)))) end end) - point = nextind(content, stop) + offset + state.point[] = nextind(state.content, stop) + state.offset[] end - function addpart(start::Int, expr, stop::Int) - if point < start - addpart(start) + + function addpart!(state, start::Int, expr, stop::Int) + if state.point[] < start + addpart!(state, start) end - if isempty(active_styles) - push!(parts, expr) + if isempty(state.active_styles) + push!(state.parts, expr) else - push!(parts, - :(StyledString(string($expr), - $(last.(Iterators.flatten(active_styles))...)))) - map!.((_, prop)::Tuple -> (nextind(content, stop + offset), prop), active_styles, active_styles) + push!(state.parts, + :($StyledString(string($expr), + $(last.(Iterators.flatten(state.active_styles))...)))) + map!.((_, prop)::Tuple -> (stop + state.offset[] + 1, prop), + state.active_styles, state.active_styles) + end + end + + function escaped!(state, i, char) + if char in ('{', '}', '$', '\\') + deleteat!(state.bytes, i + state.offset[] - 1) + state.offset[] -= ncodeunits('\\') + elseif char == '\n' + deleteat!(state.bytes, i+state.offset[]-1:i+state.offset[]) + state.offset[] -= ncodeunits("\\\n") end + state.escape[] = false + end + + function interpolated!(state, i, _) + expr, nexti = readexpr!(state, i + ncodeunits('$')) + deleteat!(state.bytes, i + state.offset[]) + state.offset[] -= ncodeunits('$') + addpart!(state, i, expr, nexti) + state.point[] = nexti + state.offset[] + state.interpolated[] = true end - for (i, char) in s - if char == '\\' - escape = true - elseif escape - if char in ('{', '}', '$') - deleteat!(content_bytes, i + offset - 1) - offset -= 1 - elseif char == '\n' - deleteat!(content_bytes, i+offset-1:i+offset) - offset -= 2 + + function readexpr!(state, pos::Int) + expr, nextpos = Meta.parseatom(state.content, pos) + nchars = length(state.content[pos:prevind(state.content, nextpos)]) + for _ in 1:min(length(state.s), nchars) + popfirst!(state.s) + end + expr, nextpos + end + + readexpr!(state) = readexpr!(state, first(popfirst!(state.s)) + 1) + + function skipwhitespace!(state) + isempty(state.s) && return + while last(peek(state.s)) โˆˆ (' ', '\t', '\n') + popfirst!(state.s) + end + end + + function begin_style!(state, i, char) + hasvalue = false + newstyles = Vector{Tuple{Int, Union{Symbol, Expr, Pair{Symbol, Any}}}}() + while read_property!(state, i, char, newstyles) end + push!(state.active_styles, newstyles) + # Adjust bytes/offset based on how much the index + # has been incremented in the processing of the + # style declaration(s). + if !isempty(state.s) + nexti = first(peek(state.s)) + deleteat!(state.bytes, i+state.offset[]:nexti+state.offset[]-1) + state.offset[] -= nexti - i + end + end + + function end_style!(state, i, char) + # Close off most recent active style + for (start, prop) in pop!(state.active_styles) + push!(state.pending_styles, (start:i+state.offset[], prop)) + end + deleteat!(state.bytes, i + state.offset[]) + state.offset[] -= ncodeunits('}') + end + + function read_property!(state, i, char, newstyles) + skipwhitespace!(state) + isempty(state.s) && return false + nextchar = last(peek(state.s)) + if nextchar == ':' + popfirst!(state.s) + return false + elseif nextchar == '(' + read_inlineface!(state, i, char, newstyles) + else + read_face_or_keyval!(state, i, char, newstyles) + end + isempty(state.s) && return false + nextchar = last(peek(state.s)) + if nextchar == ',' + popfirst!(state.s) + true + elseif nextchar == ':' + true + elseif nextchar โˆˆ (' ', '\t', '\n') + skipwhitespace!(state) + true + else + stywarn(state, "malformed styled string construct") + false + end + end + + function read_inlineface!(state, i, char, newstyles) + # Substructure parsing helper functions + function readalph!(state, lastchar) + Iterators.takewhile( + c -> 'a' <= (lastchar = last(c)) <= 'z', state.s) |> + collect .|> last |> String, lastchar + end + function readsymbol!(state, lastchar) + Iterators.takewhile( + c -> (lastchar = last(c)) โˆ‰ (' ', '\t', '\n', ',', ')'), state.s) |> + collect .|> last |> String, lastchar + end + function parsecolor(color::String) + if color == "nothing" + elseif startswith(color, '#') && length(color) == 7 + tryparse(SimpleColor, color) + elseif startswith(color, "0x") && length(color) == 8 + tryparse(SimpleColor, '#' * color[3:end]) + else + color โˆˆ valid_colornames || + stywarn(state, "unrecognised named color '$color' (should be $(join(valid_colornames, ", ", ", or ")))") + SimpleColor(Symbol(color)) end - escape = false - elseif char == '$' - # Interpolation - expr, nexti = Meta.parseatom(content, i + 1) - deleteat!(content_bytes, i + offset) - offset -= 1 - nchars = length(content[i:prevind(content, nexti)]) - for _ in 1:min(length(s), nchars-1) - popfirst!(s) + end + function nextnonwhitespace!(state, lastchar) + if lastchar โˆˆ (' ', '\t', '\n') + skipwhitespace!(state) + _, lastchar = popfirst!(state.s) end - addpart(i, expr, nexti) - point = nexti + offset - interpolated = true - elseif char == '{' - # Property declaration parsing and application - properties = true - hasvalue = false - newstyles = Vector{Tuple{Int, Union{Symbol, Expr, Pair{Symbol, Any}}}}() - while properties - if !isnothing(peek(s)) && last(peek(s)) == '(' - # Inline face - popfirst!(s) - specstr = Iterators.takewhile(c -> last(c) != ')', s) |> - collect .|> last |> String - spec = map(split(specstr, ',')) do spec - spec = rstrip(spec) - kv = split(spec, '=', limit=2) - if length(kv) == 2 - kv[1] => @something(tryparse(Bool, kv[2]), - String(kv[2])) - else "" => "" end - end |> Dict - push!(newstyles, - (nextind(content, i + offset), - Pair{Symbol, Any}(:face, convert(Face, spec)))) - if isnothing(peek(s)) || last(popfirst!(s)) != ',' - properties = false + lastchar + end + function read_underline!(state, lastchar) + if last(peek(state.s)) == '(' + popfirst!(state.s) + skipwhitespace!(state) + ucolor_str, ucolor = if last(peek(state.s)) == ',' + lastchar = last(popfirst!(state.s)) + "", nothing + else + word, lastchar = readsymbol!(state, lastchar) + word, parsecolor(word) + end + lastchar = nextnonwhitespace!(state, lastchar) + if !isempty(state) && lastchar == ',' + skipwhitespace!(state) + ustyle, lastchar = readalph!(state, lastchar) + lastchar = nextnonwhitespace!(state, lastchar) + if lastchar == ')' + lastchar = last(popfirst!(state.s)) + else + stywarn(state, "malformed underline value, should be (,