@@ -1475,7 +1475,8 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
1475
1475
val jsClassCaptures = List .newBuilder[js.ParamDef ]
1476
1476
1477
1477
def add (tree : ConstructorTree [_ <: JSCtor ]): Unit = {
1478
- val (e, c) = genJSClassCtorDispatch(tree.ctor.sym, tree.ctor.params, tree.overloadNum)
1478
+ val (e, c) = genJSClassCtorDispatch(tree.ctor.sym,
1479
+ tree.ctor.paramsAndInfo, tree.overloadNum)
1479
1480
exports += e
1480
1481
jsClassCaptures ++= c
1481
1482
tree.subCtors.foreach(add(_))
@@ -1522,7 +1523,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
1522
1523
* call, and are therefore executed later than for a Scala class.
1523
1524
*/
1524
1525
withPerMethodBodyState(sym) {
1525
- stats.foreach {
1526
+ flatStats( stats) .foreach {
1526
1527
case tree @ Apply (fun @ Select (Super (This (_), _), _), args)
1527
1528
if fun.symbol.isClassConstructor =>
1528
1529
assert(jsSuperCall.isEmpty, s " Found 2 JS Super calls at ${dd.pos}" )
@@ -1543,9 +1544,8 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
1543
1544
assert(jsSuperCall.isDefined, " Did not find Super call in primary JS " +
1544
1545
s " construtor at ${dd.pos}" )
1545
1546
1546
- val params = if (vparamss.isEmpty) Nil else vparamss.head.map(_.symbol)
1547
-
1548
- new PrimaryJSCtor (sym, params, jsSuperCall.get :: jsStats.result())
1547
+ new PrimaryJSCtor (sym, genParamsAndInfo(sym, vparamss),
1548
+ jsSuperCall.get :: jsStats.result())
1549
1549
}
1550
1550
1551
1551
private def genSecondaryJSClassCtor (dd : DefDef ): SplitSecondaryJSCtor = {
@@ -1558,7 +1558,7 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
1558
1558
val afterThisCall = List .newBuilder[js.Tree ]
1559
1559
1560
1560
withPerMethodBodyState(sym) {
1561
- stats.foreach {
1561
+ flatStats( stats) .foreach {
1562
1562
case tree @ Apply (fun @ Select (This (_), _), args)
1563
1563
if fun.symbol.isClassConstructor =>
1564
1564
assert(thisCall.isEmpty,
@@ -1579,21 +1579,27 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
1579
1579
1580
1580
val Some ((targetCtor, ctorArgs)) = thisCall
1581
1581
1582
- val params = if (vparamss.isEmpty) Nil else vparamss.head.map(_.symbol)
1583
-
1584
- new SplitSecondaryJSCtor (sym, params, beforeThisCall.result(), targetCtor,
1585
- ctorArgs, afterThisCall.result())
1582
+ new SplitSecondaryJSCtor (sym, genParamsAndInfo(sym, vparamss),
1583
+ beforeThisCall.result(), targetCtor, ctorArgs, afterThisCall.result())
1586
1584
}
1587
1585
1588
- private def genJSClassCtorDispatch (ctorSym : Symbol , allParamSyms : List [ Symbol ] ,
1589
- overloadNum : Int ): ( Exported , List [js.ParamDef ]) = {
1586
+ private def genParamsAndInfo (ctorSym : Symbol ,
1587
+ vparamss : List [ List [ ValDef ]] ): List [( js.VarRef , JSParamInfo )] = {
1590
1588
implicit val pos = ctorSym.pos
1591
1589
1592
- val allParamsAndInfos = for {
1593
- (paramSym, info) <- allParamSyms.zip(jsParamInfos(ctorSym))
1590
+ val paramSyms = if (vparamss.isEmpty) Nil else vparamss.head.map(_.symbol)
1591
+
1592
+ for {
1593
+ (paramSym, info) <- paramSyms.zip(jsParamInfos(ctorSym))
1594
1594
} yield {
1595
1595
genVarRef(paramSym) -> info
1596
1596
}
1597
+ }
1598
+
1599
+ private def genJSClassCtorDispatch (ctorSym : Symbol ,
1600
+ allParamsAndInfos : List [(js.VarRef , JSParamInfo )],
1601
+ overloadNum : Int ): (Exported , List [js.ParamDef ]) = {
1602
+ implicit val pos = ctorSym.pos
1597
1603
1598
1604
/* `allParams` are the parameters as seen from *inside* the constructor
1599
1605
* body. the symbols returned in jsParamInfos are the parameters as seen
@@ -1674,39 +1680,60 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
1674
1680
*/
1675
1681
1676
1682
def preStats (tree : ConstructorTree [SplitSecondaryJSCtor ],
1677
- nextParams : List [Symbol ]): js.Tree = {
1678
- assert(tree.ctor.ctorArgs.size == nextParams.size, " param count mismatch " )
1683
+ nextParamsAndInfo : List [(js. VarRef , JSParamInfo ) ]): js.Tree = {
1684
+ val inner = tree.subCtors.map(preStats(_, tree.ctor.paramsAndInfo) )
1679
1685
1680
- val inner = tree.subCtors.map(preStats(_, tree.ctor.params))
1686
+ assert(tree.ctor.ctorArgs.size == nextParamsAndInfo.size, " param count mismatch" )
1687
+ val paramsInfosAndArgs = nextParamsAndInfo.zip(tree.ctor.ctorArgs)
1681
1688
1682
- /* Reject undefined params (i.e. using a default value of another
1683
- * constructor) via implementation restriction.
1684
- *
1685
- * This is mostly for historical reasons. The ideal solution here would
1686
- * be to recognize calls to default param getters of JS class
1687
- * constructors and not even translate them to UndefinedParam in the
1688
- * first place.
1689
- */
1690
- def isUndefinedParam (tree : js.Tree ): Boolean = tree match {
1691
- case js.Transient (UndefinedParam ) => true
1692
- case _ => false
1693
- }
1689
+ val (captureParamsInfosAndArgs, normalParamsInfosAndArgs) =
1690
+ paramsInfosAndArgs.partition(_._1._2.capture)
1694
1691
1695
- if (tree.ctor.ctorArgs.exists(isUndefinedParam)) {
1696
- reporter.error(tree.ctor.sym.pos,
1697
- " Implementation restriction: in a JS class, a secondary " +
1698
- " constructor calling another constructor with default " +
1699
- " parameters must provide the values of all parameters." )
1692
+ val captureAssigns = for {
1693
+ ((param, _), arg) <- captureParamsInfosAndArgs
1694
+ } yield {
1695
+ js.Assign (param, arg)
1700
1696
}
1701
1697
1702
- val assignments = for {
1703
- (param, arg) <- nextParams.zip(tree.ctor.ctorArgs)
1704
- if ! isUndefinedParam(arg)
1698
+ val normalAssigns = for {
1699
+ (((param, info), arg), i) <- normalParamsInfosAndArgs.zipWithIndex
1705
1700
} yield {
1706
- js.Assign (genVarRef(param), arg)
1701
+ val newArg = arg match {
1702
+ case js.Transient (UndefinedParam ) =>
1703
+ assert(info.hasDefault,
1704
+ s " unexpected UndefinedParam for non default param: $param" )
1705
+
1706
+ /* Go full circle: We have ignored the default param getter for
1707
+ * this, we'll create it again.
1708
+ *
1709
+ * This seems not optimal: We could simply not ignore the calls to
1710
+ * default param getters in the first place.
1711
+ *
1712
+ * However, this proves to be difficult: Because of translations in
1713
+ * earlier phases, calls to default param getters may be assigned
1714
+ * to temporary variables first (see the undefinedDefaultParams
1715
+ * ScopedVar). If this happens, it becomes increasingly difficult
1716
+ * to distinguish a default param getter call for a constructor
1717
+ * call of *this* instance (in which case we would want to keep
1718
+ * the default param getter call) from one for a *different*
1719
+ * instance (in which case we would want to discard the default
1720
+ * param getter call)
1721
+ *
1722
+ * Because of this, it ends up being easier to just re-create the
1723
+ * default param getter call if necessary.
1724
+ */
1725
+ genCallDefaultGetter(tree.ctor.sym, i, tree.ctor.sym.pos, static = false ,
1726
+ captures = captureParamsInfosAndArgs.map(_._1._1))(
1727
+ prevArgsCount => normalParamsInfosAndArgs.take(prevArgsCount).map(_._1._1))
1728
+
1729
+ case arg => arg
1730
+ }
1731
+
1732
+ js.Assign (param, newArg)
1707
1733
}
1708
1734
1709
- ifOverload(tree, js.Block (inner ++ tree.ctor.beforeCall ++ assignments))
1735
+ ifOverload(tree, js.Block (
1736
+ inner ++ tree.ctor.beforeCall ++ captureAssigns ++ normalAssigns))
1710
1737
}
1711
1738
1712
1739
def postStats (tree : ConstructorTree [SplitSecondaryJSCtor ]): js.Tree = {
@@ -1718,22 +1745,24 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
1718
1745
val secondaryCtorTrees = ctorTree.subCtors
1719
1746
1720
1747
js.Block (
1721
- secondaryCtorTrees.map(preStats(_, primaryCtor.params )) ++
1748
+ secondaryCtorTrees.map(preStats(_, primaryCtor.paramsAndInfo )) ++
1722
1749
primaryCtor.body ++
1723
1750
secondaryCtorTrees.map(postStats(_))
1724
1751
)
1725
1752
}
1726
1753
1727
1754
private sealed trait JSCtor {
1728
1755
val sym : Symbol
1729
- val params : List [Symbol ]
1756
+ val paramsAndInfo : List [(js. VarRef , JSParamInfo ) ]
1730
1757
}
1731
1758
1732
1759
private class PrimaryJSCtor (val sym : Symbol ,
1733
- val params : List [Symbol ], val body : List [js.Tree ]) extends JSCtor
1760
+ val paramsAndInfo : List [(js.VarRef , JSParamInfo )],
1761
+ val body : List [js.Tree ]) extends JSCtor
1734
1762
1735
1763
private class SplitSecondaryJSCtor (val sym : Symbol ,
1736
- val params : List [Symbol ], val beforeCall : List [js.Tree ],
1764
+ val paramsAndInfo : List [(js.VarRef , JSParamInfo )],
1765
+ val beforeCall : List [js.Tree ],
1737
1766
val targetCtor : Symbol , val ctorArgs : List [js.Tree ],
1738
1767
val afterCall : List [js.Tree ]) extends JSCtor
1739
1768
@@ -6768,6 +6797,13 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
6768
6797
}
6769
6798
}
6770
6799
6800
+ private def flatStats (stats : List [Tree ]): Iterator [Tree ] = {
6801
+ stats.iterator.flatMap {
6802
+ case Block (stats, expr) => stats.iterator ++ Iterator .single(expr)
6803
+ case tree => Iterator .single(tree)
6804
+ }
6805
+ }
6806
+
6771
6807
sealed abstract class MaybeGlobalScope
6772
6808
6773
6809
object MaybeGlobalScope {
0 commit comments