Describe the bug
In eXist, errors involving functions inside element constructors like element foo { map { "x": "y" } } lack location information.
Expected behavior
I expected the errors to report the location of the error in the query, as they do in BaseX and Saxon. (Saxon has the best error description of the 3 in this case.)
To Reproduce
xquery version "3.1";
element foo { map { "x": "y" } }
eXist error:
err:XQTY0105 Enclosed expression contains function item
BaseX returns the error at the start of the enclosed content:
Stopped at /Users/joe/Downloads/file, 3/13:
[XQTY0105] Invalid content: map { "x": "y" }.
Saxon reports the error as appearing at the first character of the map constructor, with a very clear error description (if missing the error code):
Cannot add a map as a child of a constructed element
Start location: 3:16
Context (please always complete the following information):
Additional context
conf.xml? None.Whilst digging around I cannot find any linear/column number in the hierarchy. I assume for now that #setLocation is not invoked for example from the AST. Help is appreciated
org.xmldb.api.base.XMLDBException: err:XQTY0105 Enclosed expression contains function item
at org.exist.xmldb.LocalXPathQueryService.execute(LocalXPathQueryService.java:201)
at org.exist.xmldb.LocalXPathQueryService.lambda$execute$2(LocalXPathQueryService.java:165)
at org.exist.xmldb.function.LocalXmldbFunction.apply(LocalXmldbFunction.java:46)
at org.exist.xmldb.AbstractLocal.withDb(AbstractLocal.java:263)
at org.exist.xmldb.LocalXPathQueryService.execute(LocalXPathQueryService.java:164)
at org.exist.client.QueryDialog$QueryRunnable.run(QueryDialog.java:587)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.exist.xquery.XPathException: err:XQTY0105 Enclosed expression contains function item
at org.exist.xquery.EnclosedExpr.eval(EnclosedExpr.java:101)
at org.exist.xquery.ElementConstructor.eval(ElementConstructor.java:330)
at org.exist.xquery.AbstractExpression.eval(AbstractExpression.java:71)
at org.exist.xquery.PathExpr.eval(PathExpr.java:281)
at org.exist.xquery.AbstractExpression.eval(AbstractExpression.java:71)
at org.exist.xquery.XQuery.execute(XQuery.java:261)
at org.exist.xquery.XQuery.execute(XQuery.java:185)
at org.exist.xmldb.LocalXPathQueryService.execute(LocalXPathQueryService.java:198)
... 6 more
interestingly the query
xquery version "3.1";
let $a := 1
return
element foo { map { "x": "y" } }
results in
An exception occurred during query execution: err:XQTY0105 Enclosed expression contains function item [at line 3, column 6]
making the original query actually report on location (0,0) (where unknown location is internally -1,-1)
the path variable passed to org.exist.xquery.parser.XQueryTreeParser#constructor seem to contain the correct value; just a bit later the value is not in the expression.
I give up, I hope @wolfgangmm or @ljo can have a look
The current develop branch (eXist 5.3.0-SNAPSHOT e92ea8f70512dd6dbb49bc1fc059f64944bee045 20200915110349) is still affected.
This is issue is likely related to #3518 - the XQueryParser swallows the location information by introducing a virtual AST node.
This one was a little bit harder to crack. Also, I think I got lucky because compConstructorValue did the main trick: adding location info to element content sub-expressions.
The simple case works has location and throws at compile time.
A slightly modified - and more realistic scenario - still throws without location information. 鈽癸笍
element a {
attribute href { "#" },
map {} (: a function item added to element content by mistake :)
}
This way of writing it is also missing location info.
element a {
(
attribute href { "#" },
map {} (: a function item added to element content by mistake :)
)
}
Interestingly location information is available for this case:
element a { [map {}] }
There is also this edge case:
element a { ("", map {})[1] }, (: this is fine :)
element a { (map {})[2] }, (: this throws - in Saxon10-HE as well - but could actually evaluate to <a /> :)
And there is more to think about. Compare the location reported by these two queries:
let $a := map {} return element a { $a }
(: err:XQTY0105 Enclosed expression contains function item [at line 1, column 38, ...] :)
let $a := map {} return element a { "", $a }
(: err:XQTY0105 Enclosed expression contains function item [at line 1, column 6, ...] :)
sub-expression location seems to be broken somewhat.
These two report the function item to be at line 1, column 6 as well
let $a := map {} return element a { ($a) }
let $a := map {} return element a { ("", $a) }
Most helpful comment
This one was a little bit harder to crack. Also, I think I got lucky because
compConstructorValuedid the main trick: adding location info to element content sub-expressions.