Skip to content

[pull] master from GaijinEntertainment:master#1034

Merged
pull[bot] merged 12 commits into
forksnd:masterfrom
GaijinEntertainment:master
May 25, 2026
Merged

[pull] master from GaijinEntertainment:master#1034
pull[bot] merged 12 commits into
forksnd:masterfrom
GaijinEntertainment:master

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented May 25, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

borisbat and others added 12 commits May 24, 2026 20:28
…audit C1 + C5)

The "top-K distinct" composition family now splices end-to-end across array
and decs sources. Two arm pairs in mirror order share a single emission:

  C1: `_distinct_by(K1) |> _order_by(K2) |> take(N) |> to_array()`
  C5: `_order_by(K1) |> distinct() |> take(N) |> to_array()`

Both `plan_order_family` and `plan_decs_order_family` gained a `distinct` /
`distinct_by` recognizer in the walk loop. The bounded-heap path declares
`var dset : table<typedecl(...)>` above the source loop and wraps per-element
push by `if (!key_exists(dset, dkey)) { dset |> insert(dkey); HEAP_UPDATE }`.

Today this composition cascades to tier-2 (`distinct_by_to_array` →
`order_by_inplace` → `take_inplace` — full distinct materialization before
sort). After: single source pass, no full distinct array, only the bounded-N
heap allocated.

Position of `distinct` in the chain (before vs after `_order_by`) has no
bearing on emission — the set just gates the same heap update. The
bounded-heap path treats source-walk order as opaque. C1 and C5 reduce to
identical splice output; only the recognizer position differs.

