fix(data): restate dropped trait bounds on 6 structs + 32 where-clauses; bump 0.27.6-beta#493
Merged
Conversation
…rete structs
Hamiltonian, PseudoHamiltonian, ControlLaw, PathConstraint, Multiplier, and
ControlledVectorField each declare `<: AbstractX{TD,VD}` (or `{FB,TD,VD}` /
`{K,TD,VD}`) — an abstract parent that bounds TD<:TimeDependence,
VD<:VariableDependence (etc.) — without repeating that bound on their own
type-parameter list. This is not automatically inherited: `<:` between
parametric types is a structural comparison of declared bounds, so
`Hamiltonian <: AbstractHamiltonian` was `false` even though constructing an
instance with an invalid TD/VD already correctly threw a TypeError at the
supertype-check step. The gap was purely at the static/dispatch level.
Verified with a minimal reproduction before touching source: adding the bound
directly to the struct declaration is safe and non-breaking (every value that
could be constructed before still builds identically), and restores the
formal subtype relation. VectorField and HamiltonianVectorField already had
the correct pattern and were used as the reference.
See .reports/2026-07-12_alias-where-bounds-audit.md for the full audit
(companion to CTFlows.jl's .reports/2026-07-11_alias-where-bounds-audit.md
and the Handbook rule in philosophy/types-traits-interfaces.md).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ssion guard
Extends the struct-level fix (previous commit) to every where {...} clause
that drops a bound relative to the type actually written in dispatch
position. Grep flagged 48 candidates: 12 were docstring text (not real code),
10 were confirmed safe (genuinely unconstrained by design — OptionValue's T,
is_a_parameter(::Type{T}), Val{Slot} compile-time tags), 26 needed a fix —
mostly Base.show (compact + MIME) on the 6 structs fixed in the previous
commit plus VectorField/HamiltonianVectorField/ComposedVectorField/
ComposedHamiltonian (already correctly bounded, only their Base.show where
clauses had dropped it), and the _natural_sig_* label helpers in
Data/helpers.jl, plus Interpolant{M} in Interpolation/.
Adds test/suite/meta/test_data_subtyping.jl: asserts Struct <: AbstractParent
for the 6 structs fixed in the previous commit plus the 4 already-correct
ones, as a standing regression guard.
Full suite: 4713/4713 passed (4703 + 10 new).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ropping fix Documents the fix from the previous two commits (6 structs + 32 where-clauses restating their abstract parent's TD/VD/FB/K bound) in CHANGELOG.md, and adds a non-breaking note in BREAKING.md warning downstream packages (CTFlows.jl in particular) that dispatch on these types with their own unbounded where-clauses — their ground truth has changed and should be re-audited. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hamiltonian,PseudoHamiltonian,ControlLaw,PathConstraint,Multiplier,ControlledVectorFieldeach declare<: AbstractX{TD,VD}(or{FB,TD,VD}/{K,TD,VD}) without repeating thatbound on their own type-parameter list.
<:between parametric types is astructural comparison of declared bounds — Julia does not propagate an
abstract parent's bound down to a concrete subtype automatically. Verified:
Hamiltonian <: AbstractHamiltonianwasfalsebefore this fix, eventhough constructing an instance with an invalid
TD/VDalready correctlythrew a
TypeError(enforced indirectly via the supertype check). Fixed byrestating the bound directly on all 6 structs — safe and non-breaking,
since every previously-constructible value still builds identically.
where-clauses restated the same dropped bounds downstream (mostlyBase.showmethods and the_natural_sig_*label helpers inData/helpers.jl, plusInterpolation.Interpolant). Of 48 candidatesflagged by the audit grep, 12 were docstring text (not real code), 10 were
confirmed safe (genuinely unconstrained by design).
test/suite/meta/test_data_subtyping.jlasserts
Struct <: AbstractParentfor all 10 trait-parametrizedDatatypes.
CHANGELOG.mdentryand a non-breaking note in
BREAKING.mdflagging the downstream actionneeded for packages (CTFlows.jl in particular) that dispatch on these types
with their own unbounded
where-clauses.Full audit and reasoning in
.reports/2026-07-12_alias-where-bounds-audit.md— companion to CTFlows.jl's
.reports/2026-07-11_alias-where-bounds-audit.mdand the general rule now documented in the Handbook
(
philosophy/types-traits-interfaces.md).Test plan
julia --project -e 'using CTBase'— compiles cleanly at every stagePkg.test()): 4713/4713 passed, 0 failures, 0 errors(including Aqua's ambiguity check), run 3 times across the pass
minimal reproduction before touching source
🤖 Generated with Claude Code