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

JuliaLang / julia / #37433

pending completion
#37433

push

local

web-flow
Merge pull request #48513 from JuliaLang/jn/extend-once

ensure extension triggers are only run by the package that satified them

60 of 60 new or added lines in 1 file covered. (100.0%)

72324 of 82360 relevant lines covered (87.81%)

31376331.4 hits per line

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

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

3
struct MethodLookupResult
4
    # Really Vector{Core.MethodMatch}, but it's easier to represent this as
5
    # and work with Vector{Any} on the C side.
6
    matches::Vector{Any}
16,629,300✔
7
    valid_worlds::WorldRange
8
    ambig::Bool
9
end
10
length(result::MethodLookupResult) = length(result.matches)
36,485,417✔
11
function iterate(result::MethodLookupResult, args...)
3,736✔
12
    r = iterate(result.matches, args...)
65,947,977✔
13
    r === nothing && return nothing
50,369,202✔
14
    match, state = r
×
15
    return (match::MethodMatch, state)
34,790,427✔
16
end
17
getindex(result::MethodLookupResult, idx::Int) = getindex(result.matches, idx)::MethodMatch
15,128,156✔
18

19
struct MethodMatchResult
20
    matches::MethodLookupResult
16,625,522✔
21
    overlayed::Bool
22
end
23

24
"""
25
    struct InternalMethodTable <: MethodTableView
26

27
A struct representing the state of the internal method table at a
28
particular world age.
29
"""
30
struct InternalMethodTable <: MethodTableView
31
    world::UInt
373,339✔
32
end
33

34
"""
35
    struct OverlayMethodTable <: MethodTableView
36

37
Overlays the internal method table such that specific queries can be redirected to an
38
external table, e.g., to override existing method.
39
"""
40
struct OverlayMethodTable <: MethodTableView
41
    world::UInt
7,138✔
42
    mt::Core.MethodTable
43
end
44

45
struct MethodMatchKey
46
    sig # ::Type
47
    limit::Int
48
    MethodMatchKey(@nospecialize(sig), limit::Int) = new(sig, limit)
4,662,012✔
49
end
50

51
"""
52
    struct CachedMethodTable <: MethodTableView
53

54
Overlays another method table view with an additional local fast path cache that
55
can respond to repeated, identical queries faster than the original method table.
56
"""
57
struct CachedMethodTable{T<:MethodTableView} <: MethodTableView
58
    cache::IdDict{MethodMatchKey, Union{Nothing,MethodMatchResult}}
369,476✔
59
    table::T
60
end
61
CachedMethodTable(table::T) where T = CachedMethodTable{T}(IdDict{MethodMatchKey, Union{Nothing,MethodMatchResult}}(), table)
369,476✔
62

63
"""
64
    findall(sig::Type, view::MethodTableView; limit::Int=-1) ->
65
        MethodMatchResult(matches::MethodLookupResult, overlayed::Bool) or nothing
66

67
Find all methods in the given method table `view` that are applicable to the given signature `sig`.
68
If no applicable methods are found, an empty result is returned.
69
If the number of applicable methods exceeded the specified `limit`, `nothing` is returned.
70
Note that the default setting `limit=-1` does not limit the number of applicable methods.
71
`overlayed` indicates if any of the matching methods comes from an overlayed method table.
72
"""
73
function findall(@nospecialize(sig::Type), table::InternalMethodTable; limit::Int=-1)
33,322,378✔
74
    result = _findall(sig, nothing, table.world, limit)
16,779,278✔
75
    result === nothing && return nothing
16,700,552✔
76
    return MethodMatchResult(result, false)
16,621,826✔
77
end
78

79
function findall(@nospecialize(sig::Type), table::OverlayMethodTable; limit::Int=-1)
7,478✔
80
    result = _findall(sig, table.mt, table.world, limit)
3,739✔
81
    result === nothing && return nothing
3,739✔
82
    nr = length(result)
3,739✔
83
    if nr ≥ 1 && result[nr].fully_covers
3,739✔
84
        # no need to fall back to the internal method table
85
        return MethodMatchResult(result, true)
4✔
86
    end
87
    # fall back to the internal method table
88
    fallback_result = _findall(sig, nothing, table.world, limit)
3,735✔
89
    fallback_result === nothing && return nothing
3,735✔
90
    # merge the fallback match results with the internal method table
