Skip to content

Phase 2: close frontend surface-lowering coverage #75

Closed
7 of 7 issues completed
Closed

Description

@biuld

Why this phase is next

134 of the 377 unresolved passing files stop in surface lowering, before resolution, kinds, or types ever run. They are the largest single blocker in the corpus and they gate every later phase: a file that cannot lower cannot be type-checked, cannot be compiled, and cannot be executed. No standard library or backend work makes them pass.

Measured breakdown of the 134 (passing resolution, 36/413 today):

Stage Files Dominant form
expression 43 ascription e :: T, in both (e :: T) and bare e :: T form
pattern 41 multi-field constructor patterns, record patterns inside constructor patterns, pattern bindings
declaration 26 operator, constructor-operator, and type-operator aliases
type 12 type wildcards, row constructor constraints
guards 10 guarded equations and guarded case alternatives
multi-scrutinee case 2 case a, b of

Scope

Land these forms on the shared spine — AST, HIR, THIR, Core — not as special cases:

  • Ascription e :: T in expression position, including nested chains (((e :: b -> Int) :: forall b. b -> Int)).
  • Multi-field constructor patterns, record patterns nested in a constructor pattern, and pattern bindings in let/where.
  • Operator, constructor-operator (infixr 6 Cons as :), and type-operator aliases, as declarations and in export/import conflict checking.
  • Type wildcards (_ in a type), row constructor constraints, and Prim.Row-style constraints where they do not require an open-row runtime layout.
  • Guards on equations and case alternatives, including comma-separated guard lists and do inside a guard.
  • case with multiple scrutinees.
  • Unary minus, which purs desugars to negate — without it, failing/2109-negate.purs reports no diagnostic at all.

Gate

passing module resolution reaches 100% of files that do not require a missing library module, and the per-stage blocker counts above each fall to zero. New syntax lands with a purs differential case, not only a local test.

Sub-issues

Tracked as children of this epic.

References

  • docs/design/D-04-suite-roadmap.md — M2 measured baseline, FE-03..FE-07, FE-17
  • crates/psrs-ast/src/lower.rs — surface lowering, source of the this <stage> syntax is not supported yet diagnostics
  • crates/psrs-syntax/src/parser/ — parser coverage is ahead of lowering here; several forms already parse and fail to lower
  • docs/design/frontend/semantics/ — the design each form must match

Validation

cargo fmt --all --check
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
PSRS_ORACLE=annotations cargo test -p psrs-driver --test suite l2_resolution -- --ignored --nocapture

Activity

  1. biuld commented on Oct 3, 2026

    @biuld
    OwnerAuthor

    Phase 2 acceptance is met. Closing the epic.

    All six sub-issues are Done: #84 (ascription), #85 (patterns), #86 (operators,
    constructor-operators, type-operator aliases), #87 (type wildcards, Prim.Row
    constraints, polykind application), #88 (guarded equations, multi-scrutinee
    cases), #89 (the Prim hierarchy and unary minus), #90 (instance declarations
    and signatures).

    The phase's own criterion — the surface-lowering blocker count — is zero,
    measured on master at fe40d17 with
    PSRS_ORACLE=annotations cargo test -p psrs-driver --test suite -- --ignored --nocapture:
    l6_runtime_scoreboard reports no P2 surface-lowering failures, down from 61 at
    the 5298aad baseline.

    What now holds the passing suite

    All 354 first-stage blockers remain, and none of them is the front end:

    First blocker Files
    missing library module 342
    other P3 resolve 8
    P0 lex 4
    P2 surface lowering 0

    passing resolution is 59/413. The next phase is therefore not a front-end
    phase: #76 (Phase 3 — standard library), whose three issues now carry measured
    Corpus cases — #95 = 305, #96 = 12, #94 = 0 by first blocking stage.

    #94 measures 0 for a real reason worth recording: stdlib/lib/Prelude.purs
    exists and resolves, so no file's first blocker is Prelude. Its missing
    classes and value functions surface later, as the 8 unknown-name, 3 type-check,
    and 1 kind-check blockers behind the library modules. Counting by first blocking
    stage understates it, and #94 should be scheduled on that understanding rather
    than on its board number.

    Twenty-five of the 342 name a library module that no open issue owns —
    Data.Eq, Data.Symbol, Data.Predicate, Data.Monoid, Data.Foldable,
    Data.Array, Data.Unit, Data.Ordering, Data.Newtype, Data.Generic.Rep,
    Data.Functor.Contravariant, Data.Function.Uncurried, Data.Bifunctor, and
    Data.Bifoldable. That gap is filed separately rather than left implicit.

    The visible-type-application limits recorded in #87 are not Phase 2 work; they
    are filed as their own frontend slice because they share one root cause with
    #100's polykind instantiation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions