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