Skip to content

Commit 6517d3d

Browse files
authored
Merge pull request scala-js#3801 from sjrd/type-in-is-as-instanceof
Use a `Type` rather than a `TypeRef` in `Is/AsInstanceOf`, and fuse `Unbox` into `AsInstanceOf`.
2 parents 75e2536 + 4277dff commit 6517d3d

File tree

20 files changed

+257
-403
lines changed

20 files changed

+257
-403
lines changed

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

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,8 +1923,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
19231923
case js.AsInstanceOf(underlying, _) if underlying.tpe == tpe =>
19241924
underlying
19251925
case _ =>
1926-
val cls = tpe.asInstanceOf[jstpe.ClassType].className
1927-
js.AsInstanceOf(tree, jstpe.ClassRef(cls))(tree.pos)
1926+
js.AsInstanceOf(tree, tpe)(tree.pos)
19281927
}
19291928
}
19301929
}
@@ -3028,14 +3027,15 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
30283027
s"isInstanceOf[${sym.fullName}] not supported because it is a JS trait")
30293028
js.BooleanLiteral(true)
30303029
} else {
3031-
js.Unbox(js.JSBinaryOp(
3032-
js.JSBinaryOp.instanceof, value, genPrimitiveJSClass(sym)), 'Z')
3030+
js.AsInstanceOf(
3031+
js.JSBinaryOp(js.JSBinaryOp.instanceof, value, genPrimitiveJSClass(sym)),
3032+
jstpe.BooleanType)
30333033
}
30343034
} else {
30353035
// The Scala type system prevents x.isInstanceOf[Null] and ...[Nothing]
30363036
assert(sym != NullClass && sym != NothingClass,
30373037
s"Found a .isInstanceOf[$sym] at $pos")
3038-
js.IsInstanceOf(value, toTypeRef(to))
3038+
js.IsInstanceOf(value, toIRType(to))
30393039
}
30403040
}
30413041

@@ -3044,7 +3044,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
30443044
implicit pos: Position): js.Tree = {
30453045

30463046
def default: js.Tree =
3047-
js.AsInstanceOf(value, toTypeRef(to))
3047+
js.AsInstanceOf(value, toIRType(to))
30483048

30493049
val sym = to.typeSymbol
30503050

@@ -4406,18 +4406,8 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
44064406
def makePrimitiveUnbox(expr: js.Tree, tpe: Type)(
44074407
implicit pos: Position): js.Tree = {
44084408
toIRType(tpe) match {
4409-
case jstpe.NoType => expr // for JS interop cases
4410-
case jstpe.BooleanType => js.Unbox(expr, 'Z')
4411-
case jstpe.CharType => js.Unbox(expr, 'C')
4412-
case jstpe.ByteType => js.Unbox(expr, 'B')
4413-
case jstpe.ShortType => js.Unbox(expr, 'S')
4414-
case jstpe.IntType => js.Unbox(expr, 'I')
4415-
case jstpe.LongType => js.Unbox(expr, 'J')
4416-
case jstpe.FloatType => js.Unbox(expr, 'F')
4417-
case jstpe.DoubleType => js.Unbox(expr, 'D')
4418-
4419-
case _ =>
4420-
abort(s"makePrimitiveUnbox requires a primitive type, found $tpe at $pos")
4409+
case jstpe.NoType => expr // for JS interop cases
4410+
case irTpe => js.AsInstanceOf(expr, irTpe)
44214411
}
44224412
}
44234413

@@ -4550,12 +4540,14 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
45504540
case IN =>
45514541
// js.special.in(arg1, arg2)
45524542
val (arg1, arg2) = genArgs2
4553-
js.Unbox(js.JSBinaryOp(js.JSBinaryOp.in, arg1, arg2), 'Z')
4543+
js.AsInstanceOf(js.JSBinaryOp(js.JSBinaryOp.in, arg1, arg2),
4544+
jstpe.BooleanType)
45544545

45554546
case INSTANCEOF =>
45564547
// js.special.instanceof(arg1, arg2)
45574548
val (arg1, arg2) = genArgs2
4558-
js.Unbox(js.JSBinaryOp(js.JSBinaryOp.instanceof, arg1, arg2), 'Z')
4549+
js.AsInstanceOf(js.JSBinaryOp(js.JSBinaryOp.instanceof, arg1, arg2),
4550+
jstpe.BooleanType)
45594551

45604552
case DELETE =>
45614553
// js.special.delete(arg1, arg2)

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

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
512512
assert(needsRestParam,
513513
"Trying to read rest param length but needsRestParam is false")
514514
js.Match(
515-
js.Unbox(js.JSSelect(genRestArgRef(), js.StringLiteral("length")), 'I'),
515+
js.AsInstanceOf(js.JSSelect(genRestArgRef(), js.StringLiteral("length")), jstpe.IntType),
516516
cases.toList, defaultCase)(jstpe.AnyType)
517517
}
518518
}
@@ -578,8 +578,8 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
578578
}
579579

