// Copyright (C) 2020-2024 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_TYTY #define RUST_TYTY #include "rust-hir-map.h" #include "rust-common.h" #include "rust-identifier.h" #include "rust-abi.h" #include "rust-tyty-bounds.h" #include "rust-tyty-util.h" #include "rust-tyty-subst.h" #include "rust-tyty-region.h" #include "rust-system.h" namespace Rust { namespace Resolver { class TraitReference; class TraitItemReference; class AssociatedImplTrait; } // namespace Resolver namespace TyTy { class ClosureType; class FnPtr; class FnType; class CallableTypeInterface; // https://rustc-dev-guide.rust-lang.org/type-inference.html#inference-variables // https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variants enum TypeKind { INFER, ADT, STR, REF, POINTER, PARAM, ARRAY, SLICE, FNDEF, FNPTR, TUPLE, BOOL, CHAR, INT, UINT, FLOAT, USIZE, ISIZE, NEVER, PLACEHOLDER, PROJECTION, DYNAMIC, CLOSURE, // there are more to add... ERROR }; extern bool is_primitive_type_kind (TypeKind kind); class TypeKindFormat { public: static std::string to_string (TypeKind kind); }; class TyVisitor; class TyConstVisitor; class BaseType : public TypeBoundsMappings { public: virtual ~BaseType (); HirId get_ref () const; void set_ref (HirId id); HirId get_ty_ref () const; void set_ty_ref (HirId id); HirId get_orig_ref () const; virtual void accept_vis (TyVisitor &vis) = 0; virtual void accept_vis (TyConstVisitor &vis) const = 0; virtual std::string as_string () const = 0; virtual std::string get_name () const = 0; // similar to unify but does not actually perform type unification but // determines whether they are compatible. Consider the following // // fn foo() -> T { ... } // fn foo() -> i32 { ... } // // when the function has been substituted they can be considered equal. // // It can also be used to optional emit errors for trait item compatibility // checks virtual bool can_eq (const BaseType *other, bool emit_errors) const = 0; // Check value equality between two ty. Type inference rules are ignored. Two // ty are considered equal if they're of the same kind, and // 1. (For ADTs, arrays, tuples, refs) have the same underlying ty // 2. (For functions) have the same signature virtual bool is_equal (const BaseType &other) const; bool satisfies_bound (const TypeBoundPredicate &predicate, bool emit_error) const; bool bounds_compatible (const BaseType &other, location_t locus, bool emit_error) const; void inherit_bounds (const BaseType &other); void inherit_bounds ( const std::vector &specified_bounds); // is_unit returns whether this is just a unit-struct bool is_unit () const; // is_concrete returns true if the type is fully resolved to concrete // primitives bool is_concrete () const; // return the type-kind TypeKind get_kind () const; // monomorphized clone is a clone which destructures the types to get rid of // generics BaseType *monomorphized_clone () const; // get_combined_refs returns the chain of node refs involved in unification std::set get_combined_refs () const; void append_reference (HirId id); std::string mappings_str () const; std::string debug_str () const; void debug () const; // FIXME this will eventually go away const BaseType *get_root () const; // This will get the monomorphized type from Params, Placeholders or // Projections if available or error BaseType *destructure (); const BaseType *destructure () const; const RustIdent &get_ident () const; location_t get_locus () const; bool has_substitutions_defined () const; bool needs_generic_substitutions () const; std::string mangle_string () const { return TypeKindFormat::to_string (get_kind ()) + ":" + as_string () + ":" + mappings_str () + ":" + bounds_as_string (); } /* Returns a pointer to a clone of this. The caller is responsible for * releasing the memory of the returned ty. */ virtual BaseType *clone () const = 0; // Check if TyTy::BaseType is of a specific type. template WARN_UNUSED_RESULT bool is () const { static_assert (std::is_base_of::value, "Can only safely cast to TyTy types."); return this->get_kind () == T::KIND; } template T *as () const { static_assert (std::is_base_of::value, "Can only safely cast to TyTy types."); rust_assert (this->is ()); return static_cast (this); } template T *as () { static_assert (std::is_base_of::value, "Can only safely cast to TyTy types."); rust_assert (this->is ()); return static_cast (this); } // Check if TyTy::BaseType is of a specific type and convert it to that type // if so. // Returns nullptr otherwise. Works as a dynamic_cast, but without compiler // RTTI. template T *try_as () const { static_assert (std::is_base_of::value, "Can only safely cast to TyTy types."); if (!this->is ()) return nullptr; return static_cast (this); } // See above. template T *try_as () { static_assert (std::is_base_of::value, "Can only safely cast to TyTy types."); if (!this->is ()) return nullptr; return static_cast (this); } protected: BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident, std::set refs = std::set ()); BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident, std::vector specified_bounds, std::set refs = std::set ()); TypeKind kind; HirId ref; HirId ty_ref; const HirId orig_ref; std::set combined; RustIdent ident; Analysis::Mappings *mappings; }; /** Unified interface for all function-like types. */ class CallableTypeInterface : public BaseType { public: explicit CallableTypeInterface (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident, std::set refs = std::set ()) : BaseType (ref, ty_ref, kind, ident, refs) {} WARN_UNUSED_RESULT virtual size_t get_num_params () const = 0; WARN_UNUSED_RESULT virtual BaseType * get_param_type_at (size_t index) const = 0; WARN_UNUSED_RESULT virtual BaseType *get_return_type () const = 0; }; class InferType : public BaseType { public: static constexpr auto KIND = TypeKind::INFER; enum InferTypeKind { GENERAL, INTEGRAL, FLOAT }; struct TypeHint { enum SignedHint { SIGNED, UNSIGNED, UNKNOWN }; enum SizeHint { S8, S16, S32, S64, S128, SUNKNOWN }; TyTy::TypeKind kind; SignedHint shint; SizeHint szhint; static TypeHint Default () { return TypeHint{TypeKind::ERROR, UNKNOWN, SUNKNOWN}; } }; InferType (HirId ref, InferTypeKind infer_kind, TypeHint hint, location_t locus, std::set refs = std::set ()); InferType (HirId ref, HirId ty_ref, InferTypeKind infer_kind, TypeHint hint, location_t locus, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; InferTypeKind get_infer_kind () const; std::string get_name () const override final; bool default_type (BaseType **type) const; void apply_primitive_type_hint (const TyTy::BaseType &hint); private: InferTypeKind infer_kind; TypeHint default_hint; }; class ErrorType : public BaseType { public: static constexpr auto KIND = TypeKind::ERROR; ErrorType (HirId ref, std::set refs = std::set ()); ErrorType (HirId ref, HirId ty_ref, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; std::string get_name () const override final; }; class ParamType : public BaseType { public: static constexpr auto KIND = TypeKind::PARAM; ParamType (std::string symbol, location_t locus, HirId ref, HIR::GenericParam ¶m, std::vector specified_bounds, std::set refs = std::set ()); ParamType (bool is_trait_self, std::string symbol, location_t locus, HirId ref, HirId ty_ref, HIR::GenericParam ¶m, std::vector specified_bounds, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; std::string get_symbol () const; HIR::GenericParam &get_generic_param (); bool can_resolve () const; BaseType *resolve () const; std::string get_name () const override final; bool is_equal (const BaseType &other) const override; ParamType *handle_substitions (SubstitutionArgumentMappings &mappings); void set_implicit_self_trait (); bool is_implicit_self_trait () const; private: bool is_trait_self; std::string symbol; HIR::GenericParam ¶m; }; class StructFieldType { public: StructFieldType (HirId ref, std::string name, BaseType *ty, location_t locus); HirId get_ref () const; bool is_equal (const StructFieldType &other) const; std::string get_name () const; BaseType *get_field_type () const; void set_field_type (BaseType *fty); StructFieldType *clone () const; StructFieldType *monomorphized_clone () const; void debug () const; location_t get_locus () const; std::string as_string () const; private: HirId ref; std::string name; BaseType *ty; location_t locus; }; class TupleType : public BaseType { public: static constexpr auto KIND = TypeKind::TUPLE; TupleType (HirId ref, location_t locus, std::vector fields = std::vector (), std::set refs = std::set ()); TupleType (HirId ref, HirId ty_ref, location_t locus, std::vector fields = std::vector (), std::set refs = std::set ()); static TupleType *get_unit_type (HirId ref); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; size_t num_fields () const; BaseType *get_field (size_t index) const; BaseType *clone () const final override; const std::vector &get_fields () const; std::string get_name () const override final; TupleType *handle_substitions (SubstitutionArgumentMappings &mappings); private: std::vector fields; }; class TypeBoundPredicate : public SubstitutionRef { public: TypeBoundPredicate (const Resolver::TraitReference &trait_reference, BoundPolarity polarity, location_t locus); TypeBoundPredicate (DefId reference, std::vector substitutions, BoundPolarity polarity, location_t locus); TypeBoundPredicate (const TypeBoundPredicate &other); virtual ~TypeBoundPredicate (){}; TypeBoundPredicate &operator= (const TypeBoundPredicate &other); static TypeBoundPredicate error (); std::string as_string () const; std::string as_name () const; const Resolver::TraitReference *get () const; location_t get_locus () const { return locus; } std::string get_name () const; // check that this predicate is object-safe see: // https://doc.rust-lang.org/reference/items/traits.html#object-safety bool is_object_safe (bool emit_error, location_t locus) const; void apply_generic_arguments (HIR::GenericArgs *generic_args, bool has_associated_self); bool contains_item (const std::string &search) const; TypeBoundPredicateItem lookup_associated_item (const std::string &search) const; TypeBoundPredicateItem lookup_associated_item (const Resolver::TraitItemReference *ref) const; // WARNING THIS WILL ALWAYS RETURN NULLPTR BaseType * handle_substitions (SubstitutionArgumentMappings &mappings) override final; bool is_error () const; bool requires_generic_args () const; bool contains_associated_types () const; DefId get_id () const { return reference; } BoundPolarity get_polarity () const { return polarity; } std::vector get_associated_type_items (); size_t get_num_associated_bindings () const override final; TypeBoundPredicateItem lookup_associated_type (const std::string &search) override final; bool is_equal (const TypeBoundPredicate &other) const; private: struct mark_is_error { }; TypeBoundPredicate (mark_is_error); DefId reference; location_t locus; bool error_flag; BoundPolarity polarity; }; // https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.VariantDef.html class VariantDef { public: enum VariantType { NUM, TUPLE, STRUCT }; static std::string variant_type_string (VariantType type); VariantDef (HirId id, DefId defid, std::string identifier, RustIdent ident, HIR::Expr *discriminant); VariantDef (HirId id, DefId defid, std::string identifier, RustIdent ident, VariantType type, HIR::Expr *discriminant, std::vector fields); VariantDef (const VariantDef &other); VariantDef &operator= (const VariantDef &other); static VariantDef &get_error_node (); bool is_error () const; HirId get_id () const; DefId get_defid () const; VariantType get_variant_type () const; bool is_data_variant () const; bool is_dataless_variant () const; std::string get_identifier () const; size_t num_fields () const; StructFieldType *get_field_at_index (size_t index); std::vector &get_fields (); bool lookup_field (const std::string &lookup, StructFieldType **field_lookup, size_t *index) const; HIR::Expr *get_discriminant () const; std::string as_string () const; bool is_equal (const VariantDef &other) const; VariantDef *clone () const; VariantDef *monomorphized_clone () const; const RustIdent &get_ident () const; private: HirId id; DefId defid; std::string identifier; RustIdent ident; VariantType type; // can either be a structure or a discriminant value HIR::Expr *discriminant; std::vector fields; }; class ADTType : public BaseType, public SubstitutionRef { public: static constexpr auto KIND = TypeKind::ADT; enum ADTKind { STRUCT_STRUCT, TUPLE_STRUCT, UNION, ENUM }; // Representation options, specified via attributes e.g. #[repr(packed)] struct ReprOptions { // bool is_c; // bool is_transparent; //... // For align and pack: 0 = unspecified. Nonzero = byte alignment. // It is an error for both to be nonzero, this should be caught when // parsing the #[repr] attribute. unsigned char align = 0; unsigned char pack = 0; }; ADTType (HirId ref, std::string identifier, RustIdent ident, ADTKind adt_kind, std::vector variants, std::vector subst_refs, SubstitutionArgumentMappings generic_arguments = SubstitutionArgumentMappings::error (), RegionConstraints region_constraints = {}, std::set refs = std::set ()) : BaseType (ref, ref, TypeKind::ADT, ident, refs), SubstitutionRef (std::move (subst_refs), std::move (generic_arguments), region_constraints), identifier (identifier), variants (variants), adt_kind (adt_kind) {} ADTType (HirId ref, HirId ty_ref, std::string identifier, RustIdent ident, ADTKind adt_kind, std::vector variants, std::vector subst_refs, SubstitutionArgumentMappings generic_arguments = SubstitutionArgumentMappings::error (), RegionConstraints region_constraints = {}, std::set refs = std::set ()) : BaseType (ref, ty_ref, TypeKind::ADT, ident, refs), SubstitutionRef (std::move (subst_refs), std::move (generic_arguments), region_constraints), identifier (identifier), variants (variants), adt_kind (adt_kind) {} ADTType (HirId ref, HirId ty_ref, std::string identifier, RustIdent ident, ADTKind adt_kind, std::vector variants, std::vector subst_refs, ReprOptions repr, SubstitutionArgumentMappings generic_arguments = SubstitutionArgumentMappings::error (), RegionConstraints region_constraints = {}, std::set refs = std::set ()) : BaseType (ref, ty_ref, TypeKind::ADT, ident, refs), SubstitutionRef (std::move (subst_refs), std::move (generic_arguments), region_constraints), identifier (identifier), variants (variants), adt_kind (adt_kind), repr (repr) {} ADTKind get_adt_kind () const { return adt_kind; } ReprOptions get_repr_options () const { return repr; } bool is_struct_struct () const { return adt_kind == STRUCT_STRUCT; } bool is_tuple_struct () const { return adt_kind == TUPLE_STRUCT; } bool is_union () const { return adt_kind == UNION; } bool is_enum () const { return adt_kind == ENUM; } void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; std::string get_identifier () const { return identifier; } std::string get_name () const override final { return identifier + subst_as_string (); } BaseType *clone () const final override; size_t number_of_variants () const { return variants.size (); } std::vector &get_variants () { return variants; } const std::vector &get_variants () const { return variants; } bool lookup_variant (const std::string &lookup, VariantDef **found_variant) const { for (auto &variant : variants) { if (variant->get_identifier ().compare (lookup) == 0) { *found_variant = variant; return true; } } return false; } bool lookup_variant_by_id (HirId id, VariantDef **found_variant, int *index = nullptr) const { int i = 0; for (auto &variant : variants) { if (variant->get_id () == id) { if (index != nullptr) *index = i; *found_variant = variant; return true; } i++; } return false; } ADTType * handle_substitions (SubstitutionArgumentMappings &mappings) override final; private: std::string identifier; std::vector variants; ADTType::ADTKind adt_kind; ReprOptions repr; }; class FnType : public CallableTypeInterface, public SubstitutionRef { public: static constexpr auto KIND = TypeKind::FNDEF; static const uint8_t FNTYPE_DEFAULT_FLAGS = 0x00; static const uint8_t FNTYPE_IS_METHOD_FLAG = 0x01; static const uint8_t FNTYPE_IS_EXTERN_FLAG = 0x02; static const uint8_t FNTYPE_IS_VARADIC_FLAG = 0X04; FnType (HirId ref, DefId id, std::string identifier, RustIdent ident, uint8_t flags, ABI abi, std::vector> params, BaseType *type, std::vector subst_refs, SubstitutionArgumentMappings substitution_argument_mappings, RegionConstraints region_constraints, std::set refs = std::set ()) : CallableTypeInterface (ref, ref, TypeKind::FNDEF, ident, refs), SubstitutionRef (std::move (subst_refs), substitution_argument_mappings, region_constraints), params (std::move (params)), type (type), flags (flags), identifier (identifier), id (id), abi (abi) { LocalDefId local_def_id = id.localDefId; rust_assert (local_def_id != UNKNOWN_LOCAL_DEFID); } FnType (HirId ref, HirId ty_ref, DefId id, std::string identifier, RustIdent ident, uint8_t flags, ABI abi, std::vector> params, BaseType *type, std::vector subst_refs, SubstitutionArgumentMappings substitution_argument_mappings, RegionConstraints region_constraints, std::set refs = std::set ()) : CallableTypeInterface (ref, ty_ref, TypeKind::FNDEF, ident, refs), SubstitutionRef (std::move (subst_refs), substitution_argument_mappings, region_constraints), params (params), type (type), flags (flags), identifier (identifier), id (id), abi (abi) { LocalDefId local_def_id = id.localDefId; rust_assert (local_def_id != UNKNOWN_LOCAL_DEFID); } void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final { return as_string (); } std::string get_identifier () const { return identifier; } bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; size_t num_params () const { return params.size (); } bool is_method () const { if (num_params () == 0) return false; return (flags & FNTYPE_IS_METHOD_FLAG) != 0; } bool is_extern () const { return (flags & FNTYPE_IS_EXTERN_FLAG) != 0; } bool is_variadic () const { return (flags & FNTYPE_IS_VARADIC_FLAG) != 0; } DefId get_id () const { return id; } // get the Self type for the method BaseType *get_self_type () const { rust_assert (is_method ()); return param_at (0).second; } std::vector> &get_params () { return params; } const std::vector> &get_params () const { return params; } std::pair ¶m_at (size_t idx) { return params.at (idx); } const std::pair ¶m_at (size_t idx) const { return params.at (idx); } BaseType *clone () const final override; FnType * handle_substitions (SubstitutionArgumentMappings &mappings) override final; ABI get_abi () const { return abi; } uint8_t get_flags () const { return flags; } WARN_UNUSED_RESULT size_t get_num_params () const override { return params.size (); } WARN_UNUSED_RESULT BaseType *get_param_type_at (size_t index) const override { return param_at (index).second; } WARN_UNUSED_RESULT BaseType *get_return_type () const override { return type; } private: std::vector> params; BaseType *type; uint8_t flags; std::string identifier; DefId id; ABI abi; }; class FnPtr : public CallableTypeInterface { public: static constexpr auto KIND = TypeKind::FNPTR; FnPtr (HirId ref, location_t locus, std::vector params, TyVar result_type, std::set refs = std::set ()) : CallableTypeInterface (ref, ref, TypeKind::FNPTR, {Resolver::CanonicalPath::create_empty (), locus}, refs), params (std::move (params)), result_type (result_type) {} FnPtr (HirId ref, HirId ty_ref, location_t locus, std::vector params, TyVar result_type, std::set refs = std::set ()) : CallableTypeInterface (ref, ty_ref, TypeKind::FNPTR, {Resolver::CanonicalPath::create_empty (), locus}, refs), params (params), result_type (result_type) {} std::string get_name () const override final { return as_string (); } WARN_UNUSED_RESULT size_t get_num_params () const override { return params.size (); } WARN_UNUSED_RESULT BaseType *get_param_type_at (size_t index) const override { return params.at (index).get_tyty (); } WARN_UNUSED_RESULT BaseType *get_return_type () const override { return result_type.get_tyty (); } const TyVar &get_var_return_type () const { return result_type; } size_t num_params () const { return params.size (); } void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; BaseType *clone () const final override; std::vector &get_params () { return params; } const std::vector &get_params () const { return params; } private: std::vector params; TyVar result_type; }; class ClosureType : public CallableTypeInterface, public SubstitutionRef { public: static constexpr auto KIND = TypeKind::CLOSURE; ClosureType (HirId ref, DefId id, RustIdent ident, TupleType *parameters, TyVar result_type, std::vector subst_refs, std::set captures, std::set refs = std::set (), std::vector specified_bounds = std::vector ()) : CallableTypeInterface (ref, ref, TypeKind::CLOSURE, ident, refs), SubstitutionRef (std::move (subst_refs), SubstitutionArgumentMappings::error (), {}), // TODO: check region constraints parameters (parameters), result_type (std::move (result_type)), id (id), captures (captures) { LocalDefId local_def_id = id.localDefId; rust_assert (local_def_id != UNKNOWN_LOCAL_DEFID); inherit_bounds (specified_bounds); } ClosureType (HirId ref, HirId ty_ref, RustIdent ident, DefId id, TupleType *parameters, TyVar result_type, std::vector subst_refs, std::set captures, std::set refs = std::set (), std::vector specified_bounds = std::vector ()) : CallableTypeInterface (ref, ty_ref, TypeKind::CLOSURE, ident, refs), SubstitutionRef (std::move (subst_refs), SubstitutionArgumentMappings::error (), {}), // TODO parameters (parameters), result_type (std::move (result_type)), id (id), captures (captures) { LocalDefId local_def_id = id.localDefId; rust_assert (local_def_id != UNKNOWN_LOCAL_DEFID); inherit_bounds (specified_bounds); } void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; WARN_UNUSED_RESULT size_t get_num_params () const override { return parameters->num_fields (); } WARN_UNUSED_RESULT BaseType *get_param_type_at (size_t index) const override { return parameters->get_field (index); } WARN_UNUSED_RESULT BaseType *get_return_type () const override { return result_type.get_tyty (); } std::string as_string () const override; std::string get_name () const override final { return as_string (); } bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; BaseType *clone () const final override; ClosureType * handle_substitions (SubstitutionArgumentMappings &mappings) override final; TyTy::TupleType &get_parameters () const { return *parameters; } TyTy::BaseType &get_result_type () const { return *result_type.get_tyty (); } DefId get_def_id () const { return id; } void setup_fn_once_output () const; const std::set &get_captures () const { return captures; } private: TyTy::TupleType *parameters; TyVar result_type; DefId id; std::set captures; }; class ArrayType : public BaseType { public: static constexpr auto KIND = TypeKind::ARRAY; ArrayType (HirId ref, location_t locus, HIR::Expr &capacity_expr, TyVar base, std::set refs = std::set ()) : BaseType (ref, ref, TypeKind::ARRAY, {Resolver::CanonicalPath::create_empty (), locus}, refs), element_type (base), capacity_expr (capacity_expr) {} ArrayType (HirId ref, HirId ty_ref, location_t locus, HIR::Expr &capacity_expr, TyVar base, std::set refs = std::set ()) : BaseType (ref, ty_ref, TypeKind::ARRAY, {Resolver::CanonicalPath::create_empty (), locus}, refs), element_type (base), capacity_expr (capacity_expr) {} void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final { return as_string (); } bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; BaseType *get_element_type () const; const TyVar &get_var_element_type () const; BaseType *clone () const final override; HIR::Expr &get_capacity_expr () const { return capacity_expr; } ArrayType *handle_substitions (SubstitutionArgumentMappings &mappings); private: TyVar element_type; // FIXME: I dont think this should be in tyty - tyty should already be const // evaluated HIR::Expr &capacity_expr; }; class SliceType : public BaseType { public: static constexpr auto KIND = TypeKind::SLICE; SliceType (HirId ref, location_t locus, TyVar base, std::set refs = std::set ()) : BaseType (ref, ref, TypeKind::SLICE, {Resolver::CanonicalPath::create_empty (), locus}, refs), element_type (base) {} SliceType (HirId ref, HirId ty_ref, location_t locus, TyVar base, std::set refs = std::set ()) : BaseType (ref, ty_ref, TypeKind::SLICE, {Resolver::CanonicalPath::create_empty (), locus}, refs), element_type (base) {} void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final { return as_string (); } bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; BaseType *get_element_type () const; const TyVar &get_var_element_type () const; BaseType *clone () const final override; SliceType *handle_substitions (SubstitutionArgumentMappings &mappings); private: TyVar element_type; }; class BoolType : public BaseType { public: static constexpr auto KIND = TypeKind::BOOL; BoolType (HirId ref, std::set refs = std::set ()); BoolType (HirId ref, HirId ty_ref, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; }; class IntType : public BaseType { public: enum IntKind { I8, I16, I32, I64, I128 }; static constexpr auto KIND = TypeKind::INT; IntType (HirId ref, IntKind kind, std::set refs = std::set ()); IntType (HirId ref, HirId ty_ref, IntKind kind, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final; bool can_eq (const BaseType *other, bool emit_errors) const override final; IntKind get_int_kind () const; BaseType *clone () const final override; bool is_equal (const BaseType &other) const override; private: IntKind int_kind; }; class UintType : public BaseType { public: static constexpr auto KIND = TypeKind::UINT; enum UintKind { U8, U16, U32, U64, U128 }; UintType (HirId ref, UintKind kind, std::set refs = std::set ()); UintType (HirId ref, HirId ty_ref, UintKind kind, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final; bool can_eq (const BaseType *other, bool emit_errors) const override final; UintKind get_uint_kind () const; BaseType *clone () const final override; bool is_equal (const BaseType &other) const override; private: UintKind uint_kind; }; class FloatType : public BaseType { public: static constexpr auto KIND = TypeKind::FLOAT; enum FloatKind { F32, F64 }; FloatType (HirId ref, FloatKind kind, std::set refs = std::set ()); FloatType (HirId ref, HirId ty_ref, FloatKind kind, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final; bool can_eq (const BaseType *other, bool emit_errors) const override final; FloatKind get_float_kind () const; BaseType *clone () const final override; bool is_equal (const BaseType &other) const override; private: FloatKind float_kind; }; class USizeType : public BaseType { public: static constexpr auto KIND = TypeKind::USIZE; USizeType (HirId ref, std::set refs = std::set ()); USizeType (HirId ref, HirId ty_ref, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; }; class ISizeType : public BaseType { public: static constexpr auto KIND = TypeKind::ISIZE; ISizeType (HirId ref, std::set refs = std::set ()); ISizeType (HirId ref, HirId ty_ref, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; }; class CharType : public BaseType { public: static constexpr auto KIND = TypeKind::CHAR; CharType (HirId ref, std::set refs = std::set ()); CharType (HirId ref, HirId ty_ref, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; }; class StrType : public BaseType { public: static constexpr auto KIND = TypeKind::STR; StrType (HirId ref, std::set refs = std::set ()); StrType (HirId ref, HirId ty_ref, std::set refs = std::set ()); std::string get_name () const override final; void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; BaseType *clone () const final override; }; class DynamicObjectType : public BaseType { public: static constexpr auto KIND = TypeKind::DYNAMIC; DynamicObjectType (HirId ref, RustIdent ident, std::vector specified_bounds, std::set refs = std::set ()); DynamicObjectType (HirId ref, HirId ty_ref, RustIdent ident, std::vector specified_bounds, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; BaseType *clone () const final override; std::string get_name () const override final; // this returns a flat list of items including super trait bounds const std::vector< std::pair> get_object_items () const; }; class ReferenceType : public BaseType { public: static constexpr auto KIND = REF; ReferenceType (HirId ref, TyVar base, Mutability mut, Region region = Region::make_anonymous (), std::set refs = std::set ()); ReferenceType (HirId ref, HirId ty_ref, TyVar base, Mutability mut, Region region = Region::make_anonymous (), std::set refs = std::set ()); BaseType *get_base () const; const TyVar &get_var_element_type () const; void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; BaseType *clone () const final override; ReferenceType *handle_substitions (SubstitutionArgumentMappings &mappings); Mutability mutability () const; bool is_mutable () const; WARN_UNUSED_RESULT Region get_region () const; void set_region (Region region); bool is_dyn_object () const; bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const; bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const; bool is_dyn_obj_type (const TyTy::DynamicObjectType **dyn = nullptr) const; private: TyVar base; Mutability mut; Region region; }; class PointerType : public BaseType { public: static constexpr auto KIND = TypeKind::POINTER; PointerType (HirId ref, TyVar base, Mutability mut, std::set refs = std::set ()); PointerType (HirId ref, HirId ty_ref, TyVar base, Mutability mut, std::set refs = std::set ()); BaseType *get_base () const; const TyVar &get_var_element_type () const; void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; std::string get_name () const override final; bool can_eq (const BaseType *other, bool emit_errors) const override final; bool is_equal (const BaseType &other) const override; BaseType *clone () const final override; PointerType *handle_substitions (SubstitutionArgumentMappings &mappings); Mutability mutability () const; bool is_mutable () const; bool is_const () const; bool is_dyn_object () const; bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const; bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const; bool is_dyn_obj_type (const TyTy::DynamicObjectType **dyn = nullptr) const; private: TyVar base; Mutability mut; }; // https://doc.rust-lang.org/std/primitive.never.html // // Since the `!` type is really complicated and it is even still unstable // in rustc, only fairly limited support for this type is introduced here. // Unification between `!` and ANY other type (including ``) is simply // not allowed. If it is needed, it should be handled manually. For example, // unifying `!` with other types is very necessary when resolving types of // `if/else` expressions. // // See related discussion at https://github.com/Rust-GCC/gccrs/pull/364 class NeverType : public BaseType { public: static constexpr auto KIND = TypeKind::NEVER; NeverType (HirId ref, std::set refs = std::set ()); NeverType (HirId ref, HirId ty_ref, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; std::string get_name () const override final; }; // used at the type in associated types in traits // see: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html class PlaceholderType : public BaseType { public: static constexpr auto KIND = TypeKind::PLACEHOLDER; PlaceholderType (std::string symbol, HirId ref, std::set refs = std::set ()); PlaceholderType (std::string symbol, HirId ref, HirId ty_ref, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; std::string get_name () const override final; std::string get_symbol () const; void set_associated_type (HirId ref); void clear_associated_type (); bool can_resolve () const; BaseType *resolve () const; bool is_equal (const BaseType &other) const override; private: std::string symbol; }; class ProjectionType : public BaseType, public SubstitutionRef { public: static constexpr auto KIND = TypeKind::PROJECTION; ProjectionType (HirId ref, BaseType *base, const Resolver::TraitReference *trait, DefId item, std::vector subst_refs, SubstitutionArgumentMappings generic_arguments = SubstitutionArgumentMappings::error (), RegionConstraints region_constraints = {}, std::set refs = std::set ()); ProjectionType (HirId ref, HirId ty_ref, BaseType *base, const Resolver::TraitReference *trait, DefId item, std::vector subst_refs, SubstitutionArgumentMappings generic_arguments = SubstitutionArgumentMappings::error (), RegionConstraints region_constraints = {}, std::set refs = std::set ()); void accept_vis (TyVisitor &vis) override; void accept_vis (TyConstVisitor &vis) const override; std::string as_string () const override; bool can_eq (const BaseType *other, bool emit_errors) const override final; BaseType *clone () const final override; std::string get_name () const override final; const BaseType *get () const; BaseType *get (); ProjectionType * handle_substitions (SubstitutionArgumentMappings &mappings) override final; private: BaseType *base; const Resolver::TraitReference *trait; DefId item; }; template <> WARN_UNUSED_RESULT inline bool BaseType::is () const { auto kind = this->get_kind (); return kind == FNPTR || kind == FNDEF || kind == CLOSURE; } template <> WARN_UNUSED_RESULT inline bool BaseType::is () const { return this->is (); } template <> WARN_UNUSED_RESULT inline bool BaseType::is () const { auto kind = this->get_kind (); return kind == FNPTR || kind == FNDEF || kind == CLOSURE || kind == ADT || kind == PROJECTION; } template <> WARN_UNUSED_RESULT inline bool BaseType::is () const { return this->is (); } template <> WARN_UNUSED_RESULT inline SubstitutionRef * BaseType::as () { auto kind = this->get_kind (); switch (kind) { case FNDEF: return static_cast (this); case CLOSURE: return static_cast (this); case ADT: return static_cast (this); case PROJECTION: return static_cast (this); default: rust_unreachable (); } } template <> WARN_UNUSED_RESULT inline const SubstitutionRef * BaseType::as () const { auto kind = this->get_kind (); switch (kind) { case FNDEF: return static_cast (this); case CLOSURE: return static_cast (this); case ADT: return static_cast (this); case PROJECTION: return static_cast (this); default: rust_unreachable (); } } template <> WARN_UNUSED_RESULT inline SubstitutionRef * BaseType::try_as () { if (this->is ()) { return this->as (); } return nullptr; } template <> WARN_UNUSED_RESULT inline const SubstitutionRef * BaseType::try_as () const { if (this->is ()) { return this->as (); } return nullptr; } } // namespace TyTy } // namespace Rust #endif // RUST_TYTY