91
    return MethodMatchResult(
3,735✔
92
        MethodLookupResult(
93
            vcat(result.matches, fallback_result.matches),
94
            WorldRange(
95
                max(result.valid_worlds.min_world, fallback_result.valid_worlds.min_world),
96
                min(result.valid_worlds.max_world, fallback_result.valid_worlds.max_world)),
97
            result.ambig | fallback_result.ambig),
98
        !isempty(result))
99
end
100

101
function _findall(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, world::UInt, limit::Int)
7,474✔
102
    _min_val = RefValue{UInt}(typemin(UInt))
16,708,026✔
103
    _max_val = RefValue{UInt}(typemax(UInt))
16,708,026✔
104
    _ambig = RefValue{Int32}(0)
16,708,026✔
105
    ms = _methods_by_ftype(sig, mt, limit, world, false, _min_val, _max_val, _ambig)
16,708,026✔
106
    isa(ms, Vector) || return nothing
16,786,752✔
107
    return MethodLookupResult(ms, WorldRange(_min_val[], _max_val[]), _ambig[] != 0)
16,629,300✔
108
end
109

110
function findall(@nospecialize(sig::Type), table::CachedMethodTable; limit::Int=-1)
38,438,878✔
111
    if isconcretetype(sig)
19,219,439✔
112
        # as for concrete types, we cache result at on the next level
113
        return findall(sig, table.table; limit)
14,557,427✔
114
    end
115
    key = MethodMatchKey(sig, limit)
4,662,012✔
116
    if haskey(table.cache, key)
7,184,786✔
117
        return table.cache[key]
2,522,774✔
118
    else
119
        return table.cache[key] = findall(sig, table.table; limit)
2,139,238✔
120
    end
121
end
122

123
"""
124
    findsup(sig::Type, view::MethodTableView) ->
125
        (match::MethodMatch, valid_worlds::WorldRange, overlayed::Bool) or nothing
126

127
Find the (unique) method such that `sig <: match.method.sig`, while being more
128
specific than any other method with the same property. In other words, find the method
129
which is the least upper bound (supremum) under the specificity/subtype relation of
130
the queried `sig`nature. If `sig` is concrete, this is equivalent to asking for the method
131
that will be called given arguments whose types match the given signature.
132
Note that this query is also used to implement `invoke`.
133

134
Such a matching method `match` doesn't necessarily exist.
135
It is possible that no method is an upper bound of `sig`, or
136
it is possible that among the upper bounds, there is no least element.
137
In both cases `nothing` is returned.
138

139
`overlayed` indicates if any of the matching methods comes from an overlayed method table.
140
"""
141
function findsup(@nospecialize(sig::Type), table::InternalMethodTable)
290✔
142
    return (_findsup(sig, nothing, table.world)..., false)
2,245✔
143
end
144

145
function findsup(@nospecialize(sig::Type), table::OverlayMethodTable)
45✔
146
    match, valid_worlds = _findsup(sig, table.mt, table.world)
45✔
147
    match !== nothing && return match, valid_worlds, true
45✔
148
    # fall back to the internal method table
149
    fallback_match, fallback_valid_worlds = _findsup(sig, nothing, table.world)
43✔
150
    return (
43✔
151
        fallback_match,
152
        WorldRange(
153
            max(valid_worlds.min_world, fallback_valid_worlds.min_world),
154
            min(valid_worlds.max_world, fallback_valid_worlds.max_world)),
155
        false)
156
end
157

158
function _findsup(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable}, world::UInt)
262✔
159
    min_valid = RefValue{UInt}(typemin(UInt))
2,333✔
160
    max_valid = RefValue{UInt}(typemax(UInt))
2,333✔
161
    match = ccall(:jl_gf_invoke_lookup_worlds, Any, (Any, Any, UInt, Ptr{Csize_t}, Ptr{Csize_t}),
2,333✔
162
                   sig, mt, world, min_valid, max_valid)::Union{MethodMatch, Nothing}
163
    valid_worlds = WorldRange(min_valid[], max_valid[])
2,078✔
164
    return match, valid_worlds
219✔
165
end
166

167
# This query is not cached
168
findsup(@nospecialize(sig::Type), table::CachedMethodTable) = findsup(sig, table.table)
1,814✔
169

170
isoverlayed(::MethodTableView)     = error("unsatisfied MethodTableView interface")
×
171
isoverlayed(::InternalMethodTable) = false
×
172
isoverlayed(::OverlayMethodTable)  = true
3,312✔
173
isoverlayed(mt::CachedMethodTable) = isoverlayed(mt.table)
×
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