Project

Profile

Help

Bug #4636

AssertionError compiling xsl:for-each-group with a higher-order-function

Added by Michael Kay about 1 month ago. Updated about 1 month ago.

Status:
Resolved
Priority:
Normal
Assignee:
Category:
Internals
Sprint/Milestone:
-
Start date:
2020-07-08
Due date:
% Done:

0%

Estimated time:
Legacy ID:
Applies to branch:
10, 9.9
Fix Committed on Branch:
10, 9.9
Fixed in Maintenance Release:

Description

A compile-time assertion error occurs when compiling an xsl:for-each-group instruction with group-starting-with="*[$starts-function(.)], where $starts-function is an anonymous inline function.

test.xsl (2.94 KB) test.xsl Michael Kay, 2020-07-08 11:10

History

#1 Updated by Michael Kay about 1 month ago

A workaround is to change the group-starting-with attribute to

group-starting-with="*[boolean($starts.function(.))]"

(The problem arises because Saxon doesn't know whether $starts.function() might return a numeric value, and it therefore has to cater for the possibility; patterns involving a predicate where the predicate value is potentially numeric are much more complex to deal with.)

#2 Updated by Michael Kay about 1 month ago

What's happing is that optimization of the function els:wrap-elements-starting-with-names attempts to inline the function els:wrap-elements-starting-with, and after inlining, the reoptimization of the xsl:for-each-group function now knows more about the supplied group-starting-with function, in particular it knows that it will return a boolean. So it tries to take advantage of this knowledge. In particular, this enables it to use a BasePatternWithPredicate rather than a GeneralPositionalPattern, which is a lot more efficient to evaluate because it doesn't need to know the sibling position of the node being tested.

Where this goes wrong is that the group-starting-with operand of xsl:for-each-group is labelled as a "constrained class" operand, which limits the ability to substitute an expression of a different class during optimization.

The intent of marking it as constrained is to guarantee that the output of a rewrite will always be a Pattern (which is implemented as a subclass of Expression; but it's not the case that any Expression can be used in this context). However, the constraint actually being enforced is that the expression produced by the optimizer must be the same class as the original - that is, the same kind of Pattern. The constraint is too restrictive.

#3 Updated by Michael Kay about 1 month ago

  • Status changed from New to Resolved
  • Fix Committed on Branch 10, 9.9 added

I have replaced the CONSTRAINED_CLASS property of OperandRole with a property that describes an explicit constraint on the expression participating in that role; for patterns the constraint is that the expression must be a pattern, it is no longer required to be the same kind of pattern as was used before the rewrite.

Please register to edit this issue

Also available in: Atom PDF