From eabce0ce933fcddea394ad716756e25e667a15e1 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Tue, 28 Jul 2026 21:33:02 -0400 Subject: [PATCH 1/3] Restore the ExplicitImports ignores dropped in #76 #76 replaced the whole `run_qa(...)` call with a bare `run_qa(FunctionWrappersWrappers)`, which silently discarded the `all_qualified_accesses_are_public` ignore list it carried. The QA group has errored on `main` ever since with `NonPublicQualifiedAccessException` for `FunctionWrappers.FunctionWrapper` and `TruncatedStacktraces.@truncate_stacktrace`. This is invisible to `Pkg.test()`, which runs the curated default group; QA is not part of it. `:tail` is not restored: `Base.tail` is no longer reached, and ExplicitImports does not flag it. Co-Authored-By: Chris Rackauckas --- test/qa/qa.jl | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/test/qa/qa.jl b/test/qa/qa.jl index 4ce61f8..ddc2673 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -1,3 +1,19 @@ using SciMLTesting, FunctionWrappersWrappers -run_qa(FunctionWrappersWrappers) +run_qa( + FunctionWrappersWrappers; + ei_kwargs = (; + # Qualified accesses to names their owning module has not declared `public`. + # Both are irreducible — neither can be promoted at its source: + # FunctionWrappers.FunctionWrapper is the type this package exists to wrap. It + # appears in the signature of every public constructor, and callers must build + # `FunctionWrapper` tuples themselves to reach the inference-stable path, so it + # cannot be hidden. FunctionWrappers.jl is JuliaLang-owned. + # TruncatedStacktraces.@truncate_stacktrace is that package's only user-facing + # macro and is never exported. SciML/TruncatedStacktraces.jl is archived and + # read-only, so it cannot be made public there. + all_qualified_accesses_are_public = (; + ignore = (:FunctionWrapper, Symbol("@truncate_stacktrace")), + ), + ), +) From a552d4d20d94221f147eaaef3d28f793899d197e Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Tue, 28 Jul 2026 21:33:12 -0400 Subject: [PATCH 2/3] Drop the dead TruncatedStacktraces dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `@truncate_stacktrace` cannot fire in this package. TruncatedStacktraces sets `DISABLE = @load_preference("disable", true) || VERSION >= v"1.10"`, and the macro body is wrapped in `@static if !DISABLE`, so on Julia 1.10 and later it expands to nothing — and 1.10 is this package's floor. The `Base.show` method it is supposed to define has never existed on any Julia version we support, and the preference cannot override the version clause. Verified: `FunctionWrappersWrapper` contributes zero `Base.show` methods, and its type prints in full with no truncation. That makes the dependency dead weight, and it was the only reason the QA suite needed a `@truncate_stacktrace` ignore. Removing it is better than either ignoring the access or promoting the name upstream — the latter is impossible in any case, since SciML/TruncatedStacktraces.jl is archived and read-only. Only the `FunctionWrapper` ignore remains, and that one has a path out now: JuliaLang/FunctionWrappers.jl#35. Co-Authored-By: Chris Rackauckas --- Project.toml | 4 +--- src/FunctionWrappersWrappers.jl | 3 --- test/qa/qa.jl | 20 ++++++++------------ 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/Project.toml b/Project.toml index 9888436..70ec9e3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,13 +1,12 @@ name = "FunctionWrappersWrappers" uuid = "77dc65aa-8811-40c2-897b-53d922fa7daf" authors = ["Chris Elrod and contributors"] -version = "1.11.0" +version = "1.11.1" [deps] FunctionWrappers = "069b7b12-0de2-55c6-9aab-29f3d0a68a2e" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" SciMLPublic = "431bcebd-1456-4ced-9d72-93c2757fff0b" -TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" [weakdeps] Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" @@ -28,7 +27,6 @@ SafeTestsets = "0.1, 1" SciMLPublic = "1" SciMLTesting = "2.4" Test = "1" -TruncatedStacktraces = "1.1" julia = "1.10" [extras] diff --git a/src/FunctionWrappersWrappers.jl b/src/FunctionWrappersWrappers.jl index 5645d41..98edcbb 100644 --- a/src/FunctionWrappersWrappers.jl +++ b/src/FunctionWrappersWrappers.jl @@ -2,7 +2,6 @@ module FunctionWrappersWrappers using FunctionWrappers: FunctionWrappers using SciMLPublic: @public -import TruncatedStacktraces export FunctionWrappersWrapper, unwrap, wrapped_signatures, wrapped_return_types export NoCache, SingleCache, DictCache @@ -223,8 +222,6 @@ struct FunctionWrappersWrapper{FW, P, CS} end end -TruncatedStacktraces.@truncate_stacktrace FunctionWrappersWrapper - """ FunctionWrappersWrapper{FW, P, CS}(f) -> FunctionWrappersWrapper{FW, P, CS} diff --git a/test/qa/qa.jl b/test/qa/qa.jl index ddc2673..82b5be8 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -3,17 +3,13 @@ using SciMLTesting, FunctionWrappersWrappers run_qa( FunctionWrappersWrappers; ei_kwargs = (; - # Qualified accesses to names their owning module has not declared `public`. - # Both are irreducible — neither can be promoted at its source: - # FunctionWrappers.FunctionWrapper is the type this package exists to wrap. It - # appears in the signature of every public constructor, and callers must build - # `FunctionWrapper` tuples themselves to reach the inference-stable path, so it - # cannot be hidden. FunctionWrappers.jl is JuliaLang-owned. - # TruncatedStacktraces.@truncate_stacktrace is that package's only user-facing - # macro and is never exported. SciML/TruncatedStacktraces.jl is archived and - # read-only, so it cannot be made public there. - all_qualified_accesses_are_public = (; - ignore = (:FunctionWrapper, Symbol("@truncate_stacktrace")), - ), + # `FunctionWrappers.FunctionWrapper` is not declared `public` in its owning + # module. It is the type this package exists to wrap: it appears in the + # signature of every public constructor, and callers must build + # `FunctionWrapper` tuples themselves to reach the inference-stable + # construction path, so it cannot be hidden behind our own API. Drop this + # entry once JuliaLang/FunctionWrappers.jl#41 is released and the compat + # floor is raised. + all_qualified_accesses_are_public = (; ignore = (:FunctionWrapper,)), ), ) From 22e07c272c137ef1c9fec1844609f3222dc894ed Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Tue, 28 Jul 2026 21:33:42 -0400 Subject: [PATCH 3/3] Document the explicit FunctionWrappersWrapper{FW, P, CS}(fw, cs) constructor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `FunctionWrappersWrapper` is exported, so its inner constructor was already reachable as public API, but it carried no docstring — the only constructor of the type that did not. Downstream solver stacks construct through exactly this method, because supplying `FW`, `P` and `CS` directly keeps the wrapper type inferrable without relying on constant propagation through a keyword-argument frame, which the `argtypes`/`rettypes` and tuple constructors do. The docstring is attached with `@doc` on the method signature after the struct; a docstring written inside the struct body does not attach to the type's binding, so Documenter would never render it. Co-Authored-By: Chris Rackauckas --- src/FunctionWrappersWrappers.jl | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/FunctionWrappersWrappers.jl b/src/FunctionWrappersWrappers.jl index 98edcbb..64f04af 100644 --- a/src/FunctionWrappersWrappers.jl +++ b/src/FunctionWrappersWrappers.jl @@ -222,6 +222,50 @@ struct FunctionWrappersWrapper{FW, P, CS} end end +@doc """ + FunctionWrappersWrapper{FW, P, CS}(fw, cs) -> FunctionWrappersWrapper{FW, P, CS} + +Create a `FunctionWrappersWrapper` from an already-built wrapper tuple and cache storage, +with every type parameter fixed by the caller. + +This is the fully explicit form. Prefer it when the result type must be inferrable from +type parameters alone: `FW`, `P` and `CS` are given directly rather than derived from +argument values, so nothing rests on constant propagation through a keyword-argument +frame. Solver stacks that wrap a type-erased callable — where the wrapper type, and every +cache built from it, must stay concrete — construct through this method. + +The caller is responsible for consistency: `fw` must match `FW`, and `cs` must be the +storage type `P`'s fallback path expects — [`NoCacheStorage`](@ref), +[`SingleCacheStorage`](@ref), or [`DictCacheStorage`](@ref), matching the intended cache +mode. + +# Arguments +- `fw`: Tuple of `FunctionWrappers.FunctionWrapper`s, tried in order on call. +- `cs`: Cache storage instance used by the fallback path. + +# Type Parameters +- `FW`: Tuple type of the wrapped `FunctionWrapper`s. +- `P`: Fallback policy type, such as `Strict`, `AllowAll`, or `AllowNonIsBits`. +- `CS`: Cache storage type, matching `typeof(cs)`. + +# Returns +- `FunctionWrappersWrapper{FW, P, CS}`: A callable wrapper around `fw`. + +# Examples +```jldoctest +julia> using FunctionWrappers: FunctionWrapper + +julia> fw = (FunctionWrapper{Float64, Tuple{Float64, Float64}}(+),); + +julia> cs = FunctionWrappersWrappers.SingleCacheStorage(); + +julia> fww = FunctionWrappersWrapper{typeof(fw), AllowNonIsBits, typeof(cs)}(fw, cs); + +julia> fww(1.0, 2.0) +3.0 +``` +""" FunctionWrappersWrapper{FW, P, CS}(fw::FW, cs::CS) where {FW, P, CS} + """ FunctionWrappersWrapper{FW, P, CS}(f) -> FunctionWrappersWrapper{FW, P, CS}