Return #VALUE! when a LAMBDA call has too few argument positions (#557)

This commit is contained in:
MarekSpodBiedry
2026-10-12 08:35:28 +02:00
parent 3926d21aa9
commit e6c16472e4
2 changed files with 38 additions and 1 deletions
+6 -1
View File
@@ -860,7 +860,12 @@ impl<'h> Evaluator<'h> {
}
pub fn apply_lambda(&mut self, l: &Lambda, args: &[Expr]) -> Ev {
if args.len() > l.params.len() {
// Too many or too few argument positions is #VALUE!. An explicitly empty position, as in
// `(1,)`, is `Expr::Missing` and still counts as a position (it binds as omitted). `f()`
// parses to no arguments, which for a one-parameter lambda can also be read as one empty
// position, so that call still binds the parameter as omitted.
let positions_ok = args.len() == l.params.len() || (args.is_empty() && l.params.len() == 1);
if !positions_ok {
return err(CellError::Value);
}
let mut bound = Vec::with_capacity(l.params.len());
+32
View File
@@ -501,6 +501,38 @@ fn let_lambda() {
assert_eq!(t.num("A4"), 14.0);
}
#[test]
fn lambda_argument_count() {
let mut t = T::new();
t.wb.names.push(gridcraft_model::DefinedName {
name: "AddPair".into(),
scope: None,
formula: "LAMBDA(a,b,a+b)".into(),
comment: String::new(),
hidden: false,
});
t.calc.rebuild(&t.wb);
let omit = "LAMBDA(x,y,IF(ISOMITTED(y),\"Missing\",x+y))";
t.set("A1", "=LAMBDA(a,b,a+b)(2)");
t.set("A2", "=LAMBDA(a,b,a+b)(2,3,4)");
t.set("A3", &format!("={omit}(1,)"));
t.set("A4", &format!("={omit}(1)"));
t.set("A5", &format!("={omit}(1,2)"));
t.set("A6", "=LAMBDA(7)()");
t.set("A7", "=AddPair(2)");
t.set("A8", "=AddPair(2,3)");
assert_eq!(t.get("A1"), Value::Error(CellError::Value));
assert_eq!(t.get("A2"), Value::Error(CellError::Value));
assert_eq!(t.get("A3"), Value::Text("Missing".into()));
assert_eq!(t.get("A4"), Value::Error(CellError::Value));
assert_eq!(t.num("A5"), 3.0);
assert_eq!(t.num("A6"), 7.0);
assert_eq!(t.get("A7"), Value::Error(CellError::Value));
assert_eq!(t.num("A8"), 5.0);
t.set("A9", "=LAMBDA(x,ISOMITTED(x))()");
assert_eq!(t.get("A9"), Value::Bool(true));
}
#[test]
fn names_and_sheets() {
let mut t = T::new();