/
item.rs
320 lines (279 loc) · 9.85 KB
/
item.rs
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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
use std::{fmt::Debug, marker::PhantomData};
use crate::private::Sealed;
use super::expr::ExprKind;
use super::{Ident, ItemId, Span};
// Item implementations
mod extern_crate_item;
pub use self::extern_crate_item::ExternCrateItem;
mod mod_item;
pub use mod_item::ModItem;
mod static_item;
pub use self::static_item::StaticItem;
mod use_item;
pub use self::use_item::*;
mod const_item;
pub use self::const_item::ConstItem;
mod fn_item;
pub use fn_item::*;
mod ty_alias_item;
pub use ty_alias_item::*;
mod adt_item;
pub use adt_item::*;
mod trait_item;
pub use trait_item::*;
mod impl_item;
pub use impl_item::*;
mod extern_block_item;
pub use extern_block_item::*;
mod unstable_item;
pub use unstable_item::*;
/// This trait combines methods, which are common between all items.
///
/// This trait is only meant to be implemented inside this crate. The `Sealed`
/// super trait prevents external implementations.
pub trait ItemData<'ast>: Debug + Sealed {
/// Returns the [`ItemId`] of this item. This is a unique identifier used for comparison
/// and to request items from the [`AstContext`](`crate::context::AstContext`).
fn id(&self) -> ItemId;
/// The [`Span`] of the entire item. This span should be used for general item related
/// diagnostics.
fn span(&self) -> &Span<'ast>;
/// The [`Visibility`] of this item.
fn visibility(&self) -> &Visibility<'ast>;
/// This function can return [`None`] if the item was generated and has no real name
fn ident(&self) -> Option<&Ident<'ast>>;
/// Returns this item wrapped in it's [`ExprKind`] variant.
///
/// In function parameters, it's recommended to use `Into<ItemKind<'ast>>`
/// as a bound to support all items and `ItemKind<'ast>` as parameters.
fn as_item(&'ast self) -> ItemKind<'ast>;
/// The attributes attached to this item.
///
/// Currently, it's only a placeholder until a proper representation is implemented.
/// rust-marker/marker#51 tracks the task of implementing this. You're welcome to
/// leave any comments in that issue.
fn attrs(&self); // FIXME: Add return type: -> &'ast [&'ast dyn Attribute<'ast>];
}
#[repr(C)]
#[non_exhaustive]
#[derive(Debug, Copy, Clone)]
pub enum ItemKind<'ast> {
Mod(&'ast ModItem<'ast>),
ExternCrate(&'ast ExternCrateItem<'ast>),
Use(&'ast UseItem<'ast>),
Static(&'ast StaticItem<'ast>),
Const(&'ast ConstItem<'ast>),
Fn(&'ast FnItem<'ast>),
TyAlias(&'ast TyAliasItem<'ast>),
Struct(&'ast StructItem<'ast>),
Enum(&'ast EnumItem<'ast>),
Union(&'ast UnionItem<'ast>),
Trait(&'ast TraitItem<'ast>),
Impl(&'ast ImplItem<'ast>),
ExternBlock(&'ast ExternBlockItem<'ast>),
Unstable(&'ast UnstableItem<'ast>),
}
impl<'ast> ItemKind<'ast> {
impl_item_type_fn!(ItemKind: id() -> ItemId);
impl_item_type_fn!(ItemKind: span() -> &Span<'ast>);
impl_item_type_fn!(ItemKind: visibility() -> &Visibility<'ast>);
impl_item_type_fn!(ItemKind: ident() -> Option<&Ident<'ast>>);
impl_item_type_fn!(ItemKind: attrs() -> ());
}
#[non_exhaustive]
#[derive(Debug)]
pub enum AssocItemKind<'ast> {
TyAlias(&'ast TyAliasItem<'ast>),
Const(&'ast ConstItem<'ast>),
Fn(&'ast FnItem<'ast>),
}
impl<'ast> AssocItemKind<'ast> {
impl_item_type_fn!(AssocItemKind: id() -> ItemId);
impl_item_type_fn!(AssocItemKind: span() -> &Span<'ast>);
impl_item_type_fn!(AssocItemKind: visibility() -> &Visibility<'ast>);
impl_item_type_fn!(AssocItemKind: ident() -> Option<&Ident<'ast>>);
impl_item_type_fn!(AssocItemKind: attrs() -> ());
impl_item_type_fn!(AssocItemKind: as_item() -> ItemKind<'ast>);
// FIXME: Potentially add a field to the items to optionally store the owner id
}
impl<'ast> From<AssocItemKind<'ast>> for ItemKind<'ast> {
fn from(value: AssocItemKind<'ast>) -> Self {
match value {
AssocItemKind::TyAlias(item) => ItemKind::TyAlias(item),
AssocItemKind::Const(item) => ItemKind::Const(item),
AssocItemKind::Fn(item) => ItemKind::Fn(item),
}
}
}
impl<'ast> TryFrom<&ItemKind<'ast>> for AssocItemKind<'ast> {
type Error = ();
fn try_from(value: &ItemKind<'ast>) -> Result<Self, Self::Error> {
match value {
ItemKind::TyAlias(item) => Ok(AssocItemKind::TyAlias(item)),
ItemKind::Const(item) => Ok(AssocItemKind::Const(item)),
ItemKind::Fn(item) => Ok(AssocItemKind::Fn(item)),
_ => Err(()),
}
}
}
#[non_exhaustive]
#[derive(Debug)]
pub enum ExternItemKind<'ast> {
Static(&'ast StaticItem<'ast>),
Fn(&'ast FnItem<'ast>),
}
impl<'ast> ExternItemKind<'ast> {
impl_item_type_fn!(ExternItemKind: id() -> ItemId);
impl_item_type_fn!(ExternItemKind: span() -> &Span<'ast>);
impl_item_type_fn!(ExternItemKind: visibility() -> &Visibility<'ast>);
impl_item_type_fn!(ExternItemKind: ident() -> Option<&Ident<'ast>>);
impl_item_type_fn!(ExternItemKind: attrs() -> ());
impl_item_type_fn!(ExternItemKind: as_item() -> ItemKind<'ast>);
}
impl<'ast> From<ExternItemKind<'ast>> for ItemKind<'ast> {
fn from(value: ExternItemKind<'ast>) -> Self {
match value {
ExternItemKind::Static(item) => ItemKind::Static(item),
ExternItemKind::Fn(item) => ItemKind::Fn(item),
}
}
}
impl<'ast> TryFrom<ItemKind<'ast>> for ExternItemKind<'ast> {
type Error = ();
fn try_from(value: ItemKind<'ast>) -> Result<Self, Self::Error> {
match value {
ItemKind::Static(item) => Ok(ExternItemKind::Static(item)),
ItemKind::Fn(item) => Ok(ExternItemKind::Fn(item)),
_ => Err(()),
}
}
}
/// Until [trait upcasting](https://github.com/rust-lang/rust/issues/65991) has been implemented
/// and stabilized we need this to call [`ItemData`] functions for [`ItemKind`].
macro_rules! impl_item_type_fn {
(ItemKind: $method:ident () -> $return_ty:ty) => {
impl_item_type_fn!((ItemKind) $method() -> $return_ty,
Mod, ExternCrate, Use, Static, Const, Fn, TyAlias, Struct, Enum,
Union, Trait, Impl, ExternBlock, Unstable
);
};
(AssocItemKind: $method:ident () -> $return_ty:ty) => {
impl_item_type_fn!((AssocItemKind) $method() -> $return_ty,
TyAlias, Const, Fn
);
};
(ExternItemKind: $method:ident () -> $return_ty:ty) => {
impl_item_type_fn!((ExternItemKind) $method() -> $return_ty,
Static, Fn
);
};
(($self:ident) $method:ident () -> $return_ty:ty $(, $item:ident)+) => {
pub fn $method(&self) -> $return_ty {
match self {
$($self::$item(data) => data.$method(),)*
}
}
};
}
use impl_item_type_fn;
#[repr(C)]
#[derive(Debug)]
#[cfg_attr(feature = "driver-api", visibility::make(pub))]
struct CommonItemData<'ast> {
id: ItemId,
vis: Visibility<'ast>,
ident: Ident<'ast>,
}
macro_rules! impl_item_data {
($self_name:ident, $enum_name:ident) => {
impl<'ast> super::ItemData<'ast> for $self_name<'ast> {
fn id(&self) -> crate::ast::item::ItemId {
self.data.id
}
fn span(&self) -> &crate::ast::Span<'ast> {
$crate::context::with_cx(self, |cx| cx.span(self.data.id))
}
fn visibility(&self) -> &crate::ast::item::Visibility<'ast> {
&self.data.vis
}
fn ident(&self) -> Option<&crate::ast::Ident<'ast>> {
Some(&self.data.ident)
}
fn as_item(&'ast self) -> crate::ast::item::ItemKind<'ast> {
$crate::ast::item::ItemKind::$enum_name(self)
}
fn attrs(&self) {}
}
impl $crate::private::Sealed for $self_name<'_> {}
impl<'ast> From<&'ast $self_name<'ast>> for crate::ast::item::ItemKind<'ast> {
fn from(value: &'ast $self_name<'ast>) -> Self {
$crate::ast::item::ItemKind::$enum_name(value)
}
}
};
}
use impl_item_data;
#[cfg(feature = "driver-api")]
impl<'ast> CommonItemData<'ast> {
pub fn new(id: ItemId, ident: Ident<'ast>) -> Self {
Self {
id,
vis: Visibility::new(id),
ident,
}
}
}
/// This struct represents the visibility of an item.
///
/// Currently, it's only a placeholder until a proper representation is implemented.
/// rust-marker/marker#26 tracks the task of implementing this. You're welcome to
/// leave any comments in that issue.
#[repr(C)]
pub struct Visibility<'ast> {
_lifetime: PhantomData<&'ast ()>,
_item_id: ItemId,
}
impl<'ast> Debug for Visibility<'ast> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Visibility {{ /* WIP: See rust-marker/marker#26 */}}")
.finish()
}
}
#[cfg(feature = "driver-api")]
impl<'ast> Visibility<'ast> {
pub fn new(item_id: ItemId) -> Self {
Self {
_lifetime: PhantomData,
_item_id: item_id,
}
}
}
/// A body represents the expression of items.
///
/// Bodies act like a barrier between the item and expression level. When items
/// are requested, only the item information is retrieved and converted. Any
/// expression parts of these items are wrapped into a body, identified via a
/// [`BodyId`](`super::BodyId`). The body and its content will only be converted
/// request.
#[repr(C)]
#[derive(Debug)]
pub struct Body<'ast> {
owner: ItemId,
expr: ExprKind<'ast>,
}
impl<'ast> Body<'ast> {
pub fn owner(&self) -> ItemId {
self.owner
}
/// The expression wrapped by this body. In most cases this will be a
/// [block expression](`crate::ast::expr::BlockExpr`).
pub fn expr(&self) -> ExprKind<'ast> {
self.expr
}
}
#[cfg(feature = "driver-api")]
impl<'ast> Body<'ast> {
pub fn new(owner: ItemId, expr: ExprKind<'ast>) -> Self {
Self { owner, expr }
}
}