// Copyright (C) 2020-2023 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// .
#ifndef RUST_HIR_BASE_H
#define RUST_HIR_BASE_H
#include "rust-ast.h"
#include "rust-system.h"
#include "rust-token.h"
#include "rust-location.h"
#include "rust-hir-map.h"
#include "rust-diagnostics.h"
namespace Rust {
typedef std::string Identifier;
typedef int TupleIndex;
namespace HIR {
// foward decl: ast visitor
class HIRFullVisitor;
class HIRStmtVisitor;
class HIRTraitItemVisitor;
class HIRExternalItemVisitor;
class HIRVisItemVisitor;
class HIRExpressionVisitor;
class HIRPatternVisitor;
class HIRImplVisitor;
class HIRTypeVisitor;
// forward decl for use in token tree method
class Token;
class Node
{
public:
// Kind for downcasting various HIR nodes to other base classes when visiting
// them
enum BaseKind
{
/* class ExternalItem */
EXTERNAL,
/* class TraitItem */
TRAIT_ITEM,
/* class VisItem */
VIS_ITEM,
/* class Item */
ITEM,
/* class ImplItem */
IMPL,
/* class Type */
TYPE,
/* class Stmt */
STMT,
/* class Expr */
EXPR,
/* class Pattern */
PATTERN,
};
/**
* Get the kind of HIR node we are dealing with. This is useful for
* downcasting to more precise types when necessary, i.e going from an `Item*`
* to a `VisItem*`
*/
virtual BaseKind get_hir_kind () = 0;
};
// A literal - value with a type. Used in LiteralExpr and LiteralPattern.
struct Literal
{
public:
enum LitType
{
CHAR,
STRING,
BYTE,
BYTE_STRING,
INT,
FLOAT,
BOOL
};
private:
std::string value_as_string;
LitType type;
PrimitiveCoreType type_hint;
public:
std::string as_string () const { return value_as_string; }
LitType get_lit_type () const { return type; }
PrimitiveCoreType get_type_hint () const { return type_hint; }
Literal (std::string value_as_string, LitType type,
PrimitiveCoreType type_hint)
: value_as_string (std::move (value_as_string)), type (type),
type_hint (type_hint)
{}
static Literal create_error ()
{
return Literal ("", CHAR, PrimitiveCoreType::CORETYPE_UNKNOWN);
}
void set_lit_type (LitType lt) { type = lt; }
// Returns whether literal is in an invalid state.
bool is_error () const { return value_as_string == ""; }
bool is_equal (Literal &other)
{
return value_as_string == other.value_as_string && type == other.type
&& type_hint == other.type_hint;
}
};
/* Base statement abstract class. Note that most "statements" are not allowed in
* top-level module scope - only a subclass of statements called "items" are. */
class Stmt : public Node
{
public:
// Unique pointer custom clone function
std::unique_ptr clone_stmt () const
{
return std::unique_ptr (clone_stmt_impl ());
}
BaseKind get_hir_kind () override { return STMT; }
virtual ~Stmt () {}
virtual std::string as_string () const = 0;
virtual void accept_vis (HIRFullVisitor &vis) = 0;
virtual void accept_vis (HIRStmtVisitor &vis) = 0;
virtual Location get_locus () const = 0;
virtual bool is_unit_check_needed () const { return false; }
const Analysis::NodeMapping &get_mappings () const { return mappings; }
virtual bool is_item () const = 0;
protected:
Stmt (Analysis::NodeMapping mappings) : mappings (std::move (mappings)) {}
// Clone function implementation as pure virtual method
virtual Stmt *clone_stmt_impl () const = 0;
Analysis::NodeMapping mappings;
};
// Rust "item" HIR node (declaration of top-level/module-level allowed stuff)
class Item : public Stmt
{
AST::AttrVec outer_attrs;
// TODO: should outer attrs be defined here or in each derived class?
public:
enum class ItemKind
{
Static,
Constant,
TypeAlias,
Function,
UseDeclaration,
ExternBlock,
ExternCrate,
Struct,
Union,
Enum,
EnumItem, // FIXME: ARTHUR: Do we need that?
Trait,
Impl,
Module,
};
virtual ItemKind get_item_kind () const = 0;
// Unique pointer custom clone function
std::unique_ptr- clone_item () const
{
return std::unique_ptr
- (clone_item_impl ());
}
BaseKind get_hir_kind () override { return ITEM; }
std::string as_string () const override;
/* Adds crate names to the vector passed by reference, if it can
* (polymorphism). */
virtual void
add_crate_name (std::vector &names ATTRIBUTE_UNUSED) const
{}
AST::AttrVec &get_outer_attrs () { return outer_attrs; }
const AST::AttrVec &get_outer_attrs () const { return outer_attrs; }
bool is_item () const override final { return true; }
protected:
// Constructor
Item (Analysis::NodeMapping mappings,
AST::AttrVec outer_attribs = AST::AttrVec ())
: Stmt (std::move (mappings)), outer_attrs (std::move (outer_attribs))
{}
// Clone function implementation as pure virtual method
virtual Item *clone_item_impl () const = 0;
/* Save having to specify two clone methods in derived classes by making
* statement clone return item clone. Hopefully won't affect performance too
* much. */
Item *clone_stmt_impl () const override { return clone_item_impl (); }
};
// forward decl of ExprWithoutBlock
class ExprWithoutBlock;
// Base expression HIR node - abstract
class Expr : public Node
{
protected:
AST::AttrVec outer_attrs;
Analysis::NodeMapping mappings;
public:
enum BlockType
{
WITH_BLOCK,
WITHOUT_BLOCK,
};
enum ExprType
{
Lit,
Operator,
Grouped,
Array,
ArrayIndex,
Tuple,
TupleIdx,
Struct,
Call,
MethodCall,
FieldAccess,
Closure,
Block,
Continue,
Break,
Range,
Return,
UnsafeBlock,
BaseLoop,
If,
IfLet,
Match,
Await,
AsyncBlock,
Path,
};
BaseKind get_hir_kind () override final { return EXPR; }
const AST::AttrVec &get_outer_attrs () const { return outer_attrs; }
// Unique pointer custom clone function
std::unique_ptr clone_expr () const
{
return std::unique_ptr (clone_expr_impl ());
}
/* HACK: downcasting without dynamic_cast (if possible) via polymorphism -
* overrided in subclasses of ExprWithoutBlock */
virtual ExprWithoutBlock *as_expr_without_block () const { return nullptr; }
// TODO: make pure virtual if move out outer attributes to derived classes
virtual std::string as_string () const;
virtual ~Expr () {}
virtual Location get_locus () const = 0;
const Analysis::NodeMapping &get_mappings () const { return mappings; }
// Clone function implementation as pure virtual method
virtual Expr *clone_expr_impl () const = 0;
virtual BlockType get_block_expr_type () const = 0;
virtual ExprType get_expression_type () const = 0;
virtual void accept_vis (HIRExpressionVisitor &vis) = 0;
virtual void accept_vis (HIRFullVisitor &vis) = 0;
protected:
// Constructor
Expr (Analysis::NodeMapping mappings,
AST::AttrVec outer_attribs = AST::AttrVec ())
: outer_attrs (std::move (outer_attribs)), mappings (std::move (mappings))
{}
// TODO: think of less hacky way to implement this kind of thing
// Sets outer attributes.
void set_outer_attrs (AST::AttrVec outer_attrs_to_set)
{
outer_attrs = std::move (outer_attrs_to_set);
}
};
// HIR node for an expression without an accompanying block - abstract
class ExprWithoutBlock : public Expr
{
protected:
// Constructor
ExprWithoutBlock (Analysis::NodeMapping mappings,
AST::AttrVec outer_attribs = AST::AttrVec ())
: Expr (std::move (mappings), std::move (outer_attribs))
{}
// pure virtual clone implementation
virtual ExprWithoutBlock *clone_expr_without_block_impl () const = 0;
/* Save having to specify two clone methods in derived classes by making expr
* clone return exprwithoutblock clone. Hopefully won't affect performance too
* much. */
ExprWithoutBlock *clone_expr_impl () const override
{
return clone_expr_without_block_impl ();
}
public:
// Unique pointer custom clone function
std::unique_ptr clone_expr_without_block () const
{
return std::unique_ptr (clone_expr_without_block_impl ());
}
/* downcasting hack from expr to use pratt parsing with
* parse_expr_without_block */
ExprWithoutBlock *as_expr_without_block () const override
{
return clone_expr_without_block_impl ();
}
BlockType get_block_expr_type () const final override
{
return BlockType::WITHOUT_BLOCK;
};
};
// Pattern base HIR node
class Pattern : public Node
{
public:
enum PatternType
{
PATH,
LITERAL,
IDENTIFIER,
WILDCARD,
RANGE,
REFERENCE,
STRUCT,
TUPLE_STRUCT,
TUPLE,
GROUPED,
SLICE,
};
BaseKind get_hir_kind () override final { return PATTERN; }
// Unique pointer custom clone function
std::unique_ptr clone_pattern () const
{
return std::unique_ptr (clone_pattern_impl ());
}
// possible virtual methods: is_refutable()
virtual ~Pattern () {}
virtual std::string as_string () const = 0;
virtual void accept_vis (HIRFullVisitor &vis) = 0;
virtual void accept_vis (HIRPatternVisitor &vis) = 0;
virtual Analysis::NodeMapping get_pattern_mappings () const = 0;
virtual Location get_locus () const = 0;
virtual PatternType get_pattern_type () const = 0;
protected:
// Clone pattern implementation as pure virtual method
virtual Pattern *clone_pattern_impl () const = 0;
};
// forward decl for Type
class TraitBound;
// Base class for types as represented in HIR - abstract
class Type : public Node
{
public:
// Unique pointer custom clone function
std::unique_ptr clone_type () const
{
return std::unique_ptr (clone_type_impl ());
}
// virtual destructor
virtual ~Type () {}
BaseKind get_hir_kind () override final { return TYPE; }
virtual std::string as_string () const = 0;
/* HACK: convert to trait bound. Virtual method overriden by classes that
* enable this. */
virtual TraitBound *to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const
{
return nullptr;
}
/* as pointer, shouldn't require definition beforehand, only forward
* declaration. */
virtual void accept_vis (HIRFullVisitor &vis) = 0;
virtual void accept_vis (HIRTypeVisitor &vis) = 0;
virtual Analysis::NodeMapping get_mappings () const { return mappings; }
virtual Location get_locus () const { return locus; }
protected:
Type (Analysis::NodeMapping mappings, Location locus)
: mappings (mappings), locus (locus)
{}
// Clone function implementation as pure virtual method
virtual Type *clone_type_impl () const = 0;
Analysis::NodeMapping mappings;
Location locus;
};
// A type without parentheses? - abstract
class TypeNoBounds : public Type
{
public:
// Unique pointer custom clone function
std::unique_ptr clone_type_no_bounds () const
{
return std::unique_ptr (clone_type_no_bounds_impl ());
}
protected:
TypeNoBounds (Analysis::NodeMapping mappings, Location locus)
: Type (mappings, locus)
{}
// Clone function implementation as pure virtual method
virtual TypeNoBounds *clone_type_no_bounds_impl () const = 0;
/* Save having to specify two clone methods in derived classes by making type
* clone return typenobounds clone. Hopefully won't affect performance too
* much. */
TypeNoBounds *clone_type_impl () const override
{
return clone_type_no_bounds_impl ();
}
};
/* Abstract base class representing a type param bound - Lifetime and TraitBound
* extends it */
class TypeParamBound
{
public:
enum BoundType
{
LIFETIME,
TRAITBOUND
};
virtual ~TypeParamBound () {}
// Unique pointer custom clone function
std::unique_ptr clone_type_param_bound () const
{
return std::unique_ptr (clone_type_param_bound_impl ());
}
virtual std::string as_string () const = 0;
virtual void accept_vis (HIRFullVisitor &vis) = 0;
virtual Analysis::NodeMapping get_mappings () const = 0;
virtual Location get_locus () const = 0;
virtual BoundType get_bound_type () const = 0;
protected:
// Clone function implementation as pure virtual method
virtual TypeParamBound *clone_type_param_bound_impl () const = 0;
};
// Represents a lifetime (and is also a kind of type param bound)
class Lifetime : public TypeParamBound
{
private:
AST::Lifetime::LifetimeType lifetime_type;
std::string lifetime_name;
Location locus;
Analysis::NodeMapping mappings;
public:
// Constructor
Lifetime (Analysis::NodeMapping mapping, AST::Lifetime::LifetimeType type,
std::string name, Location locus)
: lifetime_type (type), lifetime_name (std::move (name)), locus (locus),
mappings (mapping)
{}
// Returns true if the lifetime is in an error state.
bool is_error () const
{
return lifetime_type == AST::Lifetime::LifetimeType::NAMED
&& lifetime_name.empty ();
}
static Lifetime error ()
{
return Lifetime (Analysis::NodeMapping::get_error (),
AST::Lifetime::LifetimeType::NAMED, "", Location ());
}
std::string as_string () const override;
void accept_vis (HIRFullVisitor &vis) override;
std::string get_name () const { return lifetime_name; }
AST::Lifetime::LifetimeType get_lifetime_type () const
{
return lifetime_type;
}
Location get_locus () const override final { return locus; }
Analysis::NodeMapping get_mappings () const override final
{
return mappings;
}
BoundType get_bound_type () const final override { return LIFETIME; }
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
Lifetime *clone_type_param_bound_impl () const override
{
return new Lifetime (*this);
}
};
/* Base generic parameter in HIR. Abstract - can be represented by a Lifetime or
* Type param */
class GenericParam
{
public:
virtual ~GenericParam () {}
enum class GenericKind
{
TYPE,
LIFETIME,
CONST,
};
// Unique pointer custom clone function
std::unique_ptr clone_generic_param () const
{
return std::unique_ptr (clone_generic_param_impl ());
}
virtual std::string as_string () const = 0;
virtual void accept_vis (HIRFullVisitor &vis) = 0;
virtual Location get_locus () const = 0;
Analysis::NodeMapping get_mappings () const { return mappings; }
enum GenericKind get_kind () const { return kind; }
protected:
// Clone function implementation as pure virtual method
virtual GenericParam *clone_generic_param_impl () const = 0;
Analysis::NodeMapping mappings;
enum GenericKind kind;
GenericParam (Analysis::NodeMapping mapping,
enum GenericKind kind = GenericKind::TYPE)
: mappings (mapping), kind (kind)
{}
};
// A lifetime generic parameter (as opposed to a type generic parameter)
class LifetimeParam : public GenericParam
{
Lifetime lifetime;
// bool has_lifetime_bounds;
// LifetimeBounds lifetime_bounds;
std::vector lifetime_bounds; // inlined LifetimeBounds
// bool has_outer_attribute;
// std::unique_ptr outer_attr;
AST::Attribute outer_attr;
Location locus;
public:
Lifetime get_lifetime () { return lifetime; }
// Returns whether the lifetime param has any lifetime bounds.
bool has_lifetime_bounds () const { return !lifetime_bounds.empty (); }
// Returns whether the lifetime param has an outer attribute.
bool has_outer_attribute () const { return !outer_attr.is_empty (); }
// Returns whether the lifetime param is in an error state.
bool is_error () const { return lifetime.is_error (); }
// Constructor
LifetimeParam (Analysis::NodeMapping mappings, Lifetime lifetime,
Location locus = Location (),
std::vector lifetime_bounds
= std::vector (),
AST::Attribute outer_attr = AST::Attribute::create_empty ())
: GenericParam (mappings, GenericKind::LIFETIME),
lifetime (std::move (lifetime)),
lifetime_bounds (std::move (lifetime_bounds)),
outer_attr (std::move (outer_attr)), locus (locus)
{}
// TODO: remove copy and assignment operator definitions - not required
// Copy constructor with clone
LifetimeParam (LifetimeParam const &other)
: GenericParam (other.mappings, GenericKind::LIFETIME),
lifetime (other.lifetime), lifetime_bounds (other.lifetime_bounds),
outer_attr (other.outer_attr), locus (other.locus)
{}
// Overloaded assignment operator to clone attribute
LifetimeParam &operator= (LifetimeParam const &other)
{
lifetime = other.lifetime;
lifetime_bounds = other.lifetime_bounds;
outer_attr = other.outer_attr;
locus = other.locus;
mappings = other.mappings;
return *this;
}
// move constructors
LifetimeParam (LifetimeParam &&other) = default;
LifetimeParam &operator= (LifetimeParam &&other) = default;
std::string as_string () const override;
void accept_vis (HIRFullVisitor &vis) override;
Location get_locus () const override final { return locus; }
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
LifetimeParam *clone_generic_param_impl () const override
{
return new LifetimeParam (*this);
}
};
class ConstGenericParam : public GenericParam
{
public:
ConstGenericParam (std::string name, std::unique_ptr type,
std::unique_ptr default_expression,
Analysis::NodeMapping mapping, Location locus)
: GenericParam (mapping, GenericKind::CONST), name (std::move (name)),
type (std::move (type)),
default_expression (std::move (default_expression)), locus (locus)
{}
ConstGenericParam (const ConstGenericParam &other) : GenericParam (other)
{
name = other.name;
locus = other.locus;
if (other.type)
type = other.type->clone_type ();
if (other.default_expression)
default_expression = other.default_expression->clone_expr ();
}
std::string as_string () const override final;
void accept_vis (HIRFullVisitor &vis) override final;
Location get_locus () const override final { return locus; };
bool has_default_expression () { return default_expression != nullptr; }
std::unique_ptr &get_type () { return type; }
std::unique_ptr &get_default_expression ()
{
rust_assert (has_default_expression ());
return default_expression;
}
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
ConstGenericParam *clone_generic_param_impl () const override
{
return new ConstGenericParam (*this);
}
private:
std::string name;
std::unique_ptr type;
/* Optional - can be a null pointer if there is no default expression */
std::unique_ptr default_expression;
Location locus;
};
// Item used in trait declarations - abstract base class
class TraitItem : public Node
{
public:
enum TraitItemKind
{
FUNC,
CONST,
TYPE
};
BaseKind get_hir_kind () override final { return TRAIT_ITEM; }
protected:
// Constructor
TraitItem (Analysis::NodeMapping mappings) : mappings (mappings) {}
// Clone function implementation as pure virtual method
virtual TraitItem *clone_trait_item_impl () const = 0;
Analysis::NodeMapping mappings;
public:
virtual ~TraitItem () {}
std::unique_ptr clone_trait_item () const
{
return std::unique_ptr (clone_trait_item_impl ());
}
virtual std::string as_string () const = 0;
virtual void accept_vis (HIRTraitItemVisitor &vis) = 0;
virtual void accept_vis (HIRFullVisitor &vis) = 0;
virtual const std::string trait_identifier () const = 0;
const Analysis::NodeMapping &get_mappings () const { return mappings; }
virtual Location get_trait_locus () const = 0;
virtual TraitItemKind get_item_kind () const = 0;
virtual AST::AttrVec &get_outer_attrs () = 0;
virtual const AST::AttrVec &get_outer_attrs () const = 0;
};
class ImplItem : public Node
{
public:
enum ImplItemType
{
FUNCTION,
TYPE_ALIAS,
CONSTANT
};
virtual ~ImplItem () {}
BaseKind get_hir_kind () override final { return IMPL; }
// Unique pointer custom clone function
std::unique_ptr clone_inherent_impl_item () const
{
return std::unique_ptr (clone_inherent_impl_item_impl ());
}
virtual std::string as_string () const = 0;
virtual void accept_vis (HIRImplVisitor &vis) = 0;
virtual void accept_vis (HIRFullVisitor &vis) = 0;
virtual void accept_vis (HIRStmtVisitor &vis) = 0;
virtual Analysis::NodeMapping get_impl_mappings () const = 0;
virtual Location get_locus () const = 0;
virtual ImplItemType get_impl_item_type () const = 0;
virtual std::string get_impl_item_name () const = 0;
protected:
// Clone function implementation as pure virtual method
virtual ImplItem *clone_inherent_impl_item_impl () const = 0;
};
// A crate HIR object - holds all the data for a single compilation unit
struct Crate
{
AST::AttrVec inner_attrs;
// dodgy spacing required here
/* TODO: is it better to have a vector of items here or a module (implicit
* top-level one)? */
std::vector > items;
Analysis::NodeMapping mappings;
public:
// Constructor
Crate (std::vector > items, AST::AttrVec inner_attrs,
Analysis::NodeMapping mappings)
: inner_attrs (std::move (inner_attrs)), items (std::move (items)),
mappings (mappings)
{}
// Copy constructor with vector clone
Crate (Crate const &other)
: inner_attrs (other.inner_attrs), mappings (other.mappings)
{
items.reserve (other.items.size ());
for (const auto &e : other.items)
items.push_back (e->clone_item ());
}
~Crate () = default;
// Overloaded assignment operator with vector clone
Crate &operator= (Crate const &other)
{
inner_attrs = other.inner_attrs;
mappings = other.mappings;
items.reserve (other.items.size ());
for (const auto &e : other.items)
items.push_back (e->clone_item ());
return *this;
}
// Move constructors
Crate (Crate &&other) = default;
Crate &operator= (Crate &&other) = default;
// Get crate representation as string (e.g. for debugging).
std::string as_string () const;
const Analysis::NodeMapping &get_mappings () const { return mappings; }
};
// Base path expression HIR node - abstract
class PathExpr : public ExprWithoutBlock
{
protected:
PathExpr (Analysis::NodeMapping mappings, AST::AttrVec outer_attribs)
: ExprWithoutBlock (std::move (mappings), std::move (outer_attribs))
{}
public:
/* Replaces the outer attributes of this path expression with the given outer
* attributes. */
void replace_outer_attrs (AST::AttrVec outer_attrs)
{
set_outer_attrs (std::move (outer_attrs));
}
ExprType get_expression_type () const final override
{
return ExprType::Path;
}
};
} // namespace HIR
} // namespace Rust
#endif