ast,daslib: fix spurious 30151 on concept_assert under lint flags (#2830)#2835
Merged
Merged
Conversation
) Two independent bugs surfaced together by the linter's `no_infer_time_folding=true` + `no_optimizations=true` policy combo. 1. Compiler: `concept_assert` / `static_assert` cond never gets folded. `typeinfo sizeof(T) <= typeinfo sizeof(U)` rewrites to `ExprConstInt <= ExprConstInt` at infer time, but `InferTypes::visit(ExprOp1/Op2/Op3)` only folds when `enableInferTimeFolding` is on. With lint disabling it and `no_optimizations` skipping `ConstFolding`, the binop stayed unfolded and `ContractFolding::visit(ExprStaticAssert*)` raised the spurious 30151. Mirror the existing static_if save+force-enable+ restore pattern in `preVisit`/`visit(ExprStaticAssert*)` so the cond subtree always folds. 2. Daslib: 6 sites used `if (typeinfo X)` instead of `static_if`. These relied on the same infer-time folding to elide the dead branch (whose body references fields/operations only valid in the true branch's universe). Under lint flags, both branches survive and the dead one fails to resolve. Convert all to `static_if`: `decs_boost.das:244` (`a._aka`), `builtin.das:403/892/914/1183`, `json_boost.das:477`. `extended_checks` gates the lint step to `matrix.target == 'linux'`, so this surfaced as "linux x64 only" in CI; verified platform-independent locally on Windows daslang.exe. Also: 2 pre-existing STYLE028 hits in `decs_boost.das` (`self->implement` -> `implement`), required by the "every changed .das file lint-clean" PR rule once the PR touches that file. Regression fixture: `tests/_issue_2830_lint_repro.das`. CI lint runs over changed .das files; the fixture exercises the failing path on this PR and continues to exercise it on any future PR that touches it. Verified locally on WSL Ubuntu2404-CI (clang 18.1.3, Release): - lint clean on all 4 repro variants - tests/decs 245/245 pass - tests/json 266/266 pass - tests/lint 8/8 + utils/lint/tests 38/38 pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a lint-mode regression where disabling infer-time folding (cop.no_infer_time_folding=true) + disabling optimizations (cop.no_optimizations=true) caused concept_assert/static_assert conditions and some typeinfo-guarded branches in daslib to stop folding, producing spurious typer/contract-folding errors (issue #2830).
Changes:
- Compiler: force-enable infer-time folding for
ExprStaticAssertcondition subtrees via a save/restore pattern inInferTypes::preVisit/visit. - Daslib: replace 6
if (typeinfo ...)sites withstatic_if (typeinfo ...)so dead branches are eliminated even when infer-time folding is off. - Tests: add a minimal lint regression fixture to ensure the failing path is exercised by CI lint on changed
.dasfiles.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
tests/_issue_2830_lint_repro.das |
Adds a lint regression fixture reproducing the issue #2830 failure mode. |
src/ast/ast_infer_type.cpp |
Save/force-enable/restore infer-time folding around ExprStaticAssert traversal to ensure conditions fold under lint policies. |
include/daScript/ast/ast_infer_type.h |
Adds savedFoldingForStaticAssert state to support the new save/restore logic. |
daslib/json_boost.das |
Converts a typeinfo-guarded if to static_if to avoid typing the dead branch under lint flags. |
daslib/decs_boost.das |
Converts if (typeinfo has_field<_aka>(a)) to static_if and fixes two STYLE028 call-site issues. |
daslib/builtin.das |
Converts several if (typeinfo ...) sites to static_if to ensure compile-time elimination under lint flags. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
borisbat
added a commit
that referenced
this pull request
May 23, 2026
#2835 fixed the typer-pass-order #2830 that originally tripped this test on the extended_checks (linux, 64) lane. With master now containing the fix, the test compiles cleanly on all lanes. Re-adding it covers a case the current suite missed: from_decs_template(type<Row>)._where(_.a >= 0)._where(_.b >= 0).count() Three chained single-field _where_s — all 3 fields read via field access, no whole-var ref. The splice must keep all 3 get_ros (no slot pruning) but elide the named-tuple bind (no decs_tup in the body, iter vars read directly). Lesson saved to memory: not every CI lane runs every test, so "platform-specific" failures often mean "we only check this on one platform" — not that the bug itself is platform-specific. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Closes #2830.
Two independent bugs the lint pipeline surfaced together
The linter runs with
cop.no_infer_time_folding = true+cop.no_optimizations = true. Bisect (toggle each lint policy off in turn) localizesno_infer_time_foldingas the sole trigger. With infer-time folding off, two distinct paths in the codebase that quietly relied on it now break:1. Compiler:
concept_assert/static_assertcond never foldstypeinfo sizeof(T) <= typeinfo sizeof(U)rewrites itself toExprConstInt <= ExprConstIntat infer time, butInferTypes::visit(ExprOp1/Op2/Op3)(ast_infer_type_op.cpp:106, :365, :405) only folds whenenableInferTimeFoldingis on. With lint disabling it andno_optimizationsskippingConstFolding, the binop stays unfolded;ContractFolding::visit(ExprStaticAssert*)(ast_const_folding.cpp:848-852) demandscond->constexpression || cond->rtti_isConstant()and raises the spurious 30151.Fix mirrors the existing static_if save+force-enable+restore pattern (ast_infer_type.cpp:4418-4422, :4428-4430) inside
preVisit(ExprStaticAssert*)/visit(ExprStaticAssert*), so the cond subtree always folds regardless of the surrounding policy.2. Daslib: 6 sites
if (typeinfo X)instead ofstatic_ifThese relied on the same infer-time fold of
ExprIfThenElse(ast_infer_type.cpp:4444) to elide the dead branch — whose body references fields/operations only valid in the true branch's universe. Under lint flags, both branches survive and the dead one fails to resolve. The decs_boost case was what the bug exposed after the compiler fix landed:Convert all 6 to
static_if:daslib/decs_boost.das:244—if (typeinfo has_field<_aka>(a))daslib/builtin.das:403—if (typeinfo can_clone_from_const(varr))daslib/builtin.das:892—if (typeinfo can_clone_from_const(val))daslib/builtin.das:914—if (typeinfo can_clone_from_const(val))daslib/builtin.das:1183—if (typeinfo is_pod(a))daslib/json_boost.das:477—if (typeinfo can_copy(anything[0]))"Linux x64 only"?
CI artifact:
extended_checksgates the lint step tomatrix.target == 'linux'. macOS / Windows builds never invokeutils/lint/main.das. Verified the bug platform-independent locally on Windows daslang.exe.Also rolled in: 2 STYLE028 in
decs_boost.dasPre-existing master lint hits (
self->implement(...)→implement(...)), forced into scope by "every changed .das file lint-clean" once the PR touches that file.Regression coverage
tests/_issue_2830_lint_repro.das— minimal[decs_template]+from_decs_template+_wherefixture. CI lint runs on changed.dasfiles, so the fixture exercises the failing path on this PR. Without the compiler fix, lint fails at theconcept_assert30151. Without thestatic_ifsweep, lint fails at the_akaresolution 30928. Both fixes required for the fixture to pass.Test plan
cop.no_infer_time_folding = trueas the single trigger[decs_template], +where one field, +where multi-field, +linq_fold count chain)tests/decs245/245,tests/json266/266,tests/lint8/8,utils/lint/tests38/38.dasfiles--verifyclean on 16695 files; lint clean on 3 ruleable changed files (builtin.dasis in the lint utility's skip list)🤖 Generated with Claude Code