580580
val optCond = typeTest match {
581-
case HijackedTypeTest(boxedClassName, _) =>
582-
Some(js.IsInstanceOf(paramRef, jstpe.ClassRef(boxedClassName)))
581+
case PrimitiveTypeTest(tpe, _) =>
582+
Some(js.IsInstanceOf(paramRef, tpe))
583583

584584
case InstanceOfTypeTest(tpe) =>
585585
Some(genIsInstanceOf(paramRef, tpe))
@@ -980,8 +980,8 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
980980

981981
private sealed abstract class RTTypeTest
982982

983-
private case class HijackedTypeTest(
984-
boxedClassName: String, rank: Int) extends RTTypeTest
983+
private case class PrimitiveTypeTest(tpe: jstpe.Type, rank: Int)
984+
extends RTTypeTest
985985

986986
// scalastyle:off equals.hash.code
987987
private case class InstanceOfTypeTest(tpe: Type) extends RTTypeTest {
@@ -1009,14 +1009,14 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
10091009
case (_, NoTypeTest) => true
10101010
case (NoTypeTest, _) => false
10111011

1012-
case (HijackedTypeTest(_, rank1), HijackedTypeTest(_, rank2)) =>
1012+
case (PrimitiveTypeTest(_, rank1), PrimitiveTypeTest(_, rank2)) =>
10131013
rank1 <= rank2
10141014

10151015
case (InstanceOfTypeTest(t1), InstanceOfTypeTest(t2)) =>
10161016
t1 <:< t2
10171017

1018-
case (_: HijackedTypeTest, _: InstanceOfTypeTest) => true
1019-
case (_: InstanceOfTypeTest, _: HijackedTypeTest) => false
1018+
case (_: PrimitiveTypeTest, _: InstanceOfTypeTest) => true
1019+
case (_: InstanceOfTypeTest, _: PrimitiveTypeTest) => false
10201020
}
10211021
}
10221022

