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

JuliaLang / julia / 1293

03 Oct 2025 01:05AM UTC coverage: 76.952% (-0.1%) from 77.068%
1293

push

buildkite

web-flow
Support superscript small q (#59544)

Co-authored-by: Steven G. Johnson <stevenj@alum.mit.edu>

61282 of 79637 relevant lines covered (76.95%)

21700458.33 hits per line

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

44.66
/base/methodshow.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
# Method and method table pretty-printing
4

5
const empty_sym = Symbol("")
6
function strip_gensym(sym)
7
    if sym === :var"#self#" || sym === :var"#unused#"
×
8
        return empty_sym
×
9
    end
10
    return Symbol(replace(String(sym), r"^(.*)#(.*#)?\d+$"sa => s"\1"))
×
11
end
12

13
function argtype_decl(env, n, @nospecialize(sig::DataType), i::Int, nargs, isva::Bool) # -> (argname, argtype)
×
14
    t = unwrapva(sig.parameters[min(i, end)])
×
15
    if i == nargs && isva
×
16
        va = sig.parameters[end]
×
17
        if isvarargtype(va) && (!isdefined(va, :N) || !isa(va.N, Int))
×
18
            t = va
×
19
        else
20
            ntotal = length(sig.parameters)
×
21
            isvarargtype(va) && (ntotal += va.N - 1)
×
22
            t = Vararg{t,ntotal-nargs+1}
×
23
        end
24
    end
25
    if isa(n,Expr)
×
26
        n = n.args[1]  # handle n::T in arg list
×
27
    end
28
    n = strip_gensym(n)
×
29
    local s
30
    if n === empty_sym
×
31
        s = ""
×
32
    else
33
        s = sprint(show_sym, n)
×
34
        t === Any && return s, ""
×
35
    end
36
    if isvarargtype(t)
×
37
        if !isdefined(t, :N)
×
38
            if unwrapva(t) === Any
×
39
                return string(s, "..."), ""
×
40
            else
41
                return s, string_with_env(env, unwrapva(t)) * "..."
×
42
            end
43
        end
44
        return s, string_with_env(env, "Vararg{", t.T, ", ", t.N, "}")
×
45
    end
46
    return s, string_with_env(env, t)
×
47
end
48

49
function method_argnames(m::Method)
33✔
50
    argnames = ccall(:jl_uncompress_argnames, Vector{Symbol}, (Any,), m.slot_syms)
3,448✔
51
    isempty(argnames) && return argnames
3,448✔
52
    return argnames[1:m.nargs]
3,448✔
53
end
54

55
function arg_decl_parts(m::Method, html=false)
×
56
    tv = Any[]
177✔
57
    sig = m.sig
×
58
    while isa(sig, UnionAll)
×
59
        push!(tv, sig.var)
×
60
        sig = sig.body
×
61
    end
×
62
    file, line = updated_methodloc(m)
×
63
    argnames = method_argnames(m)
×
64
    if length(argnames) >= m.nargs
×
65
        show_env = ImmutableDict{Symbol, Any}()
×
66
        for t in tv
×
67
            show_env = ImmutableDict(show_env, :unionall_env => t)
×
68
        end
×
69
        decls = Tuple{String,String}[argtype_decl(show_env, argnames[i], sig, i, m.nargs, m.isva)
×
70
                    for i = 1:m.nargs]
71
        decls[1] = ("", sprint(show_signature_function, unwrapva(sig.parameters[1]), false, decls[1][1], html,
×
72
                               context = show_env))
73
    else
74
        decls = Tuple{String,String}[("", "") for i = 1:length(sig.parameters::SimpleVector)]
×
75
    end
76
    return tv, decls, file, line
×
77
end
78

79
# NOTE: second argument is deprecated and is no longer used
80
function kwarg_decl(m::Method, kwtype = nothing)
×
81
    if !(m.sig === Tuple || m.sig <: Tuple{Core.Builtin, Vararg}) # OpaqueClosure or Builtin
7,141✔
82
        kwtype = typeof(Core.kwcall)
×
83
        sig = rewrap_unionall(Tuple{kwtype, NamedTuple, (unwrap_unionall(m.sig)::DataType).parameters...}, m.sig)
×
84
        kwli = ccall(:jl_methtable_lookup, Any, (Any, UInt), sig, get_world_counter())
×
85
        if kwli !== nothing
×
86
            kwli = kwli::Method
×
87
            slotnames = ccall(:jl_uncompress_argnames, Vector{Symbol}, (Any,), kwli.slot_syms)
×
88
            kws = filter(x -> !(x === empty_sym || '#' in string(x)), slotnames[(kwli.nargs + 1):end])
×
89
            # ensure the kwarg... is always printed last. The order of the arguments are not
90
            # necessarily the same as defined in the function
91
            i = findfirst(x -> endswith(string(x)::String, "..."), kws)
×
92
            if i !== nothing
×
93
                push!(kws, kws[i])
×
94
                deleteat!(kws, i)
×
95
            end
96
            isempty(kws) && push!(kws,  :var"...")
×
97
            return kws
×
98
        end
99
    end
100
    return Symbol[]
×
101
end
102

103
function show_method_params(io::IO, tv)
1,756✔
104
    if !isempty(tv)
1,756✔
105
        print(io, " where ")
×
106
        if length(tv) == 1
×
107
            show(io, tv[1])
×
108
        else
109
            print(io, "{")
×
110
            for i = 1:length(tv)
×
111
                if i > 1
×
112
                    print(io, ", ")
×
113
                end
114
                x = tv[i]
×
115
                show(io, x)
×
116
                io = IOContext(io, :unionall_env => x)
×
117
            end
×
118
            print(io, "}")
×
119
        end
120
    end
121
end
122

123
# In case the line numbers in the source code have changed since the code was compiled,
124
# allow packages to set a callback function that corrects them.
125
# (Used by Revise and perhaps other packages.)
126
# Any function `f` stored here must be consistent with the signature
127
#    f(m::Method)::Tuple{Union{Symbol,String}, Union{Int32,Int64}}
128
const methodloc_callback = Ref{Union{Function, Nothing}}(nothing)
129

130
function fixup_stdlib_path(path::String)
91,751✔
131
    # The file defining Base.Sys gets included after this file is included so make sure
132
    # this function is valid even in this intermediary state
133
    if isdefined(@__MODULE__, :Sys)
91,751✔
134
        if Sys.BUILD_STDLIB_PATH != Sys.STDLIB
91,751✔
135
            # BUILD_STDLIB_PATH gets defined in sysinfo.jl
136
            npath = normpath(path)
91,751✔
137
            npath′ = replace(npath, normpath(Sys.BUILD_STDLIB_PATH) => normpath(Sys.STDLIB))
91,751✔
138
            path = npath == npath′ ? path : npath′
91,751✔
139
        end
140
        if isdefined(@__MODULE__, :Core) && isdefined(Core, :Compiler)
91,751✔
141
            compiler_folder = dirname(String(Base.moduleloc(Core.Compiler).file))
91,751✔
142
            if dirname(path) == compiler_folder
91,751✔
143
                return abspath(Sys.STDLIB, "..", "..", "Compiler", "src", basename(path))
6✔
144
            end
145
        end
146
    end
147
    return path
91,745✔
148
end
149

150
# This function does the method location updating
151
function updated_methodloc(m::Method)::Tuple{String, Int32}
×
152
    file, line = m.file, m.line
×
153
    if methodloc_callback[] !== nothing
×
154
        try
×
155
            file, line = invokelatest(methodloc_callback[], m)::Tuple{Union{Symbol,String}, Union{Int32,Int64}}
×
156
        catch
157
        end
158
    end
159
    file = fixup_stdlib_path(string(file))
×
160
    return file, Int32(line)
×
161
end
162

163
functionloc(m::Core.MethodInstance) = functionloc(m.def)
×
164

165
"""
166
    functionloc(m::Method)
167

168
Return a tuple `(filename,line)` giving the location of a `Method` definition.
169
"""
170
function functionloc(m::Method)
×
171
    file, ln = updated_methodloc(m)
×
172
    if ln <= 0
×
173
        error("could not determine location of method definition")
×
174
    end
175
    return (find_source_file(string(file)), ln)
×
176
end
177

178
"""
179
    functionloc(f::Function, types)
180

181
Return a tuple `(filename,line)` giving the location of a generic `Function` definition.
182
"""
183
functionloc(@nospecialize(f), @nospecialize(types)) = functionloc(which(f,types))
×
184
functionloc(@nospecialize(argtypes::Union{Tuple, Type{<:Tuple}})) = functionloc(which(argtypes))
×
185

186
function functionloc(@nospecialize(f))
×
187
    mt = methods(f)
×
188
    if isempty(mt)
×
189
        if isa(f, Function)
×
190
            error("function has no definitions")
×
191
        else
192
            error("object is not callable")
×
193
        end
194
    end
195
    if length(mt) > 1
×
196
        error("function has multiple methods; please specify a type signature")
×
197
    end
198
    return functionloc(first(mt))
×
199
end
200

201
function sym_to_string(sym)
×
202
    if sym === :var"..."
×
203
        return "..."
×
204
    end
205
    s = String(sym)
×
206
    if endswith(s, "...")
×
207
        return string(sprint(show_sym, Symbol(s[1:end-3])), "...")
×
208
    else
209
        return sprint(show_sym, sym)
×
210
    end
211
end
212

213
# default compact view
214
show(io::IO, m::Method; kwargs...) = show_method(IOContext(io, :compact=>true), m; kwargs...)
37,943✔
215

216
show(io::IO, ::MIME"text/plain", m::Method; kwargs...) = show_method(io, m; kwargs...)
24✔
217

218
function show_method(io::IO, m::Method;
28,707✔
219
                     modulecolor = :light_black, digit_align_width = 1,
220
                     print_signature_only::Bool = get(io, :print_method_signature_only, false)::Bool)
221
    tv, decls, file, line = arg_decl_parts(m)
177✔
222
    if m.sig <: Tuple{Core.Builtin, Vararg}
177✔
223
        # Builtin
224
        print(io, m.name, "(...)")
3✔
225
        file = "none"
3✔
226
        line = 0
3✔
227
    else
228
        print(io, decls[1][2], "(")
174✔
229

230
        # arguments
231
        for (i,d) in enumerate(decls[2:end])
174✔
232
            printstyled(io, d[1], color=:light_black)
243✔
233
            if !isempty(d[2])
243✔
234
                print(io, "::")
198✔
235
                print_type_bicolor(io, d[2], color=:bold, inner_color=:normal)
198✔
236
            end
237
            i < length(decls)-1 && print(io, ", ")
243✔
238
        end
345✔
239

240
        kwargs = kwarg_decl(m)
174✔
241
        if !isempty(kwargs)
174✔
242
            print(io, "; ")
12✔
243
            for kw in kwargs
12✔
244
                skw = sym_to_string(kw)
15✔
245
                print(io, skw)
15✔
246
                if kw != last(kwargs)
15✔
247
                    print(io, ", ")
3✔
248
                end
249
            end
15✔
250
        end
251
        print(io, ")")
174✔
252
        show_method_params(io, tv)
174✔
253
    end
254

255
    if !print_signature_only
177✔
256
        if !(get(io, :compact, false)::Bool) # single-line mode
177✔
257
            println(io)
165✔
258
            digit_align_width += 4
165✔
259
        end
260
        # module & file, re-using function from errorshow.jl
261
        print_module_path_file(io, parentmodule(m), string(file), line; modulecolor, digit_align_width)
177✔
262
    end
263
end
264

265
function show_method_list_header(io::IO, ms::MethodList, namefmt::Function)
108✔
266
    tn = ms.tn
108✔
267
    name = tn.singletonname
108✔
268
    hasname = isdefined(tn.module, name) &&
108✔
269
              typeof(getfield(tn.module, name)) <: Function
270
    n = length(ms)
108✔
271
    m = n==1 ? "method" : "methods"
108✔
272
    print(io, "# $n $m")
108✔
273
    sname = string(name)
108✔
274
    namedisplay = namefmt(sname)
108✔
275
    if hasname
108✔
276
        what = (startswith(sname, '@') ?
156✔
277
                    "macro"
278
               : tn.module === Core && tn.wrapper <: Core.Builtin ?
279
                    "builtin function"
280
               : # else
281
                    "generic function")
282
        print(io, " for ", what, " ", namedisplay, " from ")
81✔
283

284
        col = get!(() -> popfirst!(STACKTRACE_MODULECOLORS), STACKTRACE_FIXEDCOLORS, parentmodule_before_main(tn.module))
93✔
285

286
        printstyled(io, tn.module, color=col)
81✔
287
    elseif '#' in sname
27✔
288
        print(io, " for anonymous function ", namedisplay)
9✔
289
    elseif tn === _TYPE_NAME || iskindtype(tn.wrapper)
51✔
290
        print(io, " for type constructor")
9✔
291
    else
292
        print(io, " for callable object")
9✔
293
    end
294
    !iszero(n) && print(io, ":")
108✔
295
end
296

297
# Determine the `modulecolor` value to pass to `show_method`
298
function _modulecolor(method::Method)
299
    mmt = get_methodtable(method)
330✔
300
    # TODO: this looks like a buggy bit of internal hacking, so disable for now
301
    return nothing
165✔
302
    if mmt === nothing || mmt.module === parentmodule(method)
×
303
        return nothing
×
304
    end
305
    # `mmt` is only particularly relevant for external method tables. Since the primary
306
    # method table is shared, we now need to distinguish "primary" methods by trying to
307
    # check if there is a primary `DataType` to identify it with. c.f. how `jl_method_def`
308
    # would derive this same information (for the name).
309
    ft = argument_datatype((unwrap_unionall(method.sig)::DataType).parameters[1])
×
310
    # `ft` should be the type associated with the first argument in the method signature.
311
    # If it's `Type`, try to unwrap it again.
312
    if isType(ft)
×
313
        ft = argument_datatype(ft.parameters[1])
×
314
    end
315
    if ft === nothing || parentmodule(method) === parentmodule(ft) !== Core
×
316
        return nothing
×
317
    end
318
    m = parentmodule_before_main(method)
×
319
    return get!(() -> popfirst!(STACKTRACE_MODULECOLORS), STACKTRACE_FIXEDCOLORS, m)
×
320
end
321

322
function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=true)
78✔
323
    tn = ms.tn
156✔
324
    name = tn.singletonname
78✔
325
    hasname = isdefined(tn.module, name) &&
78✔
326
              typeof(getfield(tn.module, name)) <: Function
327
    if header
78✔
328
        show_method_list_header(io, ms, str -> "\""*str*"\"")
156✔
329
    end
330
    n = rest = 0
78✔
331
    local last
332

333
    last_shown_line_infos = get(io, :last_shown_line_infos, nothing)
78✔
334
    last_shown_line_infos === nothing || empty!(last_shown_line_infos)
78✔
335

336
    digit_align_width = length(string(max > 0 ? max : length(ms)))
156✔
337

338
    for meth in ms
150✔
339
        if max == -1 || n < max
165✔
340
            n += 1
165✔
341
            println(io)
165✔
342

343
            print(io, " ", lpad("[$n]", digit_align_width + 2), " ")
165✔
344

345
            show_method(io, meth; modulecolor=_modulecolor(meth))
330✔
346

347
            file, line = updated_methodloc(meth)
165✔
348
            if last_shown_line_infos !== nothing
165✔
349
                push!(last_shown_line_infos, (string(file), line))
×
350
            end
351
        else
352
            rest += 1
×
353
            last = meth
×
354
        end
355
    end
258✔
356
    if rest > 0
