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    /// Parse a type expression.
48    ///
49    /// Returns `None` if the current token cannot start a type.
50    pub fn parse_type(&mut self) -> Option<CompletedMarker> {
51        self.parse_type_with_opts(TypeOpts::default().allow_optional())
52    }
53
54    /// Parse a type expression with options.
55    pub fn parse_type_with_opts(&mut self, opts: TypeOpts) -> Option<CompletedMarker> {
56        let ty = self.parse_type_inner()?;
57
58        // Optional suffix: Type?
59        if opts.allow_optional && self.at(QUESTION) {
60            let m = ty.precede(self);
61            self.bump_any(); // ?
62            return Some(m.complete(self, TYPE_OPTIONAL));
63        }
64
65        Some(ty)
66    }
67
68    /// Parse the core type expression (without optional suffix).
69    fn parse_type_inner(&mut self) -> Option<CompletedMarker> {
70        // Skip leading trivia before starting the type node
71        self.skip_trivia();
72
73        match self.current() {
74            // Unit or Tuple: ()  or (T1, T2, ...)
75            L_PAREN => self.parse_tuple_type(),
76            // Array or Vector: [T; N] or [T]
77            L_BRACKET => self.parse_array_or_vector_type(),
78            // Future: Future or Future<...>
79            KW_FUTURE => self.parse_future_type(),
80            // Mapping type (storage context): mapping key => value
81            KW_MAPPING => self.parse_mapping_type(),
82            // Primitive type keywords
83            _ if self.at_primitive_type() => self.parse_primitive_type(),
84            // Named/Composite type: Foo, Foo::[N], program.aleo/Type
85            IDENT => self.parse_named_type(),
86            _ => None,
87        }
88    }
89
90    /// Check if the current token is a primitive type keyword.
91    fn at_primitive_type(&self) -> bool {
92        matches!(
93            self.current(),
94            KW_ADDRESS
95                | KW_BOOL
96                | KW_FIELD
97                | KW_GROUP
98                | KW_SCALAR
99                | KW_SIGNATURE
100                | KW_STRING
101                | KW_I8
102                | KW_I16
103                | KW_I32
104                | KW_I64
105                | KW_I128
106                | KW_U8
107                | KW_U16
108                | KW_U32
109                | KW_U64
110                | KW_U128
111        )
112    }
113
114    /// Parse a primitive type keyword.
115    fn parse_primitive_type(&mut self) -> Option<CompletedMarker> {
116        if !self.at_primitive_type() {
117            return None;
118        }
119
120        let m = self.start();
121        self.bump_any();
122        Some(m.complete(self, TYPE_PATH))
123    }
124
125    /// Parse a tuple type: `(T1, T2, ...)` or unit `()`.
126    fn parse_tuple_type(&mut self) -> Option<CompletedMarker> {
127        if !self.at(L_PAREN) {
128            return None;
129        }
130
131        let m = self.start();
132        self.bump_any(); // (
133
134        // Check for unit: ()
135        if self.eat(R_PAREN) {
136            return Some(m.complete(self, TYPE_TUPLE));
137        }
138
139        // Parse first element
140        self.parse_type_with_opts(TypeOpts::default().allow_optional());
141
142        // Parse remaining elements
143        while self.eat(COMMA) {
144            if self.at(R_PAREN) {
145                // Trailing comma
146                break;
147            }
148            self.parse_type_with_opts(TypeOpts::default().allow_optional());
149        }
150
151        self.expect(R_PAREN);
152        Some(m.complete(self, TYPE_TUPLE))
153    }
154
155    /// Parse an array type `[T; N]` or vector type `[T]`.
156    fn parse_array_or_vector_type(&mut self) -> Option<CompletedMarker> {
157        if !self.at(L_BRACKET) {
158            return None;
159        }
160
161        let m = self.start();
162        self.bump_any(); // [
163
164        // Parse element type
165        self.parse_type_with_opts(TypeOpts::default().allow_optional());
166
167        // Check for array length: ; N
168        if self.eat(SEMICOLON) {
169            // Array with explicit length: [T; N]
170            self.parse_array_length();
171            self.expect(R_BRACKET);
172            return Some(m.complete(self, TYPE_ARRAY));
173        }
174
175        // Vector: [T]
176        self.expect(R_BRACKET);
177        Some(m.complete(self, TYPE_ARRAY))
178    }
179
180    /// Parse an array length expression.
181    ///
182    /// Supports integer literals (`[T; 10]`), identifiers (`[T; N]`),
183    /// paths (`[T; Foo::SIZE]`), and arbitrary expressions (`[T; N + M]`).
184    fn parse_array_length(&mut self) {
185        self.parse_expr();
186    }
187
188    /// Parse a Future type: `Future` or `Future<fn(T1, T2) -> R>`.
189    fn parse_future_type(&mut self) -> Option<CompletedMarker> {
190        if !self.at(KW_FUTURE) {
191            return None;
192        }
193
194        let m = self.start();
195        self.bump_any(); // Future
196
197        // Check for explicit Future signature: Future<fn(T) -> R>
198        if self.eat(LT) {
199            // Parse fn(...) -> R
200            self.expect(KW_FN);
201            self.expect(L_PAREN);
202
203            // Parse parameter types
204            if !self.at(R_PAREN) {
205                self.parse_type_with_opts(TypeOpts::default().allow_optional());
206                while self.eat(COMMA) {
207                    if self.at(R_PAREN) {
208                        break;
209                    }
210                    self.parse_type_with_opts(TypeOpts::default().allow_optional());
211                }
212            }
213
214            self.expect(R_PAREN);
215
216            // Return type
217            if self.eat(ARROW) {
218                self.parse_type_with_opts(TypeOpts::default().allow_optional());
219            }
220
221            self.expect(GT);
222        }
223
224        Some(m.complete(self, TYPE_FUTURE))
225    }
226
227    /// Parse a mapping type: `mapping key => value`.
228    fn parse_mapping_type(&mut self) -> Option<CompletedMarker> {
229        if !self.at(KW_MAPPING) {
230            return None;
231        }
232
233        let m = self.start();
234        self.bump_any(); // mapping
235
236        // Parse key type
237        self.parse_type();
238
239        // Expect =>
240        self.expect(FAT_ARROW);
241
242        // Parse value type
243        self.parse_type();
244
245        Some(m.complete(self, TYPE_MAPPING))
246    }
247
248    /// Parse a named/composite type.
249    ///
250    /// This handles:
251    /// - Simple names: `Foo`
252    /// - Paths: `Foo::Bar`
253    /// - Const generics: `Foo::[N]` or `Foo::<N>`
254    /// - Locators: `program.aleo/Type`
255    fn parse_named_type(&mut self) -> Option<CompletedMarker> {
256        if !self.at(IDENT) {
257            return None;
258        }
259
260        let m = self.start();
261        self.bump_any(); // first identifier
262
263        // Check for locator: name.aleo/Type
264        if self.at(DOT) && self.nth(1) == KW_ALEO {
265            self.bump_any(); // .
266            self.bump_any(); // aleo
267
268            if self.eat(SLASH) {
269                // Locator path: program.aleo/Type
270                if self.at(IDENT) {
271                    self.bump_any();
272                } else {
273                    self.error("expected type name after /".to_string());
274                }
275            }
276
277            // Optional const generic args after locator: child.aleo/Bar::[4]
278            if self.at(COLON_COLON) && self.nth(1) == L_BRACKET {
279                self.bump_any(); // ::
280                self.parse_const_generic_args_bracket();
281            }
282
283            return Some(m.complete(self, TYPE_PATH));
284        }
285
286        // Check for path or const generics: Foo::Bar or Foo::[N]
287        while self.eat(COLON_COLON) {
288            if self.at(L_BRACKET) {
289                // Const generics with brackets: Foo::[N]
290                self.parse_const_generic_args_bracket();
291                break;
292            } else if self.at(LT) {
293                // Const generics with angle brackets: Foo::<N>
294                self.parse_const_generic_args_angle();
295                break;
296            } else if self.at(IDENT) {
297                self.bump_any();
298            } else {
299                self.error("expected identifier, [, or < after ::".to_string());
300                break;
301            }
302        }
303
304        Some(m.complete(self, TYPE_PATH))
305    }
306
307    /// Parse a const generic parameter list (declaration site): `::[N: u32, M: u32]`.
308    ///
309    /// Wraps the list in a `CONST_PARAM_LIST` node. Each parameter is
310    /// wrapped in a `CONST_PARAM` node containing `name: Type`.
311    pub fn parse_const_param_list(&mut self) {
312        let m = self.start();
313
314        if !self.eat(L_BRACKET) {
315            m.abandon(self);
316            return;
317        }
318
319        // Parse comma-separated const params
320        if !self.at(R_BRACKET) {
321            self.parse_const_param();
322            while self.eat(COMMA) {
323                if self.at(R_BRACKET) {
324                    break;
325                }
326                self.parse_const_param();
327            }
328        }
329
330        self.expect(R_BRACKET);
331        m.complete(self, CONST_PARAM_LIST);
332    }
333
334    /// Parse a single const generic parameter: `N: u32`.
335    fn parse_const_param(&mut self) {
336        let m = self.start();
337        self.skip_trivia();
338
339        if self.at(IDENT) {
340            self.bump_any(); // param name
341        } else {
342            self.error("expected const parameter name".to_string());
343        }
344
345        self.expect(COLON);
346        self.parse_type();
347
348        m.complete(self, CONST_PARAM);
349    }
350
351    /// Parse const generic arguments with bracket syntax (use site): `::[N]` or `::[N + 1, u32]`.
352    ///
353    /// Each argument may be an expression or a type (for intrinsics).
354    /// Wraps the list in a `CONST_ARG_LIST` node.
355    pub fn parse_const_generic_args_bracket(&mut self) {
356        let m = self.start();
357
358        if !self.eat(L_BRACKET) {
359            m.abandon(self);
360            return;
361        }
362
363        // Parse comma-separated arguments
364        if !self.at(R_BRACKET) {
365            self.parse_const_generic_arg();
366            while self.eat(COMMA) {
367                if self.at(R_BRACKET) {
368                    break;
369                }
370                self.parse_const_generic_arg();
371            }
372        }
373
374        self.expect(R_BRACKET);
375        m.complete(self, CONST_ARG_LIST);
376    }
377
378    /// Parse const generic arguments with angle bracket syntax: `::<N>` or `::<N, M>`.
379    ///
380    /// Only accepts simple IDENT/INTEGER arguments because `>` conflicts
381    /// with the expression parser's greater-than operator. Angle bracket
382    /// generics are low priority (the LALRPOP grammar doesn't use them).
383    pub fn parse_const_generic_args_angle(&mut self) {
384        let m = self.start();
385
386        if !self.eat(LT) {
387            m.abandon(self);
388            return;
389        }
390
391        // Simple arg parser — avoids expression parser which would consume `>`.
392        if self.at(IDENT) || self.at(INTEGER) {
393            self.bump_any();
394        }
395
396        while self.eat(COMMA) {
397            if self.at(GT) {
398                break;
399            }
400            if self.at(IDENT) || self.at(INTEGER) {
401                self.bump_any();
402            } else {
403                self.error("expected const generic argument".to_string());
404                break;
405            }
406        }
407
408        self.expect(GT);
409        m.complete(self, CONST_ARG_LIST);
410    }
411
412    /// Parse a single const generic argument (expression or type).
413    ///
414    /// At use sites, `::[]` can contain either expressions (`N + 1`, `5`)
415    /// or types (`u32`, `[u8; 4]`). The heuristic: if the current token
416    /// is a primitive type keyword, or `[` followed by a primitive type
417    /// keyword (array type arg), parse as a type. Otherwise parse as an
418    /// expression.
419    fn parse_const_generic_arg(&mut self) {
420        self.skip_trivia();
421        if self.at_primitive_type() {
422            // Type argument (e.g. `u32` in `Deserialize::[u32]`)
423            self.parse_type();
424        } else if self.at(L_BRACKET) && self.nth(1).is_type_keyword() {
425            // Array type argument (e.g. `[u8; 4]` in `Deserialize::[[u8; 4]]`)
426            self.parse_type();
427        } else {
428            // Expression argument (e.g. `N + 1`, `5`, `N`)
429            self.parse_expr();
430        }
431    }
432}
433
434#[cfg(test)]
435mod tests {
436    use super::*;
437    use crate::{lexer::lex, parser::Parse};
438    use expect_test::{Expect, expect};
439
440    fn check_type(input: &str, expect: Expect) {
441        let (tokens, _) = lex(input);
442        let mut parser = Parser::new(input, &tokens);
443        let root = parser.start();
444        parser.parse_type();
445        parser.skip_trivia();
446        root.complete(&mut parser, ROOT);
447        let parse: Parse = parser.finish();
448        let output = format!("{:#?}", parse.syntax());
449        expect.assert_eq(&output);
450    }
451
452    fn check_type_optional(input: &str, expect: Expect) {
453        let (tokens, _) = lex(input);
454        let mut parser = Parser::new(input, &tokens);
455        let root = parser.start();
456        parser.parse_type_with_opts(TypeOpts::default().allow_optional());
457        parser.skip_trivia();
458        root.complete(&mut parser, ROOT);
459        let parse: Parse = parser.finish();
460        let output = format!("{:#?}", parse.syntax());
461        expect.assert_eq(&output);
462    }
463
464    // =========================================================================
465    // Primitive Types
466    // =========================================================================
467
468    #[test]
469    fn parse_type_bool() {
470        check_type("bool", expect![[r#"
471                ROOT@0..4
472                  TYPE_PATH@0..4
473                    KW_BOOL@0..4 "bool"
474            "#]]);
475    }
476
477    #[test]
478    fn parse_type_field() {
479        check_type("field", expect![[r#"
480                ROOT@0..5
481                  TYPE_PATH@0..5
482                    KW_FIELD@0..5 "field"
483            "#]]);
484    }
485
486    #[test]
487    fn parse_type_group() {
488        check_type("group", expect![[r#"
489                ROOT@0..5
490                  TYPE_PATH@0..5
491                    KW_GROUP@0..5 "group"
492            "#]]);
493    }
494
495    #[test]
496    fn parse_type_address() {
497        check_type("address", expect![[r#"
498                ROOT@0..7
499                  TYPE_PATH@0..7
500                    KW_ADDRESS@0..7 "address"
501            "#]]);
502    }
503
504    #[test]
505    fn parse_type_scalar() {
506        check_type("scalar", expect![[r#"
507                ROOT@0..6
508                  TYPE_PATH@0..6
509                    KW_SCALAR@0..6 "scalar"
510            "#]]);
511    }
512
513    #[test]
514    fn parse_type_signature() {
515        check_type("signature", expect![[r#"
516                ROOT@0..9
517                  TYPE_PATH@0..9
518                    KW_SIGNATURE@0..9 "signature"
519            "#]]);
520    }
521
522    #[test]
523    fn parse_type_string() {
524        check_type("string", expect![[r#"
525                ROOT@0..6
526                  TYPE_PATH@0..6
527                    KW_STRING@0..6 "string"
528            "#]]);
529    }
530
531    #[test]
532    fn parse_type_u32() {
533        check_type("u32", expect![[r#"
534                ROOT@0..3
535                  TYPE_PATH@0..3
536                    KW_U32@0..3 "u32"
537            "#]]);
538    }
539
540    #[test]
541    fn parse_type_i128() {
542        check_type("i128", expect![[r#"
543                ROOT@0..4
544                  TYPE_PATH@0..4
545                    KW_I128@0..4 "i128"
546            "#]]);
547    }
548
549    // =========================================================================
550    // Tuple Types
551    // =========================================================================
552
553    #[test]
554    fn parse_type_unit() {
555        check_type("()", expect![[r#"
556                ROOT@0..2
557                  TYPE_TUPLE@0..2
558                    L_PAREN@0..1 "("
559                    R_PAREN@1..2 ")"
560            "#]]);
561    }
562
563    #[test]
564    fn parse_type_tuple_single() {
565        check_type("(u32)", expect![[r#"
566                ROOT@0..5
567                  TYPE_TUPLE@0..5
568                    L_PAREN@0..1 "("
569                    TYPE_PATH@1..4
570                      KW_U32@1..4 "u32"
571                    R_PAREN@4..5 ")"
572            "#]]);
573    }
574
575    #[test]
576    fn parse_type_tuple_pair() {
577        check_type("(u32, field)", expect![[r#"
578                ROOT@0..12
579                  TYPE_TUPLE@0..12
580                    L_PAREN@0..1 "("
581                    TYPE_PATH@1..4
582                      KW_U32@1..4 "u32"
583                    COMMA@4..5 ","
584                    WHITESPACE@5..6 " "
585                    TYPE_PATH@6..11
586                      KW_FIELD@6..11 "field"
587                    R_PAREN@11..12 ")"
588            "#]]);
589    }
590
591    #[test]
592    fn parse_type_tuple_trailing_comma() {
593        check_type("(u32, field,)", expect![[r#"
594                ROOT@0..13
595                  TYPE_TUPLE@0..13
596                    L_PAREN@0..1 "("
597                    TYPE_PATH@1..4
598                      KW_U32@1..4 "u32"
599                    COMMA@4..5 ","
600                    WHITESPACE@5..6 " "
601                    TYPE_PATH@6..11
602                      KW_FIELD@6..11 "field"
603                    COMMA@11..12 ","
604                    R_PAREN@12..13 ")"
605            "#]]);
606    }
607
608    // =========================================================================
609    // Array Types
610    // =========================================================================
611
612    #[test]
613    fn parse_type_array_fixed() {
614        check_type("[u32; 10]", expect![[r#"
615            ROOT@0..9
616              TYPE_ARRAY@0..9
617                L_BRACKET@0..1 "["
618                TYPE_PATH@1..4
619                  KW_U32@1..4 "u32"
620                SEMICOLON@4..5 ";"
621                WHITESPACE@5..6 " "
622                LITERAL@6..8
623                  INTEGER@6..8 "10"
624                R_BRACKET@8..9 "]"
625        "#]]);
626    }
627
628    #[test]
629    fn parse_type_array_const_generic() {
630        check_type("[field; N]", expect![[r#"
631            ROOT@0..10
632              TYPE_ARRAY@0..10
633                L_BRACKET@0..1 "["
634                TYPE_PATH@1..6
635                  KW_FIELD@1..6 "field"
636                SEMICOLON@6..7 ";"
637                WHITESPACE@7..8 " "
638                PATH_EXPR@8..9
639                  IDENT@8..9 "N"
640                R_BRACKET@9..10 "]"
641        "#]]);
642    }
643
644    #[test]
645    fn parse_type_vector() {
646        check_type("[u8]", expect![[r#"
647                ROOT@0..4
648                  TYPE_ARRAY@0..4
649                    L_BRACKET@0..1 "["
650                    TYPE_PATH@1..3
651                      KW_U8@1..3 "u8"
652                    R_BRACKET@3..4 "]"
653            "#]]);
654    }
655
656    #[test]
657    fn parse_type_nested_array() {
658        check_type("[[u32; 3]; 2]", expect![[r#"
659            ROOT@0..13
660              TYPE_ARRAY@0..13
661                L_BRACKET@0..1 "["
662                TYPE_ARRAY@1..9
663                  L_BRACKET@1..2 "["
664                  TYPE_PATH@2..5
665                    KW_U32@2..5 "u32"
666                  SEMICOLON@5..6 ";"
667                  WHITESPACE@6..7 " "
668                  LITERAL@7..8
669                    INTEGER@7..8 "3"
670                  R_BRACKET@8..9 "]"
671                SEMICOLON@9..10 ";"
672                WHITESPACE@10..11 " "
673                LITERAL@11..12
674                  INTEGER@11..12 "2"
675                R_BRACKET@12..13 "]"
676        "#]]);
677    }
678
679    // =========================================================================
680    // Optional Types
681    // =========================================================================
682
683    #[test]
684    fn parse_type_optional() {
685        check_type_optional("u32?", expect![[r#"
686                ROOT@0..4
687                  TYPE_OPTIONAL@0..4
688                    TYPE_PATH@0..3
689                      KW_U32@0..3 "u32"
690                    QUESTION@3..4 "?"
691            "#]]);
692    }
693
694    #[test]
695    fn parse_type_optional_named() {
696        check_type_optional("Token?", expect![[r#"
697                ROOT@0..6
698                  TYPE_OPTIONAL@0..6
699                    TYPE_PATH@0..5
700                      IDENT@0..5 "Token"
701                    QUESTION@5..6 "?"
702            "#]]);
703    }
704
705    // =========================================================================
706    // Named/Composite Types
707    // =========================================================================
708
709    #[test]
710    fn parse_type_named_simple() {
711        check_type("Token", expect![[r#"
712                ROOT@0..5
713                  TYPE_PATH@0..5
714                    IDENT@0..5 "Token"
715            "#]]);
716    }
717
718    #[test]
719    fn parse_type_named_path() {
720        check_type("Foo::Bar", expect![[r#"
721                ROOT@0..8
722                  TYPE_PATH@0..8
723                    IDENT@0..3 "Foo"
724                    COLON_COLON@3..5 "::"
725                    IDENT@5..8 "Bar"
726            "#]]);
727    }
728
729    #[test]
730    fn parse_type_named_const_generic_bracket() {
731        check_type("Poseidon::[N]", expect![[r#"
732            ROOT@0..13
733              TYPE_PATH@0..13
734                IDENT@0..8 "Poseidon"
735                COLON_COLON@8..10 "::"
736                CONST_ARG_LIST@10..13
737                  L_BRACKET@10..11 "["
738                  PATH_EXPR@11..12
739                    IDENT@11..12 "N"
740                  R_BRACKET@12..13 "]"
741        "#]]);
742    }
743
744    #[test]
745    fn parse_type_named_const_generic_angle() {
746        check_type("Poseidon::<4>", expect![[r#"
747            ROOT@0..13
748              TYPE_PATH@0..13
749                IDENT@0..8 "Poseidon"
750                COLON_COLON@8..10 "::"
751                CONST_ARG_LIST@10..13
752                  LT@10..11 "<"
753                  INTEGER@11..12 "4"
754                  GT@12..13 ">"
755        "#]]);
756    }
757
758    #[test]
759    fn parse_type_locator() {
760        check_type("credits.aleo/Token", expect![[r#"
761                ROOT@0..18
762                  TYPE_PATH@0..18
763                    IDENT@0..7 "credits"
764                    DOT@7..8 "."
765                    KW_ALEO@8..12 "aleo"
766                    SLASH@12..13 "/"
767                    IDENT@13..18 "Token"
768            "#]]);
769    }
770
771    #[test]
772    fn parse_type_program_id_without_type() {
773        // Just program.aleo without /Type
774        check_type("credits.aleo", expect![[r#"
775                ROOT@0..12
776                  TYPE_PATH@0..12
777                    IDENT@0..7 "credits"
778                    DOT@7..8 "."
779                    KW_ALEO@8..12 "aleo"
780            "#]]);
781    }
782
783    // =========================================================================
784    // Future Types
785    // =========================================================================
786
787    #[test]
788    fn parse_type_future_simple() {
789        check_type("Future", expect![[r#"
790                ROOT@0..6
791                  TYPE_FUTURE@0..6
792                    KW_FUTURE@0..6 "Future"
793            "#]]);
794    }
795
796    #[test]
797    fn parse_type_future_explicit() {
798        check_type("Future<Fn(u32) -> field>", expect![[r#"
799                ROOT@0..24
800                  TYPE_FUTURE@0..24
801                    KW_FUTURE@0..6 "Future"
802                    LT@6..7 "<"
803                    KW_FN@7..9 "Fn"
804                    L_PAREN@9..10 "("
805                    TYPE_PATH@10..13
806                      KW_U32@10..13 "u32"
807                    R_PAREN@13..14 ")"
808                    WHITESPACE@14..15 " "
809                    ARROW@15..17 "->"
810                    WHITESPACE@17..18 " "
811                    TYPE_PATH@18..23
812                      KW_FIELD@18..23 "field"
813                    GT@23..24 ">"
814            "#]]);
815    }
816
817    #[test]
818    fn parse_type_future_no_params() {
819        check_type("Future<Fn() -> ()>", expect![[r#"
820                ROOT@0..18
821                  TYPE_FUTURE@0..18
822                    KW_FUTURE@0..6 "Future"
823                    LT@6..7 "<"
824                    KW_FN@7..9 "Fn"
825                    L_PAREN@9..10 "("
826                    R_PAREN@10..11 ")"
827                    WHITESPACE@11..12 " "
828                    ARROW@12..14 "->"
829                    WHITESPACE@14..15 " "
830                    TYPE_TUPLE@15..17
831                      L_PAREN@15..16 "("
832                      R_PAREN@16..17 ")"
833                    GT@17..18 ">"
834            "#]]);
835    }
836
837    // =========================================================================
838    // Mapping Types
839    // =========================================================================
840
841    #[test]
842    fn parse_type_mapping() {
843        check_type("mapping address => u64", expect![[r#"
844                ROOT@0..22
845                  TYPE_MAPPING@0..22
846                    KW_MAPPING@0..7 "mapping"
847                    WHITESPACE@7..8 " "
848                    TYPE_PATH@8..15
849                      KW_ADDRESS@8..15 "address"
850                    WHITESPACE@15..16 " "
851                    FAT_ARROW@16..18 "=>"
852                    WHITESPACE@18..19 " "
853                    TYPE_PATH@19..22
854                      KW_U64@19..22 "u64"
855            "#]]);
856    }
857
858    // =========================================================================
859    // Const Generic Arguments (Use Sites) in Types
860    // =========================================================================
861
862    fn check_type_no_errors(input: &str) {
863        let (tokens, _) = lex(input);
864        let mut parser = Parser::new(input, &tokens);
865        let root = parser.start();
866        parser.parse_type();
867        parser.skip_trivia();
868        root.complete(&mut parser, ROOT);
869        let parse: Parse = parser.finish();
870        if !parse.errors().is_empty() {
871            for err in parse.errors() {
872                eprintln!("error at {:?}: {}", err.range, err.message);
873            }
874            eprintln!("tree:\n{:#?}", parse.syntax());
875            panic!("type parse had {} error(s)", parse.errors().len());
876        }
877    }
878
879    #[test]
880    fn parse_type_const_generic_expr_simple() {
881        // Expression arg: integer literal
882        check_type_no_errors("Foo::[3]");
883    }
884
885    #[test]
886    fn parse_type_const_generic_expr_add() {
887        // Expression arg: binary expression
888        check_type_no_errors("Foo::[N + 1]");
889    }
890
891    #[test]
892    fn parse_type_const_generic_expr_mul() {
893        check_type_no_errors("Foo::[2 * N]");
894    }
895
896    #[test]
897    fn parse_type_const_generic_multi_args() {
898        check_type_no_errors("Matrix::[M, K, N]");
899    }
900
901    #[test]
902    fn parse_type_const_generic_type_arg() {
903        // Type arg: primitive type keyword (used by intrinsics)
904        check_type_no_errors("Deserialize::[u32]");
905    }
906
907    #[test]
908    fn parse_type_const_generic_array_type_arg() {
909        // Array type arg: [u8; 4] inside ::[]
910        check_type_no_errors("Deserialize::[[u8; 4]]");
911    }
912
913    #[test]
914    fn parse_type_locator_const_generic() {
915        // Locator + const generic args
916        check_type_no_errors("child.aleo/Bar::[4]");
917    }
918}