Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions DESIGN-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -710,10 +710,11 @@ the damage was real and the stated consequence was not -- worth separating, beca
what would have driven the wrong fix (a lint setting that does nothing).

[tools/check-encoding.ps1](tools/check-encoding.ps1) now rejects `///` immediately following a non-space
character at end of line, in `.rs` files. The pattern was checked for false positives across the whole
repository before being adopted: there are none, because a legitimate doc comment is always preceded by
whitespace or begins its line. The script's own description was widened from "encoding" to **text hygiene**,
since neither this rule nor the control-character rule is an encoding fault; they live here because this is the
character, in `.rs` files. The pattern was checked for false positives across the whole repository before being
adopted: there are none, because a legitimate doc comment is always preceded by whitespace or begins its line.
A preceding slash is excluded so a `////` banner comment is not flagged. The script's own description was
widened from "encoding" to **text hygiene**, since neither this rule nor the control-character rule is an
encoding fault; they live here because this is the
check CI already runs over every tracked file.

The first version of this guard was a **no-op**: it gated on a `$ext` variable that was not in scope inside the
Expand All @@ -722,6 +723,12 @@ that a guard has been written, observed to pass, and believed. The rule that cau
guard you have only seen pass is untested.** Plant the defect it is meant to catch and watch it fail, then
remove the defect and watch it pass. Both directions, every time.

The second version was anchored at end of line (`\S///\s*$`), so it caught only the *bare* glued marker -- the
rarer form. The typical splice glues a whole doc line onto the code (`let x = 1;/// The next thing`), and that
passed. This is a narrower rule than "test the guard": the guard *was* tested, against the exact instance that
motivated it, and the instance was not representative. **A guard written from one observed defect must be
checked against the general shape of the defect, not only against the instance in hand.**

## Restoring a file with an old timestamp silently disables the rebuild

Verifying a fix by planting the defect back requires *building* both states. Restoring the fixed file with
Expand Down
24 changes: 14 additions & 10 deletions tools/check-encoding.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,21 @@ foreach ($file in $files) {
# leaving its own `# Errors` section truncated or empty where the moved
# text had come from.
#
# `\S///` is the whole condition: a doc marker touching a non-space
# character. The surrounding `^.*` and `.*$` the pattern used to carry are
# not just redundant once the anchors are gone, they are the expensive
# part -- `^.*` matches to end of line and then backtracks looking for the
# marker, on every line of every file. Measured over 1.47 MB of this
# repository's own Rust, dropping them cut a no-match scan (the case CI
# runs on every clean build) from 872 ms to 288 ms across 20 passes. The
# match index still identifies the line, because the marker and the
# character it is glued to are on it.
# A doc marker touching a non-space character is the whole condition. The
# `^.*` and `.*$` the pattern used to carry are not merely redundant once
# the anchors are gone, they are the expensive part -- `^.*` matches to
# end of line and then backtracks looking for the marker, on every line of
# every file. Measured over 1.47 MB of this repository's own Rust,
# dropping them cut a no-match scan (the case CI runs on every clean
# build) from 872 ms to 288 ms across 20 passes. The match index still
# identifies the line, because the marker and the character it is glued to
# are on it.
#
# A preceding slash is excluded -- `[^\s/]` rather than `\S` -- so a
# `////` banner comment is not flagged. `\S///` matched every one of them,
# because the third slash of the banner is itself a non-space character.
if ([System.IO.Path]::GetExtension($file) -eq '.rs') {
$glued = [regex]::Match($text, '\S///')
$glued = [regex]::Match($text, '[^\s/]///')
if ($glued.Success) {
$prefix = $text.Substring(0, $glued.Index)
$line = ($prefix -split "`n").Count
Expand Down
Loading