Skip to content

fix: FindAllIndex vs FindAllSubmatchIndex return different match boundaries #176

Open

Description

@kolkov

FindAllIndex and FindAllSubmatchIndex can return different match boundaries for the same pattern and input, violating the invariant that both should agree on match positions.

Repro

re := coregex.MustCompile(`c?[[:alpha:]]{2}`)
input := " abccBy "

idx := re.FindAllStringIndex(input, -1)
fmt.Println("FindAllIndex:", idx)
// coregex: [[1 3] [3 5] [5 7]]   — took empty c? at each position

subIdx := re.FindAllStringSubmatchIndex(input, -1)
fmt.Println("FindAllSubmatchIndex:", subIdx)
// coregex: [[1 3] [3 6]]         — correctly took c at position 3
// stdlib:  [[1 3] [3 6]]

Another case — leftmost violation:

re2 := coregex.MustCompile(`[[:alpha:]]+?ab`)
fmt.Println(re2.FindAllStringIndex("abBCab", -1))
// coregex: [[2 6]]   — not leftmost
// stdlib:  [[0 6]]   — correct leftmost

Expected behavior

  1. FindAllIndex and FindAllSubmatchIndex must return identical match boundaries (the first two indices of each submatch entry must equal the corresponding index entry).
  2. Leftmost-first semantics: the engine must find the match that starts earliest, regardless of which code path is used.

Context

The two-phase search architecture (Phase 1: DFA finds boundaries, Phase 2: PikeVM extracts captures) can use different match logic than the single-phase PikeVM path. Patterns with optional prefixes expose the divergence.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: metaStrategy selection, engine orchestrationpriority: criticalRelease blocker, correctness regressiontype: bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions