XLOOKUP reference path: an empty match_mode keeps the search_mode after it (review fix-up for #396)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas 2026-10-11 15:49:32 -04:00
parent c7bd7deebb
commit 6d59233e62
2 changed files with 18 additions and 2 deletions

View File

@ -1200,9 +1200,18 @@ impl<'h> Evaluator<'h> {
let same_len = if vertical { r.range.height() == l.range.height() } else { r.range.width() == l.range.width() };
if !matches!(key, Value::Array(_)) && (vertical || horizontal) && same_len {
let mut xargs = vec![Arg { value: key, from_ref: false }, Arg { value: self.area_value(&l), from_ref: true }];
for i in [4, 5] {
// An empty match_mode before a given search_mode is the default (0), not the end.
let given = |i: usize| args.get(i).is_some_and(|e| !matches!(e, Expr::Missing));
let last = if given(5) {
5
} else if given(4) {
4
} else {
3
};
for i in 4..=last {
match args.get(i) {
Some(Expr::Missing) | None => break,
Some(Expr::Missing) | None => xargs.push(Arg { value: Value::Number(0.0), from_ref: false }),
Some(e) => {
let value = self.value(e);
xargs.push(Arg { value, from_ref: false });

View File

@ -118,6 +118,13 @@ fn xlookup_returns_a_reference() {
assert_eq!(t.get("D6"), Value::Bool(true));
t.set("D7", "=\"x\"&XLOOKUP(\"e\",A1:A5,B1:B5)&\"y\"");
assert_eq!(t.get("D7"), Value::from("xy"));
// An empty match_mode keeps the search_mode after it: search last to first.
t.set("A6", "b");
t.set("B6", "20");
t.set("D8", "=XLOOKUP(\"b\",A1:A6,B1:B6,,,-1)");
assert_eq!(t.num("D8"), 20.0);
t.set("D9", "=XLOOKUP(\"b\",A1:A6,B1:B6)");
assert_eq!(t.num("D9"), 2.0);
}
#[test]