Skip to content

The Singleton "kind" is not an upper bound #4944

Open
@Blaisorblade

Description

@Blaisorblade

A few of us discussed this, but it seems we lack an issue for it. Quoting from #4942:

If A <: Singleton and B <: Singleton, it follows that A | B <: Singleton, but for instance 1 | 2 is not actually a singleton type.

In fact, already in Scala 2 we can exploit this and write the questionable

  def f[Bound, A <: Bound, B <: Bound](cond: Boolean, a: A, b: B): Bound = if (cond) a else b
  def g(cond: Boolean): Singleton = f[Singleton, 1, 2](cond, 1, 2)

In Dotty we also get the clearly broken:

  def f[Bound, A <: Bound, B <: Bound](cond: Boolean, a: A, b: B): (A | B) & Bound = if (cond) a else b
  def g(cond: Boolean): Singleton = f[Singleton, 1, 2](cond, 1, 2)
  // def h(cond: Boolean): (1|2) & Singleton = f[Singleton, 1, 2](cond, 1, 2) // doesn't compile
  type || [A, B] = A | B
  type Boo = 0 || 1

  // def h1(cond: Boolean): (1||2) & Singleton = f[Singleton, 1, 2](cond, 1, 2) // still fails because 1 | 2 is collapsed eagerly

def f2[Bound, A <: Bound, B <: Bound](cond: Boolean, a: A, b: B): (A || B) & Bound = if (cond) a else b

def h2(cond: Boolean): (1||2) & Singleton = f2[Singleton, 1, 2](cond, 1, 2)
def h2(cond: Boolean): Int(1) Any Int(2) & Singleton

Only h fails, and just because we forbid 1|2 syntactically for now (#1551), so h2 works.
Since Singleton is special in core typing rules, @odersky suggested this endangers even soundness. Ad-hoc restrictions (say, forbidding Singleton as a type argument) seems a losing whack-a-mole game.

Discussing this with @odersky today, we figured that Singleton behaves like a kind that can't be expressed via upper bounds, so we should consider something like an annotation or a modifier (tho modifiers on type variables don't exist yet).

Migration isn't easy, but one can easily support simple use cases of form [X <: Singleton] or even [X <: Foo with Singleton]. According to @nicolasstucki, even type SingAlias = Singleton; def foo[X <: Foo with SingAlias] doesn't currently work.

Paging @milessabin and @soronpo, as this affects SIP-23.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions