Skip to content

Commit 39b1513

Browse files
Make eval great again
Okay, this one needs a little bit of explanation. So in the stone ages we used `eval`. https://github.com/SciML/ModelingToolkit.jl/blame/f9a837c775e15495921947f4995cf7ab97b5a45a/src/systems/diffeqs/abstractodesystem.jl#L122 All was good. But then that made world-age issues. All was bad. But then GeneralizedGenerated came, which was then replaced by RuntimeGeneratedFunctions, which replaced our use of eval. And all was good. https://github.com/SciML/ModelingToolkit.jl/blame/8c6b8249aed97f18a6de471cb5544689befd58e4/src/systems/diffeqs/abstractodesystem.jl#L131 This had no issues with world-age, so you can now use everything more smoothly. However, RGFs didn't play nicely with precompilation. That was fixed by caching things in the dictionary of the module, and adding `eval_module` which was a required argument for this context to allow the user to properly share where the functions would be evaluated into. All was good again. But then Julia v1.9 came around with package images. It turns out that package images attempt to cache the binaries, yay! But the data and information for an RGF is not in the binary. Oh no. SciML/DiffEqProblemLibrary.jl@3444ffe ``` Remove precompilation for MTK support Can revert later when this is fixed. ``` This was noticed in DiffEqProblemLibrary, but I subsequently forgot as all of the other v1.9 release chaos happened. So now we are trying to precompile models and failing. What did we do wrong? Well... there's a hard fix... and there's an easy fix. And the easy fix is nice and robust and has guarantees to work by Julia's compiler team itself. Awesome, so let's do that. That fix is... use eval. So at first early in the package, we added the argument `eval_expression` for whether to take the MTK generated function expression and eval it. Eval was then replaced with GG and then RGFs. However, getting the expression was then replaced with ODEFunctionExpr, ODEProblemExpr, etc. Not only that, but the expression themselves were no longer directly returned but put inside of another function, and the reason for that other function is due to adding dispatches for handling splits etc. https://github.com/SciML/ModelingToolkit.jl/blob/v9.20.0/src/systems/diffeqs/abstractodesystem.jl#L333-L337 ```julia f_oop, f_iip = eval_expression ? (drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in f_gen) : f_gen f(u, p, t) = f_oop(u, p, t) f(du, u, p, t) = f_iip(du, u, p, t) f(u, p::Tuple{Vararg{Number}}, t) = f_oop(u, p, t) f(du, u, p::Tuple{Vararg{Number}}, t) = f_iip(du, u, p, t) f(u, p::Tuple, t) = f_oop(u, p..., t) f(du, u, p::Tuple, t) = f_iip(du, u, p..., t) f(u, p::MTKParameters, t) = f_oop(u, p..., t) f(du, u, p::MTKParameters, t) = f_iip(du, u, p..., t) ``` But now obviously, this reads like nonsense then. `eval_expression=false` returns a Julia expression, which is then put inside of a Julia function, and if you actually tried to call it you get an error that Expr isn't callable. All the meanwhile, `eval_expression=true` doesn't actually `eval` the expression, because remember it used to eval it but that was replaced with RGFs. So we have a `eval_expression` keyword argument that is undocumented and also pretty much nonsense, and I want to add a feature where instead of using RGFs I want to eval the function... :thinking_face: So I re-re-cooped this keyword argument so it now means what it used to mean before it meant what it, i.e. `eval_expression=true` means we `eval` the expression. This means that `eval_expression=false` means we do the RGF thing, and that should be the default as that makes world-age work. But, we also have `eval_module` already, so we just eval into whatever module the user gives. If the user evals into their current module, then the functions in the generated code is exactly a standard Julia function, and it all works with package images. So... what about the tests. Well we had tests on this, but that's as interesting of a story. If we flip the default, then the tests only test the RGF stuff, which they are then setup to do... actually correctly, in a sense. The no-eval was simply testing the parent module ```julia @test parentmodule(typeof(ODEPrecompileTest.f_noeval_good.f.f_oop).parameters[2]) == ODEPrecompileTest ``` and indeed the parent module is in the right module, it's just an Expr there and not really what we were looking for? So in a bizarre sense the tests actually passed for the Exprs that couldn't actually do anything. So I just added tests for the eval path to the precompile test. Now it turns out the "precompile test" is actually just a test that we can put things in a module and it can work. It does not test the package image building, which is why the RGFs did not fail there. I am unsure how to do this on CI. But, I think the tests are likely good enough for now, and this gives a good solution to folks wanting to precompile. We should make sure it actually gets documented this time around.
1 parent ddcf59e commit 39b1513

