Skip to content

Commit 3945e96

Browse files
committed
Under explicit nulls, remove the rule Null <:< x.type.
The specified rule that `Null <:< x.type` when the underlying type `U` of `x` is nullable is dubious to begin with. Under explicit nulls, it becomes decidedly out of place. We now disable that rule under `-Yexplicit-nulls`.
1 parent 65363f9 commit 3945e96

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
954954
// scala.AnyRef [Scala 3: which scala.Null conforms to], the type denotes the set of values consisting
955955
// of null and the value denoted by p (i.e., the value v for which v eq p). [Otherwise,] the type
956956
// denotes the set consisting of only the value denoted by p.
957-
isNullable(tp.underlying) && tp.isStable
957+
!ctx.explicitNulls && isNullable(tp.underlying) && tp.isStable
958958
case tp: RefinedOrRecType => isNullable(tp.parent)
959959
case tp: AppliedType => isNullable(tp.tycon)
960960
case AndType(tp1, tp2) => isNullable(tp1) && isNullable(tp2)

tests/explicit-nulls/neg/i17467.check

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
-- [E007] Type Mismatch Error: tests/explicit-nulls/neg/i17467.scala:4:22 ----------------------------------------------
2+
4 | val a2: a1.type = null // error
3+
| ^^^^
4+
| Found: Null
5+
| Required: (a1 : String)
6+
| Note that implicit conversions were not tried because the result of an implicit conversion
7+
| must be more specific than (a1 : String)
8+
|
9+
| longer explanation available when compiling with `-explain`
10+
-- [E007] Type Mismatch Error: tests/explicit-nulls/neg/i17467.scala:7:22 ----------------------------------------------
11+
7 | val b2: b1.type = null // error
12+
| ^^^^
13+
| Found: Null
14+
| Required: (b1 : String | Null)
15+
| Note that implicit conversions were not tried because the result of an implicit conversion
16+
| must be more specific than (b1 : String | Null)
17+
|
18+
| longer explanation available when compiling with `-explain`
19+
-- [E172] Type Error: tests/explicit-nulls/neg/i17467.scala:8:28 -------------------------------------------------------
20+
8 | summon[Null <:< b1.type] // error
21+
| ^
22+
| Cannot prove that Null <:< (b1 : String | Null).
23+
-- [E007] Type Mismatch Error: tests/explicit-nulls/neg/i17467.scala:14:22 ---------------------------------------------
24+
14 | val c2: c1.type = null // error
25+
| ^^^^
26+
| Found: Null
27+
| Required: (c1 : Null)
28+
| Note that implicit conversions were not tried because the result of an implicit conversion
29+
| must be more specific than (c1 : Null)
30+
|
31+
| longer explanation available when compiling with `-explain`

tests/explicit-nulls/neg/i17467.scala

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
object Test:
2+
def test(): Unit =
3+
val a1: String = "foo"
4+
val a2: a1.type = null // error
5+
6+
val b1: String | Null = "foo"
7+
val b2: b1.type = null // error
8+
summon[Null <:< b1.type] // error
9+
10+
/* The following would be sound, but it would require a specific subtyping
11+
* rule (and implementation code) for debatable value. So it is an error.
12+
*/
13+
val c1: Null = null
14+
val c2: c1.type = null // error
15+
end test
16+
end Test

0 commit comments

Comments
 (0)