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#[derive(Debug, Error, Clone, PartialEq, Eq)]
21pub enum ElabError {
22 #[error("unknown type constructor `{name}`")]
24 UnknownTypeConstructor {
25 name: String,
27 },
28 #[error("type constructor `{name}` requires type arguments")]
30 MissingTypeArgs {
31 name: String,
33 },
34 #[error("type constructor `{name}` expected {expected} args, got {actual}")]
36 TypeArgCountMismatch {
37 name: String,
39 expected: usize,
41 actual: usize,
43 },
44 #[error("duplicate struct declaration `{name}`")]
46 DuplicateStructDecl {
47 name: String,
49 },
50 #[error("struct `{name}` has duplicate type parameter `{param}`")]
52 DuplicateStructTypeParam {
53 name: String,
55 param: String,
57 },
58 #[error("struct `{name}` has duplicate field `{field}`")]
60 DuplicateStructField {
61 name: String,
63 field: String,
65 },
66 #[error("unknown identifier `{name}`")]
68 UnknownIdentifier {
69 name: String,
71 },
72 #[error("unknown function `{name}`")]
74 UnknownFunction {
75 name: String,
77 },
78 #[error("call target must be a function identifier")]
80 InvalidCallTarget,
81 #[error("function `{function}` expected {expected} args, got {actual}")]
83 ArityMismatch {
84 function: String,
86 expected: usize,
88 actual: usize,
90 },
91 #[error("missing field `{field}` for struct `{name}` literal")]
93 MissingStructField {
94 name: String,
96 field: String,
98 },
99 #[error("duplicate field `{field}` in struct `{name}` literal")]
101 DuplicateStructLiteralField {
102 name: String,
104 field: String,
106 },
107 #[error("unknown field `{field}` on struct `{name}`")]
109 UnknownStructField {
110 name: String,
112 field: String,
114 },
115 #[error("cannot infer generic arguments for struct `{name}`")]
117 StructTypeArgsNotInferred {
118 name: String,
120 },
121 #[error("type mismatch: expected `{expected}`, found `{actual}`")]
123 TypeMismatch {
124 expected: Ty,
126 actual: Ty,
128 },
129 #[error("field access requires a struct value, found `{actual}`")]
131 FieldAccessNotStruct {
132 actual: Ty,
134 },
135 #[error("unsupported type syntax in runtime signature")]
137 UnsupportedTypeExpr,
138 #[error("runtime template function `{name}` has unsupported meta parameter `{param}` type")]
140 UnsupportedMetaParamType {
141 name: String,
143 param: String,
145 },
146 #[error(
148 "runtime template function `{name}` expected compile-time string literal for meta parameter `{param}`"
149 )]
150 UnsupportedMetaArg {
151 name: String,
153 param: String,
155 },
156 #[error(
158 "runtime template function `{name}` must use `any...` as its trailing variadic parameter"
159 )]
160 InvalidVariadicParam {
161 name: String,
163 },
164 #[error("runtime template function `{name}` mixes multiple variadic parameters")]
166 MultipleVariadicParams {
167 name: String,
169 },
170 #[error("call spread must use a tuple binding identifier")]
172 InvalidCallSpreadOperand,
173 #[error("call spread requires a tuple value, found `{actual}`")]
175 CallSpreadRequiresTuple {
176 actual: Ty,
178 },
179 #[error("runtime template function `{name}` has conflicting specialization inputs")]
181 ConflictingSpecialization {
182 name: String,
184 },
185 #[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
237pub fn elaborate_program(program: &Program) -> Result<Program, ElabError> {
239 let mut elaborator = Elaborator::new(program)?;
240 elaborator.elaborate()
241}
242
243pub 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
252pub 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 pub(super) fn pass_timings(&self) -> &[PassTiming] {
290 &self.pass_timings
291 }
292
293 pub(super) fn record_subpass_timings(&mut self, timings: &[PassTiming]) {
295 self.pass_timings.extend_from_slice(timings);
296 }
297
298 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}