Skip to content

Proactively compile lambdas when the type of the closure is known#60259

Merged
aviatesk merged 2 commits intoJuliaLang:masterfrom
xal-0:precompile-simple-closures
Dec 9, 2025
Merged

Proactively compile lambdas when the type of the closure is known#60259
aviatesk merged 2 commits intoJuliaLang:masterfrom
xal-0:precompile-simple-closures

Conversation

@xal-0
Copy link
Copy Markdown
Member

@xal-0 xal-0 commented Nov 27, 2025

If a method we precompile instantiates a closure struct, and there is a single compileable signature for the closure method, we can compile the closure method with few downsides.

For example:

f(x::T) where {T <: Number} = y::T -> x+y
precompile(f, (Int,))

f(1)(2)

Before, the closure method would not get precompiled, resulting in --trace-compile output:
precompile(Tuple{Foo.var"#f##0#f##1"{Int64, Int64}, Int64})

This idea was motivated by trying to make the REPL precompile script more "static". Creating a task with @task or @async expands into a no-argument lambda, which won't get precompiled with the containing method.

If a method we precompile instantiates a closure struct, and there is a single
compileable signature for the closure method, we can compile the closure method
with few downsides.

For example:
```
f(x::T) where {T <: Number} = y::T -> x+y
precompile(f, (Int,))

f(1)(2)
```

Before, the closure method would not get precompiled, resulting in
`--trace-compile` output:
`precompile(Tuple{Foo.var"#f##0#f#JuliaLang#1"{Int64, Int64}, Int64})`

This idea was motivated by trying to make the REPL precompile script more
"static".  Creating a task with `@task` or `@async` expands into a no-argument
lambda, which won't get precompiled with the containing method.
@Keno
Copy link
Copy Markdown
Member

Keno commented Nov 27, 2025

Seems fine, but wouldn't this be better handled by understanding the edge intrinsic that we added (I think) for juliac purposes?

@xal-0
Copy link
Copy Markdown
Member Author

xal-0 commented Dec 1, 2025

Could you point me in the right direction? I'm unfamiliar with where we do this stuff for JuliaC.

@vtjnash also tells me #59221 helps with the problem I originally wanted to solve for @async.

@vtjnash vtjnash added backport 1.13 Change should be backported to release-1.13 merge me PR is reviewed. Merge when all tests are passing labels Dec 2, 2025
@aviatesk aviatesk merged commit 3efd5e7 into JuliaLang:master Dec 9, 2025
10 checks passed
aviatesk pushed a commit that referenced this pull request Dec 9, 2025
…0259)

If a method we precompile instantiates a closure struct, and there is a
single compileable signature for the closure method, we can compile the
closure method with few downsides.

For example:
```julia
f(x::T) where {T <: Number} = y::T -> x+y
precompile(f, (Int,))

f(1)(2)
```

Before, the closure method would not get precompiled, resulting in
`--trace-compile` output:
`precompile(Tuple{Foo.var"#f##0#f##1"{Int64, Int64}, Int64})`

This idea was motivated by trying to make the REPL precompile script
more "static". Creating a task with `@task` or `@async` expands into a
no-argument lambda, which won't get precompiled with the containing
method.
@inkydragon inkydragon removed the merge me PR is reviewed. Merge when all tests are passing label Dec 12, 2025
@KristofferC KristofferC removed the backport 1.13 Change should be backported to release-1.13 label Jan 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants