Skip to main content

graphcal_compiler/hir/
types.rs

1//! HIR type-level reference types.
2//!
3//! The syntax AST preserves source paths (`NamePath` / `IdentPath`) for
4//! type-level references. These HIR types represent the corresponding resolved
5//! boundary: every module-owned reference carries a canonical `ResolvedName`,
6//! while lexical generic parameters carry a `GenericParamId` scoped to their
7//! owning type/function signature.
8
9use crate::registry::time_scale::TimeScale;
10use crate::syntax::ast::{GenericConstraint, MulDivOp};
11use crate::syntax::dimension::Rational;
12use crate::syntax::names::{GenericParamName, ResolvedName, TimeScaleName, namespace};
13use crate::syntax::span::{Span, Spanned};
14
15/// Canonical identity for a generic parameter in a lexical generic scope.
16///
17/// Generic parameters are not module-level symbols, so they should not be
18/// represented as `ResolvedName<GenericParam>`. Their identity is the owning
19/// generic scope plus the parameter leaf name.
20#[derive(Debug, Clone, PartialEq, Eq, Hash)]
21pub struct GenericParamId {
22    pub owner: GenericParamOwner,
23    pub name: GenericParamName,
24}
25
26impl GenericParamId {
27    /// Create a generic parameter identity from its owner and leaf name.
28    #[must_use]
29    pub const fn new(owner: GenericParamOwner, name: GenericParamName) -> Self {
30        Self { owner, name }
31    }
32}
33
34/// The lexical scope that owns a generic parameter list.
35#[derive(Debug, Clone, PartialEq, Eq, Hash)]
36pub enum GenericParamOwner {
37    /// Generic parameter on a user-defined `type` declaration.
38    Type(ResolvedName<namespace::StructType>),
39    /// Generic parameter on a function signature.
40    Function(ResolvedName<namespace::Fn>),
41}
42
43/// A resolved generic-parameter definition.
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct GenericParamDef {
46    pub id: Spanned<GenericParamId>,
47    pub constraint: GenericConstraint,
48    pub default: Option<TypeExpr>,
49}
50
51/// Built-in type forms with closed semantic meaning.
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub enum BuiltinType {
54    /// `Dimensionless`.
55    Dimensionless,
56    /// `Bool`.
57    Bool,
58    /// `Int`.
59    Int,
60    /// `Datetime` or `Datetime<Scale>`.
61    Datetime(TimeScaleName),
62}
63
64impl BuiltinType {
65    /// The default `Datetime` type is UTC.
66    #[must_use]
67    pub const fn datetime_utc() -> Self {
68        Self::Datetime(TimeScaleName::new(TimeScale::UTC))
69    }
70}
71
72/// A resolved type expression that still preserves source-level structure.
73///
74/// This is not TIR's semantic `ResolvedTypeExpr`: HIR keeps references to named
75/// dimensions/types/indexes as canonical identities instead of immediately
76/// collapsing them to registry values such as `Dimension`.
77#[derive(Debug, Clone, PartialEq, Eq)]
78pub struct TypeExpr {
79    pub kind: TypeExprKind,
80    pub span: Span,
81}
82
83impl TypeExpr {
84    /// Create a HIR type expression.
85    #[must_use]
86    pub const fn new(kind: TypeExprKind, span: Span) -> Self {
87        Self { kind, span }
88    }
89}
90
91/// The resolved shape of a type expression.
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub enum TypeExprKind {
94    /// A built-in type with closed meaning.
95    Builtin(BuiltinType),
96    /// A scalar dimension expression.
97    DimExpr(DimExpr),
98    /// An index name in a type-expression syntactic slot.
99    ///
100    /// This is not a value type. It is accepted only where the surrounding
101    /// generic parameter expects an `Index` argument; declaration annotations
102    /// reject it before TIR construction.
103    Index(IndexRef),
104    /// A user-defined non-generic struct/tagged-union type.
105    Struct(Spanned<ResolvedName<namespace::StructType>>),
106    /// A generic type parameter (`F: Type`).
107    GenericTypeParam(Spanned<GenericParamId>),
108    /// A user-defined generic type application.
109    TypeApplication {
110        name: Spanned<ResolvedName<namespace::StructType>>,
111        type_args: Vec<TypeExpr>,
112    },
113    /// An indexed type expression.
114    Indexed {
115        base: Box<TypeExpr>,
116        indexes: Vec<IndexRef>,
117    },
118}
119
120/// A resolved dimension expression.
121#[derive(Debug, Clone, PartialEq, Eq)]
122pub struct DimExpr {
123    pub terms: Vec<DimExprItem>,
124    pub span: Span,
125}
126
127/// One term of a dimension expression with its combining operator.
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub struct DimExprItem {
130    pub op: MulDivOp,
131    pub term: DimTermRef,
132}
133
134/// A resolved dimension term.
135#[derive(Debug, Clone, PartialEq, Eq)]
136pub struct DimTermRef {
137    pub target: DimTermTarget,
138    /// `None` means exponent 1. Rational exponents (`^(1/2)`) are kept exact.
139    pub power: Option<Rational>,
140    pub span: Span,
141}
142
143/// Target of a resolved dimension term.
144#[derive(Debug, Clone, PartialEq, Eq)]
145pub enum DimTermTarget {
146    /// A concrete module-owned dimension declaration.
147    Dimension(Spanned<ResolvedName<namespace::Dim>>),
148    /// A generic dimension parameter (`D: Dim`).
149    GenericParam(Spanned<GenericParamId>),
150}
151
152/// A resolved index reference in an indexed type.
153#[derive(Debug, Clone, PartialEq, Eq)]
154pub enum IndexRef {
155    /// A concrete module-owned index declaration.
156    Concrete(Spanned<ResolvedName<namespace::Index>>),
157    /// A generic index parameter (`I: Index`).
158    GenericParam(Spanned<GenericParamId>),
159    /// A type-level natural-number expression.
160    NatExpr(NatExpr),
161}
162
163/// A resolved type-level natural-number expression.
164#[derive(Debug, Clone, PartialEq, Eq)]
165pub enum NatExpr {
166    /// Integer literal.
167    Literal(u64, Span),
168    /// Generic natural-number parameter (`N: Nat`).
169    Param(Spanned<GenericParamId>),
170    /// Addition.
171    Add(Box<Self>, Box<Self>, Span),
172    /// Multiplication.
173    Mul(Box<Self>, Box<Self>, Span),
174}
175
176impl NatExpr {
177    /// Source span for the expression.
178    #[must_use]
179    pub const fn span(&self) -> Span {
180        match self {
181            Self::Literal(_, span) | Self::Add(_, _, span) | Self::Mul(_, _, span) => *span,
182            Self::Param(param) => param.span,
183        }
184    }
185}