Skip to content

syntax: don't lift alternation prefixes that can match more than one way - #1401

Merged
BurntSushi merged 2 commits into
rust-lang:masterfrom
ranflarion:lift-one-way-prefix
Nov 7, 2026
Merged

BurntSushi merged 2 commits into
rust-lang:masterfrom
ranflarion:lift-one-way-prefix

Conversation

@ranflarion

Copy link
Copy Markdown
Contributor

Fixes #1400

lift_common_prefix rewrites XA|XB as X(?:A|B), which only preserves leftmost-first semantics when X matches one way. Otherwise X(?:A|B) prefers X's first choice followed by B over X's second choice followed by A, which is what XA|XB picks. ab*b|ab*c on abbc reported 0..4 instead of 0..3, and a*?b|a*?a on ab reported 0..1 instead of 0..2.

The lifted prefix now stops at the first element that isn't a literal, a class or a look-around assertion, since each of those matches at most one way. Prefixes like [A-Z]foo|[A-Z]quux from the existing tests, and \wfoo|\wbar from fbe2e16, still lift. A shape like \w+foo|\w+bar no longer gets a top-level concatenation from this rewrite, so it can lose the reverse inner optimization that fbe2e16 mentions. I haven't run rebar. The check is also conservative: a fixed repetition such as [a-z]{3} matches one way but isn't lifted.

The new assertions in smart_alternation and the two testdata/regression.toml cases fail without the change.

Lifting a common prefix out of an alternation, `XA|XB` to `X(?:A|B)`,
changes which match leftmost-first semantics prefers when `X` can match
more than one way. For example, `ab*b|ab*c` on `abbc` reported `abbc`
instead of `abb`: after `b*` takes `bb`, the lifted form tries both
branches before it backtracks into `b*`.

Literals, classes and look-around assertions match at most one way, so
the lifted prefix now stops at the first element that is anything else.

Fixes rust-lang#1400

@BurntSushi BurntSushi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@BurntSushi
BurntSushi merged commit 3d79fe9 into rust-lang:master Nov 7, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wrong leftmost-first match when alternation branches start with the same repetition

2 participants