Skip to main content

nova_ast/
item.rs

1//! Top-level item AST nodes.
2
3use nova_diagnostics::{Span, Spanned};
4
5use crate::{expr::Expr, ty::Type, Block, Path};
6
7/// Re-export from expr for convenience (AssignOp needed by callers of item).
8pub use crate::expr::AssignOp;
9
10/// An `@name` or `@name(arg, ...)` attribute on an item.
11///
12/// Arguments are bare identifiers, not expressions: the two forms the spec uses
13/// are `@test(should_panic)` and `@derive(Copy, Clone)`, both identifier lists.
14/// Widening this to expressions later is additive; narrowing it would not be.
15#[derive(Debug, Clone)]
16pub struct Attribute {
17    pub name: Spanned<String>,
18    pub args: Vec<Spanned<String>>,
19    pub span: Span,
20}
21
22/// Visibility of a declaration.
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum Visibility {
25    Pub,
26    Private,
27}
28
29/// A function parameter.
30#[derive(Debug, Clone)]
31pub struct Param {
32    pub is_mut: bool,
33    pub name: Spanned<String>,
34    pub ty: Spanned<Type>,
35}
36
37/// A `where` clause bound, e.g. `T: Display + Clone`.
38#[derive(Debug, Clone)]
39pub struct WhereBound {
40    pub ty: Spanned<Type>,
41    pub bounds: Vec<Spanned<Path>>,
42}
43
44/// A function or method declaration.
45#[derive(Debug, Clone)]
46pub struct Function {
47    /// The `///` lines before it, one entry per line, holding the text after
48    /// the `///` (spec
49    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
50    pub docs: Vec<Spanned<String>>,
51    pub attrs: Vec<Attribute>,
52    pub vis: Visibility,
53    pub is_async: bool,
54    pub name: Spanned<String>,
55    pub generics: Vec<crate::ty::TypeParam>,
56    pub params: Vec<Param>,
57    pub return_ty: Option<Spanned<Type>>,
58    pub where_clause: Vec<WhereBound>,
59    pub body: Spanned<Block>,
60}
61
62/// A `record` (struct) declaration.
63#[derive(Debug, Clone)]
64pub struct Record {
65    /// The `///` lines before it, one entry per line, holding the text after
66    /// the `///` (spec
67    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
68    pub docs: Vec<Spanned<String>>,
69    pub attrs: Vec<Attribute>,
70    pub vis: Visibility,
71    pub name: Spanned<String>,
72    pub generics: Vec<crate::ty::TypeParam>,
73    pub fields: Vec<RecordField>,
74}
75
76/// A single field inside a `record { ... }` body.
77#[derive(Debug, Clone)]
78pub struct RecordField {
79    /// The `///` lines before it, one entry per line, holding the text after
80    /// the `///` (spec
81    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
82    pub docs: Vec<Spanned<String>>,
83    pub vis: Visibility,
84    pub name: Spanned<String>,
85    pub ty: Spanned<Type>,
86}
87
88/// A `type` alias or sum type declaration.
89///
90/// ```nova
91/// type Color = | Red | Green | Blue
92/// type Alias<T> = Vec<T>
93/// ```
94#[derive(Debug, Clone)]
95pub struct TypeDecl {
96    /// The `///` lines before it, one entry per line, holding the text after
97    /// the `///` (spec
98    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
99    pub docs: Vec<Spanned<String>>,
100    pub attrs: Vec<Attribute>,
101    pub vis: Visibility,
102    pub name: Spanned<String>,
103    pub generics: Vec<crate::ty::TypeParam>,
104    pub def: TypeDef,
105}
106
107/// The right-hand side of a `type` declaration.
108#[derive(Debug, Clone)]
109pub enum TypeDef {
110    /// A plain type alias.
111    Alias(Spanned<Type>),
112    /// A sum type (algebraic data type / enum).
113    Sum(Vec<Variant>),
114}
115
116/// A variant of a sum type.
117#[derive(Debug, Clone)]
118pub struct Variant {
119    /// The `///` lines before it, one entry per line, holding the text after
120    /// the `///` (spec
121    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
122    pub docs: Vec<Spanned<String>>,
123    pub name: Spanned<String>,
124    /// Fields of a tuple-style variant, e.g. `Ok(T)` has one field.
125    pub fields: Vec<Spanned<Type>>,
126}
127
128/// A `trait` declaration.
129#[derive(Debug, Clone)]
130pub struct TraitDecl {
131    /// The `///` lines before it, one entry per line, holding the text after
132    /// the `///` (spec
133    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
134    pub docs: Vec<Spanned<String>>,
135    pub attrs: Vec<Attribute>,
136    pub vis: Visibility,
137    pub name: Spanned<String>,
138    pub generics: Vec<crate::ty::TypeParam>,
139    pub supertraits: Vec<Spanned<Path>>,
140    /// A `where` clause on the trait itself (e.g. `trait B where Self: A`), as
141    /// opposed to the `trait B: A` shorthand (stored in `supertraits`). Parsed
142    /// but not otherwise supported yet — `nova-typeck` reports `E0900` for a
143    /// non-empty clause here rather than acting on it.
144    pub where_clause: Vec<WhereBound>,
145    pub items: Vec<TraitItem>,
146}
147
148/// An item inside a trait body.
149#[derive(Debug, Clone)]
150pub enum TraitItem {
151    /// A required method (signature only).
152    Required(FunctionSig),
153    /// A provided method (with default body).
154    Provided(Function),
155    /// An associated type declaration: `type Item`.
156    ///
157    /// `bounds` is parsed (`type Item: Display`) but **not** supported —
158    /// `nova-typeck` reports `E0900` for a non-empty list, the same way a
159    /// `where` clause on a trait is parsed here and rejected there. Parsing it
160    /// gives a precise span and a real diagnostic instead of a syntax error.
161    AssocType {
162        /// The `///` lines before it, as on the items above.
163        docs: Vec<Spanned<String>>,
164        name: Spanned<String>,
165        bounds: Vec<Spanned<Path>>,
166    },
167}
168
169/// A function signature without a body.
170#[derive(Debug, Clone)]
171pub struct FunctionSig {
172    /// The `///` lines before it, one entry per line, holding the text after
173    /// the `///` (spec
174    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
175    pub docs: Vec<Spanned<String>>,
176    pub is_async: bool,
177    pub name: Spanned<String>,
178    pub generics: Vec<crate::ty::TypeParam>,
179    pub params: Vec<Param>,
180    pub return_ty: Option<Spanned<Type>>,
181    pub where_clause: Vec<WhereBound>,
182}
183
184/// An `impl` block.
185#[derive(Debug, Clone)]
186pub struct ImplBlock {
187    /// The `///` lines before it, one entry per line, holding the text after
188    /// the `///` (spec
189    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
190    pub docs: Vec<Spanned<String>>,
191    pub attrs: Vec<Attribute>,
192    pub generics: Vec<crate::ty::TypeParam>,
193    /// If `Some`, this is a trait impl: `impl Trait for Type`.
194    pub trait_: Option<Spanned<Path>>,
195    pub ty: Spanned<Type>,
196    pub where_clause: Vec<WhereBound>,
197    pub functions: Vec<Function>,
198    pub consts: Vec<ConstDecl>,
199    /// Associated types this impl binds (`type Item = Int`).
200    ///
201    /// A third parallel vector beside `functions` and `consts`, not a variant
202    /// of a shared item enum: an `ImplBlock` has never had a unified item
203    /// list, and adding one would touch every consumer of the other two.
204    pub assoc_types: Vec<AssocTypeBinding>,
205}
206
207/// One associated-type binding inside an `impl` block: `type Item = Int`.
208///
209/// There is deliberately no `vis` field. An associated-type binding is not an
210/// independently nameable item — it is only ever reached through a projection
211/// on the impl's trait, whose own visibility already governs it — so a `pub`
212/// here would be stored and honoured by nothing. `nova-parser` rejects one
213/// instead of dropping it silently.
214#[derive(Debug, Clone)]
215pub struct AssocTypeBinding {
216    /// The `///` lines before it, one entry per line, holding the text after
217    /// the `///` (spec
218    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
219    pub docs: Vec<Spanned<String>>,
220    pub name: Spanned<String>,
221    pub ty: Spanned<Type>,
222}
223
224/// A `const` declaration.
225#[derive(Debug, Clone)]
226pub struct ConstDecl {
227    /// The `///` lines before it, one entry per line, holding the text after
228    /// the `///` (spec
229    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
230    pub docs: Vec<Spanned<String>>,
231    pub attrs: Vec<Attribute>,
232    pub vis: Visibility,
233    pub name: Spanned<String>,
234    pub ty: Spanned<Type>,
235    pub value: Spanned<Expr>,
236}
237
238/// An `import` declaration.
239#[derive(Debug, Clone)]
240pub struct Import {
241    /// The `///` lines before it, one entry per line, holding the text after
242    /// the `///` (spec
243    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
244    pub docs: Vec<Spanned<String>>,
245    pub attrs: Vec<Attribute>,
246    pub path: Spanned<Path>,
247    pub kind: ImportKind,
248}
249
250/// How an import is bound into the current namespace.
251#[derive(Debug, Clone)]
252pub enum ImportKind {
253    /// `import foo` — binds the last segment name.
254    Simple,
255    /// `import foo as bar` — binds under an alias.
256    Alias(Spanned<String>),
257    /// `import foo::{a, b, c}` — destructures selected names.
258    List(Vec<Spanned<String>>),
259}
260
261/// A `module` declaration (refers to another file).
262#[derive(Debug, Clone)]
263pub struct Module {
264    /// The `///` lines before it, one entry per line, holding the text after
265    /// the `///` (spec
266    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
267    pub docs: Vec<Spanned<String>>,
268    pub attrs: Vec<Attribute>,
269    pub path: Spanned<Path>,
270}
271
272/// An `extern` block for FFI declarations.
273#[derive(Debug, Clone)]
274pub struct ExternBlock {
275    /// The `///` lines before it, one entry per line, holding the text after
276    /// the `///` (spec
277    /// `docs/superpowers/specs/2026-10-07-phase-3-1-formatter-design.md` §4).
278    pub docs: Vec<Spanned<String>>,
279    pub attrs: Vec<Attribute>,
280    pub abi: Option<String>,
281    pub items: Vec<ExternItem>,
282}
283
284/// An item inside an `extern` block.
285#[derive(Debug, Clone)]
286pub enum ExternItem {
287    Fn(FunctionSig),
288}