Skip to content

Fix Edit Lambda for omitted optional arguments#174

Merged
jimmytacks merged 2 commits into
mainfrom
issue-151-edit-lambda-omitted-args
May 29, 2026
Merged

Fix Edit Lambda for omitted optional arguments#174
jimmytacks merged 2 commits into
mainfrom
issue-151-edit-lambda-omitted-args

Conversation

@jimmytacks
Copy link
Copy Markdown
Collaborator

@jimmytacks jimmytacks commented May 11, 2026

Closes #151.

Summary

When Edit Lambda expanded a call like =EXPLODE(A1) where the LAMBDA declared optional parameters the caller omitted ([chunk_size], [horizontal]), the omitted parameters were never bound. The folded body still referenced them — directly and via ISOMITTED(p), which is meaningless outside a LAMBDA. This produced two failure modes with the same root cause:

  • Generated lambdas (from LET to Lambda) wrap an optional param as a binding whose name equals the param: c, IF(ISOMITTED(c), 3, c). After folding that is a self-referential LET binding, which Excel rejects at formula-set time → hard 0x800A03EC exception.
  • Library lambdas (e.g. EXPLODE) wrap with a different binding name: _size, IF(ISOMITTED(chunk_size), 1, chunk_size). No self-reference, so Excel accepts the string but chunk_size is undefined → #NAME?.

Approach (agreed with Tim)

Reconstruct the plain LET the author started with before LET to Lambda — materialise every parameter to a concrete value and strip all ISOMITTED logic. Optionality is not preserved in the LET (a LET has no notion of omitted args); the author re-applies it by re-running LET to Lambda, where each binding's RHS becomes the default. This unblocks the LET to Lambda → Edit Lambda → LET to Lambda round-trip.

Per parameter:

  • Supplied → the call-site argument.
  • Omitted → the default extracted from the canonical IF(ISOMITTED(p), default, p) wrapper found in any folded binding or the body; NA() when none is discoverable (valid LET, clear #N/A "supply this" marker).
  • A folded wrapper whose binding name == param is merged in place to the resolved value — this removes the self-reference that triggers 0x800A03EC and reproduces the original binding exactly (add(1,2)c, 3; add(1,2,9)c, 9).
  • For params with no wrapper of their own (EXPLODE-style), a p, value binding is added before the folded bindings.
  • Every remaining ISOMITTED(x) is neutralised to FALSE (including standalone ones like Help?, ISOMITTED(text)), skipping string literals so help text is untouched.

Examples

add = =LAMBDA(a, b, [c], LET(c, IF(ISOMITTED(c), 3, c), a + b + c))

  • =add(1, 2)=LET(a, 1, b, 2, c, 3, a + b + c) (was: 0x800A03EC)
  • =add(1, 2, 9)=LET(a, 1, b, 2, c, 9, a + b + c)

=EXPLODE(O13) → valid LET binding chunk_size, 1 and horizontal, FALSE, with Help?, FALSE and the _size/_horiz calcs left as harmless IF(FALSE, …). (was: #NAME?)

Test plan

  • dotnet build addin/lambda-boss.slnx — 0 errors
  • dotnet test addin/lambda-boss.Tests/lambda-boss.Tests.csproj — 990/990 passing
  • New/updated tests: generated-lambda merge (omitted → default, supplied → arg), hand-authored add-param, ISOMITTED neutralisation (incl. standalone on a supplied param), ISOMITTED inside a string literal left untouched, no-default → NA(), param-substring not matched, nested-IF default extraction, full-EXPLODE valid-LET.
  • Manual smoke test in Excel: =LET(a,1,b,2,c,3,a+b+c) → LET to Lambda (mark c optional, name add) → =add(1,2) → Edit Lambda → expect =LET(a, 1, b, 2, c, 3, a + b + c), no exception, evaluates to 6. And =EXPLODE(O13) → Edit Lambda → valid LET (no #NAME?).

🤖 Generated with Claude Code

@jimmytacks jimmytacks force-pushed the issue-151-edit-lambda-omitted-args branch from 4a97d60 to a8d8a6b Compare May 12, 2026 11:05
Edit Lambda expands a LAMBDA call into an equivalent LET. When the caller
omitted optional arguments, the omitted parameters were never bound, yet
the folded body still referenced them directly and via ISOMITTED(p) -
which is meaningless outside a LAMBDA. This produced either a hard
0x800A03EC exception (generated lambdas, where the wrapper is a
self-referential binding c, IF(ISOMITTED(c), 3, c)) or a #NAME? error
(library lambdas like EXPLODE, where the wrapper binds a different name).

Bind every parameter to a concrete value and strip all ISOMITTED logic so
the result is the plain LET the author started with before LET to LAMBDA:

- Supplied params -> the call-site argument.
- Omitted params  -> the default extracted from the canonical
  IF(ISOMITTED(p), default, p) wrapper, or NA() when none is found.
- A folded wrapper whose binding name == param is merged in place to the
  resolved value (removes the self-reference that Excel rejects).
- Every remaining ISOMITTED(x) is neutralised to FALSE, skipping string
  literals so help text is untouched.

Optionality is not preserved in the LET (a LET has no notion of omitted
args); the author re-applies it by re-running LET to LAMBDA, where the
binding RHS becomes the default. This unblocks the
LET to Lambda -> Edit Lambda -> LET to Lambda round-trip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jimmytacks jimmytacks force-pushed the issue-151-edit-lambda-omitted-args branch from a8d8a6b to e291b9c Compare May 29, 2026 14:00
@jimmytacks jimmytacks changed the title Fix Edit Lambda for calls with omitted arguments Fix Edit Lambda for omitted optional arguments May 29, 2026
@jimmytacks
Copy link
Copy Markdown
Collaborator Author

Note: I force-pushed this branch. The previous commit (May 11) predated the net48 port and took a different approach — it stripped the IF wrapper to a bare p and, critically, left standalone ISOMITTED(text) references in place (which would still produce an invalid LET for lambdas like EXPLODE that have a Help?, ISOMITTED(text) line). The branch is now rebased onto current main and reimplemented per the approved plan: every ISOMITTED(x) is neutralised to FALSE, and the generated-lambda self-referential wrapper is merged in place (the cause of the 0x800A03EC exception Tim reported).

Resolve analyzer/inspection warnings in the refactor code with no
behaviour change:

- Remove the dead `firstSpelling` dictionary in BuildDefaultPromotables
  (written but never read; `nameOrder` already tracks first-found
  spellings).
- Switch explicit types to `var`, tidy `using` ordering, drop redundant
  named arguments, and normalise brace/formatting style.
- Move the `PromotedInfo` and `LiteralToken` record declarations near
  their use sites.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jimmytacks jimmytacks merged commit 3085f85 into main May 29, 2026
1 check passed
@jimmytacks jimmytacks deleted the issue-151-edit-lambda-omitted-args branch May 29, 2026 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Edit Lambda doesn't deal correctly with omitted arguments

1 participant