LCOV - code coverage report
Current view: top level - gcc/rust/parse - rust-parse-impl.hxx (source / functions) Coverage Total Hit
Test: gcc.info Lines: 74.5 % 3100 2311
Test Date: 2026-03-28 14:25:54 Functions: 72.7 % 198 144
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : /* Template implementation for Rust::Parser. Previously in rust-parse.cc (before
      20              :  * Parser was template). Separated from rust-parse.h for readability. */
      21              : 
      22              : /* DO NOT INCLUDE ANYWHERE - this is automatically included
      23              :  *   by rust-parse-impl-*.cc
      24              :  * This is also the reason why there are no include guards. */
      25              : 
      26              : #include "expected.h"
      27              : #include "rust-ast.h"
      28              : #include "rust-common.h"
      29              : #include "rust-expr.h"
      30              : #include "rust-item.h"
      31              : #include "rust-common.h"
      32              : #include "rust-parse.h"
      33              : #include "rust-token.h"
      34              : #define INCLUDE_ALGORITHM
      35              : #include "rust-diagnostics.h"
      36              : #include "rust-dir-owner.h"
      37              : #include "rust-keyword-values.h"
      38              : #include "rust-edition.h"
      39              : #include "rust-parse-error.h"
      40              : 
      41              : #include "optional.h"
      42              : 
      43              : namespace Rust {
      44              : 
      45              : /* HACK-y special handling for skipping a right angle token at the end of
      46              :  * generic arguments.
      47              :  * Currently, this replaces the "current token" with one that is identical
      48              :  * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad
      49              :  * for several reasons - it modifies the token stream to something that
      50              :  * actually doesn't make syntactic sense, it may not worked if the token
      51              :  * has already been skipped, etc. It was done because it would not
      52              :  * actually require inserting new items into the token stream (which I
      53              :  * thought would take more work to not mess up) and because I wasn't sure
      54              :  * if the "already seen right angle" flag in the parser would work
      55              :  * correctly.
      56              :  * Those two other approaches listed are in my opinion actually better
      57              :  * long-term - insertion is probably best as it reflects syntactically
      58              :  * what occurs. On the other hand, I need to do a code audit to make sure
      59              :  * that insertion doesn't mess anything up. So that's a FIXME. */
      60              : template <typename ManagedTokenSource>
      61              : bool
      62         7895 : Parser<ManagedTokenSource>::skip_generics_right_angle ()
      63              : {
      64              :   /* OK, new great idea. Have a lexer method called
      65              :    * "split_current_token(TokenType newLeft, TokenType newRight)", which is
      66              :    * called here with whatever arguments are appropriate. That lexer method
      67              :    * handles "replacing" the current token with the "newLeft" and "inserting"
      68              :    * the next token with the "newRight" (and creating a location, etc. for it)
      69              :    */
      70              : 
      71              :   /* HACK: special handling for right shift '>>', greater or equal '>=', and
      72              :    * right shift assig */
      73              :   // '>>='
      74         7895 :   const_TokenPtr tok = lexer.peek_token ();
      75         7895 :   switch (tok->get_id ())
      76              :     {
      77         7647 :     case RIGHT_ANGLE:
      78              :       // this is good - skip token
      79         7647 :       lexer.skip_token ();
      80         7647 :       return true;
      81          247 :     case RIGHT_SHIFT:
      82              :       {
      83              :         // new implementation that should be better
      84          247 :         lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE);
      85          247 :         lexer.skip_token ();
      86          247 :         return true;
      87              :       }
      88            0 :     case GREATER_OR_EQUAL:
      89              :       {
      90              :         // new implementation that should be better
      91            0 :         lexer.split_current_token (RIGHT_ANGLE, EQUAL);
      92            0 :         lexer.skip_token ();
      93            0 :         return true;
      94              :       }
      95            0 :     case RIGHT_SHIFT_EQ:
      96              :       {
      97              :         // new implementation that should be better
      98            0 :         lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL);
      99            0 :         lexer.skip_token ();
     100            0 :         return true;
     101              :       }
     102            1 :     default:
     103            1 :       add_error (Error (tok->get_locus (),
     104              :                         "expected %<>%> at end of generic argument - found %qs",
     105              :                         tok->get_token_description ()));
     106            1 :       return false;
     107              :     }
     108         7895 : }
     109              : 
     110              : /* Gets left binding power for specified token.
     111              :  * Not suitable for use at the moment or possibly ever because binding power
     112              :  * cannot be purely determined from operator token with Rust grammar - e.g.
     113              :  * method call and field access have
     114              :  * different left binding powers but the same operator token. */
     115              : template <typename ManagedTokenSource>
     116              : int
     117       102397 : Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
     118              : {
     119              :   // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
     120       102397 :   switch (token->get_id ())
     121              :     {
     122              :       /* TODO: issue here - distinguish between method calls and field access
     123              :        * somehow? Also would have to distinguish between paths and function
     124              :        * calls (:: operator), maybe more stuff. */
     125              :       /* Current plan for tackling LBP - don't do it based on token, use
     126              :        * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr
     127              :        * and handle other expressions without it. rustc only considers
     128              :        * arithmetic, logical/relational, 'as',
     129              :        * '?=', ranges, colons, and assignment to have operator precedence and
     130              :        * associativity rules applicable. It then has
     131              :        * a separate "ExprPrecedence" that also includes binary operators. */
     132              : 
     133              :       // TODO: handle operator overloading - have a function replace the
     134              :       // operator?
     135              : 
     136              :       /*case DOT:
     137              :           return LBP_DOT;*/
     138              : 
     139            0 :     case SCOPE_RESOLUTION:
     140            0 :       rust_debug (
     141              :         "possible error - looked up LBP of scope resolution operator. should "
     142              :         "be handled elsewhere.");
     143            0 :       return LBP_PATH;
     144              : 
     145              :     /* Resolved by lookahead HACK that should work with current code. If next
     146              :      * token is identifier and token after that isn't parenthesised expression
     147              :      * list, it is a field reference. */
     148         8837 :     case DOT:
     149        17674 :       if (lexer.peek_token (1)->get_id () == IDENTIFIER
     150        16772 :           && lexer.peek_token (2)->get_id () != LEFT_PAREN)
     151              :         {
     152              :           return LBP_FIELD_EXPR;
     153              :         }
     154              :       return LBP_METHOD_CALL;
     155              : 
     156              :     case LEFT_PAREN:
     157              :       return LBP_FUNCTION_CALL;
     158              : 
     159              :     case LEFT_SQUARE:
     160              :       return LBP_ARRAY_REF;
     161              : 
     162              :     // postfix question mark (i.e. error propagation expression)
     163            1 :     case QUESTION_MARK:
     164            1 :       return LBP_QUESTION_MARK;
     165              : 
     166         5288 :     case AS:
     167         5288 :       return LBP_AS;
     168              : 
     169              :     case ASTERISK:
     170              :       return LBP_MUL;
     171              :     case DIV:
     172              :       return LBP_DIV;
     173              :     case PERCENT:
     174              :       return LBP_MOD;
     175              : 
     176              :     case PLUS:
     177              :       return LBP_PLUS;
     178              :     case MINUS:
     179              :       return LBP_MINUS;
     180              : 
     181              :     case LEFT_SHIFT:
     182              :       return LBP_L_SHIFT;
     183              :     case RIGHT_SHIFT:
     184              :       return LBP_R_SHIFT;
     185              : 
     186              :     // binary & operator
     187           52 :     case AMP:
     188           52 :       return LBP_AMP;
     189              : 
     190              :     // binary ^ operator
     191           77 :     case CARET:
     192           77 :       return LBP_CARET;
     193              : 
     194              :     // binary | operator
     195           27 :     case PIPE:
     196           27 :       return LBP_PIPE;
     197              : 
     198              :     case EQUAL_EQUAL:
     199              :       return LBP_EQUAL;
     200              :     case NOT_EQUAL:
     201              :       return LBP_NOT_EQUAL;
     202              :     case RIGHT_ANGLE:
     203              :       return LBP_GREATER_THAN;
     204              :     case GREATER_OR_EQUAL:
     205              :       return LBP_GREATER_EQUAL;
     206              :     case LEFT_ANGLE:
     207              :       return LBP_SMALLER_THAN;
     208              :     case LESS_OR_EQUAL:
     209              :       return LBP_SMALLER_EQUAL;
     210              : 
     211          659 :     case LOGICAL_AND:
     212          659 :       return LBP_LOGICAL_AND;
     213              : 
     214           91 :     case OR:
     215           91 :       return LBP_LOGICAL_OR;
     216              : 
     217              :     case DOT_DOT:
     218              :       return LBP_DOT_DOT;
     219              : 
     220              :     case DOT_DOT_EQ:
     221              :       return LBP_DOT_DOT_EQ;
     222              : 
     223              :     case EQUAL:
     224              :       return LBP_ASSIG;
     225              :     case PLUS_EQ:
     226              :       return LBP_PLUS_ASSIG;
     227              :     case MINUS_EQ:
     228              :       return LBP_MINUS_ASSIG;
     229              :     case ASTERISK_EQ:
     230              :       return LBP_MULT_ASSIG;
     231              :     case DIV_EQ:
     232              :       return LBP_DIV_ASSIG;
     233              :     case PERCENT_EQ:
     234              :       return LBP_MOD_ASSIG;
     235              :     case AMP_EQ:
     236              :       return LBP_AMP_ASSIG;
     237              :     case PIPE_EQ:
     238              :       return LBP_PIPE_ASSIG;
     239              :     case CARET_EQ:
     240              :       return LBP_CARET_ASSIG;
     241              :     case LEFT_SHIFT_EQ:
     242              :       return LBP_L_SHIFT_ASSIG;
     243              :     case RIGHT_SHIFT_EQ:
     244              :       return LBP_R_SHIFT_ASSIG;
     245              : 
     246              :     /* HACK: float literal due to lexer misidentifying a dot then an integer as
     247              :      * a float */
     248              :     case FLOAT_LITERAL:
     249              :       return LBP_FIELD_EXPR;
     250              :       // field expr is same as tuple expr in precedence, i imagine
     251              :       // TODO: is this needed anymore? lexer shouldn't do that anymore
     252              : 
     253              :     // anything that can't appear in an infix position is given lowest priority
     254        74698 :     default:
     255        74698 :       return LBP_LOWEST;
     256              :     }
     257              : }
     258              : 
     259              : // Returns true when current token is EOF.
     260              : template <typename ManagedTokenSource>
     261              : bool
     262            0 : Parser<ManagedTokenSource>::done_end_of_file ()
     263              : {
     264            0 :   return lexer.peek_token ()->get_id () == END_OF_FILE;
     265              : }
     266              : 
     267              : // Parses a sequence of items within a module or the implicit top-level module
     268              : // in a crate
     269              : template <typename ManagedTokenSource>
     270              : tl::expected<std::vector<std::unique_ptr<AST::Item>>, Parse::Error::Items>
     271         4728 : Parser<ManagedTokenSource>::parse_items ()
     272              : {
     273         4728 :   std::vector<std::unique_ptr<AST::Item>> items;
     274              : 
     275         4728 :   const_TokenPtr t = lexer.peek_token ();
     276        23368 :   while (t->get_id () != END_OF_FILE)
     277              :     {
     278        18640 :       auto item = parse_item (false);
     279        18640 :       if (!item)
     280           79 :         return Parse::Error::Items::make_malformed (std::move (items));
     281              : 
     282        18561 :       items.push_back (std::move (item.value ()));
     283              : 
     284        18561 :       t = lexer.peek_token ();
     285              :     }
     286              : 
     287              :     // GCC 5->7 bug doesn't threat lvalue as an rvalue for the overload
     288              : #if __GNUC__ <= 7
     289              :   return std::move (items);
     290              : #else
     291         4649 :   return items;
     292              : #endif
     293         4728 : }
     294              : 
     295              : // Parses a crate (compilation unit) - entry point
     296              : template <typename ManagedTokenSource>
     297              : std::unique_ptr<AST::Crate>
     298         4675 : Parser<ManagedTokenSource>::parse_crate ()
     299              : {
     300              :   // parse inner attributes
     301         4675 :   AST::AttrVec inner_attrs = parse_inner_attributes ();
     302              : 
     303              :   // parse items
     304         4675 :   auto items
     305         4675 :     = parse_items ().value_or (std::vector<std::unique_ptr<AST::Item>>{});
     306              : 
     307              :   // emit all errors
     308         4844 :   for (const auto &error : error_table)
     309          169 :     error.emit ();
     310              : 
     311              :   return std::unique_ptr<AST::Crate> (
     312         4675 :     new AST::Crate (std::move (items), std::move (inner_attrs)));
     313         4675 : }
     314              : 
     315              : // Parses an identifier/keyword as a Token
     316              : template <typename ManagedTokenSource>
     317              : tl::expected<std::unique_ptr<AST::Token>, Parse::Error::Node>
     318          498 : Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
     319              : {
     320          498 :   const_TokenPtr t = lexer.peek_token ();
     321              : 
     322          498 :   if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
     323              :     {
     324          496 :       lexer.skip_token ();
     325          496 :       return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
     326              :     }
     327              :   else
     328              :     {
     329            2 :       add_error (Error (t->get_locus (), "expected keyword or identifier"));
     330            2 :       return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
     331              :     }
     332          498 : }
     333              : 
     334              : template <typename ManagedTokenSource>
     335              : bool
     336         1506 : Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
     337              : {
     338         1506 :   auto macro_name = lexer.peek_token (2)->get_id ();
     339              : 
     340         1506 :   bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
     341              : 
     342         1506 :   return t->get_str () == Values::WeakKeywords::MACRO_RULES
     343         2446 :          && lexer.peek_token (1)->get_id () == EXCLAM && allowed_macro_name;
     344              : }
     345              : 
     346              : // Parses a single item
     347              : template <typename ManagedTokenSource>
     348              : tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>
     349        24071 : Parser<ManagedTokenSource>::parse_item (bool called_from_statement)
     350              : {
     351              :   // has a "called_from_statement" parameter for better error message handling
     352              : 
     353              :   // TODO: GCC 5 does not handle implicit return type correctly so we're forced
     354              :   // to specify it almost every time until the baseline GCC gets bumped.
     355              :   // Since this type is quite long and the code is dense we use an alias.
     356              :   //
     357              :   // When support for GCC 5 stops: remove this alias as well as the explicit
     358              :   // ctor calls.
     359              :   using RType = tl::expected<std::unique_ptr<AST::Item>, Parse::Error::Item>;
     360              : 
     361              :   // parse outer attributes for item
     362        24071 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
     363        24071 :   const_TokenPtr t = lexer.peek_token ();
     364              : 
     365        24071 :   switch (t->get_id ())
     366              :     {
     367            7 :     case END_OF_FILE:
     368              :       // not necessarily an error, unless we just read outer
     369              :       // attributes which needs to be attached
     370            7 :       if (!outer_attrs.empty ())
     371              :         {
     372            0 :           Rust::AST::Attribute attr = outer_attrs.back ();
     373            0 :           Error error (attr.get_locus (),
     374              :                        "expected item after outer attribute or doc comment");
     375            0 :           add_error (std::move (error));
     376            0 :         }
     377              :       return Parse::Error::Item::make_end_of_file ();
     378              : 
     379        22707 :     case ASYNC:
     380              :     case PUB:
     381              :     case MOD:
     382              :     case EXTERN_KW:
     383              :     case USE:
     384              :     case FN_KW:
     385              :     case TYPE:
     386              :     case STRUCT_KW:
     387              :     case ENUM_KW:
     388              :     case CONST:
     389              :     case STATIC_KW:
     390              :     case AUTO:
     391              :     case TRAIT:
     392              :     case IMPL:
     393              :     case MACRO:
     394              :     /* TODO: implement union keyword but not really because of
     395              :      * context-dependence crappy hack way to parse a union written below to
     396              :      * separate it from the good code. */
     397              :     // case UNION:
     398              :     case UNSAFE: // maybe - unsafe traits are a thing
     399              :       // if any of these (should be all possible VisItem prefixes), parse a
     400              :       // VisItem
     401              :       {
     402        22707 :         auto vis_item = parse_vis_item (std::move (outer_attrs));
     403        22707 :         if (!vis_item)
     404              :           return Parse::Error::Item::make_malformed ();
     405        22652 :         return RType{std::move (vis_item)};
     406        22707 :       }
     407            3 :     case SUPER:
     408              :     case SELF:
     409              :     case CRATE:
     410              :     case DOLLAR_SIGN:
     411              :       // almost certainly macro invocation semi
     412              :       {
     413            3 :         auto macro_invoc_semi
     414            3 :           = parse_macro_invocation_semi (std::move (outer_attrs));
     415            3 :         if (!macro_invoc_semi)
     416              :           return Parse::Error::Item::make_malformed ();
     417            3 :         return RType{std::move (macro_invoc_semi)};
     418            3 :       }
     419              :     // crappy hack to do union "keyword"
     420         1354 :     case IDENTIFIER:
     421              :       // TODO: ensure std::string and literal comparison works
     422         2649 :       if (t->get_str () == Values::WeakKeywords::UNION
     423         1421 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
     424              :         {
     425           67 :           auto vis_item = parse_vis_item (std::move (outer_attrs));
     426           67 :           if (!vis_item)
     427              :             return Parse::Error::Item::make_malformed ();
     428           67 :           return RType{std::move (vis_item)};
     429              :           // or should this go straight to parsing union?
     430           67 :         }
     431         2515 :       else if (t->get_str () == Values::WeakKeywords::DEFAULT
     432         1289 :                && lexer.peek_token (1)->get_id () != EXCLAM)
     433              :         {
     434            1 :           add_error (Error (t->get_locus (),
     435              :                             "%qs is only allowed on items within %qs blocks",
     436              :                             "default", "impl"));
     437              :           return Parse::Error::Item::make_malformed ();
     438              :         }
     439         2572 :       else if (is_macro_rules_def (t))
     440              :         {
     441              :           // macro_rules! macro item
     442          936 :           auto macro_rule_def = parse_macro_rules_def (std::move (outer_attrs));
     443          936 :           if (!macro_rule_def)
     444              :             return Parse::Error::Item::make_malformed ();
     445          923 :           return RType{std::move (macro_rule_def)};
     446          936 :         }
     447          700 :       else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
     448          699 :                || lexer.peek_token (1)->get_id () == EXCLAM)
     449              :         {
     450              :           /* path (probably) or macro invocation, so probably a macro invocation
     451              :            * semi */
     452          347 :           auto macro_invocation_semi
     453          347 :             = parse_macro_invocation_semi (std::move (outer_attrs));
     454          347 :           if (!macro_invocation_semi)
     455              :             return Parse::Error::Item::make_malformed ();
     456          346 :           return RType{std::move (macro_invocation_semi)};
     457          347 :         }
     458              :       gcc_fallthrough ();
     459              :     default:
     460              :       // otherwise unrecognised
     461            6 :       add_error (Error (t->get_locus (),
     462              :                         "unrecognised token %qs for start of %s",
     463              :                         t->get_token_description (),
     464              :                         called_from_statement ? "statement" : "item"));
     465              : 
     466              :       // skip somewhere?
     467              :       return Parse::Error::Item::make_malformed ();
     468              :       break;
     469              :     }
     470        24071 : }
     471              : 
     472              : // Parses a VisItem (item that can have non-default visibility).
     473              : template <typename ManagedTokenSource>
     474              : std::unique_ptr<AST::VisItem>
     475        23318 : Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
     476              : {
     477              :   // parse visibility, which may or may not exist
     478        23318 :   auto vis_res = parse_visibility ();
     479        23318 :   if (!vis_res)
     480            0 :     return nullptr;
     481        23318 :   auto vis = vis_res.value ();
     482              : 
     483              :   // select VisItem to create depending on keyword
     484        23318 :   const_TokenPtr t = lexer.peek_token ();
     485              : 
     486        23318 :   switch (t->get_id ())
     487              :     {
     488         1369 :     case MOD:
     489         1369 :       return parse_module (std::move (vis), std::move (outer_attrs));
     490         1514 :     case EXTERN_KW:
     491              :       // lookahead to resolve syntactical production
     492         1514 :       t = lexer.peek_token (1);
     493              : 
     494         1514 :       switch (t->get_id ())
     495              :         {
     496           27 :         case CRATE:
     497           27 :           return parse_extern_crate (std::move (vis), std::move (outer_attrs));
     498            0 :         case FN_KW: // extern function
     499            0 :           return parse_function (std::move (vis), std::move (outer_attrs));
     500            0 :         case LEFT_CURLY: // extern block
     501            0 :           return parse_extern_block (std::move (vis), std::move (outer_attrs));
     502         1487 :         case STRING_LITERAL: // for specifying extern ABI
     503              :           // could be extern block or extern function, so more lookahead
     504         1487 :           t = lexer.peek_token (2);
     505              : 
     506         1487 :           switch (t->get_id ())
     507              :             {
     508            4 :             case FN_KW:
     509            4 :               return parse_function (std::move (vis), std::move (outer_attrs));
     510         1483 :             case LEFT_CURLY:
     511         1483 :               return parse_extern_block (std::move (vis),
     512         1483 :                                          std::move (outer_attrs));
     513            0 :             default:
     514            0 :               add_error (
     515            0 :                 Error (t->get_locus (),
     516              :                        "unexpected token %qs in some sort of extern production",
     517              :                        t->get_token_description ()));
     518              : 
     519            0 :               lexer.skip_token (2); // TODO: is this right thing to do?
     520            0 :               return nullptr;
     521              :             }
     522            0 :         default:
     523            0 :           add_error (
     524            0 :             Error (t->get_locus (),
     525              :                    "unexpected token %qs in some sort of extern production",
     526              :                    t->get_token_description ()));
     527              : 
     528            0 :           lexer.skip_token (1); // TODO: is this right thing to do?
     529            0 :           return nullptr;
     530              :         }
     531          682 :     case USE:
     532          682 :       return parse_use_decl (std::move (vis), std::move (outer_attrs));
     533         6389 :     case FN_KW:
     534         6389 :       return parse_function (std::move (vis), std::move (outer_attrs));
     535           62 :     case TYPE:
     536           62 :       return parse_type_alias (std::move (vis), std::move (outer_attrs));
     537         2699 :     case STRUCT_KW:
     538         2699 :       return parse_struct (std::move (vis), std::move (outer_attrs));
     539          549 :     case ENUM_KW:
     540          549 :       return parse_enum (std::move (vis), std::move (outer_attrs));
     541              :     // TODO: implement union keyword but not really because of
     542              :     // context-dependence case UNION: crappy hack to do union "keyword"
     543          111 :     case IDENTIFIER:
     544          222 :       if (t->get_str () == Values::WeakKeywords::UNION
     545          222 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
     546              :         {
     547          111 :           return parse_union (std::move (vis), std::move (outer_attrs));
     548              :           // or should item switch go straight to parsing union?
     549              :         }
     550              :       else
     551              :         {
     552              :           break;
     553              :         }
     554          560 :     case CONST:
     555              :       // lookahead to resolve syntactical production
     556          560 :       t = lexer.peek_token (1);
     557              : 
     558          560 :       switch (t->get_id ())
     559              :         {
     560          476 :         case IDENTIFIER:
     561              :         case UNDERSCORE:
     562          476 :           return parse_const_item (std::move (vis), std::move (outer_attrs));
     563            1 :         case ASYNC:
     564            1 :           return parse_async_item (std::move (vis), std::move (outer_attrs));
     565           83 :         case UNSAFE:
     566              :         case EXTERN_KW:
     567              :         case FN_KW:
     568           83 :           return parse_function (std::move (vis), std::move (outer_attrs));
     569            0 :         default:
     570            0 :           add_error (
     571            0 :             Error (t->get_locus (),
     572              :                    "unexpected token %qs in some sort of const production",
     573              :                    t->get_token_description ()));
     574              : 
     575            0 :           lexer.skip_token (1); // TODO: is this right thing to do?
     576            0 :           return nullptr;
     577              :         }
     578              :     // for async functions
     579            2 :     case ASYNC:
     580            2 :       return parse_async_item (std::move (vis), std::move (outer_attrs));
     581              : 
     582           68 :     case STATIC_KW:
     583           68 :       return parse_static_item (std::move (vis), std::move (outer_attrs));
     584         3719 :     case AUTO:
     585              :     case TRAIT:
     586         3719 :       return parse_trait (std::move (vis), std::move (outer_attrs));
     587         5231 :     case IMPL:
     588         5231 :       return parse_impl (std::move (vis), std::move (outer_attrs));
     589          317 :     case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls),
     590              :       // lookahead to resolve syntactical production
     591          317 :       t = lexer.peek_token (1);
     592              : 
     593          317 :       switch (t->get_id ())
     594              :         {
     595           56 :         case AUTO:
     596              :         case TRAIT:
     597           56 :           return parse_trait (std::move (vis), std::move (outer_attrs));
     598          193 :         case EXTERN_KW:
     599              :         case FN_KW:
     600          193 :           return parse_function (std::move (vis), std::move (outer_attrs));
     601           67 :         case IMPL:
     602           67 :           return parse_impl (std::move (vis), std::move (outer_attrs));
     603            1 :         case MOD:
     604            1 :           return parse_module (std::move (vis), std::move (outer_attrs));
     605            0 :         default:
     606            0 :           add_error (
     607            0 :             Error (t->get_locus (),
     608              :                    "unexpected token %qs in some sort of unsafe production",
     609              :                    t->get_token_description ()));
     610              : 
     611            0 :           lexer.skip_token (1); // TODO: is this right thing to do?
     612            0 :           return nullptr;
     613              :         }
     614           45 :     case MACRO:
     615           45 :       return parse_decl_macro_def (std::move (vis), std::move (outer_attrs));
     616              :     default:
     617              :       // otherwise vis item clearly doesn't exist, which is not an error
     618              :       // has a catch-all post-switch return to allow other breaks to occur
     619              :       break;
     620              :     }
     621            1 :   return nullptr;
     622        23318 : }
     623              : 
     624              : template <typename ManagedTokenSource>
     625              : std::unique_ptr<AST::Function>
     626            4 : Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis,
     627              :                                               AST::AttrVec outer_attrs)
     628              : {
     629            4 :   auto offset = (lexer.peek_token ()->get_id () == CONST) ? 1 : 0;
     630            4 :   const_TokenPtr t = lexer.peek_token (offset);
     631              : 
     632            4 :   if (get_rust_edition () == Edition::E2015)
     633              :     {
     634            1 :       add_error (Error (t->get_locus (), ErrorCode::E0670,
     635              :                         "%<async fn%> is not permitted in Rust 2015"));
     636            1 :       add_error (
     637            2 :         Error::Hint (t->get_locus (),
     638              :                      "to use %<async fn%>, switch to Rust 2018 or later"));
     639              :     }
     640              : 
     641            4 :   t = lexer.peek_token (offset + 1);
     642              : 
     643            4 :   switch (t->get_id ())
     644              :     {
     645            4 :     case UNSAFE:
     646              :     case FN_KW:
     647            4 :       return parse_function (std::move (vis), std::move (outer_attrs));
     648              : 
     649            0 :     default:
     650            0 :       add_error (
     651            0 :         Error (t->get_locus (), "expected item, found keyword %<async%>"));
     652              : 
     653            0 :       lexer.skip_token (1);
     654            0 :       return nullptr;
     655              :     }
     656            4 : }
     657              : 
     658              : // Parses a macro rules definition syntax extension whatever thing.
     659              : template <typename ManagedTokenSource>
     660              : std::unique_ptr<AST::MacroRulesDefinition>
     661          945 : Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
     662              : {
     663              :   // ensure that first token is identifier saying "macro_rules"
     664          945 :   const_TokenPtr t = lexer.peek_token ();
     665          945 :   if (t->get_id () != IDENTIFIER
     666          945 :       || t->get_str () != Values::WeakKeywords::MACRO_RULES)
     667              :     {
     668            0 :       Error error (
     669              :         t->get_locus (),
     670              :         "macro rules definition does not start with %<macro_rules%>");
     671            0 :       add_error (std::move (error));
     672              : 
     673              :       // skip after somewhere?
     674            0 :       return nullptr;
     675            0 :     }
     676          945 :   lexer.skip_token ();
     677          945 :   location_t macro_locus = t->get_locus ();
     678              : 
     679          945 :   if (!skip_token (EXCLAM))
     680              :     {
     681              :       // skip after somewhere?
     682            0 :       return nullptr;
     683              :     }
     684              : 
     685              :   // parse macro name
     686          945 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
     687          945 :   if (ident_tok == nullptr)
     688              :     {
     689            1 :       return nullptr;
     690              :     }
     691          944 :   Identifier rule_name{ident_tok};
     692              : 
     693              :   // DEBUG
     694          944 :   rust_debug ("in macro rules def, about to parse parens.");
     695              : 
     696              :   // save delim type to ensure it is reused later
     697          944 :   AST::DelimType delim_type = AST::PARENS;
     698              : 
     699              :   // Map tokens to DelimType
     700          944 :   t = lexer.peek_token ();
     701          944 :   switch (t->get_id ())
     702              :     {
     703              :     case LEFT_PAREN:
     704              :       delim_type = AST::PARENS;
     705              :       break;
     706            0 :     case LEFT_SQUARE:
     707            0 :       delim_type = AST::SQUARE;
     708            0 :       break;
     709          942 :     case LEFT_CURLY:
     710          942 :       delim_type = AST::CURLY;
     711          942 :       break;
     712            0 :     default:
     713            0 :       add_error (Error (t->get_locus (),
     714              :                         "unexpected token %qs - expecting delimiters (for a "
     715              :                         "macro rules definition)",
     716              :                         t->get_token_description ()));
     717              : 
     718            0 :       return nullptr;
     719              :     }
     720          944 :   lexer.skip_token ();
     721              : 
     722              :   // parse actual macro rules
     723          944 :   std::vector<AST::MacroRule> macro_rules;
     724              : 
     725              :   // must be at least one macro rule, so parse it
     726          944 :   AST::MacroRule initial_rule = parse_macro_rule ();
     727          944 :   if (initial_rule.is_error ())
     728              :     {
     729           12 :       Error error (lexer.peek_token ()->get_locus (),
     730              :                    "required first macro rule in macro rules definition "
     731              :                    "could not be parsed");
     732           12 :       add_error (std::move (error));
     733              : 
     734              :       // skip after somewhere?
     735           12 :       return nullptr;
     736           12 :     }
     737          932 :   macro_rules.push_back (std::move (initial_rule));
     738              : 
     739              :   // DEBUG
     740          932 :   rust_debug ("successfully pushed back initial macro rule");
     741              : 
     742          932 :   t = lexer.peek_token ();
     743              :   // parse macro rules
     744         1060 :   while (t->get_id () == SEMICOLON)
     745              :     {
     746              :       // skip semicolon
     747          635 :       lexer.skip_token ();
     748              : 
     749              :       // don't parse if end of macro rules
     750         1270 :       if (Parse::Utils::token_id_matches_delims (lexer.peek_token ()->get_id (),
     751              :                                                  delim_type))
     752              :         {
     753              :           // DEBUG
     754          507 :           rust_debug (
     755              :             "broke out of parsing macro rules loop due to finding delim");
     756              : 
     757          507 :           break;
     758              :         }
     759              : 
     760              :       // try to parse next rule
     761          128 :       AST::MacroRule rule = parse_macro_rule ();
     762          128 :       if (rule.is_error ())
     763              :         {
     764            0 :           Error error (lexer.peek_token ()->get_locus (),
     765              :                        "failed to parse macro rule in macro rules definition");
     766            0 :           add_error (std::move (error));
     767              : 
     768            0 :           return nullptr;
     769            0 :         }
     770              : 
     771          128 :       macro_rules.push_back (std::move (rule));
     772              : 
     773              :       // DEBUG
     774          128 :       rust_debug ("successfully pushed back another macro rule");
     775              : 
     776          128 :       t = lexer.peek_token ();
     777              :     }
     778              : 
     779              :   // parse end delimiters
     780          932 :   t = lexer.peek_token ();
     781          932 :   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
     782              :     {
     783              :       // tokens match opening delimiter, so skip.
     784          932 :       lexer.skip_token ();
     785              : 
     786          932 :       if (delim_type != AST::CURLY)
     787              :         {
     788              :           // skip semicolon at end of non-curly macro definitions
     789            2 :           if (!skip_token (SEMICOLON))
     790              :             {
     791              :               // as this is the end, allow recovery (probably) - may change
     792              :               return std::unique_ptr<AST::MacroRulesDefinition> (
     793            0 :                 AST::MacroRulesDefinition::mbe (
     794              :                   std::move (rule_name), delim_type, std::move (macro_rules),
     795            0 :                   std::move (outer_attrs), macro_locus));
     796              :             }
     797              :         }
     798              : 
     799              :       return std::unique_ptr<AST::MacroRulesDefinition> (
     800         1864 :         AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
     801              :                                         std::move (macro_rules),
     802          932 :                                         std::move (outer_attrs), macro_locus));
     803              :     }
     804              :   else
     805              :     {
     806              :       // tokens don't match opening delimiters, so produce error
     807            0 :       Error error (t->get_locus (),
     808              :                    "unexpected token %qs - expecting closing delimiter %qs "
     809              :                    "(for a macro rules definition)",
     810              :                    t->get_token_description (),
     811              :                    (delim_type == AST::PARENS
     812              :                       ? ")"
     813              :                       : (delim_type == AST::SQUARE ? "]" : "}")));
     814            0 :       add_error (std::move (error));
     815              : 
     816              :       /* return empty macro definiton despite possibly parsing mostly valid one
     817              :        * - TODO is this a good idea? */
     818            0 :       return nullptr;
     819            0 :     }
     820         2833 : }
     821              : 
     822              : // Parses a declarative macro 2.0 definition.
     823              : template <typename ManagedTokenSource>
     824              : std::unique_ptr<AST::MacroRulesDefinition>
     825           45 : Parser<ManagedTokenSource>::parse_decl_macro_def (AST::Visibility vis,
     826              :                                                   AST::AttrVec outer_attrs)
     827              : {
     828              :   // ensure that first token is identifier saying "macro"
     829           45 :   const_TokenPtr t = lexer.peek_token ();
     830           45 :   if (t->get_id () != MACRO)
     831              :     {
     832            0 :       Error error (
     833              :         t->get_locus (),
     834              :         "declarative macro definition does not start with %<macro%>");
     835            0 :       add_error (std::move (error));
     836              : 
     837              :       // skip after somewhere?
     838            0 :       return nullptr;
     839            0 :     }
     840           45 :   lexer.skip_token ();
     841           45 :   location_t macro_locus = t->get_locus ();
     842              : 
     843              :   // parse macro name
     844           45 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
     845           45 :   if (ident_tok == nullptr)
     846              :     {
     847            0 :       return nullptr;
     848              :     }
     849           45 :   Identifier rule_name{ident_tok};
     850              : 
     851           45 :   t = lexer.peek_token ();
     852           45 :   if (t->get_id () == LEFT_PAREN)
     853              :     {
     854              :       // single definiton of macro rule
     855              :       // e.g. `macro foo($e:expr) {}`
     856              : 
     857              :       // parse macro matcher
     858           20 :       location_t locus = lexer.peek_token ()->get_locus ();
     859           20 :       AST::MacroMatcher matcher = parse_macro_matcher ();
     860           20 :       if (matcher.is_error ())
     861            0 :         return nullptr;
     862              : 
     863              :       // check delimiter of macro matcher
     864           20 :       if (matcher.get_delim_type () != AST::DelimType::PARENS)
     865              :         {
     866            0 :           Error error (locus, "only parenthesis can be used for a macro "
     867              :                               "matcher in declarative macro definition");
     868            0 :           add_error (std::move (error));
     869            0 :           return nullptr;
     870            0 :         }
     871              : 
     872           20 :       location_t transcriber_loc = lexer.peek_token ()->get_locus ();
     873           20 :       auto delim_tok_tree = parse_delim_token_tree ();
     874           20 :       if (!delim_tok_tree)
     875            0 :         return nullptr;
     876              : 
     877           20 :       AST::MacroTranscriber transcriber (delim_tok_tree.value (),
     878              :                                          transcriber_loc);
     879              : 
     880           20 :       if (transcriber.get_token_tree ().get_delim_type ()
     881              :           != AST::DelimType::CURLY)
     882              :         {
     883            1 :           Error error (transcriber_loc,
     884              :                        "only braces can be used for a macro transcriber "
     885              :                        "in declarative macro definition");
     886            1 :           add_error (std::move (error));
     887            1 :           return nullptr;
     888            1 :         }
     889              : 
     890           19 :       std::vector<AST::MacroRule> macro_rules;
     891           19 :       macro_rules.emplace_back (std::move (matcher), std::move (transcriber),
     892              :                                 locus);
     893              : 
     894              :       return std::unique_ptr<AST::MacroRulesDefinition> (
     895           38 :         AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
     896              :                                                macro_rules,
     897              :                                                std::move (outer_attrs),
     898           19 :                                                macro_locus, vis));
     899           59 :     }
     900           25 :   else if (t->get_id () == LEFT_CURLY)
     901              :     {
     902              :       // multiple definitions of macro rule separated by comma
     903              :       // e.g. `macro foo { () => {}, ($e:expr) => {}, }`
     904              : 
     905              :       // parse left curly
     906           25 :       const_TokenPtr left_curly = expect_token (LEFT_CURLY);
     907           25 :       if (left_curly == nullptr)
     908              :         {
     909            0 :           return nullptr;
     910              :         }
     911              : 
     912              :       // parse actual macro rules
     913           25 :       std::vector<AST::MacroRule> macro_rules;
     914              : 
     915              :       // must be at least one macro rule, so parse it
     916           25 :       AST::MacroRule initial_rule = parse_macro_rule ();
     917           25 :       if (initial_rule.is_error ())
     918              :         {
     919            1 :           Error error (
     920            1 :             lexer.peek_token ()->get_locus (),
     921              :             "required first macro rule in declarative macro definition "
     922              :             "could not be parsed");
     923            1 :           add_error (std::move (error));
     924              : 
     925              :           // skip after somewhere?
     926            1 :           return nullptr;
     927            1 :         }
     928           24 :       macro_rules.push_back (std::move (initial_rule));
     929              : 
     930           24 :       t = lexer.peek_token ();
     931              :       // parse macro rules
     932           40 :       while (t->get_id () == COMMA)
     933              :         {
     934              :           // skip comma
     935           32 :           lexer.skip_token ();
     936              : 
     937              :           // don't parse if end of macro rules
     938           32 :           if (Parse::Utils::token_id_matches_delims (
     939           64 :                 lexer.peek_token ()->get_id (), AST::CURLY))
     940              :             {
     941              :               break;
     942              :             }
     943              : 
     944              :           // try to parse next rule
     945           16 :           AST::MacroRule rule = parse_macro_rule ();
     946           16 :           if (rule.is_error ())
     947              :             {
     948            0 :               Error error (
     949            0 :                 lexer.peek_token ()->get_locus (),
     950              :                 "failed to parse macro rule in declarative macro definition");
     951            0 :               add_error (std::move (error));
     952              : 
     953            0 :               return nullptr;
     954            0 :             }
     955              : 
     956           16 :           macro_rules.push_back (std::move (rule));
     957              : 
     958           16 :           t = lexer.peek_token ();
     959              :         }
     960              : 
     961              :       // parse right curly
     962           24 :       const_TokenPtr right_curly = expect_token (RIGHT_CURLY);
     963           24 :       if (right_curly == nullptr)
     964              :         {
     965            0 :           return nullptr;
     966              :         }
     967              : 
     968              :       return std::unique_ptr<AST::MacroRulesDefinition> (
     969           48 :         AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
     970              :                                                std::move (macro_rules),
     971              :                                                std::move (outer_attrs),
     972           24 :                                                macro_locus, vis));
     973           50 :     }
     974              :   else
     975              :     {
     976            0 :       add_error (Error (t->get_locus (),
     977              :                         "unexpected token %qs - expecting delimiters "
     978              :                         "(for a declarative macro definiton)",
     979              :                         t->get_token_description ()));
     980            0 :       return nullptr;
     981              :     }
     982           90 : }
     983              : 
     984              : /* Parses a visibility syntactical production (i.e. creating a non-default
     985              :  * visibility) */
     986              : template <typename ManagedTokenSource>
     987              : tl::expected<AST::Visibility, Parse::Error::Visibility>
     988        42043 : Parser<ManagedTokenSource>::parse_visibility ()
     989              : {
     990              :   // check for no visibility
     991        84086 :   if (lexer.peek_token ()->get_id () != PUB)
     992              :     {
     993        33714 :       return AST::Visibility::create_private ();
     994              :     }
     995              : 
     996         8329 :   auto vis_loc = lexer.peek_token ()->get_locus ();
     997         8329 :   lexer.skip_token ();
     998              : 
     999              :   // create simple pub visibility if
    1000              :   // - found no parentheses
    1001              :   // - found unit type `()`
    1002        16658 :   if (lexer.peek_token ()->get_id () != LEFT_PAREN
    1003         8396 :       || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
    1004              :     {
    1005         8263 :       return AST::Visibility::create_public (vis_loc);
    1006              :       // or whatever
    1007              :     }
    1008              : 
    1009           66 :   lexer.skip_token ();
    1010              : 
    1011           66 :   const_TokenPtr t = lexer.peek_token ();
    1012           66 :   auto path_loc = t->get_locus ();
    1013              : 
    1014           66 :   switch (t->get_id ())
    1015              :     {
    1016           53 :     case CRATE:
    1017           53 :       lexer.skip_token ();
    1018              : 
    1019           53 :       skip_token (RIGHT_PAREN);
    1020              : 
    1021           53 :       return AST::Visibility::create_crate (path_loc, vis_loc);
    1022            0 :     case SELF:
    1023            0 :       lexer.skip_token ();
    1024              : 
    1025            0 :       skip_token (RIGHT_PAREN);
    1026              : 
    1027            0 :       return AST::Visibility::create_self (path_loc, vis_loc);
    1028            1 :     case SUPER:
    1029            1 :       lexer.skip_token ();
    1030              : 
    1031            1 :       skip_token (RIGHT_PAREN);
    1032              : 
    1033            1 :       return AST::Visibility::create_super (path_loc, vis_loc);
    1034           12 :     case IN:
    1035              :       {
    1036           12 :         lexer.skip_token ();
    1037              : 
    1038              :         // parse the "in" path as well
    1039           12 :         auto path = parse_simple_path ();
    1040           12 :         if (!path)
    1041              :           {
    1042            0 :             Error error (lexer.peek_token ()->get_locus (),
    1043              :                          "missing path in pub(in path) visibility");
    1044            0 :             add_error (std::move (error));
    1045              : 
    1046              :             // skip after somewhere?
    1047            0 :             return Parse::Error::Visibility::make_missing_path ();
    1048            0 :           }
    1049              : 
    1050           12 :         skip_token (RIGHT_PAREN);
    1051              : 
    1052           24 :         return AST::Visibility::create_in_path (std::move (path.value ()),
    1053           12 :                                                 vis_loc);
    1054           12 :       }
    1055            0 :     default:
    1056            0 :       add_error (Error (t->get_locus (), "unexpected token %qs in visibility",
    1057              :                         t->get_token_description ()));
    1058              : 
    1059            0 :       lexer.skip_token ();
    1060              :       return Parse::Error::Visibility::make_malformed ();
    1061              :     }
    1062           66 : }
    1063              : 
    1064              : // Parses a module - either a bodied module or a module defined in another file.
    1065              : template <typename ManagedTokenSource>
    1066              : std::unique_ptr<AST::Module>
    1067         1370 : Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
    1068              :                                           AST::AttrVec outer_attrs)
    1069              : {
    1070         1370 :   location_t locus = lexer.peek_token ()->get_locus ();
    1071              : 
    1072         1370 :   Unsafety safety = Unsafety::Normal;
    1073         2740 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    1074              :     {
    1075            1 :       safety = Unsafety::Unsafe;
    1076            1 :       skip_token (UNSAFE);
    1077              :     }
    1078              : 
    1079         1370 :   skip_token (MOD);
    1080              : 
    1081         1370 :   const_TokenPtr module_name = expect_token (IDENTIFIER);
    1082         1370 :   if (module_name == nullptr)
    1083              :     {
    1084            0 :       return nullptr;
    1085              :     }
    1086         1370 :   Identifier name{module_name};
    1087              : 
    1088         1370 :   const_TokenPtr t = lexer.peek_token ();
    1089              : 
    1090         1370 :   switch (t->get_id ())
    1091              :     {
    1092          138 :     case SEMICOLON:
    1093          138 :       lexer.skip_token ();
    1094              : 
    1095              :       // Construct an external module
    1096              :       return std::unique_ptr<AST::Module> (
    1097          414 :         new AST::Module (std::move (name), std::move (vis),
    1098              :                          std::move (outer_attrs), locus, safety,
    1099          414 :                          lexer.get_filename (), inline_module_stack));
    1100         1232 :     case LEFT_CURLY:
    1101              :       {
    1102         1232 :         lexer.skip_token ();
    1103              : 
    1104              :         // parse inner attributes
    1105         1232 :         AST::AttrVec inner_attrs = parse_inner_attributes ();
    1106              : 
    1107         1232 :         std::string default_path = name.as_string ();
    1108              : 
    1109         1232 :         if (inline_module_stack.empty ())
    1110              :           {
    1111          703 :             std::string filename = lexer.get_filename ();
    1112          703 :             auto slash_idx = filename.rfind (file_separator);
    1113          703 :             if (slash_idx == std::string::npos)
    1114              :               slash_idx = 0;
    1115              :             else
    1116          703 :               slash_idx++;
    1117          703 :             filename = filename.substr (slash_idx);
    1118              : 
    1119          703 :             std::string subdir;
    1120          703 :             if (get_file_subdir (filename, subdir))
    1121          703 :               default_path = subdir + file_separator + name.as_string ();
    1122          703 :           }
    1123              : 
    1124         1232 :         std::string module_path_name
    1125              :           = extract_module_path (inner_attrs, outer_attrs, default_path);
    1126         1232 :         InlineModuleStackScope scope (*this, std::move (module_path_name));
    1127              : 
    1128              :         // parse items
    1129         1232 :         std::vector<std::unique_ptr<AST::Item>> items;
    1130         1232 :         const_TokenPtr tok = lexer.peek_token ();
    1131         4072 :         while (tok->get_id () != RIGHT_CURLY)
    1132              :           {
    1133         2840 :             auto item = parse_item (false);
    1134         2840 :             if (!item)
    1135              :               {
    1136            0 :                 Error error (tok->get_locus (),
    1137              :                              "failed to parse item in module");
    1138            0 :                 add_error (std::move (error));
    1139              : 
    1140            0 :                 return nullptr;
    1141            0 :               }
    1142              : 
    1143         2840 :             items.push_back (std::move (item.value ()));
    1144              : 
    1145         2840 :             tok = lexer.peek_token ();
    1146              :           }
    1147              : 
    1148         1232 :         if (!skip_token (RIGHT_CURLY))
    1149              :           {
    1150              :             // skip somewhere?
    1151            0 :             return nullptr;
    1152              :           }
    1153              : 
    1154              :         return std::unique_ptr<AST::Module> (
    1155         1232 :           new AST::Module (std::move (name), locus, std::move (items),
    1156              :                            std::move (vis), safety, std::move (inner_attrs),
    1157         1232 :                            std::move (outer_attrs))); // module name?
    1158         1232 :       }
    1159            0 :     default:
    1160            0 :       add_error (
    1161            0 :         Error (t->get_locus (),
    1162              :                "unexpected token %qs in module declaration/definition item",
    1163              :                t->get_token_description ()));
    1164              : 
    1165            0 :       lexer.skip_token ();
    1166            0 :       return nullptr;
    1167              :     }
    1168         1370 : }
    1169              : 
    1170              : // Parses an extern crate declaration (dependency on external crate)
    1171              : template <typename ManagedTokenSource>
    1172              : std::unique_ptr<AST::ExternCrate>
    1173           27 : Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis,
    1174              :                                                 AST::AttrVec outer_attrs)
    1175              : {
    1176           27 :   location_t locus = lexer.peek_token ()->get_locus ();
    1177           27 :   if (!skip_token (EXTERN_KW))
    1178              :     {
    1179            0 :       skip_after_semicolon ();
    1180            0 :       return nullptr;
    1181              :     }
    1182              : 
    1183           27 :   if (!skip_token (CRATE))
    1184              :     {
    1185            0 :       skip_after_semicolon ();
    1186            0 :       return nullptr;
    1187              :     }
    1188              : 
    1189              :   /* parse crate reference name - this has its own syntactical rule in reference
    1190              :    * but seems to not be used elsewhere, so i'm putting it here */
    1191           27 :   const_TokenPtr crate_name_tok = lexer.peek_token ();
    1192           27 :   std::string crate_name;
    1193              : 
    1194           27 :   switch (crate_name_tok->get_id ())
    1195              :     {
    1196           27 :     case IDENTIFIER:
    1197           27 :       crate_name = crate_name_tok->get_str ();
    1198           27 :       lexer.skip_token ();
    1199              :       break;
    1200            0 :     case SELF:
    1201            0 :       crate_name = Values::Keywords::SELF;
    1202            0 :       lexer.skip_token ();
    1203              :       break;
    1204            0 :     default:
    1205            0 :       add_error (
    1206            0 :         Error (crate_name_tok->get_locus (),
    1207              :                "expecting crate name (identifier or %<self%>), found %qs",
    1208              :                crate_name_tok->get_token_description ()));
    1209              : 
    1210            0 :       skip_after_semicolon ();
    1211            0 :       return nullptr;
    1212              :     }
    1213              : 
    1214              :   // don't parse as clause if it doesn't exist
    1215           54 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    1216              :     {
    1217           27 :       lexer.skip_token ();
    1218              : 
    1219              :       return std::unique_ptr<AST::ExternCrate> (
    1220           27 :         new AST::ExternCrate (std::move (crate_name), std::move (vis),
    1221           27 :                               std::move (outer_attrs), locus));
    1222              :     }
    1223              : 
    1224              :   /* parse as clause - this also has its own syntactical rule in reference and
    1225              :    * also seems to not be used elsewhere, so including here again. */
    1226            0 :   if (!skip_token (AS))
    1227              :     {
    1228            0 :       skip_after_semicolon ();
    1229            0 :       return nullptr;
    1230              :     }
    1231              : 
    1232            0 :   const_TokenPtr as_name_tok = lexer.peek_token ();
    1233            0 :   std::string as_name;
    1234              : 
    1235            0 :   switch (as_name_tok->get_id ())
    1236              :     {
    1237            0 :     case IDENTIFIER:
    1238            0 :       as_name = as_name_tok->get_str ();
    1239            0 :       lexer.skip_token ();
    1240              :       break;
    1241            0 :     case UNDERSCORE:
    1242            0 :       as_name = Values::Keywords::UNDERSCORE;
    1243            0 :       lexer.skip_token ();
    1244              :       break;
    1245            0 :     default:
    1246            0 :       add_error (
    1247            0 :         Error (as_name_tok->get_locus (),
    1248              :                "expecting as clause name (identifier or %<_%>), found %qs",
    1249              :                as_name_tok->get_token_description ()));
    1250              : 
    1251            0 :       skip_after_semicolon ();
    1252            0 :       return nullptr;
    1253              :     }
    1254              : 
    1255            0 :   if (!skip_token (SEMICOLON))
    1256              :     {
    1257            0 :       skip_after_semicolon ();
    1258            0 :       return nullptr;
    1259              :     }
    1260              : 
    1261              :   return std::unique_ptr<AST::ExternCrate> (
    1262            0 :     new AST::ExternCrate (std::move (crate_name), std::move (vis),
    1263            0 :                           std::move (outer_attrs), locus, std::move (as_name)));
    1264           54 : }
    1265              : 
    1266              : // Parses a use declaration.
    1267              : template <typename ManagedTokenSource>
    1268              : std::unique_ptr<AST::UseDeclaration>
    1269          682 : Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
    1270              :                                             AST::AttrVec outer_attrs)
    1271              : {
    1272          682 :   location_t locus = lexer.peek_token ()->get_locus ();
    1273          682 :   if (!skip_token (USE))
    1274              :     {
    1275            0 :       skip_after_semicolon ();
    1276            0 :       return nullptr;
    1277              :     }
    1278              : 
    1279              :   // parse use tree, which is required
    1280          682 :   std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
    1281          682 :   if (use_tree == nullptr)
    1282              :     {
    1283            1 :       Error error (lexer.peek_token ()->get_locus (),
    1284              :                    "could not parse use tree in use declaration");
    1285            1 :       add_error (std::move (error));
    1286              : 
    1287            1 :       skip_after_semicolon ();
    1288            1 :       return nullptr;
    1289            1 :     }
    1290              : 
    1291          681 :   if (!skip_token (SEMICOLON))
    1292              :     {
    1293            0 :       skip_after_semicolon ();
    1294            0 :       return nullptr;
    1295              :     }
    1296              : 
    1297              :   return std::unique_ptr<AST::UseDeclaration> (
    1298          681 :     new AST::UseDeclaration (std::move (use_tree), std::move (vis),
    1299          681 :                              std::move (outer_attrs), locus));
    1300          682 : }
    1301              : 
    1302              : // Parses a use tree (which can be recursive and is actually a base class).
    1303              : template <typename ManagedTokenSource>
    1304              : std::unique_ptr<AST::UseTree>
    1305         1267 : Parser<ManagedTokenSource>::parse_use_tree ()
    1306              : {
    1307              :   /* potential syntax definitions in attempt to get algorithm:
    1308              :    *  Glob:
    1309              :    *      <- SimplePath :: *
    1310              :    *      <- :: *
    1311              :    *      <- *
    1312              :    *  Nested tree thing:
    1313              :    *      <- SimplePath :: { COMPLICATED_INNER_TREE_THING }
    1314              :    *      <- :: COMPLICATED_INNER_TREE_THING }
    1315              :    *      <- { COMPLICATED_INNER_TREE_THING }
    1316              :    *  Rebind thing:
    1317              :    *      <- SimplePath as IDENTIFIER
    1318              :    *      <- SimplePath as _
    1319              :    *      <- SimplePath
    1320              :    */
    1321              : 
    1322              :   /* current plan of attack: try to parse SimplePath first - if fails, one of
    1323              :    * top two then try parse :: - if fails, one of top two. Next is deciding
    1324              :    * character for top two. */
    1325              : 
    1326              :   /* Thus, parsing smaller parts of use tree may require feeding into function
    1327              :    * via parameters (or could handle all in this single function because other
    1328              :    * use tree types aren't recognised as separate in the spec) */
    1329              : 
    1330              :   // TODO: I think this function is too complex, probably should split it
    1331              : 
    1332         1267 :   location_t locus = lexer.peek_token ()->get_locus ();
    1333              : 
    1334              :   // bool has_path = false;
    1335         1267 :   auto path = parse_simple_path ();
    1336              : 
    1337         1267 :   if (!path)
    1338              :     {
    1339              :       // has no path, so must be glob or nested tree UseTree type
    1340              : 
    1341            2 :       bool is_global = false;
    1342              : 
    1343              :       // check for global scope resolution operator
    1344            4 :       if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
    1345              :         {
    1346            0 :           lexer.skip_token ();
    1347            0 :           is_global = true;
    1348              :         }
    1349              : 
    1350            2 :       const_TokenPtr t = lexer.peek_token ();
    1351            2 :       switch (t->get_id ())
    1352              :         {
    1353            0 :         case ASTERISK:
    1354              :           // glob UseTree type
    1355            0 :           lexer.skip_token ();
    1356              : 
    1357            0 :           if (is_global)
    1358            0 :             return std::unique_ptr<AST::UseTreeGlob> (
    1359            0 :               new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL,
    1360            0 :                                     AST::SimplePath::create_empty (), locus));
    1361              :           else
    1362            0 :             return std::unique_ptr<AST::UseTreeGlob> (
    1363            0 :               new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH,
    1364            0 :                                     AST::SimplePath::create_empty (), locus));
    1365            2 :         case LEFT_CURLY:
    1366              :           {
    1367              :             // nested tree UseTree type
    1368            2 :             lexer.skip_token ();
    1369              : 
    1370            2 :             std::vector<std::unique_ptr<AST::UseTree>> use_trees;
    1371              : 
    1372            2 :             const_TokenPtr t = lexer.peek_token ();
    1373            5 :             while (t->get_id () != RIGHT_CURLY)
    1374              :               {
    1375            3 :                 std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
    1376            3 :                 if (use_tree == nullptr)
    1377              :                   {
    1378              :                     break;
    1379              :                   }
    1380              : 
    1381            3 :                 use_trees.push_back (std::move (use_tree));
    1382              : 
    1383            6 :                 if (lexer.peek_token ()->get_id () != COMMA)
    1384              :                   break;
    1385              : 
    1386            1 :                 lexer.skip_token ();
    1387            1 :                 t = lexer.peek_token ();
    1388              :               }
    1389              : 
    1390              :             // skip end curly delimiter
    1391            2 :             if (!skip_token (RIGHT_CURLY))
    1392              :               {
    1393              :                 // skip after somewhere?
    1394            0 :                 return nullptr;
    1395              :               }
    1396              : 
    1397            2 :             if (is_global)
    1398            0 :               return std::unique_ptr<AST::UseTreeList> (
    1399            0 :                 new AST::UseTreeList (AST::UseTreeList::GLOBAL,
    1400            0 :                                       AST::SimplePath::create_empty (),
    1401            0 :                                       std::move (use_trees), locus));
    1402              :             else
    1403            2 :               return std::unique_ptr<AST::UseTreeList> (
    1404            4 :                 new AST::UseTreeList (AST::UseTreeList::NO_PATH,
    1405            4 :                                       AST::SimplePath::create_empty (),
    1406            2 :                                       std::move (use_trees), locus));
    1407            2 :           }
    1408            0 :         case AS:
    1409              :           // this is not allowed
    1410            0 :           add_error (Error (
    1411              :             t->get_locus (),
    1412              :             "use declaration with rebind %<as%> requires a valid simple path - "
    1413              :             "none found"));
    1414              : 
    1415            0 :           skip_after_semicolon ();
    1416            0 :           return nullptr;
    1417            0 :         default:
    1418            0 :           add_error (Error (t->get_locus (),
    1419              :                             "unexpected token %qs in use tree with "
    1420              :                             "no valid simple path (i.e. list"
    1421              :                             " or glob use tree)",
    1422              :                             t->get_token_description ()));
    1423              : 
    1424            0 :           skip_after_semicolon ();
    1425            0 :           return nullptr;
    1426              :         }
    1427            2 :     }
    1428              :   else
    1429              :     {
    1430         1265 :       const_TokenPtr t = lexer.peek_token ();
    1431              : 
    1432         1265 :       switch (t->get_id ())
    1433              :         {
    1434            6 :         case AS:
    1435              :           {
    1436              :             // rebind UseTree type
    1437            6 :             lexer.skip_token ();
    1438              : 
    1439            6 :             const_TokenPtr t = lexer.peek_token ();
    1440            6 :             switch (t->get_id ())
    1441              :               {
    1442            4 :               case IDENTIFIER:
    1443              :                 // skip lexer token
    1444            4 :                 lexer.skip_token ();
    1445              : 
    1446            4 :                 return std::unique_ptr<AST::UseTreeRebind> (
    1447           12 :                   new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER,
    1448           12 :                                           std::move (path.value ()), locus, t));
    1449            2 :               case UNDERSCORE:
    1450              :                 // skip lexer token
    1451            2 :                 lexer.skip_token ();
    1452              : 
    1453            2 :                 return std::unique_ptr<AST::UseTreeRebind> (
    1454            6 :                   new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD,
    1455            2 :                                           std::move (path.value ()), locus,
    1456              :                                           {Values::Keywords::UNDERSCORE,
    1457            2 :                                            t->get_locus ()}));
    1458            0 :               default:
    1459            0 :                 add_error (Error (
    1460              :                   t->get_locus (),
    1461              :                   "unexpected token %qs in use tree with as clause - expected "
    1462              :                   "identifier or %<_%>",
    1463              :                   t->get_token_description ()));
    1464              : 
    1465            0 :                 skip_after_semicolon ();
    1466            0 :                 return nullptr;
    1467              :               }
    1468            6 :           }
    1469         1091 :         case SEMICOLON:
    1470              :           // rebind UseTree type without rebinding - path only
    1471              : 
    1472              :           // don't skip semicolon - handled in parse_use_tree
    1473              :           // lexer.skip_token();
    1474              :         case COMMA:
    1475              :         case RIGHT_CURLY:
    1476              :           // this may occur in recursive calls - assume it is ok and ignore it
    1477         1091 :           return std::unique_ptr<AST::UseTreeRebind> (
    1478         3273 :             new AST::UseTreeRebind (AST::UseTreeRebind::NONE,
    1479         1091 :                                     std::move (path.value ()), locus));
    1480              :         case SCOPE_RESOLUTION:
    1481              :           // keep going
    1482              :           break;
    1483            1 :         default:
    1484            1 :           add_error (Error (t->get_locus (),
    1485              :                             "unexpected token %qs in use tree with valid path",
    1486              :                             t->get_token_description ()));
    1487            1 :           return nullptr;
    1488              :         }
    1489              : 
    1490          167 :       skip_token ();
    1491          167 :       t = lexer.peek_token ();
    1492              : 
    1493          167 :       switch (t->get_id ())
    1494              :         {
    1495           13 :         case ASTERISK:
    1496              :           // glob UseTree type
    1497           13 :           lexer.skip_token ();
    1498              : 
    1499           13 :           return std::unique_ptr<AST::UseTreeGlob> (
    1500           39 :             new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
    1501           13 :                                   std::move (path.value ()), locus));
    1502          154 :         case LEFT_CURLY:
    1503              :           {
    1504              :             // nested tree UseTree type
    1505          154 :             lexer.skip_token ();
    1506              : 
    1507          154 :             std::vector<std::unique_ptr<AST::UseTree>> use_trees;
    1508              : 
    1509              :             // TODO: think of better control structure
    1510          154 :             const_TokenPtr t = lexer.peek_token ();
    1511          736 :             while (t->get_id () != RIGHT_CURLY)
    1512              :               {
    1513          582 :                 std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
    1514          582 :                 if (use_tree == nullptr)
    1515              :                   {
    1516              :                     break;
    1517              :                   }
    1518              : 
    1519          582 :                 use_trees.push_back (std::move (use_tree));
    1520              : 
    1521         1164 :                 if (lexer.peek_token ()->get_id () != COMMA)
    1522              :                   break;
    1523              : 
    1524          428 :                 lexer.skip_token ();
    1525          428 :                 t = lexer.peek_token ();
    1526              :               }
    1527              : 
    1528              :             // skip end curly delimiter
    1529          154 :             if (!skip_token (RIGHT_CURLY))
    1530              :               {
    1531              :                 // skip after somewhere?
    1532            0 :                 return nullptr;
    1533              :               }
    1534              : 
    1535          154 :             return std::unique_ptr<AST::UseTreeList> (
    1536          308 :               new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED,
    1537          154 :                                     std::move (path.value ()),
    1538          154 :                                     std::move (use_trees), locus));
    1539          154 :           }
    1540            0 :         default:
    1541            0 :           add_error (Error (t->get_locus (),
    1542              :                             "unexpected token %qs in use tree with valid path",
    1543              :                             t->get_token_description ()));
    1544              : 
    1545              :           // skip_after_semicolon();
    1546            0 :           return nullptr;
    1547              :         }
    1548         1265 :     }
    1549         1267 : }
    1550              : 
    1551              : // Parses a function (not a method).
    1552              : template <typename ManagedTokenSource>
    1553              : std::unique_ptr<AST::Function>
    1554        11471 : Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
    1555              :                                             AST::AttrVec outer_attrs,
    1556              :                                             bool is_external)
    1557              : {
    1558        11471 :   location_t locus = lexer.peek_token ()->get_locus ();
    1559              :   // Get qualifiers for function if they exist
    1560        11471 :   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
    1561              : 
    1562        11471 :   skip_token (FN_KW);
    1563              : 
    1564              :   // Save function name token
    1565        11471 :   const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
    1566        11471 :   if (function_name_tok == nullptr)
    1567              :     {
    1568            0 :       skip_after_next_block ();
    1569            0 :       return nullptr;
    1570              :     }
    1571        11471 :   Identifier function_name{function_name_tok};
    1572              : 
    1573              :   // parse generic params - if exist
    1574        11471 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    1575              :     = parse_generic_params_in_angles ();
    1576              : 
    1577        11471 :   if (!skip_token (LEFT_PAREN))
    1578              :     {
    1579            0 :       Error error (lexer.peek_token ()->get_locus (),
    1580              :                    "function declaration missing opening parentheses before "
    1581              :                    "parameter list");
    1582            0 :       add_error (std::move (error));
    1583              : 
    1584            0 :       skip_after_next_block ();
    1585            0 :       return nullptr;
    1586            0 :     }
    1587              : 
    1588        11471 :   auto initial_param = parse_self_param ();
    1589              : 
    1590        11471 :   if (!initial_param.has_value ()
    1591        11471 :       && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
    1592            0 :     return nullptr;
    1593              : 
    1594        13721 :   if (initial_param.has_value () && lexer.peek_token ()->get_id () == COMMA)
    1595         1369 :     skip_token ();
    1596              : 
    1597              :   // parse function parameters (only if next token isn't right paren)
    1598        11471 :   std::vector<std::unique_ptr<AST::Param>> function_params;
    1599              : 
    1600        22942 :   if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
    1601              :     function_params
    1602         5139 :       = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
    1603              : 
    1604        11471 :   if (initial_param.has_value ())
    1605         2250 :     function_params.insert (function_params.begin (),
    1606         2250 :                             std::move (*initial_param));
    1607              : 
    1608        11471 :   if (!skip_token (RIGHT_PAREN))
    1609              :     {
    1610            0 :       Error error (lexer.peek_token ()->get_locus (),
    1611              :                    "function declaration missing closing parentheses after "
    1612              :                    "parameter list");
    1613            0 :       add_error (std::move (error));
    1614              : 
    1615            0 :       skip_after_next_block ();
    1616            0 :       return nullptr;
    1617            0 :     }
    1618              : 
    1619              :   // parse function return type - if exists
    1620        11471 :   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
    1621              : 
    1622              :   // parse where clause - if exists
    1623        11471 :   AST::WhereClause where_clause = parse_where_clause ();
    1624              : 
    1625        11471 :   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
    1626        22942 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    1627         3931 :     lexer.skip_token ();
    1628              :   else
    1629              :     {
    1630         7540 :       auto block_expr = parse_block_expr ();
    1631         7540 :       if (!block_expr)
    1632           29 :         return nullptr;
    1633         7511 :       body = std::move (block_expr.value ());
    1634         7540 :     }
    1635              : 
    1636              :   return std::unique_ptr<AST::Function> (
    1637        30395 :     new AST::Function (std::move (function_name), std::move (qualifiers),
    1638              :                        std::move (generic_params), std::move (function_params),
    1639              :                        std::move (return_type), std::move (where_clause),
    1640              :                        std::move (body), std::move (vis),
    1641        11442 :                        std::move (outer_attrs), locus, false, is_external));
    1642        34413 : }
    1643              : 
    1644              : // Parses function or method qualifiers (i.e. const, unsafe, and extern).
    1645              : template <typename ManagedTokenSource>
    1646              : AST::FunctionQualifiers
    1647        18233 : Parser<ManagedTokenSource>::parse_function_qualifiers ()
    1648              : {
    1649        18233 :   Async async_status = Async::No;
    1650        18233 :   Const const_status = Const::No;
    1651        18233 :   Unsafety unsafe_status = Unsafety::Normal;
    1652        18233 :   bool has_extern = false;
    1653        18233 :   std::string abi;
    1654              : 
    1655        18233 :   const_TokenPtr t;
    1656              :   location_t locus;
    1657              :   // Check in order of const, unsafe, then extern
    1658        54699 :   for (int i = 0; i < 2; i++)
    1659              :     {
    1660        36466 :       t = lexer.peek_token ();
    1661        36466 :       locus = t->get_locus ();
    1662              : 
    1663        36466 :       switch (t->get_id ())
    1664              :         {
    1665          862 :         case CONST:
    1666          862 :           lexer.skip_token ();
    1667          862 :           const_status = Const::Yes;
    1668          862 :           break;
    1669            8 :         case ASYNC:
    1670            8 :           lexer.skip_token ();
    1671            8 :           async_status = Async::Yes;
    1672            8 :           break;
    1673              :         default:
    1674              :           // const status is still none
    1675              :           break;
    1676              :         }
    1677              :     }
    1678              : 
    1679        36466 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    1680              :     {
    1681          495 :       lexer.skip_token ();
    1682          495 :       unsafe_status = Unsafety::Unsafe;
    1683              :     }
    1684              : 
    1685        36466 :   if (lexer.peek_token ()->get_id () == EXTERN_KW)
    1686              :     {
    1687           99 :       lexer.skip_token ();
    1688           99 :       has_extern = true;
    1689              : 
    1690              :       // detect optional abi name
    1691           99 :       const_TokenPtr next_tok = lexer.peek_token ();
    1692           99 :       if (next_tok->get_id () == STRING_LITERAL)
    1693              :         {
    1694           99 :           lexer.skip_token ();
    1695           99 :           abi = next_tok->get_str ();
    1696              :         }
    1697           99 :     }
    1698              : 
    1699        36466 :   return AST::FunctionQualifiers (locus, async_status, const_status,
    1700        18233 :                                   unsafe_status, has_extern, std::move (abi));
    1701        18233 : }
    1702              : 
    1703              : // Parses generic (lifetime or type) params inside angle brackets (optional).
    1704              : template <typename ManagedTokenSource>
    1705              : std::vector<std::unique_ptr<AST::GenericParam>>
    1706        31897 : Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
    1707              : {
    1708        63794 :   if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
    1709              :     {
    1710              :       // seems to be no generic params, so exit with empty vector
    1711        27671 :       return std::vector<std::unique_ptr<AST::GenericParam>> ();
    1712              :     }
    1713         4226 :   lexer.skip_token ();
    1714              : 
    1715              :   // DEBUG:
    1716         4226 :   rust_debug ("skipped left angle in generic param");
    1717              : 
    1718         4226 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    1719              :     = parse_generic_params (Parse::Utils::is_right_angle_tok);
    1720              : 
    1721              :   // DEBUG:
    1722         4226 :   rust_debug ("finished parsing actual generic params (i.e. inside angles)");
    1723              : 
    1724         4226 :   if (!skip_generics_right_angle ())
    1725              :     {
    1726              :       // DEBUG
    1727            1 :       rust_debug ("failed to skip generics right angle - returning empty "
    1728              :                   "generic params");
    1729              : 
    1730            1 :       return std::vector<std::unique_ptr<AST::GenericParam>> ();
    1731              :     }
    1732              : 
    1733         4225 :   return generic_params;
    1734         4226 : }
    1735              : 
    1736              : template <typename ManagedTokenSource>
    1737              : template <typename EndTokenPred>
    1738              : std::unique_ptr<AST::GenericParam>
    1739         4623 : Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
    1740              : {
    1741         4623 :   auto outer_attrs = parse_outer_attributes ();
    1742         4623 :   std::unique_ptr<AST::GenericParam> param;
    1743         4623 :   auto token = lexer.peek_token ();
    1744              : 
    1745         4623 :   switch (token->get_id ())
    1746              :     {
    1747          253 :     case LIFETIME:
    1748              :       {
    1749          253 :         auto lifetime = parse_lifetime (false);
    1750          253 :         if (!lifetime)
    1751              :           {
    1752            0 :             Error error (token->get_locus (),
    1753              :                          "failed to parse lifetime in generic parameter list");
    1754            0 :             add_error (std::move (error));
    1755              : 
    1756            0 :             return nullptr;
    1757            0 :           }
    1758              : 
    1759          253 :         std::vector<AST::Lifetime> lifetime_bounds;
    1760          506 :         if (lexer.peek_token ()->get_id () == COLON)
    1761              :           {
    1762            1 :             lexer.skip_token ();
    1763              :             // parse required bounds
    1764              :             lifetime_bounds
    1765            1 :               = parse_lifetime_bounds ([is_end_token] (TokenId id) {
    1766            1 :                   return is_end_token (id) || id == COMMA;
    1767              :                 });
    1768              :           }
    1769              : 
    1770          506 :         param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam (
    1771          253 :           std::move (lifetime.value ()), std::move (lifetime_bounds),
    1772          253 :           std::move (outer_attrs), token->get_locus ()));
    1773              :         break;
    1774          506 :       }
    1775         4265 :     case IDENTIFIER:
    1776              :       {
    1777         4265 :         auto type_ident = token->get_str ();
    1778         4265 :         lexer.skip_token ();
    1779              : 
    1780         4265 :         std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    1781         8530 :         if (lexer.peek_token ()->get_id () == COLON)
    1782              :           {
    1783          646 :             lexer.skip_token ();
    1784              : 
    1785              :             // parse optional type param bounds
    1786          646 :             type_param_bounds = parse_type_param_bounds ();
    1787              :           }
    1788              : 
    1789         4265 :         std::unique_ptr<AST::Type> type = nullptr;
    1790         8530 :         if (lexer.peek_token ()->get_id () == EQUAL)
    1791              :           {
    1792          362 :             lexer.skip_token ();
    1793              : 
    1794              :             // parse required type
    1795          362 :             type = parse_type ();
    1796          362 :             if (!type)
    1797              :               {
    1798            0 :                 Error error (
    1799            0 :                   lexer.peek_token ()->get_locus (),
    1800              :                   "failed to parse type in type param in generic params");
    1801            0 :                 add_error (std::move (error));
    1802              : 
    1803            0 :                 return nullptr;
    1804            0 :               }
    1805              :           }
    1806              : 
    1807         4265 :         param = std::unique_ptr<AST::TypeParam> (
    1808        12795 :           new AST::TypeParam (std::move (type_ident), token->get_locus (),
    1809              :                               std::move (type_param_bounds), std::move (type),
    1810         4265 :                               std::move (outer_attrs)));
    1811              :         break;
    1812         4265 :       }
    1813          104 :     case CONST:
    1814              :       {
    1815          104 :         lexer.skip_token ();
    1816              : 
    1817          104 :         auto name_token = expect_token (IDENTIFIER);
    1818              : 
    1819          208 :         if (!name_token || !expect_token (COLON))
    1820            1 :           return nullptr;
    1821              : 
    1822          103 :         auto type = parse_type ();
    1823          103 :         if (!type)
    1824            1 :           return nullptr;
    1825              : 
    1826              :         // optional default value
    1827          102 :         tl::optional<AST::GenericArg> default_expr = tl::nullopt;
    1828          204 :         if (lexer.peek_token ()->get_id () == EQUAL)
    1829              :           {
    1830           20 :             lexer.skip_token ();
    1831           20 :             auto tok = lexer.peek_token ();
    1832           39 :             default_expr = parse_generic_arg ();
    1833              : 
    1834           20 :             if (!default_expr)
    1835              :               {
    1836            1 :                 Error error (tok->get_locus (),
    1837              :                              "invalid token for start of default value for "
    1838              :                              "const generic parameter: expected %<block%>, "
    1839              :                              "%<identifier%> or %<literal%>, got %qs",
    1840              :                              token_id_to_str (tok->get_id ()));
    1841              : 
    1842            1 :                 add_error (std::move (error));
    1843            1 :                 return nullptr;
    1844            1 :               }
    1845              : 
    1846              :             // At this point, we *know* that we are parsing a const
    1847              :             // expression
    1848           19 :             if (default_expr.value ().get_kind ()
    1849              :                 == AST::GenericArg::Kind::Either)
    1850            1 :               default_expr = default_expr.value ().disambiguate_to_const ();
    1851           20 :           }
    1852              : 
    1853          101 :         param = std::unique_ptr<AST::ConstGenericParam> (
    1854          423 :           new AST::ConstGenericParam (name_token->get_str (), std::move (type),
    1855              :                                       default_expr, std::move (outer_attrs),
    1856          101 :                                       token->get_locus ()));
    1857              : 
    1858              :         break;
    1859          207 :       }
    1860            1 :     default:
    1861              :       // FIXME: Can we clean this last call with a method call?
    1862            1 :       Error error (token->get_locus (),
    1863              :                    "unexpected token when parsing generic parameters: %qs",
    1864            1 :                    token->as_string ().c_str ());
    1865            1 :       add_error (std::move (error));
    1866              : 
    1867            1 :       return nullptr;
    1868            1 :     }
    1869              : 
    1870         4619 :   return param;
    1871         4623 : }
    1872              : 
    1873              : /* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost
    1874              :  * always parse_generic_params_in_angles is what is wanted. */
    1875              : template <typename ManagedTokenSource>
    1876              : template <typename EndTokenPred>
    1877              : std::vector<std::unique_ptr<AST::GenericParam>>
    1878         4226 : Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
    1879              : {
    1880         4226 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
    1881              : 
    1882              :   /* can't parse lifetime and type params separately due to lookahead issues
    1883              :    * thus, parse them all here */
    1884              : 
    1885              :   /* HACK: used to retain attribute data if a lifetime param is tentatively
    1886              :    * parsed but it turns out to be type param */
    1887         4226 :   AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
    1888              : 
    1889              :   // Did we parse a generic type param yet
    1890         4226 :   auto type_seen = false;
    1891              :   // Did we parse a const param with a default value yet
    1892         4226 :   auto const_with_default_seen = false;
    1893              :   // Did the user write a lifetime parameter after a type one
    1894         4226 :   auto order_error = false;
    1895              :   // Did the user write a const param with a default value after a type one
    1896         4226 :   auto const_with_default_order_error = false;
    1897              : 
    1898              :   // parse lifetime params
    1899        22313 :   while (!is_end_token (lexer.peek_token ()->get_id ()))
    1900              :     {
    1901         4623 :       auto param = parse_generic_param (is_end_token);
    1902         4623 :       if (param)
    1903              :         {
    1904         4619 :           if (param->get_kind () == AST::GenericParam::Kind::Type)
    1905              :             {
    1906         4265 :               type_seen = true;
    1907         4265 :               if (const_with_default_seen)
    1908         4619 :                 const_with_default_order_error = true;
    1909              :             }
    1910          354 :           else if (param->get_kind () == AST::GenericParam::Kind::Lifetime
    1911          354 :                    && type_seen)
    1912              :             {
    1913            2 :               order_error = true;
    1914            2 :               if (const_with_default_seen)
    1915            0 :                 const_with_default_order_error = true;
    1916              :             }
    1917          352 :           else if (param->get_kind () == AST::GenericParam::Kind::Const)
    1918              :             {
    1919          101 :               type_seen = true;
    1920              :               AST::ConstGenericParam *const_param
    1921          101 :                 = static_cast<AST::ConstGenericParam *> (param.get ());
    1922          101 :               if (const_param->has_default_value ())
    1923              :                 const_with_default_seen = true;
    1924           82 :               else if (const_with_default_seen)
    1925         4619 :                 const_with_default_order_error = true;
    1926              :             }
    1927              : 
    1928         4619 :           generic_params.emplace_back (std::move (param));
    1929         4619 :           maybe_skip_token (COMMA);
    1930              :         }
    1931              :       else
    1932              :         break;
    1933              :     }
    1934              : 
    1935              :   // FIXME: Add reordering hint
    1936         4226 :   if (order_error)
    1937              :     {
    1938            2 :       Error error (generic_params.front ()->get_locus (),
    1939              :                    "invalid order for generic parameters: lifetime parameters "
    1940              :                    "must be declared prior to type and const parameters");
    1941            2 :       add_error (std::move (error));
    1942            2 :     }
    1943         4226 :   if (const_with_default_order_error)
    1944              :     {
    1945            1 :       Error error (generic_params.front ()->get_locus (),
    1946              :                    "invalid order for generic parameters: generic parameters "
    1947              :                    "with a default must be trailing");
    1948            1 :       add_error (std::move (error));
    1949            1 :     }
    1950              : 
    1951         4226 :   generic_params.shrink_to_fit ();
    1952         4226 :   return generic_params;
    1953         4226 : }
    1954              : 
    1955              : /* Parses lifetime generic parameters (pointers). Will also consume any
    1956              :  * trailing comma. No extra checks for end token. */
    1957              : template <typename ManagedTokenSource>
    1958              : std::vector<std::unique_ptr<AST::LifetimeParam>>
    1959            4 : Parser<ManagedTokenSource>::parse_lifetime_params ()
    1960              : {
    1961            4 :   std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
    1962              : 
    1963           12 :   while (lexer.peek_token ()->get_id () != END_OF_FILE)
    1964              :     {
    1965            4 :       auto lifetime_param = parse_lifetime_param ();
    1966              : 
    1967            4 :       if (!lifetime_param)
    1968              :         {
    1969              :           // can't treat as error as only way to get out with trailing comma
    1970              :           break;
    1971              :         }
    1972              : 
    1973            2 :       lifetime_params.emplace_back (
    1974            2 :         new AST::LifetimeParam (std::move (lifetime_param.value ())));
    1975              : 
    1976            4 :       if (lexer.peek_token ()->get_id () != COMMA)
    1977              :         break;
    1978              : 
    1979              :       // skip commas, including trailing commas
    1980            0 :       lexer.skip_token ();
    1981              :     }
    1982              : 
    1983            4 :   lifetime_params.shrink_to_fit ();
    1984              : 
    1985            4 :   return lifetime_params;
    1986              : }
    1987              : 
    1988              : /* Parses lifetime generic parameters (pointers). Will also consume any
    1989              :  * trailing comma. Has extra is_end_token predicate checking. */
    1990              : template <typename ManagedTokenSource>
    1991              : template <typename EndTokenPred>
    1992              : std::vector<std::unique_ptr<AST::LifetimeParam>>
    1993              : Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token)
    1994              : {
    1995              :   std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
    1996              : 
    1997              :   // if end_token is not specified, it defaults to EOF, so should work fine
    1998              :   while (!is_end_token (lexer.peek_token ()->get_id ()))
    1999              :     {
    2000              :       auto lifetime_param = parse_lifetime_param ();
    2001              : 
    2002              :       if (!lifetime_param)
    2003              :         {
    2004              :           /* TODO: is it worth throwing away all lifetime params just because
    2005              :            * one failed? */
    2006              :           Error error (lexer.peek_token ()->get_locus (),
    2007              :                        "failed to parse lifetime param in lifetime params");
    2008              :           add_error (std::move (error));
    2009              : 
    2010              :           return {};
    2011              :         }
    2012              : 
    2013              :       lifetime_params.emplace_back (
    2014              :         new AST::LifetimeParam (std::move (lifetime_param)));
    2015              : 
    2016              :       if (lexer.peek_token ()->get_id () != COMMA)
    2017              :         break;
    2018              : 
    2019              :       // skip commas, including trailing commas
    2020              :       lexer.skip_token ();
    2021              :     }
    2022              : 
    2023              :   lifetime_params.shrink_to_fit ();
    2024              : 
    2025              :   return lifetime_params;
    2026              : }
    2027              : 
    2028              : /* Parses lifetime generic parameters (objects). Will also consume any
    2029              :  * trailing comma. No extra checks for end token.
    2030              :  * TODO: is this best solution? implements most of the same algorithm.
    2031              :  * TODO: seems to be unused, remove? */
    2032              : template <typename ManagedTokenSource>
    2033              : std::vector<AST::LifetimeParam>
    2034            0 : Parser<ManagedTokenSource>::parse_lifetime_params_objs ()
    2035              : {
    2036            0 :   std::vector<AST::LifetimeParam> lifetime_params;
    2037              : 
    2038              :   // bad control structure as end token cannot be guaranteed
    2039            0 :   while (true)
    2040              :     {
    2041            0 :       auto lifetime_param = parse_lifetime_param ();
    2042              : 
    2043            0 :       if (!lifetime_param)
    2044              :         {
    2045              :           // not an error as only way to exit if trailing comma
    2046              :           break;
    2047              :         }
    2048              : 
    2049            0 :       lifetime_params.push_back (std::move (lifetime_param.value ()));
    2050              : 
    2051            0 :       if (lexer.peek_token ()->get_id () != COMMA)
    2052              :         break;
    2053              : 
    2054              :       // skip commas, including trailing commas
    2055            0 :       lexer.skip_token ();
    2056              :     }
    2057              : 
    2058            0 :   lifetime_params.shrink_to_fit ();
    2059              : 
    2060            0 :   return lifetime_params;
    2061              : }
    2062              : 
    2063              : /* Parses lifetime generic parameters (objects). Will also consume any
    2064              :  * trailing comma. Has extra is_end_token predicate checking.
    2065              :  * TODO: is this best solution? implements most of the same algorithm. */
    2066              : template <typename ManagedTokenSource>
    2067              : template <typename EndTokenPred>
    2068              : std::vector<AST::LifetimeParam>
    2069           26 : Parser<ManagedTokenSource>::parse_lifetime_params_objs (
    2070              :   EndTokenPred is_end_token)
    2071              : {
    2072           26 :   std::vector<AST::LifetimeParam> lifetime_params;
    2073              : 
    2074           78 :   while (!is_end_token (lexer.peek_token ()->get_id ()))
    2075              :     {
    2076           26 :       auto lifetime_param = parse_lifetime_param ();
    2077              : 
    2078           26 :       if (!lifetime_param)
    2079              :         {
    2080              :           /* TODO: is it worth throwing away all lifetime params just because
    2081              :            * one failed? */
    2082            0 :           Error error (lexer.peek_token ()->get_locus (),
    2083              :                        "failed to parse lifetime param in lifetime params");
    2084            0 :           add_error (std::move (error));
    2085              : 
    2086            0 :           return {};
    2087            0 :         }
    2088              : 
    2089           26 :       lifetime_params.push_back (std::move (lifetime_param.value ()));
    2090              : 
    2091           52 :       if (lexer.peek_token ()->get_id () != COMMA)
    2092              :         break;
    2093              : 
    2094              :       // skip commas, including trailing commas
    2095            0 :       lexer.skip_token ();
    2096              :     }
    2097              : 
    2098           26 :   lifetime_params.shrink_to_fit ();
    2099              : 
    2100           26 :   return lifetime_params;
    2101           26 : }
    2102              : 
    2103              : /* Parses a sequence of a certain grammar rule in object form (not pointer or
    2104              :  * smart pointer), delimited by commas and ending when 'is_end_token' is
    2105              :  * satisfied (templated). Will also consume any trailing comma.
    2106              :  * FIXME: this cannot be used due to member function pointer problems (i.e.
    2107              :  * parsing_function cannot be specified properly) */
    2108              : template <typename ManagedTokenSource>
    2109              : template <typename ParseFunction, typename EndTokenPred>
    2110              : auto
    2111              : Parser<ManagedTokenSource>::parse_non_ptr_sequence (
    2112              :   ParseFunction parsing_function, EndTokenPred is_end_token,
    2113              :   std::string error_msg) -> std::vector<decltype (parsing_function ())>
    2114              : {
    2115              :   std::vector<decltype (parsing_function ())> params;
    2116              : 
    2117              :   while (!is_end_token (lexer.peek_token ()->get_id ()))
    2118              :     {
    2119              :       auto param = parsing_function ();
    2120              : 
    2121              :       if (param.is_error ())
    2122              :         {
    2123              :           // TODO: is it worth throwing away all params just because one
    2124              :           // failed?
    2125              :           Error error (lexer.peek_token ()->get_locus (),
    2126              :                        std::move (error_msg));
    2127              :           add_error (std::move (error));
    2128              : 
    2129              :           return {};
    2130              :         }
    2131              : 
    2132              :       params.push_back (std::move (param));
    2133              : 
    2134              :       if (lexer.peek_token ()->get_id () != COMMA)
    2135              :         break;
    2136              : 
    2137              :       // skip commas, including trailing commas
    2138              :       lexer.skip_token ();
    2139              :     }
    2140              : 
    2141              :   params.shrink_to_fit ();
    2142              : 
    2143              :   return params;
    2144              : }
    2145              : 
    2146              : /* Parses a single lifetime generic parameter (not including comma). */
    2147              : template <typename ManagedTokenSource>
    2148              : tl::expected<AST::LifetimeParam, Parse::Error::LifetimeParam>
    2149           30 : Parser<ManagedTokenSource>::parse_lifetime_param ()
    2150              : {
    2151              :   // parse outer attributes, which are optional and may not exist
    2152           30 :   auto outer_attrs = parse_outer_attributes ();
    2153              : 
    2154              :   // save lifetime token - required
    2155           30 :   const_TokenPtr lifetime_tok = lexer.peek_token ();
    2156           30 :   if (lifetime_tok->get_id () != LIFETIME)
    2157              :     {
    2158              :       // if lifetime is missing, must not be a lifetime param, so return error
    2159              :       return Parse::Error::LifetimeParam::make_not_a_lifetime_param ();
    2160              :     }
    2161           28 :   lexer.skip_token ();
    2162           56 :   AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (),
    2163              :                           lifetime_tok->get_locus ());
    2164              : 
    2165              :   // parse lifetime bounds, if it exists
    2166           28 :   std::vector<AST::Lifetime> lifetime_bounds;
    2167           56 :   if (lexer.peek_token ()->get_id () == COLON)
    2168              :     {
    2169              :       // parse lifetime bounds
    2170            0 :       lifetime_bounds = parse_lifetime_bounds ();
    2171              :       // TODO: have end token passed in?
    2172              :     }
    2173              : 
    2174           56 :   return AST::LifetimeParam (std::move (lifetime), std::move (lifetime_bounds),
    2175              :                              std::move (outer_attrs),
    2176           28 :                              lifetime_tok->get_locus ());
    2177           58 : }
    2178              : 
    2179              : // Parses type generic parameters. Will also consume any trailing comma.
    2180              : template <typename ManagedTokenSource>
    2181              : std::vector<std::unique_ptr<AST::TypeParam>>
    2182            0 : Parser<ManagedTokenSource>::parse_type_params ()
    2183              : {
    2184            0 :   std::vector<std::unique_ptr<AST::TypeParam>> type_params;
    2185              : 
    2186              :   // infinite loop with break on failure as no info on ending token
    2187            0 :   while (true)
    2188              :     {
    2189            0 :       std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
    2190              : 
    2191            0 :       if (type_param == nullptr)
    2192              :         {
    2193              :           // break if fails to parse
    2194              :           break;
    2195              :         }
    2196              : 
    2197            0 :       type_params.push_back (std::move (type_param));
    2198              : 
    2199            0 :       if (lexer.peek_token ()->get_id () != COMMA)
    2200              :         break;
    2201              : 
    2202              :       // skip commas, including trailing commas
    2203            0 :       lexer.skip_token ();
    2204              :     }
    2205              : 
    2206            0 :   type_params.shrink_to_fit ();
    2207            0 :   return type_params;
    2208              : }
    2209              : 
    2210              : // Parses type generic parameters. Will also consume any trailing comma.
    2211              : template <typename ManagedTokenSource>
    2212              : template <typename EndTokenPred>
    2213              : std::vector<std::unique_ptr<AST::TypeParam>>
    2214              : Parser<ManagedTokenSource>::parse_type_params (EndTokenPred is_end_token)
    2215              : {
    2216              :   std::vector<std::unique_ptr<AST::TypeParam>> type_params;
    2217              : 
    2218              :   while (!is_end_token (lexer.peek_token ()->get_id ()))
    2219              :     {
    2220              :       std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
    2221              : 
    2222              :       if (type_param == nullptr)
    2223              :         {
    2224              :           Error error (lexer.peek_token ()->get_locus (),
    2225              :                        "failed to parse type param in type params");
    2226              :           add_error (std::move (error));
    2227              : 
    2228              :           return {};
    2229              :         }
    2230              : 
    2231              :       type_params.push_back (std::move (type_param));
    2232              : 
    2233              :       if (lexer.peek_token ()->get_id () != COMMA)
    2234              :         break;
    2235              : 
    2236              :       // skip commas, including trailing commas
    2237              :       lexer.skip_token ();
    2238              :     }
    2239              : 
    2240              :   type_params.shrink_to_fit ();
    2241              :   return type_params;
    2242              :   /* TODO: this shares most code with parse_lifetime_params - good place to
    2243              :    * use template (i.e. parse_non_ptr_sequence if doable) */
    2244              : }
    2245              : 
    2246              : /* Parses a single type (generic) parameter, not including commas. May change
    2247              :  * to return value. */
    2248              : template <typename ManagedTokenSource>
    2249              : std::unique_ptr<AST::TypeParam>
    2250            0 : Parser<ManagedTokenSource>::parse_type_param ()
    2251              : {
    2252              :   // parse outer attributes, which are optional and may not exist
    2253            0 :   auto outer_attrs = parse_outer_attributes ();
    2254              : 
    2255            0 :   const_TokenPtr identifier_tok = lexer.peek_token ();
    2256            0 :   if (identifier_tok->get_id () != IDENTIFIER)
    2257              :     {
    2258              :       // return null as type param can't exist without this required
    2259              :       // identifier
    2260            0 :       return nullptr;
    2261              :     }
    2262            0 :   Identifier ident{identifier_tok};
    2263            0 :   lexer.skip_token ();
    2264              : 
    2265              :   // parse type param bounds (if they exist)
    2266            0 :   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    2267            0 :   if (lexer.peek_token ()->get_id () == COLON)
    2268              :     {
    2269            0 :       lexer.skip_token ();
    2270              : 
    2271              :       // parse type param bounds, which may or may not exist
    2272            0 :       type_param_bounds = parse_type_param_bounds ();
    2273              :     }
    2274              : 
    2275              :   // parse type (if it exists)
    2276            0 :   std::unique_ptr<AST::Type> type = nullptr;
    2277            0 :   if (lexer.peek_token ()->get_id () == EQUAL)
    2278              :     {
    2279            0 :       lexer.skip_token ();
    2280              : 
    2281              :       // parse type (now required)
    2282            0 :       type = parse_type ();
    2283            0 :       if (type == nullptr)
    2284              :         {
    2285            0 :           Error error (lexer.peek_token ()->get_locus (),
    2286              :                        "failed to parse type in type param");
    2287            0 :           add_error (std::move (error));
    2288              : 
    2289            0 :           return nullptr;
    2290            0 :         }
    2291              :     }
    2292              : 
    2293              :   return std::unique_ptr<AST::TypeParam> (
    2294            0 :     new AST::TypeParam (std::move (ident), identifier_tok->get_locus (),
    2295              :                         std::move (type_param_bounds), std::move (type),
    2296            0 :                         std::move (outer_attrs)));
    2297            0 : }
    2298              : 
    2299              : /* Parses regular (i.e. non-generic) parameters in functions or methods. Also
    2300              :  * has end token handling. */
    2301              : template <typename ManagedTokenSource>
    2302              : template <typename EndTokenPred>
    2303              : std::vector<std::unique_ptr<AST::Param>>
    2304        10035 : Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
    2305              : {
    2306        10035 :   std::vector<std::unique_ptr<AST::Param>> params;
    2307              : 
    2308        20070 :   if (is_end_token (lexer.peek_token ()->get_id ()))
    2309          827 :     return params;
    2310              : 
    2311         9208 :   auto initial_param = parse_function_param ();
    2312              : 
    2313              :   // Return empty parameter list if no parameter there
    2314         9208 :   if (initial_param == nullptr)
    2315              :     {
    2316              :       // TODO: is this an error?
    2317            0 :       return params;
    2318              :     }
    2319              : 
    2320         9208 :   params.push_back (std::move (initial_param));
    2321              : 
    2322              :   // maybe think of a better control structure here - do-while with an initial
    2323              :   // error state? basically, loop through parameter list until can't find any
    2324              :   // more params
    2325         9208 :   const_TokenPtr t = lexer.peek_token ();
    2326        11463 :   while (t->get_id () == COMMA)
    2327              :     {
    2328              :       // skip comma if applies
    2329         2255 :       lexer.skip_token ();
    2330              : 
    2331              :       // TODO: strictly speaking, shouldn't there be no trailing comma?
    2332         4510 :       if (is_end_token (lexer.peek_token ()->get_id ()))
    2333              :         break;
    2334              : 
    2335              :       // now, as right paren would break, function param is required
    2336         2255 :       auto param = parse_function_param ();
    2337         2255 :       if (param == nullptr)
    2338              :         {
    2339            0 :           Error error (lexer.peek_token ()->get_locus (),
    2340              :                        "failed to parse function param (in function params)");
    2341            0 :           add_error (std::move (error));
    2342              : 
    2343              :           // skip somewhere?
    2344            0 :           return std::vector<std::unique_ptr<AST::Param>> ();
    2345            0 :         }
    2346              : 
    2347         2255 :       params.push_back (std::move (param));
    2348              : 
    2349         2255 :       t = lexer.peek_token ();
    2350              :     }
    2351              : 
    2352         9208 :   params.shrink_to_fit ();
    2353         9208 :   return params;
    2354        10035 : }
    2355              : 
    2356              : /* Parses a single regular (i.e. non-generic) parameter in a function or
    2357              :  * method, i.e. the "name: type" bit. Also handles it not existing. */
    2358              : template <typename ManagedTokenSource>
    2359              : std::unique_ptr<AST::Param>
    2360        11463 : Parser<ManagedTokenSource>::parse_function_param ()
    2361              : {
    2362              :   // parse outer attributes if they exist
    2363        11463 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    2364              : 
    2365              :   // TODO: should saved location be at start of outer attributes or pattern?
    2366        11463 :   location_t locus = lexer.peek_token ()->get_locus ();
    2367              : 
    2368        22926 :   if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic
    2369              :     {
    2370          827 :       lexer.skip_token (); // Skip ellipsis
    2371          827 :       return std::make_unique<AST::VariadicParam> (
    2372         1654 :         AST::VariadicParam (std::move (outer_attrs), locus));
    2373              :     }
    2374              : 
    2375        10636 :   std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
    2376              : 
    2377              :   // create error function param if it doesn't exist
    2378        10636 :   if (param_pattern == nullptr)
    2379              :     {
    2380              :       // skip after something
    2381            0 :       return nullptr;
    2382              :     }
    2383              : 
    2384        10636 :   if (!skip_token (COLON))
    2385              :     {
    2386              :       // skip after something
    2387            0 :       return nullptr;
    2388              :     }
    2389              : 
    2390        21272 :   if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic
    2391              :     {
    2392           11 :       lexer.skip_token (); // Skip ellipsis
    2393           11 :       return std::make_unique<AST::VariadicParam> (
    2394           22 :         AST::VariadicParam (std::move (param_pattern), std::move (outer_attrs),
    2395           11 :                             locus));
    2396              :     }
    2397              :   else
    2398              :     {
    2399        10625 :       std::unique_ptr<AST::Type> param_type = parse_type ();
    2400        10625 :       if (param_type == nullptr)
    2401              :         {
    2402            0 :           return nullptr;
    2403              :         }
    2404        10625 :       return std::make_unique<AST::FunctionParam> (
    2405        21250 :         AST::FunctionParam (std::move (param_pattern), std::move (param_type),
    2406        10625 :                             std::move (outer_attrs), locus));
    2407        10625 :     }
    2408        11463 : }
    2409              : 
    2410              : /* Parses a function or method return type syntactical construction. Also
    2411              :  * handles a function return type not existing. */
    2412              : template <typename ManagedTokenSource>
    2413              : std::unique_ptr<AST::Type>
    2414        18187 : Parser<ManagedTokenSource>::parse_function_return_type ()
    2415              : {
    2416        36374 :   if (lexer.peek_token ()->get_id () != RETURN_TYPE)
    2417         5557 :     return nullptr;
    2418              : 
    2419              :   // skip return type, as it now obviously exists
    2420        12630 :   lexer.skip_token ();
    2421              : 
    2422        12630 :   std::unique_ptr<AST::Type> type = parse_type ();
    2423              : 
    2424        12630 :   return type;
    2425        12630 : }
    2426              : 
    2427              : /* Parses a "where clause" (in a function, struct, method, etc.). Also handles
    2428              :  * a where clause not existing, in which it will return
    2429              :  * WhereClause::create_empty(), which can be checked via
    2430              :  * WhereClause::is_empty(). */
    2431              : template <typename ManagedTokenSource>
    2432              : AST::WhereClause
    2433        31883 : Parser<ManagedTokenSource>::parse_where_clause ()
    2434              : {
    2435        31883 :   const_TokenPtr where_tok = lexer.peek_token ();
    2436        31883 :   if (where_tok->get_id () != WHERE)
    2437              :     {
    2438              :       // where clause doesn't exist, so create empty one
    2439        31594 :       return AST::WhereClause::create_empty ();
    2440              :     }
    2441              : 
    2442          289 :   lexer.skip_token ();
    2443              : 
    2444              :   /* parse where clause items - this is not a separate rule in the reference
    2445              :    * so won't be here */
    2446          289 :   std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items;
    2447              : 
    2448          289 :   std::vector<AST::LifetimeParam> for_lifetimes;
    2449          578 :   if (lexer.peek_token ()->get_id () == FOR)
    2450            1 :     for_lifetimes = parse_for_lifetimes ();
    2451              : 
    2452              :   /* HACK: where clauses end with a right curly or semicolon or equals in all
    2453              :    * uses currently */
    2454          289 :   const_TokenPtr t = lexer.peek_token ();
    2455          588 :   while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON
    2456          580 :          && t->get_id () != EQUAL)
    2457              :     {
    2458          299 :       std::unique_ptr<AST::WhereClauseItem> where_clause_item
    2459              :         = parse_where_clause_item (for_lifetimes);
    2460              : 
    2461          299 :       if (where_clause_item == nullptr)
    2462              :         {
    2463            0 :           Error error (t->get_locus (), "failed to parse where clause item");
    2464            0 :           add_error (std::move (error));
    2465              : 
    2466            0 :           return AST::WhereClause::create_empty ();
    2467            0 :         }
    2468              : 
    2469          299 :       where_clause_items.push_back (std::move (where_clause_item));
    2470              : 
    2471              :       // also skip comma if it exists
    2472          598 :       if (lexer.peek_token ()->get_id () != COMMA)
    2473              :         break;
    2474              : 
    2475          291 :       lexer.skip_token ();
    2476          291 :       t = lexer.peek_token ();
    2477              :     }
    2478              : 
    2479          289 :   where_clause_items.shrink_to_fit ();
    2480          289 :   return AST::WhereClause (std::move (where_clause_items));
    2481          289 : }
    2482              : 
    2483              : /* Parses a where clause item (lifetime or type bound). Does not parse any
    2484              :  * commas. */
    2485              : template <typename ManagedTokenSource>
    2486              : std::unique_ptr<AST::WhereClauseItem>
    2487          299 : Parser<ManagedTokenSource>::parse_where_clause_item (
    2488              :   const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
    2489              : {
    2490              :   // shitty cheat way of determining lifetime or type bound - test for
    2491              :   // lifetime
    2492          299 :   const_TokenPtr t = lexer.peek_token ();
    2493              : 
    2494          299 :   if (t->get_id () == LIFETIME)
    2495            2 :     return parse_lifetime_where_clause_item ();
    2496              :   else
    2497          297 :     return parse_type_bound_where_clause_item (outer_for_lifetimes);
    2498          299 : }
    2499              : 
    2500              : // Parses a lifetime where clause item.
    2501              : template <typename ManagedTokenSource>
    2502              : std::unique_ptr<AST::LifetimeWhereClauseItem>
    2503            2 : Parser<ManagedTokenSource>::parse_lifetime_where_clause_item ()
    2504              : {
    2505            2 :   auto parsed_lifetime = parse_lifetime (false);
    2506            2 :   if (!parsed_lifetime)
    2507              :     {
    2508              :       // TODO: error here?
    2509            0 :       return nullptr;
    2510              :     }
    2511            2 :   auto lifetime = parsed_lifetime.value ();
    2512              : 
    2513            2 :   if (!skip_token (COLON))
    2514              :     {
    2515              :       // TODO: skip after somewhere
    2516            0 :       return nullptr;
    2517              :     }
    2518              : 
    2519            2 :   std::vector<AST::Lifetime> lifetime_bounds = parse_lifetime_bounds ();
    2520              :   // TODO: have end token passed in?
    2521              : 
    2522            2 :   location_t locus = lifetime.get_locus ();
    2523              : 
    2524              :   return std::unique_ptr<AST::LifetimeWhereClauseItem> (
    2525            2 :     new AST::LifetimeWhereClauseItem (std::move (lifetime),
    2526            2 :                                       std::move (lifetime_bounds), locus));
    2527            4 : }
    2528              : 
    2529              : // Parses a type bound where clause item.
    2530              : template <typename ManagedTokenSource>
    2531              : std::unique_ptr<AST::TypeBoundWhereClauseItem>
    2532          297 : Parser<ManagedTokenSource>::parse_type_bound_where_clause_item (
    2533              :   const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
    2534              : {
    2535          297 :   std::vector<AST::LifetimeParam> for_lifetimes = outer_for_lifetimes;
    2536              : 
    2537          297 :   std::unique_ptr<AST::Type> type = parse_type ();
    2538          297 :   if (type == nullptr)
    2539              :     {
    2540            0 :       return nullptr;
    2541              :     }
    2542              : 
    2543          297 :   if (!skip_token (COLON))
    2544              :     {
    2545              :       // TODO: skip after somewhere
    2546            0 :       return nullptr;
    2547              :     }
    2548              : 
    2549          594 :   if (lexer.peek_token ()->get_id () == FOR)
    2550              :     {
    2551            8 :       auto for_lifetimes_inner = parse_for_lifetimes ();
    2552            8 :       for_lifetimes.insert (for_lifetimes.end (), for_lifetimes_inner.begin (),
    2553              :                             for_lifetimes_inner.end ());
    2554            8 :     }
    2555              : 
    2556              :   // parse type param bounds if they exist
    2557          297 :   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds
    2558              :     = parse_type_param_bounds ();
    2559              : 
    2560          297 :   location_t locus = lexer.peek_token ()->get_locus ();
    2561              : 
    2562              :   return std::unique_ptr<AST::TypeBoundWhereClauseItem> (
    2563          297 :     new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes),
    2564              :                                        std::move (type),
    2565          297 :                                        std::move (type_param_bounds), locus));
    2566          297 : }
    2567              : 
    2568              : // Parses a for lifetimes clause, including the for keyword and angle
    2569              : // brackets.
    2570              : template <typename ManagedTokenSource>
    2571              : std::vector<AST::LifetimeParam>
    2572           26 : Parser<ManagedTokenSource>::parse_for_lifetimes ()
    2573              : {
    2574           26 :   std::vector<AST::LifetimeParam> params;
    2575              : 
    2576           26 :   if (!skip_token (FOR))
    2577              :     {
    2578              :       // skip after somewhere?
    2579              :       return params;
    2580              :     }
    2581              : 
    2582           26 :   if (!skip_token (LEFT_ANGLE))
    2583              :     {
    2584              :       // skip after somewhere?
    2585              :       return params;
    2586              :     }
    2587              : 
    2588              :   /* cannot specify end token due to parsing problems with '>' tokens being
    2589              :    * nested */
    2590           26 :   params = parse_lifetime_params_objs (Parse::Utils::is_right_angle_tok);
    2591              : 
    2592           26 :   if (!skip_generics_right_angle ())
    2593              :     {
    2594              :       // DEBUG
    2595            0 :       rust_debug ("failed to skip generics right angle after (supposedly) "
    2596              :                   "finished parsing where clause items");
    2597              :       // ok, well this gets called.
    2598              : 
    2599              :       // skip after somewhere?
    2600            0 :       return params;
    2601              :     }
    2602              : 
    2603              :   return params;
    2604              : }
    2605              : 
    2606              : // Parses type parameter bounds in where clause or generic arguments.
    2607              : template <typename ManagedTokenSource>
    2608              : std::vector<std::unique_ptr<AST::TypeParamBound>>
    2609          944 : Parser<ManagedTokenSource>::parse_type_param_bounds ()
    2610              : {
    2611          944 :   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    2612              : 
    2613          944 :   std::unique_ptr<AST::TypeParamBound> initial_bound
    2614              :     = parse_type_param_bound ();
    2615              : 
    2616              :   // quick exit if null
    2617          944 :   if (initial_bound == nullptr)
    2618              :     {
    2619              :       /* error? type param bounds must have at least one term, but are bounds
    2620              :        * optional? */
    2621              :       return type_param_bounds;
    2622              :     }
    2623          944 :   type_param_bounds.push_back (std::move (initial_bound));
    2624              : 
    2625         1894 :   while (lexer.peek_token ()->get_id () == PLUS)
    2626              :     {
    2627            3 :       lexer.skip_token ();
    2628              : 
    2629            3 :       std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
    2630            3 :       if (bound == nullptr)
    2631              :         {
    2632              :           /* not an error: bound is allowed to be null as trailing plus is
    2633              :            * allowed */
    2634              :           return type_param_bounds;
    2635              :         }
    2636              : 
    2637            3 :       type_param_bounds.push_back (std::move (bound));
    2638              :     }
    2639              : 
    2640          944 :   type_param_bounds.shrink_to_fit ();
    2641              :   return type_param_bounds;
    2642          944 : }
    2643              : 
    2644              : /* Parses type parameter bounds in where clause or generic arguments, with end
    2645              :  * token handling. */
    2646              : template <typename ManagedTokenSource>
    2647              : template <typename EndTokenPred>
    2648              : std::vector<std::unique_ptr<AST::TypeParamBound>>
    2649          582 : Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token)
    2650              : {
    2651          582 :   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    2652              : 
    2653          582 :   std::unique_ptr<AST::TypeParamBound> initial_bound
    2654              :     = parse_type_param_bound ();
    2655              : 
    2656              :   // quick exit if null
    2657          582 :   if (initial_bound == nullptr)
    2658              :     {
    2659              :       /* error? type param bounds must have at least one term, but are bounds
    2660              :        * optional? */
    2661            0 :       return type_param_bounds;
    2662              :     }
    2663          582 :   type_param_bounds.push_back (std::move (initial_bound));
    2664              : 
    2665         1308 :   while (lexer.peek_token ()->get_id () == PLUS)
    2666              :     {
    2667           72 :       lexer.skip_token ();
    2668              : 
    2669              :       // break if end token character
    2670          144 :       if (is_end_token (lexer.peek_token ()->get_id ()))
    2671              :         break;
    2672              : 
    2673           72 :       std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
    2674           72 :       if (bound == nullptr)
    2675              :         {
    2676              :           // TODO how wise is it to ditch all bounds if only one failed?
    2677            0 :           Error error (lexer.peek_token ()->get_locus (),
    2678              :                        "failed to parse type param bound in type param bounds");
    2679            0 :           add_error (std::move (error));
    2680              : 
    2681            0 :           return {};
    2682            0 :         }
    2683              : 
    2684           72 :       type_param_bounds.push_back (std::move (bound));
    2685              :     }
    2686              : 
    2687          582 :   type_param_bounds.shrink_to_fit ();
    2688          582 :   return type_param_bounds;
    2689          582 : }
    2690              : 
    2691              : /* Parses a single type parameter bound in a where clause or generic argument.
    2692              :  * Does not parse the '+' between arguments. */
    2693              : template <typename ManagedTokenSource>
    2694              : std::unique_ptr<AST::TypeParamBound>
    2695         1621 : Parser<ManagedTokenSource>::parse_type_param_bound ()
    2696              : {
    2697              :   // shitty cheat way of determining lifetime or trait bound - test for
    2698              :   // lifetime
    2699         1621 :   const_TokenPtr t = lexer.peek_token ();
    2700         1621 :   switch (t->get_id ())
    2701              :     {
    2702           12 :     case LIFETIME:
    2703           12 :       return std::unique_ptr<AST::Lifetime> (
    2704           24 :         new AST::Lifetime (parse_lifetime (false).value ()));
    2705         1609 :     case LEFT_PAREN:
    2706              :     case QUESTION_MARK:
    2707              :     case FOR:
    2708              :     case IDENTIFIER:
    2709              :     case SUPER:
    2710              :     case SELF:
    2711              :     case SELF_ALIAS:
    2712              :     case CRATE:
    2713              :     case DOLLAR_SIGN:
    2714              :     case SCOPE_RESOLUTION:
    2715         1609 :       return parse_trait_bound ();
    2716            0 :     default:
    2717              :       // don't error - assume this is fine TODO
    2718            0 :       return nullptr;
    2719              :     }
    2720         1621 : }
    2721              : 
    2722              : // Parses a trait bound type param bound.
    2723              : template <typename ManagedTokenSource>
    2724              : std::unique_ptr<AST::TraitBound>
    2725         1915 : Parser<ManagedTokenSource>::parse_trait_bound ()
    2726              : {
    2727         1915 :   bool has_parens = false;
    2728         1915 :   bool has_question_mark = false;
    2729              : 
    2730         3830 :   location_t locus = lexer.peek_token ()->get_locus ();
    2731              : 
    2732              :   /* parse optional `for lifetimes`. */
    2733         1915 :   std::vector<AST::LifetimeParam> for_lifetimes;
    2734         3830 :   if (lexer.peek_token ()->get_id () == FOR)
    2735           14 :     for_lifetimes = parse_for_lifetimes ();
    2736              : 
    2737              :   // handle trait bound being in parentheses
    2738         3830 :   if (lexer.peek_token ()->get_id () == LEFT_PAREN)
    2739              :     {
    2740            0 :       has_parens = true;
    2741            0 :       lexer.skip_token ();
    2742              :     }
    2743              : 
    2744              :   // handle having question mark (optional)
    2745         3830 :   if (lexer.peek_token ()->get_id () == QUESTION_MARK)
    2746              :     {
    2747          309 :       has_question_mark = true;
    2748          309 :       lexer.skip_token ();
    2749              :     }
    2750              : 
    2751              :   // handle TypePath
    2752         1915 :   AST::TypePath type_path = parse_type_path ();
    2753         1915 :   if (type_path.is_error ())
    2754            2 :     return nullptr;
    2755              : 
    2756              :   // handle closing parentheses
    2757         1913 :   if (has_parens)
    2758              :     {
    2759            0 :       if (!skip_token (RIGHT_PAREN))
    2760              :         {
    2761            0 :           return nullptr;
    2762              :         }
    2763              :     }
    2764              : 
    2765              :   return std::unique_ptr<AST::TraitBound> (
    2766         1913 :     new AST::TraitBound (std::move (type_path), locus, has_parens,
    2767         1913 :                          has_question_mark, std::move (for_lifetimes)));
    2768         1915 : }
    2769              : 
    2770              : // Parses lifetime bounds.
    2771              : template <typename ManagedTokenSource>
    2772              : std::vector<AST::Lifetime>
    2773            2 : Parser<ManagedTokenSource>::parse_lifetime_bounds ()
    2774              : {
    2775            2 :   std::vector<AST::Lifetime> lifetime_bounds;
    2776              : 
    2777            2 :   while (true)
    2778              :     {
    2779            2 :       auto lifetime = parse_lifetime (false);
    2780              : 
    2781              :       // quick exit for parsing failure
    2782            2 :       if (!lifetime)
    2783              :         break;
    2784              : 
    2785            2 :       lifetime_bounds.push_back (std::move (lifetime.value ()));
    2786              : 
    2787              :       /* plus is maybe not allowed at end - spec defines it weirdly, so
    2788              :        * assuming allowed at end */
    2789            4 :       if (lexer.peek_token ()->get_id () != PLUS)
    2790              :         break;
    2791              : 
    2792            0 :       lexer.skip_token ();
    2793              :     }
    2794              : 
    2795            2 :   lifetime_bounds.shrink_to_fit ();
    2796            2 :   return lifetime_bounds;
    2797              : }
    2798              : 
    2799              : // Parses lifetime bounds, with added check for ending token.
    2800              : template <typename ManagedTokenSource>
    2801              : template <typename EndTokenPred>
    2802              : std::vector<AST::Lifetime>
    2803            1 : Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token)
    2804              : {
    2805            1 :   std::vector<AST::Lifetime> lifetime_bounds;
    2806              : 
    2807            4 :   while (!is_end_token (lexer.peek_token ()->get_id ()))
    2808              :     {
    2809            1 :       auto lifetime = parse_lifetime (false);
    2810              : 
    2811            1 :       if (!lifetime)
    2812              :         {
    2813              :           /* TODO: is it worth throwing away all lifetime bound info just
    2814              :            * because one failed? */
    2815            0 :           Error error (lexer.peek_token ()->get_locus (),
    2816              :                        "failed to parse lifetime in lifetime bounds");
    2817            0 :           add_error (std::move (error));
    2818              : 
    2819            0 :           return {};
    2820            0 :         }
    2821              : 
    2822            1 :       lifetime_bounds.push_back (std::move (lifetime.value ()));
    2823              : 
    2824              :       /* plus is maybe not allowed at end - spec defines it weirdly, so
    2825              :        * assuming allowed at end */
    2826            2 :       if (lexer.peek_token ()->get_id () != PLUS)
    2827              :         break;
    2828              : 
    2829            0 :       lexer.skip_token ();
    2830              :     }
    2831              : 
    2832            1 :   lifetime_bounds.shrink_to_fit ();
    2833            1 :   return lifetime_bounds;
    2834            1 : }
    2835              : 
    2836              : /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not
    2837              :  * existing. */
    2838              : template <typename ManagedTokenSource>
    2839              : tl::expected<AST::Lifetime, Parse::Error::Lifetime>
    2840         4485 : Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided)
    2841              : {
    2842         4485 :   const_TokenPtr lifetime_tok = lexer.peek_token ();
    2843         4485 :   if (lifetime_tok->get_id () != LIFETIME)
    2844              :     {
    2845         3678 :       if (allow_elided)
    2846              :         {
    2847            0 :           return AST::Lifetime::elided ();
    2848              :         }
    2849              :       else
    2850              :         {
    2851         3678 :           return tl::make_unexpected<Parse::Error::Lifetime> ({});
    2852              :         }
    2853              :     }
    2854          807 :   lexer.skip_token ();
    2855              : 
    2856         1614 :   return lifetime_from_token (lifetime_tok);
    2857         4485 : }
    2858              : 
    2859              : template <typename ManagedTokenSource>
    2860              : AST::Lifetime
    2861          847 : Parser<ManagedTokenSource>::lifetime_from_token (const_TokenPtr tok)
    2862              : {
    2863          847 :   location_t locus = tok->get_locus ();
    2864          847 :   std::string lifetime_ident = tok->get_str ();
    2865              : 
    2866          847 :   if (lifetime_ident == "static")
    2867              :     {
    2868           85 :       return AST::Lifetime (AST::Lifetime::STATIC, "", locus);
    2869              :     }
    2870          762 :   else if (lifetime_ident == "_")
    2871              :     {
    2872              :       // Explicitly and implicitly elided lifetimes follow the same rules.
    2873           43 :       return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus);
    2874              :     }
    2875              :   else
    2876              :     {
    2877         1438 :       return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident),
    2878          719 :                             locus);
    2879              :     }
    2880          847 : }
    2881              : 
    2882              : template <typename ManagedTokenSource>
    2883              : std::unique_ptr<AST::ExternalTypeItem>
    2884            4 : Parser<ManagedTokenSource>::parse_external_type_item (AST::Visibility vis,
    2885              :                                                       AST::AttrVec outer_attrs)
    2886              : {
    2887            4 :   location_t locus = lexer.peek_token ()->get_locus ();
    2888            4 :   skip_token (TYPE);
    2889              : 
    2890            4 :   const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
    2891            4 :   if (alias_name_tok == nullptr)
    2892              :     {
    2893            0 :       Error error (lexer.peek_token ()->get_locus (),
    2894              :                    "could not parse identifier in external opaque type");
    2895            0 :       add_error (std::move (error));
    2896              : 
    2897            0 :       skip_after_semicolon ();
    2898            0 :       return nullptr;
    2899            0 :     }
    2900              : 
    2901            4 :   if (!skip_token (SEMICOLON))
    2902            1 :     return nullptr;
    2903              : 
    2904              :   return std::unique_ptr<AST::ExternalTypeItem> (
    2905            9 :     new AST::ExternalTypeItem (alias_name_tok->get_str (), std::move (vis),
    2906            3 :                                std::move (outer_attrs), std::move (locus)));
    2907            4 : }
    2908              : 
    2909              : // Parses a "type alias" (typedef) item.
    2910              : template <typename ManagedTokenSource>
    2911              : std::unique_ptr<AST::TypeAlias>
    2912         1298 : Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis,
    2913              :                                               AST::AttrVec outer_attrs)
    2914              : {
    2915         1298 :   location_t locus = lexer.peek_token ()->get_locus ();
    2916         1298 :   skip_token (TYPE);
    2917              : 
    2918              :   // TODO: use this token for identifier when finished that
    2919         1298 :   const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
    2920         1298 :   if (alias_name_tok == nullptr)
    2921              :     {
    2922            0 :       Error error (lexer.peek_token ()->get_locus (),
    2923              :                    "could not parse identifier in type alias");
    2924            0 :       add_error (std::move (error));
    2925              : 
    2926            0 :       skip_after_semicolon ();
    2927            0 :       return nullptr;
    2928            0 :     }
    2929         1298 :   Identifier alias_name{alias_name_tok};
    2930              : 
    2931              :   // parse generic params, which may not exist
    2932         1298 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    2933              :     = parse_generic_params_in_angles ();
    2934              : 
    2935              :   // parse where clause, which may not exist
    2936         1298 :   AST::WhereClause where_clause = parse_where_clause ();
    2937              : 
    2938         1298 :   if (!skip_token (EQUAL))
    2939              :     {
    2940            0 :       skip_after_semicolon ();
    2941            0 :       return nullptr;
    2942              :     }
    2943              : 
    2944         1298 :   std::unique_ptr<AST::Type> type_to_alias = parse_type ();
    2945              : 
    2946         1298 :   if (!skip_token (SEMICOLON))
    2947              :     {
    2948              :       // should be skipping past this, not the next line
    2949            0 :       return nullptr;
    2950              :     }
    2951              : 
    2952              :   return std::unique_ptr<AST::TypeAlias> (
    2953         1298 :     new AST::TypeAlias (std::move (alias_name), std::move (generic_params),
    2954              :                         std::move (where_clause), std::move (type_to_alias),
    2955         1298 :                         std::move (vis), std::move (outer_attrs), locus));
    2956         2596 : }
    2957              : 
    2958              : // Parse a struct item AST node.
    2959              : template <typename ManagedTokenSource>
    2960              : std::unique_ptr<AST::Struct>
    2961         2699 : Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis,
    2962              :                                           AST::AttrVec outer_attrs)
    2963              : {
    2964              :   /* TODO: determine best way to parse the proper struct vs tuple struct -
    2965              :    * share most of initial constructs so lookahead might be impossible, and if
    2966              :    * not probably too expensive. Best way is probably unified parsing for the
    2967              :    * initial parts and then pass them in as params to more derived functions.
    2968              :    * Alternatively, just parse everything in this one function - do this if
    2969              :    * function not too long. */
    2970              : 
    2971              :   /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{'
    2972              :    * struct_fields? '}' | ';' ) */
    2973              :   /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')'
    2974              :    * where_clause? ';' */
    2975         2699 :   location_t locus = lexer.peek_token ()->get_locus ();
    2976         2699 :   skip_token (STRUCT_KW);
    2977              : 
    2978              :   // parse struct name
    2979         2699 :   const_TokenPtr name_tok = expect_token (IDENTIFIER);
    2980         2699 :   if (name_tok == nullptr)
    2981              :     {
    2982              :       // skip after somewhere?
    2983            1 :       return nullptr;
    2984              :     }
    2985         2698 :   Identifier struct_name{name_tok};
    2986              : 
    2987              :   // parse generic params, which may or may not exist
    2988         2698 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    2989              :     = parse_generic_params_in_angles ();
    2990              : 
    2991              :   // branch on next token - determines whether proper struct or tuple struct
    2992         5396 :   if (lexer.peek_token ()->get_id () == LEFT_PAREN)
    2993              :     {
    2994              :       // tuple struct
    2995              : 
    2996              :       // skip left parenthesis
    2997          990 :       lexer.skip_token ();
    2998              : 
    2999              :       // parse tuple fields
    3000          990 :       std::vector<AST::TupleField> tuple_fields;
    3001              :       // Might be empty tuple for unit tuple struct.
    3002         1980 :       if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    3003           23 :         tuple_fields = std::vector<AST::TupleField> ();
    3004              :       else
    3005          967 :         tuple_fields = parse_tuple_fields ();
    3006              : 
    3007              :       // tuple parameters must have closing parenthesis
    3008          990 :       if (!skip_token (RIGHT_PAREN))
    3009              :         {
    3010            1 :           skip_after_semicolon ();
    3011            1 :           return nullptr;
    3012              :         }
    3013              : 
    3014              :       // parse where clause, which is optional
    3015          989 :       AST::WhereClause where_clause = parse_where_clause ();
    3016              : 
    3017          989 :       if (!skip_token (SEMICOLON))
    3018              :         {
    3019              :           // can't skip after semicolon because it's meant to be here
    3020            0 :           return nullptr;
    3021              :         }
    3022              : 
    3023          989 :       return std::unique_ptr<AST::TupleStruct> (
    3024          989 :         new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name),
    3025              :                               std::move (generic_params),
    3026              :                               std::move (where_clause), std::move (vis),
    3027          989 :                               std::move (outer_attrs), locus));
    3028          990 :     }
    3029              : 
    3030              :   // assume it is a proper struct being parsed and continue outside of switch
    3031              :   // - label only here to suppress warning
    3032              : 
    3033              :   // parse where clause, which is optional
    3034         1708 :   AST::WhereClause where_clause = parse_where_clause ();
    3035              : 
    3036              :   // branch on next token - determines whether struct is a unit struct
    3037         1708 :   const_TokenPtr t = lexer.peek_token ();
    3038         1708 :   switch (t->get_id ())
    3039              :     {
    3040          950 :     case LEFT_CURLY:
    3041              :       {
    3042              :         // struct with body
    3043              : 
    3044              :         // skip curly bracket
    3045          950 :         lexer.skip_token ();
    3046              : 
    3047              :         // parse struct fields, if any
    3048          950 :         std::vector<AST::StructField> struct_fields
    3049              :           = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
    3050              : 
    3051          950 :         if (!skip_token (RIGHT_CURLY))
    3052              :           {
    3053              :             // skip somewhere?
    3054            0 :             return nullptr;
    3055              :           }
    3056              : 
    3057          950 :         return std::unique_ptr<AST::StructStruct> (new AST::StructStruct (
    3058              :           std::move (struct_fields), std::move (struct_name),
    3059              :           std::move (generic_params), std::move (where_clause), false,
    3060          950 :           std::move (vis), std::move (outer_attrs), locus));
    3061          950 :       }
    3062          757 :     case SEMICOLON:
    3063              :       // unit struct declaration
    3064              : 
    3065          757 :       lexer.skip_token ();
    3066              : 
    3067          757 :       return std::unique_ptr<AST::StructStruct> (
    3068         1514 :         new AST::StructStruct (std::move (struct_name),
    3069              :                                std::move (generic_params),
    3070              :                                std::move (where_clause), std::move (vis),
    3071          757 :                                std::move (outer_attrs), locus));
    3072            1 :     default:
    3073            1 :       add_error (Error (t->get_locus (),
    3074              :                         "unexpected token %qs in struct declaration",
    3075              :                         t->get_token_description ()));
    3076              : 
    3077              :       // skip somewhere?
    3078            1 :       return nullptr;
    3079              :     }
    3080         2698 : }
    3081              : 
    3082              : // Parses struct fields in struct declarations.
    3083              : template <typename ManagedTokenSource>
    3084              : std::vector<AST::StructField>
    3085            0 : Parser<ManagedTokenSource>::parse_struct_fields ()
    3086              : {
    3087            0 :   std::vector<AST::StructField> fields;
    3088              : 
    3089            0 :   AST::StructField initial_field = parse_struct_field ();
    3090              : 
    3091              :   // Return empty field list if no field there
    3092            0 :   if (initial_field.is_error ())
    3093              :     return fields;
    3094              : 
    3095            0 :   fields.push_back (std::move (initial_field));
    3096              : 
    3097            0 :   while (lexer.peek_token ()->get_id () == COMMA)
    3098              :     {
    3099            0 :       lexer.skip_token ();
    3100              : 
    3101            0 :       AST::StructField field = parse_struct_field ();
    3102              : 
    3103            0 :       if (field.is_error ())
    3104              :         {
    3105              :           // would occur with trailing comma, so allowed
    3106              :           break;
    3107              :         }
    3108              : 
    3109            0 :       fields.push_back (std::move (field));
    3110              :     }
    3111              : 
    3112            0 :   fields.shrink_to_fit ();
    3113              :   return fields;
    3114              :   // TODO: template if possible (parse_non_ptr_seq)
    3115            0 : }
    3116              : 
    3117              : // Parses struct fields in struct declarations.
    3118              : template <typename ManagedTokenSource>
    3119              : template <typename EndTokenPred>
    3120              : std::vector<AST::StructField>
    3121         1156 : Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
    3122              : {
    3123         1156 :   std::vector<AST::StructField> fields;
    3124              : 
    3125         1156 :   AST::StructField initial_field = parse_struct_field ();
    3126              : 
    3127              :   // Return empty field list if no field there
    3128         1156 :   if (initial_field.is_error ())
    3129           50 :     return fields;
    3130              : 
    3131         1106 :   fields.push_back (std::move (initial_field));
    3132              : 
    3133         4540 :   while (lexer.peek_token ()->get_id () == COMMA)
    3134              :     {
    3135         2085 :       lexer.skip_token ();
    3136              : 
    3137         4170 :       if (is_end_tok (lexer.peek_token ()->get_id ()))
    3138              :         break;
    3139              : 
    3140         1164 :       AST::StructField field = parse_struct_field ();
    3141         1164 :       if (field.is_error ())
    3142              :         {
    3143              :           /* TODO: should every field be ditched just because one couldn't be
    3144              :            * parsed? */
    3145            0 :           Error error (lexer.peek_token ()->get_locus (),
    3146              :                        "failed to parse struct field in struct fields");
    3147            0 :           add_error (std::move (error));
    3148              : 
    3149            0 :           return {};
    3150            0 :         }
    3151              : 
    3152         1164 :       fields.push_back (std::move (field));
    3153              :     }
    3154              : 
    3155         1106 :   fields.shrink_to_fit ();
    3156         1106 :   return fields;
    3157              :   // TODO: template if possible (parse_non_ptr_seq)
    3158         1156 : }
    3159              : 
    3160              : // Parses a single struct field (in a struct definition). Does not parse
    3161              : // commas.
    3162              : template <typename ManagedTokenSource>
    3163              : AST::StructField
    3164         2320 : Parser<ManagedTokenSource>::parse_struct_field ()
    3165              : {
    3166              :   // parse outer attributes, if they exist
    3167         2320 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3168              : 
    3169              :   // parse visibility, if it exists
    3170         2320 :   auto vis = parse_visibility ();
    3171         2320 :   if (!vis)
    3172            0 :     return AST::StructField::create_error ();
    3173              : 
    3174         2320 :   location_t locus = lexer.peek_token ()->get_locus ();
    3175              : 
    3176              :   // parse field name
    3177         2320 :   const_TokenPtr field_name_tok = lexer.peek_token ();
    3178         2320 :   if (field_name_tok->get_id () != IDENTIFIER)
    3179              :     {
    3180              :       // if not identifier, assumes there is no struct field and exits - not
    3181              :       // necessarily error
    3182           50 :       return AST::StructField::create_error ();
    3183              :     }
    3184         2270 :   Identifier field_name{field_name_tok};
    3185         2270 :   lexer.skip_token ();
    3186              : 
    3187         2270 :   if (!skip_token (COLON))
    3188              :     {
    3189              :       // skip after somewhere?
    3190            0 :       return AST::StructField::create_error ();
    3191              :     }
    3192              : 
    3193              :   // parse field type - this is required
    3194         2270 :   std::unique_ptr<AST::Type> field_type = parse_type ();
    3195         2270 :   if (field_type == nullptr)
    3196              :     {
    3197            0 :       Error error (lexer.peek_token ()->get_locus (),
    3198              :                    "could not parse type in struct field definition");
    3199            0 :       add_error (std::move (error));
    3200              : 
    3201              :       // skip after somewhere
    3202            0 :       return AST::StructField::create_error ();
    3203            0 :     }
    3204              : 
    3205         4540 :   return AST::StructField (std::move (field_name), std::move (field_type),
    3206         2270 :                            std::move (vis.value ()), locus,
    3207         2270 :                            std::move (outer_attrs));
    3208         9180 : }
    3209              : 
    3210              : // Parses tuple fields in tuple/tuple struct declarations.
    3211              : template <typename ManagedTokenSource>
    3212              : std::vector<AST::TupleField>
    3213         1392 : Parser<ManagedTokenSource>::parse_tuple_fields ()
    3214              : {
    3215         1392 :   std::vector<AST::TupleField> fields;
    3216              : 
    3217         1392 :   AST::TupleField initial_field = parse_tuple_field ();
    3218              : 
    3219              :   // Return empty field list if no field there
    3220         1392 :   if (initial_field.is_error ())
    3221              :     {
    3222            1 :       return fields;
    3223              :     }
    3224              : 
    3225         1391 :   fields.push_back (std::move (initial_field));
    3226              : 
    3227              :   // maybe think of a better control structure here - do-while with an initial
    3228              :   // error state? basically, loop through field list until can't find any more
    3229              :   // params HACK: all current syntax uses of tuple fields have them ending
    3230              :   // with a right paren token
    3231         1391 :   const_TokenPtr t = lexer.peek_token ();
    3232         2129 :   while (t->get_id () == COMMA)
    3233              :     {
    3234              :       // skip comma if applies - e.g. trailing comma
    3235          739 :       lexer.skip_token ();
    3236              : 
    3237              :       // break out due to right paren if it exists
    3238         1478 :       if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    3239              :         {
    3240              :           break;
    3241              :         }
    3242              : 
    3243          738 :       AST::TupleField field = parse_tuple_field ();
    3244          738 :       if (field.is_error ())
    3245              :         {
    3246            0 :           Error error (lexer.peek_token ()->get_locus (),
    3247              :                        "failed to parse tuple field in tuple fields");
    3248            0 :           add_error (std::move (error));
    3249              : 
    3250            0 :           return std::vector<AST::TupleField> ();
    3251            0 :         }
    3252              : 
    3253          738 :       fields.push_back (std::move (field));
    3254              : 
    3255          738 :       t = lexer.peek_token ();
    3256              :     }
    3257              : 
    3258         1391 :   fields.shrink_to_fit ();
    3259         1391 :   return fields;
    3260              : 
    3261              :   // TODO: this shares basically all code with function params and struct
    3262              :   // fields
    3263              :   // - templates?
    3264         1392 : }
    3265              : 
    3266              : /* Parses a single tuple struct field in a tuple struct definition. Does not
    3267              :  * parse commas. */
    3268              : template <typename ManagedTokenSource>
    3269              : AST::TupleField
    3270         2130 : Parser<ManagedTokenSource>::parse_tuple_field ()
    3271              : {
    3272              :   // parse outer attributes if they exist
    3273         2130 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3274              : 
    3275              :   // parse visibility if it exists
    3276         2130 :   auto visibility = parse_visibility ();
    3277         2130 :   if (!visibility)
    3278            0 :     return AST::TupleField::create_error ();
    3279              : 
    3280         2130 :   location_t locus = lexer.peek_token ()->get_locus ();
    3281              : 
    3282              :   // parse type, which is required
    3283         2130 :   std::unique_ptr<AST::Type> field_type = parse_type ();
    3284         2130 :   if (field_type == nullptr)
    3285              :     {
    3286              :       // error if null
    3287            1 :       Error error (lexer.peek_token ()->get_locus (),
    3288              :                    "could not parse type in tuple struct field");
    3289            1 :       add_error (std::move (error));
    3290              : 
    3291              :       // skip after something
    3292            1 :       return AST::TupleField::create_error ();
    3293            1 :     }
    3294              : 
    3295         2129 :   return AST::TupleField (std::move (field_type),
    3296         2129 :                           std::move (visibility.value ()), locus,
    3297         2129 :                           std::move (outer_attrs));
    3298         4260 : }
    3299              : 
    3300              : // Parses a Rust "enum" tagged union item definition.
    3301              : template <typename ManagedTokenSource>
    3302              : std::unique_ptr<AST::Enum>
    3303          549 : Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
    3304              :                                         AST::AttrVec outer_attrs)
    3305              : {
    3306          549 :   location_t locus = lexer.peek_token ()->get_locus ();
    3307          549 :   skip_token (ENUM_KW);
    3308              : 
    3309              :   // parse enum name
    3310          549 :   const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
    3311          549 :   if (enum_name_tok == nullptr)
    3312            1 :     return nullptr;
    3313              : 
    3314          548 :   Identifier enum_name = {enum_name_tok};
    3315              : 
    3316              :   // parse generic params (of enum container, not enum variants) if they exist
    3317          548 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3318              :     = parse_generic_params_in_angles ();
    3319              : 
    3320              :   // parse where clause if it exists
    3321          548 :   AST::WhereClause where_clause = parse_where_clause ();
    3322              : 
    3323          548 :   if (!skip_token (LEFT_CURLY))
    3324              :     {
    3325            0 :       skip_after_end_block ();
    3326            0 :       return nullptr;
    3327              :     }
    3328              : 
    3329              :   // parse actual enum variant definitions
    3330          548 :   std::vector<std::unique_ptr<AST::EnumItem>> enum_items
    3331              :     = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
    3332              : 
    3333          548 :   if (!skip_token (RIGHT_CURLY))
    3334              :     {
    3335            1 :       skip_after_end_block ();
    3336            1 :       return nullptr;
    3337              :     }
    3338              : 
    3339              :   return std::unique_ptr<AST::Enum> (
    3340          547 :     new AST::Enum (std::move (enum_name), std::move (vis),
    3341              :                    std::move (generic_params), std::move (where_clause),
    3342          547 :                    std::move (enum_items), std::move (outer_attrs), locus));
    3343         1096 : }
    3344              : 
    3345              : // Parses the enum variants inside an enum definiton.
    3346              : template <typename ManagedTokenSource>
    3347              : std::vector<std::unique_ptr<AST::EnumItem>>
    3348            0 : Parser<ManagedTokenSource>::parse_enum_items ()
    3349              : {
    3350            0 :   std::vector<std::unique_ptr<AST::EnumItem>> items;
    3351              : 
    3352            0 :   auto initial_item = parse_enum_item ();
    3353              : 
    3354              :   // Return empty item list if no field there
    3355            0 :   if (!initial_item)
    3356              :     return items;
    3357              : 
    3358            0 :   items.push_back (std::move (initial_item.value ()));
    3359              : 
    3360            0 :   while (lexer.peek_token ()->get_id () == COMMA)
    3361              :     {
    3362            0 :       lexer.skip_token ();
    3363              : 
    3364            0 :       auto item = parse_enum_item ();
    3365            0 :       if (!item)
    3366              :         {
    3367              :           // this would occur with a trailing comma, which is allowed
    3368              :           break;
    3369              :         }
    3370              : 
    3371            0 :       items.push_back (std::move (item.value ()));
    3372              :     }
    3373              : 
    3374            0 :   items.shrink_to_fit ();
    3375              :   return items;
    3376              : 
    3377              :   /* TODO: use template if doable (parse_non_ptr_sequence) */
    3378            0 : }
    3379              : 
    3380              : // Parses the enum variants inside an enum definiton.
    3381              : template <typename ManagedTokenSource>
    3382              : template <typename EndTokenPred>
    3383              : std::vector<std::unique_ptr<AST::EnumItem>>
    3384          548 : Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
    3385              : {
    3386          548 :   std::vector<std::unique_ptr<AST::EnumItem>> items;
    3387              : 
    3388          548 :   auto initial_item = parse_enum_item ();
    3389              : 
    3390              :   // Return empty item list if no field there
    3391          548 :   if (!initial_item)
    3392           15 :     return items;
    3393              : 
    3394          533 :   items.push_back (std::move (initial_item.value ()));
    3395              : 
    3396         2554 :   while (lexer.peek_token ()->get_id () == COMMA)
    3397              :     {
    3398         1244 :       lexer.skip_token ();
    3399              : 
    3400         2488 :       if (is_end_tok (lexer.peek_token ()->get_id ()))
    3401              :         break;
    3402              : 
    3403          744 :       auto item = parse_enum_item ();
    3404          744 :       if (!item)
    3405              :         {
    3406              :           /* TODO should this ignore all successfully parsed enum items just
    3407              :            * because one failed? */
    3408            0 :           Error error (lexer.peek_token ()->get_locus (),
    3409              :                        "failed to parse enum item in enum items");
    3410            0 :           add_error (std::move (error));
    3411              : 
    3412            0 :           return {};
    3413            0 :         }
    3414              : 
    3415          744 :       items.push_back (std::move (item.value ()));
    3416              :     }
    3417              : 
    3418          533 :   items.shrink_to_fit ();
    3419          533 :   return items;
    3420              : 
    3421              :   /* TODO: use template if doable (parse_non_ptr_sequence) */
    3422          548 : }
    3423              : 
    3424              : /* Parses a single enum variant item in an enum definition. Does not parse
    3425              :  * commas. */
    3426              : template <typename ManagedTokenSource>
    3427              : tl::expected<std::unique_ptr<AST::EnumItem>, Parse::Error::EnumVariant>
    3428         1292 : Parser<ManagedTokenSource>::parse_enum_item ()
    3429              : {
    3430              :   // parse outer attributes if they exist
    3431         1292 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3432              : 
    3433              :   // parse visibility, which may or may not exist
    3434         1292 :   auto vis_res = parse_visibility ();
    3435         1292 :   if (!vis_res)
    3436              :     return Parse::Error::EnumVariant::make_child_error ();
    3437         1292 :   auto vis = vis_res.value ();
    3438              : 
    3439              :   // parse name for enum item, which is required
    3440         1292 :   const_TokenPtr item_name_tok = lexer.peek_token ();
    3441         1292 :   if (item_name_tok->get_id () != IDENTIFIER)
    3442              :     {
    3443              :       // this may not be an error but it means there is no enum item here
    3444           30 :       return Parse::Error::EnumVariant::make_not_identifier (item_name_tok);
    3445              :     }
    3446         1277 :   lexer.skip_token ();
    3447         1277 :   Identifier item_name{item_name_tok};
    3448              : 
    3449              :   // branch based on next token
    3450         1277 :   const_TokenPtr t = lexer.peek_token ();
    3451         1277 :   switch (t->get_id ())
    3452              :     {
    3453          443 :     case LEFT_PAREN:
    3454              :       {
    3455              :         // tuple enum item
    3456          443 :         lexer.skip_token ();
    3457              : 
    3458          443 :         std::vector<AST::TupleField> tuple_fields;
    3459              :         // Might be empty tuple for unit tuple enum variant.
    3460          886 :         if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    3461           18 :           tuple_fields = std::vector<AST::TupleField> ();
    3462              :         else
    3463          425 :           tuple_fields = parse_tuple_fields ();
    3464              : 
    3465          443 :         if (!skip_token (RIGHT_PAREN))
    3466              :           {
    3467              :             // skip after somewhere
    3468              :             return Parse::Error::EnumVariant::make_unfinished_tuple_variant ();
    3469              :           }
    3470              : 
    3471          443 :         return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
    3472              :           std::move (item_name), std::move (vis), std::move (tuple_fields),
    3473          443 :           std::move (outer_attrs), item_name_tok->get_locus ()));
    3474          443 :       }
    3475           95 :     case LEFT_CURLY:
    3476              :       {
    3477              :         // struct enum item
    3478           95 :         lexer.skip_token ();
    3479              : 
    3480           95 :         std::vector<AST::StructField> struct_fields
    3481              :           = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
    3482              : 
    3483           95 :         if (!skip_token (RIGHT_CURLY))
    3484              :           {
    3485              :             // skip after somewhere
    3486              :             return Parse::Error::EnumVariant::make_unfinished_tuple_variant ();
    3487              :           }
    3488              : 
    3489           95 :         return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
    3490              :           std::move (item_name), std::move (vis), std::move (struct_fields),
    3491           95 :           std::move (outer_attrs), item_name_tok->get_locus ()));
    3492           95 :       }
    3493          278 :     case EQUAL:
    3494              :       {
    3495              :         // discriminant enum item
    3496          278 :         lexer.skip_token ();
    3497              : 
    3498          278 :         auto discriminant_expr = parse_expr ();
    3499          278 :         if (!discriminant_expr)
    3500              :           return Parse::Error::EnumVariant::make_child_error ();
    3501              : 
    3502          278 :         return std::make_unique<AST::EnumItemDiscriminant> (
    3503              :           std::move (item_name), std::move (vis),
    3504          278 :           std::move (discriminant_expr.value ()), std::move (outer_attrs),
    3505          556 :           item_name_tok->get_locus ());
    3506          278 :       }
    3507          461 :     default:
    3508              :       // regular enum with just an identifier
    3509          461 :       return std::make_unique<AST::EnumItem> (std::move (item_name),
    3510              :                                               std::move (vis),
    3511              :                                               std::move (outer_attrs),
    3512          461 :                                               item_name_tok->get_locus ());
    3513              :     }
    3514         3861 : }
    3515              : 
    3516              : // Parses a C-style (and C-compat) untagged union declaration.
    3517              : template <typename ManagedTokenSource>
    3518              : std::unique_ptr<AST::Union>
    3519          111 : Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
    3520              :                                          AST::AttrVec outer_attrs)
    3521              : {
    3522              :   /* hack - "weak keyword" by finding identifier called "union" (lookahead in
    3523              :    * item switch) */
    3524          111 :   const_TokenPtr union_keyword = expect_token (IDENTIFIER);
    3525          111 :   rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION);
    3526          111 :   location_t locus = union_keyword->get_locus ();
    3527              : 
    3528              :   // parse actual union name
    3529          111 :   const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
    3530          111 :   if (union_name_tok == nullptr)
    3531              :     {
    3532            0 :       skip_after_next_block ();
    3533            0 :       return nullptr;
    3534              :     }
    3535          111 :   Identifier union_name{union_name_tok};
    3536              : 
    3537              :   // parse optional generic parameters
    3538          111 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3539              :     = parse_generic_params_in_angles ();
    3540              : 
    3541              :   // parse optional where clause
    3542          111 :   AST::WhereClause where_clause = parse_where_clause ();
    3543              : 
    3544          111 :   if (!skip_token (LEFT_CURLY))
    3545              :     {
    3546            0 :       skip_after_end_block ();
    3547            0 :       return nullptr;
    3548              :     }
    3549              : 
    3550              :   /* parse union inner items as "struct fields" because hey, syntax reuse.
    3551              :    * Spec said so. */
    3552          111 :   std::vector<AST::StructField> union_fields
    3553              :     = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
    3554              : 
    3555          111 :   if (!skip_token (RIGHT_CURLY))
    3556              :     {
    3557              :       // skip after somewhere
    3558            0 :       return nullptr;
    3559              :     }
    3560              : 
    3561              :   return std::unique_ptr<AST::Union> (
    3562          111 :     new AST::Union (std::move (union_name), std::move (vis),
    3563              :                     std::move (generic_params), std::move (where_clause),
    3564          111 :                     std::move (union_fields), std::move (outer_attrs), locus));
    3565          333 : }
    3566              : 
    3567              : /* Parses a "constant item" (compile-time constant to maybe "inline"
    3568              :  * throughout the program - like constexpr). */
    3569              : template <typename ManagedTokenSource>
    3570              : std::unique_ptr<AST::ConstantItem>
    3571          549 : Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
    3572              :                                               AST::AttrVec outer_attrs)
    3573              : {
    3574          549 :   location_t locus = lexer.peek_token ()->get_locus ();
    3575          549 :   skip_token (CONST);
    3576              : 
    3577              :   /* get constant identifier - this is either a proper identifier or the _
    3578              :    * wildcard */
    3579          549 :   const_TokenPtr ident_tok = lexer.peek_token ();
    3580              :   // make default identifier the underscore wildcard one
    3581          549 :   std::string ident (Values::Keywords::UNDERSCORE);
    3582          549 :   switch (ident_tok->get_id ())
    3583              :     {
    3584          547 :     case IDENTIFIER:
    3585          547 :       ident = ident_tok->get_str ();
    3586          547 :       lexer.skip_token ();
    3587              :       break;
    3588            2 :     case UNDERSCORE:
    3589              :       // do nothing - identifier is already "_"
    3590            2 :       lexer.skip_token ();
    3591              :       break;
    3592            0 :     default:
    3593            0 :       add_error (
    3594            0 :         Error (ident_tok->get_locus (),
    3595              :                "expected item name (identifier or %<_%>) in constant item "
    3596              :                "declaration - found %qs",
    3597              :                ident_tok->get_token_description ()));
    3598              : 
    3599            0 :       skip_after_semicolon ();
    3600            0 :       return nullptr;
    3601              :     }
    3602              : 
    3603          549 :   if (!skip_token (COLON))
    3604              :     {
    3605            0 :       skip_after_semicolon ();
    3606            0 :       return nullptr;
    3607              :     }
    3608              : 
    3609              :   // parse constant type (required)
    3610          549 :   std::unique_ptr<AST::Type> type = parse_type ();
    3611              : 
    3612              :   // A const with no given expression value
    3613         1098 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    3614              :     {
    3615            4 :       lexer.skip_token ();
    3616              :       return std::unique_ptr<AST::ConstantItem> (
    3617            8 :         new AST::ConstantItem (std::move (ident), std::move (vis),
    3618              :                                std::move (type), std::move (outer_attrs),
    3619            4 :                                locus));
    3620              :     }
    3621              : 
    3622          545 :   if (!skip_token (EQUAL))
    3623              :     {
    3624            0 :       skip_after_semicolon ();
    3625            0 :       return nullptr;
    3626              :     }
    3627              : 
    3628              :   // parse constant expression (required)
    3629          545 :   auto expr = parse_expr ();
    3630          545 :   if (!expr)
    3631            1 :     return nullptr;
    3632              : 
    3633          544 :   if (!skip_token (SEMICOLON))
    3634              :     {
    3635              :       // skip somewhere?
    3636            0 :       return nullptr;
    3637              :     }
    3638              : 
    3639              :   return std::unique_ptr<AST::ConstantItem> (
    3640         1088 :     new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
    3641          544 :                            std::move (expr.value ()), std::move (outer_attrs),
    3642          544 :                            locus));
    3643         1098 : }
    3644              : 
    3645              : // Parses a "static item" (static storage item, with 'static lifetime).
    3646              : template <typename ManagedTokenSource>
    3647              : std::unique_ptr<AST::StaticItem>
    3648           68 : Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
    3649              :                                                AST::AttrVec outer_attrs)
    3650              : {
    3651           68 :   location_t locus = lexer.peek_token ()->get_locus ();
    3652           68 :   skip_token (STATIC_KW);
    3653              : 
    3654              :   // determine whether static item is mutable
    3655           68 :   bool is_mut = false;
    3656          136 :   if (lexer.peek_token ()->get_id () == MUT)
    3657              :     {
    3658            4 :       is_mut = true;
    3659            4 :       lexer.skip_token ();
    3660              :     }
    3661              : 
    3662           68 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    3663           68 :   if (ident_tok == nullptr)
    3664            1 :     return nullptr;
    3665              : 
    3666           67 :   Identifier ident{ident_tok};
    3667              : 
    3668           67 :   if (!skip_token (COLON))
    3669              :     {
    3670            1 :       skip_after_semicolon ();
    3671            1 :       return nullptr;
    3672              :     }
    3673              : 
    3674              :   // parse static item type (required)
    3675           66 :   std::unique_ptr<AST::Type> type = parse_type ();
    3676              : 
    3677           66 :   if (!skip_token (EQUAL))
    3678              :     {
    3679            0 :       skip_after_semicolon ();
    3680            0 :       return nullptr;
    3681              :     }
    3682              : 
    3683              :   // parse static item expression (required)
    3684           66 :   auto expr = parse_expr ();
    3685           66 :   if (!expr)
    3686            1 :     return nullptr;
    3687              : 
    3688           65 :   if (!skip_token (SEMICOLON))
    3689              :     {
    3690              :       // skip after somewhere
    3691            0 :       return nullptr;
    3692              :     }
    3693              : 
    3694              :   return std::unique_ptr<AST::StaticItem> (
    3695          130 :     new AST::StaticItem (std::move (ident), is_mut, std::move (type),
    3696           65 :                          std::move (expr.value ()), std::move (vis),
    3697           65 :                          std::move (outer_attrs), locus));
    3698          133 : }
    3699              : 
    3700              : // Parses a trait definition item, including unsafe ones.
    3701              : template <typename ManagedTokenSource>
    3702              : std::unique_ptr<AST::Trait>
    3703         3775 : Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
    3704              :                                          AST::AttrVec outer_attrs)
    3705              : {
    3706         3775 :   location_t locus = lexer.peek_token ()->get_locus ();
    3707         3775 :   bool is_unsafe = false;
    3708         3775 :   bool is_auto_trait = false;
    3709              : 
    3710         7550 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    3711              :     {
    3712           56 :       is_unsafe = true;
    3713           56 :       lexer.skip_token ();
    3714              :     }
    3715              : 
    3716         7550 :   if (lexer.peek_token ()->get_id () == AUTO)
    3717              :     {
    3718           20 :       is_auto_trait = true;
    3719           20 :       lexer.skip_token ();
    3720              :     }
    3721              : 
    3722         3775 :   skip_token (TRAIT);
    3723              : 
    3724              :   // parse trait name
    3725         3775 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    3726         3775 :   if (ident_tok == nullptr)
    3727            0 :     return nullptr;
    3728              : 
    3729         3775 :   Identifier ident{ident_tok};
    3730              : 
    3731              :   // parse generic parameters (if they exist)
    3732         3775 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3733              :     = parse_generic_params_in_angles ();
    3734              : 
    3735              :   // create placeholder type param bounds in case they don't exist
    3736         3775 :   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    3737              : 
    3738              :   // parse type param bounds (if they exist)
    3739         7550 :   if (lexer.peek_token ()->get_id () == COLON)
    3740              :     {
    3741          538 :       lexer.skip_token ();
    3742              : 
    3743          538 :       type_param_bounds = parse_type_param_bounds (
    3744           72 :         [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
    3745              :       // type_param_bounds = parse_type_param_bounds ();
    3746              :     }
    3747              : 
    3748              :   // parse where clause (if it exists)
    3749         3775 :   AST::WhereClause where_clause = parse_where_clause ();
    3750              : 
    3751         3775 :   if (!skip_token (LEFT_CURLY))
    3752              :     {
    3753            0 :       skip_after_end_block ();
    3754            0 :       return nullptr;
    3755              :     }
    3756              : 
    3757              :   // parse inner attrs (if they exist)
    3758         3775 :   AST::AttrVec inner_attrs = parse_inner_attributes ();
    3759              : 
    3760              :   // parse trait items
    3761         3775 :   std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
    3762              : 
    3763         3775 :   const_TokenPtr t = lexer.peek_token ();
    3764         7137 :   while (t->get_id () != RIGHT_CURLY)
    3765              :     {
    3766         3362 :       std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
    3767              : 
    3768         3362 :       if (trait_item == nullptr)
    3769              :         {
    3770            0 :           Error error (lexer.peek_token ()->get_locus (),
    3771              :                        "failed to parse trait item in trait");
    3772            0 :           add_error (std::move (error));
    3773              : 
    3774            0 :           return nullptr;
    3775            0 :         }
    3776         3362 :       trait_items.push_back (std::move (trait_item));
    3777              : 
    3778         3362 :       t = lexer.peek_token ();
    3779              :     }
    3780              : 
    3781         3775 :   if (!skip_token (RIGHT_CURLY))
    3782              :     {
    3783              :       // skip after something
    3784            0 :       return nullptr;
    3785              :     }
    3786              : 
    3787         3775 :   trait_items.shrink_to_fit ();
    3788              :   return std::unique_ptr<AST::Trait> (
    3789         3775 :     new AST::Trait (std::move (ident), is_unsafe, is_auto_trait,
    3790              :                     std::move (generic_params), std::move (type_param_bounds),
    3791              :                     std::move (where_clause), std::move (trait_items),
    3792              :                     std::move (vis), std::move (outer_attrs),
    3793         3775 :                     std::move (inner_attrs), locus));
    3794         7550 : }
    3795              : 
    3796              : // Parses a trait item used inside traits (not trait, the Item).
    3797              : template <typename ManagedTokenSource>
    3798              : std::unique_ptr<AST::AssociatedItem>
    3799         3364 : Parser<ManagedTokenSource>::parse_trait_item ()
    3800              : {
    3801              :   // parse outer attributes (if they exist)
    3802         3364 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3803              : 
    3804         3364 :   auto vis_res = parse_visibility ();
    3805         3364 :   if (!vis_res)
    3806            0 :     return nullptr;
    3807              : 
    3808         3364 :   auto vis = vis_res.value ();
    3809              : 
    3810              :   // lookahead to determine what type of trait item to parse
    3811         3364 :   const_TokenPtr tok = lexer.peek_token ();
    3812         3364 :   switch (tok->get_id ())
    3813              :     {
    3814            0 :     case SUPER:
    3815              :     case SELF:
    3816              :     case CRATE:
    3817              :     case DOLLAR_SIGN:
    3818              :       // these seem to be SimplePath tokens, so this is a macro invocation
    3819              :       // semi
    3820            0 :       return parse_macro_invocation_semi (std::move (outer_attrs));
    3821            1 :     case IDENTIFIER:
    3822            2 :       if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
    3823            0 :         return parse_function (std::move (vis), std::move (outer_attrs));
    3824              :       else
    3825            2 :         return parse_macro_invocation_semi (std::move (outer_attrs));
    3826          748 :     case TYPE:
    3827          748 :       return parse_trait_type (std::move (outer_attrs), vis);
    3828           41 :     case CONST:
    3829              :       // disambiguate with function qualifier
    3830           82 :       if (lexer.peek_token (1)->get_id () == IDENTIFIER)
    3831              :         {
    3832           80 :           return parse_trait_const (std::move (outer_attrs));
    3833              :         }
    3834              :       // else, fallthrough to function
    3835              :       // TODO: find out how to disable gcc "implicit fallthrough" error
    3836              :       gcc_fallthrough ();
    3837              :     case ASYNC:
    3838              :     case UNSAFE:
    3839              :     case EXTERN_KW:
    3840              :     case FN_KW:
    3841         5150 :       return parse_function (std::move (vis), std::move (outer_attrs));
    3842              :     default:
    3843              :       break;
    3844              :     }
    3845            0 :   add_error (Error (tok->get_locus (),
    3846              :                     "unrecognised token %qs for item in trait",
    3847              :                     tok->get_token_description ()));
    3848              :   // skip?
    3849            0 :   return nullptr;
    3850         6728 : }
    3851              : 
    3852              : // Parse a typedef trait item.
    3853              : template <typename ManagedTokenSource>
    3854              : std::unique_ptr<AST::TraitItemType>
    3855          748 : Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
    3856              :                                               AST::Visibility vis)
    3857              : {
    3858          748 :   location_t locus = lexer.peek_token ()->get_locus ();
    3859          748 :   skip_token (TYPE);
    3860              : 
    3861          748 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    3862          748 :   if (ident_tok == nullptr)
    3863            0 :     return nullptr;
    3864              : 
    3865         1496 :   Identifier ident{ident_tok};
    3866              : 
    3867              :   // Parse optional generic parameters for GATs (Generic Associated Types)
    3868          748 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
    3869         1496 :   if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
    3870              :     {
    3871            9 :       generic_params = parse_generic_params_in_angles ();
    3872              :     }
    3873              : 
    3874          748 :   std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    3875              : 
    3876              :   // parse optional colon
    3877         1496 :   if (lexer.peek_token ()->get_id () == COLON)
    3878              :     {
    3879           44 :       lexer.skip_token ();
    3880              : 
    3881              :       // parse optional type param bounds
    3882              :       bounds
    3883           44 :         = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
    3884              :       // bounds = parse_type_param_bounds ();
    3885              :     }
    3886              : 
    3887          748 :   if (!skip_token (SEMICOLON))
    3888              :     {
    3889              :       // skip?
    3890            0 :       return nullptr;
    3891              :     }
    3892              : 
    3893              :   return std::unique_ptr<AST::TraitItemType> (
    3894          748 :     new AST::TraitItemType (std::move (ident), std::move (generic_params),
    3895              :                             std::move (bounds), std::move (outer_attrs), vis,
    3896          748 :                             locus));
    3897          748 : }
    3898              : 
    3899              : // Parses a constant trait item.
    3900              : template <typename ManagedTokenSource>
    3901              : std::unique_ptr<AST::ConstantItem>
    3902           40 : Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
    3903              : {
    3904           40 :   location_t locus = lexer.peek_token ()->get_locus ();
    3905           40 :   skip_token (CONST);
    3906              : 
    3907              :   // parse constant item name
    3908           40 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    3909           40 :   if (ident_tok == nullptr)
    3910            0 :     return nullptr;
    3911              : 
    3912           40 :   Identifier ident{ident_tok};
    3913              : 
    3914           40 :   if (!skip_token (COLON))
    3915              :     {
    3916            0 :       skip_after_semicolon ();
    3917            0 :       return nullptr;
    3918              :     }
    3919              : 
    3920              :   // parse constant trait item type
    3921           40 :   std::unique_ptr<AST::Type> type = parse_type ();
    3922              : 
    3923              :   // parse constant trait body expression, if it exists
    3924           40 :   std::unique_ptr<AST::Expr> const_body = nullptr;
    3925           80 :   if (lexer.peek_token ()->get_id () == EQUAL)
    3926              :     {
    3927           12 :       lexer.skip_token ();
    3928              : 
    3929              :       // expression must exist, so parse it
    3930           12 :       auto expr = parse_expr ();
    3931           12 :       if (!expr)
    3932            0 :         return nullptr;
    3933           12 :       const_body = std::move (expr.value ());
    3934           12 :     }
    3935              : 
    3936           40 :   if (!skip_token (SEMICOLON))
    3937              :     {
    3938              :       // skip after something?
    3939            0 :       return nullptr;
    3940              :     }
    3941              : 
    3942          120 :   return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem (
    3943           80 :     std::move (ident), AST::Visibility::create_private (), std::move (type),
    3944           40 :     std::move (const_body), std::move (outer_attrs), locus));
    3945           80 : }
    3946              : 
    3947              : /* Parses a struct "impl" item (both inherent impl and trait impl can be
    3948              :  * parsed here), */
    3949              : template <typename ManagedTokenSource>
    3950              : std::unique_ptr<AST::Impl>
    3951         5298 : Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
    3952              :                                         AST::AttrVec outer_attrs)
    3953              : {
    3954              :   /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
    3955              :    * must be a trait impl. However, this isn't enough for full disambiguation,
    3956              :    * so don't branch here. */
    3957         5298 :   location_t locus = lexer.peek_token ()->get_locus ();
    3958         5298 :   bool is_unsafe = false;
    3959        10596 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    3960              :     {
    3961           67 :       lexer.skip_token ();
    3962           67 :       is_unsafe = true;
    3963              :     }
    3964              : 
    3965         5298 :   if (!skip_token (IMPL))
    3966              :     {
    3967            0 :       skip_after_next_block ();
    3968            0 :       return nullptr;
    3969              :     }
    3970              : 
    3971              :   // parse generic params (shared by trait and inherent impls)
    3972         5298 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3973              :     = parse_generic_params_in_angles ();
    3974              : 
    3975              :   // Again, trait impl-only feature, but optional one, so can be used for
    3976              :   // branching yet.
    3977         5298 :   bool has_exclam = false;
    3978        10596 :   if (lexer.peek_token ()->get_id () == EXCLAM)
    3979              :     {
    3980            6 :       lexer.skip_token ();
    3981            6 :       has_exclam = true;
    3982              :     }
    3983              : 
    3984              :   /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
    3985              :    * doesn't parse too much and not work. */
    3986         5298 :   AST::TypePath type_path = parse_type_path ();
    3987        10395 :   if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
    3988              :     {
    3989              :       /* cannot parse type path (or not for token next, at least), so must be
    3990              :        * inherent impl */
    3991              : 
    3992              :       // hacky conversion of TypePath stack object to Type pointer
    3993          984 :       std::unique_ptr<AST::Type> type = nullptr;
    3994          984 :       if (!type_path.is_error ())
    3995          783 :         type = std::unique_ptr<AST::TypePath> (
    3996          783 :           new AST::TypePath (std::move (type_path)));
    3997              :       else
    3998          201 :         type = parse_type ();
    3999              : 
    4000              :       // Type is required, so error if null
    4001          984 :       if (type == nullptr)
    4002              :         {
    4003            1 :           Error error (lexer.peek_token ()->get_locus (),
    4004              :                        "could not parse type in inherent impl");
    4005            1 :           add_error (std::move (error));
    4006              : 
    4007            1 :           skip_after_next_block ();
    4008            1 :           return nullptr;
    4009            1 :         }
    4010              : 
    4011              :       // parse optional where clause
    4012          983 :       AST::WhereClause where_clause = parse_where_clause ();
    4013              : 
    4014          983 :       if (!skip_token (LEFT_CURLY))
    4015              :         {
    4016              :           // TODO: does this still skip properly?
    4017            0 :           skip_after_end_block ();
    4018            0 :           return nullptr;
    4019              :         }
    4020              : 
    4021              :       // parse inner attributes (optional)
    4022          983 :       AST::AttrVec inner_attrs = parse_inner_attributes ();
    4023              : 
    4024              :       // parse inherent impl items
    4025          983 :       std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
    4026              : 
    4027          983 :       const_TokenPtr t = lexer.peek_token ();
    4028         3761 :       while (t->get_id () != RIGHT_CURLY)
    4029              :         {
    4030         2788 :           std::unique_ptr<AST::AssociatedItem> impl_item
    4031              :             = parse_inherent_impl_item ();
    4032              : 
    4033         2788 :           if (impl_item == nullptr)
    4034              :             {
    4035           10 :               Error error (
    4036           10 :                 lexer.peek_token ()->get_locus (),
    4037              :                 "failed to parse inherent impl item in inherent impl");
    4038           10 :               add_error (std::move (error));
    4039              : 
    4040           10 :               return nullptr;
    4041           10 :             }
    4042              : 
    4043         2778 :           impl_items.push_back (std::move (impl_item));
    4044              : 
    4045         2778 :           t = lexer.peek_token ();
    4046              :         }
    4047              : 
    4048          973 :       if (!skip_token (RIGHT_CURLY))
    4049              :         {
    4050              :           // skip somewhere
    4051            0 :           return nullptr;
    4052              :         }
    4053              : 
    4054              :       // DEBUG
    4055          973 :       rust_debug ("successfully parsed inherent impl");
    4056              : 
    4057          973 :       impl_items.shrink_to_fit ();
    4058              : 
    4059          973 :       return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
    4060              :         std::move (impl_items), std::move (generic_params), std::move (type),
    4061              :         std::move (where_clause), std::move (vis), std::move (inner_attrs),
    4062          973 :         std::move (outer_attrs), locus));
    4063          984 :     }
    4064              :   else
    4065              :     {
    4066              :       // type path must both be valid and next token is for, so trait impl
    4067         4314 :       if (!skip_token (FOR))
    4068              :         {
    4069            0 :           skip_after_next_block ();
    4070            0 :           return nullptr;
    4071              :         }
    4072              : 
    4073              :       // parse type
    4074         4314 :       std::unique_ptr<AST::Type> type = parse_type ();
    4075              :       // ensure type is included as it is required
    4076         4314 :       if (type == nullptr)
    4077              :         {
    4078            0 :           Error error (lexer.peek_token ()->get_locus (),
    4079              :                        "could not parse type in trait impl");
    4080            0 :           add_error (std::move (error));
    4081              : 
    4082            0 :           skip_after_next_block ();
    4083            0 :           return nullptr;
    4084            0 :         }
    4085              : 
    4086              :       // parse optional where clause
    4087         4314 :       AST::WhereClause where_clause = parse_where_clause ();
    4088              : 
    4089         4314 :       if (!skip_token (LEFT_CURLY))
    4090              :         {
    4091              :           // TODO: does this still skip properly?
    4092            0 :           skip_after_end_block ();
    4093            0 :           return nullptr;
    4094              :         }
    4095              : 
    4096              :       // parse inner attributes (optional)
    4097         4314 :       AST::AttrVec inner_attrs = parse_inner_attributes ();
    4098              : 
    4099              :       // parse trait impl items
    4100         4314 :       std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
    4101              : 
    4102         4314 :       const_TokenPtr t = lexer.peek_token ();
    4103        14602 :       while (t->get_id () != RIGHT_CURLY)
    4104              :         {
    4105         5145 :           std::unique_ptr<AST::AssociatedItem> impl_item
    4106              :             = parse_trait_impl_item ();
    4107              : 
    4108         5145 :           if (impl_item == nullptr)
    4109              :             {
    4110            1 :               Error error (lexer.peek_token ()->get_locus (),
    4111              :                            "failed to parse trait impl item in trait impl");
    4112            1 :               add_error (std::move (error));
    4113              : 
    4114            1 :               return nullptr;
    4115            1 :             }
    4116              : 
    4117         5144 :           impl_items.push_back (std::move (impl_item));
    4118              : 
    4119         5144 :           t = lexer.peek_token ();
    4120              : 
    4121              :           // DEBUG
    4122         5144 :           rust_debug ("successfully parsed a trait impl item");
    4123              :         }
    4124              :       // DEBUG
    4125         4313 :       rust_debug ("successfully finished trait impl items");
    4126              : 
    4127         4313 :       if (!skip_token (RIGHT_CURLY))
    4128              :         {
    4129              :           // skip somewhere
    4130            0 :           return nullptr;
    4131              :         }
    4132              : 
    4133              :       // DEBUG
    4134         4313 :       rust_debug ("successfully parsed trait impl");
    4135              : 
    4136         4313 :       impl_items.shrink_to_fit ();
    4137              : 
    4138         4313 :       return std::unique_ptr<AST::TraitImpl> (
    4139         8626 :         new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
    4140              :                             std::move (impl_items), std::move (generic_params),
    4141              :                             std::move (type), std::move (where_clause),
    4142              :                             std::move (vis), std::move (inner_attrs),
    4143         4313 :                             std::move (outer_attrs), locus));
    4144         4314 :     }
    4145         5298 : }
    4146              : 
    4147              : // Parses a single inherent impl item (item inside an inherent impl block).
    4148              : template <typename ManagedTokenSource>
    4149              : std::unique_ptr<AST::AssociatedItem>
    4150         2790 : Parser<ManagedTokenSource>::parse_inherent_impl_item ()
    4151              : {
    4152              :   // parse outer attributes (if they exist)
    4153         2790 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4154              : 
    4155              :   // TODO: cleanup - currently an unreadable mess
    4156              : 
    4157              :   // branch on next token:
    4158         2790 :   const_TokenPtr t = lexer.peek_token ();
    4159         2790 :   switch (t->get_id ())
    4160              :     {
    4161            1 :     case IDENTIFIER:
    4162              :       // FIXME: Arthur: Do we need to some lookahead here?
    4163            2 :       return parse_macro_invocation_semi (outer_attrs);
    4164         2141 :     case SUPER:
    4165              :     case SELF:
    4166              :     case CRATE:
    4167              :     case PUB:
    4168              :       {
    4169              :         // visibility, so not a macro invocation semi - must be constant,
    4170              :         // function, or method
    4171         2141 :         auto vis_res = parse_visibility ();
    4172         2141 :         if (!vis_res)
    4173            0 :           return nullptr;
    4174         2141 :         auto vis = vis_res.value ();
    4175              : 
    4176              :         // TODO: is a recursive call to parse_inherent_impl_item better?
    4177         4282 :         switch (lexer.peek_token ()->get_id ())
    4178              :           {
    4179         1364 :           case EXTERN_KW:
    4180              :           case UNSAFE:
    4181              :           case FN_KW:
    4182              :             // function or method
    4183         2728 :             return parse_inherent_impl_function_or_method (std::move (vis),
    4184              :                                                            std::move (
    4185         1364 :                                                              outer_attrs));
    4186          777 :           case CONST:
    4187              :             // lookahead to resolve production - could be function/method or
    4188              :             // const item
    4189          777 :             t = lexer.peek_token (1);
    4190              : 
    4191          777 :             switch (t->get_id ())
    4192              :               {
    4193            1 :               case IDENTIFIER:
    4194              :               case UNDERSCORE:
    4195            2 :                 return parse_const_item (std::move (vis),
    4196            1 :                                          std::move (outer_attrs));
    4197          776 :               case UNSAFE:
    4198              :               case EXTERN_KW:
    4199              :               case FN_KW:
    4200         1552 :                 return parse_inherent_impl_function_or_method (std::move (vis),
    4201              :                                                                std::move (
    4202          776 :                                                                  outer_attrs));
    4203            0 :               default:
    4204            0 :                 add_error (Error (t->get_locus (),
    4205              :                                   "unexpected token %qs in some sort of const "
    4206              :                                   "item in inherent impl",
    4207              :                                   t->get_token_description ()));
    4208              : 
    4209            0 :                 lexer.skip_token (1); // TODO: is this right thing to do?
    4210            0 :                 return nullptr;
    4211              :               }
    4212            0 :           default:
    4213            0 :             add_error (
    4214            0 :               Error (t->get_locus (),
    4215              :                      "unrecognised token %qs for item in inherent impl",
    4216              :                      t->get_token_description ()));
    4217              :             // skip?
    4218            0 :             return nullptr;
    4219              :           }
    4220         4282 :       }
    4221          608 :     case ASYNC:
    4222              :     case EXTERN_KW:
    4223              :     case UNSAFE:
    4224              :     case FN_KW:
    4225              :       // function or method
    4226          608 :       return parse_inherent_impl_function_or_method (
    4227          608 :         AST::Visibility::create_private (), std::move (outer_attrs));
    4228           40 :     case CONST:
    4229              :       /* lookahead to resolve production - could be function/method or const
    4230              :        * item */
    4231           40 :       t = lexer.peek_token (1);
    4232              : 
    4233           40 :       switch (t->get_id ())
    4234              :         {
    4235           40 :         case IDENTIFIER:
    4236              :         case UNDERSCORE:
    4237           80 :           return parse_const_item (AST::Visibility::create_private (),
    4238           40 :                                    std::move (outer_attrs));
    4239            0 :         case UNSAFE:
    4240              :         case EXTERN_KW:
    4241              :         case FN_KW:
    4242            0 :           return parse_inherent_impl_function_or_method (
    4243            0 :             AST::Visibility::create_private (), std::move (outer_attrs));
    4244            0 :         default:
    4245            0 :           add_error (Error (t->get_locus (),
    4246              :                             "unexpected token %qs in some sort of const item "
    4247              :                             "in inherent impl",
    4248              :                             t->get_token_description ()));
    4249              : 
    4250            0 :           lexer.skip_token (1); // TODO: is this right thing to do?
    4251            0 :           return nullptr;
    4252              :         }
    4253              :       rust_unreachable ();
    4254            0 :     default:
    4255            0 :       add_error (Error (t->get_locus (),
    4256              :                         "unrecognised token %qs for item in inherent impl",
    4257              :                         t->get_token_description ()));
    4258              : 
    4259              :       // skip?
    4260            0 :       return nullptr;
    4261              :     }
    4262         2790 : }
    4263              : 
    4264              : /* For internal use only by parse_inherent_impl_item() - splits giant method
    4265              :  * into smaller ones and prevents duplication of logic. Strictly, this parses
    4266              :  * a function or method item inside an inherent impl item block. */
    4267              : // TODO: make this a templated function with "return type" as type param -
    4268              : // InherentImplItem is this specialisation of the template while TraitImplItem
    4269              : // will be the other.
    4270              : template <typename ManagedTokenSource>
    4271              : std::unique_ptr<AST::AssociatedItem>
    4272         2748 : Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
    4273              :   AST::Visibility vis, AST::AttrVec outer_attrs)
    4274              : {
    4275         2748 :   location_t locus = lexer.peek_token ()->get_locus ();
    4276              :   // parse function or method qualifiers
    4277         2748 :   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
    4278              : 
    4279         2748 :   skip_token (FN_KW);
    4280              : 
    4281              :   // parse function or method name
    4282         2748 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4283         2748 :   if (ident_tok == nullptr)
    4284            7 :     return nullptr;
    4285              : 
    4286         2741 :   Identifier ident{ident_tok};
    4287              : 
    4288              :   // parse generic params
    4289         2741 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    4290              :     = parse_generic_params_in_angles ();
    4291              : 
    4292         2741 :   if (!skip_token (LEFT_PAREN))
    4293              :     {
    4294              :       // skip after somewhere?
    4295            0 :       return nullptr;
    4296              :     }
    4297              : 
    4298              :   // now for function vs method disambiguation - method has opening "self"
    4299              :   // param
    4300         2741 :   auto initial_param = parse_self_param ();
    4301              : 
    4302         2741 :   if (!initial_param.has_value ()
    4303         2741 :       && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
    4304            3 :     return nullptr;
    4305              : 
    4306              :   /* FIXME: ensure that self param doesn't accidently consume tokens for a
    4307              :    * function one idea is to lookahead up to 4 tokens to see whether self is
    4308              :    * one of them */
    4309         2738 :   bool is_method = false;
    4310         2738 :   if (initial_param.has_value ())
    4311              :     {
    4312         1844 :       if ((*initial_param)->is_self ())
    4313              :         is_method = true;
    4314              : 
    4315              :       /* skip comma so function and method regular params can be parsed in
    4316              :        * same way */
    4317         3688 :       if (lexer.peek_token ()->get_id () == COMMA)
    4318         1193 :         lexer.skip_token ();
    4319              :     }
    4320              : 
    4321              :   // parse trait function params
    4322         2738 :   std::vector<std::unique_ptr<AST::Param>> function_params
    4323              :     = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
    4324              : 
    4325         2738 :   if (initial_param.has_value ())
    4326         1844 :     function_params.insert (function_params.begin (),
    4327         1844 :                             std::move (*initial_param));
    4328              : 
    4329         2738 :   if (!skip_token (RIGHT_PAREN))
    4330              :     {
    4331            0 :       skip_after_end_block ();
    4332            0 :       return nullptr;
    4333              :     }
    4334              : 
    4335              :   // parse return type (optional)
    4336         2738 :   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
    4337              : 
    4338              :   // parse where clause (optional)
    4339         2738 :   AST::WhereClause where_clause = parse_where_clause ();
    4340              : 
    4341         2738 :   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
    4342         5476 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    4343            2 :     lexer.skip_token ();
    4344              :   else
    4345              :     {
    4346         2736 :       auto result = parse_block_expr ();
    4347              : 
    4348         2736 :       if (!result)
    4349              :         {
    4350            0 :           Error error (
    4351            0 :             lexer.peek_token ()->get_locus (),
    4352              :             "could not parse definition in inherent impl %s definition",
    4353              :             is_method ? "method" : "function");
    4354            0 :           add_error (std::move (error));
    4355              : 
    4356            0 :           skip_after_end_block ();
    4357            0 :           return nullptr;
    4358            0 :         }
    4359         2736 :       body = std::move (result.value ());
    4360         2736 :     }
    4361              : 
    4362         2738 :   return std::unique_ptr<AST::Function> (
    4363        10950 :     new AST::Function (std::move (ident), std::move (qualifiers),
    4364              :                        std::move (generic_params), std::move (function_params),
    4365              :                        std::move (return_type), std::move (where_clause),
    4366              :                        std::move (body), std::move (vis),
    4367         2738 :                        std::move (outer_attrs), locus));
    4368         8227 : }
    4369              : 
    4370              : // Parses a single trait impl item (item inside a trait impl block).
    4371              : template <typename ManagedTokenSource>
    4372              : std::unique_ptr<AST::AssociatedItem>
    4373         5248 : Parser<ManagedTokenSource>::parse_trait_impl_item ()
    4374              : {
    4375              :   // parse outer attributes (if they exist)
    4376         5248 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4377              : 
    4378         5248 :   auto vis_res = parse_visibility ();
    4379         5248 :   if (!vis_res)
    4380            0 :     return nullptr;
    4381         5248 :   auto visibility = vis_res.value ();
    4382              : 
    4383              :   // branch on next token:
    4384         5248 :   const_TokenPtr t = lexer.peek_token ();
    4385         5248 :   switch (t->get_id ())
    4386              :     {
    4387            0 :     case SUPER:
    4388              :     case SELF:
    4389              :     case CRATE:
    4390              :     case DOLLAR_SIGN:
    4391              :       // these seem to be SimplePath tokens, so this is a macro invocation
    4392              :       // semi
    4393            0 :       return parse_macro_invocation_semi (std::move (outer_attrs));
    4394           55 :     case IDENTIFIER:
    4395          110 :       if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
    4396           48 :         return parse_trait_impl_function_or_method (visibility,
    4397           24 :                                                     std::move (outer_attrs));
    4398              :       else
    4399           62 :         return parse_macro_invocation_semi (std::move (outer_attrs));
    4400         1236 :     case TYPE:
    4401         2472 :       return parse_type_alias (visibility, std::move (outer_attrs));
    4402         3923 :     case EXTERN_KW:
    4403              :     case UNSAFE:
    4404              :     case FN_KW:
    4405              :       // function or method
    4406         7846 :       return parse_trait_impl_function_or_method (visibility,
    4407         3923 :                                                   std::move (outer_attrs));
    4408            1 :     case ASYNC:
    4409            2 :       return parse_async_item (visibility, std::move (outer_attrs));
    4410           33 :     case CONST:
    4411              :       // lookahead to resolve production - could be function/method or const
    4412              :       // item
    4413           33 :       t = lexer.peek_token (1);
    4414              : 
    4415           33 :       switch (t->get_id ())
    4416              :         {
    4417           32 :         case IDENTIFIER:
    4418              :         case UNDERSCORE:
    4419           64 :           return parse_const_item (visibility, std::move (outer_attrs));
    4420            1 :         case UNSAFE:
    4421              :         case EXTERN_KW:
    4422              :         case FN_KW:
    4423            2 :           return parse_trait_impl_function_or_method (visibility,
    4424            1 :                                                       std::move (outer_attrs));
    4425            0 :         default:
    4426            0 :           add_error (Error (
    4427              :             t->get_locus (),
    4428              :             "unexpected token %qs in some sort of const item in trait impl",
    4429              :             t->get_token_description ()));
    4430              : 
    4431            0 :           lexer.skip_token (1); // TODO: is this right thing to do?
    4432            0 :           return nullptr;
    4433              :         }
    4434              :       rust_unreachable ();
    4435              :     default:
    4436              :       break;
    4437              :     }
    4438            0 :   add_error (Error (t->get_locus (),
    4439              :                     "unrecognised token %qs for item in trait impl",
    4440              :                     t->get_token_description ()));
    4441              : 
    4442              :   // skip?
    4443            0 :   return nullptr;
    4444        10496 : }
    4445              : 
    4446              : /* For internal use only by parse_trait_impl_item() - splits giant method into
    4447              :  * smaller ones and prevents duplication of logic. Strictly, this parses a
    4448              :  * function or method item inside a trait impl item block. */
    4449              : template <typename ManagedTokenSource>
    4450              : std::unique_ptr<AST::AssociatedItem>
    4451         3948 : Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
    4452              :   AST::Visibility vis, AST::AttrVec outer_attrs)
    4453              : {
    4454              :   // this shares virtually all logic with
    4455              :   // parse_inherent_impl_function_or_method
    4456              :   // - template?
    4457         3948 :   location_t locus = lexer.peek_token ()->get_locus ();
    4458              : 
    4459         3948 :   auto is_default = false;
    4460         3948 :   auto t = lexer.peek_token ();
    4461         3948 :   if (t->get_id () == IDENTIFIER
    4462         3948 :       && t->get_str () == Values::WeakKeywords::DEFAULT)
    4463              :     {
    4464           24 :       is_default = true;
    4465           24 :       lexer.skip_token ();
    4466              :     }
    4467              : 
    4468              :   // parse function or method qualifiers
    4469         3948 :   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
    4470              : 
    4471         3948 :   skip_token (FN_KW);
    4472              : 
    4473              :   // parse function or method name
    4474         3948 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4475         3948 :   if (ident_tok == nullptr)
    4476              :     {
    4477            0 :       return nullptr;
    4478              :     }
    4479         3948 :   Identifier ident{ident_tok};
    4480              : 
    4481              :   // DEBUG:
    4482         3948 :   rust_debug (
    4483              :     "about to start parsing generic params in trait impl function or method");
    4484              : 
    4485              :   // parse generic params
    4486         3948 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    4487              :     = parse_generic_params_in_angles ();
    4488              : 
    4489              :   // DEBUG:
    4490         3948 :   rust_debug (
    4491              :     "finished parsing generic params in trait impl function or method");
    4492              : 
    4493         3948 :   if (!skip_token (LEFT_PAREN))
    4494              :     {
    4495              :       // skip after somewhere?
    4496            0 :       return nullptr;
    4497              :     }
    4498              : 
    4499              :   // now for function vs method disambiguation - method has opening "self"
    4500              :   // param
    4501         3948 :   auto initial_param = parse_self_param ();
    4502              : 
    4503         3948 :   if (!initial_param.has_value ()
    4504         3948 :       && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
    4505            0 :     return nullptr;
    4506              : 
    4507              :   // FIXME: ensure that self param doesn't accidently consume tokens for a
    4508              :   // function
    4509         3948 :   bool is_method = false;
    4510         3948 :   if (initial_param.has_value ())
    4511              :     {
    4512         3708 :       if ((*initial_param)->is_self ())
    4513              :         is_method = true;
    4514              : 
    4515              :       // skip comma so function and method regular params can be parsed in
    4516              :       // same way
    4517         7416 :       if (lexer.peek_token ()->get_id () == COMMA)
    4518              :         {
    4519         2001 :           lexer.skip_token ();
    4520              :         }
    4521              : 
    4522              :       // DEBUG
    4523         3708 :       rust_debug ("successfully parsed self param in method trait impl item");
    4524              :     }
    4525              : 
    4526              :   // DEBUG
    4527         3948 :   rust_debug (
    4528              :     "started to parse function params in function or method trait impl item");
    4529              : 
    4530              :   // parse trait function params (only if next token isn't right paren)
    4531         3948 :   std::vector<std::unique_ptr<AST::Param>> function_params;
    4532         7896 :   if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
    4533              :     {
    4534              :       function_params
    4535         2158 :         = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
    4536              : 
    4537         2158 :       if (function_params.empty ())
    4538              :         {
    4539            0 :           Error error (
    4540            0 :             lexer.peek_token ()->get_locus (),
    4541              :             "failed to parse function params in trait impl %s definition",
    4542              :             is_method ? "method" : "function");
    4543            0 :           add_error (std::move (error));
    4544              : 
    4545            0 :           skip_after_next_block ();
    4546            0 :           return nullptr;
    4547            0 :         }
    4548              :     }
    4549              : 
    4550         3948 :   if (initial_param.has_value ())
    4551         3708 :     function_params.insert (function_params.begin (),
    4552         3708 :                             std::move (*initial_param));
    4553              : 
    4554              :   // DEBUG
    4555         3948 :   rust_debug ("successfully parsed function params in function or method "
    4556              :               "trait impl item");
    4557              : 
    4558         3948 :   if (!skip_token (RIGHT_PAREN))
    4559              :     {
    4560            0 :       skip_after_next_block ();
    4561            0 :       return nullptr;
    4562              :     }
    4563              : 
    4564              :   // parse return type (optional)
    4565         3948 :   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
    4566              : 
    4567              :   // DEBUG
    4568         3948 :   rust_debug (
    4569              :     "successfully parsed return type in function or method trait impl item");
    4570              : 
    4571              :   // parse where clause (optional)
    4572         3948 :   AST::WhereClause where_clause = parse_where_clause ();
    4573              : 
    4574              :   // DEBUG
    4575         3948 :   rust_debug (
    4576              :     "successfully parsed where clause in function or method trait impl item");
    4577              : 
    4578              :   // parse function definition (in block) - semicolon not allowed
    4579         3948 :   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
    4580              : 
    4581         7896 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    4582            1 :     lexer.skip_token ();
    4583              :   else
    4584              :     {
    4585         3947 :       auto result = parse_block_expr ();
    4586         3947 :       if (!result)
    4587              :         {
    4588            1 :           Error error (lexer.peek_token ()->get_locus (),
    4589              :                        "could not parse definition in trait impl %s definition",
    4590              :                        is_method ? "method" : "function");
    4591            1 :           add_error (std::move (error));
    4592              : 
    4593            1 :           skip_after_end_block ();
    4594            1 :           return nullptr;
    4595            1 :         }
    4596         3946 :       body = std::move (result.value ());
    4597         3947 :     }
    4598              : 
    4599         3947 :   return std::unique_ptr<AST::Function> (
    4600        15787 :     new AST::Function (std::move (ident), std::move (qualifiers),
    4601              :                        std::move (generic_params), std::move (function_params),
    4602              :                        std::move (return_type), std::move (where_clause),
    4603              :                        std::move (body), std::move (vis),
    4604         3947 :                        std::move (outer_attrs), locus, is_default));
    4605        11844 : }
    4606              : 
    4607              : // Parses an extern block of declarations.
    4608              : template <typename ManagedTokenSource>
    4609              : std::unique_ptr<AST::ExternBlock>
    4610         1483 : Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
    4611              :                                                 AST::AttrVec outer_attrs)
    4612              : {
    4613         1483 :   location_t locus = lexer.peek_token ()->get_locus ();
    4614         1483 :   skip_token (EXTERN_KW);
    4615              : 
    4616              :   // detect optional abi name
    4617         1483 :   std::string abi;
    4618         1483 :   const_TokenPtr next_tok = lexer.peek_token ();
    4619         1483 :   if (next_tok->get_id () == STRING_LITERAL)
    4620              :     {
    4621         1483 :       lexer.skip_token ();
    4622         1483 :       abi = next_tok->get_str ();
    4623              :     }
    4624              : 
    4625         1483 :   if (!skip_token (LEFT_CURLY))
    4626              :     {
    4627            0 :       skip_after_end_block ();
    4628            0 :       return nullptr;
    4629              :     }
    4630              : 
    4631         1483 :   AST::AttrVec inner_attrs = parse_inner_attributes ();
    4632              : 
    4633              :   // parse declarations inside extern block
    4634         1483 :   std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
    4635              : 
    4636         1483 :   const_TokenPtr t = lexer.peek_token ();
    4637         3709 :   while (t->get_id () != RIGHT_CURLY)
    4638              :     {
    4639         2227 :       std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
    4640              : 
    4641         2227 :       if (extern_item == nullptr)
    4642              :         {
    4643            1 :           Error error (t->get_locus (),
    4644              :                        "failed to parse external item despite not reaching "
    4645              :                        "end of extern block");
    4646            1 :           add_error (std::move (error));
    4647              : 
    4648            1 :           return nullptr;
    4649            1 :         }
    4650              : 
    4651         2226 :       extern_items.push_back (std::move (extern_item));
    4652              : 
    4653         2226 :       t = lexer.peek_token ();
    4654              :     }
    4655              : 
    4656         1482 :   if (!skip_token (RIGHT_CURLY))
    4657              :     {
    4658              :       // skip somewhere
    4659            0 :       return nullptr;
    4660              :     }
    4661              : 
    4662         1482 :   extern_items.shrink_to_fit ();
    4663              : 
    4664              :   return std::unique_ptr<AST::ExternBlock> (
    4665         1482 :     new AST::ExternBlock (std::move (abi), std::move (extern_items),
    4666              :                           std::move (vis), std::move (inner_attrs),
    4667         1482 :                           std::move (outer_attrs), locus));
    4668         2966 : }
    4669              : 
    4670              : // Parses a single extern block item (static or function declaration).
    4671              : template <typename ManagedTokenSource>
    4672              : std::unique_ptr<AST::ExternalItem>
    4673         2230 : Parser<ManagedTokenSource>::parse_external_item ()
    4674              : {
    4675              :   // parse optional outer attributes
    4676         2230 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4677              : 
    4678         2230 :   location_t locus = lexer.peek_token ()->get_locus ();
    4679              : 
    4680              :   // parse optional visibility
    4681         2230 :   auto vis_res = parse_visibility ();
    4682         2230 :   if (!vis_res)
    4683            0 :     return nullptr;
    4684         2230 :   auto vis = vis_res.value ();
    4685              : 
    4686         2230 :   const_TokenPtr t = lexer.peek_token ();
    4687         2230 :   switch (t->get_id ())
    4688              :     {
    4689            2 :     case IDENTIFIER:
    4690            4 :       return parse_macro_invocation_semi (outer_attrs);
    4691            1 :     case STATIC_KW:
    4692              :       {
    4693              :         // parse extern static item
    4694            1 :         lexer.skip_token ();
    4695              : 
    4696              :         // parse mut (optional)
    4697            1 :         bool has_mut = false;
    4698            2 :         if (lexer.peek_token ()->get_id () == MUT)
    4699              :           {
    4700            0 :             lexer.skip_token ();
    4701            0 :             has_mut = true;
    4702              :           }
    4703              : 
    4704              :         // parse identifier
    4705            1 :         const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4706            1 :         if (ident_tok == nullptr)
    4707              :           {
    4708            0 :             skip_after_semicolon ();
    4709            0 :             return nullptr;
    4710              :           }
    4711            1 :         Identifier ident{ident_tok};
    4712              : 
    4713            1 :         if (!skip_token (COLON))
    4714              :           {
    4715            0 :             skip_after_semicolon ();
    4716            0 :             return nullptr;
    4717              :           }
    4718              : 
    4719              :         // parse type (required)
    4720            1 :         std::unique_ptr<AST::Type> type = parse_type ();
    4721            1 :         if (type == nullptr)
    4722              :           {
    4723            0 :             Error error (lexer.peek_token ()->get_locus (),
    4724              :                          "failed to parse type in external static item");
    4725            0 :             add_error (std::move (error));
    4726              : 
    4727            0 :             skip_after_semicolon ();
    4728            0 :             return nullptr;
    4729            0 :           }
    4730              : 
    4731            1 :         if (!skip_token (SEMICOLON))
    4732              :           {
    4733              :             // skip after somewhere?
    4734            0 :             return nullptr;
    4735              :           }
    4736              : 
    4737            1 :         return std::unique_ptr<AST::ExternalStaticItem> (
    4738            2 :           new AST::ExternalStaticItem (std::move (ident), std::move (type),
    4739              :                                        has_mut, std::move (vis),
    4740            1 :                                        std::move (outer_attrs), locus));
    4741            3 :       }
    4742         2223 :     case FN_KW:
    4743         4446 :       return parse_function (std::move (vis), std::move (outer_attrs), true);
    4744              : 
    4745            4 :     case TYPE:
    4746            4 :       return parse_external_type_item (std::move (vis),
    4747            4 :                                        std::move (outer_attrs));
    4748            0 :     default:
    4749              :       // error
    4750            0 :       add_error (
    4751            0 :         Error (t->get_locus (),
    4752              :                "unrecognised token %qs in extern block item declaration",
    4753              :                t->get_token_description ()));
    4754              : 
    4755            0 :       skip_after_semicolon ();
    4756            0 :       return nullptr;
    4757              :     }
    4758         4460 : }
    4759              : 
    4760              : // Parses a statement (will further disambiguate any statement).
    4761              : template <typename ManagedTokenSource>
    4762              : std::unique_ptr<AST::Stmt>
    4763          741 : Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
    4764              : {
    4765              :   // quick exit for empty statement
    4766              :   // FIXME: Can we have empty statements without semicolons? Just nothing?
    4767          741 :   const_TokenPtr t = lexer.peek_token ();
    4768          741 :   if (t->get_id () == SEMICOLON)
    4769              :     {
    4770           30 :       lexer.skip_token ();
    4771           30 :       return std::unique_ptr<AST::EmptyStmt> (
    4772           30 :         new AST::EmptyStmt (t->get_locus ()));
    4773              :     }
    4774              : 
    4775              :   // parse outer attributes
    4776          711 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4777              : 
    4778              :   // parsing this will be annoying because of the many different possibilities
    4779              :   /* best may be just to copy paste in parse_item switch, and failing that try
    4780              :    * to parse outer attributes, and then pass them in to either a let
    4781              :    * statement or (fallback) expression statement. */
    4782              :   // FIXME: think of a way to do this without such a large switch?
    4783          711 :   t = lexer.peek_token ();
    4784          711 :   switch (t->get_id ())
    4785              :     {
    4786          200 :     case LET:
    4787              :       // let statement
    4788          200 :       return parse_let_stmt (std::move (outer_attrs), restrictions);
    4789          186 :     case PUB:
    4790              :     case MOD:
    4791              :     case EXTERN_KW:
    4792              :     case USE:
    4793              :     case FN_KW:
    4794              :     case TYPE:
    4795              :     case STRUCT_KW:
    4796              :     case ENUM_KW:
    4797              :     case CONST:
    4798              :     case STATIC_KW:
    4799              :     case AUTO:
    4800              :     case TRAIT:
    4801              :     case IMPL:
    4802              :     case MACRO:
    4803              :     /* TODO: implement union keyword but not really because of
    4804              :      * context-dependence crappy hack way to parse a union written below to
    4805              :      * separate it from the good code. */
    4806              :     // case UNION:
    4807              :     case UNSAFE: // maybe - unsafe traits are a thing
    4808              :       /* if any of these (should be all possible VisItem prefixes), parse a
    4809              :        * VisItem can't parse item because would require reparsing outer
    4810              :        * attributes */
    4811              :       // may also be unsafe block
    4812          372 :       if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
    4813              :         {
    4814            1 :           return parse_expr_stmt (std::move (outer_attrs), restrictions);
    4815              :         }
    4816              :       else
    4817              :         {
    4818          185 :           return parse_vis_item (std::move (outer_attrs));
    4819              :         }
    4820              :       break;
    4821              :     // crappy hack to do union "keyword"
    4822          220 :     case IDENTIFIER:
    4823          220 :       if (t->get_str () == Values::WeakKeywords::UNION
    4824          220 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
    4825              :         {
    4826            0 :           return parse_vis_item (std::move (outer_attrs));
    4827              :           // or should this go straight to parsing union?
    4828              :         }
    4829          440 :       else if (is_macro_rules_def (t))
    4830              :         {
    4831              :           // macro_rules! macro item
    4832            2 :           return parse_macro_rules_def (std::move (outer_attrs));
    4833              :         }
    4834              :       gcc_fallthrough ();
    4835              :       // TODO: find out how to disable gcc "implicit fallthrough" warning
    4836              :     default:
    4837              :       // fallback: expression statement
    4838          323 :       return parse_expr_stmt (std::move (outer_attrs), restrictions);
    4839              :       break;
    4840              :     }
    4841          711 : }
    4842              : 
    4843              : // Parses a let statement.
    4844              : template <typename ManagedTokenSource>
    4845              : std::unique_ptr<AST::LetStmt>
    4846        12943 : Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
    4847              :                                             ParseRestrictions restrictions)
    4848              : {
    4849        12943 :   location_t locus = lexer.peek_token ()->get_locus ();
    4850        12943 :   skip_token (LET);
    4851              : 
    4852              :   // parse pattern (required)
    4853        12943 :   std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    4854        12943 :   if (pattern == nullptr)
    4855              :     {
    4856            0 :       Error error (lexer.peek_token ()->get_locus (),
    4857              :                    "failed to parse pattern in let statement");
    4858            0 :       add_error (std::move (error));
    4859              : 
    4860            0 :       skip_after_semicolon ();
    4861            0 :       return nullptr;
    4862            0 :     }
    4863              : 
    4864              :   // parse type declaration (optional)
    4865        12943 :   std::unique_ptr<AST::Type> type = nullptr;
    4866        25886 :   if (lexer.peek_token ()->get_id () == COLON)
    4867              :     {
    4868              :       // must have a type declaration
    4869         2029 :       lexer.skip_token ();
    4870              : 
    4871         2029 :       type = parse_type ();
    4872         2029 :       if (type == nullptr)
    4873              :         {
    4874            0 :           Error error (lexer.peek_token ()->get_locus (),
    4875              :                        "failed to parse type in let statement");
    4876            0 :           add_error (std::move (error));
    4877              : 
    4878            0 :           skip_after_semicolon ();
    4879            0 :           return nullptr;
    4880            0 :         }
    4881              :     }
    4882              : 
    4883              :   // parse expression to set variable to (optional)
    4884        12943 :   std::unique_ptr<AST::Expr> expr = nullptr;
    4885        25886 :   if (lexer.peek_token ()->get_id () == EQUAL)
    4886              :     {
    4887              :       // must have an expression
    4888        11890 :       lexer.skip_token ();
    4889              : 
    4890        11890 :       auto expr_res = parse_expr ();
    4891        11890 :       if (!expr_res)
    4892              :         {
    4893           22 :           skip_after_semicolon ();
    4894           22 :           return nullptr;
    4895              :         }
    4896        11868 :       expr = std::move (expr_res.value ());
    4897        11890 :     }
    4898              : 
    4899        12921 :   tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
    4900        12921 :   if (maybe_skip_token (ELSE))
    4901              :     {
    4902            5 :       auto block_expr = parse_block_expr ();
    4903            5 :       if (block_expr)
    4904              :         else_expr = tl::optional<std::unique_ptr<AST::Expr>>{
    4905           10 :           std::move (block_expr.value ())};
    4906              :       else
    4907              :         else_expr = tl::nullopt;
    4908            5 :     }
    4909              : 
    4910        12921 :   if (restrictions.consume_semi)
    4911              :     {
    4912              :       // `stmt` macro variables are parsed without a semicolon, but should be
    4913              :       // parsed as a full statement when interpolated. This should be handled
    4914              :       // by having the interpolated statement be distinguishable from normal
    4915              :       // tokens, e.g. by NT tokens.
    4916        12776 :       if (restrictions.allow_close_after_expr_stmt)
    4917           55 :         maybe_skip_token (SEMICOLON);
    4918        12721 :       else if (!skip_token (SEMICOLON))
    4919            1 :         return nullptr;
    4920              :     }
    4921              : 
    4922              :   return std::unique_ptr<AST::LetStmt> (
    4923        25845 :     new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
    4924        12920 :                       std::move (else_expr), std::move (outer_attrs), locus));
    4925        12943 : }
    4926              : 
    4927              : template <typename ManagedTokenSource>
    4928              : tl::optional<AST::GenericArg>
    4929         3843 : Parser<ManagedTokenSource>::parse_generic_arg ()
    4930              : {
    4931         3843 :   auto tok = lexer.peek_token ();
    4932         3843 :   std::unique_ptr<AST::Expr> expr = nullptr;
    4933              : 
    4934         3843 :   switch (tok->get_id ())
    4935              :     {
    4936         2476 :     case IDENTIFIER:
    4937              :       {
    4938              :         // This is a bit of a weird situation: With an identifier token, we
    4939              :         // could either have a valid type or a macro (FIXME: anything else?). So
    4940              :         // we need one bit of lookahead to differentiate if this is really
    4941         2476 :         auto next_tok = lexer.peek_token (1);
    4942         2476 :         if (next_tok->get_id () == LEFT_ANGLE
    4943         2465 :             || next_tok->get_id () == SCOPE_RESOLUTION
    4944         4938 :             || next_tok->get_id () == EXCLAM)
    4945              :           {
    4946           22 :             auto type = parse_type ();
    4947           22 :             if (type)
    4948           22 :               return AST::GenericArg::create_type (std::move (type));
    4949              :             else
    4950            0 :               return tl::nullopt;
    4951           22 :           }
    4952         2454 :         else if (next_tok->get_id () == COLON)
    4953              :           {
    4954            1 :             lexer.skip_token (); // skip ident
    4955            1 :             lexer.skip_token (); // skip colon
    4956              : 
    4957            1 :             auto tok = lexer.peek_token ();
    4958            1 :             std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    4959              :               = parse_type_param_bounds ();
    4960              : 
    4961            1 :             auto type = std::unique_ptr<AST::TraitObjectType> (
    4962            1 :               new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
    4963              :                                         false));
    4964            1 :             if (type)
    4965            1 :               return AST::GenericArg::create_type (std::move (type));
    4966              :             else
    4967              :               return tl::nullopt;
    4968            2 :           }
    4969         2453 :         lexer.skip_token ();
    4970         9812 :         return AST::GenericArg::create_ambiguous (tok->get_str (),
    4971         2453 :                                                   tok->get_locus ());
    4972         2476 :       }
    4973           19 :     case LEFT_CURLY:
    4974              :       {
    4975           19 :         auto res = parse_block_expr ();
    4976           19 :         if (res)
    4977           19 :           expr = std::move (res.value ());
    4978              :         else
    4979            0 :           return tl::nullopt;
    4980           19 :       }
    4981              :       break;
    4982           91 :     case MINUS:
    4983              :     case STRING_LITERAL:
    4984              :     case CHAR_LITERAL:
    4985              :     case INT_LITERAL:
    4986              :     case FLOAT_LITERAL:
    4987              :     case TRUE_LITERAL:
    4988              :     case FALSE_LITERAL:
    4989              :       {
    4990           91 :         auto res = parse_literal_expr ();
    4991           91 :         if (res)
    4992           91 :           expr = std::move (res.value ());
    4993              :         else
    4994            0 :           return tl::nullopt;
    4995           91 :       }
    4996              :       break;
    4997              :     // FIXME: Because of this, error reporting is garbage for const generic
    4998              :     // parameter's default values
    4999         1257 :     default:
    5000              :       {
    5001         1257 :         auto type = parse_type ();
    5002              :         // FIXME: Find a better way to do this?
    5003         1257 :         if (type)
    5004         1256 :           return AST::GenericArg::create_type (std::move (type));
    5005              :         else
    5006            1 :           return tl::nullopt;
    5007         1257 :       }
    5008              :     }
    5009              : 
    5010          110 :   if (!expr)
    5011            0 :     return tl::nullopt;
    5012              : 
    5013          110 :   return AST::GenericArg::create_const (std::move (expr));
    5014         3843 : }
    5015              : 
    5016              : // Parses the generic arguments in each path segment.
    5017              : template <typename ManagedTokenSource>
    5018              : AST::GenericArgs
    5019         3643 : Parser<ManagedTokenSource>::parse_path_generic_args ()
    5020              : {
    5021         7286 :   if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
    5022            5 :     lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
    5023              : 
    5024         3643 :   if (!skip_token (LEFT_ANGLE))
    5025              :     {
    5026              :       // skip after somewhere?
    5027            0 :       return AST::GenericArgs::create_empty ();
    5028              :     }
    5029              : 
    5030              :   // We need to parse all lifetimes, then parse types and const generics in
    5031              :   // any order.
    5032              : 
    5033              :   // try to parse lifetimes first
    5034         3643 :   std::vector<AST::Lifetime> lifetime_args;
    5035              : 
    5036         3643 :   const_TokenPtr t = lexer.peek_token ();
    5037         3643 :   location_t locus = t->get_locus ();
    5038         7292 :   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
    5039              :     {
    5040         3649 :       auto lifetime = parse_lifetime (false);
    5041         3649 :       if (!lifetime)
    5042              :         {
    5043              :           // not necessarily an error
    5044              :           break;
    5045              :         }
    5046              : 
    5047           41 :       lifetime_args.push_back (std::move (lifetime.value ()));
    5048              : 
    5049              :       // if next token isn't comma, then it must be end of list
    5050           82 :       if (lexer.peek_token ()->get_id () != COMMA)
    5051              :         {
    5052              :           break;
    5053              :         }
    5054              :       // skip comma
    5055            7 :       lexer.skip_token ();
    5056              : 
    5057            7 :       t = lexer.peek_token ();
    5058              :     }
    5059              : 
    5060              :   // try to parse types and const generics second
    5061         3643 :   std::vector<AST::GenericArg> generic_args;
    5062              : 
    5063              :   // TODO: think of better control structure
    5064         3643 :   t = lexer.peek_token ();
    5065        11074 :   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
    5066              :     {
    5067              :       // FIXME: Is it fine to break if there is one binding? Can't there be
    5068              :       // bindings in between types?
    5069              : 
    5070              :       // ensure not binding being parsed as type accidently
    5071         6213 :       if (t->get_id () == IDENTIFIER
    5072         6442 :           && lexer.peek_token (1)->get_id () == EQUAL)
    5073              :         break;
    5074              : 
    5075         3823 :       auto arg = parse_generic_arg ();
    5076         3823 :       if (arg)
    5077              :         {
    5078         3823 :           generic_args.emplace_back (std::move (arg.value ()));
    5079              :         }
    5080              : 
    5081              :       // FIXME: Do we need to break if we encounter an error?
    5082              : 
    5083              :       // if next token isn't comma, then it must be end of list
    5084         7646 :       if (lexer.peek_token ()->get_id () != COMMA)
    5085              :         break;
    5086              : 
    5087              :       // skip comma
    5088          287 :       lexer.skip_token ();
    5089          287 :       t = lexer.peek_token ();
    5090              :     }
    5091              : 
    5092              :   // try to parse bindings third
    5093         3643 :   std::vector<AST::GenericArgsBinding> binding_args;
    5094              : 
    5095              :   // TODO: think of better control structure
    5096         3643 :   t = lexer.peek_token ();
    5097         3716 :   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
    5098              :     {
    5099           73 :       AST::GenericArgsBinding binding = parse_generic_args_binding ();
    5100           73 :       if (binding.is_error ())
    5101              :         {
    5102              :           // not necessarily an error
    5103              :           break;
    5104              :         }
    5105              : 
    5106           73 :       binding_args.push_back (std::move (binding));
    5107              : 
    5108              :       // if next token isn't comma, then it must be end of list
    5109          146 :       if (lexer.peek_token ()->get_id () != COMMA)
    5110              :         {
    5111              :           break;
    5112              :         }
    5113              :       // skip comma
    5114            1 :       lexer.skip_token ();
    5115              : 
    5116            1 :       t = lexer.peek_token ();
    5117              :     }
    5118              : 
    5119              :   // skip any trailing commas
    5120         7286 :   if (lexer.peek_token ()->get_id () == COMMA)
    5121            0 :     lexer.skip_token ();
    5122              : 
    5123         3643 :   if (!skip_generics_right_angle ())
    5124            0 :     return AST::GenericArgs::create_empty ();
    5125              : 
    5126         3643 :   lifetime_args.shrink_to_fit ();
    5127         3643 :   generic_args.shrink_to_fit ();
    5128         3643 :   binding_args.shrink_to_fit ();
    5129              : 
    5130         3643 :   return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
    5131         3643 :                            std::move (binding_args), locus);
    5132         7286 : }
    5133              : 
    5134              : // Parses a binding in a generic args path segment.
    5135              : template <typename ManagedTokenSource>
    5136              : AST::GenericArgsBinding
    5137           73 : Parser<ManagedTokenSource>::parse_generic_args_binding ()
    5138              : {
    5139           73 :   const_TokenPtr ident_tok = lexer.peek_token ();
    5140           73 :   if (ident_tok->get_id () != IDENTIFIER)
    5141              :     {
    5142              :       // allow non error-inducing use
    5143              :       // skip somewhere?
    5144            0 :       return AST::GenericArgsBinding::create_error ();
    5145              :     }
    5146           73 :   lexer.skip_token ();
    5147           73 :   Identifier ident{ident_tok};
    5148              : 
    5149           73 :   if (!skip_token (EQUAL))
    5150              :     {
    5151              :       // skip after somewhere?
    5152            0 :       return AST::GenericArgsBinding::create_error ();
    5153              :     }
    5154              : 
    5155              :   // parse type (required)
    5156           73 :   std::unique_ptr<AST::Type> type = parse_type ();
    5157           73 :   if (type == nullptr)
    5158              :     {
    5159              :       // skip somewhere?
    5160            0 :       return AST::GenericArgsBinding::create_error ();
    5161              :     }
    5162              : 
    5163          146 :   return AST::GenericArgsBinding (std::move (ident), std::move (type),
    5164          146 :                                   ident_tok->get_locus ());
    5165          146 : }
    5166              : 
    5167              : // Parses a self param. Also handles self param not existing.
    5168              : template <typename ManagedTokenSource>
    5169              : tl::expected<std::unique_ptr<AST::Param>, Parse::Error::Self>
    5170        18160 : Parser<ManagedTokenSource>::parse_self_param ()
    5171              : {
    5172        18160 :   bool has_reference = false;
    5173        18160 :   AST::Lifetime lifetime = AST::Lifetime::elided ();
    5174              : 
    5175        18160 :   location_t locus = lexer.peek_token ()->get_locus ();
    5176              : 
    5177              :   // TODO: Feels off, find a better way to clearly express this
    5178        72640 :   std::vector<std::vector<TokenId>> ptrs
    5179              :     = {{ASTERISK, SELF} /* *self */,
    5180              :        {ASTERISK, CONST, SELF} /* *const self */,
    5181              :        {ASTERISK, MUT, SELF} /* *mut self */};
    5182              : 
    5183        72634 :   for (auto &s : ptrs)
    5184              :     {
    5185              :       size_t i = 0;
    5186        54488 :       for (i = 0; i < s.size (); i++)
    5187       108970 :         if (lexer.peek_token (i)->get_id () != s[i])
    5188              :           break;
    5189        54477 :       if (i == s.size ())
    5190              :         {
    5191            3 :           Error error (lexer.peek_token ()->get_locus (),
    5192              :                        "cannot pass %<self%> by raw pointer");
    5193            3 :           add_error (std::move (error));
    5194            3 :           return Parse::Error::Self::make_self_raw_pointer ();
    5195            3 :         }
    5196              :     }
    5197              : 
    5198              :   // Trying to find those patterns:
    5199              :   //
    5200              :   // &'lifetime mut self
    5201              :   // &'lifetime self
    5202              :   // & mut self
    5203              :   // & self
    5204              :   // mut self
    5205              :   // self
    5206              :   //
    5207              :   // If not found, it is probably a function, exit and let function parsing
    5208              :   // handle it.
    5209              :   bool is_self = false;
    5210       108942 :   for (size_t i = 0; i < 5; i++)
    5211       181570 :     if (lexer.peek_token (i)->get_id () == SELF)
    5212         7807 :       is_self = true;
    5213              : 
    5214        18157 :   if (!is_self)
    5215              :     return Parse::Error::Self::make_not_self ();
    5216              : 
    5217              :   // test if self is a reference parameter
    5218        15608 :   if (lexer.peek_token ()->get_id () == AMP)
    5219              :     {
    5220         4638 :       has_reference = true;
    5221         4638 :       lexer.skip_token ();
    5222              : 
    5223              :       // now test whether it has a lifetime
    5224         9276 :       if (lexer.peek_token ()->get_id () == LIFETIME)
    5225              :         {
    5226              :           // something went wrong somehow
    5227            4 :           if (auto parsed_lifetime = parse_lifetime (true))
    5228              :             {
    5229            2 :               lifetime = parsed_lifetime.value ();
    5230              :             }
    5231              :           else
    5232              :             {
    5233            0 :               Error error (lexer.peek_token ()->get_locus (),
    5234              :                            "failed to parse lifetime in self param");
    5235            0 :               add_error (std::move (error));
    5236              : 
    5237              :               // skip after somewhere?
    5238            0 :               return Parse::Error::Self::make_parsing_error ();
    5239            0 :             }
    5240              :         }
    5241              :     }
    5242              : 
    5243              :   // test for mut
    5244         7804 :   bool has_mut = false;
    5245        15608 :   if (lexer.peek_token ()->get_id () == MUT)
    5246              :     {
    5247          348 :       has_mut = true;
    5248          348 :       lexer.skip_token ();
    5249              :     }
    5250              : 
    5251              :   // skip self token
    5252         7804 :   const_TokenPtr self_tok = lexer.peek_token ();
    5253         7804 :   if (self_tok->get_id () != SELF)
    5254              :     {
    5255              :       // skip after somewhere?
    5256              :       return Parse::Error::Self::make_not_self ();
    5257              :     }
    5258         7802 :   lexer.skip_token ();
    5259              : 
    5260              :   // parse optional type
    5261         7802 :   std::unique_ptr<AST::Type> type = nullptr;
    5262        15604 :   if (lexer.peek_token ()->get_id () == COLON)
    5263              :     {
    5264            1 :       lexer.skip_token ();
    5265              : 
    5266              :       // type is now required
    5267            1 :       type = parse_type ();
    5268            1 :       if (type == nullptr)
    5269              :         {
    5270            0 :           Error error (lexer.peek_token ()->get_locus (),
    5271              :                        "could not parse type in self param");
    5272            0 :           add_error (std::move (error));
    5273              : 
    5274              :           // skip after somewhere?
    5275            0 :           return Parse::Error::Self::make_parsing_error ();
    5276            0 :         }
    5277              :     }
    5278              : 
    5279              :   // ensure that cannot have both type and reference
    5280         7802 :   if (type && has_reference)
    5281              :     {
    5282            0 :       Error error (
    5283            0 :         lexer.peek_token ()->get_locus (),
    5284              :         "cannot have both a reference and a type specified in a self param");
    5285            0 :       add_error (std::move (error));
    5286              : 
    5287              :       // skip after somewhere?
    5288            0 :       return Parse::Error::Self::make_parsing_error ();
    5289            0 :     }
    5290              : 
    5291         7802 :   if (has_reference)
    5292              :     {
    5293         4638 :       return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
    5294         4638 :                                                locus);
    5295              :     }
    5296              :   else
    5297              :     {
    5298              :       // note that type may be nullptr here and that's fine
    5299         3164 :       return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
    5300         3164 :                                                locus);
    5301              :     }
    5302        25962 : }
    5303              : 
    5304              : /* Parses an expression or macro statement. */
    5305              : template <typename ManagedTokenSource>
    5306              : std::unique_ptr<AST::Stmt>
    5307          324 : Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
    5308              :                                              ParseRestrictions restrictions)
    5309              : {
    5310          324 :   location_t locus = lexer.peek_token ()->get_locus ();
    5311              : 
    5312          324 :   tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
    5313              : 
    5314          648 :   switch (lexer.peek_token ()->get_id ())
    5315              :     {
    5316          220 :     case IDENTIFIER:
    5317              :     case CRATE:
    5318              :     case SUPER:
    5319              :     case SELF:
    5320              :     case SELF_ALIAS:
    5321              :     case DOLLAR_SIGN:
    5322              :     case SCOPE_RESOLUTION:
    5323              :       {
    5324          220 :         AST::PathInExpression path = parse_path_in_expression ();
    5325              :         tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
    5326          220 :           null_denotation;
    5327              : 
    5328          440 :         if (lexer.peek_token ()->get_id () == EXCLAM)
    5329              :           {
    5330           61 :             std::unique_ptr<AST::MacroInvocation> invoc
    5331          122 :               = parse_macro_invocation_partial (std::move (path),
    5332              :                                                 std::move (outer_attrs));
    5333              : 
    5334           61 :             if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
    5335              :               {
    5336           59 :                 invoc->add_semicolon ();
    5337              :                 // Macro invocation with semicolon.
    5338           59 :                 return invoc;
    5339              :               }
    5340              : 
    5341            2 :             TokenId after_macro = lexer.peek_token ()->get_id ();
    5342              : 
    5343            2 :             if (restrictions.allow_close_after_expr_stmt
    5344            2 :                 && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
    5345              :                     || after_macro == RIGHT_SQUARE))
    5346            2 :               return invoc;
    5347              : 
    5348            0 :             if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
    5349              :                   == AST::CURLY
    5350            0 :                 && after_macro != DOT && after_macro != QUESTION_MARK)
    5351              :               {
    5352            0 :                 rust_debug ("braced macro statement");
    5353            0 :                 return invoc;
    5354              :               }
    5355              : 
    5356            0 :             null_denotation = std::move (invoc);
    5357           61 :           }
    5358              :         else
    5359              :           {
    5360              :             null_denotation
    5361          318 :               = null_denotation_path (std::move (path), {}, restrictions);
    5362              :           }
    5363              : 
    5364          636 :         expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
    5365              :                                  std::move (outer_attrs), restrictions);
    5366              :         break;
    5367          220 :       }
    5368          104 :     default:
    5369          104 :       restrictions.expr_can_be_stmt = true;
    5370          208 :       expr = parse_expr (std::move (outer_attrs), restrictions);
    5371          104 :       break;
    5372              :     }
    5373              : 
    5374          263 :   if (!expr)
    5375              :     {
    5376              :       // expr is required, error
    5377            0 :       Error error (lexer.peek_token ()->get_locus (),
    5378              :                    "failed to parse expr in expr statement");
    5379            0 :       add_error (std::move (error));
    5380              : 
    5381            0 :       skip_after_semicolon ();
    5382            0 :       return nullptr;
    5383            0 :     }
    5384              : 
    5385          263 :   bool has_semi = false;
    5386              : 
    5387          263 :   if (restrictions.consume_semi)
    5388              :     {
    5389          249 :       if (maybe_skip_token (SEMICOLON))
    5390              :         {
    5391          138 :           has_semi = true;
    5392              :         }
    5393          111 :       else if (expr.value ()->is_expr_without_block ())
    5394              :         {
    5395           10 :           if (restrictions.allow_close_after_expr_stmt)
    5396              :             {
    5397           10 :               TokenId id = lexer.peek_token ()->get_id ();
    5398           10 :               if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
    5399              :                 {
    5400            3 :                   expect_token (SEMICOLON);
    5401            3 :                   return nullptr;
    5402              :                 }
    5403              :             }
    5404              :           else
    5405              :             {
    5406            0 :               expect_token (SEMICOLON);
    5407            0 :               return nullptr;
    5408              :             }
    5409              :         }
    5410              :     }
    5411              : 
    5412          260 :   return std::make_unique<AST::ExprStmt> (std::move (expr.value ()), locus,
    5413          260 :                                           has_semi);
    5414          324 : }
    5415              : 
    5416              : // Parses a loop label used in loop expressions.
    5417              : template <typename ManagedTokenSource>
    5418              : tl::expected<AST::LoopLabel, Parse::Error::LoopLabel>
    5419           40 : Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
    5420              : {
    5421              :   // parse lifetime - if doesn't exist, assume no label
    5422           40 :   if (tok->get_id () != LIFETIME)
    5423              :     {
    5424              :       // not necessarily an error
    5425              :       return Parse::Error::LoopLabel::make_not_loop_label ();
    5426              :     }
    5427              :   /* FIXME: check for named lifetime requirement here? or check in semantic
    5428              :    * analysis phase? */
    5429           40 :   AST::Lifetime label = lifetime_from_token (tok);
    5430              : 
    5431           40 :   if (!skip_token (COLON))
    5432              :     {
    5433              :       // skip somewhere?
    5434           40 :       Parse::Error::LoopLabel::make_missing_colon ();
    5435              :     }
    5436              : 
    5437              :   return tl::expected<AST::LoopLabel, Parse::Error::LoopLabel> (
    5438           40 :     AST::LoopLabel (std::move (label), tok->get_locus ()));
    5439           40 : }
    5440              : 
    5441              : // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
    5442              : template <typename ManagedTokenSource>
    5443              : AST::MatchArm
    5444         2138 : Parser<ManagedTokenSource>::parse_match_arm ()
    5445              : {
    5446              :   // parse optional outer attributes
    5447         2138 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    5448              : 
    5449              :   // DEBUG
    5450         2138 :   rust_debug ("about to start parsing match arm patterns");
    5451              : 
    5452              :   // break early if find right curly
    5453         4276 :   if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
    5454              :     {
    5455              :       // not an error
    5456            0 :       return AST::MatchArm::create_error ();
    5457              :     }
    5458              : 
    5459              :   // parse match arm patterns - at least 1 is required
    5460         2138 :   std::unique_ptr<AST::Pattern> match_arm_pattern
    5461              :     = parse_match_arm_pattern (RIGHT_CURLY);
    5462         2138 :   if (match_arm_pattern == nullptr)
    5463              :     {
    5464            0 :       Error error (lexer.peek_token ()->get_locus (),
    5465              :                    "failed to parse any patterns in match arm");
    5466            0 :       add_error (std::move (error));
    5467              : 
    5468              :       // skip somewhere?
    5469            0 :       return AST::MatchArm::create_error ();
    5470            0 :     }
    5471              : 
    5472              :   // DEBUG
    5473         2138 :   rust_debug ("successfully parsed match arm patterns");
    5474              : 
    5475              :   // parse match arm guard expr if it exists
    5476         2138 :   std::unique_ptr<AST::Expr> guard_expr = nullptr;
    5477         4276 :   if (lexer.peek_token ()->get_id () == IF)
    5478              :     {
    5479            1 :       lexer.skip_token ();
    5480              : 
    5481            1 :       auto guard_expr_res = parse_expr ();
    5482            1 :       if (!guard_expr_res)
    5483              :         {
    5484            0 :           Error error (lexer.peek_token ()->get_locus (),
    5485              :                        "failed to parse guard expression in match arm");
    5486            0 :           add_error (std::move (error));
    5487              : 
    5488              :           // skip somewhere?
    5489            0 :           return AST::MatchArm::create_error ();
    5490            0 :         }
    5491            1 :       guard_expr = std::move (guard_expr_res.value ());
    5492            1 :     }
    5493              : 
    5494              :   // DEBUG
    5495         2138 :   rust_debug ("successfully parsed match arm");
    5496              : 
    5497         4276 :   return AST::MatchArm (std::move (match_arm_pattern),
    5498         4276 :                         lexer.peek_token ()->get_locus (),
    5499         2138 :                         std::move (guard_expr), std::move (outer_attrs));
    5500         2138 : }
    5501              : 
    5502              : /* Parses the patterns used in a match arm. End token id is the id of the
    5503              :  * token that would exist after the patterns are done (e.g. '}' for match
    5504              :  * expr, '=' for if let and while let). */
    5505              : template <typename ManagedTokenSource>
    5506              : std::unique_ptr<AST::Pattern>
    5507         2173 : Parser<ManagedTokenSource>::parse_match_arm_pattern (TokenId end_token_id)
    5508              : {
    5509              :   // skip optional leading '|'
    5510         4346 :   if (lexer.peek_token ()->get_id () == PIPE)
    5511            0 :     lexer.skip_token ();
    5512              :   /* TODO: do I even need to store the result of this? can't be used.
    5513              :    * If semantically different, I need a wrapped "match arm patterns" object
    5514              :    * for this. */
    5515              : 
    5516         2173 :   std::unique_ptr<AST::Pattern> pattern;
    5517              : 
    5518              :   // quick break out if end_token_id
    5519         4346 :   if (lexer.peek_token ()->get_id () == end_token_id)
    5520            1 :     return pattern;
    5521              : 
    5522              :   // parse required pattern - if doesn't exist, return empty
    5523         2172 :   std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
    5524         2172 :   if (initial_pattern == nullptr)
    5525              :     {
    5526              :       // FIXME: should this be an error?
    5527            0 :       return pattern;
    5528              :     }
    5529              : 
    5530         2172 :   return initial_pattern;
    5531         2173 : }
    5532              : 
    5533              : // Parses a single parameter used in a closure definition.
    5534              : template <typename ManagedTokenSource>
    5535              : AST::ClosureParam
    5536           72 : Parser<ManagedTokenSource>::parse_closure_param ()
    5537              : {
    5538           72 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    5539              : 
    5540              :   // parse pattern (which is required)
    5541           72 :   std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
    5542           72 :   if (pattern == nullptr)
    5543              :     {
    5544              :       // not necessarily an error
    5545            0 :       return AST::ClosureParam::create_error ();
    5546              :     }
    5547              : 
    5548              :   // parse optional type of param
    5549           72 :   std::unique_ptr<AST::Type> type = nullptr;
    5550          144 :   if (lexer.peek_token ()->get_id () == COLON)
    5551              :     {
    5552           63 :       lexer.skip_token ();
    5553              : 
    5554              :       // parse type, which is now required
    5555           63 :       type = parse_type ();
    5556           63 :       if (type == nullptr)
    5557              :         {
    5558            0 :           Error error (lexer.peek_token ()->get_locus (),
    5559              :                        "failed to parse type in closure parameter");
    5560            0 :           add_error (std::move (error));
    5561              : 
    5562              :           // skip somewhere?
    5563            0 :           return AST::ClosureParam::create_error ();
    5564            0 :         }
    5565              :     }
    5566              : 
    5567           72 :   location_t loc = pattern->get_locus ();
    5568           72 :   return AST::ClosureParam (std::move (pattern), loc, std::move (type),
    5569           72 :                             std::move (outer_attrs));
    5570           72 : }
    5571              : 
    5572              : // Parses a type (will further disambiguate any type).
    5573              : template <typename ManagedTokenSource>
    5574              : std::unique_ptr<AST::Type>
    5575        43414 : Parser<ManagedTokenSource>::parse_type (bool save_errors)
    5576              : {
    5577              :   /* rules for all types:
    5578              :    * NeverType:               '!'
    5579              :    * SliceType:               '[' Type ']'
    5580              :    * InferredType:            '_'
    5581              :    * MacroInvocation:         SimplePath '!' DelimTokenTree
    5582              :    * ParenthesisedType:       '(' Type ')'
    5583              :    * ImplTraitType:           'impl' TypeParamBounds
    5584              :    *  TypeParamBounds (not type)  TypeParamBound ( '+' TypeParamBound )* '+'?
    5585              :    *  TypeParamBound          Lifetime | TraitBound
    5586              :    * ImplTraitTypeOneBound:   'impl' TraitBound
    5587              :    * TraitObjectType:         'dyn'? TypeParamBounds
    5588              :    * TraitObjectTypeOneBound: 'dyn'? TraitBound
    5589              :    *  TraitBound              '?'? ForLifetimes? TypePath | '(' '?'?
    5590              :    * ForLifetimes? TypePath ')' BareFunctionType:        ForLifetimes?
    5591              :    * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
    5592              :    * LifetimeParams '>' FunctionQualifiers      ( 'async' | 'const' )?
    5593              :    * 'unsafe'?
    5594              :    * ('extern' abi?)? QualifiedPathInType:     '<' Type ( 'as' TypePath )? '>'
    5595              :    * (
    5596              :    * '::' TypePathSegment )+ TypePath:                '::'? TypePathSegment (
    5597              :    * '::' TypePathSegment)* ArrayType:               '[' Type ';' Expr ']'
    5598              :    * ReferenceType:           '&' Lifetime? 'mut'? TypeNoBounds
    5599              :    * RawPointerType:          '*' ( 'mut' | 'const' ) TypeNoBounds
    5600              :    * TupleType:               '(' Type etc. - regular tuple stuff. Also
    5601              :    * regular tuple vs parenthesised precedence
    5602              :    *
    5603              :    * Disambiguate between macro and type path via type path being parsed, and
    5604              :    * then if '!' found, convert type path to simple path for macro. Usual
    5605              :    * disambiguation for tuple vs parenthesised. For ImplTraitType and
    5606              :    * TraitObjectType individual disambiguations, they seem more like "special
    5607              :    * cases", so probably just try to parse the more general ImplTraitType or
    5608              :    * TraitObjectType and return OneBound versions if they satisfy those
    5609              :    * criteria. */
    5610              : 
    5611        43414 :   const_TokenPtr t = lexer.peek_token ();
    5612        43414 :   switch (t->get_id ())
    5613              :     {
    5614           47 :     case EXCLAM:
    5615              :       // never type - can't be macro as no path beforehand
    5616           47 :       lexer.skip_token ();
    5617           47 :       return std::unique_ptr<AST::NeverType> (
    5618           47 :         new AST::NeverType (t->get_locus ()));
    5619          858 :     case LEFT_SQUARE:
    5620              :       // slice type or array type - requires further disambiguation
    5621          858 :       return parse_slice_or_array_type ();
    5622          309 :     case LEFT_SHIFT:
    5623              :     case LEFT_ANGLE:
    5624              :       {
    5625              :         // qualified path in type
    5626          309 :         AST::QualifiedPathInType path = parse_qualified_path_in_type ();
    5627          309 :         if (path.is_error ())
    5628              :           {
    5629            0 :             if (save_errors)
    5630              :               {
    5631            0 :                 Error error (t->get_locus (),
    5632              :                              "failed to parse qualified path in type");
    5633            0 :                 add_error (std::move (error));
    5634            0 :               }
    5635              : 
    5636            0 :             return nullptr;
    5637              :           }
    5638          309 :         return std::unique_ptr<AST::QualifiedPathInType> (
    5639          309 :           new AST::QualifiedPathInType (std::move (path)));
    5640          309 :       }
    5641          104 :     case UNDERSCORE:
    5642              :       // inferred type
    5643          104 :       lexer.skip_token ();
    5644          104 :       return std::unique_ptr<AST::InferredType> (
    5645          104 :         new AST::InferredType (t->get_locus ()));
    5646         2728 :     case ASTERISK:
    5647              :       // raw pointer type
    5648         2728 :       return parse_raw_pointer_type ();
    5649         4290 :     case AMP: // does this also include AMP_AMP?
    5650              :     case LOGICAL_AND:
    5651              :       // reference type
    5652         4290 :       return parse_reference_type ();
    5653            0 :     case LIFETIME:
    5654              :       {
    5655              :         /* probably a lifetime bound, so probably type param bounds in
    5656              :          * TraitObjectType */
    5657            0 :         std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    5658              :           = parse_type_param_bounds ();
    5659              : 
    5660            0 :         return std::unique_ptr<AST::TraitObjectType> (
    5661            0 :           new AST::TraitObjectType (std::move (bounds), t->get_locus (),
    5662            0 :                                     false));
    5663            0 :       }
    5664        34461 :     case IDENTIFIER:
    5665              :     case SUPER:
    5666              :     case SELF:
    5667              :     case SELF_ALIAS:
    5668              :     case CRATE:
    5669              :     case DOLLAR_SIGN:
    5670              :     case SCOPE_RESOLUTION:
    5671              :       {
    5672              :         // macro invocation or type path - requires further disambiguation.
    5673              :         /* for parsing path component of each rule, perhaps parse it as a
    5674              :          * typepath and attempt conversion to simplepath if a trailing '!' is
    5675              :          * found */
    5676              :         /* Type path also includes TraitObjectTypeOneBound BUT if it starts
    5677              :          * with it, it is exactly the same as a TypePath syntactically, so
    5678              :          * this is a syntactical ambiguity. As such, the parser will parse it
    5679              :          * as a TypePath. This, however, does not prevent TraitObjectType from
    5680              :          * starting with a typepath. */
    5681              : 
    5682              :         // parse path as type path
    5683        34461 :         AST::TypePath path = parse_type_path ();
    5684        34461 :         if (path.is_error ())
    5685              :           {
    5686            0 :             if (save_errors)
    5687              :               {
    5688            0 :                 Error error (t->get_locus (),
    5689              :                              "failed to parse path as first component of type");
    5690            0 :                 add_error (std::move (error));
    5691            0 :               }
    5692              : 
    5693            0 :             return nullptr;
    5694              :           }
    5695        34461 :         location_t locus = path.get_locus ();
    5696              : 
    5697              :         // branch on next token
    5698        34461 :         t = lexer.peek_token ();
    5699        34461 :         switch (t->get_id ())
    5700              :           {
    5701           29 :           case EXCLAM:
    5702              :             {
    5703              :               // macro invocation
    5704              :               // convert to simple path
    5705           29 :               AST::SimplePath macro_path = path.as_simple_path ();
    5706           29 :               if (macro_path.is_empty ())
    5707              :                 {
    5708            0 :                   if (save_errors)
    5709              :                     {
    5710            0 :                       Error error (t->get_locus (),
    5711              :                                    "failed to parse simple path in macro "
    5712              :                                    "invocation (for type)");
    5713            0 :                       add_error (std::move (error));
    5714            0 :                     }
    5715              : 
    5716            0 :                   return nullptr;
    5717              :                 }
    5718              : 
    5719           29 :               lexer.skip_token ();
    5720              : 
    5721           29 :               auto tok_tree = parse_delim_token_tree ();
    5722           29 :               if (!tok_tree)
    5723            0 :                 return nullptr;
    5724              : 
    5725           87 :               return AST::MacroInvocation::Regular (
    5726           58 :                 AST::MacroInvocData (std::move (macro_path),
    5727           29 :                                      std::move (tok_tree.value ())),
    5728           29 :                 {}, locus);
    5729           58 :             }
    5730            0 :           case PLUS:
    5731              :             {
    5732              :               // type param bounds
    5733            0 :               std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    5734              : 
    5735              :               // convert type path to trait bound
    5736            0 :               std::unique_ptr<AST::TraitBound> path_bound (
    5737            0 :                 new AST::TraitBound (std::move (path), locus, false, false));
    5738            0 :               bounds.push_back (std::move (path_bound));
    5739              : 
    5740              :               /* parse rest of bounds - FIXME: better way to find when to stop
    5741              :                * parsing */
    5742            0 :               while (t->get_id () == PLUS)
    5743              :                 {
    5744            0 :                   lexer.skip_token ();
    5745              : 
    5746              :                   // parse bound if it exists - if not, assume end of sequence
    5747            0 :                   std::unique_ptr<AST::TypeParamBound> bound
    5748              :                     = parse_type_param_bound ();
    5749            0 :                   if (bound == nullptr)
    5750              :                     {
    5751              :                       break;
    5752              :                     }
    5753            0 :                   bounds.push_back (std::move (bound));
    5754              : 
    5755            0 :                   t = lexer.peek_token ();
    5756              :                 }
    5757              : 
    5758            0 :               return std::unique_ptr<AST::TraitObjectType> (
    5759            0 :                 new AST::TraitObjectType (std::move (bounds), locus, false));
    5760            0 :             }
    5761        34432 :           default:
    5762              :             // assume that this is a type path and not an error
    5763        34432 :             return std::unique_ptr<AST::TypePath> (
    5764        34432 :               new AST::TypePath (std::move (path)));
    5765              :           }
    5766        34461 :       }
    5767          400 :     case LEFT_PAREN:
    5768              :       /* tuple type or parenthesised type - requires further disambiguation
    5769              :        * (the usual). ok apparently can be a parenthesised TraitBound too, so
    5770              :        * could be TraitObjectTypeOneBound or TraitObjectType */
    5771          400 :       return parse_paren_prefixed_type ();
    5772            3 :     case FOR:
    5773              :       // TraitObjectTypeOneBound or BareFunctionType
    5774            3 :       return parse_for_prefixed_type ();
    5775           61 :     case ASYNC:
    5776              :     case CONST:
    5777              :     case UNSAFE:
    5778              :     case EXTERN_KW:
    5779              :     case FN_KW:
    5780              :       // bare function type (with no for lifetimes)
    5781           61 :       return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
    5782          120 :     case IMPL:
    5783          120 :       lexer.skip_token ();
    5784          240 :       if (lexer.peek_token ()->get_id () == LIFETIME)
    5785              :         {
    5786              :           /* cannot be one bound because lifetime prevents it from being
    5787              :            * traitbound */
    5788            0 :           std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    5789              :             = parse_type_param_bounds ();
    5790              : 
    5791            0 :           return std::unique_ptr<AST::ImplTraitType> (
    5792            0 :             new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
    5793            0 :         }
    5794              :       else
    5795              :         {
    5796              :           // should be trait bound, so parse trait bound
    5797          120 :           std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
    5798          120 :           if (initial_bound == nullptr)
    5799              :             {
    5800            0 :               if (save_errors)
    5801              :                 {
    5802            0 :                   Error error (lexer.peek_token ()->get_locus (),
    5803              :                                "failed to parse ImplTraitType initial bound");
    5804            0 :                   add_error (std::move (error));
    5805            0 :                 }
    5806              : 
    5807            0 :               return nullptr;
    5808              :             }
    5809              : 
    5810          120 :           location_t locus = t->get_locus ();
    5811              : 
    5812              :           // short cut if next token isn't '+'
    5813          120 :           t = lexer.peek_token ();
    5814          120 :           if (t->get_id () != PLUS)
    5815              :             {
    5816          120 :               return std::unique_ptr<AST::ImplTraitTypeOneBound> (
    5817          120 :                 new AST::ImplTraitTypeOneBound (std::move (initial_bound),
    5818          120 :                                                 locus));
    5819              :             }
    5820              : 
    5821              :           // parse additional type param bounds
    5822            0 :           std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    5823            0 :           bounds.push_back (std::move (initial_bound));
    5824            0 :           while (t->get_id () == PLUS)
    5825              :             {
    5826            0 :               lexer.skip_token ();
    5827              : 
    5828              :               // parse bound if it exists
    5829            0 :               std::unique_ptr<AST::TypeParamBound> bound
    5830              :                 = parse_type_param_bound ();
    5831            0 :               if (bound == nullptr)
    5832              :                 {
    5833              :                   // not an error as trailing plus may exist
    5834              :                   break;
    5835              :                 }
    5836            0 :               bounds.push_back (std::move (bound));
    5837              : 
    5838            0 :               t = lexer.peek_token ();
    5839              :             }
    5840              : 
    5841            0 :           return std::unique_ptr<AST::ImplTraitType> (
    5842            0 :             new AST::ImplTraitType (std::move (bounds), locus));
    5843          120 :         }
    5844           29 :     case DYN:
    5845              :     case QUESTION_MARK:
    5846              :       {
    5847              :         // either TraitObjectType or TraitObjectTypeOneBound
    5848           29 :         bool has_dyn = false;
    5849           29 :         if (t->get_id () == DYN)
    5850              :           {
    5851           29 :             lexer.skip_token ();
    5852           29 :             has_dyn = true;
    5853              :           }
    5854              : 
    5855           58 :         if (lexer.peek_token ()->get_id () == LIFETIME)
    5856              :           {
    5857              :             /* cannot be one bound because lifetime prevents it from being
    5858              :              * traitbound */
    5859            0 :             std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    5860              :               = parse_type_param_bounds ();
    5861              : 
    5862            0 :             return std::unique_ptr<AST::TraitObjectType> (
    5863            0 :               new AST::TraitObjectType (std::move (bounds), t->get_locus (),
    5864            0 :                                         has_dyn));
    5865            0 :           }
    5866              :         else
    5867              :           {
    5868              :             // should be trait bound, so parse trait bound
    5869           29 :             std::unique_ptr<AST::TraitBound> initial_bound
    5870              :               = parse_trait_bound ();
    5871           29 :             if (initial_bound == nullptr)
    5872              :               {
    5873            2 :                 if (save_errors)
    5874              :                   {
    5875            2 :                     Error error (
    5876            2 :                       lexer.peek_token ()->get_locus (),
    5877              :                       "failed to parse TraitObjectType initial bound");
    5878            2 :                     add_error (std::move (error));
    5879            2 :                   }
    5880              : 
    5881            2 :                 return nullptr;
    5882              :               }
    5883              : 
    5884              :             // short cut if next token isn't '+'
    5885           27 :             t = lexer.peek_token ();
    5886           27 :             if (t->get_id () != PLUS)
    5887              :               {
    5888              :                 // convert trait bound to value object
    5889           14 :                 AST::TraitBound value_bound (*initial_bound);
    5890              : 
    5891              :                 // DEBUG: removed as unique ptr, so should auto delete
    5892              :                 // delete initial_bound;
    5893              : 
    5894           14 :                 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    5895           28 :                   new AST::TraitObjectTypeOneBound (std::move (value_bound),
    5896           14 :                                                     t->get_locus (), has_dyn));
    5897           14 :               }
    5898              : 
    5899              :             // parse additional type param bounds
    5900           13 :             std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    5901           13 :             bounds.push_back (std::move (initial_bound));
    5902           33 :             while (t->get_id () == PLUS)
    5903              :               {
    5904           20 :                 lexer.skip_token ();
    5905              : 
    5906              :                 // parse bound if it exists
    5907           20 :                 std::unique_ptr<AST::TypeParamBound> bound
    5908              :                   = parse_type_param_bound ();
    5909           20 :                 if (bound == nullptr)
    5910              :                   {
    5911              :                     // not an error as trailing plus may exist
    5912              :                     break;
    5913              :                   }
    5914           20 :                 bounds.push_back (std::move (bound));
    5915              : 
    5916           20 :                 t = lexer.peek_token ();
    5917              :               }
    5918              : 
    5919           13 :             return std::unique_ptr<AST::TraitObjectType> (
    5920           13 :               new AST::TraitObjectType (std::move (bounds), t->get_locus (),
    5921           13 :                                         has_dyn));
    5922           29 :           }
    5923              :       }
    5924            4 :     default:
    5925            4 :       if (save_errors)
    5926            4 :         add_error (Error (t->get_locus (), "unrecognised token %qs in type",
    5927              :                           t->get_token_description ()));
    5928              : 
    5929            4 :       return nullptr;
    5930              :     }
    5931        43414 : }
    5932              : 
    5933              : /* Parses a type that has '(' as its first character. Returns a tuple type,
    5934              :  * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
    5935              :  * on following characters. */
    5936              : template <typename ManagedTokenSource>
    5937              : std::unique_ptr<AST::Type>
    5938          400 : Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
    5939              : {
    5940              :   /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
    5941              :    * a trait bound, not a parenthesised type, so that it can still be used in
    5942              :    * type param bounds. */
    5943              : 
    5944              :   /* NOTE: this implementation is really shit but I couldn't think of a better
    5945              :    * one. It requires essentially breaking polymorphism and downcasting via
    5946              :    * virtual method abuse, as it was copied from the rustc implementation (in
    5947              :    * which types are reified due to tagged union), after a more OOP attempt by
    5948              :    * me failed. */
    5949          400 :   location_t left_delim_locus = lexer.peek_token ()->get_locus ();
    5950              : 
    5951              :   // skip left delim
    5952          400 :   lexer.skip_token ();
    5953              :   /* while next token isn't close delim, parse comma-separated types, saving
    5954              :    * whether trailing comma happens */
    5955          400 :   const_TokenPtr t = lexer.peek_token ();
    5956          400 :   bool trailing_comma = true;
    5957          400 :   std::vector<std::unique_ptr<AST::Type>> types;
    5958              : 
    5959          727 :   while (t->get_id () != RIGHT_PAREN)
    5960              :     {
    5961          632 :       std::unique_ptr<AST::Type> type = parse_type ();
    5962          632 :       if (type == nullptr)
    5963              :         {
    5964            0 :           Error error (t->get_locus (),
    5965              :                        "failed to parse type inside parentheses (probably "
    5966              :                        "tuple or parenthesised)");
    5967            0 :           add_error (std::move (error));
    5968              : 
    5969            0 :           return nullptr;
    5970            0 :         }
    5971          632 :       types.push_back (std::move (type));
    5972              : 
    5973          632 :       t = lexer.peek_token ();
    5974          632 :       if (t->get_id () != COMMA)
    5975              :         {
    5976          305 :           trailing_comma = false;
    5977              :           break;
    5978              :         }
    5979          327 :       lexer.skip_token ();
    5980              : 
    5981          327 :       t = lexer.peek_token ();
    5982              :     }
    5983              : 
    5984          400 :   if (!skip_token (RIGHT_PAREN))
    5985              :     {
    5986            0 :       return nullptr;
    5987              :     }
    5988              : 
    5989              :   // if only one type and no trailing comma, then not a tuple type
    5990          400 :   if (types.size () == 1 && !trailing_comma)
    5991              :     {
    5992              :       // must be a TraitObjectType (with more than one bound)
    5993           10 :       if (lexer.peek_token ()->get_id () == PLUS)
    5994              :         {
    5995              :           // create type param bounds vector
    5996            0 :           std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    5997              : 
    5998              :           // HACK: convert type to traitbound and add to bounds
    5999            0 :           std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
    6000            0 :           std::unique_ptr<AST::TraitBound> converted_bound (
    6001            0 :             released_ptr->to_trait_bound (true));
    6002            0 :           if (converted_bound == nullptr)
    6003              :             {
    6004            0 :               Error error (
    6005            0 :                 lexer.peek_token ()->get_locus (),
    6006              :                 "failed to hackily converted parsed type to trait bound");
    6007            0 :               add_error (std::move (error));
    6008              : 
    6009            0 :               return nullptr;
    6010            0 :             }
    6011            0 :           bounds.push_back (std::move (converted_bound));
    6012              : 
    6013            0 :           t = lexer.peek_token ();
    6014            0 :           while (t->get_id () == PLUS)
    6015              :             {
    6016            0 :               lexer.skip_token ();
    6017              : 
    6018              :               // attempt to parse typeparambound
    6019            0 :               std::unique_ptr<AST::TypeParamBound> bound
    6020              :                 = parse_type_param_bound ();
    6021            0 :               if (bound == nullptr)
    6022              :                 {
    6023              :                   // not an error if null
    6024              :                   break;
    6025              :                 }
    6026            0 :               bounds.push_back (std::move (bound));
    6027              : 
    6028            0 :               t = lexer.peek_token ();
    6029              :             }
    6030              : 
    6031            0 :           return std::unique_ptr<AST::TraitObjectType> (
    6032            0 :             new AST::TraitObjectType (std::move (bounds), left_delim_locus,
    6033            0 :                                       false));
    6034            0 :         }
    6035              :       else
    6036              :         {
    6037              :           // release vector pointer
    6038            5 :           std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
    6039              :           /* HACK: attempt to convert to trait bound. if fails, parenthesised
    6040              :            * type */
    6041            5 :           std::unique_ptr<AST::TraitBound> converted_bound (
    6042            5 :             released_ptr->to_trait_bound (true));
    6043            5 :           if (converted_bound == nullptr)
    6044              :             {
    6045              :               // parenthesised type
    6046            5 :               return std::unique_ptr<AST::ParenthesisedType> (
    6047            5 :                 new AST::ParenthesisedType (std::move (released_ptr),
    6048            5 :                                             left_delim_locus));
    6049              :             }
    6050              :           else
    6051              :             {
    6052              :               // trait object type (one bound)
    6053              : 
    6054              :               // get value semantics trait bound
    6055            0 :               AST::TraitBound value_bound (*converted_bound);
    6056              : 
    6057            0 :               return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6058            0 :                 new AST::TraitObjectTypeOneBound (value_bound,
    6059            0 :                                                   left_delim_locus));
    6060            0 :             }
    6061            5 :         }
    6062              :     }
    6063              :   else
    6064              :     {
    6065          395 :       return std::unique_ptr<AST::TupleType> (
    6066          395 :         new AST::TupleType (std::move (types), left_delim_locus));
    6067              :     }
    6068              :   /* TODO: ensure that this ensures that dynamic dispatch for traits is not
    6069              :    * lost somehow */
    6070          400 : }
    6071              : 
    6072              : /* Parses a type that has 'for' as its first character. This means it has a
    6073              :  * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
    6074              :  * TraitObjectTypeOneBound depending on following characters. */
    6075              : template <typename ManagedTokenSource>
    6076              : std::unique_ptr<AST::Type>
    6077            3 : Parser<ManagedTokenSource>::parse_for_prefixed_type ()
    6078              : {
    6079            3 :   location_t for_locus = lexer.peek_token ()->get_locus ();
    6080              :   // parse for lifetimes in type
    6081            3 :   std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
    6082              : 
    6083              :   // branch on next token - either function or a trait type
    6084            3 :   const_TokenPtr t = lexer.peek_token ();
    6085            3 :   switch (t->get_id ())
    6086              :     {
    6087            3 :     case ASYNC:
    6088              :     case CONST:
    6089              :     case UNSAFE:
    6090              :     case EXTERN_KW:
    6091              :     case FN_KW:
    6092            3 :       return parse_bare_function_type (std::move (for_lifetimes));
    6093            0 :     case SCOPE_RESOLUTION:
    6094              :     case IDENTIFIER:
    6095              :     case SUPER:
    6096              :     case SELF:
    6097              :     case SELF_ALIAS:
    6098              :     case CRATE:
    6099              :     case DOLLAR_SIGN:
    6100              :       {
    6101              :         // path, so trait type
    6102              : 
    6103              :         // parse type path to finish parsing trait bound
    6104            0 :         AST::TypePath path = parse_type_path ();
    6105              : 
    6106            0 :         t = lexer.peek_token ();
    6107            0 :         if (t->get_id () != PLUS)
    6108              :           {
    6109              :             // must be one-bound trait type
    6110              :             // create trait bound value object
    6111            0 :             AST::TraitBound bound (std::move (path), for_locus, false, false,
    6112              :                                    std::move (for_lifetimes));
    6113              : 
    6114            0 :             return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6115            0 :               new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
    6116            0 :           }
    6117              : 
    6118              :         /* more than one bound trait type (or at least parsed as it - could be
    6119              :          * trailing '+') create trait bound pointer and bounds */
    6120            0 :         std::unique_ptr<AST::TraitBound> initial_bound (
    6121            0 :           new AST::TraitBound (std::move (path), for_locus, false, false,
    6122              :                                std::move (for_lifetimes)));
    6123            0 :         std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    6124            0 :         bounds.push_back (std::move (initial_bound));
    6125              : 
    6126            0 :         while (t->get_id () == PLUS)
    6127              :           {
    6128            0 :             lexer.skip_token ();
    6129              : 
    6130              :             // parse type param bound if it exists
    6131            0 :             std::unique_ptr<AST::TypeParamBound> bound
    6132              :               = parse_type_param_bound ();
    6133            0 :             if (bound == nullptr)
    6134              :               {
    6135              :                 // not an error - e.g. trailing plus
    6136            0 :                 return nullptr;
    6137              :               }
    6138            0 :             bounds.push_back (std::move (bound));
    6139              : 
    6140            0 :             t = lexer.peek_token ();
    6141              :           }
    6142              : 
    6143            0 :         return std::unique_ptr<AST::TraitObjectType> (
    6144            0 :           new AST::TraitObjectType (std::move (bounds), for_locus, false));
    6145            0 :       }
    6146            0 :     default:
    6147              :       // error
    6148            0 :       add_error (Error (t->get_locus (),
    6149              :                         "unrecognised token %qs in bare function type or trait "
    6150              :                         "object type or trait object type one bound",
    6151              :                         t->get_token_description ()));
    6152              : 
    6153            0 :       return nullptr;
    6154              :     }
    6155            3 : }
    6156              : 
    6157              : // Parses a maybe named param used in bare function types.
    6158              : template <typename ManagedTokenSource>
    6159              : AST::MaybeNamedParam
    6160           48 : Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
    6161              : {
    6162              :   /* Basically guess that param is named if first token is identifier or
    6163              :    * underscore and second token is semicolon. This should probably have no
    6164              :    * exceptions. rustc uses backtracking to parse these, but at the time of
    6165              :    * writing gccrs has no backtracking capabilities. */
    6166           48 :   const_TokenPtr current = lexer.peek_token ();
    6167           48 :   const_TokenPtr next = lexer.peek_token (1);
    6168              : 
    6169           48 :   Identifier name;
    6170           48 :   AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
    6171              : 
    6172           48 :   if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
    6173              :     {
    6174              :       // named param
    6175            1 :       name = {current};
    6176            1 :       kind = AST::MaybeNamedParam::IDENTIFIER;
    6177            1 :       lexer.skip_token (1);
    6178              :     }
    6179           47 :   else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
    6180              :     {
    6181              :       // wildcard param
    6182           12 :       name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
    6183            6 :       kind = AST::MaybeNamedParam::WILDCARD;
    6184            6 :       lexer.skip_token (1);
    6185              :     }
    6186              : 
    6187              :   // parse type (required)
    6188           48 :   std::unique_ptr<AST::Type> type = parse_type ();
    6189           48 :   if (type == nullptr)
    6190              :     {
    6191            0 :       Error error (lexer.peek_token ()->get_locus (),
    6192              :                    "failed to parse type in maybe named param");
    6193            0 :       add_error (std::move (error));
    6194              : 
    6195            0 :       return AST::MaybeNamedParam::create_error ();
    6196            0 :     }
    6197              : 
    6198           96 :   return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
    6199           48 :                                std::move (outer_attrs), current->get_locus ());
    6200           96 : }
    6201              : 
    6202              : /* Parses a bare function type (with the given for lifetimes for convenience -
    6203              :  * does not parse them itself). */
    6204              : template <typename ManagedTokenSource>
    6205              : std::unique_ptr<AST::BareFunctionType>
    6206           66 : Parser<ManagedTokenSource>::parse_bare_function_type (
    6207              :   std::vector<AST::LifetimeParam> for_lifetimes)
    6208              : {
    6209              :   // TODO: pass in for lifetime location as param
    6210           66 :   location_t best_try_locus = lexer.peek_token ()->get_locus ();
    6211              : 
    6212           66 :   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
    6213              : 
    6214           66 :   if (!skip_token (FN_KW))
    6215            0 :     return nullptr;
    6216              : 
    6217           66 :   if (!skip_token (LEFT_PAREN))
    6218            0 :     return nullptr;
    6219              : 
    6220              :   // parse function params, if they exist
    6221           66 :   std::vector<AST::MaybeNamedParam> params;
    6222           66 :   bool is_variadic = false;
    6223           66 :   AST::AttrVec variadic_attrs;
    6224              : 
    6225           66 :   const_TokenPtr t = lexer.peek_token ();
    6226          120 :   while (t->get_id () != RIGHT_PAREN)
    6227              :     {
    6228           48 :       AST::AttrVec temp_attrs = parse_outer_attributes ();
    6229              : 
    6230           96 :       if (lexer.peek_token ()->get_id () == ELLIPSIS)
    6231              :         {
    6232            0 :           lexer.skip_token ();
    6233            0 :           is_variadic = true;
    6234            0 :           variadic_attrs = std::move (temp_attrs);
    6235              : 
    6236            0 :           t = lexer.peek_token ();
    6237              : 
    6238            0 :           if (t->get_id () != RIGHT_PAREN)
    6239              :             {
    6240            0 :               Error error (t->get_locus (),
    6241              :                            "expected right parentheses after variadic in maybe "
    6242              :                            "named function "
    6243              :                            "parameters, found %qs",
    6244              :                            t->get_token_description ());
    6245            0 :               add_error (std::move (error));
    6246              : 
    6247            0 :               return nullptr;
    6248            0 :             }
    6249              : 
    6250              :           break;
    6251              :         }
    6252              : 
    6253           48 :       AST::MaybeNamedParam param
    6254           48 :         = parse_maybe_named_param (std::move (temp_attrs));
    6255           48 :       if (param.is_error ())
    6256              :         {
    6257            0 :           Error error (
    6258            0 :             lexer.peek_token ()->get_locus (),
    6259              :             "failed to parse maybe named param in bare function type");
    6260            0 :           add_error (std::move (error));
    6261              : 
    6262            0 :           return nullptr;
    6263            0 :         }
    6264           48 :       params.push_back (std::move (param));
    6265              : 
    6266           96 :       if (lexer.peek_token ()->get_id () != COMMA)
    6267              :         break;
    6268              : 
    6269            6 :       lexer.skip_token ();
    6270            6 :       t = lexer.peek_token ();
    6271              :     }
    6272              : 
    6273           66 :   if (!skip_token (RIGHT_PAREN))
    6274            0 :     return nullptr;
    6275              : 
    6276              :   // bare function return type, if exists
    6277           66 :   std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
    6278          132 :   if (lexer.peek_token ()->get_id () == RETURN_TYPE)
    6279              :     {
    6280           53 :       lexer.skip_token ();
    6281              : 
    6282              :       // parse required TypeNoBounds
    6283           53 :       return_type = parse_type_no_bounds ();
    6284           53 :       if (return_type == nullptr)
    6285              :         {
    6286            0 :           Error error (lexer.peek_token ()->get_locus (),
    6287              :                        "failed to parse return type (type no bounds) in bare "
    6288              :                        "function type");
    6289            0 :           add_error (std::move (error));
    6290              : 
    6291            0 :           return nullptr;
    6292            0 :         }
    6293              :     }
    6294              : 
    6295              :   return std::unique_ptr<AST::BareFunctionType> (
    6296           66 :     new AST::BareFunctionType (std::move (for_lifetimes),
    6297              :                                std::move (qualifiers), std::move (params),
    6298              :                                is_variadic, std::move (variadic_attrs),
    6299           66 :                                std::move (return_type), best_try_locus));
    6300          132 : }
    6301              : 
    6302              : template <typename ManagedTokenSource>
    6303              : std::unique_ptr<AST::ReferenceType>
    6304         4314 : Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
    6305              : {
    6306              :   // parse optional lifetime
    6307         4314 :   AST::Lifetime lifetime = AST::Lifetime::elided ();
    6308         8628 :   if (lexer.peek_token ()->get_id () == LIFETIME)
    6309              :     {
    6310          468 :       auto parsed_lifetime = parse_lifetime (true);
    6311          468 :       if (parsed_lifetime)
    6312              :         {
    6313          468 :           lifetime = parsed_lifetime.value ();
    6314              :         }
    6315              :       else
    6316              :         {
    6317            0 :           Error error (lexer.peek_token ()->get_locus (),
    6318              :                        "failed to parse lifetime in reference type");
    6319            0 :           add_error (std::move (error));
    6320              : 
    6321            0 :           return nullptr;
    6322            0 :         }
    6323          468 :     }
    6324              : 
    6325         4314 :   bool is_mut = false;
    6326         8628 :   if (lexer.peek_token ()->get_id () == MUT)
    6327              :     {
    6328          304 :       lexer.skip_token ();
    6329          304 :       is_mut = true;
    6330              :     }
    6331              : 
    6332              :   // parse type no bounds, which is required
    6333         4314 :   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
    6334         4314 :   if (type == nullptr)
    6335              :     {
    6336            0 :       Error error (lexer.peek_token ()->get_locus (),
    6337              :                    "failed to parse referenced type in reference type");
    6338            0 :       add_error (std::move (error));
    6339              : 
    6340            0 :       return nullptr;
    6341            0 :     }
    6342              : 
    6343              :   return std::unique_ptr<AST::ReferenceType> (
    6344        12942 :     new AST::ReferenceType (is_mut, std::move (type), locus,
    6345         4314 :                             std::move (lifetime)));
    6346         4314 : }
    6347              : 
    6348              : // Parses a reference type (mutable or immutable, with given lifetime).
    6349              : template <typename ManagedTokenSource>
    6350              : std::unique_ptr<AST::ReferenceType>
    6351         4314 : Parser<ManagedTokenSource>::parse_reference_type ()
    6352              : {
    6353         4314 :   auto t = lexer.peek_token ();
    6354         4314 :   auto locus = t->get_locus ();
    6355              : 
    6356         4314 :   switch (t->get_id ())
    6357              :     {
    6358         4300 :     case AMP:
    6359         4300 :       skip_token (AMP);
    6360         4300 :       return parse_reference_type_inner (locus);
    6361           14 :     case LOGICAL_AND:
    6362           14 :       skip_token (LOGICAL_AND);
    6363              :       return std::unique_ptr<AST::ReferenceType> (
    6364           42 :         new AST::ReferenceType (false, parse_reference_type_inner (locus),
    6365           14 :                                 locus));
    6366            0 :     default:
    6367            0 :       rust_unreachable ();
    6368              :     }
    6369         4314 : }
    6370              : 
    6371              : // Parses a raw (unsafe) pointer type.
    6372              : template <typename ManagedTokenSource>
    6373              : std::unique_ptr<AST::RawPointerType>
    6374         6540 : Parser<ManagedTokenSource>::parse_raw_pointer_type ()
    6375              : {
    6376         6540 :   location_t locus = lexer.peek_token ()->get_locus ();
    6377         6540 :   skip_token (ASTERISK);
    6378              : 
    6379         6540 :   AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
    6380              : 
    6381              :   // branch on next token for pointer kind info
    6382         6540 :   const_TokenPtr t = lexer.peek_token ();
    6383         6540 :   switch (t->get_id ())
    6384              :     {
    6385          721 :     case MUT:
    6386          721 :       kind = AST::RawPointerType::MUT;
    6387          721 :       lexer.skip_token ();
    6388              :       break;
    6389         5819 :     case CONST:
    6390         5819 :       kind = AST::RawPointerType::CONST;
    6391         5819 :       lexer.skip_token ();
    6392              :       break;
    6393            0 :     default:
    6394            0 :       add_error (Error (t->get_locus (),
    6395              :                         "unrecognised token %qs in raw pointer type",
    6396              :                         t->get_token_description ()));
    6397              : 
    6398            0 :       return nullptr;
    6399              :     }
    6400              : 
    6401              :   // parse type no bounds (required)
    6402         6540 :   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
    6403         6540 :   if (type == nullptr)
    6404              :     {
    6405            0 :       Error error (lexer.peek_token ()->get_locus (),
    6406              :                    "failed to parse pointed type of raw pointer type");
    6407            0 :       add_error (std::move (error));
    6408              : 
    6409            0 :       return nullptr;
    6410            0 :     }
    6411              : 
    6412              :   return std::unique_ptr<AST::RawPointerType> (
    6413         6540 :     new AST::RawPointerType (kind, std::move (type), locus));
    6414         6540 : }
    6415              : 
    6416              : /* Parses a slice or array type, depending on following arguments (as
    6417              :  * lookahead is not possible). */
    6418              : template <typename ManagedTokenSource>
    6419              : std::unique_ptr<AST::TypeNoBounds>
    6420         1514 : Parser<ManagedTokenSource>::parse_slice_or_array_type ()
    6421              : {
    6422         1514 :   location_t locus = lexer.peek_token ()->get_locus ();
    6423         1514 :   skip_token (LEFT_SQUARE);
    6424              : 
    6425              :   // parse inner type (required)
    6426         1514 :   std::unique_ptr<AST::Type> inner_type = parse_type ();
    6427         1514 :   if (inner_type == nullptr)
    6428              :     {
    6429            0 :       Error error (lexer.peek_token ()->get_locus (),
    6430              :                    "failed to parse inner type in slice or array type");
    6431            0 :       add_error (std::move (error));
    6432              : 
    6433            0 :       return nullptr;
    6434            0 :     }
    6435              : 
    6436              :   // branch on next token
    6437         1514 :   const_TokenPtr t = lexer.peek_token ();
    6438         1514 :   switch (t->get_id ())
    6439              :     {
    6440          842 :     case RIGHT_SQUARE:
    6441              :       // slice type
    6442          842 :       lexer.skip_token ();
    6443              : 
    6444          842 :       return std::unique_ptr<AST::SliceType> (
    6445          842 :         new AST::SliceType (std::move (inner_type), locus));
    6446          672 :     case SEMICOLON:
    6447              :       {
    6448              :         // array type
    6449          672 :         lexer.skip_token ();
    6450              : 
    6451              :         // parse required array size expression
    6452          672 :         auto size = parse_anon_const ();
    6453              : 
    6454          672 :         if (!size)
    6455              :           {
    6456            1 :             Error error (lexer.peek_token ()->get_locus (),
    6457              :                          "failed to parse size expression in array type");
    6458            1 :             add_error (std::move (error));
    6459              : 
    6460            1 :             return nullptr;
    6461            1 :           }
    6462              : 
    6463          671 :         if (!skip_token (RIGHT_SQUARE))
    6464              :           {
    6465            0 :             return nullptr;
    6466              :           }
    6467              : 
    6468          671 :         return std::unique_ptr<AST::ArrayType> (
    6469         1331 :           new AST::ArrayType (std::move (inner_type), std::move (*size),
    6470          671 :                               locus));
    6471          672 :       }
    6472            0 :     default:
    6473              :       // error
    6474            0 :       add_error (
    6475            0 :         Error (t->get_locus (),
    6476              :                "unrecognised token %qs in slice or array type after inner type",
    6477              :                t->get_token_description ()));
    6478              : 
    6479            0 :       return nullptr;
    6480              :     }
    6481         1514 : }
    6482              : 
    6483              : // Parses a type, taking into account type boundary disambiguation.
    6484              : template <typename ManagedTokenSource>
    6485              : std::unique_ptr<AST::TypeNoBounds>
    6486        16098 : Parser<ManagedTokenSource>::parse_type_no_bounds ()
    6487              : {
    6488        16098 :   const_TokenPtr t = lexer.peek_token ();
    6489        16098 :   switch (t->get_id ())
    6490              :     {
    6491            1 :     case EXCLAM:
    6492              :       // never type - can't be macro as no path beforehand
    6493            1 :       lexer.skip_token ();
    6494            1 :       return std::unique_ptr<AST::NeverType> (
    6495            1 :         new AST::NeverType (t->get_locus ()));
    6496          656 :     case LEFT_SQUARE:
    6497              :       // slice type or array type - requires further disambiguation
    6498          656 :       return parse_slice_or_array_type ();
    6499           22 :     case LEFT_SHIFT:
    6500              :     case LEFT_ANGLE:
    6501              :       {
    6502              :         // qualified path in type
    6503           22 :         AST::QualifiedPathInType path = parse_qualified_path_in_type ();
    6504           22 :         if (path.is_error ())
    6505              :           {
    6506            0 :             Error error (t->get_locus (),
    6507              :                          "failed to parse qualified path in type");
    6508            0 :             add_error (std::move (error));
    6509              : 
    6510            0 :             return nullptr;
    6511            0 :           }
    6512           22 :         return std::unique_ptr<AST::QualifiedPathInType> (
    6513           22 :           new AST::QualifiedPathInType (std::move (path)));
    6514           22 :       }
    6515          104 :     case UNDERSCORE:
    6516              :       // inferred type
    6517          104 :       lexer.skip_token ();
    6518          104 :       return std::unique_ptr<AST::InferredType> (
    6519          104 :         new AST::InferredType (t->get_locus ()));
    6520         3812 :     case ASTERISK:
    6521              :       // raw pointer type
    6522         3812 :       return parse_raw_pointer_type ();
    6523           24 :     case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
    6524              :     case LOGICAL_AND:
    6525              :       // reference type
    6526           24 :       return parse_reference_type ();
    6527            0 :     case LIFETIME:
    6528              :       /* probably a lifetime bound, so probably type param bounds in
    6529              :        * TraitObjectType. this is not allowed, but detection here for error
    6530              :        * message */
    6531            0 :       add_error (Error (t->get_locus (),
    6532              :                         "lifetime bounds (i.e. in type param bounds, in "
    6533              :                         "TraitObjectType) are not allowed as TypeNoBounds"));
    6534              : 
    6535            0 :       return nullptr;
    6536        11302 :     case IDENTIFIER:
    6537              :     case SUPER:
    6538              :     case SELF:
    6539              :     case SELF_ALIAS:
    6540              :     case CRATE:
    6541              :     case DOLLAR_SIGN:
    6542              :     case SCOPE_RESOLUTION:
    6543              :       {
    6544              :         // macro invocation or type path - requires further disambiguation.
    6545              :         /* for parsing path component of each rule, perhaps parse it as a
    6546              :          * typepath and attempt conversion to simplepath if a trailing '!' is
    6547              :          * found */
    6548              :         /* Type path also includes TraitObjectTypeOneBound BUT if it starts
    6549              :          * with it, it is exactly the same as a TypePath syntactically, so
    6550              :          * this is a syntactical ambiguity. As such, the parser will parse it
    6551              :          * as a TypePath. This, however, does not prevent TraitObjectType from
    6552              :          * starting with a typepath. */
    6553              : 
    6554              :         // parse path as type path
    6555        11302 :         AST::TypePath path = parse_type_path ();
    6556        11302 :         if (path.is_error ())
    6557              :           {
    6558            0 :             Error error (
    6559              :               t->get_locus (),
    6560              :               "failed to parse path as first component of type no bounds");
    6561            0 :             add_error (std::move (error));
    6562              : 
    6563            0 :             return nullptr;
    6564            0 :           }
    6565        11302 :         location_t locus = path.get_locus ();
    6566              : 
    6567              :         // branch on next token
    6568        11302 :         t = lexer.peek_token ();
    6569        11302 :         switch (t->get_id ())
    6570              :           {
    6571            1 :           case EXCLAM:
    6572              :             {
    6573              :               // macro invocation
    6574              :               // convert to simple path
    6575            1 :               AST::SimplePath macro_path = path.as_simple_path ();
    6576            1 :               if (macro_path.is_empty ())
    6577              :                 {
    6578            0 :                   Error error (t->get_locus (),
    6579              :                                "failed to parse simple path in macro "
    6580              :                                "invocation (for type)");
    6581            0 :                   add_error (std::move (error));
    6582              : 
    6583            0 :                   return nullptr;
    6584            0 :                 }
    6585              : 
    6586            1 :               lexer.skip_token ();
    6587              : 
    6588            1 :               auto tok_tree = parse_delim_token_tree ();
    6589            1 :               if (!tok_tree)
    6590            0 :                 return nullptr;
    6591              : 
    6592            3 :               return AST::MacroInvocation::Regular (
    6593            2 :                 AST::MacroInvocData (std::move (macro_path),
    6594            1 :                                      std::move (tok_tree.value ())),
    6595            1 :                 {}, locus);
    6596            2 :             }
    6597        11301 :           default:
    6598              :             // assume that this is a type path and not an error
    6599        11301 :             return std::unique_ptr<AST::TypePath> (
    6600        11301 :               new AST::TypePath (std::move (path)));
    6601              :           }
    6602        11302 :       }
    6603           18 :     case LEFT_PAREN:
    6604              :       /* tuple type or parenthesised type - requires further disambiguation
    6605              :        * (the usual). ok apparently can be a parenthesised TraitBound too, so
    6606              :        * could be TraitObjectTypeOneBound */
    6607           18 :       return parse_paren_prefixed_type_no_bounds ();
    6608            2 :     case FOR:
    6609              :     case ASYNC:
    6610              :     case CONST:
    6611              :     case UNSAFE:
    6612              :     case EXTERN_KW:
    6613              :     case FN_KW:
    6614              :       // bare function type (with no for lifetimes)
    6615            2 :       return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
    6616           14 :     case IMPL:
    6617           14 :       lexer.skip_token ();
    6618           28 :       if (lexer.peek_token ()->get_id () == LIFETIME)
    6619              :         {
    6620              :           /* cannot be one bound because lifetime prevents it from being
    6621              :            * traitbound not allowed as type no bounds, only here for error
    6622              :            * message */
    6623            0 :           Error error (
    6624            0 :             lexer.peek_token ()->get_locus (),
    6625              :             "lifetime (probably lifetime bound, in type param "
    6626              :             "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
    6627            0 :           add_error (std::move (error));
    6628              : 
    6629            0 :           return nullptr;
    6630            0 :         }
    6631              :       else
    6632              :         {
    6633              :           // should be trait bound, so parse trait bound
    6634           14 :           std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
    6635           14 :           if (initial_bound == nullptr)
    6636              :             {
    6637            0 :               Error error (lexer.peek_token ()->get_locus (),
    6638              :                            "failed to parse ImplTraitTypeOneBound bound");
    6639            0 :               add_error (std::move (error));
    6640              : 
    6641            0 :               return nullptr;
    6642            0 :             }
    6643              : 
    6644           14 :           location_t locus = t->get_locus ();
    6645              : 
    6646              :           // ensure not a trait with multiple bounds
    6647           14 :           t = lexer.peek_token ();
    6648           14 :           if (t->get_id () == PLUS)
    6649              :             {
    6650            0 :               Error error (t->get_locus (),
    6651              :                            "plus after trait bound means an ImplTraitType, "
    6652              :                            "which is not allowed as a TypeNoBounds");
    6653            0 :               add_error (std::move (error));
    6654              : 
    6655            0 :               return nullptr;
    6656            0 :             }
    6657              : 
    6658           14 :           return std::unique_ptr<AST::ImplTraitTypeOneBound> (
    6659           14 :             new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
    6660           14 :         }
    6661          143 :     case DYN:
    6662              :     case QUESTION_MARK:
    6663              :       {
    6664              :         // either TraitObjectTypeOneBound
    6665          143 :         bool has_dyn = false;
    6666          143 :         if (t->get_id () == DYN)
    6667              :           {
    6668          143 :             lexer.skip_token ();
    6669          143 :             has_dyn = true;
    6670              :           }
    6671              : 
    6672          286 :         if (lexer.peek_token ()->get_id () == LIFETIME)
    6673              :           {
    6674              :             /* means that cannot be TraitObjectTypeOneBound - so here for
    6675              :              * error message */
    6676            0 :             Error error (lexer.peek_token ()->get_locus (),
    6677              :                          "lifetime as bound in TraitObjectTypeOneBound "
    6678              :                          "is not allowed, so cannot be TypeNoBounds");
    6679            0 :             add_error (std::move (error));
    6680              : 
    6681            0 :             return nullptr;
    6682            0 :           }
    6683              : 
    6684              :         // should be trait bound, so parse trait bound
    6685          143 :         std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
    6686          143 :         if (initial_bound == nullptr)
    6687              :           {
    6688            0 :             Error error (
    6689            0 :               lexer.peek_token ()->get_locus (),
    6690              :               "failed to parse TraitObjectTypeOneBound initial bound");
    6691            0 :             add_error (std::move (error));
    6692              : 
    6693            0 :             return nullptr;
    6694            0 :           }
    6695              : 
    6696          143 :         location_t locus = t->get_locus ();
    6697              : 
    6698              :         // detect error with plus as next token
    6699          143 :         t = lexer.peek_token ();
    6700          143 :         if (t->get_id () == PLUS)
    6701              :           {
    6702            0 :             Error error (t->get_locus (),
    6703              :                          "plus after trait bound means a TraitObjectType, "
    6704              :                          "which is not allowed as a TypeNoBounds");
    6705            0 :             add_error (std::move (error));
    6706              : 
    6707            0 :             return nullptr;
    6708            0 :           }
    6709              : 
    6710              :         // convert trait bound to value object
    6711          143 :         AST::TraitBound value_bound (*initial_bound);
    6712              : 
    6713          143 :         return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6714          286 :           new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
    6715          143 :                                             has_dyn));
    6716          143 :       }
    6717            0 :     default:
    6718            0 :       add_error (Error (t->get_locus (),
    6719              :                         "unrecognised token %qs in type no bounds",
    6720              :                         t->get_token_description ()));
    6721              : 
    6722            0 :       return nullptr;
    6723              :     }
    6724        16098 : }
    6725              : 
    6726              : // Parses a type no bounds beginning with '('.
    6727              : template <typename ManagedTokenSource>
    6728              : std::unique_ptr<AST::TypeNoBounds>
    6729           18 : Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
    6730              : {
    6731              :   /* NOTE: this could probably be parsed without the HACK solution of
    6732              :    * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
    6733              : 
    6734              :   /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
    6735              :    * considered a trait bound, not a parenthesised type, so that it can still
    6736              :    * be used in type param bounds. */
    6737              : 
    6738           18 :   location_t left_paren_locus = lexer.peek_token ()->get_locus ();
    6739              : 
    6740              :   // skip left delim
    6741           18 :   lexer.skip_token ();
    6742              :   /* while next token isn't close delim, parse comma-separated types, saving
    6743              :    * whether trailing comma happens */
    6744           18 :   const_TokenPtr t = lexer.peek_token ();
    6745           18 :   bool trailing_comma = true;
    6746           18 :   std::vector<std::unique_ptr<AST::Type>> types;
    6747              : 
    6748           18 :   while (t->get_id () != RIGHT_PAREN)
    6749              :     {
    6750            2 :       std::unique_ptr<AST::Type> type = parse_type ();
    6751            2 :       if (type == nullptr)
    6752              :         {
    6753            0 :           Error error (t->get_locus (),
    6754              :                        "failed to parse type inside parentheses (probably "
    6755              :                        "tuple or parenthesised)");
    6756            0 :           add_error (std::move (error));
    6757              : 
    6758            0 :           return nullptr;
    6759            0 :         }
    6760            2 :       types.push_back (std::move (type));
    6761              : 
    6762            2 :       t = lexer.peek_token ();
    6763            2 :       if (t->get_id () != COMMA)
    6764              :         {
    6765            2 :           trailing_comma = false;
    6766              :           break;
    6767              :         }
    6768            0 :       lexer.skip_token ();
    6769              : 
    6770            0 :       t = lexer.peek_token ();
    6771              :     }
    6772              : 
    6773           18 :   if (!skip_token (RIGHT_PAREN))
    6774              :     {
    6775            0 :       return nullptr;
    6776              :     }
    6777              : 
    6778              :   // if only one type and no trailing comma, then not a tuple type
    6779           18 :   if (types.size () == 1 && !trailing_comma)
    6780              :     {
    6781              :       // must be a TraitObjectType (with more than one bound)
    6782            4 :       if (lexer.peek_token ()->get_id () == PLUS)
    6783              :         {
    6784              :           // error - this is not allowed for type no bounds
    6785            0 :           Error error (lexer.peek_token ()->get_locus (),
    6786              :                        "plus (implying TraitObjectType as type param "
    6787              :                        "bounds) is not allowed in type no bounds");
    6788            0 :           add_error (std::move (error));
    6789              : 
    6790            0 :           return nullptr;
    6791            0 :         }
    6792              :       else
    6793              :         {
    6794              :           // release vector pointer
    6795            2 :           std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
    6796              :           /* HACK: attempt to convert to trait bound. if fails, parenthesised
    6797              :            * type */
    6798            2 :           std::unique_ptr<AST::TraitBound> converted_bound (
    6799            2 :             released_ptr->to_trait_bound (true));
    6800            2 :           if (converted_bound == nullptr)
    6801              :             {
    6802              :               // parenthesised type
    6803            2 :               return std::unique_ptr<AST::ParenthesisedType> (
    6804            2 :                 new AST::ParenthesisedType (std::move (released_ptr),
    6805            2 :                                             left_paren_locus));
    6806              :             }
    6807              :           else
    6808              :             {
    6809              :               // trait object type (one bound)
    6810              : 
    6811              :               // get value semantics trait bound
    6812            0 :               AST::TraitBound value_bound (*converted_bound);
    6813              : 
    6814            0 :               return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6815            0 :                 new AST::TraitObjectTypeOneBound (value_bound,
    6816            0 :                                                   left_paren_locus));
    6817            0 :             }
    6818            2 :         }
    6819              :     }
    6820              :   else
    6821              :     {
    6822           16 :       return std::unique_ptr<AST::TupleType> (
    6823           16 :         new AST::TupleType (std::move (types), left_paren_locus));
    6824              :     }
    6825              :   /* TODO: ensure that this ensures that dynamic dispatch for traits is not
    6826              :    * lost somehow */
    6827           18 : }
    6828              : 
    6829              : // Parses tuple struct items if they exist. Does not parse parentheses.
    6830              : template <typename ManagedTokenSource>
    6831              : std::unique_ptr<AST::TupleStructItems>
    6832          924 : Parser<ManagedTokenSource>::parse_tuple_struct_items ()
    6833              : {
    6834          924 :   std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
    6835              : 
    6836              :   // DEBUG
    6837          924 :   rust_debug ("started parsing tuple struct items");
    6838              : 
    6839              :   // check for '..' at front
    6840         1848 :   if (lexer.peek_token ()->get_id () == DOT_DOT)
    6841              :     {
    6842              :       // only parse upper patterns
    6843           16 :       lexer.skip_token ();
    6844              : 
    6845              :       // DEBUG
    6846           16 :       rust_debug ("'..' at front in tuple struct items detected");
    6847              : 
    6848           16 :       std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
    6849              : 
    6850           16 :       const_TokenPtr t = lexer.peek_token ();
    6851           33 :       while (t->get_id () == COMMA)
    6852              :         {
    6853           17 :           lexer.skip_token ();
    6854              : 
    6855              :           // break if right paren
    6856           34 :           if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    6857              :             break;
    6858              : 
    6859              :           // parse pattern, which is now required
    6860           17 :           std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    6861           17 :           if (pattern == nullptr)
    6862              :             {
    6863            0 :               Error error (lexer.peek_token ()->get_locus (),
    6864              :                            "failed to parse pattern in tuple struct items");
    6865            0 :               add_error (std::move (error));
    6866              : 
    6867            0 :               return nullptr;
    6868            0 :             }
    6869           17 :           upper_patterns.push_back (std::move (pattern));
    6870              : 
    6871           17 :           t = lexer.peek_token ();
    6872              :         }
    6873              : 
    6874              :       // DEBUG
    6875           16 :       rust_debug (
    6876              :         "finished parsing tuple struct items ranged (upper/none only)");
    6877              : 
    6878           16 :       return std::unique_ptr<AST::TupleStructItemsHasRest> (
    6879           16 :         new AST::TupleStructItemsHasRest (std::move (lower_patterns),
    6880           16 :                                           std::move (upper_patterns)));
    6881           16 :     }
    6882              : 
    6883              :   // has at least some lower patterns
    6884          908 :   const_TokenPtr t = lexer.peek_token ();
    6885         1863 :   while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
    6886              :     {
    6887              :       // DEBUG
    6888          955 :       rust_debug ("about to parse pattern in tuple struct items");
    6889              : 
    6890              :       // parse pattern, which is required
    6891          955 :       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    6892          955 :       if (pattern == nullptr)
    6893              :         {
    6894            0 :           Error error (t->get_locus (),
    6895              :                        "failed to parse pattern in tuple struct items");
    6896            0 :           add_error (std::move (error));
    6897              : 
    6898            0 :           return nullptr;
    6899            0 :         }
    6900          955 :       lower_patterns.push_back (std::move (pattern));
    6901              : 
    6902              :       // DEBUG
    6903          955 :       rust_debug ("successfully parsed pattern in tuple struct items");
    6904              : 
    6905         1910 :       if (lexer.peek_token ()->get_id () != COMMA)
    6906              :         {
    6907              :           // DEBUG
    6908          862 :           rust_debug ("broke out of parsing patterns in tuple struct "
    6909              :                       "items as no comma");
    6910              : 
    6911              :           break;
    6912              :         }
    6913           93 :       lexer.skip_token ();
    6914           93 :       t = lexer.peek_token ();
    6915              :     }
    6916              : 
    6917              :   // branch on next token
    6918          908 :   t = lexer.peek_token ();
    6919          908 :   switch (t->get_id ())
    6920              :     {
    6921          884 :     case RIGHT_PAREN:
    6922          884 :       return std::unique_ptr<AST::TupleStructItemsNoRest> (
    6923          884 :         new AST::TupleStructItemsNoRest (std::move (lower_patterns)));
    6924           23 :     case DOT_DOT:
    6925              :       {
    6926              :         // has an upper range that must be parsed separately
    6927           23 :         lexer.skip_token ();
    6928              : 
    6929           23 :         std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
    6930              : 
    6931           23 :         t = lexer.peek_token ();
    6932           25 :         while (t->get_id () == COMMA)
    6933              :           {
    6934            2 :             lexer.skip_token ();
    6935              : 
    6936              :             // break if next token is right paren
    6937            4 :             if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    6938              :               break;
    6939              : 
    6940              :             // parse pattern, which is required
    6941            2 :             std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    6942            2 :             if (pattern == nullptr)
    6943              :               {
    6944            0 :                 Error error (lexer.peek_token ()->get_locus (),
    6945              :                              "failed to parse pattern in tuple struct items");
    6946            0 :                 add_error (std::move (error));
    6947              : 
    6948            0 :                 return nullptr;
    6949            0 :               }
    6950            2 :             upper_patterns.push_back (std::move (pattern));
    6951              : 
    6952            2 :             t = lexer.peek_token ();
    6953              :           }
    6954              : 
    6955           23 :         return std::unique_ptr<AST::TupleStructItemsHasRest> (
    6956           23 :           new AST::TupleStructItemsHasRest (std::move (lower_patterns),
    6957           23 :                                             std::move (upper_patterns)));
    6958           23 :       }
    6959            1 :     default:
    6960              :       // error
    6961            1 :       add_error (Error (t->get_locus (),
    6962              :                         "unexpected token %qs in tuple struct items",
    6963              :                         t->get_token_description ()));
    6964              : 
    6965            1 :       return nullptr;
    6966              :     }
    6967          924 : }
    6968              : 
    6969              : /* Parses a statement or expression (depending on whether a trailing semicolon
    6970              :  * exists). Useful for block expressions where it cannot be determined through
    6971              :  * lookahead whether it is a statement or expression to be parsed. */
    6972              : template <typename ManagedTokenSource>
    6973              : tl::expected<ExprOrStmt, Parse::Error::Node>
    6974        38768 : Parser<ManagedTokenSource>::parse_stmt_or_expr ()
    6975              : {
    6976              :   // quick exit for empty statement
    6977        38768 :   const_TokenPtr t = lexer.peek_token ();
    6978        38768 :   if (t->get_id () == SEMICOLON)
    6979              :     {
    6980           18 :       lexer.skip_token ();
    6981           18 :       std::unique_ptr<AST::EmptyStmt> stmt (
    6982           18 :         new AST::EmptyStmt (t->get_locus ()));
    6983           36 :       return ExprOrStmt (std::move (stmt));
    6984           18 :     }
    6985              : 
    6986              :   // parse outer attributes
    6987        38750 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    6988        38750 :   ParseRestrictions restrictions;
    6989        38750 :   restrictions.expr_can_be_stmt = true;
    6990              : 
    6991              :   // Defered child error checking: we need to check for a semicolon
    6992        38750 :   tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
    6993              : 
    6994              :   // parsing this will be annoying because of the many different possibilities
    6995              :   /* best may be just to copy paste in parse_item switch, and failing that try
    6996              :    * to parse outer attributes, and then pass them in to either a let
    6997              :    * statement or (fallback) expression statement. */
    6998              :   // FIXME: think of a way to do this without such a large switch?
    6999              : 
    7000              :   /* FIXME: for expressions at least, the only way that they can really be
    7001              :    * parsed properly in this way is if they don't support operators on them.
    7002              :    * They must be pratt-parsed otherwise. As such due to composability, only
    7003              :    * explicit statements will have special cases here. This should roughly
    7004              :    * correspond to "expr-with-block", but this warning is here in case it
    7005              :    * isn't the case. */
    7006        38750 :   t = lexer.peek_token ();
    7007        38750 :   switch (t->get_id ())
    7008              :     {
    7009        12743 :     case LET:
    7010              :       {
    7011              :         // let statement
    7012        12743 :         std::unique_ptr<AST::LetStmt> stmt (
    7013        12743 :           parse_let_stmt (std::move (outer_attrs)));
    7014        25486 :         return ExprOrStmt (std::move (stmt));
    7015        12743 :       }
    7016          344 :     case PUB:
    7017              :     case MOD:
    7018              :     case EXTERN_KW:
    7019              :     case USE:
    7020              :     case FN_KW:
    7021              :     case TYPE:
    7022              :     case STRUCT_KW:
    7023              :     case ENUM_KW:
    7024              :     case CONST:
    7025              :     case STATIC_KW:
    7026              :     case AUTO:
    7027              :     case TRAIT:
    7028              :     case IMPL:
    7029              :       {
    7030          344 :         std::unique_ptr<AST::VisItem> item (
    7031          344 :           parse_vis_item (std::move (outer_attrs)));
    7032          688 :         return ExprOrStmt (std::move (item));
    7033          344 :       }
    7034              :     /* TODO: implement union keyword but not really because of
    7035              :      * context-dependence crappy hack way to parse a union written below to
    7036              :      * separate it from the good code. */
    7037              :     // case UNION:
    7038         3080 :     case UNSAFE:
    7039              :       { // maybe - unsafe traits are a thing
    7040              :         /* if any of these (should be all possible VisItem prefixes), parse a
    7041              :          * VisItem - can't parse item because would require reparsing outer
    7042              :          * attributes */
    7043         3080 :         const_TokenPtr t2 = lexer.peek_token (1);
    7044         3080 :         switch (t2->get_id ())
    7045              :           {
    7046         3066 :           case LEFT_CURLY:
    7047              :             {
    7048              :               // unsafe block: parse as expression
    7049         6132 :               expr = parse_expr (std::move (outer_attrs), restrictions);
    7050              :               break;
    7051              :             }
    7052            0 :           case AUTO:
    7053              :           case TRAIT:
    7054              :             {
    7055              :               // unsafe trait
    7056            0 :               std::unique_ptr<AST::VisItem> item (
    7057            0 :                 parse_vis_item (std::move (outer_attrs)));
    7058            0 :               return ExprOrStmt (std::move (item));
    7059            0 :             }
    7060           14 :           case EXTERN_KW:
    7061              :           case FN_KW:
    7062              :             {
    7063              :               // unsafe function
    7064           14 :               std::unique_ptr<AST::VisItem> item (
    7065           14 :                 parse_vis_item (std::move (outer_attrs)));
    7066           28 :               return ExprOrStmt (std::move (item));
    7067           14 :             }
    7068            0 :           case IMPL:
    7069              :             {
    7070              :               // unsafe trait impl
    7071            0 :               std::unique_ptr<AST::VisItem> item (
    7072            0 :                 parse_vis_item (std::move (outer_attrs)));
    7073            0 :               return ExprOrStmt (std::move (item));
    7074            0 :             }
    7075            0 :           default:
    7076            0 :             add_error (Error (t2->get_locus (),
    7077              :                               "unrecognised token %qs after parsing unsafe - "
    7078              :                               "expected beginning of expression or statement",
    7079              :                               t->get_token_description ()));
    7080              : 
    7081              :             // skip somewhere?
    7082              :             return tl::unexpected<Parse::Error::Node> (
    7083            0 :               Parse::Error::Node::MALFORMED);
    7084              :           }
    7085              :         break;
    7086         3080 :       }
    7087              :       /* FIXME: this is either a macro invocation or macro invocation semi.
    7088              :        * start parsing to determine which one it is. */
    7089              :       // FIXME: old code there
    7090              : 
    7091              :     // crappy hack to do union "keyword"
    7092        12268 :     case IDENTIFIER:
    7093        21908 :       if (t->get_str () == Values::WeakKeywords::UNION
    7094        12304 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
    7095              :         {
    7096            1 :           std::unique_ptr<AST::VisItem> item (
    7097            1 :             parse_vis_item (std::move (outer_attrs)));
    7098            2 :           return ExprOrStmt (std::move (item));
    7099              :           // or should this go straight to parsing union?
    7100            1 :         }
    7101        21906 :       else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
    7102        12274 :                && lexer.peek_token (1)->get_id () == EXCLAM)
    7103              :         {
    7104              :           // macro_rules! macro item
    7105            7 :           std::unique_ptr<AST::Item> item (
    7106            7 :             parse_macro_rules_def (std::move (outer_attrs)));
    7107           14 :           return ExprOrStmt (std::move (item));
    7108            7 :         }
    7109              :       gcc_fallthrough ();
    7110              :     case SUPER:
    7111              :     case SELF:
    7112              :     case SELF_ALIAS:
    7113              :     case CRATE:
    7114              :     case SCOPE_RESOLUTION:
    7115              :     case DOLLAR_SIGN:
    7116              :       {
    7117        14716 :         AST::PathInExpression path = parse_path_in_expression ();
    7118              :         tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
    7119        14716 :           null_denotation;
    7120              : 
    7121        29432 :         if (lexer.peek_token ()->get_id () == EXCLAM)
    7122              :           {
    7123          590 :             std::unique_ptr<AST::MacroInvocation> invoc
    7124         1180 :               = parse_macro_invocation_partial (std::move (path),
    7125              :                                                 std::move (outer_attrs));
    7126          590 :             if (invoc == nullptr)
    7127              :               return tl::unexpected<Parse::Error::Node> (
    7128            0 :                 Parse::Error::Node::CHILD_ERROR);
    7129              : 
    7130          590 :             if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
    7131              :               {
    7132          398 :                 invoc->add_semicolon ();
    7133              :                 // Macro invocation with semicolon.
    7134          398 :                 return ExprOrStmt (
    7135          796 :                   std::unique_ptr<AST::Stmt> (std::move (invoc)));
    7136              :               }
    7137              : 
    7138          384 :             TokenId after_macro = lexer.peek_token ()->get_id ();
    7139              : 
    7140          192 :             AST::DelimType delim_type = invoc->get_invoc_data ()
    7141          192 :                                           .get_delim_tok_tree ()
    7142          192 :                                           .get_delim_type ();
    7143              : 
    7144          192 :             if (delim_type == AST::CURLY && after_macro != DOT
    7145            6 :                 && after_macro != QUESTION_MARK)
    7146              :               {
    7147            6 :                 rust_debug ("braced macro statement");
    7148            6 :                 return ExprOrStmt (
    7149           12 :                   std::unique_ptr<AST::Stmt> (std::move (invoc)));
    7150              :               }
    7151              : 
    7152          186 :             null_denotation = std::move (invoc);
    7153          590 :           }
    7154              :         else
    7155              :           {
    7156              :             null_denotation
    7157        28252 :               = null_denotation_path (std::move (path), {}, restrictions);
    7158              :           }
    7159              : 
    7160        57244 :         expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
    7161              :                                  std::move (outer_attrs), restrictions);
    7162              :         break;
    7163        14716 :       }
    7164         7859 :     default:
    7165              :       /* expression statement or expression itself - parse
    7166              :        * expression then make it statement if semi afterwards */
    7167        15688 :       expr = parse_expr (std::move (outer_attrs), restrictions);
    7168         7859 :       break;
    7169              :     }
    7170              : 
    7171        25237 :   const_TokenPtr after_expr = lexer.peek_token ();
    7172        25237 :   if (after_expr->get_id () == SEMICOLON)
    7173              :     {
    7174              :       // must be expression statement
    7175         7648 :       lexer.skip_token ();
    7176              : 
    7177         7648 :       if (expr)
    7178              :         {
    7179         7647 :           return ExprOrStmt (
    7180        15294 :             std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
    7181        22941 :                                              t->get_locus (), true));
    7182              :         }
    7183              :       else
    7184              :         {
    7185              :           return tl::unexpected<Parse::Error::Node> (
    7186            1 :             Parse::Error::Node::CHILD_ERROR);
    7187              :         }
    7188              :     }
    7189              : 
    7190        17589 :   if (expr)
    7191              :     {
    7192              :       // block expression statement.
    7193        17558 :       if (!expr.value ()->is_expr_without_block ()
    7194        17558 :           && after_expr->get_id () != RIGHT_CURLY)
    7195         1581 :         return ExprOrStmt (
    7196         3162 :           std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
    7197         4743 :                                            t->get_locus (), false));
    7198              : 
    7199              :       // Check if expr_without_block is properly terminated
    7200        15977 :       if (expr.value ()->is_expr_without_block ()
    7201        15977 :           && after_expr->get_id () != RIGHT_CURLY)
    7202              :         {
    7203              :           // expr_without_block must be followed by ';' or '}'
    7204            1 :           Error error (after_expr->get_locus (),
    7205              :                        "expected %<;%> or %<}%> after expression, found %qs",
    7206              :                        after_expr->get_token_description ());
    7207            1 :           add_error (std::move (error));
    7208              :           return tl::unexpected<Parse::Error::Node> (
    7209            1 :             Parse::Error::Node::MALFORMED);
    7210            1 :         }
    7211              :     }
    7212              : 
    7213              :   // return expression
    7214        16007 :   if (expr)
    7215        31952 :     return ExprOrStmt (std::move (expr.value ()));
    7216              :   else
    7217           31 :     return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
    7218        63987 : }
    7219              : 
    7220              : } // namespace Rust
    7221              : 
    7222              : #include "rust-parse-impl-utils.hxx"
    7223              : #include "rust-parse-impl-attribute.hxx"
    7224              : #include "rust-parse-impl-ttree.hxx"
    7225              : #include "rust-parse-impl-macro.hxx"
    7226              : #include "rust-parse-impl-path.hxx"
    7227              : #include "rust-parse-impl-pattern.hxx"
    7228              : #include "rust-parse-impl-expr.hxx"
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.