Rule

discarded-comparison

A comparison not reduced to a source constant is discarded or kept only by unused immutable aliases.

Release v0.1.1View Markdown

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-references typed-source-constants

Selection and scope#

Selected by the default audit profile, so an ordinary scan runs it.

Shell
./.nightshade/node_modules/.bin/nightshade ./contracts --detectors discarded-comparison
./.nightshade/node_modules/.bin/nightshade detector show discarded-comparison

The 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 detectedCorrected quietLookalike quietOther negative quietIncomplete
1/11/11/10/00

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#

Compact
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:

Compact
// nightshade-disable-next-line discarded-comparison -- Reason this match is intentional

Diagnostics cannot be suppressed, and an unmatched directive for a selected rule makes analysis incomplete. See configuration for fingerprint suppressions and baselines.

References#