| // Copyright (C) 2020-2023 Free Software Foundation, Inc. |
| |
| // This file is part of GCC. |
| |
| // GCC is free software; you can redistribute it and/or modify it under |
| // the terms of the GNU General Public License as published by the Free |
| // Software Foundation; either version 3, or (at your option) any later |
| // version. |
| |
| // GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| // WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| // for more details. |
| |
| // You should have received a copy of the GNU General Public License |
| // along with GCC; see the file COPYING3. If not see |
| // <http://www.gnu.org/licenses/>. |
| |
| #ifndef RUST_AST_TYPE_H |
| #define RUST_AST_TYPE_H |
| |
| #include "rust-ast.h" |
| #include "rust-path.h" |
| |
| namespace Rust { |
| namespace AST { |
| // definitions moved to rust-ast.h |
| class TypeParamBound; |
| class Lifetime; |
| |
| // A trait bound |
| class TraitBound : public TypeParamBound |
| { |
| bool in_parens; |
| bool opening_question_mark; |
| |
| // bool has_for_lifetimes; |
| // LifetimeParams for_lifetimes; |
| std::vector<LifetimeParam> for_lifetimes; // inlined LifetimeParams |
| |
| TypePath type_path; |
| |
| Location locus; |
| |
| public: |
| // Returns whether trait bound has "for" lifetimes |
| bool has_for_lifetimes () const { return !for_lifetimes.empty (); } |
| |
| std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; } |
| |
| TraitBound (TypePath type_path, Location locus, bool in_parens = false, |
| bool opening_question_mark = false, |
| std::vector<LifetimeParam> for_lifetimes |
| = std::vector<LifetimeParam> ()) |
| : TypeParamBound (Analysis::Mappings::get ()->get_next_node_id ()), |
| in_parens (in_parens), opening_question_mark (opening_question_mark), |
| for_lifetimes (std::move (for_lifetimes)), |
| type_path (std::move (type_path)), locus (locus) |
| {} |
| |
| TraitBound (NodeId id, TypePath type_path, Location locus, |
| bool in_parens = false, bool opening_question_mark = false, |
| std::vector<LifetimeParam> for_lifetimes |
| = std::vector<LifetimeParam> ()) |
| : TypeParamBound (id), in_parens (in_parens), |
| opening_question_mark (opening_question_mark), |
| for_lifetimes (std::move (for_lifetimes)), |
| type_path (std::move (type_path)), locus (locus) |
| {} |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: this mutable getter seems kinda dodgy |
| TypePath &get_type_path () { return type_path; } |
| const TypePath &get_type_path () const { return type_path; } |
| |
| bool is_in_parens () const { return in_parens; } |
| bool has_opening_question_mark () const { return opening_question_mark; } |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| TraitBound *clone_type_param_bound_impl () const override |
| { |
| return new TraitBound (node_id, type_path, locus, in_parens, |
| opening_question_mark, for_lifetimes); |
| } |
| }; |
| |
| // definition moved to rust-ast.h |
| class TypeNoBounds; |
| |
| // An impl trait? Poor reference material here. |
| class ImplTraitType : public Type |
| { |
| // TypeParamBounds type_param_bounds; |
| // inlined form |
| std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds; |
| |
| Location locus; |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| ImplTraitType *clone_type_impl () const override |
| { |
| return new ImplTraitType (*this); |
| } |
| |
| public: |
| ImplTraitType ( |
| std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds, |
| Location locus) |
| : type_param_bounds (std::move (type_param_bounds)), locus (locus) |
| {} |
| |
| // copy constructor with vector clone |
| ImplTraitType (ImplTraitType const &other) : locus (other.locus) |
| { |
| type_param_bounds.reserve (other.type_param_bounds.size ()); |
| for (const auto &e : other.type_param_bounds) |
| type_param_bounds.push_back (e->clone_type_param_bound ()); |
| } |
| |
| // overloaded assignment operator to clone |
| ImplTraitType &operator= (ImplTraitType const &other) |
| { |
| locus = other.locus; |
| |
| type_param_bounds.reserve (other.type_param_bounds.size ()); |
| for (const auto &e : other.type_param_bounds) |
| type_param_bounds.push_back (e->clone_type_param_bound ()); |
| |
| return *this; |
| } |
| |
| // move constructors |
| ImplTraitType (ImplTraitType &&other) = default; |
| ImplTraitType &operator= (ImplTraitType &&other) = default; |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: mutable getter seems kinda dodgy |
| std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds () |
| { |
| return type_param_bounds; |
| } |
| const std::vector<std::unique_ptr<TypeParamBound> > & |
| get_type_param_bounds () const |
| { |
| return type_param_bounds; |
| } |
| }; |
| |
| // An opaque value of another type that implements a set of traits |
| class TraitObjectType : public Type |
| { |
| bool has_dyn; |
| std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds; |
| Location locus; |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| TraitObjectType *clone_type_impl () const override |
| { |
| return new TraitObjectType (*this); |
| } |
| |
| public: |
| TraitObjectType ( |
| std::vector<std::unique_ptr<TypeParamBound> > type_param_bounds, |
| Location locus, bool is_dyn_dispatch) |
| : has_dyn (is_dyn_dispatch), |
| type_param_bounds (std::move (type_param_bounds)), locus (locus) |
| {} |
| |
| // copy constructor with vector clone |
| TraitObjectType (TraitObjectType const &other) |
| : has_dyn (other.has_dyn), locus (other.locus) |
| { |
| type_param_bounds.reserve (other.type_param_bounds.size ()); |
| for (const auto &e : other.type_param_bounds) |
| type_param_bounds.push_back (e->clone_type_param_bound ()); |
| } |
| |
| // overloaded assignment operator to clone |
| TraitObjectType &operator= (TraitObjectType const &other) |
| { |
| has_dyn = other.has_dyn; |
| locus = other.locus; |
| type_param_bounds.reserve (other.type_param_bounds.size ()); |
| for (const auto &e : other.type_param_bounds) |
| type_param_bounds.push_back (e->clone_type_param_bound ()); |
| |
| return *this; |
| } |
| |
| // move constructors |
| TraitObjectType (TraitObjectType &&other) = default; |
| TraitObjectType &operator= (TraitObjectType &&other) = default; |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| bool is_dyn () const { return has_dyn; } |
| |
| // TODO: mutable getter seems kinda dodgy |
| std::vector<std::unique_ptr<TypeParamBound> > &get_type_param_bounds () |
| { |
| return type_param_bounds; |
| } |
| const std::vector<std::unique_ptr<TypeParamBound> > & |
| get_type_param_bounds () const |
| { |
| return type_param_bounds; |
| } |
| }; |
| |
| // A type with parentheses around it, used to avoid ambiguity. |
| class ParenthesisedType : public TypeNoBounds |
| { |
| std::unique_ptr<Type> type_in_parens; |
| Location locus; |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| ParenthesisedType *clone_type_no_bounds_impl () const override |
| { |
| return new ParenthesisedType (*this); |
| } |
| |
| public: |
| // Constructor uses Type pointer for polymorphism |
| ParenthesisedType (std::unique_ptr<Type> type_inside_parens, Location locus) |
| : type_in_parens (std::move (type_inside_parens)), locus (locus) |
| {} |
| |
| /* Copy constructor uses custom deep copy method for type to preserve |
| * polymorphism */ |
| ParenthesisedType (ParenthesisedType const &other) |
| : type_in_parens (other.type_in_parens->clone_type ()), locus (other.locus) |
| {} |
| |
| // overload assignment operator to use custom clone method |
| ParenthesisedType &operator= (ParenthesisedType const &other) |
| { |
| type_in_parens = other.type_in_parens->clone_type (); |
| locus = other.locus; |
| return *this; |
| } |
| |
| // default move semantics |
| ParenthesisedType (ParenthesisedType &&other) = default; |
| ParenthesisedType &operator= (ParenthesisedType &&other) = default; |
| |
| std::string as_string () const override |
| { |
| return "(" + type_in_parens->as_string () + ")"; |
| } |
| |
| // Creates a trait bound (clone of this one's trait bound) - HACK |
| TraitBound *to_trait_bound (bool) const override |
| { |
| /* NOTE: obviously it is unknown whether the internal type is a trait bound |
| * due to polymorphism, so just let the internal type handle it. As |
| * parenthesised type, it must be in parentheses. */ |
| return type_in_parens->to_trait_bound (true); |
| } |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: would a "vis_type" be better? |
| std::unique_ptr<Type> &get_type_in_parens () |
| { |
| rust_assert (type_in_parens != nullptr); |
| return type_in_parens; |
| } |
| }; |
| |
| // Impl trait with a single bound? Poor reference material here. |
| class ImplTraitTypeOneBound : public TypeNoBounds |
| { |
| TraitBound trait_bound; |
| Location locus; |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| ImplTraitTypeOneBound *clone_type_no_bounds_impl () const override |
| { |
| return new ImplTraitTypeOneBound (*this); |
| } |
| |
| public: |
| ImplTraitTypeOneBound (TraitBound trait_bound, Location locus) |
| : trait_bound (std::move (trait_bound)), locus (locus) |
| {} |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: would a "vis_type" be better? |
| TraitBound &get_trait_bound () |
| { |
| // TODO: check to ensure invariants are met? |
| return trait_bound; |
| } |
| }; |
| |
| /* A trait object with a single trait bound. The "trait bound" is really just |
| * the trait. Basically like using an interface as a type in an OOP language. */ |
| class TraitObjectTypeOneBound : public TypeNoBounds |
| { |
| bool has_dyn; |
| TraitBound trait_bound; |
| Location locus; |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| TraitObjectTypeOneBound *clone_type_no_bounds_impl () const override |
| { |
| return new TraitObjectTypeOneBound (*this); |
| } |
| |
| public: |
| TraitObjectTypeOneBound (TraitBound trait_bound, Location locus, |
| bool is_dyn_dispatch = false) |
| : has_dyn (is_dyn_dispatch), trait_bound (std::move (trait_bound)), |
| locus (locus) |
| {} |
| |
| std::string as_string () const override; |
| |
| // Creates a trait bound (clone of this one's trait bound) - HACK |
| TraitBound *to_trait_bound (bool) const override |
| { |
| /* NOTE: this assumes there is no dynamic dispatch specified- if there was, |
| * this cloning would not be required as parsing is unambiguous. */ |
| return new TraitBound (trait_bound); |
| } |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: would a "vis_type" be better? |
| TraitBound &get_trait_bound () |
| { |
| // TODO: check to ensure invariants are met? |
| return trait_bound; |
| } |
| |
| bool is_dyn () const { return has_dyn; } |
| }; |
| |
| class TypePath; // definition moved to "rust-path.h" |
| |
| /* A type consisting of the "product" of others (the tuple's elements) in a |
| * specific order */ |
| class TupleType : public TypeNoBounds |
| { |
| std::vector<std::unique_ptr<Type> > elems; |
| Location locus; |
| |
| public: |
| // Returns whether the tuple type is the unit type, i.e. has no elements. |
| bool is_unit_type () const { return elems.empty (); } |
| |
| TupleType (std::vector<std::unique_ptr<Type> > elems, Location locus) |
| : elems (std::move (elems)), locus (locus) |
| {} |
| |
| // copy constructor with vector clone |
| TupleType (TupleType const &other) : locus (other.locus) |
| { |
| elems.reserve (other.elems.size ()); |
| for (const auto &e : other.elems) |
| elems.push_back (e->clone_type ()); |
| } |
| |
| // overloaded assignment operator to clone |
| TupleType &operator= (TupleType const &other) |
| { |
| locus = other.locus; |
| |
| elems.reserve (other.elems.size ()); |
| for (const auto &e : other.elems) |
| elems.push_back (e->clone_type ()); |
| |
| return *this; |
| } |
| |
| // move constructors |
| TupleType (TupleType &&other) = default; |
| TupleType &operator= (TupleType &&other) = default; |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: mutable getter seems kinda dodgy |
| std::vector<std::unique_ptr<Type> > &get_elems () { return elems; } |
| const std::vector<std::unique_ptr<Type> > &get_elems () const |
| { |
| return elems; |
| } |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| TupleType *clone_type_no_bounds_impl () const override |
| { |
| return new TupleType (*this); |
| } |
| }; |
| |
| /* A type with no values, representing the result of computations that never |
| * complete. Expressions of NeverType can be coerced into any other types. |
| * Represented as "!". */ |
| class NeverType : public TypeNoBounds |
| { |
| Location locus; |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| NeverType *clone_type_no_bounds_impl () const override |
| { |
| return new NeverType (*this); |
| } |
| |
| public: |
| NeverType (Location locus) : locus (locus) {} |
| |
| std::string as_string () const override { return "! (never type)"; } |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| }; |
| |
| // A type consisting of a pointer without safety or liveness guarantees |
| class RawPointerType : public TypeNoBounds |
| { |
| public: |
| enum PointerType |
| { |
| MUT, |
| CONST |
| }; |
| |
| private: |
| PointerType pointer_type; |
| std::unique_ptr<TypeNoBounds> type; |
| Location locus; |
| |
| public: |
| // Returns whether the pointer is mutable or constant. |
| PointerType get_pointer_type () const { return pointer_type; } |
| |
| // Constructor requires pointer for polymorphism reasons |
| RawPointerType (PointerType pointer_type, |
| std::unique_ptr<TypeNoBounds> type_no_bounds, Location locus) |
| : pointer_type (pointer_type), type (std::move (type_no_bounds)), |
| locus (locus) |
| {} |
| |
| // Copy constructor calls custom polymorphic clone function |
| RawPointerType (RawPointerType const &other) |
| : pointer_type (other.pointer_type), |
| type (other.type->clone_type_no_bounds ()), locus (other.locus) |
| {} |
| |
| // overload assignment operator to use custom clone method |
| RawPointerType &operator= (RawPointerType const &other) |
| { |
| pointer_type = other.pointer_type; |
| type = other.type->clone_type_no_bounds (); |
| locus = other.locus; |
| return *this; |
| } |
| |
| // default move semantics |
| RawPointerType (RawPointerType &&other) = default; |
| RawPointerType &operator= (RawPointerType &&other) = default; |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: would a "vis_type" be better? |
| std::unique_ptr<TypeNoBounds> &get_type_pointed_to () |
| { |
| rust_assert (type != nullptr); |
| return type; |
| } |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| RawPointerType *clone_type_no_bounds_impl () const override |
| { |
| return new RawPointerType (*this); |
| } |
| }; |
| |
| // A type pointing to memory owned by another value |
| class ReferenceType : public TypeNoBounds |
| { |
| // bool has_lifetime; // TODO: handle in lifetime or something? |
| Lifetime lifetime; |
| |
| bool has_mut; |
| std::unique_ptr<TypeNoBounds> type; |
| Location locus; |
| |
| public: |
| // Returns whether the reference is mutable or immutable. |
| bool is_mut () const { return has_mut; } |
| |
| // Returns whether the reference has a lifetime. |
| bool has_lifetime () const { return !lifetime.is_error (); } |
| |
| // Constructor |
| ReferenceType (bool is_mut, std::unique_ptr<TypeNoBounds> type_no_bounds, |
| Location locus, Lifetime lifetime = Lifetime::error ()) |
| : lifetime (std::move (lifetime)), has_mut (is_mut), |
| type (std::move (type_no_bounds)), locus (locus) |
| {} |
| |
| // Copy constructor with custom clone method |
| ReferenceType (ReferenceType const &other) |
| : lifetime (other.lifetime), has_mut (other.has_mut), |
| type (other.type->clone_type_no_bounds ()), locus (other.locus) |
| {} |
| |
| // Operator overload assignment operator to custom clone the unique pointer |
| ReferenceType &operator= (ReferenceType const &other) |
| { |
| lifetime = other.lifetime; |
| has_mut = other.has_mut; |
| type = other.type->clone_type_no_bounds (); |
| locus = other.locus; |
| |
| return *this; |
| } |
| |
| // move constructors |
| ReferenceType (ReferenceType &&other) = default; |
| ReferenceType &operator= (ReferenceType &&other) = default; |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: would a "vis_type" be better? |
| std::unique_ptr<TypeNoBounds> &get_type_referenced () |
| { |
| rust_assert (type != nullptr); |
| return type; |
| } |
| |
| bool get_has_mut () const { return has_mut; } |
| |
| Lifetime &get_lifetime () { return lifetime; } |
| |
| std::unique_ptr<TypeNoBounds> &get_base_type () { return type; } |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| ReferenceType *clone_type_no_bounds_impl () const override |
| { |
| return new ReferenceType (*this); |
| } |
| }; |
| |
| // A fixed-size sequence of elements of a specified type |
| class ArrayType : public TypeNoBounds |
| { |
| std::unique_ptr<Type> elem_type; |
| std::unique_ptr<Expr> size; |
| Location locus; |
| |
| public: |
| // Constructor requires pointers for polymorphism |
| ArrayType (std::unique_ptr<Type> type, std::unique_ptr<Expr> array_size, |
| Location locus) |
| : elem_type (std::move (type)), size (std::move (array_size)), locus (locus) |
| {} |
| |
| // Copy constructor requires deep copies of both unique pointers |
| ArrayType (ArrayType const &other) |
| : elem_type (other.elem_type->clone_type ()), |
| size (other.size->clone_expr ()), locus (other.locus) |
| {} |
| |
| // Overload assignment operator to deep copy pointers |
| ArrayType &operator= (ArrayType const &other) |
| { |
| elem_type = other.elem_type->clone_type (); |
| size = other.size->clone_expr (); |
| locus = other.locus; |
| return *this; |
| } |
| |
| // move constructors |
| ArrayType (ArrayType &&other) = default; |
| ArrayType &operator= (ArrayType &&other) = default; |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: would a "vis_type" be better? |
| std::unique_ptr<Type> &get_elem_type () |
| { |
| rust_assert (elem_type != nullptr); |
| return elem_type; |
| } |
| |
| // TODO: would a "vis_expr" be better? |
| std::unique_ptr<Expr> &get_size_expr () |
| { |
| rust_assert (size != nullptr); |
| return size; |
| } |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| ArrayType *clone_type_no_bounds_impl () const override |
| { |
| return new ArrayType (*this); |
| } |
| }; |
| |
| /* A dynamically-sized type representing a "view" into a sequence of elements of |
| * a type */ |
| class SliceType : public TypeNoBounds |
| { |
| std::unique_ptr<Type> elem_type; |
| Location locus; |
| |
| public: |
| // Constructor requires pointer for polymorphism |
| SliceType (std::unique_ptr<Type> type, Location locus) |
| : elem_type (std::move (type)), locus (locus) |
| {} |
| |
| // Copy constructor requires deep copy of Type smart pointer |
| SliceType (SliceType const &other) |
| : elem_type (other.elem_type->clone_type ()), locus (other.locus) |
| {} |
| |
| // Overload assignment operator to deep copy |
| SliceType &operator= (SliceType const &other) |
| { |
| elem_type = other.elem_type->clone_type (); |
| locus = other.locus; |
| |
| return *this; |
| } |
| |
| // move constructors |
| SliceType (SliceType &&other) = default; |
| SliceType &operator= (SliceType &&other) = default; |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: would a "vis_type" be better? |
| std::unique_ptr<Type> &get_elem_type () |
| { |
| rust_assert (elem_type != nullptr); |
| return elem_type; |
| } |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| SliceType *clone_type_no_bounds_impl () const override |
| { |
| return new SliceType (*this); |
| } |
| }; |
| |
| /* Type used in generic arguments to explicitly request type inference (wildcard |
| * pattern) */ |
| class InferredType : public TypeNoBounds |
| { |
| Location locus; |
| |
| // e.g. Vec<_> = whatever |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| InferredType *clone_type_no_bounds_impl () const override |
| { |
| return new InferredType (*this); |
| } |
| |
| public: |
| InferredType (Location locus) : locus (locus) {} |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| }; |
| |
| class QualifiedPathInType; // definition moved to "rust-path.h" |
| |
| // A possibly named param used in a BaseFunctionType |
| struct MaybeNamedParam |
| { |
| public: |
| enum ParamKind |
| { |
| UNNAMED, |
| IDENTIFIER, |
| WILDCARD |
| }; |
| |
| private: |
| std::vector<Attribute> outer_attrs; |
| |
| std::unique_ptr<Type> param_type; |
| |
| ParamKind param_kind; |
| Identifier name; // technically, can be an identifier or '_' |
| |
| Location locus; |
| |
| public: |
| MaybeNamedParam (Identifier name, ParamKind param_kind, |
| std::unique_ptr<Type> param_type, |
| std::vector<Attribute> outer_attrs, Location locus) |
| : outer_attrs (std::move (outer_attrs)), |
| param_type (std::move (param_type)), param_kind (param_kind), |
| name (std::move (name)), locus (locus) |
| {} |
| |
| // Copy constructor with clone |
| MaybeNamedParam (MaybeNamedParam const &other) |
| : outer_attrs (other.outer_attrs), param_kind (other.param_kind), |
| name (other.name), locus (other.locus) |
| { |
| // guard to prevent null dereference |
| if (other.param_type != nullptr) |
| param_type = other.param_type->clone_type (); |
| } |
| |
| ~MaybeNamedParam () = default; |
| |
| // Overloaded assignment operator with clone |
| MaybeNamedParam &operator= (MaybeNamedParam const &other) |
| { |
| outer_attrs = other.outer_attrs; |
| name = other.name; |
| param_kind = other.param_kind; |
| locus = other.locus; |
| |
| // guard to prevent null dereference |
| if (other.param_type != nullptr) |
| param_type = other.param_type->clone_type (); |
| else |
| param_type = nullptr; |
| |
| return *this; |
| } |
| |
| // move constructors |
| MaybeNamedParam (MaybeNamedParam &&other) = default; |
| MaybeNamedParam &operator= (MaybeNamedParam &&other) = default; |
| |
| std::string as_string () const; |
| |
| // Returns whether the param is in an error state. |
| bool is_error () const { return param_type == nullptr; } |
| |
| // Creates an error state param. |
| static MaybeNamedParam create_error () |
| { |
| return MaybeNamedParam ("", UNNAMED, nullptr, {}, Location ()); |
| } |
| |
| Location get_locus () const { return locus; } |
| |
| // TODO: this mutable getter seems really dodgy. Think up better way. |
| std::vector<Attribute> &get_outer_attrs () { return outer_attrs; } |
| const std::vector<Attribute> &get_outer_attrs () const { return outer_attrs; } |
| |
| // TODO: would a "vis_type" be better? |
| std::unique_ptr<Type> &get_type () |
| { |
| rust_assert (param_type != nullptr); |
| return param_type; |
| } |
| |
| ParamKind get_param_kind () const { return param_kind; } |
| |
| Identifier get_name () const { return name; } |
| }; |
| |
| /* A function pointer type - can be created via coercion from function items and |
| * non-capturing closures. */ |
| class BareFunctionType : public TypeNoBounds |
| { |
| // bool has_for_lifetimes; |
| // ForLifetimes for_lifetimes; |
| std::vector<LifetimeParam> for_lifetimes; // inlined version |
| |
| FunctionQualifiers function_qualifiers; |
| std::vector<MaybeNamedParam> params; |
| bool _is_variadic; |
| std::vector<Attribute> variadic_attrs; |
| |
| // bool has_return_type; |
| // BareFunctionReturnType return_type; |
| std::unique_ptr<TypeNoBounds> return_type; // inlined version |
| |
| Location locus; |
| |
| public: |
| // Whether a return type is defined with the function. |
| bool has_return_type () const { return return_type != nullptr; } |
| |
| // Whether the function has ForLifetimes. |
| bool has_for_lifetimes () const { return !for_lifetimes.empty (); } |
| |
| std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; } |
| |
| bool is_variadic () const { return _is_variadic; } |
| |
| std::vector<Attribute> &get_variadic_attr () { return variadic_attrs; }; |
| const std::vector<Attribute> &get_variadic_attr () const |
| { |
| return variadic_attrs; |
| }; |
| |
| BareFunctionType (std::vector<LifetimeParam> lifetime_params, |
| FunctionQualifiers qualifiers, |
| std::vector<MaybeNamedParam> named_params, bool is_variadic, |
| std::vector<Attribute> variadic_attrs, |
| std::unique_ptr<TypeNoBounds> type, Location locus) |
| : for_lifetimes (std::move (lifetime_params)), |
| function_qualifiers (std::move (qualifiers)), |
| params (std::move (named_params)), _is_variadic (is_variadic), |
| variadic_attrs (std::move (variadic_attrs)), |
| return_type (std::move (type)), locus (locus) |
| { |
| if (!variadic_attrs.empty ()) |
| is_variadic = true; |
| } |
| |
| // Copy constructor with clone |
| BareFunctionType (BareFunctionType const &other) |
| : for_lifetimes (other.for_lifetimes), |
| function_qualifiers (other.function_qualifiers), params (other.params), |
| _is_variadic (other._is_variadic), variadic_attrs (other.variadic_attrs), |
| locus (other.locus) |
| { |
| // guard to prevent null dereference |
| if (other.return_type != nullptr) |
| return_type = other.return_type->clone_type_no_bounds (); |
| } |
| |
| // Overload assignment operator to deep copy |
| BareFunctionType &operator= (BareFunctionType const &other) |
| { |
| for_lifetimes = other.for_lifetimes; |
| function_qualifiers = other.function_qualifiers; |
| params = other.params; |
| _is_variadic = other._is_variadic; |
| variadic_attrs = other.variadic_attrs; |
| locus = other.locus; |
| |
| // guard to prevent null dereference |
| if (other.return_type != nullptr) |
| return_type = other.return_type->clone_type_no_bounds (); |
| else |
| return_type = nullptr; |
| |
| return *this; |
| } |
| |
| // move constructors |
| BareFunctionType (BareFunctionType &&other) = default; |
| BareFunctionType &operator= (BareFunctionType &&other) = default; |
| |
| std::string as_string () const override; |
| |
| Location get_locus () const override final { return locus; } |
| |
| void accept_vis (ASTVisitor &vis) override; |
| |
| // TODO: this mutable getter seems kinda dodgy |
| std::vector<MaybeNamedParam> &get_function_params () { return params; } |
| const std::vector<MaybeNamedParam> &get_function_params () const |
| { |
| return params; |
| } |
| |
| // TODO: would a "vis_type" be better? |
| std::unique_ptr<TypeNoBounds> &get_return_type () |
| { |
| rust_assert (has_return_type ()); |
| return return_type; |
| } |
| |
| FunctionQualifiers &get_function_qualifiers () { return function_qualifiers; } |
| |
| protected: |
| /* Use covariance to implement clone function as returning this object rather |
| * than base */ |
| BareFunctionType *clone_type_no_bounds_impl () const override |
| { |
| return new BareFunctionType (*this); |
| } |
| }; |
| |
| // Forward decl - defined in rust-macro.h |
| class MacroInvocation; |
| |
| /* TODO: possible types |
| * struct type? |
| * "enum" (tagged union) type? |
| * C-like union type? |
| * function item type? |
| * closure expression types? |
| * primitive types (bool, int, float, char, str (the slice)) |
| * Although supposedly TypePaths are used to reference these types (including |
| * primitives) */ |
| |
| /* FIXME: Incomplete spec references: |
| * anonymous type parameters, aka "impl Trait in argument position" - impl then |
| * trait bounds abstract return types, aka "impl Trait in return position" - |
| * impl then trait bounds */ |
| } // namespace AST |
| } // namespace Rust |
| |
| #endif |