Skip to content
2 changes: 1 addition & 1 deletion base/docs/Docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ function metadata(__source__, __module__, expr, ismodule)
if isa(eachex, Symbol) || isexpr(eachex, :(::))
# a field declaration
if last_docstr !== nothing
push!(fields, P(namify(eachex), last_docstr))
push!(fields, P(namify(eachex)::Symbol, last_docstr))
last_docstr = nothing
end
elseif isexpr(eachex, :function) || isexpr(eachex, :(=))
Expand Down
66 changes: 49 additions & 17 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,16 @@ struct LoadingCache
located::Dict{Tuple{PkgId, Union{String, Nothing}}, Union{Tuple{PkgLoadSpec, String}, Nothing}}
end
const LOADING_CACHE = Ref{Union{LoadingCache, Nothing}}(nothing) # n.b.: all access to and through this are protected by require_lock
LoadingCache() = LoadingCache(load_path(), Dict(), Dict(), Dict(), Set(), Dict(), Dict(), Dict())
LoadingCache() = LoadingCache(
load_path(),
Dict{String, UUID}(),
Dict{String, Union{Bool, String}}(),
Dict{String, Union{Nothing, String}}(),
Set{String}(),
Dict{Tuple{PkgId, String}, Union{Nothing, Tuple{PkgId, String}}}(),
Dict{String, Union{Nothing, Tuple{PkgId, String}}}(),
Dict{Tuple{PkgId, Union{String, Nothing}}, Union{Tuple{PkgLoadSpec, String}, Nothing}}()
)


