-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
Methods have a couple of fields, .file and .line, that document their origin. But when a method is defined via a macro, it gets a little ambiguous: do you attribute the definition to the macro or to the caller of the macro? There's nothing really new here: the various complaints about figuring out where a @deprecate ... command was issued from have a long and storied history. Perhaps the most important thing here is that there is a viable (but insane) strategy for finding it, see below.
Let's consider the following example:
julia> m = @which Float32(π)
Float32(::Irrational{:π}) in Base.MathConstants at irrationals.jl:167There are a couple of interesting features here:
m.moduleisBase.MathConstants, which is the callerm.fileisirrationals.jl, the file in which the@irrationalmacro is defined. This is loaded intoBase, notBase.MathConstants.m.lineis likewise associated with the macro.- Figuring out the macro-caller's source location is tricky. For example,
julia> code = Base.uncompressed_ast(m)
CodeInfo(
1 ─ return 3.1415927f0
)
julia> code.linetable
1-element Array{Any,1}:
Core.LineInfoNode(Base.MathConstants, :Type, Symbol("irrationals.jl"), 167, 0)so again there doesn't seem to be any way of figuring out the caller's file.
I've found one viable strategy to find these methods:
- Figure out which specific macro was responsible for the definition. For example, here that means parsing
irrationals.jland looking to see which top-level expression contains line 167. - Grab
m.module'sevalorincludemethod and ask which file it's from. This is the file in which the module was created. - Parse that file and see if the module contains any additional
includedirectives, so that you get a complete list of all files that were used to define that module. - Then for each file:
- parse the file and look for
:macrocallexpressions to that particular macro - lower those calls and compute the method signature
- when you find a match, return the caller LineNumberNode.
- parse the file and look for
Obviously this is not a small amount of work; it would make life easier if Method contained enough information to figure this out more directly. To achieve that, it seems that CodeInfo needs some enhancements so that it can store the macro-caller's LineNumberNode. For example, allowing Vector{LineInfoNode} entries in code.linetable would be sufficient to document the origin. (Or make LineInfoNode a linked-list?)