LCOV - code coverage report
Current view: top level - gcc/rust/ast - rust-path.h (source / functions) Coverage Total Hit
Test: gcc.info Lines: 83.7 % 534 447
Test Date: 2026-09-19 16:22:48 Functions: 84.9 % 139 118
Legend: Lines:     hit not hit

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