@@ -4,7 +4,7 @@ package core
44
55import scala .annotation .threadUnsafe
66import Types ._ , Contexts ._ , Symbols ._ , SymDenotations ._ , StdNames ._ , Names ._
7- import Flags ._ , Scopes ._ , Decorators ._ , NameOps ._ , Periods ._
7+ import Flags ._ , Scopes ._ , Decorators ._ , NameOps ._ , Periods ._ , NullOpsDecorator . _
88import unpickleScala2 .Scala2Unpickler .ensureConstructor
99import scala .collection .mutable
1010import collection .mutable
@@ -293,7 +293,7 @@ class Definitions {
293293 @ threadUnsafe lazy val ObjectClass : ClassSymbol = {
294294 val cls = ctx.requiredClass(" java.lang.Object" )
295295 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)
297297 cls.setFlag(NoInits )
298298
299299 // The companion object doesn't really exist, `NoType` is the general
@@ -309,8 +309,18 @@ class Definitions {
309309 @ threadUnsafe lazy val AnyRefAlias : TypeSymbol = enterAliasType(tpnme.AnyRef , ObjectType )
310310 def AnyRefType : TypeRef = AnyRefAlias .typeRef
311311
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+ }
314324 @ threadUnsafe lazy val Object_synchronized : TermSymbol = enterPolyMethod(ObjectClass , nme.synchronized_, 1 ,
315325 pt => MethodType (List (pt.paramRefs(0 )), pt.paramRefs(0 )), Final )
316326 @ threadUnsafe lazy val Object_clone : TermSymbol = enterMethod(ObjectClass , nme.clone_, MethodType (Nil , ObjectType ), Protected )
@@ -344,18 +354,42 @@ class Definitions {
344354 pt => MethodType (List (FunctionOf (Nil , pt.paramRefs(0 ))), pt.paramRefs(0 )))
345355
346356 /** 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+ }
349361
350362 @ threadUnsafe lazy val NothingClass : ClassSymbol = enterCompleteClassSymbol(
351363 ScalaPackageClass , tpnme.Nothing , AbstractFinal , List (AnyClass .typeRef))
352364 def NothingType : TypeRef = NothingClass .typeRef
353365 @ 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+ }
356371 def NullType : TypeRef = NullClass .typeRef
357372 @ threadUnsafe lazy val RuntimeNullModuleRef : TermRef = ctx.requiredModuleRef(" scala.runtime.Null" )
358373
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+
359393 @ threadUnsafe lazy val ImplicitScrutineeTypeSym =
360394 newSymbol(ScalaPackageClass , tpnme.IMPLICITkw , EmptyFlags , TypeBounds .empty).entered
361395 def ImplicitScrutineeTypeRef : TypeRef = ImplicitScrutineeTypeSym .typeRef
@@ -591,12 +625,16 @@ class Definitions {
591625 @ threadUnsafe lazy val BoxedNumberClass : ClassSymbol = ctx.requiredClass(" java.lang.Number" )
592626 @ threadUnsafe lazy val ClassCastExceptionClass : ClassSymbol = ctx.requiredClass(" java.lang.ClassCastException" )
593627 @ 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
595631 case _ => false
596632 }).symbol.asTerm
597633 @ threadUnsafe lazy val ArithmeticExceptionClass : ClassSymbol = ctx.requiredClass(" java.lang.ArithmeticException" )
598634 @ 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
600638 case _ => false
601639 }).symbol.asTerm
602640
@@ -967,6 +1005,7 @@ class Definitions {
9671005 def methOfAny (tp : Type ): MethodType = MethodType (List (AnyType ), tp)
9681006 def methOfAnyVal (tp : Type ): MethodType = MethodType (List (AnyValType ), tp)
9691007 def methOfAnyRef (tp : Type ): MethodType = MethodType (List (ObjectType ), tp)
1008+ def methOfAnyRefOrNull (tp : Type ): MethodType = MethodType (List (OrType (ObjectType , NullType )), tp)
9701009
9711010 // Derived types
9721011
@@ -1128,10 +1167,23 @@ class Definitions {
11281167 name.length > prefix.length &&
11291168 name.drop(prefix.length).forall(_.isDigit))
11301169
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 = {
11321176 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 = {
11341185 tp.derivesFrom(NothingClass ) || tp.derivesFrom(NullClass )
1186+ }
11351187
11361188 /** Is a function class.
11371189 * - FunctionXXL
@@ -1225,9 +1277,12 @@ class Definitions {
12251277 () => ScalaPackageVal .termRef
12261278 )
12271279
1228- val PredefImportFns : List [() => TermRef ] = List [() => TermRef ](
1280+ lazy val PredefImportFns : List [() => TermRef ] = List [() => TermRef ](
12291281 () => 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" )
12311286 )
12321287
12331288 @ threadUnsafe lazy val RootImportFns : List [() => TermRef ] =
@@ -1475,18 +1530,22 @@ class Definitions {
14751530 // ----- Initialization ---------------------------------------------------
14761531
14771532 /** 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+ }
14901549
14911550 @ threadUnsafe lazy val syntheticCoreClasses : List [Symbol ] = syntheticScalaClasses ++ List (
14921551 EmptyPackageVal ,
0 commit comments