Skip to content

Conversation

@Keno
Copy link
Member

@Keno Keno commented Nov 9, 2024

This PR introduces a new, toplevel-only, syntax form :worldinc that semantically represents the effect of raising the current task's world age to the latest world for the remainder of the current toplevel evaluation (that context being an entry to eval or a module expression). For detailed motivation on why this is desirable, see #55145, which I won't repeat here, but the gist is that we never really defined when world-age increments and worse are inconsistent about it. This is something we need to figure out now, because the bindings partition work will make world age even more observable via bindings.

Having created a mechanism for world age increments, the big question is one of policy, i.e. when should these world age increments be inserted.

Several reasonable options exist:

  1. After world-age affecting syntax constructs (as proprosed in Make precise semantics of world-age increments in top-level thunks #55145)
  2. Option 1 + some reasonable additional cases that people rely on
  3. Before any top level call expression
  4. Before any expression at toplevel whatsover

As an example, case, consider a == a at toplevel. Depending on the semantics that could either be the same as in local scope, or each of the four world age dependent lookups (three binding lookups, one method lookup) could (potentially) occur in a different world age.

The general tradeoff here is between the risk of exposing the user to confusing world age errors and our ability to optimize top-level code (in general, any :worldinc statement will require us to fully pessimize or recompile all following code).

This PR basically implements option 2 with the following semantics:

  1. The interpreter explicit raises the world age only at :worldinc exprs or after :module exprs.
  2. The frontend inserts :worldinc after all struct definitions, method definitions, using and `import.
  3. The @eval macro inserts a worldinc following the call to eval if at toplevel
  4. A literal (syntactic) call to include gains an implicit worldinc.

Of these the fourth is probably the most questionable, but is necessary to make this non-breaking for most code patterns. Perhaps it would have been better to make include a macro from the beginning (esp because it already has semantics that look a little like reaching into the calling module), but that ship has sailed.

Unfortunately, I don't see any good intermediate options between this PR and option #3 above. I think option #3 is closest to what we have right now, but if we were to choose it and actually fix the soundness issues, I expect that we would be destroying all performance of global-scope code. For this reason, I would like to try to make the version in this PR work, even if the semantics are a little ugly.

The biggest pattern that this PR does not catch is:

eval(:(f() = 1))
f()

We could apply the same include special case to eval, but given the existence of @eval which allows addressing this at the macro level, I decided not to. We can decide which way we want to go on this based on what the package ecosystem looks like.

@Keno
Copy link
Member Author

Keno commented Nov 9, 2024

The SparseArrays test failure is known - SparseArrays.allowscalar redefines indexing methods and the test relies on that getting picked up right away. Should be changed to a macro with a worldage increment probably, but before going through the hassle of the multi repo coordination, let's finish this PR.

@Keno
Copy link
Member Author

Keno commented Nov 9, 2024

@nanosoldier runtests()

@aviatesk
Copy link
Member

aviatesk commented Nov 9, 2024

I’m not opposed to this PR, but what’s the specific reason for introducing :worldinc? From what I understand from reading #55145, it seems like modifying the runtime to adhere to these rules would avoid the discussed issues?

We stop incrementing the world age for every statement. Instead, world age (at the toplevel) is incremented to the latest world age only at the following points:
a. Entry into toplevel evaluation (i.e., at the beginning of Core.eval)
b. After any evaluation of :method
c. On the bindings branch, after introducing a new binding

(plus an increment after a :module expression as per you mentioned above)

That said, I think introducing :worldinc would make it easier to fix inference-related problems, like ensuring world-age is incremented correctly for include as done in this PR. So I’m actually in favor of adding this expression type, but I’d like to understand the reasoning clearly.

@test faz1(1) == 2
@test faz1(1.0) == 1
m = first(methods(bar1, Tuple{Int}))
Base.delete_method(m)
Copy link
Member

Choose a reason for hiding this comment

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

Does this mean that the result of Base.delete_method (and Base.delete_binding) won’t take effect until the user explicitly calls Core.@worldinc? That sounds like it would be a pretty breaking change. I agree with the idea of restricting the effect of :worldinc to the top level (for helping inference), but it seems like Base.delete_method might need some adjustments, such as calling @eval internally or something similar.

Copy link
Member Author

Choose a reason for hiding this comment

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

Does this mean that the result of Base.delete_method (and Base.delete_binding) won’t take effect until the user explicitly calls Core.@WorldInc?

It takes effect immediately (in a new world age), but the effect is not visible in the current task until it raises it world age.

Calling @eval internally will not raise the world age, because it's not at top level. delete_method is mostly used internally by Revise which can take an appropriate adjustment. There could also be a delete_method macro that does the world age raising implicitly.

@Keno
Copy link
Member Author

Keno commented Nov 10, 2024

but what’s the specific reason for introducing :worldinc?

Two reasons:

  1. As a separation of concerns issue and to put the more complicated world-age increment decisions into lowering rather than forcing the logic to be duplicated in several places
  2. To enable it to be inserted by macros that may want it

@Keno
Copy link
Member Author

Keno commented Nov 10, 2024

@vtjnash suggests implicit world-age increments between the args of :toplevel and :module. I think this is reasonable and I'll make an appropriate adjustment.

@Keno
Copy link
Member Author

Keno commented Nov 10, 2024

@vtjnash suggests implicit world-age increments between the args of :toplevel and :module.

Forgot to mention that @vtjnash pointed out that I already made world age increment for macro purposes in #53515, so it would be inconsistent for it not to increment the world age for execution, which I found convincing.

@Keno Keno force-pushed the kf/explicitageinc branch from d085375 to 4330bad Compare November 10, 2024 03:02
@nanosoldier
Copy link
Collaborator

The package evaluation job you requested has completed - possible new issues were detected.
The full report is available.

@Keno
Copy link
Member Author

Keno commented Nov 10, 2024

@nanosoldier runtests(["Tricks", "MethodInspector", "ExprTools", "OptimizingIR", "OverflowContexts", "CBOOCall", "LazyModules", "PowerSeries", "Purses", "Hygienic", "MullerPlot", "SyntaxTree", "Plugins", "ParameterisedModule", "ApproximationAnalysis", "VectorInterface", "Expronicon", "TestExtras", "Hyperspecialize", "TimerOutputs", "Behavior", "ProblemSet", "FinitePosets", "CommandLiner", "TrixiBase", "IRTools", "TypeStability", "LoweredCodeUtils", "LispSyntax", "FileIO", "Automa", "ComoniconTargetExpr", "SplittablesBase", "HAML", "JSON3", "PDDL", "Continuables", "DataSets", "DataFlowTasks", "GraphQLGen", "Revise", "ConfigurationsENV", "DebugAdapter", "LIBSVM", "FromFile", "Groups", "LazyReports", "Polyester", "Handcalcs", "PkgJogger", "IntervalLinearAlgebra", "TypeClasses", "Open62541", "MHLib", "ExtensibleEffects", "Arblib", "PlutoVista", "LegendrePolynomials", "LinkedInAPI", "SwagUI", "GraphQLClient", "Folds", "Serde", "FlatRBAC", "BenchmarkProfiles", "DataToolkitCommon", "ACSets", "SphericalHarmonicExpansions", "CrystalInfoFramework", "Experimenter", "MATDaemon", "DrelTools", "DistributedSparseGrids", "TransitionalMCMC", "AstroRepresentations", "TransformSpecifications", "PlutoPlotly", "Bukdu", "OndaEDFSchemas", "AppleHealthParser", "MultivariateChebyshev", "Onda", "AlignedSpans", "YasolSolver", "JSXGraph", "Semagrams", "Gen", "MaterialDecomposition", "CSetAutomorphisms", "GeniePlugins", "GenieSession", "GeniePackageManager", "GenieCache", "GenieDeployHeroku", "GenieCacheFileCache", "GenieDeployDocker", "GenieSessionFileSession", "InfiniteOpt", "EnergyModelsBase", "EnergyModelsCO2", "EnergyModelsRenewableProducers", "EnergyModelsGeography", "OndaEDF", "MembraneBase", "Books", "StippleMathjs", "Stipple", "StippleUI", "SparseArrayKit", "QWignerSymbols", "RegNets", "GenieDevTools", "HerbSearch", "Equate", "StippleCharts", "Herb", "StipplePlotly", "SteadyStateDiffEq", "StipplePlotlyExport", "TaylorInversion", "GenieAuthorisation", "CategoryData", "GenieFramework", "ReversePropagation", "GivEmXL", "GenericCharacterTables", "SphericalFunctions", "StippleKeplerGL", "Spehulak", "PlutoPages", "GeometryOptimization", "ProToPortal", "JuliaBUGS", "MLJTestIntegration", "CausalGPSLC", "MLJ", "WaveSpec", "Individual", "AntennaPattern", "SimpleCrop", "UnfoldBIDS", "LeafGasExchange", "Garlic", "EMpht", "Vahana", "Petri", "Lighthouse", "AffineMotions", "PlantGeomTurtle", "HetaSimulator", "Serialization", "CropRootBox"])

@nanosoldier
Copy link
Collaborator

The package evaluation job you requested has completed - possible new issues were detected.
The full report is available.

@Keno
Copy link
Member Author

Keno commented Nov 11, 2024

Alright, a fair number of tests with dependencies on JuliaInterpreter or Revise, which need to be taught about :worldinc, but also some that noticed the behavior change. I think the thing to do is

  1. an independent PR that just introduces :worldinc, but doesn't use it yet
  2. Fix JuliaInterpreter/Revise
  3. Re-run PkgEval and see what to do about the rest of the packages

Keno added a commit that referenced this pull request Nov 11, 2024
Split out from #56509 to facilitate adjusting downstream packages.
Keno added a commit that referenced this pull request Nov 11, 2024
This was part of #56509, but is an independent bugfix. The basic
issue is that these macro were using `do` block internally. This
is undesirable for test macros, because we would like them not to
affect the behavior of what they're testing. E.g. right now:
```
julia> using Test

julia> const x = 1
1

julia> @test_nowarn const x = 1
ERROR: syntax: `global const` declaration not allowed inside function around /home/keno/julia/usr/share/julia/stdlib/v1.12/Test/src/Test.jl:927
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1
```

This PR just writes out the try/finally manually, so the above
works fine after this PR.
aviatesk pushed a commit that referenced this pull request Nov 11, 2024
This was part of #56509, but is an independent bugfix. The basic issue
is that these macro were using `do` block internally. This is
undesirable for test macros, because we would like them not to affect
the behavior of what they're testing. E.g. right now:
```
julia> using Test

julia> const x = 1
1

julia> @test_nowarn const x = 1
ERROR: syntax: `global const` declaration not allowed inside function around /home/keno/julia/usr/share/julia/stdlib/v1.12/Test/src/Test.jl:927
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1
```

This PR just writes out the try/finally manually, so the above works
fine after this PR.
Keno added a commit that referenced this pull request Nov 12, 2024
Split out from #56509 to facilitate adjusting downstream packages.
for xf in backend.ast_transforms
ast = Base.invokelatest(xf, ast)
end
toplevel_eval_with_hooks(mod, Expr(:worldinc))
Copy link
Member

Choose a reason for hiding this comment

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

This is a no-op (if the implementation is not broken)

Suggested change
toplevel_eval_with_hooks(mod, Expr(:worldinc))

Copy link
Member

@vtjnash vtjnash left a comment

Choose a reason for hiding this comment

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

Overall SGTM (though needs a rebase against the parts that are merged already).

Looks like a lot of the needed added Core.@worldinc also will be already solved by making each toplevel / module statement continue to imply an updated world (since they already imply an updated macro world, and the statements are supposed to run in the world after that macro expansion, which wouldn't be possible to express with these explicit markers anyways)

One other remaining todo item is adding this to the Compiler verifier code. I don't know if we run any debug tests on PRs, but I believe we run those on nightly, and it likely should error on the unexpected Expr head.

Keno added a commit to JuliaDebug/JuliaInterpreter.jl that referenced this pull request Nov 14, 2024
These were added in JuliaLang/julia#56523.
This simply adds tracking for the world age to the interpreter, but
does not use it for anything. JuliaInterpreter's current model
of world age does not match Base anyway. We should fix that eventually,
but it's probably easier to do that once JuliaLang/julia#56509
and binding partitions are merged.
@Keno Keno force-pushed the kf/explicitageinc branch from 4330bad to 3bbfc51 Compare November 14, 2024 05:53
Keno added a commit to JuliaDebug/JuliaInterpreter.jl that referenced this pull request Nov 14, 2024
* Handle `:latestworld` expr

These were added in JuliaLang/julia#56523.
This simply adds tracking for the world age to the interpreter, but
does not use it for anything. JuliaInterpreter's current model
of world age does not match Base anyway. We should fix that eventually,
but it's probably easier to do that once JuliaLang/julia#56509
and binding partitions are merged.

* 1.6 compat
Keno added a commit to timholy/Revise.jl that referenced this pull request Nov 15, 2024
Upcoming base PR JuliaLang/julia#56509 makes precise
when exactly world age increments automatically at top-level. Packages are
mostly not supposed to notice, but of course Revise is a bit patholgical in
that it does basically expect asynchronous changes to have top level effects.
After that PR, that requires an explicit opt-in. This PR makes the appropriate
adjustments to the tests.
Keno added a commit to timholy/Revise.jl that referenced this pull request Nov 15, 2024
Upcoming base PR JuliaLang/julia#56509 makes precise
when exactly world age increments automatically at top-level. Packages are
mostly not supposed to notice, but of course Revise is a bit patholgical in
that it does basically expect asynchronous changes to have top level effects.
After that PR, that requires an explicit opt-in. This PR makes the appropriate
adjustments to the tests.
@Keno
Copy link
Member Author

Keno commented Nov 18, 2024

@nanosoldier runtests(["Tricks", "MethodInspector", "ExprTools", "OptimizingIR", "OverflowContexts", "CBOOCall", "LazyModules", "PowerSeries", "Purses", "Hygienic", "MullerPlot", "SyntaxTree", "Plugins", "ParameterisedModule", "ApproximationAnalysis", "VectorInterface", "Expronicon", "TestExtras", "Hyperspecialize", "TimerOutputs", "Behavior", "ProblemSet", "FinitePosets", "CommandLiner", "TrixiBase", "IRTools", "TypeStability", "LoweredCodeUtils", "LispSyntax", "FileIO", "Automa", "ComoniconTargetExpr", "SplittablesBase", "HAML", "JSON3", "PDDL", "Continuables", "DataSets", "DataFlowTasks", "GraphQLGen", "Revise", "ConfigurationsENV", "DebugAdapter", "LIBSVM", "FromFile", "Groups", "LazyReports", "Polyester", "Handcalcs", "PkgJogger", "IntervalLinearAlgebra", "TypeClasses", "Open62541", "MHLib", "ExtensibleEffects", "Arblib", "PlutoVista", "LegendrePolynomials", "LinkedInAPI", "SwagUI", "GraphQLClient", "Folds", "Serde", "FlatRBAC", "BenchmarkProfiles", "DataToolkitCommon", "ACSets", "SphericalHarmonicExpansions", "CrystalInfoFramework", "Experimenter", "MATDaemon", "DrelTools", "DistributedSparseGrids", "TransitionalMCMC", "AstroRepresentations", "TransformSpecifications", "PlutoPlotly", "Bukdu", "OndaEDFSchemas", "AppleHealthParser", "MultivariateChebyshev", "Onda", "AlignedSpans", "YasolSolver", "JSXGraph", "Semagrams", "Gen", "MaterialDecomposition", "CSetAutomorphisms", "GeniePlugins", "GenieSession", "GeniePackageManager", "GenieCache", "GenieDeployHeroku", "GenieCacheFileCache", "GenieDeployDocker", "GenieSessionFileSession", "InfiniteOpt", "EnergyModelsBase", "EnergyModelsCO2", "EnergyModelsRenewableProducers", "EnergyModelsGeography", "OndaEDF", "MembraneBase", "Books", "StippleMathjs", "Stipple", "StippleUI", "SparseArrayKit", "QWignerSymbols", "RegNets", "GenieDevTools", "HerbSearch", "Equate", "StippleCharts", "Herb", "StipplePlotly", "SteadyStateDiffEq", "StipplePlotlyExport", "TaylorInversion", "GenieAuthorisation", "CategoryData", "GenieFramework", "ReversePropagation", "GivEmXL", "GenericCharacterTables", "SphericalFunctions", "StippleKeplerGL", "Spehulak", "PlutoPages", "GeometryOptimization", "ProToPortal", "JuliaBUGS", "MLJTestIntegration", "CausalGPSLC", "MLJ", "WaveSpec", "Individual", "AntennaPattern", "SimpleCrop", "UnfoldBIDS", "LeafGasExchange", "Garlic", "EMpht", "Vahana", "Petri", "Lighthouse", "AffineMotions", "PlantGeomTurtle", "HetaSimulator", "Serialization", "CropRootBox"])

fingolfin pushed a commit to oscar-system/GenericCharacterTables.jl that referenced this pull request Feb 14, 2025
This test currently relies on implicit world age increments at top
level. We're re-evaluating where these go because julia is currently
inconsistent about it in the interpreter, compiler and inference.
To make sure this test keeps working on 1.12, add an explicit
world age increment. See JuliaLang/julia#56509.
fingolfin pushed a commit to oscar-system/GenericCharacterTables.jl that referenced this pull request Feb 14, 2025
This test currently relies on implicit world age increments at top
level. We're re-evaluating where these go because julia is currently
inconsistent about it in the interpreter, compiler and inference.
To make sure this test keeps working on 1.12, add an explicit
world age increment. See JuliaLang/julia#56509.
serenity4 added a commit to serenity4/Diffractor.jl that referenced this pull request Feb 21, 2025
Keno pushed a commit to JuliaDiff/Diffractor.jl that referenced this pull request Mar 3, 2025
* Adapt to JuliaLang/julia#56509

* Adapt to JuliaLang/julia#54734

* Use StmtRange explicitly

* Adapt to JuliaLang/julia#57230

* Reuse Cthulhu code structure for Compiler cache/finish overrides

* Adapt to JuliaLang/julia#57475

* Adapt to JuliaLang/julia#55976

* Adapt to JuliaLang/julia#54734

* Use CC instead of .Compiler

* Implement ir.argtypes[1] fix from JuliaLang/julia#54458

* Comment out failing tests

To highlight which are broken, should probably be fixed before merging

* Treat `getproperty(::Module, ::Symbol)` like GlobalRefs

* Uncomment passing tests, explicitly mark others as broken

* Evaluate GlobalRef only if binding is defined

* Use `rrule` for getproperty(::Module, ::Symbol)

* Bump compat bound for StructArrays

* Raise compat bound for Cthulhu

* Revert `isconst` change now that it is fixed

* Adapt to `finishinfer!` signature change

---------

Co-authored-by: Cédric Belmant <[email protected]>
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Apr 2, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Apr 2, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Apr 2, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Apr 2, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Apr 2, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Apr 4, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Apr 7, 2025
Was missing increments after closure type declarations and a kwarg function
declaration. Fixes the world age warnings when running tests.  Part of
JuliaLang/julia#56509
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Apr 18, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Apr 18, 2025
Was missing increments after closure type declarations and a kwarg function
declaration. Fixes the world age warnings when running tests.  Part of
JuliaLang/julia#56509
serenity4 pushed a commit to serenity4/julia that referenced this pull request May 1, 2025
This PR introduces a new, toplevel-only, syntax form `:worldinc` that
semantically represents the effect of raising the current task's world
age to the latest world for the remainder of the current toplevel
evaluation (that context being an entry to `eval` or a module
expression). For detailed motivation on why this is desirable, see
JuliaLang#55145, which I won't repeat here, but the gist is that we never really
defined when world-age increments and worse are inconsistent about it.
This is something we need to figure out now, because the bindings
partition work will make world age even more observable via bindings.

Having created a mechanism for world age increments, the big question is
one of policy, i.e. when should these world age increments be inserted.

Several reasonable options exist:
1. After world-age affecting syntax constructs (as proprosed in JuliaLang#55145)
2. Option 1 + some reasonable additional cases that people rely on
3. Before any top level `call` expression
4. Before any expression at toplevel whatsover

As an example, case, consider `a == a` at toplevel. Depending on the
semantics that could either be the same as in local scope, or each of
the four world age dependent lookups (three binding lookups, one method
lookup) could (potentially) occur in a different world age.

The general tradeoff here is between the risk of exposing the user to
confusing world age errors and our ability to optimize top-level code
(in general, any `:worldinc` statement will require us to fully
pessimize or recompile all following code).

This PR basically implements option 2 with the following semantics:

1. The interpreter explicit raises the world age only at `:worldinc`
exprs or after `:module` exprs.
2. The frontend inserts `:worldinc` after all struct definitions, method
definitions, `using` and `import.
3. The `@eval` macro inserts a worldinc following the call to `eval` if
at toplevel
4. A literal (syntactic) call to `include` gains an implicit `worldinc`.

Of these the fourth is probably the most questionable, but is necessary
to make this non-breaking for most code patterns. Perhaps it would have
been better to make `include` a macro from the beginning (esp because it
already has semantics that look a little like reaching into the calling
module), but that ship has sailed.

Unfortunately, I don't see any good intermediate options between this PR
and option JuliaLang#3 above. I think option JuliaLang#3 is closest to what we have right
now, but if we were to choose it and actually fix the soundness issues,
I expect that we would be destroying all performance of global-scope
code. For this reason, I would like to try to make the version in this
PR work, even if the semantics are a little ugly.

The biggest pattern that this PR does not catch is:
```
eval(:(f() = 1))
f()
```

We could apply the same `include` special case to eval, but given the
existence of `@eval` which allows addressing this at the macro level, I
decided not to. We can decide which way we want to go on this based on
what the package ecosystem looks like.
aviatesk pushed a commit to aviatesk/JuliaLowering.jl that referenced this pull request Jun 14, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
aviatesk pushed a commit to aviatesk/JuliaLowering.jl that referenced this pull request Jun 14, 2025
Was missing increments after closure type declarations and a kwarg function
declaration. Fixes the world age warnings when running tests.  Part of
JuliaLang/julia#56509
aviatesk pushed a commit to aviatesk/JuliaLowering.jl that referenced this pull request Jun 14, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
aviatesk pushed a commit to aviatesk/JuliaLowering.jl that referenced this pull request Jun 14, 2025
Was missing increments after closure type declarations and a kwarg function
declaration. Fixes the world age warnings when running tests.  Part of
JuliaLang/julia#56509
aviatesk pushed a commit to aviatesk/JuliaLowering.jl that referenced this pull request Jul 2, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
aviatesk pushed a commit to aviatesk/JuliaLowering.jl that referenced this pull request Jul 2, 2025
Was missing increments after closure type declarations and a kwarg function
declaration. Fixes the world age warnings when running tests.  Part of
JuliaLang/julia#56509
aviatesk pushed a commit to aviatesk/JuliaLowering.jl that referenced this pull request Jul 2, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above.
aviatesk pushed a commit to aviatesk/JuliaLowering.jl that referenced this pull request Jul 2, 2025
Was missing increments after closure type declarations and a kwarg function
declaration. Fixes the world age warnings when running tests.  Part of
JuliaLang/julia#56509
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Jul 29, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above (missing world age increments).

Co-authored-by: Claire Foster <[email protected]>
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Jul 29, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above (missing world age increments).

Co-authored-by: Claire Foster <[email protected]>
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Jul 30, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above (missing world age increments).

Co-authored-by: Claire Foster <[email protected]>
mlechu added a commit to mlechu/JuliaLowering.jl that referenced this pull request Aug 2, 2025
For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above (missing world age increments).

Co-authored-by: Claire Foster <[email protected]>
mlechu added a commit to JuliaLang/JuliaLowering.jl that referenced this pull request Aug 4, 2025
* Update CodeInfo struct and handling

Co-authored-by: Claire Foster <[email protected]>

* Don't produce raw symbol from globalref

This used to implicitly refer to a module-level name, but lowering is now
expected to wrap it in a `globalref`. Part of JuliaLang/julia#54772

* Updates to const and global lowering; add K"constdecl"; omit `wrap`

JuliaLang/julia#54773, JuliaLang/julia#56713, JuliaLang/julia#57470. Some
     changes omitted from `expand-decls` and `expand-assignment`.

Note that the two-argument IR "const" is K"constdecl", whereas the one-argument
    K"const" only appears in the AST.

Also note that the `wrap` parameter is omitted throughout assignment desugaring.
      As far as I'm aware, all this plumbing was just to support `const a,b,c =
     1,2,3` having `b` and `c` inherit the `const`.  TODO: find a better way of
     doing the same thing (a ScopedValue might be a clean solution; we currently
     throw an error).

The check for `let; const x = 1; end`, (which should throw) is in scope
     analysis (lisp has it in `compile`).

Co-authored-by: Claire Foster <[email protected]>

* Add `isdefinedglobal` builtin

JuliaLang/julia#54999, JuliaLang/julia#56985

* :global no longer valid_ir_argument; rm `is_defined_nothrow_global`

JuliaLang/julia#56746.  Also call :slot and :static_parameter valid (for now)

* Fix `is_defined_and_owned_global` (Core.Binding changes)

Adapt to bpart changes in JuliaLang/julia#54788

* Struct desugaring: "Undo decision to publish incomplete types..."

JuliaLang/julia#56497; Add self-referencing struct shim

I have doubts about how long this solution will stay in the base repository, and
     how complete it is (doesn't seem to work with M1.M2.S), but we are testing
     for it here.

Also change the expected value of a test changed in the same PR.

* Emit `latestworld` world age increments

For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers JuliaLang/julia#56523, JuliaLang/julia#56509, JuliaLang/julia#57299.

Also includes changes from JuliaLang/julia#57102 (bpart: Start enforcing minimum
world age for const bparts) and JuliaLang/julia#57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above (missing world age increments).

Co-authored-by: Claire Foster <[email protected]>

* bpart changes: `Core._typebody!` signature

`Core._typebody!` now takes a new "prev" argument, which we don't use yet here.
 Changes from JuliaLang/julia#57253

* bpart changes: struct desugaring

Changes from JuliaLang/julia#57253 (bpart: Fully switch to partitioned
     semantics).  This fixes one failing test and realigns struct desugaring to
     match lisp for now.

Also changed: the expected result of redefining a primitive type (now allowed).

* Additional argument in `new_opaque_closure`

Fix segfaulting test.  Thanks for the TODO

* Adapt to different `GeneratedFunctionStub` signature

Signature changed in JuliaLang/julia#57230.  Thanks @aviatesk for the help!

* Fix `public` and `export`

As of JuliaLang/julia#57765, `jl_module_public` is no longer exported.  Change
our runtime to handle it like `public` and `export` like we handle `import`
or `using` for now

* Fix modules.jl test

I believe this was a world age issue

* Regenerate IR tests

Too many to count.

* Update README to known-good julia, JuliaSyntax versions

Latest julia works.  Changes are needed to work with the latest JuliaSyntax, but
     that isn't in base julia yet, and more changes are likely to come.

* Fix small bug from #16 so tests pass

The change lifted the scope of `note`, so it was being changed in the loop

* Changes from code review: const/global lowering

Ping me if you'd like this squashed into the original const/global commit!

Co-authored-by: Claire Foster <[email protected]>

* Remove a special case

No longer needed since we no longer put `global` or `local` forms back into the
     expand_forms machine.  Some error messages change slightly as a result.

* Changes from code review

Co-authored-by: Claire Foster <[email protected]>

* Fix + test for assignment in value but not tail position

* Disallow `static_parameter` as `valid_ir_argument`

See added comment, and discussion at
    #10 (comment)

Co-authored-by: Claire Foster <[email protected]>

* Change printing of `K"latestworld"`

Parens are nice, but it wasn't consistent.

Also make it a leaf (remaining non-leaves are deleted in the next commit.)

* Move most `latestworld`s to linearization

From the docs:
```
The following statements raise the current world age:
    1. An explicit invocation of Core.@latestworld
    2. The start of every top-level statement
    3. The start of every REPL prompt
    4. Any type or struct definition
    5. Any method definition
    6. Any constant declaration
    7. Any global variable declaration (but not a global variable assignment)
    8. Any using, import, export or public statement
    9. Certain other macros like eval (depends on the macro implementation)
```

This commit handles each case as follows:

```
    1. = 9
    2. I'm not sure this actually happens (or needs to happen, unless we're
       being defensive? Doing it after each world-changing operation should
       suffice).  But if we need it, this would just be emitting once at the
       beginning of every lowered output.
    3. = 2
    4. = 6
    5. Emit seeing `method` in linearize
    6. Emit seeing `constdecl` in linearize
    7. Emit seeing `global` or `globaldecl` in linearize
    8. We just defer to `eval`, but should probably go in desugaring later
       - using/import recently became builtin calls, and I haven't
         updated JL to use them yet.  Base._import_using has an expr-based
         API that may change, and our importpath destructuring is worth keeping.
       - export and public (special forms) are handled in toplevel.c
    9. Done for us
