@@ -4,7 +4,7 @@ package core
44
55import scala .annotation .{threadUnsafe => tu }
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
@@ -269,7 +269,7 @@ class Definitions {
269269 @ tu lazy val Any_asInstanceOf : TermSymbol = enterT1ParameterlessMethod(AnyClass , nme.asInstanceOf_, _.paramRefs(0 ), Final )
270270 @ tu lazy val Any_typeTest : TermSymbol = enterT1ParameterlessMethod(AnyClass , nme.isInstanceOfPM, _ => BooleanType , Final | Synthetic | Artifact )
271271 @ tu lazy val Any_typeCast : TermSymbol = enterT1ParameterlessMethod(AnyClass , nme.asInstanceOfPM, _.paramRefs(0 ), Final | Synthetic | Artifact | StableRealizable )
272- // generated by pattern matcher, eliminated by erasure
272+ // generated by pattern matcher and explicit nulls , eliminated by erasure
273273
274274 /** def getClass[A >: this.type](): Class[? <: A] */
275275 @ tu lazy val Any_getClass : TermSymbol =
@@ -347,11 +347,29 @@ class Definitions {
347347 ScalaPackageClass , tpnme.Nothing , AbstractFinal , List (AnyClass .typeRef))
348348 def NothingType : TypeRef = NothingClass .typeRef
349349 @ tu lazy val RuntimeNothingModuleRef : TermRef = ctx.requiredModuleRef(" scala.runtime.Nothing" )
350- @ tu lazy val NullClass : ClassSymbol = enterCompleteClassSymbol(
351- ScalaPackageClass , tpnme.Null , AbstractFinal , List (ObjectClass .typeRef))
350+ @ tu lazy val NullClass : ClassSymbol = {
351+ val parent = if (ctx.explicitNulls) AnyType else ObjectType
352+ enterCompleteClassSymbol(ScalaPackageClass , tpnme.Null , AbstractFinal , parent :: Nil )
353+ }
352354 def NullType : TypeRef = NullClass .typeRef
353355 @ tu lazy val RuntimeNullModuleRef : TermRef = ctx.requiredModuleRef(" scala.runtime.Null" )
354356
357+ /** An alias for null values that originate in Java code.
358+ * This type gets special treatment in the Typer. Specifically, `JavaNull` can be selected through:
359+ * e.g.
360+ * ```
361+ * // x: String|Null
362+ * x.length // error: `Null` has no `length` field
363+ * // x2: String|JavaNull
364+ * x2.length // allowed by the Typer, but unsound (might throw NPE)
365+ * ```
366+ */
367+ lazy val JavaNullAlias : TypeSymbol = {
368+ assert(ctx.explicitNulls)
369+ enterAliasType(tpnme.JavaNull , NullType )
370+ }
371+ def JavaNullAliasType : TypeRef = JavaNullAlias .typeRef
372+
355373 @ tu lazy val ImplicitScrutineeTypeSym =
356374 newSymbol(ScalaPackageClass , tpnme.IMPLICITkw , EmptyFlags , TypeBounds .empty).entered
357375 def ImplicitScrutineeTypeRef : TypeRef = ImplicitScrutineeTypeSym .typeRef
@@ -441,12 +459,12 @@ class Definitions {
441459 @ tu lazy val Boolean_|| : Symbol = BooleanClass .requiredMethod(nme.ZOR )
442460 @ tu lazy val Boolean_== : Symbol =
443461 BooleanClass .info.member(nme.EQ ).suchThat(_.info.firstParamTypes match {
444- case List (pt) => (pt isRef BooleanClass )
462+ case List (pt) => pt. isRef( BooleanClass )
445463 case _ => false
446464 }).symbol
447465 @ tu lazy val Boolean_!= : Symbol =
448466 BooleanClass .info.member(nme.NE ).suchThat(_.info.firstParamTypes match {
449- case List (pt) => (pt isRef BooleanClass )
467+ case List (pt) => pt. isRef( BooleanClass )
450468 case _ => false
451469 }).symbol
452470
@@ -509,7 +527,7 @@ class Definitions {
509527 @ tu lazy val StringModule : Symbol = StringClass .linkedClass
510528 @ tu lazy val String_+ : TermSymbol = enterMethod(StringClass , nme.raw.PLUS , methOfAny(StringType ), Final )
511529 @ tu lazy val String_valueOf_Object : Symbol = StringModule .info.member(nme.valueOf).suchThat(_.info.firstParamTypes match {
512- case List (pt) => (pt isRef AnyClass ) || (pt isRef ObjectClass )
530+ case List (pt) => pt. isRef( AnyClass ) || pt. isRef( ObjectClass )
513531 case _ => false
514532 }).symbol
515533
@@ -520,12 +538,16 @@ class Definitions {
520538 @ tu lazy val BoxedNumberClass : ClassSymbol = ctx.requiredClass(" java.lang.Number" )
521539 @ tu lazy val ClassCastExceptionClass : ClassSymbol = ctx.requiredClass(" java.lang.ClassCastException" )
522540 @ tu lazy val ClassCastExceptionClass_stringConstructor : TermSymbol = ClassCastExceptionClass .info.member(nme.CONSTRUCTOR ).suchThat(_.info.firstParamTypes match {
523- case List (pt) => (pt isRef StringClass )
541+ case List (pt) =>
542+ val pt1 = if (ctx.explicitNulls) pt.stripNull() else pt
543+ pt1.isRef(StringClass )
524544 case _ => false
525545 }).symbol.asTerm
526546 @ tu lazy val ArithmeticExceptionClass : ClassSymbol = ctx.requiredClass(" java.lang.ArithmeticException" )
527547 @ tu lazy val ArithmeticExceptionClass_stringConstructor : TermSymbol = ArithmeticExceptionClass .info.member(nme.CONSTRUCTOR ).suchThat(_.info.firstParamTypes match {
528- case List (pt) => (pt isRef StringClass )
548+ case List (pt) =>
549+ val pt1 = if (ctx.explicitNulls) pt.stripNull() else pt
550+ pt1.isRef(StringClass )
529551 case _ => false
530552 }).symbol.asTerm
531553
@@ -793,6 +815,31 @@ class Definitions {
793815 @ tu lazy val InfixAnnot : ClassSymbol = ctx.requiredClass(" scala.annotation.infix" )
794816 @ tu lazy val AlphaAnnot : ClassSymbol = ctx.requiredClass(" scala.annotation.alpha" )
795817
818+ // A list of annotations that are commonly used to indicate that a field/method argument or return
819+ // type is not null. These annotations are used by the nullification logic in JavaNullInterop to
820+ // improve the precision of type nullification.
821+ // We don't require that any of these annotations be present in the class path, but we want to
822+ // create Symbols for the ones that are present, so they can be checked during nullification.
823+ @ tu lazy val NotNullAnnots : List [ClassSymbol ] = ctx.getClassesIfDefined(
824+ " javax.annotation.Nonnull" ::
825+ " javax.validation.constraints.NotNull" ::
826+ " androidx.annotation.NonNull" ::
827+ " android.support.annotation.NonNull" ::
828+ " android.annotation.NonNull" ::
829+ " com.android.annotations.NonNull" ::
830+ " org.eclipse.jdt.annotation.NonNull" ::
831+ " edu.umd.cs.findbugs.annotations.NonNull" ::
832+ " org.checkerframework.checker.nullness.qual.NonNull" ::
833+ " org.checkerframework.checker.nullness.compatqual.NonNullDecl" ::
834+ " org.jetbrains.annotations.NotNull" ::
835+ " org.springframework.lang.NonNull" ::
836+ " org.springframework.lang.NonNullApi" ::
837+ " org.springframework.lang.NonNullFields" ::
838+ " lombok.NonNull" ::
839+ " reactor.util.annotation.NonNull" ::
840+ " reactor.util.annotation.NonNullApi" ::
841+ " io.reactivex.annotations.NonNull" :: Nil map PreNamedString )
842+
796843 // convenient one-parameter method types
797844 def methOfAny (tp : Type ): MethodType = MethodType (List (AnyType ), tp)
798845 def methOfAnyVal (tp : Type ): MethodType = MethodType (List (AnyValType ), tp)
@@ -845,7 +892,7 @@ class Definitions {
845892 if (ctx.erasedTypes) JavaArrayType (elem)
846893 else ArrayType .appliedTo(elem :: Nil )
847894 def unapply (tp : Type )(implicit ctx : Context ): Option [Type ] = tp.dealias match {
848- case AppliedType (at, arg :: Nil ) if at isRef ArrayType .symbol => Some (arg)
895+ case AppliedType (at, arg :: Nil ) if at. isRef( ArrayType .symbol) => Some (arg)
849896 case _ => None
850897 }
851898 }
@@ -957,8 +1004,16 @@ class Definitions {
9571004 name.drop(prefix.length).forall(_.isDigit))
9581005
9591006 def isBottomClass (cls : Symbol ): Boolean =
960- cls == NothingClass || cls == NullClass
1007+ if (ctx.explicitNulls && ! ctx.phase.erasedTypes) cls == NothingClass
1008+ else isBottomClassAfterErasure(cls)
1009+
1010+ def isBottomClassAfterErasure (cls : Symbol ): Boolean = cls == NothingClass || cls == NullClass
1011+
9611012 def isBottomType (tp : Type ): Boolean =
1013+ if (ctx.explicitNulls && ! ctx.phase.erasedTypes) tp.derivesFrom(NothingClass )
1014+ else isBottomTypeAfterErasure(tp)
1015+
1016+ def isBottomTypeAfterErasure (tp : Type ): Boolean =
9621017 tp.derivesFrom(NothingClass ) || tp.derivesFrom(NullClass )
9631018
9641019 /** Is a function class.
@@ -1089,7 +1144,7 @@ class Definitions {
10891144
10901145 def isTupleType (tp : Type )(implicit ctx : Context ): Boolean = {
10911146 val arity = tp.dealias.argInfos.length
1092- arity <= MaxTupleArity && TupleType (arity) != null && (tp isRef TupleType (arity).symbol)
1147+ arity <= MaxTupleArity && TupleType (arity) != null && tp. isRef( TupleType (arity).symbol)
10931148 }
10941149
10951150 def tupleType (elems : List [Type ]): Type = {
@@ -1302,18 +1357,22 @@ class Definitions {
13021357 // ----- Initialization ---------------------------------------------------
13031358
13041359 /** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
1305- @ tu lazy val syntheticScalaClasses : List [TypeSymbol ] = List (
1306- AnyClass ,
1307- AnyRefAlias ,
1308- AnyKindClass ,
1309- andType,
1310- orType,
1311- RepeatedParamClass ,
1312- ByNameParamClass2x ,
1313- AnyValClass ,
1314- NullClass ,
1315- NothingClass ,
1316- SingletonClass )
1360+ @ tu lazy val syntheticScalaClasses : List [TypeSymbol ] = {
1361+ val synth = List (
1362+ AnyClass ,
1363+ AnyRefAlias ,
1364+ AnyKindClass ,
1365+ andType,
1366+ orType,
1367+ RepeatedParamClass ,
1368+ ByNameParamClass2x ,
1369+ AnyValClass ,
1370+ NullClass ,
1371+ NothingClass ,
1372+ SingletonClass )
1373+
1374+ if (ctx.explicitNulls) synth :+ JavaNullAlias else synth
1375+ }
13171376
13181377 @ tu lazy val syntheticCoreClasses : List [Symbol ] = syntheticScalaClasses ++ List (
13191378 EmptyPackageVal ,
0 commit comments