78✔
357
        println(io)
×
358
        if rest == 1
×
359
            show_method(io, last)
×
360
        else
361
            print(io, "... $rest methods not shown")
×
362
            if hasname
×
363
                print(io, " (use methods($name) to see them all)")
×
364
            end
365
        end
366
    end
367
    nothing
78✔
368
end
369

370
show(io::IO, ms::MethodList) = show_method_table(io, ms)
51✔
371
show(io::IO, ::MIME"text/plain", ms::MethodList) = show_method_table(io, ms)
27✔
372
show(io::IO, mt::Core.MethodTable) = print(io, mt.module, ".", mt.name, " is a Core.MethodTable with ", length(mt), " methods.")
×
373

374
function inbase(m::Module)
×
375
    if m == Base
×
376
        true
×
377
    else
378
        parent = parentmodule(m)
×
379
        parent === m ? false : inbase(parent)
×
380
    end
381
end
382
fileurl(file) = let f = find_source_file(file); f === nothing ? "" : "file://"*f; end
×
383

384
function url(m::Method)
×
385
    M = parentmodule(m)
×
386
    (m.file === :null || m.file === :string) && return ""
×
387
    file = string(m.file)
×
388
    line = m.line
×
389
    line <= 0 || occursin(r"In\[[0-9]+\]"a, file) && return ""