File tree

7 files changed

+75
-64
lines changed

7 files changed

+75
-64
lines changed

src/systems/clock_inference.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ end
192192
function generate_discrete_affect(
193193
osys::AbstractODESystem, syss, inputs, continuous_id, id_to_clock;
194194
checkbounds = true,
195-
eval_module = @__MODULE__, eval_expression = true)
195+
eval_module = @__MODULE__, eval_expression = false)
196196
@static if VERSION < v"1.7"
197197
error("The `generate_discrete_affect` function requires at least Julia 1.7")
198198
end
@@ -412,15 +412,15 @@ function generate_discrete_affect(
412412
push!(svs, sv)
413413
end
414414
if eval_expression
415+
affects = map(a -> eval_module.eval(toexpr(LiteralExpr(a))), affect_funs)
416+
inits = map(a -> eval_module.eval(toexpr(LiteralExpr(a))), init_funs)
417+
else
415418
affects = map(affect_funs) do a
416419
drop_expr(@RuntimeGeneratedFunction(eval_module, toexpr(LiteralExpr(a))))
417420
end
418421
inits = map(init_funs) do a
419422
drop_expr(@RuntimeGeneratedFunction(eval_module, toexpr(LiteralExpr(a))))
420423
end
421-
else
422-
affects = map(a -> toexpr(LiteralExpr(a)), affect_funs)
423-
inits = map(a -> toexpr(LiteralExpr(a)), init_funs)
424424
end
425425
defaults = Dict{Any, Any}(v => 0.0 for v in Iterators.flatten(inputs))
426426
return affects, inits, clocks, svs, appended_parameters, defaults

src/systems/diffeqs/abstractodesystem.jl

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ function DiffEqBase.ODEFunction{iip, specialize}(sys::AbstractODESystem,
313313
version = nothing, tgrad = false,
314314
jac = false, p = nothing,
315315
t = nothing,
316-
eval_expression = true,
316+
eval_expression = false,
317317
sparse = false, simplify = false,
318318
eval_module = @__MODULE__,
319319
steady_state = false,
@@ -327,12 +327,12 @@ function DiffEqBase.ODEFunction{iip, specialize}(sys::AbstractODESystem,
327327
if !iscomplete(sys)
328328
error("A completed system is required. Call `complete` or `structural_simplify` on the system before creating an `ODEFunction`")
329329
end
330-
f_gen = generate_function(sys, dvs, ps; expression = Val{eval_expression},
330+
f_gen = generate_function(sys, dvs, ps; expression = Val{!eval_expression},
331331
expression_module = eval_module, checkbounds = checkbounds,
332332
kwargs...)
333-
f_oop, f_iip = eval_expression ?
334-
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in f_gen) :
335-
f_gen
333+
f_oop, f_iip = eval_expression ? eval_module.eval.(f_gen) :
334+
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in f_gen)
335+
336336
f(u, p, t) = f_oop(u, p, t)
337337
f(du, u, p, t) = f_iip(du, u, p, t)
338338
f(u, p::Tuple{Vararg{Number}}, t) = f_oop(u, p, t)
@@ -352,12 +352,11 @@ function DiffEqBase.ODEFunction{iip, specialize}(sys::AbstractODESystem,
352352
if tgrad
353353
tgrad_gen = generate_tgrad(sys, dvs, ps;
354354
simplify = simplify,
355-
expression = Val{eval_expression},
355+
expression = Val{!eval_expression},
356356
expression_module = eval_module,
357357
checkbounds = checkbounds, kwargs...)
358-
tgrad_oop, tgrad_iip = eval_expression ?
359-
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in tgrad_gen) :
360-
tgrad_gen
358+
tgrad_oop, tgrad_iip = eval_expression ? eval_module.eval.(tgrad_gen) :
359+
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in tgrad_gen)
361360
if p isa Tuple
362361
__tgrad(u, p, t) = tgrad_oop(u, p..., t)
363362
__tgrad(J, u, p, t) = tgrad_iip(J, u, p..., t)
@@ -374,12 +373,12 @@ function DiffEqBase.ODEFunction{iip, specialize}(sys::AbstractODESystem,
374373
if jac
375374
jac_gen = generate_jacobian(sys, dvs, ps;
376375
simplify = simplify, sparse = sparse,
377-
expression = Val{eval_expression},
376+
expression = Val{!eval_expression},
378377
expression_module = eval_module,
379378
checkbounds = checkbounds, kwargs...)
380-
jac_oop, jac_iip = eval_expression ?
381-
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in jac_gen) :
382-
jac_gen
379+
jac_oop, jac_iip = eval_expression ? eval_module.eval.(jac_gen) :
380+
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in jac_gen)
381+
383382
_jac(u, p, t) = jac_oop(u, p, t)
384383
_jac(J, u, p, t) = jac_iip(J, u, p, t)
385384
_jac(u, p::Tuple{Vararg{Number}}, t) = jac_oop(u, p, t)
@@ -474,7 +473,7 @@ function DiffEqBase.DAEFunction{iip}(sys::AbstractODESystem, dvs = unknowns(sys)
474473
ddvs = map(diff2term Differential(get_iv(sys)), dvs),
475474
version = nothing, p = nothing,
476475
jac = false,
477-
eval_expression = true,
476+
eval_expression = false,
478477
sparse = false, simplify = false,
479478
eval_module = @__MODULE__,
480479
checkbounds = false,
@@ -485,12 +484,11 @@ function DiffEqBase.DAEFunction{iip}(sys::AbstractODESystem, dvs = unknowns(sys)
485484
error("A completed system is required. Call `complete` or `structural_simplify` on the system before creating a `DAEFunction`")
486485
end
487486
f_gen = generate_function(sys, dvs, ps; implicit_dae = true,
488-
expression = Val{eval_expression},
487+
expression = Val{!eval_expression},
489488
expression_module = eval_module, checkbounds = checkbounds,
490489
kwargs...)
491-
f_oop, f_iip = eval_expression ?
492-
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in f_gen) :
493-
f_gen
490+
f_oop, f_iip = eval_expression ? eval_module.eval.(f_gen) :
491+
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in f_gen)
494492
f(du, u, p, t) = f_oop(du, u, p, t)
495493
f(du, u, p::MTKParameters, t) = f_oop(du, u, p..., t)
496494
f(out, du, u, p, t) = f_iip(out, du, u, p, t)
@@ -499,12 +497,12 @@ function DiffEqBase.DAEFunction{iip}(sys::AbstractODESystem, dvs = unknowns(sys)
499497
if jac
500498
jac_gen = generate_dae_jacobian(sys, dvs, ps;
501499
simplify = simplify, sparse = sparse,
502-
expression = Val{eval_expression},
500+
expression = Val{!eval_expression},
503501
expression_module = eval_module,
504502
checkbounds = checkbounds, kwargs...)
505-
jac_oop, jac_iip = eval_expression ?
506-
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in jac_gen) :
507-
jac_gen
503+
jac_oop, jac_iip = eval_expression ? eval_module.eval.(jac_gen) :
504+
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in jac_gen)
505+
508506
_jac(du, u, p, ˍ₋gamma, t) = jac_oop(du, u, p, ˍ₋gamma, t)
509507
_jac(du, u, p::MTKParameters, ˍ₋gamma, t) = jac_oop(du, u, p..., ˍ₋gamma, t)
510508

@@ -770,7 +768,7 @@ function process_DEProblem(constructor, sys::AbstractODESystem, u0map, parammap;
770768
checkbounds = false, sparse = false,
771769
simplify = false,
772770
linenumbers = true, parallel = SerialForm(),
773-
eval_expression = true,
771+
eval_expression = false,
774772
use_union = true,
775773
tofloat = true,
776774
symbolic_u0 = false,

src/systems/diffeqs/sdesystem.jl

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -407,21 +407,21 @@ function DiffEqBase.SDEFunction{iip}(sys::SDESystem, dvs = unknowns(sys),
407407
ps = parameters(sys),
408408
u0 = nothing;
409409
version = nothing, tgrad = false, sparse = false,
410-
jac = false, Wfact = false, eval_expression = true,
410+
jac = false, Wfact = false, eval_expression = false,
411411
checkbounds = false,
412412
kwargs...) where {iip}
413413
if !iscomplete(sys)
414414
error("A completed `SDESystem` is required. Call `complete` or `structural_simplify` on the system before creating an `SDEFunction`")
415415
end
416416
dvs = scalarize.(dvs)
417417

418-
f_gen = generate_function(sys, dvs, ps; expression = Val{eval_expression}, kwargs...)
419-
f_oop, f_iip = eval_expression ?
420-
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in f_gen) : f_gen
421-
g_gen = generate_diffusion_function(sys, dvs, ps; expression = Val{eval_expression},
418+
f_gen = generate_function(sys, dvs, ps; expression = Val{!eval_expression}, kwargs...)
419+
f_oop, f_iip = eval_expression ? eval_module.eval.(f_gen) :
420+
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in f_gen)
421+
g_gen = generate_diffusion_function(sys, dvs, ps; expression = Val{!eval_expression},
422422
kwargs...)
423-
g_oop, g_iip = eval_expression ?
424-
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in g_gen) : g_gen
423+
g_oop, g_iip = eval_expression ? eval_module.eval.(g_gen) :
424+
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in g_gen)
425425

