-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Scalac and Dotty both implicitly convert from function literals to PartialFunction. For example, one can write:
val foo: PartialFunction[Int, String] = x => x.toStringHowever this conversion is different in Dotty and Scalac. The compilers need to generate an implementation for def isDefinedAt(x: A): Boolean. Both compilers inspect the rhs of the function literal:
- Dotty: if the rhs is a
match, implementsisDefinedAtin term of thecases, otherwise returnstrue - Scalac: if the rhs is a
match, implementsisDefinedAtin term of thecases, otherwise fails to compile
This leads to surprising behaviors:
val a: PartialFunction[Int, String] = x => x match { case 1 => x.toString }
a.isDefinedAt(2) // Dotty: false, Scalac: false
val b: PartialFunction[Int, String] = x => { x match { case 1 => x.toString } }
b.isDefinedAt(2) // Dotty: true, Scalac: false
val c: PartialFunction[Int, String] = x => { println("foo"); x match { case 1 => x.toString } }
c.isDefinedAt(2) // Dotty: true
// Scalac:
// error: type mismatch;
// found : Int => String
// required: PartialFunction[Int,String]I would argue that a function literal is a partial function that is always defined and both Dotty and Scalac are wrong.
Note: It works like this in Dotty because the compiler desugars partial function literals into function literals:
{ case 1 => x.toString } // becomes x => x match { case 1 => x.toString }Then when the compiler generates the isDefined method, it doesn't differentiate between a tree that was originally a partial function literal and one that was a function literal