wdl_analysis/
stdlib.rs

1//! Representation of WDL standard library functions.
2
3use std::cell::Cell;
4use std::fmt;
5use std::fmt::Write;
6use std::sync::LazyLock;
7
8use indexmap::IndexMap;
9use indexmap::IndexSet;
10use wdl_ast::SupportedVersion;
11use wdl_ast::version::V1;
12
13use crate::types::ArrayType;
14use crate::types::Coercible;
15use crate::types::CompoundType;
16use crate::types::MapType;
17use crate::types::Optional;
18use crate::types::PairType;
19use crate::types::PrimitiveType;
20use crate::types::Type;
21
22mod constraints;
23
24pub use constraints::*;
25
26/// The maximum number of allowable type parameters in a function signature.
27///
28/// This is intentionally set low to limit the amount of space needed to store
29/// associated data.
30///
31/// Accessing `STDLIB` will panic if a signature is defined that exceeds this
32/// number.
33pub const MAX_TYPE_PARAMETERS: usize = 4;
34
35#[allow(clippy::missing_docs_in_private_items)]
36const _: () = assert!(
37    MAX_TYPE_PARAMETERS < usize::BITS as usize,
38    "the maximum number of type parameters cannot exceed the number of bits in usize"
39);
40
41/// The maximum (inclusive) number of parameters to any standard library
42/// function.
43///
44/// A function cannot be defined with more than this number of parameters and
45/// accessing `STDLIB` will panic if a signature is defined that exceeds this
46/// number.
47///
48/// As new standard library functions are implemented, the maximum will be
49/// increased.
50pub const MAX_PARAMETERS: usize = 4;
51
52/// A helper function for writing uninferred type parameter constraints to a
53/// given writer.
54fn write_uninferred_constraints(
55    s: &mut impl fmt::Write,
56    params: &TypeParameters<'_>,
57) -> Result<(), fmt::Error> {
58    for (i, (name, constraint)) in params
59        .referenced()
60        .filter_map(|(p, ty)| {
61            // Only consider uninferred type parameters that are constrained
62            if ty.is_some() {
63                return None;
64            }
65
66            Some((p.name, p.constraint()?))
67        })
68        .enumerate()
69    {
70        if i == 0 {
71            s.write_str(" where ")?;
72        } else if i > 1 {
73            s.write_str(", ")?;
74        }
75
76        write!(s, "`{name}`: {desc}", desc = constraint.description())?;
77    }
78
79    Ok(())
80}
81
82/// An error that may occur when binding arguments to a standard library
83/// function.
84#[derive(Debug, Clone, PartialEq, Eq)]
85pub enum FunctionBindError {
86    /// The function isn't supported for the specified version of WDL.
87    RequiresVersion(SupportedVersion),
88    /// There are too few arguments to bind the call.
89    ///
90    /// The value is the minimum number of arguments required.
91    TooFewArguments(usize),
92    /// There are too many arguments to bind the call.
93    ///
94    /// The value is the maximum number of arguments allowed.
95    TooManyArguments(usize),
96    /// An argument type was mismatched.
97    ArgumentTypeMismatch {
98        /// The index of the mismatched argument.
99        index: usize,
100        /// The expected type for the argument.
101        expected: String,
102    },
103    /// The function call arguments were ambiguous.
104    Ambiguous {
105        /// The first conflicting function signature.
106        first: String,
107        /// The second conflicting function signature.
108        second: String,
109    },
110}
111
112/// Represents a generic type to a standard library function.
113#[derive(Debug, Clone)]
114pub enum GenericType {
115    /// The type is a type parameter (e.g. `X`).
116    Parameter(&'static str),
117    /// The type is a type parameter, but unqualified; for example, if the type
118    /// parameter was bound to type `X?`, then the unqualified type would be
119    /// `X`.
120    UnqualifiedParameter(&'static str),
121    /// The type is a generic `Array`.
122    Array(GenericArrayType),
123    /// The type is a generic `Pair`.
124    Pair(GenericPairType),
125    /// The type is a generic `Map`.
126    Map(GenericMapType),
127}
128
129impl GenericType {
130    /// Returns an object that implements `Display` for formatting the type.
131    pub fn display<'a>(&'a self, params: &'a TypeParameters<'a>) -> impl fmt::Display + 'a {
132        #[allow(clippy::missing_docs_in_private_items)]
133        struct Display<'a> {
134            params: &'a TypeParameters<'a>,
135            ty: &'a GenericType,
136        }
137
138        impl fmt::Display for Display<'_> {
139            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140                match self.ty {
141                    GenericType::Parameter(name) | GenericType::UnqualifiedParameter(name) => {
142                        let (_, ty) = self.params.get(name).expect("the name should be present");
143                        match ty {
144                            Some(ty) => {
145                                if let GenericType::UnqualifiedParameter(_) = self.ty {
146                                    ty.require().fmt(f)
147                                } else {
148                                    ty.fmt(f)
149                                }
150                            }
151                            None => {
152                                write!(f, "{name}")
153                            }
154                        }
155                    }
156                    GenericType::Array(ty) => ty.display(self.params).fmt(f),
157                    GenericType::Pair(ty) => ty.display(self.params).fmt(f),
158                    GenericType::Map(ty) => ty.display(self.params).fmt(f),
159                }
160            }
161        }
162
163        Display { params, ty: self }
164    }
165
166    /// Infers any type parameters from the generic type.
167    fn infer_type_parameters(
168        &self,
169        ty: &Type,
170        params: &mut TypeParameters<'_>,
171        ignore_constraints: bool,
172    ) {
173        match self {
174            Self::Parameter(name) | Self::UnqualifiedParameter(name) => {
175                // Verify the type satisfies any constraint
176                let (param, _) = params.get(name).expect("should have parameter");
177
178                if !ignore_constraints {
179                    if let Some(constraint) = param.constraint() {
180                        if !constraint.satisfied(ty) {
181                            return;
182                        }
183                    }
184                }
185
186                params.set_inferred_type(name, ty.clone());
187            }
188            Self::Array(array) => array.infer_type_parameters(ty, params, ignore_constraints),
189            Self::Pair(pair) => pair.infer_type_parameters(ty, params, ignore_constraints),
190            Self::Map(map) => map.infer_type_parameters(ty, params, ignore_constraints),
191        }
192    }
193
194    /// Realizes the generic type.
195    fn realize(&self, params: &TypeParameters<'_>) -> Option<Type> {
196        match self {
197            Self::Parameter(name) => {
198                params
199                    .get(name)
200                    .expect("type parameter should be present")
201                    .1
202            }
203            Self::UnqualifiedParameter(name) => params
204                .get(name)
205                .expect("type parameter should be present")
206                .1
207                .map(|ty| ty.require()),
208            Self::Array(ty) => ty.realize(params),
209            Self::Pair(ty) => ty.realize(params),
210            Self::Map(ty) => ty.realize(params),
211        }
212    }
213
214    /// Asserts that the type parameters referenced by the type are valid.
215    ///
216    /// # Panics
217    ///
218    /// Panics if referenced type parameter is invalid.
219    fn assert_type_parameters(&self, parameters: &[TypeParameter]) {
220        match self {
221            Self::Parameter(n) | Self::UnqualifiedParameter(n) => assert!(
222                parameters.iter().any(|p| p.name == *n),
223                "generic type references unknown type parameter `{n}`"
224            ),
225            Self::Array(a) => a.assert_type_parameters(parameters),
226            Self::Pair(p) => p.assert_type_parameters(parameters),
227            Self::Map(m) => m.assert_type_parameters(parameters),
228        }
229    }
230}
231
232impl From<GenericArrayType> for GenericType {
233    fn from(value: GenericArrayType) -> Self {
234        Self::Array(value)
235    }
236}
237
238impl From<GenericPairType> for GenericType {
239    fn from(value: GenericPairType) -> Self {
240        Self::Pair(value)
241    }
242}
243
244impl From<GenericMapType> for GenericType {
245    fn from(value: GenericMapType) -> Self {
246        Self::Map(value)
247    }
248}
249
250/// Represents a generic `Array` type.
251#[derive(Debug, Clone)]
252pub struct GenericArrayType {
253    /// The array's element type.
254    element_type: Box<FunctionalType>,
255    /// Whether or not the array is non-empty.
256    non_empty: bool,
257}
258
259impl GenericArrayType {
260    /// Constructs a new generic array type.
261    pub fn new(element_type: impl Into<FunctionalType>) -> Self {
262        Self {
263            element_type: Box::new(element_type.into()),
264            non_empty: false,
265        }
266    }
267
268    /// Constructs a new non-empty generic array type.
269    pub fn non_empty(element_type: impl Into<FunctionalType>) -> Self {
270        Self {
271            element_type: Box::new(element_type.into()),
272            non_empty: true,
273        }
274    }
275
276    /// Gets the array's element type.
277    pub fn element_type(&self) -> &FunctionalType {
278        &self.element_type
279    }
280
281    /// Determines if the array type is non-empty.
282    pub fn is_non_empty(&self) -> bool {
283        self.non_empty
284    }
285
286    /// Returns an object that implements `Display` for formatting the type.
287    pub fn display<'a>(&'a self, params: &'a TypeParameters<'a>) -> impl fmt::Display + 'a {
288        #[allow(clippy::missing_docs_in_private_items)]
289        struct Display<'a> {
290            params: &'a TypeParameters<'a>,
291            ty: &'a GenericArrayType,
292        }
293
294        impl fmt::Display for Display<'_> {
295            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296                write!(f, "Array[")?;
297                self.ty.element_type.display(self.params).fmt(f)?;
298                write!(f, "]")?;
299
300                if self.ty.is_non_empty() {
301                    write!(f, "+")?;
302                }
303
304                Ok(())
305            }
306        }
307
308        Display { params, ty: self }
309    }
310
311    /// Infers any type parameters from the generic type.
312    fn infer_type_parameters(
313        &self,
314        ty: &Type,
315        params: &mut TypeParameters<'_>,
316        ignore_constraints: bool,
317    ) {
318        match ty {
319            Type::Union => {
320                self.element_type
321                    .infer_type_parameters(&Type::Union, params, ignore_constraints);
322            }
323            Type::Compound(CompoundType::Array(ty), false) => {
324                self.element_type.infer_type_parameters(
325                    ty.element_type(),
326                    params,
327                    ignore_constraints,
328                );
329            }
330            _ => {}
331        }
332    }
333
334    /// Realizes the generic type to an `Array`.
335    fn realize(&self, params: &TypeParameters<'_>) -> Option<Type> {
336        let ty = self.element_type.realize(params)?;
337        if self.non_empty {
338            Some(ArrayType::non_empty(ty).into())
339        } else {
340            Some(ArrayType::new(ty).into())
341        }
342    }
343
344    /// Asserts that the type parameters referenced by the type are valid.
345    ///
346    /// # Panics
347    ///
348    /// Panics if referenced type parameter is invalid.
349    fn assert_type_parameters(&self, parameters: &[TypeParameter]) {
350        self.element_type.assert_type_parameters(parameters);
351    }
352}
353
354/// Represents a generic `Pair` type.
355#[derive(Debug, Clone)]
356pub struct GenericPairType {
357    /// The type of the left element of the pair.
358    left_type: Box<FunctionalType>,
359    /// The type of the right element of the pair.
360    right_type: Box<FunctionalType>,
361}
362
363impl GenericPairType {
364    /// Constructs a new generic pair type.
365    pub fn new(
366        left_type: impl Into<FunctionalType>,
367        right_type: impl Into<FunctionalType>,
368    ) -> Self {
369        Self {
370            left_type: Box::new(left_type.into()),
371            right_type: Box::new(right_type.into()),
372        }
373    }
374
375    /// Gets the pairs's left type.
376    pub fn left_type(&self) -> &FunctionalType {
377        &self.left_type
378    }
379
380    /// Gets the pairs's right type.
381    pub fn right_type(&self) -> &FunctionalType {
382        &self.right_type
383    }
384
385    /// Returns an object that implements `Display` for formatting the type.
386    pub fn display<'a>(&'a self, params: &'a TypeParameters<'a>) -> impl fmt::Display + 'a {
387        #[allow(clippy::missing_docs_in_private_items)]
388        struct Display<'a> {
389            params: &'a TypeParameters<'a>,
390            ty: &'a GenericPairType,
391        }
392
393        impl fmt::Display for Display<'_> {
394            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395                write!(f, "Pair[")?;
396                self.ty.left_type.display(self.params).fmt(f)?;
397                write!(f, ", ")?;
398                self.ty.right_type.display(self.params).fmt(f)?;
399                write!(f, "]")
400            }
401        }
402
403        Display { params, ty: self }
404    }
405
406    /// Infers any type parameters from the generic type.
407    fn infer_type_parameters(
408        &self,
409        ty: &Type,
410        params: &mut TypeParameters<'_>,
411        ignore_constraints: bool,
412    ) {
413        match ty {
414            Type::Union => {
415                self.left_type
416                    .infer_type_parameters(&Type::Union, params, ignore_constraints);
417                self.right_type
418                    .infer_type_parameters(&Type::Union, params, ignore_constraints);
419            }
420            Type::Compound(CompoundType::Pair(ty), false) => {
421                self.left_type
422                    .infer_type_parameters(ty.left_type(), params, ignore_constraints);
423                self.right_type
424                    .infer_type_parameters(ty.right_type(), params, ignore_constraints);
425            }
426            _ => {}
427        }
428    }
429
430    /// Realizes the generic type to a `Pair`.
431    fn realize(&self, params: &TypeParameters<'_>) -> Option<Type> {
432        let left_type = self.left_type.realize(params)?;
433        let right_type = self.right_type.realize(params)?;
434        Some(PairType::new(left_type, right_type).into())
435    }
436
437    /// Asserts that the type parameters referenced by the type are valid.
438    ///
439    /// # Panics
440    ///
441    /// Panics if referenced type parameter is invalid.
442    fn assert_type_parameters(&self, parameters: &[TypeParameter]) {
443        self.left_type.assert_type_parameters(parameters);
444        self.right_type.assert_type_parameters(parameters);
445    }
446}
447
448/// Represents a generic `Map` type.
449#[derive(Debug, Clone)]
450pub struct GenericMapType {
451    /// The key type of the map.
452    key_type: Box<FunctionalType>,
453    /// The value type of the map.
454    value_type: Box<FunctionalType>,
455}
456
457impl GenericMapType {
458    /// Constructs a new generic map type.
459    pub fn new(key_type: impl Into<FunctionalType>, value_type: impl Into<FunctionalType>) -> Self {
460        Self {
461            key_type: Box::new(key_type.into()),
462            value_type: Box::new(value_type.into()),
463        }
464    }
465
466    /// Gets the maps's key type.
467    pub fn key_type(&self) -> &FunctionalType {
468        &self.key_type
469    }
470
471    /// Gets the maps's value type.
472    pub fn value_type(&self) -> &FunctionalType {
473        &self.value_type
474    }
475
476    /// Returns an object that implements `Display` for formatting the type.
477    pub fn display<'a>(&'a self, params: &'a TypeParameters<'a>) -> impl fmt::Display + 'a {
478        #[allow(clippy::missing_docs_in_private_items)]
479        struct Display<'a> {
480            params: &'a TypeParameters<'a>,
481            ty: &'a GenericMapType,
482        }
483
484        impl fmt::Display for Display<'_> {
485            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
486                write!(f, "Map[")?;
487                self.ty.key_type.display(self.params).fmt(f)?;
488                write!(f, ", ")?;
489                self.ty.value_type.display(self.params).fmt(f)?;
490                write!(f, "]")
491            }
492        }
493
494        Display { params, ty: self }
495    }
496
497    /// Infers any type parameters from the generic type.
498    fn infer_type_parameters(
499        &self,
500        ty: &Type,
501        params: &mut TypeParameters<'_>,
502        ignore_constraints: bool,
503    ) {
504        match ty {
505            Type::Union => {
506                self.key_type
507                    .infer_type_parameters(&Type::Union, params, ignore_constraints);
508                self.value_type
509                    .infer_type_parameters(&Type::Union, params, ignore_constraints);
510            }
511            Type::Compound(CompoundType::Map(ty), false) => {
512                self.key_type
513                    .infer_type_parameters(ty.key_type(), params, ignore_constraints);
514                self.value_type
515                    .infer_type_parameters(ty.value_type(), params, ignore_constraints);
516            }
517            _ => {}
518        }
519    }
520
521    /// Realizes the generic type to a `Map`.
522    fn realize(&self, params: &TypeParameters<'_>) -> Option<Type> {
523        let key_type = self.key_type.realize(params)?;
524        let value_type = self.value_type.realize(params)?;
525        Some(MapType::new(key_type, value_type).into())
526    }
527
528    /// Asserts that the type parameters referenced by the type are valid.
529    ///
530    /// # Panics
531    ///
532    /// Panics if referenced type parameter is invalid.
533    fn assert_type_parameters(&self, parameters: &[TypeParameter]) {
534        self.key_type.assert_type_parameters(parameters);
535        self.value_type.assert_type_parameters(parameters);
536    }
537}
538
539/// Represents a collection of type parameters.
540#[derive(Debug, Clone)]
541pub struct TypeParameters<'a> {
542    /// The collection of type parameters.
543    parameters: &'a [TypeParameter],
544    /// The inferred types for the type parameters.
545    inferred_types: [Option<Type>; MAX_TYPE_PARAMETERS],
546    /// A bitset of type parameters that have been referenced since the last
547    /// call to `reset`.
548    referenced: Cell<usize>,
549}
550
551impl<'a> TypeParameters<'a> {
552    /// Constructs a new type parameters collection using `None` as the
553    /// calculated parameter types.
554    ///
555    /// # Panics
556    ///
557    /// Panics if the count of the given type parameters exceeds the maximum
558    /// allowed.
559    pub fn new(parameters: &'a [TypeParameter]) -> Self {
560        assert!(
561            parameters.len() < MAX_TYPE_PARAMETERS,
562            "no more than {MAX_TYPE_PARAMETERS} type parameters is supported"
563        );
564
565        Self {
566            parameters,
567            inferred_types: [const { None }; MAX_TYPE_PARAMETERS],
568            referenced: Cell::new(0),
569        }
570    }
571
572    /// Gets a type parameter and its inferred type from the collection.
573    ///
574    /// Returns `None` if the name is not a type parameter.
575    ///
576    /// This method also marks the type parameter as referenced.
577    pub fn get(&self, name: &str) -> Option<(&TypeParameter, Option<Type>)> {
578        let index = self.parameters.iter().position(|p| p.name == name)?;
579
580        // Mark the parameter as referenced
581        self.referenced.set(self.referenced.get() | (1 << index));
582
583        Some((&self.parameters[index], self.inferred_types[index].clone()))
584    }
585
586    /// Reset any referenced type parameters.
587    pub fn reset(&self) {
588        self.referenced.set(0);
589    }
590
591    /// Gets an iterator of the type parameters that have been referenced since
592    /// the last reset.
593    pub fn referenced(&self) -> impl Iterator<Item = (&TypeParameter, Option<Type>)> + use<'_> {
594        let mut bits = self.referenced.get();
595        std::iter::from_fn(move || {
596            if bits == 0 {
597                return None;
598            }
599
600            let index = bits.trailing_zeros() as usize;
601            let parameter = &self.parameters[index];
602            let ty = self.inferred_types[index].clone();
603            bits ^= bits & bits.overflowing_neg().0;
604            Some((parameter, ty))
605        })
606    }
607
608    /// Sets the inferred type of a type parameter.
609    ///
610    /// Note that a type parameter can only be inferred once; subsequent
611    /// attempts to set the inferred type will be ignored.
612    ///
613    /// # Panics
614    ///
615    /// Panics if the given name is not a type parameter.
616    fn set_inferred_type(&mut self, name: &str, ty: Type) {
617        let index = self
618            .parameters
619            .iter()
620            .position(|p| p.name == name)
621            .unwrap_or_else(|| panic!("unknown type parameter `{name}`"));
622
623        self.inferred_types[index].get_or_insert(ty);
624    }
625}
626
627/// Represents a type of a function parameter or return.
628#[derive(Debug, Clone)]
629pub enum FunctionalType {
630    /// The parameter type is a concrete WDL type.
631    Concrete(Type),
632    /// The parameter type is a generic type.
633    Generic(GenericType),
634}
635
636impl FunctionalType {
637    /// Determines if the type is generic.
638    pub fn is_generic(&self) -> bool {
639        matches!(self, Self::Generic(_))
640    }
641
642    /// Returns the concrete type.
643    ///
644    /// Returns `None` if the type is not concrete.
645    pub fn concrete_type(&self) -> Option<&Type> {
646        match self {
647            Self::Concrete(ty) => Some(ty),
648            Self::Generic(_) => None,
649        }
650    }
651
652    /// Returns an object that implements `Display` for formatting the type.
653    pub fn display<'a>(&'a self, params: &'a TypeParameters<'a>) -> impl fmt::Display + 'a {
654        #[allow(clippy::missing_docs_in_private_items)]
655        struct Display<'a> {
656            params: &'a TypeParameters<'a>,
657            ty: &'a FunctionalType,
658        }
659
660        impl fmt::Display for Display<'_> {
661            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
662                match self.ty {
663                    FunctionalType::Concrete(ty) => ty.fmt(f),
664                    FunctionalType::Generic(ty) => ty.display(self.params).fmt(f),
665                }
666            }
667        }
668
669        Display { params, ty: self }
670    }
671
672    /// Infers any type parameters if the type is generic.
673    fn infer_type_parameters(
674        &self,
675        ty: &Type,
676        params: &mut TypeParameters<'_>,
677        ignore_constraints: bool,
678    ) {
679        if let Self::Generic(generic) = self {
680            generic.infer_type_parameters(ty, params, ignore_constraints);
681        }
682    }
683
684    /// Realizes the type if the type is generic.
685    fn realize(&self, params: &TypeParameters<'_>) -> Option<Type> {
686        match self {
687            FunctionalType::Concrete(ty) => Some(ty.clone()),
688            FunctionalType::Generic(ty) => ty.realize(params),
689        }
690    }
691
692    /// Asserts that the type parameters referenced by the type are valid.
693    ///
694    /// # Panics
695    ///
696    /// Panics if referenced type parameter is invalid.
697    fn assert_type_parameters(&self, parameters: &[TypeParameter]) {
698        if let FunctionalType::Generic(ty) = self {
699            ty.assert_type_parameters(parameters)
700        }
701    }
702}
703
704impl From<Type> for FunctionalType {
705    fn from(value: Type) -> Self {
706        Self::Concrete(value)
707    }
708}
709
710impl From<PrimitiveType> for FunctionalType {
711    fn from(value: PrimitiveType) -> Self {
712        Self::Concrete(value.into())
713    }
714}
715
716impl From<GenericType> for FunctionalType {
717    fn from(value: GenericType) -> Self {
718        Self::Generic(value)
719    }
720}
721
722impl From<GenericArrayType> for FunctionalType {
723    fn from(value: GenericArrayType) -> Self {
724        Self::Generic(GenericType::Array(value))
725    }
726}
727
728impl From<GenericPairType> for FunctionalType {
729    fn from(value: GenericPairType) -> Self {
730        Self::Generic(GenericType::Pair(value))
731    }
732}
733
734impl From<GenericMapType> for FunctionalType {
735    fn from(value: GenericMapType) -> Self {
736        Self::Generic(GenericType::Map(value))
737    }
738}
739
740/// Represents a type parameter to a function.
741#[derive(Debug)]
742pub struct TypeParameter {
743    /// The name of the type parameter.
744    name: &'static str,
745    /// The type parameter constraint.
746    constraint: Option<Box<dyn Constraint>>,
747}
748
749impl TypeParameter {
750    /// Creates a new type parameter without a constraint.
751    pub fn any(name: &'static str) -> Self {
752        Self {
753            name,
754            constraint: None,
755        }
756    }
757
758    /// Creates a new type parameter with the given constraint.
759    pub fn new(name: &'static str, constraint: impl Constraint + 'static) -> Self {
760        Self {
761            name,
762            constraint: Some(Box::new(constraint)),
763        }
764    }
765
766    /// Gets the name of the type parameter.
767    pub fn name(&self) -> &str {
768        self.name
769    }
770
771    /// Gets the constraint of the type parameter.
772    pub fn constraint(&self) -> Option<&dyn Constraint> {
773        self.constraint.as_deref()
774    }
775}
776
777/// Represents the kind of binding for arguments to a function.
778#[derive(Debug, Clone)]
779enum BindingKind {
780    /// The binding was an equivalence binding, meaning all of the provided
781    /// arguments had type equivalence with corresponding concrete parameters.
782    ///
783    /// The value is the bound return type of the function.
784    Equivalence(Type),
785    /// The binding was a coercion binding, meaning at least one of the provided
786    /// arguments needed to be coerced.
787    ///
788    /// The value it the bound return type of the function.
789    Coercion(Type),
790}
791
792impl BindingKind {
793    /// Gets the binding's return type.
794    pub fn ret(&self) -> &Type {
795        match self {
796            Self::Equivalence(ty) | Self::Coercion(ty) => ty,
797        }
798    }
799}
800
801/// Represents a WDL function signature.
802#[derive(Debug)]
803pub struct FunctionSignature {
804    /// The minimum required version for the function signature.
805    minimum_version: Option<SupportedVersion>,
806    /// The generic type parameters of the function.
807    type_parameters: Vec<TypeParameter>,
808    /// The number of required parameters of the function.
809    required: Option<usize>,
810    /// The parameter types of the function.
811    parameters: Vec<FunctionalType>,
812    /// The return type of the function.
813    ret: FunctionalType,
814}
815
816impl FunctionSignature {
817    /// Builds a function signature builder.
818    pub fn builder() -> FunctionSignatureBuilder {
819        FunctionSignatureBuilder::new()
820    }
821
822    /// Gets the minimum version required to call this function signature.
823    pub fn minimum_version(&self) -> SupportedVersion {
824        self.minimum_version
825            .unwrap_or(SupportedVersion::V1(V1::Zero))
826    }
827
828    /// Gets the function's type parameters.
829    pub fn type_parameters(&self) -> &[TypeParameter] {
830        &self.type_parameters
831    }
832
833    /// Gets the types of the function's parameters.
834    pub fn parameters(&self) -> &[FunctionalType] {
835        &self.parameters
836    }
837
838    /// Gets the minimum number of required parameters.
839    ///
840    /// For a function without optional parameters, this will be the same as the
841    /// number of parameters for the function.
842    pub fn required(&self) -> usize {
843        self.required.unwrap_or(self.parameters.len())
844    }
845
846    /// Gets the function's return type.
847    pub fn ret(&self) -> &FunctionalType {
848        &self.ret
849    }
850
851    /// Determines if the function signature is generic.
852    pub fn is_generic(&self) -> bool {
853        self.generic_parameter_count() > 0 || self.ret.is_generic()
854    }
855
856    /// Gets the count of generic parameters for the function.
857    pub fn generic_parameter_count(&self) -> usize {
858        self.parameters.iter().filter(|p| p.is_generic()).count()
859    }
860
861    /// Returns an object that implements `Display` for formatting the signature
862    /// with the given function name.
863    pub fn display<'a>(&'a self, params: &'a TypeParameters<'a>) -> impl fmt::Display + 'a {
864        #[allow(clippy::missing_docs_in_private_items)]
865        struct Display<'a> {
866            params: &'a TypeParameters<'a>,
867            sig: &'a FunctionSignature,
868        }
869
870        impl fmt::Display for Display<'_> {
871            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
872                f.write_char('(')?;
873
874                self.params.reset();
875                let required = self.sig.required();
876                for (i, parameter) in self.sig.parameters.iter().enumerate() {
877                    if i > 0 {
878                        f.write_str(", ")?;
879                    }
880
881                    if i >= required {
882                        f.write_char('<')?;
883                    }
884
885                    write!(f, "{param}", param = parameter.display(self.params))?;
886
887                    if i >= required {
888                        f.write_char('>')?;
889                    }
890                }
891
892                write!(f, ") -> {ret}", ret = self.sig.ret.display(self.params))?;
893                write_uninferred_constraints(f, self.params)?;
894
895                Ok(())
896            }
897        }
898
899        Display { params, sig: self }
900    }
901
902    /// Infers the concrete types of any type parameters for the function
903    /// signature.
904    ///
905    /// Returns the collection of type parameters.
906    fn infer_type_parameters(
907        &self,
908        arguments: &[Type],
909        ignore_constraints: bool,
910    ) -> TypeParameters<'_> {
911        let mut parameters = TypeParameters::new(&self.type_parameters);
912        for (parameter, argument) in self.parameters.iter().zip(arguments.iter()) {
913            parameter.infer_type_parameters(argument, &mut parameters, ignore_constraints);
914        }
915
916        parameters
917    }
918
919    /// Determines if the there is an insufficient number of arguments to bind
920    /// to this signature.
921    fn insufficient_arguments(&self, arguments: &[Type]) -> bool {
922        arguments.len() < self.required() || arguments.len() > self.parameters.len()
923    }
924
925    /// Binds the function signature to the given arguments.
926    ///
927    /// This function will infer the type parameters for the arguments and
928    /// ensure that the argument types are equivalent to the parameter types.
929    ///
930    /// If an argument is not type equivalent, an attempt is made to coerce the
931    /// type.
932    ///
933    /// Returns the realized type of the function's return type.
934    fn bind(
935        &self,
936        version: SupportedVersion,
937        arguments: &[Type],
938    ) -> Result<BindingKind, FunctionBindError> {
939        if version < self.minimum_version() {
940            return Err(FunctionBindError::RequiresVersion(self.minimum_version()));
941        }
942
943        let required = self.required();
944        if arguments.len() < required {
945            return Err(FunctionBindError::TooFewArguments(required));
946        }
947
948        if arguments.len() > self.parameters.len() {
949            return Err(FunctionBindError::TooManyArguments(self.parameters.len()));
950        }
951
952        // Ensure the argument types are correct for the function
953        let mut coerced = false;
954        let type_parameters = self.infer_type_parameters(arguments, false);
955        for (i, (parameter, argument)) in self.parameters.iter().zip(arguments.iter()).enumerate() {
956            match parameter.realize(&type_parameters) {
957                Some(ty) => {
958                    // If a coercion hasn't occurred yet, check for type equivalence
959                    // For the purpose of this check, also accept equivalence of `T` if the
960                    // parameter type is `T?`; otherwise, fall back to coercion
961                    if !coerced && argument != &ty && argument != &ty.require() {
962                        coerced = true;
963                    }
964
965                    if coerced && !argument.is_coercible_to(&ty) {
966                        return Err(FunctionBindError::ArgumentTypeMismatch {
967                            index: i,
968                            expected: format!("`{ty}`"),
969                        });
970                    }
971                }
972                None if argument.is_union() => {
973                    // If the type is `Union`, accept it as indeterminate
974                    continue;
975                }
976                None => {
977                    // Otherwise, this is a type mismatch
978                    type_parameters.reset();
979
980                    let mut expected = String::new();
981
982                    write!(
983                        &mut expected,
984                        "`{param}`",
985                        param = parameter.display(&type_parameters)
986                    )
987                    .unwrap();
988
989                    write_uninferred_constraints(&mut expected, &type_parameters).unwrap();
990                    return Err(FunctionBindError::ArgumentTypeMismatch { index: i, expected });
991                }
992            }
993        }
994
995        // Finally, realize the return type; if it fails to realize, it means there was
996        // at least one uninferred type parameter; we return `Union` instead to indicate
997        // that the return value is indeterminate.
998        let ret = self.ret().realize(&type_parameters).unwrap_or(Type::Union);
999
1000        if coerced {
1001            Ok(BindingKind::Coercion(ret))
1002        } else {
1003            Ok(BindingKind::Equivalence(ret))
1004        }
1005    }
1006}
1007
1008impl Default for FunctionSignature {
1009    fn default() -> Self {
1010        Self {
1011            minimum_version: None,
1012            type_parameters: Default::default(),
1013            required: Default::default(),
1014            parameters: Default::default(),
1015            ret: FunctionalType::Concrete(Type::Union),
1016        }
1017    }
1018}
1019
1020/// Represents a function signature builder.
1021#[derive(Debug, Default)]
1022pub struct FunctionSignatureBuilder(FunctionSignature);
1023
1024impl FunctionSignatureBuilder {
1025    /// Constructs a new function signature builder.
1026    pub fn new() -> Self {
1027        Self(Default::default())
1028    }
1029
1030    /// Sets the minimum required version for the function signature.
1031    pub fn min_version(mut self, version: SupportedVersion) -> Self {
1032        self.0.minimum_version = Some(version);
1033        self
1034    }
1035
1036    /// Adds a constrained type parameter to the function signature.
1037    pub fn type_parameter(
1038        mut self,
1039        name: &'static str,
1040        constraint: impl Constraint + 'static,
1041    ) -> Self {
1042        self.0
1043            .type_parameters
1044            .push(TypeParameter::new(name, constraint));
1045        self
1046    }
1047
1048    /// Adds an unconstrained type parameter to the function signature.
1049    pub fn any_type_parameter(mut self, name: &'static str) -> Self {
1050        self.0.type_parameters.push(TypeParameter::any(name));
1051        self
1052    }
1053
1054    /// Adds a parameter to the function signature.
1055    pub fn parameter(mut self, ty: impl Into<FunctionalType>) -> Self {
1056        self.0.parameters.push(ty.into());
1057        self
1058    }
1059
1060    /// Sets the return value in the function signature.
1061    ///
1062    /// If this is not called, the function signature will return a `Union`
1063    /// type.
1064    pub fn ret(mut self, ret: impl Into<FunctionalType>) -> Self {
1065        self.0.ret = ret.into();
1066        self
1067    }
1068
1069    /// Sets the number of required parameters in the function signature.
1070    pub fn required(mut self, required: usize) -> Self {
1071        self.0.required = Some(required);
1072        self
1073    }
1074
1075    /// Consumes the builder and produces the function signature.
1076    ///
1077    /// # Panics
1078    ///
1079    /// This method panics if the function signature is invalid.
1080    pub fn build(self) -> FunctionSignature {
1081        let sig = self.0;
1082
1083        // Ensure the number of required parameters doesn't exceed the number of
1084        // parameters
1085        if let Some(required) = sig.required {
1086            if required > sig.parameters.len() {
1087                panic!("number of required parameters exceeds the number of parameters");
1088            }
1089        }
1090
1091        assert!(
1092            sig.type_parameters.len() <= MAX_TYPE_PARAMETERS,
1093            "too many type parameters"
1094        );
1095
1096        assert!(
1097            sig.parameters.len() <= MAX_PARAMETERS,
1098            "too many parameters"
1099        );
1100
1101        // Ensure any generic type parameters indexes are in range for the parameters
1102        for param in sig.parameters.iter() {
1103            param.assert_type_parameters(&sig.type_parameters)
1104        }
1105
1106        sig.ret().assert_type_parameters(&sig.type_parameters);
1107
1108        sig
1109    }
1110}
1111
1112/// Represents information relating to how a function binds to its arguments.
1113#[derive(Debug, Clone)]
1114pub struct Binding<'a> {
1115    /// The calculated return type from the function given the argument types.
1116    return_type: Type,
1117    /// The function overload index.
1118    ///
1119    /// For monomorphic functions, this will always be zero.
1120    index: usize,
1121    /// The signature that was bound.
1122    signature: &'a FunctionSignature,
1123}
1124
1125impl Binding<'_> {
1126    /// Gets the calculated return type of the bound function.
1127    pub fn return_type(&self) -> &Type {
1128        &self.return_type
1129    }
1130
1131    /// Gets the overload index.
1132    ///
1133    /// For monomorphic functions, this will always be zero.
1134    pub fn index(&self) -> usize {
1135        self.index
1136    }
1137
1138    /// Gets the signature that was bound.
1139    pub fn signature(&self) -> &FunctionSignature {
1140        self.signature
1141    }
1142}
1143
1144/// Represents a WDL function.
1145#[derive(Debug)]
1146pub enum Function {
1147    /// The function is monomorphic.
1148    Monomorphic(MonomorphicFunction),
1149    /// The function is polymorphic.
1150    Polymorphic(PolymorphicFunction),
1151}
1152
1153impl Function {
1154    /// Gets the minimum WDL version required to call this function.
1155    pub fn minimum_version(&self) -> SupportedVersion {
1156        match self {
1157            Self::Monomorphic(f) => f.minimum_version(),
1158            Self::Polymorphic(f) => f.minimum_version(),
1159        }
1160    }
1161
1162    /// Gets the minimum and maximum number of parameters the function has for
1163    /// the given WDL version.
1164    ///
1165    /// Returns `None` if the function is not supported for the given version.
1166    pub fn param_min_max(&self, version: SupportedVersion) -> Option<(usize, usize)> {
1167        match self {
1168            Self::Monomorphic(f) => f.param_min_max(version),
1169            Self::Polymorphic(f) => f.param_min_max(version),
1170        }
1171    }
1172
1173    /// Binds the function to the given arguments.
1174    pub fn bind<'a>(
1175        &'a self,
1176        version: SupportedVersion,
1177        arguments: &[Type],
1178    ) -> Result<Binding<'a>, FunctionBindError> {
1179        match self {
1180            Self::Monomorphic(f) => f.bind(version, arguments),
1181            Self::Polymorphic(f) => f.bind(version, arguments),
1182        }
1183    }
1184
1185    /// Realizes the return type of the function without constraints.
1186    ///
1187    /// This is typically called after a failure to bind a function so that the
1188    /// return type can be calculated despite the failure.
1189    ///
1190    /// As such, it attempts to realize any type parameters without constraints,
1191    /// as an unsatisfied constraint likely caused the bind failure.
1192    pub fn realize_unconstrained_return_type(&self, arguments: &[Type]) -> Type {
1193        match self {
1194            Self::Monomorphic(f) => {
1195                let type_parameters = f.signature.infer_type_parameters(arguments, true);
1196                f.signature
1197                    .ret()
1198                    .realize(&type_parameters)
1199                    .unwrap_or(Type::Union)
1200            }
1201            Self::Polymorphic(f) => {
1202                let mut ty = None;
1203
1204                // For polymorphic functions, the calculated return type must be the same for
1205                // each overload
1206                for signature in &f.signatures {
1207                    let type_parameters = signature.infer_type_parameters(arguments, true);
1208                    let ret_ty = signature
1209                        .ret()
1210                        .realize(&type_parameters)
1211                        .unwrap_or(Type::Union);
1212
1213                    if ty.get_or_insert(ret_ty.clone()) != &ret_ty {
1214                        return Type::Union;
1215                    }
1216                }
1217
1218                ty.unwrap_or(Type::Union)
1219            }
1220        }
1221    }
1222}
1223
1224/// Represents a monomorphic function.
1225///
1226/// In this context, a monomorphic function has only a single type (i.e.
1227/// signature).
1228#[derive(Debug)]
1229pub struct MonomorphicFunction {
1230    /// The signature of the function.
1231    signature: FunctionSignature,
1232}
1233
1234impl MonomorphicFunction {
1235    /// Constructs a new monomorphic function.
1236    pub fn new(signature: FunctionSignature) -> Self {
1237        Self { signature }
1238    }
1239
1240    /// Gets the minimum WDL version required to call this function.
1241    pub fn minimum_version(&self) -> SupportedVersion {
1242        self.signature.minimum_version()
1243    }
1244
1245    /// Gets the minimum and maximum number of parameters the function has for
1246    /// the given WDL version.
1247    ///
1248    /// Returns `None` if the function is not supported for the given version.
1249    pub fn param_min_max(&self, version: SupportedVersion) -> Option<(usize, usize)> {
1250        if version < self.signature.minimum_version() {
1251            return None;
1252        }
1253
1254        Some((self.signature.required(), self.signature.parameters.len()))
1255    }
1256
1257    /// Gets the signature of the function.
1258    pub fn signature(&self) -> &FunctionSignature {
1259        &self.signature
1260    }
1261
1262    /// Binds the function to the given arguments.
1263    pub fn bind<'a>(
1264        &'a self,
1265        version: SupportedVersion,
1266        arguments: &[Type],
1267    ) -> Result<Binding<'a>, FunctionBindError> {
1268        let return_type = self.signature.bind(version, arguments)?.ret().clone();
1269        Ok(Binding {
1270            return_type,
1271            index: 0,
1272            signature: &self.signature,
1273        })
1274    }
1275}
1276
1277impl From<MonomorphicFunction> for Function {
1278    fn from(value: MonomorphicFunction) -> Self {
1279        Self::Monomorphic(value)
1280    }
1281}
1282
1283/// Represents a polymorphic function.
1284///
1285/// In this context, a polymorphic function has more than one type (i.e.
1286/// signature); overload resolution is used to determine which signature binds
1287/// to the function call.
1288#[derive(Debug)]
1289pub struct PolymorphicFunction {
1290    /// The signatures of the function.
1291    signatures: Vec<FunctionSignature>,
1292}
1293
1294impl PolymorphicFunction {
1295    /// Constructs a new polymorphic function.
1296    ///
1297    /// # Panics
1298    ///
1299    /// Panics if the number of signatures is less than two.
1300    pub fn new(signatures: Vec<FunctionSignature>) -> Self {
1301        assert!(
1302            signatures.len() > 1,
1303            "a polymorphic function must have at least two signatures"
1304        );
1305
1306        Self { signatures }
1307    }
1308
1309    /// Gets the minimum WDL version required to call this function.
1310    pub fn minimum_version(&self) -> SupportedVersion {
1311        self.signatures
1312            .iter()
1313            .fold(None, |v: Option<SupportedVersion>, s| {
1314                Some(
1315                    v.map(|v| v.min(s.minimum_version()))
1316                        .unwrap_or_else(|| s.minimum_version()),
1317                )
1318            })
1319            .expect("there should be at least one signature")
1320    }
1321
1322    /// Gets the minimum and maximum number of parameters the function has for
1323    /// the given WDL version.
1324    ///
1325    /// Returns `None` if the function is not supported for the given version.
1326    pub fn param_min_max(&self, version: SupportedVersion) -> Option<(usize, usize)> {
1327        let mut min = usize::MAX;
1328        let mut max = 0;
1329        for sig in self
1330            .signatures
1331            .iter()
1332            .filter(|s| s.minimum_version() <= version)
1333        {
1334            min = std::cmp::min(min, sig.required());
1335            max = std::cmp::max(max, sig.parameters().len());
1336        }
1337
1338        if min == usize::MAX {
1339            return None;
1340        }
1341
1342        Some((min, max))
1343    }
1344
1345    /// Gets the signatures of the function.
1346    pub fn signatures(&self) -> &[FunctionSignature] {
1347        &self.signatures
1348    }
1349
1350    /// Binds the function to the given arguments.
1351    ///
1352    /// This performs overload resolution for the polymorphic function.
1353    pub fn bind<'a>(
1354        &'a self,
1355        version: SupportedVersion,
1356        arguments: &[Type],
1357    ) -> Result<Binding<'a>, FunctionBindError> {
1358        // Ensure that there is at least one signature with a matching minimum version.
1359        let min_version = self.minimum_version();
1360        if version < min_version {
1361            return Err(FunctionBindError::RequiresVersion(min_version));
1362        }
1363
1364        // Next check the min/max parameter counts
1365        let (min, max) = self
1366            .param_min_max(version)
1367            .expect("should have at least one signature for the version");
1368        if arguments.len() < min {
1369            return Err(FunctionBindError::TooFewArguments(min));
1370        }
1371
1372        if arguments.len() > max {
1373            return Err(FunctionBindError::TooManyArguments(max));
1374        }
1375
1376        // Overload resolution precedence is from most specific to least specific:
1377        // * Non-generic exact match
1378        // * Non-generic with coercion
1379        // * Generic exact match
1380        // * Generic with coercion
1381
1382        let mut max_mismatch_index = 0;
1383        let mut expected_types = IndexSet::new();
1384
1385        for generic in [false, true] {
1386            let mut exact: Option<(usize, Type)> = None;
1387            let mut coercion1: Option<(usize, Type)> = None;
1388            let mut coercion2 = None;
1389            for (index, signature) in self.signatures.iter().enumerate().filter(|(_, s)| {
1390                s.is_generic() == generic
1391                    && s.minimum_version() <= version
1392                    && !s.insufficient_arguments(arguments)
1393            }) {
1394                match signature.bind(version, arguments) {
1395                    Ok(BindingKind::Equivalence(ty)) => {
1396                        // We cannot have more than one exact match
1397                        if let Some((previous, _)) = exact {
1398                            return Err(FunctionBindError::Ambiguous {
1399                                first: self.signatures[previous]
1400                                    .display(&TypeParameters::new(
1401                                        &self.signatures[previous].type_parameters,
1402                                    ))
1403                                    .to_string(),
1404                                second: self.signatures[index]
1405                                    .display(&TypeParameters::new(
1406                                        &self.signatures[index].type_parameters,
1407                                    ))
1408                                    .to_string(),
1409                            });
1410                        }
1411
1412                        exact = Some((index, ty));
1413                    }
1414                    Ok(BindingKind::Coercion(ty)) => {
1415                        // If this is the first coercion, store it; otherwise, store the second
1416                        // coercion index; if there's more than one coercion, we'll report an error
1417                        // below after ensuring there's no exact match
1418                        if coercion1.is_none() {
1419                            coercion1 = Some((index, ty));
1420                        } else {
1421                            coercion2.get_or_insert(index);
1422                        }
1423                    }
1424                    Err(FunctionBindError::ArgumentTypeMismatch { index, expected }) => {
1425                        // We'll report an argument mismatch for the greatest argument index
1426                        if index > max_mismatch_index {
1427                            max_mismatch_index = index;
1428                            expected_types.clear();
1429                        }
1430
1431                        if index == max_mismatch_index {
1432                            expected_types.insert(expected);
1433                        }
1434                    }
1435                    Err(
1436                        FunctionBindError::RequiresVersion(_)
1437                        | FunctionBindError::Ambiguous { .. }
1438                        | FunctionBindError::TooFewArguments(_)
1439                        | FunctionBindError::TooManyArguments(_),
1440                    ) => unreachable!("should not encounter these errors due to above filter"),
1441                }
1442            }
1443
1444            if let Some((index, ty)) = exact {
1445                return Ok(Binding {
1446                    return_type: ty,
1447                    index,
1448                    signature: &self.signatures[index],
1449                });
1450            }
1451
1452            // Ensure there wasn't more than one coercion
1453            if let Some(previous) = coercion2 {
1454                let index = coercion1.unwrap().0;
1455                return Err(FunctionBindError::Ambiguous {
1456                    first: self.signatures[previous]
1457                        .display(&TypeParameters::new(
1458                            &self.signatures[previous].type_parameters,
1459                        ))
1460                        .to_string(),
1461                    second: self.signatures[index]
1462                        .display(&TypeParameters::new(
1463                            &self.signatures[index].type_parameters,
1464                        ))
1465                        .to_string(),
1466                });
1467            }
1468
1469            if let Some((index, ty)) = coercion1 {
1470                return Ok(Binding {
1471                    return_type: ty,
1472                    index,
1473                    signature: &self.signatures[index],
1474                });
1475            }
1476        }
1477
1478        assert!(!expected_types.is_empty());
1479
1480        let mut expected = String::new();
1481        for (i, ty) in expected_types.iter().enumerate() {
1482            if i > 0 {
1483                if expected_types.len() == 2 {
1484                    expected.push_str(" or ");
1485                } else if i == expected_types.len() - 1 {
1486                    expected.push_str(", or ");
1487                } else {
1488                    expected.push_str(", ");
1489                }
1490            }
1491
1492            expected.push_str(ty);
1493        }
1494
1495        Err(FunctionBindError::ArgumentTypeMismatch {
1496            index: max_mismatch_index,
1497            expected,
1498        })
1499    }
1500}
1501
1502impl From<PolymorphicFunction> for Function {
1503    fn from(value: PolymorphicFunction) -> Self {
1504        Self::Polymorphic(value)
1505    }
1506}
1507
1508/// A representation of the standard library.
1509#[derive(Debug)]
1510pub struct StandardLibrary {
1511    /// A map of function name to function definition.
1512    functions: IndexMap<&'static str, Function>,
1513    /// The type for `Array[Int]`.
1514    array_int: Type,
1515    /// The type for `Array[String]`.
1516    array_string: Type,
1517    /// The type for `Array[File]`.
1518    array_file: Type,
1519    /// The type for `Array[Object]`.
1520    array_object: Type,
1521    /// The type for `Array[String]+`.
1522    array_string_non_empty: Type,
1523    /// The type for `Array[Array[String]]`.
1524    array_array_string: Type,
1525    /// The type for `Map[String, String]`.
1526    map_string_string: Type,
1527    /// The type for `Map[String, Int]`.
1528    map_string_int: Type,
1529}
1530
1531impl StandardLibrary {
1532    /// Gets a standard library function by name.
1533    pub fn function(&self, name: &str) -> Option<&Function> {
1534        self.functions.get(name)
1535    }
1536
1537    /// Gets an iterator over all the functions in the standard library.
1538    pub fn functions(&self) -> impl ExactSizeIterator<Item = (&'static str, &Function)> {
1539        self.functions.iter().map(|(n, f)| (*n, f))
1540    }
1541
1542    /// Gets the type for `Array[Int]`.
1543    pub fn array_int_type(&self) -> &Type {
1544        &self.array_int
1545    }
1546
1547    /// Gets the type for `Array[String]`.
1548    pub fn array_string_type(&self) -> &Type {
1549        &self.array_string
1550    }
1551
1552    /// Gets the type for `Array[File]`.
1553    pub fn array_file_type(&self) -> &Type {
1554        &self.array_file
1555    }
1556
1557    /// Gets the type for `Array[Object]`.
1558    pub fn array_object_type(&self) -> &Type {
1559        &self.array_object
1560    }
1561
1562    /// Gets the type for `Array[String]+`.
1563    pub fn array_string_non_empty_type(&self) -> &Type {
1564        &self.array_string_non_empty
1565    }
1566
1567    /// Gets the type for `Array[Array[String]]`.
1568    pub fn array_array_string_type(&self) -> &Type {
1569        &self.array_array_string
1570    }
1571
1572    /// Gets the type for `Map[String, String]`.
1573    pub fn map_string_string_type(&self) -> &Type {
1574        &self.map_string_string
1575    }
1576
1577    /// Gets the type for `Map[String, Int]`.
1578    pub fn map_string_int_type(&self) -> &Type {
1579        &self.map_string_int
1580    }
1581}
1582
1583/// Represents the WDL standard library.
1584pub static STDLIB: LazyLock<StandardLibrary> = LazyLock::new(|| {
1585    let array_int: Type = ArrayType::new(PrimitiveType::Integer).into();
1586    let array_string: Type = ArrayType::new(PrimitiveType::String).into();
1587    let array_file: Type = ArrayType::new(PrimitiveType::File).into();
1588    let array_object: Type = ArrayType::new(Type::Object).into();
1589    let array_string_non_empty: Type = ArrayType::non_empty(PrimitiveType::String).into();
1590    let array_array_string: Type = ArrayType::new(array_string.clone()).into();
1591    let map_string_string: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
1592    let map_string_int: Type = MapType::new(PrimitiveType::String, PrimitiveType::Integer).into();
1593    let mut functions = IndexMap::new();
1594
1595    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#floor
1596    assert!(
1597        functions
1598            .insert(
1599                "floor",
1600                MonomorphicFunction::new(
1601                    FunctionSignature::builder()
1602                        .parameter(PrimitiveType::Float)
1603                        .ret(PrimitiveType::Integer)
1604                        .build(),
1605                )
1606                .into(),
1607            )
1608            .is_none()
1609    );
1610
1611    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#ceil
1612    assert!(
1613        functions
1614            .insert(
1615                "ceil",
1616                MonomorphicFunction::new(
1617                    FunctionSignature::builder()
1618                        .parameter(PrimitiveType::Float)
1619                        .ret(PrimitiveType::Integer)
1620                        .build(),
1621                )
1622                .into(),
1623            )
1624            .is_none()
1625    );
1626
1627    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#round
1628    assert!(
1629        functions
1630            .insert(
1631                "round",
1632                MonomorphicFunction::new(
1633                    FunctionSignature::builder()
1634                        .parameter(PrimitiveType::Float)
1635                        .ret(PrimitiveType::Integer)
1636                        .build(),
1637                )
1638                .into(),
1639            )
1640            .is_none()
1641    );
1642
1643    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#min
1644    assert!(
1645        functions
1646            .insert(
1647                "min",
1648                PolymorphicFunction::new(vec![
1649                    FunctionSignature::builder()
1650                        .min_version(SupportedVersion::V1(V1::One))
1651                        .parameter(PrimitiveType::Integer)
1652                        .parameter(PrimitiveType::Integer)
1653                        .ret(PrimitiveType::Integer)
1654                        .build(),
1655                    FunctionSignature::builder()
1656                        .min_version(SupportedVersion::V1(V1::One))
1657                        .parameter(PrimitiveType::Integer)
1658                        .parameter(PrimitiveType::Float)
1659                        .ret(PrimitiveType::Float)
1660                        .build(),
1661                    FunctionSignature::builder()
1662                        .min_version(SupportedVersion::V1(V1::One))
1663                        .parameter(PrimitiveType::Float)
1664                        .parameter(PrimitiveType::Integer)
1665                        .ret(PrimitiveType::Float)
1666                        .build(),
1667                    FunctionSignature::builder()
1668                        .min_version(SupportedVersion::V1(V1::One))
1669                        .parameter(PrimitiveType::Float)
1670                        .parameter(PrimitiveType::Float)
1671                        .ret(PrimitiveType::Float)
1672                        .build(),
1673                ],)
1674                .into(),
1675            )
1676            .is_none()
1677    );
1678
1679    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#max
1680    assert!(
1681        functions
1682            .insert(
1683                "max",
1684                PolymorphicFunction::new(vec![
1685                    FunctionSignature::builder()
1686                        .min_version(SupportedVersion::V1(V1::One))
1687                        .parameter(PrimitiveType::Integer)
1688                        .parameter(PrimitiveType::Integer)
1689                        .ret(PrimitiveType::Integer)
1690                        .build(),
1691                    FunctionSignature::builder()
1692                        .min_version(SupportedVersion::V1(V1::One))
1693                        .parameter(PrimitiveType::Integer)
1694                        .parameter(PrimitiveType::Float)
1695                        .ret(PrimitiveType::Float)
1696                        .build(),
1697                    FunctionSignature::builder()
1698                        .min_version(SupportedVersion::V1(V1::One))
1699                        .parameter(PrimitiveType::Float)
1700                        .parameter(PrimitiveType::Integer)
1701                        .ret(PrimitiveType::Float)
1702                        .build(),
1703                    FunctionSignature::builder()
1704                        .min_version(SupportedVersion::V1(V1::One))
1705                        .parameter(PrimitiveType::Float)
1706                        .parameter(PrimitiveType::Float)
1707                        .ret(PrimitiveType::Float)
1708                        .build(),
1709                ],)
1710                .into(),
1711            )
1712            .is_none()
1713    );
1714
1715    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#-find
1716    assert!(
1717        functions
1718            .insert(
1719                "find",
1720                MonomorphicFunction::new(
1721                    FunctionSignature::builder()
1722                        .min_version(SupportedVersion::V1(V1::Two))
1723                        .parameter(PrimitiveType::String)
1724                        .parameter(PrimitiveType::String)
1725                        .ret(Type::from(PrimitiveType::String).optional())
1726                        .build(),
1727                )
1728                .into(),
1729            )
1730            .is_none()
1731    );
1732
1733    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#-matches
1734    assert!(
1735        functions
1736            .insert(
1737                "matches",
1738                MonomorphicFunction::new(
1739                    FunctionSignature::builder()
1740                        .min_version(SupportedVersion::V1(V1::Two))
1741                        .parameter(PrimitiveType::String)
1742                        .parameter(PrimitiveType::String)
1743                        .ret(PrimitiveType::Boolean)
1744                        .build(),
1745                )
1746                .into(),
1747            )
1748            .is_none()
1749    );
1750
1751    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#sub
1752    assert!(
1753        functions
1754            .insert(
1755                "sub",
1756                MonomorphicFunction::new(
1757                    FunctionSignature::builder()
1758                        .parameter(PrimitiveType::String)
1759                        .parameter(PrimitiveType::String)
1760                        .parameter(PrimitiveType::String)
1761                        .ret(PrimitiveType::String)
1762                        .build(),
1763                )
1764                .into(),
1765            )
1766            .is_none()
1767    );
1768
1769    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#basename
1770    assert!(
1771        functions
1772            .insert(
1773                "basename",
1774                PolymorphicFunction::new(vec![
1775                    FunctionSignature::builder()
1776                        .required(1)
1777                        .parameter(PrimitiveType::File)
1778                        .parameter(PrimitiveType::String)
1779                        .ret(PrimitiveType::String)
1780                        .build(),
1781                    // This overload isn't explicitly specified in the spec, but the spec
1782                    // allows for `String` where file/directory are accepted; an explicit
1783                    // `String` overload is required as `String` may coerce to either `File` or
1784                    // `Directory`, which is ambiguous.
1785                    FunctionSignature::builder()
1786                        .min_version(SupportedVersion::V1(V1::Two))
1787                        .required(1)
1788                        .parameter(PrimitiveType::String)
1789                        .parameter(PrimitiveType::String)
1790                        .ret(PrimitiveType::String)
1791                        .build(),
1792                    FunctionSignature::builder()
1793                        .min_version(SupportedVersion::V1(V1::Two))
1794                        .required(1)
1795                        .parameter(PrimitiveType::Directory)
1796                        .parameter(PrimitiveType::String)
1797                        .ret(PrimitiveType::String)
1798                        .build(),
1799                ],)
1800                .into(),
1801            )
1802            .is_none()
1803    );
1804
1805    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#-join_paths
1806    assert!(
1807        functions
1808            .insert(
1809                "join_paths",
1810                PolymorphicFunction::new(vec![
1811                    FunctionSignature::builder()
1812                        .min_version(SupportedVersion::V1(V1::Two))
1813                        .parameter(PrimitiveType::File)
1814                        .parameter(PrimitiveType::String)
1815                        .ret(PrimitiveType::File)
1816                        .build(),
1817                    FunctionSignature::builder()
1818                        .min_version(SupportedVersion::V1(V1::Two))
1819                        .parameter(PrimitiveType::File)
1820                        .parameter(array_string_non_empty.clone())
1821                        .ret(PrimitiveType::File)
1822                        .build(),
1823                    FunctionSignature::builder()
1824                        .min_version(SupportedVersion::V1(V1::Two))
1825                        .parameter(array_string_non_empty.clone())
1826                        .ret(PrimitiveType::File)
1827                        .build(),
1828                ],)
1829                .into(),
1830            )
1831            .is_none()
1832    );
1833
1834    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#glob
1835    assert!(
1836        functions
1837            .insert(
1838                "glob",
1839                MonomorphicFunction::new(
1840                    FunctionSignature::builder()
1841                        .parameter(PrimitiveType::String)
1842                        .ret(array_file.clone())
1843                        .build(),
1844                )
1845                .into(),
1846            )
1847            .is_none()
1848    );
1849
1850    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#size
1851    assert!(
1852        functions
1853            .insert(
1854                "size",
1855                PolymorphicFunction::new(vec![
1856                    // This overload isn't explicitly in the spec, but it fixes an ambiguity in 1.2
1857                    // when passed a literal `None` value.
1858                    FunctionSignature::builder()
1859                        .min_version(SupportedVersion::V1(V1::Two))
1860                        .required(1)
1861                        .parameter(Type::None)
1862                        .parameter(PrimitiveType::String)
1863                        .ret(PrimitiveType::Float)
1864                        .build(),
1865                    FunctionSignature::builder()
1866                        .required(1)
1867                        .parameter(Type::from(PrimitiveType::File).optional())
1868                        .parameter(PrimitiveType::String)
1869                        .ret(PrimitiveType::Float)
1870                        .build(),
1871                    // This overload isn't explicitly specified in the spec, but the spec
1872                    // allows for `String` where file/directory are accepted; an explicit
1873                    // `String` overload is required as `String` may coerce to either `File` or
1874                    // `Directory`, which is ambiguous.
1875                    FunctionSignature::builder()
1876                        .min_version(SupportedVersion::V1(V1::Two))
1877                        .required(1)
1878                        .parameter(Type::from(PrimitiveType::String).optional())
1879                        .parameter(PrimitiveType::String)
1880                        .ret(PrimitiveType::Float)
1881                        .build(),
1882                    FunctionSignature::builder()
1883                        .min_version(SupportedVersion::V1(V1::Two))
1884                        .required(1)
1885                        .parameter(Type::from(PrimitiveType::Directory).optional())
1886                        .parameter(PrimitiveType::String)
1887                        .ret(PrimitiveType::Float)
1888                        .build(),
1889                    FunctionSignature::builder()
1890                        .required(1)
1891                        .type_parameter("X", SizeableConstraint)
1892                        .parameter(GenericType::Parameter("X"))
1893                        .parameter(PrimitiveType::String)
1894                        .ret(PrimitiveType::Float)
1895                        .build(),
1896                ],)
1897                .into(),
1898            )
1899            .is_none()
1900    );
1901
1902    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#stdout
1903    assert!(
1904        functions
1905            .insert(
1906                "stdout",
1907                MonomorphicFunction::new(
1908                    FunctionSignature::builder()
1909                        .ret(PrimitiveType::File)
1910                        .build(),
1911                )
1912                .into(),
1913            )
1914            .is_none()
1915    );
1916
1917    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#stderr
1918    assert!(
1919        functions
1920            .insert(
1921                "stderr",
1922                MonomorphicFunction::new(
1923                    FunctionSignature::builder()
1924                        .ret(PrimitiveType::File)
1925                        .build(),
1926                )
1927                .into(),
1928            )
1929            .is_none()
1930    );
1931
1932    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#read_string
1933    assert!(
1934        functions
1935            .insert(
1936                "read_string",
1937                MonomorphicFunction::new(
1938                    FunctionSignature::builder()
1939                        .parameter(PrimitiveType::File)
1940                        .ret(PrimitiveType::String)
1941                        .build(),
1942                )
1943                .into(),
1944            )
1945            .is_none()
1946    );
1947
1948    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#read_int
1949    assert!(
1950        functions
1951            .insert(
1952                "read_int",
1953                MonomorphicFunction::new(
1954                    FunctionSignature::builder()
1955                        .parameter(PrimitiveType::File)
1956                        .ret(PrimitiveType::Integer)
1957                        .build(),
1958                )
1959                .into(),
1960            )
1961            .is_none()
1962    );
1963
1964    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#read_float
1965    assert!(
1966        functions
1967            .insert(
1968                "read_float",
1969                MonomorphicFunction::new(
1970                    FunctionSignature::builder()
1971                        .parameter(PrimitiveType::File)
1972                        .ret(PrimitiveType::Float)
1973                        .build(),
1974                )
1975                .into(),
1976            )
1977            .is_none()
1978    );
1979
1980    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#read_boolean
1981    assert!(
1982        functions
1983            .insert(
1984                "read_boolean",
1985                MonomorphicFunction::new(
1986                    FunctionSignature::builder()
1987                        .parameter(PrimitiveType::File)
1988                        .ret(PrimitiveType::Boolean)
1989                        .build(),
1990                )
1991                .into(),
1992            )
1993            .is_none()
1994    );
1995
1996    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#read_lines
1997    assert!(
1998        functions
1999            .insert(
2000                "read_lines",
2001                MonomorphicFunction::new(
2002                    FunctionSignature::builder()
2003                        .parameter(PrimitiveType::File)
2004                        .ret(array_string.clone())
2005                        .build(),
2006                )
2007                .into(),
2008            )
2009            .is_none()
2010    );
2011
2012    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#write_lines
2013    assert!(
2014        functions
2015            .insert(
2016                "write_lines",
2017                MonomorphicFunction::new(
2018                    FunctionSignature::builder()
2019                        .parameter(array_string.clone())
2020                        .ret(PrimitiveType::File)
2021                        .build(),
2022                )
2023                .into(),
2024            )
2025            .is_none()
2026    );
2027
2028    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#read_tsv
2029    assert!(
2030        functions
2031            .insert(
2032                "read_tsv",
2033                PolymorphicFunction::new(vec![
2034                    FunctionSignature::builder()
2035                        .parameter(PrimitiveType::File)
2036                        .ret(array_array_string.clone())
2037                        .build(),
2038                    FunctionSignature::builder()
2039                        .min_version(SupportedVersion::V1(V1::Two))
2040                        .parameter(PrimitiveType::File)
2041                        .parameter(PrimitiveType::Boolean)
2042                        .ret(array_object.clone())
2043                        .build(),
2044                    FunctionSignature::builder()
2045                        .min_version(SupportedVersion::V1(V1::Two))
2046                        .parameter(PrimitiveType::File)
2047                        .parameter(PrimitiveType::Boolean)
2048                        .parameter(array_string.clone())
2049                        .ret(array_object.clone())
2050                        .build(),
2051                ],)
2052                .into(),
2053            )
2054            .is_none()
2055    );
2056
2057    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#write_tsv
2058    assert!(
2059        functions
2060            .insert(
2061                "write_tsv",
2062                PolymorphicFunction::new(vec![
2063                    FunctionSignature::builder()
2064                        .parameter(array_array_string.clone())
2065                        .ret(PrimitiveType::File)
2066                        .build(),
2067                    FunctionSignature::builder()
2068                        .min_version(SupportedVersion::V1(V1::Two))
2069                        .parameter(array_array_string.clone())
2070                        .parameter(PrimitiveType::Boolean)
2071                        .parameter(array_string.clone())
2072                        .ret(PrimitiveType::File)
2073                        .build(),
2074                    FunctionSignature::builder()
2075                        .min_version(SupportedVersion::V1(V1::Two))
2076                        .type_parameter("S", PrimitiveStructConstraint)
2077                        .required(1)
2078                        .parameter(GenericArrayType::new(GenericType::Parameter("S")))
2079                        .parameter(PrimitiveType::Boolean)
2080                        .parameter(array_string.clone())
2081                        .ret(PrimitiveType::File)
2082                        .build(),
2083                ],)
2084                .into(),
2085            )
2086            .is_none()
2087    );
2088
2089    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#read_map
2090    assert!(
2091        functions
2092            .insert(
2093                "read_map",
2094                MonomorphicFunction::new(
2095                    FunctionSignature::builder()
2096                        .parameter(PrimitiveType::File)
2097                        .ret(map_string_string.clone())
2098                        .build(),
2099                )
2100                .into(),
2101            )
2102            .is_none()
2103    );
2104
2105    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#write_map
2106    assert!(
2107        functions
2108            .insert(
2109                "write_map",
2110                MonomorphicFunction::new(
2111                    FunctionSignature::builder()
2112                        .parameter(map_string_string.clone())
2113                        .ret(PrimitiveType::File)
2114                        .build(),
2115                )
2116                .into(),
2117            )
2118            .is_none()
2119    );
2120
2121    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#read_json
2122    assert!(
2123        functions
2124            .insert(
2125                "read_json",
2126                MonomorphicFunction::new(
2127                    FunctionSignature::builder()
2128                        .parameter(PrimitiveType::File)
2129                        .ret(Type::Union)
2130                        .build(),
2131                )
2132                .into(),
2133            )
2134            .is_none()
2135    );
2136
2137    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#write_json
2138    assert!(
2139        functions
2140            .insert(
2141                "write_json",
2142                MonomorphicFunction::new(
2143                    FunctionSignature::builder()
2144                        .type_parameter("X", JsonSerializableConstraint)
2145                        .parameter(GenericType::Parameter("X"))
2146                        .ret(PrimitiveType::File)
2147                        .build(),
2148                )
2149                .into(),
2150            )
2151            .is_none()
2152    );
2153
2154    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#read_object
2155    assert!(
2156        functions
2157            .insert(
2158                "read_object",
2159                MonomorphicFunction::new(
2160                    FunctionSignature::builder()
2161                        .parameter(PrimitiveType::File)
2162                        .ret(Type::Object)
2163                        .build(),
2164                )
2165                .into(),
2166            )
2167            .is_none()
2168    );
2169
2170    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#read_objects
2171    assert!(
2172        functions
2173            .insert(
2174                "read_objects",
2175                MonomorphicFunction::new(
2176                    FunctionSignature::builder()
2177                        .parameter(PrimitiveType::File)
2178                        .ret(array_object.clone())
2179                        .build(),
2180                )
2181                .into(),
2182            )
2183            .is_none()
2184    );
2185
2186    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#write_object
2187    assert!(
2188        functions
2189            .insert(
2190                "write_object",
2191                PolymorphicFunction::new(vec![
2192                    FunctionSignature::builder()
2193                        .parameter(Type::Object)
2194                        .ret(PrimitiveType::File)
2195                        .build(),
2196                    FunctionSignature::builder()
2197                        .min_version(SupportedVersion::V1(V1::One))
2198                        .type_parameter("S", PrimitiveStructConstraint)
2199                        .parameter(GenericType::Parameter("S"))
2200                        .ret(PrimitiveType::File)
2201                        .build(),
2202                ],)
2203                .into(),
2204            )
2205            .is_none()
2206    );
2207
2208    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#write_objects
2209    assert!(
2210        functions
2211            .insert(
2212                "write_objects",
2213                PolymorphicFunction::new(vec![
2214                    FunctionSignature::builder()
2215                        .parameter(array_object.clone())
2216                        .ret(PrimitiveType::File)
2217                        .build(),
2218                    FunctionSignature::builder()
2219                        .min_version(SupportedVersion::V1(V1::One))
2220                        .type_parameter("S", PrimitiveStructConstraint)
2221                        .parameter(GenericArrayType::new(GenericType::Parameter("S")))
2222                        .ret(PrimitiveType::File)
2223                        .build(),
2224                ],)
2225                .into(),
2226            )
2227            .is_none()
2228    );
2229
2230    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#prefix
2231    assert!(
2232        functions
2233            .insert(
2234                "prefix",
2235                MonomorphicFunction::new(
2236                    FunctionSignature::builder()
2237                        .type_parameter("P", PrimitiveTypeConstraint)
2238                        .parameter(PrimitiveType::String)
2239                        .parameter(GenericArrayType::new(GenericType::Parameter("P")))
2240                        .ret(array_string.clone())
2241                        .build(),
2242                )
2243                .into(),
2244            )
2245            .is_none()
2246    );
2247
2248    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#suffix
2249    assert!(
2250        functions
2251            .insert(
2252                "suffix",
2253                MonomorphicFunction::new(
2254                    FunctionSignature::builder()
2255                        .min_version(SupportedVersion::V1(V1::One))
2256                        .type_parameter("P", PrimitiveTypeConstraint)
2257                        .parameter(PrimitiveType::String)
2258                        .parameter(GenericArrayType::new(GenericType::Parameter("P")))
2259                        .ret(array_string.clone())
2260                        .build(),
2261                )
2262                .into(),
2263            )
2264            .is_none()
2265    );
2266
2267    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#quote
2268    assert!(
2269        functions
2270            .insert(
2271                "quote",
2272                MonomorphicFunction::new(
2273                    FunctionSignature::builder()
2274                        .min_version(SupportedVersion::V1(V1::One))
2275                        .type_parameter("P", PrimitiveTypeConstraint)
2276                        .parameter(GenericArrayType::new(GenericType::Parameter("P")))
2277                        .ret(array_string.clone())
2278                        .build(),
2279                )
2280                .into(),
2281            )
2282            .is_none()
2283    );
2284
2285    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#squote
2286    assert!(
2287        functions
2288            .insert(
2289                "squote",
2290                MonomorphicFunction::new(
2291                    FunctionSignature::builder()
2292                        .min_version(SupportedVersion::V1(V1::One))
2293                        .type_parameter("P", PrimitiveTypeConstraint)
2294                        .parameter(GenericArrayType::new(GenericType::Parameter("P")))
2295                        .ret(array_string.clone())
2296                        .build(),
2297                )
2298                .into(),
2299            )
2300            .is_none()
2301    );
2302
2303    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#sep
2304    assert!(
2305        functions
2306            .insert(
2307                "sep",
2308                MonomorphicFunction::new(
2309                    FunctionSignature::builder()
2310                        .min_version(SupportedVersion::V1(V1::One))
2311                        .type_parameter("P", PrimitiveTypeConstraint)
2312                        .parameter(PrimitiveType::String)
2313                        .parameter(GenericArrayType::new(GenericType::Parameter("P")))
2314                        .ret(PrimitiveType::String)
2315                        .build(),
2316                )
2317                .into(),
2318            )
2319            .is_none()
2320    );
2321
2322    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#range
2323    assert!(
2324        functions
2325            .insert(
2326                "range",
2327                MonomorphicFunction::new(
2328                    FunctionSignature::builder()
2329                        .parameter(PrimitiveType::Integer)
2330                        .ret(array_int.clone())
2331                        .build(),
2332                )
2333                .into(),
2334            )
2335            .is_none()
2336    );
2337
2338    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#transpose
2339    assert!(
2340        functions
2341            .insert(
2342                "transpose",
2343                MonomorphicFunction::new(
2344                    FunctionSignature::builder()
2345                        .any_type_parameter("X")
2346                        .parameter(GenericArrayType::new(GenericArrayType::new(
2347                            GenericType::Parameter("X"),
2348                        )))
2349                        .ret(GenericArrayType::new(GenericArrayType::new(
2350                            GenericType::Parameter("X"),
2351                        )))
2352                        .build(),
2353                )
2354                .into(),
2355            )
2356            .is_none()
2357    );
2358
2359    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#cross
2360    assert!(
2361        functions
2362            .insert(
2363                "cross",
2364                MonomorphicFunction::new(
2365                    FunctionSignature::builder()
2366                        .any_type_parameter("X")
2367                        .any_type_parameter("Y")
2368                        .parameter(GenericArrayType::new(GenericType::Parameter("X")))
2369                        .parameter(GenericArrayType::new(GenericType::Parameter("Y")))
2370                        .ret(GenericArrayType::new(GenericPairType::new(
2371                            GenericType::Parameter("X"),
2372                            GenericType::Parameter("Y"),
2373                        )))
2374                        .build(),
2375                )
2376                .into(),
2377            )
2378            .is_none()
2379    );
2380
2381    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#zip
2382    assert!(
2383        functions
2384            .insert(
2385                "zip",
2386                MonomorphicFunction::new(
2387                    FunctionSignature::builder()
2388                        .any_type_parameter("X")
2389                        .any_type_parameter("Y")
2390                        .parameter(GenericArrayType::new(GenericType::Parameter("X")))
2391                        .parameter(GenericArrayType::new(GenericType::Parameter("Y")))
2392                        .ret(GenericArrayType::new(GenericPairType::new(
2393                            GenericType::Parameter("X"),
2394                            GenericType::Parameter("Y"),
2395                        )))
2396                        .build(),
2397                )
2398                .into(),
2399            )
2400            .is_none()
2401    );
2402
2403    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#unzip
2404    assert!(
2405        functions
2406            .insert(
2407                "unzip",
2408                MonomorphicFunction::new(
2409                    FunctionSignature::builder()
2410                        .min_version(SupportedVersion::V1(V1::One))
2411                        .any_type_parameter("X")
2412                        .any_type_parameter("Y")
2413                        .parameter(GenericArrayType::new(GenericPairType::new(
2414                            GenericType::Parameter("X"),
2415                            GenericType::Parameter("Y"),
2416                        )))
2417                        .ret(GenericPairType::new(
2418                            GenericArrayType::new(GenericType::Parameter("X")),
2419                            GenericArrayType::new(GenericType::Parameter("Y")),
2420                        ))
2421                        .build(),
2422                )
2423                .into(),
2424            )
2425            .is_none()
2426    );
2427
2428    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#-contains
2429    assert!(
2430        functions
2431            .insert(
2432                "contains",
2433                MonomorphicFunction::new(
2434                    FunctionSignature::builder()
2435                        .min_version(SupportedVersion::V1(V1::Two))
2436                        .type_parameter("P", PrimitiveTypeConstraint)
2437                        .parameter(GenericArrayType::new(GenericType::Parameter("P")))
2438                        .parameter(GenericType::Parameter("P"))
2439                        .ret(PrimitiveType::Boolean)
2440                        .build(),
2441                )
2442                .into(),
2443            )
2444            .is_none()
2445    );
2446
2447    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#-chunk
2448    assert!(
2449        functions
2450            .insert(
2451                "chunk",
2452                MonomorphicFunction::new(
2453                    FunctionSignature::builder()
2454                        .min_version(SupportedVersion::V1(V1::Two))
2455                        .any_type_parameter("X")
2456                        .parameter(GenericArrayType::new(GenericType::Parameter("X")))
2457                        .parameter(PrimitiveType::Integer)
2458                        .ret(GenericArrayType::new(GenericArrayType::new(
2459                            GenericType::Parameter("X"),
2460                        )))
2461                        .build(),
2462                )
2463                .into(),
2464            )
2465            .is_none()
2466    );
2467
2468    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#flatten
2469    assert!(
2470        functions
2471            .insert(
2472                "flatten",
2473                MonomorphicFunction::new(
2474                    FunctionSignature::builder()
2475                        .any_type_parameter("X")
2476                        .parameter(GenericArrayType::new(GenericArrayType::new(
2477                            GenericType::Parameter("X")
2478                        )))
2479                        .ret(GenericArrayType::new(GenericType::Parameter("X")))
2480                        .build(),
2481                )
2482                .into(),
2483            )
2484            .is_none()
2485    );
2486
2487    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#select_first
2488    assert!(
2489        functions
2490            .insert(
2491                "select_first",
2492                // This differs from the definition of `select_first` in that we can have a single
2493                // signature of `X select_first(Array[X?], [X])`.
2494                MonomorphicFunction::new(
2495                    FunctionSignature::builder()
2496                        .any_type_parameter("X")
2497                        .required(1)
2498                        .parameter(GenericArrayType::new(GenericType::Parameter("X")))
2499                        .parameter(GenericType::UnqualifiedParameter("X"))
2500                        .ret(GenericType::UnqualifiedParameter("X"))
2501                        .build(),
2502                )
2503                .into(),
2504            )
2505            .is_none()
2506    );
2507
2508    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#select_all
2509    assert!(
2510        functions
2511            .insert(
2512                "select_all",
2513                MonomorphicFunction::new(
2514                    FunctionSignature::builder()
2515                        .any_type_parameter("X")
2516                        .parameter(GenericArrayType::new(GenericType::Parameter("X")))
2517                        .ret(GenericArrayType::new(GenericType::UnqualifiedParameter(
2518                            "X"
2519                        )))
2520                        .build(),
2521                )
2522                .into(),
2523            )
2524            .is_none()
2525    );
2526
2527    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#as_pairs
2528    assert!(
2529        functions
2530            .insert(
2531                "as_pairs",
2532                MonomorphicFunction::new(
2533                    FunctionSignature::builder()
2534                        .min_version(SupportedVersion::V1(V1::One))
2535                        .type_parameter("K", PrimitiveTypeConstraint)
2536                        .any_type_parameter("V")
2537                        .parameter(GenericMapType::new(
2538                            GenericType::Parameter("K"),
2539                            GenericType::Parameter("V")
2540                        ))
2541                        .ret(GenericArrayType::new(GenericPairType::new(
2542                            GenericType::Parameter("K"),
2543                            GenericType::Parameter("V")
2544                        )))
2545                        .build(),
2546                )
2547                .into(),
2548            )
2549            .is_none()
2550    );
2551
2552    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#as_map
2553    assert!(
2554        functions
2555            .insert(
2556                "as_map",
2557                MonomorphicFunction::new(
2558                    FunctionSignature::builder()
2559                        .min_version(SupportedVersion::V1(V1::One))
2560                        .type_parameter("K", PrimitiveTypeConstraint)
2561                        .any_type_parameter("V")
2562                        .parameter(GenericArrayType::new(GenericPairType::new(
2563                            GenericType::Parameter("K"),
2564                            GenericType::Parameter("V")
2565                        )))
2566                        .ret(GenericMapType::new(
2567                            GenericType::Parameter("K"),
2568                            GenericType::Parameter("V")
2569                        ))
2570                        .build(),
2571                )
2572                .into(),
2573            )
2574            .is_none()
2575    );
2576
2577    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#keys
2578    assert!(
2579        functions
2580            .insert(
2581                "keys",
2582                PolymorphicFunction::new(vec![
2583                    FunctionSignature::builder()
2584                        .min_version(SupportedVersion::V1(V1::One))
2585                        .type_parameter("K", PrimitiveTypeConstraint)
2586                        .any_type_parameter("V")
2587                        .parameter(GenericMapType::new(
2588                            GenericType::Parameter("K"),
2589                            GenericType::Parameter("V")
2590                        ))
2591                        .ret(GenericArrayType::new(GenericType::Parameter("K")))
2592                        .build(),
2593                    FunctionSignature::builder()
2594                        .min_version(SupportedVersion::V1(V1::Two))
2595                        .type_parameter("S", StructConstraint)
2596                        .parameter(GenericType::Parameter("S"))
2597                        .ret(array_string.clone())
2598                        .build(),
2599                    FunctionSignature::builder()
2600                        .min_version(SupportedVersion::V1(V1::Two))
2601                        .parameter(Type::Object)
2602                        .ret(array_string.clone())
2603                        .build(),
2604                ])
2605                .into(),
2606            )
2607            .is_none()
2608    );
2609
2610    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#contains_key
2611    assert!(
2612        functions
2613            .insert(
2614                "contains_key",
2615                PolymorphicFunction::new(vec![
2616                    FunctionSignature::builder()
2617                        .min_version(SupportedVersion::V1(V1::Two))
2618                        .type_parameter("K", PrimitiveTypeConstraint)
2619                        .any_type_parameter("V")
2620                        .parameter(GenericMapType::new(
2621                            GenericType::Parameter("K"),
2622                            GenericType::Parameter("V")
2623                        ))
2624                        .parameter(GenericType::Parameter("K"))
2625                        .ret(PrimitiveType::Boolean)
2626                        .build(),
2627                    FunctionSignature::builder()
2628                        .min_version(SupportedVersion::V1(V1::Two))
2629                        .parameter(Type::Object)
2630                        .parameter(PrimitiveType::String)
2631                        .ret(PrimitiveType::Boolean)
2632                        .build(),
2633                    FunctionSignature::builder()
2634                        .min_version(SupportedVersion::V1(V1::Two))
2635                        .any_type_parameter("V")
2636                        .parameter(GenericMapType::new(
2637                            PrimitiveType::String,
2638                            GenericType::Parameter("V")
2639                        ))
2640                        .parameter(array_string.clone())
2641                        .ret(PrimitiveType::Boolean)
2642                        .build(),
2643                    FunctionSignature::builder()
2644                        .min_version(SupportedVersion::V1(V1::Two))
2645                        .type_parameter("S", StructConstraint)
2646                        .parameter(GenericType::Parameter("S"))
2647                        .parameter(array_string.clone())
2648                        .ret(PrimitiveType::Boolean)
2649                        .build(),
2650                    FunctionSignature::builder()
2651                        .min_version(SupportedVersion::V1(V1::Two))
2652                        .parameter(Type::Object)
2653                        .parameter(array_string.clone())
2654                        .ret(PrimitiveType::Boolean)
2655                        .build(),
2656                ])
2657                .into(),
2658            )
2659            .is_none()
2660    );
2661
2662    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#-values
2663    assert!(
2664        functions
2665            .insert(
2666                "values",
2667                MonomorphicFunction::new(
2668                    FunctionSignature::builder()
2669                        .min_version(SupportedVersion::V1(V1::Two))
2670                        .type_parameter("K", PrimitiveTypeConstraint)
2671                        .any_type_parameter("V")
2672                        .parameter(GenericMapType::new(
2673                            GenericType::Parameter("K"),
2674                            GenericType::Parameter("V")
2675                        ))
2676                        .ret(GenericArrayType::new(GenericType::Parameter("V")))
2677                        .build(),
2678                )
2679                .into(),
2680            )
2681            .is_none()
2682    );
2683
2684    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#collect_by_key
2685    assert!(
2686        functions
2687            .insert(
2688                "collect_by_key",
2689                MonomorphicFunction::new(
2690                    FunctionSignature::builder()
2691                        .min_version(SupportedVersion::V1(V1::One))
2692                        .type_parameter("K", PrimitiveTypeConstraint)
2693                        .any_type_parameter("V")
2694                        .parameter(GenericArrayType::new(GenericPairType::new(
2695                            GenericType::Parameter("K"),
2696                            GenericType::Parameter("V")
2697                        )))
2698                        .ret(GenericMapType::new(
2699                            GenericType::Parameter("K"),
2700                            GenericArrayType::new(GenericType::Parameter("V"))
2701                        ))
2702                        .build(),
2703                )
2704                .into(),
2705            )
2706            .is_none()
2707    );
2708
2709    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#defined
2710    assert!(
2711        functions
2712            .insert(
2713                "defined",
2714                MonomorphicFunction::new(
2715                    FunctionSignature::builder()
2716                        .any_type_parameter("X")
2717                        .parameter(GenericType::Parameter("X"))
2718                        .ret(PrimitiveType::Boolean)
2719                        .build(),
2720                )
2721                .into(),
2722            )
2723            .is_none()
2724    );
2725
2726    // https://github.com/openwdl/wdl/blob/wdl-1.2/SPEC.md#length
2727    assert!(
2728        functions
2729            .insert(
2730                "length",
2731                PolymorphicFunction::new(vec![
2732                    FunctionSignature::builder()
2733                        .any_type_parameter("X")
2734                        .parameter(GenericArrayType::new(GenericType::Parameter("X")))
2735                        .ret(PrimitiveType::Integer)
2736                        .build(),
2737                    FunctionSignature::builder()
2738                        .any_type_parameter("K")
2739                        .any_type_parameter("V")
2740                        .parameter(GenericMapType::new(
2741                            GenericType::Parameter("K"),
2742                            GenericType::Parameter("V")
2743                        ))
2744                        .ret(PrimitiveType::Integer)
2745                        .build(),
2746                    FunctionSignature::builder()
2747                        .parameter(Type::Object)
2748                        .ret(PrimitiveType::Integer)
2749                        .build(),
2750                    FunctionSignature::builder()
2751                        .parameter(PrimitiveType::String)
2752                        .ret(PrimitiveType::Integer)
2753                        .build(),
2754                ])
2755                .into(),
2756            )
2757            .is_none()
2758    );
2759
2760    StandardLibrary {
2761        functions,
2762        array_int,
2763        array_string,
2764        array_file,
2765        array_object,
2766        array_string_non_empty,
2767        array_array_string,
2768        map_string_string,
2769        map_string_int,
2770    }
2771});
2772
2773#[cfg(test)]
2774mod test {
2775    use pretty_assertions::assert_eq;
2776
2777    use super::*;
2778
2779    #[test]
2780    fn verify_stdlib_signatures() {
2781        let mut signatures = Vec::new();
2782        for (name, f) in STDLIB.functions() {
2783            match f {
2784                Function::Monomorphic(f) => {
2785                    let params = TypeParameters::new(&f.signature.type_parameters);
2786                    signatures.push(format!("{name}{sig}", sig = f.signature.display(&params)));
2787                }
2788                Function::Polymorphic(f) => {
2789                    for signature in &f.signatures {
2790                        let params = TypeParameters::new(&signature.type_parameters);
2791                        signatures.push(format!("{name}{sig}", sig = signature.display(&params)));
2792                    }
2793                }
2794            }
2795        }
2796
2797        assert_eq!(
2798            signatures,
2799            [
2800                "floor(Float) -> Int",
2801                "ceil(Float) -> Int",
2802                "round(Float) -> Int",
2803                "min(Int, Int) -> Int",
2804                "min(Int, Float) -> Float",
2805                "min(Float, Int) -> Float",
2806                "min(Float, Float) -> Float",
2807                "max(Int, Int) -> Int",
2808                "max(Int, Float) -> Float",
2809                "max(Float, Int) -> Float",
2810                "max(Float, Float) -> Float",
2811                "find(String, String) -> String?",
2812                "matches(String, String) -> Boolean",
2813                "sub(String, String, String) -> String",
2814                "basename(File, <String>) -> String",
2815                "basename(String, <String>) -> String",
2816                "basename(Directory, <String>) -> String",
2817                "join_paths(File, String) -> File",
2818                "join_paths(File, Array[String]+) -> File",
2819                "join_paths(Array[String]+) -> File",
2820                "glob(String) -> Array[File]",
2821                "size(None, <String>) -> Float",
2822                "size(File?, <String>) -> Float",
2823                "size(String?, <String>) -> Float",
2824                "size(Directory?, <String>) -> Float",
2825                "size(X, <String>) -> Float where `X`: any compound type that recursively \
2826                 contains a `File` or `Directory`",
2827                "stdout() -> File",
2828                "stderr() -> File",
2829                "read_string(File) -> String",
2830                "read_int(File) -> Int",
2831                "read_float(File) -> Float",
2832                "read_boolean(File) -> Boolean",
2833                "read_lines(File) -> Array[String]",
2834                "write_lines(Array[String]) -> File",
2835                "read_tsv(File) -> Array[Array[String]]",
2836                "read_tsv(File, Boolean) -> Array[Object]",
2837                "read_tsv(File, Boolean, Array[String]) -> Array[Object]",
2838                "write_tsv(Array[Array[String]]) -> File",
2839                "write_tsv(Array[Array[String]], Boolean, Array[String]) -> File",
2840                "write_tsv(Array[S], <Boolean>, <Array[String]>) -> File where `S`: any structure \
2841                 containing only primitive types",
2842                "read_map(File) -> Map[String, String]",
2843                "write_map(Map[String, String]) -> File",
2844                "read_json(File) -> Union",
2845                "write_json(X) -> File where `X`: any JSON-serializable type",
2846                "read_object(File) -> Object",
2847                "read_objects(File) -> Array[Object]",
2848                "write_object(Object) -> File",
2849                "write_object(S) -> File where `S`: any structure containing only primitive types",
2850                "write_objects(Array[Object]) -> File",
2851                "write_objects(Array[S]) -> File where `S`: any structure containing only \
2852                 primitive types",
2853                "prefix(String, Array[P]) -> Array[String] where `P`: any primitive type",
2854                "suffix(String, Array[P]) -> Array[String] where `P`: any primitive type",
2855                "quote(Array[P]) -> Array[String] where `P`: any primitive type",
2856                "squote(Array[P]) -> Array[String] where `P`: any primitive type",
2857                "sep(String, Array[P]) -> String where `P`: any primitive type",
2858                "range(Int) -> Array[Int]",
2859                "transpose(Array[Array[X]]) -> Array[Array[X]]",
2860                "cross(Array[X], Array[Y]) -> Array[Pair[X, Y]]",
2861                "zip(Array[X], Array[Y]) -> Array[Pair[X, Y]]",
2862                "unzip(Array[Pair[X, Y]]) -> Pair[Array[X], Array[Y]]",
2863                "contains(Array[P], P) -> Boolean where `P`: any primitive type",
2864                "chunk(Array[X], Int) -> Array[Array[X]]",
2865                "flatten(Array[Array[X]]) -> Array[X]",
2866                "select_first(Array[X], <X>) -> X",
2867                "select_all(Array[X]) -> Array[X]",
2868                "as_pairs(Map[K, V]) -> Array[Pair[K, V]] where `K`: any primitive type",
2869                "as_map(Array[Pair[K, V]]) -> Map[K, V] where `K`: any primitive type",
2870                "keys(Map[K, V]) -> Array[K] where `K`: any primitive type",
2871                "keys(S) -> Array[String] where `S`: any structure",
2872                "keys(Object) -> Array[String]",
2873                "contains_key(Map[K, V], K) -> Boolean where `K`: any primitive type",
2874                "contains_key(Object, String) -> Boolean",
2875                "contains_key(Map[String, V], Array[String]) -> Boolean",
2876                "contains_key(S, Array[String]) -> Boolean where `S`: any structure",
2877                "contains_key(Object, Array[String]) -> Boolean",
2878                "values(Map[K, V]) -> Array[V] where `K`: any primitive type",
2879                "collect_by_key(Array[Pair[K, V]]) -> Map[K, Array[V]] where `K`: any primitive \
2880                 type",
2881                "defined(X) -> Boolean",
2882                "length(Array[X]) -> Int",
2883                "length(Map[K, V]) -> Int",
2884                "length(Object) -> Int",
2885                "length(String) -> Int",
2886            ]
2887        );
2888    }
2889
2890    #[test]
2891    fn it_binds_a_simple_function() {
2892        let f = STDLIB.function("floor").expect("should have function");
2893        assert_eq!(f.minimum_version(), SupportedVersion::V1(V1::Zero));
2894
2895        let e = f
2896            .bind(SupportedVersion::V1(V1::Zero), &[])
2897            .expect_err("bind should fail");
2898        assert_eq!(e, FunctionBindError::TooFewArguments(1));
2899
2900        let e = f
2901            .bind(
2902                SupportedVersion::V1(V1::One),
2903                &[PrimitiveType::String.into(), PrimitiveType::Boolean.into()],
2904            )
2905            .expect_err("bind should fail");
2906        assert_eq!(e, FunctionBindError::TooManyArguments(1));
2907
2908        // Check for a string argument (should be a type mismatch)
2909        let e = f
2910            .bind(
2911                SupportedVersion::V1(V1::Two),
2912                &[PrimitiveType::String.into()],
2913            )
2914            .expect_err("bind should fail");
2915        assert_eq!(
2916            e,
2917            FunctionBindError::ArgumentTypeMismatch {
2918                index: 0,
2919                expected: "`Float`".into()
2920            }
2921        );
2922
2923        // Check for Union (i.e. indeterminate)
2924        let binding = f
2925            .bind(SupportedVersion::V1(V1::Zero), &[Type::Union])
2926            .expect("bind should succeed");
2927        assert_eq!(binding.index(), 0);
2928        assert_eq!(binding.return_type().to_string(), "Int");
2929
2930        // Check for a float argument
2931        let binding = f
2932            .bind(
2933                SupportedVersion::V1(V1::One),
2934                &[PrimitiveType::Float.into()],
2935            )
2936            .expect("bind should succeed");
2937        assert_eq!(binding.index(), 0);
2938        assert_eq!(binding.return_type().to_string(), "Int");
2939
2940        // Check for an integer argument (should coerce)
2941        let binding = f
2942            .bind(
2943                SupportedVersion::V1(V1::Two),
2944                &[PrimitiveType::Integer.into()],
2945            )
2946            .expect("bind should succeed");
2947        assert_eq!(binding.index(), 0);
2948        assert_eq!(binding.return_type().to_string(), "Int");
2949    }
2950
2951    #[test]
2952    fn it_binds_a_generic_function() {
2953        let f = STDLIB.function("values").expect("should have function");
2954        assert_eq!(f.minimum_version(), SupportedVersion::V1(V1::Two));
2955
2956        let e = f
2957            .bind(SupportedVersion::V1(V1::Zero), &[])
2958            .expect_err("bind should fail");
2959        assert_eq!(
2960            e,
2961            FunctionBindError::RequiresVersion(SupportedVersion::V1(V1::Two))
2962        );
2963
2964        let e = f
2965            .bind(SupportedVersion::V1(V1::Two), &[])
2966            .expect_err("bind should fail");
2967        assert_eq!(e, FunctionBindError::TooFewArguments(1));
2968
2969        let e = f
2970            .bind(
2971                SupportedVersion::V1(V1::Two),
2972                &[PrimitiveType::String.into(), PrimitiveType::Boolean.into()],
2973            )
2974            .expect_err("bind should fail");
2975        assert_eq!(e, FunctionBindError::TooManyArguments(1));
2976
2977        // Check for a string argument (should be a type mismatch)
2978        let e = f
2979            .bind(
2980                SupportedVersion::V1(V1::Two),
2981                &[PrimitiveType::String.into()],
2982            )
2983            .expect_err("bind should fail");
2984        assert_eq!(
2985            e,
2986            FunctionBindError::ArgumentTypeMismatch {
2987                index: 0,
2988                expected: "`Map[K, V]` where `K`: any primitive type".into()
2989            }
2990        );
2991
2992        // Check for Union (i.e. indeterminate)
2993        let binding = f
2994            .bind(SupportedVersion::V1(V1::Two), &[Type::Union])
2995            .expect("bind should succeed");
2996        assert_eq!(binding.index(), 0);
2997        assert_eq!(binding.return_type().to_string(), "Array[Union]");
2998
2999        // Check for a Map[String, String]
3000        let ty: Type = MapType::new(PrimitiveType::String, PrimitiveType::String).into();
3001        let binding = f
3002            .bind(SupportedVersion::V1(V1::Two), &[ty])
3003            .expect("bind should succeed");
3004        assert_eq!(binding.index(), 0);
3005        assert_eq!(binding.return_type().to_string(), "Array[String]");
3006
3007        // Check for a Map[String, Object]
3008        let ty: Type = MapType::new(PrimitiveType::String, Type::Object).into();
3009        let binding = f
3010            .bind(SupportedVersion::V1(V1::Two), &[ty])
3011            .expect("bind should succeed");
3012        assert_eq!(binding.index(), 0);
3013        assert_eq!(binding.return_type().to_string(), "Array[Object]");
3014
3015        // Check for a map with an optional primitive type
3016        let ty: Type = MapType::new(
3017            Type::from(PrimitiveType::String).optional(),
3018            PrimitiveType::Boolean,
3019        )
3020        .into();
3021        let binding = f
3022            .bind(SupportedVersion::V1(V1::Two), &[ty])
3023            .expect("bind should succeed");
3024        assert_eq!(binding.index(), 0);
3025        assert_eq!(binding.return_type().to_string(), "Array[Boolean]");
3026    }
3027
3028    #[test]
3029    fn it_removes_qualifiers() {
3030        let f = STDLIB.function("select_all").expect("should have function");
3031        assert_eq!(f.minimum_version(), SupportedVersion::V1(V1::Zero));
3032
3033        // Check for a Array[String]
3034        let array_string: Type = ArrayType::new(PrimitiveType::String).into();
3035        let binding = f
3036            .bind(SupportedVersion::V1(V1::One), &[array_string])
3037            .expect("bind should succeed");
3038        assert_eq!(binding.index(), 0);
3039        assert_eq!(binding.return_type().to_string(), "Array[String]");
3040
3041        // Check for a Array[String?] -> Array[String]
3042        let array_optional_string: Type =
3043            ArrayType::new(Type::from(PrimitiveType::String).optional()).into();
3044        let binding = f
3045            .bind(SupportedVersion::V1(V1::One), &[array_optional_string])
3046            .expect("bind should succeed");
3047        assert_eq!(binding.index(), 0);
3048        assert_eq!(binding.return_type().to_string(), "Array[String]");
3049
3050        // Check for Union (i.e. indeterminate)
3051        let binding = f
3052            .bind(SupportedVersion::V1(V1::Two), &[Type::Union])
3053            .expect("bind should succeed");
3054        assert_eq!(binding.index(), 0);
3055        assert_eq!(binding.return_type().to_string(), "Array[Union]");
3056
3057        // Check for a Array[Array[String]?] -> Array[Array[String]]
3058        let array_string = Type::from(ArrayType::new(PrimitiveType::String)).optional();
3059        let array_array_string = ArrayType::new(array_string).into();
3060        let binding = f
3061            .bind(SupportedVersion::V1(V1::Zero), &[array_array_string])
3062            .expect("bind should succeed");
3063        assert_eq!(binding.index(), 0);
3064        assert_eq!(binding.return_type().to_string(), "Array[Array[String]]");
3065    }
3066
3067    #[test]
3068    fn it_binds_concrete_overloads() {
3069        let f = STDLIB.function("max").expect("should have function");
3070        assert_eq!(f.minimum_version(), SupportedVersion::V1(V1::One));
3071
3072        let e = f
3073            .bind(SupportedVersion::V1(V1::One), &[])
3074            .expect_err("bind should fail");
3075        assert_eq!(e, FunctionBindError::TooFewArguments(2));
3076
3077        let e = f
3078            .bind(
3079                SupportedVersion::V1(V1::Two),
3080                &[
3081                    PrimitiveType::String.into(),
3082                    PrimitiveType::Boolean.into(),
3083                    PrimitiveType::File.into(),
3084                ],
3085            )
3086            .expect_err("bind should fail");
3087        assert_eq!(e, FunctionBindError::TooManyArguments(2));
3088
3089        // Check for `(Int, Int)`
3090        let binding = f
3091            .bind(
3092                SupportedVersion::V1(V1::One),
3093                &[PrimitiveType::Integer.into(), PrimitiveType::Integer.into()],
3094            )
3095            .expect("binding should succeed");
3096        assert_eq!(binding.index(), 0);
3097        assert_eq!(binding.return_type().to_string(), "Int");
3098
3099        // Check for `(Int, Float)`
3100        let binding = f
3101            .bind(
3102                SupportedVersion::V1(V1::Two),
3103                &[PrimitiveType::Integer.into(), PrimitiveType::Float.into()],
3104            )
3105            .expect("binding should succeed");
3106        assert_eq!(binding.index(), 1);
3107        assert_eq!(binding.return_type().to_string(), "Float");
3108
3109        // Check for `(Float, Int)`
3110        let binding = f
3111            .bind(
3112                SupportedVersion::V1(V1::One),
3113                &[PrimitiveType::Float.into(), PrimitiveType::Integer.into()],
3114            )
3115            .expect("binding should succeed");
3116        assert_eq!(binding.index(), 2);
3117        assert_eq!(binding.return_type().to_string(), "Float");
3118
3119        // Check for `(Float, Float)`
3120        let binding = f
3121            .bind(
3122                SupportedVersion::V1(V1::Two),
3123                &[PrimitiveType::Float.into(), PrimitiveType::Float.into()],
3124            )
3125            .expect("binding should succeed");
3126        assert_eq!(binding.index(), 3);
3127        assert_eq!(binding.return_type().to_string(), "Float");
3128
3129        // Check for `(String, Int)`
3130        let e = f
3131            .bind(
3132                SupportedVersion::V1(V1::One),
3133                &[PrimitiveType::String.into(), PrimitiveType::Integer.into()],
3134            )
3135            .expect_err("binding should fail");
3136        assert_eq!(
3137            e,
3138            FunctionBindError::ArgumentTypeMismatch {
3139                index: 0,
3140                expected: "`Int` or `Float`".into()
3141            }
3142        );
3143
3144        // Check for `(Int, String)`
3145        let e = f
3146            .bind(
3147                SupportedVersion::V1(V1::Two),
3148                &[PrimitiveType::Integer.into(), PrimitiveType::String.into()],
3149            )
3150            .expect_err("binding should fail");
3151        assert_eq!(
3152            e,
3153            FunctionBindError::ArgumentTypeMismatch {
3154                index: 1,
3155                expected: "`Int` or `Float`".into()
3156            }
3157        );
3158
3159        // Check for `(String, Float)`
3160        let e = f
3161            .bind(
3162                SupportedVersion::V1(V1::One),
3163                &[PrimitiveType::String.into(), PrimitiveType::Float.into()],
3164            )
3165            .expect_err("binding should fail");
3166        assert_eq!(
3167            e,
3168            FunctionBindError::ArgumentTypeMismatch {
3169                index: 0,
3170                expected: "`Int` or `Float`".into()
3171            }
3172        );
3173
3174        // Check for `(Float, String)`
3175        let e = f
3176            .bind(
3177                SupportedVersion::V1(V1::Two),
3178                &[PrimitiveType::Float.into(), PrimitiveType::String.into()],
3179            )
3180            .expect_err("binding should fail");
3181        assert_eq!(
3182            e,
3183            FunctionBindError::ArgumentTypeMismatch {
3184                index: 1,
3185                expected: "`Int` or `Float`".into()
3186            }
3187        );
3188    }
3189
3190    #[test]
3191    fn it_binds_generic_overloads() {
3192        let f = STDLIB
3193            .function("select_first")
3194            .expect("should have function");
3195        assert_eq!(f.minimum_version(), SupportedVersion::V1(V1::Zero));
3196
3197        let e = f
3198            .bind(SupportedVersion::V1(V1::Zero), &[])
3199            .expect_err("bind should fail");
3200        assert_eq!(e, FunctionBindError::TooFewArguments(1));
3201
3202        let e = f
3203            .bind(
3204                SupportedVersion::V1(V1::One),
3205                &[
3206                    PrimitiveType::String.into(),
3207                    PrimitiveType::Boolean.into(),
3208                    PrimitiveType::File.into(),
3209                ],
3210            )
3211            .expect_err("bind should fail");
3212        assert_eq!(e, FunctionBindError::TooManyArguments(2));
3213
3214        // Check `Int`
3215        let e = f
3216            .bind(
3217                SupportedVersion::V1(V1::Two),
3218                &[PrimitiveType::Integer.into()],
3219            )
3220            .expect_err("binding should fail");
3221        assert_eq!(
3222            e,
3223            FunctionBindError::ArgumentTypeMismatch {
3224                index: 0,
3225                expected: "`Array[X]`".into()
3226            }
3227        );
3228
3229        // Check `Array[String?]+`
3230        let array: Type = ArrayType::non_empty(Type::from(PrimitiveType::String).optional()).into();
3231        let binding = f
3232            .bind(SupportedVersion::V1(V1::Zero), &[array.clone()])
3233            .expect("binding should succeed");
3234        assert_eq!(binding.index(), 0);
3235        assert_eq!(binding.return_type().to_string(), "String");
3236
3237        // Check (`Array[String?]+`, `String`)
3238        let binding = f
3239            .bind(
3240                SupportedVersion::V1(V1::One),
3241                &[array.clone(), PrimitiveType::String.into()],
3242            )
3243            .expect("binding should succeed");
3244        assert_eq!(binding.index(), 0);
3245        assert_eq!(binding.return_type().to_string(), "String");
3246
3247        // Check (`Array[String?]+`, `Int`)
3248        let e = f
3249            .bind(
3250                SupportedVersion::V1(V1::Two),
3251                &[array.clone(), PrimitiveType::Integer.into()],
3252            )
3253            .expect_err("binding should fail");
3254        assert_eq!(
3255            e,
3256            FunctionBindError::ArgumentTypeMismatch {
3257                index: 1,
3258                expected: "`String`".into()
3259            }
3260        );
3261
3262        // Check `Array[String?]`
3263        let array: Type = ArrayType::new(Type::from(PrimitiveType::String).optional()).into();
3264        let binding = f
3265            .bind(SupportedVersion::V1(V1::Zero), &[array.clone()])
3266            .expect("binding should succeed");
3267        assert_eq!(binding.index(), 0);
3268        assert_eq!(binding.return_type().to_string(), "String");
3269
3270        // Check (`Array[String?]`, `String`)
3271        let binding = f
3272            .bind(
3273                SupportedVersion::V1(V1::One),
3274                &[array.clone(), PrimitiveType::String.into()],
3275            )
3276            .expect("binding should succeed");
3277        assert_eq!(binding.index(), 0);
3278        assert_eq!(binding.return_type().to_string(), "String");
3279
3280        // Check (`Array[String?]`, `Int`)
3281        let e = f
3282            .bind(
3283                SupportedVersion::V1(V1::Two),
3284                &[array, PrimitiveType::Integer.into()],
3285            )
3286            .expect_err("binding should fail");
3287        assert_eq!(
3288            e,
3289            FunctionBindError::ArgumentTypeMismatch {
3290                index: 1,
3291                expected: "`String`".into()
3292            }
3293        );
3294    }
3295}