Skip to content

Bug while merging vars in pattern matcher #4449

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
nicolasstucki opened this issue May 3, 2018 · 1 comment
Closed

Bug while merging vars in pattern matcher #4449

nicolasstucki opened this issue May 3, 2018 · 1 comment

Comments

@nicolasstucki
Copy link
Contributor

nicolasstucki commented May 3, 2018

The folowing pattern match produces buggy code when hoistLabels is applied in PatternMatcher.
This code can crate bytecode that crashes the JVM.

class TreeAccumulator2 {

  def foo(tasty: Tasty2)(tree: Any): Unit = {
    import tasty._
    tree match {
      case A() =>
      case B() =>
      case C() =>
      case D() =>
    }
  }

}

abstract class Tasty2 {

  type X
  type Y

  implicit def xct: scala.reflect.ClassTag[X]
  implicit def yct: scala.reflect.ClassTag[Y]

  val A: AExtractor
  trait AExtractor {
    def unapply(x: X): Boolean
  }

  val B: BExtractor
  trait BExtractor {
    def unapply(x: X): Boolean
  }

  val C: CExtractor
  trait CExtractor {
    def unapply(x: Y): Boolean // Note the type Y
  }

  val D: DExtractor
  trait DExtractor {
    def unapply(x: X): Boolean
  }

}
exception while typing package <empty> {
  @scala.annotation.internal.SourceFile("tests/pos/tasty-pat-match.scala") class
     
  TreeAccumulator2() extends Object() { 
    def foo(tasty: Tasty2)(tree: Any): Unit = 
      {
        {
          case val x1: Any(tree) = tree
          def case1(): Unit = throw new MatchError(x1)
          def case2(case x21: Option[tasty.X]): Unit = 
            if x21.isEmpty.unary_! then 
              {
                case val x3: tasty.X = x21.get
                if x3.asInstanceOf[Object].ne(null).&&(tasty.D.unapply(x3)) then
                   
                {
                  ()
                }
                 else case1()
              }
             else case1()
          def case3(case x17: Option[tasty.X]): Unit = 
            {
              case val x5: Option[tasty.Y] = tasty.yct.unapply(x1)
              if x5.isEmpty.unary_! then 
                {
                  case val x6: tasty.Y = x5.get
                  if x6.asInstanceOf[Object].ne(null).&&(tasty.C.unapply(x6))
                     then
                   
                    {
                      ()
                    }
                   else case2(x17)
                }
               else case2(x17)
            }
          def case4(case x14: Option[tasty.X]): Unit = 
            {
              case val x9: tasty.X = x14.get
              if x9.asInstanceOf[Object].ne(null).&&(tasty.B.unapply(x9)) then 
                {
                  ()
                }
               else case3(x14)
            }
          if x1.asInstanceOf[Object].ne(null) then 
            {
              case val x11: Option[tasty.X] = tasty.xct.unapply(x1)
              if x11.isEmpty.unary_! then 
                {
                  case val x12: tasty.X = x11.get
                  if x12.asInstanceOf[Object].ne(null).&&(tasty.A.unapply(x12))
                     then
                   
                    {
                      ()
                    }
                   else case4(x11)
                }
               else case3(x14)
            }
           else case1()
        }
      }
  }
  @scala.annotation.internal.SourceFile("tests/pos/tasty-pat-match.scala") 
    abstract
   class Tasty2() extends Object() { 
    type X
    type Y
    implicit def xct: ClassTag[Tasty2.this.X]
    implicit def yct: ClassTag[Tasty2.this.Y]
    val A: Tasty2.this.AExtractor
    <trait> interface trait AExtractor() extends Object { 
      def unapply(x: Tasty2.this.X): Boolean
    }
    val B: Tasty2.this.BExtractor
    <trait> interface trait BExtractor() extends Object { 
      def unapply(x: Tasty2.this.X): Boolean
    }
    val C: Tasty2.this.CExtractor
    <trait> interface trait CExtractor() extends Object { 
      def unapply(x: Tasty2.this.Y): Boolean
    }
    val D: Tasty2.this.DExtractor
    <trait> interface trait DExtractor() extends Object { 
      def unapply(x: Tasty2.this.X): Boolean
    }
  }
}

The error is that the last call to case3 has x14 as parameter but it should have x11.

@nicolasstucki
Copy link
Contributor Author

Actually, it is mergeVars which messes up.

@nicolasstucki nicolasstucki changed the title Bug while hoisting labels in pattern matcher Bug while merging vars in pattern matcher May 3, 2018
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue May 3, 2018
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue May 4, 2018
nicolasstucki added a commit that referenced this issue May 8, 2018
Fix #4449: PatternMatcher needs to split call nodes if arguments differ
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue May 11, 2018
* Define TASTY data types in scala.tasty
* Add method get a TASTY term from a quoted.Expr[T]
* Implement TASTY tree extractors

Use direct extractors for tasty trees

Workaround issue scala#4449

Rename TopLevelStatement to Tree
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue May 19, 2018
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue May 24, 2018
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

2 participants