Skip to content

Implement map destructuring in let bindings#82

Merged
ecto merged 1 commit into
mainfrom
claude/tender-knuth-nyidf8
Jul 7, 2026
Merged

Implement map destructuring in let bindings#82
ecto merged 1 commit into
mainfrom
claude/tender-knuth-nyidf8

Conversation

@ecto

@ecto ecto commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

Add support for map destructuring patterns in let bindings, allowing users to extract multiple values from a map in a single binding. This feature is implemented in both the type checker and EIR lowering, with comprehensive test coverage.

Changes

  • Type Checker (crates/loon-lang/src/check/mod.rs)

    • Added bind_map_destructure method to handle type inference for map destructuring patterns
    • Each key symbol in the pattern is bound to the map's value type
    • Default expressions (when provided) are type-checked and unified against the element type
    • Supports shorthand syntax {name name} (no default) and explicit defaults {name default_expr}
  • EIR Lowering (crates/loon-lang/src/eir/lower.rs)

    • Refactored lower_let_binding to use pattern matching instead of simple symbol check
    • Added lower_map_destructure method to generate efficient IR for map destructuring
    • Shorthand patterns (no default) use a single Op::Field that returns unit for missing keys
    • Patterns with defaults branch on key presence using Op::Builtin(Contains) to avoid evaluating defaults unnecessarily
    • Missing keys without defaults bind unit, matching the interpreter's behavior
  • Tests (crates/loon-lang/tests/backend_parity.rs)

    • Added three test cases covering:
      • Shorthand destructuring: {name name age age} binds keys to their values
      • Default expressions: defaults are only evaluated when keys are absent
      • Missing keys without defaults: bind unit and print as ()

Implementation Details

The lowering strategy uses conditional branching for patterns with defaults to ensure side effects in default expressions only occur when needed. For shorthand patterns without defaults, a simpler single-operation approach is used since Op::Field naturally returns unit for missing keys, matching the legacy interpreter's semantics.

https://claude.ai/code/session_01JzaPzShDQzi6KqNoWqCbE5

@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
loon Ready Ready Preview, Comment Jul 7, 2026 6:57am

Request Review

`[let {name age} m]` map destructuring worked on the legacy interpreter
(Param::MapDestructure in bind_param, including per-key defaults) but the
default EIR VM backend silently bound nothing — lower_let had a TODO arm.

- eir/lower.rs: lower_map_destructure binds each key via Op::Field
  (Selector::Name works on maps in the VM). A distinct per-key value is a
  default expression, lowered behind a `contains?` branch so it is only
  evaluated on the miss path; a missing key with no default binds unit,
  matching the interpreter's `None => Value::Unit`.
- check/mod.rs: bind_map_destructure binds each name to the map's value
  type (`Map Keyword v` → `v`) instead of leaving names unbound, and
  unifies any default expression against that element type.
- backend_parity.rs: shorthand, present-key-wins-over-default, and
  missing-key-binds-unit cases, all asserted equal across backends.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JzaPzShDQzi6KqNoWqCbE5
@ecto ecto force-pushed the claude/tender-knuth-nyidf8 branch from 8f57ad3 to 90aa035 Compare July 7, 2026 06:56
@cursor

cursor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@ecto ecto merged commit c34d5f6 into main Jul 7, 2026
6 checks passed
@chojiai

chojiai Bot commented Jul 7, 2026

Copy link
Copy Markdown

What shipped

You can now extract multiple values from a map in a single binding step. For example, binding {name age} to a map pulls out both keys at once, with optional fallback values for keys that may be absent. Fallback expressions are only evaluated when a key is actually missing, so any side effects in a default stay contained to that case.


Plain-English summary generated by Choji from this pull request.

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.

2 participants