Skip to content

Commit

Permalink
Backports for Julia 1.10.7 (#56381)
Browse files Browse the repository at this point in the history
Backported PRs:
- [x] #50832 <!-- Subtype: bug fix for bounds with deeper covariant var
-->
- [x] #51782 <!-- Fix remove-addrspaces pass in the presence of globals
with addrspaces -->
- [x] #55720 <!-- Fix `pkgdir` for extensions -->
- [x] #55773 <!-- Add compat entry for `Base.donotdelete` -->
- [x] #55886 <!-- irrationals: restrict assume effects annotations to
known types -->
- [x] #55867 <!-- update `hash` doc string: `widen` not required any
more -->
- [x] #56148 <!-- Make loading work when stdlib deps are missing in the
manifest -->
- [x] #55870 <!-- fix infinite recursion in `promote_type` for
`Irrational` -->
- [x] #56252 <!-- REPL: fix brace detection when ' is used for transpose
-->
- [x] #56264 <!-- inference: fix inference error from constructing
invalid `TypeVar` -->
- [x] #56276 <!-- move time_imports and trace_* macros to Base but
remain owned by InteractiveUtils -->
- [x] #56254 <!-- REPL: don't complete str and cmd macros when the input
matches the internal name like `r_` to `r"` -->
- [x] #56280 <!-- Fix trampoline warning on x86 as well -->
- [x] #56304 <!-- typeintersect: more fastpath to skip intersect under
circular env -->
- [x] #56306 <!-- InteractiveUtils.jl: fixes issue where subtypes
resolves bindings and causes deprecation warnings -->
- [x] #42080 <!-- recommend explicit `using Foo: Foo, ...` in package
code (was: "using considered harmful") -->
- [x] #56441 <!-- Profile: mention `kill -s SIGUSR1 julia_pid` for Linux
-->
- [x] #56511 <!-- The `info` in LAPACK calls should be a Ref instead of
a Ptr -->
- [x] #55052 <!-- Fix `(l/r)mul!` with `Diagonal`/`Bidiagonal` -->
- [x] #52694 <!-- Reinstate similar for AbstractQ for backward
compatibility -->
  • Loading branch information
KristofferC authored Nov 12, 2024
2 parents 67dffc4 + db84d85 commit 9ee861f
Show file tree
Hide file tree
Showing 66 changed files with 793 additions and 348 deletions.
5 changes: 1 addition & 4 deletions base/compiler/ssair/domtree.jl
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,7 @@ function SNCA!(domtree::GenericDomTree{IsPostDom}, blocks::Vector{BasicBlock}, m
ancestors = copy(D.to_parent_pre)
relevant_blocks = IsPostDom ? (1:max_pre) : (2:max_pre)
for w::PreNumber in reverse(relevant_blocks)
# LLVM initializes this to the parent, the paper initializes this to
# `w`, but it doesn't really matter (the parent is a predecessor, so at
# worst we'll discover it below). Save a memory reference here.
semi_w = typemax(PreNumber)
semi_w = ancestors[w]
last_linked = PreNumber(w + 1)
for v dom_edges(domtree, blocks, D.from_pre[w])
# For the purpose of the domtree, ignore virtual predecessors into
Expand Down
12 changes: 10 additions & 2 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -574,8 +574,16 @@ add_tfunc(svec, 0, INT_INF, @nospecs((𝕃::AbstractLattice, args...)->SimpleVec
return TypeVar
end
end
tv = TypeVar(nval, lb, ub)
return PartialTypeVar(tv, lb_certain, ub_certain)
lb_valid = lb isa Type || lb isa TypeVar
ub_valid = ub isa Type || ub isa TypeVar
if lb_valid && ub_valid
tv = TypeVar(nval, lb, ub)
return PartialTypeVar(tv, lb_certain, ub_certain)
elseif !lb_valid && lb_certain
return Union{}
elseif !ub_valid && ub_certain
return Union{}
end
end
return TypeVar
end
Expand Down
11 changes: 11 additions & 0 deletions base/docs/basedocs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ kw"help", kw"Julia", kw"julia", kw""
available for direct use. Names can also be used via dot syntax (e.g. `Foo.foo` to access
the name `foo`), whether they are `export`ed or not.
See the [manual section about modules](@ref modules) for details.

!!! note
When two or more packages/modules export a name and that name does not refer to the
same thing in each of the packages, and the packages are loaded via `using` without
an explicit list of names, it is an error to reference that name without qualification.
It is thus recommended that code intended to be forward-compatible with future versions
of its dependencies and of Julia, e.g., code in released packages, list the names it
uses from each loaded package, e.g., `using Foo: Foo, f` rather than `using Foo`.
"""
kw"using"

Expand Down Expand Up @@ -3285,6 +3293,9 @@ unused and delete the entire benchmark code).
`donotdelete(1+1)`, no add instruction needs to be executed at runtime and
the code is semantically equivalent to `donotdelete(2).`

!!! compat "Julia 1.8"
This method was added in Julia 1.8.

# Examples

```julia
Expand Down
4 changes: 1 addition & 3 deletions base/hashing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ optional second argument `h` is another hash code to be mixed with the result.
New types should implement the 2-argument form, typically by calling the 2-argument `hash`
method recursively in order to mix hashes of the contents with each other (and with `h`).
Typically, any type that implements `hash` should also implement its own [`==`](@ref) (hence
[`isequal`](@ref)) to guarantee the property mentioned above. Types supporting subtraction
(operator `-`) should also implement [`widen`](@ref), which is required to hash
values inside heterogeneous arrays.
[`isequal`](@ref)) to guarantee the property mentioned above.

The hash value may change when a new Julia process is started.

Expand Down
33 changes: 24 additions & 9 deletions base/irrationals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,22 @@ promote_rule(::Type{<:AbstractIrrational}, ::Type{Float16}) = Float16
promote_rule(::Type{<:AbstractIrrational}, ::Type{Float32}) = Float32
promote_rule(::Type{<:AbstractIrrational}, ::Type{<:AbstractIrrational}) = Float64
promote_rule(::Type{<:AbstractIrrational}, ::Type{T}) where {T<:Real} = promote_type(Float64, T)
promote_rule(::Type{S}, ::Type{T}) where {S<:AbstractIrrational,T<:Number} = promote_type(promote_type(S, real(T)), T)

function promote_rule(::Type{S}, ::Type{T}) where {S<:AbstractIrrational,T<:Number}
U = promote_type(S, real(T))
if S <: U
# prevent infinite recursion
promote_type(Float64, T)
else
promote_type(U, T)
end
end

AbstractFloat(x::AbstractIrrational) = Float64(x)::Float64
Float16(x::AbstractIrrational) = Float16(Float32(x)::Float32)
Complex{T}(x::AbstractIrrational) where {T<:Real} = Complex{T}(T(x))

# XXX this may change `DEFAULT_PRECISION`, thus not effect free
@assume_effects :total function Rational{T}(x::AbstractIrrational) where T<:Integer
function _irrational_to_rational(::Type{T}, x::AbstractIrrational) where T<:Integer
o = precision(BigFloat)
p = 256
while true
Expand All @@ -63,13 +71,16 @@ Complex{T}(x::AbstractIrrational) where {T<:Real} = Complex{T}(T(x))
p += 32
end
end
Rational{BigInt}(x::AbstractIrrational) = throw(ArgumentError("Cannot convert an AbstractIrrational to a Rational{BigInt}: use rationalize(BigInt, x) instead"))
Rational{T}(x::AbstractIrrational) where {T<:Integer} = _irrational_to_rational(T, x)
_throw_argument_error_irrational_to_rational_bigint() = throw(ArgumentError("Cannot convert an AbstractIrrational to a Rational{BigInt}: use rationalize(BigInt, x) instead"))
Rational{BigInt}(::AbstractIrrational) = _throw_argument_error_irrational_to_rational_bigint()

@assume_effects :total function (t::Type{T})(x::AbstractIrrational, r::RoundingMode) where T<:Union{Float32,Float64}
function _irrational_to_float(::Type{T}, x::AbstractIrrational, r::RoundingMode) where T<:Union{Float32,Float64}
setprecision(BigFloat, 256) do
T(BigFloat(x)::BigFloat, r)
end
end
(::Type{T})(x::AbstractIrrational, r::RoundingMode) where {T<:Union{Float32,Float64}} = _irrational_to_float(T, x, r)

float(::Type{<:AbstractIrrational}) = Float64

Expand Down Expand Up @@ -107,14 +118,18 @@ end
<=(x::AbstractFloat, y::AbstractIrrational) = x < y

# Irrational vs Rational
@assume_effects :total function rationalize(::Type{T}, x::AbstractIrrational; tol::Real=0) where T
function _rationalize_irrational(::Type{T}, x::AbstractIrrational, tol::Real) where {T<:Integer}
return rationalize(T, big(x), tol=tol)
end
@assume_effects :total function lessrational(rx::Rational{<:Integer}, x::AbstractIrrational)
# an @assume_effects :total version of `<` for determining if the rationalization of
# an irrational number required rounding up or down
function rationalize(::Type{T}, x::AbstractIrrational; tol::Real=0) where {T<:Integer}
return _rationalize_irrational(T, x, tol)
end
function _lessrational(rx::Rational, x::AbstractIrrational)
return rx < big(x)
end
function lessrational(rx::Rational, x::AbstractIrrational)
return _lessrational(rx, x)
end
function <(x::AbstractIrrational, y::Rational{T}) where T
T <: Unsigned && x < 0.0 && return true
rx = rationalize(T, x)
Expand Down
141 changes: 102 additions & 39 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,21 @@ function find_package(arg)
return locate_package(pkg, env)
end

# is there a better/faster ground truth?
function is_stdlib(pkgid::PkgId)
pkgid.name in readdir(Sys.STDLIB) || return false
stdlib_root = joinpath(Sys.STDLIB, pkgid.name)
project_file = locate_project_file(stdlib_root)
if project_file isa String
d = parsed_toml(project_file)
uuid = get(d, "uuid", nothing)
if uuid !== nothing
return UUID(uuid) == pkgid.uuid
end
end
return false
end

"""
Base.identify_package_env(name::String)::Union{Tuple{PkgId, String}, Nothing}
Base.identify_package_env(where::Union{Module,PkgId}, name::String)::Union{Tuple{PkgId, String} Nothing}
Expand Down Expand Up @@ -333,6 +348,12 @@ function identify_package_env(where::PkgId, name::String)
end
break # found in implicit environment--return "not found"
end
if pkg_env === nothing && is_stdlib(where)
# if not found it could be that manifests are from a different julia version/commit
# where stdlib dependencies have changed, so look up deps based on the stdlib Project.toml
# as a fallback
pkg_env = identify_stdlib_project_dep(where, name)
end
end
if cache !== nothing
cache.identified_where[(where, name)] = pkg_env
Expand All @@ -359,6 +380,22 @@ function identify_package_env(name::String)
return pkg_env
end

function identify_stdlib_project_dep(stdlib::PkgId, depname::String)
@debug """
Stdlib $(repr("text/plain", stdlib)) is trying to load `$depname`
which is not listed as a dep in the load path manifests, so resorting to search
in the stdlib Project.tomls for true deps"""
stdlib_projfile = locate_project_file(joinpath(Sys.STDLIB, stdlib.name))
stdlib_projfile === nothing && return nothing
found = explicit_project_deps_get(stdlib_projfile, depname)
if found !== nothing
@debug "$(repr("text/plain", stdlib)) indeed depends on $depname in project $stdlib_projfile"
pkgid = PkgId(found, depname)
return pkgid, stdlib_projfile
end
return nothing
end

_nothing_or_first(x) = x === nothing ? nothing : first(x)

"""
Expand Down Expand Up @@ -499,6 +536,8 @@ package root.
To get the root directory of the package that implements the current module
the form `pkgdir(@__MODULE__)` can be used.

If an extension module is given, the root of the parent package is returned.

```julia-repl
julia> pkgdir(Foo)
"/path/to/Foo.jl"
Expand All @@ -514,7 +553,19 @@ function pkgdir(m::Module, paths::String...)
rootmodule = moduleroot(m)
path = pathof(rootmodule)
path === nothing && return nothing
return joinpath(dirname(dirname(path)), paths...)
original = path
path, base = splitdir(dirname(path))
if base == "src"
# package source in `../src/Foo.jl`
elseif base == "ext"
# extension source in `../ext/FooExt.jl`
elseif basename(path) == "ext"
# extension source in `../ext/FooExt/FooExt.jl`
path = dirname(path)
else
error("Unexpected path structure for module source: $original")
end
return joinpath(path, paths...)
end

function get_pkgversion_from_path(path)
Expand Down Expand Up @@ -827,14 +878,14 @@ function explicit_manifest_deps_get(project_file::String, where::PkgId, name::St
entry = entry::Dict{String, Any}
uuid = get(entry, "uuid", nothing)::Union{String, Nothing}
uuid === nothing && continue
# deps is either a list of names (deps = ["DepA", "DepB"]) or
# a table of entries (deps = {"DepA" = "6ea...", "DepB" = "55d..."}
deps = get(entry, "deps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing}
if UUID(uuid) === where.uuid
found_where = true
# deps is either a list of names (deps = ["DepA", "DepB"]) or
# a table of entries (deps = {"DepA" = "6ea...", "DepB" = "55d..."}
deps = get(entry, "deps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing}
if deps isa Vector{String}
found_name = name in deps
break
found_name && @goto done
elseif deps isa Dict{String, Any}
deps = deps::Dict{String, Any}
for (dep, uuid) in deps
Expand All @@ -853,30 +904,33 @@ function explicit_manifest_deps_get(project_file::String, where::PkgId, name::St
return PkgId(UUID(uuid), name)
end
exts = extensions[where.name]::Union{String, Vector{String}}
weakdeps = get(entry, "weakdeps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing}
if (exts isa String && name == exts) || (exts isa Vector{String} && name in exts)
weakdeps = get(entry, "weakdeps", nothing)::Union{Vector{String}, Dict{String, Any}, Nothing}
if weakdeps !== nothing
if weakdeps isa Vector{String}
found_name = name in weakdeps
break
elseif weakdeps isa Dict{String, Any}
weakdeps = weakdeps::Dict{String, Any}
for (dep, uuid) in weakdeps
uuid::String
if dep === name
return PkgId(UUID(uuid), name)
for deps′ in [weakdeps, deps]
if deps′ !== nothing
if deps′ isa Vector{String}
found_name = name in deps′
found_name && @goto done
elseif deps′ isa Dict{String, Any}
deps′ = deps′::Dict{String, Any}
for (dep, uuid) in deps′
uuid::String
if dep === name
return PkgId(UUID(uuid), name)
end
end
end
end
end
end
end
# `name` is not an ext, do standard lookup as if this was the parent
return identify_package(PkgId(UUID(uuid), dep_name), name)
end
end
end
end
end
@label done
found_where || return nothing
found_name || return PkgId(name)
# Only reach here if deps was not a dict which mean we have a unique name for the dep
Expand Down Expand Up @@ -1211,12 +1265,13 @@ function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missi
proj_pkg = project_file_name_uuid(project_file, pkg.name)
if pkg == proj_pkg
d_proj = parsed_toml(project_file)
weakdeps = get(d_proj, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
extensions = get(d_proj, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
extensions === nothing && return
weakdeps === nothing && return
if weakdeps isa Dict{String, Any}
return _insert_extension_triggers(pkg, extensions, weakdeps)
weakdeps = get(Dict{String, Any}, d_proj, "weakdeps")::Union{Vector{String}, Dict{String,Any}}
deps = get(Dict{String, Any}, d_proj, "deps")::Union{Vector{String}, Dict{String,Any}}
if weakdeps isa Dict{String,Any} && deps isa Dict{String,Any}
total_deps = merge(weakdeps, deps)
return _insert_extension_triggers(pkg, extensions, total_deps)
end
end

Expand All @@ -1231,35 +1286,43 @@ function insert_extension_triggers(env::String, pkg::PkgId)::Union{Nothing,Missi
uuid = get(entry, "uuid", nothing)::Union{String, Nothing}
uuid === nothing && continue
if UUID(uuid) == pkg.uuid
weakdeps = get(entry, "weakdeps", nothing)::Union{Nothing, Vector{String}, Dict{String,Any}}
extensions = get(entry, "extensions", nothing)::Union{Nothing, Dict{String, Any}}
extensions === nothing && return
weakdeps === nothing && return
if weakdeps isa Dict{String, Any}
return _insert_extension_triggers(pkg, extensions, weakdeps)
weakdeps = get(Dict{String, Any}, entry, "weakdeps")::Union{Vector{String}, Dict{String,Any}}
deps = get(Dict{String, Any}, entry, "deps")::Union{Vector{String}, Dict{String,Any}}

function expand_deps_list(deps′::Vector{String})
deps′_expanded = Dict{String, Any}()
for (dep_name, entries) in d
dep_name in deps′ || continue
entries::Vector{Any}
if length(entries) != 1
error("expected a single entry for $(repr(dep_name)) in $(repr(project_file))")
end
entry = first(entries)::Dict{String, Any}
uuid = entry["uuid"]::String
deps′_expanded[dep_name] = uuid
end
return deps′_expanded
end

d_weakdeps = Dict{String, Any}()
for (dep_name, entries) in d
dep_name in weakdeps || continue
entries::Vector{Any}
if length(entries) != 1
error("expected a single entry for $(repr(dep_name)) in $(repr(project_file))")
end
entry = first(entries)::Dict{String, Any}
uuid = entry["uuid"]::String
d_weakdeps[dep_name] = uuid
if weakdeps isa Vector{String}
weakdeps = expand_deps_list(weakdeps)
end
@assert length(d_weakdeps) == length(weakdeps)
return _insert_extension_triggers(pkg, extensions, d_weakdeps)
if deps isa Vector{String}
deps = expand_deps_list(deps)
end

total_deps = merge(weakdeps, deps)
return _insert_extension_triggers(pkg, extensions, total_deps)
end
end
end
end
return nothing
end

function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}, weakdeps::Dict{String, Any})
function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}, totaldeps::Dict{String, Any})
for (ext, triggers) in extensions
triggers = triggers::Union{String, Vector{String}}
triggers isa String && (triggers = [triggers])
Expand All @@ -1273,7 +1336,7 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}
push!(trigger1, gid)
for trigger in triggers
# TODO: Better error message if this lookup fails?
uuid_trigger = UUID(weakdeps[trigger]::String)
uuid_trigger = UUID(totaldeps[trigger]::String)
trigger_id = PkgId(uuid_trigger, trigger)
if !haskey(Base.loaded_modules, trigger_id) || haskey(package_locks, trigger_id)
trigger1 = get!(Vector{ExtensionId}, EXT_DORMITORY, trigger_id)
Expand Down
Loading

0 comments on commit 9ee861f

Please sign in to comment.