426426
f(u, p, t) = f_oop(u, p, t)
427427
f(u, p::MTKParameters, t) = f_oop(u, p..., t)
@@ -433,11 +433,11 @@ function DiffEqBase.SDEFunction{iip}(sys::SDESystem, dvs = unknowns(sys),
433433
g(du, u, p::MTKParameters, t) = g_iip(du, u, p..., t)
434434

435435
if tgrad
436-
tgrad_gen = generate_tgrad(sys, dvs, ps; expression = Val{eval_expression},
436+
tgrad_gen = generate_tgrad(sys, dvs, ps; expression = Val{!eval_expression},
437437
kwargs...)
438-
tgrad_oop, tgrad_iip = eval_expression ?
439-
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in tgrad_gen) :
440-
tgrad_gen
438+
tgrad_oop, tgrad_iip = eval_expression ? eval_module.eval.(tgrad_gen) :
439+
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in tgrad_gen)
440+
441441
_tgrad(u, p, t) = tgrad_oop(u, p, t)
442442
_tgrad(u, p::MTKParameters, t) = tgrad_oop(u, p..., t)
443443
_tgrad(J, u, p, t) = tgrad_iip(J, u, p, t)
@@ -447,11 +447,11 @@ function DiffEqBase.SDEFunction{iip}(sys::SDESystem, dvs = unknowns(sys),
447447
end
448448

449449
if jac
450-
jac_gen = generate_jacobian(sys, dvs, ps; expression = Val{eval_expression},
450+
jac_gen = generate_jacobian(sys, dvs, ps; expression = Val{!eval_expression},
451451
sparse = sparse, kwargs...)
452-
jac_oop, jac_iip = eval_expression ?
453-
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in jac_gen) :
454-
jac_gen
452+
jac_oop, jac_iip = eval_expression ? eval_module.eval.(jac_gen) :
453+
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in jac_gen)
454+
455455
_jac(u, p, t) = jac_oop(u, p, t)
456456
_jac(u, p::MTKParameters, t) = jac_oop(u, p..., t)
457457
_jac(J, u, p, t) = jac_iip(J, u, p, t)
@@ -463,12 +463,11 @@ function DiffEqBase.SDEFunction{iip}(sys::SDESystem, dvs = unknowns(sys),
463463
if Wfact
464464
tmp_Wfact, tmp_Wfact_t = generate_factorized_W(sys, dvs, ps, true;
465465
expression = Val{true}, kwargs...)
466-
Wfact_oop, Wfact_iip = eval_expression ?
467-
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in tmp_Wfact) :
468-
tmp_Wfact
469-
Wfact_oop_t, Wfact_iip_t = eval_expression ?
470-
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in tmp_Wfact_t) :
471-
tmp_Wfact_t
466+
Wfact_oop, Wfact_iip = eval_expression ? eval_module.eval.(tmp_Wfact) :
467+
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in tmp_Wfact)
468+
Wfact_oop_t, Wfact_iip_t = eval_expression ? eval_module.eval.(tmp_Wfact_t) :
469+
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in tmp_Wfact_t)
470+
472471
_Wfact(u, p, dtgamma, t) = Wfact_oop(u, p, dtgamma, t)
473472
_Wfact(u, p::MTKParameters, dtgamma, t) = Wfact_oop(u, p..., dtgamma, t)
474473
_Wfact(W, u, p, dtgamma, t) = Wfact_iip(W, u, p, dtgamma, t)

