Skip to content

Commit 08fc382

Browse files
committed
Update comments
1 parent d4c017b commit 08fc382

12 files changed

+161
-181
lines changed

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

+2-13
Original file line numberDiff line numberDiff line change
@@ -117,26 +117,14 @@ class CheckRealizable(using Context) {
117117
case _: SingletonType | NoPrefix =>
118118
Realizable
119119
case tp =>
120-
// TODO
121-
// check the realizability of a special AndType
122-
def checkAndType(x: TermRef, y: Type) =
123-
(realizability(x) eq Realizable) && (y <:< x.widen)
124-
val isRealizableAndType = tp match {
125-
case AndType(tr: TermRef, tp1) =>
126-
checkAndType(tr, tp1)
127-
case AndType(tp1, tr: TermRef) =>
128-
checkAndType(tr, tp1)
129-
case _ => false
130-
}
131120
def isConcrete(tp: Type): Boolean = tp.dealias match {
132121
case tp: TypeRef => tp.symbol.isClass
133122
case tp: TypeProxy => isConcrete(tp.underlying)
134123
case tp: AndType => isConcrete(tp.tp1) && isConcrete(tp.tp2)
135124
case tp: OrType => isConcrete(tp.tp1) && isConcrete(tp.tp2)
136125
case _ => false
137126
}
138-
if isRealizableAndType then Realizable
139-
else if !isConcrete(tp) then NotConcrete
127+
if (!isConcrete(tp)) NotConcrete
140128
else boundsRealizability(tp).andAlso(memberRealizability(tp))
141129
}
142130

@@ -161,6 +149,7 @@ class CheckRealizable(using Context) {
161149
*/
162150
private def boundsRealizability(tp: Type) = {
163151

152+
// In unsafe nulls, we use the old subtyping to check the bounds
164153
val unsafeNullsSub = unsafeNullsEnabled
165154
def isSub(tp1: Type, tp2: Type): Boolean =
166155
Nullables.useUnsafeNullsSubTypeIf(unsafeNullsSub)(tp1 <:< tp2)

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

+3-5
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@ class Definitions {
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 {
616616
case List(pt) =>
617-
pt.isAny || (if ctx.explicitNulls then pt.stripNull else pt).isAnyRef
617+
pt.isAny || pt.stripNull.isAnyRef
618618
case _ => false
619619
}).symbol
620620

@@ -626,15 +626,13 @@ class Definitions {
626626
@tu lazy val ClassCastExceptionClass: ClassSymbol = requiredClass("java.lang.ClassCastException")
627627
@tu lazy val ClassCastExceptionClass_stringConstructor: TermSymbol = ClassCastExceptionClass.info.member(nme.CONSTRUCTOR).suchThat(_.info.firstParamTypes match {
628628
case List(pt) =>
629-
val pt1 = if ctx.explicitNulls then pt.stripNull else pt
630-
pt1.isRef(StringClass)
629+
pt.stripNull.isRef(StringClass)
631630
case _ => false
632631
}).symbol.asTerm
633632
@tu lazy val ArithmeticExceptionClass: ClassSymbol = requiredClass("java.lang.ArithmeticException")
634633
@tu lazy val ArithmeticExceptionClass_stringConstructor: TermSymbol = ArithmeticExceptionClass.info.member(nme.CONSTRUCTOR).suchThat(_.info.firstParamTypes match {
635634
case List(pt) =>
636-
val pt1 = if ctx.explicitNulls then pt.stripNull else pt
637-
pt1.isRef(StringClass)
635+
pt.stripNull.isRef(StringClass)
638636
case _ => false
639637
}).symbol.asTerm
640638

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

+4-24
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ object NullOpsDecorator {
1515
* If the type is `T1 | ... | Tn`, and `Ti` references to `Null`,
1616
* then return `T1 | ... | Ti-1 | Ti+1 | ... | Tn`.
1717
* If this type isn't (syntactically) nullable, then returns the type unchanged.
18+
* The type will not be changed if explicit-nulls is not enabled.
1819
*/
1920
def stripNull(using Context): Type = {
2021
def strip(tp: Type): Type =
@@ -41,17 +42,7 @@ object NullOpsDecorator {
4142
}
4243
if tpStriped ne tpWiden then tpStriped else tp
4344

44-
strip(self)
45-
}
46-
47-
def stripAllNulls(using Context): Type = {
48-
object RemoveNulls extends TypeMap {
49-
override def apply(tp: Type): Type =
50-
val mapped = mapOver(tp.widenTermRefExpr.stripNull)
51-
if tp eq mapped then tp else mapped
52-
}
53-
val rem = RemoveNulls(self)
54-
if rem ne self then rem else self
45+
if ctx.explicitNulls then strip(self) else self
5546
}
5647

5748
/** Is self (after widening and dealiasing) a type of the form `T | Null`? */
@@ -60,19 +51,7 @@ object NullOpsDecorator {
6051
stripped ne self
6152
}
6253

63-
/** Can the type has null value after erasure?
64-
* TODO
65-
*/
66-
// def isNullableAfterErasure(using Context): Boolean = self match {
67-
// case tp: ClassInfo => tp.cls.isNullableClassAfterErasure
68-
// case tp: TypeProxy => tp.underlying.isNullableAfterErasure
69-
// case OrType(lhs, rhs) =>
70-
// lhs.isNullableAfterErasure || rhs.isNullableAfterErasure
71-
// case AndType(lhs, rhs) =>
72-
// lhs.isNullableAfterErasure && rhs.isNullableAfterErasure
73-
// case _ =>
74-
// self.isNullType || self <:< defn.ObjectType
75-
// }
54+
/** If a type is nullable after erasure */
7655
def isNullableAfterErasure(using Context): Boolean =
7756
self.isNullType
7857
|| !self.isNothingType
@@ -82,6 +61,7 @@ object NullOpsDecorator {
8261
import ast.tpd._
8362

8463
extension (self: Tree) {
64+
// cast the type of the tree to a non-nullable type
8565
def castToNonNullable(using Context): Tree = self.typeOpt match {
8666
case OrNull(tp) => self.cast(tp)
8767
case _ => self

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,9 @@ class TypeApplications(val self: Type) extends AnyVal {
398398
case _ => if (self.isMatch) MatchAlias(self) else TypeAlias(self)
399399
}
400400

401-
/** 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.
401+
/** Translate a type of the form From[T] to either To[T] or To[? <: T] (if `wildcardArg` is set).
402+
* Ff `withOrNull` is true, the elemTp will become nullable.
403+
* Keep other types as they are.
402404
* `from` and `to` must be static classes, both with one type parameter, and the same variance.
403405
* Do the same for by name types => From[T] and => To[T]
404406
*/
@@ -429,7 +431,8 @@ class TypeApplications(val self: Type) extends AnyVal {
429431
/** If this is a repeated parameter `*T`, translate it to either `Seq[T]` or
430432
* `Array[? <: T]` depending on the value of `toArray`.
431433
* Additionally, if `translateWildcard` is true, a wildcard type
432-
* will be translated to `*<?>`.
434+
* will be translated to `*<?>`, and if `withOrNull` is true, the elemTp
435+
* will become nullable.
433436
* Other types are kept as-is.
434437
*/
435438
def translateFromRepeated(toArray: Boolean, translateWildcard: Boolean = false, withOrNull: Boolean = false)(using Context): Type =

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

+7-9
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,10 @@ object Types {
172172
case tp: ExprType => tp.resultType.isStable
173173
case tp: AnnotatedType => tp.parent.isStable
174174
case tp: AndType =>
175-
// if one side is stable and another side is realizable or a subtype,
176-
// then the AndType is stable
177-
def checkAndStable(x: Type, y: Type) =
178-
x.isStable && ((realizability(y) eq Realizable) || y <:< x.widen)
179-
checkAndStable(tp.tp1, tp.tp2) || checkAndStable(tp.tp2, tp.tp1)
175+
// TODO: fix And type check when tp contains type parames for explicit-nulls flow-typing
176+
// see: tests/explicit-nulls/pos/flow-stable.scala.disabled
177+
tp.tp1.isStable && (realizability(tp.tp2) eq Realizable) ||
178+
tp.tp2.isStable && (realizability(tp.tp1) eq Realizable)
180179
case _ => false
181180
}
182181

@@ -1047,6 +1046,7 @@ object Types {
10471046
* member `sym2` of type `that`? This is the same as `<:<`, except that
10481047
* @param matchLoosely if true the types `=> T` and `()T` are seen as overriding each other.
10491048
* @param checkClassInfo if true we check that ClassInfos are within bounds of abstract types
1049+
* @param relaxedNulls if true the null type is ignored during subtype check.
10501050
*/
10511051
final def overrides(that: Type, matchLoosely: => Boolean,
10521052
checkClassInfo: Boolean = true, relaxedNulls: Boolean = false)(using Context): Boolean = {
@@ -3178,10 +3178,8 @@ 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-
if ctx.explicitNulls then
3182-
val tp1 = tp.stripNull
3183-
if tp1 ne tp then Some(tp1) else None
3184-
else None
3181+
val tp1 = tp.stripNull
3182+
if tp1 ne tp then Some(tp1) else None
31853183
}
31863184

31873185
// ----- ExprType and LambdaTypes -----------------------------------

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

+2-4
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,7 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
155155
case SeqLiteral(elems, elemtpt) =>
156156
JavaSeqLiteral(elems, elemtpt)
157157
case _ =>
158-
// TODO remove Null from the type first
159-
val elemType = tree.tpe.stripNull.elemType
158+
val elemType = tree.tpe.elemType
160159
var elemClass = erasure(elemType).classSymbol
161160
if defn.NotRuntimeClasses.contains(elemClass) then
162161
elemClass = defn.ObjectClass
@@ -173,8 +172,7 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase =>
173172
* of generic Java varargs in `elimRepeated`.
174173
*/
175174
private def adaptToArray(tree: Tree, elemPt: Type)(implicit ctx: Context): Tree =
176-
// TODO remove Null from the type first
177-
val elemTp = tree.tpe.stripNull.elemType
175+
val elemTp = tree.tpe.elemType
178176
val elemTpMatches = elemTp <:< elemPt
179177
val treeIsArray = tree.tpe.derivesFrom(defn.ArrayClass)
180178
if elemTpMatches && treeIsArray then

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ class ExpandSAMs extends MiniPhase {
4646
checkRefinements(tpe, fn)
4747
tree
4848
case tpe =>
49-
val tpe0 = if ctx.explicitNulls then tpe.stripNull else tpe
50-
val tpe1 = checkRefinements(tpe0, fn)
49+
val tpe1 = checkRefinements(tpe.stripNull, fn)
5150
val Seq(samDenot) = tpe1.possibleSamMethods
5251
cpy.Block(tree)(stats,
5352
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 = if ctx.explicitNulls then head.stripNull else head
214+
val pinfo = head.stripNull
215215
pinfo == defn.StringType
216216
case _ => false
217217
}

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

+13-1
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,34 @@ object Nullables:
2222

2323
private def needNullifyHi(lo: Type, hi: Type)(using Context): Boolean =
2424
ctx.explicitNulls
25-
&& lo.isExactlyNull
25+
&& lo.isExactlyNull // only nullify hi if lo is exactly Null type
2626
&& hi.isValueType
27+
// We cannot check if hi is nullable, because it can cause cyclic reference.
2728

29+
/** Create a nullable type bound
30+
* If the lo is `Null`, `| Null` is added to hi
31+
*/
2832
def createNullableTypeBounds(lo: Type, hi: Type)(using Context): TypeBounds =
2933
val newHi = if needNullifyHi(lo, hi) then OrType(hi, defn.NullType, soft = false) else hi
3034
TypeBounds(lo, newHi)
3135

36+
37+
/** Create a nullable type bound tree
38+
* If the lo is `Null`, `| Null` is added to hi
39+
*/
3240
def createNullableTypeBoundsTree(lo: Tree, hi: Tree, alias: Tree = EmptyTree)(using Context): TypeBoundsTree =
3341
val hiTpe = hi.typeOpt
3442
val newHi = if needNullifyHi(lo.typeOpt, hiTpe) then TypeTree(OrType(hiTpe, defn.NullType, soft = false)) else hi
3543
TypeBoundsTree(lo, newHi, alias)
3644

45+
/** Use unsafe nulls subtyping where `Null` is a subtype of all reference types */
3746
inline def useUnsafeNullsSubTypeIf[T](cond: Boolean)(inline op: Context ?=> T)(using Context): T =
3847
val c = if cond then ctx.addMode(Mode.UnsafeNullsSubType) else ctx
3948
op(using c)
4049

50+
/** A StickyKey for TypeApply and AppliedType in unsafe nulls,
51+
* In PostTyper, a relaxed bound check is used for these types.
52+
*/
4153
val UnsafeNullsKey = Property.StickyKey[Boolean]
4254

4355
/** A set of val or var references that are known to be not null, plus a set of

0 commit comments

Comments
 (0)