Skip to content

add a vibe coded Test.detect_closure_boxes for closure boxes in loaded code#60478

Merged
KristofferC merged 4 commits intomasterfrom
kc/vibe_boxes
Jan 28, 2026
Merged

add a vibe coded Test.detect_closure_boxes for closure boxes in loaded code#60478
KristofferC merged 4 commits intomasterfrom
kc/vibe_boxes

Conversation

@KristofferC
Copy link
Copy Markdown
Member

@KristofferC KristofferC commented Dec 25, 2025

For example:

❯ ./julia contrib/scan-closure-boxes.jl --module=LibGit2
mod=LibGit2     var=branch_ref  func=#branch!#94        sig=Tuple{LibGit2.var"##branch!#94", AbstractString, Bool, Bool, typeof(LibGit2.branch!), LibGit2.GitRepo, AbstractString, AbstractString}   file=/Users/kc/julia/usr/share/julia/stdlib/v1.14/LibGit2/src/LibGit2.jl     line=416
mod=LibGit2     var=head_name   func=#checkout!#110     sig=Tuple{LibGit2.var"##checkout!#110", Bool, typeof(LibGit2.checkout!), LibGit2.GitRepo, AbstractString}    file=/Users/kc/julia/usr/share/julia/stdlib/v1.14/LibGit2/src/LibGit2.jl     line=506

and indeed:

julia> code_warntype(Tuple{LibGit2.var"##branch!#94", AbstractString, Bool, Bool, typeof(LibGit2.branch!), LibGit2.GitRepo, AbstractString, AbstractString})
MethodInstance for LibGit2.var"#branch!#94"(::AbstractString, ::Bool, ::Bool, ::typeof(LibGit2.branch!), ::GitRepo, ::AbstractString, ::AbstractString)
  from var"#branch!#94"(track::AbstractString, force::Bool, set_head::Bool, ::typeof(LibGit2.branch!), repo::GitRepo, branch_name::AbstractString, commit::AbstractString) @ LibGit2 ~/julia/usr/share/julia/stdlib/v1.14/LibGit2/src/LibGit2.jl:416
Arguments
  #branch!#94::Core.Const(LibGit2.var"#branch!#94")
  track::AbstractString
...
  branch_ref@_16::Core.Box <--------

@KristofferC
Copy link
Copy Markdown
Member Author

Not sure if this is obvious or not, but can (of course) be used with external packages as well:

