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 or program.aleo::module::Type
320                if self.at(IDENT) {
321                    self.bump_any();
322                    // Consume additional path segments: program.aleo::module::submodule::Type
323                    while self.at(COLON_COLON) && self.nth(1) == IDENT {
324                        self.bump_any(); // ::
325                        self.bump_any(); // IDENT
326                    }
327                } else {
328                    self.error("expected type name after ::");
329                }
330            }
331
332            // Optional const generic args after locator: child.aleo::Bar::[4]
333            if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
334                self.bump_any(); // ::
335                self.parse_const_generic_args_bracket();
336            }
337
338            return Some(m.complete(self, TYPE_LOCATOR));
339        }
340
341        // Check for path or const generics: Foo::Bar or Foo::[N]
342        while self.eat(COLON_COLON) {
343            if self.at(L_BRACKET) {
344                // Const generics with brackets: Foo::[N]
345                self.parse_const_generic_args_bracket();
346                break;
347            } else if self.at(LT) {
348                // Const generics with angle brackets: Foo::<N>
349                self.parse_const_generic_args_angle();
350                break;
351            } else if self.at(IDENT) {
352                self.bump_any();
353            } else {
354                self.error("expected identifier, [, or < after ::");
355                break;
356            }
357        }
358
359        Some(m.complete(self, TYPE_PATH))
360    }
361
362    /// Parse a const generic parameter list (declaration site): `::[N: u32, M: u32]`.
363    ///
364    /// Wraps the list in a `CONST_PARAM_LIST` node. Each parameter is
365    /// wrapped in a `CONST_PARAM` node containing `name: Type`.
366    pub fn parse_const_param_list(&mut self) {
367        let m = self.start();
368
369        if !self.eat(L_BRACKET) {
370            m.abandon(self);
371            return;
372        }
373
374        // Parse comma-separated const params
375        if !self.at(R_BRACKET) {
376            self.parse_const_param();
377            while self.eat(COMMA) {
378                if self.at(R_BRACKET) {
379                    break;
380                }
381                self.parse_const_param();
382            }
383        }
384
385        self.expect(R_BRACKET);
386        m.complete(self, CONST_PARAM_LIST);
387    }
388
389    /// Parse a single const generic parameter: `N: u32`.
390    fn parse_const_param(&mut self) {
391        let m = self.start();
392        self.skip_trivia();
393
394        if self.at(IDENT) {
395            self.bump_any(); // param name
396        } else {
397            self.error("expected const parameter name");
398        }
399
400        self.expect(COLON);
401        self.parse_type();
402
403        m.complete(self, CONST_PARAM);
404    }
405
406    /// Parse const generic arguments with bracket syntax (use site): `::[N]` or `::[N + 1, u32]`.
407    ///
408    /// Each argument may be an expression or a type (for intrinsics).
409    /// Wraps the list in a `CONST_ARG_LIST` node.
410    pub fn parse_const_generic_args_bracket(&mut self) {
411        let m = self.start();
412
413        if !self.eat(L_BRACKET) {
414            m.abandon(self);
415            return;
416        }
417
418        // Parse comma-separated arguments
419        if !self.at(R_BRACKET) {
420            self.parse_const_generic_arg();
421            while self.eat(COMMA) {
422                if self.at(R_BRACKET) {
423                    break;
424                }
425                // Clear error state so each argument gets fresh error reporting.
426                self.erroring = false;
427                self.parse_const_generic_arg();
428            }
429        }
430
431        self.expect(R_BRACKET);
432        m.complete(self, CONST_ARG_LIST);
433    }
434
435    /// Parse const generic arguments with angle bracket syntax: `::<N>` or `::<N, M>`.
436    ///
437    /// Only accepts simple IDENT/INTEGER arguments because `>` conflicts
438    /// with the expression parser's greater-than operator. Angle bracket
439    /// generics are low priority (the LALRPOP grammar doesn't use them).
440    pub fn parse_const_generic_args_angle(&mut self) {
441        let m = self.start();
442
443        if !self.eat(LT) {
444            m.abandon(self);
445            return;
446        }
447
448        // Simple arg parser — avoids expression parser which would consume `>`.
449        if self.at(IDENT) || self.at(INTEGER) {
450            self.bump_any();
451        }
452
453        while self.eat(COMMA) {
454            if self.at(GT) {
455                break;
456            }
457            if self.at(IDENT) || self.at(INTEGER) {
458                self.bump_any();
459            } else {
460                self.error("expected const generic argument");
461                break;
462            }
463        }
464
465        self.expect(GT);
466        m.complete(self, CONST_ARG_LIST);
467    }
468
469    /// Parse a single const generic argument (expression or type).
470    ///
471    /// At use sites, `::[]` can contain either expressions (`N + 1`, `5`)
472    /// or types (`u32`, `[u8; 4]`). The heuristic: if the current token
473    /// is a primitive type keyword, or `[` followed by a primitive type
474    /// keyword (array type arg), parse as a type. Otherwise parse as an
475    /// expression.
476    fn parse_const_generic_arg(&mut self) {
477        self.skip_trivia();
478        if matches!(self.current(), KW_PUBLIC | KW_PRIVATE | KW_CONSTANT) {
479            // Visibility-prefixed type argument (e.g. `public u64` in `_dynamic_call::[public u64]`).
480            let m = self.start();
481            self.bump_any(); // visibility keyword
482            self.parse_type();
483            m.complete(self, DYNAMIC_CALL_RETURN_TYPE);
484        } else if self.at_primitive_type() {
485            // Type argument (e.g. `u32` in `Deserialize::[u32]`)
486            self.parse_type();
487        } else if self.at(L_BRACKET) && self.nth(1).is_type_keyword() {
488            // Array type argument (e.g. `[u8; 4]` in `Deserialize::[[u8; 4]]`)
489            self.parse_type();
490        } else if self.at(KW_FINAL_UPPER) {
491            // Final type argument (e.g. `Final` in `_dynamic_call::[Final]`)
492            self.parse_type();
493        } else if self.at(KW_DYN) {
494            // Dynamic record type argument (e.g. `dyn record` in `_dynamic_call::[dyn record]`)
495            self.parse_type();
496        } else if self.at(L_PAREN) && (self.nth(1) == R_PAREN || Self::PRIMITIVE_TYPE_KINDS.contains(&self.nth(1))) {
497            // Tuple type argument (e.g. `(u32, u32)` in `_dynamic_call::[(u32, u32)]`).
498            // Distinguish from parenthesized expressions like `(A * 2)` using lookahead:
499            // `()` or `(` followed by a primitive type keyword is a tuple type.
500            self.parse_type();
501        } else {
502            // Expression argument (e.g. `N + 1`, `5`, `N`)
503            self.parse_expr();
504        }
505    }
506}
507
508#[cfg(test)]
509mod tests {
510    use super::*;
511    use crate::{lexer::lex, parser::Parse};
512    use expect_test::{Expect, expect};
513
514    fn check_type(input: &str, expect: Expect) {
515        let (tokens, _) = lex(input);
516        let mut parser = Parser::new(input, &tokens);
517        let root = parser.start();
518        parser.parse_type();
519        parser.skip_trivia();
520        root.complete(&mut parser, ROOT);
521        let parse: Parse = parser.finish(vec![]);
522        let output = format!("{:#?}", parse.syntax());
523        expect.assert_eq(&output);
524    }
525
526    fn check_type_optional(input: &str, expect: Expect) {
527        let (tokens, _) = lex(input);
528        let mut parser = Parser::new(input, &tokens);
529        let root = parser.start();
530        parser.parse_type_with_opts(TypeOpts::default().allow_optional());
531        parser.skip_trivia();
532        root.complete(&mut parser, ROOT);
533        let parse: Parse = parser.finish(vec![]);
534        let output = format!("{:#?}", parse.syntax());
535        expect.assert_eq(&output);
536    }
537
538    // =========================================================================
539    // Primitive Types
540    // =========================================================================
541
542    #[test]
543    fn parse_type_bool() {
544        check_type("bool", expect![[r#"
545            ROOT@0..4
546              TYPE_PRIMITIVE@0..4
547                KW_BOOL@0..4 "bool"
548        "#]]);
549    }
550
551    #[test]
552    fn parse_type_field() {
553        check_type("field", expect![[r#"
554            ROOT@0..5
555              TYPE_PRIMITIVE@0..5
556                KW_FIELD@0..5 "field"
557        "#]]);
558    }
559
560    #[test]
561    fn parse_type_group() {
562        check_type("group", expect![[r#"
563            ROOT@0..5
564              TYPE_PRIMITIVE@0..5
565                KW_GROUP@0..5 "group"
566        "#]]);
567    }
568
569    #[test]
570    fn parse_type_address() {
571        check_type("address", expect![[r#"
572            ROOT@0..7
573              TYPE_PRIMITIVE@0..7
574                KW_ADDRESS@0..7 "address"
575        "#]]);
576    }
577
578    #[test]
579    fn parse_type_scalar() {
580        check_type("scalar", expect![[r#"
581            ROOT@0..6
582              TYPE_PRIMITIVE@0..6
583                KW_SCALAR@0..6 "scalar"
584        "#]]);
585    }
586
587    #[test]
588    fn parse_type_signature() {
589        check_type("signature", expect![[r#"
590            ROOT@0..9
591              TYPE_PRIMITIVE@0..9
592                KW_SIGNATURE@0..9 "signature"
593        "#]]);
594    }
595
596    #[test]
597    fn parse_type_string() {
598        check_type("string", expect![[r#"
599            ROOT@0..6
600              TYPE_PRIMITIVE@0..6
601                KW_STRING@0..6 "string"
602        "#]]);
603    }
604
605    #[test]
606    fn parse_type_identifier() {
607        check_type("identifier", expect![[r#"
608            ROOT@0..10
609              TYPE_PRIMITIVE@0..10
610                KW_IDENTIFIER@0..10 "identifier"
611        "#]]);
612    }
613
614    #[test]
615    fn parse_type_u32() {
616        check_type("u32", expect![[r#"
617            ROOT@0..3
618              TYPE_PRIMITIVE@0..3
619                KW_U32@0..3 "u32"
620        "#]]);
621    }
622
623    #[test]
624    fn parse_type_i128() {
625        check_type("i128", expect![[r#"
626            ROOT@0..4
627              TYPE_PRIMITIVE@0..4
628                KW_I128@0..4 "i128"
629        "#]]);
630    }
631
632    // =========================================================================
633    // Tuple Types
634    // =========================================================================
635
636    #[test]
637    fn parse_type_unit() {
638        check_type("()", expect![[r#"
639                ROOT@0..2
640                  TYPE_TUPLE@0..2
641                    L_PAREN@0..1 "("
642                    R_PAREN@1..2 ")"
643            "#]]);
644    }
645
646    #[test]
647    fn parse_type_tuple_single() {
648        check_type("(u32)", expect![[r#"
649            ROOT@0..5
650              TYPE_TUPLE@0..5
651                L_PAREN@0..1 "("
652                TYPE_PRIMITIVE@1..4
653                  KW_U32@1..4 "u32"
654                R_PAREN@4..5 ")"
655        "#]]);
656    }
657
658    #[test]
659    fn parse_type_tuple_pair() {
660        check_type("(u32, field)", expect![[r#"
661            ROOT@0..12
662              TYPE_TUPLE@0..12
663                L_PAREN@0..1 "("
664                TYPE_PRIMITIVE@1..4
665                  KW_U32@1..4 "u32"
666                COMMA@4..5 ","
667                WHITESPACE@5..6 " "
668                TYPE_PRIMITIVE@6..11
669                  KW_FIELD@6..11 "field"
670                R_PAREN@11..12 ")"
671        "#]]);
672    }
673
674    #[test]
675    fn parse_type_tuple_trailing_comma() {
676        check_type("(u32, field,)", expect![[r#"
677            ROOT@0..13
678              TYPE_TUPLE@0..13
679                L_PAREN@0..1 "("
680                TYPE_PRIMITIVE@1..4
681                  KW_U32@1..4 "u32"
682                COMMA@4..5 ","
683                WHITESPACE@5..6 " "
684                TYPE_PRIMITIVE@6..11
685                  KW_FIELD@6..11 "field"
686                COMMA@11..12 ","
687                R_PAREN@12..13 ")"
688        "#]]);
689    }
690
691    // =========================================================================
692    // Array Types
693    // =========================================================================
694
695    #[test]
696    fn parse_type_array_fixed() {
697        check_type("[u32; 10]", expect![[r#"
698            ROOT@0..9
699              TYPE_ARRAY@0..9
700                L_BRACKET@0..1 "["
701                TYPE_PRIMITIVE@1..4
702                  KW_U32@1..4 "u32"
703                SEMICOLON@4..5 ";"
704                ARRAY_LENGTH@5..8
705                  WHITESPACE@5..6 " "
706                  LITERAL_INT@6..8
707                    INTEGER@6..8 "10"
708                R_BRACKET@8..9 "]"
709        "#]]);
710    }
711
712    #[test]
713    fn parse_type_array_const_generic() {
714        check_type("[field; N]", expect![[r#"
715            ROOT@0..10
716              TYPE_ARRAY@0..10
717                L_BRACKET@0..1 "["
718                TYPE_PRIMITIVE@1..6
719                  KW_FIELD@1..6 "field"
720                SEMICOLON@6..7 ";"
721                ARRAY_LENGTH@7..9
722                  WHITESPACE@7..8 " "
723                  PATH_EXPR@8..9
724                    IDENT@8..9 "N"
725                R_BRACKET@9..10 "]"
726        "#]]);
727    }
728
729    #[test]
730    fn parse_type_vector() {
731        check_type("[u8]", expect![[r#"
732            ROOT@0..4
733              TYPE_VECTOR@0..4
734                L_BRACKET@0..1 "["
735                TYPE_PRIMITIVE@1..3
736                  KW_U8@1..3 "u8"
737                R_BRACKET@3..4 "]"
738        "#]]);
739    }
740
741    #[test]
742    fn parse_type_nested_array() {
743        check_type("[[u32; 3]; 2]", expect![[r#"
744            ROOT@0..13
745              TYPE_ARRAY@0..13
746                L_BRACKET@0..1 "["
747                TYPE_ARRAY@1..9
748                  L_BRACKET@1..2 "["
749                  TYPE_PRIMITIVE@2..5
750                    KW_U32@2..5 "u32"
751                  SEMICOLON@5..6 ";"
752                  ARRAY_LENGTH@6..8
753                    WHITESPACE@6..7 " "
754                    LITERAL_INT@7..8
755                      INTEGER@7..8 "3"
756                  R_BRACKET@8..9 "]"
757                SEMICOLON@9..10 ";"
758                ARRAY_LENGTH@10..12
759                  WHITESPACE@10..11 " "
760                  LITERAL_INT@11..12
761                    INTEGER@11..12 "2"
762                R_BRACKET@12..13 "]"
763        "#]]);
764    }
765
766    // =========================================================================
767    // Optional Types
768    // =========================================================================
769
770    #[test]
771    fn parse_type_optional() {
772        check_type_optional("u32?", expect![[r#"
773            ROOT@0..4
774              TYPE_OPTIONAL@0..4
775                TYPE_PRIMITIVE@0..3
776                  KW_U32@0..3 "u32"
777                QUESTION@3..4 "?"
778        "#]]);
779    }
780
781    #[test]
782    fn parse_type_optional_named() {
783        check_type_optional("Token?", expect![[r#"
784                ROOT@0..6
785                  TYPE_OPTIONAL@0..6
786                    TYPE_PATH@0..5
787                      IDENT@0..5 "Token"
788                    QUESTION@5..6 "?"
789            "#]]);
790    }
791
792    // =========================================================================
793    // Named/Composite Types
794    // =========================================================================
795
796    #[test]
797    fn parse_type_named_simple() {
798        check_type("Token", expect![[r#"
799                ROOT@0..5
800                  TYPE_PATH@0..5
801                    IDENT@0..5 "Token"
802            "#]]);
803    }
804
805    #[test]
806    fn parse_type_named_path() {
807        check_type("Foo::Bar", expect![[r#"
808                ROOT@0..8
809                  TYPE_PATH@0..8
810                    IDENT@0..3 "Foo"
811                    COLON_COLON@3..5 "::"
812                    IDENT@5..8 "Bar"
813            "#]]);
814    }
815
816    #[test]
817    fn parse_type_named_const_generic_bracket() {
818        check_type("Poseidon::[N]", expect![[r#"
819            ROOT@0..13
820              TYPE_PATH@0..13
821                IDENT@0..8 "Poseidon"
822                COLON_COLON@8..10 "::"
823                CONST_ARG_LIST@10..13
824                  L_BRACKET@10..11 "["
825                  PATH_EXPR@11..12
826                    IDENT@11..12 "N"
827                  R_BRACKET@12..13 "]"
828        "#]]);
829    }
830
831    #[test]
832    fn parse_type_named_const_generic_angle() {
833        check_type("Poseidon::<4>", expect![[r#"
834            ROOT@0..13
835              TYPE_PATH@0..13
836                IDENT@0..8 "Poseidon"
837                COLON_COLON@8..10 "::"
838                CONST_ARG_LIST@10..13
839                  LT@10..11 "<"
840                  INTEGER@11..12 "4"
841                  GT@12..13 ">"
842        "#]]);
843    }
844
845    #[test]
846    fn parse_type_locator() {
847        check_type("credits.aleo::Token", expect![[r#"
848            ROOT@0..19
849              TYPE_LOCATOR@0..19
850                IDENT@0..7 "credits"
851                DOT@7..8 "."
852                KW_ALEO@8..12 "aleo"
853                COLON_COLON@12..14 "::"
854                IDENT@14..19 "Token"
855        "#]]);
856    }
857
858    #[test]
859    fn parse_type_program_id_without_type() {
860        // Just program.aleo without /Type
861        check_type("credits.aleo", expect![[r#"
862            ROOT@0..12
863              TYPE_LOCATOR@0..12
864                IDENT@0..7 "credits"
865                DOT@7..8 "."
866                KW_ALEO@8..12 "aleo"
867        "#]]);
868    }
869
870    // =========================================================================
871    // Future Types
872    // =========================================================================
873
874    #[test]
875    fn parse_type_final_simple() {
876        check_type("Final", expect![[r#"
877                ROOT@0..5
878                  TYPE_FINAL@0..5
879                    KW_FINAL_UPPER@0..5 "Final"
880            "#]]);
881    }
882
883    #[test]
884    fn parse_type_final_explicit() {
885        check_type("Final<Fn(u32) -> field>", expect![[r#"
886            ROOT@0..23
887              TYPE_FINAL@0..23
888                KW_FINAL_UPPER@0..5 "Final"
889                LT@5..6 "<"
890                KW_FN_UPPER@6..8 "Fn"
891                L_PAREN@8..9 "("
892                TYPE_PRIMITIVE@9..12
893                  KW_U32@9..12 "u32"
894                R_PAREN@12..13 ")"
895                WHITESPACE@13..14 " "
896                ARROW@14..16 "->"
897                WHITESPACE@16..17 " "
898                TYPE_PRIMITIVE@17..22
899                  KW_FIELD@17..22 "field"
900                GT@22..23 ">"
901        "#]]);
902    }
903
904    #[test]
905    fn parse_type_final_no_params() {
906        check_type("Final<Fn() -> ()>", expect![[r#"
907                ROOT@0..17
908                  TYPE_FINAL@0..17
909                    KW_FINAL_UPPER@0..5 "Final"
910                    LT@5..6 "<"
911                    KW_FN_UPPER@6..8 "Fn"
912                    L_PAREN@8..9 "("
913                    R_PAREN@9..10 ")"
914                    WHITESPACE@10..11 " "
915                    ARROW@11..13 "->"
916                    WHITESPACE@13..14 " "
917                    TYPE_TUPLE@14..16
918                      L_PAREN@14..15 "("
919                      R_PAREN@15..16 ")"
920                    GT@16..17 ">"
921            "#]]);
922    }
923
924    // =========================================================================
925    // Mapping Types
926    // =========================================================================
927
928    #[test]
929    fn parse_type_mapping() {
930        check_type("mapping address => u64", expect![[r#"
931            ROOT@0..22
932              TYPE_MAPPING@0..22
933                KW_MAPPING@0..7 "mapping"
934                WHITESPACE@7..8 " "
935                TYPE_PRIMITIVE@8..15
936                  KW_ADDRESS@8..15 "address"
937                WHITESPACE@15..16 " "
938                FAT_ARROW@16..18 "=>"
939                WHITESPACE@18..19 " "
940                TYPE_PRIMITIVE@19..22
941                  KW_U64@19..22 "u64"
942        "#]]);
943    }
944
945    // =========================================================================
946    // Const Generic Arguments (Use Sites) in Types
947    // =========================================================================
948
949    fn check_type_no_errors(input: &str) {
950        let (tokens, _) = lex(input);
951        let mut parser = Parser::new(input, &tokens);
952        let root = parser.start();
953        parser.parse_type();
954        parser.skip_trivia();
955        root.complete(&mut parser, ROOT);
956        let parse: Parse = parser.finish(vec![]);
957        if !parse.errors().is_empty() {
958            for err in parse.errors() {
959                eprintln!("error at {:?}: {}", err.range, err.message);
960            }
961            eprintln!("tree:\n{:#?}", parse.syntax());
962            panic!("type parse had {} error(s)", parse.errors().len());
963        }
964    }
965
966    #[test]
967    fn parse_type_const_generic_expr_simple() {
968        // Expression arg: integer literal
969        check_type_no_errors("Foo::[3]");
970    }
971
972    #[test]
973    fn parse_type_const_generic_expr_add() {
974        // Expression arg: binary expression
975        check_type_no_errors("Foo::[N + 1]");
976    }
977
978    #[test]
979    fn parse_type_const_generic_expr_mul() {
980        check_type_no_errors("Foo::[2 * N]");
981    }
982
983    #[test]
984    fn parse_type_const_generic_multi_args() {
985        check_type_no_errors("Matrix::[M, K, N]");
986    }
987
988    #[test]
989    fn parse_type_const_generic_type_arg() {
990        // Type arg: primitive type keyword (used by intrinsics)
991        check_type_no_errors("Deserialize::[u32]");
992    }
993
994    #[test]
995    fn parse_type_const_generic_array_type_arg() {
996        // Array type arg: [u8; 4] inside ::[]
997        check_type_no_errors("Deserialize::[[u8; 4]]");
998    }
999
1000    #[test]
1001    fn parse_type_locator_const_generic() {
1002        // Locator + const generic args
1003        check_type_no_errors("child.aleo::Bar::[4]");
1004    }
1005
1006    // =========================================================================
1007    // Nested Tuple Types (4a)
1008    // =========================================================================
1009
1010    #[test]
1011    fn parse_type_tuple_nested() {
1012        check_type("((u32, u64), bool)", expect![[r#"
1013            ROOT@0..18
1014              TYPE_TUPLE@0..18
1015                L_PAREN@0..1 "("
1016                TYPE_TUPLE@1..11
1017                  L_PAREN@1..2 "("
1018                  TYPE_PRIMITIVE@2..5
1019                    KW_U32@2..5 "u32"
1020                  COMMA@5..6 ","
1021                  WHITESPACE@6..7 " "
1022                  TYPE_PRIMITIVE@7..10
1023                    KW_U64@7..10 "u64"
1024                  R_PAREN@10..11 ")"
1025                COMMA@11..12 ","
1026                WHITESPACE@12..13 " "
1027                TYPE_PRIMITIVE@13..17
1028                  KW_BOOL@13..17 "bool"
1029                R_PAREN@17..18 ")"
1030        "#]]);
1031    }
1032
1033    // =========================================================================
1034    // Optional of Composite Types (4b)
1035    // =========================================================================
1036
1037    #[test]
1038    fn parse_type_optional_array() {
1039        check_type_optional("[u32; 3]?", expect![[r#"
1040            ROOT@0..9
1041              TYPE_OPTIONAL@0..9
1042                TYPE_ARRAY@0..8
1043                  L_BRACKET@0..1 "["
1044                  TYPE_PRIMITIVE@1..4
1045                    KW_U32@1..4 "u32"
1046                  SEMICOLON@4..5 ";"
1047                  ARRAY_LENGTH@5..7
1048                    WHITESPACE@5..6 " "
1049                    LITERAL_INT@6..7
1050                      INTEGER@6..7 "3"
1051                  R_BRACKET@7..8 "]"
1052                QUESTION@8..9 "?"
1053        "#]]);
1054    }
1055
1056    #[test]
1057    fn parse_type_optional_tuple() {
1058        check_type_optional("(u32, u64)?", expect![[r#"
1059            ROOT@0..11
1060              TYPE_OPTIONAL@0..11
1061                TYPE_TUPLE@0..10
1062                  L_PAREN@0..1 "("
1063                  TYPE_PRIMITIVE@1..4
1064                    KW_U32@1..4 "u32"
1065                  COMMA@4..5 ","
1066                  WHITESPACE@5..6 " "
1067                  TYPE_PRIMITIVE@6..9
1068                    KW_U64@6..9 "u64"
1069                  R_PAREN@9..10 ")"
1070                QUESTION@10..11 "?"
1071        "#]]);
1072    }
1073
1074    // =========================================================================
1075    // Final with Multiple Parameters (4c)
1076    // =========================================================================
1077
1078    #[test]
1079    fn parse_type_final_multi_param() {
1080        check_type("Final<Fn(u32, field, group) -> (u32, u64)>", expect![[r#"
1081            ROOT@0..42
1082              TYPE_FINAL@0..42
1083                KW_FINAL_UPPER@0..5 "Final"
1084                LT@5..6 "<"
1085                KW_FN_UPPER@6..8 "Fn"
1086                L_PAREN@8..9 "("
1087                TYPE_PRIMITIVE@9..12
1088                  KW_U32@9..12 "u32"
1089                COMMA@12..13 ","
1090                WHITESPACE@13..14 " "
1091                TYPE_PRIMITIVE@14..19
1092                  KW_FIELD@14..19 "field"
1093                COMMA@19..20 ","
1094                WHITESPACE@20..21 " "
1095                TYPE_PRIMITIVE@21..26
1096                  KW_GROUP@21..26 "group"
1097                R_PAREN@26..27 ")"
1098                WHITESPACE@27..28 " "
1099                ARROW@28..30 "->"
1100                WHITESPACE@30..31 " "
1101                TYPE_TUPLE@31..41
1102                  L_PAREN@31..32 "("
1103                  TYPE_PRIMITIVE@32..35
1104                    KW_U32@32..35 "u32"
1105                  COMMA@35..36 ","
1106                  WHITESPACE@36..37 " "
1107                  TYPE_PRIMITIVE@37..40
1108                    KW_U64@37..40 "u64"
1109                  R_PAREN@40..41 ")"
1110                GT@41..42 ">"
1111        "#]]);
1112    }
1113
1114    // =========================================================================
1115    // Const Generic Expression Arguments (4d)
1116    // =========================================================================
1117
1118    #[test]
1119    fn parse_type_const_generic_expr_sub() {
1120        check_type("Foo::[N - 1]", expect![[r#"
1121            ROOT@0..12
1122              TYPE_PATH@0..12
1123                IDENT@0..3 "Foo"
1124                COLON_COLON@3..5 "::"
1125                CONST_ARG_LIST@5..12
1126                  L_BRACKET@5..6 "["
1127                  BINARY_EXPR@6..11
1128                    PATH_EXPR@6..8
1129                      IDENT@6..7 "N"
1130                      WHITESPACE@7..8 " "
1131                    MINUS@8..9 "-"
1132                    WHITESPACE@9..10 " "
1133                    LITERAL_INT@10..11
1134                      INTEGER@10..11 "1"
1135                  R_BRACKET@11..12 "]"
1136        "#]]);
1137    }
1138}