@@ -927,7 +927,7 @@ class JSCodeGen()(using genCtx: Context) {
927927 val className = encodeClassName(classSym)
928928 val body = js.Block (
929929 js.LoadModule (className),
930- js.SelectStatic (className, fieldIdent)(irTpe))
930+ js.SelectStatic (fieldIdent)(irTpe))
931931 staticGetterDefs += js.MethodDef (
932932 js.MemberFlags .empty.withNamespace(js.MemberNamespace .PublicStatic ),
933933 encodeStaticMemberSym(f), originalName, Nil , irTpe,
@@ -1146,42 +1146,72 @@ class JSCodeGen()(using genCtx: Context) {
11461146
11471147 private def genPrimaryJSClassCtor (dd : DefDef ): PrimaryJSCtor = {
11481148 val sym = dd.symbol
1149- val Block (stats, _) = dd.rhs: @ unchecked
11501149 assert(sym.isPrimaryConstructor, s " called with non-primary ctor: $sym" )
11511150
1151+ var preSuperStats = List .newBuilder[js.Tree ]
11521152 var jsSuperCall : Option [js.JSSuperConstructorCall ] = None
1153- val jsStats = List .newBuilder[js.Tree ]
1153+ val postSuperStats = List .newBuilder[js.Tree ]
11541154
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.
11571157 *
11581158 * dotc inserts statements before the super constructor call for param
11591159 * 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.
11621171 */
11631172 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+ }
11701178
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+ }
11771205 }
1206+
1207+ rec(dd.rhs)
11781208 }
11791209
11801210 assert(jsSuperCall.isDefined,
11811211 s " Did not find Super call in primary JS construtor at ${dd.sourcePos}" )
11821212
11831213 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))
11851215 }
11861216
11871217 private def genSecondaryJSClassCtor (dd : DefDef ): SplitSecondaryJSCtor = {
@@ -2213,10 +2243,7 @@ class JSCodeGen()(using genCtx: Context) {
22132243 if (isStaticModule(currentClassSym) && ! isModuleInitialized.get.value &&
22142244 currentMethodSym.get.isClassConstructor) {
22152245 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 ())
22202247 } else {
22212248 superCall
22222249 }
@@ -4433,13 +4460,12 @@ class JSCodeGen()(using genCtx: Context) {
44334460 js.JSSelect (qual, genPrivateFieldsSymbol()),
44344461 encodeFieldSymAsStringLiteral(sym))
44354462 } else {
4436- js.JSPrivateSelect (qual, encodeClassName(sym.owner),
4437- encodeFieldSym(sym))
4463+ js.JSPrivateSelect (qual, encodeFieldSym(sym))
44384464 }
44394465
44404466 (f, true )
44414467 } 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 )
44434469 (f, true )
44444470 } else if (sym.hasAnnotation(jsdefn.JSExportStaticAnnot )) {
44454471 val jsName = sym.getAnnotation(jsdefn.JSExportStaticAnnot ).get.argumentConstantString(0 ).getOrElse {
@@ -4465,9 +4491,9 @@ class JSCodeGen()(using genCtx: Context) {
44654491
44664492 val f =
44674493 if sym.is(JavaStatic ) then
4468- js.SelectStatic (className, fieldIdent)(irType)
4494+ js.SelectStatic (fieldIdent)(irType)
44694495 else
4470- js.Select (qual, className, fieldIdent)(irType)
4496+ js.Select (qual, fieldIdent)(irType)
44714497
44724498 (f, boxed)
44734499 }
0 commit comments