@@ -927,7 +927,7 @@ class JSCodeGen()(using genCtx: Context) {
927
927
val className = encodeClassName(classSym)
928
928
val body = js.Block (
929
929
js.LoadModule (className),
930
- js.SelectStatic (className, fieldIdent)(irTpe))
930
+ js.SelectStatic (fieldIdent)(irTpe))
931
931
staticGetterDefs += js.MethodDef (
932
932
js.MemberFlags .empty.withNamespace(js.MemberNamespace .PublicStatic ),
933
933
encodeStaticMemberSym(f), originalName, Nil , irTpe,
@@ -1146,42 +1146,72 @@ class JSCodeGen()(using genCtx: Context) {
1146
1146
1147
1147
private def genPrimaryJSClassCtor (dd : DefDef ): PrimaryJSCtor = {
1148
1148
val sym = dd.symbol
1149
- val Block (stats, _) = dd.rhs: @ unchecked
1150
1149
assert(sym.isPrimaryConstructor, s " called with non-primary ctor: $sym" )
1151
1150
1151
+ var preSuperStats = List .newBuilder[js.Tree ]
1152
1152
var jsSuperCall : Option [js.JSSuperConstructorCall ] = None
1153
- val jsStats = List .newBuilder[js.Tree ]
1153
+ val postSuperStats = List .newBuilder[js.Tree ]
1154
1154
1155
- /* Move all statements after the super constructor call since JS
1156
- * cannot access `this` before the super constructor call.
1155
+ /* Move param accessor initializers after the super constructor call since
1156
+ * JS cannot access `this` before the super constructor call.
1157
1157
*
1158
1158
* dotc inserts statements before the super constructor call for param
1159
1159
* accessor initializers (including val's and var's declared in the
1160
- * params). We move those after the super constructor call, and are
1161
- * therefore executed later than for a Scala class.
1160
+ * params). Those statements are assignments whose rhs'es are always simple
1161
+ * Idents (the constructor params).
1162
+ *
1163
+ * There can also be local `val`s before the super constructor call for
1164
+ * default arguments to the super constructor. These must remain before.
1165
+ *
1166
+ * Our strategy is therefore to move only the field assignments after the
1167
+ * super constructor call. They are therefore executed later than for a
1168
+ * Scala class (as specified for non-native JS classes semantics).
1169
+ * However, side effects and evaluation order of all the other
1170
+ * computations remains unchanged.
1162
1171
*/
1163
1172
withPerMethodBodyState(sym) {
1164
- stats.foreach {
1165
- case tree @ Apply (fun @ Select (Super (This (_), _), _), args)
1166
- if fun.symbol.isClassConstructor =>
1167
- assert(jsSuperCall.isEmpty, s " Found 2 JS Super calls at ${dd.sourcePos}" )
1168
- implicit val pos : Position = tree.span
1169
- jsSuperCall = Some (js.JSSuperConstructorCall (genActualJSArgs(fun.symbol, args)))
1173
+ def isThisField (tree : Tree ): Boolean = tree match {
1174
+ case Select (ths : This , _) => ths.symbol == currentClassSym.get
1175
+ case tree : Ident => desugarIdent(tree).exists(isThisField(_))
1176
+ case _ => false
1177
+ }
1170
1178
1171
- case stat =>
1172
- val jsStat = genStat(stat)
1173
- assert(jsSuperCall.isDefined || ! jsStat.isInstanceOf [js.VarDef ],
1174
- " Trying to move a local VarDef after the super constructor call of a non-native JS class at " +
1175
- dd.sourcePos)
1176
- jsStats += jsStat
1179
+ def rec (tree : Tree ): Unit = {
1180
+ tree match {
1181
+ case Block (stats, expr) =>
1182
+ stats.foreach(rec(_))
1183
+ rec(expr)
1184
+
1185
+ case tree @ Apply (fun @ Select (Super (This (_), _), _), args)
1186
+ if fun.symbol.isClassConstructor =>
1187
+ assert(jsSuperCall.isEmpty, s " Found 2 JS Super calls at ${dd.sourcePos}" )
1188
+ implicit val pos : Position = tree.span
1189
+ jsSuperCall = Some (js.JSSuperConstructorCall (genActualJSArgs(fun.symbol, args)))
1190
+
1191
+ case tree if jsSuperCall.isDefined =>
1192
+ // Once we're past the super constructor call, everything goes after.
1193
+ postSuperStats += genStat(tree)
1194
+
1195
+ case Assign (lhs, Ident (_)) if isThisField(lhs) =>
1196
+ /* If that shape appears before the jsSuperCall, it is a param
1197
+ * accessor initializer. We move it.
1198
+ */
1199
+ postSuperStats += genStat(tree)
1200
+
1201
+ case stat =>
1202
+ // Other statements are left before.
1203
+ preSuperStats += genStat(stat)
1204
+ }
1177
1205
}
1206
+
1207
+ rec(dd.rhs)
1178
1208
}
1179
1209
1180
1210
assert(jsSuperCall.isDefined,
1181
1211
s " Did not find Super call in primary JS construtor at ${dd.sourcePos}" )
1182
1212
1183
1213
new PrimaryJSCtor (sym, genParamsAndInfo(sym, dd.paramss),
1184
- js.JSConstructorBody (Nil , jsSuperCall.get, jsStats .result())(dd.span))
1214
+ js.JSConstructorBody (preSuperStats.result() , jsSuperCall.get, postSuperStats .result())(dd.span))
1185
1215
}
1186
1216
1187
1217
private def genSecondaryJSClassCtor (dd : DefDef ): SplitSecondaryJSCtor = {
@@ -2213,10 +2243,7 @@ class JSCodeGen()(using genCtx: Context) {
2213
2243
if (isStaticModule(currentClassSym) && ! isModuleInitialized.get.value &&
2214
2244
currentMethodSym.get.isClassConstructor) {
2215
2245
isModuleInitialized.get.value = true
2216
- val className = encodeClassName(currentClassSym)
2217
- val thisType = jstpe.ClassType (className)
2218
- val initModule = js.StoreModule (className, js.This ()(thisType))
2219
- js.Block (superCall, initModule)
2246
+ js.Block (superCall, js.StoreModule ())
2220
2247
} else {
2221
2248
superCall
2222
2249
}
@@ -4433,13 +4460,12 @@ class JSCodeGen()(using genCtx: Context) {
4433
4460
js.JSSelect (qual, genPrivateFieldsSymbol()),
4434
4461
encodeFieldSymAsStringLiteral(sym))
4435
4462
} else {
4436
- js.JSPrivateSelect (qual, encodeClassName(sym.owner),
4437
- encodeFieldSym(sym))
4463
+ js.JSPrivateSelect (qual, encodeFieldSym(sym))
4438
4464
}
4439
4465
4440
4466
(f, true )
4441
4467
} else if (sym.hasAnnotation(jsdefn.JSExportTopLevelAnnot )) {
4442
- val f = js.SelectStatic (encodeClassName(sym.owner), encodeFieldSym(sym))(jstpe.AnyType )
4468
+ val f = js.SelectStatic (encodeFieldSym(sym))(jstpe.AnyType )
4443
4469
(f, true )
4444
4470
} else if (sym.hasAnnotation(jsdefn.JSExportStaticAnnot )) {
4445
4471
val jsName = sym.getAnnotation(jsdefn.JSExportStaticAnnot ).get.argumentConstantString(0 ).getOrElse {
@@ -4465,9 +4491,9 @@ class JSCodeGen()(using genCtx: Context) {
4465
4491
4466
4492
val f =
4467
4493
if sym.is(JavaStatic ) then
4468
- js.SelectStatic (className, fieldIdent)(irType)
4494
+ js.SelectStatic (fieldIdent)(irType)
4469
4495
else
4470
- js.Select (qual, className, fieldIdent)(irType)
4496
+ js.Select (qual, fieldIdent)(irType)
4471
4497
4472
4498
(f, boxed)
4473
4499
}
0 commit comments