InteractiveUtils: access bindings in latest world#60736
InteractiveUtils: access bindings in latest world#60736
Conversation
|
The main alternative to this approach might be to give |
|
I think it'd prefer if all of these gained a |
77aab44 to
0e7d6c3
Compare
|
@Keno updated. Perhaps the main thing to decide is whether |
|
|
InteractiveUtils provides a number of utilities for querying and
accessing the contents of modules. Because these modules can gain new
bindings, some callers of InteractiveUtils functions produce warnings
WARNING: Detected access to binding ... prior to its definition world.
One dramatic example occurs with the sequence
using OptimizationProblems: OptimizationProblems
using OptimizationProblems.ADNLPProblems
using ADNLPModels: ADNLPModel
when running with Revise. ADNLPProblems loads new problems via Requires,
and starting with v3.13 Revise queries `InteractiveUtils.subtypes` to
cache dependent fieldtypes. This triggers the warning.
To fix this, add `defined_since` and `world` keyword arguments to
`names`/`unsorted_names` to filter the returned names by world age.
These are then threaded through `varinfo`, `methodswith`, and `subtypes`
in InteractiveUtils so they operate on bindings in the correct world.
The defaults for `defined_since` and `world` kwargs are set to preserve
the current behavior. Revise will be able to eliminate the warnings by
passing `world=Base.tls_world_age()` to `subtypes`.
Related: timholy/Revise.jl#993
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0e7d6c3 to
214e69d
Compare
src/module.c
Outdated
| continue; | ||
| enum jl_partition_kind kind = jl_binding_kind(bpart); | ||
| if (((jl_atomic_load_relaxed(&b->flags) & BINDING_FLAG_PUBLICP) || | ||
| if ((((jl_atomic_load_relaxed(&b->flags) & BINDING_FLAG_PUBLICP) && !jl_bkind_is_some_guard(kind)) || |
There was a problem hiding this comment.
Please check---world wasn't working as intended without it, pre-definition queries were still returning the name.
There was a problem hiding this comment.
It's a behavioral change. E.g. for export'd bindings that were not assigned.
There was a problem hiding this comment.
Maybe? Undefined and public is still an option. This is not really about what's correct or not, more about what these options map to. My general preference would be not to change that since external packages are surprisingly sensitive to this list.
There was a problem hiding this comment.
If you want to filter something specific I'd rather add another boolean flag.
There was a problem hiding this comment.
Fundamentally the issue is that the guard entries for newly-created bindings in a module get backdated to the module age:
julia> module M
public z
end
Main.M
julia> age = Int(Base.get_world_counter())
39879
julia> b = GlobalRef(M, :z).binding
Binding Main.M.z
39874:∞ - undefined binding - guard entry
julia> age2 = Int(Base.get_world_counter())
39881
julia> @eval M z=1
1
julia> b = GlobalRef(M, :z).binding
Binding Main.M.z
39882:∞ - global variable with type Any
39874:39881 - undefined binding - guard entry
julia> @eval M y=1
1
julia> b = GlobalRef(M, :y).binding
Binding Main.M.y
39883:∞ - global variable with type Any
39874:39882 - undefined binding - guard entryAssuming this is necessary, I'm not sure how to identify the world age at time of creation.
This adds a new binding partition kind `PARTITION_KIND_DECLARED_GUARD` to distinguish bindings that were explicitly declared via `public x` or `export x` on an undefined name from purely implicit guard partitions created by lookup misses. Previously, `export foo` on an undefined name would set the EXPORTED flag on the existing GUARD partition. With this change, it creates a new DECLARED_GUARD partition, giving the explicit declaration its own world-stamped record. This allows tooling and error messages to distinguish "someone explicitly declared this name" from "this name was simply never resolved." This will be useful in resolving the challenges currently facing #60736. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
InteractiveUtils provides a number of utilities for querying and accessing the contents of modules. Because these modules can gain new bindings, some callers of InteractiveUtils functions produce warnings
One dramatic example occurs with the sequence
when running with Revise, where it can produce hundreds of warnings. ADNLPProblems loads new problems via Requires, and starting with v3.13 Revise queries
InteractiveUtils.subtypesto cache dependent fieldtypes. This triggers the warning, and because it runs in a separate task, the--depwarn=errortrick unfortunately failed to produce a stacktrace. Thus this was quite difficult to track down.Fixes timholy/Revise.jl#993
CC @aviatesk, @Keno