~/JuliaPkgs/DataFrames.jl
❯ ~/julia/julia --project ~/julia/contrib/scan-closure-boxes.jl --module=DataFrames 
mod=DataFrames  var=newparent   func=_combine_prepare_norm      sig=Tuple{typeof(DataFrames._combine_prepare_norm), DataFrames.GroupedDataFrame, Vector{Any}, Vararg{Bool, 6}}       file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/splitapplycombine.jl     line=56
mod=DataFrames  var=outcol      func=_combine_process_proprow   sig=Tuple{typeof(DataFrames._combine_process_proprow), Ref{Any}, Bool, DataFrames.AbstractDataFrame, DataFrames.GroupedDataFrame, Dict{Symbol, Tuple{Bool, Int64}}, Vector{DataFrames.TransformationResult}, Vector{Int64}}       file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/splitapplycombine.jl     line=286
mod=DataFrames  var=right_ixs   func=compose_inner_table        sig=Tuple{typeof(DataFrames.compose_inner_table), DataFrames.DataFrameJoiner, Bool, Union{AbstractString, Function, Symbol}, Union{AbstractString, Function, Symbol}, Symbol}     file=/Users/kc/JuliaPkgs/DataFrames.jl/src/join/composer.jl     line=237
mod=DataFrames  var=left_ixs    func=compose_inner_table        sig=Tuple{typeof(DataFrames.compose_inner_table), DataFrames.DataFrameJoiner, Bool, Union{AbstractString, Function, Symbol}, Union{AbstractString, Function, Symbol}, Symbol}     file=/Users/kc/JuliaPkgs/DataFrames.jl/src/join/composer.jl     line=237
mod=DataFrames  var=idx_keeprows        func=_combine   sig=Tuple{typeof(DataFrames._combine), DataFrames.GroupedDataFrame, Vector{Any}, Vector{Bool}, Vararg{Bool, 4}}      file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/splitapplycombine.jl     line=665
mod=DataFrames  var=first       func=_combine_with_first        sig=Tuple{typeof(DataFrames._combine_with_first), Ref{Any}, Ref{Any}, DataFrames.GroupedDataFrame, Ref{Any}, Bool, Vector{Int64}, Bool}      file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/complextransforms.jl     line=24
mod=DataFrames  var=drop        func=_deleteat!_helper  sig=Tuple{typeof(DataFrames._deleteat!_helper), DataFrames.DataFrame, Any}   file=/Users/kc/JuliaPkgs/DataFrames.jl/src/dataframe/dataframe.jl       line=897
mod=DataFrames  var=reduce_or!  func=row_group_slots!   sig=Tuple{typeof(DataFrames.row_group_slots!), NTuple{N, AbstractVector}, NTuple{N, AbstractVector}, NTuple{N, Union{Missings.EachReplaceMissing{<:AbstractVector{<:Union{Missing, Real}}}, AbstractVector{<:Real}}}, Val{false}, Vector{Int64}, Bool, Bool, Bool} where N        file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/utils.jl line=265
mod=DataFrames  var=metacol     func=_combine_process_pair_symbol       sig=Tuple{typeof(DataFrames._combine_process_pair_symbol), Bool, DataFrames.GroupedDataFrame, Dict{Symbol, Tuple{Bool, Int64}}, Vector{DataFrames.TransformationResult}, Ref{Vector{Int64}}, Symbol, Bool, Ref{Any}, Ref{Any}, Ref{Any}, Bool, Ref{Any}}  file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/splitapplycombine.jl     line=423
mod=DataFrames  var=outcols     func=_combine_rows_with_first!  sig=Tuple{typeof(DataFrames._combine_rows_with_first!), Ref{Any}, Ref{Any}, Ref{Any}, DataFrames.GroupedDataFrame, Ref{Any}, Ref{Any}, Bool, Bool}   file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/complextransforms.jl     line=243
mod=DataFrames  var=ngroups     func=#subset!#645       sig=Tuple{DataFrames.var"##subset!#645", Bool, Bool, Bool, typeof(DataFrames.subset!), DataFrames.GroupedDataFrame, Vararg{Any}}     file=/Users/kc/JuliaPkgs/DataFrames.jl/src/abstractdataframe/subset.jl       line=480
mod=DataFrames  var=newoutcols  func=_combine_rows_with_first_task!     sig=Tuple{typeof(DataFrames._combine_rows_with_first_task!), Integer, Integer, Integer, Integer, NTuple{var"#s659", AbstractVector} where var"#s659", Ref{NTuple{var"#s658", AbstractVector} where var"#s658"}, AbstractVector{Bool}, ReentrantLock, Union{Function, Type}, DataFrames.GroupedDataFrame, AbstractVector{<:Integer}, AbstractVector{<:Integer}, Union{Nothing, Tuple, NamedTuple, AbstractVector}, NTuple{var"#s140", Symbol} where var"#s140", DataFrames.FirstColCount}    file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/complextransforms.jl     line=122
mod=DataFrames  var=eltys       func=_combine_tables_with_first!        sig=Tuple{typeof(DataFrames._combine_tables_with_first!), Union{DataFrames.AbstractDataFrame, NamedTuple{<:Any, <:Tuple{Vararg{AbstractVector}}}}, NTuple{N, AbstractVector}, Vector{Int64}, Integer, Integer, Union{Function, Type}, DataFrames.GroupedDataFrame, Union{Nothing, Tuple, NamedTuple, AbstractVector}, NTuple{N, Symbol}, DataFrames.FirstColCount} where N     file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/complextransforms.jl     line=355
mod=DataFrames  var=col func=#reduce#660        sig=Tuple{DataFrames.var"##reduce#660", Union{AbstractVector{Symbol}, Symbol, AbstractVector{<:AbstractString}}, Union{Nothing, AbstractString, Symbol, Pair{<:Union{AbstractString, Symbol}, <:AbstractVector}}, DataFrames.AbstractDataFrame, typeof(reduce), typeof(vcat), Union{AbstractVector{DataFrames.AbstractDataFrame}, AbstractVector{DataFrames.DataFrame}, AbstractVector{DataFrames.SubDataFrame}, AbstractVector{Union{DataFrames.DataFrame, DataFrames.SubDataFrame}}, Tuple{DataFrames.AbstractDataFrame, Vararg{DataFrames.AbstractDataFrame}}}}       file=/Users/kc/JuliaPkgs/DataFrames.jl/src/abstractdataframe/iteration.jl       line=694
mod=DataFrames  var=len func=_  sig=Tuple{DataFrames.var"#_#186#188", Bool, Type{DataFrames.DataFrame}, Union{Vector{Any}, Vector{AbstractVector}}, DataFrames.Index}        file=/Users/kc/JuliaPkgs/DataFrames.jl/src/dataframe/dataframe.jl    line=193
mod=DataFrames  var=predefined_funs     func=_describe  sig=Tuple{typeof(DataFrames._describe), DataFrames.AbstractDataFrame, AbstractVector}        file=/Users/kc/JuliaPkgs/DataFrames.jl/src/abstractdataframe/abstractdataframe.jl   line=699
mod=DataFrames  var=idx func=_combine_process_callable  sig=Tuple{typeof(DataFrames._combine_process_callable), Ref{Any}, Bool, DataFrames.AbstractDataFrame, DataFrames.GroupedDataFrame, Dict{Symbol, Tuple{Bool, Int64}}, Vector{DataFrames.TransformationResult}, Ref{Vector{Int64}}, Bool}   file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/splitapplycombine.jl     line=371
mod=DataFrames  var=out_col_name        func=_combine_process_pair_astable      sig=Tuple{typeof(DataFrames._combine_process_pair_astable), Bool, DataFrames.GroupedDataFrame, Dict{Symbol, Tuple{Bool, Int64}}, Vector{DataFrames.TransformationResult}, Ref{Vector{Int64}}, Union{Type{DataFrames.AsTable}, AbstractVector{Symbol}}, Bool, Ref{Any}, Ref{Any}, Ref{Any}, Bool}       file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/splitapplycombine.jl        line=511
mod=DataFrames  var=nms func=_combine_process_pair_astable      sig=Tuple{typeof(DataFrames._combine_process_pair_astable), Bool, DataFrames.GroupedDataFrame, Dict{Symbol, Tuple{Bool, Int64}}, Vector{DataFrames.TransformationResult}, Ref{Vector{Int64}}, Union{Type{DataFrames.AsTable}, AbstractVector{Symbol}}, Bool, Ref{Any}, Ref{Any}, Ref{Any}, Bool}       file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/splitapplycombine.jl        line=511
mod=DataFrames  var=outcols     func=_combine_process_pair_astable      sig=Tuple{typeof(DataFrames._combine_process_pair_astable), Bool, DataFrames.GroupedDataFrame, Dict{Symbol, Tuple{Bool, Int64}}, Vector{DataFrames.TransformationResult}, Ref{Vector{Int64}}, Union{Type{DataFrames.AsTable}, AbstractVector{Symbol}}, Bool, Ref{Any}, Ref{Any}, Ref{Any}, Bool}       file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/splitapplycombine.jl        line=511
mod=DataFrames  var=idx func=_combine_process_pair_astable      sig=Tuple{typeof(DataFrames._combine_process_pair_astable), Bool, DataFrames.GroupedDataFrame, Dict{Symbol, Tuple{Bool, Int64}}, Vector{DataFrames.TransformationResult}, Ref{Vector{Int64}}, Union{Type{DataFrames.AsTable}, AbstractVector{Symbol}}, Bool, Ref{Any}, Ref{Any}, Ref{Any}, Bool}       file=/Users/kc/JuliaPkgs/DataFrames.jl/src/groupeddataframe/splitapplycombine.jl        line=511

