blob: 49415ea0b31ae0e71a35d98a038d18fd6ad41020 [file] [log] [blame]
// 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
// <http://www.gnu.org/licenses/>.
#ifndef RUST_TYTY
#define RUST_TYTY
#include "optional.h"
#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"
#include "rust-hir.h"
#include "tree.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,
CONST,
ARRAY,
SLICE,
FNDEF,
FNPTR,
TUPLE,
BOOL,
CHAR,
INT,
UINT,
FLOAT,
USIZE,
ISIZE,
NEVER,
PLACEHOLDER,
PROJECTION,
DYNAMIC,
CLOSURE,
OPAQUE,
// 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>() -> 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<TyTy::TypeBoundPredicate> &specified_bounds);
// contains_infer checks if there is an inference variable inside the type
const TyTy::BaseType *contains_infer () const;
// 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<HirId> get_combined_refs () const;
void append_reference (HirId id);
std::string mappings_str () const;
std::string debug_str () const;
void debug () const;
BaseType *get_root ();
// 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;
const SubstitutionArgumentMappings &get_subst_argument_mappings () 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 <typename T> WARN_UNUSED_RESULT bool is () const
{
static_assert (std::is_base_of<BaseType, T>::value,
"Can only safely cast to TyTy types.");
return this->get_kind () == T::KIND;
}
template <typename T> T *as () const
{
static_assert (std::is_base_of<BaseType, T>::value,
"Can only safely cast to TyTy types.");
rust_assert (this->is<T> ());
return static_cast<T *> (this);
}
template <typename T> T *as ()
{
static_assert (std::is_base_of<BaseType, T>::value,
"Can only safely cast to TyTy types.");
rust_assert (this->is<T> ());
return static_cast<T *> (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 <typename T> T *try_as () const
{
static_assert (std::is_base_of<BaseType, T>::value,
"Can only safely cast to TyTy types.");
if (!this->is<T> ())
return nullptr;
return static_cast<T *> (this);
}
// See above.
template <typename T> T *try_as ()
{
static_assert (std::is_base_of<BaseType, T>::value,
"Can only safely cast to TyTy types.");
if (!this->is<T> ())
return nullptr;
return static_cast<T *> (this);
}
protected:
BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident,
std::set<HirId> refs = std::set<HirId> ());
BaseType (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
TypeKind kind;
HirId ref;
HirId ty_ref;
const HirId orig_ref;
std::set<HirId> 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<HirId> refs = std::set<HirId> ())
: 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<HirId> refs = std::set<HirId> ());
InferType (HirId ref, HirId ty_ref, InferTypeKind infer_kind, TypeHint hint,
location_t locus, std::set<HirId> refs = std::set<HirId> ());
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<HirId> refs = std::set<HirId> ());
ErrorType (HirId ref, HirId ty_ref,
std::set<HirId> refs = std::set<HirId> ());
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 BaseGeneric : public BaseType
{
public:
virtual std::string get_symbol () const = 0;
virtual bool can_resolve () const = 0;
virtual BaseType *resolve () const = 0;
protected:
BaseGeneric (HirId ref, HirId ty_ref, TypeKind kind, RustIdent ident,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ())
: BaseType (ref, ty_ref, kind, ident, specified_bounds, refs)
{}
};
class ParamType : public BaseGeneric
{
public:
static constexpr auto KIND = TypeKind::PARAM;
ParamType (std::string symbol, location_t locus, HirId ref,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
ParamType (bool is_trait_self, std::string symbol, location_t locus,
HirId ref, HirId ty_ref,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
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 override final;
bool can_resolve () const override final;
BaseType *resolve () const override final;
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;
};
class ConstType : public BaseGeneric
{
public:
static constexpr auto KIND = TypeKind::CONST;
enum ConstKind
{
Decl,
Value,
Infer,
Error
};
ConstType (ConstKind kind, std::string symbol, TyTy::BaseType *ty, tree value,
std::vector<TypeBoundPredicate> specified_bounds, location_t locus,
HirId ref, HirId ty_ref,
std::set<HirId> refs = std::set<HirId> ());
void accept_vis (TyVisitor &vis) override;
void accept_vis (TyConstVisitor &vis) const override;
ConstKind get_const_kind () const { return const_kind; }
TyTy::BaseType *get_ty () const { return ty; }
tree get_value () const { return value; }
void set_value (tree value);
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 override final;
bool can_resolve () const override final;
BaseType *resolve () const override final;
std::string get_name () const override final;
bool is_equal (const BaseType &other) const override;
ConstType *handle_substitions (SubstitutionArgumentMappings &mappings);
private:
ConstKind const_kind;
TyTy::BaseType *ty;
tree value;
std::string symbol;
};
class OpaqueType : public BaseType
{
public:
static constexpr auto KIND = TypeKind::OPAQUE;
OpaqueType (location_t locus, HirId ref,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
OpaqueType (location_t locus, HirId ref, HirId ty_ref,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
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;
bool can_resolve () const;
BaseType *resolve () const;
std::string get_name () const override final;
bool is_equal (const BaseType &other) const override;
};
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<TyVar> fields = std::vector<TyVar> (),
std::set<HirId> refs = std::set<HirId> ());
TupleType (HirId ref, HirId ty_ref, location_t locus,
std::vector<TyVar> fields = std::vector<TyVar> (),
std::set<HirId> refs = std::set<HirId> ());
static TupleType *get_unit_type ();
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<TyVar> &get_fields () const;
std::string get_name () const override final;
TupleType *handle_substitions (SubstitutionArgumentMappings &mappings);
private:
std::vector<TyVar> fields;
};
class TypeBoundPredicate : public SubstitutionRef
{
public:
TypeBoundPredicate (const Resolver::TraitReference &trait_reference,
BoundPolarity polarity, location_t locus);
TypeBoundPredicate (DefId reference,
std::vector<SubstitutionParamMapping> 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 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 is_super_trait);
void apply_argument_mappings (SubstitutionArgumentMappings &arguments,
bool is_super_trait);
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<TypeBoundPredicateItem> 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;
bool validate_type_implements_super_traits (TyTy::BaseType &self,
HIR::Type &impl_type,
HIR::Type &trait) const;
bool validate_type_implements_this (TyTy::BaseType &self,
HIR::Type &impl_type,
HIR::Type &trait) const;
private:
struct mark_is_error
{
};
TypeBoundPredicate (mark_is_error);
void get_trait_hierachy (
std::function<void (const Resolver::TraitReference &)> callback) const;
DefId reference;
location_t locus;
bool error_flag;
BoundPolarity polarity;
std::vector<TyTy::TypeBoundPredicate> super_traits;
};
class TypeBoundPredicateItem
{
public:
TypeBoundPredicateItem (const TypeBoundPredicate parent,
const Resolver::TraitItemReference *trait_item_ref);
TypeBoundPredicateItem (const TypeBoundPredicateItem &other);
TypeBoundPredicateItem &operator= (const TypeBoundPredicateItem &other);
static TypeBoundPredicateItem error ();
bool is_error () const;
BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver);
const Resolver::TraitItemReference *get_raw_item () const;
bool needs_implementation () const;
const TypeBoundPredicate *get_parent () const;
location_t get_locus () const;
private:
TypeBoundPredicate parent;
const Resolver::TraitItemReference *trait_item_ref;
};
// 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,
tl::optional<std::unique_ptr<HIR::Expr>> &&discriminant);
VariantDef (HirId id, DefId defid, std::string identifier, RustIdent ident,
VariantType type,
tl::optional<std::unique_ptr<HIR::Expr>> &&discriminant,
std::vector<StructFieldType *> fields);
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<StructFieldType *> &get_fields ();
bool lookup_field (const std::string &lookup, StructFieldType **field_lookup,
size_t *index) const;
bool has_discriminant () const;
HIR::Expr &get_discriminant ();
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
tl::optional<std::unique_ptr<HIR::Expr>> discriminant;
std::vector<StructFieldType *> fields;
};
class ADTType : public BaseType, public SubstitutionRef
{
public:
static constexpr auto KIND = TypeKind::ADT;
enum ADTKind
{
STRUCT_STRUCT,
TUPLE_STRUCT,
UNION,
ENUM
};
enum ReprKind
{
RUST,
C,
INT,
ALIGN,
PACKED,
// TRANSPARENT,
// SIMD,
// ...
};
// Representation options, specified via attributes e.g. #[repr(packed)]
struct ReprOptions
{
ReprKind repr_kind = ReprKind::RUST;
// 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;
BaseType *repr = nullptr;
};
ADTType (DefId id, HirId ref, std::string identifier, RustIdent ident,
ADTKind adt_kind, std::vector<VariantDef *> variants,
std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings generic_arguments
= SubstitutionArgumentMappings::error (),
RegionConstraints region_constraints = RegionConstraints{},
std::set<HirId> refs = std::set<HirId> ());
ADTType (DefId id, HirId ref, HirId ty_ref, std::string identifier,
RustIdent ident, ADTKind adt_kind,
std::vector<VariantDef *> variants,
std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings generic_arguments
= SubstitutionArgumentMappings::error (),
RegionConstraints region_constraints = RegionConstraints{},
std::set<HirId> refs = std::set<HirId> ());
ADTType (DefId id, HirId ref, HirId ty_ref, std::string identifier,
RustIdent ident, ADTKind adt_kind,
std::vector<VariantDef *> variants,
std::vector<SubstitutionParamMapping> subst_refs, ReprOptions repr,
SubstitutionArgumentMappings generic_arguments
= SubstitutionArgumentMappings::error (),
RegionConstraints region_constraints = RegionConstraints{},
std::set<HirId> refs = std::set<HirId> ());
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 ();
}
DefId get_id () const;
BaseType *clone () const final override;
size_t number_of_variants () const { return variants.size (); }
std::vector<VariantDef *> &get_variants () { return variants; }
const std::vector<VariantDef *> &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:
DefId id;
std::string identifier;
std::vector<VariantDef *> variants;
ADTType::ADTKind adt_kind;
ReprOptions repr;
};
class FnParam
{
public:
FnParam (std::unique_ptr<HIR::Pattern> pattern, BaseType *type)
: pattern (std::move (pattern)), type (type)
{}
FnParam (const FnParam &) = delete;
FnParam (FnParam &&) = default;
FnParam &operator= (FnParam &&) = default;
HIR::Pattern &get_pattern () { return *pattern; }
const HIR::Pattern &get_pattern () const { return *pattern; }
bool has_pattern () { return pattern != nullptr; }
BaseType *get_type () const { return type; }
void set_type (BaseType *new_type) { type = new_type; }
FnParam clone () const
{
return FnParam (pattern->clone_pattern (), type->clone ());
}
FnParam monomorphized_clone () const
{
return FnParam (pattern->clone_pattern (), type->monomorphized_clone ());
}
private:
std::unique_ptr<HIR::Pattern> pattern;
BaseType *type;
};
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<FnParam> params, BaseType *type,
std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings substitution_argument_mappings,
RegionConstraints region_constraints,
std::set<HirId> refs = std::set<HirId> ())
: 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<FnParam> params,
BaseType *type, std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings substitution_argument_mappings,
RegionConstraints region_constraints,
std::set<HirId> refs = std::set<HirId> ())
: CallableTypeInterface (ref, ty_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 (const FnType &) = delete;
FnType (FnType &&) = default;
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).get_type ();
}
std::vector<FnParam> &get_params () { return params; }
const std::vector<FnParam> &get_params () const { return params; }
FnParam &param_at (size_t idx) { return params.at (idx); }
const FnParam &param_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).get_type ();
}
WARN_UNUSED_RESULT BaseType *get_return_type () const override
{
return type;
}
private:
std::vector<FnParam> 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<TyVar> params,
TyVar result_type, std::set<HirId> refs = std::set<HirId> ())
: 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<TyVar> params,
TyVar result_type, std::set<HirId> refs = std::set<HirId> ())
: 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<TyVar> &get_params () { return params; }
const std::vector<TyVar> &get_params () const { return params; }
private:
std::vector<TyVar> 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<SubstitutionParamMapping> subst_refs,
std::set<NodeId> captures,
std::set<HirId> refs = std::set<HirId> (),
std::vector<TypeBoundPredicate> specified_bounds
= std::vector<TypeBoundPredicate> ())
: 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<SubstitutionParamMapping> subst_refs,
std::set<NodeId> captures,
std::set<HirId> refs = std::set<HirId> (),
std::vector<TypeBoundPredicate> specified_bounds
= std::vector<TypeBoundPredicate> ())
: 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<NodeId> &get_captures () const { return captures; }
private:
TyTy::TupleType *parameters;
TyVar result_type;
DefId id;
std::set<NodeId> captures;
};
class ArrayType : public BaseType
{
public:
static constexpr auto KIND = TypeKind::ARRAY;
ArrayType (HirId ref, location_t locus, ConstType *capacity, TyVar base,
std::set<HirId> refs = std::set<HirId> ())
: BaseType (ref, ref, TypeKind::ARRAY,
{Resolver::CanonicalPath::create_empty (), locus}, refs),
element_type (base), capacity (capacity)
{}
ArrayType (HirId ref, HirId ty_ref, location_t locus, ConstType *capacity,
TyVar base, std::set<HirId> refs = std::set<HirId> ())
: BaseType (ref, ty_ref, TypeKind::ARRAY,
{Resolver::CanonicalPath::create_empty (), locus}, refs),
element_type (base), capacity (capacity)
{}
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;
ConstType *get_capacity () const { return capacity; }
ArrayType *handle_substitions (SubstitutionArgumentMappings &mappings);
private:
TyVar element_type;
ConstType *capacity;
};
class SliceType : public BaseType
{
public:
static constexpr auto KIND = TypeKind::SLICE;
SliceType (HirId ref, location_t locus, TyVar base,
std::set<HirId> refs = std::set<HirId> ())
: 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<HirId> refs = std::set<HirId> ())
: 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<HirId> refs = std::set<HirId> ());
BoolType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ());
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<HirId> refs = std::set<HirId> ());
IntType (HirId ref, HirId ty_ref, IntKind kind,
std::set<HirId> refs = std::set<HirId> ());
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<HirId> refs = std::set<HirId> ());
UintType (HirId ref, HirId ty_ref, UintKind kind,
std::set<HirId> refs = std::set<HirId> ());
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<HirId> refs = std::set<HirId> ());
FloatType (HirId ref, HirId ty_ref, FloatKind kind,
std::set<HirId> refs = std::set<HirId> ());
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<HirId> refs = std::set<HirId> ());
USizeType (HirId ref, HirId ty_ref,
std::set<HirId> refs = std::set<HirId> ());
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<HirId> refs = std::set<HirId> ());
ISizeType (HirId ref, HirId ty_ref,
std::set<HirId> refs = std::set<HirId> ());
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<HirId> refs = std::set<HirId> ());
CharType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ());
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<HirId> refs = std::set<HirId> ());
StrType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ());
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<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
DynamicObjectType (HirId ref, HirId ty_ref, RustIdent ident,
std::vector<TypeBoundPredicate> specified_bounds,
std::set<HirId> refs = std::set<HirId> ());
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<const Resolver::TraitItemReference *, const TypeBoundPredicate *>>
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<HirId> refs = std::set<HirId> ());
ReferenceType (HirId ref, HirId ty_ref, TyVar base, Mutability mut,
Region region = Region::make_anonymous (),
std::set<HirId> refs = std::set<HirId> ());
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<HirId> refs = std::set<HirId> ());
PointerType (HirId ref, HirId ty_ref, TyVar base, Mutability mut,
std::set<HirId> refs = std::set<HirId> ());
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 `<T?>`) 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<HirId> refs = std::set<HirId> ());
NeverType (HirId ref, HirId ty_ref,
std::set<HirId> refs = std::set<HirId> ());
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, DefId id, HirId ref,
std::set<HirId> refs = std::set<HirId> ());
PlaceholderType (std::string symbol, DefId id, HirId ref, HirId ty_ref,
std::set<HirId> refs = std::set<HirId> ());
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;
DefId get_def_id () const;
private:
std::string symbol;
DefId defId;
};
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<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings generic_arguments
= SubstitutionArgumentMappings::error (),
RegionConstraints region_constraints = {},
std::set<HirId> refs = std::set<HirId> ());
ProjectionType (HirId ref, HirId ty_ref, BaseType *base,
const Resolver::TraitReference *trait, DefId item,
std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings generic_arguments
= SubstitutionArgumentMappings::error (),
RegionConstraints region_constraints = {},
std::set<HirId> refs = std::set<HirId> ());
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<CallableTypeInterface> () const
{
auto kind = this->get_kind ();
return kind == FNPTR || kind == FNDEF || kind == CLOSURE;
}
template <>
WARN_UNUSED_RESULT inline bool
BaseType::is<const CallableTypeInterface> () const
{
return this->is<CallableTypeInterface> ();
}
template <>
WARN_UNUSED_RESULT inline bool
BaseType::is<SubstitutionRef> () 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 SubstitutionRef> () const
{
return this->is<SubstitutionRef> ();
}
template <>
WARN_UNUSED_RESULT inline SubstitutionRef *
BaseType::as<SubstitutionRef> ()
{
auto kind = this->get_kind ();
switch (kind)
{
case FNDEF:
return static_cast<FnType *> (this);
case CLOSURE:
return static_cast<ClosureType *> (this);
case ADT:
return static_cast<ADTType *> (this);
case PROJECTION:
return static_cast<ProjectionType *> (this);
default:
rust_unreachable ();
}
}
template <>
WARN_UNUSED_RESULT inline const SubstitutionRef *
BaseType::as<const SubstitutionRef> () const
{
auto kind = this->get_kind ();
switch (kind)
{
case FNDEF:
return static_cast<const FnType *> (this);
case CLOSURE:
return static_cast<const ClosureType *> (this);
case ADT:
return static_cast<const ADTType *> (this);
case PROJECTION:
return static_cast<const ProjectionType *> (this);
default:
rust_unreachable ();
}
}
template <>
WARN_UNUSED_RESULT inline SubstitutionRef *
BaseType::try_as<SubstitutionRef> ()
{
if (this->is<SubstitutionRef> ())
{
return this->as<SubstitutionRef> ();
}
return nullptr;
}
template <>
WARN_UNUSED_RESULT inline const SubstitutionRef *
BaseType::try_as<const SubstitutionRef> () const
{
if (this->is<const SubstitutionRef> ())
{
return this->as<const SubstitutionRef> ();
}
return nullptr;
}
} // namespace TyTy
} // namespace Rust
#endif // RUST_TYTY