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}