Skip to content

Commit

Permalink
Docs: nuances of module-ownership of methods (#39)
Browse files Browse the repository at this point in the history
Add detail to the documentation on collecting Methods. It's a deeper
dive than most of the rest of the documentation, but it is an important
caveat to describe.
  • Loading branch information
timholy authored Mar 23, 2023
1 parent 909c450 commit 6becf45
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "MethodAnalysis"
uuid = "85b6ec6f-f7df-4429-9514-a64bcd9ee824"
authors = ["Tim Holy <tim.holy@gmail.com>"]
version = "0.4.11"
version = "0.4.12"

[deps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
Expand Down
2 changes: 1 addition & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
MethodAnalysis = "85b6ec6f-f7df-4429-9514-a64bcd9ee824"

[compat]
Documenter = "0.25"
Documenter = "0.27"
59 changes: 35 additions & 24 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ true

You can do this more easily with the convenience utility [`child_modules`](@ref).

### Collecting all Methods in Core.Compiler
### Collecting all Methods of functions defined in Core.Compiler

`visit` also descends into functions, methods, and MethodInstances:

Expand All @@ -47,6 +47,13 @@ julia> first(methods(Core.Compiler.typeinf_ext)) ∈ meths
true
```

!!! note
Methods are found by visiting the function. This has an important consequence: if `PkgB` defines a new method for `PkgA.f`, you won't find that method by visiting `PkgB`: you have to visit `PkgA.f` (which you can find by visiting `PkgA`). This is a consequence of how Julia stores Methods, not a limitation of MethodAnalysis.

Thus, to find all methods defined in `PkgB`, you have to traverse the entire system (`visit() do ... end`), and check the `meth.module` field of every Method to determine which module created it.

For methods that accept keyword arguments, Julia creates "hidden" methods for filling in the default values. Prior to Julia 1.9, you could find these by visiting the module that owns the "parent" function. On Julia 1.9 and above, these instead get added as methods of `Core.kwcall`. Consequently, these methods cannot be found by visiting the module that owns the parent function.

### Getting a MethodInstance for a particular set of types

```jldoctest; setup=:(using MethodAnalysis)
Expand Down Expand Up @@ -97,7 +104,7 @@ julia> mis = methodinstances(findfirst)

Let's see all the compiled instances of `Base.setdiff` and their immediate callers:

```jldoctest; setup=(using MethodAnalysis)
```jldoctest; setup=(using MethodAnalysis), filter=[r"(6|7)", r"Instance for .*"]
julia> direct_backedges(setdiff)
6-element Vector{Any}:
MethodInstance for setdiff(::Base.KeySet{Any, Dict{Any, Any}}, ::Base.KeySet{Any, Dict{Any, Any}}) => MethodInstance for keymap_merge(::Dict{Char, Any}, ::Dict{Any, Any})
Expand All @@ -112,7 +119,7 @@ julia> direct_backedges(setdiff)

MethodAnalysis uses [AbstractTrees](https://github.com/JuliaCollections/AbstractTrees.jl) to display the complete set of backedges:

```jldoctest; setup=:(using MethodAnalysis)
```jldoctest; setup=:(using MethodAnalysis), filter=r"─ MethodInstance for.*\$"
julia> mi = methodinstance(findfirst, (BitVector,))
MethodInstance for findfirst(::BitVector)
Expand All @@ -128,27 +135,30 @@ MethodInstance for findfirst(::BitVector)
│ └─ MethodInstance for resolve_versions!(::Context, ::Vector{PackageSpec})
│ ⋮
└─ MethodInstance for update_solution!(::SolutionTrace, ::Graph)
└─ MethodInstance for converge!(::Graph, ::Messages, ::SolutionTrace, ::NodePerm, ::MaxSumParams)
├─ MethodInstance for converge!(::Graph, ::Messages, ::SolutionTrace, ::NodePerm, ::MaxSumParams)
│ ├─ MethodInstance for converge!(::Graph, ::Messages, ::SolutionTrace, ::NodePerm, ::MaxSumParams)
│ │ ├─ MethodInstance for converge!(::Graph, ::Messages, ::SolutionTrace, ::NodePerm, ::MaxSumParams)
│ │ │ ⋮
│ │ │
│ │ └─ MethodInstance for maxsum(::Graph)
│ │ ⋮
│ │
│ └─ MethodInstance for maxsum(::Graph)
│ └─ MethodInstance for resolve(::Graph)
│ ⋮
└─ MethodInstance for maxsum(::Graph)
└─ MethodInstance for resolve(::Graph)
├─ MethodInstance for trigger_failure!(::Graph, ::Vector{Int64}, ::Tuple{Int64, Int64})
│ ⋮
└─ MethodInstance for resolve_versions!(::Context, ::Vector{PackageSpec})
├─ MethodInstance for update_solution!(::SolutionTrace, ::Graph)
│ └─ MethodInstance for converge!(::Graph, ::Messages, ::SolutionTrace, ::NodePerm, ::MaxSumParams)
│ ├─ MethodInstance for converge!(::Graph, ::Messages, ::SolutionTrace, ::NodePerm, ::MaxSumParams)
│ │ ├─ MethodInstance for converge!(::Graph, ::Messages, ::SolutionTrace, ::NodePerm, ::MaxSumParams)
│ │ │ ├─ MethodInstance for converge!(::Graph, ::Messages, ::SolutionTrace, ::NodePerm, ::MaxSumParams)
│ │ │ │ ⋮
│ │ │ │
│ │ │ └─ MethodInstance for maxsum(::Graph)
│ │ │ ⋮
│ │ │
│ │ └─ MethodInstance for maxsum(::Graph)
│ │ └─ MethodInstance for resolve(::Graph)
│ │ ⋮
│ │
│ └─ MethodInstance for maxsum(::Graph)
│ └─ MethodInstance for resolve(::Graph)
│ ├─ MethodInstance for trigger_failure!(::Graph, ::Vector{Int64}, ::Tuple{Int64, Int64})
│ │ ⋮
│ │
│ └─ MethodInstance for resolve_versions!(::Context, ::Vector{PackageSpec})
│ ⋮
└─ MethodInstance for selective_eval_fromstart!(::typeof(finish_and_return!), ::Frame, ::BitVector, ::Bool)
└─ MethodInstance for selective_eval_fromstart!(::Frame, ::BitVector, ::Bool)
```

### Finding the callers of a method
Expand All @@ -173,6 +183,7 @@ There are more options, see the help for `findcallers`.
```@docs
visit
visit_backedges
visit_withmodule
```

### backedges
Expand Down
4 changes: 2 additions & 2 deletions src/MethodAnalysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ see https://github.com/simonster/Reexport.jl), unless you set `external=true`.
# Examples
```jldoctest
```jldoctest outerinner; setup=:(using MethodAnalysis), filter=r"(Main\\.O|O)"
julia> module Outer
module Inner
export Base
Expand All @@ -239,7 +239,7 @@ julia> child_modules(Outer.Inner)
In the example above, because of the `export Base`, the following `visit`-based implementation would
also collect `Base` and all of its sub-modules:
```jldoctest
```jldoctest outerinner; setup=:(using MethodAnalysis)
julia> mods = Module[]
Module[]
Expand Down

2 comments on commit 6becf45

@timholy
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/80173

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.4.12 -m "<description of version>" 6becf455606df7cc92472f594300bb69e5acd9eb
git push origin v0.4.12

Please sign in to comment.