pub struct PatNonVarErased(pub Box<Pattern>);Expand description
An ast::Pattern that is not a bare variable — the target of a
destructuring let, and the left factor that keeps the two let forms
from backtracking over each other.
§Why this type exists
let ‹target› = ‹value› in ‹body› is written twice in this grammar, as
ast::Expr::LetIn (target a BindName, plus curried params) and
ast::Expr::LetPatternIn (target a full pattern) — and at the top level
again as TopBinding::Let/TopBinding::LetPattern. Upstream writes
each of those ONCE: 0.0.6’s nxnonrecdec is the single production
patbot nonrecdecargpart DEFEQ nxlet (parser.mly:652-656), and 0.1
spells the second target pattern_non_var (parser_v1.mly:796) — a
nonterminal that, as its name says, cannot derive a bare variable.
Splitting one production into two whose common prefix is not factored is
what made this port’s worst backtracking blow-up. LetIn is tried first
and subsumes every bare-variable target, so LetPatternIn could never
succeed on one — but it was still tried, and trying it re-parses
value and body in full. With body being the rest of the file, each
enclosing let doubled the cost of every failure below it: measured over
a chain of let vN = N in ending in a broken let, 1,115 serves at 3,
9,459 at 6, 76,211 at 9, 610,227 at 12, 4,882,355 at 15 — ×2.000 per
let, in both grammars. A 129-line document with a missing in
sixteen lets deep cost 17.9M serves and was reported as
crate::ParseFailureKind::GaveUp rather than as the one-word syntax
error it is.
Requiring a non-variable target here restores upstream’s disjointness: the
two alternatives now differ at the token after let, so the choice is
made on the target alone and no tail is ever parsed twice. The same chain
costs 374, 677, 980, 1,283, 1,586 — linear, ~17 serves per atom.
§Why it loses nothing
LetPatternIn on a bare-variable target is unreachable-on-success today,
and provably so rather than by inspection: if it matched, the token after
the name is =, so LetIn’s greedy params is empty (no ast::Param
begins with =), its optional ascription/leading_bar are absent, and
its value/in_kw/body are the identical grammar — so LetIn, tried
first, has already succeeded and this variant is never reached. Only
PatBot::Var is excluded: _, Ctor, (a, b), […], x :: xs and
x as y all still take this route, because BindName accepts none of
them.
Tuple Fields§
§0: Box<Pattern>Trait Implementations§
Source§impl Clone for PatNonVarErased
impl Clone for PatNonVarErased
Source§fn clone(&self) -> PatNonVarErased
fn clone(&self) -> PatNonVarErased
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for PatNonVarErased
impl Debug for PatNonVarErased
Source§impl Deref for PatNonVarErased
impl Deref for PatNonVarErased
impl Deref for PatNonVarErased
Source§impl Parse<WithSpan<Token, Span>> for PatNonVarErased
impl Parse<WithSpan<Token, Span>> for PatNonVarErased
Source§type Error = ParseError<Span>
type Error = ParseError<Span>
<FieldTy as Parse<Atom>>::Error: Into<…> predicate re-creates a projection cycle on a
recursive field (E0275), which decycle’s bound-peeling does not break.