Skip to main content

kotlin_codegen/
model.rs

1//! Declaration model: [`KtFile`] → [`KtDecl`] (classes, functions,
2//! properties, type aliases, raw blocks). Chained builders throughout.
3//! Rendering lives in [`super::render`]; this module is pure data.
4
5use super::{code::KtCode, slot::KtPropertyValue, types::KtType};
6
7/// Visibility modifier. `Public` renders explicitly (matching the existing
8/// generated style); `Default` renders nothing.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
10pub enum KtVis {
11    #[default]
12    Default,
13    Public,
14    Internal,
15    Private,
16}
17
18impl KtVis {
19    pub(crate) fn prefix(self) -> &'static str {
20        match self {
21            KtVis::Default => "",
22            KtVis::Public => "public ",
23            KtVis::Internal => "internal ",
24            KtVis::Private => "private ",
25        }
26    }
27}
28
29/// One Kotlin source file fragment: a package plus top-level declarations.
30/// Fragments of the same package are merged by [`super::file::merge_files`].
31#[derive(Clone, Debug)]
32pub struct KtFile {
33    pub package: String,
34    pub decls: Vec<KtDecl>,
35    /// FQNs referenced only inside raw text the model can't see (e.g. body
36    /// strings built with pre-shortened type names). Registered into the
37    /// file's import set before any declaration renders.
38    pub extra_imports: Vec<String>,
39    /// Override the banner line prepended to the rendered file.
40    /// `None` uses the default banner constant from the renderer. `Some("")` suppresses it.
41    pub banner: Option<String>,
42}
43
44impl KtFile {
45    pub fn new(package: impl Into<String>) -> Self {
46        Self {
47            package: package.into(),
48            decls: Vec::new(),
49            extra_imports: Vec::new(),
50            banner: None,
51        }
52    }
53
54    /// Override the banner comment prepended to the rendered file.
55    /// Pass `""` to suppress the banner entirely.
56    pub fn banner(mut self, text: impl Into<String>) -> Self {
57        self.banner = Some(text.into());
58        self
59    }
60
61    pub fn decl(mut self, d: impl Into<KtDecl>) -> Self {
62        self.decls.push(d.into());
63        self
64    }
65
66    /// Register an FQN referenced only inside raw text.
67    pub fn import(mut self, fqn: impl Into<String>) -> Self {
68        self.extra_imports.push(fqn.into());
69        self
70    }
71
72    pub fn imports(mut self, fqns: impl IntoIterator<Item = String>) -> Self {
73        self.extra_imports.extend(fqns);
74        self
75    }
76}
77
78/// A top-level (or member-level, for `Raw`) declaration.
79#[derive(Clone, Debug)]
80pub enum KtDecl {
81    Class(KtClass),
82    Fun(KtFun),
83    FunInterface(KtFunInterface),
84    Property(KtProperty),
85    TypeAlias {
86        vis: KtVis,
87        name: String,
88        target: KtType,
89    },
90    /// Pre-rendered code at declaration position. `name` is the identity
91    /// used for duplicate detection during merge.
92    Raw {
93        name: String,
94        code: KtCode,
95    },
96}
97
98impl KtDecl {
99    /// Identity for duplicate detection within a merged package.
100    pub fn name(&self) -> &str {
101        match self {
102            KtDecl::Class(c) => &c.name,
103            KtDecl::Fun(f) => &f.name,
104            KtDecl::FunInterface(i) => &i.name,
105            KtDecl::Property(p) => &p.name,
106            KtDecl::TypeAlias { name, .. } => name,
107            KtDecl::Raw { name, .. } => name,
108        }
109    }
110}
111
112impl From<KtClass> for KtDecl {
113    fn from(c: KtClass) -> Self {
114        KtDecl::Class(c)
115    }
116}
117impl From<KtFunInterface> for KtDecl {
118    fn from(i: KtFunInterface) -> Self {
119        KtDecl::FunInterface(i)
120    }
121}
122impl From<KtFun> for KtDecl {
123    fn from(f: KtFun) -> Self {
124        KtDecl::Fun(f)
125    }
126}
127impl From<KtProperty> for KtDecl {
128    fn from(p: KtProperty) -> Self {
129        KtDecl::Property(p)
130    }
131}
132
133/// A function *signature*: everything a [`KtFun`] has except a body and
134/// modifiers.
135///
136/// This is what an abstract member is — a `fun interface`'s single method, an
137/// interface member, an abstract class member. Having no body field at all is
138/// what makes a bodied SAM method unrepresentable: a `fun interface` whose one
139/// method has a body has no abstract method, and does not compile.
140///
141/// Converts into [`KtFun`] (with [`KtBody::None`]) and so into [`KtDecl`], for
142/// use as an interface member; [`KtFun::signature`] goes the other way.
143#[derive(Clone, Debug)]
144pub struct KtFunSig {
145    pub name: String,
146    pub vis: KtVis,
147    pub annotations: Vec<String>,
148    pub kdoc: Option<String>,
149    /// Generic type-variable names: `["R"]` → `fun <R> …`.
150    pub generics: Vec<String>,
151    /// Extension receiver: `Some(Foo)` → `fun Foo.name(…)`. A separate field
152    /// rather than part of `name`, so `name` stays a plain identifier that can
153    /// be checked as one.
154    pub receiver: Option<KtType>,
155    pub params: Vec<KtParam>,
156    pub ret: Option<KtType>,
157}
158
159impl KtFunSig {
160    pub fn new(name: impl Into<String>) -> Self {
161        Self {
162            name: name.into(),
163            vis: KtVis::Default,
164            annotations: Vec::new(),
165            kdoc: None,
166            generics: Vec::new(),
167            receiver: None,
168            params: Vec::new(),
169            ret: None,
170        }
171    }
172    pub fn vis(mut self, v: KtVis) -> Self {
173        self.vis = v;
174        self
175    }
176    /// Make this an extension function on `ty`: `fun <R> Foo<R>.name(…)`.
177    pub fn receiver(mut self, ty: KtType) -> Self {
178        self.receiver = Some(ty);
179        self
180    }
181    pub fn annotation(mut self, a: impl Into<String>) -> Self {
182        self.annotations.push(a.into());
183        self
184    }
185    pub fn kdoc(mut self, d: impl Into<String>) -> Self {
186        self.kdoc = Some(d.into());
187        self
188    }
189    pub fn generic(mut self, g: impl Into<String>) -> Self {
190        self.generics.push(g.into());
191        self
192    }
193    pub fn param(mut self, p: KtParam) -> Self {
194        self.params.push(p);
195        self
196    }
197    pub fn returns(mut self, ty: KtType) -> Self {
198        self.ret = Some(ty);
199        self
200    }
201}
202
203impl From<KtFunSig> for KtFun {
204    /// A signature as a body-less function — an abstract member.
205    fn from(s: KtFunSig) -> Self {
206        KtFun {
207            name: s.name,
208            vis: s.vis,
209            modifiers: Vec::new(),
210            annotations: s.annotations,
211            kdoc: s.kdoc,
212            generics: s.generics,
213            receiver: s.receiver,
214            params: s.params,
215            ret: s.ret,
216            body: KtBody::None,
217        }
218    }
219}
220
221impl From<KtFunSig> for KtDecl {
222    fn from(s: KtFunSig) -> Self {
223        KtDecl::Fun(s.into())
224    }
225}
226
227/// A `fun interface` (SAM) declaration: exactly one abstract method.
228///
229/// The method is a [`KtFunSig`], so it cannot carry a body; its JNI-callable
230/// JVM name is the method's `name` verbatim — keep the interface and the
231/// method `public` and its params free of `@JvmInline` value classes, or
232/// Kotlin mangles the JVM method name and native `GetMethodID` fails at
233/// runtime.
234#[derive(Clone, Debug)]
235pub struct KtFunInterface {
236    pub vis: KtVis,
237    pub name: String,
238    /// Type parameters with variance as written, e.g. `["out R"]`.
239    pub type_params: Vec<String>,
240    pub kdoc: Option<String>,
241    /// The single abstract method.
242    pub method: KtFunSig,
243}
244
245impl KtFunInterface {
246    pub fn new(name: impl Into<String>, method: KtFunSig) -> Self {
247        Self {
248            vis: KtVis::Default,
249            name: name.into(),
250            type_params: Vec::new(),
251            kdoc: None,
252            method,
253        }
254    }
255    pub fn vis(mut self, v: KtVis) -> Self {
256        self.vis = v;
257        self
258    }
259    pub fn type_param(mut self, p: impl Into<String>) -> Self {
260        self.type_params.push(p.into());
261        self
262    }
263    pub fn kdoc(mut self, d: impl Into<String>) -> Self {
264        self.kdoc = Some(d.into());
265        self
266    }
267}
268
269/// The modifier a `class` carries, if any.
270#[derive(Clone, Copy, Debug, PartialEq, Eq)]
271pub enum KtClassModifier {
272    Abstract,
273    Open,
274    Sealed,
275}
276
277/// The kind of class-like declaration, carrying whatever that kind — and only
278/// that kind — can hold.
279///
280/// Primary-constructor parameters live here rather than on [`KtClass`] so the
281/// shapes Kotlin rejects cannot be built at all: an `object` has no field to
282/// put them in, a `value class` holds exactly one, and a `data class` is
283/// constructed with at least one.
284#[derive(Clone, Debug)]
285pub enum KtClassKind {
286    /// `class` / `abstract class` / `open class` / `sealed class`.
287    Class {
288        modifier: Option<KtClassModifier>,
289        ctor: Vec<KtCtorParam>,
290    },
291    /// `data class` — Kotlin requires at least one constructor property, which
292    /// [`KtClass::data`] takes.
293    Data {
294        ctor: Vec<KtCtorParam>,
295    },
296    /// `@JvmInline value class` (the annotation is added by the renderer) —
297    /// exactly one property.
298    Value {
299        field: Box<KtCtorParam>,
300    },
301    /// `enum class` with its entries and an optional primary constructor the
302    /// entries pass arguments to.
303    Enum {
304        ctor: Vec<KtCtorParam>,
305        entries: Vec<KtEnumEntry>,
306    },
307    Object,
308    /// A plain `interface` — members with no body render as abstract
309    /// signatures.
310    Interface,
311    /// A `sealed interface` — an exhaustive set of alternatives whose
312    /// implementations are nested inside it as [`Self::Data`] classes and
313    /// [`Self::DataObject`]s.
314    SealedInterface,
315    /// A `data object` — the singleton counterpart of a `data class`, for an
316    /// alternative that carries no payload.
317    DataObject,
318}
319
320impl KtClassKind {
321    /// The primary-constructor parameters this kind carries — empty for the
322    /// kinds that have no primary constructor.
323    pub fn ctor_params(&self) -> &[KtCtorParam] {
324        match self {
325            KtClassKind::Class { ctor, .. }
326            | KtClassKind::Data { ctor }
327            | KtClassKind::Enum { ctor, .. } => ctor,
328            KtClassKind::Value { field } => std::slice::from_ref(field),
329            KtClassKind::Object
330            | KtClassKind::Interface
331            | KtClassKind::SealedInterface
332            | KtClassKind::DataObject => &[],
333        }
334    }
335
336    /// The entries of an `enum class`; empty for every other kind.
337    pub fn entries(&self) -> &[KtEnumEntry] {
338        match self {
339            KtClassKind::Enum { entries, .. } => entries,
340            _ => &[],
341        }
342    }
343
344    /// The Kotlin keyword(s) introducing this kind.
345    pub(crate) fn keyword(&self) -> &'static str {
346        match self {
347            KtClassKind::Class { modifier: None, .. } => "class",
348            KtClassKind::Class {
349                modifier: Some(KtClassModifier::Abstract),
350                ..
351            } => "abstract class",
352            KtClassKind::Class {
353                modifier: Some(KtClassModifier::Open),
354                ..
355            } => "open class",
356            KtClassKind::Class {
357                modifier: Some(KtClassModifier::Sealed),
358                ..
359            } => "sealed class",
360            KtClassKind::Data { .. } => "data class",
361            KtClassKind::Enum { .. } => "enum class",
362            KtClassKind::Value { .. } => "value class",
363            KtClassKind::Object => "object",
364            KtClassKind::Interface => "interface",
365            KtClassKind::SealedInterface => "sealed interface",
366            KtClassKind::DataObject => "data object",
367        }
368    }
369}
370
371#[derive(Clone, Debug)]
372pub struct KtEnumEntry {
373    pub name: String,
374    /// Constructor arguments as raw Kotlin text: `NAME(0)`.
375    pub args: Option<KtCode>,
376}
377
378impl KtEnumEntry {
379    /// An entry with no constructor arguments.
380    pub fn new(name: impl Into<String>) -> Self {
381        Self {
382            name: name.into(),
383            args: None,
384        }
385    }
386    /// An entry with constructor arguments as raw Kotlin text.
387    pub fn with_args(name: impl Into<String>, args: impl Into<String>) -> Self {
388        Self {
389            name: name.into(),
390            args: Some(KtCode::new().line(args.into())),
391        }
392    }
393}
394
395/// Primary-constructor parameter, optionally a `val`/`var` property.
396#[derive(Clone, Debug)]
397pub struct KtCtorParam {
398    pub name: String,
399    pub ty: KtType,
400    /// `None` = plain ctor param; `Some(false)` = `val`, `Some(true)` = `var`.
401    pub prop: Option<bool>,
402    /// Render the `override` modifier (`override val id: Long`) — the
403    /// property implements an abstract of a supertype interface.
404    pub overrides: bool,
405    pub vis: KtVis,
406    pub default: Option<KtCode>,
407    pub annotations: Vec<String>,
408}
409
410impl KtCtorParam {
411    pub fn new(name: impl Into<String>, ty: KtType) -> Self {
412        Self {
413            name: name.into(),
414            ty,
415            prop: None,
416            overrides: false,
417            vis: KtVis::Default,
418            default: None,
419            annotations: Vec::new(),
420        }
421    }
422    pub fn val(mut self) -> Self {
423        self.prop = Some(false);
424        self
425    }
426    /// Mark the property as overriding a supertype-interface abstract.
427    pub fn overrides(mut self) -> Self {
428        self.overrides = true;
429        self
430    }
431    pub fn var(mut self) -> Self {
432        self.prop = Some(true);
433        self
434    }
435    pub fn vis(mut self, v: KtVis) -> Self {
436        self.vis = v;
437        self
438    }
439    pub fn default(mut self, d: impl Into<String>) -> Self {
440        self.default = Some(KtCode::new().line(d.into()));
441        self
442    }
443    pub fn annotation(mut self, a: impl Into<String>) -> Self {
444        self.annotations.push(a.into());
445        self
446    }
447}
448
449/// The one superclass a class may construct: `: NativeHandle(initialPtr)`.
450#[derive(Clone, Debug)]
451pub struct KtSuperclass {
452    pub ty: KtType,
453    /// Constructor arguments. `None` renders a bare `: NativeHandle`, which is
454    /// what a subclass with no primary constructor writes — it delegates from
455    /// its secondary constructors instead.
456    pub args: Option<KtCode>,
457}
458
459/// What a class extends and implements.
460///
461/// Kotlin lets a class construct **at most one** superclass and implement any
462/// number of interfaces. Keeping those apart — rather than in one list where
463/// any element may carry constructor arguments — makes `class A : B(x), C(y)`
464/// unrepresentable.
465#[derive(Clone, Debug, Default)]
466pub struct KtSupertypes {
467    pub superclass: Option<KtSuperclass>,
468    /// Implemented interfaces; never constructed.
469    pub interfaces: Vec<KtType>,
470}
471
472impl KtSupertypes {
473    /// Every supertype in render order: the superclass first, then interfaces.
474    pub fn iter(&self) -> impl Iterator<Item = (&KtType, Option<&KtCode>)> {
475        self.superclass
476            .iter()
477            .map(|s| (&s.ty, s.args.as_ref()))
478            .chain(self.interfaces.iter().map(|t| (t, None)))
479    }
480
481    pub fn is_empty(&self) -> bool {
482        self.superclass.is_none() && self.interfaces.is_empty()
483    }
484
485    /// # Panics
486    ///
487    /// If a superclass is already set. Kotlin permits at most one, so a second
488    /// call is a generator bug — and silently replacing the first would lose a
489    /// supertype the caller meant to keep.
490    fn set_superclass(&mut self, ty: KtType, args: Option<&str>, what: &str) {
491        if let Some(existing) = &self.superclass {
492            panic!(
493                "{what} already extends `{}`; Kotlin allows only one superclass \
494                 (use `implements` for interfaces)",
495                existing.ty
496            );
497        }
498        self.superclass = Some(KtSuperclass {
499            ty,
500            args: args.map(|s| KtCode::new().line(s.to_string())),
501        });
502    }
503}
504
505/// A `companion object`.
506///
507/// Its own type rather than a [`KtClassKind`] variant, because a companion is
508/// only meaningful inside a class body: reachable solely as
509/// [`KtClass::companion`], it cannot be built as a top-level declaration.
510///
511/// A companion has no primary constructor, so — unlike the [`KtClass`] it used
512/// to borrow its shape from — there is nowhere to put constructor parameters.
513///
514/// There is no `impl Into<KtDecl>`, so a companion cannot reach a declaration
515/// position at all:
516///
517/// ```compile_fail
518/// use kotlin_codegen::{KtCompanion, KtFile};
519/// // `companion object` is meaningless at file level — and unbuildable.
520/// let _ = KtFile::new("io.p").decl(KtCompanion::new());
521/// ```
522#[derive(Clone, Debug, Default)]
523pub struct KtCompanion {
524    /// `None` renders the anonymous form `companion object { … }` (Kotlin names
525    /// it `Companion` implicitly). `Some(n)` renders `companion object n { … }`,
526    /// which an emitter needs when the implicit `Companion` would collide with
527    /// a sibling declaration.
528    pub name: Option<String>,
529    pub vis: KtVis,
530    pub kdoc: Option<String>,
531    pub annotations: Vec<String>,
532    /// What the companion extends and implements.
533    pub supertypes: KtSupertypes,
534    pub members: Vec<KtDecl>,
535}
536
537impl KtCompanion {
538    /// An anonymous `companion object`.
539    pub fn new() -> Self {
540        Self::default()
541    }
542    /// A named `companion object Factory { … }`.
543    ///
544    /// # Panics
545    ///
546    /// On an empty name, which would render as `companion object ` with a
547    /// dangling space. [`KtCompanion::new`] is the anonymous form.
548    pub fn named(name: impl Into<String>) -> Self {
549        let name = name.into();
550        assert!(
551            !name.is_empty(),
552            "a companion object's name cannot be empty — use `KtCompanion::new()` \
553             for the anonymous form"
554        );
555        Self {
556            name: Some(name),
557            ..Self::default()
558        }
559    }
560    pub fn vis(mut self, v: KtVis) -> Self {
561        self.vis = v;
562        self
563    }
564    pub fn kdoc(mut self, d: impl Into<String>) -> Self {
565        self.kdoc = Some(d.into());
566        self
567    }
568    pub fn annotation(mut self, a: impl Into<String>) -> Self {
569        self.annotations.push(a.into());
570        self
571    }
572    /// Set the one superclass this companion extends. Kotlin allows a
573    /// companion object to extend a class, the same as any other object.
574    ///
575    /// # Panics
576    ///
577    /// If a superclass is already set — see [`KtClass::extends`].
578    pub fn extends(mut self, ty: KtType, args: Option<&str>) -> Self {
579        self.supertypes.set_superclass(ty, args, "companion object");
580        self
581    }
582
583    /// Implement an interface.
584    pub fn implements(mut self, ty: KtType) -> Self {
585        self.supertypes.interfaces.push(ty);
586        self
587    }
588    pub fn member(mut self, d: impl Into<KtDecl>) -> Self {
589        self.members.push(d.into());
590        self
591    }
592}
593
594fn describe_prop(prop: Option<bool>) -> &'static str {
595    match prop {
596        None => "a plain constructor parameter",
597        Some(false) => "a `val`",
598        Some(true) => "a `var`",
599    }
600}
601
602/// Every primary-constructor parameter of a `data class` must be a property.
603fn assert_data_property(p: &KtCtorParam) {
604    assert!(
605        p.prop.is_some(),
606        "every `data class` constructor parameter must be a property, but `{}` is {} — \
607         call `.val()` or `.var()` on it",
608        p.name,
609        describe_prop(p.prop),
610    );
611}
612
613/// A class / object / enum / data / value-class declaration.
614#[derive(Clone, Debug)]
615pub struct KtClass {
616    /// The kind, carrying this kind's primary constructor and enum entries.
617    pub kind: KtClassKind,
618    pub name: String,
619    pub vis: KtVis,
620    pub annotations: Vec<String>,
621    pub kdoc: Option<String>,
622    /// What the class extends and implements.
623    pub supertypes: KtSupertypes,
624    pub members: Vec<KtDecl>,
625    /// Boxed to keep [`KtClass`] — and so `KtDecl::Class`, the largest
626    /// variant of an enum whose others are half the size — from carrying a
627    /// companion's 232 bytes inline in every class that has none.
628    pub companion: Option<Box<KtCompanion>>,
629}
630
631impl KtClass {
632    pub fn new(kind: KtClassKind, name: impl Into<String>) -> Self {
633        Self {
634            kind,
635            name: name.into(),
636            vis: KtVis::Default,
637            annotations: Vec::new(),
638            kdoc: None,
639            supertypes: KtSupertypes::default(),
640            members: Vec::new(),
641            companion: None,
642        }
643    }
644
645    /// A plain `class` with no primary-constructor parameters yet — add them
646    /// with [`KtClass::ctor_param`].
647    pub fn class_(name: impl Into<String>) -> Self {
648        Self::new(
649            KtClassKind::Class {
650                modifier: None,
651                ctor: Vec::new(),
652            },
653            name,
654        )
655    }
656    /// A `class` carrying `abstract` / `open` / `sealed`.
657    pub fn class_with(modifier: KtClassModifier, name: impl Into<String>) -> Self {
658        Self::new(
659            KtClassKind::Class {
660                modifier: Some(modifier),
661                ctor: Vec::new(),
662            },
663            name,
664        )
665    }
666    /// A `data class`. Kotlin requires at least one constructor property, so
667    /// the first is mandatory here; add more with [`KtClass::ctor_param`].
668    ///
669    /// # Panics
670    ///
671    /// If `first` is not a `val`/`var`. Every primary-constructor parameter of
672    /// a `data class` must be a property — a plain parameter is a compile
673    /// error, not a stylistic choice.
674    pub fn data(name: impl Into<String>, first: KtCtorParam) -> Self {
675        assert_data_property(&first);
676        Self::new(KtClassKind::Data { ctor: vec![first] }, name)
677    }
678    /// A `@JvmInline value class` wrapping exactly one property.
679    ///
680    /// # Panics
681    ///
682    /// If `field` is not a `val`. A value class wraps a single *read-only*
683    /// property; `var` and plain parameters are both rejected by Kotlin.
684    pub fn value(name: impl Into<String>, field: KtCtorParam) -> Self {
685        assert!(
686            field.prop == Some(false),
687            "`value class` wraps a single read-only property, but `{}` is {} — \
688             call `.val()` on it",
689            field.name,
690            describe_prop(field.prop),
691        );
692        Self::new(
693            KtClassKind::Value {
694                field: Box::new(field),
695            },
696            name,
697        )
698    }
699    /// An `enum class` with no entries yet — add them with [`KtClass::entry`].
700    pub fn enum_(name: impl Into<String>) -> Self {
701        Self::new(
702            KtClassKind::Enum {
703                ctor: Vec::new(),
704                entries: Vec::new(),
705            },
706            name,
707        )
708    }
709    pub fn object_(name: impl Into<String>) -> Self {
710        Self::new(KtClassKind::Object, name)
711    }
712    pub fn data_object(name: impl Into<String>) -> Self {
713        Self::new(KtClassKind::DataObject, name)
714    }
715    pub fn interface_(name: impl Into<String>) -> Self {
716        Self::new(KtClassKind::Interface, name)
717    }
718    pub fn sealed_interface(name: impl Into<String>) -> Self {
719        Self::new(KtClassKind::SealedInterface, name)
720    }
721    /// The primary-constructor parameters, whichever kind holds them.
722    pub fn ctor_params(&self) -> &[KtCtorParam] {
723        self.kind.ctor_params()
724    }
725
726    pub fn vis(mut self, v: KtVis) -> Self {
727        self.vis = v;
728        self
729    }
730    pub fn annotation(mut self, a: impl Into<String>) -> Self {
731        self.annotations.push(a.into());
732        self
733    }
734    pub fn kdoc(mut self, d: impl Into<String>) -> Self {
735        self.kdoc = Some(d.into());
736        self
737    }
738    /// Append a primary-constructor parameter.
739    ///
740    /// # Panics
741    ///
742    /// If this kind has no primary constructor (`object`, `data object`,
743    /// `interface`, `sealed interface`) or holds a fixed
744    /// number of parameters (`value class` — pass its one property to
745    /// [`KtClass::value`]). Both are generator bugs that would otherwise
746    /// render as Kotlin that does not compile.
747    pub fn ctor_param(mut self, p: KtCtorParam) -> Self {
748        if matches!(self.kind, KtClassKind::Data { .. }) {
749            assert_data_property(&p);
750        }
751        match &mut self.kind {
752            KtClassKind::Class { ctor, .. }
753            | KtClassKind::Data { ctor }
754            | KtClassKind::Enum { ctor, .. } => ctor.push(p),
755            other => panic!(
756                "`{}` has no primary constructor to add parameter `{}` to",
757                other.keyword(),
758                p.name
759            ),
760        }
761        self
762    }
763
764    /// Append an entry to an `enum class`.
765    ///
766    /// # Panics
767    ///
768    /// If this kind is not [`KtClassKind::Enum`].
769    pub fn entry(mut self, e: KtEnumEntry) -> Self {
770        match &mut self.kind {
771            KtClassKind::Enum { entries, .. } => entries.push(e),
772            other => panic!(
773                "`{}` is not an enum class; cannot add entry `{}`",
774                other.keyword(),
775                e.name
776            ),
777        }
778        self
779    }
780    /// Set the one superclass this class constructs: `: NativeHandle(args)`.
781    /// `args` of `None` renders a bare `: NativeHandle`.
782    ///
783    /// # Panics
784    ///
785    /// If a superclass is already set. Kotlin permits at most one, so a second
786    /// call is a generator bug — and silently replacing the first would lose a
787    /// supertype the caller meant to keep.
788    pub fn extends(mut self, ty: KtType, args: Option<&str>) -> Self {
789        let what = format!("class `{}`", self.name);
790        self.supertypes.set_superclass(ty, args, &what);
791        self
792    }
793
794    /// Implement an interface. Any number are allowed.
795    pub fn implements(mut self, ty: KtType) -> Self {
796        self.supertypes.interfaces.push(ty);
797        self
798    }
799    pub fn member(mut self, d: impl Into<KtDecl>) -> Self {
800        self.members.push(d.into());
801        self
802    }
803    pub fn companion(mut self, c: KtCompanion) -> Self {
804        self.companion = Some(Box::new(c));
805        self
806    }
807}
808
809/// A function body — or the reason there isn't one.
810#[derive(Clone, Debug, Default)]
811pub enum KtBody {
812    /// No body because the function is abstract. Whether that is legal is
813    /// *positional* — an `interface` member needs no keyword, an abstract
814    /// class member does — which no type here can capture, so this one stays
815    /// a validated case rather than a guaranteed one.
816    #[default]
817    None,
818    /// Single-expression body: `= <expr>`.
819    Expr(KtCode),
820    /// Block body: `{ … }`.
821    Block(KtCode),
822    /// `external fun f()` — implemented natively, so no body *by definition*.
823    /// Being a body variant rather than a modifier keyword is what makes
824    /// `external fun f() { … }` unrepresentable.
825    External,
826}
827
828/// A function declaration (top-level or member).
829#[derive(Clone, Debug)]
830pub struct KtFun {
831    pub name: String,
832    pub vis: KtVis,
833    /// Modifier keywords in render order, e.g. `external`, `inline`,
834    /// `override`, `abstract`, `operator`.
835    pub modifiers: Vec<String>,
836    pub annotations: Vec<String>,
837    pub kdoc: Option<String>,
838    /// Generic type-variable names: `["R"]` → `fun <R> …`.
839    pub generics: Vec<String>,
840    /// Extension receiver: `Some(Foo)` → `fun Foo.name(…)`. See
841    /// [`KtFunSig::receiver`].
842    pub receiver: Option<KtType>,
843    pub params: Vec<KtParam>,
844    pub ret: Option<KtType>,
845    pub body: KtBody,
846}
847
848impl KtFun {
849    pub fn new(name: impl Into<String>) -> Self {
850        Self {
851            name: name.into(),
852            vis: KtVis::Default,
853            modifiers: Vec::new(),
854            annotations: Vec::new(),
855            kdoc: None,
856            generics: Vec::new(),
857            receiver: None,
858            params: Vec::new(),
859            ret: None,
860            body: KtBody::None,
861        }
862    }
863
864    pub fn vis(mut self, v: KtVis) -> Self {
865        self.vis = v;
866        self
867    }
868    /// Make this an extension function on `ty`: `fun <R> Foo<R>.name(…)`.
869    pub fn receiver(mut self, ty: KtType) -> Self {
870        self.receiver = Some(ty);
871        self
872    }
873    /// Add a modifier keyword (`override`, `inline`, `operator`, …).
874    ///
875    /// # Panics
876    ///
877    /// On `"external"` — it is a body kind, not a modifier, so that it cannot
878    /// be combined with one. Use [`KtFun::external`].
879    pub fn modifier(mut self, m: impl Into<String>) -> Self {
880        let m = m.into();
881        // A modifier string may hold several keywords ("final override"), so
882        // check each word — `"external "` and `"external inline"` would
883        // otherwise render the keyword and reopen the hole this closes.
884        assert!(
885            !m.split_whitespace().any(|w| w == "external"),
886            "`external` is not a modifier here — use `KtFun::external()`, which \
887             also rules out giving the function a body"
888        );
889        self.modifiers.push(m);
890        self
891    }
892    pub fn annotation(mut self, a: impl Into<String>) -> Self {
893        self.annotations.push(a.into());
894        self
895    }
896    pub fn kdoc(mut self, d: impl Into<String>) -> Self {
897        self.kdoc = Some(d.into());
898        self
899    }
900    pub fn generic(mut self, g: impl Into<String>) -> Self {
901        self.generics.push(g.into());
902        self
903    }
904    pub fn param(mut self, p: KtParam) -> Self {
905        self.params.push(p);
906        self
907    }
908    pub fn returns(mut self, ty: KtType) -> Self {
909        self.ret = Some(ty);
910        self
911    }
912    pub fn body(mut self, c: KtCode) -> Self {
913        self.body = KtBody::Block(c);
914        self
915    }
916    pub fn expr_body(mut self, c: KtCode) -> Self {
917        self.body = KtBody::Expr(c);
918        self
919    }
920    /// `external fun f()` — natively implemented, and so bodiless.
921    pub fn external(mut self) -> Self {
922        self.body = KtBody::External;
923        self
924    }
925
926    /// This function's signature: same name, generics, receiver, parameters and
927    /// return type, with the body and modifiers dropped. What a concrete member
928    /// looks like as an interface abstract.
929    pub fn signature(&self) -> KtFunSig {
930        KtFunSig {
931            name: self.name.clone(),
932            vis: self.vis,
933            annotations: self.annotations.clone(),
934            kdoc: self.kdoc.clone(),
935            generics: self.generics.clone(),
936            receiver: self.receiver.clone(),
937            params: self.params.clone(),
938            ret: self.ret.clone(),
939        }
940    }
941}
942
943/// A function parameter with an optional default-value expression.
944#[derive(Clone, Debug)]
945pub struct KtParam {
946    pub name: String,
947    pub ty: KtType,
948    pub default: Option<KtCode>,
949}
950
951impl KtParam {
952    pub fn new(name: impl Into<String>, ty: KtType) -> Self {
953        Self {
954            name: name.into(),
955            ty,
956            default: None,
957        }
958    }
959    pub fn default(mut self, d: impl Into<String>) -> Self {
960        self.default = Some(KtCode::new().line(d.into()));
961        self
962    }
963}
964
965/// A property declaration (top-level or member).
966#[derive(Clone, Debug)]
967pub struct KtProperty {
968    pub name: String,
969    pub ty: Option<KtType>,
970    /// The initializer or the delegate — **never both**. The exclusion used to
971    /// be two `Option<String>` fields plus a doc comment and a `debug_assert`;
972    /// it is now a sum, so the illegal state is unrepresentable.
973    pub value: KtPropertyValue,
974    pub mutable: bool,
975    pub vis: KtVis,
976    /// Inline annotations rendered before the keyword: `@Volatile internal var …`.
977    pub annotations: Vec<String>,
978    /// Keyword modifiers rendered between visibility and `val`/`var`
979    /// (`open`, `final override`, …).
980    pub modifiers: Vec<String>,
981    pub kdoc: Option<String>,
982    /// Accessor code rendered after the property declaration.
983    pub accessors: Option<KtCode>,
984}
985
986impl KtProperty {
987    pub fn val(name: impl Into<String>) -> Self {
988        Self {
989            name: name.into(),
990            ty: None,
991            value: KtPropertyValue::None,
992            mutable: false,
993            vis: KtVis::Default,
994            annotations: Vec::new(),
995            modifiers: Vec::new(),
996            kdoc: None,
997            accessors: None,
998        }
999    }
1000    pub fn var(name: impl Into<String>) -> Self {
1001        Self {
1002            mutable: true,
1003            ..Self::val(name)
1004        }
1005    }
1006    pub fn ty(mut self, t: KtType) -> Self {
1007        self.ty = Some(t);
1008        self
1009    }
1010    pub fn initializer(mut self, i: impl Into<String>) -> Self {
1011        self.value = KtPropertyValue::Initializer(KtCode::new().line(i.into()));
1012        self
1013    }
1014    pub fn delegate(mut self, d: impl Into<String>) -> Self {
1015        self.value = KtPropertyValue::Delegate(KtCode::new().line(d.into()));
1016        self
1017    }
1018    pub fn vis(mut self, v: KtVis) -> Self {
1019        self.vis = v;
1020        self
1021    }
1022    pub fn annotation(mut self, a: impl Into<String>) -> Self {
1023        self.annotations.push(a.into());
1024        self
1025    }
1026    pub fn modifier(mut self, m: impl Into<String>) -> Self {
1027        self.modifiers.push(m.into());
1028        self
1029    }
1030    pub fn kdoc(mut self, d: impl Into<String>) -> Self {
1031        self.kdoc = Some(d.into());
1032        self
1033    }
1034    pub fn accessors(mut self, c: KtCode) -> Self {
1035        self.accessors = Some(c);
1036        self
1037    }
1038}