@@ -4,7 +4,7 @@ package core
4
4
5
5
import scala .annotation .{threadUnsafe => tu }
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
@@ -269,7 +269,7 @@ class Definitions {
269
269
@ tu lazy val Any_asInstanceOf : TermSymbol = enterT1ParameterlessMethod(AnyClass , nme.asInstanceOf_, _.paramRefs(0 ), Final )
270
270
@ tu lazy val Any_typeTest : TermSymbol = enterT1ParameterlessMethod(AnyClass , nme.isInstanceOfPM, _ => BooleanType , Final | Synthetic | Artifact )
271
271
@ 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
273
273
274
274
/** def getClass[A >: this.type](): Class[? <: A] */
275
275
@ tu lazy val Any_getClass : TermSymbol =
@@ -347,11 +347,29 @@ class Definitions {
347
347
ScalaPackageClass , tpnme.Nothing , AbstractFinal , List (AnyClass .typeRef))
348
348
def NothingType : TypeRef = NothingClass .typeRef
349
349
@ 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
+ }
352
354
def NullType : TypeRef = NullClass .typeRef
353
355
@ tu lazy val RuntimeNullModuleRef : TermRef = ctx.requiredModuleRef(" scala.runtime.Null" )
354
356
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
+
355
373
@ tu lazy val ImplicitScrutineeTypeSym =
356
374
newSymbol(ScalaPackageClass , tpnme.IMPLICITkw , EmptyFlags , TypeBounds .empty).entered
357
375
def ImplicitScrutineeTypeRef : TypeRef = ImplicitScrutineeTypeSym .typeRef
@@ -441,12 +459,12 @@ class Definitions {
441
459
@ tu lazy val Boolean_|| : Symbol = BooleanClass .requiredMethod(nme.ZOR )
442
460
@ tu lazy val Boolean_== : Symbol =
443
461
BooleanClass .info.member(nme.EQ ).suchThat(_.info.firstParamTypes match {
444
- case List (pt) => (pt isRef BooleanClass )
462
+ case List (pt) => pt. isRef( BooleanClass )
445
463
case _ => false
446
464
}).symbol
447
465
@ tu lazy val Boolean_!= : Symbol =
448
466
BooleanClass .info.member(nme.NE ).suchThat(_.info.firstParamTypes match {
449
- case List (pt) => (pt isRef BooleanClass )
467
+ case List (pt) => pt. isRef( BooleanClass )
450
468
case _ => false
451
469
}).symbol
452
470
@@ -509,7 +527,7 @@ class Definitions {
509
527
@ tu lazy val StringModule : Symbol = StringClass .linkedClass
510
528
@ tu lazy val String_+ : TermSymbol = enterMethod(StringClass , nme.raw.PLUS , methOfAny(StringType ), Final )
511
529
@ 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 )
513
531
case _ => false
514
532
}).symbol
515
533
@@ -520,12 +538,16 @@ class Definitions {
520
538
@ tu lazy val BoxedNumberClass : ClassSymbol = ctx.requiredClass(" java.lang.Number" )
521
539
@ tu lazy val ClassCastExceptionClass : ClassSymbol = ctx.requiredClass(" java.lang.ClassCastException" )
522
540
@ 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 )
524
544
case _ => false
525
545
}).symbol.asTerm
526
546
@ tu lazy val ArithmeticExceptionClass : ClassSymbol = ctx.requiredClass(" java.lang.ArithmeticException" )
527
547
@ 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 )
529
551
case _ => false
530
552
}).symbol.asTerm
531
553
@@ -793,6 +815,31 @@ class Definitions {
793
815
@ tu lazy val InfixAnnot : ClassSymbol = ctx.requiredClass(" scala.annotation.infix" )
794
816
@ tu lazy val AlphaAnnot : ClassSymbol = ctx.requiredClass(" scala.annotation.alpha" )
795
817
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
+
796
843
// convenient one-parameter method types
797
844
def methOfAny (tp : Type ): MethodType = MethodType (List (AnyType ), tp)
798
845
def methOfAnyVal (tp : Type ): MethodType = MethodType (List (AnyValType ), tp)
@@ -845,7 +892,7 @@ class Definitions {
845
892
if (ctx.erasedTypes) JavaArrayType (elem)
846
893
else ArrayType .appliedTo(elem :: Nil )
847
894
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)
849
896
case _ => None
850
897
}
851
898
}
@@ -957,8 +1004,16 @@ class Definitions {
957
1004
name.drop(prefix.length).forall(_.isDigit))
958
1005
959
1006
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
+
961
1012
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 =
962
1017
tp.derivesFrom(NothingClass ) || tp.derivesFrom(NullClass )
963
1018
964
1019
/** Is a function class.
@@ -1089,7 +1144,7 @@ class Definitions {
1089
1144
1090
1145
def isTupleType (tp : Type )(implicit ctx : Context ): Boolean = {
1091
1146
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)
1093
1148
}
1094
1149
1095
1150
def tupleType (elems : List [Type ]): Type = {
@@ -1302,18 +1357,22 @@ class Definitions {
1302
1357
// ----- Initialization ---------------------------------------------------
1303
1358
1304
1359
/** 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
+ }
1317
1376
1318
1377
@ tu lazy val syntheticCoreClasses : List [Symbol ] = syntheticScalaClasses ++ List (
1319
1378
EmptyPackageVal ,
0 commit comments