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