```

Other quirks:

- `JuliaLowering.eval_closure_type` calls eval to assign a const, so we still
    need to deal with that in closure conversion.

- The `include` hack isn't mentioned in the docs, but can stay in desugaring.
      I'm not certain why we don't do the same for non-macro `eval`.

---------

Co-authored-by: Claire Foster <[email protected]>
pulsipher added a commit to infiniteopt/InfiniteOpt.jl that referenced this pull request Aug 13, 2025
* Use invokelatest after eval to adjust to upcoming julia change

In 1.12, we're cleaning up when implicit world age increments happen
at toplevel. Because these test `eval` an expression and immediately
call it, an `invokelatest` will likely be required (as it would be
right now in local scope). See JuliaLang/julia#56509

* Added note for future reference

---------

Co-authored-by: pulsipher <[email protected]>
Co-authored-by: Joshua Pulsipher <[email protected]>
c42f added a commit that referenced this pull request Oct 17, 2025
* Update CodeInfo struct and handling

Co-authored-by: Claire Foster <[email protected]>

* Don't produce raw symbol from globalref

This used to implicitly refer to a module-level name, but lowering is now
expected to wrap it in a `globalref`. Part of #54772

* Updates to const and global lowering; add K"constdecl"; omit `wrap`

#54773, #56713, #57470. Some
     changes omitted from `expand-decls` and `expand-assignment`.

Note that the two-argument IR "const" is K"constdecl", whereas the one-argument
    K"const" only appears in the AST.

Also note that the `wrap` parameter is omitted throughout assignment desugaring.
      As far as I'm aware, all this plumbing was just to support `const a,b,c =
     1,2,3` having `b` and `c` inherit the `const`.  TODO: find a better way of
     doing the same thing (a ScopedValue might be a clean solution; we currently
     throw an error).

The check for `let; const x = 1; end`, (which should throw) is in scope
     analysis (lisp has it in `compile`).

Co-authored-by: Claire Foster <[email protected]>

* Add `isdefinedglobal` builtin

#54999, #56985

* :global no longer valid_ir_argument; rm `is_defined_nothrow_global`

#56746.  Also call :slot and :static_parameter valid (for now)

* Fix `is_defined_and_owned_global` (Core.Binding changes)

Adapt to bpart changes in #54788

* Struct desugaring: "Undo decision to publish incomplete types..."

#56497; Add self-referencing struct shim

I have doubts about how long this solution will stay in the base repository, and
     how complete it is (doesn't seem to work with M1.M2.S), but we are testing
     for it here.

Also change the expected value of a test changed in the same PR.

* Emit `latestworld` world age increments

For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers #56523, #56509, #57299.

Also includes changes from #57102 (bpart: Start enforcing minimum
world age for const bparts) and #57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above (missing world age increments).

Co-authored-by: Claire Foster <[email protected]>

* bpart changes: `Core._typebody!` signature

`Core._typebody!` now takes a new "prev" argument, which we don't use yet here.
 Changes from #57253

* bpart changes: struct desugaring

Changes from #57253 (bpart: Fully switch to partitioned
     semantics).  This fixes one failing test and realigns struct desugaring to
     match lisp for now.

Also changed: the expected result of redefining a primitive type (now allowed).

* Additional argument in `new_opaque_closure`

Fix segfaulting test.  Thanks for the TODO

* Adapt to different `GeneratedFunctionStub` signature

Signature changed in #57230.  Thanks @aviatesk for the help!

* Fix `public` and `export`

As of #57765, `jl_module_public` is no longer exported.  Change
our runtime to handle it like `public` and `export` like we handle `import`
or `using` for now

* Fix modules.jl test

I believe this was a world age issue

* Regenerate IR tests

Too many to count.

* Update README to known-good julia, JuliaSyntax versions

Latest julia works.  Changes are needed to work with the latest JuliaSyntax, but
     that isn't in base julia yet, and more changes are likely to come.

* Fix small bug from JuliaLang/JuliaLowering.jl#16 so tests pass

The change lifted the scope of `note`, so it was being changed in the loop

* Changes from code review: const/global lowering

Ping me if you'd like this squashed into the original const/global commit!

Co-authored-by: Claire Foster <[email protected]>

* Remove a special case

No longer needed since we no longer put `global` or `local` forms back into the
     expand_forms machine.  Some error messages change slightly as a result.

* Changes from code review

Co-authored-by: Claire Foster <[email protected]>

* Fix + test for assignment in value but not tail position

* Disallow `static_parameter` as `valid_ir_argument`

See added comment, and discussion at
    JuliaLang/JuliaLowering.jl#10 (comment)

Co-authored-by: Claire Foster <[email protected]>

* Change printing of `K"latestworld"`

Parens are nice, but it wasn't consistent.

Also make it a leaf (remaining non-leaves are deleted in the next commit.)

* Move most `latestworld`s to linearization

From the docs:
```
The following statements raise the current world age:
    1. An explicit invocation of Core.@latestworld
    2. The start of every top-level statement
    3. The start of every REPL prompt
    4. Any type or struct definition
    5. Any method definition
    6. Any constant declaration
    7. Any global variable declaration (but not a global variable assignment)
    8. Any using, import, export or public statement
    9. Certain other macros like eval (depends on the macro implementation)
```

This commit handles each case as follows:

```
    1. = 9
    2. I'm not sure this actually happens (or needs to happen, unless we're
       being defensive? Doing it after each world-changing operation should
       suffice).  But if we need it, this would just be emitting once at the
       beginning of every lowered output.
    3. = 2
    4. = 6
    5. Emit seeing `method` in linearize
    6. Emit seeing `constdecl` in linearize
    7. Emit seeing `global` or `globaldecl` in linearize
    8. We just defer to `eval`, but should probably go in desugaring later
       - using/import recently became builtin calls, and I haven't
         updated JL to use them yet.  Base._import_using has an expr-based
         API that may change, and our importpath destructuring is worth keeping.
       - export and public (special forms) are handled in toplevel.c
    9. Done for us
```

Other quirks:

- `JuliaLowering.eval_closure_type` calls eval to assign a const, so we still
    need to deal with that in closure conversion.

- The `include` hack isn't mentioned in the docs, but can stay in desugaring.
      I'm not certain why we don't do the same for non-macro `eval`.

---------

Co-authored-by: Claire Foster <[email protected]>
topolarity pushed a commit that referenced this pull request Nov 14, 2025
* Update CodeInfo struct and handling

Co-authored-by: Claire Foster <[email protected]>

* Don't produce raw symbol from globalref

This used to implicitly refer to a module-level name, but lowering is now
expected to wrap it in a `globalref`. Part of #54772

* Updates to const and global lowering; add K"constdecl"; omit `wrap`

#54773, #56713, #57470. Some
     changes omitted from `expand-decls` and `expand-assignment`.

Note that the two-argument IR "const" is K"constdecl", whereas the one-argument
    K"const" only appears in the AST.

Also note that the `wrap` parameter is omitted throughout assignment desugaring.
      As far as I'm aware, all this plumbing was just to support `const a,b,c =
     1,2,3` having `b` and `c` inherit the `const`.  TODO: find a better way of
     doing the same thing (a ScopedValue might be a clean solution; we currently
     throw an error).

The check for `let; const x = 1; end`, (which should throw) is in scope
     analysis (lisp has it in `compile`).

Co-authored-by: Claire Foster <[email protected]>

* Add `isdefinedglobal` builtin

#54999, #56985

* :global no longer valid_ir_argument; rm `is_defined_nothrow_global`

#56746.  Also call :slot and :static_parameter valid (for now)

* Fix `is_defined_and_owned_global` (Core.Binding changes)

Adapt to bpart changes in #54788

* Struct desugaring: "Undo decision to publish incomplete types..."

#56497; Add self-referencing struct shim

I have doubts about how long this solution will stay in the base repository, and
     how complete it is (doesn't seem to work with M1.M2.S), but we are testing
     for it here.

Also change the expected value of a test changed in the same PR.

* Emit `latestworld` world age increments

For method defs, `latestworld` is produced in desugaring rather than closure
conversion for now (our closure conversion doesn't seem to cover the same
cases as lisp lowering yet).

Covers #56523, #56509, #57299.

Also includes changes from #57102 (bpart: Start enforcing minimum
world age for const bparts) and #57150 (bpart: Start enforcing
min_world for global variable definitions) since the lowering changes from those
appear to be amendments to the changes above (missing world age increments).

Co-authored-by: Claire Foster <[email protected]>

* bpart changes: `Core._typebody!` signature

`Core._typebody!` now takes a new "prev" argument, which we don't use yet here.
 Changes from #57253

* bpart changes: struct desugaring

Changes from #57253 (bpart: Fully switch to partitioned
     semantics).  This fixes one failing test and realigns struct desugaring to
     match lisp for now.

Also changed: the expected result of redefining a primitive type (now allowed).

* Additional argument in `new_opaque_closure`

Fix segfaulting test.  Thanks for the TODO

* Adapt to different `GeneratedFunctionStub` signature

Signature changed in #57230.  Thanks @aviatesk for the help!

* Fix `public` and `export`

As of #57765, `jl_module_public` is no longer exported.  Change
our runtime to handle it like `public` and `export` like we handle `import`
or `using` for now

* Fix modules.jl test

I believe this was a world age issue

* Regenerate IR tests

Too many to count.

* Update README to known-good julia, JuliaSyntax versions

Latest julia works.  Changes are needed to work with the latest JuliaSyntax, but
     that isn't in base julia yet, and more changes are likely to come.

* Fix small bug from JuliaLang/JuliaLowering.jl#16 so tests pass

The change lifted the scope of `note`, so it was being changed in the loop

* Changes from code review: const/global lowering

Ping me if you'd like this squashed into the original const/global commit!

Co-authored-by: Claire Foster <[email protected]>

* Remove a special case

No longer needed since we no longer put `global` or `local` forms back into the
     expand_forms machine.  Some error messages change slightly as a result.

* Changes from code review

Co-authored-by: Claire Foster <[email protected]>

* Fix + test for assignment in value but not tail position

* Disallow `static_parameter` as `valid_ir_argument`

See added comment, and discussion at
    JuliaLang/JuliaLowering.jl#10 (comment)

Co-authored-by: Claire Foster <[email protected]>

* Change printing of `K"latestworld"`

Parens are nice, but it wasn't consistent.

Also make it a leaf (remaining non-leaves are deleted in the next commit.)

* Move most `latestworld`s to linearization

From the docs:
```
The following statements raise the current world age:
    1. An explicit invocation of Core.@latestworld
    2. The start of every top-level statement
    3. The start of every REPL prompt
    4. Any type or struct definition
    5. Any method definition
    6. Any constant declaration
    7. Any global variable declaration (but not a global variable assignment)
    8. Any using, import, export or public statement
    9. Certain other macros like eval (depends on the macro implementation)
```

This commit handles each case as follows:

```
    1. = 9
    2. I'm not sure this actually happens (or needs to happen, unless we're
       being defensive? Doing it after each world-changing operation should
       suffice).  But if we need it, this would just be emitting once at the
       beginning of every lowered output.
    3. = 2
    4. = 6
    5. Emit seeing `method` in linearize
    6. Emit seeing `constdecl` in linearize
    7. Emit seeing `global` or `globaldecl` in linearize
    8. We just defer to `eval`, but should probably go in desugaring later
       - using/import recently became builtin calls, and I haven't
         updated JL to use them yet.  Base._import_using has an expr-based
         API that may change, and our importpath destructuring is worth keeping.
       - export and public (special forms) are handled in toplevel.c
    9. Done for us
```

Other quirks:

- `JuliaLowering.eval_closure_type` calls eval to assign a const, so we still
    need to deal with that in closure conversion.

- The `include` hack isn't mentioned in the docs, but can stay in desugaring.
      I'm not certain why we don't do the same for non-macro `eval`.

---------

Co-authored-by: Claire Foster <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor change Marginal behavior change acceptable for a minor release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants