Skip to content

--opt-report: candidate-generation pre-filters for Ptr<Shape> / Ptr<NumArray> record nothing, so "0 candidates" cannot be read #7112

Description

@proggeramlug

Follow-up to #7106.

--opt-report records at select() / deny() sites inside the per-value
rules. A value that is filtered out before it becomes a candidate produces
no entry at all, so the report cannot distinguish:

  • the analysis considered this value and rejected it (a rule, arguable), from
  • the analysis never looked at this value (nothing to point at).

This is the same ambiguity the census was built to remove, one stage upstream —
and it is why 8 of the census's 18 real workloads read "zero candidates".

The canonical-slot half of this is fixed (module-init contexts and value-level
canonical-i32 rules now record denials). Ptr<Shape>, Ptr<NumArray> and
int-valued-TA still have the hole
, at their candidate-collection pre-filters.

Mechanisms still blind

Ptr<NumArray> — whole-analysis kill switches.
crates/perry-codegen/src/collectors/ptr_numarray.rs:220-234:
collect_num_array_locals returns an empty map outright when the module has a
shape-barrier site, a numarray prototype-index barrier, or an opaque prototype
mutation. Every array local in the module vanishes from the report with no
indication that a module-wide barrier was the cause.

Ptr<NumArray> — element-type pre-filter.
ptr_numarray.rs:352-364: only HirType::Array(Number|Int32) (or the
Array<…> generic form) reaches provenance(). A boolean[] — e.g.
benchmarks/suite/11_prime_sieve.ts's sieve — is silently not a candidate.
That verdict is correct, but it is a verdict, and the report throws it away.

Ptr<Shape> has the analogous structure in
crates/perry-codegen/src/collectors/ptr_shape.rs (provenance pass 1 gates
before the containment walk that does record denials).

Evidence

benchmarks/suite/11_prime_sieve.ts reports 0 ptr-numarray candidates.
Read naively that says "this program has no array worth promoting". It has a
1,000,000-element array, in the hot loop, indexed by a proven integer. The real
answer — "declared boolean[], and the analysis only admits numeric element
types" — is a good answer that nothing in the tooling will tell you.

Ask

Record a denial at each pre-filter, with the module-wide kills recorded once per
module rather than once per local. Then candidates == 0 means "this program
has no values of this shape", and nothing else — which is what a reader
currently, and wrongly, assumes it means.

Gate

The census now fails a corpus workload whose candidate total is zero across
every analysis (check_analysis_reach, ZERO_CANDIDATE_ALLOWLIST in
scripts/compiler_output_harness/repsel_census.py). That catches the
whole-workload case. It does not catch a per-analysis zero, which is what this
issue is about.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions