8000 Enforce that jl.Throwable must a class extending jl.Object. · scala-js/scala-js@5bb0d09 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5bb0d09

Browse files
committed
Enforce that jl.Throwable must a class extending jl.Object.
The emitter relies on that to rewire `jl.Throwable` to extend JS `Error`, and bridge methods to those of `jl.Object`. It previously had a side condition that `jl.Throwable` actually extends `jl.Object` to perform that rewrite. If that were false, though, some of the guarantees we give about `Throwable`s would be broken, so I'm pretty sure something would break somewhere. It is safer to directly enforce that universal fact in the `ClassDefChecker` in the first place.
1 parent 70a4164 commit 5bb0d09

File tree

4 files changed

+23
-7
lines changed

4 files changed

+23
-7
lines changed

linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/ClassEmitter.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
6161
if (useESClass) {
6262
val parentVarWithGlobals = for (parentIdent <- superClass) yield {
6363
implicit val pos = parentIdent.pos
64-
if (shouldExtendJSError(className, superClass)) globalRef("Error")
64+
if (shouldExtendJSError(className)) globalRef("Error")
6565
else WithGlobals(globalVar(VarField.c, parentIdent.name))
6666
}
6767

@@ -190,7 +190,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
190190
case None =>
191191
WithGlobals(setPrototypeVar(ctorVar))
192192

193-
case Some(_) if shouldExtendJSError(className, superClass) =>
193+
case Some(_) if shouldExtendJSError(className) =>
194194
globalRef("Error").map(chainPrototypeWithLocalCtor(className, ctorVar, _, localDeclPrototypeVar = false))
195195

196196
case Some(parentIdent) =>
@@ -1148,6 +1148,6 @@ private[emitter] object ClassEmitter {
11481148
private val ClassInitializerOriginalName: OriginalName =
11491149
OriginalName("<clinit>")
11501150

1151-
def shouldExtendJSError(className: ClassName, superClass: Option[ClassIdent]): Boolean =
1152-
className == ThrowableClass && superClass.exists(_.name == ObjectClass)
1151+
def shouldExtendJSError(className: ClassName): Boolean =
1152+
className == ThrowableClass
11531153
}

linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/Emitter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ final class Emitter(config: Emitter.Config, prePrinter: Emitter.PrePrinter) {
576576
* because Throwable is rewired to extend JavaScript's Error instead of
577577
* j.l.Object.
578578
*/
579-
val linkedMethodsAndBridges = if (ClassEmitter.shouldExtendJSError(className, linkedClass.superClass)) {
579+
val linkedMethodsAndBridges = if (ClassEmitter.shouldExtendJSError(className)) {
580580
val existingMethods = linkedMethods
581581
.withFilter(_.flags.namespace == MemberNamespace.Public)
582582
.map(_.methodName)

linker/shared/src/main/scala/org/scalajs/linker/checker/ClassDefChecker.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ private final class ClassDefChecker(classDef: ClassDef,
128128
private def checkKind()(implicit ctx: ErrorContext): Unit = {
129129
val className = classDef.name.name
130130

131-
if (isJLObject && classDef.kind != ClassKind.Class) {
132-
reportError("java.lang.Object must be a Class")
131+
if ((isJLObject || className == ThrowableClass) && classDef.kind != ClassKind.Class) {
132+
reportError(i"$className must be a Class")
133133
} else {
134134
val isHijacked = HijackedClasses.contains(className)
135135
if (isHijacked && classDef.kind != ClassKind.HijackedClass)
@@ -176,6 +176,8 @@ private final class ClassDefChecker(classDef: ClassDef,
176176
ClassKind.NativeJSClass | ClassKind.NativeJSModuleClass =>
177177
if (classDef.superClass.isEmpty)
178178
reportError("missing superClass")
179+
else if (classDef.className == ThrowableClass && classDef.superClass.get.name != ObjectClass)
180+
reportError("the superClass of java.lang.Throwable must be java.lang.Object")
179181

180182
case ClassKind.Interface =>
181183
if (classDef.superClass.isDefined)

linker/shared/src/test/scala/org/scalajs/linker/checker/ClassDefCheckerTest.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,20 @@ class ClassDefCheckerTest {
8383
"java.lang.Object may not implement any interfaces")
8484
}
8585

86+
@Test
87+
def javaLangThrowableKind(): Unit = {
88+
assertError(
89+
classDef(ThrowableClass, kind = ClassKind.Interface),
90+
"java.lang.Throwable must be a Class")
91+
}
92+
93+
@Test
94+
def javaLangThrowableSuperClass(): Unit = {
95+
assertError(
96+
classDef(ThrowableClass, superClass = Some("Parent")),
97+
"the superClass of java.lang.Throwable must be java.lang.Object")
98+
}
99+
86100
@Test
87101
def hijackedClassesKinds(): Unit = {
88102
assertError(

0 commit comments

Comments
 (0)
0