eXist-db / exist

eXist Native XML Database and Application Platform
https://exist-db.org
GNU Lesser General Public License v2.1
430 stars 180 forks source link

Error in type-checking with "as" in for-statement [BUG] #3553

Open djbpitt opened 4 years ago

djbpitt commented 4 years ago

Describe the bug A clear and concise description of what the bug is.

for $i as xs:string in ('a', 'b', 'c')
return <p>{$i}</p>

in eXist-db raises XPTY0004 (type error), continuing “Expected xs:string, got element()“. Saxon does not raise an error. It appears, then, as if an as clause that specifies the datatype of the variable declared in a for statement is checked against the type of the return value at the end of the FLWOR expression, instead of the type of the variable.

Expected behavior A clear and concise description of what you expected to happen.

I expect the for statement in the preceding example to pass type checking.

To Reproduce

Execute:

for $i as xs:string in ('a', 'b', 'c')
return <p>{$i}</p>

in eXist-db, which raises a type error. Execute the same code in Saxon, which runs to completion, without error.

Context (please always complete the following information):

Additional context

line-o commented 4 years ago

This will also pass another test-case in XQTS 3.1.0 ("hof-046").

joewiz commented 3 years ago

I can confirm the bug and that it still affects 5.3.0.

As noted in #3971, BaseX returns the expected result too.

Also, this bug was present in 4.7.1 - possibly earlier - so it's not a recent issue.

@PieterLamers provided a link to the relevant portion of the spec:

Type checking on the variable binding of a for statement returns errors (https://www.w3.org/TR/xquery-31/#prod-xquery31-ForBinding).

Here's the test case and the similar case that @line-o alluded to - hof-046 from qt3 - adapted to xqsuite:

xquery version "3.1";

module namespace t="http://exist-db.org/xquery/test";

declare namespace test="http://exist-db.org/xquery/xqsuite";

declare
    %test:assertTrue
function t:as-string() {
    for $x as xs:string in "foo"
    return true()
};

declare
    %test:assertTrue
function t:as-function() {
    for $f as function(*) in string-join#1
    return true()
};

This returns:

<testsuite package="http://exist-db.org/xquery/test" timestamp="2021-07-06T15:34:50.711-04:00"
    tests="2" failures="0" errors="2" pending="0" time="PT0.004S">
    <testcase name="as-function" class="t:as-function">
        <error type="err:XPTY0004"
            message="It is a type error if, during the static analysis phase, an expression is found to have a static type that is not appropriate for the context in which the expression occurs, or during the dynamic evaluation phase, the dynamic type of a value does not match a required type as specified by the matching rules in 2.5.4 SequenceType Matching. Invalid type for variable $f. Expected function(*), got xs:boolean"
        />
    </testcase>
    <testcase name="as-string" class="t:as-string">
        <error type="err:XPTY0004"
            message="It is a type error if, during the static analysis phase, an expression is found to have a static type that is not appropriate for the context in which the expression occurs, or during the dynamic evaluation phase, the dynamic type of a value does not match a required type as specified by the matching rules in 2.5.4 SequenceType Matching. Invalid type for variable $x. Expected xs:string, got xs:boolean"
        />
    </testcase>
</testsuite>