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;