abeln / dotty

Scala with explicit nulls
https://github.com/abeln/dotty/wiki/scala-with-explicit-nulls
Other
23 stars 2 forks source link

Merge Nullability Analysis; Changes according to #7546 #44

Closed noti0na1 closed 4 years ago

noti0na1 commented 5 years ago

Changes according to #7546

Merge Nullability Analysis

Others

noti0na1 commented 5 years ago

I rewrote the widenUnion as below:

case tp @ OrType(lhs, rhs) =>
  tp match {
    case OrNull(tp1) =>
      // Don't widen `T|Null`, since otherwise we wouldn't be able to infer nullable unions.
      val tp1Widen = tp1.widenUnion
      if (tp1Widen.isRef(defn.AnyClass)) tp1Widen
      else tp.derivedOrType(tp1Widen, defn.NullType)
    case _ =>
      ctx.typeComparer.lub(lhs.widenUnion, rhs.widenUnion, canConstrain = true) match {
        case union: OrType => union.join
        case res => res
      }
  }

Because the original implementation will infer incorrect type for this case:

class A
class B

val x: (A | Null) | B = ???
val y = x // the lub for A and B is AnyRef, but Any | Null is inferrred 

Also, I don't think using stripNull is very expensive here, and this is more readable.

noti0na1 commented 4 years ago

@abeln

-- [E007] Type Mismatch Error: tests/explicit-nulls/pos/ref-eq.scala:9:8 -----------------------------------------------
9 |  x1.ne(1)
  |        ^
  |        Found:    Int(1)
  |        Required: Object
-- [E007] Type Mismatch Error: tests/explicit-nulls/pos/ref-eq.scala:10:8 ----------------------------------------------
10 |  x1.eq(null)
   |        ^^^^
   |        Found:    Null
   |        Required: Object
-- [E007] Type Mismatch Error: tests/explicit-nulls/pos/ref-eq.scala:11:8 ----------------------------------------------
11 |  x1.ne(null)
   |        ^^^^
   |        Found:    Null
   |        Required: Object
-- [E007] Type Mismatch Error: tests/explicit-nulls/pos/ref-eq.scala:12:8 ----------------------------------------------
12 |  x1.eq(1) // ok: implicit conversion from int to Integer
   |        ^
   |        Found:    Int(1)
   |        Required: Object
-- [E007] Type Mismatch Error: tests/explicit-nulls/pos/ref-eq.scala:13:8 ----------------------------------------------
13 |  x1.ne(1) // ok: ditto
   |        ^
   |        Found:    Int(1)
   |        Required: Object
-- [E007] Type Mismatch Error: tests/explicit-nulls/pos/ref-eq.scala:14:8 ----------------------------------------------
14 |  x1.eq(x2)
   |        ^^
   |        Found:    (String | Null)(Test.this.x2)
   |        Required: Object
-- [E007] Type Mismatch Error: tests/explicit-nulls/pos/ref-eq.scala:15:8 ----------------------------------------------
15 |  x1.ne(x2)
   |        ^^
   |        Found:    (String | Null)(Test.this.x2)
   |        Required: Object
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:18:7 -------------------------------------------
18 |  null.eq("hello")
   |  ^^^^^^^
   |  value eq is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:19:7 -------------------------------------------
19 |  null.ne("hello")
   |  ^^^^^^^
   |  value ne is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:20:7 -------------------------------------------
20 |  null.eq(null)
   |  ^^^^^^^
   |  value eq is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:21:7 -------------------------------------------
21 |  null.ne(null)
   |  ^^^^^^^
   |  value ne is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:22:7 -------------------------------------------
22 |  null.eq(x2)
   |  ^^^^^^^
   |  value eq is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:23:7 -------------------------------------------
23 |  null.ne(x2)
   |  ^^^^^^^
   |  value ne is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:25:5 -------------------------------------------
25 |  x2.eq(null)
   |  ^^^^^
   |  value eq is not a member of String | Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:26:5 -------------------------------------------
