• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #38002

06 Feb 2025 06:14AM UTC coverage: 20.322% (-2.4%) from 22.722%
#38002

push

local

web-flow
bpart: Fully switch to partitioned semantics (#57253)

This is the final PR in the binding partitions series (modulo bugs and
tweaks), i.e. it closes #54654 and thus closes #40399, which was the
original design sketch.

This thus activates the full designed semantics for binding partitions,
in particular allowing safe replacement of const bindings. It in
particular allows struct redefinitions. This thus closes
timholy/Revise.jl#18 and also closes #38584.

The biggest semantic change here is probably that this gets rid of the
notion of "resolvedness" of a binding. Previously, a lot of the behavior
of our implementation depended on when bindings were "resolved", which
could happen at basically an arbitrary point (in the compiler, in REPL
completion, in a different thread), making a lot of the semantics around
bindings ill- or at least implementation-defined. There are several
related issues in the bugtracker, so this closes #14055 closes #44604
closes #46354 closes #30277

It is also the last step to close #24569.
It also supports bindings for undef->defined transitions and thus closes
#53958 closes #54733 - however, this is not activated yet for
performance reasons and may need some further optimization.

Since resolvedness no longer exists, we need to replace it with some
hopefully more well-defined semantics. I will describe the semantics
below, but before I do I will make two notes:

1. There are a number of cases where these semantics will behave
slightly differently than the old semantics absent some other task going
around resolving random bindings.
2. The new behavior (except for the replacement stuff) was generally
permissible under the old semantics if the bindings happened to be
resolved at the right time.

With all that said, there are essentially three "strengths" of bindings:

1. Implicit Bindings: Anything implicitly obtained from `using Mod`, "no
binding", plus slightly more exotic corner cases around conflicts

2. Weakly declared bindin... (continued)

11 of 111 new or added lines in 7 files covered. (9.91%)

1273 existing lines in 68 files now uncovered.

9908 of 48755 relevant lines covered (20.32%)

105126.48 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

26.88
/stdlib/InteractiveUtils/src/InteractiveUtils.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
The `InteractiveUtils` module provides utilities for interactive use of Julia,
5
such as code introspection and clipboard access.
6
It is intended for interactive work and is loaded automatically in interactive mode.
7
"""
8
module InteractiveUtils
9

10
Base.Experimental.@optlevel 1
11

12
export apropos, edit, less, code_warntype, code_llvm, code_native, methodswith, varinfo,
13
    versioninfo, subtypes, supertypes, @which, @edit, @less, @functionloc, @code_warntype,
14
    @code_typed, @code_lowered, @code_llvm, @code_native, @time_imports, clipboard, @trace_compile, @trace_dispatch,
15
    @activate
16

17
import Base.Docs.apropos
18

19
using Base: unwrap_unionall, rewrap_unionall, isdeprecated, Bottom, summarysize,
20
    signature_type, format_bytes
21
using Base.Libc
22
using Markdown
23

24
include("editless.jl")
25
include("codeview.jl")
26
include("macros.jl")
27
include("clipboard.jl")
28

29
"""
30
    varinfo(m::Module=Main, pattern::Regex=r""; all=false, imported=false, recursive=false, sortby::Symbol=:name, minsize::Int=0)
31

32
Return a markdown table giving information about public global variables in a module, optionally restricted
33
to those matching `pattern`.
34

35
The memory consumption estimate is an approximate lower bound on the size of the internal structure of the object.
36

37
- `all` : also list non-public objects defined in the module, deprecated objects, and compiler-generated objects.
38
- `imported` : also list objects explicitly imported from other modules.
39
- `recursive` : recursively include objects in sub-modules, observing the same settings in each.
40
- `sortby` : the column to sort results by. Options are `:name` (default), `:size`, and `:summary`.
41
- `minsize` : only includes objects with size at least `minsize` bytes. Defaults to `0`.
42

43
The output of `varinfo` is intended for display purposes only.  See also [`names`](@ref) to get an array of symbols defined in
44
a module, which is suitable for more general manipulations.
45
"""
46
function varinfo(m::Module=Base.active_module(), pattern::Regex=r""; all::Bool = false, imported::Bool = false, recursive::Bool = false, sortby::Symbol = :name, minsize::Int=0)
×
47
    sortby in (:name, :size, :summary) || throw(ArgumentError("Unrecognized `sortby` value `:$sortby`. Possible options are `:name`, `:size`, and `:summary`"))
×
48
    rows = Vector{Any}[]
×
49
    workqueue = [(m, ""),]
×
50
    while !isempty(workqueue)
×
51
        m2, prep = popfirst!(workqueue)
×
52
        for v in names(m2; all, imported)
×
53
            if !isdefined(m2, v) || !occursin(pattern, string(v))
×
54
                continue
×
55
            end
56
            value = getfield(m2, v)
×
57
            isbuiltin = value === Base || value === Base.active_module() || value === Core
×
58
            if recursive && !isbuiltin && isa(value, Module) && value !== m2 && nameof(value) === v && parentmodule(value) === m2
×
59
                push!(workqueue, (value, "$prep$v."))
×
60
            end
61
            ssize_str, ssize = if isbuiltin
×
62
                    ("", typemax(Int))
×
63
                else
64
                    ss = summarysize(value)
×
65
                    (format_bytes(ss), ss)
×
66
                end
67
            if ssize >= minsize
×
68
                push!(rows, Any[string(prep, v), ssize_str, summary(value), ssize])
×
69
            end
70
        end
×
71
    end
×
72
    let (col, rev) = if sortby === :name
×
73
            1, false
×
74
        elseif sortby === :size
×
75
            4, true
×
76
        elseif sortby === :summary
×
77
            3, false
×
78
        else
79
            @assert "unreachable"
×
80
        end
81
        sort!(rows; by=r->r[col], rev)
×
82
    end
83
    pushfirst!(rows, Any["name", "size", "summary"])
×
84

85
    return Markdown.MD(Any[Markdown.Table(map(r->r[1:3], rows), Symbol[:l, :r, :l])])
×
86
end
87
varinfo(pat::Regex; kwargs...) = varinfo(Base.active_module(), pat; kwargs...)
×
88

89
"""
90
    versioninfo(io::IO=stdout; verbose::Bool=false)
91

92
Print information about the version of Julia in use. The output is
93
controlled with boolean keyword arguments:
94

95
- `verbose`: print all additional information
96

97
!!! warning "Warning"
98
    The output of this function may contain sensitive information. Before sharing the output,
99
    please review the output and remove any data that should not be shared publicly.
100

101
See also: [`VERSION`](@ref).
102
"""
103
function versioninfo(io::IO=stdout; verbose::Bool=false)
2✔
104
    println(io, "Julia Version $VERSION")
1✔
105
    if !isempty(Base.GIT_VERSION_INFO.commit_short)
1✔
106
        println(io, "Commit $(Base.GIT_VERSION_INFO.commit_short) ($(Base.GIT_VERSION_INFO.date_string))")
1✔
107
    end
108
    official_release = Base.TAGGED_RELEASE_BANNER == "Official https://julialang.org release"
1✔
109
    if Base.isdebugbuild() || !isempty(Base.TAGGED_RELEASE_BANNER) || (Base.GIT_VERSION_INFO.tagged_commit && !official_release)
2✔
110
        println(io, "Build Info:")
×
111
        if Base.isdebugbuild()
×
112
            println(io, "  DEBUG build")
×
113
        end
114
        if !isempty(Base.TAGGED_RELEASE_BANNER)
×
115
            println(io, "  ", Base.TAGGED_RELEASE_BANNER)
×
116
        end
117
        if Base.GIT_VERSION_INFO.tagged_commit && !official_release
×
118
            println(io,
×
119
                """
120

121
                    Note: This is an unofficial build, please report bugs to the project
122
                    responsible for this build and not to the Julia project unless you can
123
                    reproduce the issue using official builds available at https://julialang.org/downloads
124
                """
125
            )
126
        end
127
    end
128
    println(io, "Platform Info:")
1✔
129
    println(io, "  OS: ", Sys.iswindows() ? "Windows" : Sys.isapple() ?
1✔
130
        "macOS" : Sys.KERNEL, " (", Sys.MACHINE, ")")
131

132
    if verbose
1✔
133
        lsb = ""
×
134
        if Sys.islinux()
×
135
            try lsb = readchomp(pipeline(`lsb_release -ds`, stderr=devnull)); catch; end
×
136
        end
137
        if Sys.iswindows()
×
138
            try lsb = strip(read(`$(ENV["COMSPEC"]) /c ver`, String)); catch; end
×
139
        end
140
        if !isempty(lsb)
×
141
            println(io, "      ", lsb)
×
142
        end
143
        if Sys.isunix()
×
144
            println(io, "  uname: ", readchomp(`uname -mprsv`))
×
145
        end
146
    end
147

148
    if verbose
1✔
149
        cpuio = IOBuffer() # print cpu_summary with correct alignment
×
150
        Sys.cpu_summary(cpuio)
×
151
        for (i, line) in enumerate(split(chomp(String(take!(cpuio))), "\n"))
×
152
            prefix = i == 1 ? "  CPU: " : "       "
×
153
            println(io, prefix, line)
×
154
        end
×
155
    else
156
        cpu = Sys.cpu_info()
1✔
157
        println(io, "  CPU: ", length(cpu), " × ", cpu[1].model)
1✔
158
    end
159

160
    if verbose
1✔
161
        println(io, "  Memory: $(Sys.total_memory()/2^30) GB ($(Sys.free_memory()/2^20) MB free)")
×
162
        try println(io, "  Uptime: $(Sys.uptime()) sec"); catch; end
×
163
        print(io, "  Load Avg: ")
×
164
        Base.print_matrix(io, Sys.loadavg()')
×
165
        println(io)
×
166
    end
167
    println(io, "  WORD_SIZE: ", Sys.WORD_SIZE)
1✔
168
    println(io, "  LLVM: libLLVM-",Base.libllvm_version," (", Sys.JIT, ", ", Sys.CPU_NAME, ")")
1✔
169
    println(io, "  GC: ", unsafe_string(ccall(:jl_gc_active_impl, Ptr{UInt8}, ())))
1✔
170
    println(io, """Threads: $(Threads.nthreads(:default)) default, $(Threads.nthreads(:interactive)) interactive, \
1✔
171
      $(Threads.ngcthreads()) GC (on $(Sys.CPU_THREADS) virtual cores)""")
172

173
    function is_nonverbose_env(k::String)
1✔
174
        return occursin(r"^JULIA_|^DYLD_|^LD_", k)
132✔
175
    end
176
    function is_verbose_env(k::String)
1✔
177
        return occursin(r"PATH|FLAG|^TERM$|HOME", k) && !is_nonverbose_env(k)
×
178
    end
179
    env_strs = String[
2✔
180
        String["  $(k) = $(v)" for (k,v) in ENV if is_nonverbose_env(uppercase(k))];
181
        (verbose ?
182
         String["  $(k) = $(v)" for (k,v) in ENV if is_verbose_env(uppercase(k))] :
183
         String[]);
184
    ]
185
    if !isempty(env_strs)
1✔
186
        println(io, "Environment:")
1✔
187
        for str in env_strs
1✔
188
            println(io, str)
4✔
189
        end
4✔
190
    end
191
end
192

193

194
function type_close_enough(@nospecialize(x), @nospecialize(t))
×
195
    x == t && return true
×
196
    # TODO: handle UnionAll properly
197
    return (isa(x, DataType) && isa(t, DataType) && x.name === t.name && x <: t) ||
×
198
           (isa(x, Union) && isa(t, DataType) && (type_close_enough(x.a, t) || type_close_enough(x.b, t)))
199
end
200

201
# `methodswith` -- shows a list of methods using the type given
202
"""
203
    methodswith(typ[, module or function]; supertypes::Bool=false])
204

205
Return an array of methods with an argument of type `typ`.
206

207
The optional second argument restricts the search to a particular module or function
208
(the default is all top-level modules).
209

210
If keyword `supertypes` is `true`, also return arguments with a parent type of `typ`,
211
excluding type `Any`.
212

213
See also: [`methods`](@ref).
214
"""
215
function methodswith(@nospecialize(t::Type), @nospecialize(f::Base.Callable), meths = Method[]; supertypes::Bool=false)
×
216
    for d in methods(f)
×
217
        if any(function (x)
×
218
                   let x = rewrap_unionall(x, d.sig)
×
219
                       (type_close_enough(x, t) ||
×
220
                        (supertypes ? (isa(x, Type) && t <: x && (!isa(x,TypeVar) || x.ub != Any)) :
221
                         (isa(x,TypeVar) && x.ub != Any && t == x.ub)) &&
222
                        x != Any)
223
                   end
224
               end,
225
               unwrap_unionall(d.sig).parameters)
226
            push!(meths, d)
×
227
        end
228
    end
×
229
    return meths
×
230
end
231

232
function _methodswith(@nospecialize(t::Type), m::Module, supertypes::Bool)
×
233
    meths = Method[]
×
234
    for nm in names(m)
×
235
        if isdefined(m, nm)
×
236
            f = getfield(m, nm)
×
237
            if isa(f, Base.Callable)
×
238
                methodswith(t, f, meths; supertypes = supertypes)
×
239
            end
240
        end
241
    end
×
242
    return unique(meths)
×
243
end
244

245
methodswith(@nospecialize(t::Type), m::Module; supertypes::Bool=false) = _methodswith(t, m, supertypes)
×
246

247
function methodswith(@nospecialize(t::Type); supertypes::Bool=false)
×
248
    meths = Method[]
×
249
    for mod in Base.loaded_modules_array()
×
250
        append!(meths, _methodswith(t, mod, supertypes))
×
251
    end
×
252
    return unique(meths)
×
253
end
254

255
# subtypes
256
function _subtypes_in!(mods::Array, x::Type)
×
257
    xt = unwrap_unionall(x)
×
258
    if !isabstracttype(x) || !isa(xt, DataType)
×
259
        # Fast path
260
        return Type[]
×
261
    end
262
    sts = Vector{Any}()
×
263
    while !isempty(mods)
×
264
        m = pop!(mods)
×
265
        xt = xt::DataType
×
266
        for s in names(m, all = true)
×
NEW
267
            if !isdeprecated(m, s) && isdefined(m, s)
×
268
                t = getfield(m, s)
×
269
                dt = isa(t, UnionAll) ? unwrap_unionall(t) : t
×
270
                if isa(dt, DataType)
×
271
                    if dt.name.name === s && dt.name.module == m && supertype(dt).name == xt.name
×
272
                        ti = typeintersect(t, x)
×
273
                        ti != Bottom && push!(sts, ti)
×
274
                    end
275
                elseif isa(t, Module) && nameof(t) === s && parentmodule(t) === m && t !== m
×
276
                    t === Base || push!(mods, t) # exclude Base, since it also parented by Main
×
277
                end
278
            end
279
        end
×
280
    end
×
281
    return permute!(sts, sortperm(map(string, sts)))
×
282
end
283

284
subtypes(m::Module, x::Type) = _subtypes_in!([m], x)
×
285

286
"""
287
    subtypes(T::DataType)
288

289
Return a list of immediate subtypes of DataType `T`. Note that all currently loaded subtypes
290
are included, including those not visible in the current module.
291

292
See also [`supertype`](@ref), [`supertypes`](@ref), [`methodswith`](@ref).
293

294
# Examples
295
```jldoctest
296
julia> subtypes(Integer)
297
3-element Vector{Any}:
298
 Bool
299
 Signed
300
 Unsigned
301
```
302
"""
303
subtypes(x::Type) = _subtypes_in!(Base.loaded_modules_array(), x)
×
304

305
"""
306
    supertypes(T::Type)
307

308
Return a tuple `(T, ..., Any)` of `T` and all its supertypes, as determined by
309
successive calls to the [`supertype`](@ref) function, listed in order of `<:`
310
and terminated by `Any`.
311

312
See also [`subtypes`](@ref).
313

314
# Examples
315
```jldoctest
316
julia> supertypes(Int)
317
(Int64, Signed, Integer, Real, Number, Any)
318
```
319
"""
320
function supertypes(T::Type)
×
321
    S = supertype(T)
×
322
    # note: we return a tuple here, not an Array as for subtypes, because in
323
    #       the future we could evaluate this function statically if desired.
324
    return S === T ? (T,) : (T, supertypes(S)...)
×
325
end
326

327
# TODO: @deprecate peakflops to LinearAlgebra
328
export peakflops
329
"""
330
    peakflops(n::Integer=4096; eltype::DataType=Float64, ntrials::Integer=3, parallel::Bool=false)
