1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
use std::fmt::Debug;
use std::marker::PhantomData;
use crate::span::{HasSpan, Span};
use crate::{common::SpanId, private::Sealed};
mod other_ty;
mod prim_ty;
mod ptr_ty;
mod sequence_ty;
mod trait_ty;
mod user_ty;
pub use other_ty::*;
pub use prim_ty::*;
pub use ptr_ty::*;
pub use sequence_ty::*;
pub use trait_ty::*;
pub use user_ty::*;
/// This trait combines methods, which are common between all syntactic types.
///
/// This trait is only meant to be implemented inside this crate. The `Sealed`
/// super trait prevents external implementations.
pub trait TyData<'ast>: Debug + HasSpan<'ast> + Sealed {
/// Returns `&self` wrapped in it's [`TyKind`] variant.
///
/// In function parameters, it's recommended to use `Into<SynTyKind<'ast>>`
/// as a bound to support all expressions and `SynTyKind<'ast>` as parameters.
fn as_kind(&'ast self) -> TyKind<'ast>;
}
#[repr(C)]
#[non_exhaustive]
#[derive(Debug, Copy, Clone)]
pub enum TyKind<'ast> {
// ================================
// Primitive types
// ================================
/// The `bool` type
Bool(&'ast BoolTy<'ast>),
/// A numeric type like [`u32`], [`i32`], [`f64`]
Num(&'ast NumTy<'ast>),
/// A textual type like [`char`] or [`str`]
Text(&'ast TextTy<'ast>),
/// The never type [`!`](prim@never)
Never(&'ast NeverTy<'ast>),
// ================================
// Sequence types
// ================================
/// A tuple type like [`()`](prim@tuple), [`(T, U)`](prim@tuple)
Tuple(&'ast TupleTy<'ast>),
/// An array with a known size like: [`[T; N]`](prim@array)
Array(&'ast ArrayTy<'ast>),
/// A variable length slice like [`[T]`](prim@slice)
Slice(&'ast SliceTy<'ast>),
// ================================
// Pointer types
// ================================
/// A reference like [`&T`](prim@reference) or [`&mut T`](prim@reference)
Ref(&'ast RefTy<'ast>),
/// A raw pointer like [`*const T`](prim@pointer) or [`*mut T`](prim@pointer)
RawPtr(&'ast RawPtrTy<'ast>),
/// A function pointer like [`fn (T) -> U`](prim@fn)
FnPtr(&'ast FnPtrTy<'ast>),
// ================================
// Trait types
// ================================
/// A trait object like [`dyn Trait`](https://doc.rust-lang.org/stable/std/keyword.dyn.html)
TraitObj(&'ast TraitObjTy<'ast>),
/// An [`impl Trait`](https://doc.rust-lang.org/stable/std/keyword.impl.html) type like:
///
/// ```
/// trait Trait {}
/// # impl Trait for () {}
///
/// // argument position: anonymous type parameter
/// fn foo(arg: impl Trait) {
/// }
///
/// // return position: abstract return type
/// fn bar() -> impl Trait {
/// }
/// ```
///
/// See: <https://doc.rust-lang.org/stable/reference/types/impl-trait.html>
ImplTrait(&'ast ImplTraitTy<'ast>),
// ================================
// Syntactic types
// ================================
/// An inferred type
Inferred(&'ast InferredTy<'ast>),
Path(&'ast PathTy<'ast>),
}
impl<'ast> TyKind<'ast> {
/// Returns `true` if this is a primitive type.
#[must_use]
pub fn is_primitive_ty(&self) -> bool {
matches!(self, Self::Bool(..) | Self::Num(..) | Self::Text(..) | Self::Never(..))
}
/// Returns `true` if this is a sequence type.
#[must_use]
pub fn is_sequence_ty(&self) -> bool {
matches!(self, Self::Tuple(..) | Self::Array(..) | Self::Slice(..))
}
/// Returns `true` if this is a function type.
#[must_use]
pub fn is_fn(&self) -> bool {
matches!(self, Self::FnPtr(..))
}
/// Returns `true` if this is a pointer type.
#[must_use]
pub fn is_ptr_ty(&self) -> bool {
matches!(self, Self::Ref(..) | Self::RawPtr(..) | Self::FnPtr(..))
}
/// Returns `true` if this is a trait type.
#[must_use]
pub fn is_trait_ty(&self) -> bool {
matches!(self, Self::TraitObj(..) | Self::ImplTrait(..))
}
#[must_use]
pub fn is_inferred(&self) -> bool {
matches!(self, Self::Inferred(..))
}
/// Peel off all reference types in this type until there are none left.
///
/// This method is idempotent, i.e. `ty.peel_refs().peel_refs() == ty.peel_refs()`.
///
/// # Examples
///
/// - `u8` -> `u8`
/// - `&'a mut u8` -> `u8`
/// - `&'a &'b u8` -> `u8`
/// - `&'a *const &'b u8 -> *const &'b u8`
///
/// # Acknowledgements
///
/// This method was based on rustc's internal [`peel_refs`] method.
///
/// [`peel_refs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.peel_refs
#[must_use]
pub fn peel_refs(self) -> Self {
// XXX: exactly the same `peel_refs` method exists on `sem::TyKind`.
// If you modify this method here, please check if the modifications
// should also apply to `sem::TyKind` as well.
let mut ty = self;
while let Self::Ref(ref_ty) = ty {
ty = ref_ty.inner_ty();
}
ty
}
}
impl<'ast> TyKind<'ast> {
impl_syn_ty_data_fn!(span() -> &Span<'ast>);
}
crate::span::impl_spanned_for!(TyKind<'ast>);
/// Until [trait upcasting](https://github.com/rust-lang/rust/issues/65991) has been implemented
/// and stabilized we need this to call [`SynTyData`] functions for every [`SynTyKind`].
macro_rules! impl_syn_ty_data_fn {
($method:ident () -> $return_ty:ty) => {
impl_syn_ty_data_fn!($method() -> $return_ty,
Bool, Num, Text, Never,
Tuple, Array, Slice,
Ref, RawPtr, FnPtr,
TraitObj, ImplTrait,
Inferred, Path
);
};
($method:ident () -> $return_ty:ty $(, $item:ident)+) => {
pub fn $method(&self) -> $return_ty {
match self {
$(TyKind::$item(data) => data.$method(),)*
}
}
};
}
use impl_syn_ty_data_fn;
#[repr(C)]
#[derive(Debug)]
#[cfg_attr(feature = "driver-api", visibility::make(pub))]
pub(crate) struct CommonSynTyData<'ast> {
_lifetime: PhantomData<&'ast ()>,
span: SpanId,
}
#[cfg(feature = "driver-api")]
impl<'ast> CommonSynTyData<'ast> {
pub fn new_syntactic(span: SpanId) -> Self {
Self {
_lifetime: PhantomData,
span,
}
}
}
macro_rules! impl_ty_data {
($self_ty:ty, $enum_name:ident) => {
impl<'ast> $crate::ast::ty::TyData<'ast> for $self_ty {
fn as_kind(&'ast self) -> $crate::ast::ty::TyKind<'ast> {
self.into()
}
}
$crate::span::impl_has_span_via_field!($self_ty, data.span);
impl<'ast> $crate::private::Sealed for $self_ty {}
impl<'ast> From<&'ast $self_ty> for $crate::ast::ty::TyKind<'ast> {
fn from(from: &'ast $self_ty) -> Self {
$crate::ast::ty::TyKind::$enum_name(from)
}
}
};
}
use impl_ty_data;