Skip to content

"case" function literal incorrectly desugared #873

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 Oct 27, 2015 · 4 comments
Closed

"case" function literal incorrectly desugared #873

smarter opened this issue Oct 27, 2015 · 4 comments

Comments

@smarter
Copy link
Member

smarter commented Oct 27, 2015

object Test {
  def call(k: (Int, Int) => Unit): Unit = ???
  def test = call({ case (x, y) => ()})
}

This fails with:

funlit.scala:9: error: wrong number of parameters, expected: 2
  def test = call({ case (x, y) => ()})
                  ^
result of funlit.scala after frontend:
package <empty> {
  final lazy module val Test: Test$ = new Test$()
  final module class Test$() extends Object() { this: Test.type => 
    def call(k: Function2[Int, Int, Unit]): Unit = ???
    def test: Unit = 
      Test.call({
        def $anonfun(x$1: <error>): Unit = 
          x$1 match {
            case Tuple2.unapply[Nothing', Nothing'](x @ _, y @ _) => 
              ()
          }
        closure($anonfun)
      })
  }
}
two errors found

Because { case (x, y) => ()} is expanded to x$1 => x$1 match { case (x, y) => ()}, instead it should be expanded to (x$1, x$2) => (x$1, x$2) match { case (x, y) => ()} (like in Scala 2) because this compiles fine in Dotty:

object Test {
  def call(k: (Int, Int) => Unit): Unit = ???
  def test = call((a, b) => (a, b) match { case (x, y) => ()})
}
@odersky
Copy link
Contributor

odersky commented Oct 27, 2015

That's certainly not as specified. I don't know what scalac does here. But
note that the following also compiles in scalac and dotty:

val xs = List(1, 2, 3).zipWithIndex

xs.map{ (case (x, y) => x + y }

And the translation is x$1: (Int, Int) => x$1 match ...

So it seems scalac does some conversion according to the expected type. I
think doing some conversion here is OK, but it should be done for the
version without case. I.e.

 xs.map((x, y) => x + y)

should work. But the example you gave should not work. Can you file another
issue along these lines?

On Tue, Oct 27, 2015 at 3:12 AM, Guillaume Martres <[email protected]

wrote:

object Test {
def call(k: (Int, Int) => Unit): Unit = ???
def test = call({ case (x, y) => ()})
}

This fails with:

funlit.scala:9: error: wrong number of parameters, expected: 2
def test = call({ case (x, y) => ()})
^
result of funlit.scala after frontend:
package {
final lazy module val Test: Test$ = new Test$()
final module class Test$() extends Object() { this: Test.type =>
def call(k: Function2[Int, Int, Unit]): Unit = ???
def test: Unit =
Test.call({
def $anonfun(x$1: ): Unit =
x$1 match {
case Tuple2.unapply[Nothing', Nothing'](x @ _, y @ _) =>
()
}
closure($anonfun)
})
}
}
two errors found

Because { case (x, y) => ()} is expanded to x$1 => x$1 match { case (x,
y) => ()}, instead it should be expanded to (x$1, x$2) => (x$1, x$2)
match { case (x, y) => ()} (like in Scala 2) because this compiles fine
in Dotty:

object Test {
def call(k: (Int, Int) => Unit): Unit = ???
def test = call((a, b) => (a, b) match { case (x, y) => ()})
}


Reply to this email directly or view it on GitHub
#873.

Martin Odersky
EPFL

@smarter
Copy link
Member Author

smarter commented Oct 27, 2015

I think doing some conversion here is OK, but it should be done for the version without case.

So that would be the inverse of what scalac is doing, since List(1, 2, 3).zipWithIndex.map((x, y) => x + y) does not work in scalac. Supporting that would be nice, but it does not help for more complex examples like:

object Test {
  def call(k: (Int, Int) => Int): Unit = ???
  def test = call({
    case (1, 2) => 1
    case (a, b) => a + b
  })
}

Do you think we could have a nicer way of expressing this in dotty than:

  def test = call((_, _) match {
    case (1, 2) => 1
    case (a, b) => a + b
  })

?
I'm wondering about this because I got SBT integration working with dotty and tried to get molecule-core in https://github.com/molecule-labs/molecule to compile with dotty (because it's reasonably large and has no dependencies), and it uses case function literals often.

@odersky
Copy link
Contributor

odersky commented Oct 27, 2015

Maybe ask on the scala gitter. As far as I can see this is a bug in scalac.
The spec has no provisions to allow the behavior you describe.

Cheers

  • Martin

On Tue, Oct 27, 2015 at 5:09 PM, Guillaume Martres <[email protected]

wrote:

I think doing some conversion here is OK, but it should be done for the
version without case.

So that would be the inverse of what scalac is doing, since List(1, 2,
3).zipWithIndex.map((x, y) => x + y) does not work in scalac. Supporting
that would be nice, but it does not help for more complex examples like:

object Test {
def call(k: (Int, Int) => Int): Unit = ???
def test = call({
case (1, 2) => 1
case (a, b) => a + b
})
}

Do you think we could have a nicer way of expressing this in dotty than:

def test = call((_, _) match {
case (1, 2) => 1
case (a, b) => a + b
})

?
I'm wondering about this because I got SBT integration working with dotty
and tried to get molecule-core in
https://github.com/molecule-labs/molecule to compile with dotty (because
it's reasonably large and has no dependencies), and it uses case function
literals often.


Reply to this email directly or view it on GitHub
#873 (comment).

Martin Odersky
EPFL

odersky added a commit to dotty-staging/dotty that referenced this issue Oct 30, 2015
This is sepcified in Sec. 8.5 of the SLS. Fixes scala#873. Review by @smarter.
@SethTisue
Copy link
Member

at https://gitter.im/scala/contributors?at=56332776196bdeec543b9ac3 @odersky writes "It is specified in Sec. 8.5 of the Spec. So, it’s a feature, not a bug, after all"

odersky referenced this issue Nov 2, 2015
Allow pattern matching anonymous functions of arity > 1
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

3 participants