Skip to main content

leo_parser_rowan/parser/
types.rs

1// Copyright (C) 2019-2026 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17//! Type parsing for the Leo language.
18//!
19//! This module implements parsing for all Leo type expressions:
20//! - Primitive types: bool, field, group, scalar, address, signature, string
21//! - Integer types: u8, u16, u32, u64, u128, i8, i16, i32, i64, i128
22//! - Array types: [Type; len] or [Type] (vector)
23//! - Tuple types: (Type1, Type2, ...) or () (unit)
24//! - Optional types: Type?
25//! - Future types: Future or Future<fn(Types) -> Type>
26//! - Composite types: Named, Foo::[N], program.aleo::Type (locator)
27
28use super::{CompletedMarker, Parser};
29use crate::syntax_kind::SyntaxKind::*;
30
31/// Options for type parsing to handle context-sensitive cases.
32#[derive(Default, Clone, Copy)]
33pub struct TypeOpts {
34    /// Whether to allow the optional `?` suffix.
35    pub allow_optional: bool,
36}
37
38impl TypeOpts {
39    /// Allow optional suffix on parsed type.
40    pub fn allow_optional(mut self) -> Self {
41        self.allow_optional = true;
42        self
43    }
44}
45
46impl Parser<'_, '_> {
47    /// Primitive type keywords allowed in cast expressions.
48    pub const PRIMITIVE_TYPE_KINDS: &'static [crate::syntax_kind::SyntaxKind] = &[
49        KW_ADDRESS,
50        KW_BOOL,
51        KW_FIELD,
52        KW_GROUP,
53        KW_SCALAR,
54        KW_SIGNATURE,
55        KW_STRING,
56        KW_IDENTIFIER,
57        KW_DYN,
58        KW_I8,
59        KW_I16,
60        KW_I32,
61        KW_I64,
62        KW_I128,
63        KW_U8,
64        KW_U16,
65        KW_U32,
66        KW_U64,
67        KW_U128,
68    ];
69
70    /// Parse a type expression.
71    ///
72    /// Returns `None` if the current token cannot start a type.
73    pub fn parse_type(&mut self) -> Option<CompletedMarker> {
74        self.parse_type_with_opts(TypeOpts::default().allow_optional())
75    }
76
77    /// Parse a type expression with options.
78    pub fn parse_type_with_opts(&mut self, opts: TypeOpts) -> Option<CompletedMarker> {
79        let ty = self.parse_type_inner()?;
80
81        // Optional suffix: Type?
82        if opts.allow_optional && self.at(QUESTION) {
83            let m = ty.precede(self);
84            self.bump_any(); // ?
85            return Some(m.complete(self, TYPE_OPTIONAL));
86        }
87
88        Some(ty)
89    }
90
91    /// Parse the core type expression (without optional suffix).
92    fn parse_type_inner(&mut self) -> Option<CompletedMarker> {
93        // Skip leading trivia before starting the type node
94        self.skip_trivia();
95
96        match self.current() {
97            // Unit or Tuple: ()  or (T1, T2, ...)
98            L_PAREN => self.parse_tuple_type(),
99            // Array or Vector: [T; N] or [T]
100            L_BRACKET => self.parse_array_or_vector_type(),
101            // Final: Final or Final<...>
102            KW_FINAL_UPPER => self.parse_future_type(),
103            // Mapping type (storage context): mapping key => value
104            KW_MAPPING => self.parse_mapping_type(),
105            // Dynamic record type: dyn record
106            KW_DYN => self.parse_dyn_record_type(),
107            // Primitive type keywords
108            _ if self.at_primitive_type() => self.parse_primitive_type(),
109            // Named/Composite type: Foo, Foo::[N], program.aleo::Type
110            IDENT => self.parse_named_type(),
111            _ => None,
112        }
113    }
114
115    /// Check if the current token is a primitive type keyword.
116    fn at_primitive_type(&self) -> bool {
117        Self::PRIMITIVE_TYPE_KINDS.contains(&self.current())
118    }
119
120    /// Parse a cast type (primitive types and `dyn record`).
121    pub fn parse_cast_type(&mut self) -> Option<CompletedMarker> {
122        if self.at_primitive_type() {
123            self.parse_primitive_type()
124        } else if self.at(KW_DYN) {
125            self.parse_dyn_record_type()
126        } else {
127            None
128        }
129    }
130
131    /// Parse a primitive type keyword.
132    fn parse_primitive_type(&mut self) -> Option<CompletedMarker> {
133        if !self.at_primitive_type() {
134            return None;
135        }
136
137        // Skip trivia before starting the node so leading whitespace
138        // isn't captured inside the TYPE_PRIMITIVE.
139        self.skip_trivia();
140        let m = self.start();
141        let kind = self.current();
142        self.bump_raw();
143        // `dyn record` is a two-token primitive type.
144        if kind == KW_DYN {
145            self.expect(KW_RECORD);
146        }
147        Some(m.complete(self, TYPE_PRIMITIVE))
148    }
149
150    /// Parse a `dyn record` type.
151    fn parse_dyn_record_type(&mut self) -> Option<CompletedMarker> {
152        if !self.at(KW_DYN) {
153            return None;
154        }
155        self.skip_trivia();
156        let m = self.start();
157        self.bump_any(); // dyn
158        // Expect `record` keyword following `dyn`.
159        if !self.eat(KW_RECORD) {
160            self.error("expected `record` after `dyn`");
161        }
162        Some(m.complete(self, TYPE_DYN_RECORD))
163    }
164
165    /// Parse a tuple type: `(T1, T2, ...)` or unit `()`.
166    fn parse_tuple_type(&mut self) -> Option<CompletedMarker> {
167        if !self.at(L_PAREN) {
168            return None;
169        }
170
171        let m = self.start();
172        self.bump_any(); // (
173
174        // Check for unit: ()
175        if self.eat(R_PAREN) {
176            return Some(m.complete(self, TYPE_TUPLE));
177        }
178
179        // Parse first element
180        self.parse_type_with_opts(TypeOpts::default().allow_optional());
181
182        // Parse remaining elements
183        while self.eat(COMMA) {
184            if self.at(R_PAREN) {
185                // Trailing comma
186                break;
187            }
188            self.parse_type_with_opts(TypeOpts::default().allow_optional());
189        }
190
191        self.expect(R_PAREN);
192        Some(m.complete(self, TYPE_TUPLE))
193    }
194
195    /// Parse an array type `[T; N]` or vector type `[T]`.
196    fn parse_array_or_vector_type(&mut self) -> Option<CompletedMarker> {
197        if !self.at(L_BRACKET) {
198            return None;
199        }
200
201        let m = self.start();
202        self.bump_any(); // [
203
204        // Parse element type
205        self.parse_type_with_opts(TypeOpts::default().allow_optional());
206
207        // Check for array length: ; N
208        if self.eat(SEMICOLON) {
209            // Array with explicit length: [T; N]
210            let len = self.start();
211            self.parse_array_length();
212            len.complete(self, ARRAY_LENGTH);
213            self.expect(R_BRACKET);
214            return Some(m.complete(self, TYPE_ARRAY));
215        }
216
217        // If we see ',' instead of ';' or ']', suggest the array syntax.
218        if self.at(COMMA) {
219            self.error("expected ';' for array type, found ','");
220            self.recover(&[R_BRACKET]);
221            self.eat(R_BRACKET);
222            return Some(m.complete(self, TYPE_ARRAY));
223        }
224
225        // Vector: [T]
226        self.expect(R_BRACKET);
227        Some(m.complete(self, TYPE_VECTOR))
228    }
229
230    /// Parse an array length expression.
231    ///
232    /// Supports integer literals (`[T; 10]`), identifiers (`[T; N]`),
233    /// paths (`[T; Foo::SIZE]`), and arbitrary expressions (`[T; N + M]`).
234    fn parse_array_length(&mut self) {
235        self.parse_expr();
236    }
237
238    /// Parse a Final type: `Final` or `Final<fn(T1, T2) -> R>`.
239    fn parse_future_type(&mut self) -> Option<CompletedMarker> {
240        if !self.at(KW_FINAL_UPPER) {
241            return None;
242        }
243
244        let m = self.start();
245        self.bump_any(); // Future
246
247        // Check for explicit Future signature: Future<fn(T) -> R>
248        if self.eat(LT) {
249            // Parse fn(...) -> R
250            self.expect(KW_FN_UPPER);
251            self.expect(L_PAREN);
252
253            // Parse parameter types
254            if !self.at(R_PAREN) {
255                self.parse_type_with_opts(TypeOpts::default().allow_optional());
256                while self.eat(COMMA) {
257                    if self.at(R_PAREN) {
258                        break;
259                    }
260                    self.parse_type_with_opts(TypeOpts::default().allow_optional());
261                }
262            }
263
264            self.expect(R_PAREN);
265
266            // Return type
267            if self.eat(ARROW) {
268                self.parse_type_with_opts(TypeOpts::default().allow_optional());
269            }
270
271            self.expect(GT);
272        }
273
274        Some(m.complete(self, TYPE_FINAL))
275    }
276
277    /// Parse a mapping type: `mapping key => value`.
278    fn parse_mapping_type(&mut self) -> Option<CompletedMarker> {
279        if !self.at(KW_MAPPING) {
280            return None;
281        }
282
283        let m = self.start();
284        self.bump_any(); // mapping
285
286        // Parse key type
287        self.parse_type();
288
289        // Expect =>
290        self.expect(FAT_ARROW);
291
292        // Parse value type
293        self.parse_type();
294
295        Some(m.complete(self, TYPE_MAPPING))
296    }
297
298    /// Parse a named/composite type.
299    ///
300    /// This handles:
301    /// - Simple names: `Foo`
302    /// - Paths: `Foo::Bar`
303    /// - Const generics: `Foo::[N]` or `Foo::<N>`
304    /// - Locators: `program.aleo::Type`
305    fn parse_named_type(&mut self) -> Option<CompletedMarker> {
306        if !self.at(IDENT) {
307            return None;
308        }
309
310        let m = self.start();
311        self.bump_any(); // first identifier
312
313        // Check for locator: name.aleo::Type
314        if self.at(DOT) && self.nth(1) == KW_ALEO {
315            self.bump_any(); // .
316            self.bump_any(); // aleo
317
318            if self.eat(COLON_COLON) {
319                // Locator path: program.aleo::Type
320                if self.at(IDENT) {
321                    self.bump_any();
322                } else {
323                    self.error("expected type name after ::");
324                }
325            }
326
327            // Optional const generic args after locator: child.aleo::Bar::[4]
328            if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
329                self.bump_any(); // ::
330                self.parse_const_generic_args_bracket();
331            }
332
333            return Some(m.complete(self, TYPE_LOCATOR));
334        }
335
336        // Check for path or const generics: Foo::Bar or Foo::[N]
337        while self.eat(COLON_COLON) {
338            if self.at(L_BRACKET) {
339                // Const generics with brackets: Foo::[N]
340                self.parse_const_generic_args_bracket();
341                break;
342            } else if self.at(LT) {
343                // Const generics with angle brackets: Foo::<N>
344                self.parse_const_generic_args_angle();
345                break;
346            } else if self.at(IDENT) {
347                self.bump_any();
348            } else {
349                self.error("expected identifier, [, or < after ::");
350                break;
351            }
352        }
353
354        Some(m.complete(self, TYPE_PATH))
355    }
356
357    /// Parse a const generic parameter list (declaration site): `::[N: u32, M: u32]`.
358    ///
359    /// Wraps the list in a `CONST_PARAM_LIST` node. Each parameter is
360    /// wrapped in a `CONST_PARAM` node containing `name: Type`.
361    pub fn parse_const_param_list(&mut self) {
362        let m = self.start();
363
364        if !self.eat(L_BRACKET) {
365            m.abandon(self);
366            return;
367        }
368
369        // Parse comma-separated const params
370        if !self.at(R_BRACKET) {
371            self.parse_const_param();
372            while self.eat(COMMA) {
373                if self.at(R_BRACKET) {
374                    break;
375                }
376                self.parse_const_param();
377            }
378        }
379
380        self.expect(R_BRACKET);
381        m.complete(self, CONST_PARAM_LIST);
382    }
383
384    /// Parse a single const generic parameter: `N: u32`.
385    fn parse_const_param(&mut self) {
386        let m = self.start();
387        self.skip_trivia();
388
389        if self.at(IDENT) {
390            self.bump_any(); // param name
391        } else {
392            self.error("expected const parameter name");
393        }
394
395        self.expect(COLON);
396        self.parse_type();
397
398        m.complete(self, CONST_PARAM);
399    }
400
401    /// Parse const generic arguments with bracket syntax (use site): `::[N]` or `::[N + 1, u32]`.
402    ///
403    /// Each argument may be an expression or a type (for intrinsics).
404    /// Wraps the list in a `CONST_ARG_LIST` node.
405    pub fn parse_const_generic_args_bracket(&mut self) {
406        let m = self.start();
407
408        if !self.eat(L_BRACKET) {
409            m.abandon(self);
410            return;
411        }
412
413        // Parse comma-separated arguments
414        if !self.at(R_BRACKET) {
415            self.parse_const_generic_arg();
416            while self.eat(COMMA) {
417                if self.at(R_BRACKET) {
418                    break;
419                }
420                // Clear error state so each argument gets fresh error reporting.
421                self.erroring = false;
422                self.parse_const_generic_arg();
423            }
424        }
425
426        self.expect(R_BRACKET);
427        m.complete(self, CONST_ARG_LIST);
428    }
429
430    /// Parse const generic arguments with angle bracket syntax: `::<N>` or `::<N, M>`.
431    ///
432    /// Only accepts simple IDENT/INTEGER arguments because `>` conflicts
433    /// with the expression parser's greater-than operator. Angle bracket
434    /// generics are low priority (the LALRPOP grammar doesn't use them).
435    pub fn parse_const_generic_args_angle(&mut self) {
436        let m = self.start();
437
438        if !self.eat(LT) {
439            m.abandon(self);
440            return;
441        }
442
443        // Simple arg parser — avoids expression parser which would consume `>`.
444        if self.at(IDENT) || self.at(INTEGER) {
445            self.bump_any();
446        }
447
448        while self.eat(COMMA) {
449            if self.at(GT) {
450                break;
451            }
452            if self.at(IDENT) || self.at(INTEGER) {
453                self.bump_any();
454            } else {
455                self.error("expected const generic argument");
456                break;
457            }
458        }
459
460        self.expect(GT);
461        m.complete(self, CONST_ARG_LIST);
462    }
463
464    /// Parse a single const generic argument (expression or type).
465    ///
466    /// At use sites, `::[]` can contain either expressions (`N + 1`, `5`)
467    /// or types (`u32`, `[u8; 4]`). The heuristic: if the current token
468    /// is a primitive type keyword, or `[` followed by a primitive type
469    /// keyword (array type arg), parse as a type. Otherwise parse as an
470    /// expression.
471    fn parse_const_generic_arg(&mut self) {
472        self.skip_trivia();
473        if matches!(self.current(), KW_PUBLIC | KW_PRIVATE | KW_CONSTANT) {
474            // Visibility-prefixed type argument (e.g. `public u64` in `_dynamic_call::[public u64]`).
475            let m = self.start();
476            self.bump_any(); // visibility keyword
477            self.parse_type();
478            m.complete(self, DYNAMIC_CALL_RETURN_TYPE);
479        } else if self.at_primitive_type() {
480            // Type argument (e.g. `u32` in `Deserialize::[u32]`)
481            self.parse_type();
482        } else if self.at(L_BRACKET) && self.nth(1).is_type_keyword() {
483            // Array type argument (e.g. `[u8; 4]` in `Deserialize::[[u8; 4]]`)
484            self.parse_type();
485        } else if self.at(KW_FINAL_UPPER) {
486            // Final type argument (e.g. `Final` in `_dynamic_call::[Final]`)
487            self.parse_type();
488        } else if self.at(KW_DYN) {
489            // Dynamic record type argument (e.g. `dyn record` in `_dynamic_call::[dyn record]`)
490            self.parse_type();
491        } else if self.at(L_PAREN) && (self.nth(1) == R_PAREN || Self::PRIMITIVE_TYPE_KINDS.contains(&self.nth(1))) {
492            // Tuple type argument (e.g. `(u32, u32)` in `_dynamic_call::[(u32, u32)]`).
493            // Distinguish from parenthesized expressions like `(A * 2)` using lookahead:
494            // `()` or `(` followed by a primitive type keyword is a tuple type.
495            self.parse_type();
496        } else {
497            // Expression argument (e.g. `N + 1`, `5`, `N`)
498            self.parse_expr();
499        }
500    }
501}
502
503#[cfg(test)]
504mod tests {
505    use super::*;
506    use crate::{lexer::lex, parser::Parse};
507    use expect_test::{Expect, expect};
508
509    fn check_type(input: &str, expect: Expect) {
510        let (tokens, _) = lex(input);
511        let mut parser = Parser::new(input, &tokens);
512        let root = parser.start();
513        parser.parse_type();
514        parser.skip_trivia();
515        root.complete(&mut parser, ROOT);
516        let parse: Parse = parser.finish(vec![]);
517        let output = format!("{:#?}", parse.syntax());
518        expect.assert_eq(&output);
519    }
520
521    fn check_type_optional(input: &str, expect: Expect) {
522        let (tokens, _) = lex(input);
523        let mut parser = Parser::new(input, &tokens);
524        let root = parser.start();
525        parser.parse_type_with_opts(TypeOpts::default().allow_optional());
526        parser.skip_trivia();
527        root.complete(&mut parser, ROOT);
528        let parse: Parse = parser.finish(vec![]);
529        let output = format!("{:#?}", parse.syntax());
530        expect.assert_eq(&output);
531    }
532
533    // =========================================================================
534    // Primitive Types
535    // =========================================================================
536
537    #[test]
538    fn parse_type_bool() {
539        check_type("bool", expect![[r#"
540            ROOT@0..4
541              TYPE_PRIMITIVE@0..4
542                KW_BOOL@0..4 "bool"
543        "#]]);
544    }
545
546    #[test]
547    fn parse_type_field() {
548        check_type("field", expect![[r#"
549            ROOT@0..5
550              TYPE_PRIMITIVE@0..5
551                KW_FIELD@0..5 "field"
552        "#]]);
553    }
554
555    #[test]
556    fn parse_type_group() {
557        check_type("group", expect![[r#"
558            ROOT@0..5
559              TYPE_PRIMITIVE@0..5
560                KW_GROUP@0..5 "group"
561        "#]]);
562    }
563
564    #[test]
565    fn parse_type_address() {
566        check_type("address", expect![[r#"
567            ROOT@0..7
568              TYPE_PRIMITIVE@0..7
569                KW_ADDRESS@0..7 "address"
570        "#]]);
571    }
572
573    #[test]
574    fn parse_type_scalar() {
575        check_type("scalar", expect![[r#"
576            ROOT@0..6
577              TYPE_PRIMITIVE@0..6
578                KW_SCALAR@0..6 "scalar"
579        "#]]);
580    }
581
582    #[test]
583    fn parse_type_signature() {
584        check_type("signature", expect![[r#"
585            ROOT@0..9
586              TYPE_PRIMITIVE@0..9
587                KW_SIGNATURE@0..9 "signature"
588        "#]]);
589    }
590
591    #[test]
592    fn parse_type_string() {
593        check_type("string", expect![[r#"
594            ROOT@0..6
595              TYPE_PRIMITIVE@0..6
596                KW_STRING@0..6 "string"
597        "#]]);
598    }
599
600    #[test]
601    fn parse_type_identifier() {
602        check_type("identifier", expect![[r#"
603            ROOT@0..10
604              TYPE_PRIMITIVE@0..10
605                KW_IDENTIFIER@0..10 "identifier"
606        "#]]);
607    }
608
609    #[test]
610    fn parse_type_u32() {
611        check_type("u32", expect![[r#"
612            ROOT@0..3
613              TYPE_PRIMITIVE@0..3
614                KW_U32@0..3 "u32"
615        "#]]);
616    }
617
618    #[test]
619    fn parse_type_i128() {
620        check_type("i128", expect![[r#"
621            ROOT@0..4
622              TYPE_PRIMITIVE@0..4
623                KW_I128@0..4 "i128"
624        "#]]);
625    }
626
627    // =========================================================================
628    // Tuple Types
629    // =========================================================================
630
631    #[test]
632    fn parse_type_unit() {
633        check_type("()", expect![[r#"
634                ROOT@0..2
635                  TYPE_TUPLE@0..2
636                    L_PAREN@0..1 "("
637                    R_PAREN@1..2 ")"
638            "#]]);
639    }
640
641    #[test]
642    fn parse_type_tuple_single() {
643        check_type("(u32)", expect![[r#"
644            ROOT@0..5
645              TYPE_TUPLE@0..5
646                L_PAREN@0..1 "("
647                TYPE_PRIMITIVE@1..4
648                  KW_U32@1..4 "u32"
649                R_PAREN@4..5 ")"
650        "#]]);
651    }
652
653    #[test]
654    fn parse_type_tuple_pair() {
655        check_type("(u32, field)", expect![[r#"
656            ROOT@0..12
657              TYPE_TUPLE@0..12
658                L_PAREN@0..1 "("
659                TYPE_PRIMITIVE@1..4
660                  KW_U32@1..4 "u32"
661                COMMA@4..5 ","
662                WHITESPACE@5..6 " "
663                TYPE_PRIMITIVE@6..11
664                  KW_FIELD@6..11 "field"
665                R_PAREN@11..12 ")"
666        "#]]);
667    }
668
669    #[test]
670    fn parse_type_tuple_trailing_comma() {
671        check_type("(u32, field,)", expect![[r#"
672            ROOT@0..13
673              TYPE_TUPLE@0..13
674                L_PAREN@0..1 "("
675                TYPE_PRIMITIVE@1..4
676                  KW_U32@1..4 "u32"
677                COMMA@4..5 ","
678                WHITESPACE@5..6 " "
679                TYPE_PRIMITIVE@6..11
680                  KW_FIELD@6..11 "field"
681                COMMA@11..12 ","
682                R_PAREN@12..13 ")"
683        "#]]);
684    }
685
686    // =========================================================================
687    // Array Types
688    // =========================================================================
689
690    #[test]
691    fn parse_type_array_fixed() {
692        check_type("[u32; 10]", expect![[r#"
693            ROOT@0..9
694              TYPE_ARRAY@0..9
695                L_BRACKET@0..1 "["
696                TYPE_PRIMITIVE@1..4
697                  KW_U32@1..4 "u32"
698                SEMICOLON@4..5 ";"
699                ARRAY_LENGTH@5..8
700                  WHITESPACE@5..6 " "
701                  LITERAL_INT@6..8
702                    INTEGER@6..8 "10"
703                R_BRACKET@8..9 "]"
704        "#]]);
705    }
706
707    #[test]
708    fn parse_type_array_const_generic() {
709        check_type("[field; N]", expect![[r#"
710            ROOT@0..10
711              TYPE_ARRAY@0..10
712                L_BRACKET@0..1 "["
713                TYPE_PRIMITIVE@1..6
714                  KW_FIELD@1..6 "field"
715                SEMICOLON@6..7 ";"
716                ARRAY_LENGTH@7..9
717                  WHITESPACE@7..8 " "
718                  PATH_EXPR@8..9
719                    IDENT@8..9 "N"
720                R_BRACKET@9..10 "]"
721        "#]]);
722    }
723
724    #[test]
725    fn parse_type_vector() {
726        check_type("[u8]", expect![[r#"
727            ROOT@0..4
728              TYPE_VECTOR@0..4
729                L_BRACKET@0..1 "["
730                TYPE_PRIMITIVE@1..3
731                  KW_U8@1..3 "u8"
732                R_BRACKET@3..4 "]"
733        "#]]);
734    }
735
736    #[test]
737    fn parse_type_nested_array() {
738        check_type("[[u32; 3]; 2]", expect![[r#"
739            ROOT@0..13
740              TYPE_ARRAY@0..13
741                L_BRACKET@0..1 "["
742                TYPE_ARRAY@1..9
743                  L_BRACKET@1..2 "["
744                  TYPE_PRIMITIVE@2..5
745                    KW_U32@2..5 "u32"
746                  SEMICOLON@5..6 ";"
747                  ARRAY_LENGTH@6..8
748                    WHITESPACE@6..7 " "
749                    LITERAL_INT@7..8
750                      INTEGER@7..8 "3"
751                  R_BRACKET@8..9 "]"
752                SEMICOLON@9..10 ";"
753                ARRAY_LENGTH@10..12
754                  WHITESPACE@10..11 " "
755                  LITERAL_INT@11..12
756                    INTEGER@11..12 "2"
757                R_BRACKET@12..13 "]"
758        "#]]);
759    }
760
761    // =========================================================================
762    // Optional Types
763    // =========================================================================
764
765    #[test]
766    fn parse_type_optional() {
767        check_type_optional("u32?", expect![[r#"
768            ROOT@0..4
769              TYPE_OPTIONAL@0..4
770                TYPE_PRIMITIVE@0..3
771                  KW_U32@0..3 "u32"
772                QUESTION@3..4 "?"
773        "#]]);
774    }
775
776    #[test]
777    fn parse_type_optional_named() {
778        check_type_optional("Token?", expect![[r#"
779                ROOT@0..6
780                  TYPE_OPTIONAL@0..6
781                    TYPE_PATH@0..5
782                      IDENT@0..5 "Token"
783                    QUESTION@5..6 "?"
784            "#]]);
785    }
786
787    // =========================================================================
788    // Named/Composite Types
789    // =========================================================================
790
791    #[test]
792    fn parse_type_named_simple() {
793        check_type("Token", expect![[r#"
794                ROOT@0..5
795                  TYPE_PATH@0..5
796                    IDENT@0..5 "Token"
797            "#]]);
798    }
799
800    #[test]
801    fn parse_type_named_path() {
802        check_type("Foo::Bar", expect![[r#"
803                ROOT@0..8
804                  TYPE_PATH@0..8
805                    IDENT@0..3 "Foo"
806                    COLON_COLON@3..5 "::"
807                    IDENT@5..8 "Bar"
808            "#]]);
809    }
810
811    #[test]
812    fn parse_type_named_const_generic_bracket() {
813        check_type("Poseidon::[N]", expect![[r#"
814            ROOT@0..13
815              TYPE_PATH@0..13
816                IDENT@0..8 "Poseidon"
817                COLON_COLON@8..10 "::"
818                CONST_ARG_LIST@10..13
819                  L_BRACKET@10..11 "["
820                  PATH_EXPR@11..12
821                    IDENT@11..12 "N"
822                  R_BRACKET@12..13 "]"
823        "#]]);
824    }
825
826    #[test]
827    fn parse_type_named_const_generic_angle() {
828        check_type("Poseidon::<4>", expect![[r#"
829            ROOT@0..13
830              TYPE_PATH@0..13
831                IDENT@0..8 "Poseidon"
832                COLON_COLON@8..10 "::"
833                CONST_ARG_LIST@10..13
834                  LT@10..11 "<"
835                  INTEGER@11..12 "4"
836                  GT@12..13 ">"
837        "#]]);
838    }
839
840    #[test]
841    fn parse_type_locator() {
842        check_type("credits.aleo::Token", expect![[r#"
843            ROOT@0..19
844              TYPE_LOCATOR@0..19
845                IDENT@0..7 "credits"
846                DOT@7..8 "."
847                KW_ALEO@8..12 "aleo"
848                COLON_COLON@12..14 "::"
849                IDENT@14..19 "Token"
850        "#]]);
851    }
852
853    #[test]
854    fn parse_type_program_id_without_type() {
855        // Just program.aleo without /Type
856        check_type("credits.aleo", expect![[r#"
857            ROOT@0..12
858              TYPE_LOCATOR@0..12
859                IDENT@0..7 "credits"
860                DOT@7..8 "."
861                KW_ALEO@8..12 "aleo"
862        "#]]);
863    }
864
865    // =========================================================================
866    // Future Types
867    // =========================================================================
868
869    #[test]
870    fn parse_type_final_simple() {
871        check_type("Final", expect![[r#"
872                ROOT@0..5
873                  TYPE_FINAL@0..5
874                    KW_FINAL_UPPER@0..5 "Final"
875            "#]]);
876    }
877
878    #[test]
879    fn parse_type_final_explicit() {
880        check_type("Final<Fn(u32) -> field>", expect![[r#"
881            ROOT@0..23
882              TYPE_FINAL@0..23
883                KW_FINAL_UPPER@0..5 "Final"
884                LT@5..6 "<"
885                KW_FN_UPPER@6..8 "Fn"
886                L_PAREN@8..9 "("
887                TYPE_PRIMITIVE@9..12
888                  KW_U32@9..12 "u32"
889                R_PAREN@12..13 ")"
890                WHITESPACE@13..14 " "
891                ARROW@14..16 "->"
892                WHITESPACE@16..17 " "
893                TYPE_PRIMITIVE@17..22
894                  KW_FIELD@17..22 "field"
895                GT@22..23 ">"
896        "#]]);
897    }
898
899    #[test]
900    fn parse_type_final_no_params() {
901        check_type("Final<Fn() -> ()>", expect![[r#"
902                ROOT@0..17
903                  TYPE_FINAL@0..17
904                    KW_FINAL_UPPER@0..5 "Final"
905                    LT@5..6 "<"
906                    KW_FN_UPPER@6..8 "Fn"
907                    L_PAREN@8..9 "("
908                    R_PAREN@9..10 ")"
909                    WHITESPACE@10..11 " "
910                    ARROW@11..13 "->"
911                    WHITESPACE@13..14 " "
912                    TYPE_TUPLE@14..16
913                      L_PAREN@14..15 "("
914                      R_PAREN@15..16 ")"
915                    GT@16..17 ">"
916            "#]]);
917    }
918
919    // =========================================================================
920    // Mapping Types
921    // =========================================================================
922
923    #[test]
924    fn parse_type_mapping() {
925        check_type("mapping address => u64", expect![[r#"
926            ROOT@0..22
927              TYPE_MAPPING@0..22
928                KW_MAPPING@0..7 "mapping"
929                WHITESPACE@7..8 " "
930                TYPE_PRIMITIVE@8..15
931                  KW_ADDRESS@8..15 "address"
932                WHITESPACE@15..16 " "
933                FAT_ARROW@16..18 "=>"
934                WHITESPACE@18..19 " "
935                TYPE_PRIMITIVE@19..22
936                  KW_U64@19..22 "u64"
937        "#]]);
938    }
939
940    // =========================================================================
941    // Const Generic Arguments (Use Sites) in Types
942    // =========================================================================
943
944    fn check_type_no_errors(input: &str) {
945        let (tokens, _) = lex(input);
946        let mut parser = Parser::new(input, &tokens);
947        let root = parser.start();
948        parser.parse_type();
949        parser.skip_trivia();
950        root.complete(&mut parser, ROOT);
951        let parse: Parse = parser.finish(vec![]);
952        if !parse.errors().is_empty() {
953            for err in parse.errors() {
954                eprintln!("error at {:?}: {}", err.range, err.message);
955            }
956            eprintln!("tree:\n{:#?}", parse.syntax());
957            panic!("type parse had {} error(s)", parse.errors().len());
958        }
959    }
960
961    #[test]
962    fn parse_type_const_generic_expr_simple() {
963        // Expression arg: integer literal
964        check_type_no_errors("Foo::[3]");
965    }
966
967    #[test]
968    fn parse_type_const_generic_expr_add() {
969        // Expression arg: binary expression
970        check_type_no_errors("Foo::[N + 1]");
971    }
972
973    #[test]
974    fn parse_type_const_generic_expr_mul() {
975        check_type_no_errors("Foo::[2 * N]");
976    }
977
978    #[test]
979    fn parse_type_const_generic_multi_args() {
980        check_type_no_errors("Matrix::[M, K, N]");
981    }
982
983    #[test]
984    fn parse_type_const_generic_type_arg() {
985        // Type arg: primitive type keyword (used by intrinsics)
986        check_type_no_errors("Deserialize::[u32]");
987    }
988
989    #[test]
990    fn parse_type_const_generic_array_type_arg() {
991        // Array type arg: [u8; 4] inside ::[]
992        check_type_no_errors("Deserialize::[[u8; 4]]");
993    }
994
995    #[test]
996    fn parse_type_locator_const_generic() {
997        // Locator + const generic args
998        check_type_no_errors("child.aleo::Bar::[4]");
999    }
1000
1001    // =========================================================================
1002    // Nested Tuple Types (4a)
1003    // =========================================================================
1004
1005    #[test]
1006    fn parse_type_tuple_nested() {
1007        check_type("((u32, u64), bool)", expect![[r#"
1008            ROOT@0..18
1009              TYPE_TUPLE@0..18
1010                L_PAREN@0..1 "("
1011                TYPE_TUPLE@1..11
1012                  L_PAREN@1..2 "("
1013                  TYPE_PRIMITIVE@2..5
1014                    KW_U32@2..5 "u32"
1015                  COMMA@5..6 ","
1016                  WHITESPACE@6..7 " "
1017                  TYPE_PRIMITIVE@7..10
1018                    KW_U64@7..10 "u64"
1019                  R_PAREN@10..11 ")"
1020                COMMA@11..12 ","
1021                WHITESPACE@12..13 " "
1022                TYPE_PRIMITIVE@13..17
1023                  KW_BOOL@13..17 "bool"
1024                R_PAREN@17..18 ")"
1025        "#]]);
1026    }
1027
1028    // =========================================================================
1029    // Optional of Composite Types (4b)
1030    // =========================================================================
1031
1032    #[test]
1033    fn parse_type_optional_array() {
1034        check_type_optional("[u32; 3]?", expect![[r#"
1035            ROOT@0..9
1036              TYPE_OPTIONAL@0..9
1037                TYPE_ARRAY@0..8
1038                  L_BRACKET@0..1 "["
1039                  TYPE_PRIMITIVE@1..4
1040                    KW_U32@1..4 "u32"
1041                  SEMICOLON@4..5 ";"
1042                  ARRAY_LENGTH@5..7
1043                    WHITESPACE@5..6 " "
1044                    LITERAL_INT@6..7
1045                      INTEGER@6..7 "3"
1046                  R_BRACKET@7..8 "]"
1047                QUESTION@8..9 "?"
1048        "#]]);
1049    }
1050
1051    #[test]
1052    fn parse_type_optional_tuple() {
1053        check_type_optional("(u32, u64)?", expect![[r#"
1054            ROOT@0..11
1055              TYPE_OPTIONAL@0..11
1056                TYPE_TUPLE@0..10
1057                  L_PAREN@0..1 "("
1058                  TYPE_PRIMITIVE@1..4
1059                    KW_U32@1..4 "u32"
1060                  COMMA@4..5 ","
1061                  WHITESPACE@5..6 " "
1062                  TYPE_PRIMITIVE@6..9
1063                    KW_U64@6..9 "u64"
1064                  R_PAREN@9..10 ")"
1065                QUESTION@10..11 "?"
1066        "#]]);
1067    }
1068
1069    // =========================================================================
1070    // Final with Multiple Parameters (4c)
1071    // =========================================================================
1072
1073    #[test]
1074    fn parse_type_final_multi_param() {
1075        check_type("Final<Fn(u32, field, group) -> (u32, u64)>", expect![[r#"
1076            ROOT@0..42
1077              TYPE_FINAL@0..42
1078                KW_FINAL_UPPER@0..5 "Final"
1079                LT@5..6 "<"
1080                KW_FN_UPPER@6..8 "Fn"
1081                L_PAREN@8..9 "("
1082                TYPE_PRIMITIVE@9..12
1083                  KW_U32@9..12 "u32"
1084                COMMA@12..13 ","
1085                WHITESPACE@13..14 " "
1086                TYPE_PRIMITIVE@14..19
1087                  KW_FIELD@14..19 "field"
1088                COMMA@19..20 ","
1089                WHITESPACE@20..21 " "
1090                TYPE_PRIMITIVE@21..26
1091                  KW_GROUP@21..26 "group"
1092                R_PAREN@26..27 ")"
1093                WHITESPACE@27..28 " "
1094                ARROW@28..30 "->"
1095                WHITESPACE@30..31 " "
1096                TYPE_TUPLE@31..41
1097                  L_PAREN@31..32 "("
1098                  TYPE_PRIMITIVE@32..35
1099                    KW_U32@32..35 "u32"
1100                  COMMA@35..36 ","
1101                  WHITESPACE@36..37 " "
1102                  TYPE_PRIMITIVE@37..40
1103                    KW_U64@37..40 "u64"
1104                  R_PAREN@40..41 ")"
1105                GT@41..42 ">"
1106        "#]]);
1107    }
1108
1109    // =========================================================================
1110    // Const Generic Expression Arguments (4d)
1111    // =========================================================================
1112
1113    #[test]
1114    fn parse_type_const_generic_expr_sub() {
1115        check_type("Foo::[N - 1]", expect![[r#"
1116            ROOT@0..12
1117              TYPE_PATH@0..12
1118                IDENT@0..3 "Foo"
1119                COLON_COLON@3..5 "::"
1120                CONST_ARG_LIST@5..12
1121                  L_BRACKET@5..6 "["
1122                  BINARY_EXPR@6..11
1123                    PATH_EXPR@6..8
1124                      IDENT@6..7 "N"
1125                      WHITESPACE@7..8 " "
1126                    MINUS@8..9 "-"
1127                    WHITESPACE@9..10 " "
1128                    LITERAL_INT@10..11
1129                      INTEGER@10..11 "1"
1130                  R_BRACKET@11..12 "]"
1131        "#]]);
1132    }
1133}