src/systems/discrete_system/discrete_system.jl

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ end
222222

223223
function process_DiscreteProblem(constructor, sys::DiscreteSystem, u0map, parammap;
224224
linenumbers = true, parallel = SerialForm(),
225-
eval_expression = true,
225+
eval_expression = false,
226226
use_union = false,
227227
tofloat = !use_union,
228228
kwargs...)
@@ -271,7 +271,7 @@ function SciMLBase.DiscreteProblem(
271271
sys::DiscreteSystem, u0map = [], tspan = get_tspan(sys),
272272
parammap = SciMLBase.NullParameters();
273273
eval_module = @__MODULE__,
274-
eval_expression = true,
274+
eval_expression = false,
275275
use_union = false,
276276
kwargs...
277277
)
@@ -308,18 +308,17 @@ function SciMLBase.DiscreteFunction{iip, specialize}(
308308
version = nothing,
309309
p = nothing,
310310
t = nothing,
311-
eval_expression = true,
311+
eval_expression = false,
312312
eval_module = @__MODULE__,
313313
analytic = nothing,
314314
kwargs...) where {iip, specialize}
315315
if !iscomplete(sys)
316316
error("A completed `DiscreteSystem` is required. Call `complete` or `structural_simplify` on the system before creating a `DiscreteProblem`")
317317
end
318-
f_gen = generate_function(sys, dvs, ps; expression = Val{eval_expression},
318+
f_gen = generate_function(sys, dvs, ps; expression = Val{!eval_expression},
319319
expression_module = eval_module, kwargs...)
320-
f_oop, f_iip = eval_expression ?
321-
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in f_gen) :
322-
f_gen
320+
f_oop, f_iip = eval_expression ? eval_module.eval.(f_gen) :
321+
(drop_expr(@RuntimeGeneratedFunction(eval_module, ex)) for ex in f_gen)
323322
f(u, p, t) = f_oop(u, p, t)
324323
f(du, u, p, t) = f_iip(du, u, p, t)
325324