331

332
`peakflops` computes the peak flop rate of the computer by using double precision
333
[`gemm!`](@ref LinearAlgebra.BLAS.gemm!). For more information see
334
[`LinearAlgebra.peakflops`](@ref).
335

336
!!! compat "Julia 1.1"
337
    This function will be moved from `InteractiveUtils` to `LinearAlgebra` in the
338
    future. In Julia 1.1 and later it is available as `LinearAlgebra.peakflops`.
339
"""
340
function peakflops(n::Integer=4096; eltype::DataType=Float64, ntrials::Integer=3, parallel::Bool=false)
×
341
    # Base.depwarn("`peakflops` has moved to the LinearAlgebra module, " *
342
    #              "add `using LinearAlgebra` to your imports.", :peakflops)
343
    let LinearAlgebra = Base.require_stdlib(Base.PkgId(
×
344
            Base.UUID((0x37e2e46d_f89d_539d,0xb4ee_838fcccc9c8e)), "LinearAlgebra"))
345
        return LinearAlgebra.peakflops(n, eltype=eltype, ntrials=ntrials, parallel=parallel)
×
346
    end
347
end
348

349
function report_bug(kind)
1✔
350
    @info "Loading BugReporting package..."
1✔
351
    BugReportingId = Base.PkgId(
1✔
352
        Base.UUID((0xbcf9a6e7_4020_453c,0xb88e_690564246bb8)), "BugReporting")
353
    # Check if the BugReporting package exists in the current environment
354
    local BugReporting
355
    if Base.locate_package(BugReportingId) === nothing
1✔
356
        @info "Package `BugReporting` not found - attempting temporary installation"
1✔
357
        # Create a temporary environment and add BugReporting
358
        let Pkg = Base.require_stdlib(Base.PkgId(
1✔
359
            Base.UUID((0x44cfe95a_1eb2_52ea,0xb672_e2afdf69b78f)), "Pkg"))
360
            mktempdir() do tmp
1✔
361
                old_load_path = copy(LOAD_PATH)
2✔
362
                push!(empty!(LOAD_PATH), joinpath(tmp, "Project.toml"))
3✔
363
                old_active_project = Base.ACTIVE_PROJECT[]
1✔
364
                Base.ACTIVE_PROJECT[] = nothing
1✔
365
                pkgspec = @invokelatest Pkg.PackageSpec(BugReportingId.name, BugReportingId.uuid)
2✔
366
                @invokelatest Pkg.add(pkgspec)
1✔
367
                BugReporting = Base.require(BugReportingId)
1✔
368
                append!(empty!(LOAD_PATH), old_load_path)
2✔
369
                Base.ACTIVE_PROJECT[] = old_active_project
1✔
370
            end
371
        end
372
    else
373
        BugReporting = Base.require(BugReportingId)
×
374
    end
375
    return @invokelatest BugReporting.make_interactive_report(kind, ARGS)
1✔
376
end
377

378
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc