Skip to content

Commit db0d5f9

Browse files
committed
Rename stripNull
1 parent 08fc382 commit db0d5f9

File tree

9 files changed

+54
-26
lines changed

9 files changed

+54
-26
lines changed

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -613,8 +613,7 @@ class Definitions {
613613
@tu lazy val StringModule: Symbol = StringClass.linkedClass
614614
@tu lazy val String_+ : TermSymbol = enterMethod(StringClass, nme.raw.PLUS, methOfAny(StringType), Final)
615615
@tu lazy val String_valueOf_Object: Symbol = StringModule.info.member(nme.valueOf).suchThat(_.info.firstParamTypes match {
616-
case List(pt) =>
617-
pt.isAny || pt.stripNull.isAnyRef
616+
case List(pt) => pt.isAny || pt.stripNullWhenExplicit.isAnyRef
618617
case _ => false
619618
}).symbol
620619

@@ -626,13 +625,13 @@ class Definitions {
626625
@tu lazy val ClassCastExceptionClass: ClassSymbol = requiredClass("java.lang.ClassCastException")
627626
@tu lazy val ClassCastExceptionClass_stringConstructor: TermSymbol = ClassCastExceptionClass.info.member(nme.CONSTRUCTOR).suchThat(_.info.firstParamTypes match {
628627
case List(pt) =>
629-
pt.stripNull.isRef(StringClass)
628+
pt.stripNullWhenExplicit.isRef(StringClass)
630629
case _ => false
631630
}).symbol.asTerm
632631
@tu lazy val ArithmeticExceptionClass: ClassSymbol = requiredClass("java.lang.ArithmeticException")
633632
@tu lazy val ArithmeticExceptionClass_stringConstructor: TermSymbol = ArithmeticExceptionClass.info.member(nme.CONSTRUCTOR).suchThat(_.info.firstParamTypes match {
634633
case List(pt) =>
635-
pt.stripNull.isRef(StringClass)
634+
pt.stripNullWhenExplicit.isRef(StringClass)
636635
case _ => false
637636
}).symbol.asTerm
638637

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object NullOpsDecorator {
1717
* If this type isn't (syntactically) nullable, then returns the type unchanged.
1818
* The type will not be changed if explicit-nulls is not enabled.
1919
*/
20-
def stripNull(using Context): Type = {
20+
def stripNullWhenExplicit(using Context): Type = {
2121
def strip(tp: Type): Type =
2222
val tpWiden = tp.widenDealias
2323
val tpStriped = tpWiden match {
@@ -47,7 +47,7 @@ object NullOpsDecorator {
4747

4848
/** Is self (after widening and dealiasing) a type of the form `T | Null`? */
4949
def isNullableUnion(using Context): Boolean = {
50-
val stripped = self.stripNull
50+
val stripped = self.stripNullWhenExplicit
5151
stripped ne self
5252
}
5353

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,7 @@ object Types {
833833
case OrNull(tp1) if Feature.unsafeNullsEnabled =>
834834
// Selecting `name` from a type `T | Null` is like selecting `name` from `T`, if
835835
// unsafeNulls is enabled. This can throw at runtime, but we trade soundness for usability.
836-
tp1.findMember(name, pre.stripNull, required, excluded)
836+
tp1.findMember(name, pre.stripNullWhenExplicit, required, excluded)
837837
case _ =>
838838
// we need to keep the invariant that `pre <: tp`. Branch `union-types-narrow-prefix`
839839
// achieved that by narrowing `pre` to each alternative, but it led to merge errors in
@@ -3178,7 +3178,7 @@ object Types {
31783178
def apply(tp: Type)(using Context) =
31793179
if tp.isNullType then tp else OrType(tp, defn.NullType, soft = false)
31803180
def unapply(tp: Type)(using Context): Option[Type] =
3181-
val tp1 = tp.stripNull
3181+
val tp1 = tp.stripNullWhenExplicit
31823182
if tp1 ne tp then Some(tp1) else None
31833183
}
31843184

compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ExpandSAMs extends MiniPhase {
4646
checkRefinements(tpe, fn)
4747
tree
4848
case tpe =>
49-
val tpe1 = checkRefinements(tpe.stripNull, fn)
49+
val tpe1 = checkRefinements(tpe.stripNullWhenExplicit, fn)
5050
val Seq(samDenot) = tpe1.possibleSamMethods
5151
cpy.Block(tree)(stats,
5252
AnonClass(tpe1 :: Nil, fn.symbol.asTerm :: Nil, samDenot.symbol.asTerm.name :: Nil))

compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
211211
def filterStringConstructor(s: Symbol): Boolean = s.info match {
212212
case m: MethodType if s.isConstructor && m.paramInfos.size == 1 =>
213213
val head = m.paramInfos.head
214-
val pinfo = head.stripNull
214+
val pinfo = head.stripNullWhenExplicit
215215
pinfo == defn.StringType
216216
case _ => false
217217
}

compiler/src/dotty/tools/dotc/typer/Typer.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1314,7 +1314,7 @@ class Typer extends Namer
13141314
if (tree.tpt.isEmpty)
13151315
meth1.tpe.widen match {
13161316
case mt: MethodType =>
1317-
val pt1 = pt.stripNull
1317+
val pt1 = pt.stripNullWhenExplicit
13181318
pt1 match {
13191319
case SAMType(sam)
13201320
if !defn.isFunctionType(pt1)
@@ -1673,7 +1673,7 @@ class Typer extends Namer
16731673
}
16741674

16751675
def typedSeqLiteral(tree: untpd.SeqLiteral, pt: Type)(using Context): SeqLiteral = {
1676-
val elemProto = pt.stripNull.elemType match {
1676+
val elemProto = pt.stripNullWhenExplicit.elemType match {
16771677
case NoType => WildcardType
16781678
case bounds: TypeBounds => WildcardType(bounds)
16791679
case elemtp => elemtp

docs/docs/internals/explicit-nulls.md

+4-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ title: "Explicit Nulls"
55

66
The explicit nulls feature (enabled via a flag) changes the Scala type hierarchy
77
so that reference types (e.g. `String`) are non-nullable. We can still express nullability
8-
with union types: e.g. `val x: String|Null = null`.
8+
with union types: e.g. `val x: String | Null = null`.
99

1010
The implementation of the feature in dotty can be conceptually divided in several parts:
1111
1. changes to the type hierarchy so that `Null` is only a subtype of `Any`
@@ -27,15 +27,13 @@ We change the type hierarchy so that `Null` is only a subtype of `Any` by:
2727

2828
## Working with Nullable Unions
2929

30-
There are some utility functions for nullable types in `NullOpsDecorator.scala` . They are extension methods for `Type`; hence we can use them in this way: `tp.f(...)`.
30+
There are some utility functions for nullable types in `NullOpsDecorator.scala`.
31+
They are extension methods for `Type`; hence we can use them in this way: `tp.f(...)`.
3132

32-
- `stripNull` syntactically strips all `Null` types in the union:
33+
- `stripNullWhenExplicit` syntactically strips all `Null` types in the union:
3334
e.g. `String|Null => String`.
34-
- `stripAllNullS` collapses all `Null` unions within this type, and not just the outermost
35-
ones (as `stripNull` does).
3635
- `isNullableUnion` determines whether `this` is a nullable union.
3736
- `isNullableAfterErasure` determines whether `this` type can have `null` value after erasure.
38-
- `isUnsafelyConvertible` determines whether we can convert `this` type to `pt` unsafely if we ignore `Null` type.
3937

4038
Within `Types.scala`, we also defined an extractor `OrNull` to extract the non-nullable part of a nullable unions .
4139

docs/docs/reference/other-new-features/explicit-nulls.md

+34-7
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ So far, we have found the following useful:
5555

5656
Don't use `.nn` on mutable variables directly, because it may introduce an unknown type into the type of the variable.
5757

58+
- An `unsafeNulls` language feature
59+
60+
When imported, `T | Null` can be used as `T`, similar to regular Scala (without explicit nulls).
61+
62+
See UnsafeNulls section for more details.
63+
5864
## Unsoundness
5965

6066
The new type system is unsound with respect to `null`. This means there are still instances where an expression has a non-nullable type like `String`, but its value is actually `null`.
@@ -439,17 +445,38 @@ We don't support:
439445
440446
### UnsafeNulls
441447
442-
It is difficult to work with nullable values, we introduce a language feature `unsafeNulls`. Inside this "unsafe" scope, all `T | Null` values can be used as `T`, and `Null` type keeps being a subtype of `Any`.
448+
It is difficult to work with many nullable values, we introduce a language feature `unsafeNulls`.
449+
Inside this "unsafe" scope, all `T | Null` values can be used as `T`.
443450
444-
Users can import `scala.language.unsafeNulls` to create such scopes, or use `-language:unsafeNulls` to enable this feature globally. The following unsafe null operations will apply to all nullable types:
445-
1. select member of `T` on `T | Null` object
446-
2. call extension methods of `T` on `T | Null`
447-
3. convert `T1` to `T2` if `T1.stripAllNulls <:< T2.stripAllNulls` or `T1` is `Null` and `T2` has null value after erasure
448-
4. allow equality check between `T` and `T | Null`
451+
Users can import `scala.language.unsafeNulls` to create such scopes, or use `-language:unsafeNulls` to enable this feature globally (for migration purpose only).
452+
453+
Assume `T` is a reference type (a subtype of `AnyRef`), the following unsafe operation rules are
454+
applied in this unsafe-nulls scope:
455+
1. the members of `T` can be found on `T | Null`
456+
2. a value with type `T` can be compared with `T | Null` and `Null`
457+
3. suppose `T1` is not a subtype of `T2` using explicit-nulls subtyping (where `Null` is a direct
458+
subtype of Any), extension methods and implicit conversions designed for `T2` can be used for
459+
`T1` if `T1` is a subtype of `T2` using regular subtyping rules (where `Null` is a subtype of every
460+
reference type)
461+
4. suppose `T1` is not a subtype of `T2` using explicit-nulls subtyping, a value with type `T1`
462+
can be used as `T2` if `T1` is a subtype of `T2` using regular subtyping rules
449463
450464
Addtionally, `null` can be used as `AnyRef` (`Object`), which means you can select `.eq` or `.toString` on it.
451465
452-
The intention of this `unsafeNulls` is to give users a better migration path for explicit nulls. Projects for Scala 2 or regular dotty can try this by adding `-Yexplicit-nulls -language:unsafeNulls` to the compile options. A small number of manual modifications are expected (for example, some code relies on the fact of `Null <:< AnyRef`). To migrate to full explicit nulls in the future, `-language:unsafeNulls` can be dropped and add `import scala.language.unsafeNulls` only when needed.
466+
The program in `unsafeNulls` will have a **similar** semantic as regular Scala, but not **equivalent**.
467+
468+
For example, the following code cannot be compiled even using unsafe nulls. Because of the
469+
Java interoperation, the type of the get method becomes `T | Null`.
470+
471+
```Scala
472+
def head[T](xs: java.util.List[T]): T = xs.get(0) // error
473+
```
474+
475+
Since the compiler doesn’t know whether `T` is a reference type, it is unable to cast `T | Null`
476+
to `T`. A `.nn` need to be inserted after `xs.get(0)` by user manually to fix the error, which
477+
strips the `Nul`l from its type.
478+
479+
The intention of this `unsafeNulls` is to give users a better migration path for explicit nulls. Projects for Scala 2 or regular dotty can try this by adding `-Yexplicit-nulls -language:unsafeNulls` to the compile options. A small number of manual modifications are expected. To migrate to full explicit nulls in the future, `-language:unsafeNulls` can be dropped and add `import scala.language.unsafeNulls` only when needed.
453480
454481
```scala
455482
def f(x: String): String = ???

library/src/scala/runtime/stdLibPatches/language.scala

+5-1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ object language:
101101
*/
102102
object `3.1`
103103

104-
/** Unsafe Nulls fot Explicit Nulls */
104+
/** Unsafe Nulls fot Explicit Nulls
105+
* Inside the "unsafe" scope, `Null` is considered as a subtype of all reference types.
106+
*
107+
* @see [[http://dotty.epfl.ch/docs/reference/other-new-features/explicit-nulls.html]]
108+
*/
105109
object unsafeNulls
106110
end language

0 commit comments

Comments
 (0)