@KristofferC
Copy link
Copy Markdown
Member Author

KristofferC commented Dec 25, 2025

@aviatesk maybe you have some thoughts about this? I guess this is kind of the same as https://github.com/aviatesk/JET.jl/blob/cf77ed77e46b1a3bda92494818792272269d1d1a/src/analyzers/optanalyzer.jl#L276-L306? Is there a way to only run the CapturedVariableReport "pass" to get an output similar to above? I like how this doesn't have much "noise".

@KristofferC KristofferC changed the title add a vibe coded script to contrib that checks for closures boxes in loaded code add a vibe coded script to contrib that checks for closure boxes in loaded code Dec 25, 2025
@aviatesk
Copy link
Copy Markdown
Member

Sure, we can definitely provide that kind of analysis as a special analyzer for JET.jl. Right now, JET only works with v1.12, but maybe we want to give it a shot?

@aviatesk
Copy link
Copy Markdown
Member

aviatesk commented Dec 25, 2025

So you can do something like

using JET

struct CapturedVariableFilter{RC<:JET.ReportConfig}
    inner::RC
end
function CapturedVariableFilter(; target_modules = nothing, ignored_modules = nothing)
    CapturedVariableFilter(JET.ReportConfig(target_modules, ignored_modules))
end

function JET.configured_reports(config::CapturedVariableFilter, reports::Vector{JET.InferenceErrorReport})
    reports = filter(r->r isa JET.CapturedVariableReport, reports)
    return JET.configured_reports(config.inner, reports)
