Skip to content

Function returning Nothing has over-specialised type in default parameter #23873

@katrinafyi

Description

@katrinafyi

This means that some type-safe code will fail to compile.

Compiler version

Tested on 3.7.2, 3.3.6, 3.7.3-RC1, 3.0.0 (all via scastie)

Minimized code

https://scastie.scala-lang.org/b1zJrCWFR9yD71xTREwJtA

trait C[T] {
}

class Cls[T](f: T => C[T] = (x: T) => throw new Exception("a"))

val _ = Cls[Int]() // doesn't compile


def f[T](g: T => C[T] = (x: T) => throw new Exception("a")) = ()
val _ = f[Int]() // doesn't compile

def default[T](x: T) = ???
class Cls2[T](f: T => C[T] = default[T])
val _ = new Cls2[Int]() // doesn't compile

Output

Note that the return type of the function / lambda is over-specifialised to C[Nothing], despite the fact there's no code to restrict it to that. This causes a type error at the call-site of the constructor/function.

It is not clear why the type error happens only when calling, rather than when defining the default parameter.

[error] -- [E007] Type Mismatch Error: /home/X.scala:6:8 
[error] 6 |val _ = Cls[Int]() // doesn't compile
[error]   |        ^^^^^^^^
[error]   |        Found:    Int => C[Nothing]
[error]   |        Required: Int => C[Int]
[error]   |
[error]   | longer explanation available when compiling with `-explain`
[error] -- [E007] Type Mismatch Error: /home/X.scala:10:8 
[error] 10 |val _ = f[Int]() // doesn't compile
[error]    |        ^^^^^^
[error]    |        Found:    Int => C[Nothing]
[error]    |        Required: Int => C[Int]
[error]    |
[error]    | longer explanation available when compiling with `-explain`
[error] -- [E007] Type Mismatch Error: /home/X.scala:14:12 
[error] 14 |val _ = new Cls2[Int]() // doesn't compile
[error]    |            ^^^^^^^^^
[error]    |            Found:    Int => C[Nothing]
[error]    |            Required: Int => C[Int]
[error]    |
[error]    | longer explanation available when compiling with `-explain`

Expectation

As far as I can tell, this code should type-check. The function's return type should be Nothing, so it should be coercible to the required T => C[T] type.

These changes will cause the code to start compiling:

  • changing the parameter type to T => Nothing
  • adding a variance annotation to C, either + or - will work
  • type-annotating the function with : T => C[T] or : T => Nothing
  • type-annotating the throwing expression as (throw new Exception()): C[T]
  • explicitly passing the parameter, even without removing the default parameter
  • using scala 2.13.16

These changes will not cause the code to compile:

  • changing the parameter field to a var or val
  • type-annotating the throwing expression as (??? : Nothing)

Given the longevity of this bug, I'd be surprised if it hadn't been seen before, but I couldn't find any other reports with a quick search.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions