Skip to content

[feature] XQuery 4.0 type coercion rules - #6260

Open
joewiz wants to merge 3 commits into
eXist-db:developfrom
joewiz:feature/xq4-type-promotion
Open

[feature] XQuery 4.0 type coercion rules#6260
joewiz wants to merge 3 commits into
eXist-db:developfrom
joewiz:feature/xq4-type-promotion

Conversation

@joewiz

@joewiz joewiz commented Apr 25, 2026

Copy link
Copy Markdown
Member

Summary

  • Implement XQuery 4.0 coercion rules from spec §3.4.1, version-gated behind xquery version "4.0"
  • Add implicit casting: xs:string → xs:anyURI, xs:hexBinary ↔ xs:base64Binary, bidirectional numeric
  • Add relabeling for derived atomic types (e.g., xs:integer 3 accepted as xs:positiveInteger)
  • Accept xquery version "4.0" in the ANTLR tree walker

What Changed

XQueryTree.g — Accept xquery version "4.0", setting context version to 40.

DynamicTypeCheck.java — New xq4ImplicitCast() method handles runtime coercion per spec §3.4.1:

  • Item 4 (Implicit Casting table): xs:string→xs:anyURI, xs:hexBinary↔xs:base64Binary, any numeric → any numeric
  • Item 6 (Relabeling): derived type acceptance when datum is in value space
  • isXQ4ImplicitCast() and isXQ4Relabeling() are static for reuse by the static check

Function.java — Bypass static type check for XQ4 implicit casts and relabeling (line 305).

UntypedValueCheck.java — Version-gate the xs:integer → xs:positiveInteger rejection; allow in XQ4 per §3.4.1 item 6.

xq4-type-promotion.xql — 8 XQSuite tests (XQ 4.0 module) covering all coercion rules.

xq4-type-promotion-gating.xql — 1 version-gating test (XQ 3.1 module) confirming xs:string→xs:anyURI is correctly rejected.

Spec References

Design Decisions

  • No changes to Type.java — the type hierarchy is correct; coercion operates at the function argument level via DynamicTypeCheck, exactly as the spec intends
  • Version-gated — all new rules only activate when xquery version "4.0" is declared
  • The 76 date/time XQTS failures (xs:time is not a sub-type of xs:dateTime) are NOT type promotion — they require function signature changes for fn:*-from-dateTime (QT4 PR1481), tracked separately

Test Plan

  • 9 XQSuite tests pass (string→anyURI, binary coercion, numeric coercion, relabeling, version gating)
  • Full exist-core test suite: 6601 tests, 0 failures, 0 regressions
  • XQTS QT4 run to verify function-call-promotion-* tests pass

🤖 Generated with Claude Code

@joewiz
joewiz requested a review from a team as a code owner April 25, 2026 04:28
Comment thread exist-core/src/main/antlr/org/exist/xquery/parser/XQueryTree.g Outdated
@joewiz

joewiz commented Apr 25, 2026

Copy link
Copy Markdown
Member Author

[This response was co-authored with Claude Code. -Joe]

Thanks @reinhapa — addressed in 826ef2d:

  • Converted the XQuery version if-else chain in XQueryTree.g to a switch-as-expression

@line-o line-o added xquery issue is related to xquery implementation XQ4 xquery 4 labels May 7, 2026
@line-o
line-o requested a review from a team May 7, 2026 21:45
joewiz added a commit to joewiz/exist that referenced this pull request May 30, 2026
Per @duncdrum and @line-o on PR eXist-db#6344: both reviewers flagged the two
xs:hexBinary ↔ xs:base64Binary code paths as XQ 4.0-specific (the
comments literally say "(XQuery 4.0)") and noted they don't belong in
this XQ 3.1 conformance subset. Removed:

- DynamicTypeCheck.java: the xs:base64Binary ↔ xs:hexBinary type-promotion
  branch in the static-type-check ladder
- GeneralComparison.java: case (d) of resolveNumericType — cast both
  operands of a general comparison to xs:base64Binary when both are
  binary types. Renumbered the now-final XPTY0004 case from (e) to (d).

