rukalang/elab/
prelude.rs

1pub(super) use std::collections::{BTreeMap, BTreeSet};
2
3pub(super) use ruka_frontend::IntrinsicId;
4pub(super) use ruka_types::{can_safely_coerce_numeric, is_truncation_cast};
5pub(super) use thiserror::Error;
6
7pub(super) use crate::check::Ty;
8pub(super) use crate::meta::{
9    expand_function_template_instance, MetaEvalError, TemplateMetaBinding,
10};
11pub(super) use crate::pass::{Pass, PassContext, PassTiming};
12pub(super) use crate::syntax::ast::{
13    Block, CallArg, Expr, FunctionDecl, MatchPattern, NamedTypeField, OwnershipMode, Param,
14    PrefixOp, Program, Stmt, StructDecl, TypeExpr, TypeRef,
15};
16
17use super::helpers::ty_to_type_expr;
18
19/// Elaboration error produced while concretizing type syntax.
20#[derive(Debug, Error, Clone, PartialEq, Eq)]
21pub enum ElabError {
22    /// Type constructor name could not be resolved.
23    #[error("unknown type constructor `{name}`")]
24    UnknownTypeConstructor {
25        /// Type constructor name.
26        name: String,
27    },
28    /// Generic type constructor was used without type arguments.
29    #[error("type constructor `{name}` requires type arguments")]
30    MissingTypeArgs {
31        /// Type constructor name.
32        name: String,
33    },
34    /// Generic type constructor was used with wrong type-argument count.
35    #[error("type constructor `{name}` expected {expected} args, got {actual}")]
36    TypeArgCountMismatch {
37        /// Type constructor name.
38        name: String,
39        /// Expected number of type arguments.
40        expected: usize,
41        /// Provided number of type arguments.
42        actual: usize,
43    },
44    /// Struct declaration duplicated an existing type name.
45    #[error("duplicate struct declaration `{name}`")]
46    DuplicateStructDecl {
47        /// Struct name.
48        name: String,
49    },
50    /// Struct declaration repeated a type parameter.
51    #[error("struct `{name}` has duplicate type parameter `{param}`")]
52    DuplicateStructTypeParam {
53        /// Struct name.
54        name: String,
55        /// Duplicate type parameter name.
56        param: String,
57    },
58    /// Struct declaration repeated a field name.
59    #[error("struct `{name}` has duplicate field `{field}`")]
60    DuplicateStructField {
61        /// Struct name.
62        name: String,
63        /// Duplicate field name.
64        field: String,
65    },
66    /// Referenced identifier was not found in scope.
67    #[error("unknown identifier `{name}`")]
68    UnknownIdentifier {
69        /// Identifier name.
70        name: String,
71    },
72    /// Called function name could not be resolved.
73    #[error("unknown function `{name}`")]
74    UnknownFunction {
75        /// Function name.
76        name: String,
77    },
78    /// Call target expression was not a function identifier.
79    #[error("call target must be a function identifier")]
80    InvalidCallTarget,
81    /// Function call supplied wrong number of arguments.
82    #[error("function `{function}` expected {expected} args, got {actual}")]
83    ArityMismatch {
84        /// Function name.
85        function: String,
86        /// Expected argument count.
87        expected: usize,
88        /// Actual argument count.
89        actual: usize,
90    },
91    /// Struct literal omitted a required field.
92    #[error("missing field `{field}` for struct `{name}` literal")]
93    MissingStructField {
94        /// Struct name.
95        name: String,
96        /// Missing field name.
97        field: String,
98    },
99    /// Struct literal repeated a field name.
100    #[error("duplicate field `{field}` in struct `{name}` literal")]
101    DuplicateStructLiteralField {
102        /// Struct name.
103        name: String,
104        /// Duplicate field name.
105        field: String,
106    },
107    /// Struct literal referenced an unknown field.
108    #[error("unknown field `{field}` on struct `{name}`")]
109    UnknownStructField {
110        /// Struct name.
111        name: String,
112        /// Unknown field name.
113        field: String,
114    },
115    /// Generic struct arguments could not be inferred.
116    #[error("cannot infer generic arguments for struct `{name}`")]
117    StructTypeArgsNotInferred {
118        /// Struct name.
119        name: String,
120    },
121    /// Inferred and expected types were incompatible.
122    #[error("type mismatch: expected `{expected}`, found `{actual}`")]
123    TypeMismatch {
124        /// Expected type.
125        expected: Ty,
126        /// Actual inferred type.
127        actual: Ty,
128    },
129    /// Field access base expression was not a struct.
130    #[error("field access requires a struct value, found `{actual}`")]
131    FieldAccessNotStruct {
132        /// Actual base expression type.
133        actual: Ty,
134    },
135    /// Type syntax is unsupported in runtime signatures.
136    #[error("unsupported type syntax in runtime signature")]
137    UnsupportedTypeExpr,
138    /// Runtime template meta parameter used unsupported type.
139    #[error("runtime template function `{name}` has unsupported meta parameter `{param}` type")]
140    UnsupportedMetaParamType {
141        /// Runtime template function name.
142        name: String,
143        /// Meta parameter name.
144        param: String,
145    },
146    /// Runtime template meta argument was not a compile-time string literal.
147    #[error(
148        "runtime template function `{name}` expected compile-time string literal for meta parameter `{param}`"
149    )]
150    UnsupportedMetaArg {
151        /// Runtime template function name.
152        name: String,
153        /// Meta parameter name.
154        param: String,
155    },
156    /// Variadic runtime template parameter used an invalid form.
157    #[error(
158        "runtime template function `{name}` must use `any...` as its trailing variadic parameter"
159    )]
160    InvalidVariadicParam {
161        /// Runtime template function name.
162        name: String,
163    },
164    /// Runtime template declared more than one variadic parameter.
165    #[error("runtime template function `{name}` mixes multiple variadic parameters")]
166    MultipleVariadicParams {
167        /// Runtime template function name.
168        name: String,
169    },
170    /// Call spread operand was not a tuple binding identifier.
171    #[error("call spread must use a tuple binding identifier")]
172    InvalidCallSpreadOperand,
173    /// Call spread operand was not a tuple value.
174    #[error("call spread requires a tuple value, found `{actual}`")]
175    CallSpreadRequiresTuple {
176        /// Actual spread operand type.
177        actual: Ty,
178    },
179    /// Runtime template specialization inputs were contradictory.
180    #[error("runtime template function `{name}` has conflicting specialization inputs")]
181    ConflictingSpecialization {
182        /// Runtime template function name.
183        name: String,
184    },
185    /// Meta evaluation failed while elaborating generated code.
186    #[error(transparent)]
187    MetaEval(#[from] MetaEvalError),
188}
189
190#[derive(Debug, Clone)]
191pub(super) struct StructTemplate {
192    pub(super) type_params: Vec<String>,
193    pub(super) fields: Vec<NamedTypeField>,
194}
195
196#[derive(Debug, Clone)]
197pub(super) struct EnumTemplate {
198    pub(super) type_params: Vec<String>,
199    pub(super) variants: BTreeMap<String, Vec<TypeExpr>>,
200}
201
202#[derive(Debug, Clone)]
203pub(super) struct FunctionSig {
204    pub(super) params: Vec<(OwnershipMode, Ty)>,
205    pub(super) return_ty: Ty,
206}
207
208#[derive(Debug, Clone)]
209pub(super) struct RuntimeFunctionTemplate {
210    pub(super) type_params: Vec<String>,
211    pub(super) function: FunctionDecl,
212}
213
214#[derive(Debug, Clone)]
215pub(super) struct TemplateCallBinding {
216    pub(super) type_bindings: BTreeMap<String, Ty>,
217    pub(super) meta_bindings: BTreeMap<String, TemplateMetaBinding>,
218    pub(super) runtime_args: Vec<Expr>,
219    pub(super) variadic_pack_tys: Vec<Ty>,
220    pub(super) specialization_key: SpecializationKey,
221}
222
223#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
224pub(super) enum SpecializationValue {
225    Type(Ty),
226    Int(i64),
227    String(String),
228    Pack(Vec<Ty>),
229}
230
231#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
232pub(super) struct SpecializationKey {
233    pub(super) function_name: String,
234    pub(super) values: Vec<SpecializationValue>,
235}
236
237/// Elaborate a frontend program by resolving and concretizing runtime types.
238pub fn elaborate_program(program: &Program) -> Result<Program, ElabError> {
239    let mut elaborator = Elaborator::new(program)?;
240    elaborator.elaborate()
241}
242
243/// Elaborate a frontend program and return elaboration subpass timings.
244pub fn elaborate_program_with_timings(
245    program: &Program,
246) -> Result<(Program, Vec<PassTiming>), ElabError> {
247    let mut elaborator = Elaborator::new(program)?;
248    let output = elaborator.elaborate()?;
249    Ok((output, elaborator.pass_timings().to_vec()))
250}
251
252/// Elaborate a generated runtime expression using a restricted local environment.
253pub fn elaborate_meta_generated_expr(
254    program: &Program,
255    expr: &Expr,
256    locals: &[(String, TypeExpr)],
257) -> Result<(Expr, TypeExpr), ElabError> {
258    let mut elaborator = Elaborator::new(program)?;
259    elaborator.resolve_signatures()?;
260
261    let mut typed_locals = Vec::with_capacity(locals.len());
262    for (name, ty) in locals {
263        let resolved =
264            elaborator.resolve_type_expr(ty, &BTreeMap::new(), &BTreeSet::new(), None)?;
265        typed_locals.push((name.clone(), resolved));
266    }
267
268    let mut expr = expr.clone();
269    let ty = elaborator.elaborate_expr(&mut expr, None, &mut typed_locals)?;
270    Ok((expr, ty_to_type_expr(&ty)))
271}
272
273pub(super) struct Elaborator {
274    pub(super) program: Program,
275    pub(super) templates: BTreeMap<String, StructTemplate>,
276    pub(super) enum_templates: BTreeMap<String, EnumTemplate>,
277    pub(super) signatures: BTreeMap<String, FunctionSig>,
278    pub(super) function_templates: BTreeMap<String, RuntimeFunctionTemplate>,
279    pub(super) specializations: BTreeMap<SpecializationKey, String>,
280    pub(super) concrete_structs: BTreeMap<String, StructDecl>,
281    pub(super) instantiating_structs: BTreeSet<String>,
282    pub(super) instantiating_functions: BTreeSet<SpecializationKey>,
283    pub(super) next_function_instance_id: usize,
284    pub(super) pass_timings: Vec<PassTiming>,
285}
286
287impl Elaborator {
288    /// Return recorded elaboration subpass timings.
289    pub(super) fn pass_timings(&self) -> &[PassTiming] {
290        &self.pass_timings
291    }
292
293    /// Append one batch of elaboration subpass timings.
294    pub(super) fn record_subpass_timings(&mut self, timings: &[PassTiming]) {
295        self.pass_timings.extend_from_slice(timings);
296    }
297
298    /// Run one elaboration subpass and return output with collected timing samples.
299    pub(super) fn run_subpass<P>(
300        pass: &mut P,
301        input: P::In,
302    ) -> Result<(P::Out, Vec<PassTiming>), P::Error>
303    where
304        P: Pass,
305    {
306        let mut pass_context = PassContext::new();
307        let output = pass_context.run_pass(pass, input)?;
308        Ok((output, pass_context.pass_timings().to_vec()))
309    }
310}