Obscure issue when using "instance of" inside function on results of array:filter
The attached XSLT results run in oXygen 21 results in the following error:
Engine name: Saxon-PE 22.214.171.124 Severity: error Description: Internal error evaluating template rule at line 8 in module file:/C:/aaprojects/datypic/functx/functx/saxonissues.xsl
It seems like a very obscure issue because other calls to array:filter are fine, and "instance of" on the results works fine if it is not inside a function. Something to do with function conversion rules? But why this array and not others?
(This was originally part of a larger XSLT that tests my XQuery book examples in the context of FunctX, but I have distilled it down.) I can't test this on 9.9 because it requires PE and I don't have a license. Thanks!
#1 Updated by Michael Kay 10 months ago
No failure using either Saxon-EE 126.96.36.199 or Saxon-EE 188.8.131.52 (Or to be more accurate, using my current development versions, which may include some bug fixes not in the released versions).
Confirmed: no failure using the issued Saxon-EE 184.108.40.206 or 220.127.116.11.
However, the problem does occur using the issued Saxon-PE 18.104.22.168 or 22.214.171.124.
So this is a rare case of something that fails under Saxon-PE but works under EE. That probably means I will have to create (or reconstitute) a development/debugging environment specific to PE.
#2 Updated by Michael Kay 10 months ago
- Status changed from New to In Progress
Note that the simpler but equivalent expression using
in place of
starts-with#2(?, 'a') seems to work just fine.
I wonder if we should rewrite a dynamic call on a statically-known function with a static call on the same function? (Or perhaps, that's what we're attempting to do when it fails....)
#3 Updated by Michael Kay 10 months ago
Looking at it by code-reading, without the debugger, we can see that it's failing to bind a call to a user-defined function because there's no current component. In fact, all the signs are that it's failing to resolve the call on local:is-array(). It's not easy to see how that should be affected by the dynamic/partially-applied call on
fn:starts-with(). Perhaps a binding slot number is being reused or incorrectly allocated, which would cause completely unpredictable failures.
#4 Updated by Michael Kay 10 months ago
I can trigger the failure in my normal development environment by running with -opt:0, which suppresses optimizations.
As suspected, the call on
local:is-array() is failing because there is no current component. (It doesn't fail with optimization enabled because the function call gets inlined; in fact, the function and the "instance of" expression are never evaluated because it's possible to infer by static type analysis alone that the result must be true).
It seems that the call on
starts-with#2 (via various wrapping layers of
FunctionCoercer instances) is causing the current component in the context to be wrongly set to null, which then causes the completely straightforward call on local:is-array() to fail. The conditions for setting the current component to null should be the same as the conditions that cause a new context to be allocated, but with this particular set of circumstances, we are trying to avoid creating a new context, but are then corrupting the old one.
The dynamic function
starts-with#2 is represented as an instance of
UserFunctionReference.BoundUserFunction; the comments on this class (and its name) wrongly imply that it is used only for references to user-defined functions, and not for references to system-defined functions. This appears to be the source of the confusion. For a call to a system-defined function there is no need to create a new context; but in that case the current component should not be reset.
#5 Updated by Michael Kay 10 months ago
- Status changed from In Progress to Resolved
- Applies to branch 9.9, trunk added
- Fix Committed on Branch 9.9, trunk added
I think the simplest fix is to change
UserFunctionReference.BoundUserFunction.call() so that it doesn't set the current component in the new context if it is null. It's a bit difficult to convince myself that that changes covers all cases, but it certainly covers this one.
Please register to edit this issue