Skip to content

Stack overflow in LabelDef phase when pattern matching on many complex cases #2903

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
smarter opened this issue Jul 22, 2017 · 0 comments
Closed

Comments

@smarter
Copy link
Member

smarter commented Jul 22, 2017

This code compiles fine with Scala 2.11 and 2.12 but stack overflows in Dotty (both with the old and new patmat, even with -optimise):

case class Foo01(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo02(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo03(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo04(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo05(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo06(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo07(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo08(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo09(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo10(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo11(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo12(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo13(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo14(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo15(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo16(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo17(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo18(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo19(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo20(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo21(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo22(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo23(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo24(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo25(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo26(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo27(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo28(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)
case class Foo29(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int)

object Test {
  def stuff() = {}

  def test(x: Any): Unit = x match {
    case Foo01(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo02(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo03(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo04(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo05(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo06(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo07(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo08(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo09(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo11(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo13(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo14(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo15(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo17(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo18(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo19(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo20(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo21(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo22(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo23(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo24(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo25(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo26(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo27(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo28(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
    case Foo29(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) => stuff()
  }
}

By commenting out 4 cases you can make it go a bit further and only die with a stack overflow in GenBCode.

The corresponding real world code I'm looking at is https://github.com/epfl-lara/stainless/blob/bf0ef122f4d3b3c9a852425e4db9ca55941398bc/frontends/dotty/src/main/scala/stainless/frontends/dotc/CodeExtraction.scala#L674-L1205

nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Nov 28, 2017
* Extract all match arguments before checking conditions on them like scalac does.
  This avoids an extra nested block for each match variable.
* Merge conditions of nested `if` expressions if their `else` branch is the same.
  This optimization combined with the previous removes most of the nested `if`s
  created to check the matched args.
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Nov 28, 2017
* Extract all match arguments before checking conditions on them like scalac does.
  This avoids an extra nested block for each match variable.
* Merge conditions of nested `if` expressions if their `else` branch is the same.
  This optimization combined with the previous removes most of the nested `if`s
  created to check the matched args.
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Nov 29, 2017
* Extract all match arguments before checking conditions on them like scalac does.
  This avoids an extra nested block for each match variable.
* Merge conditions of nested `if` expressions if their `else` branch is the same.
  This optimization combined with the previous removes most of the nested `if`s
  created to check the matched args.
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Nov 29, 2017
* Extract all match arguments before checking conditions on them like scalac does.
  This avoids an extra nested block for each match variable.
* Merge conditions of nested `if` expressions if their `else` branch is the same.
  This optimization combined with the previous removes most of the nested `if`s
  created to check the matched args.
odersky added a commit that referenced this issue Dec 23, 2017
Fix #2903: Reduce the depth of trees generated in PatternMatcher
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant