rukalang/elab/
validate_calls.rs

1use super::prelude::*;
2
3/// Validate runtime call arguments against one resolved signature.
4///
5/// Input invariant: argument list belongs to one runtime call target.
6/// Output invariant: argument count matches `params` and each argument has been
7/// elaborated against the corresponding parameter type.
8///
9/// This pass runs after call-spread normalization. It rejects arity mismatch,
10/// rejects non-expression argument kinds in runtime call slots, and elaborates
11/// each value argument against the expected parameter type.
12///
13/// Pass name: `elab.validate_runtime_call_args`.
14struct ValidateRuntimeCallArgsPass<'a> {
15    elaborator: &'a mut Elaborator,
16    params: &'a [(OwnershipMode, Ty)],
17    locals: &'a mut Vec<(String, Ty)>,
18    callee_name: &'a str,
19}
20
21impl<'a> Pass for ValidateRuntimeCallArgsPass<'a> {
22    type In = Vec<CallArg>;
23    type Out = Vec<CallArg>;
24    type Error = ElabError;
25
26    const NAME: &'static str = "elab.validate_runtime_call_args";
27
28    fn run(
29        &mut self,
30        mut input: Self::In,
31        _cx: &mut PassContext,
32    ) -> Result<Self::Out, Self::Error> {
33        self.elaborator
34            .normalize_runtime_calls_and_spreads(&mut input, self.locals)?;
35
36        if input.len() != self.params.len() {
37            return Err(ElabError::ArityMismatch {
38                function: self.callee_name.to_owned(),
39                expected: self.params.len(),
40                actual: input.len(),
41            });
42        }
43
44        for (arg, (_, param_ty)) in input.iter_mut().zip(self.params.iter()) {
45            let CallArg::Expr(expr) = arg else {
46                return Err(ElabError::UnsupportedTypeExpr);
47            };
48            let _ = self
49                .elaborator
50                .elaborate_expr(expr, Some(param_ty), self.locals)?;
51        }
52
53        Ok(input)
54    }
55}
56
57impl Elaborator {
58    /// Validate and elaborate one runtime call argument list.
59    pub(super) fn validate_runtime_call_args(
60        &mut self,
61        args: &mut Vec<CallArg>,
62        params: &[(OwnershipMode, Ty)],
63        locals: &mut Vec<(String, Ty)>,
64        callee_name: &str,
65    ) -> Result<(), ElabError> {
66        let mut pass = ValidateRuntimeCallArgsPass {
67            elaborator: self,
68            params,
69            locals,
70            callee_name,
71        };
72        let (output, timings) = Elaborator::run_subpass(&mut pass, std::mem::take(args))?;
73        *args = output;
74        self.record_subpass_timings(&timings);
75        Ok(())
76    }
77}