end
julia> function func(x)
           local y
           f = function ()
               y = x
           end
           return y
       end;

julia> report_opt(func, (Int,), report_config=CapturedVariableFilter())
═════ 1 possible error found ═════
┌ func(x::Int64) @ Main ./REPL[4]:2
│ captured variable `y` detected
└────────────────────

julia> using LibGit2

julia> report_opt(LibGit2.branch!, (LibGit2.GitRepo,String); report_config=CapturedVariableFilter())
═════ 1 possible error found ═════
┌ branch!(repo::GitRepo, branch_name::String) @ LibGit2 /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-R17H3W25T9.0/build/default-honeycrisp-R17H3W25T9-0/julialang/julia-release-1-dot-12/usr/share/julia/stdlib/v1.12/LibGit2/src/LibGit2.jl:405
│┌ branch!(repo::GitRepo, branch_name::String, commit::String) @ LibGit2 /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-R17H3W25T9.0/build/default-honeycrisp-R17H3W25T9-0/julialang/julia-release-1-dot-12/usr/share/julia/stdlib/v1.12/LibGit2/src/LibGit2.jl:405
││┌ branch!(repo::GitRepo, branch_name::String, commit::String; track::String, force::Bool, set_head::Bool) @ LibGit2 /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-R17H3W25T9.0/build/default-honeycrisp-R17H3W25T9-0/julialang/julia-release-1-dot-12/usr/share/julia/stdlib/v1.12/LibGit2/src/LibGit2.jl:411
│││ captured variable `branch_ref` detected
││└────────────────────

@aviatesk
Copy link
Copy Markdown
Member

One thing to note is that report_opt, by default, doesn't report these kinds of performance issues for calls to abstract signatures to reduce noise (because dynamic dispatch would be reported at the callsite anyway instead). However, if your script, like in this PR, traverses methods and performs a comprehensive analysis, this tuning might not be useful since our focus is only on captured variables.
We can avoid that problem by specifying skip_noncompileable_calls=true:

julia> report_opt(LibGit2.branch!, (LibGit2.GitRepo,AbstractString); report_config=CapturedVariableFilter())
No errors detected


