xee_interpreter/sequence/
matching.rs

1// This module matches types for inline functions or type checks
2// The convert module is used for checking and converting values for
3// external functions declared with xpath_fn
4
5use xee_schema_type::Xs;
6use xee_xpath_ast::ast;
7use xee_xpath_ast::parse_sequence_type;
8use xee_xpath_ast::Namespaces;
9use xee_xpath_type::TypeInfo;
10use xot::Xot;
11
12use crate::atomic;
13use crate::context;
14use crate::error;
15use crate::function;
16use crate::xml;
17
18use super::core::Sequence;
19use super::item::Item;
20use super::iter::one;
21use super::iter::option;
22
23impl Sequence {
24    /// Check a type for qee-qt assert-type
25    pub fn matches_type<'a>(
26        &self,
27        s: &str,
28        xot: &Xot,
29        get_signature: &impl Fn(&function::Function) -> &'a function::Signature,
30    ) -> error::Result<bool> {
31        let namespaces = Namespaces::default();
32        let sequence_type = parse_sequence_type(s, &namespaces)?;
33        if self
34            .clone()
35            .sequence_type_matching(&sequence_type, xot, get_signature)
36            .is_ok()
37        {
38            Ok(true)
39        } else {
40            Ok(false)
41        }
42    }
43
44    // sequence type matching for the purposes of instance of
45    pub(crate) fn sequence_type_matching<'a>(
46        self,
47        sequence_type: &ast::SequenceType,
48        xot: &Xot,
49        get_signature: &impl Fn(&function::Function) -> &'a function::Signature,
50    ) -> error::Result<Self> {
51        self.sequence_type_matching_convert(
52            sequence_type,
53            &|atomic, _| Ok(atomic),
54            &|function_test, item| item.function_type_matching(function_test, &get_signature),
55            xot,
56        )
57    }
58
59    // sequence type matching, including function conversion rules
60    pub(crate) fn sequence_type_matching_function_conversion<'a>(
61        self,
62        sequence_type: &ast::SequenceType,
63        context: &'a context::StaticContext,
64        xot: &Xot,
65        get_signature: &impl Fn(&function::Function) -> &'a function::Signature,
66    ) -> error::Result<Self> {
67        self.sequence_type_matching_convert(
68            sequence_type,
69            &|atomic, xs| Self::cast_or_promote_atomic(atomic, xs, context),
70            &|function_test, item| item.function_arity_matching(function_test, &get_signature),
71            xot,
72        )
73    }
74
75    fn cast_or_promote_atomic(
76        atom: atomic::Atomic,
77        xs: Xs,
78        context: &context::StaticContext,
79    ) -> error::Result<atomic::Atomic> {
80        let atom = if matches!(atom, atomic::Atomic::Untyped(_)) {
81            match xs {
82                // function conversion rules 3.1.5.2 it says: If the item is of
83                // type xs:untypedAtomic and the expected type is
84                // namespace-sensitive, a type error [err:XPTY0117] is raised.
85                Xs::QName | Xs::Notation => {
86                    return Err(error::Error::XPTY0117);
87                }
88                _ => atom.cast_to_schema_type(xs, context)?,
89            }
90        } else {
91            atom
92        };
93        atom.type_promote(xs)
94    }
95
96    fn sequence_type_matching_convert(
97        self,
98        t: &ast::SequenceType,
99        cast_or_promote_atomic: &impl Fn(atomic::Atomic, Xs) -> error::Result<atomic::Atomic>,
100        check_function: &impl Fn(&ast::FunctionTest, &Item) -> error::Result<()>,
101        xot: &Xot,
102    ) -> error::Result<Self> {
103        match t {
104            ast::SequenceType::Empty => {
105                if self.is_empty() {
106                    Ok(self)
107                } else {
108                    Err(error::Error::XPTY0004)
109                }
110            }
111            ast::SequenceType::Item(occurrence_item) => self.occurrence_item_matching(
112                occurrence_item,
113                cast_or_promote_atomic,
114                check_function,
115                xot,
116            ),
117        }
118    }
119
120    fn occurrence_item_matching(
121        self,
122        occurrence_item: &ast::Item,
123        cast_or_promote_atomic: &impl Fn(atomic::Atomic, Xs) -> error::Result<atomic::Atomic>,
124        check_function: &impl Fn(&ast::FunctionTest, &Item) -> error::Result<()>,
125        xot: &Xot,
126    ) -> error::Result<Self> {
127        match &occurrence_item.item_type {
128            ast::ItemType::AtomicOrUnionType(xs) => self.atomic_occurrence_item_matching(
129                occurrence_item,
130                cast_or_promote_atomic,
131                *xs,
132                xot,
133            ),
134            _ => self.non_atomic_occurrence_item_matching(
135                occurrence_item,
136                cast_or_promote_atomic,
137                check_function,
138                xot,
139            ),
140        }
141    }
142
143    // there is some duplication here for performance reasons; non-atomic
144    // occurrence type matching doesn't have to handle casting or promotion
145
146    fn non_atomic_occurrence_item_matching(
147        self,
148        occurrence_item: &ast::Item,
149        cast_or_promote_atomic: &impl Fn(atomic::Atomic, Xs) -> error::Result<atomic::Atomic>,
150        check_function: &impl Fn(&ast::FunctionTest, &Item) -> error::Result<()>,
151        xot: &Xot,
152    ) -> error::Result<Self> {
153        match occurrence_item.occurrence {
154            ast::Occurrence::One => {
155                let one = one(self.iter())?;
156                one.non_atomic_item_type_matching(
157                    &occurrence_item.item_type,
158                    cast_or_promote_atomic,
159                    check_function,
160                    xot,
161                )?;
162            }
163            ast::Occurrence::Option => {
164                let option = option(self.iter())?;
165                if let Some(item) = option {
166                    item.non_atomic_item_type_matching(
167                        &occurrence_item.item_type,
168                        cast_or_promote_atomic,
169                        check_function,
170                        xot,
171                    )?;
172                }
173            }
174            ast::Occurrence::Many => {
175                match occurrence_item.item_type {
176                    ast::ItemType::Item => {
177                        // we don't have to do anything, as we already know
178                        // all items are items
179                    }
180                    _ => {
181                        for item in self.iter() {
182                            item.non_atomic_item_type_matching(
183                                &occurrence_item.item_type,
184                                cast_or_promote_atomic,
185                                check_function,
186                                xot,
187                            )?;
188                        }
189                    }
190                }
191            }
192            ast::Occurrence::NonEmpty => {
193                if self.is_empty() {
194                    return Err(error::Error::XPTY0004);
195                }
196                match occurrence_item.item_type {
197                    ast::ItemType::Item => {
198                        // we don't have to do anything, as we already know
199                        // all items are items
200                    }
201                    _ => {
202                        for item in self.iter() {
203                            item.non_atomic_item_type_matching(
204                                &occurrence_item.item_type,
205                                cast_or_promote_atomic,
206                                check_function,
207                                xot,
208                            )?;
209                        }
210                    }
211                }
212            }
213        }
214        Ok(self)
215    }
216
217    fn atomic_occurrence_item_matching(
218        self,
219        occurrence_item: &ast::Item,
220        cast_or_promote_atomic: &impl Fn(atomic::Atomic, Xs) -> error::Result<atomic::Atomic>,
221        xs: Xs,
222        xot: &Xot,
223    ) -> error::Result<Self> {
224        match occurrence_item.occurrence {
225            ast::Occurrence::One => {
226                let one = one(self.atomized(xot))?;
227                let atom = one?.atomic_type_matching(xs, cast_or_promote_atomic)?;
228                Ok(atom.into())
229            }
230            ast::Occurrence::Option => {
231                let option = option(self.atomized(xot))?;
232                if let Some(atom) = option {
233                    let atom = atom?.atomic_type_matching(xs, cast_or_promote_atomic)?;
234                    Ok(atom.into())
235                } else {
236                    Ok(self)
237                }
238            }
239            ast::Occurrence::Many => {
240                let mut atoms = Vec::with_capacity(self.len());
241                for atom in self.atomized(xot) {
242                    atoms.push(atom?.atomic_type_matching(xs, cast_or_promote_atomic)?);
243                }
244                Ok(atoms.into())
245            }
246            ast::Occurrence::NonEmpty => {
247                if self.is_empty() {
248                    return Err(error::Error::XPTY0004);
249                }
250                let mut atoms = Vec::with_capacity(self.len());
251                for atom in self.atomized(xot) {
252                    atoms.push(atom?.atomic_type_matching(xs, cast_or_promote_atomic)?);
253                }
254                Ok(atoms.into())
255            }
256        }
257    }
258}
259
260impl Item {
261    pub(crate) fn non_atomic_item_type_matching(
262        self,
263        item_type: &ast::ItemType,
264        cast_or_promote_atomic: &impl Fn(atomic::Atomic, Xs) -> error::Result<atomic::Atomic>,
265        check_function: &impl Fn(&ast::FunctionTest, &Item) -> error::Result<()>,
266        xot: &Xot,
267    ) -> error::Result<()> {
268        match item_type {
269            ast::ItemType::Item => {}
270            ast::ItemType::AtomicOrUnionType(_) => {
271                unreachable!()
272            }
273            ast::ItemType::KindTest(kind_test) => {
274                self.kind_test_matching(kind_test, xot)?;
275            }
276            ast::ItemType::FunctionTest(function_test) => {
277                check_function(function_test, &self)?;
278            }
279            ast::ItemType::MapTest(map_test) => match map_test {
280                ast::MapTest::AnyMapTest => {
281                    if !self.is_map() {
282                        return Err(error::Error::XPTY0004);
283                    }
284                }
285                ast::MapTest::TypedMapTest(typed_map_test) => {
286                    let map = self.to_map()?;
287                    for (key, value) in map.entries() {
288                        key.clone().atomic_type_matching(
289                            typed_map_test.key_type,
290                            cast_or_promote_atomic,
291                        )?;
292                        value.clone().sequence_type_matching_convert(
293                            &typed_map_test.value_type,
294                            cast_or_promote_atomic,
295                            check_function,
296                            xot,
297                        )?;
298                    }
299                }
300            },
301            ast::ItemType::ArrayTest(array_test) => match array_test {
302                ast::ArrayTest::AnyArrayTest => {
303                    if !self.is_array() {
304                        return Err(error::Error::XPTY0004);
305                    }
306                }
307                ast::ArrayTest::TypedArrayTest(typed_array_test) => {
308                    let array = self.to_array()?;
309                    for sequence in array.iter() {
310                        sequence.clone().sequence_type_matching_convert(
311                            &typed_array_test.item_type,
312                            cast_or_promote_atomic,
313                            check_function,
314                            xot,
315                        )?;
316                    }
317                }
318            },
319        }
320        Ok(())
321    }
322
323    fn kind_test_matching(&self, kind_test: &ast::KindTest, xot: &Xot) -> error::Result<()> {
324        match self {
325            Item::Node(node) => {
326                if xml::kind_test(kind_test, xot, *node) {
327                    Ok(())
328                } else {
329                    Err(error::Error::XPTY0004)
330                }
331            }
332            Item::Atomic(_) => Err(error::Error::XPTY0004),
333            Item::Function(_) => Err(error::Error::XPTY0004),
334        }
335    }
336
337    pub(crate) fn function_arity_matching<'a>(
338        &self,
339        function_test: &ast::FunctionTest,
340        get_signature: &impl Fn(&function::Function) -> &'a function::Signature,
341    ) -> error::Result<()> {
342        match function_test {
343            ast::FunctionTest::AnyFunctionTest => {
344                self.to_function()?;
345                Ok(())
346            }
347            ast::FunctionTest::TypedFunctionTest(typed_function_test) => {
348                let function = self.to_function()?;
349                let signature = get_signature(&function);
350                if signature.arity() == typed_function_test.parameter_types.len() {
351                    Ok(())
352                } else {
353                    Err(error::Error::XPTY0004)
354                }
355            }
356        }
357    }
358
359    pub(crate) fn function_type_matching<'a>(
360        &self,
361        function_test: &ast::FunctionTest,
362        get_signature: &impl Fn(&function::Function) -> &'a function::Signature,
363    ) -> error::Result<()> {
364        match function_test {
365            ast::FunctionTest::AnyFunctionTest => {
366                self.to_function()?;
367                Ok(())
368            }
369            ast::FunctionTest::TypedFunctionTest(typed_function_test) => {
370                let function = self.to_function()?;
371                let signature = get_signature(&function);
372                if signature.arity() != typed_function_test.parameter_types.len() {
373                    return Err(error::Error::XPTY0004);
374                }
375                if Self::function_type_matching_helper(typed_function_test, signature) {
376                    Ok(())
377                } else {
378                    Err(error::Error::XPTY0004)
379                }
380            }
381        }
382    }
383
384    fn function_type_matching_helper(
385        function_test: &ast::TypedFunctionTest,
386        signature: &function::Signature,
387    ) -> bool {
388        let default_sequence_type = Self::default_sequence_type();
389        let function_return_type = signature.return_type().unwrap_or(&default_sequence_type);
390        // return type is covariant
391        if !function_return_type.subtype(&function_test.return_type) {
392            return false;
393        }
394
395        for (function_parameter, test_parameter) in signature
396            .parameter_types()
397            .iter()
398            .zip(&function_test.parameter_types)
399        {
400            let function_parameter = function_parameter
401                .as_ref()
402                .unwrap_or(&default_sequence_type);
403            // parameter is contravariant
404            if !test_parameter.subtype(function_parameter) {
405                return false;
406            }
407        }
408
409        true
410    }
411
412    fn default_sequence_type() -> ast::SequenceType {
413        ast::SequenceType::Item(ast::Item {
414            item_type: ast::ItemType::Item,
415            occurrence: ast::Occurrence::Many,
416        })
417    }
418}
419
420impl atomic::Atomic {
421    fn atomic_type_matching(
422        self,
423        xs: Xs,
424        cast_or_promote_atomic: &impl Fn(atomic::Atomic, Xs) -> error::Result<atomic::Atomic>,
425    ) -> error::Result<Self> {
426        let atom = cast_or_promote_atomic(self, xs)?;
427        let schema_type = atom.schema_type();
428        if schema_type.derives_from(xs) || schema_type.matches(xs) {
429            Ok(atom)
430        } else {
431            Err(error::Error::XPTY0004)
432        }
433    }
434}
435
436#[cfg(test)]
437mod tests {
438
439    use super::*;
440
441    use ibig::ibig;
442    use xee_name::Namespaces;
443    use xee_xpath_ast::parse_sequence_type;
444
445    #[test]
446    fn test_one_integer() {
447        let namespaces = Namespaces::default();
448        let sequence_type = parse_sequence_type("xs:integer", &namespaces).unwrap();
449
450        let right_sequence: Sequence = vec![ibig!(1)].into();
451        let wrong_amount_sequence: Sequence = vec![ibig!(1), ibig!(2)].into();
452        let wrong_type_sequence: Sequence = vec![false].into();
453        let xot = Xot::new();
454
455        let right_result = right_sequence.clone().sequence_type_matching(
456            &sequence_type,
457            &xot,
458            &|_| unreachable!(),
459        );
460        assert_eq!(&right_result.unwrap(), &right_sequence);
461
462        let wrong_amount_result =
463            wrong_amount_sequence.sequence_type_matching(&sequence_type, &xot, &|_| unreachable!());
464        assert_eq!(wrong_amount_result, Err(error::Error::XPTY0004));
465        let wrong_type_result =
466            wrong_type_sequence.sequence_type_matching(&sequence_type, &xot, &|_| unreachable!());
467        assert_eq!(wrong_type_result, Err(error::Error::XPTY0004));
468    }
469
470    #[test]
471    fn test_one_long_matches_integer() {
472        let namespaces = Namespaces::default();
473        let sequence_type = parse_sequence_type("xs:integer", &namespaces).unwrap();
474
475        let right_sequence = Sequence::from(vec![Item::from(1i64)]);
476        let wrong_amount_sequence = Sequence::from(vec![Item::from(1i64), Item::from(1i64)]);
477        let wrong_type_sequence = Sequence::from(vec![Item::from(atomic::Atomic::from(false))]);
478        let xot = Xot::new();
479
480        let right_result = right_sequence.clone().sequence_type_matching(
481            &sequence_type,
482            &xot,
483            &|_| unreachable!(),
484        );
485        assert_eq!(right_result, Ok(right_sequence));
486        let wrong_amount_result =
487            wrong_amount_sequence.sequence_type_matching(&sequence_type, &xot, &|_| unreachable!());
488        assert_eq!(wrong_amount_result, Err(error::Error::XPTY0004));
489        let wrong_type_result =
490            wrong_type_sequence.sequence_type_matching(&sequence_type, &xot, &|_| unreachable!());
491        assert_eq!(wrong_type_result, Err(error::Error::XPTY0004));
492    }
493
494    #[test]
495    fn test_one_any_atomic() {
496        let namespaces = Namespaces::default();
497        let sequence_type = parse_sequence_type("xs:anyAtomicType", &namespaces).unwrap();
498
499        let right_sequence = Sequence::from(vec![Item::from(atomic::Atomic::from(1i64))]);
500        let wrong_amount_sequence =
501            Sequence::from(vec![Item::from(ibig!(1)), Item::from(ibig!(2))]);
502        let right_type_sequence2 = Sequence::from(vec![Item::from(atomic::Atomic::from(false))]);
503        let xot = Xot::new();
504
505        let right_result = right_sequence.clone().sequence_type_matching(
506            &sequence_type,
507            &xot,
508            &|_| unreachable!(),
509        );
510        assert_eq!(right_result, Ok(right_sequence));
511        let wrong_amount_result =
512            wrong_amount_sequence.sequence_type_matching(&sequence_type, &xot, &|_| unreachable!());
513        assert_eq!(wrong_amount_result, Err(error::Error::XPTY0004));
514        let right_type_result2 = right_type_sequence2.clone().sequence_type_matching(
515            &sequence_type,
516            &xot,
517            &|_| unreachable!(),
518        );
519        assert_eq!(right_type_result2, Ok(right_type_sequence2));
520    }
521
522    #[test]
523    fn test_one_item() {
524        let namespaces = Namespaces::default();
525        let sequence_type = parse_sequence_type("item()", &namespaces).unwrap();
526        let mut xot = Xot::new();
527        let root = xot.parse("<doc/>").unwrap();
528        let node = xot.document_element(root).unwrap();
529        let right_sequence = Sequence::from(vec![Item::from(atomic::Atomic::from(1i64))]);
530        let wrong_amount_sequence = Sequence::from(vec![
531            Item::from(atomic::Atomic::from(1i64)),
532            Item::from(atomic::Atomic::from(2i64)),
533        ]);
534        let right_type_sequence2 = Sequence::from(vec![Item::from(node)]);
535
536        let right_result = right_sequence.clone().sequence_type_matching(
537            &sequence_type,
538            &xot,
539            &|_| unreachable!(),
540        );
541        assert_eq!(right_result, Ok(right_sequence));
542
543        let wrong_amount_result =
544            wrong_amount_sequence.sequence_type_matching(&sequence_type, &xot, &|_| unreachable!());
545        assert_eq!(wrong_amount_result, Err(error::Error::XPTY0004));
546        let right_type_result2 = right_type_sequence2.clone().sequence_type_matching(
547            &sequence_type,
548            &xot,
549            &|_| unreachable!(),
550        );
551        assert_eq!(right_type_result2, Ok(right_type_sequence2));
552    }
553
554    #[test]
555    fn test_option_integer() {
556        let namespaces = Namespaces::default();
557        let sequence_type = parse_sequence_type("xs:integer?", &namespaces).unwrap();
558
559        let right_sequence = Sequence::from(vec![Item::from(atomic::Atomic::from(ibig!(1)))]);
560        let wrong_amount_sequence =
561            Sequence::from(vec![Item::from(ibig!(1)), Item::from(ibig!(2))]);
562        let right_empty_sequence = Sequence::default();
563        let xot = Xot::new();
564
565        let right_result = right_sequence.clone().sequence_type_matching(
566            &sequence_type,
567            &xot,
568            &|_| unreachable!(),
569        );
570        assert_eq!(right_result, Ok(right_sequence));
571        let wrong_amount_result =
572            wrong_amount_sequence.sequence_type_matching(&sequence_type, &xot, &|_| unreachable!());
573        assert_eq!(wrong_amount_result, Err(error::Error::XPTY0004));
574        let right_empty_result = right_empty_sequence.clone().sequence_type_matching(
575            &sequence_type,
576            &xot,
577            &|_| unreachable!(),
578        );
579        assert_eq!(right_empty_result, Ok(right_empty_sequence));
580    }
581
582    #[test]
583    fn test_many_integer() {
584        let namespaces = Namespaces::default();
585        let sequence_type = parse_sequence_type("xs:integer*", &namespaces).unwrap();
586
587        let right_sequence = Sequence::from(vec![Item::from(atomic::Atomic::from(ibig!(1)))]);
588        let right_multi_sequence = Sequence::from(vec![Item::from(ibig!(1)), Item::from(ibig!(2))]);
589        let right_empty_sequence = Sequence::default();
590        let xot = Xot::new();
591
592        let right_result = right_sequence.clone().sequence_type_matching(
593            &sequence_type,
594            &xot,
595            &|_| unreachable!(),
596        );
597        assert_eq!(right_result, Ok(right_sequence));
598
599        let right_multi_result = right_multi_sequence.clone().sequence_type_matching(
600            &sequence_type,
601            &xot,
602            &|_| unreachable!(),
603        );
604        assert_eq!(right_multi_result, Ok(right_multi_sequence));
605
606        let right_empty_result = right_empty_sequence.clone().sequence_type_matching(
607            &sequence_type,
608            &xot,
609            &|_| unreachable!(),
610        );
611        assert_eq!(right_empty_result, Ok(right_empty_sequence));
612    }
613
614    #[test]
615    fn test_many_node() {
616        let namespaces = Namespaces::default();
617        let sequence_type = parse_sequence_type("node()*", &namespaces).unwrap();
618
619        let mut xot = Xot::new();
620        let doc = xot.parse(r#"<doc><a attr="Attr">A</a><b/></doc>"#).unwrap();
621        let doc = xot.document_element(doc).unwrap();
622        let a = xot.first_child(doc).unwrap();
623        let b = xot.next_sibling(a).unwrap();
624        let text = xot.first_child(a).unwrap();
625        let attr = xot
626            .attributes(a)
627            .get_node(xot.name("attr").unwrap())
628            .unwrap();
629
630        let right_sequence = Sequence::from(vec![
631            Item::from(doc),
632            Item::from(a),
633            Item::from(b),
634            Item::from(text),
635            Item::from(attr),
636        ]);
637
638        let wrong_sequence = Sequence::from(vec![Item::from(ibig!(1))]);
639
640        let right_result = right_sequence.clone().sequence_type_matching(
641            &sequence_type,
642            &xot,
643            &|_| unreachable!(),
644        );
645        assert_eq!(right_result, Ok(right_sequence));
646
647        let wrong_result =
648            wrong_sequence.sequence_type_matching(&sequence_type, &xot, &|_| unreachable!());
649        assert_eq!(wrong_result, Err(error::Error::XPTY0004));
650    }
651
652    #[test]
653    fn test_many_element() {
654        let namespaces = Namespaces::default();
655        let sequence_type = parse_sequence_type("element()*", &namespaces).unwrap();
656
657        let mut xot = Xot::new();
658        let doc = xot.parse(r#"<doc><a attr="Attr">A</a><b/></doc>"#).unwrap();
659        let doc = xot.document_element(doc).unwrap();
660        let a = xot.first_child(doc).unwrap();
661        let b = xot.next_sibling(a).unwrap();
662        let text = xot.first_child(a).unwrap();
663        let attr = xot
664            .attributes(a)
665            .get_node(xot.name("attr").unwrap())
666            .unwrap();
667
668        let right_sequence = Sequence::from(vec![Item::from(doc), Item::from(a), Item::from(b)]);
669
670        let wrong_sequence_text = Sequence::from(vec![Item::from(text)]);
671        let wrong_sequence_attr = Sequence::from(vec![Item::from(attr)]);
672
673        let right_result = right_sequence.clone().sequence_type_matching(
674            &sequence_type,
675            &xot,
676            &|_| unreachable!(),
677        );
678        assert_eq!(right_result, Ok(right_sequence));
679
680        let wrong_result =
681            wrong_sequence_text.sequence_type_matching(&sequence_type, &xot, &|_| unreachable!());
682        assert_eq!(wrong_result, Err(error::Error::XPTY0004));
683        let wrong_result =
684            wrong_sequence_attr.sequence_type_matching(&sequence_type, &xot, &|_| unreachable!());
685        assert_eq!(wrong_result, Err(error::Error::XPTY0004));
686    }
687
688    #[test]
689    fn test_many_atomized_promote() {
690        let namespaces = Namespaces::default();
691        let sequence_type = parse_sequence_type("xs:double*", &namespaces).unwrap();
692
693        // integers count as decimals, so should be promoted to a double
694        let right_sequence = Sequence::from(vec![Item::from(ibig!(1)), Item::from(ibig!(2))]);
695
696        let static_context = context::StaticContext::default();
697        let xot = Xot::new();
698        let right_result = right_sequence.sequence_type_matching_function_conversion(
699            &sequence_type,
700            &static_context,
701            &xot,
702            &|_| unreachable!(),
703        );
704        // atomization has changed the result sequence
705        assert_eq!(
706            right_result,
707            Ok(Sequence::from(vec![
708                Item::from(atomic::Atomic::from(1f64)),
709                Item::from(atomic::Atomic::from(2f64)),
710            ]))
711        );
712    }
713
714    #[test]
715    fn test_many_cast_untyped() {
716        let namespaces = Namespaces::default();
717        let sequence_type = parse_sequence_type("xs:integer*", &namespaces).unwrap();
718
719        let mut xot = Xot::new();
720        let doc = xot.parse(r#"<doc><a>1</a><b>2</b></doc>"#).unwrap();
721        let doc = xot.document_element(doc).unwrap();
722        let a = xot.first_child(doc).unwrap();
723        let b = xot.next_sibling(a).unwrap();
724
725        let right_sequence = Sequence::from(vec![Item::from(a), Item::from(b)]);
726
727        let static_context = context::StaticContext::default();
728
729        let right_result = right_sequence.sequence_type_matching_function_conversion(
730            &sequence_type,
731            &static_context,
732            &xot,
733            &|_| unreachable!(),
734        );
735        // atomization has changed the result sequence
736        assert_eq!(
737            right_result,
738            Ok(Sequence::from(vec![
739                Item::from(atomic::Atomic::from(ibig!(1))),
740                Item::from(atomic::Atomic::from(ibig!(2))),
741            ]))
742        );
743    }
744
745    #[test]
746    fn test_any_function_test() {
747        let namespaces = Namespaces::default();
748        let sequence_type = parse_sequence_type("function(*)", &namespaces).unwrap();
749        let function =
750            function::StaticFunctionData::new(function::StaticFunctionId(1), vec![]).into();
751        let right_sequence = Sequence::from(vec![Item::Function(function)]);
752
753        let signature = function::Signature::new(
754            vec![Some(
755                parse_sequence_type("xs:integer", &namespaces).unwrap(),
756            )],
757            Some(parse_sequence_type("xs:integer", &namespaces).unwrap()),
758        );
759
760        let xot = Xot::new();
761
762        let right_result =
763            right_sequence
764                .clone()
765                .sequence_type_matching(&sequence_type, &xot, &|_| &signature);
766        assert_eq!(&right_result.unwrap(), &right_sequence);
767    }
768
769    #[test]
770    fn test_function_test_same_parameters() {
771        let namespaces = Namespaces::default();
772        let sequence_type =
773            parse_sequence_type("function(xs:integer) as xs:integer", &namespaces).unwrap();
774        let function =
775            function::StaticFunctionData::new(function::StaticFunctionId(1), vec![]).into();
776        let right_sequence = Sequence::from(vec![Item::Function(function)]);
777
778        let signature = function::Signature::new(
779            vec![Some(
780                parse_sequence_type("xs:integer", &namespaces).unwrap(),
781            )],
782            Some(parse_sequence_type("xs:integer", &namespaces).unwrap()),
783        );
784
785        let xot = Xot::new();
786
787        let right_result =
788            right_sequence
789                .clone()
790                .sequence_type_matching(&sequence_type, &xot, &|_| &signature);
791        assert_eq!(&right_result.unwrap(), &right_sequence);
792    }
793
794    #[test]
795    fn test_function_test_derived_parameters() {
796        let namespaces = Namespaces::default();
797        let sequence_type =
798            parse_sequence_type("function(xs:integer) as xs:integer", &namespaces).unwrap();
799        let function =
800            function::StaticFunctionData::new(function::StaticFunctionId(1), vec![]).into();
801        let right_sequence = Sequence::from(vec![Item::Function(function)]);
802
803        let signature = function::Signature::new(
804            vec![Some(
805                parse_sequence_type("xs:integer", &namespaces).unwrap(),
806            )],
807            Some(parse_sequence_type("xs:integer", &namespaces).unwrap()),
808        );
809
810        let xot = Xot::new();
811
812        let right_result =
813            right_sequence
814                .clone()
815                .sequence_type_matching(&sequence_type, &xot, &|_| &signature);
816        assert_eq!(&right_result.unwrap(), &right_sequence);
817    }
818
819    #[test]
820    fn test_function_test_wrong_arity() {
821        let namespaces = Namespaces::default();
822        let sequence_type =
823            parse_sequence_type("function(xs:integer) as xs:integer", &namespaces).unwrap();
824        let function =
825            function::StaticFunctionData::new(function::StaticFunctionId(1), vec![]).into();
826        let wrong_sequence = Sequence::from(vec![Item::Function(function)]);
827
828        let signature = function::Signature::new(
829            vec![
830                Some(parse_sequence_type("xs:integer", &namespaces).unwrap()),
831                Some(parse_sequence_type("xs:integer", &namespaces).unwrap()),
832            ],
833            Some(parse_sequence_type("xs:integer", &namespaces).unwrap()),
834        );
835
836        let xot = Xot::new();
837
838        let wrong_result =
839            wrong_sequence
840                .clone()
841                .sequence_type_matching(&sequence_type, &xot, &|_| &signature);
842        assert_eq!(wrong_result, Err(error::Error::XPTY0004));
843    }
844}