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.2 % 3108 2305
Test Date: 2026-02-28 14:20:25 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         7893 : 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         7893 :   const_TokenPtr tok = lexer.peek_token ();
      75         7893 :   switch (tok->get_id ())
      76              :     {
      77         7645 :     case RIGHT_ANGLE:
      78              :       // this is good - skip token
      79         7645 :       lexer.skip_token ();
      80         7645 :       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         7893 : }
     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       101918 : Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
     118              : {
     119              :   // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
     120       101918 :   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         8785 :     case DOT:
     149        17570 :       if (lexer.peek_token (1)->get_id () == IDENTIFIER
     150        16668 :           && 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        74380 :     default:
     255        74380 :       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         4711 : Parser<ManagedTokenSource>::parse_items ()
     272              : {
     273         4711 :   std::vector<std::unique_ptr<AST::Item>> items;
     274              : 
     275         4711 :   const_TokenPtr t = lexer.peek_token ();
     276        23306 :   while (t->get_id () != END_OF_FILE)
     277              :     {
     278        18595 :       auto item = parse_item (false);
     279        18595 :       if (!item)
     280           74 :         return Parse::Error::Items::make_malformed (std::move (items));
     281              : 
     282        18521 :       items.push_back (std::move (item.value ()));
     283              : 
     284        18521 :       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         4637 :   return items;
     292              : #endif
     293         4711 : }
     294              : 
     295              : // Parses a crate (compilation unit) - entry point
     296              : template <typename ManagedTokenSource>
     297              : std::unique_ptr<AST::Crate>
     298         4658 : Parser<ManagedTokenSource>::parse_crate ()
     299              : {
     300              :   // parse inner attributes
     301         4658 :   AST::AttrVec inner_attrs = parse_inner_attributes ();
     302              : 
     303              :   // parse items
     304         4658 :   auto items
     305         4658 :     = parse_items ().value_or (std::vector<std::unique_ptr<AST::Item>>{});
     306              : 
     307              :   // emit all errors
     308         4822 :   for (const auto &error : error_table)
     309          164 :     error.emit ();
     310              : 
     311              :   return std::unique_ptr<AST::Crate> (
     312         4658 :     new AST::Crate (std::move (items), std::move (inner_attrs)));
     313         4658 : }
     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          497 : Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
     319              : {
     320          497 :   const_TokenPtr t = lexer.peek_token ();
     321              : 
     322          497 :   if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
     323              :     {
     324          495 :       lexer.skip_token ();
     325          495 :       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          497 : }
     333              : 
     334              : template <typename ManagedTokenSource>
     335              : bool
     336         1500 : Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
     337              : {
     338         1500 :   auto macro_name = lexer.peek_token (2)->get_id ();
     339              : 
     340         1500 :   bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
     341              : 
     342         1500 :   return t->get_str () == Values::WeakKeywords::MACRO_RULES
     343         2435 :          && 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        24019 : 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        24019 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
     363        24019 :   const_TokenPtr t = lexer.peek_token ();
     364              : 
     365        24019 :   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        22665 :     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        22665 :         auto vis_item = parse_vis_item (std::move (outer_attrs));
     403        22665 :         if (!vis_item)
     404              :           return Parse::Error::Item::make_malformed ();
     405        22615 :         return RType{std::move (vis_item)};
     406        22665 :       }
     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         1344 :     case IDENTIFIER:
     421              :       // TODO: ensure std::string and literal comparison works
     422         2629 :       if (t->get_str () == Values::WeakKeywords::UNION
     423         1407 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
     424              :         {
     425           63 :           auto vis_item = parse_vis_item (std::move (outer_attrs));
     426           63 :           if (!vis_item)
     427              :             return Parse::Error::Item::make_malformed ();
     428           63 :           return RType{std::move (vis_item)};
     429              :           // or should this go straight to parsing union?
     430           63 :         }
     431         2503 :       else if (t->get_str () == Values::WeakKeywords::DEFAULT
     432         1283 :                && 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         2560 :       else if (is_macro_rules_def (t))
     440              :         {
     441              :           // macro_rules! macro item
     442          931 :           auto macro_rule_def = parse_macro_rules_def (std::move (outer_attrs));
     443          931 :           if (!macro_rule_def)
     444              :             return Parse::Error::Item::make_malformed ();
     445          918 :           return RType{std::move (macro_rule_def)};
     446          931 :         }
     447          698 :       else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
     448          697 :                || lexer.peek_token (1)->get_id () == EXCLAM)
     449              :         {
     450              :           /* path (probably) or macro invocation, so probably a macro invocation
     451              :            * semi */
     452          346 :           auto macro_invocation_semi
     453          346 :             = parse_macro_invocation_semi (std::move (outer_attrs));
     454          346 :           if (!macro_invocation_semi)
     455              :             return Parse::Error::Item::make_malformed ();
     456          345 :           return RType{std::move (macro_invocation_semi)};
     457          346 :         }
     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        24019 : }
     471              : 
     472              : // Parses a VisItem (item that can have non-default visibility).
     473              : template <typename ManagedTokenSource>
     474              : std::unique_ptr<AST::VisItem>
     475        23272 : Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
     476              : {
     477              :   // parse visibility, which may or may not exist
     478        23272 :   auto vis_res = parse_visibility ();
     479        23272 :   if (!vis_res)
     480            0 :     return nullptr;
     481        23272 :   auto vis = vis_res.value ();
     482              : 
     483              :   // select VisItem to create depending on keyword
     484        23272 :   const_TokenPtr t = lexer.peek_token ();
     485              : 
     486        23272 :   switch (t->get_id ())
     487              :     {
     488         1366 :     case MOD:
     489         1366 :       return parse_module (std::move (vis), std::move (outer_attrs));
     490         1510 :     case EXTERN_KW:
     491              :       // lookahead to resolve syntactical production
     492         1510 :       t = lexer.peek_token (1);
     493              : 
     494         1510 :       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         1483 :         case STRING_LITERAL: // for specifying extern ABI
     503              :           // could be extern block or extern function, so more lookahead
     504         1483 :           t = lexer.peek_token (2);
     505              : 
     506         1483 :           switch (t->get_id ())
     507              :             {
     508            2 :             case FN_KW:
     509            2 :               return parse_function (std::move (vis), std::move (outer_attrs));
     510         1481 :             case LEFT_CURLY:
     511         1481 :               return parse_extern_block (std::move (vis),
     512         1481 :                                          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          679 :     case USE:
     532          679 :       return parse_use_decl (std::move (vis), std::move (outer_attrs));
     533         6377 :     case FN_KW:
     534         6377 :       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         2691 :     case STRUCT_KW:
     538         2691 :       return parse_struct (std::move (vis), std::move (outer_attrs));
     539          547 :     case ENUM_KW:
     540          547 :       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          107 :     case IDENTIFIER:
     544          214 :       if (t->get_str () == Values::WeakKeywords::UNION
     545          214 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
     546              :         {
     547          107 :           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          558 :     case CONST:
     555              :       // lookahead to resolve syntactical production
     556          558 :       t = lexer.peek_token (1);
     557              : 
     558          558 :       switch (t->get_id ())
     559              :         {
     560          474 :         case IDENTIFIER:
     561              :         case UNDERSCORE:
     562          474 :           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           67 :     case STATIC_KW:
     583           67 :       return parse_static_item (std::move (vis), std::move (outer_attrs));
     584         3712 :     case AUTO:
     585              :     case TRAIT:
     586         3712 :       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        23272 : }
     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          940 : Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
     662              : {
     663              :   // ensure that first token is identifier saying "macro_rules"
     664          940 :   const_TokenPtr t = lexer.peek_token ();
     665          940 :   if (t->get_id () != IDENTIFIER
     666          940 :       || 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          940 :   lexer.skip_token ();
     677          940 :   location_t macro_locus = t->get_locus ();
     678              : 
     679          940 :   if (!skip_token (EXCLAM))
     680              :     {
     681              :       // skip after somewhere?
     682            0 :       return nullptr;
     683              :     }
     684              : 
     685              :   // parse macro name
     686          940 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
     687          940 :   if (ident_tok == nullptr)
     688              :     {
     689            1 :       return nullptr;
     690              :     }
     691          939 :   Identifier rule_name{ident_tok};
     692              : 
     693              :   // DEBUG
     694          939 :   rust_debug ("in macro rules def, about to parse parens.");
     695              : 
     696              :   // save delim type to ensure it is reused later
     697          939 :   AST::DelimType delim_type = AST::PARENS;
     698              : 
     699              :   // Map tokens to DelimType
     700          939 :   t = lexer.peek_token ();
     701          939 :   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          938 :     case LEFT_CURLY:
     710          938 :       delim_type = AST::CURLY;
     711          938 :       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          939 :   lexer.skip_token ();
     721              : 
     722              :   // parse actual macro rules
     723          939 :   std::vector<AST::MacroRule> macro_rules;
     724              : 
     725              :   // must be at least one macro rule, so parse it
     726          939 :   AST::MacroRule initial_rule = parse_macro_rule ();
     727          939 :   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          927 :   macro_rules.push_back (std::move (initial_rule));
     738              : 
     739              :   // DEBUG
     740          927 :   rust_debug ("successfully pushed back initial macro rule");
     741              : 
     742          927 :   t = lexer.peek_token ();
     743              :   // parse macro rules
     744         1052 :   while (t->get_id () == SEMICOLON)
     745              :     {
     746              :       // skip semicolon
     747          628 :       lexer.skip_token ();
     748              : 
     749              :       // don't parse if end of macro rules
     750         1256 :       if (Parse::Utils::token_id_matches_delims (lexer.peek_token ()->get_id (),
     751              :                                                  delim_type))
     752              :         {
     753              :           // DEBUG
     754          503 :           rust_debug (
     755              :             "broke out of parsing macro rules loop due to finding delim");
     756              : 
     757          503 :           break;
     758              :         }
     759              : 
     760              :       // try to parse next rule
     761          125 :       AST::MacroRule rule = parse_macro_rule ();
     762          125 :       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          125 :       macro_rules.push_back (std::move (rule));
     772              : 
     773              :       // DEBUG
     774          125 :       rust_debug ("successfully pushed back another macro rule");
     775              : 
     776          125 :       t = lexer.peek_token ();
     777              :     }
     778              : 
     779              :   // parse end delimiters
     780          927 :   t = lexer.peek_token ();
     781          927 :   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
     782              :     {
     783              :       // tokens match opening delimiter, so skip.
     784          927 :       lexer.skip_token ();
     785              : 
     786          927 :       if (delim_type != AST::CURLY)
     787              :         {
     788              :           // skip semicolon at end of non-curly macro definitions
     789            1 :           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         1854 :         AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
     801              :                                         std::move (macro_rules),
     802          927 :                                         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         2818 : }
     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        41980 : Parser<ManagedTokenSource>::parse_visibility ()
     989              : {
     990              :   // check for no visibility
     991        83960 :   if (lexer.peek_token ()->get_id () != PUB)
     992              :     {
     993        33665 :       return AST::Visibility::create_private ();
     994              :     }
     995              : 
     996         8315 :   auto vis_loc = lexer.peek_token ()->get_locus ();
     997         8315 :   lexer.skip_token ();
     998              : 
     999              :   // create simple pub visibility if
    1000              :   // - found no parentheses
    1001              :   // - found unit type `()`
    1002        16630 :   if (lexer.peek_token ()->get_id () != LEFT_PAREN
    1003         8382 :       || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
    1004              :     {
    1005         8249 :       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         1367 : Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
    1068              :                                           AST::AttrVec outer_attrs)
    1069              : {
    1070         1367 :   location_t locus = lexer.peek_token ()->get_locus ();
    1071              : 
    1072         1367 :   Unsafety safety = Unsafety::Normal;
    1073         2734 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    1074              :     {
    1075            1 :       safety = Unsafety::Unsafe;
    1076            1 :       skip_token (UNSAFE);
    1077              :     }
    1078              : 
    1079         1367 :   skip_token (MOD);
    1080              : 
    1081         1367 :   const_TokenPtr module_name = expect_token (IDENTIFIER);
    1082         1367 :   if (module_name == nullptr)
    1083              :     {
    1084            0 :       return nullptr;
    1085              :     }
    1086         1367 :   Identifier name{module_name};
    1087              : 
    1088         1367 :   const_TokenPtr t = lexer.peek_token ();
    1089              : 
    1090         1367 :   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         1229 :     case LEFT_CURLY:
    1101              :       {
    1102         1229 :         lexer.skip_token ();
    1103              : 
    1104              :         // parse inner attributes
    1105         1229 :         AST::AttrVec inner_attrs = parse_inner_attributes ();
    1106              : 
    1107         1229 :         std::string default_path = name.as_string ();
    1108              : 
    1109         1229 :         if (inline_module_stack.empty ())
    1110              :           {
    1111          702 :             std::string filename = lexer.get_filename ();
    1112          702 :             auto slash_idx = filename.rfind (file_separator);
    1113          702 :             if (slash_idx == std::string::npos)
    1114              :               slash_idx = 0;
    1115              :             else
    1116          702 :               slash_idx++;
    1117          702 :             filename = filename.substr (slash_idx);
    1118              : 
    1119          702 :             std::string subdir;
    1120          702 :             if (get_file_subdir (filename, subdir))
    1121          702 :               default_path = subdir + file_separator + name.as_string ();
    1122          702 :           }
    1123              : 
    1124         1229 :         std::string module_path_name
    1125              :           = extract_module_path (inner_attrs, outer_attrs, default_path);
    1126         1229 :         InlineModuleStackScope scope (*this, std::move (module_path_name));
    1127              : 
    1128              :         // parse items
    1129         1229 :         std::vector<std::unique_ptr<AST::Item>> items;
    1130         1229 :         const_TokenPtr tok = lexer.peek_token ();
    1131         4063 :         while (tok->get_id () != RIGHT_CURLY)
    1132              :           {
    1133         2834 :             auto item = parse_item (false);
    1134         2834 :             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         2834 :             items.push_back (std::move (item.value ()));
    1144              : 
    1145         2834 :             tok = lexer.peek_token ();
    1146              :           }
    1147              : 
    1148         1229 :         if (!skip_token (RIGHT_CURLY))
    1149              :           {
    1150              :             // skip somewhere?
    1151            0 :             return nullptr;
    1152              :           }
    1153              : 
    1154              :         return std::unique_ptr<AST::Module> (
    1155         1229 :           new AST::Module (std::move (name), locus, std::move (items),
    1156              :                            std::move (vis), safety, std::move (inner_attrs),
    1157         1229 :                            std::move (outer_attrs))); // module name?
    1158         1229 :       }
    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         1367 : }
    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          679 : Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
    1270              :                                             AST::AttrVec outer_attrs)
    1271              : {
    1272          679 :   location_t locus = lexer.peek_token ()->get_locus ();
    1273          679 :   if (!skip_token (USE))
    1274              :     {
    1275            0 :       skip_after_semicolon ();
    1276            0 :       return nullptr;
    1277              :     }
    1278              : 
    1279              :   // parse use tree, which is required
    1280          679 :   std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
    1281          679 :   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          678 :   if (!skip_token (SEMICOLON))
    1292              :     {
    1293            0 :       skip_after_semicolon ();
    1294            0 :       return nullptr;
    1295              :     }
    1296              : 
    1297              :   return std::unique_ptr<AST::UseDeclaration> (
    1298          678 :     new AST::UseDeclaration (std::move (use_tree), std::move (vis),
    1299          678 :                              std::move (outer_attrs), locus));
    1300          679 : }
    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         1264 : 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         1264 :   location_t locus = lexer.peek_token ()->get_locus ();
    1333              : 
    1334              :   // bool has_path = false;
    1335         1264 :   auto path = parse_simple_path ();
    1336              : 
    1337         1264 :   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         1262 :       const_TokenPtr t = lexer.peek_token ();
    1431              : 
    1432         1262 :       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         1090 :         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         1090 :           return std::unique_ptr<AST::UseTreeRebind> (
    1478         3270 :             new AST::UseTreeRebind (AST::UseTreeRebind::NONE,
    1479         1090 :                                     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          165 :       skip_token ();
    1491          165 :       t = lexer.peek_token ();
    1492              : 
    1493          165 :       switch (t->get_id ())
    1494              :         {
    1495           11 :         case ASTERISK:
    1496              :           // glob UseTree type
    1497           11 :           lexer.skip_token ();
    1498              : 
    1499           11 :           return std::unique_ptr<AST::UseTreeGlob> (
    1500           33 :             new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
    1501           11 :                                   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         1262 :     }
    1549         1264 : }
    1550              : 
    1551              : // Parses a function (not a method).
    1552              : template <typename ManagedTokenSource>
    1553              : std::unique_ptr<AST::Function>
    1554        11454 : Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
    1555              :                                             AST::AttrVec outer_attrs,
    1556              :                                             bool is_external)
    1557              : {
    1558        11454 :   location_t locus = lexer.peek_token ()->get_locus ();
    1559              :   // Get qualifiers for function if they exist
    1560        11454 :   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
    1561              : 
    1562        11454 :   skip_token (FN_KW);
    1563              : 
    1564              :   // Save function name token
    1565        11454 :   const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
    1566        11454 :   if (function_name_tok == nullptr)
    1567              :     {
    1568            0 :       skip_after_next_block ();
    1569            0 :       return nullptr;
    1570              :     }
    1571        11454 :   Identifier function_name{function_name_tok};
    1572              : 
    1573              :   // parse generic params - if exist
    1574        11454 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    1575              :     = parse_generic_params_in_angles ();
    1576              : 
    1577        11454 :   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        11454 :   auto initial_param = parse_self_param ();
    1589              : 
    1590        11454 :   if (!initial_param.has_value ()
    1591        11454 :       && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
    1592            0 :     return nullptr;
    1593              : 
    1594        13704 :   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        11454 :   std::vector<std::unique_ptr<AST::Param>> function_params;
    1599              : 
    1600        22908 :   if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
    1601              :     function_params
    1602         5137 :       = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
    1603              : 
    1604        11454 :   if (initial_param.has_value ())
    1605         2250 :     function_params.insert (function_params.begin (),
    1606         2250 :                             std::move (*initial_param));
    1607              : 
    1608        11454 :   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        11454 :   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
    1621              : 
    1622              :   // parse where clause - if exists
    1623        11454 :   AST::WhereClause where_clause = parse_where_clause ();
    1624              : 
    1625        11454 :   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
    1626        22908 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    1627         3928 :     lexer.skip_token ();
    1628              :   else
    1629              :     {
    1630         7526 :       auto block_expr = parse_block_expr ();
    1631         7526 :       if (!block_expr)
    1632           28 :         return nullptr;
    1633         7498 :       body = std::move (block_expr.value ());
    1634         7526 :     }
    1635              : 
    1636              :   return std::unique_ptr<AST::Function> (
    1637        30350 :     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        11426 :                        std::move (outer_attrs), locus, false, is_external));
    1642        34362 : }
    1643              : 
    1644              : // Parses function or method qualifiers (i.e. const, unsafe, and extern).
    1645              : template <typename ManagedTokenSource>
    1646              : AST::FunctionQualifiers
    1647        18216 : Parser<ManagedTokenSource>::parse_function_qualifiers ()
    1648              : {
    1649        18216 :   Async async_status = Async::No;
    1650        18216 :   Const const_status = Const::No;
    1651        18216 :   Unsafety unsafe_status = Unsafety::Normal;
    1652        18216 :   bool has_extern = false;
    1653        18216 :   std::string abi;
    1654              : 
    1655        18216 :   const_TokenPtr t;
    1656              :   location_t locus;
    1657              :   // Check in order of const, unsafe, then extern
    1658        54648 :   for (int i = 0; i < 2; i++)
    1659              :     {
    1660        36432 :       t = lexer.peek_token ();
    1661        36432 :       locus = t->get_locus ();
    1662              : 
    1663        36432 :       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        36432 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    1680              :     {
    1681          495 :       lexer.skip_token ();
    1682          495 :       unsafe_status = Unsafety::Unsafe;
    1683              :     }
    1684              : 
    1685        36432 :   if (lexer.peek_token ()->get_id () == EXTERN_KW)
    1686              :     {
    1687           97 :       lexer.skip_token ();
    1688           97 :       has_extern = true;
    1689              : 
    1690              :       // detect optional abi name
    1691           97 :       const_TokenPtr next_tok = lexer.peek_token ();
    1692           97 :       if (next_tok->get_id () == STRING_LITERAL)
    1693              :         {
    1694           97 :           lexer.skip_token ();
    1695           97 :           abi = next_tok->get_str ();
    1696              :         }
    1697           97 :     }
    1698              : 
    1699        36432 :   return AST::FunctionQualifiers (locus, async_status, const_status,
    1700        18216 :                                   unsafe_status, has_extern, std::move (abi));
    1701        18216 : }
    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        31861 : Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
    1707              : {
    1708        63722 :   if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
    1709              :     {
    1710              :       // seems to be no generic params, so exit with empty vector
    1711        27637 :       return std::vector<std::unique_ptr<AST::GenericParam>> ();
    1712              :     }
    1713         4224 :   lexer.skip_token ();
    1714              : 
    1715              :   // DEBUG:
    1716         4224 :   rust_debug ("skipped left angle in generic param");
    1717              : 
    1718         4224 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    1719              :     = parse_generic_params (Parse::Utils::is_right_angle_tok);
    1720              : 
    1721              :   // DEBUG:
    1722         4224 :   rust_debug ("finished parsing actual generic params (i.e. inside angles)");
    1723              : 
    1724         4224 :   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         4223 :   return generic_params;
    1734         4224 : }
    1735              : 
    1736              : template <typename ManagedTokenSource>
    1737              : template <typename EndTokenPred>
    1738              : std::unique_ptr<AST::GenericParam>
    1739         4621 : Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
    1740              : {
    1741         4621 :   auto outer_attrs = parse_outer_attributes ();
    1742         4621 :   std::unique_ptr<AST::GenericParam> param;
    1743         4621 :   auto token = lexer.peek_token ();
    1744              : 
    1745         4621 :   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         4263 :     case IDENTIFIER:
    1776              :       {
    1777         4263 :         auto type_ident = token->get_str ();
    1778         4263 :         lexer.skip_token ();
    1779              : 
    1780         4263 :         std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    1781         8526 :         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         4263 :         std::unique_ptr<AST::Type> type = nullptr;
    1790         8526 :         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         4263 :         param = std::unique_ptr<AST::TypeParam> (
    1808        12789 :           new AST::TypeParam (std::move (type_ident), token->get_locus (),
    1809              :                               std::move (type_param_bounds), std::move (type),
    1810         4263 :                               std::move (outer_attrs)));
    1811              :         break;
    1812         4263 :       }
    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         4617 :   return param;
    1871         4621 : }
    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         4224 : Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
    1879              : {
    1880         4224 :   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         4224 :   AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
    1888              : 
    1889              :   // Did we parse a generic type param yet
    1890         4224 :   auto type_seen = false;
    1891              :   // Did we parse a const param with a default value yet
    1892         4224 :   auto const_with_default_seen = false;
    1893              :   // Did the user write a lifetime parameter after a type one
    1894         4224 :   auto order_error = false;
    1895              :   // Did the user write a const param with a default value after a type one
    1896         4224 :   auto const_with_default_order_error = false;
    1897              : 
    1898              :   // parse lifetime params
    1899        22303 :   while (!is_end_token (lexer.peek_token ()->get_id ()))
    1900              :     {
    1901         4621 :       auto param = parse_generic_param (is_end_token);
    1902         4621 :       if (param)
    1903              :         {
    1904         4617 :           if (param->get_kind () == AST::GenericParam::Kind::Type)
    1905              :             {
    1906         4263 :               type_seen = true;
    1907         4263 :               if (const_with_default_seen)
    1908         4617 :                 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         4617 :                 const_with_default_order_error = true;
    1926              :             }
    1927              : 
    1928         4617 :           generic_params.emplace_back (std::move (param));
    1929         4617 :           maybe_skip_token (COMMA);
    1930              :         }
    1931              :       else
    1932              :         break;
    1933              :     }
    1934              : 
    1935              :   // FIXME: Add reordering hint
    1936         4224 :   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         4224 :   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         4224 :   generic_params.shrink_to_fit ();
    1952         4224 :   return generic_params;
    1953         4224 : }
    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        10033 : Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
    2305              : {
    2306        10033 :   std::vector<std::unique_ptr<AST::Param>> params;
    2307              : 
    2308        20066 :   if (is_end_token (lexer.peek_token ()->get_id ()))
    2309          827 :     return params;
    2310              : 
    2311         9206 :   auto initial_param = parse_function_param ();
    2312              : 
    2313              :   // Return empty parameter list if no parameter there
    2314         9206 :   if (initial_param == nullptr)
    2315              :     {
    2316              :       // TODO: is this an error?
    2317            0 :       return params;
    2318              :     }
    2319              : 
    2320         9206 :   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         9206 :   const_TokenPtr t = lexer.peek_token ();
    2326        11461 :   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         9206 :   params.shrink_to_fit ();
    2353         9206 :   return params;
    2354        10033 : }
    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        11461 : Parser<ManagedTokenSource>::parse_function_param ()
    2361              : {
    2362              :   // parse outer attributes if they exist
    2363        11461 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    2364              : 
    2365              :   // TODO: should saved location be at start of outer attributes or pattern?
    2366        11461 :   location_t locus = lexer.peek_token ()->get_locus ();
    2367              : 
    2368        22922 :   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        10634 :   std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
    2376              : 
    2377              :   // create error function param if it doesn't exist
    2378        10634 :   if (param_pattern == nullptr)
    2379              :     {
    2380              :       // skip after something
    2381            0 :       return nullptr;
    2382              :     }
    2383              : 
    2384        10634 :   if (!skip_token (COLON))
    2385              :     {
    2386              :       // skip after something
    2387            0 :       return nullptr;
    2388              :     }
    2389              : 
    2390        21268 :   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        10623 :       std::unique_ptr<AST::Type> param_type = parse_type ();
    2400        10623 :       if (param_type == nullptr)
    2401              :         {
    2402            0 :           return nullptr;
    2403              :         }
    2404        10623 :       return std::make_unique<AST::FunctionParam> (
    2405        21246 :         AST::FunctionParam (std::move (param_pattern), std::move (param_type),
    2406        10623 :                             std::move (outer_attrs), locus));
    2407        10623 :     }
    2408        11461 : }
    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        18170 : Parser<ManagedTokenSource>::parse_function_return_type ()
    2415              : {
    2416        36340 :   if (lexer.peek_token ()->get_id () != RETURN_TYPE)
    2417         5545 :     return nullptr;
    2418              : 
    2419              :   // skip return type, as it now obviously exists
    2420        12625 :   lexer.skip_token ();
    2421              : 
    2422        12625 :   std::unique_ptr<AST::Type> type = parse_type ();
    2423              : 
    2424        12625 :   return type;
    2425        12625 : }
    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        31847 : Parser<ManagedTokenSource>::parse_where_clause ()
    2434              : {
    2435        31847 :   const_TokenPtr where_tok = lexer.peek_token ();
    2436        31847 :   if (where_tok->get_id () != WHERE)
    2437              :     {
    2438              :       // where clause doesn't exist, so create empty one
    2439        31558 :       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         2691 : 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         2691 :   location_t locus = lexer.peek_token ()->get_locus ();
    2976         2691 :   skip_token (STRUCT_KW);
    2977              : 
    2978              :   // parse struct name
    2979         2691 :   const_TokenPtr name_tok = expect_token (IDENTIFIER);
    2980         2691 :   if (name_tok == nullptr)
    2981              :     {
    2982            0 :       Error error (lexer.peek_token ()->get_locus (),
    2983              :                    "could not parse struct or tuple struct identifier");
    2984            0 :       add_error (std::move (error));
    2985              : 
    2986              :       // skip after somewhere?
    2987            0 :       return nullptr;
    2988            0 :     }
    2989         2691 :   Identifier struct_name{name_tok};
    2990              : 
    2991              :   // parse generic params, which may or may not exist
    2992         2691 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    2993              :     = parse_generic_params_in_angles ();
    2994              : 
    2995              :   // branch on next token - determines whether proper struct or tuple struct
    2996         5382 :   if (lexer.peek_token ()->get_id () == LEFT_PAREN)
    2997              :     {
    2998              :       // tuple struct
    2999              : 
    3000              :       // skip left parenthesis
    3001          990 :       lexer.skip_token ();
    3002              : 
    3003              :       // parse tuple fields
    3004          990 :       std::vector<AST::TupleField> tuple_fields;
    3005              :       // Might be empty tuple for unit tuple struct.
    3006         1980 :       if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    3007           23 :         tuple_fields = std::vector<AST::TupleField> ();
    3008              :       else
    3009          967 :         tuple_fields = parse_tuple_fields ();
    3010              : 
    3011              :       // tuple parameters must have closing parenthesis
    3012          990 :       if (!skip_token (RIGHT_PAREN))
    3013              :         {
    3014            1 :           skip_after_semicolon ();
    3015            1 :           return nullptr;
    3016              :         }
    3017              : 
    3018              :       // parse where clause, which is optional
    3019          989 :       AST::WhereClause where_clause = parse_where_clause ();
    3020              : 
    3021          989 :       if (!skip_token (SEMICOLON))
    3022              :         {
    3023              :           // can't skip after semicolon because it's meant to be here
    3024            0 :           return nullptr;
    3025              :         }
    3026              : 
    3027          989 :       return std::unique_ptr<AST::TupleStruct> (
    3028          989 :         new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name),
    3029              :                               std::move (generic_params),
    3030              :                               std::move (where_clause), std::move (vis),
    3031          989 :                               std::move (outer_attrs), locus));
    3032          990 :     }
    3033              : 
    3034              :   // assume it is a proper struct being parsed and continue outside of switch
    3035              :   // - label only here to suppress warning
    3036              : 
    3037              :   // parse where clause, which is optional
    3038         1701 :   AST::WhereClause where_clause = parse_where_clause ();
    3039              : 
    3040              :   // branch on next token - determines whether struct is a unit struct
    3041         1701 :   const_TokenPtr t = lexer.peek_token ();
    3042         1701 :   switch (t->get_id ())
    3043              :     {
    3044          945 :     case LEFT_CURLY:
    3045              :       {
    3046              :         // struct with body
    3047              : 
    3048              :         // skip curly bracket
    3049          945 :         lexer.skip_token ();
    3050              : 
    3051              :         // parse struct fields, if any
    3052          945 :         std::vector<AST::StructField> struct_fields
    3053              :           = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
    3054              : 
    3055          945 :         if (!skip_token (RIGHT_CURLY))
    3056              :           {
    3057              :             // skip somewhere?
    3058            0 :             return nullptr;
    3059              :           }
    3060              : 
    3061          945 :         return std::unique_ptr<AST::StructStruct> (new AST::StructStruct (
    3062              :           std::move (struct_fields), std::move (struct_name),
    3063              :           std::move (generic_params), std::move (where_clause), false,
    3064          945 :           std::move (vis), std::move (outer_attrs), locus));
    3065          945 :       }
    3066          755 :     case SEMICOLON:
    3067              :       // unit struct declaration
    3068              : 
    3069          755 :       lexer.skip_token ();
    3070              : 
    3071          755 :       return std::unique_ptr<AST::StructStruct> (
    3072         1510 :         new AST::StructStruct (std::move (struct_name),
    3073              :                                std::move (generic_params),
    3074              :                                std::move (where_clause), std::move (vis),
    3075          755 :                                std::move (outer_attrs), locus));
    3076            1 :     default:
    3077            1 :       add_error (Error (t->get_locus (),
    3078              :                         "unexpected token %qs in struct declaration",
    3079              :                         t->get_token_description ()));
    3080              : 
    3081              :       // skip somewhere?
    3082            1 :       return nullptr;
    3083              :     }
    3084         2691 : }
    3085              : 
    3086              : // Parses struct fields in struct declarations.
    3087              : template <typename ManagedTokenSource>
    3088              : std::vector<AST::StructField>
    3089            0 : Parser<ManagedTokenSource>::parse_struct_fields ()
    3090              : {
    3091            0 :   std::vector<AST::StructField> fields;
    3092              : 
    3093            0 :   AST::StructField initial_field = parse_struct_field ();
    3094              : 
    3095              :   // Return empty field list if no field there
    3096            0 :   if (initial_field.is_error ())
    3097              :     return fields;
    3098              : 
    3099            0 :   fields.push_back (std::move (initial_field));
    3100              : 
    3101            0 :   while (lexer.peek_token ()->get_id () == COMMA)
    3102              :     {
    3103            0 :       lexer.skip_token ();
    3104              : 
    3105            0 :       AST::StructField field = parse_struct_field ();
    3106              : 
    3107            0 :       if (field.is_error ())
    3108              :         {
    3109              :           // would occur with trailing comma, so allowed
    3110              :           break;
    3111              :         }
    3112              : 
    3113            0 :       fields.push_back (std::move (field));
    3114              :     }
    3115              : 
    3116            0 :   fields.shrink_to_fit ();
    3117              :   return fields;
    3118              :   // TODO: template if possible (parse_non_ptr_seq)
    3119            0 : }
    3120              : 
    3121              : // Parses struct fields in struct declarations.
    3122              : template <typename ManagedTokenSource>
    3123              : template <typename EndTokenPred>
    3124              : std::vector<AST::StructField>
    3125         1147 : Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
    3126              : {
    3127         1147 :   std::vector<AST::StructField> fields;
    3128              : 
    3129         1147 :   AST::StructField initial_field = parse_struct_field ();
    3130              : 
    3131              :   // Return empty field list if no field there
    3132         1147 :   if (initial_field.is_error ())
    3133           45 :     return fields;
    3134              : 
    3135         1102 :   fields.push_back (std::move (initial_field));
    3136              : 
    3137         4524 :   while (lexer.peek_token ()->get_id () == COMMA)
    3138              :     {
    3139         2077 :       lexer.skip_token ();
    3140              : 
    3141         4154 :       if (is_end_tok (lexer.peek_token ()->get_id ()))
    3142              :         break;
    3143              : 
    3144         1160 :       AST::StructField field = parse_struct_field ();
    3145         1160 :       if (field.is_error ())
    3146              :         {
    3147              :           /* TODO: should every field be ditched just because one couldn't be
    3148              :            * parsed? */
    3149            0 :           Error error (lexer.peek_token ()->get_locus (),
    3150              :                        "failed to parse struct field in struct fields");
    3151            0 :           add_error (std::move (error));
    3152              : 
    3153            0 :           return {};
    3154            0 :         }
    3155              : 
    3156         1160 :       fields.push_back (std::move (field));
    3157              :     }
    3158              : 
    3159         1102 :   fields.shrink_to_fit ();
    3160         1102 :   return fields;
    3161              :   // TODO: template if possible (parse_non_ptr_seq)
    3162         1147 : }
    3163              : 
    3164              : // Parses a single struct field (in a struct definition). Does not parse
    3165              : // commas.
    3166              : template <typename ManagedTokenSource>
    3167              : AST::StructField
    3168         2307 : Parser<ManagedTokenSource>::parse_struct_field ()
    3169              : {
    3170              :   // parse outer attributes, if they exist
    3171         2307 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3172              : 
    3173              :   // parse visibility, if it exists
    3174         2307 :   auto vis = parse_visibility ();
    3175         2307 :   if (!vis)
    3176            0 :     return AST::StructField::create_error ();
    3177              : 
    3178         2307 :   location_t locus = lexer.peek_token ()->get_locus ();
    3179              : 
    3180              :   // parse field name
    3181         2307 :   const_TokenPtr field_name_tok = lexer.peek_token ();
    3182         2307 :   if (field_name_tok->get_id () != IDENTIFIER)
    3183              :     {
    3184              :       // if not identifier, assumes there is no struct field and exits - not
    3185              :       // necessarily error
    3186           45 :       return AST::StructField::create_error ();
    3187              :     }
    3188         2262 :   Identifier field_name{field_name_tok};
    3189         2262 :   lexer.skip_token ();
    3190              : 
    3191         2262 :   if (!skip_token (COLON))
    3192              :     {
    3193              :       // skip after somewhere?
    3194            0 :       return AST::StructField::create_error ();
    3195              :     }
    3196              : 
    3197              :   // parse field type - this is required
    3198         2262 :   std::unique_ptr<AST::Type> field_type = parse_type ();
    3199         2262 :   if (field_type == nullptr)
    3200              :     {
    3201            0 :       Error error (lexer.peek_token ()->get_locus (),
    3202              :                    "could not parse type in struct field definition");
    3203            0 :       add_error (std::move (error));
    3204              : 
    3205              :       // skip after somewhere
    3206            0 :       return AST::StructField::create_error ();
    3207            0 :     }
    3208              : 
    3209         4524 :   return AST::StructField (std::move (field_name), std::move (field_type),
    3210         2262 :                            std::move (vis.value ()), locus,
    3211         2262 :                            std::move (outer_attrs));
    3212         9138 : }
    3213              : 
    3214              : // Parses tuple fields in tuple/tuple struct declarations.
    3215              : template <typename ManagedTokenSource>
    3216              : std::vector<AST::TupleField>
    3217         1392 : Parser<ManagedTokenSource>::parse_tuple_fields ()
    3218              : {
    3219         1392 :   std::vector<AST::TupleField> fields;
    3220              : 
    3221         1392 :   AST::TupleField initial_field = parse_tuple_field ();
    3222              : 
    3223              :   // Return empty field list if no field there
    3224         1392 :   if (initial_field.is_error ())
    3225              :     {
    3226            1 :       return fields;
    3227              :     }
    3228              : 
    3229         1391 :   fields.push_back (std::move (initial_field));
    3230              : 
    3231              :   // maybe think of a better control structure here - do-while with an initial
    3232              :   // error state? basically, loop through field list until can't find any more
    3233              :   // params HACK: all current syntax uses of tuple fields have them ending
    3234              :   // with a right paren token
    3235         1391 :   const_TokenPtr t = lexer.peek_token ();
    3236         2129 :   while (t->get_id () == COMMA)
    3237              :     {
    3238              :       // skip comma if applies - e.g. trailing comma
    3239          739 :       lexer.skip_token ();
    3240              : 
    3241              :       // break out due to right paren if it exists
    3242         1478 :       if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    3243              :         {
    3244              :           break;
    3245              :         }
    3246              : 
    3247          738 :       AST::TupleField field = parse_tuple_field ();
    3248          738 :       if (field.is_error ())
    3249              :         {
    3250            0 :           Error error (lexer.peek_token ()->get_locus (),
    3251              :                        "failed to parse tuple field in tuple fields");
    3252            0 :           add_error (std::move (error));
    3253              : 
    3254            0 :           return std::vector<AST::TupleField> ();
    3255            0 :         }
    3256              : 
    3257          738 :       fields.push_back (std::move (field));
    3258              : 
    3259          738 :       t = lexer.peek_token ();
    3260              :     }
    3261              : 
    3262         1391 :   fields.shrink_to_fit ();
    3263         1391 :   return fields;
    3264              : 
    3265              :   // TODO: this shares basically all code with function params and struct
    3266              :   // fields
    3267              :   // - templates?
    3268         1392 : }
    3269              : 
    3270              : /* Parses a single tuple struct field in a tuple struct definition. Does not
    3271              :  * parse commas. */
    3272              : template <typename ManagedTokenSource>
    3273              : AST::TupleField
    3274         2130 : Parser<ManagedTokenSource>::parse_tuple_field ()
    3275              : {
    3276              :   // parse outer attributes if they exist
    3277         2130 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3278              : 
    3279              :   // parse visibility if it exists
    3280         2130 :   auto visibility = parse_visibility ();
    3281         2130 :   if (!visibility)
    3282            0 :     return AST::TupleField::create_error ();
    3283              : 
    3284         2130 :   location_t locus = lexer.peek_token ()->get_locus ();
    3285              : 
    3286              :   // parse type, which is required
    3287         2130 :   std::unique_ptr<AST::Type> field_type = parse_type ();
    3288         2130 :   if (field_type == nullptr)
    3289              :     {
    3290              :       // error if null
    3291            1 :       Error error (lexer.peek_token ()->get_locus (),
    3292              :                    "could not parse type in tuple struct field");
    3293            1 :       add_error (std::move (error));
    3294              : 
    3295              :       // skip after something
    3296            1 :       return AST::TupleField::create_error ();
    3297            1 :     }
    3298              : 
    3299         2129 :   return AST::TupleField (std::move (field_type),
    3300         2129 :                           std::move (visibility.value ()), locus,
    3301         2129 :                           std::move (outer_attrs));
    3302         4260 : }
    3303              : 
    3304              : // Parses a Rust "enum" tagged union item definition.
    3305              : template <typename ManagedTokenSource>
    3306              : std::unique_ptr<AST::Enum>
    3307          547 : Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
    3308              :                                         AST::AttrVec outer_attrs)
    3309              : {
    3310          547 :   location_t locus = lexer.peek_token ()->get_locus ();
    3311          547 :   skip_token (ENUM_KW);
    3312              : 
    3313              :   // parse enum name
    3314          547 :   const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
    3315          547 :   if (enum_name_tok == nullptr)
    3316            0 :     return nullptr;
    3317              : 
    3318          547 :   Identifier enum_name = {enum_name_tok};
    3319              : 
    3320              :   // parse generic params (of enum container, not enum variants) if they exist
    3321          547 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3322              :     = parse_generic_params_in_angles ();
    3323              : 
    3324              :   // parse where clause if it exists
    3325          547 :   AST::WhereClause where_clause = parse_where_clause ();
    3326              : 
    3327          547 :   if (!skip_token (LEFT_CURLY))
    3328              :     {
    3329            0 :       skip_after_end_block ();
    3330            0 :       return nullptr;
    3331              :     }
    3332              : 
    3333              :   // parse actual enum variant definitions
    3334          547 :   std::vector<std::unique_ptr<AST::EnumItem>> enum_items
    3335              :     = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
    3336              : 
    3337          547 :   if (!skip_token (RIGHT_CURLY))
    3338              :     {
    3339            0 :       skip_after_end_block ();
    3340            0 :       return nullptr;
    3341              :     }
    3342              : 
    3343              :   return std::unique_ptr<AST::Enum> (
    3344          547 :     new AST::Enum (std::move (enum_name), std::move (vis),
    3345              :                    std::move (generic_params), std::move (where_clause),
    3346          547 :                    std::move (enum_items), std::move (outer_attrs), locus));
    3347         1094 : }
    3348              : 
    3349              : // Parses the enum variants inside an enum definiton.
    3350              : template <typename ManagedTokenSource>
    3351              : std::vector<std::unique_ptr<AST::EnumItem>>
    3352            0 : Parser<ManagedTokenSource>::parse_enum_items ()
    3353              : {
    3354            0 :   std::vector<std::unique_ptr<AST::EnumItem>> items;
    3355              : 
    3356            0 :   std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
    3357              : 
    3358              :   // Return empty item list if no field there
    3359            0 :   if (initial_item == nullptr)
    3360              :     return items;
    3361              : 
    3362            0 :   items.push_back (std::move (initial_item));
    3363              : 
    3364            0 :   while (lexer.peek_token ()->get_id () == COMMA)
    3365              :     {
    3366            0 :       lexer.skip_token ();
    3367              : 
    3368            0 :       std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
    3369            0 :       if (item == nullptr)
    3370              :         {
    3371              :           // this would occur with a trailing comma, which is allowed
    3372              :           break;
    3373              :         }
    3374              : 
    3375            0 :       items.push_back (std::move (item));
    3376              :     }
    3377              : 
    3378            0 :   items.shrink_to_fit ();
    3379              :   return items;
    3380              : 
    3381              :   /* TODO: use template if doable (parse_non_ptr_sequence) */
    3382            0 : }
    3383              : 
    3384              : // Parses the enum variants inside an enum definiton.
    3385              : template <typename ManagedTokenSource>
    3386              : template <typename EndTokenPred>
    3387              : std::vector<std::unique_ptr<AST::EnumItem>>
    3388          547 : Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
    3389              : {
    3390          547 :   std::vector<std::unique_ptr<AST::EnumItem>> items;
    3391              : 
    3392          547 :   std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
    3393              : 
    3394              :   // Return empty item list if no field there
    3395          547 :   if (initial_item == nullptr)
    3396           14 :     return items;
    3397              : 
    3398          533 :   items.push_back (std::move (initial_item));
    3399              : 
    3400         2554 :   while (lexer.peek_token ()->get_id () == COMMA)
    3401              :     {
    3402         1244 :       lexer.skip_token ();
    3403              : 
    3404         2488 :       if (is_end_tok (lexer.peek_token ()->get_id ()))
    3405              :         break;
    3406              : 
    3407          744 :       std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
    3408          744 :       if (item == nullptr)
    3409              :         {
    3410              :           /* TODO should this ignore all successfully parsed enum items just
    3411              :            * because one failed? */
    3412            0 :           Error error (lexer.peek_token ()->get_locus (),
    3413              :                        "failed to parse enum item in enum items");
    3414            0 :           add_error (std::move (error));
    3415              : 
    3416            0 :           return {};
    3417            0 :         }
    3418              : 
    3419          744 :       items.push_back (std::move (item));
    3420              :     }
    3421              : 
    3422          533 :   items.shrink_to_fit ();
    3423          533 :   return items;
    3424              : 
    3425              :   /* TODO: use template if doable (parse_non_ptr_sequence) */
    3426          547 : }
    3427              : 
    3428              : /* Parses a single enum variant item in an enum definition. Does not parse
    3429              :  * commas. */
    3430              : template <typename ManagedTokenSource>
    3431              : std::unique_ptr<AST::EnumItem>
    3432         1291 : Parser<ManagedTokenSource>::parse_enum_item ()
    3433              : {
    3434              :   // parse outer attributes if they exist
    3435         1291 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3436              : 
    3437              :   // parse visibility, which may or may not exist
    3438         1291 :   auto vis_res = parse_visibility ();
    3439         1291 :   if (!vis_res)
    3440            0 :     return nullptr;
    3441         1291 :   auto vis = vis_res.value ();
    3442              : 
    3443              :   // parse name for enum item, which is required
    3444         1291 :   const_TokenPtr item_name_tok = lexer.peek_token ();
    3445         1291 :   if (item_name_tok->get_id () != IDENTIFIER)
    3446              :     {
    3447              :       // this may not be an error but it means there is no enum item here
    3448           14 :       return nullptr;
    3449              :     }
    3450         1277 :   lexer.skip_token ();
    3451         1277 :   Identifier item_name{item_name_tok};
    3452              : 
    3453              :   // branch based on next token
    3454         1277 :   const_TokenPtr t = lexer.peek_token ();
    3455         1277 :   switch (t->get_id ())
    3456              :     {
    3457          443 :     case LEFT_PAREN:
    3458              :       {
    3459              :         // tuple enum item
    3460          443 :         lexer.skip_token ();
    3461              : 
    3462          443 :         std::vector<AST::TupleField> tuple_fields;
    3463              :         // Might be empty tuple for unit tuple enum variant.
    3464          886 :         if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    3465           18 :           tuple_fields = std::vector<AST::TupleField> ();
    3466              :         else
    3467          425 :           tuple_fields = parse_tuple_fields ();
    3468              : 
    3469          443 :         if (!skip_token (RIGHT_PAREN))
    3470              :           {
    3471              :             // skip after somewhere
    3472            0 :             return nullptr;
    3473              :           }
    3474              : 
    3475          443 :         return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
    3476              :           std::move (item_name), std::move (vis), std::move (tuple_fields),
    3477          443 :           std::move (outer_attrs), item_name_tok->get_locus ()));
    3478          443 :       }
    3479           95 :     case LEFT_CURLY:
    3480              :       {
    3481              :         // struct enum item
    3482           95 :         lexer.skip_token ();
    3483              : 
    3484           95 :         std::vector<AST::StructField> struct_fields
    3485              :           = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
    3486              : 
    3487           95 :         if (!skip_token (RIGHT_CURLY))
    3488              :           {
    3489              :             // skip after somewhere
    3490            0 :             return nullptr;
    3491              :           }
    3492              : 
    3493           95 :         return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
    3494              :           std::move (item_name), std::move (vis), std::move (struct_fields),
    3495           95 :           std::move (outer_attrs), item_name_tok->get_locus ()));
    3496           95 :       }
    3497          278 :     case EQUAL:
    3498              :       {
    3499              :         // discriminant enum item
    3500          278 :         lexer.skip_token ();
    3501              : 
    3502          278 :         auto discriminant_expr = parse_expr ();
    3503          278 :         if (!discriminant_expr)
    3504            0 :           return nullptr;
    3505              : 
    3506          278 :         return std::unique_ptr<AST::EnumItemDiscriminant> (
    3507          556 :           new AST::EnumItemDiscriminant (std::move (item_name), std::move (vis),
    3508          278 :                                          std::move (discriminant_expr.value ()),
    3509              :                                          std::move (outer_attrs),
    3510          278 :                                          item_name_tok->get_locus ()));
    3511          278 :       }
    3512          461 :     default:
    3513              :       // regular enum with just an identifier
    3514              :       return std::unique_ptr<AST::EnumItem> (
    3515          461 :         new AST::EnumItem (std::move (item_name), std::move (vis),
    3516              :                            std::move (outer_attrs),
    3517          461 :                            item_name_tok->get_locus ()));
    3518              :     }
    3519         3859 : }
    3520              : 
    3521              : // Parses a C-style (and C-compat) untagged union declaration.
    3522              : template <typename ManagedTokenSource>
    3523              : std::unique_ptr<AST::Union>
    3524          107 : Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
    3525              :                                          AST::AttrVec outer_attrs)
    3526              : {
    3527              :   /* hack - "weak keyword" by finding identifier called "union" (lookahead in
    3528              :    * item switch) */
    3529          107 :   const_TokenPtr union_keyword = expect_token (IDENTIFIER);
    3530          107 :   rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION);
    3531          107 :   location_t locus = union_keyword->get_locus ();
    3532              : 
    3533              :   // parse actual union name
    3534          107 :   const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
    3535          107 :   if (union_name_tok == nullptr)
    3536              :     {
    3537            0 :       skip_after_next_block ();
    3538            0 :       return nullptr;
    3539              :     }
    3540          107 :   Identifier union_name{union_name_tok};
    3541              : 
    3542              :   // parse optional generic parameters
    3543          107 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3544              :     = parse_generic_params_in_angles ();
    3545              : 
    3546              :   // parse optional where clause
    3547          107 :   AST::WhereClause where_clause = parse_where_clause ();
    3548              : 
    3549          107 :   if (!skip_token (LEFT_CURLY))
    3550              :     {
    3551            0 :       skip_after_end_block ();
    3552            0 :       return nullptr;
    3553              :     }
    3554              : 
    3555              :   /* parse union inner items as "struct fields" because hey, syntax reuse.
    3556              :    * Spec said so. */
    3557          107 :   std::vector<AST::StructField> union_fields
    3558              :     = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
    3559              : 
    3560          107 :   if (!skip_token (RIGHT_CURLY))
    3561              :     {
    3562              :       // skip after somewhere
    3563            0 :       return nullptr;
    3564              :     }
    3565              : 
    3566              :   return std::unique_ptr<AST::Union> (
    3567          107 :     new AST::Union (std::move (union_name), std::move (vis),
    3568              :                     std::move (generic_params), std::move (where_clause),
    3569          107 :                     std::move (union_fields), std::move (outer_attrs), locus));
    3570          321 : }
    3571              : 
    3572              : /* Parses a "constant item" (compile-time constant to maybe "inline"
    3573              :  * throughout the program - like constexpr). */
    3574              : template <typename ManagedTokenSource>
    3575              : std::unique_ptr<AST::ConstantItem>
    3576          547 : Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
    3577              :                                               AST::AttrVec outer_attrs)
    3578              : {
    3579          547 :   location_t locus = lexer.peek_token ()->get_locus ();
    3580          547 :   skip_token (CONST);
    3581              : 
    3582              :   /* get constant identifier - this is either a proper identifier or the _
    3583              :    * wildcard */
    3584          547 :   const_TokenPtr ident_tok = lexer.peek_token ();
    3585              :   // make default identifier the underscore wildcard one
    3586          547 :   std::string ident (Values::Keywords::UNDERSCORE);
    3587          547 :   switch (ident_tok->get_id ())
    3588              :     {
    3589          547 :     case IDENTIFIER:
    3590          547 :       ident = ident_tok->get_str ();
    3591          547 :       lexer.skip_token ();
    3592              :       break;
    3593            0 :     case UNDERSCORE:
    3594              :       // do nothing - identifier is already "_"
    3595            0 :       lexer.skip_token ();
    3596              :       break;
    3597            0 :     default:
    3598            0 :       add_error (
    3599            0 :         Error (ident_tok->get_locus (),
    3600              :                "expected item name (identifier or %<_%>) in constant item "
    3601              :                "declaration - found %qs",
    3602              :                ident_tok->get_token_description ()));
    3603              : 
    3604            0 :       skip_after_semicolon ();
    3605            0 :       return nullptr;
    3606              :     }
    3607              : 
    3608          547 :   if (!skip_token (COLON))
    3609              :     {
    3610            0 :       skip_after_semicolon ();
    3611            0 :       return nullptr;
    3612              :     }
    3613              : 
    3614              :   // parse constant type (required)
    3615          547 :   std::unique_ptr<AST::Type> type = parse_type ();
    3616              : 
    3617              :   // A const with no given expression value
    3618         1094 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    3619              :     {
    3620            4 :       lexer.skip_token ();
    3621              :       return std::unique_ptr<AST::ConstantItem> (
    3622            8 :         new AST::ConstantItem (std::move (ident), std::move (vis),
    3623              :                                std::move (type), std::move (outer_attrs),
    3624            4 :                                locus));
    3625              :     }
    3626              : 
    3627          543 :   if (!skip_token (EQUAL))
    3628              :     {
    3629            0 :       skip_after_semicolon ();
    3630            0 :       return nullptr;
    3631              :     }
    3632              : 
    3633              :   // parse constant expression (required)
    3634          543 :   auto expr = parse_expr ();
    3635          543 :   if (!expr)
    3636            1 :     return nullptr;
    3637              : 
    3638          542 :   if (!skip_token (SEMICOLON))
    3639              :     {
    3640              :       // skip somewhere?
    3641            0 :       return nullptr;
    3642              :     }
    3643              : 
    3644              :   return std::unique_ptr<AST::ConstantItem> (
    3645         1084 :     new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
    3646          542 :                            std::move (expr.value ()), std::move (outer_attrs),
    3647          542 :                            locus));
    3648         1094 : }
    3649              : 
    3650              : // Parses a "static item" (static storage item, with 'static lifetime).
    3651              : template <typename ManagedTokenSource>
    3652              : std::unique_ptr<AST::StaticItem>
    3653           67 : Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
    3654              :                                                AST::AttrVec outer_attrs)
    3655              : {
    3656           67 :   location_t locus = lexer.peek_token ()->get_locus ();
    3657           67 :   skip_token (STATIC_KW);
    3658              : 
    3659              :   // determine whether static item is mutable
    3660           67 :   bool is_mut = false;
    3661          134 :   if (lexer.peek_token ()->get_id () == MUT)
    3662              :     {
    3663            4 :       is_mut = true;
    3664            4 :       lexer.skip_token ();
    3665              :     }
    3666              : 
    3667           67 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    3668           67 :   if (ident_tok == nullptr)
    3669            0 :     return nullptr;
    3670              : 
    3671           67 :   Identifier ident{ident_tok};
    3672              : 
    3673           67 :   if (!skip_token (COLON))
    3674              :     {
    3675            1 :       skip_after_semicolon ();
    3676            1 :       return nullptr;
    3677              :     }
    3678              : 
    3679              :   // parse static item type (required)
    3680           66 :   std::unique_ptr<AST::Type> type = parse_type ();
    3681              : 
    3682           66 :   if (!skip_token (EQUAL))
    3683              :     {
    3684            0 :       skip_after_semicolon ();
    3685            0 :       return nullptr;
    3686              :     }
    3687              : 
    3688              :   // parse static item expression (required)
    3689           66 :   auto expr = parse_expr ();
    3690           66 :   if (!expr)
    3691            1 :     return nullptr;
    3692              : 
    3693           65 :   if (!skip_token (SEMICOLON))
    3694              :     {
    3695              :       // skip after somewhere
    3696            0 :       return nullptr;
    3697              :     }
    3698              : 
    3699              :   return std::unique_ptr<AST::StaticItem> (
    3700          130 :     new AST::StaticItem (std::move (ident), is_mut, std::move (type),
    3701           65 :                          std::move (expr.value ()), std::move (vis),
    3702           65 :                          std::move (outer_attrs), locus));
    3703          133 : }
    3704              : 
    3705              : // Parses a trait definition item, including unsafe ones.
    3706              : template <typename ManagedTokenSource>
    3707              : std::unique_ptr<AST::Trait>
    3708         3768 : Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
    3709              :                                          AST::AttrVec outer_attrs)
    3710              : {
    3711         3768 :   location_t locus = lexer.peek_token ()->get_locus ();
    3712         3768 :   bool is_unsafe = false;
    3713         3768 :   bool is_auto_trait = false;
    3714              : 
    3715         7536 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    3716              :     {
    3717           56 :       is_unsafe = true;
    3718           56 :       lexer.skip_token ();
    3719              :     }
    3720              : 
    3721         7536 :   if (lexer.peek_token ()->get_id () == AUTO)
    3722              :     {
    3723           20 :       is_auto_trait = true;
    3724           20 :       lexer.skip_token ();
    3725              :     }
    3726              : 
    3727         3768 :   skip_token (TRAIT);
    3728              : 
    3729              :   // parse trait name
    3730         3768 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    3731         3768 :   if (ident_tok == nullptr)
    3732            0 :     return nullptr;
    3733              : 
    3734         3768 :   Identifier ident{ident_tok};
    3735              : 
    3736              :   // parse generic parameters (if they exist)
    3737         3768 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3738              :     = parse_generic_params_in_angles ();
    3739              : 
    3740              :   // create placeholder type param bounds in case they don't exist
    3741         3768 :   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    3742              : 
    3743              :   // parse type param bounds (if they exist)
    3744         7536 :   if (lexer.peek_token ()->get_id () == COLON)
    3745              :     {
    3746          538 :       lexer.skip_token ();
    3747              : 
    3748          538 :       type_param_bounds = parse_type_param_bounds (
    3749           72 :         [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
    3750              :       // type_param_bounds = parse_type_param_bounds ();
    3751              :     }
    3752              : 
    3753              :   // parse where clause (if it exists)
    3754         3768 :   AST::WhereClause where_clause = parse_where_clause ();
    3755              : 
    3756         3768 :   if (!skip_token (LEFT_CURLY))
    3757              :     {
    3758            0 :       skip_after_end_block ();
    3759            0 :       return nullptr;
    3760              :     }
    3761              : 
    3762              :   // parse inner attrs (if they exist)
    3763         3768 :   AST::AttrVec inner_attrs = parse_inner_attributes ();
    3764              : 
    3765              :   // parse trait items
    3766         3768 :   std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
    3767              : 
    3768         3768 :   const_TokenPtr t = lexer.peek_token ();
    3769         7130 :   while (t->get_id () != RIGHT_CURLY)
    3770              :     {
    3771         3362 :       std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
    3772              : 
    3773         3362 :       if (trait_item == nullptr)
    3774              :         {
    3775            0 :           Error error (lexer.peek_token ()->get_locus (),
    3776              :                        "failed to parse trait item in trait");
    3777            0 :           add_error (std::move (error));
    3778              : 
    3779            0 :           return nullptr;
    3780            0 :         }
    3781         3362 :       trait_items.push_back (std::move (trait_item));
    3782              : 
    3783         3362 :       t = lexer.peek_token ();
    3784              :     }
    3785              : 
    3786         3768 :   if (!skip_token (RIGHT_CURLY))
    3787              :     {
    3788              :       // skip after something
    3789            0 :       return nullptr;
    3790              :     }
    3791              : 
    3792         3768 :   trait_items.shrink_to_fit ();
    3793              :   return std::unique_ptr<AST::Trait> (
    3794         3768 :     new AST::Trait (std::move (ident), is_unsafe, is_auto_trait,
    3795              :                     std::move (generic_params), std::move (type_param_bounds),
    3796              :                     std::move (where_clause), std::move (trait_items),
    3797              :                     std::move (vis), std::move (outer_attrs),
    3798         3768 :                     std::move (inner_attrs), locus));
    3799         7536 : }
    3800              : 
    3801              : // Parses a trait item used inside traits (not trait, the Item).
    3802              : template <typename ManagedTokenSource>
    3803              : std::unique_ptr<AST::AssociatedItem>
    3804         3364 : Parser<ManagedTokenSource>::parse_trait_item ()
    3805              : {
    3806              :   // parse outer attributes (if they exist)
    3807         3364 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3808              : 
    3809         3364 :   auto vis_res = parse_visibility ();
    3810         3364 :   if (!vis_res)
    3811            0 :     return nullptr;
    3812              : 
    3813         3364 :   auto vis = vis_res.value ();
    3814              : 
    3815              :   // lookahead to determine what type of trait item to parse
    3816         3364 :   const_TokenPtr tok = lexer.peek_token ();
    3817         3364 :   switch (tok->get_id ())
    3818              :     {
    3819            0 :     case SUPER:
    3820              :     case SELF:
    3821              :     case CRATE:
    3822              :     case DOLLAR_SIGN:
    3823              :       // these seem to be SimplePath tokens, so this is a macro invocation
    3824              :       // semi
    3825            0 :       return parse_macro_invocation_semi (std::move (outer_attrs));
    3826            1 :     case IDENTIFIER:
    3827            2 :       if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
    3828            0 :         return parse_function (std::move (vis), std::move (outer_attrs));
    3829              :       else
    3830            2 :         return parse_macro_invocation_semi (std::move (outer_attrs));
    3831          748 :     case TYPE:
    3832          748 :       return parse_trait_type (std::move (outer_attrs), vis);
    3833           41 :     case CONST:
    3834              :       // disambiguate with function qualifier
    3835           82 :       if (lexer.peek_token (1)->get_id () == IDENTIFIER)
    3836              :         {
    3837           80 :           return parse_trait_const (std::move (outer_attrs));
    3838              :         }
    3839              :       // else, fallthrough to function
    3840              :       // TODO: find out how to disable gcc "implicit fallthrough" error
    3841              :       gcc_fallthrough ();
    3842              :     case ASYNC:
    3843              :     case UNSAFE:
    3844              :     case EXTERN_KW:
    3845              :     case FN_KW:
    3846         5150 :       return parse_function (std::move (vis), std::move (outer_attrs));
    3847              :     default:
    3848              :       break;
    3849              :     }
    3850            0 :   add_error (Error (tok->get_locus (),
    3851              :                     "unrecognised token %qs for item in trait",
    3852              :                     tok->get_token_description ()));
    3853              :   // skip?
    3854            0 :   return nullptr;
    3855         6728 : }
    3856              : 
    3857              : // Parse a typedef trait item.
    3858              : template <typename ManagedTokenSource>
    3859              : std::unique_ptr<AST::TraitItemType>
    3860          748 : Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
    3861              :                                               AST::Visibility vis)
    3862              : {
    3863          748 :   location_t locus = lexer.peek_token ()->get_locus ();
    3864          748 :   skip_token (TYPE);
    3865              : 
    3866          748 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    3867          748 :   if (ident_tok == nullptr)
    3868            0 :     return nullptr;
    3869              : 
    3870         1496 :   Identifier ident{ident_tok};
    3871              : 
    3872              :   // Parse optional generic parameters for GATs (Generic Associated Types)
    3873          748 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
    3874         1496 :   if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
    3875              :     {
    3876            9 :       generic_params = parse_generic_params_in_angles ();
    3877              :     }
    3878              : 
    3879          748 :   std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    3880              : 
    3881              :   // parse optional colon
    3882         1496 :   if (lexer.peek_token ()->get_id () == COLON)
    3883              :     {
    3884           44 :       lexer.skip_token ();
    3885              : 
    3886              :       // parse optional type param bounds
    3887              :       bounds
    3888           44 :         = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
    3889              :       // bounds = parse_type_param_bounds ();
    3890              :     }
    3891              : 
    3892          748 :   if (!skip_token (SEMICOLON))
    3893              :     {
    3894              :       // skip?
    3895            0 :       return nullptr;
    3896              :     }
    3897              : 
    3898              :   return std::unique_ptr<AST::TraitItemType> (
    3899          748 :     new AST::TraitItemType (std::move (ident), std::move (generic_params),
    3900              :                             std::move (bounds), std::move (outer_attrs), vis,
    3901          748 :                             locus));
    3902          748 : }
    3903              : 
    3904              : // Parses a constant trait item.
    3905              : template <typename ManagedTokenSource>
    3906              : std::unique_ptr<AST::ConstantItem>
    3907           40 : Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
    3908              : {
    3909           40 :   location_t locus = lexer.peek_token ()->get_locus ();
    3910           40 :   skip_token (CONST);
    3911              : 
    3912              :   // parse constant item name
    3913           40 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    3914           40 :   if (ident_tok == nullptr)
    3915            0 :     return nullptr;
    3916              : 
    3917           40 :   Identifier ident{ident_tok};
    3918              : 
    3919           40 :   if (!skip_token (COLON))
    3920              :     {
    3921            0 :       skip_after_semicolon ();
    3922            0 :       return nullptr;
    3923              :     }
    3924              : 
    3925              :   // parse constant trait item type
    3926           40 :   std::unique_ptr<AST::Type> type = parse_type ();
    3927              : 
    3928              :   // parse constant trait body expression, if it exists
    3929           40 :   std::unique_ptr<AST::Expr> const_body = nullptr;
    3930           80 :   if (lexer.peek_token ()->get_id () == EQUAL)
    3931              :     {
    3932           12 :       lexer.skip_token ();
    3933              : 
    3934              :       // expression must exist, so parse it
    3935           12 :       auto expr = parse_expr ();
    3936           12 :       if (!expr)
    3937            0 :         return nullptr;
    3938           12 :       const_body = std::move (expr.value ());
    3939           12 :     }
    3940              : 
    3941           40 :   if (!skip_token (SEMICOLON))
    3942              :     {
    3943              :       // skip after something?
    3944            0 :       return nullptr;
    3945              :     }
    3946              : 
    3947          120 :   return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem (
    3948           80 :     std::move (ident), AST::Visibility::create_private (), std::move (type),
    3949           40 :     std::move (const_body), std::move (outer_attrs), locus));
    3950           80 : }
    3951              : 
    3952              : /* Parses a struct "impl" item (both inherent impl and trait impl can be
    3953              :  * parsed here), */
    3954              : template <typename ManagedTokenSource>
    3955              : std::unique_ptr<AST::Impl>
    3956         5298 : Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
    3957              :                                         AST::AttrVec outer_attrs)
    3958              : {
    3959              :   /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
    3960              :    * must be a trait impl. However, this isn't enough for full disambiguation,
    3961              :    * so don't branch here. */
    3962         5298 :   location_t locus = lexer.peek_token ()->get_locus ();
    3963         5298 :   bool is_unsafe = false;
    3964        10596 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    3965              :     {
    3966           67 :       lexer.skip_token ();
    3967           67 :       is_unsafe = true;
    3968              :     }
    3969              : 
    3970         5298 :   if (!skip_token (IMPL))
    3971              :     {
    3972            0 :       skip_after_next_block ();
    3973            0 :       return nullptr;
    3974              :     }
    3975              : 
    3976              :   // parse generic params (shared by trait and inherent impls)
    3977         5298 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3978              :     = parse_generic_params_in_angles ();
    3979              : 
    3980              :   // Again, trait impl-only feature, but optional one, so can be used for
    3981              :   // branching yet.
    3982         5298 :   bool has_exclam = false;
    3983        10596 :   if (lexer.peek_token ()->get_id () == EXCLAM)
    3984              :     {
    3985            6 :       lexer.skip_token ();
    3986            6 :       has_exclam = true;
    3987              :     }
    3988              : 
    3989              :   /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
    3990              :    * doesn't parse too much and not work. */
    3991         5298 :   AST::TypePath type_path = parse_type_path ();
    3992        10395 :   if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
    3993              :     {
    3994              :       /* cannot parse type path (or not for token next, at least), so must be
    3995              :        * inherent impl */
    3996              : 
    3997              :       // hacky conversion of TypePath stack object to Type pointer
    3998          984 :       std::unique_ptr<AST::Type> type = nullptr;
    3999          984 :       if (!type_path.is_error ())
    4000          783 :         type = std::unique_ptr<AST::TypePath> (
    4001          783 :           new AST::TypePath (std::move (type_path)));
    4002              :       else
    4003          201 :         type = parse_type ();
    4004              : 
    4005              :       // Type is required, so error if null
    4006          984 :       if (type == nullptr)
    4007              :         {
    4008            1 :           Error error (lexer.peek_token ()->get_locus (),
    4009              :                        "could not parse type in inherent impl");
    4010            1 :           add_error (std::move (error));
    4011              : 
    4012            1 :           skip_after_next_block ();
    4013            1 :           return nullptr;
    4014            1 :         }
    4015              : 
    4016              :       // parse optional where clause
    4017          983 :       AST::WhereClause where_clause = parse_where_clause ();
    4018              : 
    4019          983 :       if (!skip_token (LEFT_CURLY))
    4020              :         {
    4021              :           // TODO: does this still skip properly?
    4022            0 :           skip_after_end_block ();
    4023            0 :           return nullptr;
    4024              :         }
    4025              : 
    4026              :       // parse inner attributes (optional)
    4027          983 :       AST::AttrVec inner_attrs = parse_inner_attributes ();
    4028              : 
    4029              :       // parse inherent impl items
    4030          983 :       std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
    4031              : 
    4032          983 :       const_TokenPtr t = lexer.peek_token ();
    4033         3761 :       while (t->get_id () != RIGHT_CURLY)
    4034              :         {
    4035         2788 :           std::unique_ptr<AST::AssociatedItem> impl_item
    4036              :             = parse_inherent_impl_item ();
    4037              : 
    4038         2788 :           if (impl_item == nullptr)
    4039              :             {
    4040           10 :               Error error (
    4041           10 :                 lexer.peek_token ()->get_locus (),
    4042              :                 "failed to parse inherent impl item in inherent impl");
    4043           10 :               add_error (std::move (error));
    4044              : 
    4045           10 :               return nullptr;
    4046           10 :             }
    4047              : 
    4048         2778 :           impl_items.push_back (std::move (impl_item));
    4049              : 
    4050         2778 :           t = lexer.peek_token ();
    4051              :         }
    4052              : 
    4053          973 :       if (!skip_token (RIGHT_CURLY))
    4054              :         {
    4055              :           // skip somewhere
    4056            0 :           return nullptr;
    4057              :         }
    4058              : 
    4059              :       // DEBUG
    4060          973 :       rust_debug ("successfully parsed inherent impl");
    4061              : 
    4062          973 :       impl_items.shrink_to_fit ();
    4063              : 
    4064          973 :       return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
    4065              :         std::move (impl_items), std::move (generic_params), std::move (type),
    4066              :         std::move (where_clause), std::move (vis), std::move (inner_attrs),
    4067          973 :         std::move (outer_attrs), locus));
    4068          984 :     }
    4069              :   else
    4070              :     {
    4071              :       // type path must both be valid and next token is for, so trait impl
    4072         4314 :       if (!skip_token (FOR))
    4073              :         {
    4074            0 :           skip_after_next_block ();
    4075            0 :           return nullptr;
    4076              :         }
    4077              : 
    4078              :       // parse type
    4079         4314 :       std::unique_ptr<AST::Type> type = parse_type ();
    4080              :       // ensure type is included as it is required
    4081         4314 :       if (type == nullptr)
    4082              :         {
    4083            0 :           Error error (lexer.peek_token ()->get_locus (),
    4084              :                        "could not parse type in trait impl");
    4085            0 :           add_error (std::move (error));
    4086              : 
    4087            0 :           skip_after_next_block ();
    4088            0 :           return nullptr;
    4089            0 :         }
    4090              : 
    4091              :       // parse optional where clause
    4092         4314 :       AST::WhereClause where_clause = parse_where_clause ();
    4093              : 
    4094         4314 :       if (!skip_token (LEFT_CURLY))
    4095              :         {
    4096              :           // TODO: does this still skip properly?
    4097            0 :           skip_after_end_block ();
    4098            0 :           return nullptr;
    4099              :         }
    4100              : 
    4101              :       // parse inner attributes (optional)
    4102         4314 :       AST::AttrVec inner_attrs = parse_inner_attributes ();
    4103              : 
    4104              :       // parse trait impl items
    4105         4314 :       std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
    4106              : 
    4107         4314 :       const_TokenPtr t = lexer.peek_token ();
    4108        14602 :       while (t->get_id () != RIGHT_CURLY)
    4109              :         {
    4110         5145 :           std::unique_ptr<AST::AssociatedItem> impl_item
    4111              :             = parse_trait_impl_item ();
    4112              : 
    4113         5145 :           if (impl_item == nullptr)
    4114              :             {
    4115            1 :               Error error (lexer.peek_token ()->get_locus (),
    4116              :                            "failed to parse trait impl item in trait impl");
    4117            1 :               add_error (std::move (error));
    4118              : 
    4119            1 :               return nullptr;
    4120            1 :             }
    4121              : 
    4122         5144 :           impl_items.push_back (std::move (impl_item));
    4123              : 
    4124         5144 :           t = lexer.peek_token ();
    4125              : 
    4126              :           // DEBUG
    4127         5144 :           rust_debug ("successfully parsed a trait impl item");
    4128              :         }
    4129              :       // DEBUG
    4130         4313 :       rust_debug ("successfully finished trait impl items");
    4131              : 
    4132         4313 :       if (!skip_token (RIGHT_CURLY))
    4133              :         {
    4134              :           // skip somewhere
    4135            0 :           return nullptr;
    4136              :         }
    4137              : 
    4138              :       // DEBUG
    4139         4313 :       rust_debug ("successfully parsed trait impl");
    4140              : 
    4141         4313 :       impl_items.shrink_to_fit ();
    4142              : 
    4143         4313 :       return std::unique_ptr<AST::TraitImpl> (
    4144         8626 :         new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
    4145              :                             std::move (impl_items), std::move (generic_params),
    4146              :                             std::move (type), std::move (where_clause),
    4147              :                             std::move (vis), std::move (inner_attrs),
    4148         4313 :                             std::move (outer_attrs), locus));
    4149         4314 :     }
    4150         5298 : }
    4151              : 
    4152              : // Parses a single inherent impl item (item inside an inherent impl block).
    4153              : template <typename ManagedTokenSource>
    4154              : std::unique_ptr<AST::AssociatedItem>
    4155         2790 : Parser<ManagedTokenSource>::parse_inherent_impl_item ()
    4156              : {
    4157              :   // parse outer attributes (if they exist)
    4158         2790 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4159              : 
    4160              :   // TODO: cleanup - currently an unreadable mess
    4161              : 
    4162              :   // branch on next token:
    4163         2790 :   const_TokenPtr t = lexer.peek_token ();
    4164         2790 :   switch (t->get_id ())
    4165              :     {
    4166            1 :     case IDENTIFIER:
    4167              :       // FIXME: Arthur: Do we need to some lookahead here?
    4168            2 :       return parse_macro_invocation_semi (outer_attrs);
    4169         2141 :     case SUPER:
    4170              :     case SELF:
    4171              :     case CRATE:
    4172              :     case PUB:
    4173              :       {
    4174              :         // visibility, so not a macro invocation semi - must be constant,
    4175              :         // function, or method
    4176         2141 :         auto vis_res = parse_visibility ();
    4177         2141 :         if (!vis_res)
    4178            0 :           return nullptr;
    4179         2141 :         auto vis = vis_res.value ();
    4180              : 
    4181              :         // TODO: is a recursive call to parse_inherent_impl_item better?
    4182         4282 :         switch (lexer.peek_token ()->get_id ())
    4183              :           {
    4184         1364 :           case EXTERN_KW:
    4185              :           case UNSAFE:
    4186              :           case FN_KW:
    4187              :             // function or method
    4188         2728 :             return parse_inherent_impl_function_or_method (std::move (vis),
    4189              :                                                            std::move (
    4190         1364 :                                                              outer_attrs));
    4191          777 :           case CONST:
    4192              :             // lookahead to resolve production - could be function/method or
    4193              :             // const item
    4194          777 :             t = lexer.peek_token (1);
    4195              : 
    4196          777 :             switch (t->get_id ())
    4197              :               {
    4198            1 :               case IDENTIFIER:
    4199              :               case UNDERSCORE:
    4200            2 :                 return parse_const_item (std::move (vis),
    4201            1 :                                          std::move (outer_attrs));
    4202          776 :               case UNSAFE:
    4203              :               case EXTERN_KW:
    4204              :               case FN_KW:
    4205         1552 :                 return parse_inherent_impl_function_or_method (std::move (vis),
    4206              :                                                                std::move (
    4207          776 :                                                                  outer_attrs));
    4208            0 :               default:
    4209            0 :                 add_error (Error (t->get_locus (),
    4210              :                                   "unexpected token %qs in some sort of const "
    4211              :                                   "item in inherent impl",
    4212              :                                   t->get_token_description ()));
    4213              : 
    4214            0 :                 lexer.skip_token (1); // TODO: is this right thing to do?
    4215            0 :                 return nullptr;
    4216              :               }
    4217            0 :           default:
    4218            0 :             add_error (
    4219            0 :               Error (t->get_locus (),
    4220              :                      "unrecognised token %qs for item in inherent impl",
    4221              :                      t->get_token_description ()));
    4222              :             // skip?
    4223            0 :             return nullptr;
    4224              :           }
    4225         4282 :       }
    4226          608 :     case ASYNC:
    4227              :     case EXTERN_KW:
    4228              :     case UNSAFE:
    4229              :     case FN_KW:
    4230              :       // function or method
    4231          608 :       return parse_inherent_impl_function_or_method (
    4232          608 :         AST::Visibility::create_private (), std::move (outer_attrs));
    4233           40 :     case CONST:
    4234              :       /* lookahead to resolve production - could be function/method or const
    4235              :        * item */
    4236           40 :       t = lexer.peek_token (1);
    4237              : 
    4238           40 :       switch (t->get_id ())
    4239              :         {
    4240           40 :         case IDENTIFIER:
    4241              :         case UNDERSCORE:
    4242           80 :           return parse_const_item (AST::Visibility::create_private (),
    4243           40 :                                    std::move (outer_attrs));
    4244            0 :         case UNSAFE:
    4245              :         case EXTERN_KW:
    4246              :         case FN_KW:
    4247            0 :           return parse_inherent_impl_function_or_method (
    4248            0 :             AST::Visibility::create_private (), std::move (outer_attrs));
    4249            0 :         default:
    4250            0 :           add_error (Error (t->get_locus (),
    4251              :                             "unexpected token %qs in some sort of const item "
    4252              :                             "in inherent impl",
    4253              :                             t->get_token_description ()));
    4254              : 
    4255            0 :           lexer.skip_token (1); // TODO: is this right thing to do?
    4256            0 :           return nullptr;
    4257              :         }
    4258              :       rust_unreachable ();
    4259            0 :     default:
    4260            0 :       add_error (Error (t->get_locus (),
    4261              :                         "unrecognised token %qs for item in inherent impl",
    4262              :                         t->get_token_description ()));
    4263              : 
    4264              :       // skip?
    4265            0 :       return nullptr;
    4266              :     }
    4267         2790 : }
    4268              : 
    4269              : /* For internal use only by parse_inherent_impl_item() - splits giant method
    4270              :  * into smaller ones and prevents duplication of logic. Strictly, this parses
    4271              :  * a function or method item inside an inherent impl item block. */
    4272              : // TODO: make this a templated function with "return type" as type param -
    4273              : // InherentImplItem is this specialisation of the template while TraitImplItem
    4274              : // will be the other.
    4275              : template <typename ManagedTokenSource>
    4276              : std::unique_ptr<AST::AssociatedItem>
    4277         2748 : Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
    4278              :   AST::Visibility vis, AST::AttrVec outer_attrs)
    4279              : {
    4280         2748 :   location_t locus = lexer.peek_token ()->get_locus ();
    4281              :   // parse function or method qualifiers
    4282         2748 :   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
    4283              : 
    4284         2748 :   skip_token (FN_KW);
    4285              : 
    4286              :   // parse function or method name
    4287         2748 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4288         2748 :   if (ident_tok == nullptr)
    4289            7 :     return nullptr;
    4290              : 
    4291         2741 :   Identifier ident{ident_tok};
    4292              : 
    4293              :   // parse generic params
    4294         2741 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    4295              :     = parse_generic_params_in_angles ();
    4296              : 
    4297         2741 :   if (!skip_token (LEFT_PAREN))
    4298              :     {
    4299              :       // skip after somewhere?
    4300            0 :       return nullptr;
    4301              :     }
    4302              : 
    4303              :   // now for function vs method disambiguation - method has opening "self"
    4304              :   // param
    4305         2741 :   auto initial_param = parse_self_param ();
    4306              : 
    4307         2741 :   if (!initial_param.has_value ()
    4308         2741 :       && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
    4309            3 :     return nullptr;
    4310              : 
    4311              :   /* FIXME: ensure that self param doesn't accidently consume tokens for a
    4312              :    * function one idea is to lookahead up to 4 tokens to see whether self is
    4313              :    * one of them */
    4314         2738 :   bool is_method = false;
    4315         2738 :   if (initial_param.has_value ())
    4316              :     {
    4317         1844 :       if ((*initial_param)->is_self ())
    4318              :         is_method = true;
    4319              : 
    4320              :       /* skip comma so function and method regular params can be parsed in
    4321              :        * same way */
    4322         3688 :       if (lexer.peek_token ()->get_id () == COMMA)
    4323         1193 :         lexer.skip_token ();
    4324              :     }
    4325              : 
    4326              :   // parse trait function params
    4327         2738 :   std::vector<std::unique_ptr<AST::Param>> function_params
    4328              :     = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
    4329              : 
    4330         2738 :   if (initial_param.has_value ())
    4331         1844 :     function_params.insert (function_params.begin (),
    4332         1844 :                             std::move (*initial_param));
    4333              : 
    4334         2738 :   if (!skip_token (RIGHT_PAREN))
    4335              :     {
    4336            0 :       skip_after_end_block ();
    4337            0 :       return nullptr;
    4338              :     }
    4339              : 
    4340              :   // parse return type (optional)
    4341         2738 :   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
    4342              : 
    4343              :   // parse where clause (optional)
    4344         2738 :   AST::WhereClause where_clause = parse_where_clause ();
    4345              : 
    4346         2738 :   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
    4347         5476 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    4348            2 :     lexer.skip_token ();
    4349              :   else
    4350              :     {
    4351         2736 :       auto result = parse_block_expr ();
    4352              : 
    4353         2736 :       if (!result)
    4354              :         {
    4355            0 :           Error error (
    4356            0 :             lexer.peek_token ()->get_locus (),
    4357              :             "could not parse definition in inherent impl %s definition",
    4358              :             is_method ? "method" : "function");
    4359            0 :           add_error (std::move (error));
    4360              : 
    4361            0 :           skip_after_end_block ();
    4362            0 :           return nullptr;
    4363            0 :         }
    4364         2736 :       body = std::move (result.value ());
    4365         2736 :     }
    4366              : 
    4367         2738 :   return std::unique_ptr<AST::Function> (
    4368        10950 :     new AST::Function (std::move (ident), std::move (qualifiers),
    4369              :                        std::move (generic_params), std::move (function_params),
    4370              :                        std::move (return_type), std::move (where_clause),
    4371              :                        std::move (body), std::move (vis),
    4372         2738 :                        std::move (outer_attrs), locus));
    4373         8227 : }
    4374              : 
    4375              : // Parses a single trait impl item (item inside a trait impl block).
    4376              : template <typename ManagedTokenSource>
    4377              : std::unique_ptr<AST::AssociatedItem>
    4378         5248 : Parser<ManagedTokenSource>::parse_trait_impl_item ()
    4379              : {
    4380              :   // parse outer attributes (if they exist)
    4381         5248 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4382              : 
    4383         5248 :   auto vis_res = parse_visibility ();
    4384         5248 :   if (!vis_res)
    4385            0 :     return nullptr;
    4386         5248 :   auto visibility = vis_res.value ();
    4387              : 
    4388              :   // branch on next token:
    4389         5248 :   const_TokenPtr t = lexer.peek_token ();
    4390         5248 :   switch (t->get_id ())
    4391              :     {
    4392            0 :     case SUPER:
    4393              :     case SELF:
    4394              :     case CRATE:
    4395              :     case DOLLAR_SIGN:
    4396              :       // these seem to be SimplePath tokens, so this is a macro invocation
    4397              :       // semi
    4398            0 :       return parse_macro_invocation_semi (std::move (outer_attrs));
    4399           55 :     case IDENTIFIER:
    4400          110 :       if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
    4401           48 :         return parse_trait_impl_function_or_method (visibility,
    4402           24 :                                                     std::move (outer_attrs));
    4403              :       else
    4404           62 :         return parse_macro_invocation_semi (std::move (outer_attrs));
    4405         1236 :     case TYPE:
    4406         2472 :       return parse_type_alias (visibility, std::move (outer_attrs));
    4407         3923 :     case EXTERN_KW:
    4408              :     case UNSAFE:
    4409              :     case FN_KW:
    4410              :       // function or method
    4411         7846 :       return parse_trait_impl_function_or_method (visibility,
    4412         3923 :                                                   std::move (outer_attrs));
    4413            1 :     case ASYNC:
    4414            2 :       return parse_async_item (visibility, std::move (outer_attrs));
    4415           33 :     case CONST:
    4416              :       // lookahead to resolve production - could be function/method or const
    4417              :       // item
    4418           33 :       t = lexer.peek_token (1);
    4419              : 
    4420           33 :       switch (t->get_id ())
    4421              :         {
    4422           32 :         case IDENTIFIER:
    4423              :         case UNDERSCORE:
    4424           64 :           return parse_const_item (visibility, std::move (outer_attrs));
    4425            1 :         case UNSAFE:
    4426              :         case EXTERN_KW:
    4427              :         case FN_KW:
    4428            2 :           return parse_trait_impl_function_or_method (visibility,
    4429            1 :                                                       std::move (outer_attrs));
    4430            0 :         default:
    4431            0 :           add_error (Error (
    4432              :             t->get_locus (),
    4433              :             "unexpected token %qs in some sort of const item in trait impl",
    4434              :             t->get_token_description ()));
    4435              : 
    4436            0 :           lexer.skip_token (1); // TODO: is this right thing to do?
    4437            0 :           return nullptr;
    4438              :         }
    4439              :       rust_unreachable ();
    4440              :     default:
    4441              :       break;
    4442              :     }
    4443            0 :   add_error (Error (t->get_locus (),
    4444              :                     "unrecognised token %qs for item in trait impl",
    4445              :                     t->get_token_description ()));
    4446              : 
    4447              :   // skip?
    4448            0 :   return nullptr;
    4449        10496 : }
    4450              : 
    4451              : /* For internal use only by parse_trait_impl_item() - splits giant method into
    4452              :  * smaller ones and prevents duplication of logic. Strictly, this parses a
    4453              :  * function or method item inside a trait impl item block. */
    4454              : template <typename ManagedTokenSource>
    4455              : std::unique_ptr<AST::AssociatedItem>
    4456         3948 : Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
    4457              :   AST::Visibility vis, AST::AttrVec outer_attrs)
    4458              : {
    4459              :   // this shares virtually all logic with
    4460              :   // parse_inherent_impl_function_or_method
    4461              :   // - template?
    4462         3948 :   location_t locus = lexer.peek_token ()->get_locus ();
    4463              : 
    4464         3948 :   auto is_default = false;
    4465         3948 :   auto t = lexer.peek_token ();
    4466         3948 :   if (t->get_id () == IDENTIFIER
    4467         3948 :       && t->get_str () == Values::WeakKeywords::DEFAULT)
    4468              :     {
    4469           24 :       is_default = true;
    4470           24 :       lexer.skip_token ();
    4471              :     }
    4472              : 
    4473              :   // parse function or method qualifiers
    4474         3948 :   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
    4475              : 
    4476         3948 :   skip_token (FN_KW);
    4477              : 
    4478              :   // parse function or method name
    4479         3948 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4480         3948 :   if (ident_tok == nullptr)
    4481              :     {
    4482            0 :       return nullptr;
    4483              :     }
    4484         3948 :   Identifier ident{ident_tok};
    4485              : 
    4486              :   // DEBUG:
    4487         3948 :   rust_debug (
    4488              :     "about to start parsing generic params in trait impl function or method");
    4489              : 
    4490              :   // parse generic params
    4491         3948 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    4492              :     = parse_generic_params_in_angles ();
    4493              : 
    4494              :   // DEBUG:
    4495         3948 :   rust_debug (
    4496              :     "finished parsing generic params in trait impl function or method");
    4497              : 
    4498         3948 :   if (!skip_token (LEFT_PAREN))
    4499              :     {
    4500              :       // skip after somewhere?
    4501            0 :       return nullptr;
    4502              :     }
    4503              : 
    4504              :   // now for function vs method disambiguation - method has opening "self"
    4505              :   // param
    4506         3948 :   auto initial_param = parse_self_param ();
    4507              : 
    4508         3948 :   if (!initial_param.has_value ()
    4509         3948 :       && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
    4510            0 :     return nullptr;
    4511              : 
    4512              :   // FIXME: ensure that self param doesn't accidently consume tokens for a
    4513              :   // function
    4514         3948 :   bool is_method = false;
    4515         3948 :   if (initial_param.has_value ())
    4516              :     {
    4517         3708 :       if ((*initial_param)->is_self ())
    4518              :         is_method = true;
    4519              : 
    4520              :       // skip comma so function and method regular params can be parsed in
    4521              :       // same way
    4522         7416 :       if (lexer.peek_token ()->get_id () == COMMA)
    4523              :         {
    4524         2001 :           lexer.skip_token ();
    4525              :         }
    4526              : 
    4527              :       // DEBUG
    4528         3708 :       rust_debug ("successfully parsed self param in method trait impl item");
    4529              :     }
    4530              : 
    4531              :   // DEBUG
    4532         3948 :   rust_debug (
    4533              :     "started to parse function params in function or method trait impl item");
    4534              : 
    4535              :   // parse trait function params (only if next token isn't right paren)
    4536         3948 :   std::vector<std::unique_ptr<AST::Param>> function_params;
    4537         7896 :   if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
    4538              :     {
    4539              :       function_params
    4540         2158 :         = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
    4541              : 
    4542         2158 :       if (function_params.empty ())
    4543              :         {
    4544            0 :           Error error (
    4545            0 :             lexer.peek_token ()->get_locus (),
    4546              :             "failed to parse function params in trait impl %s definition",
    4547              :             is_method ? "method" : "function");
    4548            0 :           add_error (std::move (error));
    4549              : 
    4550            0 :           skip_after_next_block ();
    4551            0 :           return nullptr;
    4552            0 :         }
    4553              :     }
    4554              : 
    4555         3948 :   if (initial_param.has_value ())
    4556         3708 :     function_params.insert (function_params.begin (),
    4557         3708 :                             std::move (*initial_param));
    4558              : 
    4559              :   // DEBUG
    4560         3948 :   rust_debug ("successfully parsed function params in function or method "
    4561              :               "trait impl item");
    4562              : 
    4563         3948 :   if (!skip_token (RIGHT_PAREN))
    4564              :     {
    4565            0 :       skip_after_next_block ();
    4566            0 :       return nullptr;
    4567              :     }
    4568              : 
    4569              :   // parse return type (optional)
    4570         3948 :   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
    4571              : 
    4572              :   // DEBUG
    4573         3948 :   rust_debug (
    4574              :     "successfully parsed return type in function or method trait impl item");
    4575              : 
    4576              :   // parse where clause (optional)
    4577         3948 :   AST::WhereClause where_clause = parse_where_clause ();
    4578              : 
    4579              :   // DEBUG
    4580         3948 :   rust_debug (
    4581              :     "successfully parsed where clause in function or method trait impl item");
    4582              : 
    4583              :   // parse function definition (in block) - semicolon not allowed
    4584         3948 :   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
    4585              : 
    4586         7896 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    4587            1 :     lexer.skip_token ();
    4588              :   else
    4589              :     {
    4590         3947 :       auto result = parse_block_expr ();
    4591         3947 :       if (!result)
    4592              :         {
    4593            1 :           Error error (lexer.peek_token ()->get_locus (),
    4594              :                        "could not parse definition in trait impl %s definition",
    4595              :                        is_method ? "method" : "function");
    4596            1 :           add_error (std::move (error));
    4597              : 
    4598            1 :           skip_after_end_block ();
    4599            1 :           return nullptr;
    4600            1 :         }
    4601         3946 :       body = std::move (result.value ());
    4602         3947 :     }
    4603              : 
    4604         3947 :   return std::unique_ptr<AST::Function> (
    4605        15787 :     new AST::Function (std::move (ident), std::move (qualifiers),
    4606              :                        std::move (generic_params), std::move (function_params),
    4607              :                        std::move (return_type), std::move (where_clause),
    4608              :                        std::move (body), std::move (vis),
    4609         3947 :                        std::move (outer_attrs), locus, is_default));
    4610        11844 : }
    4611              : 
    4612              : // Parses an extern block of declarations.
    4613              : template <typename ManagedTokenSource>
    4614              : std::unique_ptr<AST::ExternBlock>
    4615         1481 : Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
    4616              :                                                 AST::AttrVec outer_attrs)
    4617              : {
    4618         1481 :   location_t locus = lexer.peek_token ()->get_locus ();
    4619         1481 :   skip_token (EXTERN_KW);
    4620              : 
    4621              :   // detect optional abi name
    4622         1481 :   std::string abi;
    4623         1481 :   const_TokenPtr next_tok = lexer.peek_token ();
    4624         1481 :   if (next_tok->get_id () == STRING_LITERAL)
    4625              :     {
    4626         1481 :       lexer.skip_token ();
    4627         1481 :       abi = next_tok->get_str ();
    4628              :     }
    4629              : 
    4630         1481 :   if (!skip_token (LEFT_CURLY))
    4631              :     {
    4632            0 :       skip_after_end_block ();
    4633            0 :       return nullptr;
    4634              :     }
    4635              : 
    4636         1481 :   AST::AttrVec inner_attrs = parse_inner_attributes ();
    4637              : 
    4638              :   // parse declarations inside extern block
    4639         1481 :   std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
    4640              : 
    4641         1481 :   const_TokenPtr t = lexer.peek_token ();
    4642         3704 :   while (t->get_id () != RIGHT_CURLY)
    4643              :     {
    4644         2224 :       std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
    4645              : 
    4646         2224 :       if (extern_item == nullptr)
    4647              :         {
    4648            1 :           Error error (t->get_locus (),
    4649              :                        "failed to parse external item despite not reaching "
    4650              :                        "end of extern block");
    4651            1 :           add_error (std::move (error));
    4652              : 
    4653            1 :           return nullptr;
    4654            1 :         }
    4655              : 
    4656         2223 :       extern_items.push_back (std::move (extern_item));
    4657              : 
    4658         2223 :       t = lexer.peek_token ();
    4659              :     }
    4660              : 
    4661         1480 :   if (!skip_token (RIGHT_CURLY))
    4662              :     {
    4663              :       // skip somewhere
    4664            0 :       return nullptr;
    4665              :     }
    4666              : 
    4667         1480 :   extern_items.shrink_to_fit ();
    4668              : 
    4669              :   return std::unique_ptr<AST::ExternBlock> (
    4670         1480 :     new AST::ExternBlock (std::move (abi), std::move (extern_items),
    4671              :                           std::move (vis), std::move (inner_attrs),
    4672         1480 :                           std::move (outer_attrs), locus));
    4673         2962 : }
    4674              : 
    4675              : // Parses a single extern block item (static or function declaration).
    4676              : template <typename ManagedTokenSource>
    4677              : std::unique_ptr<AST::ExternalItem>
    4678         2227 : Parser<ManagedTokenSource>::parse_external_item ()
    4679              : {
    4680              :   // parse optional outer attributes
    4681         2227 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4682              : 
    4683         2227 :   location_t locus = lexer.peek_token ()->get_locus ();
    4684              : 
    4685              :   // parse optional visibility
    4686         2227 :   auto vis_res = parse_visibility ();
    4687         2227 :   if (!vis_res)
    4688            0 :     return nullptr;
    4689         2227 :   auto vis = vis_res.value ();
    4690              : 
    4691         2227 :   const_TokenPtr t = lexer.peek_token ();
    4692         2227 :   switch (t->get_id ())
    4693              :     {
    4694            2 :     case IDENTIFIER:
    4695            4 :       return parse_macro_invocation_semi (outer_attrs);
    4696            1 :     case STATIC_KW:
    4697              :       {
    4698              :         // parse extern static item
    4699            1 :         lexer.skip_token ();
    4700              : 
    4701              :         // parse mut (optional)
    4702            1 :         bool has_mut = false;
    4703            2 :         if (lexer.peek_token ()->get_id () == MUT)
    4704              :           {
    4705            0 :             lexer.skip_token ();
    4706            0 :             has_mut = true;
    4707              :           }
    4708              : 
    4709              :         // parse identifier
    4710            1 :         const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4711            1 :         if (ident_tok == nullptr)
    4712              :           {
    4713            0 :             skip_after_semicolon ();
    4714            0 :             return nullptr;
    4715              :           }
    4716            1 :         Identifier ident{ident_tok};
    4717              : 
    4718            1 :         if (!skip_token (COLON))
    4719              :           {
    4720            0 :             skip_after_semicolon ();
    4721            0 :             return nullptr;
    4722              :           }
    4723              : 
    4724              :         // parse type (required)
    4725            1 :         std::unique_ptr<AST::Type> type = parse_type ();
    4726            1 :         if (type == nullptr)
    4727              :           {
    4728            0 :             Error error (lexer.peek_token ()->get_locus (),
    4729              :                          "failed to parse type in external static item");
    4730            0 :             add_error (std::move (error));
    4731              : 
    4732            0 :             skip_after_semicolon ();
    4733            0 :             return nullptr;
    4734            0 :           }
    4735              : 
    4736            1 :         if (!skip_token (SEMICOLON))
    4737              :           {
    4738              :             // skip after somewhere?
    4739            0 :             return nullptr;
    4740              :           }
    4741              : 
    4742            1 :         return std::unique_ptr<AST::ExternalStaticItem> (
    4743            2 :           new AST::ExternalStaticItem (std::move (ident), std::move (type),
    4744              :                                        has_mut, std::move (vis),
    4745            1 :                                        std::move (outer_attrs), locus));
    4746            3 :       }
    4747         2220 :     case FN_KW:
    4748         4440 :       return parse_function (std::move (vis), std::move (outer_attrs), true);
    4749              : 
    4750            4 :     case TYPE:
    4751            4 :       return parse_external_type_item (std::move (vis),
    4752            4 :                                        std::move (outer_attrs));
    4753            0 :     default:
    4754              :       // error
    4755            0 :       add_error (
    4756            0 :         Error (t->get_locus (),
    4757              :                "unrecognised token %qs in extern block item declaration",
    4758              :                t->get_token_description ()));
    4759              : 
    4760            0 :       skip_after_semicolon ();
    4761            0 :       return nullptr;
    4762              :     }
    4763         4454 : }
    4764              : 
    4765              : // Parses a statement (will further disambiguate any statement).
    4766              : template <typename ManagedTokenSource>
    4767              : std::unique_ptr<AST::Stmt>
    4768          741 : Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
    4769              : {
    4770              :   // quick exit for empty statement
    4771              :   // FIXME: Can we have empty statements without semicolons? Just nothing?
    4772          741 :   const_TokenPtr t = lexer.peek_token ();
    4773          741 :   if (t->get_id () == SEMICOLON)
    4774              :     {
    4775           30 :       lexer.skip_token ();
    4776           30 :       return std::unique_ptr<AST::EmptyStmt> (
    4777           30 :         new AST::EmptyStmt (t->get_locus ()));
    4778              :     }
    4779              : 
    4780              :   // parse outer attributes
    4781          711 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4782              : 
    4783              :   // parsing this will be annoying because of the many different possibilities
    4784              :   /* best may be just to copy paste in parse_item switch, and failing that try
    4785              :    * to parse outer attributes, and then pass them in to either a let
    4786              :    * statement or (fallback) expression statement. */
    4787              :   // FIXME: think of a way to do this without such a large switch?
    4788          711 :   t = lexer.peek_token ();
    4789          711 :   switch (t->get_id ())
    4790              :     {
    4791          200 :     case LET:
    4792              :       // let statement
    4793          200 :       return parse_let_stmt (std::move (outer_attrs), restrictions);
    4794          186 :     case PUB:
    4795              :     case MOD:
    4796              :     case EXTERN_KW:
    4797              :     case USE:
    4798              :     case FN_KW:
    4799              :     case TYPE:
    4800              :     case STRUCT_KW:
    4801              :     case ENUM_KW:
    4802              :     case CONST:
    4803              :     case STATIC_KW:
    4804              :     case AUTO:
    4805              :     case TRAIT:
    4806              :     case IMPL:
    4807              :     case MACRO:
    4808              :     /* TODO: implement union keyword but not really because of
    4809              :      * context-dependence crappy hack way to parse a union written below to
    4810              :      * separate it from the good code. */
    4811              :     // case UNION:
    4812              :     case UNSAFE: // maybe - unsafe traits are a thing
    4813              :       /* if any of these (should be all possible VisItem prefixes), parse a
    4814              :        * VisItem can't parse item because would require reparsing outer
    4815              :        * attributes */
    4816              :       // may also be unsafe block
    4817          372 :       if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
    4818              :         {
    4819            1 :           return parse_expr_stmt (std::move (outer_attrs), restrictions);
    4820              :         }
    4821              :       else
    4822              :         {
    4823          185 :           return parse_vis_item (std::move (outer_attrs));
    4824              :         }
    4825              :       break;
    4826              :     // crappy hack to do union "keyword"
    4827          220 :     case IDENTIFIER:
    4828          220 :       if (t->get_str () == Values::WeakKeywords::UNION
    4829          220 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
    4830              :         {
    4831            0 :           return parse_vis_item (std::move (outer_attrs));
    4832              :           // or should this go straight to parsing union?
    4833              :         }
    4834          440 :       else if (is_macro_rules_def (t))
    4835              :         {
    4836              :           // macro_rules! macro item
    4837            2 :           return parse_macro_rules_def (std::move (outer_attrs));
    4838              :         }
    4839              :       gcc_fallthrough ();
    4840              :       // TODO: find out how to disable gcc "implicit fallthrough" warning
    4841              :     default:
    4842              :       // fallback: expression statement
    4843          323 :       return parse_expr_stmt (std::move (outer_attrs), restrictions);
    4844              :       break;
    4845              :     }
    4846          711 : }
    4847              : 
    4848              : // Parses a let statement.
    4849              : template <typename ManagedTokenSource>
    4850              : std::unique_ptr<AST::LetStmt>
    4851        12925 : Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
    4852              :                                             ParseRestrictions restrictions)
    4853              : {
    4854        12925 :   location_t locus = lexer.peek_token ()->get_locus ();
    4855        12925 :   skip_token (LET);
    4856              : 
    4857              :   // parse pattern (required)
    4858        12925 :   std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    4859        12925 :   if (pattern == nullptr)
    4860              :     {
    4861            0 :       Error error (lexer.peek_token ()->get_locus (),
    4862              :                    "failed to parse pattern in let statement");
    4863            0 :       add_error (std::move (error));
    4864              : 
    4865            0 :       skip_after_semicolon ();
    4866            0 :       return nullptr;
    4867            0 :     }
    4868              : 
    4869              :   // parse type declaration (optional)
    4870        12925 :   std::unique_ptr<AST::Type> type = nullptr;
    4871        25850 :   if (lexer.peek_token ()->get_id () == COLON)
    4872              :     {
    4873              :       // must have a type declaration
    4874         2027 :       lexer.skip_token ();
    4875              : 
    4876         2027 :       type = parse_type ();
    4877         2027 :       if (type == nullptr)
    4878              :         {
    4879            0 :           Error error (lexer.peek_token ()->get_locus (),
    4880              :                        "failed to parse type in let statement");
    4881            0 :           add_error (std::move (error));
    4882              : 
    4883            0 :           skip_after_semicolon ();
    4884            0 :           return nullptr;
    4885            0 :         }
    4886              :     }
    4887              : 
    4888              :   // parse expression to set variable to (optional)
    4889        12925 :   std::unique_ptr<AST::Expr> expr = nullptr;
    4890        25850 :   if (lexer.peek_token ()->get_id () == EQUAL)
    4891              :     {
    4892              :       // must have an expression
    4893        11872 :       lexer.skip_token ();
    4894              : 
    4895        11872 :       auto expr_res = parse_expr ();
    4896        11872 :       if (!expr_res)
    4897              :         {
    4898           22 :           skip_after_semicolon ();
    4899           22 :           return nullptr;
    4900              :         }
    4901        11850 :       expr = std::move (expr_res.value ());
    4902        11872 :     }
    4903              : 
    4904        12903 :   tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
    4905        12903 :   if (maybe_skip_token (ELSE))
    4906              :     {
    4907            5 :       auto block_expr = parse_block_expr ();
    4908            5 :       if (block_expr)
    4909              :         else_expr = tl::optional<std::unique_ptr<AST::Expr>>{
    4910           10 :           std::move (block_expr.value ())};
    4911              :       else
    4912              :         else_expr = tl::nullopt;
    4913            5 :     }
    4914              : 
    4915        12903 :   if (restrictions.consume_semi)
    4916              :     {
    4917              :       // `stmt` macro variables are parsed without a semicolon, but should be
    4918              :       // parsed as a full statement when interpolated. This should be handled
    4919              :       // by having the interpolated statement be distinguishable from normal
    4920              :       // tokens, e.g. by NT tokens.
    4921        12758 :       if (restrictions.allow_close_after_expr_stmt)
    4922           55 :         maybe_skip_token (SEMICOLON);
    4923        12703 :       else if (!skip_token (SEMICOLON))
    4924            1 :         return nullptr;
    4925              :     }
    4926              : 
    4927              :   return std::unique_ptr<AST::LetStmt> (
    4928        25809 :     new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
    4929        12902 :                       std::move (else_expr), std::move (outer_attrs), locus));
    4930        12925 : }
    4931              : 
    4932              : template <typename ManagedTokenSource>
    4933              : tl::optional<AST::GenericArg>
    4934         3843 : Parser<ManagedTokenSource>::parse_generic_arg ()
    4935              : {
    4936         3843 :   auto tok = lexer.peek_token ();
    4937         3843 :   std::unique_ptr<AST::Expr> expr = nullptr;
    4938              : 
    4939         3843 :   switch (tok->get_id ())
    4940              :     {
    4941         2476 :     case IDENTIFIER:
    4942              :       {
    4943              :         // This is a bit of a weird situation: With an identifier token, we
    4944              :         // could either have a valid type or a macro (FIXME: anything else?). So
    4945              :         // we need one bit of lookahead to differentiate if this is really
    4946         2476 :         auto next_tok = lexer.peek_token (1);
    4947         2476 :         if (next_tok->get_id () == LEFT_ANGLE
    4948         2465 :             || next_tok->get_id () == SCOPE_RESOLUTION
    4949         4938 :             || next_tok->get_id () == EXCLAM)
    4950              :           {
    4951           22 :             auto type = parse_type ();
    4952           22 :             if (type)
    4953           22 :               return AST::GenericArg::create_type (std::move (type));
    4954              :             else
    4955            0 :               return tl::nullopt;
    4956           22 :           }
    4957         2454 :         else if (next_tok->get_id () == COLON)
    4958              :           {
    4959            1 :             lexer.skip_token (); // skip ident
    4960            1 :             lexer.skip_token (); // skip colon
    4961              : 
    4962            1 :             auto tok = lexer.peek_token ();
    4963            1 :             std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    4964              :               = parse_type_param_bounds ();
    4965              : 
    4966            1 :             auto type = std::unique_ptr<AST::TraitObjectType> (
    4967            1 :               new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
    4968              :                                         false));
    4969            1 :             if (type)
    4970            1 :               return AST::GenericArg::create_type (std::move (type));
    4971              :             else
    4972              :               return tl::nullopt;
    4973            2 :           }
    4974         2453 :         lexer.skip_token ();
    4975         9812 :         return AST::GenericArg::create_ambiguous (tok->get_str (),
    4976         2453 :                                                   tok->get_locus ());
    4977         2476 :       }
    4978           19 :     case LEFT_CURLY:
    4979              :       {
    4980           19 :         auto res = parse_block_expr ();
    4981           19 :         if (res)
    4982           19 :           expr = std::move (res.value ());
    4983              :         else
    4984            0 :           return tl::nullopt;
    4985           19 :       }
    4986              :       break;
    4987           91 :     case MINUS:
    4988              :     case STRING_LITERAL:
    4989              :     case CHAR_LITERAL:
    4990              :     case INT_LITERAL:
    4991              :     case FLOAT_LITERAL:
    4992              :     case TRUE_LITERAL:
    4993              :     case FALSE_LITERAL:
    4994              :       {
    4995           91 :         auto res = parse_literal_expr ();
    4996           91 :         if (res)
    4997           91 :           expr = std::move (res.value ());
    4998              :         else
    4999            0 :           return tl::nullopt;
    5000           91 :       }
    5001              :       break;
    5002              :     // FIXME: Because of this, error reporting is garbage for const generic
    5003              :     // parameter's default values
    5004         1257 :     default:
    5005              :       {
    5006         1257 :         auto type = parse_type ();
    5007              :         // FIXME: Find a better way to do this?
    5008         1257 :         if (type)
    5009         1256 :           return AST::GenericArg::create_type (std::move (type));
    5010              :         else
    5011            1 :           return tl::nullopt;
    5012         1257 :       }
    5013              :     }
    5014              : 
    5015          110 :   if (!expr)
    5016            0 :     return tl::nullopt;
    5017              : 
    5018          110 :   return AST::GenericArg::create_const (std::move (expr));
    5019         3843 : }
    5020              : 
    5021              : // Parses the generic arguments in each path segment.
    5022              : template <typename ManagedTokenSource>
    5023              : AST::GenericArgs
    5024         3643 : Parser<ManagedTokenSource>::parse_path_generic_args ()
    5025              : {
    5026         7286 :   if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
    5027            5 :     lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
    5028              : 
    5029         3643 :   if (!skip_token (LEFT_ANGLE))
    5030              :     {
    5031              :       // skip after somewhere?
    5032            0 :       return AST::GenericArgs::create_empty ();
    5033              :     }
    5034              : 
    5035              :   // We need to parse all lifetimes, then parse types and const generics in
    5036              :   // any order.
    5037              : 
    5038              :   // try to parse lifetimes first
    5039         3643 :   std::vector<AST::Lifetime> lifetime_args;
    5040              : 
    5041         3643 :   const_TokenPtr t = lexer.peek_token ();
    5042         3643 :   location_t locus = t->get_locus ();
    5043         7292 :   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
    5044              :     {
    5045         3649 :       auto lifetime = parse_lifetime (false);
    5046         3649 :       if (!lifetime)
    5047              :         {
    5048              :           // not necessarily an error
    5049              :           break;
    5050              :         }
    5051              : 
    5052           41 :       lifetime_args.push_back (std::move (lifetime.value ()));
    5053              : 
    5054              :       // if next token isn't comma, then it must be end of list
    5055           82 :       if (lexer.peek_token ()->get_id () != COMMA)
    5056              :         {
    5057              :           break;
    5058              :         }
    5059              :       // skip comma
    5060            7 :       lexer.skip_token ();
    5061              : 
    5062            7 :       t = lexer.peek_token ();
    5063              :     }
    5064              : 
    5065              :   // try to parse types and const generics second
    5066         3643 :   std::vector<AST::GenericArg> generic_args;
    5067              : 
    5068              :   // TODO: think of better control structure
    5069         3643 :   t = lexer.peek_token ();
    5070        11074 :   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
    5071              :     {
    5072              :       // FIXME: Is it fine to break if there is one binding? Can't there be
    5073              :       // bindings in between types?
    5074              : 
    5075              :       // ensure not binding being parsed as type accidently
    5076         6213 :       if (t->get_id () == IDENTIFIER
    5077         6442 :           && lexer.peek_token (1)->get_id () == EQUAL)
    5078              :         break;
    5079              : 
    5080         3823 :       auto arg = parse_generic_arg ();
    5081         3823 :       if (arg)
    5082              :         {
    5083         3823 :           generic_args.emplace_back (std::move (arg.value ()));
    5084              :         }
    5085              : 
    5086              :       // FIXME: Do we need to break if we encounter an error?
    5087              : 
    5088              :       // if next token isn't comma, then it must be end of list
    5089         7646 :       if (lexer.peek_token ()->get_id () != COMMA)
    5090              :         break;
    5091              : 
    5092              :       // skip comma
    5093          287 :       lexer.skip_token ();
    5094          287 :       t = lexer.peek_token ();
    5095              :     }
    5096              : 
    5097              :   // try to parse bindings third
    5098         3643 :   std::vector<AST::GenericArgsBinding> binding_args;
    5099              : 
    5100              :   // TODO: think of better control structure
    5101         3643 :   t = lexer.peek_token ();
    5102         3716 :   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
    5103              :     {
    5104           73 :       AST::GenericArgsBinding binding = parse_generic_args_binding ();
    5105           73 :       if (binding.is_error ())
    5106              :         {
    5107              :           // not necessarily an error
    5108              :           break;
    5109              :         }
    5110              : 
    5111           73 :       binding_args.push_back (std::move (binding));
    5112              : 
    5113              :       // if next token isn't comma, then it must be end of list
    5114          146 :       if (lexer.peek_token ()->get_id () != COMMA)
    5115              :         {
    5116              :           break;
    5117              :         }
    5118              :       // skip comma
    5119            1 :       lexer.skip_token ();
    5120              : 
    5121            1 :       t = lexer.peek_token ();
    5122              :     }
    5123              : 
    5124              :   // skip any trailing commas
    5125         7286 :   if (lexer.peek_token ()->get_id () == COMMA)
    5126            0 :     lexer.skip_token ();
    5127              : 
    5128         3643 :   if (!skip_generics_right_angle ())
    5129            0 :     return AST::GenericArgs::create_empty ();
    5130              : 
    5131         3643 :   lifetime_args.shrink_to_fit ();
    5132         3643 :   generic_args.shrink_to_fit ();
    5133         3643 :   binding_args.shrink_to_fit ();
    5134              : 
    5135         3643 :   return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
    5136         3643 :                            std::move (binding_args), locus);
    5137         7286 : }
    5138              : 
    5139              : // Parses a binding in a generic args path segment.
    5140              : template <typename ManagedTokenSource>
    5141              : AST::GenericArgsBinding
    5142           73 : Parser<ManagedTokenSource>::parse_generic_args_binding ()
    5143              : {
    5144           73 :   const_TokenPtr ident_tok = lexer.peek_token ();
    5145           73 :   if (ident_tok->get_id () != IDENTIFIER)
    5146              :     {
    5147              :       // allow non error-inducing use
    5148              :       // skip somewhere?
    5149            0 :       return AST::GenericArgsBinding::create_error ();
    5150              :     }
    5151           73 :   lexer.skip_token ();
    5152           73 :   Identifier ident{ident_tok};
    5153              : 
    5154           73 :   if (!skip_token (EQUAL))
    5155              :     {
    5156              :       // skip after somewhere?
    5157            0 :       return AST::GenericArgsBinding::create_error ();
    5158              :     }
    5159              : 
    5160              :   // parse type (required)
    5161           73 :   std::unique_ptr<AST::Type> type = parse_type ();
    5162           73 :   if (type == nullptr)
    5163              :     {
    5164              :       // skip somewhere?
    5165            0 :       return AST::GenericArgsBinding::create_error ();
    5166              :     }
    5167              : 
    5168          146 :   return AST::GenericArgsBinding (std::move (ident), std::move (type),
    5169          146 :                                   ident_tok->get_locus ());
    5170          146 : }
    5171              : 
    5172              : // Parses a self param. Also handles self param not existing.
    5173              : template <typename ManagedTokenSource>
    5174              : tl::expected<std::unique_ptr<AST::Param>, Parse::Error::Self>
    5175        18143 : Parser<ManagedTokenSource>::parse_self_param ()
    5176              : {
    5177        18143 :   bool has_reference = false;
    5178        18143 :   AST::Lifetime lifetime = AST::Lifetime::elided ();
    5179              : 
    5180        18143 :   location_t locus = lexer.peek_token ()->get_locus ();
    5181              : 
    5182              :   // TODO: Feels off, find a better way to clearly express this
    5183        72572 :   std::vector<std::vector<TokenId>> ptrs
    5184              :     = {{ASTERISK, SELF} /* *self */,
    5185              :        {ASTERISK, CONST, SELF} /* *const self */,
    5186              :        {ASTERISK, MUT, SELF} /* *mut self */};
    5187              : 
    5188        72566 :   for (auto &s : ptrs)
    5189              :     {
    5190              :       size_t i = 0;
    5191        54437 :       for (i = 0; i < s.size (); i++)
    5192       108868 :         if (lexer.peek_token (i)->get_id () != s[i])
    5193              :           break;
    5194        54426 :       if (i == s.size ())
    5195              :         {
    5196            3 :           Error error (lexer.peek_token ()->get_locus (),
    5197              :                        "cannot pass %<self%> by raw pointer");
    5198            3 :           add_error (std::move (error));
    5199            3 :           return Parse::Error::Self::make_self_raw_pointer ();
    5200            3 :         }
    5201              :     }
    5202              : 
    5203              :   // Trying to find those patterns:
    5204              :   //
    5205              :   // &'lifetime mut self
    5206              :   // &'lifetime self
    5207              :   // & mut self
    5208              :   // & self
    5209              :   // mut self
    5210              :   // self
    5211              :   //
    5212              :   // If not found, it is probably a function, exit and let function parsing
    5213              :   // handle it.
    5214              :   bool is_self = false;
    5215       108840 :   for (size_t i = 0; i < 5; i++)
    5216       181400 :     if (lexer.peek_token (i)->get_id () == SELF)
    5217         7807 :       is_self = true;
    5218              : 
    5219        18140 :   if (!is_self)
    5220              :     return Parse::Error::Self::make_not_self ();
    5221              : 
    5222              :   // test if self is a reference parameter
    5223        15608 :   if (lexer.peek_token ()->get_id () == AMP)
    5224              :     {
    5225         4638 :       has_reference = true;
    5226         4638 :       lexer.skip_token ();
    5227              : 
    5228              :       // now test whether it has a lifetime
    5229         9276 :       if (lexer.peek_token ()->get_id () == LIFETIME)
    5230              :         {
    5231              :           // something went wrong somehow
    5232            4 :           if (auto parsed_lifetime = parse_lifetime (true))
    5233              :             {
    5234            2 :               lifetime = parsed_lifetime.value ();
    5235              :             }
    5236              :           else
    5237              :             {
    5238            0 :               Error error (lexer.peek_token ()->get_locus (),
    5239              :                            "failed to parse lifetime in self param");
    5240            0 :               add_error (std::move (error));
    5241              : 
    5242              :               // skip after somewhere?
    5243            0 :               return Parse::Error::Self::make_parsing_error ();
    5244            0 :             }
    5245              :         }
    5246              :     }
    5247              : 
    5248              :   // test for mut
    5249         7804 :   bool has_mut = false;
    5250        15608 :   if (lexer.peek_token ()->get_id () == MUT)
    5251              :     {
    5252          348 :       has_mut = true;
    5253          348 :       lexer.skip_token ();
    5254              :     }
    5255              : 
    5256              :   // skip self token
    5257         7804 :   const_TokenPtr self_tok = lexer.peek_token ();
    5258         7804 :   if (self_tok->get_id () != SELF)
    5259              :     {
    5260              :       // skip after somewhere?
    5261              :       return Parse::Error::Self::make_not_self ();
    5262              :     }
    5263         7802 :   lexer.skip_token ();
    5264              : 
    5265              :   // parse optional type
    5266         7802 :   std::unique_ptr<AST::Type> type = nullptr;
    5267        15604 :   if (lexer.peek_token ()->get_id () == COLON)
    5268              :     {
    5269            1 :       lexer.skip_token ();
    5270              : 
    5271              :       // type is now required
    5272            1 :       type = parse_type ();
    5273            1 :       if (type == nullptr)
    5274              :         {
    5275            0 :           Error error (lexer.peek_token ()->get_locus (),
    5276              :                        "could not parse type in self param");
    5277            0 :           add_error (std::move (error));
    5278              : 
    5279              :           // skip after somewhere?
    5280            0 :           return Parse::Error::Self::make_parsing_error ();
    5281            0 :         }
    5282              :     }
    5283              : 
    5284              :   // ensure that cannot have both type and reference
    5285         7802 :   if (type && has_reference)
    5286              :     {
    5287            0 :       Error error (
    5288            0 :         lexer.peek_token ()->get_locus (),
    5289              :         "cannot have both a reference and a type specified in a self param");
    5290            0 :       add_error (std::move (error));
    5291              : 
    5292              :       // skip after somewhere?
    5293            0 :       return Parse::Error::Self::make_parsing_error ();
    5294            0 :     }
    5295              : 
    5296         7802 :   if (has_reference)
    5297              :     {
    5298         4638 :       return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
    5299         4638 :                                                locus);
    5300              :     }
    5301              :   else
    5302              :     {
    5303              :       // note that type may be nullptr here and that's fine
    5304         3164 :       return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
    5305         3164 :                                                locus);
    5306              :     }
    5307        25945 : }
    5308              : 
    5309              : /* Parses an expression or macro statement. */
    5310              : template <typename ManagedTokenSource>
    5311              : std::unique_ptr<AST::Stmt>
    5312          324 : Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
    5313              :                                              ParseRestrictions restrictions)
    5314              : {
    5315          324 :   location_t locus = lexer.peek_token ()->get_locus ();
    5316              : 
    5317          324 :   tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
    5318              : 
    5319          648 :   switch (lexer.peek_token ()->get_id ())
    5320              :     {
    5321          220 :     case IDENTIFIER:
    5322              :     case CRATE:
    5323              :     case SUPER:
    5324              :     case SELF:
    5325              :     case SELF_ALIAS:
    5326              :     case DOLLAR_SIGN:
    5327              :     case SCOPE_RESOLUTION:
    5328              :       {
    5329          220 :         AST::PathInExpression path = parse_path_in_expression ();
    5330              :         tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
    5331          220 :           null_denotation;
    5332              : 
    5333          440 :         if (lexer.peek_token ()->get_id () == EXCLAM)
    5334              :           {
    5335           61 :             std::unique_ptr<AST::MacroInvocation> invoc
    5336          122 :               = parse_macro_invocation_partial (std::move (path),
    5337              :                                                 std::move (outer_attrs));
    5338              : 
    5339           61 :             if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
    5340              :               {
    5341           59 :                 invoc->add_semicolon ();
    5342              :                 // Macro invocation with semicolon.
    5343           59 :                 return invoc;
    5344              :               }
    5345              : 
    5346            2 :             TokenId after_macro = lexer.peek_token ()->get_id ();
    5347              : 
    5348            2 :             if (restrictions.allow_close_after_expr_stmt
    5349            2 :                 && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
    5350              :                     || after_macro == RIGHT_SQUARE))
    5351            2 :               return invoc;
    5352              : 
    5353            0 :             if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
    5354              :                   == AST::CURLY
    5355            0 :                 && after_macro != DOT && after_macro != QUESTION_MARK)
    5356              :               {
    5357            0 :                 rust_debug ("braced macro statement");
    5358            0 :                 return invoc;
    5359              :               }
    5360              : 
    5361            0 :             null_denotation = std::move (invoc);
    5362           61 :           }
    5363              :         else
    5364              :           {
    5365              :             null_denotation
    5366          318 :               = null_denotation_path (std::move (path), {}, restrictions);
    5367              :           }
    5368              : 
    5369          636 :         expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
    5370              :                                  std::move (outer_attrs), restrictions);
    5371              :         break;
    5372          220 :       }
    5373          104 :     default:
    5374          104 :       restrictions.expr_can_be_stmt = true;
    5375          208 :       expr = parse_expr (std::move (outer_attrs), restrictions);
    5376          104 :       break;
    5377              :     }
    5378              : 
    5379          263 :   if (!expr)
    5380              :     {
    5381              :       // expr is required, error
    5382            0 :       Error error (lexer.peek_token ()->get_locus (),
    5383              :                    "failed to parse expr in expr statement");
    5384            0 :       add_error (std::move (error));
    5385              : 
    5386            0 :       skip_after_semicolon ();
    5387            0 :       return nullptr;
    5388            0 :     }
    5389              : 
    5390          263 :   bool has_semi = false;
    5391              : 
    5392          263 :   if (restrictions.consume_semi)
    5393              :     {
    5394          249 :       if (maybe_skip_token (SEMICOLON))
    5395              :         {
    5396          138 :           has_semi = true;
    5397              :         }
    5398          111 :       else if (expr.value ()->is_expr_without_block ())
    5399              :         {
    5400           10 :           if (restrictions.allow_close_after_expr_stmt)
    5401              :             {
    5402           10 :               TokenId id = lexer.peek_token ()->get_id ();
    5403           10 :               if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
    5404              :                 {
    5405            3 :                   expect_token (SEMICOLON);
    5406            3 :                   return nullptr;
    5407              :                 }
    5408              :             }
    5409              :           else
    5410              :             {
    5411            0 :               expect_token (SEMICOLON);
    5412            0 :               return nullptr;
    5413              :             }
    5414              :         }
    5415              :     }
    5416              : 
    5417          260 :   return std::make_unique<AST::ExprStmt> (std::move (expr.value ()), locus,
    5418          260 :                                           has_semi);
    5419          324 : }
    5420              : 
    5421              : // Parses a loop label used in loop expressions.
    5422              : template <typename ManagedTokenSource>
    5423              : tl::expected<AST::LoopLabel, Parse::Error::LoopLabel>
    5424           40 : Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
    5425              : {
    5426              :   // parse lifetime - if doesn't exist, assume no label
    5427           40 :   if (tok->get_id () != LIFETIME)
    5428              :     {
    5429              :       // not necessarily an error
    5430              :       return Parse::Error::LoopLabel::make_not_loop_label ();
    5431              :     }
    5432              :   /* FIXME: check for named lifetime requirement here? or check in semantic
    5433              :    * analysis phase? */
    5434           40 :   AST::Lifetime label = lifetime_from_token (tok);
    5435              : 
    5436           40 :   if (!skip_token (COLON))
    5437              :     {
    5438              :       // skip somewhere?
    5439           40 :       Parse::Error::LoopLabel::make_missing_colon ();
    5440              :     }
    5441              : 
    5442              :   return tl::expected<AST::LoopLabel, Parse::Error::LoopLabel> (
    5443           40 :     AST::LoopLabel (std::move (label), tok->get_locus ()));
    5444           40 : }
    5445              : 
    5446              : // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
    5447              : template <typename ManagedTokenSource>
    5448              : AST::MatchArm
    5449         2136 : Parser<ManagedTokenSource>::parse_match_arm ()
    5450              : {
    5451              :   // parse optional outer attributes
    5452         2136 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    5453              : 
    5454              :   // DEBUG
    5455         2136 :   rust_debug ("about to start parsing match arm patterns");
    5456              : 
    5457              :   // break early if find right curly
    5458         4272 :   if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
    5459              :     {
    5460              :       // not an error
    5461            0 :       return AST::MatchArm::create_error ();
    5462              :     }
    5463              : 
    5464              :   // parse match arm patterns - at least 1 is required
    5465         2136 :   std::unique_ptr<AST::Pattern> match_arm_pattern
    5466              :     = parse_match_arm_pattern (RIGHT_CURLY);
    5467         2136 :   if (match_arm_pattern == nullptr)
    5468              :     {
    5469            0 :       Error error (lexer.peek_token ()->get_locus (),
    5470              :                    "failed to parse any patterns in match arm");
    5471            0 :       add_error (std::move (error));
    5472              : 
    5473              :       // skip somewhere?
    5474            0 :       return AST::MatchArm::create_error ();
    5475            0 :     }
    5476              : 
    5477              :   // DEBUG
    5478         2136 :   rust_debug ("successfully parsed match arm patterns");
    5479              : 
    5480              :   // parse match arm guard expr if it exists
    5481         2136 :   std::unique_ptr<AST::Expr> guard_expr = nullptr;
    5482         4272 :   if (lexer.peek_token ()->get_id () == IF)
    5483              :     {
    5484            1 :       lexer.skip_token ();
    5485              : 
    5486            1 :       auto guard_expr_res = parse_expr ();
    5487            1 :       if (!guard_expr_res)
    5488              :         {
    5489            0 :           Error error (lexer.peek_token ()->get_locus (),
    5490              :                        "failed to parse guard expression in match arm");
    5491            0 :           add_error (std::move (error));
    5492              : 
    5493              :           // skip somewhere?
    5494            0 :           return AST::MatchArm::create_error ();
    5495            0 :         }
    5496            1 :       guard_expr = std::move (guard_expr_res.value ());
    5497            1 :     }
    5498              : 
    5499              :   // DEBUG
    5500         2136 :   rust_debug ("successfully parsed match arm");
    5501              : 
    5502         4272 :   return AST::MatchArm (std::move (match_arm_pattern),
    5503         4272 :                         lexer.peek_token ()->get_locus (),
    5504         2136 :                         std::move (guard_expr), std::move (outer_attrs));
    5505         2136 : }
    5506              : 
    5507              : /* Parses the patterns used in a match arm. End token id is the id of the
    5508              :  * token that would exist after the patterns are done (e.g. '}' for match
    5509              :  * expr, '=' for if let and while let). */
    5510              : template <typename ManagedTokenSource>
    5511              : std::unique_ptr<AST::Pattern>
    5512         2171 : Parser<ManagedTokenSource>::parse_match_arm_pattern (TokenId end_token_id)
    5513              : {
    5514              :   // skip optional leading '|'
    5515         4342 :   if (lexer.peek_token ()->get_id () == PIPE)
    5516            0 :     lexer.skip_token ();
    5517              :   /* TODO: do I even need to store the result of this? can't be used.
    5518              :    * If semantically different, I need a wrapped "match arm patterns" object
    5519              :    * for this. */
    5520              : 
    5521         2171 :   std::unique_ptr<AST::Pattern> pattern;
    5522              : 
    5523              :   // quick break out if end_token_id
    5524         4342 :   if (lexer.peek_token ()->get_id () == end_token_id)
    5525            1 :     return pattern;
    5526              : 
    5527              :   // parse required pattern - if doesn't exist, return empty
    5528         2170 :   std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
    5529         2170 :   if (initial_pattern == nullptr)
    5530              :     {
    5531              :       // FIXME: should this be an error?
    5532            0 :       return pattern;
    5533              :     }
    5534              : 
    5535         2170 :   return initial_pattern;
    5536         2171 : }
    5537              : 
    5538              : // Parses a single parameter used in a closure definition.
    5539              : template <typename ManagedTokenSource>
    5540              : AST::ClosureParam
    5541           72 : Parser<ManagedTokenSource>::parse_closure_param ()
    5542              : {
    5543           72 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    5544              : 
    5545              :   // parse pattern (which is required)
    5546           72 :   std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
    5547           72 :   if (pattern == nullptr)
    5548              :     {
    5549              :       // not necessarily an error
    5550            0 :       return AST::ClosureParam::create_error ();
    5551              :     }
    5552              : 
    5553              :   // parse optional type of param
    5554           72 :   std::unique_ptr<AST::Type> type = nullptr;
    5555          144 :   if (lexer.peek_token ()->get_id () == COLON)
    5556              :     {
    5557           63 :       lexer.skip_token ();
    5558              : 
    5559              :       // parse type, which is now required
    5560           63 :       type = parse_type ();
    5561           63 :       if (type == nullptr)
    5562              :         {
    5563            0 :           Error error (lexer.peek_token ()->get_locus (),
    5564              :                        "failed to parse type in closure parameter");
    5565            0 :           add_error (std::move (error));
    5566              : 
    5567              :           // skip somewhere?
    5568            0 :           return AST::ClosureParam::create_error ();
    5569            0 :         }
    5570              :     }
    5571              : 
    5572           72 :   location_t loc = pattern->get_locus ();
    5573           72 :   return AST::ClosureParam (std::move (pattern), loc, std::move (type),
    5574           72 :                             std::move (outer_attrs));
    5575           72 : }
    5576              : 
    5577              : // Parses a type (will further disambiguate any type).
    5578              : template <typename ManagedTokenSource>
    5579              : std::unique_ptr<AST::Type>
    5580        43391 : Parser<ManagedTokenSource>::parse_type (bool save_errors)
    5581              : {
    5582              :   /* rules for all types:
    5583              :    * NeverType:               '!'
    5584              :    * SliceType:               '[' Type ']'
    5585              :    * InferredType:            '_'
    5586              :    * MacroInvocation:         SimplePath '!' DelimTokenTree
    5587              :    * ParenthesisedType:       '(' Type ')'
    5588              :    * ImplTraitType:           'impl' TypeParamBounds
    5589              :    *  TypeParamBounds (not type)  TypeParamBound ( '+' TypeParamBound )* '+'?
    5590              :    *  TypeParamBound          Lifetime | TraitBound
    5591              :    * ImplTraitTypeOneBound:   'impl' TraitBound
    5592              :    * TraitObjectType:         'dyn'? TypeParamBounds
    5593              :    * TraitObjectTypeOneBound: 'dyn'? TraitBound
    5594              :    *  TraitBound              '?'? ForLifetimes? TypePath | '(' '?'?
    5595              :    * ForLifetimes? TypePath ')' BareFunctionType:        ForLifetimes?
    5596              :    * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
    5597              :    * LifetimeParams '>' FunctionQualifiers      ( 'async' | 'const' )?
    5598              :    * 'unsafe'?
    5599              :    * ('extern' abi?)? QualifiedPathInType:     '<' Type ( 'as' TypePath )? '>'
    5600              :    * (
    5601              :    * '::' TypePathSegment )+ TypePath:                '::'? TypePathSegment (
    5602              :    * '::' TypePathSegment)* ArrayType:               '[' Type ';' Expr ']'
    5603              :    * ReferenceType:           '&' Lifetime? 'mut'? TypeNoBounds
    5604              :    * RawPointerType:          '*' ( 'mut' | 'const' ) TypeNoBounds
    5605              :    * TupleType:               '(' Type etc. - regular tuple stuff. Also
    5606              :    * regular tuple vs parenthesised precedence
    5607              :    *
    5608              :    * Disambiguate between macro and type path via type path being parsed, and
    5609              :    * then if '!' found, convert type path to simple path for macro. Usual
    5610              :    * disambiguation for tuple vs parenthesised. For ImplTraitType and
    5611              :    * TraitObjectType individual disambiguations, they seem more like "special
    5612              :    * cases", so probably just try to parse the more general ImplTraitType or
    5613              :    * TraitObjectType and return OneBound versions if they satisfy those
    5614              :    * criteria. */
    5615              : 
    5616        43391 :   const_TokenPtr t = lexer.peek_token ();
    5617        43391 :   switch (t->get_id ())
    5618              :     {
    5619           46 :     case EXCLAM:
    5620              :       // never type - can't be macro as no path beforehand
    5621           46 :       lexer.skip_token ();
    5622           46 :       return std::unique_ptr<AST::NeverType> (
    5623           46 :         new AST::NeverType (t->get_locus ()));
    5624          854 :     case LEFT_SQUARE:
    5625              :       // slice type or array type - requires further disambiguation
    5626          854 :       return parse_slice_or_array_type ();
    5627          309 :     case LEFT_SHIFT:
    5628              :     case LEFT_ANGLE:
    5629              :       {
    5630              :         // qualified path in type
    5631          309 :         AST::QualifiedPathInType path = parse_qualified_path_in_type ();
    5632          309 :         if (path.is_error ())
    5633              :           {
    5634            0 :             if (save_errors)
    5635              :               {
    5636            0 :                 Error error (t->get_locus (),
    5637              :                              "failed to parse qualified path in type");
    5638            0 :                 add_error (std::move (error));
    5639            0 :               }
    5640              : 
    5641            0 :             return nullptr;
    5642              :           }
    5643          309 :         return std::unique_ptr<AST::QualifiedPathInType> (
    5644          309 :           new AST::QualifiedPathInType (std::move (path)));
    5645          309 :       }
    5646          104 :     case UNDERSCORE:
    5647              :       // inferred type
    5648          104 :       lexer.skip_token ();
    5649          104 :       return std::unique_ptr<AST::InferredType> (
    5650          104 :         new AST::InferredType (t->get_locus ()));
    5651         2728 :     case ASTERISK:
    5652              :       // raw pointer type
    5653         2728 :       return parse_raw_pointer_type ();
    5654         4290 :     case AMP: // does this also include AMP_AMP?
    5655              :     case LOGICAL_AND:
    5656              :       // reference type
    5657         4290 :       return parse_reference_type ();
    5658            0 :     case LIFETIME:
    5659              :       {
    5660              :         /* probably a lifetime bound, so probably type param bounds in
    5661              :          * TraitObjectType */
    5662            0 :         std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    5663              :           = parse_type_param_bounds ();
    5664              : 
    5665            0 :         return std::unique_ptr<AST::TraitObjectType> (
    5666            0 :           new AST::TraitObjectType (std::move (bounds), t->get_locus (),
    5667            0 :                                     false));
    5668            0 :       }
    5669        34447 :     case IDENTIFIER:
    5670              :     case SUPER:
    5671              :     case SELF:
    5672              :     case SELF_ALIAS:
    5673              :     case CRATE:
    5674              :     case DOLLAR_SIGN:
    5675              :     case SCOPE_RESOLUTION:
    5676              :       {
    5677              :         // macro invocation or type path - requires further disambiguation.
    5678              :         /* for parsing path component of each rule, perhaps parse it as a
    5679              :          * typepath and attempt conversion to simplepath if a trailing '!' is
    5680              :          * found */
    5681              :         /* Type path also includes TraitObjectTypeOneBound BUT if it starts
    5682              :          * with it, it is exactly the same as a TypePath syntactically, so
    5683              :          * this is a syntactical ambiguity. As such, the parser will parse it
    5684              :          * as a TypePath. This, however, does not prevent TraitObjectType from
    5685              :          * starting with a typepath. */
    5686              : 
    5687              :         // parse path as type path
    5688        34447 :         AST::TypePath path = parse_type_path ();
    5689        34447 :         if (path.is_error ())
    5690              :           {
    5691            0 :             if (save_errors)
    5692              :               {
    5693            0 :                 Error error (t->get_locus (),
    5694              :                              "failed to parse path as first component of type");
    5695            0 :                 add_error (std::move (error));
    5696            0 :               }
    5697              : 
    5698            0 :             return nullptr;
    5699              :           }
    5700        34447 :         location_t locus = path.get_locus ();
    5701              : 
    5702              :         // branch on next token
    5703        34447 :         t = lexer.peek_token ();
    5704        34447 :         switch (t->get_id ())
    5705              :           {
    5706           29 :           case EXCLAM:
    5707              :             {
    5708              :               // macro invocation
    5709              :               // convert to simple path
    5710           29 :               AST::SimplePath macro_path = path.as_simple_path ();
    5711           29 :               if (macro_path.is_empty ())
    5712              :                 {
    5713            0 :                   if (save_errors)
    5714              :                     {
    5715            0 :                       Error error (t->get_locus (),
    5716              :                                    "failed to parse simple path in macro "
    5717              :                                    "invocation (for type)");
    5718            0 :                       add_error (std::move (error));
    5719            0 :                     }
    5720              : 
    5721            0 :                   return nullptr;
    5722              :                 }
    5723              : 
    5724           29 :               lexer.skip_token ();
    5725              : 
    5726           29 :               auto tok_tree = parse_delim_token_tree ();
    5727           29 :               if (!tok_tree)
    5728            0 :                 return nullptr;
    5729              : 
    5730           87 :               return AST::MacroInvocation::Regular (
    5731           58 :                 AST::MacroInvocData (std::move (macro_path),
    5732           29 :                                      std::move (tok_tree.value ())),
    5733           29 :                 {}, locus);
    5734           58 :             }
    5735            0 :           case PLUS:
    5736              :             {
    5737              :               // type param bounds
    5738            0 :               std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    5739              : 
    5740              :               // convert type path to trait bound
    5741            0 :               std::unique_ptr<AST::TraitBound> path_bound (
    5742            0 :                 new AST::TraitBound (std::move (path), locus, false, false));
    5743            0 :               bounds.push_back (std::move (path_bound));
    5744              : 
    5745              :               /* parse rest of bounds - FIXME: better way to find when to stop
    5746              :                * parsing */
    5747            0 :               while (t->get_id () == PLUS)
    5748              :                 {
    5749            0 :                   lexer.skip_token ();
    5750              : 
    5751              :                   // parse bound if it exists - if not, assume end of sequence
    5752            0 :                   std::unique_ptr<AST::TypeParamBound> bound
    5753              :                     = parse_type_param_bound ();
    5754            0 :                   if (bound == nullptr)
    5755              :                     {
    5756              :                       break;
    5757              :                     }
    5758            0 :                   bounds.push_back (std::move (bound));
    5759              : 
    5760            0 :                   t = lexer.peek_token ();
    5761              :                 }
    5762              : 
    5763            0 :               return std::unique_ptr<AST::TraitObjectType> (
    5764            0 :                 new AST::TraitObjectType (std::move (bounds), locus, false));
    5765            0 :             }
    5766        34418 :           default:
    5767              :             // assume that this is a type path and not an error
    5768        34418 :             return std::unique_ptr<AST::TypePath> (
    5769        34418 :               new AST::TypePath (std::move (path)));
    5770              :           }
    5771        34447 :       }
    5772          396 :     case LEFT_PAREN:
    5773              :       /* tuple type or parenthesised type - requires further disambiguation
    5774              :        * (the usual). ok apparently can be a parenthesised TraitBound too, so
    5775              :        * could be TraitObjectTypeOneBound or TraitObjectType */
    5776          396 :       return parse_paren_prefixed_type ();
    5777            3 :     case FOR:
    5778              :       // TraitObjectTypeOneBound or BareFunctionType
    5779            3 :       return parse_for_prefixed_type ();
    5780           61 :     case ASYNC:
    5781              :     case CONST:
    5782              :     case UNSAFE:
    5783              :     case EXTERN_KW:
    5784              :     case FN_KW:
    5785              :       // bare function type (with no for lifetimes)
    5786           61 :       return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
    5787          120 :     case IMPL:
    5788          120 :       lexer.skip_token ();
    5789          240 :       if (lexer.peek_token ()->get_id () == LIFETIME)
    5790              :         {
    5791              :           /* cannot be one bound because lifetime prevents it from being
    5792              :            * traitbound */
    5793            0 :           std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    5794              :             = parse_type_param_bounds ();
    5795              : 
    5796            0 :           return std::unique_ptr<AST::ImplTraitType> (
    5797            0 :             new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
    5798            0 :         }
    5799              :       else
    5800              :         {
    5801              :           // should be trait bound, so parse trait bound
    5802          120 :           std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
    5803          120 :           if (initial_bound == nullptr)
    5804              :             {
    5805            0 :               if (save_errors)
    5806              :                 {
    5807            0 :                   Error error (lexer.peek_token ()->get_locus (),
    5808              :                                "failed to parse ImplTraitType initial bound");
    5809            0 :                   add_error (std::move (error));
    5810            0 :                 }
    5811              : 
    5812            0 :               return nullptr;
    5813              :             }
    5814              : 
    5815          120 :           location_t locus = t->get_locus ();
    5816              : 
    5817              :           // short cut if next token isn't '+'
    5818          120 :           t = lexer.peek_token ();
    5819          120 :           if (t->get_id () != PLUS)
    5820              :             {
    5821          120 :               return std::unique_ptr<AST::ImplTraitTypeOneBound> (
    5822          120 :                 new AST::ImplTraitTypeOneBound (std::move (initial_bound),
    5823          120 :                                                 locus));
    5824              :             }
    5825              : 
    5826              :           // parse additional type param bounds
    5827            0 :           std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    5828            0 :           bounds.push_back (std::move (initial_bound));
    5829            0 :           while (t->get_id () == PLUS)
    5830              :             {
    5831            0 :               lexer.skip_token ();
    5832              : 
    5833              :               // parse bound if it exists
    5834            0 :               std::unique_ptr<AST::TypeParamBound> bound
    5835              :                 = parse_type_param_bound ();
    5836            0 :               if (bound == nullptr)
    5837              :                 {
    5838              :                   // not an error as trailing plus may exist
    5839              :                   break;
    5840              :                 }
    5841            0 :               bounds.push_back (std::move (bound));
    5842              : 
    5843            0 :               t = lexer.peek_token ();
    5844              :             }
    5845              : 
    5846            0 :           return std::unique_ptr<AST::ImplTraitType> (
    5847            0 :             new AST::ImplTraitType (std::move (bounds), locus));
    5848          120 :         }
    5849           29 :     case DYN:
    5850              :     case QUESTION_MARK:
    5851              :       {
    5852              :         // either TraitObjectType or TraitObjectTypeOneBound
    5853           29 :         bool has_dyn = false;
    5854           29 :         if (t->get_id () == DYN)
    5855              :           {
    5856           29 :             lexer.skip_token ();
    5857           29 :             has_dyn = true;
    5858              :           }
    5859              : 
    5860           58 :         if (lexer.peek_token ()->get_id () == LIFETIME)
    5861              :           {
    5862              :             /* cannot be one bound because lifetime prevents it from being
    5863              :              * traitbound */
    5864            0 :             std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    5865              :               = parse_type_param_bounds ();
    5866              : 
    5867            0 :             return std::unique_ptr<AST::TraitObjectType> (
    5868            0 :               new AST::TraitObjectType (std::move (bounds), t->get_locus (),
    5869            0 :                                         has_dyn));
    5870            0 :           }
    5871              :         else
    5872              :           {
    5873              :             // should be trait bound, so parse trait bound
    5874           29 :             std::unique_ptr<AST::TraitBound> initial_bound
    5875              :               = parse_trait_bound ();
    5876           29 :             if (initial_bound == nullptr)
    5877              :               {
    5878            2 :                 if (save_errors)
    5879              :                   {
    5880            2 :                     Error error (
    5881            2 :                       lexer.peek_token ()->get_locus (),
    5882              :                       "failed to parse TraitObjectType initial bound");
    5883            2 :                     add_error (std::move (error));
    5884            2 :                   }
    5885              : 
    5886            2 :                 return nullptr;
    5887              :               }
    5888              : 
    5889              :             // short cut if next token isn't '+'
    5890           27 :             t = lexer.peek_token ();
    5891           27 :             if (t->get_id () != PLUS)
    5892              :               {
    5893              :                 // convert trait bound to value object
    5894           14 :                 AST::TraitBound value_bound (*initial_bound);
    5895              : 
    5896              :                 // DEBUG: removed as unique ptr, so should auto delete
    5897              :                 // delete initial_bound;
    5898              : 
    5899           14 :                 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    5900           28 :                   new AST::TraitObjectTypeOneBound (std::move (value_bound),
    5901           14 :                                                     t->get_locus (), has_dyn));
    5902           14 :               }
    5903              : 
    5904              :             // parse additional type param bounds
    5905           13 :             std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    5906           13 :             bounds.push_back (std::move (initial_bound));
    5907           33 :             while (t->get_id () == PLUS)
    5908              :               {
    5909           20 :                 lexer.skip_token ();
    5910              : 
    5911              :                 // parse bound if it exists
    5912           20 :                 std::unique_ptr<AST::TypeParamBound> bound
    5913              :                   = parse_type_param_bound ();
    5914           20 :                 if (bound == nullptr)
    5915              :                   {
    5916              :                     // not an error as trailing plus may exist
    5917              :                     break;
    5918              :                   }
    5919           20 :                 bounds.push_back (std::move (bound));
    5920              : 
    5921           20 :                 t = lexer.peek_token ();
    5922              :               }
    5923              : 
    5924           13 :             return std::unique_ptr<AST::TraitObjectType> (
    5925           13 :               new AST::TraitObjectType (std::move (bounds), t->get_locus (),
    5926           13 :                                         has_dyn));
    5927           29 :           }
    5928              :       }
    5929            4 :     default:
    5930            4 :       if (save_errors)
    5931            4 :         add_error (Error (t->get_locus (), "unrecognised token %qs in type",
    5932              :                           t->get_token_description ()));
    5933              : 
    5934            4 :       return nullptr;
    5935              :     }
    5936        43391 : }
    5937              : 
    5938              : /* Parses a type that has '(' as its first character. Returns a tuple type,
    5939              :  * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
    5940              :  * on following characters. */
    5941              : template <typename ManagedTokenSource>
    5942              : std::unique_ptr<AST::Type>
    5943          396 : Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
    5944              : {
    5945              :   /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
    5946              :    * a trait bound, not a parenthesised type, so that it can still be used in
    5947              :    * type param bounds. */
    5948              : 
    5949              :   /* NOTE: this implementation is really shit but I couldn't think of a better
    5950              :    * one. It requires essentially breaking polymorphism and downcasting via
    5951              :    * virtual method abuse, as it was copied from the rustc implementation (in
    5952              :    * which types are reified due to tagged union), after a more OOP attempt by
    5953              :    * me failed. */
    5954          396 :   location_t left_delim_locus = lexer.peek_token ()->get_locus ();
    5955              : 
    5956              :   // skip left delim
    5957          396 :   lexer.skip_token ();
    5958              :   /* while next token isn't close delim, parse comma-separated types, saving
    5959              :    * whether trailing comma happens */
    5960          396 :   const_TokenPtr t = lexer.peek_token ();
    5961          396 :   bool trailing_comma = true;
    5962          396 :   std::vector<std::unique_ptr<AST::Type>> types;
    5963              : 
    5964          723 :   while (t->get_id () != RIGHT_PAREN)
    5965              :     {
    5966          632 :       std::unique_ptr<AST::Type> type = parse_type ();
    5967          632 :       if (type == nullptr)
    5968              :         {
    5969            0 :           Error error (t->get_locus (),
    5970              :                        "failed to parse type inside parentheses (probably "
    5971              :                        "tuple or parenthesised)");
    5972            0 :           add_error (std::move (error));
    5973              : 
    5974            0 :           return nullptr;
    5975            0 :         }
    5976          632 :       types.push_back (std::move (type));
    5977              : 
    5978          632 :       t = lexer.peek_token ();
    5979          632 :       if (t->get_id () != COMMA)
    5980              :         {
    5981          305 :           trailing_comma = false;
    5982              :           break;
    5983              :         }
    5984          327 :       lexer.skip_token ();
    5985              : 
    5986          327 :       t = lexer.peek_token ();
    5987              :     }
    5988              : 
    5989          396 :   if (!skip_token (RIGHT_PAREN))
    5990              :     {
    5991            0 :       return nullptr;
    5992              :     }
    5993              : 
    5994              :   // if only one type and no trailing comma, then not a tuple type
    5995          396 :   if (types.size () == 1 && !trailing_comma)
    5996              :     {
    5997              :       // must be a TraitObjectType (with more than one bound)
    5998           10 :       if (lexer.peek_token ()->get_id () == PLUS)
    5999              :         {
    6000              :           // create type param bounds vector
    6001            0 :           std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    6002              : 
    6003              :           // HACK: convert type to traitbound and add to bounds
    6004            0 :           std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
    6005            0 :           std::unique_ptr<AST::TraitBound> converted_bound (
    6006            0 :             released_ptr->to_trait_bound (true));
    6007            0 :           if (converted_bound == nullptr)
    6008              :             {
    6009            0 :               Error error (
    6010            0 :                 lexer.peek_token ()->get_locus (),
    6011              :                 "failed to hackily converted parsed type to trait bound");
    6012            0 :               add_error (std::move (error));
    6013              : 
    6014            0 :               return nullptr;
    6015            0 :             }
    6016            0 :           bounds.push_back (std::move (converted_bound));
    6017              : 
    6018            0 :           t = lexer.peek_token ();
    6019            0 :           while (t->get_id () == PLUS)
    6020              :             {
    6021            0 :               lexer.skip_token ();
    6022              : 
    6023              :               // attempt to parse typeparambound
    6024            0 :               std::unique_ptr<AST::TypeParamBound> bound
    6025              :                 = parse_type_param_bound ();
    6026            0 :               if (bound == nullptr)
    6027              :                 {
    6028              :                   // not an error if null
    6029              :                   break;
    6030              :                 }
    6031            0 :               bounds.push_back (std::move (bound));
    6032              : 
    6033            0 :               t = lexer.peek_token ();
    6034              :             }
    6035              : 
    6036            0 :           return std::unique_ptr<AST::TraitObjectType> (
    6037            0 :             new AST::TraitObjectType (std::move (bounds), left_delim_locus,
    6038            0 :                                       false));
    6039            0 :         }
    6040              :       else
    6041              :         {
    6042              :           // release vector pointer
    6043            5 :           std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
    6044              :           /* HACK: attempt to convert to trait bound. if fails, parenthesised
    6045              :            * type */
    6046            5 :           std::unique_ptr<AST::TraitBound> converted_bound (
    6047            5 :             released_ptr->to_trait_bound (true));
    6048            5 :           if (converted_bound == nullptr)
    6049              :             {
    6050              :               // parenthesised type
    6051            5 :               return std::unique_ptr<AST::ParenthesisedType> (
    6052            5 :                 new AST::ParenthesisedType (std::move (released_ptr),
    6053            5 :                                             left_delim_locus));
    6054              :             }
    6055              :           else
    6056              :             {
    6057              :               // trait object type (one bound)
    6058              : 
    6059              :               // get value semantics trait bound
    6060            0 :               AST::TraitBound value_bound (*converted_bound);
    6061              : 
    6062            0 :               return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6063            0 :                 new AST::TraitObjectTypeOneBound (value_bound,
    6064            0 :                                                   left_delim_locus));
    6065            0 :             }
    6066            5 :         }
    6067              :     }
    6068              :   else
    6069              :     {
    6070          391 :       return std::unique_ptr<AST::TupleType> (
    6071          391 :         new AST::TupleType (std::move (types), left_delim_locus));
    6072              :     }
    6073              :   /* TODO: ensure that this ensures that dynamic dispatch for traits is not
    6074              :    * lost somehow */
    6075          396 : }
    6076              : 
    6077              : /* Parses a type that has 'for' as its first character. This means it has a
    6078              :  * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
    6079              :  * TraitObjectTypeOneBound depending on following characters. */
    6080              : template <typename ManagedTokenSource>
    6081              : std::unique_ptr<AST::Type>
    6082            3 : Parser<ManagedTokenSource>::parse_for_prefixed_type ()
    6083              : {
    6084            3 :   location_t for_locus = lexer.peek_token ()->get_locus ();
    6085              :   // parse for lifetimes in type
    6086            3 :   std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
    6087              : 
    6088              :   // branch on next token - either function or a trait type
    6089            3 :   const_TokenPtr t = lexer.peek_token ();
    6090            3 :   switch (t->get_id ())
    6091              :     {
    6092            3 :     case ASYNC:
    6093              :     case CONST:
    6094              :     case UNSAFE:
    6095              :     case EXTERN_KW:
    6096              :     case FN_KW:
    6097            3 :       return parse_bare_function_type (std::move (for_lifetimes));
    6098            0 :     case SCOPE_RESOLUTION:
    6099              :     case IDENTIFIER:
    6100              :     case SUPER:
    6101              :     case SELF:
    6102              :     case SELF_ALIAS:
    6103              :     case CRATE:
    6104              :     case DOLLAR_SIGN:
    6105              :       {
    6106              :         // path, so trait type
    6107              : 
    6108              :         // parse type path to finish parsing trait bound
    6109            0 :         AST::TypePath path = parse_type_path ();
    6110              : 
    6111            0 :         t = lexer.peek_token ();
    6112            0 :         if (t->get_id () != PLUS)
    6113              :           {
    6114              :             // must be one-bound trait type
    6115              :             // create trait bound value object
    6116            0 :             AST::TraitBound bound (std::move (path), for_locus, false, false,
    6117              :                                    std::move (for_lifetimes));
    6118              : 
    6119            0 :             return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6120            0 :               new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
    6121            0 :           }
    6122              : 
    6123              :         /* more than one bound trait type (or at least parsed as it - could be
    6124              :          * trailing '+') create trait bound pointer and bounds */
    6125            0 :         std::unique_ptr<AST::TraitBound> initial_bound (
    6126            0 :           new AST::TraitBound (std::move (path), for_locus, false, false,
    6127              :                                std::move (for_lifetimes)));
    6128            0 :         std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    6129            0 :         bounds.push_back (std::move (initial_bound));
    6130              : 
    6131            0 :         while (t->get_id () == PLUS)
    6132              :           {
    6133            0 :             lexer.skip_token ();
    6134              : 
    6135              :             // parse type param bound if it exists
    6136            0 :             std::unique_ptr<AST::TypeParamBound> bound
    6137              :               = parse_type_param_bound ();
    6138            0 :             if (bound == nullptr)
    6139              :               {
    6140              :                 // not an error - e.g. trailing plus
    6141            0 :                 return nullptr;
    6142              :               }
    6143            0 :             bounds.push_back (std::move (bound));
    6144              : 
    6145            0 :             t = lexer.peek_token ();
    6146              :           }
    6147              : 
    6148            0 :         return std::unique_ptr<AST::TraitObjectType> (
    6149            0 :           new AST::TraitObjectType (std::move (bounds), for_locus, false));
    6150            0 :       }
    6151            0 :     default:
    6152              :       // error
    6153            0 :       add_error (Error (t->get_locus (),
    6154              :                         "unrecognised token %qs in bare function type or trait "
    6155              :                         "object type or trait object type one bound",
    6156              :                         t->get_token_description ()));
    6157              : 
    6158            0 :       return nullptr;
    6159              :     }
    6160            3 : }
    6161              : 
    6162              : // Parses a maybe named param used in bare function types.
    6163              : template <typename ManagedTokenSource>
    6164              : AST::MaybeNamedParam
    6165           48 : Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
    6166              : {
    6167              :   /* Basically guess that param is named if first token is identifier or
    6168              :    * underscore and second token is semicolon. This should probably have no
    6169              :    * exceptions. rustc uses backtracking to parse these, but at the time of
    6170              :    * writing gccrs has no backtracking capabilities. */
    6171           48 :   const_TokenPtr current = lexer.peek_token ();
    6172           48 :   const_TokenPtr next = lexer.peek_token (1);
    6173              : 
    6174           48 :   Identifier name;
    6175           48 :   AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
    6176              : 
    6177           48 :   if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
    6178              :     {
    6179              :       // named param
    6180            1 :       name = {current};
    6181            1 :       kind = AST::MaybeNamedParam::IDENTIFIER;
    6182            1 :       lexer.skip_token (1);
    6183              :     }
    6184           47 :   else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
    6185              :     {
    6186              :       // wildcard param
    6187           12 :       name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
    6188            6 :       kind = AST::MaybeNamedParam::WILDCARD;
    6189            6 :       lexer.skip_token (1);
    6190              :     }
    6191              : 
    6192              :   // parse type (required)
    6193           48 :   std::unique_ptr<AST::Type> type = parse_type ();
    6194           48 :   if (type == nullptr)
    6195              :     {
    6196            0 :       Error error (lexer.peek_token ()->get_locus (),
    6197              :                    "failed to parse type in maybe named param");
    6198            0 :       add_error (std::move (error));
    6199              : 
    6200            0 :       return AST::MaybeNamedParam::create_error ();
    6201            0 :     }
    6202              : 
    6203           96 :   return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
    6204           48 :                                std::move (outer_attrs), current->get_locus ());
    6205           96 : }
    6206              : 
    6207              : /* Parses a bare function type (with the given for lifetimes for convenience -
    6208              :  * does not parse them itself). */
    6209              : template <typename ManagedTokenSource>
    6210              : std::unique_ptr<AST::BareFunctionType>
    6211           66 : Parser<ManagedTokenSource>::parse_bare_function_type (
    6212              :   std::vector<AST::LifetimeParam> for_lifetimes)
    6213              : {
    6214              :   // TODO: pass in for lifetime location as param
    6215           66 :   location_t best_try_locus = lexer.peek_token ()->get_locus ();
    6216              : 
    6217           66 :   AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
    6218              : 
    6219           66 :   if (!skip_token (FN_KW))
    6220            0 :     return nullptr;
    6221              : 
    6222           66 :   if (!skip_token (LEFT_PAREN))
    6223            0 :     return nullptr;
    6224              : 
    6225              :   // parse function params, if they exist
    6226           66 :   std::vector<AST::MaybeNamedParam> params;
    6227           66 :   bool is_variadic = false;
    6228           66 :   AST::AttrVec variadic_attrs;
    6229              : 
    6230           66 :   const_TokenPtr t = lexer.peek_token ();
    6231          120 :   while (t->get_id () != RIGHT_PAREN)
    6232              :     {
    6233           48 :       AST::AttrVec temp_attrs = parse_outer_attributes ();
    6234              : 
    6235           96 :       if (lexer.peek_token ()->get_id () == ELLIPSIS)
    6236              :         {
    6237            0 :           lexer.skip_token ();
    6238            0 :           is_variadic = true;
    6239            0 :           variadic_attrs = std::move (temp_attrs);
    6240              : 
    6241            0 :           t = lexer.peek_token ();
    6242              : 
    6243            0 :           if (t->get_id () != RIGHT_PAREN)
    6244              :             {
    6245            0 :               Error error (t->get_locus (),
    6246              :                            "expected right parentheses after variadic in maybe "
    6247              :                            "named function "
    6248              :                            "parameters, found %qs",
    6249              :                            t->get_token_description ());
    6250            0 :               add_error (std::move (error));
    6251              : 
    6252            0 :               return nullptr;
    6253            0 :             }
    6254              : 
    6255              :           break;
    6256              :         }
    6257              : 
    6258           48 :       AST::MaybeNamedParam param
    6259           48 :         = parse_maybe_named_param (std::move (temp_attrs));
    6260           48 :       if (param.is_error ())
    6261              :         {
    6262            0 :           Error error (
    6263            0 :             lexer.peek_token ()->get_locus (),
    6264              :             "failed to parse maybe named param in bare function type");
    6265            0 :           add_error (std::move (error));
    6266              : 
    6267            0 :           return nullptr;
    6268            0 :         }
    6269           48 :       params.push_back (std::move (param));
    6270              : 
    6271           96 :       if (lexer.peek_token ()->get_id () != COMMA)
    6272              :         break;
    6273              : 
    6274            6 :       lexer.skip_token ();
    6275            6 :       t = lexer.peek_token ();
    6276              :     }
    6277              : 
    6278           66 :   if (!skip_token (RIGHT_PAREN))
    6279            0 :     return nullptr;
    6280              : 
    6281              :   // bare function return type, if exists
    6282           66 :   std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
    6283          132 :   if (lexer.peek_token ()->get_id () == RETURN_TYPE)
    6284              :     {
    6285           53 :       lexer.skip_token ();
    6286              : 
    6287              :       // parse required TypeNoBounds
    6288           53 :       return_type = parse_type_no_bounds ();
    6289           53 :       if (return_type == nullptr)
    6290              :         {
    6291            0 :           Error error (lexer.peek_token ()->get_locus (),
    6292              :                        "failed to parse return type (type no bounds) in bare "
    6293              :                        "function type");
    6294            0 :           add_error (std::move (error));
    6295              : 
    6296            0 :           return nullptr;
    6297            0 :         }
    6298              :     }
    6299              : 
    6300              :   return std::unique_ptr<AST::BareFunctionType> (
    6301           66 :     new AST::BareFunctionType (std::move (for_lifetimes),
    6302              :                                std::move (qualifiers), std::move (params),
    6303              :                                is_variadic, std::move (variadic_attrs),
    6304           66 :                                std::move (return_type), best_try_locus));
    6305          132 : }
    6306              : 
    6307              : template <typename ManagedTokenSource>
    6308              : std::unique_ptr<AST::ReferenceType>
    6309         4314 : Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
    6310              : {
    6311              :   // parse optional lifetime
    6312         4314 :   AST::Lifetime lifetime = AST::Lifetime::elided ();
    6313         8628 :   if (lexer.peek_token ()->get_id () == LIFETIME)
    6314              :     {
    6315          468 :       auto parsed_lifetime = parse_lifetime (true);
    6316          468 :       if (parsed_lifetime)
    6317              :         {
    6318          468 :           lifetime = parsed_lifetime.value ();
    6319              :         }
    6320              :       else
    6321              :         {
    6322            0 :           Error error (lexer.peek_token ()->get_locus (),
    6323              :                        "failed to parse lifetime in reference type");
    6324            0 :           add_error (std::move (error));
    6325              : 
    6326            0 :           return nullptr;
    6327            0 :         }
    6328          468 :     }
    6329              : 
    6330         4314 :   bool is_mut = false;
    6331         8628 :   if (lexer.peek_token ()->get_id () == MUT)
    6332              :     {
    6333          304 :       lexer.skip_token ();
    6334          304 :       is_mut = true;
    6335              :     }
    6336              : 
    6337              :   // parse type no bounds, which is required
    6338         4314 :   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
    6339         4314 :   if (type == nullptr)
    6340              :     {
    6341            0 :       Error error (lexer.peek_token ()->get_locus (),
    6342              :                    "failed to parse referenced type in reference type");
    6343            0 :       add_error (std::move (error));
    6344              : 
    6345            0 :       return nullptr;
    6346            0 :     }
    6347              : 
    6348              :   return std::unique_ptr<AST::ReferenceType> (
    6349        12942 :     new AST::ReferenceType (is_mut, std::move (type), locus,
    6350         4314 :                             std::move (lifetime)));
    6351         4314 : }
    6352              : 
    6353              : // Parses a reference type (mutable or immutable, with given lifetime).
    6354              : template <typename ManagedTokenSource>
    6355              : std::unique_ptr<AST::ReferenceType>
    6356         4314 : Parser<ManagedTokenSource>::parse_reference_type ()
    6357              : {
    6358         4314 :   auto t = lexer.peek_token ();
    6359         4314 :   auto locus = t->get_locus ();
    6360              : 
    6361         4314 :   switch (t->get_id ())
    6362              :     {
    6363         4300 :     case AMP:
    6364         4300 :       skip_token (AMP);
    6365         4300 :       return parse_reference_type_inner (locus);
    6366           14 :     case LOGICAL_AND:
    6367           14 :       skip_token (LOGICAL_AND);
    6368              :       return std::unique_ptr<AST::ReferenceType> (
    6369           42 :         new AST::ReferenceType (false, parse_reference_type_inner (locus),
    6370           14 :                                 locus));
    6371            0 :     default:
    6372            0 :       rust_unreachable ();
    6373              :     }
    6374         4314 : }
    6375              : 
    6376              : // Parses a raw (unsafe) pointer type.
    6377              : template <typename ManagedTokenSource>
    6378              : std::unique_ptr<AST::RawPointerType>
    6379         6540 : Parser<ManagedTokenSource>::parse_raw_pointer_type ()
    6380              : {
    6381         6540 :   location_t locus = lexer.peek_token ()->get_locus ();
    6382         6540 :   skip_token (ASTERISK);
    6383              : 
    6384         6540 :   AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
    6385              : 
    6386              :   // branch on next token for pointer kind info
    6387         6540 :   const_TokenPtr t = lexer.peek_token ();
    6388         6540 :   switch (t->get_id ())
    6389              :     {
    6390          721 :     case MUT:
    6391          721 :       kind = AST::RawPointerType::MUT;
    6392          721 :       lexer.skip_token ();
    6393              :       break;
    6394         5819 :     case CONST:
    6395         5819 :       kind = AST::RawPointerType::CONST;
    6396         5819 :       lexer.skip_token ();
    6397              :       break;
    6398            0 :     default:
    6399            0 :       add_error (Error (t->get_locus (),
    6400              :                         "unrecognised token %qs in raw pointer type",
    6401              :                         t->get_token_description ()));
    6402              : 
    6403            0 :       return nullptr;
    6404              :     }
    6405              : 
    6406              :   // parse type no bounds (required)
    6407         6540 :   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
    6408         6540 :   if (type == nullptr)
    6409              :     {
    6410            0 :       Error error (lexer.peek_token ()->get_locus (),
    6411              :                    "failed to parse pointed type of raw pointer type");
    6412            0 :       add_error (std::move (error));
    6413              : 
    6414            0 :       return nullptr;
    6415            0 :     }
    6416              : 
    6417              :   return std::unique_ptr<AST::RawPointerType> (
    6418         6540 :     new AST::RawPointerType (kind, std::move (type), locus));
    6419         6540 : }
    6420              : 
    6421              : /* Parses a slice or array type, depending on following arguments (as
    6422              :  * lookahead is not possible). */
    6423              : template <typename ManagedTokenSource>
    6424              : std::unique_ptr<AST::TypeNoBounds>
    6425         1510 : Parser<ManagedTokenSource>::parse_slice_or_array_type ()
    6426              : {
    6427         1510 :   location_t locus = lexer.peek_token ()->get_locus ();
    6428         1510 :   skip_token (LEFT_SQUARE);
    6429              : 
    6430              :   // parse inner type (required)
    6431         1510 :   std::unique_ptr<AST::Type> inner_type = parse_type ();
    6432         1510 :   if (inner_type == nullptr)
    6433              :     {
    6434            0 :       Error error (lexer.peek_token ()->get_locus (),
    6435              :                    "failed to parse inner type in slice or array type");
    6436            0 :       add_error (std::move (error));
    6437              : 
    6438            0 :       return nullptr;
    6439            0 :     }
    6440              : 
    6441              :   // branch on next token
    6442         1510 :   const_TokenPtr t = lexer.peek_token ();
    6443         1510 :   switch (t->get_id ())
    6444              :     {
    6445          842 :     case RIGHT_SQUARE:
    6446              :       // slice type
    6447          842 :       lexer.skip_token ();
    6448              : 
    6449          842 :       return std::unique_ptr<AST::SliceType> (
    6450          842 :         new AST::SliceType (std::move (inner_type), locus));
    6451          668 :     case SEMICOLON:
    6452              :       {
    6453              :         // array type
    6454          668 :         lexer.skip_token ();
    6455              : 
    6456              :         // parse required array size expression
    6457          668 :         auto size = parse_anon_const ();
    6458              : 
    6459          668 :         if (!size)
    6460              :           {
    6461            1 :             Error error (lexer.peek_token ()->get_locus (),
    6462              :                          "failed to parse size expression in array type");
    6463            1 :             add_error (std::move (error));
    6464              : 
    6465            1 :             return nullptr;
    6466            1 :           }
    6467              : 
    6468          667 :         if (!skip_token (RIGHT_SQUARE))
    6469              :           {
    6470            0 :             return nullptr;
    6471              :           }
    6472              : 
    6473          667 :         return std::unique_ptr<AST::ArrayType> (
    6474         1323 :           new AST::ArrayType (std::move (inner_type), std::move (*size),
    6475          667 :                               locus));
    6476          668 :       }
    6477            0 :     default:
    6478              :       // error
    6479            0 :       add_error (
    6480            0 :         Error (t->get_locus (),
    6481              :                "unrecognised token %qs in slice or array type after inner type",
    6482              :                t->get_token_description ()));
    6483              : 
    6484            0 :       return nullptr;
    6485              :     }
    6486         1510 : }
    6487              : 
    6488              : // Parses a type, taking into account type boundary disambiguation.
    6489              : template <typename ManagedTokenSource>
    6490              : std::unique_ptr<AST::TypeNoBounds>
    6491        16098 : Parser<ManagedTokenSource>::parse_type_no_bounds ()
    6492              : {
    6493        16098 :   const_TokenPtr t = lexer.peek_token ();
    6494        16098 :   switch (t->get_id ())
    6495              :     {
    6496            1 :     case EXCLAM:
    6497              :       // never type - can't be macro as no path beforehand
    6498            1 :       lexer.skip_token ();
    6499            1 :       return std::unique_ptr<AST::NeverType> (
    6500            1 :         new AST::NeverType (t->get_locus ()));
    6501          656 :     case LEFT_SQUARE:
    6502              :       // slice type or array type - requires further disambiguation
    6503          656 :       return parse_slice_or_array_type ();
    6504           22 :     case LEFT_SHIFT:
    6505              :     case LEFT_ANGLE:
    6506              :       {
    6507              :         // qualified path in type
    6508           22 :         AST::QualifiedPathInType path = parse_qualified_path_in_type ();
    6509           22 :         if (path.is_error ())
    6510              :           {
    6511            0 :             Error error (t->get_locus (),
    6512              :                          "failed to parse qualified path in type");
    6513            0 :             add_error (std::move (error));
    6514              : 
    6515            0 :             return nullptr;
    6516            0 :           }
    6517           22 :         return std::unique_ptr<AST::QualifiedPathInType> (
    6518           22 :           new AST::QualifiedPathInType (std::move (path)));
    6519           22 :       }
    6520          104 :     case UNDERSCORE:
    6521              :       // inferred type
    6522          104 :       lexer.skip_token ();
    6523          104 :       return std::unique_ptr<AST::InferredType> (
    6524          104 :         new AST::InferredType (t->get_locus ()));
    6525         3812 :     case ASTERISK:
    6526              :       // raw pointer type
    6527         3812 :       return parse_raw_pointer_type ();
    6528           24 :     case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
    6529              :     case LOGICAL_AND:
    6530              :       // reference type
    6531           24 :       return parse_reference_type ();
    6532            0 :     case LIFETIME:
    6533              :       /* probably a lifetime bound, so probably type param bounds in
    6534              :        * TraitObjectType. this is not allowed, but detection here for error
    6535              :        * message */
    6536            0 :       add_error (Error (t->get_locus (),
    6537              :                         "lifetime bounds (i.e. in type param bounds, in "
    6538              :                         "TraitObjectType) are not allowed as TypeNoBounds"));
    6539              : 
    6540            0 :       return nullptr;
    6541        11302 :     case IDENTIFIER:
    6542              :     case SUPER:
    6543              :     case SELF:
    6544              :     case SELF_ALIAS:
    6545              :     case CRATE:
    6546              :     case DOLLAR_SIGN:
    6547              :     case SCOPE_RESOLUTION:
    6548              :       {
    6549              :         // macro invocation or type path - requires further disambiguation.
    6550              :         /* for parsing path component of each rule, perhaps parse it as a
    6551              :          * typepath and attempt conversion to simplepath if a trailing '!' is
    6552              :          * found */
    6553              :         /* Type path also includes TraitObjectTypeOneBound BUT if it starts
    6554              :          * with it, it is exactly the same as a TypePath syntactically, so
    6555              :          * this is a syntactical ambiguity. As such, the parser will parse it
    6556              :          * as a TypePath. This, however, does not prevent TraitObjectType from
    6557              :          * starting with a typepath. */
    6558              : 
    6559              :         // parse path as type path
    6560        11302 :         AST::TypePath path = parse_type_path ();
    6561        11302 :         if (path.is_error ())
    6562              :           {
    6563            0 :             Error error (
    6564              :               t->get_locus (),
    6565              :               "failed to parse path as first component of type no bounds");
    6566            0 :             add_error (std::move (error));
    6567              : 
    6568            0 :             return nullptr;
    6569            0 :           }
    6570        11302 :         location_t locus = path.get_locus ();
    6571              : 
    6572              :         // branch on next token
    6573        11302 :         t = lexer.peek_token ();
    6574        11302 :         switch (t->get_id ())
    6575              :           {
    6576            1 :           case EXCLAM:
    6577              :             {
    6578              :               // macro invocation
    6579              :               // convert to simple path
    6580            1 :               AST::SimplePath macro_path = path.as_simple_path ();
    6581            1 :               if (macro_path.is_empty ())
    6582              :                 {
    6583            0 :                   Error error (t->get_locus (),
    6584              :                                "failed to parse simple path in macro "
    6585              :                                "invocation (for type)");
    6586            0 :                   add_error (std::move (error));
    6587              : 
    6588            0 :                   return nullptr;
    6589            0 :                 }
    6590              : 
    6591            1 :               lexer.skip_token ();
    6592              : 
    6593            1 :               auto tok_tree = parse_delim_token_tree ();
    6594            1 :               if (!tok_tree)
    6595            0 :                 return nullptr;
    6596              : 
    6597            3 :               return AST::MacroInvocation::Regular (
    6598            2 :                 AST::MacroInvocData (std::move (macro_path),
    6599            1 :                                      std::move (tok_tree.value ())),
    6600            1 :                 {}, locus);
    6601            2 :             }
    6602        11301 :           default:
    6603              :             // assume that this is a type path and not an error
    6604        11301 :             return std::unique_ptr<AST::TypePath> (
    6605        11301 :               new AST::TypePath (std::move (path)));
    6606              :           }
    6607        11302 :       }
    6608           18 :     case LEFT_PAREN:
    6609              :       /* tuple type or parenthesised type - requires further disambiguation
    6610              :        * (the usual). ok apparently can be a parenthesised TraitBound too, so
    6611              :        * could be TraitObjectTypeOneBound */
    6612           18 :       return parse_paren_prefixed_type_no_bounds ();
    6613            2 :     case FOR:
    6614              :     case ASYNC:
    6615              :     case CONST:
    6616              :     case UNSAFE:
    6617              :     case EXTERN_KW:
    6618              :     case FN_KW:
    6619              :       // bare function type (with no for lifetimes)
    6620            2 :       return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
    6621           14 :     case IMPL:
    6622           14 :       lexer.skip_token ();
    6623           28 :       if (lexer.peek_token ()->get_id () == LIFETIME)
    6624              :         {
    6625              :           /* cannot be one bound because lifetime prevents it from being
    6626              :            * traitbound not allowed as type no bounds, only here for error
    6627              :            * message */
    6628            0 :           Error error (
    6629            0 :             lexer.peek_token ()->get_locus (),
    6630              :             "lifetime (probably lifetime bound, in type param "
    6631              :             "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
    6632            0 :           add_error (std::move (error));
    6633              : 
    6634            0 :           return nullptr;
    6635            0 :         }
    6636              :       else
    6637              :         {
    6638              :           // should be trait bound, so parse trait bound
    6639           14 :           std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
    6640           14 :           if (initial_bound == nullptr)
    6641              :             {
    6642            0 :               Error error (lexer.peek_token ()->get_locus (),
    6643              :                            "failed to parse ImplTraitTypeOneBound bound");
    6644            0 :               add_error (std::move (error));
    6645              : 
    6646            0 :               return nullptr;
    6647            0 :             }
    6648              : 
    6649           14 :           location_t locus = t->get_locus ();
    6650              : 
    6651              :           // ensure not a trait with multiple bounds
    6652           14 :           t = lexer.peek_token ();
    6653           14 :           if (t->get_id () == PLUS)
    6654              :             {
    6655            0 :               Error error (t->get_locus (),
    6656              :                            "plus after trait bound means an ImplTraitType, "
    6657              :                            "which is not allowed as a TypeNoBounds");
    6658            0 :               add_error (std::move (error));
    6659              : 
    6660            0 :               return nullptr;
    6661            0 :             }
    6662              : 
    6663           14 :           return std::unique_ptr<AST::ImplTraitTypeOneBound> (
    6664           14 :             new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
    6665           14 :         }
    6666          143 :     case DYN:
    6667              :     case QUESTION_MARK:
    6668              :       {
    6669              :         // either TraitObjectTypeOneBound
    6670          143 :         bool has_dyn = false;
    6671          143 :         if (t->get_id () == DYN)
    6672              :           {
    6673          143 :             lexer.skip_token ();
    6674          143 :             has_dyn = true;
    6675              :           }
    6676              : 
    6677          286 :         if (lexer.peek_token ()->get_id () == LIFETIME)
    6678              :           {
    6679              :             /* means that cannot be TraitObjectTypeOneBound - so here for
    6680              :              * error message */
    6681            0 :             Error error (lexer.peek_token ()->get_locus (),
    6682              :                          "lifetime as bound in TraitObjectTypeOneBound "
    6683              :                          "is not allowed, so cannot be TypeNoBounds");
    6684            0 :             add_error (std::move (error));
    6685              : 
    6686            0 :             return nullptr;
    6687            0 :           }
    6688              : 
    6689              :         // should be trait bound, so parse trait bound
    6690          143 :         std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
    6691          143 :         if (initial_bound == nullptr)
    6692              :           {
    6693            0 :             Error error (
    6694            0 :               lexer.peek_token ()->get_locus (),
    6695              :               "failed to parse TraitObjectTypeOneBound initial bound");
    6696            0 :             add_error (std::move (error));
    6697              : 
    6698            0 :             return nullptr;
    6699            0 :           }
    6700              : 
    6701          143 :         location_t locus = t->get_locus ();
    6702              : 
    6703              :         // detect error with plus as next token
    6704          143 :         t = lexer.peek_token ();
    6705          143 :         if (t->get_id () == PLUS)
    6706              :           {
    6707            0 :             Error error (t->get_locus (),
    6708              :                          "plus after trait bound means a TraitObjectType, "
    6709              :                          "which is not allowed as a TypeNoBounds");
    6710            0 :             add_error (std::move (error));
    6711              : 
    6712            0 :             return nullptr;
    6713            0 :           }
    6714              : 
    6715              :         // convert trait bound to value object
    6716          143 :         AST::TraitBound value_bound (*initial_bound);
    6717              : 
    6718          143 :         return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6719          286 :           new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
    6720          143 :                                             has_dyn));
    6721          143 :       }
    6722            0 :     default:
    6723            0 :       add_error (Error (t->get_locus (),
    6724              :                         "unrecognised token %qs in type no bounds",
    6725              :                         t->get_token_description ()));
    6726              : 
    6727            0 :       return nullptr;
    6728              :     }
    6729        16098 : }
    6730              : 
    6731              : // Parses a type no bounds beginning with '('.
    6732              : template <typename ManagedTokenSource>
    6733              : std::unique_ptr<AST::TypeNoBounds>
    6734           18 : Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
    6735              : {
    6736              :   /* NOTE: this could probably be parsed without the HACK solution of
    6737              :    * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
    6738              : 
    6739              :   /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
    6740              :    * considered a trait bound, not a parenthesised type, so that it can still
    6741              :    * be used in type param bounds. */
    6742              : 
    6743           18 :   location_t left_paren_locus = lexer.peek_token ()->get_locus ();
    6744              : 
    6745              :   // skip left delim
    6746           18 :   lexer.skip_token ();
    6747              :   /* while next token isn't close delim, parse comma-separated types, saving
    6748              :    * whether trailing comma happens */
    6749           18 :   const_TokenPtr t = lexer.peek_token ();
    6750           18 :   bool trailing_comma = true;
    6751           18 :   std::vector<std::unique_ptr<AST::Type>> types;
    6752              : 
    6753           18 :   while (t->get_id () != RIGHT_PAREN)
    6754              :     {
    6755            2 :       std::unique_ptr<AST::Type> type = parse_type ();
    6756            2 :       if (type == nullptr)
    6757              :         {
    6758            0 :           Error error (t->get_locus (),
    6759              :                        "failed to parse type inside parentheses (probably "
    6760              :                        "tuple or parenthesised)");
    6761            0 :           add_error (std::move (error));
    6762              : 
    6763            0 :           return nullptr;
    6764            0 :         }
    6765            2 :       types.push_back (std::move (type));
    6766              : 
    6767            2 :       t = lexer.peek_token ();
    6768            2 :       if (t->get_id () != COMMA)
    6769              :         {
    6770            2 :           trailing_comma = false;
    6771              :           break;
    6772              :         }
    6773            0 :       lexer.skip_token ();
    6774              : 
    6775            0 :       t = lexer.peek_token ();
    6776              :     }
    6777              : 
    6778           18 :   if (!skip_token (RIGHT_PAREN))
    6779              :     {
    6780            0 :       return nullptr;
    6781              :     }
    6782              : 
    6783              :   // if only one type and no trailing comma, then not a tuple type
    6784           18 :   if (types.size () == 1 && !trailing_comma)
    6785              :     {
    6786              :       // must be a TraitObjectType (with more than one bound)
    6787            4 :       if (lexer.peek_token ()->get_id () == PLUS)
    6788              :         {
    6789              :           // error - this is not allowed for type no bounds
    6790            0 :           Error error (lexer.peek_token ()->get_locus (),
    6791              :                        "plus (implying TraitObjectType as type param "
    6792              :                        "bounds) is not allowed in type no bounds");
    6793            0 :           add_error (std::move (error));
    6794              : 
    6795            0 :           return nullptr;
    6796            0 :         }
    6797              :       else
    6798              :         {
    6799              :           // release vector pointer
    6800            2 :           std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
    6801              :           /* HACK: attempt to convert to trait bound. if fails, parenthesised
    6802              :            * type */
    6803            2 :           std::unique_ptr<AST::TraitBound> converted_bound (
    6804            2 :             released_ptr->to_trait_bound (true));
    6805            2 :           if (converted_bound == nullptr)
    6806              :             {
    6807              :               // parenthesised type
    6808            2 :               return std::unique_ptr<AST::ParenthesisedType> (
    6809            2 :                 new AST::ParenthesisedType (std::move (released_ptr),
    6810            2 :                                             left_paren_locus));
    6811              :             }
    6812              :           else
    6813              :             {
    6814              :               // trait object type (one bound)
    6815              : 
    6816              :               // get value semantics trait bound
    6817            0 :               AST::TraitBound value_bound (*converted_bound);
    6818              : 
    6819            0 :               return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6820            0 :                 new AST::TraitObjectTypeOneBound (value_bound,
    6821            0 :                                                   left_paren_locus));
    6822            0 :             }
    6823            2 :         }
    6824              :     }
    6825              :   else
    6826              :     {
    6827           16 :       return std::unique_ptr<AST::TupleType> (
    6828           16 :         new AST::TupleType (std::move (types), left_paren_locus));
    6829              :     }
    6830              :   /* TODO: ensure that this ensures that dynamic dispatch for traits is not
    6831              :    * lost somehow */
    6832           18 : }
    6833              : 
    6834              : // Parses tuple struct items if they exist. Does not parse parentheses.
    6835              : template <typename ManagedTokenSource>
    6836              : std::unique_ptr<AST::TupleStructItems>
    6837          924 : Parser<ManagedTokenSource>::parse_tuple_struct_items ()
    6838              : {
    6839          924 :   std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
    6840              : 
    6841              :   // DEBUG
    6842          924 :   rust_debug ("started parsing tuple struct items");
    6843              : 
    6844              :   // check for '..' at front
    6845         1848 :   if (lexer.peek_token ()->get_id () == DOT_DOT)
    6846              :     {
    6847              :       // only parse upper patterns
    6848           16 :       lexer.skip_token ();
    6849              : 
    6850              :       // DEBUG
    6851           16 :       rust_debug ("'..' at front in tuple struct items detected");
    6852              : 
    6853           16 :       std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
    6854              : 
    6855           16 :       const_TokenPtr t = lexer.peek_token ();
    6856           33 :       while (t->get_id () == COMMA)
    6857              :         {
    6858           17 :           lexer.skip_token ();
    6859              : 
    6860              :           // break if right paren
    6861           34 :           if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    6862              :             break;
    6863              : 
    6864              :           // parse pattern, which is now required
    6865           17 :           std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    6866           17 :           if (pattern == nullptr)
    6867              :             {
    6868            0 :               Error error (lexer.peek_token ()->get_locus (),
    6869              :                            "failed to parse pattern in tuple struct items");
    6870            0 :               add_error (std::move (error));
    6871              : 
    6872            0 :               return nullptr;
    6873            0 :             }
    6874           17 :           upper_patterns.push_back (std::move (pattern));
    6875              : 
    6876           17 :           t = lexer.peek_token ();
    6877              :         }
    6878              : 
    6879              :       // DEBUG
    6880           16 :       rust_debug (
    6881              :         "finished parsing tuple struct items ranged (upper/none only)");
    6882              : 
    6883           16 :       return std::unique_ptr<AST::TupleStructItemsHasRest> (
    6884           16 :         new AST::TupleStructItemsHasRest (std::move (lower_patterns),
    6885           16 :                                           std::move (upper_patterns)));
    6886           16 :     }
    6887              : 
    6888              :   // has at least some lower patterns
    6889          908 :   const_TokenPtr t = lexer.peek_token ();
    6890         1863 :   while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
    6891              :     {
    6892              :       // DEBUG
    6893          955 :       rust_debug ("about to parse pattern in tuple struct items");
    6894              : 
    6895              :       // parse pattern, which is required
    6896          955 :       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    6897          955 :       if (pattern == nullptr)
    6898              :         {
    6899            0 :           Error error (t->get_locus (),
    6900              :                        "failed to parse pattern in tuple struct items");
    6901            0 :           add_error (std::move (error));
    6902              : 
    6903            0 :           return nullptr;
    6904            0 :         }
    6905          955 :       lower_patterns.push_back (std::move (pattern));
    6906              : 
    6907              :       // DEBUG
    6908          955 :       rust_debug ("successfully parsed pattern in tuple struct items");
    6909              : 
    6910         1910 :       if (lexer.peek_token ()->get_id () != COMMA)
    6911              :         {
    6912              :           // DEBUG
    6913          862 :           rust_debug ("broke out of parsing patterns in tuple struct "
    6914              :                       "items as no comma");
    6915              : 
    6916              :           break;
    6917              :         }
    6918           93 :       lexer.skip_token ();
    6919           93 :       t = lexer.peek_token ();
    6920              :     }
    6921              : 
    6922              :   // branch on next token
    6923          908 :   t = lexer.peek_token ();
    6924          908 :   switch (t->get_id ())
    6925              :     {
    6926          884 :     case RIGHT_PAREN:
    6927          884 :       return std::unique_ptr<AST::TupleStructItemsNoRest> (
    6928          884 :         new AST::TupleStructItemsNoRest (std::move (lower_patterns)));
    6929           23 :     case DOT_DOT:
    6930              :       {
    6931              :         // has an upper range that must be parsed separately
    6932           23 :         lexer.skip_token ();
    6933              : 
    6934           23 :         std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
    6935              : 
    6936           23 :         t = lexer.peek_token ();
    6937           25 :         while (t->get_id () == COMMA)
    6938              :           {
    6939            2 :             lexer.skip_token ();
    6940              : 
    6941              :             // break if next token is right paren
    6942            4 :             if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    6943              :               break;
    6944              : 
    6945              :             // parse pattern, which is required
    6946            2 :             std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    6947            2 :             if (pattern == nullptr)
    6948              :               {
    6949            0 :                 Error error (lexer.peek_token ()->get_locus (),
    6950              :                              "failed to parse pattern in tuple struct items");
    6951            0 :                 add_error (std::move (error));
    6952              : 
    6953            0 :                 return nullptr;
    6954            0 :               }
    6955            2 :             upper_patterns.push_back (std::move (pattern));
    6956              : 
    6957            2 :             t = lexer.peek_token ();
    6958              :           }
    6959              : 
    6960           23 :         return std::unique_ptr<AST::TupleStructItemsHasRest> (
    6961           23 :           new AST::TupleStructItemsHasRest (std::move (lower_patterns),
    6962           23 :                                             std::move (upper_patterns)));
    6963           23 :       }
    6964            1 :     default:
    6965              :       // error
    6966            1 :       add_error (Error (t->get_locus (),
    6967              :                         "unexpected token %qs in tuple struct items",
    6968              :                         t->get_token_description ()));
    6969              : 
    6970            1 :       return nullptr;
    6971              :     }
    6972          924 : }
    6973              : 
    6974              : /* Parses a statement or expression (depending on whether a trailing semicolon
    6975              :  * exists). Useful for block expressions where it cannot be determined through
    6976              :  * lookahead whether it is a statement or expression to be parsed. */
    6977              : template <typename ManagedTokenSource>
    6978              : tl::expected<ExprOrStmt, Parse::Error::Node>
    6979        38626 : Parser<ManagedTokenSource>::parse_stmt_or_expr ()
    6980              : {
    6981              :   // quick exit for empty statement
    6982        38626 :   const_TokenPtr t = lexer.peek_token ();
    6983        38626 :   if (t->get_id () == SEMICOLON)
    6984              :     {
    6985           18 :       lexer.skip_token ();
    6986           18 :       std::unique_ptr<AST::EmptyStmt> stmt (
    6987           18 :         new AST::EmptyStmt (t->get_locus ()));
    6988           36 :       return ExprOrStmt (std::move (stmt));
    6989           18 :     }
    6990              : 
    6991              :   // parse outer attributes
    6992        38608 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    6993        38608 :   ParseRestrictions restrictions;
    6994        38608 :   restrictions.expr_can_be_stmt = true;
    6995              : 
    6996              :   // Defered child error checking: we need to check for a semicolon
    6997        38608 :   tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
    6998              : 
    6999              :   // parsing this will be annoying because of the many different possibilities
    7000              :   /* best may be just to copy paste in parse_item switch, and failing that try
    7001              :    * to parse outer attributes, and then pass them in to either a let
    7002              :    * statement or (fallback) expression statement. */
    7003              :   // FIXME: think of a way to do this without such a large switch?
    7004              : 
    7005              :   /* FIXME: for expressions at least, the only way that they can really be
    7006              :    * parsed properly in this way is if they don't support operators on them.
    7007              :    * They must be pratt-parsed otherwise. As such due to composability, only
    7008              :    * explicit statements will have special cases here. This should roughly
    7009              :    * correspond to "expr-with-block", but this warning is here in case it
    7010              :    * isn't the case. */
    7011        38608 :   t = lexer.peek_token ();
    7012        38608 :   switch (t->get_id ())
    7013              :     {
    7014        12725 :     case LET:
    7015              :       {
    7016              :         // let statement
    7017        12725 :         std::unique_ptr<AST::LetStmt> stmt (
    7018        12725 :           parse_let_stmt (std::move (outer_attrs)));
    7019        25450 :         return ExprOrStmt (std::move (stmt));
    7020        12725 :       }
    7021          344 :     case PUB:
    7022              :     case MOD:
    7023              :     case EXTERN_KW:
    7024              :     case USE:
    7025              :     case FN_KW:
    7026              :     case TYPE:
    7027              :     case STRUCT_KW:
    7028              :     case ENUM_KW:
    7029              :     case CONST:
    7030              :     case STATIC_KW:
    7031              :     case AUTO:
    7032              :     case TRAIT:
    7033              :     case IMPL:
    7034              :       {
    7035          344 :         std::unique_ptr<AST::VisItem> item (
    7036          344 :           parse_vis_item (std::move (outer_attrs)));
    7037          688 :         return ExprOrStmt (std::move (item));
    7038          344 :       }
    7039              :     /* TODO: implement union keyword but not really because of
    7040              :      * context-dependence crappy hack way to parse a union written below to
    7041              :      * separate it from the good code. */
    7042              :     // case UNION:
    7043         3076 :     case UNSAFE:
    7044              :       { // maybe - unsafe traits are a thing
    7045              :         /* if any of these (should be all possible VisItem prefixes), parse a
    7046              :          * VisItem - can't parse item because would require reparsing outer
    7047              :          * attributes */
    7048         3076 :         const_TokenPtr t2 = lexer.peek_token (1);
    7049         3076 :         switch (t2->get_id ())
    7050              :           {
    7051         3062 :           case LEFT_CURLY:
    7052              :             {
    7053              :               // unsafe block: parse as expression
    7054         6124 :               expr = parse_expr (std::move (outer_attrs), restrictions);
    7055              :               break;
    7056              :             }
    7057            0 :           case AUTO:
    7058              :           case TRAIT:
    7059              :             {
    7060              :               // unsafe trait
    7061            0 :               std::unique_ptr<AST::VisItem> item (
    7062            0 :                 parse_vis_item (std::move (outer_attrs)));
    7063            0 :               return ExprOrStmt (std::move (item));
    7064            0 :             }
    7065           14 :           case EXTERN_KW:
    7066              :           case FN_KW:
    7067              :             {
    7068              :               // unsafe function
    7069           14 :               std::unique_ptr<AST::VisItem> item (
    7070           14 :                 parse_vis_item (std::move (outer_attrs)));
    7071           28 :               return ExprOrStmt (std::move (item));
    7072           14 :             }
    7073            0 :           case IMPL:
    7074              :             {
    7075              :               // unsafe trait impl
    7076            0 :               std::unique_ptr<AST::VisItem> item (
    7077            0 :                 parse_vis_item (std::move (outer_attrs)));
    7078            0 :               return ExprOrStmt (std::move (item));
    7079            0 :             }
    7080            0 :           default:
    7081            0 :             add_error (Error (t2->get_locus (),
    7082              :                               "unrecognised token %qs after parsing unsafe - "
    7083              :                               "expected beginning of expression or statement",
    7084              :                               t->get_token_description ()));
    7085              : 
    7086              :             // skip somewhere?
    7087              :             return tl::unexpected<Parse::Error::Node> (
    7088            0 :               Parse::Error::Node::MALFORMED);
    7089              :           }
    7090              :         break;
    7091         3076 :       }
    7092              :       /* FIXME: this is either a macro invocation or macro invocation semi.
    7093              :        * start parsing to determine which one it is. */
    7094              :       // FIXME: old code there
    7095              : 
    7096              :     // crappy hack to do union "keyword"
    7097        12203 :     case IDENTIFIER:
    7098        21778 :       if (t->get_str () == Values::WeakKeywords::UNION
    7099        12239 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
    7100              :         {
    7101            1 :           std::unique_ptr<AST::VisItem> item (
    7102            1 :             parse_vis_item (std::move (outer_attrs)));
    7103            2 :           return ExprOrStmt (std::move (item));
    7104              :           // or should this go straight to parsing union?
    7105            1 :         }
    7106        21776 :       else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
    7107        12209 :                && lexer.peek_token (1)->get_id () == EXCLAM)
    7108              :         {
    7109              :           // macro_rules! macro item
    7110            7 :           std::unique_ptr<AST::Item> item (
    7111            7 :             parse_macro_rules_def (std::move (outer_attrs)));
    7112           14 :           return ExprOrStmt (std::move (item));
    7113            7 :         }
    7114              :       gcc_fallthrough ();
    7115              :     case SUPER:
    7116              :     case SELF:
    7117              :     case SELF_ALIAS:
    7118              :     case CRATE:
    7119              :     case SCOPE_RESOLUTION:
    7120              :     case DOLLAR_SIGN:
    7121              :       {
    7122        14651 :         AST::PathInExpression path = parse_path_in_expression ();
    7123              :         tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
    7124        14651 :           null_denotation;
    7125              : 
    7126        29302 :         if (lexer.peek_token ()->get_id () == EXCLAM)
    7127              :           {
    7128          590 :             std::unique_ptr<AST::MacroInvocation> invoc
    7129         1180 :               = parse_macro_invocation_partial (std::move (path),
    7130              :                                                 std::move (outer_attrs));
    7131          590 :             if (invoc == nullptr)
    7132              :               return tl::unexpected<Parse::Error::Node> (
    7133            0 :                 Parse::Error::Node::CHILD_ERROR);
    7134              : 
    7135          590 :             if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
    7136              :               {
    7137          398 :                 invoc->add_semicolon ();
    7138              :                 // Macro invocation with semicolon.
    7139          398 :                 return ExprOrStmt (
    7140          796 :                   std::unique_ptr<AST::Stmt> (std::move (invoc)));
    7141              :               }
    7142              : 
    7143          384 :             TokenId after_macro = lexer.peek_token ()->get_id ();
    7144              : 
    7145          192 :             AST::DelimType delim_type = invoc->get_invoc_data ()
    7146          192 :                                           .get_delim_tok_tree ()
    7147          192 :                                           .get_delim_type ();
    7148              : 
    7149          192 :             if (delim_type == AST::CURLY && after_macro != DOT
    7150            6 :                 && after_macro != QUESTION_MARK)
    7151              :               {
    7152            6 :                 rust_debug ("braced macro statement");
    7153            6 :                 return ExprOrStmt (
    7154           12 :                   std::unique_ptr<AST::Stmt> (std::move (invoc)));
    7155              :               }
    7156              : 
    7157          186 :             null_denotation = std::move (invoc);
    7158          590 :           }
    7159              :         else
    7160              :           {
    7161              :             null_denotation
    7162        28122 :               = null_denotation_path (std::move (path), {}, restrictions);
    7163              :           }
    7164              : 
    7165        56984 :         expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
    7166              :                                  std::move (outer_attrs), restrictions);
    7167              :         break;
    7168        14651 :       }
    7169         7804 :     default:
    7170              :       /* expression statement or expression itself - parse
    7171              :        * expression then make it statement if semi afterwards */
    7172        15579 :       expr = parse_expr (std::move (outer_attrs), restrictions);
    7173         7804 :       break;
    7174              :     }
    7175              : 
    7176        25113 :   const_TokenPtr after_expr = lexer.peek_token ();
    7177        25113 :   if (after_expr->get_id () == SEMICOLON)
    7178              :     {
    7179              :       // must be expression statement
    7180         7584 :       lexer.skip_token ();
    7181              : 
    7182         7584 :       if (expr)
    7183              :         {
    7184         7583 :           return ExprOrStmt (
    7185        15166 :             std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
    7186        22749 :                                              t->get_locus (), true));
    7187              :         }
    7188              :       else
    7189              :         {
    7190              :           return tl::unexpected<Parse::Error::Node> (
    7191            1 :             Parse::Error::Node::CHILD_ERROR);
    7192              :         }
    7193              :     }
    7194              : 
    7195        17529 :   if (expr)
    7196              :     {
    7197              :       // block expression statement.
    7198        17499 :       if (!expr.value ()->is_expr_without_block ()
    7199        17499 :           && after_expr->get_id () != RIGHT_CURLY)
    7200         1533 :         return ExprOrStmt (
    7201         3066 :           std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
    7202         4599 :                                            t->get_locus (), false));
    7203              : 
    7204              :       // Check if expr_without_block is properly terminated
    7205        15966 :       if (expr.value ()->is_expr_without_block ()
    7206        15966 :           && after_expr->get_id () != RIGHT_CURLY)
    7207              :         {
    7208              :           // expr_without_block must be followed by ';' or '}'
    7209            1 :           Error error (after_expr->get_locus (),
    7210              :                        "expected %<;%> or %<}%> after expression, found %qs",
    7211              :                        after_expr->get_token_description ());
    7212            1 :           add_error (std::move (error));
    7213              :           return tl::unexpected<Parse::Error::Node> (
    7214            1 :             Parse::Error::Node::MALFORMED);
    7215            1 :         }
    7216              :     }
    7217              : 
    7218              :   // return expression
    7219        15995 :   if (expr)
    7220        31930 :     return ExprOrStmt (std::move (expr.value ()));
    7221              :   else
    7222           30 :     return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
    7223        63721 : }
    7224              : 
    7225              : } // namespace Rust
    7226              : 
    7227              : #include "rust-parse-impl-utils.hxx"
    7228              : #include "rust-parse-impl-attribute.hxx"
    7229              : #include "rust-parse-impl-ttree.hxx"
    7230              : #include "rust-parse-impl-macro.hxx"
    7231              : #include "rust-parse-impl-path.hxx"
    7232              : #include "rust-parse-impl-pattern.hxx"
    7233              : #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.