Skip to content

Compiler generated implicit conversion between function literal and PartialFunction #4241

Closed
@allanrenucci

Description

@allanrenucci

Scalac and Dotty both implicitly convert from function literals to PartialFunction. For example, one can write:

val foo: PartialFunction[Int, String] = x => x.toString

However 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, implements isDefinedAt in term of the cases, otherwise returns true
  • Scalac: if the rhs is a match, implements isDefinedAt in term of the cases, 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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions