graphcal_compiler/syntax/phase.rs
1//! AST phase parameter (issue: phased AST split).
2//!
3//! The AST is parameterized over a [`Phase`] type so that variants that exist
4//! only at earlier stages of compilation are statically excluded from later
5//! stages.
6//!
7//! Two phases:
8//!
9//! - [`Raw`] — produced by the parser. Carries every surface sugar via
10//! [`crate::syntax::ast::RawDeclSugar`] /
11//! [`crate::syntax::ast::RawExprSugar`]. Consumed by the formatter and any
12//! surface-aware tooling.
13//! - [`Desugared`] — produced by [`crate::desugar`]. Surface-sugar slots
14//! are [`core::convert::Infallible`], so `match` arms over them are
15//! unreachable. Reference paths stay syntactic
16//! ([`crate::syntax::ast::UnresolvedRef`]); HIR lowering is the single
17//! stage that classifies and resolves them.
18//!
19//! ```text
20//! parser → File<Raw> → desugar → File<Desugared> → HIR/IR → TIR → eval
21//! ↘ formatter
22//! ```
23
24use core::convert::Infallible;
25use core::fmt::Debug;
26
27pub(crate) mod sealed {
28 pub trait Sealed {}
29}
30
31/// Marker trait for AST phases.
32///
33/// Sealed: only [`Raw`] and [`Desugared`] implement it.
34pub trait Phase: 'static + sealed::Sealed {
35 /// Phase-specific declaration sugar variants.
36 ///
37 /// Carried by `DeclKind::Sugar(_)`. For [`Raw`] this is
38 /// [`crate::syntax::ast::RawDeclSugar`]; for [`Desugared`] it is
39 /// [`Infallible`] so the variant cannot be constructed.
40 type DeclSugar: Debug + Clone;
41
42 /// Phase-specific expression sugar variants.
43 ///
44 /// Carried by `ExprKind::Sugar(_)`. For [`Raw`] this is
45 /// [`crate::syntax::ast::RawExprSugar`]; for [`Desugared`] it is
46 /// [`Infallible`].
47 type ExprSugar: Debug + Clone;
48}
49
50/// Pre-desugar phase: every surface sugar is representable.
51///
52/// Produced by the parser. The formatter and any other surface-aware
53/// consumer reads this phase.
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum Raw {}
56
57impl sealed::Sealed for Raw {}
58
59/// Post-desugar phase: surface-sugar variants are statically impossible.
60///
61/// Produced by [`crate::desugar`]. Unresolved identifier paths are still
62/// representable; HIR lowering resolves them. This is the final syntax-AST
63/// phase — every downstream consumer reads HIR, not a further AST phase.
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum Desugared {}
66
67impl sealed::Sealed for Desugared {}
68
69/// Helper for matching against `Sugar(Infallible)` arms.
70///
71/// In post-desugar code, `match decl.kind { ..., Sugar(s) => never(s) }`
72/// is the canonical way to handle the impossible case without runtime panic.
73#[inline]
74#[must_use]
75pub const fn never<T>(x: Infallible) -> T {
76 match x {}
77}