×
390
    Sys.iswindows() && (file = replace(file, '\\' => '/'))
×
391
    if inbase(M)
×
392
        if isempty(Base.GIT_VERSION_INFO.commit)
×
393
            # this url will only work if we're on a tagged release
394
            return "https://github.com/JuliaLang/julia/tree/v$VERSION/base/$file#L$line"
×
395
        else
396
            return "https://github.com/JuliaLang/julia/tree/$(Base.GIT_VERSION_INFO.commit)/base/$file#L$line"
×
397
        end
398
    end
399
    libgit2_id = PkgId(UUID((0x76f85450_5226_5b5a,0x8eaa_529ad045b433)), "LibGit2")
×
400
    LibGit2 = maybe_root_module(libgit2_id)
×
401
    if LibGit2 isa Module
×
402
        try
×
403
            d = dirname(file)
×
404
            return let file = file
×
405
                LibGit2.with(LibGit2.GitRepoExt(d)) do repo
×
406
                    LibGit2.with(LibGit2.GitConfig(repo)) do cfg
×
407
                        u = LibGit2.get(cfg, "remote.origin.url", "")
×
408
                        u = (match(LibGit2.GITHUB_REGEX,u)::AbstractMatch).captures[1]
×
409
                        commit = string(LibGit2.head_oid(repo))
×
410
                        root = LibGit2.path(repo)
×
411
                        if startswith(file, root) || startswith(realpath(file), root)
×
412
                            "https://github.com/$u/tree/$commit/"*file[length(root)+1:end]*"#L$line"
×
413
                        else
414
                            fileurl(file)
×
415
                        end
416
                    end
417
                end
418
            end::String
419
        catch
×
420
            # oops, this was a bad idea
421
        end
422
    end
423
    return fileurl(file)
×
424
end
425

426
function show(io::IO, ::MIME"text/html", m::Method)
36✔
427
    tv, decls, file, line = arg_decl_parts(m, true)
36✔
428
    sig = unwrap_unionall(m.sig)
36✔
429
    if sig <: Tuple{Core.Builtin, Vararg}
36✔
430
        print(io, m.name, "(...) in ", parentmodule(m))
×
431
        return
×
432
    end
433
    print(io, decls[1][2], "(")
36✔
434
    join(
36✔
435
        io,
436
        String[
437
            isempty(d[2]) ? string(d[1]) : string(d[1], "::<b>", d[2] , "</b>") for d in decls[2:end]
438
        ],
439
        ", ",
440
        ", ",
441
    )
442
    kwargs = kwarg_decl(m)
36✔
443
    if !isempty(kwargs)
36✔
444
        print(io, "; <i>")
15✔
445
        join(io, map(sym_to_string, kwargs), ", ", ", ")
15✔
446
        print(io, "</i>")
15✔
447
    end
448
    print(io, ")")
36✔
449
    if !isempty(tv)
36✔
450
        print(io,"<i>")
6✔
451
        show_method_params(io, tv)
6✔
452
        print(io,"</i>")
6✔
453
    end
454
    print(io, " in ", parentmodule(m))
36✔
455
    if line > 0
36✔
456
        file, line = updated_methodloc(m)
36✔
457
        u = url(m)
36✔
458
        if isempty(u)
36✔
459
            print(io, " at ", file, ":", line)
×
460
        else
461
            print(io, """ at <a href="$u" target="_blank">""",
36✔
462
                  file, ":", line, "</a>")
463
        end
464
    end
465
end
466

467
function show(io::IO, mime::MIME"text/html", ms::MethodList)
30✔
468
    show_method_list_header(io, ms, str -> "<b>"*str*"</b>")
60✔
469
    print(io, "<ul>")
30✔
470
    for meth in ms
60✔
471
        print(io, "<li> ")
30✔
472
        show(io, mime, meth)
30✔
473
        print(io, "</li> ")
30✔
474
    end
30✔
475
    print(io, "</ul>")
30✔
476
end
477

478
# pretty-printing of AbstractVector{Method}
479
function show(io::IO, mime::MIME"text/plain", mt::AbstractVector{Method})
3✔
480
    last_shown_line_infos = get(io, :last_shown_line_infos, nothing)
3✔
481
    last_shown_line_infos === nothing || empty!(last_shown_line_infos)
3✔
482
    first = true
3✔
483
    for (i, m) in enumerate(mt)
3✔
484
        first || println(io)
×
485
        first = false
×
486
        print(io, "[$(i)] ")
×
487
        show(io, m)
×
488
        file, line = updated_methodloc(m)
×
489
        if last_shown_line_infos !== nothing
×
490
            push!(last_shown_line_infos, (string(file), line))
×
491
        end
492
    end
×
493
    first && summary(io, mt)
3✔
494
    nothing
3✔
495
end
496

497
function show(io::IO, mime::MIME"text/html", mt::AbstractVector{Method})
3✔
498
    summary(io, mt)
3✔
499
    if !isempty(mt)
3✔
500
        print(io, ":<ul>")
×
501
        for d in mt
×
502
            print(io, "<li> ")
×
503
            show(io, mime, d)
×
504
        end
×
505
        print(io, "</ul>")
×
506
    end
507
    nothing
3✔
508
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

© 2026 Coveralls, Inc