These will be reintroduced together with the rest of XQ 4.0 type
coercion in v2/xq4-core-functions (PR eXist-db#6260).

XQuery3Tests: 1030/1030 pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread exist-core/src/main/java/org/exist/xquery/UntypedValueCheck.java

@dizzzz dizzzz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dizzzz
dizzzz requested review from a team, duncdrum, line-o and reinhapa July 18, 2026 16:12
@dizzzz

dizzzz commented Jul 18, 2026

Copy link
Copy Markdown
Member

@reinhapa any new thoughts?

joewiz and others added 3 commits July 18, 2026 12:51
Add version-gated XQ4 coercion rules that only apply when
`xquery version "4.0"` is declared:

- Implicit Casting (§3.4.1 item 4): xs:string → xs:anyURI,
  xs:hexBinary ↔ xs:base64Binary, bidirectional numeric coercion
- Relabeling (§3.4.1 item 6): derived type acceptance when datum
  is within value space (e.g., xs:integer 3 → xs:positiveInteger)
- Accept `xquery version "4.0"` in the parser

Runtime coercion in DynamicTypeCheck, static check bypass in
Function.java, version-gated integer→positiveInteger in
UntypedValueCheck. No changes to the type hierarchy in Type.java.

Includes 9 XQSuite tests covering all coercion rules plus a
version-gating test confirming XQ 3.1 modules reject string→anyURI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Convert version if-else chain in XQueryTree.g to switch-as-expression.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Simplify DynamicTypeCheck.isXQ4ImplicitCast to a single boolean return, dropping
the xs:double/xs:float to xs:decimal cases already subsumed by the any-numeric to
any-numeric rule; collapse the boolean return in isXQ4Relabeling; and extract the
XQuery 4.0 coercion disjunct in Function.checkArgumentType into an
isXQ4CoercionAllowed helper so it no longer inflates that method's condition. No
behavior change; the full XQuery3Tests suite (including the XQ4 type-promotion
tests) still passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@joewiz
joewiz force-pushed the feature/xq4-type-promotion branch from 826ef2d to 43f21ab Compare July 18, 2026 18:01
@joewiz

joewiz commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

[This response was prompted by Joe, drafted by Claude Code, and reviewed by Joe.]

Picked this one back up. Two updates, and a scope question for you all.

Rebased and green. The branch was ~930 commits behind, and the earlier Windows CI failure turned out to be purely the 45-minute integration-test timeout (no test failures) — which is long gone on current develop (that job now finishes in ~24 min). Rebased onto develop (clean, no conflicts), the full suite passes, and CI is green.

A scope finding worth your input. I ran the actual QT4 function-call-promotion tests against the branch. 5 of 9 pass; 4 fail:

  • Pass: 403, 404, 405 (string ↔ anyURI) and 408, 409 (binary promotion of a function result).
  • Fail (XPTY0004): 401, 402, 406, 407.

The four failures aren't in the argument coercion this PR implements — 408/409 confirm hexBinary/base64Binary promotion works at the call boundary. They fail because each test body then compares the coerced value, e.g. $z = xs:base64Binary(...) with $z now an xs:hexBinary. Making that comparison succeed requires applying §3.4.1 implicit casting to value-comparison operands as well — a distinct slice of the spec that this PR (scoped to function-call/return coercion) does not touch. In XQuery 3.1 that comparison is correctly an XPTY0004, and everything here is gated behind xquery version "4.0", so 3.1 behavior is unchanged either way.

The question: how would you like to handle the comparison-coercion gap?

  1. Treat this PR as a correct, self-contained increment (function-call/return coercion), merge it when XQ4 work is in scope, and do value-comparison coercion as a follow-up PR — with the four QT4 cases tracked against that follow-up.
  2. Or expand this PR to also cover comparison-operand coercion, aiming for the full 9/9 before it merges.

We'd lean toward (1) — it keeps a reviewable, spec-correct increment moving and separates a genuinely different mechanism — but this is squarely your call, especially given XQ4 is parked behind 7.0 for now. Happy to open a tracking issue for the comparison-coercion follow-up if that's useful.

@dizzzz

dizzzz commented Jul 20, 2026

Copy link
Copy Markdown
Member

I agree with (1) "as is"

@duncdrum

Copy link
Copy Markdown
Contributor

same here 3.1 as is

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

XQ4 xquery 4 xquery issue is related to xquery implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants