Skip to content

Reach the AutoDePSpecialize wrappers through public APIs - #1124

Draft
ChrisRackauckas-Claude wants to merge 2 commits into
SciML:masterfrom
ChrisRackauckas-Claude:agent/public-fww-path-nlsbase
Draft

Reach the AutoDePSpecialize wrappers through public APIs#1124
ChrisRackauckas-Claude wants to merge 2 commits into
SciML:masterfrom
ChrisRackauckas-Claude:agent/public-fww-path-nlsbase

Conversation

@ChrisRackauckas-Claude

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Jul 28, 2026

Copy link
Copy Markdown
Member

Ignore this PR until it has been reviewed by @ChrisRackauckas.

Supersedes #1121. Closes #1118.

Summary

#1121 removed the ExplicitImports violations by reconstructing the same objects through indirect public surface — deriving SingleCacheStorage's type by reflecting on a throwaway FunctionWrappersWrapper, swapping wrap_void_opaque for a reuse of wrapfun_iip, and substituting SII.all_symbols for has_sys. This takes the other route: promote each name at its owning package and then just use it.

The starting point was a local QA run on clean master, which reports four non-public accesses, not the two in #1118ExplicitImports stops at the first failing module, so the extension's violations were masking NonlinearSolveBase's own:

Module `NonlinearSolveBaseForwardDiffExt`:
- `SingleCacheStorage` is not public in `FunctionWrappersWrappers`  (ext/…ForwardDiffExt.jl:86)
- `wrapfun_iip_opaque` is not public in `NonlinearSolveBase`        (ext/…ForwardDiffExt.jl:122)
Module `NonlinearSolveBase`:
- `ImmutableNonlinearProblem` is not public in `SciMLBase`          (src/autospecialize.jl:295)
- `has_sys` is not public in `SciMLBase`                            (src/autospecialize.jl:309)

FunctionWrappersWrappers

The extension builds its wrapper as FunctionWrappersWrapper{typeof(fwt), AllowNonIsBits, typeof(cs)}(fwt, cs) with cs = SingleCacheStorage(). SingleCacheStorage was @public and documented on main (SciML/FunctionWrappersWrappers.jl#72) but sat in an unregistered 1.11.0.

1.11.0 is now registered (General#162490), which makes that name public — so _make_fww_iip needs no change at all and is byte-identical to master. The only edit here is the compat floor.

An earlier revision of this PR rewrote the call to go through the keyword constructor FunctionWrappersWrapper(fwt; policy). That has been reverted. It was unnecessary, and it was the wrong trade: the explicit {FW, P, CS}(fwt, cs) form fixes the wrapper type from type parameters alone, whereas the keyword form derives CS from _make_cache_storage(cache) and therefore leans on constant propagation through a keyword-argument frame to stay concrete. Nothing on the norecompile path should rest on that holding.

SciML/FunctionWrappersWrappers.jl#79 is the matching follow-up: the two-argument inner constructor was reachable as public API (the type is exported) but was the only constructor of the type with no docstring. That PR documents it, so the whole called path is public and documented.

SciMLBase

has_sys was the only member of the AbstractSciMLFunction field-existence trait family that was neither public nor documented, and ImmutableNonlinearProblem was non-public while ImmutableODEProblem was already @public. Both are addressed in SciML/SciMLBase.jl#1474, so the two guards in maybe_opaque_wrap keep their exact semantics rather than being reworded.

This matters for ImmutableNonlinearProblem specifically: #1121 replaced prob isa NonlinearProblem || prob isa ImmutableNonlinearProblem with problem_type(prob) isa StandardNonlinearProblem, which is not equivalent — IntervalNonlinearProblem also defaults to problem_type = StandardNonlinearProblem() and is also <: AbstractNonlinearProblem, so it would newly pass the guard and then reach prob.u0, a field it does not have.

RespecializeParams

Nothing needed. wrap_void_opaque is already exported and documented in the released 1.x, and ExplicitImports never flagged it — #1121's rewrite of that path was not required.

wrapfun_iip_opaque

NonlinearSolveBase's own extension point, defined in src/ and overloaded in its own extension, exactly like wrapfun_iip. It becomes an explicit import and joins wrapfun_iip in the ignore entry that already covers this category ("NonlinearSolveBase (own internal)"). Making it public would commit a still-evolving internal (AutoDePSpecialize reverse-mode support is a planned follow-up) to SemVer-stable public API.

Validation

Rebased onto current master (cb25573a). #1126 synced NonlinearSolveBase down to the registered 2.38.0, so the version here is now 2.38.1 rather than 2.39.1, and the compat floors were re-applied on top of master's.

Only SciMLBase is developed — it is the one dependency still unregistered. FunctionWrappersWrappers 1.12.0 and SciMLTesting 2.6.1 resolve from the registry, which is exactly what CI will do:

FunctionWrappersWrappers  1.12.0  [registry]
SciMLTesting              2.6.1   [registry]
SciMLBase                 3.41.0  [dev]
NonlinearSolveBase        2.38.1  [dev]

NonlinearSolveBase QA — all four violations gone, group fully green:

Test Summary:     | Pass  Total     Time
Quality Assurance |   20     20  1m10.2s

NonlinearSolveBase Core — full group, zero failures:

Test Summary:              | Pass  Total  Time
AutoDePSpecialize opaque-p |   25     25  4.6s
…
     Testing NonlinearSolveBase tests passed

Runic 1.7.0 --check on all changed files exits 0.

Blocked on

Links

The NonlinearSolveBase QA group fails on `master` with two
`ExplicitImports.NonPublicQualifiedAccessException`s in the ForwardDiff
extension, and two more in NonlinearSolveBase itself that the first pair was
masking. Rather than reconstruct the same objects through indirect public
surface, promote each name at its owning package and use it.

- `FunctionWrappersWrappers.SingleCacheStorage` plus the raw
  `FunctionWrappersWrapper{FW, P, CS}(fwt, cs)` inner constructor become the
  public `FunctionWrappersWrapper(fwt; policy)` tuple constructor, which exists
  for exactly this inferrability case. It yields the identical concrete wrapper
  type, so the norecompile path is unchanged. Requires
  FunctionWrappersWrappers 1.11.
- `SciMLBase.has_sys` and `SciMLBase.ImmutableNonlinearProblem` are public as of
  SciMLBase 3.41, so the guards in `maybe_opaque_wrap` keep their exact
  semantics. `ImmutableNonlinearProblem` comes off the ExplicitImports ignore
  list.
- `wrapfun_iip_opaque` is NonlinearSolveBase's own extension point, overloaded
  in its own extension exactly like `wrapfun_iip`. It joins `wrapfun_iip` as an
  explicit import and in the same ignore entry, which already documents this
  category.

`RespecializeParams.wrap_void_opaque` needed nothing: it is already exported and
documented, and ExplicitImports never flagged it.

Adds a direct dual-call regression test for the opaque wrapper's Jacobian
signature, the shape AD actually reaches.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Reverts `_make_fww_iip` to its `master` form. With FunctionWrappersWrappers
1.11.0 registered, `SingleCacheStorage` is public, so the original code passes
the non-public-access check unchanged — rebuilding the wrapper through the
keyword constructor was never necessary.

It was also the wrong trade. The explicit `{FW, P, CS}(fwt, cs)` form fixes the
wrapper type from type parameters alone, while the keyword form derives `CS`
from `_make_cache_storage(cache)` and so leans on constant propagation through a
keyword-argument frame to stay concrete. Nothing on the norecompile path should
depend on that holding.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.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.

NonlinearSolveBase QA imports non-public wrapfun_iip_opaque after #1107

2 participants