1  // Copyright (C) 2020-2023 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_HIR_BASE_H
      20  #define RUST_HIR_BASE_H
      21  
      22  #include "rust-ast.h"
      23  #include "rust-system.h"
      24  #include "rust-token.h"
      25  #include "rust-location.h"
      26  #include "rust-hir-map.h"
      27  #include "rust-diagnostics.h"
      28  
      29  namespace Rust {
      30  typedef std::string Identifier;
      31  typedef int TupleIndex;
      32  
      33  namespace HIR {
      34  // foward decl: ast visitor
      35  class HIRFullVisitor;
      36  class HIRStmtVisitor;
      37  class HIRTraitItemVisitor;
      38  class HIRExternalItemVisitor;
      39  class HIRVisItemVisitor;
      40  class HIRExpressionVisitor;
      41  class HIRPatternVisitor;
      42  class HIRImplVisitor;
      43  class HIRTypeVisitor;
      44  
      45  // forward decl for use in token tree method
      46  class Token;
      47  
      48  class Node
      49  {
      50  public:
      51    // Kind for downcasting various HIR nodes to other base classes when visiting
      52    // them
      53    enum BaseKind
      54    {
      55      /* class ExternalItem */
      56      EXTERNAL,
      57      /* class TraitItem */
      58      TRAIT_ITEM,
      59      /* class VisItem */
      60      VIS_ITEM,
      61      /* class Item */
      62      ITEM,
      63      /* class ImplItem */
      64      IMPL,
      65      /* class Type */
      66      TYPE,
      67      /* class Stmt */
      68      STMT,
      69      /* class Expr */
      70      EXPR,
      71      /* class Pattern */
      72      PATTERN,
      73    };
      74  
      75    /**
      76     * Get the kind of HIR node we are dealing with. This is useful for
      77     * downcasting to more precise types when necessary, i.e going from an `Item*`
      78     * to a `VisItem*`
      79     */
      80    virtual BaseKind get_hir_kind () = 0;
      81  };
      82  
      83  // A literal - value with a type. Used in LiteralExpr and LiteralPattern.
      84  struct Literal
      85  {
      86  public:
      87    enum LitType
      88    {
      89      CHAR,
      90      STRING,
      91      BYTE,
      92      BYTE_STRING,
      93      INT,
      94      FLOAT,
      95      BOOL
      96    };
      97  
      98  private:
      99    std::string value_as_string;
     100    LitType type;
     101    PrimitiveCoreType type_hint;
     102  
     103  public:
     104    std::string as_string () const { return value_as_string; }
     105  
     106    LitType get_lit_type () const { return type; }
     107  
     108    PrimitiveCoreType get_type_hint () const { return type_hint; }
     109  
     110    Literal (std::string value_as_string, LitType type,
     111  	   PrimitiveCoreType type_hint)
     112      : value_as_string (std::move (value_as_string)), type (type),
     113        type_hint (type_hint)
     114    {}
     115  
     116    static Literal create_error ()
     117    {
     118      return Literal ("", CHAR, PrimitiveCoreType::CORETYPE_UNKNOWN);
     119    }
     120  
     121    void set_lit_type (LitType lt) { type = lt; }
     122  
     123    // Returns whether literal is in an invalid state.
     124    bool is_error () const { return value_as_string == ""; }
     125  
     126    bool is_equal (Literal &other)
     127    {
     128      return value_as_string == other.value_as_string && type == other.type
     129  	   && type_hint == other.type_hint;
     130    }
     131  };
     132  
     133  /* Base statement abstract class. Note that most "statements" are not allowed in
     134   * top-level module scope - only a subclass of statements called "items" are. */
     135  class Stmt : public Node
     136  {
     137  public:
     138    // Unique pointer custom clone function
     139    std::unique_ptr<Stmt> clone_stmt () const
     140    {
     141      return std::unique_ptr<Stmt> (clone_stmt_impl ());
     142    }
     143  
     144    BaseKind get_hir_kind () override { return STMT; }
     145  
     146    virtual ~Stmt () {}
     147  
     148    virtual std::string as_string () const = 0;
     149  
     150    virtual void accept_vis (HIRFullVisitor &vis) = 0;
     151    virtual void accept_vis (HIRStmtVisitor &vis) = 0;
     152  
     153    virtual Location get_locus () const = 0;
     154  
     155    virtual bool is_unit_check_needed () const { return false; }
     156  
     157    const Analysis::NodeMapping &get_mappings () const { return mappings; }
     158  
     159    virtual bool is_item () const = 0;
     160  
     161  protected:
     162    Stmt (Analysis::NodeMapping mappings) : mappings (std::move (mappings)) {}
     163  
     164    // Clone function implementation as pure virtual method
     165    virtual Stmt *clone_stmt_impl () const = 0;
     166  
     167    Analysis::NodeMapping mappings;
     168  };
     169  
     170  // Rust "item" HIR node (declaration of top-level/module-level allowed stuff)
     171  class Item : public Stmt
     172  {
     173    AST::AttrVec outer_attrs;
     174  
     175    // TODO: should outer attrs be defined here or in each derived class?
     176  
     177  public:
     178    enum class ItemKind
     179    {
     180      Static,
     181      Constant,
     182      TypeAlias,
     183      Function,
     184      UseDeclaration,
     185      ExternBlock,
     186      ExternCrate,
     187      Struct,
     188      Union,
     189      Enum,
     190      EnumItem, // FIXME: ARTHUR: Do we need that?
     191      Trait,
     192      Impl,
     193      Module,
     194    };
     195  
     196    virtual ItemKind get_item_kind () const = 0;
     197  
     198    // Unique pointer custom clone function
     199    std::unique_ptr<Item> clone_item () const
     200    {
     201      return std::unique_ptr<Item> (clone_item_impl ());
     202    }
     203  
     204    BaseKind get_hir_kind () override { return ITEM; }
     205  
     206    std::string as_string () const override;
     207  
     208    /* Adds crate names to the vector passed by reference, if it can
     209     * (polymorphism). */
     210    virtual void
     211    add_crate_name (std::vector<std::string> &names ATTRIBUTE_UNUSED) const
     212    {}
     213  
     214    AST::AttrVec &get_outer_attrs () { return outer_attrs; }
     215    const AST::AttrVec &get_outer_attrs () const { return outer_attrs; }
     216  
     217    bool is_item () const override final { return true; }
     218  
     219  protected:
     220    // Constructor
     221    Item (Analysis::NodeMapping mappings,
     222  	AST::AttrVec outer_attribs = AST::AttrVec ())
     223      : Stmt (std::move (mappings)), outer_attrs (std::move (outer_attribs))
     224    {}
     225  
     226    // Clone function implementation as pure virtual method
     227    virtual Item *clone_item_impl () const = 0;
     228  
     229    /* Save having to specify two clone methods in derived classes by making
     230     * statement clone return item clone. Hopefully won't affect performance too
     231     * much. */
     232    Item *clone_stmt_impl () const override { return clone_item_impl (); }
     233  };
     234  
     235  // forward decl of ExprWithoutBlock
     236  class ExprWithoutBlock;
     237  
     238  // Base expression HIR node - abstract
     239  class Expr : public Node
     240  {
     241  protected:
     242    AST::AttrVec outer_attrs;
     243    Analysis::NodeMapping mappings;
     244  
     245  public:
     246    enum BlockType
     247    {
     248      WITH_BLOCK,
     249      WITHOUT_BLOCK,
     250    };
     251  
     252    enum ExprType
     253    {
     254      Lit,
     255      Operator,
     256      Grouped,
     257      Array,
     258      ArrayIndex,
     259      Tuple,
     260      TupleIdx,
     261      Struct,
     262      Call,
     263      MethodCall,
     264      FieldAccess,
     265      Closure,
     266      Block,
     267      Continue,
     268      Break,
     269      Range,
     270      Return,
     271      UnsafeBlock,
     272      BaseLoop,
     273      If,
     274      IfLet,
     275      Match,
     276      Await,
     277      AsyncBlock,
     278      Path,
     279    };
     280  
     281    BaseKind get_hir_kind () override final { return EXPR; }
     282  
     283    const AST::AttrVec &get_outer_attrs () const { return outer_attrs; }
     284  
     285    // Unique pointer custom clone function
     286    std::unique_ptr<Expr> clone_expr () const
     287    {
     288      return std::unique_ptr<Expr> (clone_expr_impl ());
     289    }
     290  
     291    /* HACK: downcasting without dynamic_cast (if possible) via polymorphism -
     292     * overrided in subclasses of ExprWithoutBlock */
     293    virtual ExprWithoutBlock *as_expr_without_block () const { return nullptr; }
     294  
     295    // TODO: make pure virtual if move out outer attributes to derived classes
     296    virtual std::string as_string () const;
     297  
     298    virtual ~Expr () {}
     299  
     300    virtual Location get_locus () const = 0;
     301  
     302    const Analysis::NodeMapping &get_mappings () const { return mappings; }
     303  
     304    // Clone function implementation as pure virtual method
     305    virtual Expr *clone_expr_impl () const = 0;
     306  
     307    virtual BlockType get_block_expr_type () const = 0;
     308  
     309    virtual ExprType get_expression_type () const = 0;
     310  
     311    virtual void accept_vis (HIRExpressionVisitor &vis) = 0;
     312    virtual void accept_vis (HIRFullVisitor &vis) = 0;
     313  
     314  protected:
     315    // Constructor
     316    Expr (Analysis::NodeMapping mappings,
     317  	AST::AttrVec outer_attribs = AST::AttrVec ())
     318      : outer_attrs (std::move (outer_attribs)), mappings (std::move (mappings))
     319    {}
     320  
     321    // TODO: think of less hacky way to implement this kind of thing
     322    // Sets outer attributes.
     323    void set_outer_attrs (AST::AttrVec outer_attrs_to_set)
     324    {
     325      outer_attrs = std::move (outer_attrs_to_set);
     326    }
     327  };
     328  
     329  // HIR node for an expression without an accompanying block - abstract
     330  class ExprWithoutBlock : public Expr
     331  {
     332  protected:
     333    // Constructor
     334    ExprWithoutBlock (Analysis::NodeMapping mappings,
     335  		    AST::AttrVec outer_attribs = AST::AttrVec ())
     336      : Expr (std::move (mappings), std::move (outer_attribs))
     337    {}
     338  
     339    // pure virtual clone implementation
     340    virtual ExprWithoutBlock *clone_expr_without_block_impl () const = 0;
     341  
     342    /* Save having to specify two clone methods in derived classes by making expr
     343     * clone return exprwithoutblock clone. Hopefully won't affect performance too
     344     * much. */
     345    ExprWithoutBlock *clone_expr_impl () const override
     346    {
     347      return clone_expr_without_block_impl ();
     348    }
     349  
     350  public:
     351    // Unique pointer custom clone function
     352    std::unique_ptr<ExprWithoutBlock> clone_expr_without_block () const
     353    {
     354      return std::unique_ptr<ExprWithoutBlock> (clone_expr_without_block_impl ());
     355    }
     356  
     357    /* downcasting hack from expr to use pratt parsing with
     358     * parse_expr_without_block */
     359    ExprWithoutBlock *as_expr_without_block () const override
     360    {
     361      return clone_expr_without_block_impl ();
     362    }
     363  
     364    BlockType get_block_expr_type () const final override
     365    {
     366      return BlockType::WITHOUT_BLOCK;
     367    };
     368  };
     369  
     370  // Pattern base HIR node
     371  class Pattern : public Node
     372  {
     373  public:
     374    enum PatternType
     375    {
     376      PATH,
     377      LITERAL,
     378      IDENTIFIER,
     379      WILDCARD,
     380      RANGE,
     381      REFERENCE,
     382      STRUCT,
     383      TUPLE_STRUCT,
     384      TUPLE,
     385      GROUPED,
     386      SLICE,
     387    };
     388  
     389    BaseKind get_hir_kind () override final { return PATTERN; }
     390  
     391    // Unique pointer custom clone function
     392    std::unique_ptr<Pattern> clone_pattern () const
     393    {
     394      return std::unique_ptr<Pattern> (clone_pattern_impl ());
     395    }
     396  
     397    // possible virtual methods: is_refutable()
     398  
     399    virtual ~Pattern () {}
     400  
     401    virtual std::string as_string () const = 0;
     402  
     403    virtual void accept_vis (HIRFullVisitor &vis) = 0;
     404    virtual void accept_vis (HIRPatternVisitor &vis) = 0;
     405  
     406    virtual Analysis::NodeMapping get_pattern_mappings () const = 0;
     407  
     408    virtual Location get_locus () const = 0;
     409  
     410    virtual PatternType get_pattern_type () const = 0;
     411  
     412  protected:
     413    // Clone pattern implementation as pure virtual method
     414    virtual Pattern *clone_pattern_impl () const = 0;
     415  };
     416  
     417  // forward decl for Type
     418  class TraitBound;
     419  
     420  // Base class for types as represented in HIR - abstract
     421  class Type : public Node
     422  {
     423  public:
     424    // Unique pointer custom clone function
     425    std::unique_ptr<Type> clone_type () const
     426    {
     427      return std::unique_ptr<Type> (clone_type_impl ());
     428    }
     429  
     430    // virtual destructor
     431    virtual ~Type () {}
     432  
     433    BaseKind get_hir_kind () override final { return TYPE; }
     434  
     435    virtual std::string as_string () const = 0;
     436  
     437    /* HACK: convert to trait bound. Virtual method overriden by classes that
     438     * enable this. */
     439    virtual TraitBound *to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const
     440    {
     441      return nullptr;
     442    }
     443    /* as pointer, shouldn't require definition beforehand, only forward
     444     * declaration. */
     445  
     446    virtual void accept_vis (HIRFullVisitor &vis) = 0;
     447    virtual void accept_vis (HIRTypeVisitor &vis) = 0;
     448  
     449    virtual Analysis::NodeMapping get_mappings () const { return mappings; }
     450    virtual Location get_locus () const { return locus; }
     451  
     452  protected:
     453    Type (Analysis::NodeMapping mappings, Location locus)
     454      : mappings (mappings), locus (locus)
     455    {}
     456  
     457    // Clone function implementation as pure virtual method
     458    virtual Type *clone_type_impl () const = 0;
     459  
     460    Analysis::NodeMapping mappings;
     461    Location locus;
     462  };
     463  
     464  // A type without parentheses? - abstract
     465  class TypeNoBounds : public Type
     466  {
     467  public:
     468    // Unique pointer custom clone function
     469    std::unique_ptr<TypeNoBounds> clone_type_no_bounds () const
     470    {
     471      return std::unique_ptr<TypeNoBounds> (clone_type_no_bounds_impl ());
     472    }
     473  
     474  protected:
     475    TypeNoBounds (Analysis::NodeMapping mappings, Location locus)
     476      : Type (mappings, locus)
     477    {}
     478  
     479    // Clone function implementation as pure virtual method
     480    virtual TypeNoBounds *clone_type_no_bounds_impl () const = 0;
     481  
     482    /* Save having to specify two clone methods in derived classes by making type
     483     * clone return typenobounds clone. Hopefully won't affect performance too
     484     * much. */
     485    TypeNoBounds *clone_type_impl () const override
     486    {
     487      return clone_type_no_bounds_impl ();
     488    }
     489  };
     490  
     491  /* Abstract base class representing a type param bound - Lifetime and TraitBound
     492   * extends it */
     493  class TypeParamBound
     494  {
     495  public:
     496    enum BoundType
     497    {
     498      LIFETIME,
     499      TRAITBOUND
     500    };
     501  
     502    virtual ~TypeParamBound () {}
     503  
     504    // Unique pointer custom clone function
     505    std::unique_ptr<TypeParamBound> clone_type_param_bound () const
     506    {
     507      return std::unique_ptr<TypeParamBound> (clone_type_param_bound_impl ());
     508    }
     509  
     510    virtual std::string as_string () const = 0;
     511  
     512    virtual void accept_vis (HIRFullVisitor &vis) = 0;
     513  
     514    virtual Analysis::NodeMapping get_mappings () const = 0;
     515  
     516    virtual Location get_locus () const = 0;
     517  
     518    virtual BoundType get_bound_type () const = 0;
     519  
     520  protected:
     521    // Clone function implementation as pure virtual method
     522    virtual TypeParamBound *clone_type_param_bound_impl () const = 0;
     523  };
     524  
     525  // Represents a lifetime (and is also a kind of type param bound)
     526  class Lifetime : public TypeParamBound
     527  {
     528  private:
     529    AST::Lifetime::LifetimeType lifetime_type;
     530    std::string lifetime_name;
     531    Location locus;
     532    Analysis::NodeMapping mappings;
     533  
     534  public:
     535    // Constructor
     536    Lifetime (Analysis::NodeMapping mapping, AST::Lifetime::LifetimeType type,
     537  	    std::string name, Location locus)
     538      : lifetime_type (type), lifetime_name (std::move (name)), locus (locus),
     539        mappings (mapping)
     540    {}
     541  
     542    // Returns true if the lifetime is in an error state.
     543    bool is_error () const
     544    {
     545      return lifetime_type == AST::Lifetime::LifetimeType::NAMED
     546  	   && lifetime_name.empty ();
     547    }
     548  
     549    static Lifetime error ()
     550    {
     551      return Lifetime (Analysis::NodeMapping::get_error (),
     552  		     AST::Lifetime::LifetimeType::NAMED, "", Location ());
     553    }
     554  
     555    std::string as_string () const override;
     556  
     557    void accept_vis (HIRFullVisitor &vis) override;
     558  
     559    std::string get_name () const { return lifetime_name; }
     560  
     561    AST::Lifetime::LifetimeType get_lifetime_type () const
     562    {
     563      return lifetime_type;
     564    }
     565  
     566    Location get_locus () const override final { return locus; }
     567  
     568    Analysis::NodeMapping get_mappings () const override final
     569    {
     570      return mappings;
     571    }
     572  
     573    BoundType get_bound_type () const final override { return LIFETIME; }
     574  
     575  protected:
     576    /* Use covariance to implement clone function as returning this object rather
     577     * than base */
     578    Lifetime *clone_type_param_bound_impl () const override
     579    {
     580      return new Lifetime (*this);
     581    }
     582  };
     583  
     584  /* Base generic parameter in HIR. Abstract - can be represented by a Lifetime or
     585   * Type param */
     586  class GenericParam
     587  {
     588  public:
     589    virtual ~GenericParam () {}
     590  
     591    enum class GenericKind
     592    {
     593      TYPE,
     594      LIFETIME,
     595      CONST,
     596    };
     597  
     598    // Unique pointer custom clone function
     599    std::unique_ptr<GenericParam> clone_generic_param () const
     600    {
     601      return std::unique_ptr<GenericParam> (clone_generic_param_impl ());
     602    }
     603  
     604    virtual std::string as_string () const = 0;
     605  
     606    virtual void accept_vis (HIRFullVisitor &vis) = 0;
     607  
     608    virtual Location get_locus () const = 0;
     609  
     610    Analysis::NodeMapping get_mappings () const { return mappings; }
     611  
     612    enum GenericKind get_kind () const { return kind; }
     613  
     614  protected:
     615    // Clone function implementation as pure virtual method
     616    virtual GenericParam *clone_generic_param_impl () const = 0;
     617  
     618    Analysis::NodeMapping mappings;
     619  
     620    enum GenericKind kind;
     621  
     622    GenericParam (Analysis::NodeMapping mapping,
     623  		enum GenericKind kind = GenericKind::TYPE)
     624      : mappings (mapping), kind (kind)
     625    {}
     626  };
     627  
     628  // A lifetime generic parameter (as opposed to a type generic parameter)
     629  class LifetimeParam : public GenericParam
     630  {
     631    Lifetime lifetime;
     632  
     633    // bool has_lifetime_bounds;
     634    // LifetimeBounds lifetime_bounds;
     635    std::vector<Lifetime> lifetime_bounds; // inlined LifetimeBounds
     636  
     637    // bool has_outer_attribute;
     638    // std::unique_ptr<Attribute> outer_attr;
     639    AST::Attribute outer_attr;
     640  
     641    Location locus;
     642  
     643  public:
     644    Lifetime get_lifetime () { return lifetime; }
     645  
     646    // Returns whether the lifetime param has any lifetime bounds.
     647    bool has_lifetime_bounds () const { return !lifetime_bounds.empty (); }
     648  
     649    // Returns whether the lifetime param has an outer attribute.
     650    bool has_outer_attribute () const { return !outer_attr.is_empty (); }
     651  
     652    // Returns whether the lifetime param is in an error state.
     653    bool is_error () const { return lifetime.is_error (); }
     654  
     655    // Constructor
     656    LifetimeParam (Analysis::NodeMapping mappings, Lifetime lifetime,
     657  		 Location locus = Location (),
     658  		 std::vector<Lifetime> lifetime_bounds
     659  		 = std::vector<Lifetime> (),
     660  		 AST::Attribute outer_attr = AST::Attribute::create_empty ())
     661      : GenericParam (mappings, GenericKind::LIFETIME),
     662        lifetime (std::move (lifetime)),
     663        lifetime_bounds (std::move (lifetime_bounds)),
     664        outer_attr (std::move (outer_attr)), locus (locus)
     665    {}
     666  
     667    // TODO: remove copy and assignment operator definitions - not required
     668  
     669    // Copy constructor with clone
     670    LifetimeParam (LifetimeParam const &other)
     671      : GenericParam (other.mappings, GenericKind::LIFETIME),
     672        lifetime (other.lifetime), lifetime_bounds (other.lifetime_bounds),
     673        outer_attr (other.outer_attr), locus (other.locus)
     674    {}
     675  
     676    // Overloaded assignment operator to clone attribute
     677    LifetimeParam &operator= (LifetimeParam const &other)
     678    {
     679      lifetime = other.lifetime;
     680      lifetime_bounds = other.lifetime_bounds;
     681      outer_attr = other.outer_attr;
     682      locus = other.locus;
     683      mappings = other.mappings;
     684  
     685      return *this;
     686    }
     687  
     688    // move constructors
     689    LifetimeParam (LifetimeParam &&other) = default;
     690    LifetimeParam &operator= (LifetimeParam &&other) = default;
     691  
     692    std::string as_string () const override;
     693  
     694    void accept_vis (HIRFullVisitor &vis) override;
     695  
     696    Location get_locus () const override final { return locus; }
     697  
     698  protected:
     699    /* Use covariance to implement clone function as returning this object rather
     700     * than base */
     701    LifetimeParam *clone_generic_param_impl () const override
     702    {
     703      return new LifetimeParam (*this);
     704    }
     705  };
     706  
     707  class ConstGenericParam : public GenericParam
     708  {
     709  public:
     710    ConstGenericParam (std::string name, std::unique_ptr<Type> type,
     711  		     std::unique_ptr<Expr> default_expression,
     712  		     Analysis::NodeMapping mapping, Location locus)
     713      : GenericParam (mapping, GenericKind::CONST), name (std::move (name)),
     714        type (std::move (type)),
     715        default_expression (std::move (default_expression)), locus (locus)
     716    {}
     717  
     718    ConstGenericParam (const ConstGenericParam &other) : GenericParam (other)
     719    {
     720      name = other.name;
     721      locus = other.locus;
     722  
     723      if (other.type)
     724        type = other.type->clone_type ();
     725      if (other.default_expression)
     726        default_expression = other.default_expression->clone_expr ();
     727    }
     728  
     729    std::string as_string () const override final;
     730  
     731    void accept_vis (HIRFullVisitor &vis) override final;
     732  
     733    Location get_locus () const override final { return locus; };
     734  
     735    bool has_default_expression () { return default_expression != nullptr; }
     736  
     737    std::unique_ptr<Type> &get_type () { return type; }
     738    std::unique_ptr<Expr> &get_default_expression ()
     739    {
     740      rust_assert (has_default_expression ());
     741  
     742      return default_expression;
     743    }
     744  
     745  protected:
     746    /* Use covariance to implement clone function as returning this object rather
     747     * than base */
     748    ConstGenericParam *clone_generic_param_impl () const override
     749    {
     750      return new ConstGenericParam (*this);
     751    }
     752  
     753  private:
     754    std::string name;
     755    std::unique_ptr<Type> type;
     756  
     757    /* Optional - can be a null pointer if there is no default expression */
     758    std::unique_ptr<Expr> default_expression;
     759  
     760    Location locus;
     761  };
     762  
     763  // Item used in trait declarations - abstract base class
     764  class TraitItem : public Node
     765  {
     766  public:
     767    enum TraitItemKind
     768    {
     769      FUNC,
     770      CONST,
     771      TYPE
     772    };
     773  
     774    BaseKind get_hir_kind () override final { return TRAIT_ITEM; }
     775  
     776  protected:
     777    // Constructor
     778    TraitItem (Analysis::NodeMapping mappings) : mappings (mappings) {}
     779  
     780    // Clone function implementation as pure virtual method
     781    virtual TraitItem *clone_trait_item_impl () const = 0;
     782  
     783    Analysis::NodeMapping mappings;
     784  
     785  public:
     786    virtual ~TraitItem () {}
     787  
     788    std::unique_ptr<TraitItem> clone_trait_item () const
     789    {
     790      return std::unique_ptr<TraitItem> (clone_trait_item_impl ());
     791    }
     792  
     793    virtual std::string as_string () const = 0;
     794  
     795    virtual void accept_vis (HIRTraitItemVisitor &vis) = 0;
     796    virtual void accept_vis (HIRFullVisitor &vis) = 0;
     797  
     798    virtual const std::string trait_identifier () const = 0;
     799  
     800    const Analysis::NodeMapping &get_mappings () const { return mappings; }
     801  
     802    virtual Location get_trait_locus () const = 0;
     803  
     804    virtual TraitItemKind get_item_kind () const = 0;
     805  
     806    virtual AST::AttrVec &get_outer_attrs () = 0;
     807    virtual const AST::AttrVec &get_outer_attrs () const = 0;
     808  };
     809  
     810  class ImplItem : public Node
     811  {
     812  public:
     813    enum ImplItemType
     814    {
     815      FUNCTION,
     816      TYPE_ALIAS,
     817      CONSTANT
     818    };
     819  
     820    virtual ~ImplItem () {}
     821  
     822    BaseKind get_hir_kind () override final { return IMPL; }
     823  
     824    // Unique pointer custom clone function
     825    std::unique_ptr<ImplItem> clone_inherent_impl_item () const
     826    {
     827      return std::unique_ptr<ImplItem> (clone_inherent_impl_item_impl ());
     828    }
     829  
     830    virtual std::string as_string () const = 0;
     831  
     832    virtual void accept_vis (HIRImplVisitor &vis) = 0;
     833    virtual void accept_vis (HIRFullVisitor &vis) = 0;
     834    virtual void accept_vis (HIRStmtVisitor &vis) = 0;
     835  
     836    virtual Analysis::NodeMapping get_impl_mappings () const = 0;
     837  
     838    virtual Location get_locus () const = 0;
     839  
     840    virtual ImplItemType get_impl_item_type () const = 0;
     841  
     842    virtual std::string get_impl_item_name () const = 0;
     843  
     844  protected:
     845    // Clone function implementation as pure virtual method
     846    virtual ImplItem *clone_inherent_impl_item_impl () const = 0;
     847  };
     848  
     849  // A crate HIR object - holds all the data for a single compilation unit
     850  struct Crate
     851  {
     852    AST::AttrVec inner_attrs;
     853    // dodgy spacing required here
     854    /* TODO: is it better to have a vector of items here or a module (implicit
     855     * top-level one)? */
     856    std::vector<std::unique_ptr<Item> > items;
     857  
     858    Analysis::NodeMapping mappings;
     859  
     860  public:
     861    // Constructor
     862    Crate (std::vector<std::unique_ptr<Item> > items, AST::AttrVec inner_attrs,
     863  	 Analysis::NodeMapping mappings)
     864      : inner_attrs (std::move (inner_attrs)), items (std::move (items)),
     865        mappings (mappings)
     866    {}
     867  
     868    // Copy constructor with vector clone
     869    Crate (Crate const &other)
     870      : inner_attrs (other.inner_attrs), mappings (other.mappings)
     871    {
     872      items.reserve (other.items.size ());
     873      for (const auto &e : other.items)
     874        items.push_back (e->clone_item ());
     875    }
     876  
     877    ~Crate () = default;
     878  
     879    // Overloaded assignment operator with vector clone
     880    Crate &operator= (Crate const &other)
     881    {
     882      inner_attrs = other.inner_attrs;
     883      mappings = other.mappings;
     884  
     885      items.reserve (other.items.size ());
     886      for (const auto &e : other.items)
     887        items.push_back (e->clone_item ());
     888  
     889      return *this;
     890    }
     891  
     892    // Move constructors
     893    Crate (Crate &&other) = default;
     894    Crate &operator= (Crate &&other) = default;
     895  
     896    // Get crate representation as string (e.g. for debugging).
     897    std::string as_string () const;
     898  
     899    const Analysis::NodeMapping &get_mappings () const { return mappings; }
     900  };
     901  
     902  // Base path expression HIR node - abstract
     903  class PathExpr : public ExprWithoutBlock
     904  {
     905  protected:
     906    PathExpr (Analysis::NodeMapping mappings, AST::AttrVec outer_attribs)
     907      : ExprWithoutBlock (std::move (mappings), std::move (outer_attribs))
     908    {}
     909  
     910  public:
     911    /* Replaces the outer attributes of this path expression with the given outer
     912     * attributes. */
     913    void replace_outer_attrs (AST::AttrVec outer_attrs)
     914    {
     915      set_outer_attrs (std::move (outer_attrs));
     916    }
     917  
     918    ExprType get_expression_type () const final override
     919    {
     920      return ExprType::Path;
     921    }
     922  };
     923  } // namespace HIR
     924  } // namespace Rust
     925  
     926  #endif