Skip to content

Commit 1726660

Browse files
committed
Add notNull member to Any
Add a method $nn to Any that has type def $nn: this.type & NotNull The method is marked as stable & realizable, which means it can appear in paths. Special handling is required in asSeenFrom, to reflect the fact that $nn are not real selections, i.e. the selected item has the same owner as the one in the prefix. N.B. I tried to make $nn a field instead, but this caused AbstractMethod errors for reasons I cannot quite track down.
1 parent b32e30a commit 1726660

File tree

9 files changed

+26
-5
lines changed

9 files changed

+26
-5
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ class Definitions {
254254
List(AnyClass.typeRef, NotNullClass.typeRef)))
255255
def AnyValType: TypeRef = AnyValClass.typeRef
256256

257-
@tu lazy val Any_== : TermSymbol = enterMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final)
257+
@tu lazy val Any_== : TermSymbol = enterMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final)
258258
@tu lazy val Any_!= : TermSymbol = enterMethod(AnyClass, nme.NE, methOfAny(BooleanType), Final)
259259
@tu lazy val Any_equals: TermSymbol = enterMethod(AnyClass, nme.equals_, methOfAny(BooleanType))
260260
@tu lazy val Any_hashCode: TermSymbol = enterMethod(AnyClass, nme.hashCode_, MethodType(Nil, IntType))
@@ -263,6 +263,8 @@ class Definitions {
263263
@tu lazy val Any_isInstanceOf: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final)
264264
@tu lazy val Any_asInstanceOf: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, _.paramRefs(0), Final)
265265
@tu lazy val Any_typeTest: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOfPM, _ => BooleanType, Final | Synthetic | Artifact)
266+
@tu lazy val Any_notNull: TermSymbol = newSymbol(AnyClass, nme.NOT_NULL, Method | Final | Erased | Artifact| StableRealizable,
267+
AndType(AnyClass.thisType, NotNullClass.typeRef)).entered
266268
@tu lazy val Any_typeCast: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOfPM, _.paramRefs(0), Final | Synthetic | Artifact | StableRealizable)
267269
// generated by pattern matcher, eliminated by erasure
268270

@@ -275,7 +277,9 @@ class Definitions {
275277
bounds = TypeBounds.lower(AnyClass.thisType))
276278

277279
private def AnyMethods: List[TermSymbol] = List(Any_==, Any_!=, Any_equals, Any_hashCode,
278-
Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf, Any_typeTest, Any_typeCast)
280+
Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf, Any_typeTest, Any_typeCast, Any_notNull)
281+
282+
def isAny_notNull(sym: Symbol)(given Context) = sym.name == nme.NOT_NULL && sym == Any_notNull
279283

280284
@tu lazy val ObjectClass: ClassSymbol = {
281285
val cls = ctx.requiredClass("java.lang.Object")

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ object StdNames {
262262
val MIRROR_PREFIX: N = "$m."
263263
val MIRROR_SHORT: N = "$m"
264264
val MIRROR_UNTYPED: N = "$m$untyped"
265+
val NOT_NULL: N = "$nn"
265266
val REIFY_FREE_PREFIX: N = "free$"
266267
val REIFY_FREE_THIS_SUFFIX: N = "$this"
267268
val REIFY_FREE_VALUE_SUFFIX: N = "$value"

compiler/src/dotty/tools/dotc/core/TypeErasure.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ object TypeErasure {
197197
else if (sym.isAbstractType) TypeAlias(WildcardType)
198198
else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(erasureCtx))
199199
else if (sym.is(Label)) erase.eraseResult(sym.info)(erasureCtx)
200+
else if sym.is(Erased) && defn.isAny_notNull(sym) then NoType // Q: Should we delete all erased symbols that way?
200201
else erase.eraseInfo(tp, sym)(erasureCtx) match {
201202
case einfo: MethodType =>
202203
if (sym.isGetter && einfo.resultType.isRef(defn.UnitClass))

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
8181
// called which we override to set the `approximated` flag.
8282
range(defn.NothingType, pre)
8383
else pre
84-
else if ((pre.termSymbol is Package) && !(thiscls is Package))
84+
else if (pre.termSymbol.is(Package) && !thiscls.is(Package))
8585
toPrefix(pre.select(nme.PACKAGE), cls, thiscls)
8686
else
8787
toPrefix(pre.baseType(cls).normalizedPrefix, cls.owner, thiscls)

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,8 @@ object Erasure {
426426
* e.m -> e.[]m if `m` is an array operation other than `clone`.
427427
*/
428428
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
429+
if defn.isAny_notNull(tree.symbol) then return typed(tree.qualifier, pt)
430+
429431
val qual1 = typed(tree.qualifier, AnySelectionProto)
430432

431433
def mapOwner(sym: Symbol): Symbol = {

compiler/src/dotty/tools/dotc/typer/Nullables.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ object Nullables with
269269
* Therefore, variables with unreachable assignments can be assumed to be not-null
270270
* only if their type asserts it.
271271
*
272-
* Note: we the local variables through their offset and not through their name
272+
* Note: we track the local variables through their offset and not through their name
273273
* because of shadowing.
274274
*/
275275
def assignmentSpans(given Context): Map[Int, List[Span]] =

compiler/src/dotty/tools/repl/ReplDriver.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ class ReplDriver(settings: Array[String],
272272

273273
val vals =
274274
info.fields
275-
.filterNot(_.symbol.isOneOf(ParamAccessor | Private | Synthetic | Module))
275+
.filterNot(_.symbol.isOneOf(ParamAccessor | Private | Synthetic | Artifact | Module))
276276
.filter(_.symbol.name.is(SimpleNameKind))
277277
.sortBy(_.name)
278278

tests/pos/notNull.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,16 @@ object Test with
1818
val y = notNull(identity(x)); val yc: Int = y
1919
val z = notNull(x); val zc: Int = z
2020
}
21+
locally {
22+
val x: Int | Null = ???
23+
val y = identity(x).$nn; val yc: Int = y
24+
val z = x.$nn; val zc: Int = z
25+
}
26+
class C { type T }
27+
locally {
28+
val x: C { type T = Int } = new C { type T = Int }
29+
val y: x.$nn.T = 33
30+
val z = y; val zc: Int = z
31+
}
32+
2133

tests/run-macros/i6518.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
##
33
$asInstanceOf$
44
$isInstanceOf$
5+
$nn
56
==
67
andThen
78
apply

0 commit comments

Comments
 (0)