use crate::builtins::Builtin;
use derive_more::derive::From;
use rayon::prelude::*;
use solar_ast::ast;
use solar_data_structures::{
index::{Idx, IndexVec},
newtype_index, BumpExt,
};
use solar_interface::{diagnostics::ErrorGuaranteed, source_map::SourceFile, Ident, Span};
use std::{fmt, ops::ControlFlow, sync::Arc};
use strum::EnumIs;
pub use ast::{
BinOp, BinOpKind, ContractKind, DataLocation, ElementaryType, FunctionKind, Lit,
StateMutability, UnOp, UnOpKind, VarMut, Visibility,
};
pub struct Arena {
pub bump: bumpalo::Bump,
pub literals: typed_arena::Arena<Lit>,
}
impl Arena {
pub fn new() -> Self {
Self { bump: bumpalo::Bump::new(), literals: typed_arena::Arena::new() }
}
pub fn allocated_bytes(&self) -> usize {
self.bump.allocated_bytes()
+ (self.literals.len() + self.literals.uninitialized_array().len())
* std::mem::size_of::<Lit>()
}
pub fn used_bytes(&self) -> usize {
self.bump.used_bytes() + self.literals.len() * std::mem::size_of::<Lit>()
}
}
impl Default for Arena {
fn default() -> Self {
Self::new()
}
}
impl std::ops::Deref for Arena {
type Target = bumpalo::Bump;
#[inline]
fn deref(&self) -> &Self::Target {
&self.bump
}
}
#[derive(Debug)]
pub struct Hir<'hir> {
pub(crate) sources: IndexVec<SourceId, Source<'hir>>,
pub(crate) contracts: IndexVec<ContractId, Contract<'hir>>,
pub(crate) functions: IndexVec<FunctionId, Function<'hir>>,
pub(crate) structs: IndexVec<StructId, Struct<'hir>>,
pub(crate) enums: IndexVec<EnumId, Enum<'hir>>,
pub(crate) udvts: IndexVec<UdvtId, Udvt<'hir>>,
pub(crate) events: IndexVec<EventId, Event<'hir>>,
pub(crate) errors: IndexVec<ErrorId, Error<'hir>>,
pub(crate) variables: IndexVec<VariableId, Variable<'hir>>,
}
macro_rules! indexvec_methods {
($($singular:ident => $plural:ident, $id:ty => $type:ty;)*) => { paste::paste! {
$(
#[doc = "Returns the " $singular " associated with the given ID."]
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
pub fn $singular(&self, id: $id) -> &$type {
if cfg!(debug_assertions) {
&self.$plural[id]
} else {
unsafe { self.$plural.raw.get_unchecked(id.index()) }
}
}
#[doc = "Returns an iterator over all of the " $singular " IDs."]
#[inline]
pub fn [<$singular _ids>](&self) -> impl ExactSizeIterator<Item = $id> + DoubleEndedIterator + Clone {
(0..self.$plural.len()).map($id::from_usize)
}
#[doc = "Returns a parallel iterator over all of the " $singular " IDs."]
#[inline]
pub fn [<par_ $singular _ids>](&self) -> impl IndexedParallelIterator<Item = $id> {
(0..self.$plural.len()).into_par_iter().map($id::from_usize)
}
#[doc = "Returns an iterator over all of the " $singular " values."]
#[inline]
pub fn $plural(&self) -> impl ExactSizeIterator<Item = &$type> + DoubleEndedIterator + Clone {
self.$plural.raw.iter()
}
#[doc = "Returns a parallel iterator over all of the " $singular " values."]
#[inline]
pub fn [<par_ $plural>](&self) -> impl IndexedParallelIterator<Item = &$type> {
self.$plural.raw.par_iter()
}
#[doc = "Returns an iterator over all of the " $singular " IDs and their associated values."]
#[inline]
pub fn [<$plural _enumerated>](&self) -> impl ExactSizeIterator<Item = ($id, &$type)> + DoubleEndedIterator + Clone {
self.$plural().enumerate().map(|(i, v)| ($id::from_usize(i), v))
}
#[doc = "Returns an iterator over all of the " $singular " IDs and their associated values."]
#[inline]
pub fn [<par_ $plural _enumerated>](&self) -> impl IndexedParallelIterator<Item = ($id, &$type)> {
self.[<par_ $plural>]().enumerate().map(|(i, v)| ($id::from_usize(i), v))
}
)*
pub(crate) fn shrink_to_fit(&mut self) {
$(
self.$plural.shrink_to_fit();
)*
}
}};
}
impl<'hir> Hir<'hir> {
pub(crate) fn new() -> Self {
Self {
sources: IndexVec::new(),
contracts: IndexVec::new(),
functions: IndexVec::new(),
structs: IndexVec::new(),
enums: IndexVec::new(),
udvts: IndexVec::new(),
events: IndexVec::new(),
errors: IndexVec::new(),
variables: IndexVec::new(),
}
}
indexvec_methods! {
source => sources, SourceId => Source<'hir>;
contract => contracts, ContractId => Contract<'hir>;
function => functions, FunctionId => Function<'hir>;
strukt => structs, StructId => Struct<'hir>;
enumm => enums, EnumId => Enum<'hir>;
udvt => udvts, UdvtId => Udvt<'hir>;
event => events, EventId => Event<'hir>;
error => errors, ErrorId => Error<'hir>;
variable => variables, VariableId => Variable<'hir>;
}
#[inline]
pub fn item(&self, id: impl Into<ItemId>) -> Item<'_, 'hir> {
match id.into() {
ItemId::Contract(id) => Item::Contract(self.contract(id)),
ItemId::Function(id) => Item::Function(self.function(id)),
ItemId::Variable(id) => Item::Variable(self.variable(id)),
ItemId::Struct(id) => Item::Struct(self.strukt(id)),
ItemId::Enum(id) => Item::Enum(self.enumm(id)),
ItemId::Udvt(id) => Item::Udvt(self.udvt(id)),
ItemId::Error(id) => Item::Error(self.error(id)),
ItemId::Event(id) => Item::Event(self.event(id)),
}
}
pub fn item_ids(&self) -> impl DoubleEndedIterator<Item = ItemId> + Clone {
std::iter::empty::<ItemId>()
.chain(self.contract_ids().map(ItemId::Contract))
.chain(self.function_ids().map(ItemId::Function))
.chain(self.variable_ids().map(ItemId::Variable))
.chain(self.strukt_ids().map(ItemId::Struct))
.chain(self.enumm_ids().map(ItemId::Enum))
.chain(self.udvt_ids().map(ItemId::Udvt))
.chain(self.error_ids().map(ItemId::Error))
.chain(self.event_ids().map(ItemId::Event))
}
pub fn par_item_ids(&self) -> impl ParallelIterator<Item = ItemId> {
rayon::iter::empty::<ItemId>()
.chain(self.par_contract_ids().map(ItemId::Contract))
.chain(self.par_function_ids().map(ItemId::Function))
.chain(self.par_variable_ids().map(ItemId::Variable))
.chain(self.par_strukt_ids().map(ItemId::Struct))
.chain(self.par_enumm_ids().map(ItemId::Enum))
.chain(self.par_udvt_ids().map(ItemId::Udvt))
.chain(self.par_error_ids().map(ItemId::Error))
.chain(self.par_event_ids().map(ItemId::Event))
}
pub fn contract_item_ids(
&self,
id: ContractId,
) -> impl Iterator<Item = ItemId> + Clone + use<'_> {
self.contract(id)
.linearized_bases
.iter()
.copied()
.flat_map(|base| self.contract(base).items.iter().copied())
}
pub fn contract_items(&self, id: ContractId) -> impl Iterator<Item = Item<'_, 'hir>> + Clone {
self.contract_item_ids(id).map(move |id| self.item(id))
}
}
newtype_index! {
pub struct SourceId;
pub struct ContractId;
pub struct FunctionId;
pub struct StructId;
pub struct EnumId;
pub struct UdvtId;
pub struct EventId;
pub struct ErrorId;
pub struct VariableId;
}
newtype_index! {
pub struct ExprId;
}
pub struct Source<'hir> {
pub file: Arc<SourceFile>,
pub imports: &'hir [(ast::ItemId, SourceId)],
pub items: &'hir [ItemId],
}
impl fmt::Debug for Source<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Source")
.field("file", &self.file.name)
.field("imports", &self.imports)
.field("items", &self.items)
.finish()
}
}
#[derive(Clone, Copy, Debug, EnumIs)]
pub enum Item<'a, 'hir> {
Contract(&'a Contract<'hir>),
Function(&'a Function<'hir>),
Struct(&'a Struct<'hir>),
Enum(&'a Enum<'hir>),
Udvt(&'a Udvt<'hir>),
Error(&'a Error<'hir>),
Event(&'a Event<'hir>),
Variable(&'a Variable<'hir>),
}
impl<'hir> Item<'_, 'hir> {
#[inline]
pub fn name(self) -> Option<Ident> {
match self {
Item::Contract(c) => Some(c.name),
Item::Function(f) => f.name,
Item::Struct(s) => Some(s.name),
Item::Enum(e) => Some(e.name),
Item::Udvt(u) => Some(u.name),
Item::Error(e) => Some(e.name),
Item::Event(e) => Some(e.name),
Item::Variable(v) => v.name,
}
}
#[inline]
pub fn description(self) -> &'static str {
match self {
Item::Contract(c) => c.kind.to_str(),
Item::Function(f) => f.kind.to_str(),
Item::Struct(_) => "struct",
Item::Enum(_) => "enum",
Item::Udvt(_) => "UDVT",
Item::Error(_) => "error",
Item::Event(_) => "event",
Item::Variable(_) => "variable",
}
}
#[inline]
pub fn span(self) -> Span {
match self {
Item::Contract(c) => c.span,
Item::Function(f) => f.span,
Item::Struct(s) => s.span,
Item::Enum(e) => e.span,
Item::Udvt(u) => u.span,
Item::Error(e) => e.span,
Item::Event(e) => e.span,
Item::Variable(v) => v.span,
}
}
#[inline]
pub fn contract(self) -> Option<ContractId> {
match self {
Item::Contract(_) => None,
Item::Function(f) => f.contract,
Item::Struct(s) => s.contract,
Item::Enum(e) => e.contract,
Item::Udvt(u) => u.contract,
Item::Error(e) => e.contract,
Item::Event(e) => e.contract,
Item::Variable(v) => v.contract,
}
}
#[inline]
pub fn parameters(self) -> Option<&'hir [VariableId]> {
Some(match self {
Item::Struct(s) => s.fields,
Item::Function(f) => f.parameters,
Item::Event(e) => e.parameters,
Item::Error(e) => e.parameters,
_ => return None,
})
}
#[inline]
pub fn is_visible_in_derived_contracts(self) -> bool {
self.is_visible_in_contract() && self.visibility() >= Visibility::Internal
}
#[inline]
pub fn is_visible_in_contract(self) -> bool {
(if let Item::Function(f) = self {
matches!(f.kind, FunctionKind::Function | FunctionKind::Modifier)
} else {
true
}) && self.visibility() != Visibility::External
}
#[inline]
pub fn is_public(&self) -> bool {
self.visibility() >= Visibility::Public
}
#[inline]
pub fn visibility(self) -> Visibility {
match self {
Item::Variable(v) => v.visibility.unwrap_or(Visibility::Internal),
Item::Contract(_)
| Item::Function(_)
| Item::Struct(_)
| Item::Enum(_)
| Item::Udvt(_)
| Item::Error(_)
| Item::Event(_) => Visibility::Public,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, From, EnumIs)]
pub enum ItemId {
Contract(ContractId),
Function(FunctionId),
Variable(VariableId),
Struct(StructId),
Enum(EnumId),
Udvt(UdvtId),
Error(ErrorId),
Event(EventId),
}
impl fmt::Debug for ItemId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("ItemId::")?;
match self {
Self::Contract(id) => id.fmt(f),
Self::Function(id) => id.fmt(f),
Self::Variable(id) => id.fmt(f),
Self::Struct(id) => id.fmt(f),
Self::Enum(id) => id.fmt(f),
Self::Udvt(id) => id.fmt(f),
Self::Error(id) => id.fmt(f),
Self::Event(id) => id.fmt(f),
}
}
}
impl ItemId {
pub fn description(&self) -> &'static str {
match self {
Self::Contract(_) => "contract",
Self::Function(_) => "function",
Self::Variable(_) => "variable",
Self::Struct(_) => "struct",
Self::Enum(_) => "enum",
Self::Udvt(_) => "UDVT",
Self::Error(_) => "error",
Self::Event(_) => "event",
}
}
#[inline]
pub fn matches(&self, other: &Self) -> bool {
std::mem::discriminant(self) == std::mem::discriminant(other)
}
pub fn as_contract(&self) -> Option<ContractId> {
if let Self::Contract(v) = *self {
Some(v)
} else {
None
}
}
pub fn as_function(&self) -> Option<FunctionId> {
if let Self::Function(v) = *self {
Some(v)
} else {
None
}
}
pub fn as_variable(&self) -> Option<VariableId> {
if let Self::Variable(v) = *self {
Some(v)
} else {
None
}
}
}
#[derive(Debug)]
pub struct Contract<'hir> {
pub source: SourceId,
pub span: Span,
pub name: Ident,
pub kind: ContractKind,
pub bases: &'hir [ContractId],
pub linearized_bases: &'hir [ContractId],
pub ctor: Option<FunctionId>,
pub fallback: Option<FunctionId>,
pub receive: Option<FunctionId>,
pub items: &'hir [ItemId],
}
impl Contract<'_> {
pub fn functions(&self) -> impl Iterator<Item = FunctionId> + Clone + use<'_> {
self.items.iter().filter_map(ItemId::as_function)
}
pub fn all_functions(&self) -> impl Iterator<Item = FunctionId> + Clone + use<'_> {
self.functions().chain(self.ctor).chain(self.fallback).chain(self.receive)
}
pub fn variables(&self) -> impl Iterator<Item = VariableId> + Clone + use<'_> {
self.items.iter().filter_map(ItemId::as_variable)
}
pub fn can_be_deployed(&self) -> bool {
matches!(self.kind, ContractKind::Contract | ContractKind::Library)
}
pub fn is_abstract(&self) -> bool {
self.kind.is_abstract_contract()
}
}
#[derive(Debug)]
pub struct Function<'hir> {
pub source: SourceId,
pub contract: Option<ContractId>,
pub span: Span,
pub name: Option<Ident>,
pub kind: FunctionKind,
pub visibility: Visibility,
pub state_mutability: StateMutability,
pub modifiers: &'hir [ItemId],
pub marked_virtual: bool,
pub virtual_: bool,
pub override_: bool,
pub overrides: &'hir [ContractId],
pub parameters: &'hir [VariableId],
pub returns: &'hir [VariableId],
pub body: Option<Block<'hir>>,
pub gettee: Option<VariableId>,
}
impl Function<'_> {
pub fn is_free(&self) -> bool {
self.contract.is_none()
}
pub fn is_ordinary(&self) -> bool {
self.kind.is_ordinary()
}
pub fn is_getter(&self) -> bool {
self.gettee.is_some()
}
pub fn is_part_of_external_interface(&self) -> bool {
self.is_ordinary() && self.visibility >= Visibility::Public
}
pub fn variables(&self) -> impl DoubleEndedIterator<Item = VariableId> + Clone + use<'_> {
self.parameters.iter().copied().chain(self.returns.iter().copied())
}
}
#[derive(Debug)]
pub struct Struct<'hir> {
pub source: SourceId,
pub contract: Option<ContractId>,
pub span: Span,
pub name: Ident,
pub fields: &'hir [VariableId],
}
#[derive(Debug)]
pub struct Enum<'hir> {
pub source: SourceId,
pub contract: Option<ContractId>,
pub span: Span,
pub name: Ident,
pub variants: &'hir [Ident],
}
#[derive(Debug)]
pub struct Udvt<'hir> {
pub source: SourceId,
pub contract: Option<ContractId>,
pub span: Span,
pub name: Ident,
pub ty: Type<'hir>,
}
#[derive(Debug)]
pub struct Event<'hir> {
pub source: SourceId,
pub contract: Option<ContractId>,
pub span: Span,
pub name: Ident,
pub anonymous: bool,
pub parameters: &'hir [VariableId],
}
#[derive(Debug)]
pub struct EventParameter<'hir> {
pub ty: Type<'hir>,
pub indexed: bool,
pub name: Option<Ident>,
}
#[derive(Debug)]
pub struct Error<'hir> {
pub source: SourceId,
pub contract: Option<ContractId>,
pub span: Span,
pub name: Ident,
pub parameters: &'hir [VariableId],
}
#[derive(Debug)]
pub struct Variable<'hir> {
pub source: SourceId,
pub contract: Option<ContractId>,
pub span: Span,
pub ty: Type<'hir>,
pub name: Option<Ident>,
pub visibility: Option<Visibility>,
pub mutability: Option<VarMut>,
pub data_location: Option<DataLocation>,
pub override_: bool,
pub overrides: &'hir [ContractId],
pub indexed: bool,
pub initializer: Option<&'hir Expr<'hir>>,
pub is_state_variable: bool,
pub getter: Option<FunctionId>,
}
impl<'hir> Variable<'hir> {
pub fn new(ty: Type<'hir>, name: Option<Ident>) -> Self {
Self {
source: SourceId::MAX,
contract: None,
span: Span::DUMMY,
ty,
name,
visibility: None,
mutability: None,
data_location: None,
override_: false,
overrides: &[],
indexed: false,
initializer: None,
is_state_variable: false,
getter: None,
}
}
pub fn is_state_variable(&self) -> bool {
self.is_state_variable
}
pub fn is_public(&self) -> bool {
self.visibility >= Some(Visibility::Public)
}
}
pub type Block<'hir> = &'hir [Stmt<'hir>];
#[derive(Debug)]
pub struct Stmt<'hir> {
pub span: Span,
pub kind: StmtKind<'hir>,
}
#[derive(Debug)]
pub enum StmtKind<'hir> {
DeclSingle(VariableId),
DeclMulti(&'hir [Option<VariableId>], &'hir Expr<'hir>),
Block(Block<'hir>),
UncheckedBlock(Block<'hir>),
Emit(&'hir [Res], CallArgs<'hir>),
Revert(&'hir [Res], CallArgs<'hir>),
Return(Option<&'hir Expr<'hir>>),
Break,
Continue,
Loop(Block<'hir>, LoopSource),
If(&'hir Expr<'hir>, &'hir Stmt<'hir>, Option<&'hir Stmt<'hir>>),
Try(&'hir StmtTry<'hir>),
Expr(&'hir Expr<'hir>),
Placeholder,
Err(ErrorGuaranteed),
}
#[derive(Debug)]
pub struct StmtTry<'hir> {
pub expr: Expr<'hir>,
pub returns: &'hir [VariableId],
pub block: Block<'hir>,
pub catch: &'hir [CatchClause<'hir>],
}
#[derive(Debug)]
pub struct CatchClause<'hir> {
pub name: Option<Ident>,
pub args: &'hir [VariableId],
pub block: Block<'hir>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LoopSource {
For,
While,
DoWhile,
}
impl LoopSource {
pub fn name(self) -> &'static str {
match self {
Self::For => "for",
Self::While => "while",
Self::DoWhile => "do while",
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, From, Hash)]
pub enum Res {
Item(ItemId),
Namespace(SourceId),
Builtin(Builtin),
Err(ErrorGuaranteed),
}
impl fmt::Debug for Res {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Res::")?;
match self {
Self::Item(id) => write!(f, "Item({id:?})"),
Self::Namespace(id) => write!(f, "Namespace({id:?})"),
Self::Builtin(b) => write!(f, "Builtin({b:?})"),
Self::Err(_) => f.write_str("Err"),
}
}
}
macro_rules! impl_try_from {
($($t:ty => $pat:pat => $e:expr),* $(,)?) => {
$(
impl TryFrom<Res> for $t {
type Error = ();
fn try_from(decl: Res) -> Result<Self, ()> {
match decl {
$pat => $e,
_ => Err(()),
}
}
}
)*
};
}
impl_try_from!(
ItemId => Res::Item(id) => Ok(id),
ContractId => Res::Item(ItemId::Contract(id)) => Ok(id),
EventId => Res::Item(ItemId::Event(id)) => Ok(id),
ErrorId => Res::Item(ItemId::Error(id)) => Ok(id),
);
impl Res {
pub fn description(&self) -> &'static str {
match self {
Self::Item(item) => item.description(),
Self::Namespace(_) => "namespace",
Self::Builtin(_) => "builtin",
Self::Err(_) => "<error>",
}
}
pub fn matches(&self, other: &Self) -> bool {
match (self, other) {
(Self::Item(a), Self::Item(b)) => a.matches(b),
_ => std::mem::discriminant(self) == std::mem::discriminant(other),
}
}
pub fn is_err(&self) -> bool {
matches!(self, Self::Err(_))
}
}
#[derive(Debug)]
pub struct Expr<'hir> {
pub id: ExprId,
pub kind: ExprKind<'hir>,
pub span: Span,
}
impl Expr<'_> {
pub fn peel_parens(&self) -> &Self {
let mut expr = self;
while let ExprKind::Tuple([Some(inner)]) = expr.kind {
expr = inner;
}
expr
}
}
#[derive(Debug)]
pub enum ExprKind<'hir> {
Array(&'hir [Expr<'hir>]),
Assign(&'hir Expr<'hir>, Option<BinOp>, &'hir Expr<'hir>),
Binary(&'hir Expr<'hir>, BinOp, &'hir Expr<'hir>),
Call(&'hir Expr<'hir>, CallArgs<'hir>),
CallOptions(&'hir Expr<'hir>, &'hir [NamedArg<'hir>]),
Delete(&'hir Expr<'hir>),
Ident(&'hir [Res]),
Index(&'hir Expr<'hir>, Option<&'hir Expr<'hir>>),
Slice(&'hir Expr<'hir>, Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>),
Lit(&'hir Lit),
Member(&'hir Expr<'hir>, Ident),
New(Type<'hir>),
Payable(&'hir Expr<'hir>),
Ternary(&'hir Expr<'hir>, &'hir Expr<'hir>, &'hir Expr<'hir>),
Tuple(&'hir [Option<&'hir Expr<'hir>>]),
TypeCall(Type<'hir>),
Type(Type<'hir>),
Unary(UnOp, &'hir Expr<'hir>),
Err(ErrorGuaranteed),
}
#[derive(Debug)]
pub struct NamedArg<'hir> {
pub name: Ident,
pub value: Expr<'hir>,
}
#[derive(Debug)]
pub enum CallArgs<'hir> {
Unnamed(&'hir [Expr<'hir>]),
Named(&'hir [NamedArg<'hir>]),
}
impl Default for CallArgs<'_> {
fn default() -> Self {
Self::empty()
}
}
impl CallArgs<'_> {
pub fn empty() -> Self {
Self::Unnamed(Default::default())
}
}
#[derive(Clone, Debug)]
pub struct Type<'hir> {
pub span: Span,
pub kind: TypeKind<'hir>,
}
impl Type<'_> {
pub const DUMMY: Self =
Self { span: Span::DUMMY, kind: TypeKind::Err(ErrorGuaranteed::new_unchecked()) };
pub fn is_dummy(&self) -> bool {
self.span == Span::DUMMY && matches!(self.kind, TypeKind::Err(_))
}
pub fn visit<T>(&self, f: &mut impl FnMut(&Self) -> ControlFlow<T>) -> ControlFlow<T> {
f(self)?;
match self.kind {
TypeKind::Elementary(_) => ControlFlow::Continue(()),
TypeKind::Array(ty) => ty.element.visit(f),
TypeKind::Function(ty) => {
for ty in ty.parameters {
ty.visit(f)?;
}
for ty in ty.returns {
ty.visit(f)?;
}
ControlFlow::Continue(())
}
TypeKind::Mapping(ty) => {
ty.key.visit(f)?;
ty.value.visit(f)
}
TypeKind::Custom(_) => ControlFlow::Continue(()),
TypeKind::Err(_) => ControlFlow::Continue(()),
}
}
}
#[derive(Clone, Debug)]
pub enum TypeKind<'hir> {
Elementary(ElementaryType),
Array(&'hir TypeArray<'hir>),
Function(&'hir TypeFunction<'hir>),
Mapping(&'hir TypeMapping<'hir>),
Custom(ItemId),
Err(ErrorGuaranteed),
}
impl TypeKind<'_> {
pub fn is_elementary(&self) -> bool {
matches!(self, Self::Elementary(_))
}
}
#[derive(Debug)]
pub struct TypeArray<'hir> {
pub element: Type<'hir>,
pub size: Option<&'hir Expr<'hir>>,
}
#[derive(Debug)]
pub struct TypeFunction<'hir> {
pub parameters: &'hir [Type<'hir>],
pub visibility: Visibility,
pub state_mutability: StateMutability,
pub returns: &'hir [Type<'hir>],
}
#[derive(Debug)]
pub struct TypeMapping<'hir> {
pub key: Type<'hir>,
pub key_name: Option<Ident>,
pub value: Type<'hir>,
pub value_name: Option<Ident>,
}