Skip to content

Compiler loops when compiling a pattern match with a large number of patterns #12241

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
adamw opened this issue Apr 27, 2021 · 1 comment · Fixed by #12271
Closed

Compiler loops when compiling a pattern match with a large number of patterns #12241

adamw opened this issue Apr 27, 2021 · 1 comment · Fixed by #12271

Comments

@adamw
Copy link
Contributor

adamw commented Apr 27, 2021

Compiler version

3.0.0-RC3

Minimized code

That's as far as I've been able to minimize. Removing some of the cases, or matching against a single EndpointInput, not a tuple, makes the code compile.

I suspect it's a loop, as I can wait for a couple of minutes and compilation doesn't complete, CPU usage is high.

I'm running compilation through sbt.

sealed trait EndpointInput[T]

object EndpointInput {
  case class Pair[T]() extends EndpointInput[T]
  case class MappedPair[T]() extends EndpointInput[T]
  case class Pair2[T]() extends EndpointInput[T]
  case class MappedPair2[T]() extends EndpointInput[T]
  case class FixedMethod[T]() extends EndpointInput[T]
  case class FixedPath[T]() extends EndpointInput[T]
  case class PathCapture[T]() extends EndpointInput[T]
  case class PathsCapture[T]() extends EndpointInput[T]
  case class Query[T]() extends EndpointInput[T]
  case class QueryParams[T]() extends EndpointInput[T]
  case class Cookie[T]() extends EndpointInput[T]
  case class ExtractFromRequest[T]() extends EndpointInput[T]
  case class ApiKey[T]() extends EndpointInput[T]
  case class Http[T]() extends EndpointInput[T]
  case class Body[R, T]() extends EndpointInput[T]
  case class FixedHeader[T]() extends EndpointInput[T]
  case class Header[T]() extends EndpointInput[T]
  case class Headers[T]() extends EndpointInput[T]
  case class StatusCode[T]() extends EndpointInput[T]
  case class Empty[T]() extends EndpointInput[T]
}

object Test extends App {
  import EndpointInput._

  def compare(left: EndpointInput[_], right: EndpointInput[_]): Boolean =
    (left, right) match {
      case (Pair(), Pair()) => true
      case (MappedPair(), MappedPair()) => true
      case (Pair2(), Pair2()) => true
      case (MappedPair2(), MappedPair2()) => true
      case (FixedMethod(), FixedMethod()) => true
      case (FixedPath(), FixedPath()) => true
      case (PathCapture(), PathCapture()) => true
      case (PathsCapture(), PathsCapture()) => true
      case (Query(), Query()) => true
      case (QueryParams(), QueryParams()) => true
      case (Cookie(), Cookie()) => true
      case (ExtractFromRequest(), ExtractFromRequest()) => true
      case (ApiKey(), ApiKey()) => true
      case (Http(), Http()) => true
      case (Body(), Body()) => true
      case (FixedHeader(), FixedHeader()) => true
      case (Header(), Header()) => true
      case (Headers(), Headers()) => true
      case (StatusCode(), StatusCode()) => true
      case (_, _) => false
    }
}

Output

Fragment of the stack trace: https://gist.github.com/adamw/d06722ab6826aad108beca979065a90b

@adamw
Copy link
Contributor Author

adamw commented Apr 27, 2021

Work-around: split the pattern match into two stages (first the first half of the cases, then the second)

  def compare(left: EndpointInput[_], right: EndpointInput[_]): Boolean =
    (left, right) match {
      case (Pair(), Pair()) => true
      case (MappedPair(), MappedPair()) => true
      case (Pair2(), Pair2()) => true
      case (MappedPair2(), MappedPair2()) => true
      case (FixedMethod(), FixedMethod()) => true
      case (FixedPath(), FixedPath()) => true
      case (PathCapture(), PathCapture()) => true
      case (PathsCapture(), PathsCapture()) => true
      case (Query(), Query()) => true
      case (l, r) => (l, r) match {
        case (QueryParams(), QueryParams()) => true
        case (Cookie(), Cookie()) => true
        case (ExtractFromRequest(), ExtractFromRequest()) => true
        case (ApiKey(), ApiKey()) => true
        case (Http(), Http()) => true
        case (Body(), Body()) => true
        case (FixedHeader(), FixedHeader()) => true
        case (Header(), Header()) => true
        case (Headers(), Headers()) => true
        case (StatusCode(), StatusCode()) => true
        case (_, _) => false
      }
    }

liufengyun added a commit to dotty-staging/dotty that referenced this issue Apr 29, 2021
liufengyun added a commit that referenced this issue Apr 29, 2021
michelou pushed a commit to michelou/scala3 that referenced this issue May 1, 2021
liufengyun added a commit to dotty-staging/dotty that referenced this issue May 3, 2021
@Kordyjan Kordyjan added this to the 3.0.1 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants