Skip to content

Macro hardening#151

Open
Wietse wants to merge 3 commits into
Paligo:mainfrom
Wietse:macro-hardening
Open

Macro hardening#151
Wietse wants to merge 3 commits into
Paligo:mainfrom
Wietse:macro-hardening

Conversation

@Wietse

@Wietse Wietse commented May 14, 2026

Copy link
Copy Markdown

xee-xpath-macros currently panics at macro-expansion time when given certain bad #[xpath_fn] inputs, with no span pointing at the user's code. This PR replaces the panic sites with bail_spanned! errors so users see clean compile errors at the right location:

  • missing signature string in #[xpath_fn(context_first)]
  • NonEmpty + occurrence in signatures
  • typed array / map tests
  • constrained element tests (element(foo), element(*, xs:string))
  • unsupported kind tests (attribute(), text(), comment(), ...)
  • atomic types without a Rust wrapper
  • Rust argument count vs. XPath signature parameter count mismatch (previously an out-of-bounds index panic)

Each error is covered by an insta snapshot test pinning the message text. To give meaningful spans, fn_arg: &syn::FnArg is threaded through the internal helpers in convert.rs. Public macro API unchanged.

No semantic change to the macro's happy path. XPath conformance unchanged: 20,221 passing, 0 failing.

@faassen

faassen commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Can you run cargo fmt? The build fails because of this.

@Wietse

Wietse commented May 19, 2026

Copy link
Copy Markdown
Author

Can you run cargo fmt? The build fails because of this.

Done. (I've added a pre-push hook locally so this shouldn't happen again).

Wietse added 3 commits May 20, 2026 00:51
Convert the panic / unwrap sites in xee-xpath-macros to bail_spanned!
errors so that bad #[xpath_fn] signatures produce compile errors
pointing at the user's code, instead of bare panics at macro
expansion time.

Sites converted:

  - parse.rs:49 — `expect("Signature not found")` when #[xpath_fn]
    is invoked with keyword args only (no signature string).
  - convert.rs — six panic sites for unsupported signature shapes:
    NonEmpty occurrence (`+`), named element tests (`element(foo)`),
    non-`element` / non-`item` kind tests, typed array tests,
    typed map tests, and atomic types without a Rust wrapper.

The convert.rs sites threaded `fn_arg: &syn::FnArg` through the
internal helpers so each error's span points at the offending
Rust argument. The public surface (`convert_sequence_type`) is
unchanged; only internal helpers gained a parameter.

Adds insta snapshot tests for each converted site, pinning the
error message text and confirming the error path is reached
rather than the panic.

No semantic change to the macro's happy path. Conformance suite
unchanged: Passed 20221, Failed 0, Error 0.
Two review findings on the first hardening pass:

1. (High) Arity mismatch between the XPath signature and the Rust
   function still panicked with a bare `index out of bounds` from
   `ast.sig.inputs[i + adjust]` in `make_wrapper`. The new
   `bail_spanned!` paths in convert.rs never got a chance to run
   for this case. Add an explicit bounds check after `adjust` is
   determined, surfacing a `syn::Error` pointing at the function
   name with both counts and (when relevant) a note about how
   many arguments were injected. Adds three regression tests:
   too-few Rust args, too-many Rust args, and a mismatch under
   `context` injection.

2. (Low) `convert_kind_test`'s diagnostic for `Element(Some(_))`
   reported "named element tests" but the AST shape
   (ElementOrAttributeTest with name_or_wildcard + optional
   type_name) also covers `element(*, xs:string)` and other
   typed/wildcard forms. Generalise the wording to "constrained
   element tests" with examples, and add a snapshot for
   `element(*, xs:string)` to lock in coverage.
@Wietse Wietse force-pushed the macro-hardening branch from 189aa8b to d82421c Compare May 19, 2026 23:01
@Wietse

Wietse commented May 19, 2026

Copy link
Copy Markdown
Author

Rebased onto main after you fixed the clippy warnings yourself.

If you want to avoid these surprises you could pin the Rust toolchain version in CI.

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