Skip to content

Commit a91beae

Browse files
committed
Address a number of review comments.
1 parent 5bade1d commit a91beae

File tree

3 files changed

+134
-160
lines changed

3 files changed

+134
-160
lines changed

compiler/src/dotty/tools/backend/sjs/JSCodeGen.scala

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,10 +1132,32 @@ class JSCodeGen()(using genCtx: Context) {
11321132
* This is used for the primary constructor of a non-native JS class,
11331133
* because those cannot access `this` before the super constructor call.
11341134
*
1135-
* dotc inserts statements before the super constructor call for param
1136-
* accessor initializers (including val's and var's declared in the params).
1137-
* We move those after the super constructor call, and are therefore
1138-
* executed later than for a Scala class.
1135+
* Normally, in Scala, param accessors (i.e., fields declared directly in
1136+
* constructor parameters) are initialized *before* the super constructor
1137+
* call. This is important for cases like
1138+
*
1139+
* abstract class A {
1140+
* def a: Int
1141+
* println(a)
1142+
* }
1143+
* class B(val a: Int) extends A
1144+
*
1145+
* where `a` is supposed to be correctly initialized by the time `println`
1146+
* is executed.
1147+
*
1148+
* However, in a JavaScript class, this is forbidden: it is not allowed to
1149+
* read the `this` value in a constructor before the super constructor call.
1150+
*
1151+
* Therefore, for JavaScript classes, we specifically move all those early
1152+
* assignments after the super constructor call, to comply with JavaScript
1153+
* limitations. This clearly introduces a semantic difference in
1154+
* initialization order between Scala classes and JavaScript classes, but
1155+
* there is nothing we can do about it. That difference in behavior is
1156+
* basically spec'ed in Scala.js the language, since specifying it any other
1157+
* way would prevent JavaScript classes from ever having constructor
1158+
* parameters.
1159+
*
1160+
* We do the same thing in Scala 2, obviously.
11391161
*/
11401162
private def moveAllStatementsAfterSuperConstructorCall(body: js.Tree): js.Tree = {
11411163
val bodyStats = body match {
@@ -1447,7 +1469,7 @@ class JSCodeGen()(using genCtx: Context) {
14471469
val genBoxedRhs = box(genRhs, atPhase(elimErasedValueTypePhase)(sym.info))
14481470
js.Assign(field, genBoxedRhs)
14491471
} else {
1450-
js.Assign(field,genRhs)
1472+
js.Assign(field, genRhs)
14511473
}
14521474
}
14531475

@@ -1773,28 +1795,28 @@ class JSCodeGen()(using genCtx: Context) {
17731795
s"but isInnerNonNativeJSClass = $nestedJSClass")
17741796

17751797
def genArgs: List[js.TreeOrJSSpread] = genActualJSArgs(ctor, args)
1776-
1777-
if (cls == jsdefn.JSObjectClass && args.isEmpty)
1778-
js.JSObjectConstr(Nil)
1779-
else if (cls == jsdefn.JSArrayClass && args.isEmpty)
1780-
js.JSArrayConstr(Nil)
1781-
else if (cls.isAnonymousClass)
1782-
genNewAnonJSClass(cls, jsClassValue.get, args.map(genExpr))(fun.span)
1783-
else if (!nestedJSClass)
1784-
js.JSNew(genLoadJSConstructor(cls), genArgs)
1785-
else if (!atPhase(erasurePhase)(cls.is(ModuleClass))) // LambdaLift removes the ModuleClass flag of lifted classes
1786-
js.JSNew(jsClassValue.get, genArgs)
1787-
else
1788-
genCreateInnerJSModule(cls, jsClassValue.get, args.map(genExpr))
1798+
def genArgsAsClassCaptures: List[js.Tree] = args.map(genExpr)
1799+
1800+
jsClassValue.fold {
1801+
// Static JS class (by construction, it cannot be a module class, as their News do not reach the back-end)
1802+
if (cls == jsdefn.JSObjectClass && args.isEmpty)
1803+
js.JSObjectConstr(Nil)
1804+
else if (cls == jsdefn.JSArrayClass && args.isEmpty)
1805+
js.JSArrayConstr(Nil)
1806+
else
1807+
js.JSNew(genLoadJSConstructor(cls), genArgs)
1808+
} { jsClassVal =>
1809+
// Nested JS class
1810+
if (cls.isAnonymousClass)
1811+
genNewAnonJSClass(cls, jsClassVal, genArgsAsClassCaptures)(fun.span)
1812+
else if (atPhase(erasurePhase)(cls.is(ModuleClass))) // LambdaLift removes the ModuleClass flag of lifted classes
1813+
js.JSNew(js.CreateJSClass(encodeClassName(cls), jsClassVal :: genArgsAsClassCaptures), Nil)
1814+
else
1815+
js.JSNew(jsClassVal, genArgs)
1816+
}
17891817
}
17901818
}
17911819

1792-
/** Gen JS code to create the JS class of an inner JS module class. */
1793-
private def genCreateInnerJSModule(sym: Symbol, jsSuperClassValue: js.Tree, args: List[js.Tree])(
1794-
implicit pos: Position): js.Tree = {
1795-
js.JSNew(js.CreateJSClass(encodeClassName(sym), jsSuperClassValue :: args), Nil)
1796-
}
1797-
17981820
/** Generate an instance of an anonymous (non-lambda) JS class inline
17991821
*
18001822
* @param sym Class to generate the instance of

0 commit comments

Comments
 (0)