Rule
discarded-comparison
A comparison not reduced to a source constant is discarded or kept only by unused immutable aliases.
Specimen 03 of 96 · Audit-default ordinary rules
- Severity
- low
- Confidence
- high
- Maturity
- experimental
- Selection
- Audit default
- Policy intent
- not required
- Release
- v0.1.1
- Engine facts used
resolved-source-referencestyped-source-constants
Selection and scope#
Selected by the default audit profile, so an ordinary scan runs it.
./.nightshade/node_modules/.bin/nightshade ./contracts --detectors discarded-comparison
./.nightshade/node_modules/.bin/nightshade detector show discarded-comparisonThe first command runs only this rule; --detectors takes a comma-separated list. The second prints the rule's metadata from your installed version.
Severity is review priority. It does not express exploitability or impact. Confidence is detector metadata, not a probability. All built-in rules are experimental.
Compiler scope: the engine supports the pinned profiles 0.28.0, 0.29.0, 0.30.0, 0.31.1, 0.33.0-rc.2, 0.34.0, 0.35.0-rc.1 and 0.35.0, with ZKIR2 by default. Support for this rule can be narrower; the rule documentation below states any narrower scope.
Corpus checks#
Synthetic corpus checks for this rule in the 0.1.1 proof run. A check counts only with compiler acceptance and complete analysis.
| Positive detected | Corrected quiet | Lookalike quiet | Other negative quiet | Incomplete |
|---|---|---|---|---|
| 1/1 | 1/1 | 1/1 | 0/0 | 0 |
No deviations were recorded for this rule.
These are behavior checks on synthetic fixtures, not a precision or recall estimate. See evaluation.
Rule documentation#
From docs/detectors/discarded-comparison.md at v0.1.1.
Availability: default-on, severity low, confidence high. Select it alone with --detectors discarded-comparison.
The rule reports a resolved comparison (==, !=, <, <=, >, >=) whose Boolean outcome is discarded, unless typed scalar source folding resolves the outcome to a constant. It covers expression statements, unused local bindings and unused immutable identity aliases. Disclosure and identity casts preserve this relationship. A sequence discards each prefix result and retains only its tail; prefixes are checked even inside a returned or otherwise consumed sequence. Only entry-reachable root-source circuits are linted. Source-dead branches, empty numeric for ranges and components after a definite rejection are excluded.
Example and scenario#
export circuit increment(limit: Uint<64>): [] {
Ownable_assertOnlyOwner();
count < limit; // evaluates the check but discards its Boolean result
count.increment(1);
}The owner check still enforces authorization. The comparison does not enforce the intended limit through this use. Replace it with assert(count < limit, "limit reached"), or consume the outcome in the intended control flow. A Boolean view that returns the comparison is an intentional API and stays quiet.
Recommendation and limits#
This is a source-use fact. Operand evaluation, proof constraints and side effects remain; other guards may enforce the same condition. No feasible failure, absence of authorization or deployed vulnerability is claimed. Any non-alias reference conservatively retains a binding, including captures, control flow, computed predicates, aggregates and assignments. One used alias retains an entire fan-out. General computed-result liveness, arbitrary predicate helper forwarding and imported-body linting are outside this rule. Source reachability is structural through the resolved source call graph: a callback used only by a zero-length map/fold can still be linted. This does not establish callback execution or successful execution. Constant folding covers typed scalar source constants, not every tautology or symbolic relationship.
Evidence and known false positives#
Suppress a match#
If a match is intentional, suppress it on the line before with the exact rule ID and a reason of at least eight characters:
// nightshade-disable-next-line discarded-comparison -- Reason this match is intentionalDiagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See configuration for fingerprint suppressions and baselines.