Skip to content

Commit

Permalink
Explicitly store a module's location (#55963)
Browse files Browse the repository at this point in the history
Revise wants to know what file a module's `module` definition is in.
Currently it does this by looking at the source location for the
implicitly generated `eval` method. This is terrible for two reasons:

1. The method may not exist if the module is a baremodule (which is not
particularly common, which is probably why we haven't seen it).
2. The fact that the implicitly generated `eval` method has this
location information is an implementation detail that I'd like to get
rid of (#55949).

This PR adds explicit file/line info to `Module`, so that Revise doesn't
have to use the hack anymore.
  • Loading branch information
Keno authored Oct 2, 2024
1 parent 5fc582b commit d19bb47
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 0 deletions.
11 changes: 11 additions & 0 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ function fullname(m::Module)
return (fullname(mp)..., mn)
end

"""
moduleloc(m::Module) -> LineNumberNode
Get the location of the `module` definition.
"""
function moduleloc(m::Module)
line = Ref{Int32}(0)
file = ccall(:jl_module_getloc, Ref{Symbol}, (Any, Ref{Int32}), m, line)
return LineNumberNode(Int(line[]), file)
end

"""
names(x::Module; all::Bool=false, imported::Bool=false, usings::Bool=false) -> Vector{Symbol}
Expand Down
1 change: 1 addition & 0 deletions src/jl_exported_funcs.inc
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@
XX(jl_module_name) \
XX(jl_module_names) \
XX(jl_module_parent) \
XX(jl_module_getloc) \
XX(jl_module_public) \
XX(jl_module_public_p) \
XX(jl_module_use) \
Expand Down
2 changes: 2 additions & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,8 @@ typedef struct _jl_module_t {
struct _jl_module_t *parent;
_Atomic(jl_svec_t*) bindings;
_Atomic(jl_genericmemory_t*) bindingkeyset; // index lookup by name into bindings
jl_sym_t *file;
int32_t line;
// hidden fields:
arraylist_t usings; // modules with all bindings potentially imported
jl_uuid_t build_id;
Expand Down
10 changes: 10 additions & 0 deletions src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, jl_module_t *parent, ui
m->compile = -1;
m->infer = -1;
m->max_methods = -1;
m->file = name; // Using the name as a placeholder is better than nothing
m->line = 0;
m->hash = parent == NULL ? bitmix(name->hash, jl_module_type->hash) :
bitmix(name->hash, parent->hash);
JL_MUTEX_INIT(&m->lock, "module->lock");
Expand Down Expand Up @@ -1179,6 +1181,14 @@ jl_module_t *jl_module_root(jl_module_t *m)
}
}

JL_DLLEXPORT jl_sym_t *jl_module_getloc(jl_module_t *m, int32_t *line)
{
if (line) {
*line = m->line;
}
return m->file;
}

JL_DLLEXPORT jl_uuid_t jl_module_build_id(jl_module_t *m) { return m->build_id; }
JL_DLLEXPORT jl_uuid_t jl_module_uuid(jl_module_t* m) { return m->uuid; }

Expand Down
3 changes: 3 additions & 0 deletions src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,9 @@ static void jl_write_module(jl_serializer_state *s, uintptr_t item, jl_module_t
jl_atomic_store_relaxed(&newm->bindingkeyset, NULL);
arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, bindingkeyset)));
arraylist_push(&s->relocs_list, (void*)backref_id(s, jl_atomic_load_relaxed(&m->bindingkeyset), s->link_ids_relocs));
newm->file = NULL;
arraylist_push(&s->relocs_list, (void*)(reloc_offset + offsetof(jl_module_t, file)));
arraylist_push(&s->relocs_list, (void*)backref_id(s, m->file, s->link_ids_relocs));

// write out the usings list
memset(&newm->usings._space, 0, sizeof(newm->usings._space));
Expand Down
4 changes: 4 additions & 0 deletions src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ static jl_value_t *jl_eval_module_expr(jl_module_t *parent_module, jl_expr_t *ex
form = NULL;
}

newm->file = jl_symbol(filename);
jl_gc_wb_knownold(newm, newm->file);
newm->line = lineno;

for (int i = 0; i < jl_array_nrows(exprs); i++) {
// process toplevel form
ct->world_age = jl_atomic_load_acquire(&jl_world_counter);
Expand Down

0 comments on commit d19bb47

Please sign in to comment.