Skip to content

Commit 8e3da53

Browse files
committed
Adapt the compiler to generate non-nullable types.
For `This` nodes and `IsInstanceOf` nodes. We only active the relevant deserialization hacks when reading IR from before 1.17.
1 parent 22b69c8 commit 8e3da53

File tree

4 files changed

+29
-18
lines changed

4 files changed

+29
-18
lines changed

compiler/src/main/scala/org/scalajs/nscplugin/GenJSCode.scala

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,19 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
152152
private val fieldsMutatedInCurrentClass = new ScopedVar[mutable.Set[Name]]
153153
private val generatedSAMWrapperCount = new ScopedVar[VarBox[Int]]
154154

155+
def currentThisTypeNullable: jstpe.Type =
156+
encodeClassType(currentClassSym)
157+
155158
def currentThisType: jstpe.Type = {
156-
encodeClassType(currentClassSym) match {
159+
currentThisTypeNullable match {
157160
case tpe @ jstpe.ClassType(cls, _) =>
158-
jstpe.BoxedClassToPrimType.getOrElse(cls, tpe)
159-
case tpe =>
161+
jstpe.BoxedClassToPrimType.getOrElse(cls, tpe.toNonNullable)
162+
case tpe @ jstpe.AnyType =>
163+
// We are in a JS class, in which even `this` is nullable
160164
tpe
165+
case tpe =>
166+
throw new AssertionError(
167+
s"Unexpected IR this type $tpe for class ${currentClassSym.get}")
161168
}
162169
}
163170

@@ -2124,8 +2131,13 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
21242131
if (thisSym.isMutable)
21252132
mutableLocalVars += thisSym
21262133

2134+
/* The `thisLocalIdent` must be nullable. Even though we initially
2135+
* assign it to `this`, which is non-nullable, tail-recursive calls
2136+
* may reassign it to a different value, which in general will be
2137+
* nullable.
2138+
*/
21272139
val thisLocalIdent = encodeLocalSym(thisSym)
2128-
val thisLocalType = currentThisType
2140+
val thisLocalType = currentThisTypeNullable
21292141

21302142
val genRhs = {
21312143
/* #3267 In default methods, scalac will type its _$this
@@ -2222,7 +2234,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
22222234
* @param tree
22232235
* The tree to adapt.
22242236
* @param tpe
2225-
* The target type, which must be either `AnyType` or `ClassType(_)`.
2237+
* The target type, which must be either `AnyType` or `ClassType`.
22262238
*/
22272239
private def forceAdapt(tree: js.Tree, tpe: jstpe.Type): js.Tree = {
22282240
if (tree.tpe == tpe || tpe == jstpe.AnyType) {
@@ -2670,7 +2682,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
26702682
js.This()(currentThisType)
26712683
} { thisLocalIdent =>
26722684
// .copy() to get the correct position
2673-
js.VarRef(thisLocalIdent.copy())(currentThisType)
2685+
js.VarRef(thisLocalIdent.copy())(currentThisTypeNullable)
26742686
}
26752687
}
26762688

@@ -3333,7 +3345,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
33333345
val isTailJumpThisLocalVar = formalArgSym.name == nme.THIS
33343346

33353347
val tpe =
3336-
if (isTailJumpThisLocalVar) currentThisType
3348+
if (isTailJumpThisLocalVar) currentThisTypeNullable
33373349
else toIRType(formalArgSym.tpe)
33383350

33393351
val fixedActualArg =
@@ -3561,7 +3573,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
35613573
// The Scala type system prevents x.isInstanceOf[Null] and ...[Nothing]
35623574
assert(sym != NullClass && sym != NothingClass,
35633575
s"Found a .isInstanceOf[$sym] at $pos")
3564-
js.IsInstanceOf(value, toIRType(to))
3576+
js.IsInstanceOf(value, toIRType(to).toNonNullable)
35653577
}
35663578
}
35673579

@@ -6334,7 +6346,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
63346346
}
63356347
val className = encodeClassName(currentClassSym).withSuffix(suffix)
63366348

