Skip to content

Commit 94c9ca8

Browse files
committed
Do not (ab)use blocks for top level trees
1 parent 2f1fc32 commit 94c9ca8

File tree

6 files changed

+357
-398
lines changed

6 files changed

+357
-398
lines changed

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

Lines changed: 55 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,15 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
4545

4646
def buildClass(className: ClassName, kind: ClassKind, jsClassCaptures: Option[List[ParamDef]],
4747
hasClassInitializer: Boolean,
48-
superClass: Option[ClassIdent], jsSuperClass: Option[Tree], useESClass: Boolean, ctor: js.Tree,
48+
superClass: Option[ClassIdent], jsSuperClass: Option[Tree], useESClass: Boolean, ctorDefs: List[js.Tree],
4949
memberDefs: List[js.MethodDef], exportedDefs: List[js.Tree])(
5050
implicit moduleContext: ModuleContext,
51-
globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[js.Tree] = {
51+
globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[List[js.Tree]] = {
5252

53-
def allES6Defs = {
54-
js.Block(ctor +: (memberDefs ++ exportedDefs)) match {
55-
case js.Block(allDefs) => allDefs
56-
case js.Skip() => Nil
57-
case oneDef => List(oneDef)
58-
}
59-
}
53+
def allES6Defs = ctorDefs ++ memberDefs ++ exportedDefs
6054

61-
def allES5Defs(classVar: js.Tree) = {
62-
WithGlobals(js.Block(
63-
ctor, assignES5ClassMembers(classVar, memberDefs), js.Block(exportedDefs: _*)))
64-
}
55+
def allES5Defs(classVar: js.Tree) =
56+
WithGlobals(ctorDefs ++ assignES5ClassMembers(classVar, memberDefs) ++ exportedDefs)
6557

6658
if (!kind.isJSClass) {
6759
assert(jsSuperClass.isEmpty, className)
@@ -95,7 +87,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
9587

9688
val entireClassDefWithGlobals = if (useESClass) {
9789
genJSSuperCtor(superClass, jsSuperClass).map { jsSuperClass =>
98-
classValueVar := js.ClassDef(Some(classValueIdent), Some(jsSuperClass), allES6Defs)
90+
List(classValueVar := js.ClassDef(Some(classValueIdent), Some(jsSuperClass), allES6Defs))
9991
}
10092
} else {
10193
allES5Defs(classValueVar)
@@ -106,7 +98,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
10698
entireClassDef <- entireClassDefWithGlobals
10799
createStaticFields <- genCreateStaticFieldsOfJSClass(className)
108100
} yield {
109-
optStoreJSSuperClass.toList ::: entireClassDef :: createStaticFields
101+
optStoreJSSuperClass.toList ::: entireClassDef ::: createStaticFields
110102
}
111103

112104
jsClassCaptures.fold {
@@ -125,7 +117,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
125117
)
126118
createAccessor <- globalFunctionDef("a", className, Nil, None, body)
127119
} yield {
128-
js.Block(createClassValueVar, createAccessor)
120+
createClassValueVar :: createAccessor
129121
}
130122
} { jsClassCaptures =>
131123
val captureParamDefs = for (param <- jsClassCaptures) yield {
@@ -173,7 +165,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
173165
def genScalaClassConstructor(className: ClassName, superClass: Option[ClassIdent],
174166
useESClass: Boolean, initToInline: Option[MethodDef])(
175167
implicit moduleContext: ModuleContext,
176-
globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[js.Tree] = {
168+
globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[List[js.Tree]] = {
177169

178170
assert(superClass.isDefined || className == ObjectClass,
179171
s"Class $className is missing a parent class")
@@ -192,9 +184,9 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
192184
}
193185

194186
if (args.isEmpty && isTrivialCtorBody)
195-
js.Skip()
187+
Nil
196188
else
197-
js.MethodDef(static = false, js.Ident("constructor"), args, restParam, body)
189+
js.MethodDef(static = false, js.Ident("constructor"), args, restParam, body) :: Nil
198190
}
199191
} else {
200192
import TreeDSL._
@@ -203,13 +195,13 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
203195

204196
val chainProtoWithGlobals = superClass match {
205197
case None =>
206-
WithGlobals(js.Skip())
198+
WithGlobals.nil
207199

208200
case Some(_) if shouldExtendJSError(className, superClass) =>
209201
untrackedGlobalRef("Error").map(chainPrototypeWithLocalCtor(className, ctorVar, _))
210202

211203
case Some(parentIdent) =>
212-
WithGlobals(ctorVar.prototype := js.New(globalVar("h", parentIdent.name), Nil))
204+
WithGlobals(List(ctorVar.prototype := js.New(globalVar("h", parentIdent.name), Nil)))
213205
}
214206

215207
for {
@@ -219,36 +211,34 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
219211
inheritableCtorDef <-
220212
globalFunctionDef("h", className, Nil, None, js.Skip())
221213
chainProto <- chainProtoWithGlobals
222-
} yield {
223-
js.Block(
224-
// Real constructor
225-
js.DocComment("@constructor"),
226-
realCtorDef,
227-
chainProto,
228-
genIdentBracketSelect(ctorVar.prototype, "constructor") := ctorVar,
229-
230-
// Inheritable constructor
231-
js.DocComment("@constructor"),
232-
inheritableCtorDef,
233-
globalVar("h", className).prototype := ctorVar.prototype
234-
)
235-
}
214+
} yield (
215+
// Real constructor
216+
js.DocComment("@constructor") ::
217+
realCtorDef :::
218+
chainProto :::
219+
(genIdentBracketSelect(ctorVar.prototype, "constructor") := ctorVar) ::
220+
221+
// Inheritable constructor
222+
js.DocComment("@constructor") ::
223+
inheritableCtorDef :::
224+
(globalVar("h", className).prototype := ctorVar.prototype) :: Nil
225+
)
236226
}
237227
}
238228

239229
/** Generates the JS constructor for a JS class. */
240230
def genJSConstructor(className: ClassName, superClass: Option[ClassIdent],
241231
jsSuperClass: Option[Tree], useESClass: Boolean, jsConstructorDef: JSConstructorDef)(
242232
implicit moduleContext: ModuleContext,
243-
globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[js.Tree] = {
233+
globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[List[js.Tree]] = {
244234

245235
val JSConstructorDef(_, params, restParam, body) = jsConstructorDef
246236
val ctorFunWithGlobals = desugarToFunction(className, params, restParam, body)
247237

248238
if (useESClass) {
249239
for (fun <- ctorFunWithGlobals) yield {
250240
js.MethodDef(static = false, js.Ident("constructor"),
251-
fun.args, fun.restParam, fun.body)
241+
fun.args, fun.restParam, fun.body) :: Nil
252242
}
253243
} else {
254244
for {
@@ -259,12 +249,10 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
259249

260250
val ctorVar = fileLevelVar("b", genName(className))
261251

262-
js.Block(
263-
js.DocComment("@constructor"),
264-
ctorVar := ctorFun,
265-
chainPrototypeWithLocalCtor(className, ctorVar, superCtor),
266-
genIdentBracketSelect(ctorVar.prototype, "constructor") := ctorVar
267-
)
252+
js.DocComment("@constructor") ::
253+
(ctorVar := ctorFun) ::
254+
chainPrototypeWithLocalCtor(className, ctorVar, superCtor) :::
255+
(genIdentBracketSelect(ctorVar.prototype, "constructor") := ctorVar) :: Nil
268256
}
269257
}
270258
}
@@ -348,12 +336,12 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
348336
}
349337

350338
private def chainPrototypeWithLocalCtor(className: ClassName, ctorVar: js.Tree,
351-
superCtor: js.Tree)(implicit pos: Position): js.Tree = {
339+
superCtor: js.Tree)(implicit pos: Position): List[js.Tree] = {
352340
import TreeDSL._
353341

354342
val dummyCtor = fileLevelVar("hh", genName(className))
355343

356-
js.Block(
344+
List(
357345
js.DocComment("@constructor"),
358346
genConst(dummyCtor.ident, js.Function(false, Nil, None, js.Skip())),
359347
dummyCtor.prototype := superCtor.prototype,
@@ -396,7 +384,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
396384
globalVarDef("t", varScope, value, origName.orElse(name))
397385
}
398386

399-
WithGlobals.list(defs)
387+
WithGlobals.flatten(defs)
400388
}
401389

402390
/** Generates the creation of the private JS field defs for a JavaScript
@@ -424,7 +412,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
424412
}
425413
}
426414

427-
WithGlobals.list(defs)
415+
WithGlobals.flatten(defs)
428416
}
429417

430418
/** Generates the creation of the static fields for a JavaScript class. */
@@ -497,7 +485,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
497485

498486
def genStaticLikeMethod(className: ClassName, method: MethodDef)(
499487
implicit moduleContext: ModuleContext,
500-
globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = {
488+
globalKnowledge: GlobalKnowledge): WithGlobals[List[js.Tree]] = {
501489
val methodBody = method.body.getOrElse(
502490
throw new AssertionError("Cannot generate an abstract method"))
503491

@@ -570,11 +558,11 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
570558
private def genJSProperty(className: ClassName, kind: ClassKind, useESClass: Boolean,
571559
property: JSPropertyDef)(
572560
implicit moduleContext: ModuleContext,
573-
globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = {
561+
globalKnowledge: GlobalKnowledge): WithGlobals[List[js.Tree]] = {
574562
if (useESClass)
575563
genJSPropertyES6(className, property)
576564
else
577-
genJSPropertyES5(className, kind, property)
565+
genJSPropertyES5(className, kind, property).map(_ :: Nil)
578566
}
579567

580568
private def genJSPropertyES5(className: ClassName, kind: ClassKind, property: JSPropertyDef)(
@@ -612,31 +600,27 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
612600

613601
private def genJSPropertyES6(className: ClassName, property: JSPropertyDef)(
614602
implicit moduleContext: ModuleContext,
615-
globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = {
603+
globalKnowledge: GlobalKnowledge): WithGlobals[List[js.Tree]] = {
616604
implicit val pos = property.pos
617605

618606
val static = property.flags.namespace.isStatic
619607

620608
genMemberNameTree(property.name).flatMap { propName =>
621-
val getterWithGlobals = property.getterBody.fold {
622-
WithGlobals[js.Tree](js.Skip())
623-
} { body =>
609+
val getterWithGlobals = property.getterBody.map { body =>
624610
for (fun <- desugarToFunction(className, Nil, body, resultType = AnyType))
625611
yield js.GetterDef(static, propName, fun.body)
626612
}
627613

628-
val setterWithGlobals = property.setterArgAndBody.fold {
629-
WithGlobals[js.Tree](js.Skip())
630-
} { case (arg, body) =>
614+
val setterWithGlobals = property.setterArgAndBody.map { case (arg, body) =>
631615
for (fun <- desugarToFunction(className, arg :: Nil, body, resultType = NoType))
632616
yield js.SetterDef(static, propName, fun.args.head, fun.body)
633617
}
634618

635619
for {
636-
getter <- getterWithGlobals
637-
setter <- setterWithGlobals
620+
getter <- WithGlobals.option(getterWithGlobals)
621+
setter <- WithGlobals.option(setterWithGlobals)
638622
} yield {
639-
js.Block(getter, setter)
623+
getter.toList ::: setter.toList
640624
}
641625
}
642626
}
@@ -756,11 +740,11 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
756740
val createIsStatWithGlobals = if (needIsFunction) {
757741
globalFunctionDef("is", className, List(objParam), None, js.Return(isExpression))
758742
} else {
759-
WithGlobals(js.Skip())
743+
WithGlobals.nil
760744
}
761745

762746
val createAsStatWithGlobals = if (semantics.asInstanceOfs == Unchecked) {
763-
WithGlobals(js.Skip())
747+
WithGlobals.nil
764748
} else {
765749
globalFunctionDef("as", className, List(objParam), None, js.Return {
766750
val isCond =
@@ -780,10 +764,10 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
780764
createIsStat <- createIsStatWithGlobals
781765
createAsStat <- createAsStatWithGlobals
782766
} yield {
783-
List(createIsStat, createAsStat)
767+
createIsStat ::: createAsStat
784768
}
785769
} else {
786-
WithGlobals(Nil)
770+
WithGlobals.nil
787771
}
788772
}
789773

@@ -816,7 +800,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
816800
}
817801

818802
val createAsArrayOfStatWithGlobals = if (semantics.asInstanceOfs == Unchecked) {
819-
WithGlobals(js.Skip())
803+
WithGlobals.nil
820804
} else {
821805
globalFunctionDef("asArrayOf", className, List(objParam, depthParam), None, {
822806
js.Return {
@@ -835,7 +819,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
835819
createIsArrayOfStat <- createIsArrayOfStatWithGlobals
836820
createAsArrayOfStat <- createAsArrayOfStatWithGlobals
837821
} yield {
838-
List(createIsArrayOfStat, createAsArrayOfStat)
822+
createIsArrayOfStat ::: createAsArrayOfStat
839823
}
840824
}
841825

@@ -855,7 +839,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
855839
superClass: Option[ClassIdent], ancestors: List[ClassName],
856840
jsNativeLoadSpec: Option[JSNativeLoadSpec])(
857841
implicit moduleContext: ModuleContext,
858-
globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[js.Tree] = {
842+
globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[List[js.Tree]] = {
859843
import TreeDSL._
860844

861845
val isObjectClass =
@@ -959,7 +943,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
959943

960944
def genModuleAccessor(className: ClassName, kind: ClassKind)(
961945
implicit moduleContext: ModuleContext,
962-
globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[js.Tree] = {
946+
globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[List[js.Tree]] = {
963947
import TreeDSL._
964948

965949
val tpe = ClassType(className)
@@ -1013,14 +997,14 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
1013997
globalFunctionDef("m", className, Nil, None, body)
1014998
}
1015999

1016-
createAccessor.map(js.Block(createModuleInstanceField, _))
1000+
createAccessor.map(createModuleInstanceField :: _)
10171001
}
10181002

10191003
def genExportedMember(className: ClassName, kind: ClassKind, useESClass: Boolean, member: JSMethodPropDef)(
10201004
implicit moduleContext: ModuleContext,
1021-
globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = {
1005+
globalKnowledge: GlobalKnowledge): WithGlobals[List[js.Tree]] = {
10221006
member match {
1023-
case m: JSMethodDef => genJSMethod(className, kind, useESClass, m)
1007+
case m: JSMethodDef => genJSMethod(className, kind, useESClass, m).map(_ :: Nil)
10241008
case p: JSPropertyDef => genJSProperty(className, kind, useESClass, p)
10251009
}
10261010
}

0 commit comments

Comments
 (0)