From 9a94765ea2929a2e11f0b2d166a963f058eaecb0 Mon Sep 17 00:00:00 2001 From: Rodin Date: Thu, 30 Apr 2026 07:05:38 -0700 Subject: [PATCH] changelog: 2026-04-30 digest (initial) --- .watermark.json | 7 +++++++ changelog/2026-04-30.md | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 .watermark.json create mode 100644 changelog/2026-04-30.md diff --git a/.watermark.json b/.watermark.json new file mode 100644 index 0000000..d1d10c1 --- /dev/null +++ b/.watermark.json @@ -0,0 +1,7 @@ +{ + "source_repo": "elixir-lang/elixir", + "last_digest_sha": "55a3899e75efd579723da1927500b82f206329e4", + "last_digest_at": "2026-04-30T14:01:00Z", + "last_refresh_sha": null, + "last_refresh_at": null +} diff --git a/changelog/2026-04-30.md b/changelog/2026-04-30.md new file mode 100644 index 0000000..8970924 --- /dev/null +++ b/changelog/2026-04-30.md @@ -0,0 +1,44 @@ +# Elixir Digest — 2026-04-30 + +## Type System / Gradual Typing + +### #15324 — Fix invalid type inference on size compare in guards +- **Author:** lukaszsamson +- **Merged:** 2026-04-29 +- Mirror expressions like `tuple_size(x) >= 2` and `2 <= tuple_size(x)` were producing different type inferences. +- Fix introduces `mirror_order/1` helper that correctly flips comparison operators when operands are swapped. +- Impact: Guards with size on the right now correctly infer the same type as left-sided equivalents. + +### #15322 — Fix map union optimization for open maps +- **Author:** gldubc (Guillaume Duboc) +- **Merged:** 2026-04-29 +- Optimizer subtype shortcut incorrectly concluded open map contained by closed map when field types matched. +- Open maps can have extra keys — fix rejects shortcut on tag (open/closed) mismatch. +- Impact: Fixes false type narrowing with unions of open and closed map types. + +### #15319 — Fix map difference union optimization +- **Author:** gldubc (Guillaume Duboc) +- **Merged:** 2026-04-28 +- Disabled `:union` case of single-key open-map difference optimization. +- Could build invalid union literals causing double negation to leave phantom empty maps. + +## Core / Runtime + +### #15306 — Fix reentrancy of Code.eval_* +- **Author:** lukaszsamson +- **Merged:** 2026-04-28 +- Nested `Code.eval_string` clobbered outer eval's `dbg_callback` and `?elixir_eval_env` in process dict. +- Fix: save/restore pattern (save before, restore in `after` block). +- Discussion: Jonatan Kłosko caught test was not actually testing nested eval; José simplified implementation. +- Lesson: Process dictionary as implicit state = reentrancy bugs. Deliberate trade-off for version decoupling. + +### #15316 — Consistently return path as binary in relative_to_cwd +- **Author:** lukaszsamson +- **Merged:** 2026-04-28 +- `Path.relative_to_cwd/1` could return chardata on `:file.get_cwd` failure. +- All code paths now normalize to binary. + +## Patterns to Extract + +- **Process dict save/restore for reentrancy** (#15306): When using process dict as implicit state, always save/restore in try/after to handle reentrancy. The Elixir team chose this over closures to avoid coupling eval to specific Elixir versions. +- **Set-theoretic type system edge cases** (#15322, #15319): Open vs closed map distinction is subtle in BDD-based type representations. Subtype checks must respect structural tags, not just field types.