From 4baf2598525726ee49e98a69b52cad14a7a7ce99 Mon Sep 17 00:00:00 2001 From: Michael Kay Date: Fri, 6 Oct 2023 22:31:28 +0100 Subject: [PATCH] Fix issue #730 --- specifications/xquery-40/src/expressions.xml | 135 ++++++++++++++----- 1 file changed, 100 insertions(+), 35 deletions(-) diff --git a/specifications/xquery-40/src/expressions.xml b/specifications/xquery-40/src/expressions.xml index e0395973e9..09f9932b70 100644 --- a/specifications/xquery-40/src/expressions.xml +++ b/specifications/xquery-40/src/expressions.xml @@ -4992,30 +4992,28 @@ name.

-

- A FunctionTest matches a , - potentially also checking its function signature - and - annotations (see ). - - An AnyFunctionTest - matches any item that is a function. - - A TypedFunctionTest matches an - item if it is a function and the function’s type signature (as defined in - ) is a A FunctionTest matches selected function items, + potentially checking their signature + (which includes the types of the arguments and results, and also their annotations, + as described in )).

+ +

An AnyFunctionTest + matches any item that is a function.

+ +

A TypedFunctionTest matches an + item if it is a and the function’s type signature (as defined in + ) is a subtype of the TypedFunctionTest. -

+ >TypedFunctionTest.

+ + +

In addition, a TypedFunctionTest + may match certain maps and arrays, as described in and +

+ +

Here are some examples of FunctionTests: @@ -5124,9 +5122,9 @@ name.

The MapTest map(*) matches any map. The MapTest - map(X, Y) matches any map where the type of every key - is an instance of X and the type of every value is an - instance of Y.

+ map(K, V) matches any map where the type of every key + is an instance of K and the type of every value is an + instance of V.

@@ -5169,7 +5167,47 @@ name.

-

Because of the rules for subtyping of function types according to their signature, it follows that the item type +

A map is also a function item, and therefore matches certain + function tests. Specifically, a map that matches map(K, V) also matches a function + test of the form function(xs:anyAtomicType) as R provided that both the following + conditions are satisfied:

+ + +

V is a of R

+

empty-sequence() is a of R

+
+ + + +

To understand this rule, consider the use of a map $M in a function + call $M($K), which is equivalent to the function call map:get($M, $K). + This function accepts any atomic value for the argument $K, and hence satisfies + a function test that requires an argument type of xs:anyAtomicType. If the + key $K is present in the map, the result of the function will be a value of + type V; 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 V + and the empty sequence as possible results.

+

The key type K does not enter into this rule. That is because in the function call + $M($K), the sought key $K does not have to be of the same + type as the keys actually present in the map.

+

The transitivity rules for item type matching mean that if an item M + matches a type T, and T is a + of U, then M also matches type U. So the fact + that a map from integers to strings (map(xs:integer, xs:string)) + matches function(xs:anyAtomicType) as xs:string? + means that it will also match other function tests such as + function(xs:integer) as xs:string? and + function(xs:decimal) as xs:anyAtomicType?

+

Furthermore, the rules for + 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 + map(xs:integer, xs:string) can be coerced to a function of + type function(xs:integer) as xs:string; in this situation a type + error will occur only if a call on the function actually returns an empty sequence.

+
+ +

Because of the rules for subtyping of function types according to their signature, it follows that the item type function(A) as item()*, 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 function(xs:integer) as item()*; a call on the map that treats it as a function with an integer argument will always succeed, @@ -5177,7 +5215,7 @@ name.

-

The function signature of a map matching type +

The function signature of a map matching type map(K, V), treated as a function, is function(xs:anyAtomicType) as V?. It is thus always a subtype of function(xs:anyAtomicType) as item()* regardless of the @@ -5484,7 +5522,34 @@ declare function flatten($tree as tree) as item()* { -

The function signature of an array +

An array that matches array(T) + also matches the function test function(xs:integer) as T.

+ + +

To understand this rule, consider the use of an array $A in a function + call $A($I), which is equivalent to the function call array:get($A, $I). + This function accepts any integer for the argument $I, and the result + will either be an instance of T, or an error.

+ +

The transitivity rules for item type matching mean that if an item A + matches a type T, and T is a + of U, then A also matches type U. So the fact + that an array of strings (array(xs:string)) + matches function(xs:integer) as xs:string + means that it will also match other function tests such as + function(xs:long) as item()*.

+

Furthermore, the rules for + 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 + array(node()) can be coerced to a function of + type function(xs:integer) as element(); 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.

+
+ + +

The function signature of an array matching array(X), treated as a function, is function(xs:integer) as X. It is thus always a subtype of function(xs:integer) as item()* @@ -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.

- +

Rules defining whether one array type is a of another are given in .

@@ -6256,13 +6321,13 @@ declare function flatten($tree as tree) as item()* { - -

Both the following are true:

+ +

All the following are true:

A is map(K, V)

-

B is function(xs:anyAtomicType) as W, - where W has the same item type as V, but also allows - an empty sequence.

+

B is function(xs:anyAtomicType) as R

+

VR

+

empty-sequence()R

Examples: