// Copyright (C) 2020-2025 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 // . #ifndef RUST_HIR_PATH_H #define RUST_HIR_PATH_H #include "rust-hir-map.h" #include "rust-hir-simple-path.h" #include "rust-hir-type-no-bounds.h" #include "rust-hir-pattern-abstract.h" #include "rust-hir-expr-abstract.h" namespace Rust { namespace HIR { // The "identifier" (not generic args) aspect of each path expression segment class PathIdentSegment { std::string segment_name; // TODO: should this have location info stored? // only allow identifiers, "super", "self", "Self", "crate", or "$crate" public: PathIdentSegment (std::string segment_name) : segment_name (std::move (segment_name)) {} /* TODO: insert check in constructor for this? Or is this a semantic error * best handled then? */ /* TODO: does this require visitor? pretty sure this isn't polymorphic, but * not entirely sure */ // Creates an error PathIdentSegment. static PathIdentSegment create_error () { return PathIdentSegment (""); } // Returns whether PathIdentSegment is in an error state. bool is_error () const { return segment_name.empty (); } std::string as_string () const { return segment_name; } }; // A binding of an identifier to a type used in generic arguments in paths class GenericArgsBinding { Identifier identifier; std::unique_ptr type; location_t locus; public: // Returns whether binding is in an error state. bool is_error () const { return type == nullptr; // and also identifier is empty, but cheaper computation } // Creates an error state generic args binding. static GenericArgsBinding create_error () { return GenericArgsBinding ({""}, nullptr); } // Pointer type for type in constructor to enable polymorphism GenericArgsBinding (Identifier ident, std::unique_ptr type_ptr, location_t locus = UNDEF_LOCATION); // Copy constructor has to deep copy the type as it is a unique pointer GenericArgsBinding (GenericArgsBinding const &other); // default destructor ~GenericArgsBinding () = default; // Overload assignment operator to deep copy the pointed-to type GenericArgsBinding &operator= (GenericArgsBinding const &other); // move constructors GenericArgsBinding (GenericArgsBinding &&other) = default; GenericArgsBinding &operator= (GenericArgsBinding &&other) = default; std::string as_string () const; Identifier &get_identifier () { return identifier; } const Identifier &get_identifier () const { return identifier; } Type &get_type () { rust_assert (type); return *type; } const Type &get_type () const { rust_assert (type); return *type; } location_t get_locus () const { return locus; } }; class ConstGenericArg { // FIXME: Do we need to disambiguate or no? We should be able to disambiguate // at name-resolution, hence no need for ambiguities here public: ConstGenericArg (std::unique_ptr expression, location_t locus); ConstGenericArg (const ConstGenericArg &other); ConstGenericArg operator= (const ConstGenericArg &other); std::unique_ptr &get_expression () { return expression; } private: std::unique_ptr expression; location_t locus; }; class GenericArgs { std::vector lifetime_args; std::vector > type_args; std::vector binding_args; std::vector const_args; location_t locus; public: // Returns true if there are any generic arguments bool has_generic_args () const { return !(lifetime_args.empty () && type_args.empty () && binding_args.empty ()); } GenericArgs (std::vector lifetime_args, std::vector > type_args, std::vector binding_args, std::vector const_args, location_t locus); // copy constructor with vector clone GenericArgs (GenericArgs const &other); ~GenericArgs () = default; // overloaded assignment operator to vector clone GenericArgs &operator= (GenericArgs const &other); // move constructors GenericArgs (GenericArgs &&other) = default; GenericArgs &operator= (GenericArgs &&other) = default; // Creates an empty GenericArgs (no arguments) static GenericArgs create_empty (location_t locus = UNDEF_LOCATION) { return GenericArgs ({}, {}, {}, {}, locus); } bool is_empty () const; std::string as_string () const; std::vector &get_lifetime_args () { return lifetime_args; } const std::vector &get_lifetime_args () const { return lifetime_args; } std::vector > &get_type_args () { return type_args; } std::vector &get_binding_args () { return binding_args; } std::vector &get_const_args () { return const_args; } location_t get_locus () const { return locus; } }; /* A segment of a path in expression, including an identifier aspect and maybe * generic args */ class PathExprSegment { private: Analysis::NodeMapping mappings; PathIdentSegment segment_name; GenericArgs generic_args; location_t locus; public: PathExprSegment (Analysis::NodeMapping mappings, PathIdentSegment segment_name, location_t locus, GenericArgs generic_args); PathExprSegment (PathExprSegment const &other); PathExprSegment &operator= (PathExprSegment const &other); // move constructors PathExprSegment (PathExprSegment &&other) = default; PathExprSegment &operator= (PathExprSegment &&other) = default; std::string as_string () const; location_t get_locus () const { return locus; } PathIdentSegment &get_segment () { return segment_name; } const PathIdentSegment &get_segment () const { return segment_name; } GenericArgs &get_generic_args () { return generic_args; } const Analysis::NodeMapping &get_mappings () const { return mappings; } bool has_generic_args () const { return generic_args.has_generic_args (); } }; // HIR node representing a pattern that involves a "path" - abstract base class class PathPattern : public Pattern { public: enum class Kind { Segmented, LangItem }; private: std::vector segments; tl::optional lang_item; Kind kind; protected: PathPattern (std::vector segments) : segments (std::move (segments)), lang_item (tl::nullopt), kind (Kind::Segmented) {} PathPattern (LangItem::Kind lang_item) : segments ({}), lang_item (lang_item), kind (Kind::LangItem) {} // Returns whether path has segments. bool has_segments () const { rust_assert (kind == Kind::Segmented); return !segments.empty (); } /* Converts path segments to their equivalent SimplePath segments if possible, * and creates a SimplePath from them. */ AST::SimplePath convert_to_simple_path (bool with_opening_scope_resolution) const; public: /* Returns whether the path is a single segment (excluding qualified path * initial as segment). */ bool is_single_segment () const { rust_assert (kind == Kind::Segmented); return segments.size () == 1; } std::string as_string () const override; void iterate_path_segments (std::function cb); size_t get_num_segments () const { rust_assert (kind == Kind::Segmented); return segments.size (); } std::vector &get_segments () { rust_assert (kind == Kind::Segmented); return segments; } const std::vector &get_segments () const { rust_assert (kind == Kind::Segmented); return segments; } PathExprSegment &get_root_seg () { rust_assert (kind == Kind::Segmented); return segments.at (0); } const PathExprSegment &get_final_segment () const { rust_assert (kind == Kind::Segmented); return segments.back (); } LangItem::Kind get_lang_item () const { rust_assert (kind == Kind::LangItem); return *lang_item; } PatternType get_pattern_type () const override final { return PatternType::PATH; } bool is_lang_item () const { return kind == Kind::LangItem; } Kind get_path_kind () const { return kind; } }; /* HIR node representing a path-in-expression pattern (path that allows generic * arguments) */ class PathInExpression : public PathPattern, public PathExpr { bool has_opening_scope_resolution; location_t locus; public: std::string as_string () const override; // Constructor PathInExpression (Analysis::NodeMapping mappings, std::vector path_segments, location_t locus = UNDEF_LOCATION, bool has_opening_scope_resolution = false, std::vector outer_attrs = std::vector ()); // lang-item Constructor PathInExpression (Analysis::NodeMapping mappings, LangItem::Kind kind, location_t locus = UNDEF_LOCATION, bool has_opening_scope_resolution = false, std::vector outer_attrs = std::vector ()); // Creates an error state path in expression. static PathInExpression create_error () { return PathInExpression (Analysis::NodeMapping::get_error (), std::vector ()); } // Returns whether path in expression is in an error state. bool is_error () const { return !has_segments (); } /* Converts PathInExpression to SimplePath if possible (i.e. no generic * arguments). Otherwise returns an empty SimplePath. */ AST::SimplePath as_simple_path () const { /* delegate to parent class as can't access segments. however, * QualifiedPathInExpression conversion to simple path wouldn't make sense, * so the method in the parent class should be protected, not public. Have * to pass in opening scope resolution as parent class has no access to it. */ return convert_to_simple_path (has_opening_scope_resolution); } location_t get_locus () const override final { return locus; } void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; void accept_vis (HIRPatternVisitor &vis) override; bool opening_scope_resolution () { return has_opening_scope_resolution; } bool is_self () const; const Analysis::NodeMapping &get_mappings () const override final { return mappings; } protected: /* Use covariance to implement clone function as returning this object rather * than base */ PathInExpression *clone_pattern_impl () const override { return new PathInExpression (*this); } /* Use covariance to implement clone function as returning this object rather * than base */ PathInExpression *clone_expr_without_block_impl () const override { return new PathInExpression (*this); } }; /* Base class for segments used in type paths - not abstract (represents an * ident-only segment) */ class TypePathSegment { public: enum SegmentType { REG, GENERIC, FUNCTION }; private: Analysis::NodeMapping mappings; tl::optional ident_segment; tl::optional lang_item; location_t locus; protected: bool has_separating_scope_resolution; SegmentType type; public: // Clone function implementation - not pure virtual as overrided by subclasses virtual TypePathSegment *clone_type_path_segment_impl () const { return new TypePathSegment (*this); } public: virtual ~TypePathSegment () {} virtual SegmentType get_type () const { return SegmentType::REG; } // Unique pointer custom clone function std::unique_ptr clone_type_path_segment () const { return std::unique_ptr (clone_type_path_segment_impl ()); } TypePathSegment (Analysis::NodeMapping mappings, PathIdentSegment ident_segment, bool has_separating_scope_resolution, location_t locus); TypePathSegment (Analysis::NodeMapping mappings, LangItem::Kind lang_item, location_t locus); TypePathSegment (Analysis::NodeMapping mappings, std::string segment_name, bool has_separating_scope_resolution, location_t locus); virtual std::string as_string () const { if (ident_segment) return ident_segment->as_string (); return LangItem::PrettyString (*lang_item); } /* Returns whether the type path segment is in an error state. May be virtual * in future. */ bool is_error () const { rust_assert (ident_segment); return ident_segment->is_error (); } /* Returns whether segment is identifier only (as opposed to generic args or * function). Overriden in derived classes with other segments. */ virtual bool is_ident_only () const { return true; } location_t get_locus () const { return locus; } // not pure virtual as class not abstract virtual void accept_vis (HIRFullVisitor &vis); const Analysis::NodeMapping &get_mappings () const { return mappings; } const PathIdentSegment &get_ident_segment () const { rust_assert (ident_segment); return *ident_segment; } const LangItem::Kind &get_lang_item () const { rust_assert (lang_item); return *lang_item; } bool is_generic_segment () const { return get_type () == SegmentType::GENERIC; } bool is_lang_item () const { return lang_item.has_value (); } }; // Segment used in type path with generic args class TypePathSegmentGeneric : public TypePathSegment { GenericArgs generic_args; public: bool has_generic_args () const { return generic_args.has_generic_args (); } bool is_ident_only () const override { return false; } // Constructor with PathIdentSegment and GenericArgs TypePathSegmentGeneric (Analysis::NodeMapping mappings, PathIdentSegment ident_segment, bool has_separating_scope_resolution, GenericArgs generic_args, location_t locus); TypePathSegmentGeneric (Analysis::NodeMapping mappings, LangItem::Kind lang_item, GenericArgs generic_args, location_t locus); // Constructor from segment name and all args TypePathSegmentGeneric (Analysis::NodeMapping mappings, std::string segment_name, bool has_separating_scope_resolution, std::vector lifetime_args, std::vector > type_args, std::vector binding_args, std::vector const_args, location_t locus); std::string as_string () const override; void accept_vis (HIRFullVisitor &vis) override; GenericArgs &get_generic_args () { return generic_args; } virtual SegmentType get_type () const override final { return SegmentType::GENERIC; } // Use covariance to override base class method TypePathSegmentGeneric *clone_type_path_segment_impl () const override { return new TypePathSegmentGeneric (*this); } }; // A function as represented in a type path class TypePathFunction { std::vector > inputs; std::unique_ptr return_type; public: // Returns whether the return type of the function has been specified. bool has_return_type () const { return return_type != nullptr; } // Returns whether the function has inputs. bool has_inputs () const { return !inputs.empty (); } // Constructor TypePathFunction (std::vector > inputs, std::unique_ptr type); // Copy constructor with clone TypePathFunction (TypePathFunction const &other); ~TypePathFunction () = default; // Overloaded assignment operator to clone type TypePathFunction &operator= (TypePathFunction const &other); // move constructors TypePathFunction (TypePathFunction &&other) = default; TypePathFunction &operator= (TypePathFunction &&other) = default; std::string as_string () const; const std::vector > &get_params () const { return inputs; }; std::vector > &get_params () { return inputs; }; const Type &get_return_type () const { return *return_type; }; Type &get_return_type () { return *return_type; }; }; // Segment used in type path with a function argument class TypePathSegmentFunction : public TypePathSegment { TypePathFunction function_path; public: // Constructor with PathIdentSegment and TypePathFn TypePathSegmentFunction (Analysis::NodeMapping mappings, PathIdentSegment ident_segment, bool has_separating_scope_resolution, TypePathFunction function_path, location_t locus); // Constructor with segment name and TypePathFn TypePathSegmentFunction (Analysis::NodeMapping mappings, std::string segment_name, bool has_separating_scope_resolution, TypePathFunction function_path, location_t locus); std::string as_string () const override; bool is_ident_only () const override { return false; } void accept_vis (HIRFullVisitor &vis) override; SegmentType get_type () const override final { return SegmentType::FUNCTION; } TypePathFunction &get_function_path () { return function_path; } // Use covariance to override base class method TypePathSegmentFunction *clone_type_path_segment_impl () const override { return new TypePathSegmentFunction (*this); } }; // Path used inside types class TypePath : public TypeNoBounds { public: bool has_opening_scope_resolution; std::vector > segments; protected: /* Use covariance to implement clone function as returning this object rather * than base */ TypePath *clone_type_impl () const override { return new TypePath (*this); } /* Use covariance to implement clone function as returning this object rather * than base */ TypePath *clone_type_no_bounds_impl () const override { return new TypePath (*this); } public: /* Returns whether the TypePath has an opening scope resolution operator (i.e. * is global path or crate-relative path, not module-relative) */ bool has_opening_scope_resolution_op () const { return has_opening_scope_resolution; } // Returns whether the TypePath is in an invalid state. bool is_error () const { return segments.empty (); } // Creates an error state TypePath. static TypePath create_error () { return TypePath (Analysis::NodeMapping::get_error (), std::vector > (), UNDEF_LOCATION); } // Constructor TypePath (Analysis::NodeMapping mappings, std::vector > segments, location_t locus, bool has_opening_scope_resolution = false); // Copy constructor with vector clone TypePath (TypePath const &other); // Overloaded assignment operator with clone TypePath &operator= (TypePath const &other); // move constructors TypePath (TypePath &&other) = default; TypePath &operator= (TypePath &&other) = default; std::string as_string () const override; /* Converts TypePath to SimplePath if possible (i.e. no generic or function * arguments). Otherwise returns an empty SimplePath. */ AST::SimplePath as_simple_path () const; // Creates a trait bound with a clone of this type path as its only element. std::unique_ptr to_trait_bound (bool in_parens) const override; void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRTypeVisitor &vis) override; size_t get_num_segments () const { return segments.size (); } std::vector > &get_segments () { return segments; } TypePathSegment &get_final_segment () { return *segments.back (); } }; class QualifiedPathType { std::unique_ptr type; std::unique_ptr trait; location_t locus; Analysis::NodeMapping mappings; public: // Constructor QualifiedPathType (Analysis::NodeMapping mappings, std::unique_ptr type, std::unique_ptr trait, location_t locus); // Copy constructor uses custom deep copy for Type to preserve polymorphism QualifiedPathType (QualifiedPathType const &other); // default destructor ~QualifiedPathType () = default; // overload assignment operator to use custom clone method QualifiedPathType &operator= (QualifiedPathType const &other); // move constructor QualifiedPathType (QualifiedPathType &&other) = default; QualifiedPathType &operator= (QualifiedPathType &&other) = default; // Returns whether the qualified path type has a rebind as clause. bool has_as_clause () const { return trait != nullptr; } std::string as_string () const; location_t get_locus () const { return locus; } Analysis::NodeMapping get_mappings () const { return mappings; } bool has_type () { return type != nullptr; } bool has_trait () { return trait != nullptr; } Type &get_type () { rust_assert (type); return *type; } TypePath &get_trait () { rust_assert (trait); return *trait; } bool trait_has_generic_args () const; GenericArgs &get_trait_generic_args (); }; /* HIR node representing a qualified path-in-expression pattern (path that * allows specifying trait functions) */ class QualifiedPathInExpression : public PathPattern, public PathExpr { QualifiedPathType path_type; location_t locus; public: std::string as_string () const override; QualifiedPathInExpression (Analysis::NodeMapping mappings, QualifiedPathType qual_path_type, std::vector path_segments, location_t locus = UNDEF_LOCATION, std::vector outer_attrs = std::vector ()); // lang-item constructor QualifiedPathInExpression (Analysis::NodeMapping mappings, QualifiedPathType qual_path_type, LangItem::Kind lang_item, location_t locus = UNDEF_LOCATION, std::vector outer_attrs = std::vector ()); location_t get_locus () const override final { return locus; } void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRExpressionVisitor &vis) override; void accept_vis (HIRPatternVisitor &vis) override; QualifiedPathType &get_path_type () { return path_type; } location_t get_locus () { return locus; } const Analysis::NodeMapping &get_mappings () const override final { return mappings; } protected: /* Use covariance to implement clone function as returning this object rather * than base */ QualifiedPathInExpression *clone_pattern_impl () const override { return new QualifiedPathInExpression (*this); } /* Use covariance to implement clone function as returning this object rather * than base */ QualifiedPathInExpression *clone_expr_without_block_impl () const override { return new QualifiedPathInExpression (*this); } }; /* Represents a qualified path in a type; used for disambiguating trait function * calls */ class QualifiedPathInType : public TypeNoBounds { QualifiedPathType path_type; std::unique_ptr associated_segment; std::vector > segments; protected: /* Use covariance to implement clone function as returning this object rather * than base */ QualifiedPathInType *clone_type_impl () const override { return new QualifiedPathInType (*this); } /* Use covariance to implement clone function as returning this object rather * than base */ QualifiedPathInType *clone_type_no_bounds_impl () const override { return new QualifiedPathInType (*this); } public: QualifiedPathInType ( Analysis::NodeMapping mappings, QualifiedPathType qual_path_type, std::unique_ptr associated_segment, std::vector > path_segments, location_t locus = UNDEF_LOCATION); // Copy constructor with vector clone QualifiedPathInType (QualifiedPathInType const &other); // Overloaded assignment operator with vector clone QualifiedPathInType &operator= (QualifiedPathInType const &other); // move constructors QualifiedPathInType (QualifiedPathInType &&other) = default; QualifiedPathInType &operator= (QualifiedPathInType &&other) = default; std::string as_string () const override; void accept_vis (HIRFullVisitor &vis) override; void accept_vis (HIRTypeVisitor &vis) override; QualifiedPathType &get_path_type () { return path_type; } TypePathSegment &get_associated_segment () { return *associated_segment; } std::vector > &get_segments () { return segments; } }; } // namespace HIR } // namespace Rust #endif