Skip to main content

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}