v1 constraints:
- Inline-able order key required (existing bounded-heap gate; mirrors
  plan_order_family's pre-existing constraint).
- first / first_or_default + distinct deferred (streaming-min path not
  extended in v1).
- Composes with WHERE (filter before distinct gate) and terminal `_select`
  (project ≤N heap survivors at return).

Tests: +9 tests / 18 sub-runs in
`tests/linq/test_linq_fold_theme3_c1_c5_distinct_order_take.das`. Coverage:
C1 ascending + descending, C5 with distinct (whole-tuple key), WHERE +
distinct gate, terminal `_select`, parity vs handwritten cascade, decs lane
for both C1 and C5, anti-test for non-inline order key cascade.

1515/1515 linq tests pass (interp) — was 1497 baseline post-PR-#2862.
245/245 decs tests pass. Lint + format clean.

Living-doc refresh per [[feedback-living-linq-fold-patterns-rst]]: new row in
both Array and Decs tables of `doc/source/reference/linq_fold_patterns.rst`;
audit doc C1 + C5 rows flipped FALLS-OFF → SPLICE-FIRES, Status section
gained a "Theme 3 Phase 3 — landed 2026-05-24" block. "Still open" reframed
to Themes 6/7/8 (Theme 3 closed entirely).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…e + RST/test polish

Copilot review surfaced 3 categories of valid concerns. All folded in.

## Semantic bails (silent miscompile fixes)

The R0 recognizer accepted `distinct[_by]` unconditionally and only enforced
the set-gate in the bounded-heap path. Three shapes either silently dropped
distinct or produced wrong output:

1. `_order_by(K2).distinct_by(K1)`: cascade semantics = "min-K2 per K1" (sort
   first, then keep FIRST K1 per group in sort order). The source-walk set-gate
   would keep an ARBITRARY K1 representative (first seen during walk, not
   first in sort order). Concrete counter-example: `[(A,5),(B,3),(A,1)] ->
   order_by(ts).distinct_by(name)` cascade → [(A,1),(B,3)]; broken splice
   would have kept (A,5). Plain `distinct()` after order_by is still safe —
   whole-tuple equality is position-invariant.
2. `_distinct[_by]` without `take`: the set-gate lives only in the bounded-
   heap path. Without take the splice would fall through to the bottom emit
   that ignores `distinctName`, silently dropping dedup.
3. `take(N).distinct[_by]()`: cascade takes first N source elements then
   dedups; splice would have dedup'd all source then taken N distinct — wrong.

Fixed in both `plan_order_family` and `plan_decs_order_family` by extending
the distinct branch's combined bail (`distinctName != "" || firstName != ""
|| selectLam != null || takeExpr != null || (name == "distinct_by" &&
hasOrder)`) and adding a post-loop guard (`!hasOrder || (distinctName != ""
&& takeExpr == null)`).

## var inscope on dset

The R0 dset declaration was a plain `var ... : table<...>`. Other table-
holding splices in linq_fold (notably `plan_distinct`) use `var inscope` so
finalize fires reliably on scope exit. Both lanes (array + decs) updated to
match the convention.

## Docs + test polish

- RST rows previously documented `._distinct()` (no such shorthand macro
  exists in daslib/linq_boost — only `_distinct_by` has one). Updated to
  plain `.distinct()` in both Array and Decs tables; rows also document the
  3 new bail conditions explicitly.
- C5 tests (array + decs) previously tracked distinctness by `r.name` only,
  which would not catch a buggy "name-only dedup" implementation. Switched
  to combined-key tracking (`"{r.name}:{r.score}"`) + exact-key existence
  assertions.

## New cascade-guard tests

Added 3 anti-tests verifying the bails: `order_by.distinct_by` (must cascade
to honor sort-aware dedup), `distinct_by` without take (must cascade so
dedup isn't dropped), `take.distinct_by` (must cascade so distinct isn't
applied pre-take). Each test asserts the correct output AS IF cascade fires
— the bail itself is invisible to user-visible behavior.

Tests: 18 → 24 sub-runs (1497 → 1521 total linq). 245/245 decs. Lint clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…heme3-c1-c5-distinct-order-take

linq_fold: Theme 3 Phase 3 — distinct[_by] + order_by + take (audit C1 + C5)
Adds collapse_chained_selects pre-pass that mutates the linq call array
in place, folding consecutive _select(f) |> _select(g) into a single
_select(g(f(_))) before the per-arm pattern-match. Symmetric to how
chained _where already compose via &&.

Composition: clone the INNER lambda for its param TYPE, rename its bound
param to a fresh qn("cs", at) name to avoid apply_template recursive
substitution when both lambdas share the boost-side `_` desugar, then
overwrite its body with outer's body where outer's param is substituted
by the renamed-inner body. Chain backlink rewired so subsequent planner
passes see the shortened AST (without this, plan_decs_order_family
re-flattens the original chain and re-collapses, compounding ._N
accessors).

Gated on !has_sideeffects(innerBody) — collapsing shifts evaluation
count when outer references its param zero or many times (cascade
always evaluates inner once per element). Impure inner cascades; output
remains correct.

Wired into 8 planners: plan_order_family, plan_reverse, plan_distinct,
plan_decs_order_family, plan_decs_reverse, plan_decs_distinct,
plan_decs_join, plan_zip. The two order_family planners are defensive
no-ops today (they don't accept any leading _select) but inherit the
collapse if their grammar extends. plan_loop_or_count, plan_group_by_core,
and plan_decs_unroll already handle chained selects natively via their
intermediateBinds / chain-info machinery.

Tests: 9 [test] / 18 sub-runs in
tests/linq/test_linq_fold_theme7_chained_select.das.
1539/1539 linq + 245/245 decs interp green.

Closes audit benchmarks/sql/linq_fold_chain_audit.md row 7c (zip + N
chained _selects) and the equivalent chained-select-before-arm-op shape
on plan_distinct, plan_reverse, plan_decs_*, and plan_decs_join.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Walk through the 30s -> 7.5s compile-time descent for dasImgui macros:
compiler-side wins (~20% across the board), lambda -> @@ where possible,
JsonValue?/from_JV/JV -> json_sprint/json_sscan for fixed schemas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lable shape, comment latent func variant

- C1: add design comment in collapse_chained_selects explaining why LinqCall.name=="select" matching is safe even though it covers both `select` and `select_to_array` (downstream planners build emission from scratch using cll._1.name + the lambda, never re-evaluating cll._0.func; fold_linq_default picks the variant at emission time from top._type.isIterator). No behavior change.
- C2: document in linq_fold_patterns.rst that collapse only applies to peelable single-arg single-return ExprMakeBlock lambdas — multi-statement, captured, or function-pointer projections skip.
- C3-C6: drop 4 expression-form `unsafe(_fold(...))` wraps + 2 block-form `unsafe { _fold(...) }` wraps in tests — verified the splice output is safe-typed (no unsafe required for any of the 9 test runs).

18/18 sub-runs still pass. Full linq 1539/1539 interp green. Lint + format clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
forge-logo.svg shipped with a homemade `>`-in-a-gradient-tile placeholder
that didn't match the brand on daslang.io. Swap in the actual currentColor
glyph path from site/files/daslang.svg, tinted amber (#e8a13a) to match the
nav lockup. Wordmark text (daslang + .io) and colors are unchanged.
…eal-glyph

doc: replace placeholder Sphinx logo with real daslang glyph
…-perfview-fix

blog: fix PerfView typo + link dasImgui docs in macros post
…heme7-chained-select-collapse

linq_fold: Theme 7 — chained _select collapse (audit 7c)
@pull pull Bot locked and limited conversation to collaborators May 25, 2026
@pull pull Bot added the ⤵️ pull label May 25, 2026
@pull pull Bot merged commit 2c18845 into forksnd:master May 25, 2026
2 of 5 checks passed
@pull pull Bot had a problem deploying to github-pages May 25, 2026 08:58 Error
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant