Skip to content

Parser: spurious 'expected identifier' for non-ident-headed type args (Vec<&str>, tuples, arrays) #78

Description

@StreamDemon

Summary

type_args_after_open in crates/sploosh-parser/src/lib.rs rejects spec-legal type arguments that do not start with an identifier:

fn f(v: Vec<&str>) {}          // Err: "expected identifier" at the `&`
fn f(v: Vec<(i64, i64)>) {}    // same
fn f(v: Vec<[u8; 4]>) {}       // same

All of these are legal per LANGUAGE_SPEC.md §3 / §16 (type_args = type_arg { "," type_arg } with type_arg = type | IDENT "=" type).

Root cause

The associated-type-binding checkpoint tries self.ident() first and backtracks by resetting self.pos — but ident() pushes an "expected identifier" ParseError into self.errors before the backtrack, and the checkpoint never truncates self.errors. The fallback ty() then parses the type argument correctly, but the stale error survives and parse_program returns Err.

Verified empirically against the real crates (probe test, 2026-07-02): all four shapes above fail today; each parses fine once the spurious error is discarded.

Suggested fix

Record self.errors.len() alongside the position checkpoint and truncate on backtrack, or restructure the Assoc lookahead to peek (Ident followed by =) before committing, which avoids the error-pushing path entirely. The peek option cannot regress error ordering elsewhere and matches how other lookaheads in the parser work (turbofish, send-statement head).

Scope note

Found during the parser enhancement wave (PR #71) while designing the attribute-argument parser; deliberately not fixed there because that wave is scoped to no-behavior-change refactors. The probe cases above should land as regression tests with the fix.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions