fn run_with_args()

in starlark/src/eval/bc/instr_impl.rs [1413:1497]


    fn run_with_args<'v>(
        eval: &mut Evaluator<'v, '_>,
        stack: &mut BcStackPtr<'v, '_>,
        _ip: BcPtrAddr,
        (pops, def_data): &Self::Arg,
        _pops: (),
    ) -> anyhow::Result<Value<'v>> {
        let pop = stack.pop_slice(*pops);

        let mut parameters =
            ParametersSpec::with_capacity(def_data.function_name.clone(), def_data.params.len());
        let mut parameter_types = Vec::new();
        let mut parameter_captures = Vec::new();

        let mut pop_index = 0;

        // count here rather than enumerate because '*' doesn't get a real
        // index in the parameter mapping, and it messes up the indexes
        let mut i = 0;
        for x in &def_data.params {
            if let Some(t) = x.ty() {
                assert!(*t == pop_index);
                let v = pop[pop_index as usize];
                pop_index += 1;
                let name = x.name().unwrap_or("unknown").to_owned();
                parameter_types.push((
                    i,
                    name,
                    v,
                    expr_throw(TypeCompiled::new(v, eval.heap()), x.span, eval).map_err(|e| e.0)?,
                ));
            }
            match &x.node {
                ParameterCompiled::Normal(n, _) => parameters.required(&n.name),
                ParameterCompiled::WithDefaultValue(n, ty, v) => {
                    assert!(*v == pop_index);
                    let value = pop[pop_index as usize];
                    pop_index += 1;

                    if ty.is_some() {
                        // Check the type of the default
                        let (_, _, ty_value, ty_compiled) = parameter_types.last().unwrap();
                        expr_throw(
                            value.check_type_compiled(*ty_value, ty_compiled, Some(&n.name)),
                            x.span,
                            eval,
                        )
                        .map_err(|e| e.0)?;
                    }
                    parameters.defaulted(&n.name, value);
                }
                ParameterCompiled::NoArgs => parameters.no_args(),
                ParameterCompiled::Args(_, _) => parameters.args(),
                ParameterCompiled::KwArgs(_, _) => parameters.kwargs(),
            };
            if let Captured::Yes = x.captured() {
                parameter_captures.push(i);
            }
            if !matches!(x.node, ParameterCompiled::NoArgs) {
                i += 1;
            }
        }
        let return_type = match &def_data.return_type {
            None => None,
            Some(v) => {
                assert!(v.node == pop_index);
                let value = pop[pop_index as usize];
                pop_index += 1;
                Some((
                    value,
                    expr_throw(TypeCompiled::new(value, eval.heap()), v.span, eval)
                        .map_err(|e| e.0)?,
                ))
            }
        };
        assert!(pop_index as usize == pop.len());
        Ok(eval.heap().alloc(Def::new(
            parameters,
            parameter_captures,
            parameter_types,
            return_type,
            def_data.info,
            eval,
        )))
    }