marker_api/ast/
ty.rs

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