Skip to content

Null and singletons cause inconsistencies #15069

Open
@s5bug

Description

@s5bug

Compiler version

3.1.1, 3.1.2

Example 1:

Transitivity of subtyping is violated:

val fredToFredOrWilma: "Fred" <:< ("Fred" | "Wilma") = summon

val nullToFred: Null <:< "Fred" = summon

val nullToFredOrWilma: Null <:< ("Fred" | "Wilma") = summon // errors

Output

no implicit argument of type T was found for parameter x of method summon in object Predef

where:    T is a type variable with constraint <: Null <:< (("Fred" : String) | ("Wilma" : String))

Expectation

Either:

  1. nullToFred fails
  2. <:< is transitive and Null <:< "Fred" <:< ("Fred" | "Wilma")

Example 2:

scala> val x: "Fred" = null
val x: "Fred" = null 
scala> x
val res1: String = Fred // notice this is not `null`!

Expectation

Either:

  1. null is not assignable to a "Fred"
  2. x reports a value of null

Example 3:

Null is accepted for variable .types but not object .types (which are both nullable in the JVM):

scala> val foo: Int = 1
val foo: Int = 1

scala> val fooNull: foo.type = null
-- [E007] Type Mismatch Error: -------------------------------------------------
1 |val fooNull: foo.type = null
  |                        ^^^^
  |                        Found:    Null
  |                        Required: (foo : Int)

longer explanation available when compiling with `-explain`
1 error found

scala> val bar: String = "bar"
val bar: String = bar

scala> val barNull: bar.type = null
val barNull: bar.type = null

scala> object baz
// defined object baz

scala> val bazNull: baz.type = null
-- [E007] Type Mismatch Error: -------------------------------------------------
1 |val bazNull: baz.type = null
  |                        ^^^^
  |                        Found:    Null
  |                        Required: baz.type

longer explanation available when compiling with `-explain`
1 error found

Expectation

Either:

  1. null should not be accepted as an inhabitant of bar.type
  2. null should be accepted as an inhabitant of baz.type

Example 4:

Unions of two singletons don't accept null, but not a union of a singleton and a non-nullable:

scala> val f: "Foo" = null
val f: "Foo" = null

scala> val g: ("Foo" | 1) = null
-- [E007] Type Mismatch Error: -------------------------------------------------
1 |val g: ("Foo" | 1) = null
  |                     ^^^^
  |                     Found:    Null
  |                     Required: ("Foo" : String) | (1 : Int)

longer explanation available when compiling with `-explain`
1 error found

scala> val h: ("Foo" | Int) = null
val h: "Foo" | Int = null

scala> val i: ("Foo" | "Bar") = null
-- [E007] Type Mismatch Error: -------------------------------------------------
1 |val i: ("Foo" | "Bar") = null
  |                         ^^^^
  |                         Found:    Null
  |                         Required: ("Foo" : String) | ("Bar" : String)

longer explanation available when compiling with `-explain`
1 error found

Expectation

Either:

  1. The declarations for f and h are invalid
  2. The declarations for g and i are valid

If Scala 2 behaviors are wanted to be kept, then the proper path is taking the (2.) options.

However, if (2.) is taken, it means that any AnyRef & Singleton will actually have two values, not one.

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