src/systems/nonlinear/nonlinearsystem.jl

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -277,15 +277,15 @@ function SciMLBase.NonlinearFunction{iip}(sys::NonlinearSystem, dvs = unknowns(s
277277
ps = full_parameters(sys), u0 = nothing;
278278
version = nothing,
279279
jac = false,
280-
eval_expression = true,
280+
eval_expression = false,
281281
sparse = false, simplify = false,
282282
kwargs...) where {iip}
283283
if !iscomplete(sys)
284284
error("A completed `NonlinearSystem` is required. Call `complete` or `structural_simplify` on the system before creating a `NonlinearFunction`")
285285
end
286-
f_gen = generate_function(sys, dvs, ps; expression = Val{eval_expression}, kwargs...)
287-
f_oop, f_iip = eval_expression ?
288-
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in f_gen) : f_gen
286+
f_gen = generate_function(sys, dvs, ps; expression = Val{!eval_expression}, kwargs...)
287+
f_oop, f_iip = eval_expression ? eval_module.eval.(f_gen) :
288+
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in f_gen)
289289
f(u, p) = f_oop(u, p)
290290
f(u, p::MTKParameters) = f_oop(u, p...)
291291
f(du, u, p) = f_iip(du, u, p)
@@ -294,10 +294,9 @@ function SciMLBase.NonlinearFunction{iip}(sys::NonlinearSystem, dvs = unknowns(s
294294
if jac
295295
jac_gen = generate_jacobian(sys, dvs, ps;
296296
simplify = simplify, sparse = sparse,
297-
expression = Val{eval_expression}, kwargs...)
298-
jac_oop, jac_iip = eval_expression ?
299-
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in jac_gen) :
300-
jac_gen
297+
expression = Val{!eval_expression}, kwargs...)
298+
jac_oop, jac_iip = eval_expression ? eval_module.eval.(jac_gen) :
299+
(drop_expr(@RuntimeGeneratedFunction(ex)) for ex in jac_gen)
301300
_jac(u, p) = jac_oop(u, p)
302301
_jac(u, p::MTKParameters) = jac_oop(u, p...)
303302
_jac(J, u, p) = jac_iip(J, u, p)
@@ -376,7 +375,7 @@ function process_NonlinearProblem(constructor, sys::NonlinearSystem, u0map, para
376375
checkbounds = false, sparse = false,
377376
simplify = false,
378377
linenumbers = true, parallel = SerialForm(),
379-
eval_expression = true,
378+
eval_expression = false,
380379
use_union = false,
381380
tofloat = !use_union,
382381
kwargs...)

test/precompile_test.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,11 @@ end
3030
@test parentmodule(typeof(ODEPrecompileTest.f_noeval_good.f.f_oop).parameters[2]) ==
3131
ODEPrecompileTest
3232
@test ODEPrecompileTest.f_noeval_good(u, p, 0.1) == [4, 0, -16]
33+
34+
@test_throws KeyError ODEPrecompileTest.f_eval_bad(u, p, 0.1)
35+
36+
@test parentmodule(typeof(ODEPrecompileTest.f_eval_good.f.f_iip).parameters[2]) ==
37+
ODEPrecompileTest
38+
@test parentmodule(typeof(ODEPrecompileTest.f_eval_good.f.f_oop).parameters[2]) ==
39+
ODEPrecompileTest
40+
@test ODEPrecompileTest.f_eval_good(u, p, 0.1) == [4, 0, -16]

test/precompile_test/ODEPrecompileTest.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,12 @@ const f_noeval_bad = system(; eval_expression = false)
2727
using RuntimeGeneratedFunctions
2828
RuntimeGeneratedFunctions.init(@__MODULE__)
2929
const f_noeval_good = system(; eval_expression = false, eval_module = @__MODULE__)
30+
31+
# Eval the expression but into MTK's module, which means it won't be properly cached by
32+
# the package image
33+
const f_eval_bad = system(; eval_expression = true, eval_module = @__MODULE__)
34+
35+
# Change the module the eval'd function is eval'd into to be the containing module,
36+
# which should make it be in the package image
37+
const f_eval_good = system(; eval_expression = true, eval_module = @__MODULE__)
3038
end

0 commit comments

Comments
 (0)