struct TOMLCache{Dates}
Expand Down Expand Up @@ -343,25 +352,22 @@ Same as [`Base.identify_package`](@ref) except that the path to the environment
is also returned, except when the identity is not identified.
"""
identify_package_env(where::Module, name::String) = identify_package_env(PkgId(where), name)
function identify_package_env(where::Union{PkgId, Nothing}, name::String)
function identify_package_env(where::PkgId, name::String)
# Special cases
if where !== nothing
if where.name === name
# Project tries to load itself
return (where, nothing)
elseif where.uuid === nothing
# Project without Project.toml - treat as toplevel load
where = nothing
end
if where.name === name
# Project tries to load itself
return (where, nothing)
elseif where.uuid === nothing
# Project without Project.toml - treat as toplevel load
return identify_package_env(nothing, name)
end

# Check if we have a cached answer for this
assert_havelock(require_lock)
cache = LOADING_CACHE[]
cache_key = where === nothing ? name : (where, name)
cache_key = (where, name)
if cache !== nothing
env_cache = where === nothing ? cache.identified : cache.identified_where
pkg_env = get(env_cache, cache_key, missing)
pkg_env = get(cache.identified_where, cache_key, missing)
pkg_env === missing || return pkg_env
end

Expand All @@ -372,14 +378,14 @@ function identify_package_env(where::Union{PkgId, Nothing}, name::String)
pkgid = environment_deps_get(env, where, name)
# If we didn't find `where` at all, keep looking through the environment stack
pkgid === nothing && continue
if pkgid.uuid !== nothing || where === nothing
pkg_env = pkgid, env
if pkgid.uuid !== nothing
pkg_env = (pkgid, env)
end
# If we don't have pkgid.uuid, still break here - this is a sentinel that indicates
# that we've found `where` but it did not have the required dependency. We terminate the search.
break
end
if pkg_env === nothing && where !== nothing && is_stdlib(where)
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
Expand All @@ -388,7 +394,33 @@ function identify_package_env(where::Union{PkgId, Nothing}, name::String)

# Cache the result
if cache !== nothing
env_cache[cache_key] = pkg_env
cache.identified_where[cache_key] = pkg_env
end
return pkg_env
end
function identify_package_env(where::Nothing, name::String)
# Check if we have a cached answer for this
assert_havelock(require_lock)
cache = LOADING_CACHE[]
if cache !== nothing
pkg_env = get(cache.identified, name, missing)
pkg_env === missing || return pkg_env
end

# Main part: Search through all environments in the load path to see if we have
# a matching entry.
pkg_env = nothing
for env in load_path()
pkgid = environment_deps_get(env, nothing, name)
# If we didn't find `where` at all, keep looking through the environment stack
pkgid === nothing && continue
pkg_env = (pkgid, env)
break
end

# Cache the result
if cache !== nothing
cache.identified[name] = pkg_env
end
return pkg_env
end
Expand Down
42 changes: 25 additions & 17 deletions base/precompilation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -568,15 +568,15 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
_from_loading::Bool,
configs::Vector{Config},
io::IOContext{IO},
fancyprint::Bool,
fancyprint::Bool,
manifest::Bool,
ignore_loaded::Bool)
requested_pkgs = copy(pkgs) # for understanding user intent
pkg_names = pkgs isa Vector{String} ? copy(pkgs) : String[pkg.name for pkg in pkgs]
if pkgs isa Vector{PkgId}
requested_pkgids = copy(pkgs)
requested_pkgids = copy(pkgs)
else
requested_pkgids = PkgId[]
requested_pkgids = PkgId[]
for name in pkgs
pkgid = Base.identify_package(name)
if pkgid === nothing
Expand All @@ -586,9 +586,10 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
throw(PkgPrecompileError("Unknown package: $name"))
end
end
push!(requested_pkgids, pkgid)
push!(requested_pkgids, pkgid)
end
end
requested_pkgids = requested_pkgids′

time_start = time_ns()

Expand All @@ -605,17 +606,20 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
# suppress precompilation progress messages when precompiling for loading packages, except during interactive sessions
# or when specified by logging heuristics that explicitly require it
# since the complicated IO implemented here can have somewhat disastrous consequences when happening in the background (e.g. #59599)
logio = io
logcalls = nothing
logio = io
logcalls = nothing
if _from_loading
if isinteractive()
logcalls = CoreLogging.Info # sync with Base.compilecache
logcalls = CoreLogging.Info # sync with Base.compilecache
else
logio = IOContext{IO}(devnull)
fancyprint = false
logcalls = CoreLogging.Debug # sync with Base.compilecache
logio = IOContext{IO}(devnull)
fancyprint = false
logcalls = CoreLogging.Debug # sync with Base.compilecache
end
end
fancyprint = fancyprint′
logio = logio′
logcalls = logcalls′

nconfigs = length(configs)
hascolor = get(logio, :color, false)::Bool
Expand Down Expand Up @@ -992,7 +996,7 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
for pkg_config in pkg_queue_show
dep, config = pkg_config
loaded = warn_loaded && haskey(Base.loaded_modules, dep)
flags, cacheflags = config
local flags, cacheflags = config
name = describe_pkg(dep, dep in project_deps, dep in serial_deps, flags, cacheflags)
line = if pkg_config in precomperr_deps
string(color_string(" ? ", Base.warn_color()), name)
Expand Down Expand Up @@ -1077,7 +1081,7 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
notify(was_processed[pkg_config])
continue
end
flags, cacheflags = config
local flags, cacheflags = config
task = @async begin
try
loaded = warn_loaded && haskey(Base.loaded_modules, pkg)
Expand Down Expand Up @@ -1118,17 +1122,21 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
end
# for extensions, any extension that can trigger it needs to be accounted for here (even stdlibs, which are excluded from direct_deps)
loadable_exts = haskey(ext_to_parent, pkg) ? filter((dep)->haskey(ext_to_parent, dep), triggers[pkg]) : nothing
if !isempty(deps)

flags_ =if !isempty(deps)
# if deps is empty, either it doesn't have any (so compiled-modules is
# irrelevant) or we couldn't compute them (so we actually should attempt
# serial compile, as the dependencies are not in the parallel list)
flags = `$flags --compiled-modules=strict`
`$flags --compiled-modules=strict`
else
flags
end

if _from_loading && pkg in requested_pkgids
# loading already took the cachefile_lock and printed logmsg for its explicit requests
t = @elapsed ret = begin
Base.compilecache(pkg, sourcespec, std_pipe, std_pipe, !ignore_loaded;
flags, cacheflags, loadable_exts)
flags=flags_, cacheflags, loadable_exts)
end
else
# allows processes to wait if another process is precompiling a given package to
Expand All @@ -1138,7 +1146,7 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
if interrupted_or_done[]
return ErrorException("canceled")
end
cachepaths = Base.find_all_in_cache_path(pkg)
local cachepaths = Base.find_all_in_cache_path(pkg)
local freshpath = Base.compilecache_freshest_path(pkg; ignore_loaded, stale_cache, cachepath_cache, cachepaths, sourcespec, flags=cacheflags)
local is_stale = freshpath === nothing
if !is_stale
Expand All @@ -1149,7 +1157,7 @@ function _precompilepkgs(pkgs::Union{Vector{String}, Vector{PkgId}},
@debug "Precompiling $(repr("text/plain", pkg))"
end
Base.compilecache(pkg, sourcespec, std_pipe, std_pipe, !ignore_loaded;
flags, cacheflags, loadable_exts)
flags=flags_, cacheflags, loadable_exts)
end
end
if ret isa Exception
Expand Down
2 changes: 1 addition & 1 deletion base/shell.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ function shell_split(s::AbstractString)
parsed = shell_parse(s, false)[1]
args = String[]
for arg in parsed
push!(args, string(arg...))
push!(args, string(arg...)::String)
end
args
end
Expand Down
42 changes: 27 additions & 15 deletions base/strings/annotated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ function annotatedstring(xs...)
size = filesize(s.io)
if x isa AnnotatedString
for annot in x.annotations
push!(annotations, setindex(annot, annot.region .+ size, :region))
push!(annotations, @inline(setindex(annot, annot.region .+ size, :region)))
end
print(s, x.string)
elseif x isa SubString{<:AnnotatedString}
Expand All @@ -259,7 +259,7 @@ function annotatedstring(xs...)
if start <= x.offset + x.ncodeunits && stop > x.offset
rstart = size + max(0, start - x.offset - 1) + 1
rstop = size + min(stop, x.offset + x.ncodeunits) - x.offset
push!(annotations, setindex(annot, rstart:rstop, :region))
push!(annotations, @inline(setindex(annot, rstart:rstop, :region)))
end
end
print(s, SubString(x.string.string, x.offset, x.ncodeunits, Val(:noshift)))
Expand Down Expand Up @@ -293,12 +293,12 @@ function repeat(str::AnnotatedString, r::Integer)
elseif allequal(a -> a.region, str.annotations) && first(str.annotations).region == fullregion
newfullregion = firstindex(unannot):lastindex(unannot)
for annot in str.annotations
push!(annotations, setindex(annot, newfullregion, :region))
push!(annotations, @inline(setindex(annot, newfullregion, :region)))
end
else
for offset in 0:len:(r-1)*len
for annot in str.annotations
push!(annotations, setindex(annot, annot.region .+ offset, :region))
push!(annotations, @inline(setindex(annot, annot.region .+ offset, :region)))
end
end
end
Expand All @@ -318,10 +318,10 @@ function reverse(s::AnnotatedString)
lastind = lastindex(s)
AnnotatedString(
reverse(s.string),
[setindex(annot,
[@inline(setindex(annot,
UnitRange(1 + lastind - last(annot.region),
1 + lastind - first(annot.region)),
:region)
:region))
for annot in s.annotations])
end

Expand Down Expand Up @@ -389,16 +389,28 @@ See also: [`annotate!`](@ref).
annotations(s::AnnotatedString) = s.annotations

function annotations(s::SubString{<:AnnotatedString})
RegionAnnotation[
setindex(ann, first(ann.region)-s.offset:last(ann.region)-s.offset, :region)
for ann in annotations(s.string, s.offset+1:s.offset+s.ncodeunits)]
substr_range = s.offset+1:s.offset+s.ncodeunits
result = RegionAnnotation[]
for ann in annotations(s.string, substr_range)
# Shift the region to be relative to the substring start
shifted_region = first(ann.region)-s.offset:last(ann.region)-s.offset
# @inline setindex makes :region const knowable (#60365)
push!(result, @inline(setindex(ann, shifted_region, :region)))
end
return result
end

function annotations(s::AnnotatedString, pos::UnitRange{<:Integer})
# TODO optimise
RegionAnnotation[
setindex(ann, max(first(pos), first(ann.region)):min(last(pos), last(ann.region)), :region)
for ann in s.annotations if !isempty(intersect(pos, ann.region))]
result = RegionAnnotation[]
for ann in s.annotations
if !isempty(intersect(pos, ann.region))
clamped_region = max(first(pos), first(ann.region)):min(last(pos), last(ann.region))
# @inline setindex makes :region const knowable (#60365)
push!(result, @inline(setindex(ann, clamped_region, :region)))
end
end
return result
end

annotations(s::AnnotatedString, pos::Integer) = annotations(s, pos:pos)
Expand Down Expand Up @@ -455,7 +467,7 @@ function annotated_chartransform(f::Function, str::AnnotatedString, state=nothin
start, stop = first(annot.region), last(annot.region)
start_offset = last(offsets[findlast(<=(start) ∘ first, offsets)::Int])
stop_offset = last(offsets[findlast(<=(stop) ∘ first, offsets)::Int])
push!(annots, setindex(annot, (start + start_offset):(stop + stop_offset), :region))
push!(annots, @inline(setindex(annot, (start + start_offset):(stop + stop_offset), :region)))
end
AnnotatedString(takestring!(outstr), annots)
end
Expand Down Expand Up @@ -509,7 +521,7 @@ function eachregion(s::AnnotatedString, subregion::UnitRange{Int}=firstindex(s):
pos = first(events).pos
if pos > first(subregion)
push!(regions, thisind(s, first(subregion)):prevind(s, pos))
push!(annots, [])
push!(annots, Annotation[])
end
activelist = Int[]
for event in events
Expand All @@ -526,7 +538,7 @@ function eachregion(s::AnnotatedString, subregion::UnitRange{Int}=firstindex(s):
end
if last(events).pos < nextind(s, last(subregion))
push!(regions, last(events).pos:thisind(s, last(subregion)))
push!(annots, [])
push!(annots, Annotation[])
end
RegionIterator(s.string, regions, annots)
end
Expand Down
Loading