Skip to content

Tuple-returning unapply for capture groups needs compile-time-known arity, not runtime CaptureMatcher.parse #73

Description

@halotukozak

Follow-up to #52, scoped down from it: today's CaptureMatcher.unapplySeq (Capture.scala:84, landed in 5bee7d5) is Seq-based, mirroring scala.util.matching.Regex.unapplySeq - case myMatcher(g1, g2) => ... works, but arity is checked structurally at the match site against a runtime Seq, not against a fixed tuple type.

Why it's Seq and not Tuple2/Tuple3/...: CaptureMatcher.numGroups (Capture.scala:68) is a runtime value, only known after CaptureMatcher.parse(pattern: String) (Capture.scala:91) parses a fully dynamic string. CaptureMatcher itself carries no type-level trace of that arity - two instances built from "(a)(b)" vs "(a)(b)(c)" have the identical type CaptureMatcher. A Tuple-returning unapply needs the arity fixed in the type the compiler sees at the case myMatcher(g1, g2) => site, which a single def unapply(...) on the class can't vary per-instance.

What a tuple-returning variant would need:

  • Arity known at Scala compile time, i.e. the pattern must be a literal (inline/macro), not an arbitrary runtime String - CaptureMatcher.parse can't serve this, since it's explicitly the dynamic, Either[RegexParseError, CaptureMatcher]-returning entry point.
  • Some way to carry that arity in the type - either a phantom type param (CaptureMatcher[N <: Int & Singleton]) or a distinct macro-produced carrier type, echoing how TokenMatcher is already a separate compiled artifact rather than bolted onto Regex (see Support case myRegex(g1, g2) => ... pattern matching once capturing groups exist #52's own "Needs a decision on the carrier type" note, and the precedent in Add a compile-time macro that builds TokenMatcher's DFA, not just parses to Regex #51 for macro-time compilation of a literal pattern set).
  • A decision on where this lives: extending CaptureMatcher with an inline compile-time-literal entry point alongside the existing runtime parse, vs. a wholly separate type.

Not a small tweak to the existing unapplySeq - it's a distinct compile-time-macro feature, so splitting it out of #52 rather than reopening scope there.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions