Skip to content

Commit

Permalink
Fix issue #730
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelhkay committed Oct 6, 2023
1 parent 35a08e0 commit 4baf259
Showing 1 changed file with 100 additions and 35 deletions.
135 changes: 100 additions & 35 deletions specifications/xquery-40/src/expressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4992,30 +4992,28 @@ name.</p>
<prodrecap id="TypedFunctionTest" ref="TypedFunctionTest"/>
</scrap>

<p>
A <nt def="FunctionTest">FunctionTest</nt> matches a <termref
def="dt-function-item"/>,
potentially also checking its <xtermref spec="DM31"
ref="dt-signature">function signature</xtermref>
<phrase role="xquery">and
annotations (see <specref ref="id-annotations"
/>)</phrase>.

An <nt def="AnyFunctionTest"
>AnyFunctionTest</nt>
matches any item that is a function.

A <nt
def="TypedFunctionTest"
>TypedFunctionTest</nt> matches an
item if it is a <termref
def="dt-function-item"
>function</termref> and the function’s type signature (as defined in
<xspecref
spec="DM31" ref="function-items"/>) is a <termref def="dt-subtype"
<p>A <nt def="FunctionTest">FunctionTest</nt> matches selected <termref
def="dt-function-item">function items</termref>,
potentially checking their <xtermref spec="DM31"
ref="dt-signature">signature</xtermref>
(which includes the types of the arguments and results<phrase role="xquery">, and also their annotations,
as described in <specref ref="id-annotations"/>)</phrase>).</p>

<p>An <nt def="AnyFunctionTest">AnyFunctionTest</nt>
matches any item that is a function.</p>

<p>A <nt def="TypedFunctionTest">TypedFunctionTest</nt> matches an
item if it is a <termref def="dt-function-item"/> and the function’s type signature (as defined in
<xspecref spec="DM31" ref="function-items"/>) is a <termref def="dt-subtype"
>subtype</termref> of the <nt def="TypedFunctionTest"
>TypedFunctionTest</nt>.
</p>
>TypedFunctionTest</nt>.</p>


<p diff="add" at="issue730">In addition, a <nt def="TypedFunctionTest">TypedFunctionTest</nt>
may match certain maps and arrays, as described in <specref ref="id-map-test"/> and
<specref ref="id-array-test"/></p>



<p>
Here are some examples of <nt def="FunctionTest">FunctionTest</nt>s:
Expand Down Expand Up @@ -5124,9 +5122,9 @@ name.</p>

<p>The <nt def="MapTest">MapTest</nt>
<code>map(*)</code> matches any map. The <nt def="MapTest">MapTest</nt>
<code>map(X, Y)</code> matches any map where the type of every key
is an instance of <code>X</code> and the type of every value is an
instance of <code>Y</code>.</p>
<code>map(K, V)</code> matches any map where <phrase diff="del" at="issue730">the type of </phrase>every key
is an instance of <code>K</code> and <phrase diff="del" at="issue730">the type of </phrase>every value is an
instance of <code>V</code>.</p>



Expand Down Expand Up @@ -5169,15 +5167,55 @@ name.</p>
</item>
</ulist>

<p>Because of the rules for subtyping of function types according to their signature, it follows that the item type
<p diff="add" at="issue730">A map is also a function item, and therefore matches certain
function tests. Specifically, a map that matches <code>map(K, V)</code> also matches a function
test of the form <code>function(xs:anyAtomicType) as R</code> provided that both the following
conditions are satisfied:</p>

<ulist diff="add" at="issue730">
<item><p><var>V</var> is a <termref def="dt-subtype"/> of <var>R</var></p></item>
<item><p><var>empty-sequence()</var> is a <termref def="dt-subtype"/> of <var>R</var></p></item>
</ulist>


<note diff="add" at="issue730">
<p>To understand this rule, consider the use of a map <code>$M</code> in a function
call <code>$M($K)</code>, which is equivalent to the function call <code>map:get($M, $K)</code>.
This function accepts any atomic value for the argument <code>$K</code>, and hence satisfies
a function test that requires an argument type of <code>xs:anyAtomicType</code>. If the
key <code>$K</code> is present in the map, the result of the function will be a value of
type <var>V</var>; if not, it will be an empty sequence. The map is therefore substitutable
for the function test provided that the function test allows both a value of type <var>V</var>
and the empty sequence as possible results.</p>
<p>The key type <var>K</var> does not enter into this rule. That is because in the function call
<code>$M($K)</code>, the sought key <code>$K</code> does not have to be of the same
type as the keys actually present in the map.</p>
<p>The transitivity rules for item type matching mean that if an item <var>M</var>
matches a type <var>T</var>, and <var>T</var> is a <termref def="dt-subtype"/>
of <var>U</var>, then <var>M</var> also matches type <var>U</var>. So the fact
that a map from integers to strings (<code>map(xs:integer, xs:string)</code>)
matches <code>function(xs:anyAtomicType) as xs:string?</code>
means that it will also match other function tests such as
<code>function(xs:integer) as xs:string?</code> and
<code>function(xs:decimal) as xs:anyAtomicType?</code></p>
<p>Furthermore, the rules for
<termref def="dt-function-coercion"/> mean that any map can be supplied as a value in a
context where it does not actually match the required function type, but
can be coerced to a function that does. For example a map of type
<code>map(xs:integer, xs:string)</code> can be coerced to a function of
type <code>function(xs:integer) as xs:string</code>; in this situation a type
error will occur only if a call on the function actually returns an empty sequence. </p>
</note>

