[pull] master from GaijinEntertainment:master#1013
Merged
Conversation
Flip two predicates on tLambda in TypeDecl: - canCopy() false -> true: lambda is a fat pointer (one char* to a heap capture frame), so '=' aliases cheaply; pass-by-value is free. - isSafeToDelete() true -> false: aliases mean 'delete lam' must be gated by unsafe, matching raw-pointer and class delete. This cascades through composites: array<lambda<...>>, structs with a lambda field, tuples/variants containing a lambda all inherit the unsafe-delete rule (Structure::isSafeToDelete walks fields, and the existing tArray/tTable branches recurse into element types). Side-effect (intended UX win): capturing a lambda from inside another lambda no longer needs an explicit @capture(<- inner) annotation - default capture_any now picks copy (pointer alias) instead of forced move. Existing @capture(<- ...) / @capture(& ...) annotations stay valid. Sites that newly require unsafe-delete: - daslib/archive.das: 4 generic 'serialize' overloads (struct/tuple/ variant/table) - daslib/decs.das: restart / after_gc / commit - daslib/heartbeat.das: set_heartbeat - tests: aot/test_lambdas, language/lambda_capture, lambda_capture_modes, jit_tests/invoke New positive coverage (interpreter + AOT mirror): - tests/language/lambda_copy.das, tests/aot/test_lambda_copy.das - '=' aliases the capture frame (proven by alternating invocations) - pass-by-value (independent local vars per invoke) - struct copy aliases lambda field - implicit capture-of-lambda inside another lambda Doc updates: - doc/source/reference/language/lambdas.rst - doc/source/reference/language/move_copy_clone.rst (type table row) - doc/source/reference/tutorials/14_lambdas.rst - doc/source/reference/tutorials/20_lifetime.rst (delete-needs-unsafe) - tutorials/language/14_lambdas.das (drop "lambdas can't be copied" comment, add copy/alias note) - CLAUDE.md (Pass-by-value section) Build infra (bundled - pre-existing limitations that surfaced): - CMakeLists.txt DAS_AOT_EXT: chunk AOT batches (60 files each) to stay under Windows' 32K command-line limit when worktree/CI paths are deep (absolute paths blow it; chunked add_custom_command runs COMMAND-per-batch sequentially). - tests/aot/CMakeLists.txt: gate test_aot_live_host* AOT under IF(NOT DAS_HV_DISABLED), skip daslib/just_in_time.das from the daslib AOT batch when DAS_LLVM_DISABLED=ON. Both AOT-compile by requiring external modules (dashv, LLVM.dll) and fail unconditionally without them. Verification: ctest 35/35; interpreter 7804/7810 (6 platform-skip); AOT (--use-aot) 7193/7199 (6 platform-skip). HV enabled, LLVM off. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-9be7f9 lambda: copyable (alias), delete requires unsafe
Closes the `_while` row in the test_linq_partition.das coverage checklist. take_while(pred) breaks the loop on the first false-pred element; skip_while(pred) flips a one-way `skipping` flag on the first false then emits everything after. How it lands: 1. wrap_with_skip_take → wrap_with_ranges, append_skip_take_prelude → append_ranges_prelude. Both helpers gain skipWhileCond / takeWhileCond / skippingName args. All 4 lane builders thread the new state through their signatures — predicate-driven ranges are now first-class alongside count-driven. 2. Per-match prefix order in the loop body: (1) take-guard, (2) skip counter, (3) skip_while flip (NEW), (4) take_while break (NEW), (5) takeCount++, body. takeCount++ moved below the predicate gates so skip_while-skipped and take_while-rejected elements don't eat the take(N) budget. Pure skip/take chains are unchanged (the new prefixes are no-ops when both predicates are null). 3. classify_terminator extension: take_while and skip_while join where_/ select/take/skip in the ARRAY-trailing arm so `_take_while(p).to_array()` splices into the array lane instead of cascading. 4. Canonical chain order rejected by plan_loop_or_count: [where_/select]* → skip? → skip_while? → take_while? → take? → terminator. Each later op rejects predecessors that violate this order; out-of-order chains cascade to tier 2 (correct, just no splice). Bail cases (cascade to tier 2): - `_select(...)._take_while(...)` or `_select(...)._skip_while(...)` — predicate currently peels with itName; lifting to chained-bind names is a follow-up that requires moving select binds above the predicate gates. - Multiple take_while or multiple skip_while in one chain. - skip / take appearing AFTER skip_while / take_while. Headline (100K rows, INTERP): | Benchmark | m1 sql | m3 linq | m3f this PR | Win | |--- |-------:|--------:|------------:|----:| | take_while_match | 7 | 23 | **2** | 11.5× over m3 / 3.5× over m1 SQL | | skip_while_match | 3 | 20 | **5** | 4× over m3 (sqlite COUNT-WHERE index-scan still 1.67× faster) | THRESHOLD = 50000 against n = 100000, so take_while breaks halfway and skip_while flips halfway. take_while_match is the standout: splice exits the for-loop on the first false-pred element (~50k of 100k source rows), while m3 still pays for the full take_while_impl array allocation + the subsequent count length read. Test plan: - Parity tests (tests/linq/test_linq_fold.das): 24 new subtests across 2 [test] functions covering bare/where/select/skip-take/empty/all-true/ all-false/cascade-bails for both operators and each lane. - AST-shape tests (tests/linq/test_linq_fold_ast.das): 8 new tests + 9 target_* helpers covering splice + cascade fingerprints. - Interpreter: 369/369 fold + 133/133 ast + wider tests/linq/*.das sweep (15 files, all green). - AOT (test_aot -use-aot): 369/369 fold + 133/133 ast green. - Lint + format: clean across all touched files. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bundled cosmetic fixes from PR #2732's Copilot review (PR-F is queued and will land before this PR-G stack): - benchmarks/sql/single_match.das:9 — comment claimed `LIMIT 2` but the SQL used `_first()` (LIMIT 1, fixture-side id uniqueness already asserts exactly-one). Reworded to match the code. - benchmarks/sql/aggregate_match.das:9 — comment said "max(price - min)" but the reducer is `sum(price)`. Reworded to "sum of prices". The 3rd Copilot suggestion — renaming the test label "aggregate: sum of doubles" → "aggregate: sum with multiplier" — lands in the PR-G commit ahead of this one since that file is already touched there. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dasImgui cards (PR-D + table rail + popup/loop ID patterns):
- aot-header-hand-maintained-not-regenerated: aot_dasIMGUI.h must
carry hand-written DAS_MOD_API decls when new C++ helpers are
bound; not regenerated from anything.
- ffi-const-ref-return-and-decltype-name-collision: the failure
modes of `addExtern<DAS_BIND_FUN(...)>` — runtime "missing
WrapType implementation" on const-ref returns and compile-time
`decltype incorrect argument` on namespace/identifier collision.
- popup-id-stack-mismatch-stateful-overload: open_popup /
open_popup_on_item_click with a string id outside the popup
container body fails because the trigger and BeginPopup hash
against different ID-stack depths.
- registry-path-brackets-vs-slash-indexed-vs-container: indexed
widget paths use IDENT[N], container paths use IDENT/N; mixing
them (test/record wait targets with /0) silently no-ops.
- sort-specs-block-arg-helper-for-sortable-data-table: the
TableSortSpec struct + `sort_specs() $(specs) { ... }` pattern
that wraps the cpp ImGuiTableSortSpecs pointer drain.
- synced-table-instances-shared-boost-ident-in-a-for-loop: sharing
the same boost IDENT across iterations of a `for` loop in
dasImgui binds BeginTable to one table instance — synced layout
is the intended behavior.
- with-id-for-per-iter-id-namespacing-inside-loops: `with_id(i) { ... }`
is the daslang shape for ImGui's PushID/PopID per-iter
namespacing when widget IDENTs are literal strings.
- imgui-angled-headers-row-plus-normal-headers-row-both-intentional:
cpp imgui_demo calls TableAngledHeadersRow AND TableHeadersRow —
the angled row has no column context menu, so both rows are
intentional.
daslang card:
- table-safe-index-safe-only-with-null-coalescing: `table?[key]` is
safe ONLY when immediately consumed by `??`. Bare `tab?[k]` /
stored pointer escapes the table's storage and the compiler
enforces `unsafe()`. Mirrors the rule just landed in CLAUDE.md
(commit 760b69fac).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-2026-05-19 mouse-data: 8 dasImgui + 1 daslang cards from PR-D / PR-E work
The lint pass rejected C++ reserved words as variable/struct/class/field/
enum/enum-value names because the AOT C++ emitter would otherwise produce
invalid C++ (struct char {}, for (auto& register : ...), ...). Function
names already had this restriction dropped in 2026-05-14 by extending
aotSuffixNameEx to detect keywords and prepend _Func.
This continues that pattern across the remaining sites:
ast_lint.cpp drops 8 isCppKeyword(...) guards:
- enum / enum-value / structure / structure-field names
- global-let / for-iter / let / type-arg variable names
- function-argument / block-argument names
Module-name guard stays (modules emit raw into namespace X { ... }).
daslib/aot_cpp.das extends the mangling:
- aotFieldName adds _f_ prefix for keyword names (already did this for
DELETE to avoid Windows SDK winnt.h macro collision).
- aotStructName passes "_S" suffix instead of "" - aotSuffixNameEx
prepends it only when the name is a keyword, so non-keyword structs
emit unchanged.
- New helpers aotEnumName (_E) and aotEnumValueName (_V) mirror the
same shape for enums.
- Replaces 5 raw enumType.name / structType.name emission sites with
the helpers (type-decl emission, enum class decl/value decl, enum
value access expressions, struct rtti field offsetof site).
- aotSuffixNameEx gains a string overload that forwards to the
das_string one so callers can pass either.
Tests:
- tests/language/cpp_keywords_as_names.das (new): positive coverage
for every now-allowed shape - for-iter, let, global var, struct
fields, struct name, class name, enum name, enum values, typedef
alias, function arg, function-type arg name, lambda arg. Uses C++
keywords that aren't daslang reserved (char, register, short,
extern, mutable, volatile, signed, long, union).
- tests/aot/test_cpp_keyword_names.das extended to mirror every
shape through AOT codegen alongside the existing function-name
coverage.
- tests/language/failed_reserved_names.das deleted - supplanted.
Interpreter: 7920 tests, 7914 passed, 6 skipped, 0 failed.
AOT: 7309 tests, 7303 passed, 6 skipped, 0 failed.
Lint + das-fmt --verify pass on all 3 changed .das files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ake-while-skip-while linq_fold: take_while/skip_while predicate-driven ranges (PR-G)
Two new bit flags on Structure::FieldDeclaration that make class-method abstractness and parent-inheritance state inspectable from AST macros and tooling: - _abstract (0x400): set when the method is declared `def abstract` (init=null, body must come from a derived class). Cleared on override. - inherited (0x800): set on fields cloned from a parent class that are not (re)declared in this class. Cleared when the field is declared or overridden locally. parentType keeps its existing narrow semantic (type pending from parent auto-resolution; transient, cleared during inference). A new explicit "inherited" bit avoids overloading it. Both bits are exposed via fld.flags._abstract / fld.flags.inherited in the FieldDeclarationFlags bitfield binding. AstSerializer bumped to 85. Tests under tests/language/ verify the three flag combinations (declared-here-abstract, inherited-from-parent, overridden) at compile time via a [structure_macro] helper, plus a runtime override-dispatch sanity check.
…-as-names allow C++ keywords as daslang identifiers (vars, structs, fields, enums)
…abstract-inherited-flags ast: add _abstract and inherited bits to FieldDeclaration
Phase 1 of the linq zip extension plan (LINQ_TO_DECS.md). Extends the existing 2-ary and 3-ary `zip` family to arities 4..8 with full overload coverage per arity: - lockstep iter / array / zip_to_array (no selector) - result-selector iter / array / zip_to_array (block<...>) - private `zipN_impl` / `zipN_impl_const` helpers per arity Also adds a `static_if` reserve in `select_many_impl` mirroring the existing zip pattern — closes a pre-existing PERF006 hint on length-bearing sources. Tests in `tests/linq/test_linq_transform.das` cover all arities and overloads (72 tests for zip; 1047 total linq tests including AOT mode green). LINT003/002 on pre-existing test functions also fixed per the "fix all lint" rule. `benchmarks/sql/LINQ_TO_DECS.md` documents the multi-phase plan: this PR is Phase 1; future phases add `plan_zip` splice in linq_fold (Phase 2), `from_decs_template(type<Foo>)` macro (Phase 3), and `plan_from_decs_template` splice for SoA-without-buffer decs iteration (Phase 4). Mouse card documents an intermittent daslang bug observed during this work — a 4-ary block call with lambda params `p, q, r, s` returning stale first-param values. Could not produce reliable minimal repro; workaround documented. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
linq: N-ary zip family extended to arities 4-8
…count
Adds plan_zip planner ahead of plan_loop_or_count in the _fold cascade.
Recognizes 2-ary zip(srcA, srcB) chains and splices them into a single
multi-iterator for-loop with no intermediate tuple buffer.
Z1 — no-terminator: emits invoke($($i(srcA), $i(srcB)) { var buf : array<tuple>;
[reserve when both have length]; for (itA, itB in srcA, srcB) { buf |>
push_clone((itA, itB)); }; return <- buf [|> to_sequence_move] }, srcA, srcB).
Covers zip(arr, arr), zip(iter, iter) |> to_array, and zip(iter, iter) →
iterator. Shortest-source truncation comes free with daslang's multi-iter for.
Z2 — count/long_count terminator: when both sources are length-bearing,
emits the length-min shortcut directly (int / int64). Otherwise emits a
counter loop (acc++, no buffer). No-pred only — predicated count deferred.
Z7 — trims `zip` from is_buffer_required_op marker arm (now dead since
plan_zip catches all zip-led chains before plan_loop_or_count).
Z3 (fused chain ops: where_/select/take/skip between zip and terminator)
and Z4..Z6 (3..8-ary mechanical expansion) deferred to a stacked follow-up.
Verification: lint clean; 154/154 test_linq_fold_ast pass; full linq suite
green under interpret (test_linq* — 480+ tests); 1103/1103 under -use-aot.
…lan-zip linq_fold: plan_zip splice arm (Phase 2A — bare zip + count/long_count)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 : )