26 |  x2.ne(null)
   |  ^^^^^
   |  value ne is not a member of String | Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:27:5 -------------------------------------------
27 |  x2.eq(x1)
   |  ^^^^^
   |  value eq is not a member of String | Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:28:5 -------------------------------------------
28 |  x2.ne(x1)
   |  ^^^^^
   |  value ne is not a member of String | Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:29:5 -------------------------------------------
29 |  x2.eq(x2)
   |  ^^^^^
   |  value eq is not a member of String | Null
-- [E008] Member Not Found Error: tests/explicit-nulls/pos/ref-eq.scala:30:5 -------------------------------------------
30 |  x2.ne(x2)
   |  ^^^^^
   |  value ne is not a member of String | Null
Compilation failed for: 'tests/explicit-nulls/pos/ref-eq.scala'          
-- [E008] Member Not Found Error: tests/explicit-nulls/run/subtype-any.scala:5:16 --------------------------------------
5 |    assert(null.eq(null))
  |           ^^^^^^^
  |           value eq is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/run/subtype-any.scala:6:17 --------------------------------------
6 |    assert(!null.ne(null))
  |            ^^^^^^^
  |            value ne is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/run/subtype-any.scala:8:17 --------------------------------------
8 |    assert(!null.eq("hello"))
  |            ^^^^^^^
  |            value eq is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/run/subtype-any.scala:9:16 --------------------------------------
9 |    assert(null.ne("hello"))
  |           ^^^^^^^
  |           value ne is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/run/subtype-any.scala:11:17 -------------------------------------
11 |    assert(!null.eq(4))
   |            ^^^^^^^
   |            value eq is not a member of Null
-- [E008] Member Not Found Error: tests/explicit-nulls/run/subtype-any.scala:12:16 -------------------------------------
12 |    assert(null.ne(4))
   |           ^^^^^^^
   |           value ne is not a member of Null
-- [E007] Type Mismatch Error: tests/explicit-nulls/run/subtype-any.scala:14:23 ----------------------------------------
14 |    assert(!"hello".eq(null))
   |                       ^^^^
   |                       Found:    Null
   |                       Required: Object
-- [E007] Type Mismatch Error: tests/explicit-nulls/run/subtype-any.scala:15:22 ----------------------------------------
15 |    assert("hello".ne(null))
   |                      ^^^^
   |                      Found:    Null
   |                      Required: Object
-- [E007] Type Mismatch Error: tests/explicit-nulls/run/subtype-any.scala:17:17 ----------------------------------------
17 |    assert(!4.eq(null))
   |                 ^^^^
   |                 Found:    Null
   |                 Required: Object
-- [E007] Type Mismatch Error: tests/explicit-nulls/run/subtype-any.scala:18:16 ----------------------------------------
18 |    assert(4.ne(null))
   |                ^^^^
   |                Found:    Null
   |                Required: Object
-- [E008] Member Not Found Error: tests/explicit-nulls/run/subtype-any.scala:21:13 -------------------------------------
21 |    assert(x.eq(null))
   |           ^^^^
   |           value eq is not a member of String | Null
-- [E008] Member Not Found Error: tests/explicit-nulls/run/subtype-any.scala:22:14 -------------------------------------
22 |    assert(!x.ne(null))
   |            ^^^^
   |            value ne is not a member of String | Null
-- [E008] Member Not Found Error: tests/explicit-nulls/run/subtype-any.scala:25:15 -------------------------------------
25 |    assert(!x2.eq(null))
   |            ^^^^^
   |            value eq is not a member of AnyRef | Null
-- [E008] Member Not Found Error: tests/explicit-nulls/run/subtype-any.scala:26:14 -------------------------------------
26 |    assert(x2.ne(null))
   |           ^^^^^
   |           value ne is not a member of AnyRef | Null
Compilation failed for: 'tests/explicit-nulls/run/subtype-any.scala'