LCOV - code coverage report
Current view: top level - gcc/rust/ast - rust-path.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 80.7 % 538 434
Test Date: 2026-03-28 14:25:54 Functions: 83.0 % 141 117
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       726954 : 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       145330 :   PathIdentSegment (std::string segment_name, location_t locus)
      43       145888 :     : segment_name (std::move (segment_name)), locus (locus)
      44              :   {}
      45              : 
      46              :   // Creates an error PathIdentSegment.
      47            8 :   static PathIdentSegment create_error ()
      48              :   {
      49            8 :     return PathIdentSegment ("", UNDEF_LOCATION);
      50              :   }
      51              : 
      52              :   // Returns whether PathIdentSegment is in an error state.
      53        87058 :   bool is_error () const { return segment_name.empty (); }
      54              : 
      55       551532 :   std::string as_string () const { return segment_name; }
      56              : 
      57         6168 :   location_t get_locus () const { return locus; }
      58              : 
      59        31900 :   bool is_super_path_seg () const
      60              :   {
      61        63800 :     return as_string ().compare ("super") == 0;
      62              :   }
      63        47138 :   bool is_crate_path_seg () const
      64              :   {
      65        94276 :     return as_string ().compare ("crate") == 0;
      66              :   }
      67       196798 :   bool is_lower_self_seg () const { return as_string ().compare ("self") == 0; }
      68       108080 :   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           73 :   bool is_error () const
      82              :   {
      83           73 :     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           73 :   GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr,
     104              :                       location_t locus = UNDEF_LOCATION)
     105           73 :     : 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           86 :   GenericArgsBinding (GenericArgsBinding const &other)
     110           86 :     : identifier (other.identifier), locus (other.locus)
     111              :   {
     112              :     // guard to protect from null pointer dereference
     113           86 :     if (other.type != nullptr)
     114           86 :       type = other.type->clone_type ();
     115           86 :   }
     116              : 
     117              :   // default destructor
     118          160 :   ~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           74 :   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         1298 :   Type &get_type ()
     143              :   {
     144         1298 :     rust_assert (type != nullptr);
     145         1298 :     return *type;
     146              :   }
     147              : 
     148          278 :   std::unique_ptr<Type> &get_type_ptr ()
     149              :   {
     150          278 :     rust_assert (type != nullptr);
     151          278 :     return type;
     152              :   }
     153              : 
     154          104 :   location_t get_locus () const { return locus; }
     155              : 
     156          104 :   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          141 :   static GenericArg create_const (std::unique_ptr<Expr> expression)
     185              :   {
     186          141 :     auto locus = expression->get_locus ();
     187          141 :     return GenericArg (std::move (expression), nullptr, {""}, Kind::Const,
     188          282 :                        locus);
     189              :   }
     190              : 
     191         3764 :   static GenericArg create_type (std::unique_ptr<Type> type)
     192              :   {
     193         3764 :     auto locus = type->get_locus ();
     194        11292 :     return GenericArg (nullptr, std::move (type), {""}, Kind::Type, locus);
     195              :   }
     196              : 
     197         2453 :   static GenericArg create_ambiguous (Identifier path, location_t locus)
     198              :   {
     199         4906 :     return GenericArg (nullptr, nullptr, std::move (path), Kind::Either, locus);
     200              :   }
     201              : 
     202            0 :   GenericArg reconstruct () const
     203              :   {
     204            0 :     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            0 :       case Kind::Either:
     212            0 :       default:
     213              :         // For ambiguous or error states, copy constructs are sufficient
     214            0 :         return GenericArg (*this);
     215              :       }
     216              :   }
     217              : 
     218         8679 :   GenericArg (const GenericArg &other)
     219         8679 :     : path (other.path), kind (other.kind), locus (other.locus)
     220              :   {
     221         8679 :     if (other.expression)
     222          129 :       expression = other.expression->clone_expr ();
     223         8679 :     if (other.type)
     224         4919 :       type = other.type->clone_type ();
     225         8679 :   }
     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         7994 :   GenericArg (GenericArg &&other) = default;
     242         2347 :   GenericArg &operator= (GenericArg &&other) = default;
     243              : 
     244        85114 :   Kind get_kind () const { return kind; }
     245            0 :   location_t get_locus () const { return locus; }
     246              : 
     247        47640 :   void accept_vis (AST::ASTVisitor &visitor)
     248              :   {
     249        47640 :     switch (get_kind ())
     250              :       {
     251         1311 :       case Kind::Const:
     252         1311 :         get_expression ().accept_vis (visitor);
     253         1311 :         break;
     254        19425 :       case Kind::Type:
     255        19425 :         get_type ().accept_vis (visitor);
     256        19425 :         break;
     257              :       case Kind::Either:
     258              :         break;
     259              :       }
     260        47640 :   }
     261              : 
     262         1836 :   Expr &get_expression ()
     263              :   {
     264         1836 :     rust_assert (kind == Kind::Const);
     265              : 
     266         1836 :     return *expression;
     267              :   }
     268              : 
     269          138 :   std::unique_ptr<Expr> &get_expression_ptr ()
     270              :   {
     271          138 :     rust_assert (kind == Kind::Const);
     272              : 
     273          138 :     return expression;
     274              :   }
     275              : 
     276        32968 :   Type &get_type ()
     277              :   {
     278        32968 :     rust_assert (kind == Kind::Type);
     279              : 
     280        32968 :     return *type;
     281              :   }
     282              : 
     283         3842 :   std::unique_ptr<Type> &get_type_ptr ()
     284              :   {
     285         3842 :     rust_assert (kind == Kind::Type);
     286              : 
     287         3842 :     return type;
     288              :   }
     289              : 
     290         4692 :   const std::string get_path () const
     291              :   {
     292         4692 :     rust_assert (kind == Kind::Either);
     293              : 
     294         4692 :     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         6358 :   GenericArg (std::unique_ptr<Expr> expression, std::unique_ptr<Type> type,
     326              :               Identifier path, Kind kind, location_t locus)
     327         2522 :     : expression (std::move (expression)), type (std::move (type)),
     328         6358 :       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          101 :   ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type,
     378              :                      tl::optional<GenericArg> default_value,
     379              :                      AST::AttrVec outer_attrs, location_t locus)
     380          101 :     : name (name), type (std::move (type)),
     381          101 :       default_value (std::move (default_value)), outer_attrs (outer_attrs),
     382          101 :       locus (locus)
     383          101 :   {}
     384              : 
     385           97 :   ConstGenericParam (const ConstGenericParam &other)
     386           97 :     : GenericParam (), name (other.name), type (other.type->clone_type ()),
     387           97 :       default_value (other.default_value), outer_attrs (other.outer_attrs),
     388           97 :       locus (other.locus)
     389           97 :   {}
     390              : 
     391         1435 :   bool has_type () const { return type != nullptr; }
     392         1536 :   bool has_default_value () const { return default_value.has_value (); }
     393              : 
     394          291 :   const Identifier &get_name () const { return name; }
     395              : 
     396         1446 :   AST::AttrVec &get_outer_attrs () { return outer_attrs; }
     397              : 
     398         1338 :   AST::Type &get_type ()
     399              :   {
     400         1338 :     rust_assert (has_type ());
     401              : 
     402         1338 :     return *type;
     403              :   }
     404              : 
     405           97 :   std::unique_ptr<AST::Type> &get_type_ptr ()
     406              :   {
     407           97 :     rust_assert (has_type ());
     408              : 
     409           97 :     return type;
     410              :   }
     411              : 
     412          266 :   GenericArg &get_default_value_unchecked ()
     413              :   {
     414          266 :     rust_assert (has_default_value ());
     415              : 
     416          266 :     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            0 :   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          465 :   location_t get_locus () const override final { return locus; }
     438              : 
     439          303 :   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           97 :   ConstGenericParam *clone_generic_param_impl () const override
     445              :   {
     446           97 :     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       938874 :   bool has_generic_args () const
     461              :   {
     462       938185 :     return !(lifetime_args.empty () && generic_args.empty ()
     463       843317 :              && binding_args.empty ());
     464              :   }
     465              : 
     466        89798 :   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        89798 :     : lifetime_args (std::move (lifetime_args)),
     471        89798 :       generic_args (std::move (generic_args)),
     472        89798 :       binding_args (std::move (binding_args)), locus (locus)
     473        89798 :   {}
     474              : 
     475              :   // copy constructor with vector clone
     476        75006 :   GenericArgs (GenericArgs const &other)
     477        75006 :     : lifetime_args (other.lifetime_args), binding_args (other.binding_args),
     478        75006 :       locus (other.locus)
     479              :   {
     480        75006 :     generic_args.clear ();
     481        75006 :     generic_args.reserve (other.generic_args.size ());
     482        83439 :     for (const auto &arg : other.generic_args)
     483         8433 :       generic_args.emplace_back (arg);
     484        75006 :   }
     485              : 
     486       318855 :   ~GenericArgs () = default;
     487              : 
     488          134 :   GenericArgs reconstruct () const
     489              :   {
     490          134 :     std::vector<GenericArg> new_args;
     491          134 :     new_args.reserve (generic_args.size ());
     492          134 :     for (const auto &arg : generic_args)
     493            0 :       new_args.push_back (arg.reconstruct ());
     494              : 
     495          134 :     std::vector<GenericArgsBinding> new_bindings;
     496          134 :     new_bindings.reserve (binding_args.size ());
     497          134 :     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          134 :     return GenericArgs (lifetime_args, std::move (new_args),
     502          134 :                         std::move (new_bindings), locus);
     503          134 :   }
     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       192130 :   GenericArgs (GenericArgs &&other) = default;
     522              :   GenericArgs &operator= (GenericArgs &&other) = default;
     523              : 
     524              :   // Creates an empty GenericArgs (no arguments)
     525        85423 :   static GenericArgs create_empty () { return GenericArgs ({}, {}, {}); }
     526              : 
     527              :   std::string as_string () const;
     528              : 
     529        79030 :   std::vector<GenericArg> &get_generic_args () { return generic_args; }
     530              : 
     531        79041 :   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        45457 :   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         3701 :   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       212639 : 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      1334062 :   bool has_generic_args () const { return generic_args.has_generic_args (); }
     561              : 
     562              :   // Constructor for segment (from IdentSegment and GenericArgs)
     563        86463 :   PathExprSegment (PathIdentSegment segment_name, location_t locus,
     564              :                    GenericArgs generic_args = GenericArgs::create_empty ())
     565        86463 :     : segment_name (std::move (segment_name)),
     566        86463 :       generic_args (std::move (generic_args)), locus (locus),
     567        86463 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     568        86463 :   {}
     569              : 
     570              :   /* Constructor for segment with generic arguments (from segment name and all
     571              :    * args) */
     572              :   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              :     : segment_name (PathIdentSegment (std::move (segment_name), locus)),
     577              :       generic_args (GenericArgs (std::move (lifetime_args),
     578              :                                  std::move (generic_args),
     579              :                                  std::move (binding_args))),
     580              :       locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ())
     581              :   {}
     582              : 
     583              :   // Returns whether path expression segment is in an error state.
     584        87003 :   bool is_error () const { return segment_name.is_error (); }
     585              : 
     586              :   // Creates an error-state path expression segment.
     587            8 :   static PathExprSegment create_error ()
     588              :   {
     589            8 :     return PathExprSegment (PathIdentSegment::create_error (), UNDEF_LOCATION);
     590              :   }
     591              : 
     592              :   std::string as_string () const;
     593              : 
     594        38766 :   location_t get_locus () const { return locus; }
     595              : 
     596              :   // TODO: is this better? Or is a "vis_pattern" better?
     597        20779 :   GenericArgs &get_generic_args ()
     598              :   {
     599        20779 :     rust_assert (has_generic_args ());
     600        20779 :     return generic_args;
     601              :   }
     602              : 
     603       511624 :   PathIdentSegment &get_ident_segment () { return segment_name; }
     604        96628 :   const PathIdentSegment &get_ident_segment () const { return segment_name; }
     605              : 
     606        73018 :   NodeId get_node_id () const { return node_id; }
     607              : 
     608          134 :   PathExprSegment reconstruct () const
     609              :   {
     610          134 :     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        42418 :   bool is_lower_self_seg () const
     624              :   {
     625        84565 :     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        74289 :   Path (std::vector<PathExprSegment> segments)
     641        74289 :     : segments (std::move (segments)), lang_item (tl::nullopt),
     642        74289 :       kind (Kind::Regular)
     643              :   {}
     644              : 
     645          144 :   Path (LangItem::Kind lang_item)
     646          144 :     : segments ({}), lang_item (lang_item), kind (Kind::LangItem)
     647          144 :   {}
     648              : 
     649              :   // Returns whether path has segments.
     650         8522 :   bool has_segments () const
     651              :   {
     652         8522 :     rust_assert (kind == Kind::Regular);
     653         8522 :     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        97019 :   bool is_single_segment () const
     663              :   {
     664        97019 :     rust_assert (kind == Kind::Regular);
     665        97019 :     return segments.size () == 1;
     666              :   }
     667              : 
     668              :   std::string as_string () const override;
     669              : 
     670       550752 :   bool is_lang_item () const { return kind == Kind::LangItem; }
     671              : 
     672              :   // TODO: this seems kinda dodgy
     673       596525 :   std::vector<PathExprSegment> &get_segments ()
     674              :   {
     675       596525 :     rust_assert (kind == Kind::Regular);
     676       596525 :     return segments;
     677              :   }
     678        24256 :   const std::vector<PathExprSegment> &get_segments () const
     679              :   {
     680        24256 :     rust_assert (kind == Kind::Regular);
     681        24256 :     return segments;
     682              :   }
     683              : 
     684          352 :   LangItem::Kind get_lang_item () const
     685              :   {
     686          352 :     rust_assert (kind == Kind::LangItem);
     687          352 :     return *lang_item;
     688              :   }
     689              : 
     690            0 :   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        74175 :   PathInExpression (std::vector<PathExprSegment> path_segments,
     716              :                     std::vector<Attribute> outer_attrs, location_t locus,
     717              :                     bool has_opening_scope_resolution = false)
     718       148350 :     : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)),
     719        74175 :       has_opening_scope_resolution (has_opening_scope_resolution),
     720        74175 :       locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ()),
     721        74175 :       marked_for_strip (false)
     722        74175 :   {}
     723              : 
     724          144 :   PathInExpression (LangItem::Kind lang_item,
     725              :                     std::vector<Attribute> outer_attrs, location_t locus)
     726          288 :     : Path (lang_item), outer_attrs (std::move (outer_attrs)),
     727          144 :       has_opening_scope_resolution (false), locus (locus),
     728          144 :       _node_id (Analysis::Mappings::get ().get_next_node_id ()),
     729          144 :       marked_for_strip (false)
     730          144 :   {}
     731              : 
     732              :   // Creates an error state path in expression.
     733            8 :   static PathInExpression create_error ()
     734              :   {
     735            8 :     return PathInExpression (std::vector<PathExprSegment> (), {},
     736           16 :                              UNDEF_LOCATION);
     737              :   }
     738              : 
     739              :   // Returns whether path in expression is in an error state.
     740         6057 :   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         2465 :   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         2465 :     return convert_to_simple_path (has_opening_scope_resolution);
     753              :   }
     754              : 
     755           67 :   std::unique_ptr<PathInExpression> reconstruct () const
     756              :   {
     757           67 :     std::vector<PathExprSegment> new_segments;
     758           67 :     new_segments.reserve (segments.size ());
     759          201 :     for (const auto &seg : segments)
     760          268 :       new_segments.push_back (seg.reconstruct ());
     761              : 
     762           67 :     auto *new_path
     763           67 :       = new PathInExpression (std::move (new_segments), outer_attrs, locus,
     764           67 :                               has_opening_scope_resolution);
     765              : 
     766           67 :     return std::unique_ptr<PathInExpression> (new_path);
     767           67 :   }
     768              : 
     769        62406 :   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       143868 :   bool is_marked_for_strip () const override { return marked_for_strip; }
     775              : 
     776        49493 :   bool opening_scope_resolution () const
     777              :   {
     778        49493 :     return has_opening_scope_resolution;
     779              :   }
     780              : 
     781        74254 :   NodeId get_node_id () const override { return _node_id; }
     782              : 
     783              :   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
     784       606519 :   std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
     785              : 
     786         9856 :   void set_outer_attrs (std::vector<Attribute> new_attrs) override
     787              :   {
     788         9856 :     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        20687 :   Expr::Kind get_expr_kind () const override
     798              :   {
     799        20687 :     return Expr::Kind::PathInExpression;
     800              :   }
     801              : 
     802              : protected:
     803              :   /* Use covariance to implement clone function as returning this object
     804              :    * rather than base */
     805         1153 :   PathInExpression *clone_pattern_impl () const final override
     806              :   {
     807         1153 :     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        39580 :   /*virtual*/ PathInExpression *clone_path_in_expression_impl () const
     818              :   {
     819        39580 :     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              :   tl::optional<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       102614 :   virtual TypePathSegment *clone_type_path_segment_impl () const
     850              :   {
     851       102614 :     return new TypePathSegment (*this);
     852              :   }
     853           93 :   virtual TypePathSegment *reconstruct_impl () const
     854              :   {
     855          186 :     return new TypePathSegment (lang_item, ident_segment,
     856           93 :                                 has_separating_scope_resolution, locus);
     857              :   }
     858              : 
     859              : public:
     860       212233 :   virtual ~TypePathSegment () {}
     861              : 
     862           75 :   virtual SegmentType get_type () const { return SegmentType::REG; }
     863              : 
     864              :   // Unique pointer custom clone function
     865       106610 :   std::unique_ptr<TypePathSegment> clone_type_path_segment () const
     866              :   {
     867       106610 :     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        54937 :   TypePathSegment (PathIdentSegment ident_segment,
     876              :                    bool has_separating_scope_resolution, location_t locus)
     877       109874 :     : lang_item (tl::nullopt), ident_segment (std::move (ident_segment)),
     878        54937 :       locus (locus),
     879        54937 :       has_separating_scope_resolution (has_separating_scope_resolution),
     880        54937 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     881        54937 :   {}
     882              : 
     883          390 :   TypePathSegment (LangItem::Kind lang_item, location_t locus)
     884          390 :     : lang_item (lang_item), ident_segment (tl::nullopt), locus (locus),
     885          390 :       has_separating_scope_resolution (false),
     886          390 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     887          390 :   {}
     888              : 
     889         4066 :   TypePathSegment (std::string segment_name,
     890              :                    bool has_separating_scope_resolution, location_t locus)
     891         4066 :     : lang_item (tl::nullopt),
     892         4066 :       ident_segment (PathIdentSegment (std::move (segment_name), locus)),
     893         4066 :       locus (locus),
     894         4066 :       has_separating_scope_resolution (has_separating_scope_resolution),
     895         8132 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     896         4066 :   {}
     897              : 
     898              :   // General constructor
     899           93 :   TypePathSegment (tl::optional<LangItem::Kind> lang_item,
     900              :                    tl::optional<PathIdentSegment> ident_segment,
     901              :                    bool has_separating_scope_resolution, location_t locus)
     902          186 :     : lang_item (lang_item), ident_segment (ident_segment), locus (locus),
     903           93 :       has_separating_scope_resolution (has_separating_scope_resolution),
     904           93 :       node_id (Analysis::Mappings::get ().get_next_node_id ())
     905           93 :   {}
     906              : 
     907       107407 :   TypePathSegment (TypePathSegment const &other)
     908       214814 :     : lang_item (other.lang_item), ident_segment (other.ident_segment),
     909       107407 :       locus (other.locus),
     910       107407 :       has_separating_scope_resolution (other.has_separating_scope_resolution),
     911       107407 :       node_id (other.node_id)
     912       107407 :   {}
     913              : 
     914              :   TypePathSegment &operator= (TypePathSegment const &other)
     915              :   {
     916              :     ident_segment = other.ident_segment;
     917              :     lang_item = other.lang_item;
     918              :     locus = other.locus;
     919              :     has_separating_scope_resolution = other.has_separating_scope_resolution;
     920              :     node_id = other.node_id;
     921              : 
     922              :     return *this;
     923              :   }
     924              : 
     925              :   TypePathSegment (TypePathSegment &&other) = default;
     926              :   TypePathSegment &operator= (TypePathSegment &&other) = default;
     927              : 
     928          318 :   virtual std::string as_string () const
     929              :   {
     930          318 :     if (lang_item.has_value ())
     931            0 :       return LangItem::PrettyString (*lang_item);
     932              : 
     933          318 :     return ident_segment->as_string ();
     934              :   }
     935              : 
     936              :   /* Returns whether the type path segment is in an error state. May be
     937              :    * virtual in future. */
     938           55 :   bool is_error () const
     939              :   {
     940           55 :     rust_assert (ident_segment);
     941           55 :     return ident_segment->is_error ();
     942              :   }
     943              : 
     944              :   /* Returns whether segment is identifier only (as opposed to generic args or
     945              :    * function). Overridden in derived classes with other segments. */
     946           30 :   virtual bool is_ident_only () const { return true; }
     947              : 
     948       282065 :   bool is_lang_item () const { return lang_item.has_value (); }
     949              : 
     950         3135 :   location_t get_locus () const { return locus; }
     951              : 
     952              :   // not pure virtual as class not abstract
     953              :   virtual void accept_vis (ASTVisitor &vis);
     954              : 
     955        55168 :   bool get_separating_scope_resolution () const
     956              :   {
     957        55168 :     return has_separating_scope_resolution;
     958              :   }
     959              : 
     960       173045 :   PathIdentSegment &get_ident_segment ()
     961              :   {
     962       173045 :     rust_assert (!is_lang_item ());
     963       173045 :     return *ident_segment;
     964              :   };
     965              : 
     966            2 :   const PathIdentSegment &get_ident_segment () const
     967              :   {
     968            2 :     rust_assert (!is_lang_item ());
     969            2 :     return *ident_segment;
     970              :   };
     971              : 
     972         1168 :   LangItem::Kind get_lang_item () const
     973              :   {
     974         1168 :     rust_assert (is_lang_item ());
     975         1168 :     return *lang_item;
     976              :   }
     977              : 
     978       111693 :   NodeId get_node_id () const { return node_id; }
     979              : 
     980              :   bool is_crate_path_seg () const
     981              :   {
     982              :     return get_ident_segment ().is_crate_path_seg ();
     983              :   }
     984              :   bool is_super_path_seg () const
     985              :   {
     986              :     return get_ident_segment ().is_super_path_seg ();
     987              :   }
     988              :   bool is_big_self_seg () const
     989              :   {
     990              :     return get_ident_segment ().is_big_self_seg ();
     991              :   }
     992              :   bool is_lower_self_seg () const
     993              :   {
     994              :     return get_ident_segment ().is_lower_self_seg ();
     995              :   }
     996              : };
     997              : 
     998              : // Segment used in type path with generic args
     999              : class TypePathSegmentGeneric : public TypePathSegment
    1000              : {
    1001              :   GenericArgs generic_args;
    1002              : 
    1003              : public:
    1004           11 :   SegmentType get_type () const override { return SegmentType::GENERIC; }
    1005              : 
    1006       109691 :   bool has_generic_args () const { return generic_args.has_generic_args (); }
    1007              : 
    1008            0 :   bool is_ident_only () const override { return false; }
    1009              : 
    1010              :   // Constructor with PathIdentSegment and GenericArgs
    1011         2857 :   TypePathSegmentGeneric (PathIdentSegment ident_segment,
    1012              :                           bool has_separating_scope_resolution,
    1013              :                           GenericArgs generic_args, location_t locus)
    1014         2857 :     : TypePathSegment (std::move (ident_segment),
    1015              :                        has_separating_scope_resolution, locus),
    1016         2857 :       generic_args (std::move (generic_args))
    1017         2857 :   {}
    1018              : 
    1019           49 :   TypePathSegmentGeneric (LangItem::Kind lang_item, GenericArgs generic_args,
    1020              :                           location_t locus)
    1021           49 :     : TypePathSegment (lang_item, locus),
    1022           49 :       generic_args (std::move (generic_args))
    1023           49 :   {}
    1024              : 
    1025              :   // Constructor from segment name and all args
    1026              :   TypePathSegmentGeneric (std::string segment_name,
    1027              :                           bool has_separating_scope_resolution,
    1028              :                           std::vector<Lifetime> lifetime_args,
    1029              :                           std::vector<GenericArg> generic_args,
    1030              :                           std::vector<GenericArgsBinding> binding_args,
    1031              :                           location_t locus)
    1032              :     : TypePathSegment (std::move (segment_name),
    1033              :                        has_separating_scope_resolution, locus),
    1034              :       generic_args (GenericArgs (std::move (lifetime_args),
    1035              :                                  std::move (generic_args),
    1036              :                                  std::move (binding_args)))
    1037              :   {}
    1038              : 
    1039              :   // Copy constructor with vector clone
    1040         4763 :   TypePathSegmentGeneric (TypePathSegmentGeneric const &other)
    1041         4763 :     : TypePathSegment (other), generic_args (other.generic_args)
    1042         4763 :   {}
    1043              : 
    1044              :   // Overloaded assignment operator with vector clone
    1045              :   TypePathSegmentGeneric &operator= (TypePathSegmentGeneric const &other)
    1046              :   {
    1047              :     generic_args = other.generic_args;
    1048              : 
    1049              :     return *this;
    1050              :   }
    1051              : 
    1052              :   // move constructors
    1053              :   TypePathSegmentGeneric (TypePathSegmentGeneric &&other) = default;
    1054              :   TypePathSegmentGeneric &operator= (TypePathSegmentGeneric &&other) = default;
    1055              : 
    1056              :   std::string as_string () const override;
    1057              : 
    1058              :   void accept_vis (ASTVisitor &vis) override;
    1059              : 
    1060              :   // TODO: is this better? Or is a "vis_pattern" better?
    1061        57928 :   GenericArgs &get_generic_args () { return generic_args; }
    1062              : 
    1063              :   // Use covariance to override base class method
    1064         4763 :   TypePathSegmentGeneric *clone_type_path_segment_impl () const override
    1065              :   {
    1066         4763 :     return new TypePathSegmentGeneric (*this);
    1067              :   }
    1068              : 
    1069            0 :   TypePathSegmentGeneric *reconstruct_impl () const override
    1070              :   {
    1071            0 :     return new TypePathSegmentGeneric (get_ident_segment (),
    1072            0 :                                        has_separating_scope_resolution,
    1073            0 :                                        generic_args.reconstruct (),
    1074            0 :                                        get_locus ());
    1075              :   }
    1076              : };
    1077              : 
    1078              : // A function as represented in a type path
    1079              : struct TypePathFunction
    1080              : {
    1081              : private:
    1082              :   // TODO: remove
    1083              :   /*bool has_inputs;
    1084              :   TypePathFnInputs inputs;*/
    1085              :   // inlined from TypePathFnInputs
    1086              :   std::vector<std::unique_ptr<Type>> inputs;
    1087              : 
    1088              :   // bool has_type;
    1089              :   std::unique_ptr<Type> return_type;
    1090              : 
    1091              :   // FIXME: think of better way to mark as invalid than taking up storage
    1092              :   bool is_invalid;
    1093              : 
    1094              :   location_t locus;
    1095              : 
    1096              : protected:
    1097              :   // Constructor only used to create invalid type path functions.
    1098            0 :   TypePathFunction (bool is_invalid, location_t locus)
    1099            0 :     : is_invalid (is_invalid), locus (locus)
    1100              :   {}
    1101              : 
    1102              : public:
    1103              :   // Returns whether the return type of the function has been specified.
    1104          582 :   bool has_return_type () const { return return_type != nullptr; }
    1105              : 
    1106              :   // Returns whether the function has inputs.
    1107            5 :   bool has_inputs () const { return !inputs.empty (); }
    1108              : 
    1109              :   // Returns whether function is in an error state.
    1110          612 :   bool is_error () const { return is_invalid; }
    1111              : 
    1112              :   // Creates an error state function.
    1113            0 :   static TypePathFunction create_error ()
    1114              :   {
    1115            0 :     return TypePathFunction (true, UNDEF_LOCATION);
    1116              :   }
    1117              : 
    1118              :   // Constructor
    1119           30 :   TypePathFunction (std::vector<std::unique_ptr<Type>> inputs, location_t locus,
    1120              :                     std::unique_ptr<Type> type = nullptr)
    1121           30 :     : inputs (std::move (inputs)), return_type (std::move (type)),
    1122           30 :       is_invalid (false), locus (locus)
    1123              :   {}
    1124              : 
    1125              :   // Copy constructor with clone
    1126           30 :   TypePathFunction (TypePathFunction const &other)
    1127           30 :     : is_invalid (other.is_invalid)
    1128              :   {
    1129              :     // guard to protect from null pointer dereference
    1130           30 :     if (other.return_type != nullptr)
    1131           28 :       return_type = other.return_type->clone_type ();
    1132              : 
    1133           30 :     inputs.reserve (other.inputs.size ());
    1134           62 :     for (const auto &e : other.inputs)
    1135           32 :       inputs.push_back (e->clone_type ());
    1136           30 :   }
    1137              : 
    1138           30 :   ~TypePathFunction () = default;
    1139              : 
    1140              :   // Overloaded assignment operator to clone type
    1141              :   TypePathFunction &operator= (TypePathFunction const &other)
    1142              :   {
    1143              :     is_invalid = other.is_invalid;
    1144              : 
    1145              :     // guard to protect from null pointer dereference
    1146              :     if (other.return_type != nullptr)
    1147              :       return_type = other.return_type->clone_type ();
    1148              :     else
    1149              :       return_type = nullptr;
    1150              : 
    1151              :     inputs.reserve (other.inputs.size ());
    1152              :     for (const auto &e : other.inputs)
    1153              :       inputs.push_back (e->clone_type ());
    1154              : 
    1155              :     return *this;
    1156              :   }
    1157              : 
    1158              :   // move constructors
    1159           30 :   TypePathFunction (TypePathFunction &&other) = default;
    1160              :   TypePathFunction &operator= (TypePathFunction &&other) = default;
    1161              : 
    1162              :   std::string as_string () const;
    1163              : 
    1164              :   // TODO: this mutable getter seems really dodgy. Think up better way.
    1165              :   const std::vector<std::unique_ptr<Type>> &get_params () const
    1166              :   {
    1167              :     return inputs;
    1168              :   }
    1169          582 :   std::vector<std::unique_ptr<Type>> &get_params () { return inputs; }
    1170              : 
    1171              :   // TODO: is this better? Or is a "vis_pattern" better?
    1172          462 :   Type &get_return_type ()
    1173              :   {
    1174          462 :     rust_assert (has_return_type ());
    1175          462 :     return *return_type;
    1176              :   }
    1177              : 
    1178           84 :   std::unique_ptr<Type> &get_return_type_ptr ()
    1179              :   {
    1180           84 :     rust_assert (has_return_type ());
    1181           84 :     return return_type;
    1182              :   }
    1183              : 
    1184            0 :   TypePathFunction reconstruct () const
    1185              :   {
    1186            0 :     std::vector<std::unique_ptr<Type>> new_inputs;
    1187            0 :     new_inputs.reserve (inputs.size ());
    1188            0 :     for (const auto &e : inputs)
    1189            0 :       new_inputs.push_back (e->reconstruct ());
    1190              : 
    1191            0 :     std::unique_ptr<Type> new_ret = nullptr;
    1192            0 :     if (return_type)
    1193            0 :       new_ret = return_type->reconstruct ();
    1194              : 
    1195            0 :     return TypePathFunction (std::move (new_inputs), locus,
    1196            0 :                              std::move (new_ret));
    1197            0 :   }
    1198              : 
    1199            5 :   location_t get_locus () const { return locus; }
    1200              : };
    1201              : 
    1202              : // Segment used in type path with a function argument
    1203              : class TypePathSegmentFunction : public TypePathSegment
    1204              : {
    1205              :   TypePathFunction function_path;
    1206              : 
    1207              : public:
    1208            7 :   SegmentType get_type () const override { return SegmentType::FUNCTION; }
    1209              : 
    1210              :   // Constructor with PathIdentSegment and TypePathFn
    1211           30 :   TypePathSegmentFunction (PathIdentSegment ident_segment,
    1212              :                            bool has_separating_scope_resolution,
    1213              :                            TypePathFunction function_path, location_t locus)
    1214           30 :     : TypePathSegment (std::move (ident_segment),
    1215              :                        has_separating_scope_resolution, locus),
    1216           30 :       function_path (std::move (function_path))
    1217           30 :   {}
    1218              : 
    1219              :   // Constructor with segment name and TypePathFn
    1220              :   TypePathSegmentFunction (std::string segment_name,
    1221              :                            bool has_separating_scope_resolution,
    1222              :                            TypePathFunction function_path, location_t locus)
    1223              :     : TypePathSegment (std::move (segment_name),
    1224              :                        has_separating_scope_resolution, locus),
    1225              :       function_path (std::move (function_path))
    1226              :   {}
    1227              : 
    1228              :   std::string as_string () const override;
    1229              : 
    1230            5 :   bool is_ident_only () const override { return false; }
    1231              : 
    1232              :   void accept_vis (ASTVisitor &vis) override;
    1233              : 
    1234              :   // TODO: is this better? Or is a "vis_pattern" better?
    1235          582 :   TypePathFunction &get_type_path_function ()
    1236              :   {
    1237          582 :     rust_assert (!function_path.is_error ());
    1238          582 :     return function_path;
    1239              :   }
    1240              : 
    1241              :   // Use covariance to override base class method
    1242           30 :   TypePathSegmentFunction *clone_type_path_segment_impl () const override
    1243              :   {
    1244           30 :     return new TypePathSegmentFunction (*this);
    1245              :   }
    1246              : 
    1247            0 :   TypePathSegmentFunction *reconstruct_impl () const override
    1248              :   {
    1249            0 :     return new TypePathSegmentFunction (get_ident_segment (),
    1250            0 :                                         has_separating_scope_resolution,
    1251            0 :                                         function_path.reconstruct (),
    1252            0 :                                         get_locus ());
    1253              :   }
    1254              : };
    1255              : 
    1256        65912 : class TypePath : public TypeNoBounds
    1257              : {
    1258              :   bool has_opening_scope_resolution;
    1259              :   std::vector<std::unique_ptr<TypePathSegment>> segments;
    1260              :   location_t locus;
    1261              : 
    1262              : protected:
    1263              :   /* Use covariance to implement clone function as returning this object
    1264              :    * rather than base */
    1265        83377 :   TypePath *clone_type_no_bounds_impl () const override
    1266              :   {
    1267        83377 :     return new TypePath (*this);
    1268              :   }
    1269           93 :   TypePath *reconstruct_impl () const override
    1270              :   {
    1271          465 :     return new TypePath (reconstruct_vec (segments), locus,
    1272          186 :                          has_opening_scope_resolution);
    1273              :   }
    1274              : 
    1275              : public:
    1276              :   /* Returns whether the TypePath has an opening scope resolution operator
    1277              :    * (i.e. is global path or crate-relative path, not module-relative) */
    1278       111454 :   bool has_opening_scope_resolution_op () const
    1279              :   {
    1280       111454 :     return has_opening_scope_resolution;
    1281              :   }
    1282              : 
    1283              :   // Returns whether the TypePath is in an invalid state.
    1284        73044 :   bool is_error () const { return segments.empty (); }
    1285              : 
    1286              :   // Creates an error state TypePath.
    1287          631 :   static TypePath create_error ()
    1288              :   {
    1289          631 :     return TypePath (std::vector<std::unique_ptr<TypePathSegment>> (),
    1290          631 :                      UNDEF_LOCATION);
    1291              :   }
    1292              : 
    1293              :   // Constructor
    1294        57934 :   TypePath (std::vector<std::unique_ptr<TypePathSegment>> segments,
    1295              :             location_t locus, bool has_opening_scope_resolution = false)
    1296         3280 :     : TypeNoBounds (),
    1297        57934 :       has_opening_scope_resolution (has_opening_scope_resolution),
    1298        57934 :       segments (std::move (segments)), locus (locus)
    1299              :   {}
    1300              : 
    1301            0 :   TypePath (LangItem::Kind lang_item,
    1302              :             std::vector<std::unique_ptr<TypePathSegment>> segments,
    1303              :             location_t locus, bool has_opening_scope_resolution = false)
    1304            0 :     : TypeNoBounds (),
    1305            0 :       has_opening_scope_resolution (has_opening_scope_resolution),
    1306            0 :       segments (std::move (segments)), locus (locus)
    1307              :   {}
    1308              : 
    1309              :   // Copy constructor with vector clone
    1310       104093 :   TypePath (TypePath const &other)
    1311       104093 :     : TypeNoBounds (other),
    1312       104093 :       has_opening_scope_resolution (other.has_opening_scope_resolution),
    1313       104093 :       locus (other.locus)
    1314              :   {
    1315       104093 :     segments.reserve (other.segments.size ());
    1316       210703 :     for (const auto &e : other.segments)
    1317       106610 :       segments.push_back (e->clone_type_path_segment ());
    1318       104093 :   }
    1319              : 
    1320              :   // Overloaded assignment operator with clone
    1321              :   TypePath &operator= (TypePath const &other)
    1322              :   {
    1323              :     TypeNoBounds::operator= (other);
    1324              :     has_opening_scope_resolution = other.has_opening_scope_resolution;
    1325              :     locus = other.locus;
    1326              : 
    1327              :     segments.reserve (other.segments.size ());
    1328              :     for (const auto &e : other.segments)
    1329              :       segments.push_back (e->clone_type_path_segment ());
    1330              : 
    1331              :     return *this;
    1332              :   }
    1333              : 
    1334              :   // move constructors
    1335        55513 :   TypePath (TypePath &&other) = default;
    1336          431 :   TypePath &operator= (TypePath &&other) = default;
    1337              : 
    1338              :   std::string as_string () const override;
    1339              : 
    1340              :   std::string make_debug_string () const;
    1341              : 
    1342              :   /* Converts TypePath to SimplePath if possible (i.e. no generic or function
    1343              :    * arguments). Otherwise returns an empty SimplePath. */
    1344              :   SimplePath as_simple_path () const;
    1345              : 
    1346              :   // Creates a trait bound with a clone of this type path as its only element.
    1347              :   TraitBound *to_trait_bound (bool in_parens) const override;
    1348              : 
    1349        99271 :   location_t get_locus () const override final { return locus; }
    1350       297240 :   NodeId get_node_id () const override { return node_id; }
    1351              : 
    1352            0 :   void mark_for_strip () override {}
    1353       248188 :   bool is_marked_for_strip () const override { return false; }
    1354              : 
    1355              :   void accept_vis (ASTVisitor &vis) override;
    1356              : 
    1357              :   // TODO: this seems kinda dodgy
    1358         3648 :   std::vector<std::unique_ptr<TypePathSegment>> &get_segments ()
    1359              :   {
    1360      1217705 :     return segments;
    1361              :   }
    1362        54301 :   const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const
    1363              :   {
    1364        54303 :     return segments;
    1365              :   }
    1366              : 
    1367              :   size_t get_num_segments () const { return segments.size (); }
    1368              : 
    1369          258 :   Type::Kind get_type_kind () const override { return Type::Kind::TypePath; }
    1370              : };
    1371              : 
    1372              : struct QualifiedPathType
    1373              : {
    1374              : private:
    1375              :   std::unique_ptr<Type> type_to_invoke_on;
    1376              :   TypePath trait_path;
    1377              :   location_t locus;
    1378              :   NodeId node_id;
    1379              : 
    1380              : public:
    1381              :   // Constructor
    1382          445 :   QualifiedPathType (std::unique_ptr<Type> invoke_on_type,
    1383              :                      location_t locus = UNDEF_LOCATION,
    1384              :                      TypePath trait_path = TypePath::create_error ())
    1385          445 :     : type_to_invoke_on (std::move (invoke_on_type)), trait_path (trait_path),
    1386          445 :       locus (locus), node_id (Analysis::Mappings::get ().get_next_node_id ())
    1387          445 :   {}
    1388              : 
    1389              :   // Copy constructor uses custom deep copy for Type to preserve polymorphism
    1390          983 :   QualifiedPathType (QualifiedPathType const &other)
    1391          983 :     : trait_path (other.trait_path), locus (other.locus)
    1392              :   {
    1393          983 :     node_id = other.node_id;
    1394              :     // guard to prevent null dereference
    1395          983 :     if (other.type_to_invoke_on != nullptr)
    1396          983 :       type_to_invoke_on = other.type_to_invoke_on->clone_type ();
    1397          983 :   }
    1398              : 
    1399              :   // default destructor
    1400         2334 :   ~QualifiedPathType () = default;
    1401              : 
    1402              :   // overload assignment operator to use custom clone method
    1403              :   QualifiedPathType &operator= (QualifiedPathType const &other)
    1404              :   {
    1405              :     node_id = other.node_id;
    1406              :     trait_path = other.trait_path;
    1407              :     locus = other.locus;
    1408              : 
    1409              :     // guard to prevent null dereference
    1410              :     if (other.type_to_invoke_on != nullptr)
    1411              :       type_to_invoke_on = other.type_to_invoke_on->clone_type ();
    1412              :     else
    1413              :       type_to_invoke_on = nullptr;
    1414              : 
    1415              :     return *this;
    1416              :   }
    1417              : 
    1418              :   // move constructor
    1419         1301 :   QualifiedPathType (QualifiedPathType &&other) = default;
    1420            0 :   QualifiedPathType &operator= (QualifiedPathType &&other) = default;
    1421              : 
    1422            0 :   QualifiedPathType reconstruct () const
    1423              :   {
    1424            0 :     auto new_type = type_to_invoke_on->reconstruct ();
    1425              : 
    1426              :     // trait_path is stored by value, but reconstruct returns a unique_ptr.
    1427              :     // We must dereference it to pass to the constructor.
    1428              :     // This is safe because the constructor makes its own copy/move.
    1429            0 :     auto new_trait_path_ptr = trait_path.reconstruct ();
    1430            0 :     TypePath *concrete_ptr
    1431            0 :       = static_cast<TypePath *> (new_trait_path_ptr.get ());
    1432              : 
    1433            0 :     return QualifiedPathType (std::move (new_type), locus, *concrete_ptr);
    1434            0 :   }
    1435              : 
    1436              :   // Returns whether the qualified path type has a rebind as clause.
    1437         9809 :   bool has_as_clause () const { return !trait_path.is_error (); }
    1438              : 
    1439              :   // Returns whether the qualified path type is in an error state.
    1440        10763 :   bool is_error () const { return type_to_invoke_on == nullptr; }
    1441              : 
    1442              :   // Creates an error state qualified path type.
    1443            0 :   static QualifiedPathType create_error ()
    1444              :   {
    1445            0 :     return QualifiedPathType (nullptr);
    1446              :   }
    1447              : 
    1448              :   std::string as_string () const;
    1449              : 
    1450          532 :   location_t get_locus () const { return locus; }
    1451              : 
    1452              :   // TODO: is this better? Or is a "vis_pattern" better?
    1453         8388 :   Type &get_type ()
    1454              :   {
    1455         8388 :     rust_assert (type_to_invoke_on != nullptr);
    1456         8388 :     return *type_to_invoke_on;
    1457              :   }
    1458              : 
    1459         1421 :   std::unique_ptr<Type> &get_type_ptr ()
    1460              :   {
    1461         1421 :     rust_assert (type_to_invoke_on != nullptr);
    1462         1421 :     return type_to_invoke_on;
    1463              :   }
    1464              : 
    1465              :   // TODO: is this better? Or is a "vis_pattern" better?
    1466         8882 :   TypePath &get_as_type_path ()
    1467              :   {
    1468         8882 :     rust_assert (has_as_clause ());
    1469         8882 :     return trait_path;
    1470              :   }
    1471              : 
    1472          356 :   NodeId get_node_id () const { return node_id; }
    1473              : };
    1474              : 
    1475              : /* AST node representing a qualified path-in-expression pattern (path that
    1476              :  * allows specifying trait functions) */
    1477              : class QualifiedPathInExpression : public Path, public ExprWithoutBlock
    1478              : {
    1479              :   std::vector<Attribute> outer_attrs;
    1480              :   QualifiedPathType path_type;
    1481              :   location_t locus;
    1482              :   NodeId _node_id;
    1483              : 
    1484              : public:
    1485              :   std::string as_string () const override;
    1486              : 
    1487          114 :   QualifiedPathInExpression (QualifiedPathType qual_path_type,
    1488              :                              std::vector<PathExprSegment> path_segments,
    1489              :                              std::vector<Attribute> outer_attrs,
    1490              :                              location_t locus)
    1491          228 :     : Path (std::move (path_segments)), outer_attrs (std::move (outer_attrs)),
    1492          114 :       path_type (std::move (qual_path_type)), locus (locus),
    1493          114 :       _node_id (Analysis::Mappings::get ().get_next_node_id ())
    1494          114 :   {}
    1495              : 
    1496              :   /* TODO: maybe make a shortcut constructor that has QualifiedPathType
    1497              :    * elements as params */
    1498              : 
    1499              :   // Returns whether qualified path in expression is in an error state.
    1500          526 :   bool is_error () const { return path_type.is_error (); }
    1501              : 
    1502              :   // Creates an error qualified path in expression.
    1503            0 :   static QualifiedPathInExpression create_error ()
    1504              :   {
    1505            0 :     return QualifiedPathInExpression (QualifiedPathType::create_error (), {},
    1506            0 :                                       {}, UNDEF_LOCATION);
    1507              :   }
    1508              : 
    1509          310 :   location_t get_locus () const override final { return locus; }
    1510              : 
    1511              :   void accept_vis (ASTVisitor &vis) override;
    1512              : 
    1513              :   // Invalid if path_type is error, so base stripping on that.
    1514            0 :   void mark_for_strip () override
    1515              :   {
    1516            0 :     path_type = QualifiedPathType::create_error ();
    1517            0 :   }
    1518          526 :   bool is_marked_for_strip () const override { return is_error (); }
    1519              : 
    1520              :   // TODO: is this better? Or is a "vis_pattern" better?
    1521         2720 :   QualifiedPathType &get_qualified_path_type ()
    1522              :   {
    1523         2720 :     rust_assert (!path_type.is_error ());
    1524         2720 :     return path_type;
    1525              :   }
    1526              : 
    1527              :   const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
    1528         2954 :   std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
    1529              : 
    1530           97 :   void set_outer_attrs (std::vector<Attribute> new_attrs) override
    1531              :   {
    1532           97 :     outer_attrs = std::move (new_attrs);
    1533            0 :   }
    1534              : 
    1535          144 :   NodeId get_node_id () const override { return _node_id; }
    1536              : 
    1537          114 :   Expr::Kind get_expr_kind () const override
    1538              :   {
    1539          114 :     return Expr::Kind::QualifiedPathInExpression;
    1540              :   }
    1541              : 
    1542              :   std::unique_ptr<QualifiedPathInExpression> reconstruct () const
    1543              :   {
    1544              :     std::vector<PathExprSegment> new_segments;
    1545              :     new_segments.reserve (segments.size ());
    1546              :     for (const auto &seg : segments)
    1547              :       new_segments.push_back (seg.reconstruct ());
    1548              : 
    1549              :     auto *new_path = new QualifiedPathInExpression (path_type.reconstruct (),
    1550              :                                                     std::move (new_segments),
    1551              :                                                     outer_attrs, locus);
    1552              : 
    1553              :     return std::unique_ptr<QualifiedPathInExpression> (new_path);
    1554              :   }
    1555              : 
    1556              : protected:
    1557              :   /* Use covariance to implement clone function as returning this object
    1558              :    * rather than base */
    1559            0 :   QualifiedPathInExpression *clone_pattern_impl () const final override
    1560              :   {
    1561            0 :     return clone_qual_path_in_expression_impl ();
    1562              :   }
    1563              : 
    1564              :   /* Use covariance to implement clone function as returning this object
    1565              :    * rather than base */
    1566              :   QualifiedPathInExpression *
    1567            0 :   clone_expr_without_block_impl () const final override
    1568              :   {
    1569            0 :     return clone_qual_path_in_expression_impl ();
    1570              :   }
    1571              : 
    1572              :   /*virtual*/ QualifiedPathInExpression *
    1573          169 :   clone_qual_path_in_expression_impl () const
    1574              :   {
    1575          169 :     return new QualifiedPathInExpression (*this);
    1576              :   }
    1577              : };
    1578              : 
    1579              : /* Represents a qualified path in a type; used for disambiguating trait
    1580              :  * function calls */
    1581              : class QualifiedPathInType : public TypeNoBounds
    1582              : {
    1583              :   QualifiedPathType path_type;
    1584              :   std::unique_ptr<TypePathSegment> associated_segment;
    1585              :   std::vector<std::unique_ptr<TypePathSegment>> segments;
    1586              :   location_t locus;
    1587              : 
    1588              : protected:
    1589              :   /* Use covariance to implement clone function as returning this object
    1590              :    * rather than base */
    1591          797 :   QualifiedPathInType *clone_type_no_bounds_impl () const override
    1592              :   {
    1593          797 :     return new QualifiedPathInType (*this);
    1594              :   }
    1595            0 :   QualifiedPathInType *reconstruct_impl () const override
    1596              :   {
    1597            0 :     return new QualifiedPathInType (path_type.reconstruct (),
    1598            0 :                                     associated_segment->reconstruct (),
    1599            0 :                                     reconstruct_vec (segments), locus);
    1600              :   }
    1601              : 
    1602              : public:
    1603          331 :   QualifiedPathInType (
    1604              :     QualifiedPathType qual_path_type,
    1605              :     std::unique_ptr<TypePathSegment> associated_segment,
    1606              :     std::vector<std::unique_ptr<TypePathSegment>> path_segments,
    1607              :     location_t locus)
    1608          662 :     : path_type (std::move (qual_path_type)),
    1609          331 :       associated_segment (std::move (associated_segment)),
    1610          331 :       segments (std::move (path_segments)), locus (locus)
    1611          331 :   {}
    1612              : 
    1613              :   // Copy constructor with vector clone
    1614          797 :   QualifiedPathInType (QualifiedPathInType const &other)
    1615          797 :     : path_type (other.path_type), locus (other.locus)
    1616              :   {
    1617          797 :     auto seg = other.associated_segment->clone_type_path_segment_impl ();
    1618          797 :     associated_segment = std::unique_ptr<TypePathSegment> (seg);
    1619              : 
    1620          797 :     segments.reserve (other.segments.size ());
    1621          797 :     for (const auto &e : other.segments)
    1622            0 :       segments.push_back (e->clone_type_path_segment ());
    1623          797 :   }
    1624              : 
    1625              :   // Overloaded assignment operator with vector clone
    1626              :   QualifiedPathInType &operator= (QualifiedPathInType const &other)
    1627              :   {
    1628              :     auto seg = other.associated_segment->clone_type_path_segment_impl ();
    1629              :     associated_segment = std::unique_ptr<TypePathSegment> (seg);
    1630              : 
    1631              :     path_type = other.path_type;
    1632              :     locus = other.locus;
    1633              : 
    1634              :     segments.reserve (other.segments.size ());
    1635              :     for (const auto &e : other.segments)
    1636              :       segments.push_back (e->clone_type_path_segment ());
    1637              : 
    1638              :     return *this;
    1639              :   }
    1640              : 
    1641              :   // move constructors
    1642          331 :   QualifiedPathInType (QualifiedPathInType &&other) = default;
    1643              :   QualifiedPathInType &operator= (QualifiedPathInType &&other) = default;
    1644              : 
    1645              :   // Returns whether qualified path in type is in an error state.
    1646          331 :   bool is_error () const { return path_type.is_error (); }
    1647              : 
    1648              :   // Creates an error state qualified path in type.
    1649            0 :   static QualifiedPathInType create_error ()
    1650              :   {
    1651            0 :     return QualifiedPathInType (
    1652            0 :       QualifiedPathType::create_error (), nullptr,
    1653            0 :       std::vector<std::unique_ptr<TypePathSegment>> (), UNDEF_LOCATION);
    1654              :   }
    1655              : 
    1656              :   std::string as_string () const override;
    1657              : 
    1658              :   void accept_vis (ASTVisitor &vis) override;
    1659              : 
    1660              :   // TODO: is this better? Or is a "vis_pattern" better?
    1661         7815 :   QualifiedPathType &get_qualified_path_type ()
    1662              :   {
    1663         7815 :     rust_assert (!path_type.is_error ());
    1664         7815 :     return path_type;
    1665              :   }
    1666              : 
    1667              :   std::unique_ptr<TypePathSegment> &get_associated_segment ()
    1668              :   {
    1669         5127 :     return associated_segment;
    1670              :   }
    1671              : 
    1672              :   // TODO: this seems kinda dodgy
    1673              :   std::vector<std::unique_ptr<TypePathSegment>> &get_segments ()
    1674              :   {
    1675         5836 :     return segments;
    1676              :   }
    1677              :   const std::vector<std::unique_ptr<TypePathSegment>> &get_segments () const
    1678              :   {
    1679              :     return segments;
    1680              :   }
    1681              : 
    1682          248 :   location_t get_locus () const override final { return locus; }
    1683              : 
    1684            0 :   Type::Kind get_type_kind () const override
    1685              :   {
    1686            0 :     return Type::Kind::QualifiedPathInType;
    1687              :   }
    1688              : };
    1689              : } // namespace AST
    1690              : } // namespace Rust
    1691              : 
    1692              : #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.