(root)/
gcc-13.2.0/
gcc/
rust/
ast/
rust-type.h
       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_AST_TYPE_H
      20  #define RUST_AST_TYPE_H
      21  
      22  #include "rust-ast.h"
      23  #include "rust-path.h"
      24  
      25  namespace Rust {
      26  namespace AST {
      27  // definitions moved to rust-ast.h
      28  class TypeParamBound;
      29  class Lifetime;
      30  
      31  // A trait bound
      32  class TraitBound : public TypeParamBound
      33  {
      34    bool in_parens;
      35    bool opening_question_mark;
      36  
      37    // bool has_for_lifetimes;
      38    // LifetimeParams for_lifetimes;
      39    std::vector<LifetimeParam> for_lifetimes; // inlined LifetimeParams
      40  
      41    TypePath type_path;
      42  
      43    Location locus;
      44  
      45  public:
      46    // Returns whether trait bound has "for" lifetimes
      47    bool has_for_lifetimes () const { return !for_lifetimes.empty (); }
      48  
      49    std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; }
      50  
      51    TraitBound (TypePath type_path, Location locus, bool in_parens = false,
      52  	      bool opening_question_mark = false,
      53  	      std::vector<LifetimeParam> for_lifetimes
      54  	      = std::vector<LifetimeParam> ())
      55      : TypeParamBound (Analysis::Mappings::get ()->get_next_node_id ()),
      56        in_parens (in_parens), opening_question_mark (opening_question_mark),
      57        for_lifetimes (std::move (for_lifetimes)),
      58        type_path (std::move (type_path)), locus (locus)
      59    {}
      60  
      61    TraitBound (NodeId id, TypePath type_path, Location locus,
      62  	      bool in_parens = false, bool opening_question_mark = false,
      63  	      std::vector<LifetimeParam> for_lifetimes
      64  	      = std::vector<LifetimeParam> ())
      65      : TypeParamBound (id), in_parens (in_parens),
      66        opening_question_mark (opening_question_mark),
      67        for_lifetimes (std::move (for_lifetimes)),
      68        type_path (std::move (type_path)), locus (locus)
      69    {}
      70  
      71    std::string as_string () const override;
      72  
      73    Location get_locus () const override final { return locus; }
      74  
      75    void accept_vis (ASTVisitor &vis) override;
      76  
      77    // TODO: this mutable getter seems kinda dodgy
      78    TypePath &get_type_path () { return type_path; }
      79    const TypePath &get_type_path () const { return type_path; }
      80  
      81    bool is_in_parens () const { return in_parens; }
      82    bool has_opening_question_mark () const { return opening_question_mark; }
      83  
      84  protected:
      85    /* Use covariance to implement clone function as returning this object rather
      86     * than base */
      87    TraitBound *clone_type_param_bound_impl () const override
      88    {
      89      return new TraitBound (node_id, type_path, locus, in_parens,
      90  			   opening_question_mark, for_lifetimes);
      91    }
      92  };
      93  
      94  // definition moved to rust-ast.h
      95  class TypeNoBounds;
      96  
      97  // An impl trait? Poor reference material here.
      98  class ImplTraitType : public Type
      99  {
     100    // TypeParamBounds type_param_bounds;
     101    // inlined form
     102    std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds;
     103  
     104    Location locus;
     105  
     106  protected:
     107    /* Use covariance to implement clone function as returning this object rather
     108     * than base */
     109    ImplTraitType *clone_type_impl () const override
     110    {
     111      return new ImplTraitType (*this);
     112    }
     113  
     114  public:
     115    ImplTraitType (
     116      std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds,
     117      Location locus)
     118      : type_param_bounds (std::move (type_param_bounds)), locus (locus)
     119    {}
     120  
     121    // copy constructor with vector clone
     122    ImplTraitType (ImplTraitType const &other) : locus (other.locus)
     123    {
     124      type_param_bounds.reserve (other.type_param_bounds.size ());
     125      for (const auto &e : other.type_param_bounds)
     126        type_param_bounds.push_back (e->clone_type_param_bound ());
     127    }
     128  
     129    // overloaded assignment operator to clone
     130    ImplTraitType &operator= (ImplTraitType const &other)
     131    {
     132      locus = other.locus;
     133  
     134      type_param_bounds.reserve (other.type_param_bounds.size ());
     135      for (const auto &e : other.type_param_bounds)
     136        type_param_bounds.push_back (e->clone_type_param_bound ());
     137  
     138      return *this;
     139    }
     140  
     141    // move constructors
     142    ImplTraitType (ImplTraitType &&other) = default;
     143    ImplTraitType &operator= (ImplTraitType &&other) = default;
     144  
     145    std::string as_string () const override;
     146  
     147    Location get_locus () const override final { return locus; }
     148  
     149    void accept_vis (ASTVisitor &vis) override;
     150  
     151    // TODO: mutable getter seems kinda dodgy
     152    std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds ()
     153    {
     154      return type_param_bounds;
     155    }
     156    const std::vector<std::unique_ptr<TypeParamBound> > &
     157    get_type_param_bounds () const
     158    {
     159      return type_param_bounds;
     160    }
     161  };
     162  
     163  // An opaque value of another type that implements a set of traits
     164  class TraitObjectType : public Type
     165  {
     166    bool has_dyn;
     167    std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds;
     168    Location locus;
     169  
     170  protected:
     171    /* Use covariance to implement clone function as returning this object rather
     172     * than base */
     173    TraitObjectType *clone_type_impl () const override
     174    {
     175      return new TraitObjectType (*this);
     176    }
     177  
     178  public:
     179    TraitObjectType (
     180      std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds,
     181      Location locus, bool is_dyn_dispatch)
     182      : has_dyn (is_dyn_dispatch),
     183        type_param_bounds (std::move (type_param_bounds)), locus (locus)
     184    {}
     185  
     186    // copy constructor with vector clone
     187    TraitObjectType (TraitObjectType const &other)
     188      : has_dyn (other.has_dyn), locus (other.locus)
     189    {
     190      type_param_bounds.reserve (other.type_param_bounds.size ());
     191      for (const auto &e : other.type_param_bounds)
     192        type_param_bounds.push_back (e->clone_type_param_bound ());
     193    }
     194  
     195    // overloaded assignment operator to clone
     196    TraitObjectType &operator= (TraitObjectType const &other)
     197    {
     198      has_dyn = other.has_dyn;
     199      locus = other.locus;
     200      type_param_bounds.reserve (other.type_param_bounds.size ());
     201      for (const auto &e : other.type_param_bounds)
     202        type_param_bounds.push_back (e->clone_type_param_bound ());
     203  
     204      return *this;
     205    }
     206  
     207    // move constructors
     208    TraitObjectType (TraitObjectType &&other) = default;
     209    TraitObjectType &operator= (TraitObjectType &&other) = default;
     210  
     211    std::string as_string () const override;
     212  
     213    Location get_locus () const override final { return locus; }
     214  
     215    void accept_vis (ASTVisitor &vis) override;
     216  
     217    bool is_dyn () const { return has_dyn; }
     218  
     219    // TODO: mutable getter seems kinda dodgy
     220    std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds ()
     221    {
     222      return type_param_bounds;
     223    }
     224    const std::vector<std::unique_ptr<TypeParamBound> > &
     225    get_type_param_bounds () const
     226    {
     227      return type_param_bounds;
     228    }
     229  };
     230  
     231  // A type with parentheses around it, used to avoid ambiguity.
     232  class ParenthesisedType : public TypeNoBounds
     233  {
     234    std::unique_ptr<Type> type_in_parens;
     235    Location locus;
     236  
     237  protected:
     238    /* Use covariance to implement clone function as returning this object rather
     239     * than base */
     240    ParenthesisedType *clone_type_no_bounds_impl () const override
     241    {
     242      return new ParenthesisedType (*this);
     243    }
     244  
     245  public:
     246    // Constructor uses Type pointer for polymorphism
     247    ParenthesisedType (std::unique_ptr<Type> type_inside_parens, Location locus)
     248      : type_in_parens (std::move (type_inside_parens)), locus (locus)
     249    {}
     250  
     251    /* Copy constructor uses custom deep copy method for type to preserve
     252     * polymorphism */
     253    ParenthesisedType (ParenthesisedType const &other)
     254      : type_in_parens (other.type_in_parens->clone_type ()), locus (other.locus)
     255    {}
     256  
     257    // overload assignment operator to use custom clone method
     258    ParenthesisedType &operator= (ParenthesisedType const &other)
     259    {
     260      type_in_parens = other.type_in_parens->clone_type ();
     261      locus = other.locus;
     262      return *this;
     263    }
     264  
     265    // default move semantics
     266    ParenthesisedType (ParenthesisedType &&other) = default;
     267    ParenthesisedType &operator= (ParenthesisedType &&other) = default;
     268  
     269    std::string as_string () const override
     270    {
     271      return "(" + type_in_parens->as_string () + ")";
     272    }
     273  
     274    // Creates a trait bound (clone of this one's trait bound) - HACK
     275    TraitBound *to_trait_bound (bool) const override
     276    {
     277      /* NOTE: obviously it is unknown whether the internal type is a trait bound
     278       * due to polymorphism, so just let the internal type handle it. As
     279       * parenthesised type, it must be in parentheses. */
     280      return type_in_parens->to_trait_bound (true);
     281    }
     282  
     283    Location get_locus () const override final { return locus; }
     284  
     285    void accept_vis (ASTVisitor &vis) override;
     286  
     287    // TODO: would a "vis_type" be better?
     288    std::unique_ptr<Type> &get_type_in_parens ()
     289    {
     290      rust_assert (type_in_parens != nullptr);
     291      return type_in_parens;
     292    }
     293  };
     294  
     295  // Impl trait with a single bound? Poor reference material here.
     296  class ImplTraitTypeOneBound : public TypeNoBounds
     297  {
     298    TraitBound trait_bound;
     299    Location locus;
     300  
     301  protected:
     302    /* Use covariance to implement clone function as returning this object rather
     303     * than base */
     304    ImplTraitTypeOneBound *clone_type_no_bounds_impl () const override
     305    {
     306      return new ImplTraitTypeOneBound (*this);
     307    }
     308  
     309  public:
     310    ImplTraitTypeOneBound (TraitBound trait_bound, Location locus)
     311      : trait_bound (std::move (trait_bound)), locus (locus)
     312    {}
     313  
     314    std::string as_string () const override;
     315  
     316    Location get_locus () const override final { return locus; }
     317  
     318    void accept_vis (ASTVisitor &vis) override;
     319  
     320    // TODO: would a "vis_type" be better?
     321    TraitBound &get_trait_bound ()
     322    {
     323      // TODO: check to ensure invariants are met?
     324      return trait_bound;
     325    }
     326  };
     327  
     328  /* A trait object with a single trait bound. The "trait bound" is really just
     329   * the trait. Basically like using an interface as a type in an OOP language. */
     330  class TraitObjectTypeOneBound : public TypeNoBounds
     331  {
     332    bool has_dyn;
     333    TraitBound trait_bound;
     334    Location locus;
     335  
     336  protected:
     337    /* Use covariance to implement clone function as returning this object rather
     338     * than base */
     339    TraitObjectTypeOneBound *clone_type_no_bounds_impl () const override
     340    {
     341      return new TraitObjectTypeOneBound (*this);
     342    }
     343  
     344  public:
     345    TraitObjectTypeOneBound (TraitBound trait_bound, Location locus,
     346  			   bool is_dyn_dispatch = false)
     347      : has_dyn (is_dyn_dispatch), trait_bound (std::move (trait_bound)),
     348        locus (locus)
     349    {}
     350  
     351    std::string as_string () const override;
     352  
     353    // Creates a trait bound (clone of this one's trait bound) - HACK
     354    TraitBound *to_trait_bound (bool) const override
     355    {
     356      /* NOTE: this assumes there is no dynamic dispatch specified- if there was,
     357       * this cloning would not be required as parsing is unambiguous. */
     358      return new TraitBound (trait_bound);
     359    }
     360  
     361    Location get_locus () const override final { return locus; }
     362  
     363    void accept_vis (ASTVisitor &vis) override;
     364  
     365    // TODO: would a "vis_type" be better?
     366    TraitBound &get_trait_bound ()
     367    {
     368      // TODO: check to ensure invariants are met?
     369      return trait_bound;
     370    }
     371  
     372    bool is_dyn () const { return has_dyn; }
     373  };
     374  
     375  class TypePath; // definition moved to "rust-path.h"
     376  
     377  /* A type consisting of the "product" of others (the tuple's elements) in a
     378   * specific order */
     379  class TupleType : public TypeNoBounds
     380  {
     381    std::vector<std::unique_ptr<Type> > elems;
     382    Location locus;
     383  
     384  public:
     385    // Returns whether the tuple type is the unit type, i.e. has no elements.
     386    bool is_unit_type () const { return elems.empty (); }
     387  
     388    TupleType (std::vector<std::unique_ptr<Type> > elems, Location locus)
     389      : elems (std::move (elems)), locus (locus)
     390    {}
     391  
     392    // copy constructor with vector clone
     393    TupleType (TupleType const &other) : locus (other.locus)
     394    {
     395      elems.reserve (other.elems.size ());
     396      for (const auto &e : other.elems)
     397        elems.push_back (e->clone_type ());
     398    }
     399  
     400    // overloaded assignment operator to clone
     401    TupleType &operator= (TupleType const &other)
     402    {
     403      locus = other.locus;
     404  
     405      elems.reserve (other.elems.size ());
     406      for (const auto &e : other.elems)
     407        elems.push_back (e->clone_type ());
     408  
     409      return *this;
     410    }
     411  
     412    // move constructors
     413    TupleType (TupleType &&other) = default;
     414    TupleType &operator= (TupleType &&other) = default;
     415  
     416    std::string as_string () const override;
     417  
     418    Location get_locus () const override final { return locus; }
     419  
     420    void accept_vis (ASTVisitor &vis) override;
     421  
     422    // TODO: mutable getter seems kinda dodgy
     423    std::vector<std::unique_ptr<Type> > &get_elems () { return elems; }
     424    const std::vector<std::unique_ptr<Type> > &get_elems () const
     425    {
     426      return elems;
     427    }
     428  
     429  protected:
     430    /* Use covariance to implement clone function as returning this object rather
     431     * than base */
     432    TupleType *clone_type_no_bounds_impl () const override
     433    {
     434      return new TupleType (*this);
     435    }
     436  };
     437  
     438  /* A type with no values, representing the result of computations that never
     439   * complete. Expressions of NeverType can be coerced into any other types.
     440   * Represented as "!". */
     441  class NeverType : public TypeNoBounds
     442  {
     443    Location locus;
     444  
     445  protected:
     446    /* Use covariance to implement clone function as returning this object rather
     447     * than base */
     448    NeverType *clone_type_no_bounds_impl () const override
     449    {
     450      return new NeverType (*this);
     451    }
     452  
     453  public:
     454    NeverType (Location locus) : locus (locus) {}
     455  
     456    std::string as_string () const override { return "! (never type)"; }
     457  
     458    Location get_locus () const override final { return locus; }
     459  
     460    void accept_vis (ASTVisitor &vis) override;
     461  };
     462  
     463  // A type consisting of a pointer without safety or liveness guarantees
     464  class RawPointerType : public TypeNoBounds
     465  {
     466  public:
     467    enum PointerType
     468    {
     469      MUT,
     470      CONST
     471    };
     472  
     473  private:
     474    PointerType pointer_type;
     475    std::unique_ptr<TypeNoBounds> type;
     476    Location locus;
     477  
     478  public:
     479    // Returns whether the pointer is mutable or constant.
     480    PointerType get_pointer_type () const { return pointer_type; }
     481  
     482    // Constructor requires pointer for polymorphism reasons
     483    RawPointerType (PointerType pointer_type,
     484  		  std::unique_ptr<TypeNoBounds> type_no_bounds, Location locus)
     485      : pointer_type (pointer_type), type (std::move (type_no_bounds)),
     486        locus (locus)
     487    {}
     488  
     489    // Copy constructor calls custom polymorphic clone function
     490    RawPointerType (RawPointerType const &other)
     491      : pointer_type (other.pointer_type),
     492        type (other.type->clone_type_no_bounds ()), locus (other.locus)
     493    {}
     494  
     495    // overload assignment operator to use custom clone method
     496    RawPointerType &operator= (RawPointerType const &other)
     497    {
     498      pointer_type = other.pointer_type;
     499      type = other.type->clone_type_no_bounds ();
     500      locus = other.locus;
     501      return *this;
     502    }
     503  
     504    // default move semantics
     505    RawPointerType (RawPointerType &&other) = default;
     506    RawPointerType &operator= (RawPointerType &&other) = default;
     507  
     508    std::string as_string () const override;
     509  
     510    Location get_locus () const override final { return locus; }
     511  
     512    void accept_vis (ASTVisitor &vis) override;
     513  
     514    // TODO: would a "vis_type" be better?
     515    std::unique_ptr<TypeNoBounds> &get_type_pointed_to ()
     516    {
     517      rust_assert (type != nullptr);
     518      return type;
     519    }
     520  
     521  protected:
     522    /* Use covariance to implement clone function as returning this object rather
     523     * than base */
     524    RawPointerType *clone_type_no_bounds_impl () const override
     525    {
     526      return new RawPointerType (*this);
     527    }
     528  };
     529  
     530  // A type pointing to memory owned by another value
     531  class ReferenceType : public TypeNoBounds
     532  {
     533    // bool has_lifetime; // TODO: handle in lifetime or something?
     534    Lifetime lifetime;
     535  
     536    bool has_mut;
     537    std::unique_ptr<TypeNoBounds> type;
     538    Location locus;
     539  
     540  public:
     541    // Returns whether the reference is mutable or immutable.
     542    bool is_mut () const { return has_mut; }
     543  
     544    // Returns whether the reference has a lifetime.
     545    bool has_lifetime () const { return !lifetime.is_error (); }
     546  
     547    // Constructor
     548    ReferenceType (bool is_mut, std::unique_ptr<TypeNoBounds> type_no_bounds,
     549  		 Location locus, Lifetime lifetime = Lifetime::error ())
     550      : lifetime (std::move (lifetime)), has_mut (is_mut),
     551        type (std::move (type_no_bounds)), locus (locus)
     552    {}
     553  
     554    // Copy constructor with custom clone method
     555    ReferenceType (ReferenceType const &other)
     556      : lifetime (other.lifetime), has_mut (other.has_mut),
     557        type (other.type->clone_type_no_bounds ()), locus (other.locus)
     558    {}
     559  
     560    // Operator overload assignment operator to custom clone the unique pointer
     561    ReferenceType &operator= (ReferenceType const &other)
     562    {
     563      lifetime = other.lifetime;
     564      has_mut = other.has_mut;
     565      type = other.type->clone_type_no_bounds ();
     566      locus = other.locus;
     567  
     568      return *this;
     569    }
     570  
     571    // move constructors
     572    ReferenceType (ReferenceType &&other) = default;
     573    ReferenceType &operator= (ReferenceType &&other) = default;
     574  
     575    std::string as_string () const override;
     576  
     577    Location get_locus () const override final { return locus; }
     578  
     579    void accept_vis (ASTVisitor &vis) override;
     580  
     581    // TODO: would a "vis_type" be better?
     582    std::unique_ptr<TypeNoBounds> &get_type_referenced ()
     583    {
     584      rust_assert (type != nullptr);
     585      return type;
     586    }
     587  
     588    bool get_has_mut () const { return has_mut; }
     589  
     590    Lifetime &get_lifetime () { return lifetime; }
     591  
     592    std::unique_ptr<TypeNoBounds> &get_base_type () { return type; }
     593  
     594  protected:
     595    /* Use covariance to implement clone function as returning this object rather
     596     * than base */
     597    ReferenceType *clone_type_no_bounds_impl () const override
     598    {
     599      return new ReferenceType (*this);
     600    }
     601  };
     602  
     603  // A fixed-size sequence of elements of a specified type
     604  class ArrayType : public TypeNoBounds
     605  {
     606    std::unique_ptr<Type> elem_type;
     607    std::unique_ptr<Expr> size;
     608    Location locus;
     609  
     610  public:
     611    // Constructor requires pointers for polymorphism
     612    ArrayType (std::unique_ptr<Type> type, std::unique_ptr<Expr> array_size,
     613  	     Location locus)
     614      : elem_type (std::move (type)), size (std::move (array_size)), locus (locus)
     615    {}
     616  
     617    // Copy constructor requires deep copies of both unique pointers
     618    ArrayType (ArrayType const &other)
     619      : elem_type (other.elem_type->clone_type ()),
     620        size (other.size->clone_expr ()), locus (other.locus)
     621    {}
     622  
     623    // Overload assignment operator to deep copy pointers
     624    ArrayType &operator= (ArrayType const &other)
     625    {
     626      elem_type = other.elem_type->clone_type ();
     627      size = other.size->clone_expr ();
     628      locus = other.locus;
     629      return *this;
     630    }
     631  
     632    // move constructors
     633    ArrayType (ArrayType &&other) = default;
     634    ArrayType &operator= (ArrayType &&other) = default;
     635  
     636    std::string as_string () const override;
     637  
     638    Location get_locus () const override final { return locus; }
     639  
     640    void accept_vis (ASTVisitor &vis) override;
     641  
     642    // TODO: would a "vis_type" be better?
     643    std::unique_ptr<Type> &get_elem_type ()
     644    {
     645      rust_assert (elem_type != nullptr);
     646      return elem_type;
     647    }
     648  
     649    // TODO: would a "vis_expr" be better?
     650    std::unique_ptr<Expr> &get_size_expr ()
     651    {
     652      rust_assert (size != nullptr);
     653      return size;
     654    }
     655  
     656  protected:
     657    /* Use covariance to implement clone function as returning this object rather
     658     * than base */
     659    ArrayType *clone_type_no_bounds_impl () const override
     660    {
     661      return new ArrayType (*this);
     662    }
     663  };
     664  
     665  /* A dynamically-sized type representing a "view" into a sequence of elements of
     666   * a type */
     667  class SliceType : public TypeNoBounds
     668  {
     669    std::unique_ptr<Type> elem_type;
     670    Location locus;
     671  
     672  public:
     673    // Constructor requires pointer for polymorphism
     674    SliceType (std::unique_ptr<Type> type, Location locus)
     675      : elem_type (std::move (type)), locus (locus)
     676    {}
     677  
     678    // Copy constructor requires deep copy of Type smart pointer
     679    SliceType (SliceType const &other)
     680      : elem_type (other.elem_type->clone_type ()), locus (other.locus)
     681    {}
     682  
     683    // Overload assignment operator to deep copy
     684    SliceType &operator= (SliceType const &other)
     685    {
     686      elem_type = other.elem_type->clone_type ();
     687      locus = other.locus;
     688  
     689      return *this;
     690    }
     691  
     692    // move constructors
     693    SliceType (SliceType &&other) = default;
     694    SliceType &operator= (SliceType &&other) = default;
     695  
     696    std::string as_string () const override;
     697  
     698    Location get_locus () const override final { return locus; }
     699  
     700    void accept_vis (ASTVisitor &vis) override;
     701  
     702    // TODO: would a "vis_type" be better?
     703    std::unique_ptr<Type> &get_elem_type ()
     704    {
     705      rust_assert (elem_type != nullptr);
     706      return elem_type;
     707    }
     708  
     709  protected:
     710    /* Use covariance to implement clone function as returning this object rather
     711     * than base */
     712    SliceType *clone_type_no_bounds_impl () const override
     713    {
     714      return new SliceType (*this);
     715    }
     716  };
     717  
     718  /* Type used in generic arguments to explicitly request type inference (wildcard
     719   * pattern) */
     720  class InferredType : public TypeNoBounds
     721  {
     722    Location locus;
     723  
     724    // e.g. Vec<_> = whatever
     725  protected:
     726    /* Use covariance to implement clone function as returning this object rather
     727     * than base */
     728    InferredType *clone_type_no_bounds_impl () const override
     729    {
     730      return new InferredType (*this);
     731    }
     732  
     733  public:
     734    InferredType (Location locus) : locus (locus) {}
     735  
     736    std::string as_string () const override;
     737  
     738    Location get_locus () const override final { return locus; }
     739  
     740    void accept_vis (ASTVisitor &vis) override;
     741  };
     742  
     743  class QualifiedPathInType; // definition moved to "rust-path.h"
     744  
     745  // A possibly named param used in a BaseFunctionType
     746  struct MaybeNamedParam
     747  {
     748  public:
     749    enum ParamKind
     750    {
     751      UNNAMED,
     752      IDENTIFIER,
     753      WILDCARD
     754    };
     755  
     756  private:
     757    std::vector<Attribute> outer_attrs;
     758  
     759    std::unique_ptr<Type> param_type;
     760  
     761    ParamKind param_kind;
     762    Identifier name; // technically, can be an identifier or '_'
     763  
     764    Location locus;
     765  
     766  public:
     767    MaybeNamedParam (Identifier name, ParamKind param_kind,
     768  		   std::unique_ptr<Type> param_type,
     769  		   std::vector<Attribute> outer_attrs, Location locus)
     770      : outer_attrs (std::move (outer_attrs)),
     771        param_type (std::move (param_type)), param_kind (param_kind),
     772        name (std::move (name)), locus (locus)
     773    {}
     774  
     775    // Copy constructor with clone
     776    MaybeNamedParam (MaybeNamedParam const &other)
     777      : outer_attrs (other.outer_attrs), param_kind (other.param_kind),
     778        name (other.name), locus (other.locus)
     779    {
     780      // guard to prevent null dereference
     781      if (other.param_type != nullptr)
     782        param_type = other.param_type->clone_type ();
     783    }
     784  
     785    ~MaybeNamedParam () = default;
     786  
     787    // Overloaded assignment operator with clone
     788    MaybeNamedParam &operator= (MaybeNamedParam const &other)
     789    {
     790      outer_attrs = other.outer_attrs;
     791      name = other.name;
     792      param_kind = other.param_kind;
     793      locus = other.locus;
     794  
     795      // guard to prevent null dereference
     796      if (other.param_type != nullptr)
     797        param_type = other.param_type->clone_type ();
     798      else
     799        param_type = nullptr;
     800  
     801      return *this;
     802    }
     803  
     804    // move constructors
     805    MaybeNamedParam (MaybeNamedParam &&other) = default;
     806    MaybeNamedParam &operator= (MaybeNamedParam &&other) = default;
     807  
     808    std::string as_string () const;
     809  
     810    // Returns whether the param is in an error state.
     811    bool is_error () const { return param_type == nullptr; }
     812  
     813    // Creates an error state param.
     814    static MaybeNamedParam create_error ()
     815    {
     816      return MaybeNamedParam ("", UNNAMED, nullptr, {}, Location ());
     817    }
     818  
     819    Location get_locus () const { return locus; }
     820  
     821    // TODO: this mutable getter seems really dodgy. Think up better way.
     822    std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
     823    const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; }
     824  
     825    // TODO: would a "vis_type" be better?
     826    std::unique_ptr<Type> &get_type ()
     827    {
     828      rust_assert (param_type != nullptr);
     829      return param_type;
     830    }
     831  
     832    ParamKind get_param_kind () const { return param_kind; }
     833  
     834    Identifier get_name () const { return name; }
     835  };
     836  
     837  /* A function pointer type - can be created via coercion from function items and
     838   * non-capturing closures. */
     839  class BareFunctionType : public TypeNoBounds
     840  {
     841    // bool has_for_lifetimes;
     842    // ForLifetimes for_lifetimes;
     843    std::vector<LifetimeParam> for_lifetimes; // inlined version
     844  
     845    FunctionQualifiers function_qualifiers;
     846    std::vector<MaybeNamedParam> params;
     847    bool _is_variadic;
     848    std::vector<Attribute> variadic_attrs;
     849  
     850    // bool has_return_type;
     851    // BareFunctionReturnType return_type;
     852    std::unique_ptr<TypeNoBounds> return_type; // inlined version
     853  
     854    Location locus;
     855  
     856  public:
     857    // Whether a return type is defined with the function.
     858    bool has_return_type () const { return return_type != nullptr; }
     859  
     860    // Whether the function has ForLifetimes.
     861    bool has_for_lifetimes () const { return !for_lifetimes.empty (); }
     862  
     863    std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; }
     864  
     865    bool is_variadic () const { return _is_variadic; }
     866  
     867    std::vector<Attribute> &get_variadic_attr () { return variadic_attrs; };
     868    const std::vector<Attribute> &get_variadic_attr () const
     869    {
     870      return variadic_attrs;
     871    };
     872  
     873    BareFunctionType (std::vector<LifetimeParam> lifetime_params,
     874  		    FunctionQualifiers qualifiers,
     875  		    std::vector<MaybeNamedParam> named_params, bool is_variadic,
     876  		    std::vector<Attribute> variadic_attrs,
     877  		    std::unique_ptr<TypeNoBounds> type, Location locus)
     878      : for_lifetimes (std::move (lifetime_params)),
     879        function_qualifiers (std::move (qualifiers)),
     880        params (std::move (named_params)), _is_variadic (is_variadic),
     881        variadic_attrs (std::move (variadic_attrs)),
     882        return_type (std::move (type)), locus (locus)
     883    {
     884      if (!variadic_attrs.empty ())
     885        is_variadic = true;
     886    }
     887  
     888    // Copy constructor with clone
     889    BareFunctionType (BareFunctionType const &other)
     890      : for_lifetimes (other.for_lifetimes),
     891        function_qualifiers (other.function_qualifiers), params (other.params),
     892        _is_variadic (other._is_variadic), variadic_attrs (other.variadic_attrs),
     893        locus (other.locus)
     894    {
     895      // guard to prevent null dereference
     896      if (other.return_type != nullptr)
     897        return_type = other.return_type->clone_type_no_bounds ();
     898    }
     899  
     900    // Overload assignment operator to deep copy
     901    BareFunctionType &operator= (BareFunctionType const &other)
     902    {
     903      for_lifetimes = other.for_lifetimes;
     904      function_qualifiers = other.function_qualifiers;
     905      params = other.params;
     906      _is_variadic = other._is_variadic;
     907      variadic_attrs = other.variadic_attrs;
     908      locus = other.locus;
     909  
     910      // guard to prevent null dereference
     911      if (other.return_type != nullptr)
     912        return_type = other.return_type->clone_type_no_bounds ();
     913      else
     914        return_type = nullptr;
     915  
     916      return *this;
     917    }
     918  
     919    // move constructors
     920    BareFunctionType (BareFunctionType &&other) = default;
     921    BareFunctionType &operator= (BareFunctionType &&other) = default;
     922  
     923    std::string as_string () const override;
     924  
     925    Location get_locus () const override final { return locus; }
     926  
     927    void accept_vis (ASTVisitor &vis) override;
     928  
     929    // TODO: this mutable getter seems kinda dodgy
     930    std::vector<MaybeNamedParam> &get_function_params () { return params; }
     931    const std::vector<MaybeNamedParam> &get_function_params () const
     932    {
     933      return params;
     934    }
     935  
     936    // TODO: would a "vis_type" be better?
     937    std::unique_ptr<TypeNoBounds> &get_return_type ()
     938    {
     939      rust_assert (has_return_type ());
     940      return return_type;
     941    }
     942  
     943    FunctionQualifiers &get_function_qualifiers () { return function_qualifiers; }
     944  
     945  protected:
     946    /* Use covariance to implement clone function as returning this object rather
     947     * than base */
     948    BareFunctionType *clone_type_no_bounds_impl () const override
     949    {
     950      return new BareFunctionType (*this);
     951    }
     952  };
     953  
     954  // Forward decl - defined in rust-macro.h
     955  class MacroInvocation;
     956  
     957  /* TODO: possible types
     958   * struct type?
     959   * "enum" (tagged union) type?
     960   * C-like union type?
     961   * function item type?
     962   * closure expression types?
     963   * primitive types (bool, int, float, char, str (the slice))
     964   * Although supposedly TypePaths are used to reference these types (including
     965   * primitives) */
     966  
     967  /* FIXME: Incomplete spec references:
     968   *  anonymous type parameters, aka "impl Trait in argument position" - impl then
     969   * trait bounds abstract return types, aka "impl Trait in return position" -
     970   * impl then trait bounds */
     971  } // namespace AST
     972  } // namespace Rust
     973  
     974  #endif