Skip to content

Pattern Matching generates incorrect code when matching a nested case class #431

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 Mar 25, 2015 · 5 comments
Closed

Comments

@smarter
Copy link
Member

smarter commented Mar 25, 2015

The following code:

case class Foo(val underlying: Int)

object O {
  def test(): Unit = {
    val x: Option[Foo] = Some(Foo(1))
    x match {
      case Some(m) =>
        println(m)
    }
  }
}

Generates after patternMatcher:

final module class O$() extends Object() { this: O.type => 
  def test(): Unit = {
    val x: Option[Foo] = Some.apply[Foo'](Foo.apply(1))
    {
      case val selector12: Option[Foo] = x
      {
        def case31(): Unit = {
          def matchFail21(): Unit = throw new MatchError(selector12)
          if selector12.isInstanceOf[Some[Foo']] then {
            val x21: Some[Foo'] = selector12.asInstanceOf[Some[Foo']]
            {
              val o41: Option[Foo] = 
                Some.unapply[Foo'](selector12.asInstanceOf[Some[Foo']])
              if o41.isDefined then {
                val x31: Foo = o41.get
                {
                  val m: Foo = x31._1.asInstanceOf[Foo]
                  {
                    {
                      println(m)
                    }
                  }
                }
              } else matchFail21()
            }
          } else matchFail21()
        }
        case31()
      }
    }
  }
}

Note that x31 has type Foo, but the next line calls x31._1.asInstanceOf[Foo] which does not make sense as the accessor of Foo has type Int, not Foo.

@smarter
Copy link
Member Author

smarter commented Mar 25, 2015

@DarkDimius : Could you take a look ?

@DarkDimius
Copy link
Contributor

@smarter could you test for case class with 2 fields, will the problem persist?
It seems that I haven't entirely fixed https://issues.scala-lang.org/browse/SI-7897

@smarter
Copy link
Member Author

smarter commented Mar 25, 2015

@DarkDimius: with 2 fields in Foo, same problem:

final module class O$() extends Object() { this: O.type => 
  def test(): Unit = {
    val x: Option[Foo] = Some.apply[Foo'](Foo.apply(1, 2))
    {
      case val selector12: Option[Foo] = x
      {
        def case31(): Unit = {
          def matchFail21(): Unit = throw new MatchError(selector12)
          if selector12.isInstanceOf[Some[Foo']] then {
            val x21: Some[Foo'] = selector12.asInstanceOf[Some[Foo']]
            {
              val o41: Option[Foo] = 
                Some.unapply[Foo'](selector12.asInstanceOf[Some[Foo']])
              if o41.isDefined then {
                val x31: Foo = o41.get
                {
                  val m: Foo = x31._1.asInstanceOf[Foo]
                  {
                    {
                      println(m)
                    }
                  }
                }
              } else matchFail21()
            }
          } else matchFail21()
        }
        case31()
      }
    }
  }
}

@smarter
Copy link
Member Author

smarter commented Mar 25, 2015

The problem doesn't seem to happen if I replace Option by a custom case class:

case class Foo(val ff: Int)
sealed trait Option2[T]
case class Some2[T](underlying: T) extends Option2[T]
case object None2 extends Option2[Nothing]

object O {
  def test(): Unit = {
    val x: Option2[Foo] = Some2(Foo(1))
    x match {
      case Some2(m) =>
        println(m)
    }
  }
}

Becomes:

final module class O$() extends Object() { this: O.type => 
  def test(): Unit = {
    val x: Option2[Foo] = Some2.apply[Foo'](Foo.apply(1))
    {
      case val selector13: Option2[Foo] = x
      {
        def case51(): Unit = {
          def matchFail31(): Unit = throw new MatchError(selector13)
          if selector13.isInstanceOf[Some2[Foo']] then {
            val x21: Some2[Foo'] = selector13.asInstanceOf[Some2[Foo']]
            {
              val x31: Some2[Foo] = 
                Some2.unapply[Foo'](selector13.asInstanceOf[Some2[Foo']])
              {
                val m: Foo = x31._1
                {
                  {
                    println(m)
                  }
                }
              }
            }
          } else matchFail31()
        }
        case51()
      }
    }
  }
}

@DarkDimius
Copy link
Contributor

b8807ca I guess should fix it, but I'm not sure if it wouldn't break something else.
That's a particular moment when we need run tests to validate that pattern matching does what it should do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants