@@ -4,7 +4,7 @@ package core
4
4
5
5
import scala .annotation .threadUnsafe
6
6
import Types ._ , Contexts ._ , Symbols ._ , SymDenotations ._ , StdNames ._ , Names ._
7
- import Flags ._ , Scopes ._ , Decorators ._ , NameOps ._ , Periods ._
7
+ import Flags ._ , Scopes ._ , Decorators ._ , NameOps ._ , Periods ._ , NullOpsDecorator . _
8
8
import unpickleScala2 .Scala2Unpickler .ensureConstructor
9
9
import scala .collection .mutable
10
10
import collection .mutable
@@ -293,7 +293,7 @@ class Definitions {
293
293
@ threadUnsafe lazy val ObjectClass : ClassSymbol = {
294
294
val cls = ctx.requiredClass(" java.lang.Object" )
295
295
assert(! cls.isCompleted, " race for completing java.lang.Object" )
296
- cls.info = ClassInfo (cls.owner.thisType, cls, AnyClass .typeRef :: Nil , newScope)
296
+ cls.info = ClassInfo (cls.owner.thisType, cls, AnyType :: Nil , newScope)
297
297
cls.setFlag(NoInits )
298
298
299
299
// The companion object doesn't really exist, `NoType` is the general
@@ -309,8 +309,18 @@ class Definitions {
309
309
@ threadUnsafe lazy val AnyRefAlias : TypeSymbol = enterAliasType(tpnme.AnyRef , ObjectType )
310
310
def AnyRefType : TypeRef = AnyRefAlias .typeRef
311
311
312
- @ threadUnsafe lazy val Object_eq : TermSymbol = enterMethod(ObjectClass , nme.eq, methOfAnyRef(BooleanType ), Final )
313
- @ threadUnsafe lazy val Object_ne : TermSymbol = enterMethod(ObjectClass , nme.ne, methOfAnyRef(BooleanType ), Final )
312
+ @ threadUnsafe lazy val Object_eq : TermSymbol = {
313
+ // If explicit nulls is enabled, then we want to allow `(x: String).eq(null)`, so we need
314
+ // to adjust the signature of `eq` accordingly.
315
+ val tpe = if (ctx.explicitNulls) methOfAnyRefOrNull(BooleanType ) else methOfAnyRef(BooleanType )
316
+ enterMethod(ObjectClass , nme.eq, tpe, Final )
317
+ }
318
+ @ threadUnsafe lazy val Object_ne : TermSymbol = {
319
+ // If explicit nulls is enabled, then we want to allow `(x: String).ne(null)`, so we need
320
+ // to adjust the signature of `ne` accordingly.
321
+ val tpe = if (ctx.explicitNulls) methOfAnyRefOrNull(BooleanType ) else methOfAnyRef(BooleanType )
322
+ enterMethod(ObjectClass , nme.ne, tpe, Final )
323
+ }
314
324
@ threadUnsafe lazy val Object_synchronized : TermSymbol = enterPolyMethod(ObjectClass , nme.synchronized_, 1 ,
315
325
pt => MethodType (List (pt.paramRefs(0 )), pt.paramRefs(0 )), Final )
316
326
@ threadUnsafe lazy val Object_clone : TermSymbol = enterMethod(ObjectClass , nme.clone_, MethodType (Nil , ObjectType ), Protected )
@@ -344,18 +354,42 @@ class Definitions {
344
354
pt => MethodType (List (FunctionOf (Nil , pt.paramRefs(0 ))), pt.paramRefs(0 )))
345
355
346
356
/** Method representing a throw */
347
- @ threadUnsafe lazy val throwMethod : TermSymbol = enterMethod(OpsPackageClass , nme.THROWkw ,
348
- MethodType (List (ThrowableType ), NothingType ))
357
+ @ threadUnsafe lazy val throwMethod : TermSymbol = {
358
+ val argTpe = if (ctx.explicitNulls) OrType (ThrowableType , NullType ) else ThrowableType
359
+ enterMethod(OpsPackageClass , nme.THROWkw , MethodType (List (argTpe), NothingType ))
360
+ }
349
361
350
362
@ threadUnsafe lazy val NothingClass : ClassSymbol = enterCompleteClassSymbol(
351
363
ScalaPackageClass , tpnme.Nothing , AbstractFinal , List (AnyClass .typeRef))
352
364
def NothingType : TypeRef = NothingClass .typeRef
353
365
@ threadUnsafe lazy val RuntimeNothingModuleRef : TermRef = ctx.requiredModuleRef(" scala.runtime.Nothing" )
354
- @ threadUnsafe lazy val NullClass : ClassSymbol = enterCompleteClassSymbol(
355
- ScalaPackageClass , tpnme.Null , AbstractFinal , List (ObjectClass .typeRef))
366
+
367
+ @ threadUnsafe lazy val NullClass : ClassSymbol = {
368
+ val parents = List (if (ctx.explicitNulls) AnyType else ObjectType )
369
+ enterCompleteClassSymbol(ScalaPackageClass , tpnme.Null , AbstractFinal , parents)
370
+ }
356
371
def NullType : TypeRef = NullClass .typeRef
357
372
@ threadUnsafe lazy val RuntimeNullModuleRef : TermRef = ctx.requiredModuleRef(" scala.runtime.Null" )
358
373
374
+ /** An alias for null values that originate in Java code.
375
+ * This type gets special treatment in the Typer. Specifically, `JavaNull` can be selected through:
376
+ * e.g.
377
+ * ```
378
+ * // x: String|Null
379
+ * x.length // error: `Null` has no `length` field
380
+ * // x2: String|JavaNull
381
+ * x2.length // allowed by the Typer, but unsound (might throw NPE)
382
+ * ```
383
+ */
384
+ lazy val JavaNullAlias : TypeSymbol = {
385
+ assert(ctx.explicitNulls)
386
+ enterAliasType(tpnme.JavaNull , NullType )
387
+ }
388
+ def JavaNullAliasType : TypeRef = {
389
+ assert(ctx.explicitNulls)
390
+ JavaNullAlias .typeRef
391
+ }
392
+
359
393
@ threadUnsafe lazy val ImplicitScrutineeTypeSym =
360
394
newSymbol(ScalaPackageClass , tpnme.IMPLICITkw , EmptyFlags , TypeBounds .empty).entered
361
395
def ImplicitScrutineeTypeRef : TypeRef = ImplicitScrutineeTypeSym .typeRef
@@ -591,12 +625,16 @@ class Definitions {
591
625
@ threadUnsafe lazy val BoxedNumberClass : ClassSymbol = ctx.requiredClass(" java.lang.Number" )
592
626
@ threadUnsafe lazy val ClassCastExceptionClass : ClassSymbol = ctx.requiredClass(" java.lang.ClassCastException" )
593
627
@ threadUnsafe lazy val ClassCastExceptionClass_stringConstructor : TermSymbol = ClassCastExceptionClass .info.member(nme.CONSTRUCTOR ).suchThat(_.info.firstParamTypes match {
594
- case List (pt) => (pt isRef StringClass )
628
+ case List (pt) =>
629
+ val pt1 = if (ctx.explicitNulls) pt.stripNull else pt
630
+ pt1 isRef StringClass
595
631
case _ => false
596
632
}).symbol.asTerm
597
633
@ threadUnsafe lazy val ArithmeticExceptionClass : ClassSymbol = ctx.requiredClass(" java.lang.ArithmeticException" )
598
634
@ threadUnsafe lazy val ArithmeticExceptionClass_stringConstructor : TermSymbol = ArithmeticExceptionClass .info.member(nme.CONSTRUCTOR ).suchThat(_.info.firstParamTypes match {
599
- case List (pt) => (pt isRef StringClass )
635
+ case List (pt) =>
636
+ val pt1 = if (ctx.explicitNulls) pt.stripNull else pt
637
+ pt1 isRef StringClass
600
638
case _ => false
601
639
}).symbol.asTerm
602
640
@@ -967,6 +1005,7 @@ class Definitions {
967
1005
def methOfAny (tp : Type ): MethodType = MethodType (List (AnyType ), tp)
968
1006
def methOfAnyVal (tp : Type ): MethodType = MethodType (List (AnyValType ), tp)
969
1007
def methOfAnyRef (tp : Type ): MethodType = MethodType (List (ObjectType ), tp)
1008
+ def methOfAnyRefOrNull (tp : Type ): MethodType = MethodType (List (OrType (ObjectType , NullType )), tp)
970
1009
971
1010
// Derived types
972
1011
@@ -1128,10 +1167,23 @@ class Definitions {
1128
1167
name.length > prefix.length &&
1129
1168
name.drop(prefix.length).forall(_.isDigit))
1130
1169
1131
- def isBottomClass (cls : Symbol ): Boolean =
1170
+ def isBottomClass (cls : Symbol ): Boolean = {
1171
+ if (ctx.explicitNulls && ! ctx.phase.erasedTypes) cls == NothingClass
1172
+ else isBottomClassAfterErasure(cls)
1173
+ }
1174
+
1175
+ def isBottomClassAfterErasure (cls : Symbol ): Boolean = {
1132
1176
cls == NothingClass || cls == NullClass
1133
- def isBottomType (tp : Type ): Boolean =
1177
+ }
1178
+
1179
+ def isBottomType (tp : Type ): Boolean = {
1180
+ if (ctx.explicitNulls && ! ctx.phase.erasedTypes) tp.derivesFrom(NothingClass )
1181
+ else isBottomTypeAfterErasure(tp)
1182
+ }
1183
+
1184
+ def isBottomTypeAfterErasure (tp : Type ): Boolean = {
1134
1185
tp.derivesFrom(NothingClass ) || tp.derivesFrom(NullClass )
1186
+ }
1135
1187
1136
1188
/** Is a function class.
1137
1189
* - FunctionXXL
@@ -1225,9 +1277,12 @@ class Definitions {
1225
1277
() => ScalaPackageVal .termRef
1226
1278
)
1227
1279
1228
- val PredefImportFns : List [() => TermRef ] = List [() => TermRef ](
1280
+ lazy val PredefImportFns : List [() => TermRef ] = List [() => TermRef ](
1229
1281
() => ScalaPredefModuleRef ,
1230
- () => DottyPredefModuleRef
1282
+ () => DottyPredefModuleRef ,
1283
+ // TODO(abeln): is this in the right place?
1284
+ // And is it ok to import this unconditionally?
1285
+ () => ctx.requiredModuleRef(" scala.ExplicitNullsOps" )
1231
1286
)
1232
1287
1233
1288
@ threadUnsafe lazy val RootImportFns : List [() => TermRef ] =
@@ -1475,18 +1530,22 @@ class Definitions {
1475
1530
// ----- Initialization ---------------------------------------------------
1476
1531
1477
1532
/** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
1478
- @ threadUnsafe lazy val syntheticScalaClasses : List [TypeSymbol ] = List (
1479
- AnyClass ,
1480
- AnyRefAlias ,
1481
- AnyKindClass ,
1482
- andType,
1483
- orType,
1484
- RepeatedParamClass ,
1485
- ByNameParamClass2x ,
1486
- AnyValClass ,
1487
- NullClass ,
1488
- NothingClass ,
1489
- SingletonClass )
1533
+ @ threadUnsafe lazy val syntheticScalaClasses : List [TypeSymbol ] = {
1534
+ val synth = List (
1535
+ AnyClass ,
1536
+ AnyRefAlias ,
1537
+ AnyKindClass ,
1538
+ andType,
1539
+ orType,
1540
+ RepeatedParamClass ,
1541
+ ByNameParamClass2x ,
1542
+ AnyValClass ,
1543
+ NullClass ,
1544
+ NothingClass ,
1545
+ SingletonClass )
1546
+
1547
+ if (ctx.explicitNulls) synth :+ JavaNullAlias else synth
1548
+ }
1490
1549
1491
1550
@ threadUnsafe lazy val syntheticCoreClasses : List [Symbol ] = syntheticScalaClasses ++ List (
1492
1551
EmptyPackageVal ,
0 commit comments