6337-
val classType = jstpe.ClassType(className, nullable = true)
6349+
val thisType = jstpe.ClassType(className, nullable = false)
63386350

63396351
// val f: Any
63406352
val fFieldIdent = js.FieldIdent(FieldName(className, SimpleFieldName("f")))
@@ -6353,10 +6365,10 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
63536365
jstpe.NoType,
63546366
Some(js.Block(List(
63556367
js.Assign(
6356-
js.Select(js.This()(classType), fFieldIdent)(jstpe.AnyType),
6368+
js.Select(js.This()(thisType), fFieldIdent)(jstpe.AnyType),
63576369
fParamDef.ref),
63586370
js.ApplyStatically(js.ApplyFlags.empty.withConstructor(true),
6359-
js.This()(classType),
6371+
js.This()(thisType),
63606372
ir.Names.ObjectClass,
63616373
js.MethodIdent(ir.Names.NoArgConstructorName),
63626374
Nil)(jstpe.NoType)))))(
@@ -6404,7 +6416,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
64046416
}.map((ensureBoxed _).tupled)
64056417

64066418
val call = js.JSFunctionApply(
6407-
js.Select(js.This()(classType), fFieldIdent)(jstpe.AnyType),
6419+
js.Select(js.This()(thisType), fFieldIdent)(jstpe.AnyType),
64086420
actualParams)
64096421

64106422
val body = fromAny(call, enteringPhase(currentRun.posterasurePhase) {

compiler/src/main/scala/org/scalajs/nscplugin/GenJSExports.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,7 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
930930

931931
private sealed abstract class RTTypeTest
932932

933-
private case class PrimitiveTypeTest(tpe: jstpe.Type, rank: Int)
933+
private case class PrimitiveTypeTest(tpe: jstpe.PrimType, rank: Int)
934934
extends RTTypeTest
935935

936936
// scalastyle:off equals.hash.code

ir/shared/src/main/scala/org/scalajs/ir/Serializers.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,7 @@ object Serializers {
12341234
case TagIsInstanceOf =>
12351235
val expr = readTree()
12361236
val testType0 = readType()
1237-
val testType = if (true /* hacks.use16 */) { // scalastyle:ignore
1237+
val testType = if (hacks.use16) {
12381238
testType0 match {
12391239
case ClassType(className, true) => ClassType(className, nullable = false)
12401240
case ArrayType(arrayTypeRef, true) => ArrayType(arrayTypeRef, nullable = false)
@@ -1414,7 +1414,7 @@ object Serializers {
14141414
val originalName = readOriginalName()
14151415
val kind = ClassKind.fromByte(readByte())
14161416

1417-
if (true /* hacks.use16 */) { // scalastyle:ignore
1417+
if (hacks.use16) {
14181418
thisTypeForHack = kind match {
14191419
case ClassKind.Class | ClassKind.ModuleClass | ClassKind.Interface =>
14201420
Some(ClassType(cls, nullable = false))

project/JavaLangObject.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ object JavaLangObject {
2626
implicit val DummyPos = NoPosition
2727

2828
// ClassType(Object) is normally invalid, but not in this class def
29-
val ThisType = ClassType(ObjectClass, nullable = true) // temp to test deserialization hack
29+
val ThisType = ClassType(ObjectClass, nullable = false)
3030

3131
val ObjectClassRef = ClassRef(ObjectClass)
3232
val ClassClassRef = ClassRef(ClassClass)
@@ -101,8 +101,7 @@ object JavaLangObject {
101101
Nil,
102102
AnyType,
103103
Some {
104-
// temporarily use nullable in IsInstanceOf to test deserialization hack
105-
If(IsInstanceOf(This()(ThisType), ClassType(CloneableClass, nullable = true)), {
104+
If(IsInstanceOf(This()(ThisType), ClassType(CloneableClass, nullable = false)), {
106105
Clone(AsInstanceOf(This()(ThisType), ClassType(CloneableClass, nullable = true)))
107106
}, {
108107
Throw(New(ClassName("java.lang.CloneNotSupportedException"),

0 commit comments

Comments
 (0)