Skip to content

QA: resolve Base.Broadcast.axistype ambiguity with CommonWorldInvalidations#180

Merged
ChrisRackauckas merged 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:fix-axistype-cwi-ambiguity
Jun 24, 2026
Merged

QA: resolve Base.Broadcast.axistype ambiguity with CommonWorldInvalidations#180
ChrisRackauckas merged 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:fix-axistype-cwi-ambiguity

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Contributor

Please ignore until reviewed by @ChrisRackauckas.

Problem

The master CI QA lane (both julia 1 and lts) is red. Aqua.test_ambiguities(Static; recursive=false) reports 4 ambiguities:

Ambiguity #1..4
axistype(::Any, ::CommonWorldInvalidations.UDespec{1,2,3,4})  @ CommonWorldInvalidations
axistype(r::OptionallyStaticUnitRange{StaticInt{1}}, ::Any)   @ Static  src/ranges.jl:382

Root cause

CommonWorldInvalidations v1.1.0 (picked up under Static's [compat] CommonWorldInvalidations = "1"; v1.0.0 had no such methods) ships despecialization methods

Base.Broadcast.axistype(::Any, ::UDespec_k)   # UDespec_k <: AbstractUnitRange{Float64}

Static's broadcast-axis helpers were declared with a bare ::Any open slot:

axistype(r::OptionallyStaticUnitRange{StaticInt{1}}, _)
axistype(_, r::OptionallyStaticUnitRange{StaticInt{1}})

At the intersection (OptionallyStaticUnitRange{StaticInt{1}}, UDespec_k) neither method is more specific (Static wins the first arg, CWI wins the second) → an unresolvable diagonal ambiguity. The only method that resolves it is one referencing CWI's internal UDespec fixture types, which Static must not depend on.

Fix

A broadcast axis is always an AbstractUnitRange{<:Integer} (axes carry integer indices; Base.Broadcast.axistype is only ever reached from _bcs1(a, b) with both args being array axes). Narrowing the open slot from ::Any to AbstractUnitRange{<:Integer} keeps every real call dispatching to Static's methods while excluding CWI's Float64-eltype fixture types — removing the diagonal without naming CWI internals.

OptionallyStaticUnitRange{StaticInt{1}} is itself <: AbstractUnitRange{<:Integer}, so the existing 3-arg (OSUR, OSUR) disambiguator remains strictly more specific and unchanged.

Verification (run locally)

  • QA green on Julia 1.12 and 1.10 (lts): Aqua + ExplicitImports11 Pass, 1 Broken (the pre-existing test_piracies(broken=true)), 0 Fail. The 4 ambiguities are gone.
  • Core suite green: 2615/2615 passing on Julia 1.12 (includes the axistype behavior tests in test/shared/ranges.jl).
  • Confirmed the unmodified master reproduces the 4 ambiguities on lts, and the fix clears them on both channels.

🤖 Generated with Claude Code

…ations

CommonWorldInvalidations v1.1.0 ships despecialization methods
`Base.Broadcast.axistype(::Any, ::UDespec_k)` where the `UDespec` fixture
types are `<: AbstractUnitRange{Float64}`. Static's broadcast-axis helpers
were declared with a bare `::Any` open slot:

    axistype(r::OptionallyStaticUnitRange{StaticInt{1}}, _)
    axistype(_, r::OptionallyStaticUnitRange{StaticInt{1}})

That forms a diagonal ambiguity with CWI's methods at the intersection
`(OptionallyStaticUnitRange{StaticInt{1}}, UDespec_k)` — neither method is
more specific — so Aqua.test_ambiguities reported 4 ambiguities and the QA
lane (julia 1 and lts) went red.

A broadcast axis is always an `AbstractUnitRange{<:Integer}`, so narrowing
the open slot from `::Any` to `AbstractUnitRange{<:Integer}` keeps every
real call dispatching to these methods while excluding CWI's Float64-eltype
fixture types, removing the ambiguity without referencing CWI internals.
Behavior is unchanged: Core suite passes 2615/2615 and QA is green on
both julia 1 (1.12) and lts (1.10).

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisRackauckas ChrisRackauckas marked this pull request as ready for review June 24, 2026 12:00
@ChrisRackauckas ChrisRackauckas merged commit a78d475 into SciML:master Jun 24, 2026
21 of 26 checks passed
ChrisRackauckas added a commit that referenced this pull request Jun 27, 2026
Convert the hand-rolled Aqua/ExplicitImports body in test/qa/qa.jl to the
SciMLTesting 1.6 run_qa form and turn on the full ExplicitImports suite.

- qa.jl: single run_qa(Static; ...) call. Aqua.test_all replaces the
  per-sub-check calls; ambiguities recursive=false preserved via aqua_kwargs;
  the test_piracies(broken=true) finding becomes aqua_broken=(:piracies,)
  (Base.promote_shape overload on Tuple{Vararg{Union{Int,StaticInt}}}, tracked
  in #181 — the prior piracy issue #162 was a different, now-resolved method).
- explicit_imports=true enables all six EI checks (was two). Four pass bare;
  all_qualified_accesses_are_public ignores 22 Base/Base.Broadcast/
  Base.IteratorsMD internals, all_explicit_imports_are_public ignores
  IfElse.ifelse — other packages' not-yet-public names, documented per ignore.
- test/qa/Project.toml: drop ExplicitImports + SafeTestsets (both transitive
  via SciMLTesting); keep Aqua direct (ambiguities child-proc needs it);
  SciMLTesting compat -> "1.6".

Verified locally against released SciMLTesting 1.6.0 (Julia 1.10 and 1.12),
develop-by-path so the master axistype fix (#180) is in scope: 16 Pass,
1 Broken (piracies), 0 Fail, 0 Error; ExplicitImports 6/6 pass.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

2 participants