Repository navigation
Conversation
@def and @init generated code resolved CTModels, ExaModels and CTBase by name in the caller's module, so `import OptimalControl` or `using OptimalControl: @def` failed with `UndefVarError` (#356). The three modules are now direct dependencies and are interpolated as module objects into the emitted expressions — the same GlobalRef mechanism __wrap already used for CTBase.CTException — so they resolve where the macros are defined, never in the caller. The configurable prefixes had no remaining purpose (only the package's own tests set them): PREFIX_FUN, PREFIX_EXA, E_PREFIX, INIT_PREFIX, their getters/setters and the __default_*_prefix functions are removed, replaced by three constants FUN/EXA/ERR in defaults.jl. init_prefix is removed too: @init had the same defect and nothing outside CTParser references it. ext/CTParserExaModels.jl is folded into src/exa_linalg.jl: ExaModels is always loaded, so the extension mechanism no longer applies. The port stays temporary until ExaModels wires its own extension (#325). Qualified imports of the three modules in src/CTParser.jl follow MOD4 (using X: X); MOD6 already required their call sites qualified, the change only moves the resolution point. Refs #356. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- test/test_prefix.jl is deleted and test_prefix_bis.jl renamed to test_backends.jl: the file keeps covering backend activation and the parser defaults, and gains the contract for the new FUN / EXA / ERR constants — module objects, not symbols — plus an isdefined guard so the removed API cannot quietly come back (TST7: specific assertions). - test/runtests.jl drops the six prefix imports. - test/test_initial_guess.jl drops the init_prefix setter testset (the setter is gone with INIT_PREFIX). - test/test_aqua.jl now sees the code that lived in the extension: Aqua skips extensions (TST8), so neither the deliberate piracy nor the upstream ambiguities of the ExaModels linear-algebra port were ever checked. In src/ they are. The piracy is whitelisted precisely with treat_as_own on the ExaModels node types it ports to — not on the whole module — and the ambiguity check runs package-only with the stdlib functions the port extends excluded (upstream's own ambiguities, ported verbatim; they leave with the file, #325). - test/Project.toml aligns the CTModels compat on src's. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
test/test_hygiene.jl reproduces the failure mode of #356 inside the suite: nested modules are namespaces where the packages are loaded but none of the names CTModels / ExaModels / CTBase is bound — exactly what `import OptimalControl` leaves a caller with. A flat test file could not reproduce it: runtests.jl binds all three names in Main. - module Bare binds only the macros: @def (:fun and :exa builder), @init, and the typed errors thrown from generated code (the :exa dyn_check via @def_exa, __throw inside @init, the getter's val check) all resolve to CTBase.ParsingError / CTBase.IncorrectArgument. - module Shadowed binds the same names to junk values (CTModels = 42): the interpolated module objects must win over any caller binding. The fixture modules live at the test module's top level (TST1, TST3). Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
CHANGELOG.md records the removed prefix API with a migration block (CHG3), the fix of #356, the fold of the extension into src/, the new direct dependencies and the test changes; the compatibility footer now says the release is breaking instead of claiming an unchanged API. BREAKING.md mirrors the entry with the same migration block. The docs index no longer documents prefix_fun/prefix_exa/init_prefix, and AGENTS.md describes src/exa_linalg.jl instead of ext/ and states that the generated code refers to the modules by object (FUN/EXA/ERR). Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ReviewReviewed at c5049f0 against ct-conventions v0.10.0 / ct-agents v0.4.0. Verdict: good to merge once the remaining test-plan items are done. The fix is right: it uses the mechanism What I checked
Minor points (none blocking)
Release noteThis PR is breaking, so the next release must be a breaking bump (a minor bump in 0.x). 🤖 Generated with Claude Code |
…le (#356) - __gen_spec_value documented pref as a Symbol prefix; it is now a Module. - test_hygiene: Shadowed gets the same broken_init as Bare, so the expansion-time ParsingError is checked with the names bound to junk too. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Closes #356.
Summary
The code generated by
@defand@initnamedCTModels,ExaModelsandCTBaseby symbol, so it only ran in a module that had bindings with these names:import OptimalControlorusing OptimalControl: @deffailed withUndefVarError: CTModels not defined. The module objects are now interpolated into the generated expressions, so they resolve where the macros are defined (same mechanism__wrapalready used forCTBase.CTException, and the one applied to@Liein CTLie.jl#43).CTModels,ExaModelsandLinearAlgebraare direct dependencies (CTModels = "0.19, 0.20, 0.21", the range used across the ecosystem).src/defaults.jl:FUN = CTModels,EXA = ExaModels,ERR = CTBase.ext/CTParserExaModels.jlis folded intosrc/exa_linalg.jl(methods unchanged; still temporary, Align CTParser with CTBase 0.29 / CTModels 0.18 / ExaModels 0.12 #325).Decisions (ct-conventions v0.10.0)
init_prefixis removed too, beyond the literal list of the issue:@inithad the identical defect (import OptimalControl+@initfails the same way) and nothing outside CTParser references it. Leaving it would only half-fix the bug.TST8: an extension escaped it). The deliberate piracy is whitelisted withtreat_as_ownon the five ExaModels node types, not on the whole module, so a new pirated method elsewhere still fails. The ambiguity check follows the ecosystem pattern (ambiguities=falseintest_all, thenAqua.test_ambiguities(CTParser; exclude=...)), excluding the stdlib functions the port extends; those ambiguities are upstream's, ported verbatim, and leave with the file.TST1,TST3):runtests.jlbinds all three names inMain, so a flat test could not fail before the fix.test/test_hygiene.jluses nested modules where the packages are loaded but the names are unbound (whatimport OptimalControlleaves), plus a module bindingCTModels = 42,ExaModels = "nope",CTBase = nothing. It covers@def(:funand:exa),@init, and the typed errors raised from generated code.test_prefix.jlis deleted,test_prefix_bis.jlbecomestest_backends.jlwith a contract onFUN/EXA/ERRand anisdefinedguard against the removed API coming back.Breaking
The prefix API is removed (
prefix_fun(!),prefix_exa(!),e_prefix(!),init_prefix(!), the__default_*prefix*functions and thePREFIX_*constants). Documented inCHANGELOG.mdandBREAKING.mdwith a migration block (CHG3). The only external caller found is the archivedProjetLong26/CTTransfo. ExaModels is now loaded with CTParser, including for users of the functional backend only (it is already a dependency of OptimalControl).Test plan
Pkg.test("CTParser"): 15/15 files, 2627 pass, 9 broken (the expected GPU@test_skip), 0 failtest_hygiene.jlfails onmain's generated code (moduleBareraisesUndefVarError), passes hereCTModels/ExaModels/CTBasefor the generated code (separate PR there)Conventions: ct-conventions v0.10.0, ct-agents v0.4.0.
Generated with Devin