Skip to content

Table lookup collision lint and safe table indexing#2252

Merged
borisbat merged 6 commits intomasterfrom
table-lookup
Mar 11, 2026
Merged

Table lookup collision lint and safe table indexing#2252
borisbat merged 6 commits intomasterfrom
table-lookup

Conversation

@borisbat
Copy link
Collaborator

@borisbat borisbat commented Mar 10, 2026

Summary

  • Add table_lookup_collision (40216) lint error that detects multiple lookups of the same table in a single expression (tab[a] = tab[b], fun(tab[a], tab[b]), etc.) — these cause undefined behavior because table insertion can rehash and invalidate references
  • Add ExprAt::underDeref flag, set by ExprRef2Value, to mark value lookups as safe (no collision risk when the result is immediately copied out)
  • Change unsafe_table_lookup default to false — single tab[key] is now safe; the linter catches the actually dangerous multi-lookup patterns
  • Fix crash when global variable initializer contains a table lookup (missing push/pop of collision set in preVisitGlobalLetInit/visitGlobalLetInit)
  • Gitignore doc/source/stdlib/detail/ (generated by das2rst, no need to track)

Test plan

  • failed_table_lookup_collision.das — 6 collision cases (copy, clone, move, field access, swap, function call) + 3 safe cases (different tables, value lookups, separate expressions)
  • Run full tests/language/ suite to verify no regressions
  • Verify global variable init with table lookup no longer crashes

🤖 Generated with Claude Code

borisbat and others added 6 commits March 10, 2026 11:51
These files are regenerated every time das2rst runs and don't need to be tracked.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add table_lookup_collision (40216) lint error detecting multiple
  lookups of the same table in a single expression (tab[a] = tab[b],
  fun(tab[a], tab[b]), etc.)
- Add ExprAt::underDeref flag set by ExprRef2Value to mark value
  lookups as safe (no collision risk when result is copied out)
- Change unsafe_table_lookup default to false. Single tab[key] is
  now safe; the linter catches the actually dangerous patterns
- Fix crash when global variable init contains a table lookup
  (push/pop collision set in preVisitGlobalLetInit/visitGlobalLetInit)
- Update language docs (tables.rst, unsafe.rst, options.rst) and
  generated stdlib docs (ExprAtFlags, CodeOfPolicies)
- Add expect test: failed_table_lookup_collision.das (6 collision
  cases + 3 safe cases)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exercises the push/pop fix in preVisitGlobalLetInit that prevented
a crash when table lookups appeared in global variable initializers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The gitignore rule excludes generated RST files but the directory
itself must exist for das2rst to write into it. Add .gitkeep so
CI checkout has the directory.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The write_to_detail macro handler runs during compilation, before
das2rst main creates the directory. With detail/ gitignored, CI
checkout has no directory to write into.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@borisbat borisbat merged commit 37c8851 into master Mar 11, 2026
26 checks passed
@borisbat borisbat deleted the table-lookup branch March 11, 2026 01:07
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.

1 participant