rukalang/elab/
normalize_calls.rs1use super::prelude::*;
2
3struct NormalizeRuntimeCallsAndSpreadsPass<'a> {
15 elaborator: &'a mut Elaborator,
16 locals: &'a mut Vec<(String, Ty)>,
17}
18
19impl<'a> Pass for NormalizeRuntimeCallsAndSpreadsPass<'a> {
20 type In = Vec<CallArg>;
21 type Out = Vec<CallArg>;
22 type Error = ElabError;
23
24 const NAME: &'static str = "elab.normalize_runtime_calls_and_spreads";
25
26 fn run(&mut self, input: Self::In, _cx: &mut PassContext) -> Result<Self::Out, Self::Error> {
27 let mut expanded = Vec::new();
28 for arg in input {
29 match arg {
30 CallArg::Expr(expr) => expanded.push(CallArg::Expr(expr)),
31 CallArg::Type(ty) => expanded.push(CallArg::Type(ty)),
32 CallArg::Spread(mut expr) => {
33 let Expr::Ident { .. } = &expr else {
34 return Err(ElabError::InvalidCallSpreadOperand);
35 };
36 let tuple_ty = self
37 .elaborator
38 .elaborate_expr(&mut expr, None, self.locals)?;
39 match tuple_ty {
40 Ty::Unit => {}
41 Ty::Tuple(items) => {
42 for index in 0..items.len() {
43 expanded.push(CallArg::Expr(Expr::Field {
44 base: Box::new(expr.clone()),
45 field: index.to_string(),
46 }));
47 }
48 }
49 actual => return Err(ElabError::CallSpreadRequiresTuple { actual }),
50 }
51 }
52 }
53 }
54 Ok(expanded)
55 }
56}
57
58impl Elaborator {
59 pub(super) fn normalize_runtime_calls_and_spreads(
61 &mut self,
62 args: &mut Vec<CallArg>,
63 locals: &mut Vec<(String, Ty)>,
64 ) -> Result<(), ElabError> {
65 let mut pass = NormalizeRuntimeCallsAndSpreadsPass {
66 elaborator: self,
67 locals,
68 };
69 let (output, timings) = Elaborator::run_subpass(&mut pass, std::mem::take(args))?;
70 *args = output;
71 self.record_subpass_timings(&timings);
72 Ok(())
73 }
74}