@@ -1055,18 +1055,18 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
10551055
(toIRType(tpe): @unchecked) match {
10561056
case jstpe.AnyType => NoTypeTest
10571057

1058-
case jstpe.NoType => HijackedTypeTest(Defs.BoxedUnitClass, 0)
1059-
case jstpe.BooleanType => HijackedTypeTest(Defs.BoxedBooleanClass, 1)
1060-
case jstpe.CharType => HijackedTypeTest(Defs.BoxedCharacterClass, 2)
1061-
case jstpe.ByteType => HijackedTypeTest(Defs.BoxedByteClass, 3)
1062-
case jstpe.ShortType => HijackedTypeTest(Defs.BoxedShortClass, 4)
1063-
case jstpe.IntType => HijackedTypeTest(Defs.BoxedIntegerClass, 5)
1064-
case jstpe.LongType => HijackedTypeTest(Defs.BoxedLongClass, 6)
1065-
case jstpe.FloatType => HijackedTypeTest(Defs.BoxedFloatClass, 7)
1066-
case jstpe.DoubleType => HijackedTypeTest(Defs.BoxedDoubleClass, 8)
1067-
1068-
case jstpe.ClassType(Defs.BoxedUnitClass) => HijackedTypeTest(Defs.BoxedUnitClass, 0)
1069-
case jstpe.ClassType(Defs.BoxedStringClass) => HijackedTypeTest(Defs.BoxedStringClass, 9)
1058+
case jstpe.NoType => PrimitiveTypeTest(jstpe.UndefType, 0)
1059+
case jstpe.BooleanType => PrimitiveTypeTest(jstpe.BooleanType, 1)
1060+
case jstpe.CharType => PrimitiveTypeTest(jstpe.CharType, 2)
1061+
case jstpe.ByteType => PrimitiveTypeTest(jstpe.ByteType, 3)
1062+
case jstpe.ShortType => PrimitiveTypeTest(jstpe.ShortType, 4)
1063+
case jstpe.IntType => PrimitiveTypeTest(jstpe.IntType, 5)
1064+
case jstpe.LongType => PrimitiveTypeTest(jstpe.LongType, 6)
1065+
case jstpe.FloatType => PrimitiveTypeTest(jstpe.FloatType, 7)
1066+
case jstpe.DoubleType => PrimitiveTypeTest(jstpe.DoubleType, 8)
1067+
1068+
case jstpe.ClassType(Defs.BoxedUnitClass) => PrimitiveTypeTest(jstpe.UndefType, 0)
1069+
case jstpe.ClassType(Defs.BoxedStringClass) => PrimitiveTypeTest(jstpe.StringType, 9)
10701070
case jstpe.ClassType(_) => InstanceOfTypeTest(tpe)
10711071

10721072
case jstpe.ArrayType(_) => InstanceOfTypeTest(tpe)

ir/src/main/scala/org/scalajs/ir/Hashers.scala

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -303,20 +303,15 @@ object Hashers {
303303
mixIdent(field)
304304
mixType(tree.tpe)
305305

306-
case IsInstanceOf(expr, cls) =>
306+
case IsInstanceOf(expr, testType) =>
307307
mixTag(TagIsInstanceOf)
308308
mixTree(expr)
309-
mixTypeRef(cls)
309+
mixType(testType)
310310

311-
case AsInstanceOf(expr, cls) =>
311+
case AsInstanceOf(expr, tpe) =>
312312
mixTag(TagAsInstanceOf)
313313
mixTree(expr)
314-
mixTypeRef(cls)
315-
316-
case Unbox(expr, charCode) =>
317-
mixTag(TagUnbox)
318-
mixTree(expr)
319-
mixInt(charCode)
314+
mixType(tpe)
320315

321316
case GetClass(expr) =>
322317
mixTag(TagGetClass)

ir/src/main/scala/org/scalajs/ir/Printers.scala

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -496,22 +496,16 @@ object Printers {
496496
print('.')
497497
print(field)
498498

499-
case IsInstanceOf(expr, typeRef) =>
499+
case IsInstanceOf(expr, testType) =>
500500
print(expr)
501501
print(".isInstanceOf[")
502-
print(typeRef)
502+
print(testType)
503503
print(']')
504504

505-
case AsInstanceOf(expr, typeRef) =>
505+
case AsInstanceOf(expr, tpe) =>
506506
print(expr)
507507
print(".asInstanceOf[")
508-
print(typeRef)
509-
print(']')
510-
511-
case Unbox(expr, charCode) =>
512-
print(expr)
513-
print(".asInstanceOf[")
514-
print(charCode)
508+
print(tpe)
515509
print(']')
516510

517511
case GetClass(expr) =>

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

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -294,17 +294,13 @@ object Serializers {
294294
writeTree(record); writeIdent(field)
295295
writeType(tree.tpe)
296296

297-
case IsInstanceOf(expr, typeRef) =>
297+
case IsInstanceOf(expr, testType) =>
298298
writeByte(TagIsInstanceOf)
299-
writeTree(expr); writeTypeRef(typeRef)
299+
writeTree(expr); writeType(testType)
300300

301-
case AsInstanceOf(expr, typeRef) =>
301+
case AsInstanceOf(expr, tpe) =>
302302
writeByte(TagAsInstanceOf)
303-
writeTree(expr); writeTypeRef(typeRef)
304-
305-
case Unbox(expr, charCode) =>
306-
writeByte(TagUnbox)
307-
writeTree(expr); writeByte(charCode.toByte)
303+
writeTree(expr); writeType(tpe)
308304

309305
case GetClass(expr) =>
310306
writeByte(TagGetClass)
@@ -914,9 +910,8 @@ object Serializers {
914910
case TagArrayLength => ArrayLength(readTree())
915911
case TagArraySelect => ArraySelect(readTree(), readTree())(readType())
916912
case TagRecordValue => RecordValue(readType().asInstanceOf[RecordType], readTrees())
917-
case TagIsInstanceOf => IsInstanceOf(readTree(), readTypeRef())
918-
case TagAsInstanceOf => AsInstanceOf(readTree(), readTypeRef())
919-
case TagUnbox => Unbox(readTree(), readByte().toChar)
913+
case TagIsInstanceOf => IsInstanceOf(readTree(), readType())
914+
case TagAsInstanceOf => AsInstanceOf(readTree(), readType())
920915
case TagGetClass => GetClass(readTree())
921916

922917
case TagJSNew => JSNew(readTree(), readTreeOrJSSpreads())

ir/src/main/scala/org/scalajs/ir/Tags.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ private[ir] object Tags {
5757
final val TagRecordSelect = TagRecordValue + 1
5858
final val TagIsInstanceOf = TagRecordSelect + 1
5959
final val TagAsInstanceOf = TagIsInstanceOf + 1
60-
final val TagUnbox = TagAsInstanceOf + 1
61-
final val TagGetClass = TagUnbox + 1
60+
final val TagGetClass = TagAsInstanceOf + 1
6261

6362
final val TagJSNew = TagGetClass + 1
6463
final val TagJSPrivateSelect = TagJSNew + 1

ir/src/main/scala/org/scalajs/ir/Transformers.scala

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,11 @@ object Transformers {
130130
case RecordSelect(record, field) =>
131131
RecordSelect(transformExpr(record), field)(tree.tpe)
132132

133-
case IsInstanceOf(expr, cls) =>
134-
IsInstanceOf(transformExpr(expr), cls)
133+
case IsInstanceOf(expr, testType) =>
134+
IsInstanceOf(transformExpr(expr), testType)
135135

136-
case AsInstanceOf(expr, cls) =>
137-
AsInstanceOf(transformExpr(expr), cls)
138-
139-
case Unbox(expr, charCode) =>
140-
Unbox(transformExpr(expr), charCode)
136+
case AsInstanceOf(expr, tpe) =>
137+
AsInstanceOf(transformExpr(expr), tpe)
141138

142139
case GetClass(expr) =>
143140
GetClass(transformExpr(expr))

ir/src/main/scala/org/scalajs/ir/Traversers.scala

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,10 @@ object Traversers {
124124
case RecordSelect(record, field) =>
125125
traverse(record)
126126

127-
case IsInstanceOf(expr, cls) =>
127+
case IsInstanceOf(expr, _) =>
128128
traverse(expr)
129129

130-
case AsInstanceOf(expr, cls) =>
131-
traverse(expr)
132-
133-
case Unbox(expr, charCode) =>
130+
case AsInstanceOf(expr, _) =>
134131
traverse(expr)
135132

136133
case GetClass(expr) =>

ir/src/main/scala/org/scalajs/ir/Trees.scala

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -434,32 +434,14 @@ object Trees {
434434
implicit val pos: Position)
435435
extends Tree
436436

437-
case class IsInstanceOf(expr: Tree, typeRef: TypeRef)(
438-
implicit val pos: Position) extends Tree {
437+
case class IsInstanceOf(expr: Tree, testType: Type)(
438+
implicit val pos: Position)
439+
extends Tree {
439440
val tpe = BooleanType
440441
}
441442

442-
case class AsInstanceOf(expr: Tree, typeRef: TypeRef)(
443-
implicit val pos: Position) extends Tree {
444-
val tpe = typeRef match {
445-
case ClassRef(className) => ClassType(className)
446-
case typeRef: ArrayTypeRef => ArrayType(typeRef)
447-
}
448-
}
449-
450-
case class Unbox(expr: Tree, charCode: Char)(
451-
implicit val pos: Position) extends Tree {
452-
val tpe = (charCode: @switch) match {
453-
case 'Z' => BooleanType
454-
case 'C' => CharType
455-
case 'B' => ByteType
456-
case 'S' => ShortType
457-
case 'I' => IntType
458-
case 'J' => LongType
459-
case 'F' => FloatType
460-
case 'D' => DoubleType
461-
}
462-
}
443+
case class AsInstanceOf(expr: Tree, tpe: Type)(implicit val pos: Position)
444+
extends Tree
463445

464446
case class GetClass(expr: Tree)(implicit val pos: Position) extends Tree {
465447
val tpe = ClassType(Definitions.ClassClass)

ir/src/test/scala/org/scalajs/ir/PrintersTest.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -569,10 +569,8 @@ class PrintersTest {
569569
@Test def printAsInstanceOf(): Unit = {
570570
assertPrintEquals("x.asInstanceOf[T]",
571571
AsInstanceOf(ref("x", AnyType), BoxedStringClass))
572-
}
573-
574-
@Test def printUnbox(): Unit = {
575-
assertPrintEquals("x.asInstanceOf[I]", Unbox(ref("x", AnyType), 'I'))
572+
assertPrintEquals("x.asInstanceOf[int]",
573+
AsInstanceOf(ref("x", AnyType), IntType))
576574
}
577575

578576
@Test def printGetClass(): Unit = {

linker/shared/src/main/scala/org/scalajs/linker/analyzer/Infos.scala

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,16 @@ object Infos {
294294
this
295295
}
296296

297-
def addUsedInstanceTest(tpe: TypeRef): this.type =
298-
addUsedInstanceTest(baseNameOf(tpe))
297+
def maybeAddUsedInstanceTest(tpe: Type): this.type = {
298+
tpe match {
299+
case ClassType(className) =>
300+
addUsedInstanceTest(className)
301+
case ArrayType(ArrayTypeRef(baseClassName, _)) =>
302+
addUsedInstanceTest(baseClassName)
303+
case _ =>
304+
}
305+
this
306+
}
299307

300308
def addUsedInstanceTest(cls: String): this.type = {
301309
usedInstanceTests += cls
@@ -520,10 +528,10 @@ object Infos {
520528
case LoadModule(ClassRef(cls)) =>
521529
builder.addAccessedModule(cls)
522530

523-
case IsInstanceOf(_, tpe) =>
524-
builder.addUsedInstanceTest(tpe)
531+
case IsInstanceOf(_, testType) =>
532+
builder.maybeAddUsedInstanceTest(testType)
525533
case AsInstanceOf(_, tpe) =>
526-
builder.addUsedInstanceTest(tpe)
534+
builder.maybeAddUsedInstanceTest(tpe)
527535

528536
case BinaryOp(op, _, rhs) =>
529537
import BinaryOp._

0 commit comments

Comments
 (0)