Project

Profile

Help

Bug #6003

closed

Inline function expression evaluated using xsl:evaluate

Added by Michael Kay over 1 year ago. Updated about 1 year ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
XSLT conformance
Sprint/Milestone:
-
Start date:
2023-05-01
Due date:
% Done:

100%

Estimated time:
Legacy ID:
Applies to branch:
11, 12, trunk
Fix Committed on Branch:
11, 12, trunk
Fixed in Maintenance Release:
Platforms:
.NET, Java

Description

A problem occurs when using xsl:evaluate to evaluate an expression in the form of an inline function such as

function($x) { $lib?xyz('abc')}

where the value of $lib is supplied using xsl:evaluate/xsl:with-param.

The expression compiles OK, but a dynamic error occurs because $lib has the wrong dynamic type; it looks as if the supplied value of $lib has not been picked up correctly.

XML and XSLT repro files attached.


Files

evaluationTest.xml (1.1 KB) evaluationTest.xml Michael Kay, 2023-05-01 13:21
validation.xslt (2.89 KB) validation.xslt Michael Kay, 2023-05-01 13:21

Related issues

Has duplicate Saxon - Bug #6004: java.lang.RuntimeException: Internal error in XSLT 3 using xsl:evaluate on function call of anonymous functionDuplicate2023-05-01

Actions
Actions #1

Updated by Michael Kay over 1 year ago

  • Description updated (diff)
Actions #2

Updated by Martin Honnen over 1 year ago

For a test, I have run the code through SaxonJS's xslt3 command line tool, it gives an error as well, but a very different one:

xslt3 -t -s:Downloads\evaluationTest.xml -xsl:Downloads\validation.xslt
SaxonJS 2.5 from Saxonica
Node.js version v16.17.1
Compiling stylesheet C:\Users\marti\Downloads\validation.xslt
Stylesheet compilation time: 0.249s
Asynchronous transform with options: stylesheetText={"N":"package","version":"20",(string), stylesheetBaseURI=file://C:/Users/marti/Download(string), stylesheetParams=[object Object](string), outputProperties=[object Object](string), extraOptions=[object Object](string), destination=stdout(string), baseOutputURI=file://C:/Users/marti/(string), logLevel=2(string), sourceFileName=file://C:/Users/marti/Download(string),
SEF generated by SaxonJS 2.5 at 2023-05-01T22:27:47.954+02:00
 in root of document
<?xml version="1.0" encoding="UTF-8"?>
<innings>
   <number>1</number>
   <battingSide>yorkshire</battingSide>
   <fieldingSide>lancashire</fieldingSide>
   <over>
      <bowler>1</bowler>Transformation failure: Error XTTE0570 at validation.xslt#39
  Required item type of value in 'xsl:variable name="Q{}read_function"' expression is (function(element(*)) as element(*)?); supplied value is anonymous function (arity 1)
Error XTTE0570 at validation.xslt#39
  Required item type of value in 'xsl:variable name="Q{}read_function"' expression is (function(element(*)) as element(*)?); supplied value is anonymous function (arity 1)
Actions #3

Updated by Michael Kay over 1 year ago

We've been debugging this in SaxonJ 12.x.

As a workaround, I think you can replace

                function($instance as element(over)) as element(player)
		{
		$lib?readRel($instance, 'fieldingSide')
		          /player[number=$instance/bowler]
		}

with

                let $lib2 := $lib return 
                function($instance as element(over)) as element(player)
		{
		$lib2?readRel($instance, 'fieldingSide')
		          /player[number=$instance/bowler]
		}

(this actually fails for unrelated reasons, but I think that's because the logic has been trimmed down for the repro).

Actions #4

Updated by Michael Kay over 1 year ago

What's happening here is that we're parsing the XPath expression, we find the inline function, we're parsing its body, and we hit the variable reference $lib. The variable hasn't been locally declared, so we go to the static context to see if it can be resolved. It can, because the xsl:evaluate instruction added it to the static context (as an XPathVariable instance with slot number 0). The XPathVariable object is typically used for free-standing XPath expressions that refer to a variable that isn't declared within the expression itself. The variable reference $lib is parsed into a LocalVariableReference with this XPathVariable as its binding.

When we've finished parsing the function body, we walk the tree allocating slot numbers to variable references, and $lib gets the slot number of the XPathVariable it is bound to, which is zero. At execution time, the variable is evaluated by looking in slot 0 of the current stack frame - but this is the stack frame of the inline function itself, and slot 0 holds the value of the $instance argument.

There are two ways we could go on this. We could treat the variable like a global variable reference, in which case it doesn't need to go in the function's closure because its value doesn't change during execution. Or we could treat it like a local variable - as it it were declared outside the function in a let clause. That case works because we gather the "implicitParams" of an inline function before parsing it, and when a variable reference is recognised as being bound to one of these implicitParams, we effectively add it to the function closure (which is actually implemented by creating another function and partially applying it, but that's immaterial here).

At present I think the second option is probably less disruptive, so I'm going to try that approach.

Actions #5

Updated by Michael Kay over 1 year ago

The worst case we have to consider is probably where the XPath expression is evaluated using the JAXP API. This was of course designed for XPath 1.0 but we allow its use with later XPath versions. It's particularly problematic because in a case like this, there's no prior knowledge that the variable $lib actually exists in the static context; variables are discovered only at run-time. This means that we can't, prior to parsing the inline function, gather the variables that it might reference and mark them as "implicitParams" to be treated differently when a variable reference is encountered. So perhaps we should go down the "global variable" route instead....

Actions #6

Updated by Michael Kay over 1 year ago

  • Status changed from New to In Progress

Well, putting the JAXP case aside, I've got this test working. In XParser.findOuterRangeVariable(), before we start looking for XSLT-declared variables in the outer context, we consider parameters defined for a free-standing XPath expression using a new method findXPathParameter that's very similar to findOuterXsltVariable. This recognizes the variable for what it is and effectively adds it to the closure of the inline function.

Need to do a bit of work on the test case to turn it into a regression test because it's actually still crashing for unrelated reasons.

We should also test the equivalent JAXP XPath invocation, and perhaps add some complications like having nested inline functions.

Actions #7

Updated by Michael Kay over 1 year ago

Created XSLT3 test case evaluate-051 which demonstrates the failure and tests the fix.

Retrofitted and tested the fix on the 11.x branch.

Actions #8

Updated by Michael Kay over 1 year ago

I found that it's not really possible to mimic this directly using the JAXP XPath API, because the API requires the return type to be one of the four XPath 1.0 types, which means the expression can't return a function. We can get close by creating and invoking the function within the XPath expression; but this test case works with or without the patch.

In fact this is working in a completely different way. The undeclared variable compiles to a JAXPVariableReference, which calls the variable resolver to get the variable's value at run time, and this all works fine; the bug doesn't kick in because it's not using slot numbers to access the value.

But I retained the test case, XPathTest.testBug6003.

Actions #9

Updated by Michael Kay over 1 year ago

Transferred the SaxonJS equivalent bug to bug #6011.

Actions #10

Updated by Michael Kay over 1 year ago

  • Status changed from In Progress to Resolved
  • Applies to branch 11, 12, trunk added
  • Fix Committed on Branch 11, 12, trunk added
  • Platforms .NET, Java added
Actions #11

Updated by Michael Kay over 1 year ago

  • Has duplicate Bug #6004: java.lang.RuntimeException: Internal error in XSLT 3 using xsl:evaluate on function call of anonymous function added
Actions #12

Updated by O'Neil Delpratt over 1 year ago

  • Status changed from Resolved to Closed
  • % Done changed from 0 to 100
  • Fixed in Maintenance Release 12.3 added

Bug fix applied in the Saxon 12.3 maintenance release.

Actions #13

Updated by O'Neil Delpratt over 1 year ago

  • Status changed from Closed to Resolved

Leaving this bug issue as resolved until resolved against Saxon 11.

Actions #14

Updated by Debbie Lockett about 1 year ago

  • Status changed from Resolved to Closed
  • Fixed in Maintenance Release 11.6 added

Bug fix applied in the Saxon 11.6 maintenance release.

Please register to edit this issue

Also available in: Atom PDF