@@ -286,7 +286,12 @@ class Definitions {
286
286
lazy val ObjectClass : ClassSymbol = {
287
287
val cls = ctx.requiredClass(" java.lang.Object" )
288
288
assert(! cls.isCompleted, " race for completing java.lang.Object" )
289
- cls.info = ClassInfo (cls.owner.thisType, cls, AnyClass .typeRef :: Nil , newScope)
289
+ val parents = if (ctx.settings.YexplicitNulls .value) {
290
+ AnyType :: RefEqType :: Nil
291
+ } else {
292
+ AnyType :: Nil
293
+ }
294
+ cls.info = ClassInfo (cls.owner.thisType, cls, parents, newScope)
290
295
cls.setFlag(NoInits )
291
296
292
297
// The companion object doesn't really exist, `NoType` is the general
@@ -303,8 +308,17 @@ class Definitions {
303
308
lazy val AnyRefAlias : TypeSymbol = enterAliasType(tpnme.AnyRef , ObjectType )
304
309
def AnyRefType : TypeRef = AnyRefAlias .typeRef
305
310
306
- lazy val Object_eq : TermSymbol = enterMethod(ObjectClass , nme.eq, methOfAnyRef(BooleanType ), Final )
307
- lazy val Object_ne : TermSymbol = enterMethod(ObjectClass , nme.ne, methOfAnyRef(BooleanType ), Final )
311
+ // TODO(abeln): modify usage sites to use `RefEq_eq/ne` once we migrate to explicit nulls?
312
+ lazy val Object_eq : TermSymbol = if (ctx.settings.YexplicitNulls .value) {
313
+ RefEq_eq
314
+ } else {
315
+ enterMethod(ObjectClass , nme.eq, methOfAnyRef(BooleanType ), Final )
316
+ }
317
+ lazy val Object_ne : TermSymbol = if (ctx.settings.YexplicitNulls .value) {
318
+ RefEq_ne
319
+ } else {
320
+ enterMethod(ObjectClass , nme.ne, methOfAnyRef(BooleanType ), Final )
321
+ }
308
322
lazy val Object_synchronized : TermSymbol = enterPolyMethod(ObjectClass , nme.synchronized_, 1 ,
309
323
pt => MethodType (List (pt.paramRefs(0 )), pt.paramRefs(0 )), Final )
310
324
lazy val Object_clone : TermSymbol = enterMethod(ObjectClass , nme.clone_, MethodType (Nil , ObjectType ), Protected )
@@ -351,11 +365,40 @@ class Definitions {
351
365
ScalaPackageClass , tpnme.Nothing , AbstractFinal , List (AnyClass .typeRef))
352
366
def NothingType : TypeRef = NothingClass .typeRef
353
367
lazy val RuntimeNothingModuleRef : TermRef = ctx.requiredModuleRef(" scala.runtime.Nothing" )
368
+
369
+ /** `RefEq` is the trait defining the reference equality operators (`eq`, `neq`).
370
+ * It's a supertype of both `AnyRef` (which is non-nullable) and `Null`.
371
+ * With `RefEq`, we can compare `null` for reference equality a la `null eq foo`.
372
+ * `RefEq` is just a marker trait and there's no corresponding class file, since it gets erased to `Object`.
373
+ */
374
+ lazy val RefEqClass : ClassSymbol = {
375
+ assert(ctx.settings.YexplicitNulls .value)
376
+ enterCompleteClassSymbol(ScalaPackageClass , tpnme.RefEq , Trait , AnyClass .typeRef :: Nil )
377
+ }
378
+ def RefEqType : TypeRef = {
379
+ assert(ctx.settings.YexplicitNulls .value)
380
+ RefEqClass .typeRef
381
+ }
382
+
383
+ lazy val RefEq_eq : TermSymbol = {
384
+ assert(ctx.settings.YexplicitNulls .value)
385
+ enterMethod(RefEqClass , nme.eq, MethodType (List (RefEqType ), BooleanType ), Final )
386
+ }
387
+ lazy val RefEq_ne : TermSymbol = {
388
+ assert(ctx.settings.YexplicitNulls .value)
389
+ enterMethod(RefEqClass , nme.ne, MethodType (List (RefEqType ), BooleanType ), Final )
390
+ }
391
+
392
+ def RefEqMethods : List [TermSymbol ] = {
393
+ assert(ctx.settings.YexplicitNulls .value)
394
+ List (RefEq_eq , RefEq_ne )
395
+ }
396
+
354
397
lazy val NullClass : ClassSymbol = {
355
398
val parents = if (ctx.settings.YexplicitNulls .value) {
356
- List (AnyClass .typeRef )
399
+ List (AnyType , RefEqType )
357
400
} else {
358
- List (ObjectClass .typeRef )
401
+ List (ObjectType )
359
402
}
360
403
enterCompleteClassSymbol(ScalaPackageClass , tpnme.Null , AbstractFinal , parents)
361
404
}
@@ -1205,7 +1248,14 @@ class Definitions {
1205
1248
lazy val UnqualifiedOwnerTypes : Set [NamedType ] =
1206
1249
RootImportTypes .toSet[NamedType ] ++ RootImportTypes .map(_.symbol.moduleClass.typeRef)
1207
1250
1208
- lazy val NotRuntimeClasses : Set [Symbol ] = Set (AnyClass , AnyValClass , NullClass , NothingClass )
1251
+ lazy val NotRuntimeClasses : Set [Symbol ] = {
1252
+ val classes : Set [Symbol ] = Set (AnyClass , AnyValClass , NullClass , NothingClass )
1253
+ if (ctx.settings.YexplicitNulls .value) {
1254
+ classes + RefEqClass
1255
+ } else {
1256
+ classes
1257
+ }
1258
+ }
1209
1259
1210
1260
/** Classes that are known not to have an initializer irrespective of
1211
1261
* whether NoInits is set. Note: FunctionXXLClass is in this set
@@ -1400,13 +1450,20 @@ class Definitions {
1400
1450
def isValueSubClass (sym1 : Symbol , sym2 : Symbol ): Boolean =
1401
1451
valueTypeEnc(sym2.asClass.name) % valueTypeEnc(sym1.asClass.name) == 0
1402
1452
1403
- lazy val specialErasure : SimpleIdentityMap [Symbol , ClassSymbol ] =
1404
- SimpleIdentityMap .Empty [Symbol ]
1405
- .updated(AnyClass , ObjectClass )
1406
- .updated(AnyValClass , ObjectClass )
1407
- .updated(SingletonClass , ObjectClass )
1408
- .updated(TupleClass , ObjectClass )
1409
- .updated(NonEmptyTupleClass , ProductClass )
1453
+ lazy val specialErasure : SimpleIdentityMap [Symbol , ClassSymbol ] = {
1454
+ val idMap =
1455
+ SimpleIdentityMap .Empty [Symbol ]
1456
+ .updated(AnyClass , ObjectClass )
1457
+ .updated(AnyValClass , ObjectClass )
1458
+ .updated(SingletonClass , ObjectClass )
1459
+ .updated(TupleClass , ObjectClass )
1460
+ .updated(NonEmptyTupleClass , ProductClass )
1461
+ if (ctx.settings.YexplicitNulls .value) {
1462
+ idMap.updated(RefEqClass , ObjectClass )
1463
+ } else {
1464
+ idMap
1465
+ }
1466
+ }
1410
1467
1411
1468
// ----- Initialization ---------------------------------------------------
1412
1469
@@ -1426,7 +1483,7 @@ class Definitions {
1426
1483
SingletonClass ,
1427
1484
EqualsPatternClass )
1428
1485
1429
- if (ctx.settings.YexplicitNulls .value) synth :+ JavaNullAlias
1486
+ if (ctx.settings.YexplicitNulls .value) synth ++ List ( JavaNullAlias , RefEqClass )
1430
1487
else synth
1431
1488
}
1432
1489
@@ -1435,8 +1492,14 @@ class Definitions {
1435
1492
OpsPackageClass )
1436
1493
1437
1494
/** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */
1438
- lazy val syntheticCoreMethods : List [TermSymbol ] =
1439
- AnyMethods ++ ObjectMethods ++ List (String_+ , throwMethod)
1495
+ lazy val syntheticCoreMethods : List [TermSymbol ] = {
1496
+ val methods = AnyMethods ++ ObjectMethods ++ List (String_+ , throwMethod)
1497
+ if (ctx.settings.YexplicitNulls .value) {
1498
+ methods ++ RefEqMethods
1499
+ } else {
1500
+ methods
1501
+ }
1502
+ }
1440
1503
1441
1504
lazy val reservedScalaClassNames : Set [Name ] = syntheticScalaClasses.map(_.name).toSet
1442
1505
0 commit comments