LCOV - code coverage report
Current view: top level - gcc/rust/ast - rust-path.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 83.1 % 532 442
Test Date: 2026-08-22 16:33:35 Functions: 84.9 % 139 118
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              : #ifndef RUST_AST_PATH_H
      20              : #define RUST_AST_PATH_H
      21              : /* "Path" (identifier within namespaces, essentially) handling. Required include
      22              :  * for virtually all AST-related functionality. */
      23              : 
      24              : #include "optional.h"
      25              : #include "rust-ast.h"
      26              : #include "rust-hir-map.h"
      27              : #include "rust-mapping-common.h"
      28              : #include "rust-system.h"
      29              : #include "system.h"
      30              : 
      31              : namespace Rust {
      32              : namespace AST {
      33              : 
      34              : // The "identifier" (not generic args) aspect of each path expression segment
      35      2365193 : class PathIdentSegment
      36              : {
      37              :   std::string segment_name;
      38              :   location_t locus;
      39              : 
      40              :   // only allow identifiers, "super", "self", "Self", "crate", or "$crate"
      41              : public:
      42       578172 :   PathIdentSegment (std::string segment_name, location_t locus)
      43       584892 :     : segment_name (std::move (segment_name)), locus (locus)
      44              :   {}
      45              : 
      46              :   // Creates an error PathIdentSegment.
      47            9 :   static PathIdentSegment create_error ()
      48              :   {
      49            9 :     return PathIdentSegment ("", UNDEF_LOCATION);
      50              :   }
      51              : 
      52              :   // Returns whether PathIdentSegment is in an error state.
      53       470108 :   bool is_error () const { return segment_name.empty (); }
      54              : 
      55      1026403 :   std::string as_string () const { return segment_name; }
      56              : 
      57       351978 :   location_t get_locus () const { return locus; }
      58              : 
      59        37549 :   bool is_super_path_seg () const
      60              :   {
      61        75098 :     return as_string ().compare ("super") == 0;
      62              :   }
      63        37548 :   bool is_crate_path_seg () const
      64              :   {
      65        75096 :     return as_string ().compare ("crate") == 0;
      66              :   }
      67       674872 :   bool is_lower_self_seg () const { return as_string ().compare ("self") == 0; }
      68       309522 :   bool is_big_self_seg () const { return as_string ().compare ("Self") == 0; }
      69              : };
      70              : 
      71              : // A binding of an identifier to a type used in generic arguments in paths
      72              : struct GenericArgsBinding
      73              : {
      74              : private:
      75              :   Identifier identifier;
      76              :   std::unique_ptr<Type> type;
      77              :   location_t locus;
      78              : 
      79              : public:
      80              :   // Returns whether binding is in an error state.
      81          331 :   bool is_error () const
      82              :   {
      83          331 :     return type == nullptr;
      84              :     // and also identifier is empty, but cheaper computation
      85              :   }
      86              : 
      87            0 :   GenericArgsBinding reconstruct () const
      88              :   {
      89            0 :     std::unique_ptr<Type> new_type = nullptr;
      90            0 :     if (type)
      91            0 :       new_type = type->reconstruct ();
      92              : 
      93            0 :     return GenericArgsBinding (identifier, std::move (new_type), locus);
      94            0 :   }
      95              : 
      96              :   // Creates an error state generic args binding.
      97            0 :   static GenericArgsBinding create_error ()
      98              :   {
      99            0 :     return GenericArgsBinding ({""}, nullptr);
     100              :   }
     101              : 
     102              :   // Pointer type for type in constructor to enable polymorphism
     103          331 :   GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr,
     104              :                       location_t locus = UNDEF_LOCATION)
     105          331 :     : identifier (std::move (ident)), type (std::move (type_ptr)), locus (locus)
     106              :   {}
     107              : 
     108              :   // Copy constructor has to deep copy the type as it is a unique pointer
     109         1468 :   GenericArgsBinding (GenericArgsBinding const &other)
     110         1468 :     : identifier (other.identifier), locus (other.locus)
     111              :   {
     112              :     // guard to protect from null pointer dereference
     113         1468 :     if (other.type != nullptr)
     114         1468 :       type = other.type->clone_type ();
     115         1468 :   }
     116              : 
     117              :   // default destructor
     118         1807 :   ~GenericArgsBinding () = default;
     119              : 
     120              :   // Overload assignment operator to deep copy the pointed-to type
     121              :   GenericArgsBinding &operator= (GenericArgsBinding const &other)
     122              :   {
     123              :     identifier = other.identifier;
     124              :     locus = other.locus;
     125              : 
     126              :     // guard to protect from null pointer dereference
     127              :     if (other.type != nullptr)
     128              :       type = other.type->clone_type ();
     129              :     else
     130              :       type = nullptr;
     131              : 
     132              :     return *this;
     133              :   }
     134              : 
     135              :   // move constructors
     136          339 :   GenericArgsBinding (GenericArgsBinding &&other) = default;
     137              :   GenericArgsBinding &operator= (GenericArgsBinding &&other) = default;
     138              : 
     139              :   std::string as_string () const;
     140              : 
     141              :   // TODO: is this better? Or is a "vis_pattern" better?
     142        45667 :   Type &get_type ()
     143              :   {
     144        45667 :     rust_assert (type != nullptr);
     145        45667 :     return *type;
     146              :   }
     147              : 
     148        18384 :   std::unique_ptr<Type> &get_type_ptr ()
     149              :   {
     150        18384 :     rust_assert (type != nullptr);
     151        18384 :     return type;
     152              :   }
     153              : 
     154          112 :   location_t get_locus () const { return locus; }
     155              : 
     156          112 :   Identifier get_identifier () const { return identifier; }
     157              : };
     158              : 
     159              : /* Class representing a const generic application */
     160              : class GenericArg
     161              : {
     162              : public:
     163              :   /**
     164              :    * const generic arguments cannot always be differentiated with generic type
     165              :    * arguments during parsing, e.g:
     166              :    * ```rust
     167              :    * let a: Foo<N>;
     168              :    * ```
     169              :    *
     170              :    * Is N a type? A constant defined elsewhere? The parser cannot know, and must
     171              :    * not draw any conclusions. We must wait until later passes of the compiler
     172              :    * to decide whether this refers to a constant item or a type.
     173              :    *
     174              :    * On the other hand, simple expressions like literals or block expressions
     175              :    * will always be constant expressions: There is no ambiguity at all.
     176              :    */
     177              :   enum class Kind
     178              :   {
     179              :     Const,  // A const value
     180              :     Type,   // A type argument (not discernable during parsing)
     181              :     Either, // Either a type or a const value, cleared up during resolving
     182              :   };
     183              : 
     184          186 :   static GenericArg create_const (std::unique_ptr<Expr> expression)
     185              :   {
     186          186 :     auto locus = expression->get_locus ();
     187          186 :     return GenericArg (std::move (expression), nullptr, {""}, Kind::Const,
     188          372 :                        locus);
     189              :   }
     190              : 
     191        18297 :   static GenericArg create_type (std::unique_ptr<Type> type)
     192              :   {
     193        18297 :     auto locus = type->get_locus ();
     194        54891 :     return GenericArg (nullptr, std::move (type), {""}, Kind::Type, locus);
     195              :   }
     196              : 
     197        13641 :   static GenericArg create_ambiguous (Identifier path, location_t locus)
     198              :   {
     199        27282 :     return GenericArg (nullptr, nullptr, std::move (path), Kind::Either, locus);
     200              :   }
     201              : 
     202            3 :   GenericArg reconstruct () const
     203              :   {
     204            3 :     switch (kind)
     205              :       {
     206            0 :       case Kind::Type:
     207            0 :         return create_type (type->reconstruct ());
     208            0 :       case Kind::Const:
     209              :         // FIXME: Use reconstruct_expr when available
     210            0 :         return create_const (expression->clone_expr ());
     211            3 :       case Kind::Either:
     212            3 :       default:
     213              :         // For ambiguous or error states, copy constructs are sufficient
     214            3 :         return GenericArg (*this);
     215              :       }
     216              :   }
     217              : 
     218       111880 :   GenericArg (const GenericArg &other)
     219       111880 :     : path (other.path), kind (other.kind), locus (other.locus)
     220              :   {
     221       111880 :     if (other.expression)
     222          268 :       expression = other.expression->clone_expr ();
     223       111880 :     if (other.type)
     224        37988 :       type = other.type->clone_type ();
     225       111880 :   }
     226              : 
     227              :   GenericArg operator= (const GenericArg &other)
     228              :   {
     229              :     kind = other.kind;
     230              :     path = other.path;
     231              :     locus = other.locus;
     232              : 
     233              :     if (other.expression)
     234              :       expression = other.expression->clone_expr ();
     235              :     if (other.type)
     236              :       type = other.type->clone_type ();
     237              : 
     238              :     return *this;
     239              :   }
     240              : 
     241        39961 :   GenericArg (GenericArg &&other) = default;
     242        12335 :   GenericArg &operator= (GenericArg &&other) = default;
     243              : 
     244      3851161 :   Kind get_kind () const { return kind; }
     245            0 :   location_t get_locus () const { return locus; }
     246              : 
     247      2093966 :   void accept_vis (AST::ASTVisitor &visitor)
     248              :   {
     249      2093966 :     switch (get_kind ())
     250              :       {
     251         2681 :       case Kind::Const:
     252         2681 :         get_expression ().accept_vis (visitor);
     253         2681 :         break;
     254       674042 :       case Kind::Type:
     255       674042 :         get_type ().accept_vis (visitor);
     256       674042 :         break;
     257              :       case Kind::Either:
     258              :         break;
     259              :       }
     260      2093966 :   }
     261              : 
     262         3503 :   Expr &get_expression ()
     263              :   {
     264         3503 :     rust_assert (kind == Kind::Const);
     265              : 
     266         3503 :     return *expression;
     267              :   }
     268              : 
     269          323 :   std::unique_ptr<Expr> &get_expression_ptr ()
     270              :   {
     271          323 :     rust_assert (kind == Kind::Const);
     272              : 
     273          323 :     return expression;
     274              :   }
     275              : 
     276      1034527 :   Type &get_type ()
     277              :   {
     278      1034527 :     rust_assert (kind == Kind::Type);
     279              : 
     280      1034527 :     return *type;
     281              :   }
     282              : 
     283       153683 :   std::unique_ptr<Type> &get_type_ptr ()
     284              :   {
     285       153683 :     rust_assert (kind == Kind::Type);
     286              : 
     287       153683 :     return type;
     288              :   }
     289              : 
     290        24675 :   const std::string get_path () const
     291              :   {
     292        24675 :     rust_assert (kind == Kind::Either);
     293              : 
     294        24675 :     return path.as_string ();
     295              :   }
     296              : 
     297            0 :   std::string as_string () const
     298              :   {
     299            0 :     switch (get_kind ())
     300              :       {
     301            0 :       case Kind::Either:
     302            0 :         return "Ambiguous: " + path.as_string ();
     303            0 :       case Kind::Const:
     304            0 :         return "Const: { " + expression->as_string () + " }";
     305            0 :       case Kind::Type:
     306            0 :         return "Type: " + type->as_string ();
     307              :       }
     308              : 
     309            0 :     return "";
     310              :   }
     311              : 
     312              :   /**
     313              :    * Disambiguate an ambiguous generic argument to a const generic argument,
     314              :    * unequivocally
     315              :    */
     316              :   GenericArg disambiguate_to_const () const;
     317              : 
     318              :   /**
     319              :    * Disambiguate an ambiguous generic argument to a type argument,
     320              :    * unequivocally
     321              :    */
     322              :   GenericArg disambiguate_to_type () const;
     323              : 
     324              : private:
     325        32124 :   GenericArg (std::unique_ptr<Expr> expression, std::unique_ptr<Type> type,
     326              :               Identifier path, Kind kind, location_t locus)
     327        14014 :     : expression (std::move (expression)), type (std::move (type)),
     328        32124 :       path (std::move (path)), kind (kind), locus (locus)
     329              :   {}
     330              : 
     331              :   /**
     332              :    * Expression associated with a `Clear` const generic application
     333              :    * A null pointer here is allowed in the case that the const argument is
     334              :    * ambiguous.
     335              :    */
     336              :   std::unique_ptr<Expr> expression;
     337              : 
     338              :   /**
     339              :    * If the argument ends up being a type argument instead. A null pointer will
     340              :    * be present here until the resolving phase.
     341              :    */
     342              :   std::unique_ptr<Type> type;
     343              : 
     344              :   /**
     345              :    * Optional path which cannot be differentiated between a constant item and
     346              :    * a type. Only used for ambiguous const generic arguments, otherwise
     347              :    * empty.
     348              :    */
     349              :   Identifier path;
     350              : 
     351              :   /* Which kind of const generic application are we dealing with */
     352              :   Kind kind;
     353              : 
     354              :   location_t locus;
     355              : };
     356              : 
     357              : /**
     358              :  * Representation of const generic parameters
     359              :  */
     360              : class ConstGenericParam : public GenericParam
     361              : {
     362              :   /* Name of the parameter */
     363              :   Identifier name;
     364              : 
     365              :   /* Mandatory type of the const parameter - a null pointer is an error */
     366              :   std::unique_ptr<AST::Type> type;
     367              : 
     368              :   /**
     369              :    * Default value for the const generic parameter
     370              :    */
     371              :   tl::optional<GenericArg> default_value;
     372              : 
     373              :   AST::AttrVec outer_attrs;
     374              :   location_t locus;
     375              : 
     376              : public:
     377          186 :   ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type,
     378              :                      tl::optional<GenericArg> default_value,
     379              :                      AST::AttrVec outer_attrs, location_t locus)
     380          186 :     : name (name), type (std::move (type)),
     381          186 :       default_value (std::move (default_value)), outer_attrs (outer_attrs),
     382          186 :       locus (locus)
     383          186 :   {}
     384              : 
     385          396 :   ConstGenericParam (const ConstGenericParam &other)
     386          396 :     : GenericParam (), name (other.name), type (other.type->clone_type ()),
     387          396 :       default_value (other.default_value), outer_attrs (other.outer_attrs),
     388          396 :       locus (other.locus)
     389          396 :   {}
     390              : 
     391        16284 :   bool has_type () const { return type != nullptr; }
     392        16456 :   bool has_default_value () const { return default_value.has_value (); }
     393              : 
     394         3028 :   const Identifier &get_name () const { return name; }
     395              : 
     396        16371 :   AST::AttrVec &get_outer_attrs () { return outer_attrs; }
     397              : 
     398        13270 :   AST::Type &get_type ()
     399              :   {
     400        13270 :     rust_assert (has_type ());
     401              : 
     402        13270 :     return *type;
     403              :   }
     404              : 
     405         3014 :   std::unique_ptr<AST::Type> &get_type_ptr ()
     406              :   {
     407         3014 :     rust_assert (has_type ());
     408              : 
     409         3014 :     return type;
     410              :   }
     411              : 
     412          361 :   GenericArg &get_default_value_unchecked ()
     413              :   {
     414          361 :     rust_assert (has_default_value ());
     415              : 
     416          361 :     return default_value.value ();
     417              :   }
     418              : 
     419            0 :   const GenericArg &get_default_value_unchecked () const
     420              :   {
     421            0 :     rust_assert (has_default_value ());
     422              : 
     423            0 :     return default_value.value ();
     424              :   }
     425              : 
     426            7 :   tl::optional<GenericArg> &get_default_value () { return default_value; }
     427              : 
     428              :   const tl::optional<GenericArg> &get_default_value () const
     429              :   {
     430              :     return default_value;
     431              :   }
     432              : 
     433              :   std::string as_string () const override;
     434              : 
     435              :   void accept_vis (ASTVisitor &vis) override;
     436              : 
     437         3197 :   location_t get_locus () const override final { return locus; }
     438              : 
     439          544 :   Kind get_kind () const override final { return Kind::Const; }
     440              : 
     441              : protected:
     442              :   /* Use covariance to implement clone function as returning this object rather
     443              :    * than base */
     444          396 :   ConstGenericParam *clone_generic_param_impl () const override
     445              :   {
     446          396 :     return new ConstGenericParam (*this);
     447              :   }
     448              : };
     449              : 
     450              : // Generic arguments allowed in each path expression segment - inline?
     451              : struct GenericArgs
     452              : {
     453              :   std::vector<Lifetime> lifetime_args;
     454              :   std::vector<GenericArg> generic_args;
     455              :   std::vector<GenericArgsBinding> binding_args;
     456              :   location_t locus;
     457              : 
     458              : public:
     459              :   // Returns true if there are any generic arguments
     460     39012808 :   bool has_generic_args () const
     461              :   {
     462     38644751 :     return !(lifetime_args.empty () && generic_args.empty ()
     463     34992523 :              && binding_args.empty ());
     464              :   }
     465              : 
     466       443080 :   GenericArgs (std::vector<Lifetime> lifetime_args,
     467              :                std::vector<GenericArg> generic_args,
     468              :                std::vector<GenericArgsBinding> binding_args,
     469              :                location_t locus = UNDEF_LOCATION)
     470       443080 :     : lifetime_args (std::move (lifetime_args)),
     471       443080 :       generic_args (std::move (generic_args)),
     472       443080 :       binding_args (std::move (binding_args)), locus (locus)
     473       443080 :   {}
     474              : 
     475              :   // copy constructor with vector clone
     476       972359 :   GenericArgs (GenericArgs const &other)
     477       972359 :     : lifetime_args (other.lifetime_args), binding_args (other.binding_args),
     478       972359 :       locus (other.locus)
     479              :   {
     480       972359 :     generic_args.clear ();
     481       972359 :     generic_args.reserve (other.generic_args.size ());
     482      1083547 :     for (const auto &arg : other.generic_args)
     483       111188 :       generic_args.emplace_back (arg);
     484       972359 :   }
     485              : 
     486      2183888 :   ~GenericArgs () = default;
     487              : 
     488          196 :   GenericArgs reconstruct () const
     489              :   {
     490          196 :     std::vector<GenericArg> new_args;
     491          196 :     new_args.reserve (generic_args.size ());
     492          199 :     for (const auto &arg : generic_args)
     493            3 :       new_args.push_back (arg.reconstruct ());
     494              : 
     495          196 :     std::vector<GenericArgsBinding> new_bindings;
     496          196 :     new_bindings.reserve (binding_args.size ());
     497          196 :     for (const auto &binding : binding_args)
     498            0 :       new_bindings.push_back (binding.reconstruct ());
     499              : 
     500              :     // Lifetimes are values, so they can be copied directly
     501          196 :     return GenericArgs (lifetime_args, std::move (new_args),
     502          196 :                         std::move (new_bindings), locus);
     503          196 :   }
     504              : 
     505              :   // overloaded assignment operator to vector clone
     506              :   GenericArgs &operator= (GenericArgs const &other)
     507              :   {
     508              :     lifetime_args = other.lifetime_args;
     509              :     binding_args = other.binding_args;
     510              :     locus = other.locus;
     511              : 
     512              :     generic_args.clear ();
     513              :     generic_args.reserve (other.generic_args.size ());
     514              :     for (const auto &arg : other.generic_args)
     515              :       generic_args.emplace_back (arg);
     516              : 
     517              :     return *this;
     518              :   }
     519              : 
     520              :   // move constructors
     521       935754 :   GenericArgs (GenericArgs &&other) = default;
     522              :   GenericArgs &operator= (GenericArgs &&other) = default;
     523              : 
     524              :   // Creates an empty GenericArgs (no arguments)
     525       421440 :   static GenericArgs create_empty () { return GenericArgs ({}, {}, {}); }
     526              : 
     527              :   std::string as_string () const;
     528              : 
     529      3942734 :   std::vector<GenericArg> &get_generic_args () { return generic_args; }
     530              : 
     531      3942745 :   std::vector<GenericArgsBinding> &get_binding_args () { return binding_args; }
     532              : 
     533              :   const std::vector<GenericArgsBinding> &get_binding_args () const
     534              :   {
     535              :     return binding_args;
     536              :   }
     537              : 
     538      1622877 :   std::vector<Lifetime> &get_lifetime_args () { return lifetime_args; };
     539              : 
     540              :   const std::vector<Lifetime> &get_lifetime_args () const
     541              :   {
     542              :     return lifetime_args;
     543              :   };
     544              : 
     545         4594 :   location_t get_locus () const { return locus; }
     546              : };
     547              : 
     548              : /* A segment of a path in expression, including an identifier aspect and maybe
     549              :  * generic args */
     550      1420851 : class PathExprSegment
     551              : { // or should this extend PathIdentSegment?
     552              : private:
     553              :   PathIdentSegment segment_name;
     554              :   GenericArgs generic_args;
     555              :   location_t locus;
     556              :   NodeId node_id;
     557              : 
     558              : public:
     559              :   // Returns true if there are any generic arguments
     560     50065981 :   bool has_generic_args () const { return generic_args.has_generic_args (); }
     561              : 
     562              :   // Constructor for segment (from IdentSegment and GenericArgs)
     563       423034 :   PathExprSegment (PathIdentSegment segment_name, location_t locus,
     564              :                    GenericArgs generic_args = GenericArgs::create_empty ())
     565       423034 :     : segment_name (std::move (segment_name)),
     566       423034 :       generic_args (std::move (generic_args)), locus (locus),
     567       423034 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     568       423034 :   {}
     569              : 
     570              :   /* Constructor for segment with generic arguments (from segment name and all
     571              :    * args) */
     572          514 :   PathExprSegment (std::string segment_name, location_t locus,
     573              :                    std::vector<Lifetime> lifetime_args = {},
     574              :                    std::vector<GenericArg> generic_args = {},
     575              :                    std::vector<GenericArgsBinding> binding_args = {})
     576          514 :     : segment_name (PathIdentSegment (std::move (segment_name), locus)),
     577          514 :       generic_args (GenericArgs (std::move (lifetime_args),
     578              :                                  std::move (generic_args),
     579          514 :                                  std::move (binding_args))),
     580          514 :       locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ())
     581          514 :   {}
     582              : 
     583              :   // Returns whether path expression segment is in an error state.
     584       469583 :   bool is_error () const { return segment_name.is_error (); }
     585              : 
     586              :   // Creates an error-state path expression segment.
     587            9 :   static PathExprSegment create_error ()
     588              :   {
     589            9 :     return PathExprSegment (PathIdentSegment::create_error (), UNDEF_LOCATION);
     590              :   }
     591              : 
     592              :   std::string as_string () const;
     593              : 
     594        92687 :   location_t get_locus () const { return locus; }
     595              : 
     596              :   // TODO: is this better? Or is a "vis_pattern" better?
     597       144289 :   GenericArgs &get_generic_args ()
     598              :   {
     599       144289 :     rust_assert (has_generic_args ());
     600       144289 :     return generic_args;
     601              :   }
     602              : 
     603     20671057 :   PathIdentSegment &get_ident_segment () { return segment_name; }
     604       421285 :   const PathIdentSegment &get_ident_segment () const { return segment_name; }
     605              : 
     606       165638 :   NodeId get_node_id () const { return node_id; }
     607              : 
     608          192 :   PathExprSegment reconstruct () const
     609              :   {
     610          192 :     return PathExprSegment (segment_name, locus, generic_args.reconstruct ());
     611              :   }
     612              : 
     613              :   bool is_super_path_seg () const
     614              :   {
     615              :     return !has_generic_args () && get_ident_segment ().is_super_path_seg ();
     616              :   }
     617              : 
     618              :   bool is_crate_path_seg () const
     619              :   {
     620              :     return !has_generic_args () && get_ident_segment ().is_crate_path_seg ();
     621              :   }
     622              : 
     623       301496 :   bool is_lower_self_seg () const
     624              :   {
     625       602480 :     return !has_generic_args () && get_ident_segment ().is_lower_self_seg ();
     626              :   }
     627              : };
     628              : 
     629              : // AST node representing a pattern that involves a "path" - abstract base
     630              : // class
     631              : class Path : public Pattern
     632              : {
     633              : public:
     634              :   enum class Kind
     635              :   {
     636              :     LangItem,
     637              :     Regular,
     638              :   };
     639              : 
     640       372435 :   Path (std::vector<PathExprSegment> segments)
     641       372435 :     : segments (std::move (segments)), lang_item (tl::nullopt),
     642       372435 :       kind (Kind::Regular)
     643              :   {}
     644              : 
     645         1732 :   Path (LangItem::Kind lang_item)
     646         1732 :     : segments ({}), lang_item (lang_item), kind (Kind::LangItem)
     647         1732 :   {}
     648              : 
     649              :   // Returns whether path has segments.
     650       130383 :   bool has_segments () const
     651              :   {
     652       130383 :     rust_assert (kind == Kind::Regular);
     653       130383 :     return !segments.empty ();
     654              :   }
     655              : 
     656              :   /* Converts path segments to their equivalent SimplePath segments if
     657              :    * possible, and creates a SimplePath from them. */
     658              :   SimplePath convert_to_simple_path (bool with_opening_scope_resolution) const;
     659              : 
     660              :   /* Returns whether the path is a single segment (excluding qualified path
     661              :    * initial as segment). */
     662       523917 :   bool is_single_segment () const
     663              :   {
     664       523917 :     rust_assert (kind == Kind::Regular);
     665       523917 :     return segments.size () == 1;
     666              :   }
     667              : 
     668              :   std::string as_string () const override;
     669              : 
     670     19542413 :   bool is_lang_item () const { return kind == Kind::LangItem; }
     671              : 
     672              :   // TODO: this seems kinda dodgy
     673     19894390 :   std::vector<PathExprSegment> &get_segments ()
     674              :   {
     675     19894390 :     rust_assert (kind == Kind::Regular);
     676     19894390 :     return segments;
     677              :   }
     678       100186 :   const std::vector<PathExprSegment> &get_segments () const
     679              :   {
     680       100186 :     rust_assert (kind == Kind::Regular);
     681       100186 :     return segments;
     682              :   }
     683              : 
     684         2012 :   LangItem::Kind get_lang_item () const
     685              :   {
     686         2012 :     rust_assert (kind == Kind::LangItem);
     687         2012 :     return *lang_item;
     688              :   }
     689              : 
     690        24440 :   Pattern::Kind get_pattern_kind () override { return Pattern::Kind::Path; }
     691              :   Path::Kind get_path_kind () { return kind; }
     692              : 
     693              : protected:
     694              :   std::vector<PathExprSegment> segments;
     695              :   tl::optional<LangItem::Kind> lang_item;
     696              : 
     697              :   Path::Kind kind;
     698              : };
     699              : 
     700              : /* AST node representing a path-in-expression pattern (path that allows
     701              :  * generic arguments) */
     702              : class PathInExpression : public Path, public ExprWithoutBlock
     703              : {
     704              :   std::vector<Attribute> outer_attrs;
     705              :   bool has_opening_scope_resolution;
     706              :   location_t locus;
     707              :   NodeId _node_id;
     708              : 
     709              :   bool marked_for_strip;
     710              : 
     711              : public:
     712              :   std::string as_string () const override;
     713              : 
     714              :   // Constructor
     715       372219 :   PathInExpression (std::vector<PathExprSegment> path_segments,
     716              :                     std::vector<Attribute> outer_attrs, location_t locus,
     717              :                     bool has_opening_scope_resolution = false)
     718       372219 :     : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)),
     719       372219 :       has_opening_scope_resolution (has_opening_scope_resolution),
     720       372219 :       locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ()),
     721       372219 :       marked_for_strip (false)
     722       372219 :   {}
     723              : 
     724         1732 :   PathInExpression (LangItem::Kind lang_item,
     725              :                     std::vector<Attribute> outer_attrs, location_t locus)
     726         1732 :     : Path (lang_item), outer_attrs (std::move (outer_attrs)),
     727         1732 :       has_opening_scope_resolution (false), locus (locus),
     728         1732 :       _node_id (Analysis::Mappings::get ().get_next_node_id ()),
     729         1732 :       marked_for_strip (false)
     730         1732 :   {}
     731              : 
     732              :   // Creates an error state path in expression.
     733            9 :   static PathInExpression create_error ()
     734              :   {
     735            9 :     return PathInExpression (std::vector<PathExprSegment> (), {},
     736           18 :                              UNDEF_LOCATION);
     737              :   }
     738              : 
     739              :   // Returns whether path in expression is in an error state.
     740        77111 :   bool is_error () const { return !has_segments (); }
     741              : 
     742              :   /* Converts PathInExpression to SimplePath if possible (i.e. no generic
     743              :    * arguments). Otherwise returns an empty SimplePath. */
     744        53272 :   SimplePath as_simple_path () const
     745              :   {
     746              :     /* delegate to parent class as can't access segments. however,
     747              :      * QualifiedPathInExpression conversion to simple path wouldn't make
     748              :      * sense, so the method in the parent class should be protected, not
     749              :      * public. Have to pass in opening scope resolution as parent class has no
     750              :      * access to it.
     751              :      */
     752        53272 :     return convert_to_simple_path (has_opening_scope_resolution);
     753              :   }
     754              : 
     755           96 :   std::unique_ptr<PathInExpression> reconstruct () const
     756              :   {
     757           96 :     std::vector<PathExprSegment> new_segments;
     758           96 :     new_segments.reserve (segments.size ());
     759          288 :     for (const auto &seg : segments)
     760          384 :       new_segments.push_back (seg.reconstruct ());
     761              : 
     762           96 :     auto *new_path
     763           96 :       = new PathInExpression (std::move (new_segments), outer_attrs, locus,
     764           96 :                               has_opening_scope_resolution);
     765              : 
     766           96 :     return std::unique_ptr<PathInExpression> (new_path);
     767           96 :   }
     768              : 
     769       276570 :   location_t get_locus () const override final { return locus; }
     770              : 
     771              :   void accept_vis (ASTVisitor &vis) override;
     772              : 
     773            0 :   void mark_for_strip () override { marked_for_strip = true; }
     774      5800748 :   bool is_marked_for_strip () const override { return marked_for_strip; }
     775              : 
     776       151576 :   bool opening_scope_resolution () const
     777              :   {
     778       151576 :     return has_opening_scope_resolution;
     779              :   }
     780              : 
     781      2574871 :   NodeId get_node_id () const override { return _node_id; }
     782              : 
     783              :   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
     784     23054723 :   std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
     785              : 
     786        26250 :   void set_outer_attrs (std::vector<Attribute> new_attrs) override
     787              :   {
     788        26250 :     outer_attrs = std::move (new_attrs);
     789            0 :   }
     790              : 
     791              :   PathExprSegment &get_final_segment () { return get_segments ().back (); }
     792              :   const PathExprSegment &get_final_segment () const
     793              :   {
     794              :     return get_segments ().back ();
     795              :   }
     796              : 
     797        95570 :   Expr::Kind get_expr_kind () const override
     798              :   {
     799        95570 :     return Expr::Kind::PathInExpression;
     800              :   }
     801              : 
     802              : protected:
     803              :   /* Use covariance to implement clone function as returning this object
     804              :    * rather than base */
     805         4651 :   PathInExpression *clone_pattern_impl () const final override
     806              :   {
     807         4651 :     return clone_path_in_expression_impl ();
     808              :   }
     809              : 
     810              :   /* Use covariance to implement clone function as returning this object
     811              :    * rather than base */
     812            0 :   PathInExpression *clone_expr_without_block_impl () const final override
     813              :   {
     814            0 :     return clone_path_in_expression_impl ();
     815              :   }
     816              : 
     817       575797 :   /*virtual*/ PathInExpression *clone_path_in_expression_impl () const
     818              :   {
     819       575797 :     return new PathInExpression (*this);
     820              :   }
     821              : };
     822              : 
     823              : /* Base class for segments used in type paths - not abstract (represents an
     824              :  * ident-only segment) */
     825              : class TypePathSegment
     826              : {
     827              : public:
     828              :   enum SegmentType
     829              :   {
     830              :     REG,
     831              :     GENERIC,
     832              :     FUNCTION
     833              :   };
     834              : 
     835              : private:
     836              :   tl::optional<LangItem::Kind> lang_item;
     837              :   PathIdentSegment ident_segment;
     838              :   location_t locus;
     839              : 
     840              : protected:
     841              :   /* This is protected because it is only really used by derived classes, not
     842              :    * the base. */
     843              :   bool has_separating_scope_resolution;
     844              :   NodeId node_id;
     845              : 
     846              : public:
     847              :   // Clone function implementation - not pure virtual as overrided by
     848              :   // subclasses
     849       473357 :   virtual TypePathSegment *clone_type_path_segment_impl () const
     850              :   {
     851       473357 :     return new TypePathSegment (*this);
     852              :   }
     853          174 :   virtual TypePathSegment *reconstruct_impl () const
     854              :   {
     855          348 :     return new TypePathSegment (lang_item, ident_segment,
     856          174 :                                 has_separating_scope_resolution, locus);
     857              :   }
     858              : 
     859              : public:
     860       485431 :   virtual ~TypePathSegment () {}
     861              : 
     862           92 :   virtual SegmentType get_type () const { return SegmentType::REG; }
     863              : 
     864              :   // Unique pointer custom clone function
     865       553805 :   std::unique_ptr<TypePathSegment> clone_type_path_segment () const
     866              :   {
     867       553805 :     return std::unique_ptr<TypePathSegment> (clone_type_path_segment_impl ());
     868              :   }
     869              :   // Unique pointer custom reconstruct function
     870            0 :   std::unique_ptr<TypePathSegment> reconstruct () const
     871              :   {
     872            0 :     return reconstruct_base (this);
     873              :   }
     874              : 
     875       135308 :   TypePathSegment (PathIdentSegment ident_segment,
     876              :                    bool has_separating_scope_resolution, location_t locus)
     877       270616 :     : lang_item (tl::nullopt), ident_segment (std::move (ident_segment)),
     878       135308 :       locus (locus),
     879       135308 :       has_separating_scope_resolution (has_separating_scope_resolution),
     880       135308 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     881       135308 :   {}
     882              : 
     883         1208 :   TypePathSegment (LangItem::Kind lang_item, PathIdentSegment ident_segment,
     884              :                    location_t locus)
     885         2416 :     : lang_item (lang_item), ident_segment (ident_segment), locus (locus),
     886         1208 :       has_separating_scope_resolution (false),
     887         1208 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     888         1208 :   {}
     889              : 
     890        18323 :   TypePathSegment (std::string segment_name,
     891              :                    bool has_separating_scope_resolution, location_t locus)
     892        18323 :     : lang_item (tl::nullopt),
     893        18323 :       ident_segment (PathIdentSegment (std::move (segment_name), locus)),
     894        18323 :       locus (locus),
     895        18323 :       has_separating_scope_resolution (has_separating_scope_resolution),
     896        36646 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     897        18323 :   {}
     898              : 
     899              :   // General constructor
     900          174 :   TypePathSegment (tl::optional<LangItem::Kind> lang_item,
     901              :                    PathIdentSegment ident_segment,
     902              :                    bool has_separating_scope_resolution, location_t locus)
     903          348 :     : lang_item (lang_item), ident_segment (ident_segment), locus (locus),
     904          174 :       has_separating_scope_resolution (has_separating_scope_resolution),
     905          174 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     906          174 :   {}
     907              : 
     908       579146 :   TypePathSegment (TypePathSegment const &other)
     909       579146 :     : lang_item (other.lang_item), ident_segment (other.ident_segment),
     910       579146 :       locus (other.locus),
     911       579146 :       has_separating_scope_resolution (other.has_separating_scope_resolution),
     912       579146 :       node_id (other.node_id)
     913       579146 :   {}
     914              : 
     915              :   TypePathSegment &operator= (TypePathSegment const &other)
     916              :   {
     917              :     ident_segment = other.ident_segment;
     918              :     lang_item = other.lang_item;
     919              :     locus = other.locus;
     920              :     has_separating_scope_resolution = other.has_separating_scope_resolution;
     921              :     node_id = other.node_id;
     922              : 
     923              :     return *this;
     924              :   }
     925              : 
     926              :   TypePathSegment (TypePathSegment &&other) = default;
     927              :   TypePathSegment &operator= (TypePathSegment &&other) = default;
     928              : 
     929         2565 :   virtual std::string as_string () const
     930              :   {
     931         2565 :     if (lang_item.has_value ())
     932            0 :       return LangItem::PrettyString (*lang_item);
     933              : 
     934         2565 :     return ident_segment.as_string ();
     935              :   }
     936              : 
     937              :   /* Returns whether the type path segment is in an error state. May be
     938              :    * virtual in future. */
     939          525 :   bool is_error () const { return ident_segment.is_error (); }
     940              : 
     941              :   /* Returns whether segment is identifier only (as opposed to generic args or
     942              :    * function). Overridden in derived classes with other segments. */
     943          498 :   virtual bool is_ident_only () const { return true; }
     944              : 
     945       436988 :   bool is_lang_item () const { return lang_item.has_value (); }
     946              : 
     947         4034 :   location_t get_locus () const { return locus; }
     948              : 
     949              :   // not pure virtual as class not abstract
     950              :   virtual void accept_vis (ASTVisitor &vis);
     951              : 
     952        56855 :   bool get_separating_scope_resolution () const
     953              :   {
     954        56855 :     return has_separating_scope_resolution;
     955              :   }
     956              : 
     957       492118 :   PathIdentSegment &get_ident_segment () { return ident_segment; };
     958              : 
     959           23 :   const PathIdentSegment &get_ident_segment () const { return ident_segment; };
     960              : 
     961         3181 :   LangItem::Kind get_lang_item () const
     962              :   {
     963         3181 :     rust_assert (is_lang_item ());
     964         3181 :     return *lang_item;
     965              :   }
     966              : 
     967       197109 :   NodeId get_node_id () const { return node_id; }
     968              : 
     969              :   bool is_crate_path_seg () const
     970              :   {
     971              :     return get_ident_segment ().is_crate_path_seg ();
     972              :   }
     973              :   bool is_super_path_seg () const
     974              :   {
     975              :     return get_ident_segment ().is_super_path_seg ();
     976              :   }
     977              :   bool is_big_self_seg () const
     978              :   {
     979              :     return get_ident_segment ().is_big_self_seg ();
     980              :   }
     981              :   bool is_lower_self_seg () const
     982              :   {
     983              :     return get_ident_segment ().is_lower_self_seg ();
     984              :   }
     985              : };
     986              : 
     987              : // Segment used in type path with generic args
     988              : class TypePathSegmentGeneric : public TypePathSegment
     989              : {
     990              :   GenericArgs generic_args;
     991              : 
     992              : public:
     993           11 :   SegmentType get_type () const override { return SegmentType::GENERIC; }
     994              : 
     995      7217198 :   bool has_generic_args () const { return generic_args.has_generic_args (); }
     996              : 
     997            0 :   bool is_ident_only () const override { return false; }
     998              : 
     999              :   // Constructor with PathIdentSegment and GenericArgs
    1000        18331 :   TypePathSegmentGeneric (PathIdentSegment ident_segment,
    1001              :                           bool has_separating_scope_resolution,
    1002              :                           GenericArgs generic_args, location_t locus)
    1003              :     : TypePathSegment (std::move (ident_segment),
    1004              :                        has_separating_scope_resolution, locus),
    1005        18331 :       generic_args (std::move (generic_args))
    1006        18331 :   {}
    1007              : 
    1008          107 :   TypePathSegmentGeneric (LangItem::Kind lang_item,
    1009              :                           PathIdentSegment ident_segment,
    1010              :                           GenericArgs generic_args, location_t locus)
    1011              :     : TypePathSegment (lang_item, ident_segment, locus),
    1012          107 :       generic_args (std::move (generic_args))
    1013          107 :   {}
    1014              : 
    1015              :   // Constructor from segment name and all args
    1016              :   TypePathSegmentGeneric (std::string segment_name,
    1017              :                           bool has_separating_scope_resolution,
    1018              :                           std::vector<Lifetime> lifetime_args,
    1019              :                           std::vector<GenericArg> generic_args,
    1020              :                           std::vector<GenericArgsBinding> binding_args,
    1021              :                           location_t locus)
    1022              :     : TypePathSegment (std::move (segment_name),
    1023              :                        has_separating_scope_resolution, locus),
    1024              :       generic_args (GenericArgs (std::move (lifetime_args),
    1025              :                                  std::move (generic_args),
    1026              :                                  std::move (binding_args)))
    1027              :   {}
    1028              : 
    1029              :   // Copy constructor with vector clone
    1030       104124 :   TypePathSegmentGeneric (TypePathSegmentGeneric const &other)
    1031       104124 :     : TypePathSegment (other), generic_args (other.generic_args)
    1032       104124 :   {}
    1033              : 
    1034              :   // Overloaded assignment operator with vector clone
    1035              :   TypePathSegmentGeneric &operator= (TypePathSegmentGeneric const &other)
    1036              :   {
    1037              :     generic_args = other.generic_args;
    1038              : 
    1039              :     return *this;
    1040              :   }
    1041              : 
    1042              :   // move constructors
    1043              :   TypePathSegmentGeneric (TypePathSegmentGeneric &&other) = default;
    1044              :   TypePathSegmentGeneric &operator= (TypePathSegmentGeneric &&other) = default;
    1045              : 
    1046              :   std::string as_string () const override;
    1047              : 
    1048              :   void accept_vis (ASTVisitor &vis) override;
    1049              : 
    1050              :   // TODO: is this better? Or is a "vis_pattern" better?
    1051      3795417 :   GenericArgs &get_generic_args () { return generic_args; }
    1052              : 
    1053              :   // Use covariance to override base class method
    1054       104124 :   TypePathSegmentGeneric *clone_type_path_segment_impl () const override
    1055              :   {
    1056       104124 :     return new TypePathSegmentGeneric (*this);
    1057              :   }
    1058              : 
    1059            4 :   TypePathSegmentGeneric *reconstruct_impl () const override
    1060              :   {
    1061            4 :     return new TypePathSegmentGeneric (get_ident_segment (),
    1062            4 :                                        has_separating_scope_resolution,
    1063           12 :                                        generic_args.reconstruct (),
    1064            4 :                                        get_locus ());
    1065              :   }
    1066              : };
    1067              : 
    1068              : // A function as represented in a type path
    1069              : struct TypePathFunction
    1070              : {
    1071              : private:
    1072              :   // TODO: remove
    1073              :   /*bool has_inputs;
    1074              :   TypePathFnInputs inputs;*/
    1075              :   // inlined from TypePathFnInputs
    1076              :   std::vector<std::unique_ptr<Type>> inputs;
    1077              : 
    1078              :   // bool has_type;
    1079              :   std::unique_ptr<Type> return_type;
    1080              : 
    1081              :   // FIXME: think of better way to mark as invalid than taking up storage
    1082              :   bool is_invalid;
    1083              : 
    1084              :   location_t locus;
    1085              : 
    1086              : protected:
    1087              :   // Constructor only used to create invalid type path functions.
    1088            0 :   TypePathFunction (bool is_invalid, location_t locus)
    1089            0 :     : is_invalid (is_invalid), locus (locus)
    1090              :   {}
    1091              : 
    1092              : public:
    1093              :   // Returns whether the return type of the function has been specified.
    1094       175592 :   bool has_return_type () const { return return_type != nullptr; }
    1095              : 
    1096              :   // Returns whether the function has inputs.
    1097           27 :   bool has_inputs () const { return !inputs.empty (); }
    1098              : 
    1099              :   // Returns whether function is in an error state.
    1100       176128 :   bool is_error () const { return is_invalid; }
    1101              : 
    1102              :   // Creates an error state function.
    1103            0 :   static TypePathFunction create_error ()
    1104              :   {
    1105            0 :     return TypePathFunction (true, UNDEF_LOCATION);
    1106              :   }
    1107              : 
    1108              :   // Constructor
    1109          536 :   TypePathFunction (std::vector<std::unique_ptr<Type>> inputs, location_t locus,
    1110              :                     std::unique_ptr<Type> type = nullptr)
    1111          536 :     : inputs (std::move (inputs)), return_type (std::move (type)),
    1112          536 :       is_invalid (false), locus (locus)
    1113              :   {}
    1114              : 
    1115              :   // Copy constructor with clone
    1116         1665 :   TypePathFunction (TypePathFunction const &other)
    1117         1665 :     : is_invalid (other.is_invalid)
    1118              :   {
    1119              :     // guard to protect from null pointer dereference
    1120         1665 :     if (other.return_type != nullptr)
    1121         1600 :       return_type = other.return_type->clone_type ();
    1122              : 
    1123         1665 :     inputs.reserve (other.inputs.size ());
    1124         3982 :     for (const auto &e : other.inputs)
    1125         2317 :       inputs.push_back (e->clone_type ());
    1126         1665 :   }
    1127              : 
    1128          536 :   ~TypePathFunction () = default;
    1129              : 
    1130              :   // Overloaded assignment operator to clone type
    1131              :   TypePathFunction &operator= (TypePathFunction const &other)
    1132              :   {
    1133              :     is_invalid = other.is_invalid;
    1134              : 
    1135              :     // guard to protect from null pointer dereference
    1136              :     if (other.return_type != nullptr)
    1137              :       return_type = other.return_type->clone_type ();
    1138              :     else
    1139              :       return_type = nullptr;
    1140              : 
    1141              :     inputs.reserve (other.inputs.size ());
    1142              :     for (const auto &e : other.inputs)
    1143              :       inputs.push_back (e->clone_type ());
    1144              : 
    1145              :     return *this;
    1146              :   }
    1147              : 
    1148              :   // move constructors
    1149          536 :   TypePathFunction (TypePathFunction &&other) = default;
    1150              :   TypePathFunction &operator= (TypePathFunction &&other) = default;
    1151              : 
    1152              :   std::string as_string () const;
    1153              : 
    1154              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    1155              :   const std::vector<std::unique_ptr<Type>> &get_params () const
    1156              :   {
    1157              :     return inputs;
    1158              :   }
    1159       175592 :   std::vector<std::unique_ptr<Type>> &get_params () { return inputs; }
    1160              : 
    1161              :   // TODO: is this better? Or is a "vis_pattern" better?
    1162       135070 :   Type &get_return_type ()
    1163              :   {
    1164       135070 :     rust_assert (has_return_type ());
    1165       135070 :     return *return_type;
    1166              :   }
    1167              : 
    1168        34663 :   std::unique_ptr<Type> &get_return_type_ptr ()
    1169              :   {
    1170        34663 :     rust_assert (has_return_type ());
    1171        34663 :     return return_type;
    1172              :   }
    1173              : 
    1174            0 :   TypePathFunction reconstruct () const
    1175              :   {
    1176            0 :     std::vector<std::unique_ptr<Type>> new_inputs;
    1177            0 :     new_inputs.reserve (inputs.size ());
    1178            0 :     for (const auto &e : inputs)
    1179            0 :       new_inputs.push_back (e->reconstruct ());
    1180              : 
    1181            0 :     std::unique_ptr<Type> new_ret = nullptr;
    1182            0 :     if (return_type)
    1183            0 :       new_ret = return_type->reconstruct ();
    1184              : 
    1185            0 :     return TypePathFunction (std::move (new_inputs), locus,
    1186            0 :                              std::move (new_ret));
    1187            0 :   }
    1188              : 
    1189           27 :   location_t get_locus () const { return locus; }
    1190              : };
    1191              : 
    1192              : // Segment used in type path with a function argument
    1193              : class TypePathSegmentFunction : public TypePathSegment
    1194              : {
    1195              :   TypePathFunction function_path;
    1196              : 
    1197              : public:
    1198           27 :   SegmentType get_type () const override { return SegmentType::FUNCTION; }
    1199              : 
    1200              :   // Constructor with PathIdentSegment and TypePathFn
    1201          536 :   TypePathSegmentFunction (PathIdentSegment ident_segment,
    1202              :                            bool has_separating_scope_resolution,
    1203              :                            TypePathFunction function_path, location_t locus)
    1204              :     : TypePathSegment (std::move (ident_segment),
    1205              :                        has_separating_scope_resolution, locus),
    1206          536 :       function_path (std::move (function_path))
    1207          536 :   {}
    1208              : 
    1209              :   // Constructor with segment name and TypePathFn
    1210              :   TypePathSegmentFunction (std::string segment_name,
    1211              :                            bool has_separating_scope_resolution,
    1212              :                            TypePathFunction function_path, location_t locus)
    1213              :     : TypePathSegment (std::move (segment_name),
    1214              :                        has_separating_scope_resolution, locus),
    1215              :       function_path (std::move (function_path))
    1216              :   {}
    1217              : 
    1218              :   std::string as_string () const override;
    1219              : 
    1220           27 :   bool is_ident_only () const override { return false; }
    1221              : 
    1222              :   void accept_vis (ASTVisitor &vis) override;
    1223              : 
    1224              :   // TODO: is this better? Or is a "vis_pattern" better?
    1225       175592 :   TypePathFunction &get_type_path_function ()
    1226              :   {
    1227       175592 :     rust_assert (!function_path.is_error ());
    1228       175592 :     return function_path;
    1229              :   }
    1230              : 
    1231              :   // Use covariance to override base class method
    1232         1665 :   TypePathSegmentFunction *clone_type_path_segment_impl () const override
    1233              :   {
    1234         1665 :     return new TypePathSegmentFunction (*this);
    1235              :   }
    1236              : 
    1237            0 :   TypePathSegmentFunction *reconstruct_impl () const override
    1238              :   {
    1239            0 :     return new TypePathSegmentFunction (get_ident_segment (),
    1240            0 :                                         has_separating_scope_resolution,
    1241            0 :                                         function_path.reconstruct (),
    1242            0 :                                         get_locus ());
    1243              :   }
    1244              : };
    1245              : 
    1246       209500 : class TypePath : public TypeNoBounds
    1247              : {
    1248              :   bool has_opening_scope_resolution;
    1249              :   std::vector<std::unique_ptr<TypePathSegment>> segments;
    1250              :   location_t locus;
    1251              : 
    1252              : protected:
    1253              :   /* Use covariance to implement clone function as returning this object
    1254              :    * rather than base */
    1255       406380 :   TypePath *clone_type_no_bounds_impl () const override
    1256              :   {
    1257       406380 :     return new TypePath (*this);
    1258              :   }
    1259          178 :   TypePath *reconstruct_impl () const override
    1260              :   {
    1261          890 :     return new TypePath (reconstruct_vec (segments), locus,
    1262          356 :                          has_opening_scope_resolution);
    1263              :   }
    1264              : 
    1265              : public:
    1266              :   /* Returns whether the TypePath has an opening scope resolution operator
    1267              :    * (i.e. is global path or crate-relative path, not module-relative) */
    1268       242293 :   bool has_opening_scope_resolution_op () const
    1269              :   {
    1270       242293 :     return has_opening_scope_resolution;
    1271              :   }
    1272              : 
    1273              :   // Returns whether the TypePath is in an invalid state.
    1274      2091749 :   bool is_error () const { return segments.empty (); }
    1275              : 
    1276              :   // Creates an error state TypePath.
    1277         3971 :   static TypePath create_error ()
    1278              :   {
    1279        11913 :     return TypePath (std::vector<std::unique_ptr<TypePathSegment>> (),
    1280         3971 :                      UNDEF_LOCATION);
    1281              :   }
    1282              : 
    1283              :   // Constructor
    1284       148883 :   TypePath (std::vector<std::unique_ptr<TypePathSegment>> segments,
    1285              :             location_t locus, bool has_opening_scope_resolution = false)
    1286              :     : TypeNoBounds (),
    1287       148883 :       has_opening_scope_resolution (has_opening_scope_resolution),
    1288       148883 :       segments (std::move (segments)), locus (locus)
    1289              :   {}
    1290              : 
    1291            0 :   TypePath (LangItem::Kind lang_item,
    1292              :             std::vector<std::unique_ptr<TypePathSegment>> segments,
    1293              :             location_t locus, bool has_opening_scope_resolution = false)
    1294              :     : TypeNoBounds (),
    1295            0 :       has_opening_scope_resolution (has_opening_scope_resolution),
    1296            0 :       segments (std::move (segments)), locus (locus)
    1297              :   {}
    1298              : 
    1299              :   // Copy constructor with vector clone
    1300       527893 :   TypePath (TypePath const &other)
    1301              :     : TypeNoBounds (other),
    1302       527893 :       has_opening_scope_resolution (other.has_opening_scope_resolution),
    1303       527893 :       locus (other.locus)
    1304              :   {
    1305       527893 :     segments.reserve (other.segments.size ());
    1306      1081698 :     for (const auto &e : other.segments)
    1307       553805 :       segments.push_back (e->clone_type_path_segment ());
    1308       527893 :   }
    1309              : 
    1310              :   // Overloaded assignment operator with clone
    1311              :   TypePath &operator= (TypePath const &other)
    1312              :   {
    1313              :     TypeNoBounds::operator= (other);
    1314              :     has_opening_scope_resolution = other.has_opening_scope_resolution;
    1315              :     locus = other.locus;
    1316              : 
    1317              :     segments.reserve (other.segments.size ());
    1318              :     for (const auto &e : other.segments)
    1319              :       segments.push_back (e->clone_type_path_segment ());
    1320              : 
    1321              :     return *this;
    1322              :   }
    1323              : 
    1324              :   // move constructors
    1325       128562 :   TypePath (TypePath &&other) = default;
    1326         3701 :   TypePath &operator= (TypePath &&other) = default;
    1327              : 
    1328              :   std::string as_string () const override;
    1329              : 
    1330              :   std::string make_debug_string () const;
    1331              : 
    1332              :   /* Converts TypePath to SimplePath if possible (i.e. no generic or function
    1333              :    * arguments). Otherwise returns an empty SimplePath. */
    1334              :   SimplePath as_simple_path () const;
    1335              : 
    1336              :   // Creates a trait bound with a clone of this type path as its only element.
    1337              :   TraitBound *to_trait_bound (bool in_parens) const override;
    1338              : 
    1339       162438 :   location_t get_locus () const override final { return locus; }
    1340      2347775 :   NodeId get_node_id () const override { return node_id; }
    1341              : 
    1342            0 :   void mark_for_strip () override {}
    1343      4235625 :   bool is_marked_for_strip () const override { return false; }
    1344              : 
    1345              :   void accept_vis (ASTVisitor &vis) override;
    1346              : 
    1347              :   // TODO: this seems kinda dodgy
    1348        55939 :   std::vector<std::unique_ptr<TypePathSegment>> &get_segments ()
    1349              :   {
    1350     18381874 :     return segments;
    1351              :   }
    1352       131208 :   const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const
    1353              :   {
    1354       131226 :     return segments;
    1355              :   }
    1356              : 
    1357              :   size_t get_num_segments () const { return segments.size (); }
    1358              : 
    1359         1482 :   Type::Kind get_type_kind () const override { return Type::Kind::TypePath; }
    1360              : };
    1361              : 
    1362              : struct QualifiedPathType
    1363              : {
    1364              : private:
    1365              :   std::unique_ptr<Type> type_to_invoke_on;
    1366              :   TypePath trait_path;
    1367              :   location_t locus;
    1368              :   NodeId node_id;
    1369              : 
    1370              : public:
    1371              :   // Constructor
    1372         3776 :   QualifiedPathType (std::unique_ptr<Type> invoke_on_type,
    1373              :                      location_t locus = UNDEF_LOCATION,
    1374              :                      TypePath trait_path = TypePath::create_error ())
    1375         3776 :     : type_to_invoke_on (std::move (invoke_on_type)), trait_path (trait_path),
    1376         3776 :       locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ())
    1377         3776 :   {}
    1378              : 
    1379              :   // Copy constructor uses custom deep copy for Type to preserve polymorphism
    1380        26245 :   QualifiedPathType (QualifiedPathType const &other)
    1381        26245 :     : trait_path (other.trait_path), locus (other.locus)
    1382              :   {
    1383        26245 :     node_id = other.node_id;
    1384              :     // guard to prevent null dereference
    1385        26245 :     if (other.type_to_invoke_on != nullptr)
    1386        26245 :       type_to_invoke_on = other.type_to_invoke_on->clone_type ();
    1387        26245 :   }
    1388              : 
    1389              :   // default destructor
    1390        37519 :   ~QualifiedPathType () = default;
    1391              : 
    1392              :   // overload assignment operator to use custom clone method
    1393              :   QualifiedPathType &operator= (QualifiedPathType const &other)
    1394              :   {
    1395              :     node_id = other.node_id;
    1396              :     trait_path = other.trait_path;
    1397              :     locus = other.locus;
    1398              : 
    1399              :     // guard to prevent null dereference
    1400              :     if (other.type_to_invoke_on != nullptr)
    1401              :       type_to_invoke_on = other.type_to_invoke_on->clone_type ();
    1402              :     else
    1403              :       type_to_invoke_on = nullptr;
    1404              : 
    1405              :     return *this;
    1406              :   }
    1407              : 
    1408              :   // move constructor
    1409        11274 :   QualifiedPathType (QualifiedPathType &&other) = default;
    1410            0 :   QualifiedPathType &operator= (QualifiedPathType &&other) = default;
    1411              : 
    1412            0 :   QualifiedPathType reconstruct () const
    1413              :   {
    1414            0 :     auto new_type = type_to_invoke_on->reconstruct ();
    1415              : 
    1416              :     // trait_path is stored by value, but reconstruct returns a unique_ptr.
    1417              :     // We must dereference it to pass to the constructor.
    1418              :     // This is safe because the constructor makes its own copy/move.
    1419            0 :     auto new_trait_path_ptr = trait_path.reconstruct ();
    1420            0 :     TypePath *concrete_ptr
    1421            0 :       = static_cast<TypePath *> (new_trait_path_ptr.get ());
    1422              : 
    1423            0 :     return QualifiedPathType (std::move (new_type), locus, *concrete_ptr);
    1424            0 :   }
    1425              : 
    1426              :   // Returns whether the qualified path type has a rebind as clause.
    1427       998286 :   bool has_as_clause () const { return !trait_path.is_error (); }
    1428              : 
    1429              :   // Returns whether the qualified path type is in an error state.
    1430      1012439 :   bool is_error () const { return type_to_invoke_on == nullptr; }
    1431              : 
    1432              :   // Creates an error state qualified path type.
    1433            0 :   static QualifiedPathType create_error ()
    1434              :   {
    1435            0 :     return QualifiedPathType (nullptr);
    1436              :   }
    1437              : 
    1438              :   std::string as_string () const;
    1439              : 
    1440          933 :   location_t get_locus () const { return locus; }
    1441              : 
    1442              :   // TODO: is this better? Or is a "vis_pattern" better?
    1443       781163 :   Type &get_type ()
    1444              :   {
    1445       781163 :     rust_assert (type_to_invoke_on != nullptr);
    1446       781163 :     return *type_to_invoke_on;
    1447              :   }
    1448              : 
    1449       217123 :   std::unique_ptr<Type> &get_type_ptr ()
    1450              :   {
    1451       217123 :     rust_assert (type_to_invoke_on != nullptr);
    1452       217123 :     return type_to_invoke_on;
    1453              :   }
    1454              : 
    1455              :   // TODO: is this better? Or is a "vis_pattern" better?
    1456       964802 :   TypePath &get_as_type_path ()
    1457              :   {
    1458       964802 :     rust_assert (has_as_clause ());
    1459       964802 :     return trait_path;
    1460              :   }
    1461              : 
    1462          358 :   NodeId get_node_id () const { return node_id; }
    1463              : };
    1464              : 
    1465              : /* AST node representing a qualified path-in-expression pattern (path that
    1466              :  * allows specifying trait functions) */
    1467              : class QualifiedPathInExpression : public Path, public ExprWithoutBlock
    1468              : {
    1469              :   std::vector<Attribute> outer_attrs;
    1470              :   QualifiedPathType path_type;
    1471              :   location_t locus;
    1472              :   NodeId _node_id;
    1473              : 
    1474              : public:
    1475              :   std::string as_string () const override;
    1476              : 
    1477          216 :   QualifiedPathInExpression (QualifiedPathType qual_path_type,
    1478              :                              std::vector<PathExprSegment> path_segments,
    1479              :                              std::vector<Attribute> outer_attrs,
    1480              :                              location_t locus)
    1481          216 :     : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)),
    1482          216 :       path_type (std::move (qual_path_type)), locus (locus),
    1483          216 :       _node_id (Analysis::Mappings::get ().get_next_node_id ())
    1484          216 :   {}
    1485              : 
    1486              :   /* TODO: maybe make a shortcut constructor that has QualifiedPathType
    1487              :    * elements as params */
    1488              : 
    1489              :   // Returns whether qualified path in expression is in an error state.
    1490        10404 :   bool is_error () const { return path_type.is_error (); }
    1491              : 
    1492              :   // Creates an error qualified path in expression.
    1493            0 :   static QualifiedPathInExpression create_error ()
    1494              :   {
    1495            0 :     return QualifiedPathInExpression (QualifiedPathType::create_error (), {},
    1496            0 :                                       {}, UNDEF_LOCATION);
    1497              :   }
    1498              : 
    1499          369 :   location_t get_locus () const override final { return locus; }
    1500              : 
    1501              :   void accept_vis (ASTVisitor &vis) override;
    1502              : 
    1503              :   // Invalid if path_type is error, so base stripping on that.
    1504            0 :   void mark_for_strip () override
    1505              :   {
    1506            0 :     path_type = QualifiedPathType::create_error ();
    1507            0 :   }
    1508        10404 :   bool is_marked_for_strip () const override { return is_error (); }
    1509              : 
    1510              :   // TODO: is this better? Or is a "vis_pattern" better?
    1511        43934 :   QualifiedPathType &get_qualified_path_type ()
    1512              :   {
    1513        43934 :     rust_assert (!path_type.is_error ());
    1514        43934 :     return path_type;
    1515              :   }
    1516              : 
    1517              :   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
    1518        52166 :   std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
    1519              : 
    1520          189 :   void set_outer_attrs (std::vector<Attribute> new_attrs) override
    1521              :   {
    1522          189 :     outer_attrs = std::move (new_attrs);
    1523            0 :   }
    1524              : 
    1525         3760 :   NodeId get_node_id () const override { return _node_id; }
    1526              : 
    1527          216 :   Expr::Kind get_expr_kind () const override
    1528              :   {
    1529          216 :     return Expr::Kind::QualifiedPathInExpression;
    1530              :   }
    1531              : 
    1532              :   std::unique_ptr<QualifiedPathInExpression> reconstruct () const
    1533              :   {
    1534              :     std::vector<PathExprSegment> new_segments;
    1535              :     new_segments.reserve (segments.size ());
    1536              :     for (const auto &seg : segments)
    1537              :       new_segments.push_back (seg.reconstruct ());
    1538              : 
    1539              :     auto *new_path = new QualifiedPathInExpression (path_type.reconstruct (),
    1540              :                                                     std::move (new_segments),
    1541              :                                                     outer_attrs, locus);
    1542              : 
    1543              :     return std::unique_ptr<QualifiedPathInExpression> (new_path);
    1544              :   }
    1545              : 
    1546              : protected:
    1547              :   /* Use covariance to implement clone function as returning this object
    1548              :    * rather than base */
    1549            0 :   QualifiedPathInExpression *clone_pattern_impl () const final override
    1550              :   {
    1551            0 :     return clone_qual_path_in_expression_impl ();
    1552              :   }
    1553              : 
    1554              :   /* Use covariance to implement clone function as returning this object
    1555              :    * rather than base */
    1556              :   QualifiedPathInExpression *
    1557            0 :   clone_expr_without_block_impl () const final override
    1558              :   {
    1559            0 :     return clone_qual_path_in_expression_impl ();
    1560              :   }
    1561              : 
    1562              :   /*virtual*/ QualifiedPathInExpression *
    1563          877 :   clone_qual_path_in_expression_impl () const
    1564              :   {
    1565          877 :     return new QualifiedPathInExpression (*this);
    1566              :   }
    1567              : };
    1568              : 
    1569              : /* Represents a qualified path in a type; used for disambiguating trait
    1570              :  * function calls */
    1571              : class QualifiedPathInType : public TypeNoBounds
    1572              : {
    1573              :   QualifiedPathType path_type;
    1574              :   std::unique_ptr<TypePathSegment> associated_segment;
    1575              :   std::vector<std::unique_ptr<TypePathSegment>> segments;
    1576              :   location_t locus;
    1577              : 
    1578              : protected:
    1579              :   /* Use covariance to implement clone function as returning this object
    1580              :    * rather than base */
    1581        25341 :   QualifiedPathInType *clone_type_no_bounds_impl () const override
    1582              :   {
    1583        25341 :     return new QualifiedPathInType (*this);
    1584              :   }
    1585            0 :   QualifiedPathInType *reconstruct_impl () const override
    1586              :   {
    1587            0 :     return new QualifiedPathInType (path_type.reconstruct (),
    1588            0 :                                     associated_segment->reconstruct (),
    1589            0 :                                     reconstruct_vec (segments), locus);
    1590              :   }
    1591              : 
    1592              : public:
    1593         3560 :   QualifiedPathInType (
    1594              :     QualifiedPathType qual_path_type,
    1595              :     std::unique_ptr<TypePathSegment> associated_segment,
    1596              :     std::vector<std::unique_ptr<TypePathSegment>> path_segments,
    1597              :     location_t locus)
    1598         3560 :     : path_type (std::move (qual_path_type)),
    1599         3560 :       associated_segment (std::move (associated_segment)),
    1600         3560 :       segments (std::move (path_segments)), locus (locus)
    1601         3560 :   {}
    1602              : 
    1603              :   // Copy constructor with vector clone
    1604        25341 :   QualifiedPathInType (QualifiedPathInType const &other)
    1605        25341 :     : path_type (other.path_type), locus (other.locus)
    1606              :   {
    1607        25341 :     auto seg = other.associated_segment->clone_type_path_segment_impl ();
    1608        25341 :     associated_segment = std::unique_ptr<TypePathSegment> (seg);
    1609              : 
    1610        25341 :     segments.reserve (other.segments.size ());
    1611        25341 :     for (const auto &e : other.segments)
    1612            0 :       segments.push_back (e->clone_type_path_segment ());
    1613        25341 :   }
    1614              : 
    1615              :   // Overloaded assignment operator with vector clone
    1616              :   QualifiedPathInType &operator= (QualifiedPathInType const &other)
    1617              :   {
    1618              :     auto seg = other.associated_segment->clone_type_path_segment_impl ();
    1619              :     associated_segment = std::unique_ptr<TypePathSegment> (seg);
    1620              : 
    1621              :     path_type = other.path_type;
    1622              :     locus = other.locus;
    1623              : 
    1624              :     segments.reserve (other.segments.size ());
    1625              :     for (const auto &e : other.segments)
    1626              :       segments.push_back (e->clone_type_path_segment ());
    1627              : 
    1628              :     return *this;
    1629              :   }
    1630              : 
    1631              :   // move constructors
    1632         3560 :   QualifiedPathInType (QualifiedPathInType &&other) = default;
    1633              :   QualifiedPathInType &operator= (QualifiedPathInType &&other) = default;
    1634              : 
    1635              :   // Returns whether qualified path in type is in an error state.
    1636         3560 :   bool is_error () const { return path_type.is_error (); }
    1637              : 
    1638              :   // Creates an error state qualified path in type.
    1639            0 :   static QualifiedPathInType create_error ()
    1640              :   {
    1641            0 :     return QualifiedPathInType (
    1642            0 :       QualifiedPathType::create_error (), nullptr,
    1643            0 :       std::vector<std::unique_ptr<TypePathSegment>> (), UNDEF_LOCATION);
    1644              :   }
    1645              : 
    1646              :   std::string as_string () const override;
    1647              : 
    1648              :   void accept_vis (ASTVisitor &vis) override;
    1649              : 
    1650              :   // TODO: is this better? Or is a "vis_pattern" better?
    1651       955078 :   QualifiedPathType &get_qualified_path_type ()
    1652              :   {
    1653       955078 :     rust_assert (!path_type.is_error ());
    1654       955078 :     return path_type;
    1655              :   }
    1656              : 
    1657              :   std::unique_ptr<TypePathSegment> &get_associated_segment ()
    1658              :   {
    1659       645350 :     return associated_segment;
    1660              :   }
    1661              : 
    1662              :   // TODO: this seems kinda dodgy
    1663              :   std::vector<std::unique_ptr<TypePathSegment>> &get_segments ()
    1664              :   {
    1665       748394 :     return segments;
    1666              :   }
    1667              :   const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const
    1668              :   {
    1669              :     return segments;
    1670              :   }
    1671              : 
    1672          264 :   location_t get_locus () const override final { return locus; }
    1673              : 
    1674            0 :   Type::Kind get_type_kind () const override
    1675              :   {
    1676            0 :     return Type::Kind::QualifiedPathInType;
    1677              :   }
    1678              : };
    1679              : } // namespace AST
    1680              : } // namespace Rust
    1681              : 
    1682              : #endif
        

Generated by: LCOV version 2.4-beta

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