<p diff="del" at="issue730">Because of the rules for subtyping of function types according to their signature, it follows that the item type
<code>function(A) as item()*</code>, where A is an atomic type, also matches any map, regardless of the type of the keys actually
found in the map. For example, a map whose keys are all strings can be supplied where the required type is
<code>function(xs:integer) as item()*</code>; a call on the map that treats it as a function with an integer argument will always succeed,
and will always return an empty sequence.</p>



<p>The function signature of a map matching type
<p diff="del" at="issue730">The function signature of a map matching type
<code>map(K, V)</code>, treated as a function, is
<code>function(xs:anyAtomicType) as V?</code>. It is thus always a
subtype of <code>function(xs:anyAtomicType) as item()*</code> regardless of the
Expand Down Expand Up @@ -5484,7 +5522,34 @@ declare function flatten($tree as tree) as item()* {



<p>The function signature of an array
<p diff="add" at="issue730">An array that matches <code>array(T)</code>
also matches the function test <code>function(xs:integer) as T</code>.</p>

<note diff="add" at="issue730">
<p>To understand this rule, consider the use of an array <code>$A</code> in a function
call <code>$A($I)</code>, which is equivalent to the function call <code>array:get($A, $I)</code>.
This function accepts any integer for the argument <code>$I</code>, and the result
will either be an instance of <var>T</var>, or an error.</p>

<p>The transitivity rules for item type matching mean that if an item <var>A</var>
matches a type <var>T</var>, and <var>T</var> is a <termref def="dt-subtype"/>
of <var>U</var>, then <var>A</var> also matches type <var>U</var>. So the fact
that an array of strings (<code>array(xs:string)</code>)
matches <code>function(xs:integer) as xs:string</code>
means that it will also match other function tests such as
<code>function(xs:long) as item()*</code>.</p>
<p>Furthermore, the rules for
<termref def="dt-function-coercion"/> mean that any array can be supplied as a value in a
context where it does not actually match the required function type, but
can be coerced to a function that does. For example an array of type
<code>array(node())</code> can be coerced to a function of
type <code>function(xs:integer) as element()</code>; in this situation a type
error will occur only if a call on the function actually returns a node
that is not an element node.</p>
</note>


<p diff="del" at="issue730">The function signature of an array
matching <code>array(X)</code>, treated as a function, is
<code>function(xs:integer) as X</code>. It is thus always a subtype of
<code>function(xs:integer) as item()*</code>
Expand All @@ -5498,7 +5563,7 @@ declare function flatten($tree as tree) as item()* {
operator. In such cases, a type error will occur only if an actual
call on the array (treated as a function) returns a value that is
not an instance of the required return type.</p>

<p>Rules defining whether one array type is a <termref def="dt-subtype"/> of another
are given in <specref ref="id-item-subtype-arrays"/>.</p>

Expand Down Expand Up @@ -6256,13 +6321,13 @@ declare function flatten($tree as tree) as item()* {
</example>
</item>

<item>
<p>Both the following are true:</p>
<item diff="chg" at="issue730">
<p>All the following are true:</p>
<olist>
<item><p><var>A</var> is <code>map(<var>K</var>, <var>V</var>)</code></p></item>
<item><p><var>B</var> is <code>function(xs:anyAtomicType) as <var>W</var></code>,
where <var>W</var> has the same item type as <var>V</var>, but also allows
an empty sequence.</p></item>
<item><p><var>B</var> is <code>function(xs:anyAtomicType) as <var>R</var></code></p></item>
<item><p><var>V</var> <var>R</var></p></item>
<item><p><code>empty-sequence()</code> ⊆ <var>R</var></p></item>
</olist>
<example>
<head>Examples:</head>
Expand Down

0 comments on commit 4baf259

Please sign in to comment.