Skip to content

Commit 68b79fa

Browse files
committed
Update doc and clean code
1 parent dd79d4d commit 68b79fa

File tree

4 files changed

+13
-21
lines changed

4 files changed

+13
-21
lines changed

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

+7-5
Original file line numberDiff line numberDiff line change
@@ -400,16 +400,15 @@ class TypeApplications(val self: Type) extends AnyVal {
400400
case _ => if (self.isMatch) MatchAlias(self) else TypeAlias(self)
401401
}
402402

403-
/** Translate a type of the form From[T] to either To[T] or To[? <: T] (if `wildcardArg` is set).
404-
* Keep other types as they are.
403+
/** Translate a type of the form From[T] to either To[T] or To[? <: T] (if `wildcardArg` is set). Keep other types as they are.
405404
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
406405
* Do the same for by name types => From[T] and => To[T]
407406
*/
408-
def translateParameterized(from: ClassSymbol, to: ClassSymbol, wildcardArg: Boolean = false)(using Context): Type = self match
407+
def translateParameterized(from: ClassSymbol, to: ClassSymbol, wildcardArg: Boolean = false)(using Context): Type = self match {
409408
case self @ ExprType(tp) =>
410409
self.derivedExprType(tp.translateParameterized(from, to))
411410
case _ =>
412-
if self.derivesFrom(from) then
411+
if (self.derivesFrom(from)) {
413412
def elemType(tp: Type): Type = tp.widenDealias match
414413
case tp: OrType =>
415414
if tp.tp1.isBottomType then elemType(tp.tp2)
@@ -420,12 +419,15 @@ class TypeApplications(val self: Type) extends AnyVal {
420419
val arg = elemType(self)
421420
val arg1 = if (wildcardArg) TypeBounds.upper(arg) else arg
422421
to.typeRef.appliedTo(arg1)
422+
}
423423
else self
424+
}
424425

425426
/** If this is a repeated parameter `*T`, translate it to either `Seq[T]` or
426427
* `Array[? <: T]` depending on the value of `toArray`.
427428
* Additionally, if `translateWildcard` is true, a wildcard type
428-
* will be translated to `*<?>`. Other types are kept as-is.
429+
* will be translated to `*<?>`.
430+
* Other types are kept as-is.
429431
*/
430432
def translateFromRepeated(toArray: Boolean, translateWildcard: Boolean = false)(using Context): Type =
431433
val seqClass = if (toArray) defn.ArrayClass else defn.SeqClass

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

-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import transform.TypeUtils._
1212
import transform.ContextFunctionResults._
1313
import unpickleScala2.Scala2Erasure
1414
import Decorators._
15-
import NullOpsDecorator._
1615
import Definitions.MaxImplementedFunctionArity
1716
import scala.annotation.tailrec
1817

@@ -566,9 +565,6 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
566565

567566
private def eraseArray(tp: Type)(using Context) = {
568567
val defn.ArrayOf(elemtp) = tp
569-
// println(elemtp.show)
570-
// println(isUnboundedGeneric(elemtp))
571-
// println()
572568
if (classify(elemtp).derivesFrom(defn.NullClass)) JavaArrayType(defn.ObjectType)
573569
else if (isUnboundedGeneric(elemtp) && !sourceLanguage.isJava) defn.ObjectType
574570
else JavaArrayType(erasureFn(sourceLanguage, semiEraseVCs = false, isConstructor, wildcardOK)(elemtp))

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

+4
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,10 @@ object Types {
10841084
*
10851085
* (*) when matching with a Java method, we also regard Any and Object as equivalent
10861086
* parameter types.
1087+
*
1088+
* Under explicit nulls, this function will always use unsafe-nulls semamtics to
1089+
* check the types. This is because we are using a relaxed rule (ignoring `Null` types)
1090+
* to check overriding Java methods.
10871091
*/
10881092
def matches(that: Type)(using Context): Boolean = {
10891093
record("matches")

docs/docs/internals/explicit-nulls.md

+2-12
Original file line numberDiff line numberDiff line change
@@ -87,24 +87,14 @@ we don't have a type that is a supertype of `Null` and a subtype of `String`.
8787
Hence, when we read a type bound from Scala 2 Tasty or Scala 3 Tasty, the upper bound is nullified if the lower
8888
bound is exactly `Null`. The example above would become `class C[T >: Null <: String | Null]`.
8989

90-
## Unsafe Nulls
90+
## Unsafe Nulls Feature and SafeNulls Mode
9191

9292
The `unsafeNulls` language feature is currently disabled by default. It can be enabled by importing `scala.language.unsafeNulls` or using `-language:unsafeNulls`. The feature object is defined in `library/src/scalaShadowing/language.scala`. We can use `config.Feature.enabled(nme.unsafeNulls)` to check if this feature is enabled.
9393

94-
The unsafe nulls conversion could happen if:
95-
1. the explicit nulls flag is enabled, and
96-
2. `unsafeNulls` language feature is enabled, or `UnsafeNullConversion` mode is in the context.
97-
98-
The reason to use the `UnsafeNullConversion` mode is because the current context may not see the language feature. For example, implicit search could run in some different contexts.
94+
We use the `SafeNulls` mode to track `unsafeNulls`. If explicit nulls is enabled without `unsafeNulls`, there is a `SafeNulls` mode in the context; when `unsafeNulls` is enabled, `SafeNulls` mode will be removed from the context.
9995

10096
Since we want to allow selecting member on nullable values, when searching a member of a type, the `| Null` part should be ignored. See `goOr` in `Types.scala`.
10197

102-
During adapting, if the type of the tree is not a subtype of the expected type, the `adaptToSubType` in `Typer.scala` will run. The implicit search is invoked to find conversions for the tree. Since implicit search (finding candidates and trying to type the new tree) could run in some different contexts, we have to pass the `UnsafeNullConversion` mode to the search context.
103-
104-
The SAM type conversion also happens in `adaptToSubType`. We need to strip `Null` from `pt` in order to get class information.
105-
106-
We need to modify the overloading resolution as well. The `isCompatible` and `necessarilyCompatible` functions in `ProtoTypes.scala` are used to compare types for overloading resolution. When `unsafeNulls` is enabled, we need to strip all nulls from the type before comparison.
107-
10898
## Flow Typing
10999

110100
As typing happens, we accumulate a set of `NotNullInfo`s in the `Context` (see

0 commit comments

Comments
 (0)