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.5 % 3243 2512
Test Date: 2026-10-24 16:24:59 Functions: 79.7 % 212 169
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        32244 : 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        32244 :   const_TokenPtr tok = lexer.peek_token ();
      75        32244 :   switch (tok->get_id ())
      76              :     {
      77        28253 :     case RIGHT_ANGLE:
      78              :       // this is good - skip token
      79        28253 :       lexer.skip_token ();
      80        28253 :       return true;
      81         3990 :     case RIGHT_SHIFT:
      82              :       {
      83              :         // new implementation that should be better
      84         3990 :         lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE);
      85         3990 :         lexer.skip_token ();
      86         3990 :         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        32244 : }
     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       894871 : Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
     118              : {
     119              :   // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
     120       894871 :   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              :       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        51669 :     case DOT:
     149       103338 :       if (lexer.peek_token (1)->get_id () == IDENTIFIER
     150        94265 :           && 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          250 :     case QUESTION_MARK:
     164          250 :       return LBP_QUESTION_MARK;
     165              : 
     166        10844 :     case AS:
     167        10844 :       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         4380 :     case AMP:
     188         4380 :       return LBP_AMP;
     189              : 
     190              :     // binary ^ operator
     191          164 :     case CARET:
     192          164 :       return LBP_CARET;
     193              : 
     194              :     // binary | operator
     195         3249 :     case PIPE:
     196         3249 :       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         1436 :     case LOGICAL_AND:
     212         1436 :       return LBP_LOGICAL_AND;
     213              : 
     214          748 :     case OR:
     215          748 :       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       781128 :     default:
     255       781128 :       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         5527 : Parser<ManagedTokenSource>::parse_items ()
     272              : {
     273         5527 :   std::vector<std::unique_ptr<AST::Item>> items;
     274              : 
     275         5527 :   const_TokenPtr t = lexer.peek_token ();
     276        33479 :   while (t->get_id () != END_OF_FILE)
     277              :     {
     278        27952 :       auto item = parse_item (false);
     279        27952 :       if (!item)
     280           84 :         return Parse::Error::Items::make_malformed (std::move (items));
     281              : 
     282        27868 :       items.push_back (std::move (item.value ()));
     283              : 
     284        27868 :       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         5443 :   return items;
     292              : #endif
     293         5527 : }
     294              : 
     295              : // Parses a crate (compilation unit) - entry point
     296              : template <typename ManagedTokenSource>
     297              : std::unique_ptr<AST::Crate>
     298         5238 : Parser<ManagedTokenSource>::parse_crate ()
     299              : {
     300              :   // parse inner attributes
     301         5238 :   AST::AttrVec inner_attrs = parse_inner_attributes ();
     302              : 
     303              :   // parse items
     304        10476 :   auto items
     305         5238 :     = parse_items ().value_or (std::vector<std::unique_ptr<AST::Item>>{});
     306              : 
     307              :   // emit all errors
     308         5423 :   for (const auto &error : error_table)
     309          185 :     error.emit ();
     310              : 
     311              :   return std::unique_ptr<AST::Crate> (
     312         5238 :     new AST::Crate (std::move (items), std::move (inner_attrs)));
     313         5238 : }
     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        13405 : Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
     319              : {
     320        13405 :   const_TokenPtr t = lexer.peek_token ();
     321              : 
     322        13405 :   if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
     323              :     {
     324        13390 :       lexer.skip_token ();
     325        13390 :       return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
     326              :     }
     327              :   else
     328              :     {
     329           15 :       add_error (Error (t->get_locus (), "expected keyword or identifier"));
     330           15 :       return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
     331              :     }
     332        13405 : }
     333              : 
     334              : template <typename ManagedTokenSource>
     335              : bool
     336         5453 : Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
     337              : {
     338         5453 :   auto macro_name = lexer.peek_token (2)->get_id ();
     339              : 
     340         5453 :   bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
     341              : 
     342         5453 :   return t->get_str () == Values::WeakKeywords::MACRO_RULES
     343         5461 :          && 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        44823 : 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        44823 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
     363        44823 :   const_TokenPtr t = lexer.peek_token ();
     364              : 
     365        44823 :   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        39559 :     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        39559 :         auto vis_item = parse_vis_item (std::move (outer_attrs));
     403        39559 :         if (!vis_item)
     404           62 :           return Parse::Error::Item::make_malformed ();
     405        39497 :         return RType{std::move (vis_item)};
     406        39559 :       }
     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         5254 :     case IDENTIFIER:
     421              :       // TODO: ensure std::string and literal comparison works
     422         5254 :       if (t->get_str () == Values::WeakKeywords::UNION
     423         5321 :           && 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         5187 :       else if (t->get_str () == Values::WeakKeywords::DEFAULT
     432         5189 :                && 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        10372 :       else if (is_macro_rules_def (t))
     439              :         {
     440              :           // macro_rules! macro item
     441         1247 :           auto macro_rule_def = parse_macro_rules_def (std::move (outer_attrs));
     442         1247 :           if (!macro_rule_def)
     443           13 :             return Parse::Error::Item::make_malformed ();
     444         1234 :           return RType{std::move (macro_rule_def)};
     445         1247 :         }
     446         7878 :       else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
     447         7877 :                || lexer.peek_token (1)->get_id () == EXCLAM)
     448              :         {
     449              :           /* path (probably) or macro invocation, so probably a macro invocation
     450              :            * semi */
     451         3936 :           auto macro_invocation_semi
     452         3936 :             = parse_macro_invocation_semi (std::move (outer_attrs));
     453         3936 :           if (!macro_invocation_semi)
     454            1 :             return Parse::Error::Item::make_malformed ();
     455         3935 :           return RType{std::move (macro_invocation_semi)};
     456         3936 :         }
     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        44823 : }
     470              : 
     471              : // Parses a VisItem (item that can have non-default visibility).
     472              : template <typename ManagedTokenSource>
     473              : std::unique_ptr<AST::VisItem>
     474        40803 : Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
     475              : {
     476              :   // parse visibility, which may or may not exist
     477        40803 :   auto vis_res = parse_visibility ();
     478        40803 :   if (!vis_res)
     479            0 :     return nullptr;
     480        40803 :   auto vis = vis_res.value ();
     481              : 
     482              :   // select VisItem to create depending on keyword
     483        40803 :   const_TokenPtr t = lexer.peek_token ();
     484              : 
     485        40803 :   switch (t->get_id ())
     486              :     {
     487         1815 :     case MOD:
     488         1815 :       return parse_module (std::move (vis), std::move (outer_attrs));
     489         1859 :     case EXTERN_KW:
     490              :       // lookahead to resolve syntactical production
     491         1859 :       t = lexer.peek_token (1);
     492              : 
     493         1859 :       switch (t->get_id ())
     494              :         {
     495           70 :         case CRATE:
     496           70 :           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         1788 :         case STRING_LITERAL: // for specifying extern ABI
     502              :           // could be extern block or extern function, so more lookahead
     503         1788 :           t = lexer.peek_token (2);
     504              : 
     505         1788 :           switch (t->get_id ())
     506              :             {
     507            2 :             case FN_KW:
     508            2 :               return parse_function (std::move (vis), std::move (outer_attrs));
     509         1786 :             case LEFT_CURLY:
     510         1786 :               return parse_extern_block (std::move (vis),
     511         1786 :                                          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         2049 :     case USE:
     531         2049 :       return parse_use_decl (std::move (vis), std::move (outer_attrs));
     532         7451 :     case FN_KW:
     533         7451 :       return parse_function (std::move (vis), std::move (outer_attrs));
     534          112 :     case TYPE:
     535          112 :       return parse_type_alias (std::move (vis), std::move (outer_attrs));
     536         3885 :     case STRUCT_KW:
     537         3885 :       return parse_struct (std::move (vis), std::move (outer_attrs));
     538          670 :     case ENUM_KW:
     539          670 :       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          117 :     case IDENTIFIER:
     543          117 :       if (t->get_str () == Values::WeakKeywords::UNION
     544          233 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
     545              :         {
     546          116 :           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         1215 :     case CONST:
     557              :       // lookahead to resolve syntactical production
     558         1215 :       t = lexer.peek_token (1);
     559              : 
     560         1215 :       switch (t->get_id ())
     561              :         {
     562         1091 :         case IDENTIFIER:
     563              :         case UNDERSCORE:
     564         1091 :           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          123 :         case UNSAFE:
     568              :         case EXTERN_KW:
     569              :         case FN_KW:
     570          123 :           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          136 :     case STATIC_KW:
     585          136 :       return parse_static_item (std::move (vis), std::move (outer_attrs));
     586         4499 :     case AUTO:
     587              :     case TRAIT:
     588         4499 :       return parse_trait (std::move (vis), std::move (outer_attrs));
     589        12798 :     case IMPL:
     590        12798 :       return parse_impl (std::move (vis), std::move (outer_attrs));
     591         4117 :     case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls),
     592              :       // lookahead to resolve syntactical production
     593         4117 :       t = lexer.peek_token (1);
     594              : 
     595         4117 :       switch (t->get_id ())
     596              :         {
     597           85 :         case AUTO:
     598              :         case TRAIT:
     599           85 :           return parse_trait (std::move (vis), std::move (outer_attrs));
     600         3733 :         case EXTERN_KW:
     601              :         case FN_KW:
     602         3733 :           return parse_function (std::move (vis), std::move (outer_attrs));
     603          297 :         case IMPL:
     604          297 :           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           73 :     case MACRO:
     617           73 :       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        40803 : }
     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         1766 : Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
     664              : {
     665              :   // ensure that first token is identifier saying "macro_rules"
     666         1766 :   const_TokenPtr t = lexer.peek_token ();
     667         1766 :   if (t->get_id () != IDENTIFIER
     668         1766 :       || 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         1766 :   lexer.skip_token ();
     679         1766 :   location_t macro_locus = t->get_locus ();
     680              : 
     681         1766 :   if (!skip_token (EXCLAM))
     682              :     {
     683              :       // skip after somewhere?
     684            0 :       return nullptr;
     685              :     }
     686              : 
     687              :   // parse macro name
     688         1766 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
     689         1766 :   if (ident_tok == nullptr)
     690              :     {
     691            1 :       return nullptr;
     692              :     }
     693         3530 :   Identifier rule_name{ident_tok};
     694              : 
     695              :   // DEBUG
     696         1765 :   rust_debug ("in macro rules def, about to parse parens.");
     697              : 
     698              :   // save delim type to ensure it is reused later
     699         1765 :   AST::DelimType delim_type = AST::PARENS;
     700              : 
     701              :   // Map tokens to DelimType
     702         1765 :   t = lexer.peek_token ();
     703         1765 :   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         1764 :     case LEFT_CURLY:
     712         1764 :       delim_type = AST::CURLY;
     713         1764 :       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         1765 :   lexer.skip_token ();
     723              : 
     724              :   // parse actual macro rules
     725         1765 :   std::vector<AST::MacroRule> macro_rules;
     726              : 
     727              :   // must be at least one macro rule, so parse it
     728         1765 :   AST::MacroRule initial_rule = parse_macro_rule ();
     729         1765 :   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         1753 :   macro_rules.push_back (std::move (initial_rule));
     740              : 
     741              :   // DEBUG
     742         1753 :   rust_debug ("successfully pushed back initial macro rule");
     743              : 
     744         1753 :   t = lexer.peek_token ();
     745              :   // parse macro rules
     746         1925 :   while (t->get_id () == SEMICOLON)
     747              :     {
     748              :       // skip semicolon
     749         1321 :       lexer.skip_token ();
     750              : 
     751              :       // don't parse if end of macro rules
     752         2642 :       if (Parse::Utils::token_id_matches_delims (lexer.peek_token ()->get_id (),
     753              :                                                  delim_type))
     754              :         {
     755              :           // DEBUG
     756         1149 :           rust_debug (
     757              :             "broke out of parsing macro rules loop due to finding delim");
     758              : 
     759         1149 :           break;
     760              :         }
     761              : 
     762              :       // try to parse next rule
     763          172 :       AST::MacroRule rule = parse_macro_rule ();
     764          172 :       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          172 :       macro_rules.push_back (std::move (rule));
     774              : 
     775              :       // DEBUG
     776          172 :       rust_debug ("successfully pushed back another macro rule");
     777              : 
     778          172 :       t = lexer.peek_token ();
     779              :     }
     780              : 
     781              :   // parse end delimiters
     782         1753 :   t = lexer.peek_token ();
     783         1753 :   if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
     784              :     {
     785              :       // tokens match opening delimiter, so skip.
     786         1753 :       lexer.skip_token ();
     787              : 
     788         1753 :       if (delim_type != AST::CURLY)
     789              :         {
     790              :           // skip semicolon at end of non-curly macro definitions
     791            1 :           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         3506 :         AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
     803              :                                         std::move (macro_rules),
     804         1753 :                                         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         5296 : }
     823              : 
     824              : // Parses a declarative macro 2.0 definition.
     825              : template <typename ManagedTokenSource>
     826              : std::unique_ptr<AST::MacroRulesDefinition>
     827           73 : 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           73 :   const_TokenPtr t = lexer.peek_token ();
     832           73 :   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           73 :   lexer.skip_token ();
     843           73 :   location_t macro_locus = t->get_locus ();
     844              : 
     845              :   // parse macro name
     846           73 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
     847           73 :   if (ident_tok == nullptr)
     848              :     {
     849            0 :       return nullptr;
     850              :     }
     851          146 :   Identifier rule_name{ident_tok};
     852              : 
     853           73 :   t = lexer.peek_token ();
     854           73 :   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           48 :       location_t locus = lexer.peek_token ()->get_locus ();
     861           48 :       AST::MacroMatcher matcher = parse_macro_matcher ();
     862           48 :       if (matcher.is_error ())
     863            0 :         return nullptr;
     864              : 
     865              :       // check delimiter of macro matcher
     866           48 :       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           48 :       location_t transcriber_loc = lexer.peek_token ()->get_locus ();
     875           48 :       auto delim_tok_tree = parse_delim_token_tree ();
     876           48 :       if (!delim_tok_tree)
     877            0 :         return nullptr;
     878              : 
     879           48 :       AST::MacroTranscriber transcriber (delim_tok_tree.value (),
     880              :                                          transcriber_loc);
     881              : 
     882           48 :       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           47 :       std::vector<AST::MacroRule> macro_rules;
     893           47 :       macro_rules.emplace_back (std::move (matcher), std::move (transcriber),
     894              :                                 locus);
     895              : 
     896              :       return std::unique_ptr<AST::MacroRulesDefinition> (
     897           94 :         AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
     898              :                                                macro_rules,
     899              :                                                std::move (outer_attrs),
     900           47 :                                                macro_locus, vis));
     901          143 :     }
     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          146 : }
     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        77741 : Parser<ManagedTokenSource>::parse_visibility ()
     991              : {
     992              :   // check for no visibility
     993       155482 :   if (lexer.peek_token ()->get_id () != PUB)
     994              :     {
     995        60699 :       return AST::Visibility::create_private ();
     996              :     }
     997              : 
     998        17042 :   auto vis_loc = lexer.peek_token ()->get_locus ();
     999        17042 :   lexer.skip_token ();
    1000              : 
    1001              :   // create simple pub visibility if
    1002              :   // - found no parentheses
    1003              :   // - found unit type `()`
    1004        34084 :   if (lexer.peek_token ()->get_id () != LEFT_PAREN
    1005        17458 :       || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
    1006              :     {
    1007        16627 :       return AST::Visibility::create_public (vis_loc);
    1008              :       // or whatever
    1009              :     }
    1010              : 
    1011          415 :   lexer.skip_token ();
    1012              : 
    1013          415 :   const_TokenPtr t = lexer.peek_token ();
    1014          415 :   auto path_loc = t->get_locus ();
    1015              : 
    1016          415 :   switch (t->get_id ())
    1017              :     {
    1018          280 :     case CRATE:
    1019          280 :       lexer.skip_token ();
    1020              : 
    1021          280 :       skip_token (RIGHT_PAREN);
    1022              : 
    1023          280 :       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          115 :     case SUPER:
    1031          115 :       lexer.skip_token ();
    1032              : 
    1033          115 :       skip_token (RIGHT_PAREN);
    1034              : 
    1035          115 :       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          415 : }
    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         1816 : Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
    1070              :                                           AST::AttrVec outer_attrs)
    1071              : {
    1072         1816 :   location_t locus = lexer.peek_token ()->get_locus ();
    1073              : 
    1074         1816 :   Unsafety safety = Unsafety::Normal;
    1075         3632 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    1076              :     {
    1077            1 :       safety = Unsafety::Unsafe;
    1078            1 :       skip_token (UNSAFE);
    1079              :     }
    1080              : 
    1081         1816 :   skip_token (MOD);
    1082              : 
    1083         1816 :   const_TokenPtr module_name = expect_token (IDENTIFIER);
    1084         1816 :   if (module_name == nullptr)
    1085              :     {
    1086            0 :       return nullptr;
    1087              :     }
    1088         3632 :   Identifier name{module_name};
    1089              : 
    1090         1816 :   const_TokenPtr t = lexer.peek_token ();
    1091              : 
    1092         1816 :   switch (t->get_id ())
    1093              :     {
    1094          335 :     case SEMICOLON:
    1095          335 :       lexer.skip_token ();
    1096              : 
    1097              :       // Construct an external module
    1098              :       return std::unique_ptr<AST::Module> (
    1099         1005 :         new AST::Module (std::move (name), std::move (vis),
    1100              :                          std::move (outer_attrs), locus, safety,
    1101         1005 :                          lexer.get_filename (), inline_module_stack));
    1102         1481 :     case LEFT_CURLY:
    1103              :       {
    1104         1481 :         lexer.skip_token ();
    1105              : 
    1106              :         // parse inner attributes
    1107         1481 :         AST::AttrVec inner_attrs = parse_inner_attributes ();
    1108              : 
    1109         1481 :         std::string default_path = name.as_string ();
    1110              : 
    1111         1481 :         if (inline_module_stack.empty ())
    1112              :           {
    1113         1060 :             std::string filename = lexer.get_filename ();
    1114         1060 :             auto slash_idx = filename.rfind (file_separator);
    1115         1060 :             if (slash_idx == std::string::npos)
    1116              :               slash_idx = 0;
    1117              :             else
    1118         1060 :               slash_idx++;
    1119         1060 :             filename = filename.substr (slash_idx);
    1120              : 
    1121         1060 :             std::string subdir;
    1122         1060 :             if (get_file_subdir (filename, subdir))
    1123         1047 :               default_path = subdir + file_separator + name.as_string ();
    1124         1060 :           }
    1125              : 
    1126         1481 :         std::string module_path_name
    1127              :           = extract_module_path (inner_attrs, outer_attrs, default_path);
    1128         1481 :         InlineModuleStackScope scope (*this, std::move (module_path_name));
    1129              : 
    1130              :         // parse items
    1131         1481 :         std::vector<std::unique_ptr<AST::Item>> items;
    1132         1481 :         const_TokenPtr tok = lexer.peek_token ();
    1133         6992 :         while (tok->get_id () != RIGHT_CURLY)
    1134              :           {
    1135         5511 :             auto item = parse_item (false);
    1136         5511 :             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         5510 :             items.push_back (std::move (item.value ()));
    1146              : 
    1147         5510 :             tok = lexer.peek_token ();
    1148              :           }
    1149              : 
    1150         1480 :         if (!skip_token (RIGHT_CURLY))
    1151              :           {
    1152              :             // skip somewhere?
    1153            0 :             return nullptr;
    1154              :           }
    1155              : 
    1156              :         return std::unique_ptr<AST::Module> (
    1157         1480 :           new AST::Module (std::move (name), locus, std::move (items),
    1158              :                            std::move (vis), safety, std::move (inner_attrs),
    1159         1480 :                            std::move (outer_attrs))); // module name?
    1160         1481 :       }
    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         1816 : }
    1171              : 
    1172              : // Parses an extern crate declaration (dependency on external crate)
    1173              : template <typename ManagedTokenSource>
    1174              : std::unique_ptr<AST::ExternCrate>
    1175           70 : Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis,
    1176              :                                                 AST::AttrVec outer_attrs)
    1177              : {
    1178           70 :   location_t locus = lexer.peek_token ()->get_locus ();
    1179           70 :   if (!skip_token (EXTERN_KW))
    1180              :     {
    1181            0 :       skip_after_semicolon ();
    1182            0 :       return nullptr;
    1183              :     }
    1184              : 
    1185           70 :   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           70 :   const_TokenPtr crate_name_tok = lexer.peek_token ();
    1194           70 :   std::string crate_name;
    1195              : 
    1196           70 :   switch (crate_name_tok->get_id ())
    1197              :     {
    1198           69 :     case IDENTIFIER:
    1199           69 :       crate_name = crate_name_tok->get_str ();
    1200           69 :       lexer.skip_token ();
    1201           69 :       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          140 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    1218              :     {
    1219           61 :       lexer.skip_token ();
    1220              : 
    1221              :       return std::unique_ptr<AST::ExternCrate> (
    1222           61 :         new AST::ExternCrate (std::move (crate_name), std::move (vis),
    1223           61 :                               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          158 : }
    1267              : 
    1268              : // Parses a use declaration.
    1269              : template <typename ManagedTokenSource>
    1270              : std::unique_ptr<AST::UseDeclaration>
    1271         2049 : Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
    1272              :                                             AST::AttrVec outer_attrs)
    1273              : {
    1274         2049 :   location_t locus = lexer.peek_token ()->get_locus ();
    1275         2049 :   if (!skip_token (USE))
    1276              :     {
    1277            0 :       skip_after_semicolon ();
    1278            0 :       return nullptr;
    1279              :     }
    1280              : 
    1281              :   // parse use tree, which is required
    1282         2049 :   std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
    1283         2049 :   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         2048 :   if (!skip_token (SEMICOLON))
    1294              :     {
    1295            0 :       skip_after_semicolon ();
    1296            0 :       return nullptr;
    1297              :     }
    1298              : 
    1299              :   return std::unique_ptr<AST::UseDeclaration> (
    1300         2048 :     new AST::UseDeclaration (std::move (use_tree), std::move (vis),
    1301         2048 :                              std::move (outer_attrs), locus));
    1302         2049 : }
    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         3933 : 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         3933 :   location_t locus = lexer.peek_token ()->get_locus ();
    1335              : 
    1336              :   // bool has_path = false;
    1337         3933 :   auto path = parse_simple_path ();
    1338              : 
    1339         3933 :   if (!path)
    1340              :     {
    1341              :       // has no path, so must be glob or nested tree UseTree type
    1342              : 
    1343            6 :       bool is_global = false;
    1344              : 
    1345              :       // check for global scope resolution operator
    1346           12 :       if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
    1347              :         {
    1348            1 :           lexer.skip_token ();
    1349            1 :           is_global = true;
    1350              :         }
    1351              : 
    1352            6 :       const_TokenPtr t = lexer.peek_token ();
    1353            6 :       switch (t->get_id ())
    1354              :         {
    1355            4 :         case ASTERISK:
    1356              :           // glob UseTree type
    1357            4 :           lexer.skip_token ();
    1358              : 
    1359            4 :           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            3 :             return std::unique_ptr<AST::UseTreeGlob> (
    1365            6 :               new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH,
    1366            9 :                                     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            6 :     }
    1430              :   else
    1431              :     {
    1432         3927 :       const_TokenPtr t = lexer.peek_token ();
    1433              : 
    1434         3927 :       switch (t->get_id ())
    1435              :         {
    1436           23 :         case AS:
    1437              :           {
    1438              :             // rebind UseTree type
    1439           23 :             lexer.skip_token ();
    1440              : 
    1441           23 :             const_TokenPtr t = lexer.peek_token ();
    1442           23 :             switch (t->get_id ())
    1443              :               {
    1444           21 :               case IDENTIFIER:
    1445              :                 // skip lexer token
    1446           21 :                 lexer.skip_token ();
    1447              : 
    1448           21 :                 return std::unique_ptr<AST::UseTreeRebind> (
    1449           63 :                   new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER,
    1450           63 :                                           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           23 :           }
    1471         3077 :         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         3077 :           return std::unique_ptr<AST::UseTreeRebind> (
    1480         9231 :             new AST::UseTreeRebind (AST::UseTreeRebind::NONE,
    1481         3077 :                                     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          826 :       skip_token ();
    1493          826 :       t = lexer.peek_token ();
    1494              : 
    1495          826 :       switch (t->get_id ())
    1496              :         {
    1497          241 :         case ASTERISK:
    1498              :           // glob UseTree type
    1499          241 :           lexer.skip_token ();
    1500              : 
    1501          241 :           return std::unique_ptr<AST::UseTreeGlob> (
    1502          723 :             new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
    1503          241 :                                   std::move (path.value ()), locus));
    1504          585 :         case LEFT_CURLY:
    1505              :           {
    1506              :             // nested tree UseTree type
    1507          585 :             lexer.skip_token ();
    1508              : 
    1509          585 :             std::vector<std::unique_ptr<AST::UseTree>> use_trees;
    1510              : 
    1511              :             // TODO: think of better control structure
    1512          585 :             const_TokenPtr t = lexer.peek_token ();
    1513         2466 :             while (t->get_id () != RIGHT_CURLY)
    1514              :               {
    1515         1881 :                 std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
    1516         1881 :                 if (use_tree == nullptr)
    1517              :                   {
    1518              :                     break;
    1519              :                   }
    1520              : 
    1521         1881 :                 use_trees.push_back (std::move (use_tree));
    1522              : 
    1523         3762 :                 if (lexer.peek_token ()->get_id () != COMMA)
    1524              :                   break;
    1525              : 
    1526         1333 :                 lexer.skip_token ();
    1527         1333 :                 t = lexer.peek_token ();
    1528              :               }
    1529              : 
    1530              :             // skip end curly delimiter
    1531          585 :             if (!skip_token (RIGHT_CURLY))
    1532              :               {
    1533              :                 // skip after somewhere?
    1534            0 :                 return nullptr;
    1535              :               }
    1536              : 
    1537          585 :             return std::unique_ptr<AST::UseTreeList> (
    1538         1170 :               new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED,
    1539          585 :                                     std::move (path.value ()),
    1540          585 :                                     std::move (use_trees), locus));
    1541          585 :           }
    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         3927 :     }
    1551         3933 : }
    1552              : 
    1553              : // Parses a function (not a method).
    1554              : template <typename ManagedTokenSource>
    1555              : std::unique_ptr<AST::Function>
    1556        18161 : Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
    1557              :                                             AST::AttrVec outer_attrs,
    1558              :                                             bool is_external)
    1559              : {
    1560        18161 :   location_t locus = lexer.peek_token ()->get_locus ();
    1561              :   // Get qualifiers for function if they exist
    1562        18161 :   auto qualifiers = parse_function_qualifiers ();
    1563        18161 :   if (!qualifiers)
    1564            1 :     return nullptr;
    1565              : 
    1566        18160 :   skip_token (FN_KW);
    1567              : 
    1568              :   // Save function name token
    1569        18160 :   const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
    1570        18160 :   if (function_name_tok == nullptr)
    1571              :     {
    1572            0 :       skip_after_next_block ();
    1573            0 :       return nullptr;
    1574              :     }
    1575        36320 :   Identifier function_name{function_name_tok};
    1576              : 
    1577              :   // parse generic params - if exist
    1578        18160 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    1579              :     = parse_generic_params_in_angles ();
    1580              : 
    1581        18160 :   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        18160 :   auto initial_param = parse_self_param ();
    1593              : 
    1594        18160 :   if (!initial_param.has_value ()
    1595        18160 :       && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
    1596            0 :     return nullptr;
    1597              : 
    1598        21034 :   if (initial_param.has_value () && lexer.peek_token ()->get_id () == COMMA)
    1599         1713 :     skip_token ();
    1600              : 
    1601              :   // parse function parameters (only if next token isn't right paren)
    1602        18160 :   std::vector<std::unique_ptr<AST::Param>> function_params;
    1603              : 
    1604        36320 :   if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
    1605              :     function_params
    1606         9045 :       = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
    1607              : 
    1608        18160 :   if (initial_param.has_value ())
    1609         2874 :     function_params.insert (function_params.begin (),
    1610         2874 :                             std::move (*initial_param));
    1611              : 
    1612        18160 :   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        18159 :   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
    1625              : 
    1626              :   // parse where clause - if exists
    1627        18159 :   AST::WhereClause where_clause = parse_where_clause ();
    1628              : 
    1629        18159 :   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
    1630        36318 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    1631         5761 :     lexer.skip_token ();
    1632              :   else
    1633              :     {
    1634        12398 :       auto block_expr = parse_block_expr ();
    1635        12398 :       if (!block_expr)
    1636           30 :         return nullptr;
    1637        12368 :       body = std::move (block_expr.value ());
    1638        12398 :     }
    1639              : 
    1640        48626 :   return std::unique_ptr<AST::Function> (new AST::Function (
    1641        18129 :     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        18129 :     std::move (vis), std::move (outer_attrs), locus, is_external));
    1645        54480 : }
    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        36533 : Parser<ManagedTokenSource>::parse_function_qualifiers ()
    1651              : {
    1652        36533 :   location_t locus = lexer.peek_token ()->get_locus ();
    1653              : 
    1654        36533 :   auto parsed = parse_function_qualifiers_raw (locus);
    1655        36533 :   if (!parsed)
    1656            3 :     return tl::unexpected<Parse::Error::Node> (parsed.error ());
    1657              : 
    1658        73060 :   return function_qualifiers_from_keywords (locus, std::move (parsed->first),
    1659        73060 :                                             std::move (parsed->second));
    1660        36533 : }
    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        36530 : Parser<ManagedTokenSource>::function_qualifiers_from_keywords (
    1670              :   location_t locus, const std::vector<TokenId> keywords, std::string abi)
    1671              : {
    1672        36530 :   Default default_status = Default::No;
    1673        36530 :   Async async_status = Async::No;
    1674        36530 :   Const const_status = Const::No;
    1675        36530 :   Unsafety unsafe_status = Unsafety::Normal;
    1676        36530 :   bool has_extern = false;
    1677              : 
    1678        44546 :   for (auto qualifier : keywords)
    1679              :     {
    1680         8016 :       switch (qualifier)
    1681              :         {
    1682           74 :         case IDENTIFIER:
    1683              :           // only "default" is valid in this context
    1684           74 :           default_status = Default::Yes;
    1685           74 :           continue;
    1686         2399 :         case CONST:
    1687         2399 :           const_status = Const::Yes;
    1688         2399 :           continue;
    1689           11 :         case ASYNC:
    1690           11 :           async_status = Async::Yes;
    1691           11 :           continue;
    1692         4776 :         case UNSAFE:
    1693         4776 :           unsafe_status = Unsafety::Unsafe;
    1694         4776 :           continue;
    1695          756 :         case EXTERN_KW:
    1696          756 :           has_extern = true;
    1697          756 :           continue;
    1698            0 :         default:
    1699              :           // non-qualifier token in input
    1700            0 :           rust_unreachable ();
    1701              :         }
    1702              :     }
    1703              : 
    1704        73060 :   return AST::FunctionQualifiers (locus, default_status, async_status,
    1705              :                                   const_status, unsafe_status, has_extern,
    1706        36530 :                                   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        36533 : Parser<ManagedTokenSource>::parse_function_qualifiers_raw (location_t locus)
    1714              : {
    1715        36533 :   std::vector<TokenId> found_order;
    1716        36533 :   std::string abi;
    1717              : 
    1718              :   // this will terminate on duplicates or the first non-qualifier token
    1719         8026 :   while (true)
    1720              :     {
    1721        44558 :       auto token = lexer.peek_token ();
    1722        44558 :       const TokenId token_id = token->get_id ();
    1723        44558 :       location_t locus = lexer.peek_token ()->get_locus ();
    1724              : 
    1725        44558 :       switch (token_id)
    1726              :         {
    1727           76 :         case IDENTIFIER:
    1728           76 :           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         7269 :           found_order.push_back (token_id);
    1739         7269 :           lexer.skip_token ();
    1740         7269 :           break;
    1741          757 :         case EXTERN_KW:
    1742              :           {
    1743          757 :             found_order.push_back (token_id);
    1744          757 :             lexer.skip_token ();
    1745              : 
    1746              :             // detect optional abi name
    1747          757 :             const_TokenPtr next_tok = lexer.peek_token ();
    1748          757 :             if (next_tok->get_id () == STRING_LITERAL)
    1749              :               {
    1750          757 :                 abi = next_tok->get_str ();
    1751          757 :                 lexer.skip_token ();
    1752              :               }
    1753          757 :           }
    1754          757 :           break;
    1755        36532 :         default:
    1756              :           // non-qualifier keyword
    1757        36532 :           goto done;
    1758              :         }
    1759              : 
    1760        16052 :       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        36532 : done:
    1772              : 
    1773        36532 :   if (!ensure_function_qualifier_order (locus, found_order))
    1774            2 :     return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
    1775              : 
    1776        73060 :   return make_pair (found_order, abi);
    1777        36533 : }
    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        36532 : 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         8023 :   auto token_priority = [] (const TokenId id) {
    1792         8023 :     switch (id)
    1793              :       {
    1794              :       case IDENTIFIER: // "default"; the only "weak" keyword considered here
    1795              :         return 1;
    1796         2400 :       case CONST:
    1797         2400 :         return 2;
    1798           12 :       case ASYNC:
    1799           12 :         return 3;
    1800         4778 :       case UNSAFE:
    1801         4778 :         return 4;
    1802          757 :       case EXTERN_KW:
    1803          757 :         return 5;
    1804            0 :       default:
    1805            0 :         rust_unreachable ();
    1806              :       };
    1807              :   };
    1808              : 
    1809        36532 :   size_t last_priority = 0;
    1810        44553 :   for (auto token_id : found_order)
    1811              :     {
    1812         8023 :       const size_t priority = token_priority (token_id);
    1813         8023 :       if (priority <= last_priority)
    1814              :         {
    1815            2 :           emit_function_qualifier_order_error_msg (locus, found_order);
    1816            2 :           return false;
    1817              :         }
    1818              : 
    1819         8021 :       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        62554 : Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
    1880              : {
    1881       125108 :   if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
    1882              :     {
    1883              :       // seems to be no generic params, so exit with empty vector
    1884        52925 :       return std::vector<std::unique_ptr<AST::GenericParam>> ();
    1885              :     }
    1886         9629 :   lexer.skip_token ();
    1887              : 
    1888              :   // DEBUG:
    1889         9629 :   rust_debug ("skipped left angle in generic param");
    1890              : 
    1891         9629 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    1892              :     = parse_generic_params (Parse::Utils::is_right_angle_tok);
    1893              : 
    1894              :   // DEBUG:
    1895         9629 :   rust_debug ("finished parsing actual generic params (i.e. inside angles)");
    1896              : 
    1897         9629 :   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         9628 :   return generic_params;
    1907         9629 : }
    1908              : 
    1909              : template <typename ManagedTokenSource>
    1910              : template <typename EndTokenPred>
    1911              : std::unique_ptr<AST::GenericParam>
    1912        15705 : Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
    1913              : {
    1914        15705 :   auto outer_attrs = parse_outer_attributes ();
    1915        15705 :   std::unique_ptr<AST::GenericParam> param;
    1916        15705 :   auto token = lexer.peek_token ();
    1917              : 
    1918        15705 :   switch (token->get_id ())
    1919              :     {
    1920         1716 :     case LIFETIME:
    1921              :       {
    1922         1716 :         auto lifetime = parse_lifetime (false);
    1923         1716 :         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         1716 :         std::vector<AST::Lifetime> lifetime_bounds;
    1933         3432 :         if (lexer.peek_token ()->get_id () == COLON)
    1934              :           {
    1935           25 :             lexer.skip_token ();
    1936              :             // parse required bounds
    1937              :             lifetime_bounds
    1938           25 :               = parse_lifetime_bounds ([is_end_token] (TokenId id) {
    1939           26 :                   return is_end_token (id) || id == COMMA;
    1940              :                 });
    1941              :           }
    1942              : 
    1943         3432 :         param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam (
    1944         1716 :           std::move (lifetime.value ()), std::move (lifetime_bounds),
    1945         1716 :           std::move (outer_attrs), token->get_locus ()));
    1946              :         break;
    1947         3432 :       }
    1948        13783 :     case IDENTIFIER:
    1949              :       {
    1950        13783 :         auto type_ident = token->get_str ();
    1951        13783 :         lexer.skip_token ();
    1952              : 
    1953        13783 :         std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    1954        27566 :         if (lexer.peek_token ()->get_id () == COLON)
    1955              :           {
    1956         3140 :             lexer.skip_token ();
    1957              : 
    1958              :             // parse optional type param bounds
    1959         3140 :             type_param_bounds = parse_type_param_bounds ();
    1960              :           }
    1961              : 
    1962        13783 :         std::unique_ptr<AST::Type> type = nullptr;
    1963        27566 :         if (lexer.peek_token ()->get_id () == EQUAL)
    1964              :           {
    1965          453 :             lexer.skip_token ();
    1966              : 
    1967              :             // parse required type
    1968          453 :             type = parse_type ();
    1969          453 :             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        13783 :         param = std::unique_ptr<AST::TypeParam> (
    1981        41349 :           new AST::TypeParam (std::move (type_ident), token->get_locus (),
    1982              :                               std::move (type_param_bounds), std::move (type),
    1983        13783 :                               std::move (outer_attrs)));
    1984              :         break;
    1985        13783 :       }
    1986          205 :     case CONST:
    1987              :       {
    1988          205 :         lexer.skip_token ();
    1989              : 
    1990          205 :         auto name_token = expect_token (IDENTIFIER);
    1991              : 
    1992          410 :         if (!name_token || !expect_token (COLON))
    1993            1 :           return nullptr;
    1994              : 
    1995          204 :         auto type = parse_type ();
    1996          204 :         if (!type)
    1997            1 :           return nullptr;
    1998              : 
    1999              :         // optional default value
    2000          203 :         tl::optional<AST::GenericArg> default_expr = tl::nullopt;
    2001          406 :         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          202 :         param = std::unique_ptr<AST::ConstGenericParam> (
    2037          830 :           new AST::ConstGenericParam (name_token->get_str (), std::move (type),
    2038              :                                       default_expr, std::move (outer_attrs),
    2039          202 :                                       token->get_locus ()));
    2040              : 
    2041              :         break;
    2042          409 :       }
    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        15701 :   return param;
    2054        15705 : }
    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         9629 : Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
    2062              : {
    2063         9629 :   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         9629 :   AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
    2071              : 
    2072              :   // Did we parse a generic type param yet
    2073         9629 :   auto type_seen = false;
    2074              :   // Did we parse a const param with a default value yet
    2075         9629 :   auto const_with_default_seen = false;
    2076              :   // Did the user write a lifetime parameter after a type one
    2077         9629 :   auto order_error = false;
    2078              :   // Did the user write a const param with a default value after a type one
    2079         9629 :   auto const_with_default_order_error = false;
    2080              : 
    2081              :   // parse lifetime params
    2082        66365 :   while (!is_end_token (lexer.peek_token ()->get_id ()))
    2083              :     {
    2084        15705 :       auto param = parse_generic_param (is_end_token);
    2085        15705 :       if (param)
    2086              :         {
    2087        15701 :           if (param->get_kind () == AST::GenericParam::Kind::Type)
    2088              :             {
    2089        13783 :               type_seen = true;
    2090        13783 :               if (const_with_default_seen)
    2091        15701 :                 const_with_default_order_error = true;
    2092              :             }
    2093         1918 :           else if (param->get_kind () == AST::GenericParam::Kind::Lifetime
    2094         1918 :                    && 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         1916 :           else if (param->get_kind () == AST::GenericParam::Kind::Const)
    2101              :             {
    2102          202 :               type_seen = true;
    2103              :               AST::ConstGenericParam *const_param
    2104          202 :                 = static_cast<AST::ConstGenericParam *> (param.get ());
    2105          202 :               if (const_param->has_default_value ())
    2106              :                 const_with_default_seen = true;
    2107          180 :               else if (const_with_default_seen)
    2108        15701 :                 const_with_default_order_error = true;
    2109              :             }
    2110              : 
    2111        15701 :           generic_params.emplace_back (std::move (param));
    2112        15701 :           maybe_skip_token (COMMA);
    2113              :         }
    2114              :       else
    2115              :         break;
    2116              :     }
    2117              : 
    2118              :   // FIXME: Add reordering hint
    2119         9629 :   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         9629 :   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         9629 :   generic_params.shrink_to_fit ();
    2135         9629 :   return generic_params;
    2136         9629 : }
    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        23393 : Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
    2488              : {
    2489        23393 :   std::vector<std::unique_ptr<AST::Param>> params;
    2490              : 
    2491        46786 :   if (is_end_token (lexer.peek_token ()->get_id ()))
    2492         2098 :     return params;
    2493              : 
    2494        21295 :   auto initial_param = parse_function_param ();
    2495              : 
    2496              :   // Return empty parameter list if no parameter there
    2497        21295 :   if (initial_param == nullptr)
    2498              :     {
    2499              :       // TODO: is this an error?
    2500            1 :       return params;
    2501              :     }
    2502              : 
    2503        21294 :   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        21294 :   const_TokenPtr t = lexer.peek_token ();
    2509        28781 :   while (t->get_id () == COMMA)
    2510              :     {
    2511              :       // skip comma if applies
    2512         7810 :       lexer.skip_token ();
    2513              : 
    2514              :       // TODO: strictly speaking, shouldn't there be no trailing comma?
    2515        15620 :       if (is_end_token (lexer.peek_token ()->get_id ()))
    2516              :         break;
    2517              : 
    2518              :       // now, as right paren would break, function param is required
    2519         7487 :       auto param = parse_function_param ();
    2520         7487 :       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         7487 :       params.push_back (std::move (param));
    2531              : 
    2532         7487 :       t = lexer.peek_token ();
    2533              :     }
    2534              : 
    2535        21294 :   params.shrink_to_fit ();
    2536        21294 :   return params;
    2537        23393 : }
    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        28782 : Parser<ManagedTokenSource>::parse_function_param ()
    2544              : {
    2545              :   // parse outer attributes if they exist
    2546        28782 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    2547              : 
    2548              :   // TODO: should saved location be at start of outer attributes or pattern?
    2549        28782 :   location_t locus = lexer.peek_token ()->get_locus ();
    2550              : 
    2551        57564 :   if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic
    2552              :     {
    2553          887 :       lexer.skip_token (); // Skip ellipsis
    2554          887 :       return std::make_unique<AST::VariadicParam> (
    2555         1774 :         AST::VariadicParam (std::move (outer_attrs), locus));
    2556              :     }
    2557              : 
    2558        27895 :   std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
    2559              : 
    2560              :   // create error function param if it doesn't exist
    2561        27895 :   if (param_pattern == nullptr)
    2562              :     {
    2563              :       // skip after something
    2564            1 :       return nullptr;
    2565              :     }
    2566              : 
    2567        27894 :   if (!skip_token (COLON))
    2568              :     {
    2569              :       // skip after something
    2570            0 :       return nullptr;
    2571              :     }
    2572              : 
    2573        55788 :   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        27883 :       std::unique_ptr<AST::Type> param_type = parse_type ();
    2583        27883 :       if (param_type == nullptr)
    2584              :         {
    2585            0 :           return nullptr;
    2586              :         }
    2587        27883 :       return std::make_unique<AST::FunctionParam> (
    2588        55766 :         AST::FunctionParam (std::move (param_pattern), std::move (param_type),
    2589        27883 :                             std::move (outer_attrs), locus));
    2590        27883 :     }
    2591        28782 : }
    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        36438 : Parser<ManagedTokenSource>::parse_function_return_type ()
    2598              : {
    2599        72876 :   if (lexer.peek_token ()->get_id () != RETURN_TYPE)
    2600         9624 :     return nullptr;
    2601              : 
    2602              :   // skip return type, as it now obviously exists
    2603        26814 :   lexer.skip_token ();
    2604              : 
    2605        26814 :   std::unique_ptr<AST::Type> type = parse_type ();
    2606              : 
    2607        26814 :   return type;
    2608        26814 : }
    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        62531 : Parser<ManagedTokenSource>::parse_where_clause ()
    2617              : {
    2618        62531 :   const_TokenPtr where_tok = lexer.peek_token ();
    2619        62531 :   if (where_tok->get_id () != WHERE)
    2620              :     {
    2621              :       // where clause doesn't exist, so create empty one
    2622        61221 :       return AST::WhereClause::create_empty ();
    2623              :     }
    2624              : 
    2625         1310 :   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         1310 :   std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items;
    2630              : 
    2631         1310 :   std::vector<AST::LifetimeParam> for_lifetimes;
    2632         2620 :   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         1310 :   const_TokenPtr t = lexer.peek_token ();
    2638         2978 :   while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON
    2639         2783 :          && t->get_id () != EQUAL)
    2640              :     {
    2641         1668 :       std::unique_ptr<AST::WhereClauseItem> where_clause_item
    2642              :         = parse_where_clause_item (for_lifetimes);
    2643              : 
    2644         1668 :       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         1668 :       where_clause_items.push_back (std::move (where_clause_item));
    2653              : 
    2654              :       // also skip comma if it exists
    2655         3336 :       if (lexer.peek_token ()->get_id () != COMMA)
    2656              :         break;
    2657              : 
    2658         1473 :       lexer.skip_token ();
    2659         1473 :       t = lexer.peek_token ();
    2660              :     }
    2661              : 
    2662         1310 :   where_clause_items.shrink_to_fit ();
    2663         1310 :   return AST::WhereClause (std::move (where_clause_items));
    2664         1310 : }
    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         1668 : 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         1668 :   const_TokenPtr t = lexer.peek_token ();
    2676              : 
    2677         1668 :   if (t->get_id () == LIFETIME)
    2678            3 :     return parse_lifetime_where_clause_item ();
    2679              :   else
    2680         1665 :     return parse_type_bound_where_clause_item (outer_for_lifetimes);
    2681         1668 : }
    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         1665 : Parser<ManagedTokenSource>::parse_type_bound_where_clause_item (
    2716              :   const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
    2717              : {
    2718         1665 :   std::vector<AST::LifetimeParam> for_lifetimes = outer_for_lifetimes;
    2719              : 
    2720         1665 :   std::unique_ptr<AST::Type> type = parse_type ();
    2721         1665 :   if (type == nullptr)
    2722              :     {
    2723            0 :       return nullptr;
    2724              :     }
    2725              : 
    2726         1665 :   if (!skip_token (COLON))
    2727              :     {
    2728              :       // TODO: skip after somewhere
    2729            0 :       return nullptr;
    2730              :     }
    2731              : 
    2732         3330 :   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         1665 :   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds
    2741              :     = parse_type_param_bounds ();
    2742              : 
    2743         1665 :   location_t locus = lexer.peek_token ()->get_locus ();
    2744              : 
    2745              :   return std::unique_ptr<AST::TypeBoundWhereClauseItem> (
    2746         1665 :     new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes),
    2747              :                                        std::move (type),
    2748         1665 :                                        std::move (type_param_bounds), locus));
    2749         1665 : }
    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              :       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         4900 : Parser<ManagedTokenSource>::parse_type_param_bounds ()
    2793              : {
    2794         4900 :   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    2795              : 
    2796         4900 :   std::unique_ptr<AST::TypeParamBound> initial_bound
    2797              :     = parse_type_param_bound ();
    2798              : 
    2799              :   // quick exit if null
    2800         4900 :   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         4900 :   type_param_bounds.push_back (std::move (initial_bound));
    2807              : 
    2808        10522 :   while (lexer.peek_token ()->get_id () == PLUS)
    2809              :     {
    2810          361 :       lexer.skip_token ();
    2811              : 
    2812          361 :       std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
    2813          361 :       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          361 :       type_param_bounds.push_back (std::move (bound));
    2821              :     }
    2822              : 
    2823         4900 :   type_param_bounds.shrink_to_fit ();
    2824              :   return type_param_bounds;
    2825         4900 : }
    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          742 : Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token)
    2833              : {
    2834          742 :   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    2835              : 
    2836          742 :   std::unique_ptr<AST::TypeParamBound> initial_bound
    2837              :     = parse_type_param_bound ();
    2838              : 
    2839              :   // quick exit if null
    2840          742 :   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          742 :   type_param_bounds.push_back (std::move (initial_bound));
    2847              : 
    2848         1694 :   while (lexer.peek_token ()->get_id () == PLUS)
    2849              :     {
    2850          105 :       lexer.skip_token ();
    2851              : 
    2852              :       // break if end token character
    2853          210 :       if (is_end_token (lexer.peek_token ()->get_id ()))
    2854              :         break;
    2855              : 
    2856          105 :       std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
    2857          105 :       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          105 :       type_param_bounds.push_back (std::move (bound));
    2868              :     }
    2869              : 
    2870          742 :   type_param_bounds.shrink_to_fit ();
    2871          742 :   return type_param_bounds;
    2872          742 : }
    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         6182 : Parser<ManagedTokenSource>::parse_type_param_bound ()
    2879              : {
    2880              :   // shitty cheat way of determining lifetime or trait bound - test for
    2881              :   // lifetime
    2882         6182 :   const_TokenPtr t = lexer.peek_token ();
    2883         6182 :   switch (t->get_id ())
    2884              :     {
    2885          293 :     case LIFETIME:
    2886          293 :       return std::unique_ptr<AST::Lifetime> (
    2887          586 :         new AST::Lifetime (parse_lifetime (false).value ()));
    2888         5889 :     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         5889 :       return parse_trait_bound ();
    2899            0 :     default:
    2900              :       // don't error - assume this is fine TODO
    2901            0 :       return nullptr;
    2902              :     }
    2903         6182 : }
    2904              : 
    2905              : // Parses a trait bound type param bound.
    2906              : template <typename ManagedTokenSource>
    2907              : std::unique_ptr<AST::TraitBound>
    2908         6439 : Parser<ManagedTokenSource>::parse_trait_bound ()
    2909              : {
    2910         6439 :   bool has_parens = false;
    2911         6439 :   bool has_question_mark = false;
    2912              : 
    2913         6439 :   location_t locus = lexer.peek_token ()->get_locus ();
    2914              : 
    2915              :   /* parse optional `for lifetimes`. */
    2916         6439 :   std::vector<AST::LifetimeParam> for_lifetimes;
    2917        12878 :   if (lexer.peek_token ()->get_id () == FOR)
    2918            7 :     for_lifetimes = parse_for_lifetimes ();
    2919              : 
    2920              :   // handle trait bound being in parentheses
    2921        12878 :   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        12878 :   if (lexer.peek_token ()->get_id () == QUESTION_MARK)
    2929              :     {
    2930          948 :       has_question_mark = true;
    2931          948 :       lexer.skip_token ();
    2932              :     }
    2933              : 
    2934              :   // handle TypePath
    2935         6439 :   AST::TypePath type_path = parse_type_path ();
    2936         6439 :   if (type_path.is_error ())
    2937            2 :     return nullptr;
    2938              : 
    2939              :   // handle closing parentheses
    2940         6437 :   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         6437 :     new AST::TraitBound (std::move (type_path), locus, has_parens,
    2950         6437 :                          has_question_mark, std::move (for_lifetimes)));
    2951         6439 : }
    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           25 : Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token)
    2987              : {
    2988           25 :   std::vector<AST::Lifetime> lifetime_bounds;
    2989              : 
    2990          103 :   while (!is_end_token (lexer.peek_token ()->get_id ()))
    2991              :     {
    2992           26 :       auto lifetime = parse_lifetime (false);
    2993              : 
    2994           26 :       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           26 :       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           52 :       if (lexer.peek_token ()->get_id () != PLUS)
    3010              :         break;
    3011              : 
    3012            1 :       lexer.skip_token ();
    3013              :     }
    3014              : 
    3015           25 :   lifetime_bounds.shrink_to_fit ();
    3016           25 :   return lifetime_bounds;
    3017           25 : }
    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        27904 : Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided)
    3024              : {
    3025        27904 :   const_TokenPtr lifetime_tok = lexer.peek_token ();
    3026        27904 :   if (lifetime_tok->get_id () != LIFETIME)
    3027              :     {
    3028        21615 :       if (allow_elided)
    3029              :         {
    3030            0 :           return AST::Lifetime::elided ();
    3031              :         }
    3032              :       else
    3033              :         {
    3034        21615 :           return tl::make_unexpected<Parse::Error::Lifetime> ({});
    3035              :         }
    3036              :     }
    3037         6289 :   lexer.skip_token ();
    3038              : 
    3039        12578 :   return lifetime_from_token (lifetime_tok);
    3040        27904 : }
    3041              : 
    3042              : template <typename ManagedTokenSource>
    3043              : AST::Lifetime
    3044         6350 : Parser<ManagedTokenSource>::lifetime_from_token (const_TokenPtr tok)
    3045              : {
    3046         6350 :   location_t locus = tok->get_locus ();
    3047         6350 :   std::string lifetime_ident = tok->get_str ();
    3048              : 
    3049         6350 :   if (lifetime_ident == "static")
    3050              :     {
    3051          145 :       return AST::Lifetime (AST::Lifetime::STATIC, "", locus);
    3052              :     }
    3053         6205 :   else if (lifetime_ident == "_")
    3054              :     {
    3055              :       // Explicitly and implicitly elided lifetimes follow the same rules.
    3056         1059 :       return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus);
    3057              :     }
    3058              :   else
    3059              :     {
    3060        10292 :       return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident),
    3061         5146 :                             locus);
    3062              :     }
    3063         6350 : }
    3064              : 
    3065              : template <typename ManagedTokenSource>
    3066              : std::unique_ptr<AST::ExternalTypeItem>
    3067            8 : Parser<ManagedTokenSource>::parse_external_type_item (AST::Visibility vis,
    3068              :                                                       AST::AttrVec outer_attrs)
    3069              : {
    3070            8 :   location_t locus = lexer.peek_token ()->get_locus ();
    3071            8 :   skip_token (TYPE);
    3072              : 
    3073            8 :   const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
    3074            8 :   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            8 :   if (!skip_token (SEMICOLON))
    3085            1 :     return nullptr;
    3086              : 
    3087              :   return std::unique_ptr<AST::ExternalTypeItem> (
    3088           21 :     new AST::ExternalTypeItem (alias_name_tok->get_str (), std::move (vis),
    3089            7 :                                std::move (outer_attrs), std::move (locus)));
    3090            8 : }
    3091              : 
    3092              : // Parses a "type alias" (typedef) item.
    3093              : template <typename ManagedTokenSource>
    3094              : std::unique_ptr<AST::TypeAlias>
    3095         4367 : Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis,
    3096              :                                               AST::AttrVec outer_attrs)
    3097              : {
    3098         4367 :   location_t locus = lexer.peek_token ()->get_locus ();
    3099         4367 :   skip_token (TYPE);
    3100              : 
    3101              :   // TODO: use this token for identifier when finished that
    3102         4367 :   const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
    3103         4367 :   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         8734 :   Identifier alias_name{alias_name_tok};
    3113              : 
    3114              :   // parse generic params, which may not exist
    3115         4367 :   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         4367 :   AST::WhereClause where_clause = parse_where_clause ();
    3120              : 
    3121         4367 :   if (!skip_token (EQUAL))
    3122              :     {
    3123            0 :       skip_after_semicolon ();
    3124            0 :       return nullptr;
    3125              :     }
    3126              : 
    3127         4367 :   std::unique_ptr<AST::Type> type_to_alias = parse_type ();
    3128              : 
    3129         4367 :   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         4367 :     new AST::TypeAlias (std::move (alias_name), std::move (generic_params),
    3137              :                         std::move (where_clause), std::move (type_to_alias),
    3138         4367 :                         std::move (vis), std::move (outer_attrs), locus));
    3139         8734 : }
    3140              : 
    3141              : // Parse a struct item AST node.
    3142              : template <typename ManagedTokenSource>
    3143              : std::unique_ptr<AST::Struct>
    3144         3885 : 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         3885 :   location_t locus = lexer.peek_token ()->get_locus ();
    3159         3885 :   skip_token (STRUCT_KW);
    3160              : 
    3161              :   // parse struct name
    3162         3885 :   const_TokenPtr name_tok = expect_token (IDENTIFIER);
    3163         3885 :   if (name_tok == nullptr)
    3164              :     {
    3165              :       // skip after somewhere?
    3166            1 :       return nullptr;
    3167              :     }
    3168         7768 :   Identifier struct_name{name_tok};
    3169              : 
    3170              :   // parse generic params, which may or may not exist
    3171         3884 :   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         7768 :   if (lexer.peek_token ()->get_id () == LEFT_PAREN)
    3176              :     {
    3177              :       // tuple struct
    3178              : 
    3179              :       // skip left parenthesis
    3180         1194 :       lexer.skip_token ();
    3181              : 
    3182              :       // parse tuple fields
    3183         1194 :       std::vector<AST::TupleField> tuple_fields;
    3184              :       // Might be empty tuple for unit tuple struct.
    3185         2388 :       if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    3186           23 :         tuple_fields = std::vector<AST::TupleField> ();
    3187              :       else
    3188         1171 :         tuple_fields = parse_tuple_fields ();
    3189              : 
    3190              :       // tuple parameters must have closing parenthesis
    3191         1194 :       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         1193 :       AST::WhereClause where_clause = parse_where_clause ();
    3199              : 
    3200         1193 :       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         1193 :       return std::unique_ptr<AST::TupleStruct> (
    3207         1193 :         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         1193 :                               std::move (outer_attrs), locus));
    3211         1194 :     }
    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         2690 :   AST::WhereClause where_clause = parse_where_clause ();
    3218              : 
    3219              :   // branch on next token - determines whether struct is a unit struct
    3220         2690 :   const_TokenPtr t = lexer.peek_token ();
    3221         2690 :   switch (t->get_id ())
    3222              :     {
    3223         1450 :     case LEFT_CURLY:
    3224              :       {
    3225              :         // struct with body
    3226              : 
    3227              :         // skip curly bracket
    3228         1450 :         lexer.skip_token ();
    3229              : 
    3230              :         // parse struct fields, if any
    3231         1450 :         std::vector<AST::StructField> struct_fields
    3232              :           = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
    3233              : 
    3234         1450 :         if (!skip_token (RIGHT_CURLY))
    3235              :           {
    3236              :             // skip somewhere?
    3237            0 :             return nullptr;
    3238              :           }
    3239              : 
    3240         1450 :         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         1450 :           std::move (vis), std::move (outer_attrs), locus));
    3244         1450 :       }
    3245         1239 :     case SEMICOLON:
    3246              :       // unit struct declaration
    3247              : 
    3248         1239 :       lexer.skip_token ();
    3249              : 
    3250         1239 :       return std::unique_ptr<AST::StructStruct> (
    3251         2478 :         new AST::StructStruct (std::move (struct_name),
    3252              :                                std::move (generic_params),
    3253              :                                std::move (where_clause), std::move (vis),
    3254         1239 :                                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         3884 : }
    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         1666 : Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
    3305              : {
    3306         1666 :   std::vector<AST::StructField> fields;
    3307              : 
    3308         1666 :   AST::StructField initial_field = parse_struct_field ();
    3309              : 
    3310              :   // Return empty field list if no field there
    3311         1666 :   if (initial_field.is_error ())
    3312           59 :     return fields;
    3313              : 
    3314         1607 :   fields.push_back (std::move (initial_field));
    3315              : 
    3316         6394 :   while (lexer.peek_token ()->get_id () == COMMA)
    3317              :     {
    3318         2988 :       lexer.skip_token ();
    3319              : 
    3320         5976 :       if (is_end_tok (lexer.peek_token ()->get_id ()))
    3321              :         break;
    3322              : 
    3323         1590 :       AST::StructField field = parse_struct_field ();
    3324         1590 :       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         1590 :       fields.push_back (std::move (field));
    3336              :     }
    3337              : 
    3338         1607 :   fields.shrink_to_fit ();
    3339         1607 :   return fields;
    3340              :   // TODO: template if possible (parse_non_ptr_seq)
    3341         1666 : }
    3342              : 
    3343              : // Parses a single struct field (in a struct definition). Does not parse
    3344              : // commas.
    3345              : template <typename ManagedTokenSource>
    3346              : AST::StructField
    3347         3256 : Parser<ManagedTokenSource>::parse_struct_field ()
    3348              : {
    3349              :   // parse outer attributes, if they exist
    3350         3256 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3351              : 
    3352              :   // parse visibility, if it exists
    3353         3256 :   auto vis = parse_visibility ();
    3354         3256 :   if (!vis)
    3355            0 :     return AST::StructField::create_error ();
    3356              : 
    3357         3256 :   location_t locus = lexer.peek_token ()->get_locus ();
    3358              : 
    3359              :   // parse field name
    3360         3256 :   const_TokenPtr field_name_tok = lexer.peek_token ();
    3361         3256 :   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           59 :       return AST::StructField::create_error ();
    3366              :     }
    3367         6394 :   Identifier field_name{field_name_tok};
    3368         3197 :   lexer.skip_token ();
    3369              : 
    3370         3197 :   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         3197 :   std::unique_ptr<AST::Type> field_type = parse_type ();
    3378         3197 :   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         6394 :   return AST::StructField (std::move (field_name), std::move (field_type),
    3389         3197 :                            std::move (vis.value ()), locus,
    3390         3197 :                            std::move (outer_attrs));
    3391        12906 : }
    3392              : 
    3393              : // Parses tuple fields in tuple/tuple struct declarations.
    3394              : template <typename ManagedTokenSource>
    3395              : std::vector<AST::TupleField>
    3396         1708 : Parser<ManagedTokenSource>::parse_tuple_fields ()
    3397              : {
    3398         1708 :   std::vector<AST::TupleField> fields;
    3399              : 
    3400         1708 :   AST::TupleField initial_field = parse_tuple_field ();
    3401              : 
    3402              :   // Return empty field list if no field there
    3403         1708 :   if (initial_field.is_error ())
    3404              :     {
    3405            1 :       return fields;
    3406              :     }
    3407              : 
    3408         1707 :   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         1707 :   const_TokenPtr t = lexer.peek_token ();
    3415         2943 :   while (t->get_id () == COMMA)
    3416              :     {
    3417              :       // skip comma if applies - e.g. trailing comma
    3418         1239 :       lexer.skip_token ();
    3419              : 
    3420              :       // break out due to right paren if it exists
    3421         2478 :       if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    3422              :         {
    3423              :           break;
    3424              :         }
    3425              : 
    3426         1236 :       AST::TupleField field = parse_tuple_field ();
    3427         1236 :       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         1236 :       fields.push_back (std::move (field));
    3437              : 
    3438         1236 :       t = lexer.peek_token ();
    3439              :     }
    3440              : 
    3441         1707 :   fields.shrink_to_fit ();
    3442         1707 :   return fields;
    3443              : 
    3444              :   // TODO: this shares basically all code with function params and struct
    3445              :   // fields
    3446              :   // - templates?
    3447         1708 : }
    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         2944 : Parser<ManagedTokenSource>::parse_tuple_field ()
    3454              : {
    3455              :   // parse outer attributes if they exist
    3456         2944 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3457              : 
    3458              :   // parse visibility if it exists
    3459         2944 :   auto visibility = parse_visibility ();
    3460         2944 :   if (!visibility)
    3461            0 :     return AST::TupleField::create_error ();
    3462              : 
    3463         2944 :   location_t locus = lexer.peek_token ()->get_locus ();
    3464              : 
    3465              :   // parse type, which is required
    3466         2944 :   std::unique_ptr<AST::Type> field_type = parse_type ();
    3467         2944 :   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         2943 :   return AST::TupleField (std::move (field_type),
    3479         2943 :                           std::move (visibility.value ()), locus,
    3480         2943 :                           std::move (outer_attrs));
    3481         5888 : }
    3482              : 
    3483              : // Parses a Rust "enum" tagged union item definition.
    3484              : template <typename ManagedTokenSource>
    3485              : std::unique_ptr<AST::Enum>
    3486          670 : Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
    3487              :                                         AST::AttrVec outer_attrs)
    3488              : {
    3489          670 :   location_t locus = lexer.peek_token ()->get_locus ();
    3490          670 :   skip_token (ENUM_KW);
    3491              : 
    3492              :   // parse enum name
    3493          670 :   const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
    3494          670 :   if (enum_name_tok == nullptr)
    3495            1 :     return nullptr;
    3496              : 
    3497         1338 :   Identifier enum_name = {enum_name_tok};
    3498              : 
    3499              :   // parse generic params (of enum container, not enum variants) if they exist
    3500          669 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3501              :     = parse_generic_params_in_angles ();
    3502              : 
    3503              :   // parse where clause if it exists
    3504          669 :   AST::WhereClause where_clause = parse_where_clause ();
    3505              : 
    3506          669 :   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          669 :   std::vector<std::unique_ptr<AST::EnumItem>> enum_items
    3514              :     = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
    3515              : 
    3516          669 :   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          668 :     new AST::Enum (std::move (enum_name), std::move (vis),
    3524              :                    std::move (generic_params), std::move (where_clause),
    3525          668 :                    std::move (enum_items), std::move (outer_attrs), locus));
    3526         1338 : }
    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          669 : Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
    3568              : {
    3569          669 :   std::vector<std::unique_ptr<AST::EnumItem>> items;
    3570              : 
    3571          669 :   auto initial_item = parse_enum_item ();
    3572              : 
    3573              :   // Return empty item list if no field there
    3574          669 :   if (!initial_item)
    3575           27 :     return items;
    3576              : 
    3577          642 :   items.push_back (std::move (initial_item.value ()));
    3578              : 
    3579         3100 :   while (lexer.peek_token ()->get_id () == COMMA)
    3580              :     {
    3581         1524 :       lexer.skip_token ();
    3582              : 
    3583         3048 :       if (is_end_tok (lexer.peek_token ()->get_id ()))
    3584              :         break;
    3585              : 
    3586          908 :       auto item = parse_enum_item ();
    3587          908 :       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          908 :       items.push_back (std::move (item.value ()));
    3599              :     }
    3600              : 
    3601          642 :   items.shrink_to_fit ();
    3602          642 :   return items;
    3603              : 
    3604              :   /* TODO: use template if doable (parse_non_ptr_sequence) */
    3605          669 : }
    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         1577 : Parser<ManagedTokenSource>::parse_enum_item ()
    3612              : {
    3613              :   // parse outer attributes if they exist
    3614         1577 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    3615              : 
    3616              :   // parse visibility, which may or may not exist
    3617         1577 :   auto vis_res = parse_visibility ();
    3618         1577 :   if (!vis_res)
    3619            0 :     return Parse::Error::EnumVariant::make_child_error ();
    3620         1577 :   auto vis = vis_res.value ();
    3621              : 
    3622              :   // parse name for enum item, which is required
    3623         1577 :   const_TokenPtr item_name_tok = lexer.peek_token ();
    3624         1577 :   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           54 :       return Parse::Error::EnumVariant::make_not_identifier (item_name_tok);
    3628              :     }
    3629         1550 :   lexer.skip_token ();
    3630         3100 :   Identifier item_name{item_name_tok};
    3631              : 
    3632              :   // branch based on next token
    3633         1550 :   const_TokenPtr t = lexer.peek_token ();
    3634         1550 :   switch (t->get_id ())
    3635              :     {
    3636          558 :     case LEFT_PAREN:
    3637              :       {
    3638              :         // tuple enum item
    3639          558 :         lexer.skip_token ();
    3640              : 
    3641          558 :         std::vector<AST::TupleField> tuple_fields;
    3642              :         // Might be empty tuple for unit tuple enum variant.
    3643         1116 :         if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    3644           21 :           tuple_fields = std::vector<AST::TupleField> ();
    3645              :         else
    3646          537 :           tuple_fields = parse_tuple_fields ();
    3647              : 
    3648          558 :         if (!skip_token (RIGHT_PAREN))
    3649              :           {
    3650              :             // skip after somewhere
    3651            0 :             return Parse::Error::EnumVariant::make_unfinished_tuple_variant ();
    3652              :           }
    3653              : 
    3654          558 :         return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
    3655              :           std::move (item_name), std::move (vis), std::move (tuple_fields),
    3656          558 :           std::move (outer_attrs), item_name_tok->get_locus ()));
    3657          558 :       }
    3658          100 :     case LEFT_CURLY:
    3659              :       {
    3660              :         // struct enum item
    3661          100 :         lexer.skip_token ();
    3662              : 
    3663          100 :         std::vector<AST::StructField> struct_fields
    3664              :           = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
    3665              : 
    3666          100 :         if (!skip_token (RIGHT_CURLY))
    3667              :           {
    3668              :             // skip after somewhere
    3669            0 :             return Parse::Error::EnumVariant::make_unfinished_tuple_variant ();
    3670              :           }
    3671              : 
    3672          100 :         return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
    3673              :           std::move (item_name), std::move (vis), std::move (struct_fields),
    3674          100 :           std::move (outer_attrs), item_name_tok->get_locus ()));
    3675          100 :       }
    3676          296 :     case EQUAL:
    3677              :       {
    3678              :         // discriminant enum item
    3679          296 :         lexer.skip_token ();
    3680              : 
    3681          296 :         auto discriminant_expr = parse_expr ();
    3682          296 :         if (!discriminant_expr)
    3683            0 :           return Parse::Error::EnumVariant::make_child_error ();
    3684              : 
    3685          296 :         return std::make_unique<AST::EnumItemDiscriminant> (
    3686              :           std::move (item_name), std::move (vis),
    3687          296 :           std::move (discriminant_expr.value ()), std::move (outer_attrs),
    3688          592 :           item_name_tok->get_locus ());
    3689          296 :       }
    3690          596 :     default:
    3691              :       // regular enum with just an identifier
    3692          596 :       return std::make_unique<AST::EnumItem> (std::move (item_name),
    3693              :                                               std::move (vis),
    3694              :                                               std::move (outer_attrs),
    3695          596 :                                               item_name_tok->get_locus ());
    3696              :     }
    3697         4704 : }
    3698              : 
    3699              : // Parses a C-style (and C-compat) untagged union declaration.
    3700              : template <typename ManagedTokenSource>
    3701              : std::unique_ptr<AST::Union>
    3702          116 : 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          116 :   const_TokenPtr union_keyword = expect_token (IDENTIFIER);
    3708          116 :   rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION);
    3709          116 :   location_t locus = union_keyword->get_locus ();
    3710              : 
    3711              :   // parse actual union name
    3712          116 :   const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
    3713          116 :   if (union_name_tok == nullptr)
    3714              :     {
    3715            0 :       skip_after_next_block ();
    3716            0 :       return nullptr;
    3717              :     }
    3718          232 :   Identifier union_name{union_name_tok};
    3719              : 
    3720              :   // parse optional generic parameters
    3721          116 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3722              :     = parse_generic_params_in_angles ();
    3723              : 
    3724              :   // parse optional where clause
    3725          116 :   AST::WhereClause where_clause = parse_where_clause ();
    3726              : 
    3727          116 :   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          116 :   std::vector<AST::StructField> union_fields
    3736              :     = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
    3737              : 
    3738          116 :   if (!skip_token (RIGHT_CURLY))
    3739              :     {
    3740              :       // skip after somewhere
    3741            0 :       return nullptr;
    3742              :     }
    3743              : 
    3744              :   return std::unique_ptr<AST::Union> (
    3745          116 :     new AST::Union (std::move (union_name), std::move (vis),
    3746              :                     std::move (generic_params), std::move (where_clause),
    3747          116 :                     std::move (union_fields), std::move (outer_attrs), locus));
    3748          348 : }
    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         1311 : Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
    3755              :                                               AST::AttrVec outer_attrs)
    3756              : {
    3757         1311 :   location_t locus = lexer.peek_token ()->get_locus ();
    3758         1311 :   skip_token (CONST);
    3759              : 
    3760              :   /* get constant identifier - this is either a proper identifier or the _
    3761              :    * wildcard */
    3762         1311 :   const_TokenPtr ident_tok = lexer.peek_token ();
    3763              :   // make default identifier the underscore wildcard one
    3764         1311 :   std::string ident (Values::Keywords::UNDERSCORE);
    3765         1311 :   switch (ident_tok->get_id ())
    3766              :     {
    3767         1303 :     case IDENTIFIER:
    3768         1303 :       ident = ident_tok->get_str ();
    3769         1303 :       lexer.skip_token ();
    3770         1303 :       break;
    3771            8 :     case UNDERSCORE:
    3772              :       // do nothing - identifier is already "_"
    3773            8 :       lexer.skip_token ();
    3774            8 :       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         1311 :   if (!skip_token (COLON))
    3787              :     {
    3788            0 :       skip_after_semicolon ();
    3789            0 :       return nullptr;
    3790              :     }
    3791              : 
    3792              :   // parse constant type (required)
    3793         1311 :   std::unique_ptr<AST::Type> type = parse_type ();
    3794              : 
    3795              :   // A const with no given expression value
    3796         2622 :   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         1307 :   if (!skip_token (EQUAL))
    3806              :     {
    3807            0 :       skip_after_semicolon ();
    3808            0 :       return nullptr;
    3809              :     }
    3810              : 
    3811              :   // parse constant expression (required)
    3812         1307 :   auto expr = parse_expr ();
    3813         1307 :   if (!expr)
    3814            1 :     return nullptr;
    3815              : 
    3816         1306 :   if (!skip_token (SEMICOLON))
    3817              :     {
    3818              :       // skip somewhere?
    3819            0 :       return nullptr;
    3820              :     }
    3821              : 
    3822              :   return std::unique_ptr<AST::ConstantItem> (
    3823         2612 :     new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
    3824         1306 :                            std::move (expr.value ()), std::move (outer_attrs),
    3825         1306 :                            locus));
    3826         2622 : }
    3827              : 
    3828              : // Parses a "static item" (static storage item, with 'static lifetime).
    3829              : template <typename ManagedTokenSource>
    3830              : std::unique_ptr<AST::StaticItem>
    3831          136 : Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
    3832              :                                                AST::AttrVec outer_attrs)
    3833              : {
    3834          136 :   location_t locus = lexer.peek_token ()->get_locus ();
    3835          136 :   skip_token (STATIC_KW);
    3836              : 
    3837              :   // determine whether static item is mutable
    3838          136 :   bool is_mut = false;
    3839          272 :   if (lexer.peek_token ()->get_id () == MUT)
    3840              :     {
    3841           19 :       is_mut = true;
    3842           19 :       lexer.skip_token ();
    3843              :     }
    3844              : 
    3845          136 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    3846          136 :   if (ident_tok == nullptr)
    3847            1 :     return nullptr;
    3848              : 
    3849          270 :   Identifier ident{ident_tok};
    3850              : 
    3851          135 :   if (!skip_token (COLON))
    3852              :     {
    3853            1 :       skip_after_semicolon ();
    3854            1 :       return nullptr;
    3855              :     }
    3856              : 
    3857              :   // parse static item type (required)
    3858          134 :   std::unique_ptr<AST::Type> type = parse_type ();
    3859              : 
    3860          134 :   if (!skip_token (EQUAL))
    3861              :     {
    3862            0 :       skip_after_semicolon ();
    3863            0 :       return nullptr;
    3864              :     }
    3865              : 
    3866              :   // parse static item expression (required)
    3867          134 :   auto expr = parse_expr ();
    3868          134 :   if (!expr)
    3869            1 :     return nullptr;
    3870              : 
    3871          133 :   if (!skip_token (SEMICOLON))
    3872              :     {
    3873              :       // skip after somewhere
    3874            0 :       return nullptr;
    3875              :     }
    3876              : 
    3877              :   return std::unique_ptr<AST::StaticItem> (
    3878          266 :     new AST::StaticItem (std::move (ident), is_mut, std::move (type),
    3879          133 :                          std::move (expr.value ()), std::move (vis),
    3880          133 :                          std::move (outer_attrs), locus));
    3881          269 : }
    3882              : 
    3883              : // Parses a trait definition item, including unsafe ones.
    3884              : // also handles trait aliases
    3885              : template <typename ManagedTokenSource>
    3886              : std::unique_ptr<AST::VisItem>
    3887         4584 : Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
    3888              :                                          AST::AttrVec outer_attrs)
    3889              : {
    3890         4584 :   location_t locus = lexer.peek_token ()->get_locus ();
    3891         4584 :   bool is_unsafe = false;
    3892         4584 :   bool is_auto_trait = false;
    3893         4584 :   bool is_alias = false;
    3894              : 
    3895         9168 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    3896              :     {
    3897           85 :       is_unsafe = true;
    3898           85 :       lexer.skip_token ();
    3899              :     }
    3900              : 
    3901         9168 :   if (lexer.peek_token ()->get_id () == AUTO)
    3902              :     {
    3903           30 :       is_auto_trait = true;
    3904           30 :       lexer.skip_token ();
    3905              :     }
    3906              : 
    3907         4584 :   skip_token (TRAIT);
    3908              : 
    3909              :   // parse trait name
    3910         4584 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    3911         4584 :   if (ident_tok == nullptr)
    3912            0 :     return nullptr;
    3913              : 
    3914         9168 :   Identifier ident{ident_tok};
    3915              : 
    3916              :   // parse generic parameters (if they exist)
    3917         4584 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    3918              :     = parse_generic_params_in_angles ();
    3919              : 
    3920              :   // create placeholder type param bounds in case they don't exist
    3921         4584 :   std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
    3922              : 
    3923              :   // this might be a trait alias
    3924         9168 :   if (lexer.peek_token ()->get_id () == EQUAL)
    3925              :     {
    3926            2 :       lexer.skip_token ();
    3927              : 
    3928            2 :       if (is_auto_trait)
    3929            0 :         rust_error_at (locus, "trait aliases cannot be %<auto%>");
    3930            2 :       if (is_unsafe)
    3931            0 :         rust_error_at (locus, "trait aliases cannot be %<unsafe%>");
    3932              : 
    3933            2 :       type_param_bounds = parse_type_param_bounds (
    3934            0 :         [] (TokenId id) { return id == WHERE || id == SEMICOLON; });
    3935              : 
    3936            2 :       is_alias = true;
    3937              :     }
    3938              :   // otherwise, parse type param bounds (if they exist)
    3939         9164 :   else if (lexer.peek_token ()->get_id () == COLON)
    3940              :     {
    3941          671 :       lexer.skip_token ();
    3942              : 
    3943          671 :       type_param_bounds = parse_type_param_bounds (
    3944           95 :         [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
    3945              :       // type_param_bounds = parse_type_param_bounds ();
    3946              :     }
    3947              : 
    3948              :   // parse where clause (if it exists)
    3949         4584 :   AST::WhereClause where_clause = parse_where_clause ();
    3950              : 
    3951              :   // if this was a trait alias, finish up
    3952         4584 :   if (is_alias)
    3953              :     {
    3954            2 :       if (!skip_token (SEMICOLON))
    3955            0 :         return nullptr;
    3956              : 
    3957            2 :       return std::make_unique<AST::TraitAlias> (std::move (ident),
    3958              :                                                 std::move (generic_params),
    3959              :                                                 std::move (where_clause),
    3960              :                                                 std::move (type_param_bounds),
    3961              :                                                 std::move (vis),
    3962            2 :                                                 std::move (outer_attrs), locus);
    3963              :     }
    3964              : 
    3965         4582 :   if (!skip_token (LEFT_CURLY))
    3966              :     {
    3967            0 :       skip_after_end_block ();
    3968            0 :       return nullptr;
    3969              :     }
    3970              : 
    3971              :   // parse inner attrs (if they exist)
    3972         4582 :   AST::AttrVec inner_attrs = parse_inner_attributes ();
    3973              : 
    3974              :   // parse trait items
    3975         4582 :   std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
    3976              : 
    3977         4582 :   const_TokenPtr t = lexer.peek_token ();
    3978         8849 :   while (t->get_id () != RIGHT_CURLY)
    3979              :     {
    3980         4267 :       std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
    3981              : 
    3982         4267 :       if (trait_item == nullptr)
    3983              :         {
    3984            0 :           Error error (lexer.peek_token ()->get_locus (),
    3985              :                        "failed to parse trait item in trait");
    3986            0 :           add_error (std::move (error));
    3987              : 
    3988            0 :           return nullptr;
    3989            0 :         }
    3990         4267 :       trait_items.push_back (std::move (trait_item));
    3991              : 
    3992         4267 :       t = lexer.peek_token ();
    3993              :     }
    3994              : 
    3995         4582 :   if (!skip_token (RIGHT_CURLY))
    3996              :     {
    3997              :       // skip after something
    3998            0 :       return nullptr;
    3999              :     }
    4000              : 
    4001         4582 :   trait_items.shrink_to_fit ();
    4002         4582 :   return std::unique_ptr<AST::Trait> (
    4003         9164 :     new AST::Trait (std::move (ident), is_unsafe, is_auto_trait,
    4004              :                     std::move (generic_params), std::move (type_param_bounds),
    4005              :                     std::move (where_clause), std::move (trait_items),
    4006              :                     std::move (vis), std::move (outer_attrs),
    4007         4582 :                     std::move (inner_attrs), locus));
    4008         9166 : }
    4009              : 
    4010              : // Parses a trait item used inside traits (not trait, the Item).
    4011              : template <typename ManagedTokenSource>
    4012              : std::unique_ptr<AST::AssociatedItem>
    4013         4269 : Parser<ManagedTokenSource>::parse_trait_item ()
    4014              : {
    4015              :   // parse outer attributes (if they exist)
    4016         4269 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4017              : 
    4018         4269 :   auto vis_res = parse_visibility ();
    4019         4269 :   if (!vis_res)
    4020            0 :     return nullptr;
    4021              : 
    4022         4269 :   auto vis = vis_res.value ();
    4023              : 
    4024              :   // lookahead to determine what type of trait item to parse
    4025         4269 :   const_TokenPtr tok = lexer.peek_token ();
    4026         4269 :   switch (tok->get_id ())
    4027              :     {
    4028            0 :     case SUPER:
    4029              :     case SELF:
    4030              :     case CRATE:
    4031              :     case DOLLAR_SIGN:
    4032              :       // these seem to be SimplePath tokens, so this is a macro invocation
    4033              :       // semi
    4034            0 :       return parse_macro_invocation_semi (std::move (outer_attrs));
    4035            1 :     case IDENTIFIER:
    4036            2 :       if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
    4037            0 :         return parse_function (std::move (vis), std::move (outer_attrs));
    4038              :       else
    4039            2 :         return parse_macro_invocation_semi (std::move (outer_attrs));
    4040          911 :     case TYPE:
    4041          911 :       return parse_trait_type (std::move (outer_attrs), vis);
    4042           62 :     case CONST:
    4043              :       // disambiguate with function qualifier
    4044          124 :       if (lexer.peek_token (1)->get_id () == IDENTIFIER)
    4045              :         {
    4046          122 :           return parse_trait_const (std::move (outer_attrs));
    4047              :         }
    4048              :       // else, fallthrough to function
    4049              :       // TODO: find out how to disable gcc "implicit fallthrough" error
    4050              :       gcc_fallthrough ();
    4051              :     case ASYNC:
    4052              :     case UNSAFE:
    4053              :     case EXTERN_KW:
    4054              :     case FN_KW:
    4055         6592 :       return parse_function (std::move (vis), std::move (outer_attrs));
    4056              :     default:
    4057              :       break;
    4058              :     }
    4059            0 :   add_error (Error (tok->get_locus (),
    4060              :                     "unrecognised token %qs for item in trait",
    4061              :                     tok->get_token_description ()));
    4062              :   // skip?
    4063            0 :   return nullptr;
    4064         8538 : }
    4065              : 
    4066              : // Parse a typedef trait item.
    4067              : template <typename ManagedTokenSource>
    4068              : std::unique_ptr<AST::TraitItemType>
    4069          911 : Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
    4070              :                                               AST::Visibility vis)
    4071              : {
    4072          911 :   location_t locus = lexer.peek_token ()->get_locus ();
    4073          911 :   skip_token (TYPE);
    4074              : 
    4075          911 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4076          911 :   if (ident_tok == nullptr)
    4077            0 :     return nullptr;
    4078              : 
    4079         1822 :   Identifier ident{ident_tok};
    4080              : 
    4081              :   // Parse optional generic parameters for GATs (Generic Associated Types)
    4082          911 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
    4083         1822 :   if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
    4084              :     {
    4085           17 :       generic_params = parse_generic_params_in_angles ();
    4086              :     }
    4087              : 
    4088          911 :   std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    4089              : 
    4090              :   // parse optional colon
    4091         1822 :   if (lexer.peek_token ()->get_id () == COLON)
    4092              :     {
    4093           69 :       lexer.skip_token ();
    4094              : 
    4095              :       // parse optional type param bounds
    4096              :       bounds
    4097           69 :         = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
    4098              :       // bounds = parse_type_param_bounds ();
    4099              :     }
    4100              : 
    4101          911 :   if (!skip_token (SEMICOLON))
    4102              :     {
    4103              :       // skip?
    4104            0 :       return nullptr;
    4105              :     }
    4106              : 
    4107              :   return std::unique_ptr<AST::TraitItemType> (
    4108          911 :     new AST::TraitItemType (std::move (ident), std::move (generic_params),
    4109              :                             std::move (bounds), std::move (outer_attrs), vis,
    4110          911 :                             locus));
    4111          911 : }
    4112              : 
    4113              : // Parses a constant trait item.
    4114              : template <typename ManagedTokenSource>
    4115              : std::unique_ptr<AST::ConstantItem>
    4116           61 : Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
    4117              : {
    4118           61 :   location_t locus = lexer.peek_token ()->get_locus ();
    4119           61 :   skip_token (CONST);
    4120              : 
    4121              :   // parse constant item name
    4122           61 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4123           61 :   if (ident_tok == nullptr)
    4124            0 :     return nullptr;
    4125              : 
    4126          122 :   Identifier ident{ident_tok};
    4127              : 
    4128           61 :   if (!skip_token (COLON))
    4129              :     {
    4130            0 :       skip_after_semicolon ();
    4131            0 :       return nullptr;
    4132              :     }
    4133              : 
    4134              :   // parse constant trait item type
    4135           61 :   std::unique_ptr<AST::Type> type = parse_type ();
    4136              : 
    4137              :   // parse constant trait body expression, if it exists
    4138           61 :   std::unique_ptr<AST::Expr> const_body = nullptr;
    4139          122 :   if (lexer.peek_token ()->get_id () == EQUAL)
    4140              :     {
    4141           12 :       lexer.skip_token ();
    4142              : 
    4143              :       // expression must exist, so parse it
    4144           12 :       auto expr = parse_expr ();
    4145           12 :       if (!expr)
    4146            0 :         return nullptr;
    4147           12 :       const_body = std::move (expr.value ());
    4148           12 :     }
    4149              : 
    4150           61 :   if (!skip_token (SEMICOLON))
    4151              :     {
    4152              :       // skip after something?
    4153            0 :       return nullptr;
    4154              :     }
    4155              : 
    4156          183 :   return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem (
    4157          122 :     std::move (ident), AST::Visibility::create_private (), std::move (type),
    4158           61 :     std::move (const_body), std::move (outer_attrs), locus));
    4159          122 : }
    4160              : 
    4161              : /* Parses a struct "impl" item (both inherent impl and trait impl can be
    4162              :  * parsed here), */
    4163              : template <typename ManagedTokenSource>
    4164              : std::unique_ptr<AST::Impl>
    4165        13095 : Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
    4166              :                                         AST::AttrVec outer_attrs)
    4167              : {
    4168              :   /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
    4169              :    * must be a trait impl. However, this isn't enough for full disambiguation,
    4170              :    * so don't branch here. */
    4171        13095 :   location_t locus = lexer.peek_token ()->get_locus ();
    4172        13095 :   bool is_unsafe = false;
    4173        26190 :   if (lexer.peek_token ()->get_id () == UNSAFE)
    4174              :     {
    4175          297 :       lexer.skip_token ();
    4176          297 :       is_unsafe = true;
    4177              :     }
    4178              : 
    4179        13095 :   if (!skip_token (IMPL))
    4180              :     {
    4181            0 :       skip_after_next_block ();
    4182            0 :       return nullptr;
    4183              :     }
    4184              : 
    4185              :   // parse generic params (shared by trait and inherent impls)
    4186        13095 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    4187              :     = parse_generic_params_in_angles ();
    4188              : 
    4189              :   // Again, trait impl-only feature, but optional one, so can be used for
    4190              :   // branching yet.
    4191        13095 :   bool has_exclam = false;
    4192        26190 :   if (lexer.peek_token ()->get_id () == EXCLAM)
    4193              :     {
    4194           26 :       lexer.skip_token ();
    4195           26 :       has_exclam = true;
    4196              :     }
    4197              : 
    4198              :   /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
    4199              :    * doesn't parse too much and not work. */
    4200        13095 :   AST::TypePath type_path = parse_type_path ();
    4201        25951 :   if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
    4202              :     {
    4203              :       /* cannot parse type path (or not for token next, at least), so must be
    4204              :        * inherent impl */
    4205              : 
    4206              :       // hacky conversion of TypePath stack object to Type pointer
    4207         1568 :       std::unique_ptr<AST::Type> type = nullptr;
    4208         1568 :       if (!type_path.is_error ())
    4209         1329 :         type = std::unique_ptr<AST::TypePath> (
    4210         1329 :           new AST::TypePath (std::move (type_path)));
    4211              :       else
    4212          239 :         type = parse_type ();
    4213              : 
    4214              :       // Type is required, so error if null
    4215         1568 :       if (type == nullptr)
    4216              :         {
    4217            1 :           Error error (lexer.peek_token ()->get_locus (),
    4218              :                        "could not parse type in inherent impl");
    4219            1 :           add_error (std::move (error));
    4220              : 
    4221            1 :           skip_after_next_block ();
    4222            1 :           return nullptr;
    4223            1 :         }
    4224              : 
    4225              :       // parse optional where clause
    4226         1567 :       AST::WhereClause where_clause = parse_where_clause ();
    4227              : 
    4228         1567 :       if (!skip_token (LEFT_CURLY))
    4229              :         {
    4230              :           // TODO: does this still skip properly?
    4231            0 :           skip_after_end_block ();
    4232            0 :           return nullptr;
    4233              :         }
    4234              : 
    4235              :       // parse inner attributes (optional)
    4236         1567 :       AST::AttrVec inner_attrs = parse_inner_attributes ();
    4237              : 
    4238              :       // parse inherent impl items
    4239         1567 :       std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
    4240              : 
    4241         1567 :       const_TokenPtr t = lexer.peek_token ();
    4242         6790 :       while (t->get_id () != RIGHT_CURLY)
    4243              :         {
    4244         5233 :           std::unique_ptr<AST::AssociatedItem> impl_item
    4245              :             = parse_inherent_impl_item ();
    4246              : 
    4247         5233 :           if (impl_item == nullptr)
    4248              :             {
    4249           10 :               Error error (
    4250           10 :                 lexer.peek_token ()->get_locus (),
    4251              :                 "failed to parse inherent impl item in inherent impl");
    4252           10 :               add_error (std::move (error));
    4253              : 
    4254           10 :               return nullptr;
    4255           10 :             }
    4256              : 
    4257         5223 :           impl_items.push_back (std::move (impl_item));
    4258              : 
    4259         5223 :           t = lexer.peek_token ();
    4260              :         }
    4261              : 
    4262         1557 :       if (!skip_token (RIGHT_CURLY))
    4263              :         {
    4264              :           // skip somewhere
    4265            0 :           return nullptr;
    4266              :         }
    4267              : 
    4268              :       // DEBUG
    4269         1557 :       rust_debug ("successfully parsed inherent impl");
    4270              : 
    4271         1557 :       impl_items.shrink_to_fit ();
    4272              : 
    4273         1557 :       return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
    4274              :         std::move (impl_items), std::move (generic_params), std::move (type),
    4275              :         std::move (where_clause), std::move (vis), std::move (inner_attrs),
    4276         1557 :         std::move (outer_attrs), locus));
    4277         1568 :     }
    4278              :   else
    4279              :     {
    4280              :       // type path must both be valid and next token is for, so trait impl
    4281        11527 :       if (!skip_token (FOR))
    4282              :         {
    4283            0 :           skip_after_next_block ();
    4284            0 :           return nullptr;
    4285              :         }
    4286              : 
    4287              :       // parse type
    4288        11527 :       std::unique_ptr<AST::Type> type = parse_type ();
    4289              :       // ensure type is included as it is required
    4290        11527 :       if (type == nullptr)
    4291              :         {
    4292            0 :           Error error (lexer.peek_token ()->get_locus (),
    4293              :                        "could not parse type in trait impl");
    4294            0 :           add_error (std::move (error));
    4295              : 
    4296            0 :           skip_after_next_block ();
    4297            0 :           return nullptr;
    4298            0 :         }
    4299              : 
    4300              :       // parse optional where clause
    4301        11527 :       AST::WhereClause where_clause = parse_where_clause ();
    4302              : 
    4303        11527 :       if (!skip_token (LEFT_CURLY))
    4304              :         {
    4305              :           // TODO: does this still skip properly?
    4306            0 :           skip_after_end_block ();
    4307            0 :           return nullptr;
    4308              :         }
    4309              : 
    4310              :       // parse inner attributes (optional)
    4311        11527 :       AST::AttrVec inner_attrs = parse_inner_attributes ();
    4312              : 
    4313              :       // parse trait impl items
    4314        11527 :       std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
    4315              : 
    4316        11527 :       const_TokenPtr t = lexer.peek_token ();
    4317        27343 :       while (t->get_id () != RIGHT_CURLY)
    4318              :         {
    4319        15819 :           std::unique_ptr<AST::AssociatedItem> impl_item
    4320              :             = parse_trait_impl_item ();
    4321              : 
    4322        15819 :           if (impl_item == nullptr)
    4323              :             {
    4324            3 :               Error error (lexer.peek_token ()->get_locus (),
    4325              :                            "failed to parse trait impl item in trait impl");
    4326            3 :               add_error (std::move (error));
    4327              : 
    4328            3 :               return nullptr;
    4329            3 :             }
    4330              : 
    4331        15816 :           impl_items.push_back (std::move (impl_item));
    4332              : 
    4333        15816 :           t = lexer.peek_token ();
    4334              : 
    4335              :           // DEBUG
    4336        15816 :           rust_debug ("successfully parsed a trait impl item");
    4337              :         }
    4338              :       // DEBUG
    4339        11524 :       rust_debug ("successfully finished trait impl items");
    4340              : 
    4341        11524 :       if (!skip_token (RIGHT_CURLY))
    4342              :         {
    4343              :           // skip somewhere
    4344            0 :           return nullptr;
    4345              :         }
    4346              : 
    4347              :       // DEBUG
    4348        11524 :       rust_debug ("successfully parsed trait impl");
    4349              : 
    4350        11524 :       impl_items.shrink_to_fit ();
    4351              : 
    4352        11524 :       return std::unique_ptr<AST::TraitImpl> (
    4353        23048 :         new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
    4354              :                             std::move (impl_items), std::move (generic_params),
    4355              :                             std::move (type), std::move (where_clause),
    4356              :                             std::move (vis), std::move (inner_attrs),
    4357        11524 :                             std::move (outer_attrs), locus));
    4358        11527 :     }
    4359        13095 : }
    4360              : 
    4361              : // Parses a single inherent impl item (item inside an inherent impl block).
    4362              : template <typename ManagedTokenSource>
    4363              : std::unique_ptr<AST::AssociatedItem>
    4364         7239 : Parser<ManagedTokenSource>::parse_inherent_impl_item ()
    4365              : {
    4366              :   // parse outer attributes (if they exist)
    4367         7239 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4368              : 
    4369              :   // TODO: cleanup - currently an unreadable mess
    4370              : 
    4371              :   // branch on next token:
    4372         7239 :   const_TokenPtr t = lexer.peek_token ();
    4373         7239 :   switch (t->get_id ())
    4374              :     {
    4375         1091 :     case IDENTIFIER:
    4376              :       // FIXME: Arthur: Do we need to some lookahead here?
    4377         2182 :       return parse_macro_invocation_semi (outer_attrs);
    4378         5262 :     case SUPER:
    4379              :     case SELF:
    4380              :     case CRATE:
    4381              :     case PUB:
    4382              :       {
    4383              :         // visibility, so not a macro invocation semi - must be constant,
    4384              :         // function, or method
    4385         5262 :         auto vis_res = parse_visibility ();
    4386         5262 :         if (!vis_res)
    4387            0 :           return nullptr;
    4388         5262 :         auto vis = vis_res.value ();
    4389              : 
    4390              :         // TODO: is a recursive call to parse_inherent_impl_item better?
    4391        10524 :         switch (lexer.peek_token ()->get_id ())
    4392              :           {
    4393         2900 :           case EXTERN_KW:
    4394              :           case UNSAFE:
    4395              :           case FN_KW:
    4396              :             // function or method
    4397         5800 :             return parse_inherent_impl_function_or_method (std::move (vis),
    4398              :                                                            std::move (
    4399         2900 :                                                              outer_attrs));
    4400         2362 :           case CONST:
    4401              :             // lookahead to resolve production - could be function/method or
    4402              :             // const item
    4403         2362 :             t = lexer.peek_token (1);
    4404              : 
    4405         2362 :             switch (t->get_id ())
    4406              :               {
    4407          102 :               case IDENTIFIER:
    4408              :               case UNDERSCORE:
    4409          204 :                 return parse_const_item (std::move (vis),
    4410          102 :                                          std::move (outer_attrs));
    4411         2260 :               case UNSAFE:
    4412              :               case EXTERN_KW:
    4413              :               case FN_KW:
    4414         4520 :                 return parse_inherent_impl_function_or_method (std::move (vis),
    4415              :                                                                std::move (
    4416         2260 :                                                                  outer_attrs));
    4417            0 :               default:
    4418            0 :                 add_error (Error (t->get_locus (),
    4419              :                                   "unexpected token %qs in some sort of const "
    4420              :                                   "item in inherent impl",
    4421              :                                   t->get_token_description ()));
    4422              : 
    4423            0 :                 lexer.skip_token (1); // TODO: is this right thing to do?
    4424            0 :                 return nullptr;
    4425              :               }
    4426            0 :           default:
    4427            0 :             add_error (
    4428            0 :               Error (t->get_locus (),
    4429              :                      "unrecognised token %qs for item in inherent impl",
    4430              :                      t->get_token_description ()));
    4431              :             // skip?
    4432            0 :             return nullptr;
    4433              :           }
    4434        10524 :       }
    4435          830 :     case ASYNC:
    4436              :     case EXTERN_KW:
    4437              :     case UNSAFE:
    4438              :     case FN_KW:
    4439              :       // function or method
    4440          830 :       return parse_inherent_impl_function_or_method (
    4441          830 :         AST::Visibility::create_private (), std::move (outer_attrs));
    4442           56 :     case CONST:
    4443              :       /* lookahead to resolve production - could be function/method or const
    4444              :        * item */
    4445           56 :       t = lexer.peek_token (1);
    4446              : 
    4447           56 :       switch (t->get_id ())
    4448              :         {
    4449           43 :         case IDENTIFIER:
    4450              :         case UNDERSCORE:
    4451           86 :           return parse_const_item (AST::Visibility::create_private (),
    4452           43 :                                    std::move (outer_attrs));
    4453           13 :         case UNSAFE:
    4454              :         case EXTERN_KW:
    4455              :         case FN_KW:
    4456           13 :           return parse_inherent_impl_function_or_method (
    4457           13 :             AST::Visibility::create_private (), std::move (outer_attrs));
    4458            0 :         default:
    4459            0 :           add_error (Error (t->get_locus (),
    4460              :                             "unexpected token %qs in some sort of const item "
    4461              :                             "in inherent impl",
    4462              :                             t->get_token_description ()));
    4463              : 
    4464            0 :           lexer.skip_token (1); // TODO: is this right thing to do?
    4465            0 :           return nullptr;
    4466              :         }
    4467              :       rust_unreachable ();
    4468            0 :     default:
    4469            0 :       add_error (Error (t->get_locus (),
    4470              :                         "unrecognised token %qs for item in inherent impl",
    4471              :                         t->get_token_description ()));
    4472              : 
    4473              :       // skip?
    4474            0 :       return nullptr;
    4475              :     }
    4476         7239 : }
    4477              : 
    4478              : /* For internal use only by parse_inherent_impl_item() - splits giant method
    4479              :  * into smaller ones and prevents duplication of logic. Strictly, this parses
    4480              :  * a function or method item inside an inherent impl item block. */
    4481              : // TODO: make this a templated function with "return type" as type param -
    4482              : // InherentImplItem is this specialisation of the template while TraitImplItem
    4483              : // will be the other.
    4484              : template <typename ManagedTokenSource>
    4485              : std::unique_ptr<AST::AssociatedItem>
    4486         6003 : Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
    4487              :   AST::Visibility vis, AST::AttrVec outer_attrs)
    4488              : {
    4489         6003 :   location_t locus = lexer.peek_token ()->get_locus ();
    4490              :   // parse function or method qualifiers
    4491         6003 :   auto qualifiers = parse_function_qualifiers ();
    4492         6003 :   if (!qualifiers)
    4493            0 :     return nullptr;
    4494              : 
    4495         6003 :   skip_token (FN_KW);
    4496              : 
    4497              :   // parse function or method name
    4498         6003 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4499         6003 :   if (ident_tok == nullptr)
    4500            7 :     return nullptr;
    4501              : 
    4502        11992 :   Identifier ident{ident_tok};
    4503              : 
    4504              :   // parse generic params
    4505         5996 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    4506              :     = parse_generic_params_in_angles ();
    4507              : 
    4508         5996 :   if (!skip_token (LEFT_PAREN))
    4509              :     {
    4510              :       // skip after somewhere?
    4511            0 :       return nullptr;
    4512              :     }
    4513              : 
    4514              :   // now for function vs method disambiguation - method has opening "self"
    4515              :   // param
    4516         5996 :   auto initial_param = parse_self_param ();
    4517              : 
    4518         5996 :   if (!initial_param.has_value ()
    4519         5996 :       && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
    4520            3 :     return nullptr;
    4521              : 
    4522              :   /* FIXME: ensure that self param doesn't accidently consume tokens for a
    4523              :    * function one idea is to lookahead up to 4 tokens to see whether self is
    4524              :    * one of them */
    4525         5993 :   bool is_method = false;
    4526         5993 :   if (initial_param.has_value ())
    4527              :     {
    4528         4436 :       if ((*initial_param)->is_self ())
    4529              :         is_method = true;
    4530              : 
    4531              :       /* skip comma so function and method regular params can be parsed in
    4532              :        * same way */
    4533         8872 :       if (lexer.peek_token ()->get_id () == COMMA)
    4534         2593 :         lexer.skip_token ();
    4535              :     }
    4536              : 
    4537              :   // parse trait function params
    4538         5993 :   std::vector<std::unique_ptr<AST::Param>> function_params
    4539              :     = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
    4540              : 
    4541         5993 :   if (initial_param.has_value ())
    4542         4436 :     function_params.insert (function_params.begin (),
    4543         4436 :                             std::move (*initial_param));
    4544              : 
    4545         5993 :   if (!skip_token (RIGHT_PAREN))
    4546              :     {
    4547            0 :       skip_after_end_block ();
    4548            0 :       return nullptr;
    4549              :     }
    4550              : 
    4551              :   // parse return type (optional)
    4552         5993 :   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
    4553              : 
    4554              :   // parse where clause (optional)
    4555         5993 :   AST::WhereClause where_clause = parse_where_clause ();
    4556              : 
    4557         5993 :   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
    4558        11986 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    4559            2 :     lexer.skip_token ();
    4560              :   else
    4561              :     {
    4562         5991 :       auto result = parse_block_expr ();
    4563              : 
    4564         5991 :       if (!result)
    4565              :         {
    4566            0 :           Error error (
    4567            0 :             lexer.peek_token ()->get_locus (),
    4568              :             "could not parse definition in inherent impl %s definition",
    4569              :             is_method ? "method" : "function");
    4570            0 :           add_error (std::move (error));
    4571              : 
    4572            0 :           skip_after_end_block ();
    4573            0 :           return nullptr;
    4574            0 :         }
    4575         5991 :       body = std::move (result.value ());
    4576         5991 :     }
    4577              : 
    4578         5993 :   return std::unique_ptr<AST::Function> (
    4579        23970 :     new AST::Function (std::move (ident), std::move (qualifiers.value ()),
    4580              :                        std::move (generic_params), std::move (function_params),
    4581              :                        std::move (return_type), std::move (where_clause),
    4582              :                        std::move (body), std::move (vis),
    4583         5993 :                        std::move (outer_attrs), locus));
    4584        17992 : }
    4585              : 
    4586              : // Parses a single trait impl item (item inside a trait impl block).
    4587              : template <typename ManagedTokenSource>
    4588              : std::unique_ptr<AST::AssociatedItem>
    4589        16072 : Parser<ManagedTokenSource>::parse_trait_impl_item ()
    4590              : {
    4591              :   // parse outer attributes (if they exist)
    4592        16072 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4593              : 
    4594        16072 :   auto vis_res = parse_visibility ();
    4595        16072 :   if (!vis_res)
    4596            0 :     return nullptr;
    4597        16072 :   auto visibility = vis_res.value ();
    4598              : 
    4599              :   // branch on next token:
    4600        16072 :   const_TokenPtr t = lexer.peek_token ();
    4601        16072 :   switch (t->get_id ())
    4602              :     {
    4603            0 :     case SUPER:
    4604              :     case SELF:
    4605              :     case CRATE:
    4606              :     case DOLLAR_SIGN:
    4607              :       // these seem to be SimplePath tokens, so this is a macro invocation
    4608              :       // semi
    4609            0 :       return parse_macro_invocation_semi (std::move (outer_attrs));
    4610          147 :     case IDENTIFIER:
    4611          294 :       if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
    4612          148 :         return parse_trait_impl_function_or_method (visibility,
    4613           74 :                                                     std::move (outer_attrs));
    4614              :       else
    4615          146 :         return parse_macro_invocation_semi (std::move (outer_attrs));
    4616         4255 :     case TYPE:
    4617         8510 :       return parse_type_alias (visibility, std::move (outer_attrs));
    4618        11593 :     case EXTERN_KW:
    4619              :     case UNSAFE:
    4620              :     case FN_KW:
    4621              :       // function or method
    4622        23186 :       return parse_trait_impl_function_or_method (visibility,
    4623        11593 :                                                   std::move (outer_attrs));
    4624            1 :     case ASYNC:
    4625            2 :       return parse_async_item (visibility, std::move (outer_attrs));
    4626           76 :     case CONST:
    4627              :       // lookahead to resolve production - could be function/method or const
    4628              :       // item
    4629           76 :       t = lexer.peek_token (1);
    4630              : 
    4631           76 :       switch (t->get_id ())
    4632              :         {
    4633           75 :         case IDENTIFIER:
    4634              :         case UNDERSCORE:
    4635          150 :           return parse_const_item (visibility, std::move (outer_attrs));
    4636            1 :         case UNSAFE:
    4637              :         case EXTERN_KW:
    4638              :         case FN_KW:
    4639            2 :           return parse_trait_impl_function_or_method (visibility,
    4640            1 :                                                       std::move (outer_attrs));
    4641            0 :         default:
    4642            0 :           add_error (Error (
    4643              :             t->get_locus (),
    4644              :             "unexpected token %qs in some sort of const item in trait impl",
    4645              :             t->get_token_description ()));
    4646              : 
    4647            0 :           lexer.skip_token (1); // TODO: is this right thing to do?
    4648            0 :           return nullptr;
    4649              :         }
    4650              :       rust_unreachable ();
    4651              :     default:
    4652              :       break;
    4653              :     }
    4654            0 :   add_error (Error (t->get_locus (),
    4655              :                     "unrecognised token %qs for item in trait impl",
    4656              :                     t->get_token_description ()));
    4657              : 
    4658              :   // skip?
    4659            0 :   return nullptr;
    4660        32144 : }
    4661              : 
    4662              : /* For internal use only by parse_trait_impl_item() - splits giant method into
    4663              :  * smaller ones and prevents duplication of logic. Strictly, this parses a
    4664              :  * function or method item inside a trait impl item block. */
    4665              : template <typename ManagedTokenSource>
    4666              : std::unique_ptr<AST::AssociatedItem>
    4667        11668 : Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
    4668              :   AST::Visibility vis, AST::AttrVec outer_attrs)
    4669              : {
    4670              :   // this shares virtually all logic with
    4671              :   // parse_inherent_impl_function_or_method
    4672              :   // - template?
    4673        11668 :   location_t locus = lexer.peek_token ()->get_locus ();
    4674              : 
    4675              :   // parse function or method qualifiers
    4676        11668 :   auto qualifiers = parse_function_qualifiers ();
    4677        11668 :   if (!qualifiers)
    4678            2 :     return nullptr;
    4679              : 
    4680        11666 :   skip_token (FN_KW);
    4681              : 
    4682              :   // parse function or method name
    4683        11666 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4684        11666 :   if (ident_tok == nullptr)
    4685              :     {
    4686            0 :       return nullptr;
    4687              :     }
    4688        23332 :   Identifier ident{ident_tok};
    4689              : 
    4690              :   // DEBUG:
    4691        11666 :   rust_debug (
    4692              :     "about to start parsing generic params in trait impl function or method");
    4693              : 
    4694              :   // parse generic params
    4695        11666 :   std::vector<std::unique_ptr<AST::GenericParam>> generic_params
    4696              :     = parse_generic_params_in_angles ();
    4697              : 
    4698              :   // DEBUG:
    4699        11666 :   rust_debug (
    4700              :     "finished parsing generic params in trait impl function or method");
    4701              : 
    4702        11666 :   if (!skip_token (LEFT_PAREN))
    4703              :     {
    4704              :       // skip after somewhere?
    4705            0 :       return nullptr;
    4706              :     }
    4707              : 
    4708              :   // now for function vs method disambiguation - method has opening "self"
    4709              :   // param
    4710        11666 :   auto initial_param = parse_self_param ();
    4711              : 
    4712        11666 :   if (!initial_param.has_value ()
    4713        11666 :       && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
    4714            0 :     return nullptr;
    4715              : 
    4716              :   // FIXME: ensure that self param doesn't accidently consume tokens for a
    4717              :   // function
    4718        11666 :   bool is_method = false;
    4719        11666 :   if (initial_param.has_value ())
    4720              :     {
    4721        10507 :       if ((*initial_param)->is_self ())
    4722              :         is_method = true;
    4723              : 
    4724              :       // skip comma so function and method regular params can be parsed in
    4725              :       // same way
    4726        21014 :       if (lexer.peek_token ()->get_id () == COMMA)
    4727              :         {
    4728         7438 :           lexer.skip_token ();
    4729              :         }
    4730              : 
    4731              :       // DEBUG
    4732        10507 :       rust_debug ("successfully parsed self param in method trait impl item");
    4733              :     }
    4734              : 
    4735              :   // DEBUG
    4736        11666 :   rust_debug (
    4737              :     "started to parse function params in function or method trait impl item");
    4738              : 
    4739              :   // parse trait function params (only if next token isn't right paren)
    4740        11666 :   std::vector<std::unique_ptr<AST::Param>> function_params;
    4741        23332 :   if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
    4742              :     {
    4743              :       function_params
    4744         8355 :         = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
    4745              : 
    4746         8355 :       if (function_params.empty ())
    4747              :         {
    4748            0 :           Error error (
    4749            0 :             lexer.peek_token ()->get_locus (),
    4750              :             "failed to parse function params in trait impl %s definition",
    4751              :             is_method ? "method" : "function");
    4752            0 :           add_error (std::move (error));
    4753              : 
    4754            0 :           skip_after_next_block ();
    4755            0 :           return nullptr;
    4756            0 :         }
    4757              :     }
    4758              : 
    4759        11666 :   if (initial_param.has_value ())
    4760        10507 :     function_params.insert (function_params.begin (),
    4761        10507 :                             std::move (*initial_param));
    4762              : 
    4763              :   // DEBUG
    4764        11666 :   rust_debug ("successfully parsed function params in function or method "
    4765              :               "trait impl item");
    4766              : 
    4767        11666 :   if (!skip_token (RIGHT_PAREN))
    4768              :     {
    4769            0 :       skip_after_next_block ();
    4770            0 :       return nullptr;
    4771              :     }
    4772              : 
    4773              :   // parse return type (optional)
    4774        11666 :   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
    4775              : 
    4776              :   // DEBUG
    4777        11666 :   rust_debug (
    4778              :     "successfully parsed return type in function or method trait impl item");
    4779              : 
    4780              :   // parse where clause (optional)
    4781        11666 :   AST::WhereClause where_clause = parse_where_clause ();
    4782              : 
    4783              :   // DEBUG
    4784        11666 :   rust_debug (
    4785              :     "successfully parsed where clause in function or method trait impl item");
    4786              : 
    4787              :   // parse function definition (in block) - semicolon not allowed
    4788        11666 :   tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
    4789              : 
    4790        23332 :   if (lexer.peek_token ()->get_id () == SEMICOLON)
    4791            1 :     lexer.skip_token ();
    4792              :   else
    4793              :     {
    4794        11665 :       auto result = parse_block_expr ();
    4795        11665 :       if (!result)
    4796              :         {
    4797            1 :           Error error (lexer.peek_token ()->get_locus (),
    4798              :                        "could not parse definition in trait impl %s definition",
    4799              :                        is_method ? "method" : "function");
    4800            1 :           add_error (std::move (error));
    4801              : 
    4802            1 :           skip_after_end_block ();
    4803            1 :           return nullptr;
    4804            1 :         }
    4805        11664 :       body = std::move (result.value ());
    4806        11665 :     }
    4807              : 
    4808        11665 :   return std::unique_ptr<AST::Function> (
    4809        46659 :     new AST::Function (std::move (ident), std::move (qualifiers.value ()),
    4810              :                        std::move (generic_params), std::move (function_params),
    4811              :                        std::move (return_type), std::move (where_clause),
    4812              :                        std::move (body), std::move (vis),
    4813        11665 :                        std::move (outer_attrs), locus));
    4814        34998 : }
    4815              : 
    4816              : // Parses an extern block of declarations.
    4817              : template <typename ManagedTokenSource>
    4818              : std::unique_ptr<AST::ExternBlock>
    4819         1787 : Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
    4820              :                                                 AST::AttrVec outer_attrs)
    4821              : {
    4822         1787 :   location_t locus = lexer.peek_token ()->get_locus ();
    4823         1787 :   skip_token (EXTERN_KW);
    4824              : 
    4825              :   // detect optional abi name
    4826         1787 :   std::string abi;
    4827         1787 :   const_TokenPtr next_tok = lexer.peek_token ();
    4828         1787 :   if (next_tok->get_id () == STRING_LITERAL)
    4829              :     {
    4830         1786 :       lexer.skip_token ();
    4831         1786 :       abi = next_tok->get_str ();
    4832              :     }
    4833              : 
    4834         1787 :   if (!skip_token (LEFT_CURLY))
    4835              :     {
    4836            0 :       skip_after_end_block ();
    4837            0 :       return nullptr;
    4838              :     }
    4839              : 
    4840         1787 :   AST::AttrVec inner_attrs = parse_inner_attributes ();
    4841              : 
    4842              :   // parse declarations inside extern block
    4843         1787 :   std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
    4844              : 
    4845         1787 :   const_TokenPtr t = lexer.peek_token ();
    4846         5341 :   while (t->get_id () != RIGHT_CURLY)
    4847              :     {
    4848         3555 :       std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
    4849              : 
    4850         3555 :       if (extern_item == nullptr)
    4851              :         {
    4852            1 :           Error error (t->get_locus (),
    4853              :                        "failed to parse external item despite not reaching "
    4854              :                        "end of extern block");
    4855            1 :           add_error (std::move (error));
    4856              : 
    4857            1 :           return nullptr;
    4858            1 :         }
    4859              : 
    4860         3554 :       extern_items.push_back (std::move (extern_item));
    4861              : 
    4862         3554 :       t = lexer.peek_token ();
    4863              :     }
    4864              : 
    4865         1786 :   if (!skip_token (RIGHT_CURLY))
    4866              :     {
    4867              :       // skip somewhere
    4868            0 :       return nullptr;
    4869              :     }
    4870              : 
    4871         1786 :   extern_items.shrink_to_fit ();
    4872              : 
    4873              :   return std::unique_ptr<AST::ExternBlock> (
    4874         1786 :     new AST::ExternBlock (std::move (abi), std::move (extern_items),
    4875              :                           std::move (vis), std::move (inner_attrs),
    4876         1786 :                           std::move (outer_attrs), locus));
    4877         3574 : }
    4878              : 
    4879              : // Parses a single extern block item (static or function declaration).
    4880              : template <typename ManagedTokenSource>
    4881              : std::unique_ptr<AST::ExternalItem>
    4882         3558 : Parser<ManagedTokenSource>::parse_external_item ()
    4883              : {
    4884              :   // parse optional outer attributes
    4885         3558 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4886              : 
    4887         3558 :   location_t locus = lexer.peek_token ()->get_locus ();
    4888              : 
    4889              :   // parse optional visibility
    4890         3558 :   auto vis_res = parse_visibility ();
    4891         3558 :   if (!vis_res)
    4892            0 :     return nullptr;
    4893         3558 :   auto vis = vis_res.value ();
    4894              : 
    4895         3558 :   const_TokenPtr t = lexer.peek_token ();
    4896         3558 :   switch (t->get_id ())
    4897              :     {
    4898            2 :     case IDENTIFIER:
    4899            4 :       return parse_macro_invocation_semi (outer_attrs);
    4900            1 :     case STATIC_KW:
    4901              :       {
    4902              :         // parse extern static item
    4903            1 :         lexer.skip_token ();
    4904              : 
    4905              :         // parse mut (optional)
    4906            1 :         bool has_mut = false;
    4907            2 :         if (lexer.peek_token ()->get_id () == MUT)
    4908              :           {
    4909            0 :             lexer.skip_token ();
    4910            0 :             has_mut = true;
    4911              :           }
    4912              : 
    4913              :         // parse identifier
    4914            1 :         const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    4915            1 :         if (ident_tok == nullptr)
    4916              :           {
    4917            0 :             skip_after_semicolon ();
    4918            0 :             return nullptr;
    4919              :           }
    4920            2 :         Identifier ident{ident_tok};
    4921              : 
    4922            1 :         if (!skip_token (COLON))
    4923              :           {
    4924            0 :             skip_after_semicolon ();
    4925            0 :             return nullptr;
    4926              :           }
    4927              : 
    4928              :         // parse type (required)
    4929            1 :         std::unique_ptr<AST::Type> type = parse_type ();
    4930            1 :         if (type == nullptr)
    4931              :           {
    4932            0 :             Error error (lexer.peek_token ()->get_locus (),
    4933              :                          "failed to parse type in external static item");
    4934            0 :             add_error (std::move (error));
    4935              : 
    4936            0 :             skip_after_semicolon ();
    4937            0 :             return nullptr;
    4938            0 :           }
    4939              : 
    4940            1 :         if (!skip_token (SEMICOLON))
    4941              :           {
    4942              :             // skip after somewhere?
    4943            0 :             return nullptr;
    4944              :           }
    4945              : 
    4946            1 :         return std::unique_ptr<AST::ExternalStaticItem> (
    4947            2 :           new AST::ExternalStaticItem (std::move (ident), std::move (type),
    4948              :                                        has_mut, std::move (vis),
    4949            1 :                                        std::move (outer_attrs), locus));
    4950            3 :       }
    4951         3547 :     case FN_KW:
    4952         7094 :       return parse_function (std::move (vis), std::move (outer_attrs), true);
    4953              : 
    4954            8 :     case TYPE:
    4955            8 :       return parse_external_type_item (std::move (vis),
    4956            8 :                                        std::move (outer_attrs));
    4957            0 :     default:
    4958              :       // error
    4959            0 :       add_error (
    4960            0 :         Error (t->get_locus (),
    4961              :                "unrecognised token %qs in extern block item declaration",
    4962              :                t->get_token_description ()));
    4963              : 
    4964            0 :       skip_after_semicolon ();
    4965            0 :       return nullptr;
    4966              :     }
    4967         7116 : }
    4968              : 
    4969              : // Parses a statement (will further disambiguate any statement).
    4970              : template <typename ManagedTokenSource>
    4971              : std::unique_ptr<AST::Stmt>
    4972         1087 : Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
    4973              : {
    4974              :   // quick exit for empty statement
    4975              :   // FIXME: Can we have empty statements without semicolons? Just nothing?
    4976         1087 :   const_TokenPtr t = lexer.peek_token ();
    4977         1087 :   if (t->get_id () == SEMICOLON)
    4978              :     {
    4979           30 :       lexer.skip_token ();
    4980           30 :       return std::unique_ptr<AST::EmptyStmt> (
    4981           30 :         new AST::EmptyStmt (t->get_locus ()));
    4982              :     }
    4983              : 
    4984              :   // parse outer attributes
    4985         1057 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    4986              : 
    4987              :   // parsing this will be annoying because of the many different possibilities
    4988              :   /* best may be just to copy paste in parse_item switch, and failing that try
    4989              :    * to parse outer attributes, and then pass them in to either a let
    4990              :    * statement or (fallback) expression statement. */
    4991              :   // FIXME: think of a way to do this without such a large switch?
    4992         1057 :   t = lexer.peek_token ();
    4993         1057 :   switch (t->get_id ())
    4994              :     {
    4995          227 :     case LET:
    4996              :       // let statement
    4997          227 :       return parse_let_stmt (std::move (outer_attrs), restrictions);
    4998          186 :     case PUB:
    4999              :     case MOD:
    5000              :     case EXTERN_KW:
    5001              :     case USE:
    5002              :     case FN_KW:
    5003              :     case TYPE:
    5004              :     case STRUCT_KW:
    5005              :     case ENUM_KW:
    5006              :     case CONST:
    5007              :     case STATIC_KW:
    5008              :     case AUTO:
    5009              :     case TRAIT:
    5010              :     case IMPL:
    5011              :     case MACRO:
    5012              :     /* TODO: implement union keyword but not really because of
    5013              :      * context-dependence crappy hack way to parse a union written below to
    5014              :      * separate it from the good code. */
    5015              :     // case UNION:
    5016              :     case UNSAFE: // maybe - unsafe traits are a thing
    5017              :       /* if any of these (should be all possible VisItem prefixes), parse a
    5018              :        * VisItem can't parse item because would require reparsing outer
    5019              :        * attributes */
    5020              :       // may also be unsafe block
    5021          372 :       if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
    5022              :         {
    5023            1 :           return parse_expr_stmt (std::move (outer_attrs), restrictions);
    5024              :         }
    5025              :       else
    5026              :         {
    5027          185 :           return parse_vis_item (std::move (outer_attrs));
    5028              :         }
    5029              :       break;
    5030              :     // crappy hack to do union "keyword"
    5031          267 :     case IDENTIFIER:
    5032          267 :       if (t->get_str () == Values::WeakKeywords::UNION
    5033          267 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
    5034              :         {
    5035            0 :           return parse_vis_item (std::move (outer_attrs));
    5036              :           // or should this go straight to parsing union?
    5037              :         }
    5038          534 :       else if (is_macro_rules_def (t))
    5039              :         {
    5040              :           // macro_rules! macro item
    5041            2 :           return parse_macro_rules_def (std::move (outer_attrs));
    5042              :         }
    5043              :       gcc_fallthrough ();
    5044              :       // TODO: find out how to disable gcc "implicit fallthrough" warning
    5045              :     default:
    5046              :       // fallback: expression statement
    5047          642 :       return parse_expr_stmt (std::move (outer_attrs), restrictions);
    5048              :       break;
    5049              :     }
    5050         1057 : }
    5051              : 
    5052              : // Parses a let statement.
    5053              : template <typename ManagedTokenSource>
    5054              : std::unique_ptr<AST::LetStmt>
    5055        24710 : Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
    5056              :                                             ParseRestrictions restrictions)
    5057              : {
    5058        24710 :   location_t locus = lexer.peek_token ()->get_locus ();
    5059        24710 :   skip_token (LET);
    5060              : 
    5061              :   // parse pattern (required)
    5062        24710 :   std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    5063        24710 :   if (pattern == nullptr)
    5064              :     {
    5065            0 :       Error error (lexer.peek_token ()->get_locus (),
    5066              :                    "failed to parse pattern in let statement");
    5067            0 :       add_error (std::move (error));
    5068              : 
    5069            0 :       skip_after_semicolon ();
    5070            0 :       return nullptr;
    5071            0 :     }
    5072              : 
    5073              :   // parse type declaration (optional)
    5074        24710 :   std::unique_ptr<AST::Type> type = nullptr;
    5075        49420 :   if (lexer.peek_token ()->get_id () == COLON)
    5076              :     {
    5077              :       // must have a type declaration
    5078         2712 :       lexer.skip_token ();
    5079              : 
    5080         2712 :       type = parse_type ();
    5081         2712 :       if (type == nullptr)
    5082              :         {
    5083            0 :           Error error (lexer.peek_token ()->get_locus (),
    5084              :                        "failed to parse type in let statement");
    5085            0 :           add_error (std::move (error));
    5086              : 
    5087            0 :           skip_after_semicolon ();
    5088            0 :           return nullptr;
    5089            0 :         }
    5090              :     }
    5091              : 
    5092              :   // parse expression to set variable to (optional)
    5093        24710 :   std::unique_ptr<AST::Expr> expr = nullptr;
    5094        49420 :   if (lexer.peek_token ()->get_id () == EQUAL)
    5095              :     {
    5096              :       // must have an expression
    5097        23576 :       lexer.skip_token ();
    5098              : 
    5099        23576 :       auto expr_res = parse_expr ();
    5100        23576 :       if (!expr_res)
    5101              :         {
    5102           22 :           skip_after_semicolon ();
    5103           22 :           return nullptr;
    5104              :         }
    5105        23554 :       expr = std::move (expr_res.value ());
    5106        23576 :     }
    5107              : 
    5108        24688 :   tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
    5109        24688 :   if (maybe_skip_token (ELSE))
    5110              :     {
    5111            5 :       auto block_expr = parse_block_expr ();
    5112            5 :       if (block_expr)
    5113              :         else_expr = tl::optional<std::unique_ptr<AST::Expr>>{
    5114           10 :           std::move (block_expr.value ())};
    5115              :       else
    5116              :         else_expr = tl::nullopt;
    5117            5 :     }
    5118              : 
    5119        24688 :   if (restrictions.consume_semi)
    5120              :     {
    5121              :       // `stmt` macro variables are parsed without a semicolon, but should be
    5122              :       // parsed as a full statement when interpolated. This should be handled
    5123              :       // by having the interpolated statement be distinguishable from normal
    5124              :       // tokens, e.g. by NT tokens.
    5125        24543 :       if (restrictions.allow_close_after_expr_stmt)
    5126           82 :         maybe_skip_token (SEMICOLON);
    5127        24461 :       else if (!skip_token (SEMICOLON))
    5128            1 :         return nullptr;
    5129              :     }
    5130              : 
    5131              :   return std::unique_ptr<AST::LetStmt> (
    5132        49379 :     new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
    5133        24687 :                       std::move (else_expr), std::move (outer_attrs), locus));
    5134        24710 : }
    5135              : 
    5136              : template <typename ManagedTokenSource>
    5137              : tl::optional<AST::GenericArg>
    5138        23210 : Parser<ManagedTokenSource>::parse_generic_arg ()
    5139              : {
    5140        23210 :   auto tok = lexer.peek_token ();
    5141        23210 :   std::unique_ptr<AST::Expr> expr = nullptr;
    5142              : 
    5143        23210 :   switch (tok->get_id ())
    5144              :     {
    5145        17835 :     case IDENTIFIER:
    5146              :       {
    5147              :         // This is a bit of a weird situation: With an identifier token, we
    5148              :         // could either have a valid type or a macro (FIXME: anything else?). So
    5149              :         // we need one bit of lookahead to differentiate if this is really
    5150        17835 :         auto next_tok = lexer.peek_token (1);
    5151        17835 :         if (next_tok->get_id () == LEFT_ANGLE
    5152        16731 :             || next_tok->get_id () == SCOPE_RESOLUTION
    5153        34114 :             || next_tok->get_id () == EXCLAM)
    5154              :           {
    5155         1564 :             auto type = parse_type ();
    5156         1564 :             if (type)
    5157         1564 :               return AST::GenericArg::create_type (std::move (type));
    5158              :             else
    5159            0 :               return tl::nullopt;
    5160         1564 :           }
    5161        16271 :         else if (next_tok->get_id () == COLON)
    5162              :           {
    5163            0 :             lexer.skip_token (); // skip ident
    5164            0 :             lexer.skip_token (); // skip colon
    5165              : 
    5166            0 :             auto tok = lexer.peek_token ();
    5167            0 :             std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    5168              :               = parse_type_param_bounds ();
    5169              : 
    5170            0 :             auto type = std::unique_ptr<AST::TraitObjectType> (
    5171            0 :               new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
    5172              :                                         false));
    5173            0 :             if (type)
    5174            0 :               return AST::GenericArg::create_type (std::move (type));
    5175              :             else
    5176              :               return tl::nullopt;
    5177            0 :           }
    5178        16271 :         lexer.skip_token ();
    5179        65084 :         return AST::GenericArg::create_ambiguous (tok->get_str (),
    5180        16271 :                                                   tok->get_locus ());
    5181        20011 :       }
    5182           23 :     case LEFT_CURLY:
    5183              :       {
    5184           23 :         auto res = parse_block_expr ();
    5185           23 :         if (res)
    5186           23 :           expr = std::move (res.value ());
    5187              :         else
    5188            0 :           return tl::nullopt;
    5189            0 :       }
    5190           23 :       break;
    5191           92 :     case MINUS:
    5192              :     case STRING_LITERAL:
    5193              :     case CHAR_LITERAL:
    5194              :     case INT_LITERAL:
    5195              :     case FLOAT_LITERAL:
    5196              :     case TRUE_LITERAL:
    5197              :     case FALSE_LITERAL:
    5198              :       {
    5199           92 :         auto res = parse_literal_expr ();
    5200           92 :         if (res)
    5201           92 :           expr = std::move (res.value ());
    5202              :         else
    5203            0 :           return tl::nullopt;
    5204            0 :       }
    5205           92 :       break;
    5206              :     // FIXME: Because of this, error reporting is garbage for const generic
    5207              :     // parameter's default values
    5208         5260 :     default:
    5209              :       {
    5210         5260 :         auto type = parse_type ();
    5211              :         // FIXME: Find a better way to do this?
    5212         5260 :         if (type)
    5213         5259 :           return AST::GenericArg::create_type (std::move (type));
    5214              :         else
    5215            1 :           return tl::nullopt;
    5216         5260 :       }
    5217              :     }
    5218              : 
    5219          115 :   if (!expr)
    5220            0 :     return tl::nullopt;
    5221              : 
    5222          115 :   return AST::GenericArg::create_const (std::move (expr));
    5223        23210 : }
    5224              : 
    5225              : // Parses the generic arguments in each path segment.
    5226              : template <typename ManagedTokenSource>
    5227              : AST::GenericArgs
    5228        22593 : Parser<ManagedTokenSource>::parse_path_generic_args ()
    5229              : {
    5230        45186 :   if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
    5231           21 :     lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
    5232              : 
    5233        22593 :   if (!skip_token (LEFT_ANGLE))
    5234              :     {
    5235              :       // skip after somewhere?
    5236            0 :       return AST::GenericArgs::create_empty ();
    5237              :     }
    5238              : 
    5239              :   // We need to parse all lifetimes, then parse types and const generics in
    5240              :   // any order.
    5241              : 
    5242              :   // try to parse lifetimes first
    5243        22593 :   std::vector<AST::Lifetime> lifetime_args;
    5244              : 
    5245        22593 :   const_TokenPtr t = lexer.peek_token ();
    5246        22593 :   location_t locus = t->get_locus ();
    5247        46096 :   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
    5248              :     {
    5249        23503 :       auto lifetime = parse_lifetime (false);
    5250        23503 :       if (!lifetime)
    5251              :         {
    5252              :           // not necessarily an error
    5253              :           break;
    5254              :         }
    5255              : 
    5256         2024 :       lifetime_args.push_back (std::move (lifetime.value ()));
    5257              : 
    5258              :       // if next token isn't comma, then it must be end of list
    5259         4048 :       if (lexer.peek_token ()->get_id () != COMMA)
    5260              :         {
    5261              :           break;
    5262              :         }
    5263              :       // skip comma
    5264          911 :       lexer.skip_token ();
    5265              : 
    5266          911 :       t = lexer.peek_token ();
    5267              :     }
    5268              : 
    5269              :   // try to parse types and const generics second
    5270        22593 :   std::vector<AST::GenericArg> generic_args;
    5271              : 
    5272              :   // TODO: think of better control structure
    5273        22593 :   t = lexer.peek_token ();
    5274        46285 :   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
    5275              :     {
    5276              :       // FIXME: Is it fine to break if there is one binding? Can't there be
    5277              :       // bindings in between types?
    5278              : 
    5279              :       // ensure not binding being parsed as type accidently
    5280        23692 :       if (t->get_id () == IDENTIFIER
    5281        47384 :           && (lexer.peek_token (1)->get_id () == EQUAL
    5282        41620 :               || lexer.peek_token (1)->get_id () == COLON))
    5283              :         break;
    5284              : 
    5285        23186 :       auto arg = parse_generic_arg ();
    5286        23186 :       if (arg)
    5287              :         {
    5288        23186 :           generic_args.emplace_back (std::move (arg.value ()));
    5289              :         }
    5290              : 
    5291              :       // FIXME: Do we need to break if we encounter an error?
    5292              : 
    5293              :       // if next token isn't comma, then it must be end of list
    5294        46372 :       if (lexer.peek_token ()->get_id () != COMMA)
    5295              :         break;
    5296              : 
    5297              :       // skip comma
    5298         2222 :       lexer.skip_token ();
    5299         2222 :       t = lexer.peek_token ();
    5300              :     }
    5301              : 
    5302              :   // try to parse bindings third
    5303        22593 :   std::vector<AST::GenericArgsBinding> binding_args;
    5304              : 
    5305              :   // TODO: think of better control structure
    5306        22593 :   t = lexer.peek_token ();
    5307        23109 :   while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
    5308              :     {
    5309          516 :       AST::GenericArgsBinding binding = parse_generic_args_binding ();
    5310          516 :       if (binding.is_error ())
    5311              :         {
    5312              :           // not necessarily an error
    5313              :           break;
    5314              :         }
    5315              : 
    5316          516 :       binding_args.push_back (std::move (binding));
    5317              : 
    5318              :       // if next token isn't comma, then it must be end of list
    5319         1032 :       if (lexer.peek_token ()->get_id () != COMMA)
    5320              :         {
    5321              :           break;
    5322              :         }
    5323              :       // skip comma
    5324           10 :       lexer.skip_token ();
    5325              : 
    5326           10 :       t = lexer.peek_token ();
    5327              :     }
    5328              : 
    5329              :   // skip any trailing commas
    5330        45186 :   if (lexer.peek_token ()->get_id () == COMMA)
    5331            0 :     lexer.skip_token ();
    5332              : 
    5333        22593 :   if (!skip_generics_right_angle ())
    5334            0 :     return AST::GenericArgs::create_empty ();
    5335              : 
    5336        22593 :   lifetime_args.shrink_to_fit ();
    5337        22593 :   generic_args.shrink_to_fit ();
    5338        22593 :   binding_args.shrink_to_fit ();
    5339              : 
    5340        22593 :   return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
    5341        22593 :                            std::move (binding_args), locus);
    5342        45186 : }
    5343              : 
    5344              : // Parses a binding in a generic args path segment.
    5345              : template <typename ManagedTokenSource>
    5346              : AST::GenericArgsBinding
    5347          516 : Parser<ManagedTokenSource>::parse_generic_args_binding ()
    5348              : {
    5349          516 :   const_TokenPtr ident_tok = lexer.peek_token ();
    5350          516 :   if (ident_tok->get_id () != IDENTIFIER)
    5351              :     {
    5352              :       // allow non error-inducing use
    5353              :       // skip somewhere?
    5354            0 :       return AST::GenericArgsBinding::create_error ();
    5355              :     }
    5356          516 :   lexer.skip_token ();
    5357         1032 :   Identifier ident{ident_tok};
    5358              : 
    5359         1032 :   if (lexer.peek_token ()->get_id () == COLON)
    5360              :     {
    5361           95 :       lexer.skip_token ();
    5362           95 :       auto bounds_locus = lexer.peek_token ()->get_locus ();
    5363           95 :       auto bounds = parse_type_param_bounds ();
    5364           95 :       auto type = std::unique_ptr<AST::Type> (
    5365           95 :         new AST::ImplTraitType (std::move (bounds), bounds_locus));
    5366          190 :       return AST::GenericArgsBinding (
    5367              :         std::move (ident), std::move (type), ident_tok->get_locus (),
    5368          190 :         AST::GenericArgsBinding::Kind::Constraint);
    5369           95 :     }
    5370              : 
    5371          421 :   if (!skip_token (EQUAL))
    5372            0 :     return AST::GenericArgsBinding::create_error ();
    5373              : 
    5374              :   // parse type (required)
    5375          421 :   std::unique_ptr<AST::Type> type = parse_type ();
    5376          421 :   if (type == nullptr)
    5377              :     {
    5378              :       // skip somewhere?
    5379            0 :       return AST::GenericArgsBinding::create_error ();
    5380              :     }
    5381              : 
    5382          842 :   return AST::GenericArgsBinding (std::move (ident), std::move (type),
    5383          842 :                                   ident_tok->get_locus ());
    5384          937 : }
    5385              : 
    5386              : // Parses a self param. Also handles self param not existing.
    5387              : template <typename ManagedTokenSource>
    5388              : tl::expected<std::unique_ptr<AST::Param>, Parse::Error::Self>
    5389        35822 : Parser<ManagedTokenSource>::parse_self_param ()
    5390              : {
    5391        35822 :   bool has_reference = false;
    5392        35822 :   AST::Lifetime lifetime = AST::Lifetime::elided ();
    5393              : 
    5394        35822 :   location_t locus = lexer.peek_token ()->get_locus ();
    5395              : 
    5396              :   // TODO: Feels off, find a better way to clearly express this
    5397       143288 :   std::vector<std::vector<TokenId>> ptrs
    5398              :     = {{ASTERISK, SELF} /* *self */,
    5399              :        {ASTERISK, CONST, SELF} /* *const self */,
    5400              :        {ASTERISK, MUT, SELF} /* *mut self */};
    5401              : 
    5402       143282 :   for (auto &s : ptrs)
    5403              :     {
    5404              :       size_t i = 0;
    5405       107474 :       for (i = 0; i < s.size (); i++)
    5406       214942 :         if (lexer.peek_token (i)->get_id () != s[i])
    5407              :           break;
    5408       107463 :       if (i == s.size ())
    5409              :         {
    5410            3 :           Error error (lexer.peek_token ()->get_locus (),
    5411              :                        "cannot pass %<self%> by raw pointer");
    5412            3 :           add_error (std::move (error));
    5413            3 :           return Parse::Error::Self::make_self_raw_pointer ();
    5414            3 :         }
    5415              :     }
    5416              : 
    5417              :   // Trying to find those patterns:
    5418              :   //
    5419              :   // &'lifetime mut self
    5420              :   // &'lifetime self
    5421              :   // & mut self
    5422              :   // & self
    5423              :   // mut self
    5424              :   // self
    5425              :   //
    5426              :   // If not found, it is probably a function, exit and let function parsing
    5427              :   // handle it.
    5428              :   bool is_self = false;
    5429       214914 :   for (size_t i = 0; i < 5; i++)
    5430       358190 :     if (lexer.peek_token (i)->get_id () == SELF)
    5431        17826 :       is_self = true;
    5432              : 
    5433        35819 :   if (!is_self)
    5434        17998 :     return Parse::Error::Self::make_not_self ();
    5435              : 
    5436              :   // test if self is a reference parameter
    5437        35642 :   if (lexer.peek_token ()->get_id () == AMP)
    5438              :     {
    5439         9934 :       has_reference = true;
    5440         9934 :       lexer.skip_token ();
    5441              : 
    5442              :       // now test whether it has a lifetime
    5443        19868 :       if (lexer.peek_token ()->get_id () == LIFETIME)
    5444              :         {
    5445              :           // something went wrong somehow
    5446          106 :           if (auto parsed_lifetime = parse_lifetime (true))
    5447              :             {
    5448           53 :               lifetime = parsed_lifetime.value ();
    5449              :             }
    5450              :           else
    5451              :             {
    5452            0 :               Error error (lexer.peek_token ()->get_locus (),
    5453              :                            "failed to parse lifetime in self param");
    5454            0 :               add_error (std::move (error));
    5455              : 
    5456              :               // skip after somewhere?
    5457            0 :               return Parse::Error::Self::make_parsing_error ();
    5458            0 :             }
    5459              :         }
    5460              :     }
    5461              : 
    5462              :   // test for mut
    5463        17821 :   bool has_mut = false;
    5464        35642 :   if (lexer.peek_token ()->get_id () == MUT)
    5465              :     {
    5466         2878 :       has_mut = true;
    5467         2878 :       lexer.skip_token ();
    5468              :     }
    5469              : 
    5470              :   // skip self token
    5471        17821 :   const_TokenPtr self_tok = lexer.peek_token ();
    5472        17821 :   if (self_tok->get_id () != SELF)
    5473              :     {
    5474              :       // skip after somewhere?
    5475            4 :       return Parse::Error::Self::make_not_self ();
    5476              :     }
    5477        17817 :   lexer.skip_token ();
    5478              : 
    5479              :   // parse optional type
    5480        17817 :   std::unique_ptr<AST::Type> type = nullptr;
    5481        35634 :   if (lexer.peek_token ()->get_id () == COLON)
    5482              :     {
    5483           28 :       lexer.skip_token ();
    5484              : 
    5485              :       // type is now required
    5486           28 :       type = parse_type ();
    5487           28 :       if (type == nullptr)
    5488              :         {
    5489            0 :           Error error (lexer.peek_token ()->get_locus (),
    5490              :                        "could not parse type in self param");
    5491            0 :           add_error (std::move (error));
    5492              : 
    5493              :           // skip after somewhere?
    5494            0 :           return Parse::Error::Self::make_parsing_error ();
    5495            0 :         }
    5496              :     }
    5497              : 
    5498              :   // ensure that cannot have both type and reference
    5499        17817 :   if (type && has_reference)
    5500              :     {
    5501            0 :       Error error (
    5502            0 :         lexer.peek_token ()->get_locus (),
    5503              :         "cannot have both a reference and a type specified in a self param");
    5504            0 :       add_error (std::move (error));
    5505              : 
    5506              :       // skip after somewhere?
    5507            0 :       return Parse::Error::Self::make_parsing_error ();
    5508            0 :     }
    5509              : 
    5510        17817 :   if (has_reference)
    5511              :     {
    5512         9934 :       return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
    5513         9934 :                                                locus);
    5514              :     }
    5515              :   else
    5516              :     {
    5517              :       // note that type may be nullptr here and that's fine
    5518         7883 :       return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
    5519         7883 :                                                locus);
    5520              :     }
    5521        53639 : }
    5522              : 
    5523              : /* Parses an expression or macro statement. */
    5524              : template <typename ManagedTokenSource>
    5525              : std::unique_ptr<AST::Stmt>
    5526          643 : Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
    5527              :                                              ParseRestrictions restrictions)
    5528              : {
    5529          643 :   location_t locus = lexer.peek_token ()->get_locus ();
    5530              : 
    5531          643 :   tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
    5532              : 
    5533         1286 :   switch (lexer.peek_token ()->get_id ())
    5534              :     {
    5535          271 :     case IDENTIFIER:
    5536              :     case CRATE:
    5537              :     case SUPER:
    5538              :     case SELF:
    5539              :     case SELF_ALIAS:
    5540              :     case DOLLAR_SIGN:
    5541              :     case SCOPE_RESOLUTION:
    5542              :       {
    5543          271 :         AST::PathInExpression path = parse_path_in_expression ();
    5544              :         tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
    5545          271 :           null_denotation;
    5546              : 
    5547          542 :         if (lexer.peek_token ()->get_id () == EXCLAM)
    5548              :           {
    5549           61 :             std::unique_ptr<AST::MacroInvocation> invoc
    5550          122 :               = parse_macro_invocation_partial (std::move (path),
    5551              :                                                 std::move (outer_attrs));
    5552              : 
    5553           61 :             if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
    5554              :               {
    5555           59 :                 invoc->add_semicolon ();
    5556              :                 // Macro invocation with semicolon.
    5557           59 :                 return invoc;
    5558              :               }
    5559              : 
    5560            2 :             TokenId after_macro = lexer.peek_token ()->get_id ();
    5561              : 
    5562            2 :             if (restrictions.allow_close_after_expr_stmt
    5563            2 :                 && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
    5564              :                     || after_macro == RIGHT_SQUARE))
    5565            2 :               return invoc;
    5566              : 
    5567            0 :             if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
    5568              :                   == AST::CURLY
    5569            0 :                 && after_macro != DOT && after_macro != QUESTION_MARK)
    5570              :               {
    5571            0 :                 rust_debug ("braced macro statement");
    5572            0 :                 return invoc;
    5573              :               }
    5574              : 
    5575            0 :             null_denotation = std::move (invoc);
    5576           61 :           }
    5577              :         else
    5578              :           {
    5579              :             null_denotation
    5580          420 :               = null_denotation_path (std::move (path), {}, restrictions);
    5581              :           }
    5582              : 
    5583          840 :         expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
    5584              :                                  std::move (outer_attrs), restrictions);
    5585              :         break;
    5586          271 :       }
    5587          372 :     default:
    5588          372 :       restrictions.expr_can_be_stmt = true;
    5589          744 :       expr = parse_expr (std::move (outer_attrs), restrictions);
    5590          372 :       break;
    5591              :     }
    5592              : 
    5593          582 :   if (!expr)
    5594              :     {
    5595              :       // expr is required, error
    5596            0 :       Error error (lexer.peek_token ()->get_locus (),
    5597              :                    "failed to parse expr in expr statement");
    5598            0 :       add_error (std::move (error));
    5599              : 
    5600            0 :       skip_after_semicolon ();
    5601            0 :       return nullptr;
    5602            0 :     }
    5603              : 
    5604          582 :   bool has_semi = false;
    5605              : 
    5606          582 :   if (restrictions.consume_semi)
    5607              :     {
    5608          566 :       if (maybe_skip_token (SEMICOLON))
    5609              :         {
    5610          166 :           has_semi = true;
    5611              :         }
    5612          400 :       else if (expr.value ()->is_expr_without_block ())
    5613              :         {
    5614           34 :           if (restrictions.allow_close_after_expr_stmt)
    5615              :             {
    5616           34 :               TokenId id = lexer.peek_token ()->get_id ();
    5617           34 :               if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
    5618              :                 {
    5619            3 :                   expect_token (SEMICOLON);
    5620            3 :                   return nullptr;
    5621              :                 }
    5622              :             }
    5623              :           else
    5624              :             {
    5625            0 :               expect_token (SEMICOLON);
    5626            0 :               return nullptr;
    5627              :             }
    5628              :         }
    5629              :     }
    5630              : 
    5631          579 :   return std::make_unique<AST::ExprStmt> (std::move (expr.value ()), locus,
    5632          579 :                                           has_semi);
    5633          643 : }
    5634              : 
    5635              : // Parses a loop label used in loop expressions.
    5636              : template <typename ManagedTokenSource>
    5637              : tl::expected<AST::LoopLabel, Parse::Error::LoopLabel>
    5638           61 : Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
    5639              : {
    5640              :   // parse lifetime - if doesn't exist, assume no label
    5641           61 :   if (tok->get_id () != LIFETIME)
    5642              :     {
    5643              :       // not necessarily an error
    5644            0 :       return Parse::Error::LoopLabel::make_not_loop_label ();
    5645              :     }
    5646              :   /* FIXME: check for named lifetime requirement here? or check in semantic
    5647              :    * analysis phase? */
    5648          122 :   AST::Lifetime label = lifetime_from_token (tok);
    5649              : 
    5650           61 :   if (!skip_token (COLON))
    5651              :     {
    5652              :       // skip somewhere?
    5653           61 :       Parse::Error::LoopLabel::make_missing_colon ();
    5654              :     }
    5655              : 
    5656              :   return tl::expected<AST::LoopLabel, Parse::Error::LoopLabel> (
    5657           61 :     AST::LoopLabel (std::move (label), tok->get_locus ()));
    5658           61 : }
    5659              : 
    5660              : // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
    5661              : template <typename ManagedTokenSource>
    5662              : AST::MatchArm
    5663        50502 : Parser<ManagedTokenSource>::parse_match_arm ()
    5664              : {
    5665              :   // parse optional outer attributes
    5666        50502 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    5667              : 
    5668              :   // DEBUG
    5669        50502 :   rust_debug ("about to start parsing match arm patterns");
    5670              : 
    5671              :   // break early if find right curly
    5672       101004 :   if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
    5673              :     {
    5674              :       // not an error
    5675            0 :       return AST::MatchArm::create_error ();
    5676              :     }
    5677              : 
    5678              :   // parse match arm patterns - at least 1 is required
    5679        50502 :   std::unique_ptr<AST::Pattern> match_arm_pattern
    5680              :     = parse_match_arm_pattern (RIGHT_CURLY);
    5681        50502 :   if (match_arm_pattern == nullptr)
    5682              :     {
    5683            0 :       Error error (lexer.peek_token ()->get_locus (),
    5684              :                    "failed to parse any patterns in match arm");
    5685            0 :       add_error (std::move (error));
    5686              : 
    5687              :       // skip somewhere?
    5688            0 :       return AST::MatchArm::create_error ();
    5689            0 :     }
    5690              : 
    5691              :   // DEBUG
    5692        50502 :   rust_debug ("successfully parsed match arm patterns");
    5693              : 
    5694              :   // parse match arm guard expr if it exists
    5695        50502 :   std::unique_ptr<AST::Expr> guard_expr = nullptr;
    5696       101004 :   if (lexer.peek_token ()->get_id () == IF)
    5697              :     {
    5698          104 :       lexer.skip_token ();
    5699              : 
    5700          104 :       auto guard_expr_res = parse_expr ();
    5701          104 :       if (!guard_expr_res)
    5702              :         {
    5703            0 :           Error error (lexer.peek_token ()->get_locus (),
    5704              :                        "failed to parse guard expression in match arm");
    5705            0 :           add_error (std::move (error));
    5706              : 
    5707              :           // skip somewhere?
    5708            0 :           return AST::MatchArm::create_error ();
    5709            0 :         }
    5710          104 :       guard_expr = std::move (guard_expr_res.value ());
    5711          104 :     }
    5712              : 
    5713              :   // DEBUG
    5714        50502 :   rust_debug ("successfully parsed match arm");
    5715              : 
    5716       101004 :   return AST::MatchArm (std::move (match_arm_pattern),
    5717       101004 :                         lexer.peek_token ()->get_locus (),
    5718        50502 :                         std::move (guard_expr), std::move (outer_attrs));
    5719        50502 : }
    5720              : 
    5721              : /* Parses the patterns used in a match arm. End token id is the id of the
    5722              :  * token that would exist after the patterns are done (e.g. '}' for match
    5723              :  * expr, '=' for if let and while let). */
    5724              : template <typename ManagedTokenSource>
    5725              : std::unique_ptr<AST::Pattern>
    5726        50717 : Parser<ManagedTokenSource>::parse_match_arm_pattern (TokenId end_token_id)
    5727              : {
    5728              :   // skip optional leading '|'
    5729       101434 :   if (lexer.peek_token ()->get_id () == PIPE)
    5730            0 :     lexer.skip_token ();
    5731              :   /* TODO: do I even need to store the result of this? can't be used.
    5732              :    * If semantically different, I need a wrapped "match arm patterns" object
    5733              :    * for this. */
    5734              : 
    5735        50717 :   std::unique_ptr<AST::Pattern> pattern;
    5736              : 
    5737              :   // quick break out if end_token_id
    5738       101434 :   if (lexer.peek_token ()->get_id () == end_token_id)
    5739            1 :     return pattern;
    5740              : 
    5741              :   // parse required pattern - if doesn't exist, return empty
    5742        50716 :   std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
    5743        50716 :   if (initial_pattern == nullptr)
    5744              :     {
    5745              :       // FIXME: should this be an error?
    5746            0 :       return pattern;
    5747              :     }
    5748              : 
    5749        50716 :   return initial_pattern;
    5750        50717 : }
    5751              : 
    5752              : // Parses a single parameter used in a closure definition.
    5753              : template <typename ManagedTokenSource>
    5754              : AST::ClosureParam
    5755          611 : Parser<ManagedTokenSource>::parse_closure_param ()
    5756              : {
    5757          611 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    5758              : 
    5759              :   // parse pattern (which is required)
    5760          611 :   std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
    5761          611 :   if (pattern == nullptr)
    5762              :     {
    5763              :       // not necessarily an error
    5764            0 :       return AST::ClosureParam::create_error ();
    5765              :     }
    5766              : 
    5767              :   // parse optional type of param
    5768          611 :   std::unique_ptr<AST::Type> type = nullptr;
    5769         1222 :   if (lexer.peek_token ()->get_id () == COLON)
    5770              :     {
    5771           88 :       lexer.skip_token ();
    5772              : 
    5773              :       // parse type, which is now required
    5774           88 :       type = parse_type ();
    5775           88 :       if (type == nullptr)
    5776              :         {
    5777            0 :           Error error (lexer.peek_token ()->get_locus (),
    5778              :                        "failed to parse type in closure parameter");
    5779            0 :           add_error (std::move (error));
    5780              : 
    5781              :           // skip somewhere?
    5782            0 :           return AST::ClosureParam::create_error ();
    5783            0 :         }
    5784              :     }
    5785              : 
    5786          611 :   location_t loc = pattern->get_locus ();
    5787          611 :   return AST::ClosureParam (std::move (pattern), loc, std::move (type),
    5788          611 :                             std::move (outer_attrs));
    5789          611 : }
    5790              : 
    5791              : // Parses a type (will further disambiguate any type).
    5792              : template <typename ManagedTokenSource>
    5793              : std::unique_ptr<AST::Type>
    5794       118134 : Parser<ManagedTokenSource>::parse_type (bool save_errors)
    5795              : {
    5796              :   /* rules for all types:
    5797              :    * NeverType:               '!'
    5798              :    * SliceType:               '[' Type ']'
    5799              :    * InferredType:            '_'
    5800              :    * MacroInvocation:         SimplePath '!' DelimTokenTree
    5801              :    * ParenthesisedType:       '(' Type ')'
    5802              :    * ImplTraitType:           'impl' TypeParamBounds
    5803              :    *  TypeParamBounds (not type)  TypeParamBound ( '+' TypeParamBound )* '+'?
    5804              :    *  TypeParamBound          Lifetime | TraitBound
    5805              :    * ImplTraitTypeOneBound:   'impl' TraitBound
    5806              :    * TraitObjectType:         'dyn'? TypeParamBounds
    5807              :    * TraitObjectTypeOneBound: 'dyn'? TraitBound
    5808              :    *  TraitBound              '?'? ForLifetimes? TypePath | '(' '?'?
    5809              :    * ForLifetimes? TypePath ')' BareFunctionType:        ForLifetimes?
    5810              :    * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
    5811              :    * LifetimeParams '>' FunctionQualifiers      ( 'async' | 'const' )?
    5812              :    * 'unsafe'?
    5813              :    * ('extern' abi?)? QualifiedPathInType:     '<' Type ( 'as' TypePath )? '>'
    5814              :    * (
    5815              :    * '::' TypePathSegment )+ TypePath:                '::'? TypePathSegment (
    5816              :    * '::' TypePathSegment)* ArrayType:               '[' Type ';' Expr ']'
    5817              :    * ReferenceType:           '&' Lifetime? 'mut'? TypeNoBounds
    5818              :    * RawPointerType:          '*' ( 'mut' | 'const' ) TypeNoBounds
    5819              :    * TupleType:               '(' Type etc. - regular tuple stuff. Also
    5820              :    * regular tuple vs parenthesised precedence
    5821              :    *
    5822              :    * Disambiguate between macro and type path via type path being parsed, and
    5823              :    * then if '!' found, convert type path to simple path for macro. Usual
    5824              :    * disambiguation for tuple vs parenthesised. For ImplTraitType and
    5825              :    * TraitObjectType individual disambiguations, they seem more like "special
    5826              :    * cases", so probably just try to parse the more general ImplTraitType or
    5827              :    * TraitObjectType and return OneBound versions if they satisfy those
    5828              :    * criteria. */
    5829              : 
    5830       118134 :   const_TokenPtr t = lexer.peek_token ();
    5831       118134 :   switch (t->get_id ())
    5832              :     {
    5833          258 :     case EXCLAM:
    5834              :       // never type - can't be macro as no path beforehand
    5835          258 :       lexer.skip_token ();
    5836          258 :       return std::unique_ptr<AST::NeverType> (
    5837          258 :         new AST::NeverType (t->get_locus ()));
    5838         1530 :     case LEFT_SQUARE:
    5839              :       // slice type or array type - requires further disambiguation
    5840         1530 :       return parse_slice_or_array_type ();
    5841         3557 :     case LEFT_SHIFT:
    5842              :     case LEFT_ANGLE:
    5843              :       {
    5844              :         // qualified path in type
    5845         3557 :         AST::QualifiedPathInType path = parse_qualified_path_in_type ();
    5846         3557 :         if (path.is_error ())
    5847              :           {
    5848            0 :             if (save_errors)
    5849              :               {
    5850            0 :                 Error error (t->get_locus (),
    5851              :                              "failed to parse qualified path in type");
    5852            0 :                 add_error (std::move (error));
    5853            0 :               }
    5854              : 
    5855            0 :             return nullptr;
    5856              :           }
    5857         3557 :         return std::unique_ptr<AST::QualifiedPathInType> (
    5858         3557 :           new AST::QualifiedPathInType (std::move (path)));
    5859         3557 :       }
    5860          337 :     case UNDERSCORE:
    5861              :       // inferred type
    5862          337 :       lexer.skip_token ();
    5863          337 :       return std::unique_ptr<AST::InferredType> (
    5864          337 :         new AST::InferredType (t->get_locus ()));
    5865         3890 :     case ASTERISK:
    5866              :       // raw pointer type
    5867         3890 :       return parse_raw_pointer_type ();
    5868        12978 :     case AMP: // does this also include AMP_AMP?
    5869              :     case LOGICAL_AND:
    5870              :       // reference type
    5871        12978 :       return parse_reference_type ();
    5872            0 :     case LIFETIME:
    5873              :       {
    5874              :         /* probably a lifetime bound, so probably type param bounds in
    5875              :          * TraitObjectType */
    5876            0 :         std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    5877              :           = parse_type_param_bounds ();
    5878              : 
    5879            0 :         return std::unique_ptr<AST::TraitObjectType> (
    5880            0 :           new AST::TraitObjectType (std::move (bounds), t->get_locus (),
    5881            0 :                                     false));
    5882            0 :       }
    5883        93212 :     case IDENTIFIER:
    5884              :     case SUPER:
    5885              :     case SELF:
    5886              :     case SELF_ALIAS:
    5887              :     case CRATE:
    5888              :     case DOLLAR_SIGN:
    5889              :     case SCOPE_RESOLUTION:
    5890              :       {
    5891              :         // macro invocation or type path - requires further disambiguation.
    5892              :         /* for parsing path component of each rule, perhaps parse it as a
    5893              :          * typepath and attempt conversion to simplepath if a trailing '!' is
    5894              :          * found */
    5895              :         /* Type path also includes TraitObjectTypeOneBound BUT if it starts
    5896              :          * with it, it is exactly the same as a TypePath syntactically, so
    5897              :          * this is a syntactical ambiguity. As such, the parser will parse it
    5898              :          * as a TypePath. This, however, does not prevent TraitObjectType from
    5899              :          * starting with a typepath. */
    5900              : 
    5901              :         // parse path as type path
    5902        93212 :         AST::TypePath path = parse_type_path ();
    5903        93212 :         if (path.is_error ())
    5904              :           {
    5905            0 :             if (save_errors)
    5906              :               {
    5907            0 :                 Error error (t->get_locus (),
    5908              :                              "failed to parse path as first component of type");
    5909            0 :                 add_error (std::move (error));
    5910            0 :               }
    5911              : 
    5912            0 :             return nullptr;
    5913              :           }
    5914        93212 :         location_t locus = path.get_locus ();
    5915              : 
    5916              :         // branch on next token
    5917        93212 :         t = lexer.peek_token ();
    5918        93212 :         switch (t->get_id ())
    5919              :           {
    5920          497 :           case EXCLAM:
    5921              :             {
    5922              :               // macro invocation
    5923              :               // convert to simple path
    5924          497 :               AST::SimplePath macro_path = path.as_simple_path ();
    5925          497 :               if (macro_path.is_empty ())
    5926              :                 {
    5927            0 :                   if (save_errors)
    5928              :                     {
    5929            0 :                       Error error (t->get_locus (),
    5930              :                                    "failed to parse simple path in macro "
    5931              :                                    "invocation (for type)");
    5932            0 :                       add_error (std::move (error));
    5933            0 :                     }
    5934              : 
    5935            0 :                   return nullptr;
    5936              :                 }
    5937              : 
    5938          497 :               lexer.skip_token ();
    5939              : 
    5940          497 :               auto tok_tree = parse_delim_token_tree ();
    5941          497 :               if (!tok_tree)
    5942            0 :                 return nullptr;
    5943              : 
    5944          994 :               return AST::MacroInvocation::Regular (
    5945          994 :                 AST::MacroInvocData (std::move (macro_path),
    5946          497 :                                      std::move (tok_tree.value ())),
    5947          497 :                 {}, locus);
    5948          994 :             }
    5949           29 :           case PLUS:
    5950              :             {
    5951              :               // type param bounds
    5952           29 :               std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    5953              : 
    5954              :               // convert type path to trait bound
    5955           29 :               std::unique_ptr<AST::TraitBound> path_bound (
    5956           29 :                 new AST::TraitBound (std::move (path), locus, false, false));
    5957           29 :               bounds.push_back (std::move (path_bound));
    5958              : 
    5959              :               /* parse rest of bounds - FIXME: better way to find when to stop
    5960              :                * parsing */
    5961           58 :               while (t->get_id () == PLUS)
    5962              :                 {
    5963           29 :                   lexer.skip_token ();
    5964              : 
    5965              :                   // parse bound if it exists - if not, assume end of sequence
    5966           29 :                   std::unique_ptr<AST::TypeParamBound> bound
    5967              :                     = parse_type_param_bound ();
    5968           29 :                   if (bound == nullptr)
    5969              :                     {
    5970              :                       break;
    5971              :                     }
    5972           29 :                   bounds.push_back (std::move (bound));
    5973              : 
    5974           29 :                   t = lexer.peek_token ();
    5975              :                 }
    5976              : 
    5977           29 :               return std::unique_ptr<AST::TraitObjectType> (
    5978           29 :                 new AST::TraitObjectType (std::move (bounds), locus, false));
    5979           29 :             }
    5980        92686 :           default:
    5981              :             // assume that this is a type path and not an error
    5982        92686 :             return std::unique_ptr<AST::TypePath> (
    5983        92686 :               new AST::TypePath (std::move (path)));
    5984              :           }
    5985        93212 :       }
    5986         1353 :     case LEFT_PAREN:
    5987              :       /* tuple type or parenthesised type - requires further disambiguation
    5988              :        * (the usual). ok apparently can be a parenthesised TraitBound too, so
    5989              :        * could be TraitObjectTypeOneBound or TraitObjectType */
    5990         1353 :       return parse_paren_prefixed_type ();
    5991            5 :     case FOR:
    5992              :       // TraitObjectTypeOneBound or BareFunctionType
    5993            5 :       return parse_for_prefixed_type ();
    5994          695 :     case ASYNC:
    5995              :     case CONST:
    5996              :     case UNSAFE:
    5997              :     case EXTERN_KW:
    5998              :     case FN_KW:
    5999              :       // bare function type (with no for lifetimes)
    6000          695 :       return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
    6001          243 :     case IMPL:
    6002          243 :       lexer.skip_token ();
    6003          486 :       if (lexer.peek_token ()->get_id () == LIFETIME)
    6004              :         {
    6005              :           /* cannot be one bound because lifetime prevents it from being
    6006              :            * traitbound */
    6007            0 :           std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    6008              :             = parse_type_param_bounds ();
    6009              : 
    6010            0 :           return std::unique_ptr<AST::ImplTraitType> (
    6011            0 :             new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
    6012            0 :         }
    6013              :       else
    6014              :         {
    6015              :           // should be trait bound, so parse trait bound
    6016          243 :           std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
    6017          243 :           if (initial_bound == nullptr)
    6018              :             {
    6019            0 :               if (save_errors)
    6020              :                 {
    6021            0 :                   Error error (lexer.peek_token ()->get_locus (),
    6022              :                                "failed to parse ImplTraitType initial bound");
    6023            0 :                   add_error (std::move (error));
    6024            0 :                 }
    6025              : 
    6026            0 :               return nullptr;
    6027              :             }
    6028              : 
    6029          243 :           location_t locus = t->get_locus ();
    6030              : 
    6031              :           // short cut if next token isn't '+'
    6032          243 :           t = lexer.peek_token ();
    6033          243 :           if (t->get_id () != PLUS)
    6034              :             {
    6035          239 :               return std::unique_ptr<AST::ImplTraitTypeOneBound> (
    6036          239 :                 new AST::ImplTraitTypeOneBound (std::move (initial_bound),
    6037          239 :                                                 locus));
    6038              :             }
    6039              : 
    6040              :           // parse additional type param bounds
    6041            4 :           std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    6042            4 :           bounds.push_back (std::move (initial_bound));
    6043            8 :           while (t->get_id () == PLUS)
    6044              :             {
    6045            4 :               lexer.skip_token ();
    6046              : 
    6047              :               // parse bound if it exists
    6048            4 :               std::unique_ptr<AST::TypeParamBound> bound
    6049              :                 = parse_type_param_bound ();
    6050            4 :               if (bound == nullptr)
    6051              :                 {
    6052              :                   // not an error as trailing plus may exist
    6053              :                   break;
    6054              :                 }
    6055            4 :               bounds.push_back (std::move (bound));
    6056              : 
    6057            4 :               t = lexer.peek_token ();
    6058              :             }
    6059              : 
    6060            4 :           return std::unique_ptr<AST::ImplTraitType> (
    6061            4 :             new AST::ImplTraitType (std::move (bounds), locus));
    6062          243 :         }
    6063           60 :     case DYN:
    6064              :     case QUESTION_MARK:
    6065              :       {
    6066              :         // either TraitObjectType or TraitObjectTypeOneBound
    6067           60 :         bool has_dyn = false;
    6068           60 :         if (t->get_id () == DYN)
    6069              :           {
    6070           60 :             lexer.skip_token ();
    6071           60 :             has_dyn = true;
    6072              :           }
    6073              : 
    6074          120 :         if (lexer.peek_token ()->get_id () == LIFETIME)
    6075              :           {
    6076              :             /* cannot be one bound because lifetime prevents it from being
    6077              :              * traitbound */
    6078            0 :             std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
    6079              :               = parse_type_param_bounds ();
    6080              : 
    6081            0 :             return std::unique_ptr<AST::TraitObjectType> (
    6082            0 :               new AST::TraitObjectType (std::move (bounds), t->get_locus (),
    6083            0 :                                         has_dyn));
    6084            0 :           }
    6085              :         else
    6086              :           {
    6087              :             // should be trait bound, so parse trait bound
    6088           60 :             std::unique_ptr<AST::TraitBound> initial_bound
    6089              :               = parse_trait_bound ();
    6090           60 :             if (initial_bound == nullptr)
    6091              :               {
    6092            2 :                 if (save_errors)
    6093              :                   {
    6094            2 :                     Error error (
    6095            2 :                       lexer.peek_token ()->get_locus (),
    6096              :                       "failed to parse TraitObjectType initial bound");
    6097            2 :                     add_error (std::move (error));
    6098            2 :                   }
    6099              : 
    6100            2 :                 return nullptr;
    6101              :               }
    6102              : 
    6103              :             // short cut if next token isn't '+'
    6104           58 :             t = lexer.peek_token ();
    6105           58 :             if (t->get_id () != PLUS)
    6106              :               {
    6107              :                 // convert trait bound to value object
    6108           27 :                 AST::TraitBound value_bound (*initial_bound);
    6109              : 
    6110              :                 // DEBUG: removed as unique ptr, so should auto delete
    6111              :                 // delete initial_bound;
    6112              : 
    6113           27 :                 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6114           54 :                   new AST::TraitObjectTypeOneBound (std::move (value_bound),
    6115           27 :                                                     t->get_locus (), has_dyn));
    6116           27 :               }
    6117              : 
    6118              :             // parse additional type param bounds
    6119           31 :             std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    6120           31 :             bounds.push_back (std::move (initial_bound));
    6121           72 :             while (t->get_id () == PLUS)
    6122              :               {
    6123           41 :                 lexer.skip_token ();
    6124              : 
    6125              :                 // parse bound if it exists
    6126           41 :                 std::unique_ptr<AST::TypeParamBound> bound
    6127              :                   = parse_type_param_bound ();
    6128           41 :                 if (bound == nullptr)
    6129              :                   {
    6130              :                     // not an error as trailing plus may exist
    6131              :                     break;
    6132              :                   }
    6133           41 :                 bounds.push_back (std::move (bound));
    6134              : 
    6135           41 :                 t = lexer.peek_token ();
    6136              :               }
    6137              : 
    6138           31 :             return std::unique_ptr<AST::TraitObjectType> (
    6139           31 :               new AST::TraitObjectType (std::move (bounds), t->get_locus (),
    6140           31 :                                         has_dyn));
    6141           60 :           }
    6142              :       }
    6143           16 :     default:
    6144           16 :       if (save_errors)
    6145           16 :         add_error (Error (t->get_locus (), "unrecognised token %qs in type",
    6146              :                           t->get_token_description ()));
    6147              : 
    6148           16 :       return nullptr;
    6149              :     }
    6150       118134 : }
    6151              : 
    6152              : /* Parses a type that has '(' as its first character. Returns a tuple type,
    6153              :  * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
    6154              :  * on following characters. */
    6155              : template <typename ManagedTokenSource>
    6156              : std::unique_ptr<AST::Type>
    6157         1353 : Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
    6158              : {
    6159              :   /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
    6160              :    * a trait bound, not a parenthesised type, so that it can still be used in
    6161              :    * type param bounds. */
    6162              : 
    6163              :   /* NOTE: this implementation is really shit but I couldn't think of a better
    6164              :    * one. It requires essentially breaking polymorphism and downcasting via
    6165              :    * virtual method abuse, as it was copied from the rustc implementation (in
    6166              :    * which types are reified due to tagged union), after a more OOP attempt by
    6167              :    * me failed. */
    6168         1353 :   location_t left_delim_locus = lexer.peek_token ()->get_locus ();
    6169              : 
    6170              :   // skip left delim
    6171         1353 :   lexer.skip_token ();
    6172              :   /* while next token isn't close delim, parse comma-separated types, saving
    6173              :    * whether trailing comma happens */
    6174         1353 :   const_TokenPtr t = lexer.peek_token ();
    6175         1353 :   bool trailing_comma = true;
    6176         1353 :   std::vector<std::unique_ptr<AST::Type>> types;
    6177              : 
    6178         3071 :   while (t->get_id () != RIGHT_PAREN)
    6179              :     {
    6180         2677 :       std::unique_ptr<AST::Type> type = parse_type ();
    6181         2677 :       if (type == nullptr)
    6182              :         {
    6183            0 :           Error error (t->get_locus (),
    6184              :                        "failed to parse type inside parentheses (probably "
    6185              :                        "tuple or parenthesised)");
    6186            0 :           add_error (std::move (error));
    6187              : 
    6188            0 :           return nullptr;
    6189            0 :         }
    6190         2677 :       types.push_back (std::move (type));
    6191              : 
    6192         2677 :       t = lexer.peek_token ();
    6193         2677 :       if (t->get_id () != COMMA)
    6194              :         {
    6195          959 :           trailing_comma = false;
    6196              :           break;
    6197              :         }
    6198         1718 :       lexer.skip_token ();
    6199              : 
    6200         1718 :       t = lexer.peek_token ();
    6201              :     }
    6202              : 
    6203         1353 :   if (!skip_token (RIGHT_PAREN))
    6204              :     {
    6205            0 :       return nullptr;
    6206              :     }
    6207              : 
    6208              :   // if only one type and no trailing comma, then not a tuple type
    6209         1353 :   if (types.size () == 1 && !trailing_comma)
    6210              :     {
    6211              :       // must be a TraitObjectType (with more than one bound)
    6212           10 :       if (lexer.peek_token ()->get_id () == PLUS)
    6213              :         {
    6214              :           // create type param bounds vector
    6215            0 :           std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    6216              : 
    6217              :           // HACK: convert type to traitbound and add to bounds
    6218            0 :           std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
    6219            0 :           std::unique_ptr<AST::TraitBound> converted_bound (
    6220            0 :             released_ptr->to_trait_bound (true));
    6221            0 :           if (converted_bound == nullptr)
    6222              :             {
    6223            0 :               Error error (
    6224            0 :                 lexer.peek_token ()->get_locus (),
    6225              :                 "failed to hackily converted parsed type to trait bound");
    6226            0 :               add_error (std::move (error));
    6227              : 
    6228            0 :               return nullptr;
    6229            0 :             }
    6230            0 :           bounds.push_back (std::move (converted_bound));
    6231              : 
    6232            0 :           t = lexer.peek_token ();
    6233            0 :           while (t->get_id () == PLUS)
    6234              :             {
    6235            0 :               lexer.skip_token ();
    6236              : 
    6237              :               // attempt to parse typeparambound
    6238            0 :               std::unique_ptr<AST::TypeParamBound> bound
    6239              :                 = parse_type_param_bound ();
    6240            0 :               if (bound == nullptr)
    6241              :                 {
    6242              :                   // not an error if null
    6243              :                   break;
    6244              :                 }
    6245            0 :               bounds.push_back (std::move (bound));
    6246              : 
    6247            0 :               t = lexer.peek_token ();
    6248              :             }
    6249              : 
    6250            0 :           return std::unique_ptr<AST::TraitObjectType> (
    6251            0 :             new AST::TraitObjectType (std::move (bounds), left_delim_locus,
    6252            0 :                                       false));
    6253            0 :         }
    6254              :       else
    6255              :         {
    6256              :           // release vector pointer
    6257            5 :           std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
    6258              :           /* HACK: attempt to convert to trait bound. if fails, parenthesised
    6259              :            * type */
    6260            5 :           std::unique_ptr<AST::TraitBound> converted_bound (
    6261            5 :             released_ptr->to_trait_bound (true));
    6262            5 :           if (converted_bound == nullptr)
    6263              :             {
    6264              :               // parenthesised type
    6265            5 :               return std::unique_ptr<AST::ParenthesisedType> (
    6266            5 :                 new AST::ParenthesisedType (std::move (released_ptr),
    6267            5 :                                             left_delim_locus));
    6268              :             }
    6269              :           else
    6270              :             {
    6271              :               // trait object type (one bound)
    6272              : 
    6273              :               // get value semantics trait bound
    6274            0 :               AST::TraitBound value_bound (*converted_bound);
    6275              : 
    6276            0 :               return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6277            0 :                 new AST::TraitObjectTypeOneBound (value_bound,
    6278            0 :                                                   left_delim_locus));
    6279            0 :             }
    6280            5 :         }
    6281              :     }
    6282              :   else
    6283              :     {
    6284         1348 :       return std::unique_ptr<AST::TupleType> (
    6285         1348 :         new AST::TupleType (std::move (types), left_delim_locus));
    6286              :     }
    6287              :   /* TODO: ensure that this ensures that dynamic dispatch for traits is not
    6288              :    * lost somehow */
    6289         1353 : }
    6290              : 
    6291              : /* Parses a type that has 'for' as its first character. This means it has a
    6292              :  * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
    6293              :  * TraitObjectTypeOneBound depending on following characters. */
    6294              : template <typename ManagedTokenSource>
    6295              : std::unique_ptr<AST::Type>
    6296            5 : Parser<ManagedTokenSource>::parse_for_prefixed_type ()
    6297              : {
    6298            5 :   location_t for_locus = lexer.peek_token ()->get_locus ();
    6299              :   // parse for lifetimes in type
    6300            5 :   std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
    6301              : 
    6302              :   // branch on next token - either function or a trait type
    6303            5 :   const_TokenPtr t = lexer.peek_token ();
    6304            5 :   switch (t->get_id ())
    6305              :     {
    6306            4 :     case ASYNC:
    6307              :     case CONST:
    6308              :     case UNSAFE:
    6309              :     case EXTERN_KW:
    6310              :     case FN_KW:
    6311            4 :       return parse_bare_function_type (std::move (for_lifetimes));
    6312            1 :     case SCOPE_RESOLUTION:
    6313              :     case IDENTIFIER:
    6314              :     case SUPER:
    6315              :     case SELF:
    6316              :     case SELF_ALIAS:
    6317              :     case CRATE:
    6318              :     case DOLLAR_SIGN:
    6319              :       {
    6320              :         // path, so trait type
    6321              : 
    6322              :         // parse type path to finish parsing trait bound
    6323            1 :         AST::TypePath path = parse_type_path ();
    6324              : 
    6325            1 :         t = lexer.peek_token ();
    6326            1 :         if (t->get_id () != PLUS)
    6327              :           {
    6328              :             // must be one-bound trait type
    6329              :             // create trait bound value object
    6330            1 :             AST::TraitBound bound (std::move (path), for_locus, false, false,
    6331              :                                    std::move (for_lifetimes));
    6332              : 
    6333            1 :             return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6334            2 :               new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
    6335            1 :           }
    6336              : 
    6337              :         /* more than one bound trait type (or at least parsed as it - could be
    6338              :          * trailing '+') create trait bound pointer and bounds */
    6339            0 :         std::unique_ptr<AST::TraitBound> initial_bound (
    6340            0 :           new AST::TraitBound (std::move (path), for_locus, false, false,
    6341              :                                std::move (for_lifetimes)));
    6342            0 :         std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
    6343            0 :         bounds.push_back (std::move (initial_bound));
    6344              : 
    6345            0 :         while (t->get_id () == PLUS)
    6346              :           {
    6347            0 :             lexer.skip_token ();
    6348              : 
    6349              :             // parse type param bound if it exists
    6350            0 :             std::unique_ptr<AST::TypeParamBound> bound
    6351              :               = parse_type_param_bound ();
    6352            0 :             if (bound == nullptr)
    6353              :               {
    6354              :                 // not an error - e.g. trailing plus
    6355            0 :                 return nullptr;
    6356              :               }
    6357            0 :             bounds.push_back (std::move (bound));
    6358              : 
    6359            0 :             t = lexer.peek_token ();
    6360              :           }
    6361              : 
    6362            0 :         return std::unique_ptr<AST::TraitObjectType> (
    6363            0 :           new AST::TraitObjectType (std::move (bounds), for_locus, false));
    6364            1 :       }
    6365            0 :     default:
    6366              :       // error
    6367            0 :       add_error (Error (t->get_locus (),
    6368              :                         "unrecognised token %qs in bare function type or trait "
    6369              :                         "object type or trait object type one bound",
    6370              :                         t->get_token_description ()));
    6371              : 
    6372            0 :       return nullptr;
    6373              :     }
    6374            5 : }
    6375              : 
    6376              : // Parses a maybe named param used in bare function types.
    6377              : template <typename ManagedTokenSource>
    6378              : AST::MaybeNamedParam
    6379         3824 : Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
    6380              : {
    6381              :   /* Basically guess that param is named if first token is identifier or
    6382              :    * underscore and second token is semicolon. This should probably have no
    6383              :    * exceptions. rustc uses backtracking to parse these, but at the time of
    6384              :    * writing gccrs has no backtracking capabilities. */
    6385         3824 :   const_TokenPtr current = lexer.peek_token ();
    6386         3824 :   const_TokenPtr next = lexer.peek_token (1);
    6387              : 
    6388         3824 :   Identifier name;
    6389         3824 :   AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
    6390              : 
    6391         3824 :   if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
    6392              :     {
    6393              :       // named param
    6394            1 :       name = {current};
    6395            1 :       kind = AST::MaybeNamedParam::IDENTIFIER;
    6396            1 :       lexer.skip_token (1);
    6397              :     }
    6398         3823 :   else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
    6399              :     {
    6400              :       // wildcard param
    6401           12 :       name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
    6402            6 :       kind = AST::MaybeNamedParam::WILDCARD;
    6403            6 :       lexer.skip_token (1);
    6404              :     }
    6405              : 
    6406              :   // parse type (required)
    6407         3824 :   std::unique_ptr<AST::Type> type = parse_type ();
    6408         3824 :   if (type == nullptr)
    6409              :     {
    6410            0 :       Error error (lexer.peek_token ()->get_locus (),
    6411              :                    "failed to parse type in maybe named param");
    6412            0 :       add_error (std::move (error));
    6413              : 
    6414            0 :       return AST::MaybeNamedParam::create_error ();
    6415            0 :     }
    6416              : 
    6417         7648 :   return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
    6418         3824 :                                std::move (outer_attrs), current->get_locus ());
    6419         7648 : }
    6420              : 
    6421              : /* Parses a bare function type (with the given for lifetimes for convenience -
    6422              :  * does not parse them itself). */
    6423              : template <typename ManagedTokenSource>
    6424              : std::unique_ptr<AST::BareFunctionType>
    6425          701 : Parser<ManagedTokenSource>::parse_bare_function_type (
    6426              :   std::vector<AST::LifetimeParam> for_lifetimes)
    6427              : {
    6428              :   // TODO: pass in for lifetime location as param
    6429          701 :   location_t best_try_locus = lexer.peek_token ()->get_locus ();
    6430              : 
    6431          701 :   auto qualifiers = parse_function_qualifiers ();
    6432          701 :   if (!qualifiers)
    6433            0 :     return nullptr;
    6434              : 
    6435          701 :   if (!skip_token (FN_KW))
    6436            0 :     return nullptr;
    6437              : 
    6438          701 :   if (!skip_token (LEFT_PAREN))
    6439            0 :     return nullptr;
    6440              : 
    6441              :   // parse function params, if they exist
    6442          701 :   std::vector<AST::MaybeNamedParam> params;
    6443          701 :   bool is_variadic = false;
    6444          701 :   AST::AttrVec variadic_attrs;
    6445              : 
    6446          701 :   const_TokenPtr t = lexer.peek_token ();
    6447         8089 :   while (t->get_id () != RIGHT_PAREN)
    6448              :     {
    6449         4016 :       AST::AttrVec temp_attrs = parse_outer_attributes ();
    6450              : 
    6451         8032 :       if (lexer.peek_token ()->get_id () == ELLIPSIS)
    6452              :         {
    6453          192 :           lexer.skip_token ();
    6454          192 :           is_variadic = true;
    6455          192 :           variadic_attrs = std::move (temp_attrs);
    6456              : 
    6457          192 :           t = lexer.peek_token ();
    6458              : 
    6459          192 :           if (t->get_id () != RIGHT_PAREN)
    6460              :             {
    6461            0 :               Error error (t->get_locus (),
    6462              :                            "expected right parentheses after variadic in maybe "
    6463              :                            "named function "
    6464              :                            "parameters, found %qs",
    6465              :                            t->get_token_description ());
    6466            0 :               add_error (std::move (error));
    6467              : 
    6468            0 :               return nullptr;
    6469            0 :             }
    6470              : 
    6471              :           break;
    6472              :         }
    6473              : 
    6474         3824 :       AST::MaybeNamedParam param
    6475         3824 :         = parse_maybe_named_param (std::move (temp_attrs));
    6476         3824 :       if (param.is_error ())
    6477              :         {
    6478            0 :           Error error (
    6479            0 :             lexer.peek_token ()->get_locus (),
    6480              :             "failed to parse maybe named param in bare function type");
    6481            0 :           add_error (std::move (error));
    6482              : 
    6483            0 :           return nullptr;
    6484            0 :         }
    6485         3824 :       params.push_back (std::move (param));
    6486              : 
    6487         7648 :       if (lexer.peek_token ()->get_id () != COMMA)
    6488              :         break;
    6489              : 
    6490         3372 :       lexer.skip_token ();
    6491         3372 :       t = lexer.peek_token ();
    6492              :     }
    6493              : 
    6494          701 :   if (!skip_token (RIGHT_PAREN))
    6495            0 :     return nullptr;
    6496              : 
    6497              :   // bare function return type, if exists
    6498          701 :   std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
    6499         1402 :   if (lexer.peek_token ()->get_id () == RETURN_TYPE)
    6500              :     {
    6501          672 :       lexer.skip_token ();
    6502              : 
    6503              :       // parse required TypeNoBounds
    6504          672 :       return_type = parse_type_no_bounds ();
    6505          672 :       if (return_type == nullptr)
    6506              :         {
    6507            0 :           Error error (lexer.peek_token ()->get_locus (),
    6508              :                        "failed to parse return type (type no bounds) in bare "
    6509              :                        "function type");
    6510            0 :           add_error (std::move (error));
    6511              : 
    6512            0 :           return nullptr;
    6513            0 :         }
    6514              :     }
    6515              : 
    6516          701 :   return std::unique_ptr<AST::BareFunctionType> (new AST::BareFunctionType (
    6517          701 :     std::move (for_lifetimes), std::move (qualifiers.value ()),
    6518              :     std::move (params), is_variadic, std::move (variadic_attrs),
    6519          701 :     std::move (return_type), best_try_locus));
    6520         1402 : }
    6521              : 
    6522              : template <typename ManagedTokenSource>
    6523              : std::unique_ptr<AST::ReferenceType>
    6524        13054 : Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
    6525              : {
    6526              :   // parse optional lifetime
    6527        13054 :   AST::Lifetime lifetime = AST::Lifetime::elided ();
    6528        26108 :   if (lexer.peek_token ()->get_id () == LIFETIME)
    6529              :     {
    6530         2120 :       auto parsed_lifetime = parse_lifetime (true);
    6531         2120 :       if (parsed_lifetime)
    6532              :         {
    6533         2120 :           lifetime = parsed_lifetime.value ();
    6534              :         }
    6535              :       else
    6536              :         {
    6537            0 :           Error error (lexer.peek_token ()->get_locus (),
    6538              :                        "failed to parse lifetime in reference type");
    6539            0 :           add_error (std::move (error));
    6540              : 
    6541            0 :           return nullptr;
    6542            0 :         }
    6543         2120 :     }
    6544              : 
    6545        13054 :   bool is_mut = false;
    6546        26108 :   if (lexer.peek_token ()->get_id () == MUT)
    6547              :     {
    6548         1961 :       lexer.skip_token ();
    6549         1961 :       is_mut = true;
    6550              :     }
    6551              : 
    6552              :   // parse type no bounds, which is required
    6553        13054 :   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
    6554        13054 :   if (type == nullptr)
    6555              :     {
    6556            0 :       Error error (lexer.peek_token ()->get_locus (),
    6557              :                    "failed to parse referenced type in reference type");
    6558            0 :       add_error (std::move (error));
    6559              : 
    6560            0 :       return nullptr;
    6561            0 :     }
    6562              : 
    6563              :   return std::unique_ptr<AST::ReferenceType> (
    6564        39162 :     new AST::ReferenceType (is_mut, std::move (type), locus,
    6565        13054 :                             std::move (lifetime)));
    6566        13054 : }
    6567              : 
    6568              : // Parses a reference type (mutable or immutable, with given lifetime).
    6569              : template <typename ManagedTokenSource>
    6570              : std::unique_ptr<AST::ReferenceType>
    6571        13054 : Parser<ManagedTokenSource>::parse_reference_type ()
    6572              : {
    6573        13054 :   auto t = lexer.peek_token ();
    6574        13054 :   auto locus = t->get_locus ();
    6575              : 
    6576        13054 :   switch (t->get_id ())
    6577              :     {
    6578        13006 :     case AMP:
    6579        13006 :       skip_token (AMP);
    6580        13006 :       return parse_reference_type_inner (locus);
    6581           48 :     case LOGICAL_AND:
    6582           48 :       skip_token (LOGICAL_AND);
    6583              :       return std::unique_ptr<AST::ReferenceType> (
    6584          144 :         new AST::ReferenceType (false, parse_reference_type_inner (locus),
    6585           48 :                                 locus));
    6586            0 :     default:
    6587            0 :       rust_unreachable ();
    6588              :     }
    6589        13054 : }
    6590              : 
    6591              : // Parses a raw (unsafe) pointer type.
    6592              : template <typename ManagedTokenSource>
    6593              : std::unique_ptr<AST::RawPointerType>
    6594         8784 : Parser<ManagedTokenSource>::parse_raw_pointer_type ()
    6595              : {
    6596         8784 :   location_t locus = lexer.peek_token ()->get_locus ();
    6597         8784 :   skip_token (ASTERISK);
    6598              : 
    6599         8784 :   AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
    6600              : 
    6601              :   // branch on next token for pointer kind info
    6602         8784 :   const_TokenPtr t = lexer.peek_token ();
    6603         8784 :   switch (t->get_id ())
    6604              :     {
    6605         1718 :     case MUT:
    6606         1718 :       kind = AST::RawPointerType::MUT;
    6607         1718 :       lexer.skip_token ();
    6608         1718 :       break;
    6609         7066 :     case CONST:
    6610         7066 :       kind = AST::RawPointerType::CONST;
    6611         7066 :       lexer.skip_token ();
    6612         7066 :       break;
    6613            0 :     default:
    6614            0 :       add_error (Error (t->get_locus (),
    6615              :                         "unrecognised token %qs in raw pointer type",
    6616              :                         t->get_token_description ()));
    6617              : 
    6618            0 :       return nullptr;
    6619              :     }
    6620              : 
    6621              :   // parse type no bounds (required)
    6622         8784 :   std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
    6623         8784 :   if (type == nullptr)
    6624              :     {
    6625            0 :       Error error (lexer.peek_token ()->get_locus (),
    6626              :                    "failed to parse pointed type of raw pointer type");
    6627            0 :       add_error (std::move (error));
    6628              : 
    6629            0 :       return nullptr;
    6630            0 :     }
    6631              : 
    6632              :   return std::unique_ptr<AST::RawPointerType> (
    6633         8784 :     new AST::RawPointerType (kind, std::move (type), locus));
    6634         8784 : }
    6635              : 
    6636              : /* Parses a slice or array type, depending on following arguments (as
    6637              :  * lookahead is not possible). */
    6638              : template <typename ManagedTokenSource>
    6639              : std::unique_ptr<AST::TypeNoBounds>
    6640         2992 : Parser<ManagedTokenSource>::parse_slice_or_array_type ()
    6641              : {
    6642         2992 :   location_t locus = lexer.peek_token ()->get_locus ();
    6643         2992 :   skip_token (LEFT_SQUARE);
    6644              : 
    6645              :   // parse inner type (required)
    6646         2992 :   std::unique_ptr<AST::Type> inner_type = parse_type ();
    6647         2992 :   if (inner_type == nullptr)
    6648              :     {
    6649            0 :       Error error (lexer.peek_token ()->get_locus (),
    6650              :                    "failed to parse inner type in slice or array type");
    6651            0 :       add_error (std::move (error));
    6652              : 
    6653            0 :       return nullptr;
    6654            0 :     }
    6655              : 
    6656              :   // branch on next token
    6657         2992 :   const_TokenPtr t = lexer.peek_token ();
    6658         2992 :   switch (t->get_id ())
    6659              :     {
    6660         1805 :     case RIGHT_SQUARE:
    6661              :       // slice type
    6662         1805 :       lexer.skip_token ();
    6663              : 
    6664         1805 :       return std::unique_ptr<AST::SliceType> (
    6665         1805 :         new AST::SliceType (std::move (inner_type), locus));
    6666         1187 :     case SEMICOLON:
    6667              :       {
    6668              :         // array type
    6669         1187 :         lexer.skip_token ();
    6670              : 
    6671              :         // parse required array size expression
    6672         1187 :         auto size = parse_anon_const ();
    6673              : 
    6674         1187 :         if (!size)
    6675              :           {
    6676            1 :             Error error (lexer.peek_token ()->get_locus (),
    6677              :                          "failed to parse size expression in array type");
    6678            1 :             add_error (std::move (error));
    6679              : 
    6680            1 :             return nullptr;
    6681            1 :           }
    6682              : 
    6683         1186 :         if (!skip_token (RIGHT_SQUARE))
    6684              :           {
    6685            0 :             return nullptr;
    6686              :           }
    6687              : 
    6688         1186 :         return std::unique_ptr<AST::ArrayType> (
    6689         2359 :           new AST::ArrayType (std::move (inner_type), std::move (*size),
    6690         1186 :                               locus));
    6691         1187 :       }
    6692            0 :     default:
    6693              :       // error
    6694            0 :       add_error (
    6695            0 :         Error (t->get_locus (),
    6696              :                "unrecognised token %qs in slice or array type after inner type",
    6697              :                t->get_token_description ()));
    6698              : 
    6699            0 :       return nullptr;
    6700              :     }
    6701         2992 : }
    6702              : 
    6703              : // Parses a type, taking into account type boundary disambiguation.
    6704              : template <typename ManagedTokenSource>
    6705              : std::unique_ptr<AST::TypeNoBounds>
    6706        32265 : Parser<ManagedTokenSource>::parse_type_no_bounds ()
    6707              : {
    6708        32265 :   const_TokenPtr t = lexer.peek_token ();
    6709        32265 :   switch (t->get_id ())
    6710              :     {
    6711            5 :     case EXCLAM:
    6712              :       // never type - can't be macro as no path beforehand
    6713            5 :       lexer.skip_token ();
    6714            5 :       return std::unique_ptr<AST::NeverType> (
    6715            5 :         new AST::NeverType (t->get_locus ()));
    6716         1462 :     case LEFT_SQUARE:
    6717              :       // slice type or array type - requires further disambiguation
    6718         1462 :       return parse_slice_or_array_type ();
    6719           26 :     case LEFT_SHIFT:
    6720              :     case LEFT_ANGLE:
    6721              :       {
    6722              :         // qualified path in type
    6723           26 :         AST::QualifiedPathInType path = parse_qualified_path_in_type ();
    6724           26 :         if (path.is_error ())
    6725              :           {
    6726            0 :             Error error (t->get_locus (),
    6727              :                          "failed to parse qualified path in type");
    6728            0 :             add_error (std::move (error));
    6729              : 
    6730            0 :             return nullptr;
    6731            0 :           }
    6732           26 :         return std::unique_ptr<AST::QualifiedPathInType> (
    6733           26 :           new AST::QualifiedPathInType (std::move (path)));
    6734           26 :       }
    6735          225 :     case UNDERSCORE:
    6736              :       // inferred type
    6737          225 :       lexer.skip_token ();
    6738          225 :       return std::unique_ptr<AST::InferredType> (
    6739          225 :         new AST::InferredType (t->get_locus ()));
    6740         4894 :     case ASTERISK:
    6741              :       // raw pointer type
    6742         4894 :       return parse_raw_pointer_type ();
    6743           76 :     case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
    6744              :     case LOGICAL_AND:
    6745              :       // reference type
    6746           76 :       return parse_reference_type ();
    6747            0 :     case LIFETIME:
    6748              :       /* probably a lifetime bound, so probably type param bounds in
    6749              :        * TraitObjectType. this is not allowed, but detection here for error
    6750              :        * message */
    6751            0 :       add_error (Error (t->get_locus (),
    6752              :                         "lifetime bounds (i.e. in type param bounds, in "
    6753              :                         "TraitObjectType) are not allowed as TypeNoBounds"));
    6754              : 
    6755            0 :       return nullptr;
    6756        24996 :     case IDENTIFIER:
    6757              :     case SUPER:
    6758              :     case SELF:
    6759              :     case SELF_ALIAS:
    6760              :     case CRATE:
    6761              :     case DOLLAR_SIGN:
    6762              :     case SCOPE_RESOLUTION:
    6763              :       {
    6764              :         // macro invocation or type path - requires further disambiguation.
    6765              :         /* for parsing path component of each rule, perhaps parse it as a
    6766              :          * typepath and attempt conversion to simplepath if a trailing '!' is
    6767              :          * found */
    6768              :         /* Type path also includes TraitObjectTypeOneBound BUT if it starts
    6769              :          * with it, it is exactly the same as a TypePath syntactically, so
    6770              :          * this is a syntactical ambiguity. As such, the parser will parse it
    6771              :          * as a TypePath. This, however, does not prevent TraitObjectType from
    6772              :          * starting with a typepath. */
    6773              : 
    6774              :         // parse path as type path
    6775        24996 :         AST::TypePath path = parse_type_path ();
    6776        24996 :         if (path.is_error ())
    6777              :           {
    6778            0 :             Error error (
    6779              :               t->get_locus (),
    6780              :               "failed to parse path as first component of type no bounds");
    6781            0 :             add_error (std::move (error));
    6782              : 
    6783            0 :             return nullptr;
    6784            0 :           }
    6785        24996 :         location_t locus = path.get_locus ();
    6786              : 
    6787              :         // branch on next token
    6788        24996 :         t = lexer.peek_token ();
    6789        24996 :         switch (t->get_id ())
    6790              :           {
    6791            1 :           case EXCLAM:
    6792              :             {
    6793              :               // macro invocation
    6794              :               // convert to simple path
    6795            1 :               AST::SimplePath macro_path = path.as_simple_path ();
    6796            1 :               if (macro_path.is_empty ())
    6797              :                 {
    6798            0 :                   Error error (t->get_locus (),
    6799              :                                "failed to parse simple path in macro "
    6800              :                                "invocation (for type)");
    6801            0 :                   add_error (std::move (error));
    6802              : 
    6803            0 :                   return nullptr;
    6804            0 :                 }
    6805              : 
    6806            1 :               lexer.skip_token ();
    6807              : 
    6808            1 :               auto tok_tree = parse_delim_token_tree ();
    6809            1 :               if (!tok_tree)
    6810            0 :                 return nullptr;
    6811              : 
    6812            2 :               return AST::MacroInvocation::Regular (
    6813            2 :                 AST::MacroInvocData (std::move (macro_path),
    6814            1 :                                      std::move (tok_tree.value ())),
    6815            1 :                 {}, locus);
    6816            2 :             }
    6817        24995 :           default:
    6818              :             // assume that this is a type path and not an error
    6819        24995 :             return std::unique_ptr<AST::TypePath> (
    6820        24995 :               new AST::TypePath (std::move (path)));
    6821              :           }
    6822        24996 :       }
    6823          332 :     case LEFT_PAREN:
    6824              :       /* tuple type or parenthesised type - requires further disambiguation
    6825              :        * (the usual). ok apparently can be a parenthesised TraitBound too, so
    6826              :        * could be TraitObjectTypeOneBound */
    6827          332 :       return parse_paren_prefixed_type_no_bounds ();
    6828            2 :     case FOR:
    6829              :     case ASYNC:
    6830              :     case CONST:
    6831              :     case UNSAFE:
    6832              :     case EXTERN_KW:
    6833              :     case FN_KW:
    6834              :       // bare function type (with no for lifetimes)
    6835            2 :       return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
    6836           30 :     case IMPL:
    6837           30 :       lexer.skip_token ();
    6838           60 :       if (lexer.peek_token ()->get_id () == LIFETIME)
    6839              :         {
    6840              :           /* cannot be one bound because lifetime prevents it from being
    6841              :            * traitbound not allowed as type no bounds, only here for error
    6842              :            * message */
    6843            0 :           Error error (
    6844            0 :             lexer.peek_token ()->get_locus (),
    6845              :             "lifetime (probably lifetime bound, in type param "
    6846              :             "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
    6847            0 :           add_error (std::move (error));
    6848              : 
    6849            0 :           return nullptr;
    6850            0 :         }
    6851              :       else
    6852              :         {
    6853              :           // should be trait bound, so parse trait bound
    6854           30 :           std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
    6855           30 :           if (initial_bound == nullptr)
    6856              :             {
    6857            0 :               Error error (lexer.peek_token ()->get_locus (),
    6858              :                            "failed to parse ImplTraitTypeOneBound bound");
    6859            0 :               add_error (std::move (error));
    6860              : 
    6861            0 :               return nullptr;
    6862            0 :             }
    6863              : 
    6864           30 :           location_t locus = t->get_locus ();
    6865              : 
    6866              :           // ensure not a trait with multiple bounds
    6867           30 :           t = lexer.peek_token ();
    6868           30 :           if (t->get_id () == PLUS)
    6869              :             {
    6870            0 :               Error error (t->get_locus (),
    6871              :                            "plus after trait bound means an ImplTraitType, "
    6872              :                            "which is not allowed as a TypeNoBounds");
    6873            0 :               add_error (std::move (error));
    6874              : 
    6875            0 :               return nullptr;
    6876            0 :             }
    6877              : 
    6878           30 :           return std::unique_ptr<AST::ImplTraitTypeOneBound> (
    6879           30 :             new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
    6880           30 :         }
    6881          217 :     case DYN:
    6882              :     case QUESTION_MARK:
    6883              :       {
    6884              :         // either TraitObjectTypeOneBound
    6885          217 :         bool has_dyn = false;
    6886          217 :         if (t->get_id () == DYN)
    6887              :           {
    6888          217 :             lexer.skip_token ();
    6889          217 :             has_dyn = true;
    6890              :           }
    6891              : 
    6892          434 :         if (lexer.peek_token ()->get_id () == LIFETIME)
    6893              :           {
    6894              :             /* means that cannot be TraitObjectTypeOneBound - so here for
    6895              :              * error message */
    6896            0 :             Error error (lexer.peek_token ()->get_locus (),
    6897              :                          "lifetime as bound in TraitObjectTypeOneBound "
    6898              :                          "is not allowed, so cannot be TypeNoBounds");
    6899            0 :             add_error (std::move (error));
    6900              : 
    6901            0 :             return nullptr;
    6902            0 :           }
    6903              : 
    6904              :         // should be trait bound, so parse trait bound
    6905          217 :         std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
    6906          217 :         if (initial_bound == nullptr)
    6907              :           {
    6908            0 :             Error error (
    6909            0 :               lexer.peek_token ()->get_locus (),
    6910              :               "failed to parse TraitObjectTypeOneBound initial bound");
    6911            0 :             add_error (std::move (error));
    6912              : 
    6913            0 :             return nullptr;
    6914            0 :           }
    6915              : 
    6916          217 :         location_t locus = t->get_locus ();
    6917              : 
    6918              :         // detect error with plus as next token
    6919          217 :         t = lexer.peek_token ();
    6920          217 :         if (t->get_id () == PLUS)
    6921              :           {
    6922            0 :             Error error (t->get_locus (),
    6923              :                          "plus after trait bound means a TraitObjectType, "
    6924              :                          "which is not allowed as a TypeNoBounds");
    6925            0 :             add_error (std::move (error));
    6926              : 
    6927            0 :             return nullptr;
    6928            0 :           }
    6929              : 
    6930              :         // convert trait bound to value object
    6931          217 :         AST::TraitBound value_bound (*initial_bound);
    6932              : 
    6933          217 :         return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    6934          434 :           new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
    6935          217 :                                             has_dyn));
    6936          217 :       }
    6937            0 :     default:
    6938            0 :       add_error (Error (t->get_locus (),
    6939              :                         "unrecognised token %qs in type no bounds",
    6940              :                         t->get_token_description ()));
    6941              : 
    6942            0 :       return nullptr;
    6943              :     }
    6944        32265 : }
    6945              : 
    6946              : // Parses a type no bounds beginning with '('.
    6947              : template <typename ManagedTokenSource>
    6948              : std::unique_ptr<AST::TypeNoBounds>
    6949          332 : Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
    6950              : {
    6951              :   /* NOTE: this could probably be parsed without the HACK solution of
    6952              :    * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
    6953              : 
    6954              :   /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
    6955              :    * considered a trait bound, not a parenthesised type, so that it can still
    6956              :    * be used in type param bounds. */
    6957              : 
    6958          332 :   location_t left_paren_locus = lexer.peek_token ()->get_locus ();
    6959              : 
    6960              :   // skip left delim
    6961          332 :   lexer.skip_token ();
    6962              :   /* while next token isn't close delim, parse comma-separated types, saving
    6963              :    * whether trailing comma happens */
    6964          332 :   const_TokenPtr t = lexer.peek_token ();
    6965          332 :   bool trailing_comma = true;
    6966          332 :   std::vector<std::unique_ptr<AST::Type>> types;
    6967              : 
    6968          967 :   while (t->get_id () != RIGHT_PAREN)
    6969              :     {
    6970          659 :       std::unique_ptr<AST::Type> type = parse_type ();
    6971          659 :       if (type == nullptr)
    6972              :         {
    6973            0 :           Error error (t->get_locus (),
    6974              :                        "failed to parse type inside parentheses (probably "
    6975              :                        "tuple or parenthesised)");
    6976            0 :           add_error (std::move (error));
    6977              : 
    6978            0 :           return nullptr;
    6979            0 :         }
    6980          659 :       types.push_back (std::move (type));
    6981              : 
    6982          659 :       t = lexer.peek_token ();
    6983          659 :       if (t->get_id () != COMMA)
    6984              :         {
    6985           24 :           trailing_comma = false;
    6986              :           break;
    6987              :         }
    6988          635 :       lexer.skip_token ();
    6989              : 
    6990          635 :       t = lexer.peek_token ();
    6991              :     }
    6992              : 
    6993          332 :   if (!skip_token (RIGHT_PAREN))
    6994              :     {
    6995            0 :       return nullptr;
    6996              :     }
    6997              : 
    6998              :   // if only one type and no trailing comma, then not a tuple type
    6999          332 :   if (types.size () == 1 && !trailing_comma)
    7000              :     {
    7001              :       // must be a TraitObjectType (with more than one bound)
    7002           26 :       if (lexer.peek_token ()->get_id () == PLUS)
    7003              :         {
    7004              :           // error - this is not allowed for type no bounds
    7005            0 :           Error error (lexer.peek_token ()->get_locus (),
    7006              :                        "plus (implying TraitObjectType as type param "
    7007              :                        "bounds) is not allowed in type no bounds");
    7008            0 :           add_error (std::move (error));
    7009              : 
    7010            0 :           return nullptr;
    7011            0 :         }
    7012              :       else
    7013              :         {
    7014              :           // release vector pointer
    7015           13 :           std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
    7016              :           /* HACK: attempt to convert to trait bound. if fails, parenthesised
    7017              :            * type */
    7018           13 :           std::unique_ptr<AST::TraitBound> converted_bound (
    7019           13 :             released_ptr->to_trait_bound (true));
    7020           13 :           if (converted_bound == nullptr)
    7021              :             {
    7022              :               // parenthesised type
    7023           13 :               return std::unique_ptr<AST::ParenthesisedType> (
    7024           13 :                 new AST::ParenthesisedType (std::move (released_ptr),
    7025           13 :                                             left_paren_locus));
    7026              :             }
    7027              :           else
    7028              :             {
    7029              :               // trait object type (one bound)
    7030              : 
    7031              :               // get value semantics trait bound
    7032            0 :               AST::TraitBound value_bound (*converted_bound);
    7033              : 
    7034            0 :               return std::unique_ptr<AST::TraitObjectTypeOneBound> (
    7035            0 :                 new AST::TraitObjectTypeOneBound (value_bound,
    7036            0 :                                                   left_paren_locus));
    7037            0 :             }
    7038           13 :         }
    7039              :     }
    7040              :   else
    7041              :     {
    7042          319 :       return std::unique_ptr<AST::TupleType> (
    7043          319 :         new AST::TupleType (std::move (types), left_paren_locus));
    7044              :     }
    7045              :   /* TODO: ensure that this ensures that dynamic dispatch for traits is not
    7046              :    * lost somehow */
    7047          332 : }
    7048              : 
    7049              : // Parses tuple struct items if they exist. Does not parse parentheses.
    7050              : template <typename ManagedTokenSource>
    7051              : std::unique_ptr<AST::TupleStructItems>
    7052         2076 : Parser<ManagedTokenSource>::parse_tuple_struct_items ()
    7053              : {
    7054         2076 :   std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
    7055              : 
    7056              :   // DEBUG
    7057         2076 :   rust_debug ("started parsing tuple struct items");
    7058              : 
    7059              :   // check for '..' at front
    7060         4152 :   if (lexer.peek_token ()->get_id () == DOT_DOT)
    7061              :     {
    7062              :       // only parse upper patterns
    7063           25 :       lexer.skip_token ();
    7064              : 
    7065              :       // DEBUG
    7066           25 :       rust_debug ("'..' at front in tuple struct items detected");
    7067              : 
    7068           25 :       std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
    7069              : 
    7070           25 :       const_TokenPtr t = lexer.peek_token ();
    7071           42 :       while (t->get_id () == COMMA)
    7072              :         {
    7073           17 :           lexer.skip_token ();
    7074              : 
    7075              :           // break if right paren
    7076           34 :           if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    7077              :             break;
    7078              : 
    7079              :           // parse pattern, which is now required
    7080           17 :           std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    7081           17 :           if (pattern == nullptr)
    7082              :             {
    7083            0 :               Error error (lexer.peek_token ()->get_locus (),
    7084              :                            "failed to parse pattern in tuple struct items");
    7085            0 :               add_error (std::move (error));
    7086              : 
    7087            0 :               return nullptr;
    7088            0 :             }
    7089           17 :           upper_patterns.push_back (std::move (pattern));
    7090              : 
    7091           17 :           t = lexer.peek_token ();
    7092              :         }
    7093              : 
    7094              :       // DEBUG
    7095           25 :       rust_debug (
    7096              :         "finished parsing tuple struct items ranged (upper/none only)");
    7097              : 
    7098           25 :       return std::unique_ptr<AST::TupleStructItemsHasRest> (
    7099           25 :         new AST::TupleStructItemsHasRest (std::move (lower_patterns),
    7100           25 :                                           std::move (upper_patterns)));
    7101           25 :     }
    7102              : 
    7103              :   // has at least some lower patterns
    7104         2051 :   const_TokenPtr t = lexer.peek_token ();
    7105         2204 :   while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
    7106              :     {
    7107              :       // DEBUG
    7108         2148 :       rust_debug ("about to parse pattern in tuple struct items");
    7109              : 
    7110              :       // parse pattern, which is required
    7111         2148 :       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    7112         2148 :       if (pattern == nullptr)
    7113              :         {
    7114            0 :           Error error (t->get_locus (),
    7115              :                        "failed to parse pattern in tuple struct items");
    7116            0 :           add_error (std::move (error));
    7117              : 
    7118            0 :           return nullptr;
    7119            0 :         }
    7120         2148 :       lower_patterns.push_back (std::move (pattern));
    7121              : 
    7122              :       // DEBUG
    7123         2148 :       rust_debug ("successfully parsed pattern in tuple struct items");
    7124              : 
    7125         4296 :       if (lexer.peek_token ()->get_id () != COMMA)
    7126              :         {
    7127              :           // DEBUG
    7128         1995 :           rust_debug ("broke out of parsing patterns in tuple struct "
    7129              :                       "items as no comma");
    7130              : 
    7131              :           break;
    7132              :         }
    7133          153 :       lexer.skip_token ();
    7134          153 :       t = lexer.peek_token ();
    7135              :     }
    7136              : 
    7137              :   // branch on next token
    7138         2051 :   t = lexer.peek_token ();
    7139         2051 :   switch (t->get_id ())
    7140              :     {
    7141         2021 :     case RIGHT_PAREN:
    7142         2021 :       return std::unique_ptr<AST::TupleStructItemsNoRest> (
    7143         2021 :         new AST::TupleStructItemsNoRest (std::move (lower_patterns)));
    7144           29 :     case DOT_DOT:
    7145              :       {
    7146              :         // has an upper range that must be parsed separately
    7147           29 :         lexer.skip_token ();
    7148              : 
    7149           29 :         std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
    7150              : 
    7151           29 :         t = lexer.peek_token ();
    7152           35 :         while (t->get_id () == COMMA)
    7153              :           {
    7154            6 :             lexer.skip_token ();
    7155              : 
    7156              :             // break if next token is right paren
    7157           12 :             if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
    7158              :               break;
    7159              : 
    7160              :             // parse pattern, which is required
    7161            6 :             std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
    7162            6 :             if (pattern == nullptr)
    7163              :               {
    7164            0 :                 Error error (lexer.peek_token ()->get_locus (),
    7165              :                              "failed to parse pattern in tuple struct items");
    7166            0 :                 add_error (std::move (error));
    7167              : 
    7168            0 :                 return nullptr;
    7169            0 :               }
    7170            6 :             upper_patterns.push_back (std::move (pattern));
    7171              : 
    7172            6 :             t = lexer.peek_token ();
    7173              :           }
    7174              : 
    7175           29 :         return std::unique_ptr<AST::TupleStructItemsHasRest> (
    7176           29 :           new AST::TupleStructItemsHasRest (std::move (lower_patterns),
    7177           29 :                                             std::move (upper_patterns)));
    7178           29 :       }
    7179            1 :     default:
    7180              :       // error
    7181            1 :       add_error (Error (t->get_locus (),
    7182              :                         "unexpected token %qs in tuple struct items",
    7183              :                         t->get_token_description ()));
    7184              : 
    7185            1 :       return nullptr;
    7186              :     }
    7187         2076 : }
    7188              : 
    7189              : /* Parses a statement or expression (depending on whether a trailing semicolon
    7190              :  * exists). Useful for block expressions where it cannot be determined through
    7191              :  * lookahead whether it is a statement or expression to be parsed. */
    7192              : template <typename ManagedTokenSource>
    7193              : tl::expected<ExprOrStmt, Parse::Error::Node>
    7194        80902 : Parser<ManagedTokenSource>::parse_stmt_or_expr ()
    7195              : {
    7196              :   // quick exit for empty statement
    7197        80902 :   const_TokenPtr t = lexer.peek_token ();
    7198        80902 :   if (t->get_id () == SEMICOLON)
    7199              :     {
    7200           18 :       lexer.skip_token ();
    7201           18 :       std::unique_ptr<AST::EmptyStmt> stmt (
    7202           18 :         new AST::EmptyStmt (t->get_locus ()));
    7203           36 :       return ExprOrStmt (std::move (stmt));
    7204           18 :     }
    7205              : 
    7206              :   // parse outer attributes
    7207        80884 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
    7208        80884 :   ParseRestrictions restrictions;
    7209        80884 :   restrictions.expr_can_be_stmt = true;
    7210              : 
    7211              :   // Defered child error checking: we need to check for a semicolon
    7212        80884 :   tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
    7213              : 
    7214              :   // parsing this will be annoying because of the many different possibilities
    7215              :   /* best may be just to copy paste in parse_item switch, and failing that try
    7216              :    * to parse outer attributes, and then pass them in to either a let
    7217              :    * statement or (fallback) expression statement. */
    7218              :   // FIXME: think of a way to do this without such a large switch?
    7219              : 
    7220              :   /* FIXME: for expressions at least, the only way that they can really be
    7221              :    * parsed properly in this way is if they don't support operators on them.
    7222              :    * They must be pratt-parsed otherwise. As such due to composability, only
    7223              :    * explicit statements will have special cases here. This should roughly
    7224              :    * correspond to "expr-with-block", but this warning is here in case it
    7225              :    * isn't the case. */
    7226        80884 :   t = lexer.peek_token ();
    7227        80884 :   switch (t->get_id ())
    7228              :     {
    7229        24483 :     case LET:
    7230              :       {
    7231              :         // let statement
    7232        24483 :         std::unique_ptr<AST::LetStmt> stmt (
    7233        24483 :           parse_let_stmt (std::move (outer_attrs)));
    7234        48966 :         return ExprOrStmt (std::move (stmt));
    7235        24483 :       }
    7236          967 :     case PUB:
    7237              :     case MOD:
    7238              :     case EXTERN_KW:
    7239              :     case USE:
    7240              :     case FN_KW:
    7241              :     case TYPE:
    7242              :     case STRUCT_KW:
    7243              :     case ENUM_KW:
    7244              :     case CONST:
    7245              :     case STATIC_KW:
    7246              :     case AUTO:
    7247              :     case TRAIT:
    7248              :     case IMPL:
    7249              :       {
    7250          967 :         std::unique_ptr<AST::VisItem> item (
    7251          967 :           parse_vis_item (std::move (outer_attrs)));
    7252         1934 :         return ExprOrStmt (std::move (item));
    7253          967 :       }
    7254              :     /* TODO: implement union keyword but not really because of
    7255              :      * context-dependence crappy hack way to parse a union written below to
    7256              :      * separate it from the good code. */
    7257              :     // case UNION:
    7258         4721 :     case UNSAFE:
    7259              :       { // maybe - unsafe traits are a thing
    7260              :         /* if any of these (should be all possible VisItem prefixes), parse a
    7261              :          * VisItem - can't parse item because would require reparsing outer
    7262              :          * attributes */
    7263         4721 :         const_TokenPtr t2 = lexer.peek_token (1);
    7264         4721 :         switch (t2->get_id ())
    7265              :           {
    7266         4698 :           case LEFT_CURLY:
    7267              :             {
    7268              :               // unsafe block: parse as expression
    7269         9396 :               expr = parse_expr (std::move (outer_attrs), restrictions);
    7270              :               break;
    7271              :             }
    7272            0 :           case AUTO:
    7273              :           case TRAIT:
    7274              :             {
    7275              :               // unsafe trait
    7276            0 :               std::unique_ptr<AST::VisItem> item (
    7277            0 :                 parse_vis_item (std::move (outer_attrs)));
    7278            0 :               return ExprOrStmt (std::move (item));
    7279            0 :             }
    7280           23 :           case EXTERN_KW:
    7281              :           case FN_KW:
    7282              :             {
    7283              :               // unsafe function
    7284           23 :               std::unique_ptr<AST::VisItem> item (
    7285           23 :                 parse_vis_item (std::move (outer_attrs)));
    7286           46 :               return ExprOrStmt (std::move (item));
    7287           23 :             }
    7288            0 :           case IMPL:
    7289              :             {
    7290              :               // unsafe trait impl
    7291            0 :               std::unique_ptr<AST::VisItem> item (
    7292            0 :                 parse_vis_item (std::move (outer_attrs)));
    7293            0 :               return ExprOrStmt (std::move (item));
    7294            0 :             }
    7295            0 :           default:
    7296            0 :             add_error (Error (t2->get_locus (),
    7297              :                               "unrecognised token %qs after parsing unsafe - "
    7298              :                               "expected beginning of expression or statement",
    7299              :                               t->get_token_description ()));
    7300              : 
    7301              :             // skip somewhere?
    7302              :             return tl::unexpected<Parse::Error::Node> (
    7303            0 :               Parse::Error::Node::MALFORMED);
    7304              :           }
    7305              :         break;
    7306        62739 :       }
    7307              :       /* FIXME: this is either a macro invocation or macro invocation semi.
    7308              :        * start parsing to determine which one it is. */
    7309              :       // FIXME: old code there
    7310              : 
    7311              :     // crappy hack to do union "keyword"
    7312        29025 :     case IDENTIFIER:
    7313        29025 :       if (t->get_str () == Values::WeakKeywords::UNION
    7314        29061 :           && lexer.peek_token (1)->get_id () == IDENTIFIER)
    7315              :         {
    7316            1 :           std::unique_ptr<AST::VisItem> item (
    7317            1 :             parse_vis_item (std::move (outer_attrs)));
    7318            2 :           return ExprOrStmt (std::move (item));
    7319              :           // or should this go straight to parsing union?
    7320            1 :         }
    7321        29024 :       else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
    7322        29541 :                && lexer.peek_token (1)->get_id () == EXCLAM)
    7323              :         {
    7324              :           // macro_rules! macro item
    7325          517 :           std::unique_ptr<AST::Item> item (
    7326          517 :             parse_macro_rules_def (std::move (outer_attrs)));
    7327         1034 :           return ExprOrStmt (std::move (item));
    7328          517 :         }
    7329              :       gcc_fallthrough ();
    7330              :     case SUPER:
    7331              :     case SELF:
    7332              :     case SELF_ALIAS:
    7333              :     case CRATE:
    7334              :     case SCOPE_RESOLUTION:
    7335              :     case DOLLAR_SIGN:
    7336              :       {
    7337        34967 :         AST::PathInExpression path = parse_path_in_expression ();
    7338              :         tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
    7339        34967 :           null_denotation;
    7340              : 
    7341        69934 :         if (lexer.peek_token ()->get_id () == EXCLAM)
    7342              :           {
    7343         2704 :             std::unique_ptr<AST::MacroInvocation> invoc
    7344         5408 :               = parse_macro_invocation_partial (std::move (path),
    7345              :                                                 std::move (outer_attrs));
    7346         2704 :             if (invoc == nullptr)
    7347              :               return tl::unexpected<Parse::Error::Node> (
    7348            0 :                 Parse::Error::Node::CHILD_ERROR);
    7349              : 
    7350         2704 :             if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
    7351              :               {
    7352         1516 :                 invoc->add_semicolon ();
    7353              :                 // Macro invocation with semicolon.
    7354         1516 :                 return ExprOrStmt (
    7355         3032 :                   std::unique_ptr<AST::Stmt> (std::move (invoc)));
    7356              :               }
    7357              : 
    7358         2376 :             TokenId after_macro = lexer.peek_token ()->get_id ();
    7359              : 
    7360         1188 :             AST::DelimType delim_type = invoc->get_invoc_data ()
    7361         1188 :                                           .get_delim_tok_tree ()
    7362         1188 :                                           .get_delim_type ();
    7363              : 
    7364         1188 :             if (delim_type == AST::CURLY && after_macro != DOT
    7365           20 :                 && after_macro != QUESTION_MARK)
    7366              :               {
    7367           20 :                 rust_debug ("braced macro statement");
    7368           20 :                 return ExprOrStmt (
    7369           40 :                   std::unique_ptr<AST::Stmt> (std::move (invoc)));
    7370              :               }
    7371              : 
    7372         1168 :             null_denotation = std::move (invoc);
    7373         2704 :           }
    7374              :         else
    7375              :           {
    7376              :             null_denotation
    7377        64525 :               = null_denotation_path (std::move (path), {}, restrictions);
    7378              :           }
    7379              : 
    7380       133718 :         expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
    7381              :                                  std::move (outer_attrs), restrictions);
    7382              :         break;
    7383        34967 :       }
    7384        15228 :     default:
    7385              :       /* expression statement or expression itself - parse
    7386              :        * expression then make it statement if semi afterwards */
    7387        30426 :       expr = parse_expr (std::move (outer_attrs), restrictions);
    7388        15228 :       break;
    7389              :     }
    7390              : 
    7391        53357 :   const_TokenPtr after_expr = lexer.peek_token ();
    7392        53357 :   if (after_expr->get_id () == SEMICOLON)
    7393              :     {
    7394              :       // must be expression statement
    7395        14810 :       lexer.skip_token ();
    7396              : 
    7397        14810 :       if (expr)
    7398              :         {
    7399        14809 :           return ExprOrStmt (
    7400        29618 :             std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
    7401        44427 :                                              t->get_locus (), true));
    7402              :         }
    7403              :       else
    7404              :         {
    7405              :           return tl::unexpected<Parse::Error::Node> (
    7406            1 :             Parse::Error::Node::CHILD_ERROR);
    7407              :         }
    7408              :     }
    7409              : 
    7410        38547 :   if (expr)
    7411              :     {
    7412              :       // block expression statement.
    7413        38515 :       if (!expr.value ()->is_expr_without_block ()
    7414        38515 :           && after_expr->get_id () != RIGHT_CURLY)
    7415         3614 :         return ExprOrStmt (
    7416         7228 :           std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
    7417        10842 :                                            t->get_locus (), false));
    7418              : 
    7419              :       // Check if expr_without_block is properly terminated
    7420        34901 :       if (expr.value ()->is_expr_without_block ()
    7421        34901 :           && after_expr->get_id () != RIGHT_CURLY)
    7422              :         {
    7423              :           // expr_without_block must be followed by ';' or '}'
    7424            1 :           Error error (after_expr->get_locus (),
    7425              :                        "expected %<;%> or %<}%> after expression, found %qs",
    7426              :                        after_expr->get_token_description ());
    7427            1 :           add_error (std::move (error));
    7428              :           return tl::unexpected<Parse::Error::Node> (
    7429            1 :             Parse::Error::Node::MALFORMED);
    7430            1 :         }
    7431              :     }
    7432              : 
    7433              :   // return expression
    7434        34932 :   if (expr)
    7435        69800 :     return ExprOrStmt (std::move (expr.value ()));
    7436              :   else
    7437           32 :     return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
    7438       134241 : }
    7439              : 
    7440              : } // namespace Rust
    7441              : 
    7442              : #include "rust-parse-impl-utils.hxx"
    7443              : #include "rust-parse-impl-attribute.hxx"
    7444              : #include "rust-parse-impl-ttree.hxx"
    7445              : #include "rust-parse-impl-macro.hxx"
    7446              : #include "rust-parse-impl-path.hxx"
    7447              : #include "rust-parse-impl-pattern.hxx"
    7448              : #include "rust-parse-impl-expr.hxx"
        

Generated by: LCOV version 2.5.0-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.