julia> report_opt(LibGit2.branch!, (LibGit2.GitRepo,AbstractString); report_config=CapturedVariableFilter(), skip_noncompileable_calls=false)
═════ 1 possible error found ═════
┌ branch!(repo::GitRepo, branch_name::AbstractString) @ LibGit2 /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-R17H3W25T9.0/build/default-honeycrisp-R17H3W25T9-0/julialang/julia-release-1-dot-12/usr/share/julia/stdlib/v1.12/LibGit2/src/LibGit2.jl:405
│┌ branch!(repo::GitRepo, branch_name::AbstractString, commit::String) @ LibGit2 /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-R17H3W25T9.0/build/default-honeycrisp-R17H3W25T9-0/julialang/julia-release-1-dot-12/usr/share/julia/stdlib/v1.12/LibGit2/src/LibGit2.jl:405
││┌ branch!(repo::GitRepo, branch_name::AbstractString, commit::String; track::String, force::Bool, set_head::Bool) @ LibGit2 /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-honeycrisp-R17H3W25T9.0/build/default-honeycrisp-R17H3W25T9-0/julialang/julia-release-1-dot-12/usr/share/julia/stdlib/v1.12/LibGit2/src/LibGit2.jl:411
│││ captured variable `branch_ref` detected
││└────────────────────

@KristofferC
Copy link
Copy Markdown
Member Author

I guess closure boxes are a bit special since you don't even need types to find them so you can just blast through methods and look at the lowered code (like what this PR does).

@aviatesk
Copy link
Copy Markdown
Member

Yeah I think JET might be too much just to find closure boxes.

@fingolfin
Copy link
Copy Markdown
Member

Fun! How about using PrettyTables to render the output?

Also, may I suggest merging file and line into a single FILE:LINE output? Many terminals allow clicking (possibly together with a modifier key like cmd or ctrl) on such an "enriched" path to directly jump to that location in an editor.

longemen3000 added a commit to ClapeyronThermo/Clapeyron.jl that referenced this pull request Dec 29, 2025
KristofferC added a commit to JuliaIO/Tar.jl that referenced this pull request Dec 29, 2025
KristofferC added a commit to Ferrite-FEM/Ferrite.jl that referenced this pull request Dec 29, 2025
Uses JuliaLang/julia#60478 to find `Core.Box` entries in the package and remove them. After this, there are no such closure boxes in the package.
KristofferC added a commit to JuliaLang/Pkg.jl that referenced this pull request Dec 29, 2025
Base.visit(Core.methodtable) do m
scan_method!(lines, m, modules)
end
sort!(lines, by = entry -> entry.mod)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The sorting is very unstable, how about using this instead (it works well for me)

Suggested change
sort!(lines, by = entry -> entry.mod)
sort!(lines, by = entry -> (entry.mod, entry.func, entry.var))

@vtjnash
Copy link
Copy Markdown
Member

vtjnash commented Dec 29, 2025

The improvements derived from this seem like a good idea. However, I question whether it is useful to merge this into contrib, or merely leave it as a closed PR for historical reference.

@KristofferC
Copy link
Copy Markdown
Member Author

Yeah, I can make it a Pkg app or something instead.

KristofferC added a commit to KristofferC/DataFrames.jl that referenced this pull request Dec 30, 2025
I used JuliaLang/julia#60478 to find all the `Core.Box` instances in the package and then fix them.
KristofferC added a commit to JuliaLang/Pkg.jl that referenced this pull request Dec 30, 2025
KristofferC added a commit to JuliaLang/Pkg.jl that referenced this pull request Dec 30, 2025
KristofferC added a commit to JuliaLang/Pkg.jl that referenced this pull request Dec 30, 2025
KristofferC added a commit to Ferrite-FEM/Ferrite.jl that referenced this pull request Dec 30, 2025
Uses JuliaLang/julia#60478 to find `Core.Box` entries in the package and remove them. After this, there are no such closure boxes in the package.
@KristofferC
Copy link
Copy Markdown
Member Author

I like Test.detect_core_boxes. I will try shift this PR to that.

jipolanco added a commit to jipolanco/VortexPasta.jl that referenced this pull request Jan 12, 2026
Detected using script from JuliaLang/julia#60478

This was the only Core.Box detected in VortexPasta.
allowed_undefineds=nothing)
@nospecialize mods
ambs = Set{Method}()
mods = collect(mods)::Vector{Module}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

julia> Test.detect_unbound_args()
ERROR: TypeError: in typeassert, expected Vector{Module}, got a value of type Vector{Union{}}

@KristofferC
Copy link
Copy Markdown
Member Author

KristofferC commented Jan 12, 2026

It is now in Test.

@giordano giordano added the testsystem The unit testing framework and Test stdlib label Jan 12, 2026
@giordano giordano changed the title add a vibe coded script to contrib that checks for closure boxes in loaded code add a vibe coded Test.detect_closure_boxes for closure boxes in loaded code Jan 12, 2026
Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com>
@KristofferC
Copy link
Copy Markdown
Member Author

I dunno if the all_modules version is needed but it is something I often want myself at least and there isn't really any good public way of getting all loaded modules I think.

@KristofferC
Copy link
Copy Markdown
Member Author

With the script, it was very easy to get the code_warntype of the method. Not equally easy now. You can do

julia> m, vars = first(Test.detect_closure_boxes(JuliaLowering))
_expand_ast_tree(ctx, srcref, tree) @ JuliaLowering ~/julia/JuliaLowering/src/ast.jl:235 => [:srcref]

julia> m
_expand_ast_tree(ctx, srcref, tree)
     @ JuliaLowering ~/julia/JuliaLowering/src/ast.jl:235

julia> Base.uncompressed_ast(m)
CodeInfo(
     @ /home/kc/julia/JuliaLowering/src/ast.jl:236 within `unknown scope`
1 ──        srcref@_43 = srcref@_3
│    %2   = srcref@_43
│           srcref@_43 = Core.Box(%2)
│           Core.NewvarNode(:(#1))
...

but that doesn't have the nice code_warntype printing. For that you can do something ugly like


julia> function _code_warntype(m::Method; kwargs...)
           sig = m.sig.parameters
           f = sig[1].instance
           argtypes = Tuple{sig[2:end]...}
           code_warntype(f, argtypes; kwargs...)
       end
_code_warntype (generic function with 1 method)

julia> _code_warntype(m)
MethodInstance for JuliaLowering._expand_ast_tree(::Any, ::Any, ::Any)
  from _expand_ast_tree(ctx, srcref, tree) @ JuliaLowering ~/julia/JuliaLowering/src/ast.jl:235
Arguments
  #self#::Core.Const(JuliaLowering._expand_ast_tree)
  ctx::Any
  srcref@_3::Any
  tree::Any

Would be nice to have an easy way to get the warn type printout from the results of the detect function.

@giordano
Copy link
Copy Markdown
Member

Can you not store the tuple of the signature, like you had in the script?

@nospecialize
ambs = Set{Tuple{Method,Method}}()
mods = collect(mods)::Vector{Module}
mods = Module[mods...]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Unrelated bugfix, should be separated out into independent PR and backported to v1.10, v1.12, v1.13?

@KristofferC
Copy link
Copy Markdown
Member Author

With the newish argument type deduction for @code_warntype it is actually quite easy to copy paste the output of the method definition printouts to it so I think this API is ok.

Keno pushed a commit that referenced this pull request Jan 28, 2026
Changes recursive closures into proper methods. Best to review without
whitespace. Found via #60478:

```  
julia> Test.detect_closure_boxes_all_modules()
8-element Vector{Pair{Method, Vector{Symbol}}}:
  prune(graph1_a::Base.JuliaSyntax.SyntaxGraph, entrypoints_a::Vector{Int64}) @ Base.JuliaSyntax /JuliaSyntax/src/porcelain/syntax_graph.jl:816 => [:get_resolved!]
  _stm_check_usage(pats::Expr) @ Base.JuliaSyntax /JuliaSyntax/src/porcelain/syntax_graph.jl:1095 => [:_stm_check_pattern]
```
@KristofferC KristofferC merged commit 1c9ecc2 into master Jan 28, 2026
8 checks passed
@KristofferC KristofferC deleted the kc/vibe_boxes branch January 28, 2026 11:22
fredrikekre pushed a commit to Ferrite-FEM/Ferrite.jl that referenced this pull request Jan 29, 2026
Uses JuliaLang/julia#60478 to find `Core.Box` entries in the package and remove them. After this, there are no such closure boxes in the package.
aviatesk pushed a commit that referenced this pull request Mar 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

testsystem The unit testing framework and Test stdlib

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants