Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
8ed2e52
Base: Replace many 1-arg `@assert`s with 2-arg (#61230)
topolarity Mar 4, 2026
8eb1cfb
Bump SparseArrays version
JamesWrigley Mar 13, 2026
71a383e
Merge pull request #61322 from JamesWrigley/sparsearrays-bump
ViralBShah Mar 14, 2026
20ec61f
inference: Cache tombstoned const-prop results to prevent non-termina…
aviatesk Mar 15, 2026
aabfe94
Revert "make sched_task more robust (#59669)"
KristofferC Feb 18, 2026
cd8c9ef
Revert "simplify `wait()` (#58595)"
KristofferC Feb 18, 2026
0ea99be
Revert "Scheduler: Use a "scheduler" task for thread sleep (#57544)"
KristofferC Feb 18, 2026
aaeedb1
compensate test for "Commit 3847ff1434 — Replace Base.Workqueues with…
KristofferC Mar 18, 2026
8fa5c01
Merge pull request #61065 from JuliaLang/kc/ctrl_c_revert
KristofferC Mar 18, 2026
76dac3f
precompilation: fix show_progress crash when bar.current goes negativ…
IanButterworth Mar 16, 2026
32083c9
REPL: fix highlighting of the region and of enclosing parentheses (#6…
matthias314 Mar 17, 2026
68e5869
deps: re-sign bundled zstd on macOS (#61355)
fingolfin Mar 20, 2026
705ed5d
Remove duplicated entry in NEWS.md for Julia 1.13
PatrickHaecker Mar 26, 2026
0cdca89
subtype: isolate `Union` state in `subtype_ccheck` to prevent exponen…
aviatesk Mar 27, 2026
fb9683b
check `issimpleenoughtype` for PartialStruct during `issimplertype` (…
adienes Mar 31, 2026
02b51c5
Merge pull request #61412 from PatrickHaecker/patch-8
JamesWrigley Apr 8, 2026
5915365
Fix `nothrow` effects for `(s/z)ext_int` / `trunc_int` intrinsics (#6…
topolarity Mar 30, 2026
7005f63
subtype: ignore the rest ∃ decisions if env is unchanged during `loca…
N5N3 Apr 6, 2026
41699d4
Use `@static if` in `CompilerSupportLibraries_jll.__init__()` (#61516)
topolarity Apr 7, 2026
d4713ea
Fix `Base.summarysize` crash for instances of foreign types (#61517)
fingolfin Apr 7, 2026
9671cb2
Fix performance regression in hvcat of simple matrices (#57422)
BioTurboNick Apr 8, 2026
a5b1dac
store crc of sysimage at build time and stop recomputing it on every …
KristofferC Apr 9, 2026
9d78958
Fix-up `--trim` support for `hcat` / `vcat` / etc. (#61551)
topolarity Apr 10, 2026
d108372
Fix `--trim` compatibility for `BoundsError` (#61561)
topolarity Apr 11, 2026
2881701
subtype: Rename `right` to existential (#61424)
Keno Mar 30, 2026
c60a268
precompile: fix deps list for extensions relying on stdlibs
vtjnash Oct 31, 2025
dfd93da
Reapply "precompile: fail in (closer to) linear time and linear error…
vtjnash Oct 31, 2025
633c488
precompilation: fix extension dep graph to iterate to fixed point (#6…
IanButterworth Mar 16, 2026
b1f9a86
Set max_methods to 1 for merge/merge!/mergewith/mergewith! (#61330)
JamesWrigley Mar 25, 2026
1cfbf42
inference: Respect `@nospecializeinfer` semantics in constant prop (#…
aviatesk Apr 8, 2026
c095d49
Print `full_name` after precompiling extension (#60456)
JoshuaLampert Dec 23, 2025
03dd28b
REPL: Fix call to correct `hascolor` function (#61142)
DilumAluthge Mar 1, 2026
1685f4e
Preferences: Fully serialize compile-time preferences (#61214)
topolarity Mar 5, 2026
e4103a5
LateLowerGCFrame: Fix GC rooting for stores through select/phi of all…
gbaraldi Mar 9, 2026
a2a0c05
precompilation: make the handling of project vs workspace more simila…
KristofferC Mar 13, 2026
82f57d0
precompilation: improve warn_loaded messaging for transitive deps (#6…
IanButterworth Mar 14, 2026
1b5cd3c
fixup "precompilation: improve warn_loaded messaging for transitive d…
IanButterworth Mar 15, 2026
921785e
codegen: emit bounds checks as cold branches instead of ANDs (#61535)
gbaraldi Apr 10, 2026
d7e8801
Convert to Float64 in TOML's printvalue() to avoid invalidations (#61…
JamesWrigley Apr 14, 2026
32f1b68
reduce probability of spurious error when outputs are interleaved
KristofferC Apr 15, 2026
b451085
fixup! allow finding stdlibs that are normal packages in the manifest…
KristofferC Apr 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions Compiler/src/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1307,7 +1307,6 @@ end
function const_prop_call(interp::AbstractInterpreter,
mi::MethodInstance, result::MethodCallResult, arginfo::ArgInfo, sv::AbsIntState,
concrete_eval_result::Union{Nothing,ConstCallResult}=nothing)
inf_cache = get_inference_cache(interp)
𝕃ᵢ = typeinf_lattice(interp)
forwarded_argtypes = compute_forwarded_argtypes(interp, arginfo, sv)
# use `cache_argtypes` that has been constructed for fresh regular inference if available
Expand All @@ -1318,8 +1317,14 @@ function const_prop_call(interp::AbstractInterpreter,
cache_argtypes = matching_cache_argtypes(𝕃ᵢ, mi)
end
argtypes = matching_cache_argtypes(𝕃ᵢ, mi, forwarded_argtypes, cache_argtypes)
inf_result = cache_lookup(𝕃ᵢ, mi, argtypes, inf_cache)
if inf_result !== nothing
argtypes = get_nospecializeinfer_argtypes(argtypes, cache_argtypes, mi.def::Method)
inf_result = cache_lookup(𝕃ᵢ, mi, argtypes, get_inference_cache(interp))
if inf_result === missing
# a previous const-prop attempt hit a cycle and produced a limited result;
# don't re-attempt the same work that would lead to the same limited outcome
add_remark!(interp, sv, "[constprop] Found cached but limited constant inference result")
return nothing
elseif inf_result isa InferenceResult
# found the cache for this constant prop'
if inf_result.result === nothing
add_remark!(interp, sv, "[constprop] Found cached constant inference in a cycle")
Expand Down Expand Up @@ -1356,6 +1361,13 @@ function const_prop_call(interp::AbstractInterpreter,
pop!(callstack)
return nothing
end
if inf_result.tombstone
# This const-prop attempt resolved but hit a cycle and produced a limited result.
# The tombstoned entry is already cached by `promotecache!` via the normal local
# cache mechanism, so `constprop_cache_lookup` will find it on subsequent lookups.
add_remark!(interp, sv, "[constprop] Constant inference produced a limited result")
return nothing
end
existing_edge = result.edge
inf_result.ci_as_edge = codeinst_as_edge(interp, frame, existing_edge)
@assert frame.frameid != 0 && frame.cycleid == frame.frameid
Expand Down
30 changes: 28 additions & 2 deletions Compiler/src/inferenceresult.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,25 @@ function matching_cache_argtypes(::AbstractLattice, mi::MethodInstance)
return most_general_argtypes(isa(def, Method) ? def : nothing, specTypes)
end

# For `@nospecializeinfer` methods, widen the `@nospecialize`'d argument positions back to
# `cache_argtypes` values to respect the `@nospecializeinfer` semantics.
# This also ensures that the constprop `argtypes` have the same length as `cache_argtypes`.
function get_nospecializeinfer_argtypes(argtypes::Vector{Any}, cache_argtypes::Vector{Any},
method::Method)
is_nospecializeinfer(method) || return argtypes
nargs = Int(method.nargs)
new_argtypes = Vector{Any}(undef, length(cache_argtypes))
for i = 1:length(cache_argtypes)
i_arg = min(i - 1, nargs - 1) # 0-indexed, 0 is the function slot
if i_arg > 0 && !iszero(method.nospecialize & (1 << (i_arg - 1)))
new_argtypes[i] = cache_argtypes[i]
else
new_argtypes[i] = argtypes[i]
end
end
return new_argtypes
end

struct SimpleArgtypes
argtypes::Vector{Any}
end
Expand Down Expand Up @@ -182,8 +201,8 @@ function cache_lookup(𝕃::AbstractLattice, mi::MethodInstance, given_argtypes:
cache::Vector{InferenceResult})
method = mi.def::Method
nargtypes = length(given_argtypes)
found_tombstone = false
for cached_result in cache
cached_result.tombstone && continue # ignore deleted entries (due to LimitedAccuracy)
cached_result.linfo === mi || continue
cache_argtypes = cached_result.argtypes
@assert length(cache_argtypes) == nargtypes "invalid `cache_argtypes` for `mi`"
Expand All @@ -193,8 +212,15 @@ function cache_lookup(𝕃::AbstractLattice, mi::MethodInstance, given_argtypes:
@goto next_cache
end
end
# Don't return tombstoned entries as cache items: they represent rejected work
# (due to LimitedAccuracy). Instead, record that a tombstone was found so the
# caller can avoid re-attempting the same const-prop that would hit the same limit.
if cached_result.tombstone
found_tombstone = true
@goto next_cache
end
return cached_result
@label next_cache
end
return nothing
return found_tombstone ? missing : nothing
end
10 changes: 8 additions & 2 deletions Compiler/src/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2988,16 +2988,22 @@ function intrinsic_exct(𝕃::AbstractLattice, f::IntrinsicFunction, argtypes::V
return ErrorException
end

# fpext, fptrunc, fptoui, fptosi, uitofp, and sitofp have further
# restrictions on the allowed types.
# fpext, sext_int, zext_int, fptrunc, trunc_int, fptoui, fptosi, uitofp, and sitofp
# have further restrictions on the allowed types.
if f === Intrinsics.fpext &&
!(ty <: CORE_FLOAT_TYPES && xty <: CORE_FLOAT_TYPES && Core.sizeof(ty) > Core.sizeof(xty))
return ErrorException
end
if (f === Intrinsics.sext_int || f === Intrinsics.zext_int) && !(Core.sizeof(ty) > Core.sizeof(xty))
return ErrorException
end
if f === Intrinsics.fptrunc &&
!(ty <: CORE_FLOAT_TYPES && xty <: CORE_FLOAT_TYPES && Core.sizeof(ty) < Core.sizeof(xty))
return ErrorException
end
if f === Intrinsics.trunc_int && !(Core.sizeof(ty) < Core.sizeof(xty))
return ErrorException
end
if (f === Intrinsics.fptoui || f === Intrinsics.fptosi) && !(xty <: CORE_FLOAT_TYPES)
return ErrorException
end
Expand Down
10 changes: 6 additions & 4 deletions Compiler/src/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -608,12 +608,14 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter, cycleid::
# A parent may be cached still, but not this intermediate work:
# we can throw everything else away now. Caching anything can confuse later
# heuristics to consider it worth trying to pursue compiling this further and
# finding infinite work as a result. Avoiding caching helps to ensure there is only
# a finite amount of work that can be discovered later (although potentially still a
# large multiplier on it).
# finding infinite work as a result. Avoiding global caching helps to ensure there
# is only a finite amount of work that can be discovered later (although potentially
# still a large multiplier on it). We still allow local caching so that tombstoned
# entries can be found by `constprop_cache_lookup` to prevent re-attempting the same
# const-prop work that would hit the same limit.
result.src = nothing
result.tombstone = true
me.cache_mode = CACHE_MODE_NULL
me.cache_mode &= ~CACHE_MODE_GLOBAL
set_inlineable!(me.src, false)
else
# annotate fulltree with type information,
Expand Down
1 change: 1 addition & 0 deletions Compiler/src/typelimits.jl
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ end
typea === typeb && return true
if typea isa PartialStruct
aty = widenconst(typea)
issimplertype(𝕃, aty, widenconst(typeb)) || return false
if typeb isa Const || typeb isa PartialStruct
@assert n_initialized(typea) ≤ n_initialized(typeb) "typeb ⊑ typea is assumed"
elseif typeb isa PartialStruct
Expand Down
27 changes: 27 additions & 0 deletions Compiler/test/effects.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1493,3 +1493,30 @@ function null_offset(offset)
Ptr{UInt8}(C_NULL) + offset
end
@test null_offset(Int(100)) == Ptr{UInt8}(UInt(100))

# https://github.com/JuliaLang/julia/issues/61435
function catch_error_61435(f, x)
try
f(x)
catch
return :caught
end
end
let f = (x) -> Core.Intrinsics.sext_int(Int16, x)
@test Compiler.is_nothrow(Base.infer_effects(f, (Int8,)))
@test !Compiler.is_nothrow(Base.infer_effects(f, (Int16,)))
@test !Compiler.is_nothrow(Base.infer_effects(f, (Int32,)))
@test catch_error_61435(f, Int16(0)) === :caught
end
let f = (x) -> Core.Intrinsics.zext_int(UInt16, x)
@test Compiler.is_nothrow(Base.infer_effects(f, (UInt8,)))
@test !Compiler.is_nothrow(Base.infer_effects(f, (UInt16,)))
@test !Compiler.is_nothrow(Base.infer_effects(f, (UInt32,)))
@test catch_error_61435(f, UInt16(0)) === :caught
end
let f = (x) -> Core.Intrinsics.trunc_int(Int16, x)
@test !Compiler.is_nothrow(Base.infer_effects(f, (Int8,)))
@test !Compiler.is_nothrow(Base.infer_effects(f, (Int16,)))
@test Compiler.is_nothrow(Base.infer_effects(f, (Int32,)))
@test catch_error_61435(f, Int16(0)) === :caught
end
36 changes: 36 additions & 0 deletions Compiler/test/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5077,6 +5077,22 @@ let 𝕃ᵢ = Compiler.fallback_lattice
@test t.fields == Any[Const(42), Int]
end

# issue #60715
let 𝕃 = Compiler.fallback_lattice
local fn, fn1, pn, pn1
F(n) = iszero(n) ? Union{} : Tuple{Int, Union{Int, F(n-1)}}
P(n) = (f = F(n); Compiler.PartialStruct(𝕃, f, [Const(0), fieldtype(f, 2)]))

n = 0
while Compiler.issimpleenoughtype(F(n+1))
n += 1
fn, fn1, pn, pn1 = F(n), F(n+1), P(n), P(n+1)
@test Compiler.:⊑(𝕃, pn, pn1)
end
@test !Compiler.issimplertype(𝕃, pn1, pn)
@test !isa(Compiler.tmerge(𝕃, pn, pn1), Compiler.PartialStruct)
end

foo_empty_vararg(i...) = i[2]
bar_empty_vararg(i) = foo_empty_vararg(10, 20, 30, i...)
@test bar_empty_vararg(Union{}[]) === 20
Expand Down Expand Up @@ -6545,4 +6561,24 @@ function issue60883()
end
@test issue60883() === true

# issue #60715
let
f() = 1; f(_, x...) = (0, f(x...))
@test f(1, 2, 3) == (0, (0, (0, 1)))
end

# aviatesk/JETLS.jl/issues/618
Base.@nospecializeinfer function jetls618(a, @nospecialize(rest...))
if a > 0
z = a + length(rest)
else
z = 0
end
println(z)
return z
end
@test Base.infer_return_type() do
jetls618(1,2,3), jetls618(1,2,3,4)
end == Tuple{Int,Int}

end # module inference
8 changes: 7 additions & 1 deletion Compiler/test/inline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,14 @@ end
end

(src, _) = only(code_typed(sum27403, Tuple{Vector{Int}}))
is_bounds_throw_invoke_target(@nospecialize(callee)) =
callee === Base.throw_boundserror ||
callee == Core.GlobalRef(Base, :throw_boundserror) ||
callee == Core.GlobalRef(Base, :_throw_boundserror_indices) ||
(callee isa Core.MethodInstance && (callee.def.def.name === :throw_boundserror ||
callee.def.def.name === :_throw_boundserror_indices))
@test !any(src.code) do x
x isa Expr && x.head === :invoke && !(x.args[2] in (Core.GlobalRef(Base, :throw_boundserror), Base.throw_boundserror))
x isa Expr && x.head === :invoke && !is_bounds_throw_invoke_target(x.args[2])
end
end

Expand Down
5 changes: 0 additions & 5 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,6 @@ Deprecated or removed

* The method `merge(combine::Callable, d::AbstractDict...)` is now deprecated to favor `mergewith` instead ([#59775]).

Deprecated or removed
---------------------

* The method `merge(combine::Callable, d::AbstractDict...)` is now deprecated to favor `mergewith` instead ([#59775]).

<!--- generated by NEWS-update.jl: -->
[#47102]: https://github.com/JuliaLang/julia/issues/47102
[#48507]: https://github.com/JuliaLang/julia/issues/48507
Expand Down
57 changes: 30 additions & 27 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ See also [`checkbounds`](@ref).
"""
function checkbounds_indices(::Type{Bool}, inds::Tuple, I::Tuple{Any, Vararg})
@inline
return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &
return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &&
checkbounds_indices(Bool, safe_tail(inds), tail(I))
end

Expand Down Expand Up @@ -2394,9 +2394,7 @@ end
function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
N < 0 &&
throw(ArgumentError("concatenation dimension must be non-negative"))
A = cat_similar(xs[1], T, (ntuple(Returns(1), Val(N - 1))..., length(xs)))
hvncat_fill!(A, false, xs)
return A
return reshape(T[xs...], (ntuple(Returns(1), Val(N - 1))..., length(xs)))
end

function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N}
Expand Down Expand Up @@ -2720,55 +2718,60 @@ function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::

# copy into final array
A = cat_similar(as[1], T, ntuple(i -> outdims[i], nd))
hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
if !any(iszero, outdims)
hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
end
return A
end

function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int},
d1::Int, d2::Int, as::Tuple) where {T, N}
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int}, d1::Int, d2::Int, as::Tuple) where {T, N}
N > 1 || throw(ArgumentError("dimensions of the destination array must be at least 2"))
length(scratch1) == length(scratch2) == N ||
throw(ArgumentError("scratch vectors must have as many elements as the destination array has dimensions"))
0 < d1 < 3 &&
0 < d2 < 3 &&
d1 != d2 ||
throw(ArgumentError("d1 and d2 must be either 1 or 2, exclusive."))
outdims = size(A)
outdimsprod = cumprod(size(A))
offsets = scratch1
inneroffsets = scratch2
for a ∈ as
startindex = CartesianIndex(ntuple(i -> offsets[i] + 1, Val(N)))
if isa(a, AbstractArray)
for ai ∈ a
@inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
A[Ai] = ai

@inbounds for j ∈ 1:N
inneroffsets[j] += 1
inneroffsets[j] < cat_size(a, j) && break
inneroffsets[j] = 0
if !isempty(a)
if length(a) > 4
endindex = CartesianIndex(ntuple(i -> offsets[i] + cat_size(a, i), Val(N)))
@inbounds A[startindex:endindex] = a
else
for ai ∈ a
@inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdimsprod, N)
@inbounds A[Ai] = ai
@inbounds for j ∈ 1:N
inneroffsets[j] += 1
inneroffsets[j] < cat_size(a, j) && break
inneroffsets[j] = 0
end
end
end
end
else
@inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
A[Ai] = a
@inbounds A[startindex] = a
end

@inbounds for j ∈ (d1, d2, 3:N...)
offsets[j] += cat_size(a, j)
offsets[j] < outdims[j] && break
offsets[j] = 0
@inbounds for i ∈ (d1, d2, 3:N...)
offsets[i] += cat_size(a, i)
offsets[i] < cat_size(A, i) && break
offsets[i] = 0
end
end
end

@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
outdims::Tuple{Vararg{Int}}, nd::Int)
outdimsprod::NTuple{N, Int}, nd::Int) where {N}
Ai = inneroffsets[1] + offsets[1] + 1
for j ∈ 2:nd
increment = inneroffsets[j] + offsets[j]
for k ∈ 1:j-1
increment *= outdims[k]
end
increment *= outdimsprod[j - 1]
Ai += increment
end
Ai
Expand Down Expand Up @@ -3490,7 +3493,7 @@ julia> map!(+, zeros(Int, 5), 100:999, 1:3)
```
"""
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
@assert !isempty(As) # should dispatch to map!(f, A)
@assert !isempty(As) "should dispatch to map!(f, A)"
map_n!(f, dest, As)
end

Expand Down
4 changes: 4 additions & 0 deletions base/abstractdict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ function merge!(d::AbstractDict, others::AbstractDict...)
end
return d
end
typeof(merge!).name.max_methods = UInt8(1)

"""
mergewith!(combine, d::AbstractDict, others::AbstractDict...) -> d
Expand Down Expand Up @@ -282,6 +283,7 @@ Dict{Int64, Int64} with 3 entries:
function mergewith!(combine, d::AbstractDict, others::AbstractDict...)
foldl(mergewith!(combine), others; init = d)
end
typeof(mergewith!).name.max_methods = UInt8(1)

function mergewith!(combine, d1::AbstractDict, d2::AbstractDict)
for (k, v) in d2
Expand Down Expand Up @@ -358,6 +360,7 @@ Dict{String, Float64} with 3 entries:
"""
merge(d::AbstractDict, others::AbstractDict...) =
merge!(_typeddict(d, others...), others...)
typeof(merge).name.max_methods = UInt8(1)

"""
mergewith(combine, d::AbstractDict, others::AbstractDict...)
Expand Down Expand Up @@ -405,6 +408,7 @@ Dict{Any, Any} with 1 entry:
mergewith(combine, d::AbstractDict, others::AbstractDict...) =
mergewith!(combine, _typeddict(d, others...), others...)
mergewith(combine) = (args...) -> mergewith(combine, args...)
typeof(mergewith).name.max_methods = UInt8(1)
merge(combine::Callable, d::AbstractDict, others::AbstractDict...) =
merge!(combine, _typeddict(d, others...), others...)

Expand Down
Loading
Loading