@@ -745,21 +745,25 @@ trait Namers extends MethodSynthesis {
745
745
746
746
def enterTypeDef (tree : TypeDef ) = assignAndEnterFinishedSymbol(tree)
747
747
748
- def enterDefDef (tree : DefDef ): Unit = tree match {
749
- case DefDef (_, nme.CONSTRUCTOR , _, _, _, _) =>
750
- assignAndEnterFinishedSymbol(tree)
751
- case DefDef (mods, name, _, _, _, _) =>
752
- val sym = enterInScope(assignMemberSymbol(tree))
748
+ def enterDefDef (tree : DefDef ): Unit = {
749
+ tree match {
750
+ case DefDef (_, nme.CONSTRUCTOR , _, _, _, _) =>
751
+ assignAndEnterFinishedSymbol(tree)
752
+ case DefDef (mods, name, _, _, _, _) =>
753
+ val sym = enterInScope(assignMemberSymbol(tree))
753
754
754
- val completer =
755
- if (sym hasFlag SYNTHETIC ) {
756
- if (name == nme.copy) copyMethodCompleter(tree)
757
- else if (sym hasFlag CASE ) applyUnapplyMethodCompleter(tree, context)
758
- else completerOf(tree)
759
- } else completerOf(tree)
755
+ val completer =
756
+ if (sym hasFlag SYNTHETIC ) {
757
+ if (name == nme.copy) copyMethodCompleter(tree)
758
+ else if (sym hasFlag CASE ) applyUnapplyMethodCompleter(tree, context)
759
+ else completerOf(tree)
760
+ } else completerOf(tree)
760
761
761
- sym setInfo completer
762
+ sym setInfo completer
762
763
}
764
+ if (mexists(tree.vparamss)(_.mods.hasDefault))
765
+ enterDefaultGetters(tree.symbol, tree, tree.vparamss, tree.tparams)
766
+ }
763
767
764
768
def enterClassDef (tree : ClassDef ): Unit = {
765
769
val ClassDef (mods, _, _, impl) = tree
@@ -1189,6 +1193,12 @@ trait Namers extends MethodSynthesis {
1189
1193
val module = clazz.sourceModule
1190
1194
for (cda <- module.attachments.get[ConstructorDefaultsAttachment ]) {
1191
1195
debuglog(s " Storing the template namer in the ConstructorDefaultsAttachment of ${module.debugLocationString}. " )
1196
+ if (cda.defaults.nonEmpty) {
1197
+ for (sym <- cda.defaults) {
1198
+ decls.enter(sym)
1199
+ }
1200
+ cda.defaults.clear()
1201
+ }
1192
1202
cda.companionModuleClassNamer = templateNamer
1193
1203
}
1194
1204
val classTp = ClassInfoType (parents, decls, clazz)
@@ -1419,6 +1429,42 @@ trait Namers extends MethodSynthesis {
1419
1429
pluginsTypeSig(methSig, typer, ddef, resTpGiven)
1420
1430
}
1421
1431
1432
+ /**
1433
+ * For every default argument, insert a method symbol computing that default
1434
+ */
1435
+ def enterDefaultGetters (meth : Symbol , ddef : DefDef , vparamss : List [List [ValDef ]], tparams : List [TypeDef ]) {
1436
+ val methOwner = meth.owner
1437
+ val search = DefaultGetterNamerSearch (context, meth, initCompanionModule = false )
1438
+ var posCounter = 1
1439
+
1440
+ mforeach(vparamss){(vparam) =>
1441
+ // true if the corresponding parameter of the base class has a default argument
1442
+ if (vparam.mods.hasDefault) {
1443
+ val name = nme.defaultGetterName(meth.name, posCounter)
1444
+
1445
+ search.createAndEnter { owner : Symbol =>
1446
+ methOwner.resetFlag(INTERFACE ) // there's a concrete member now
1447
+ val default = owner.newMethodSymbol(name, vparam.pos, paramFlagsToDefaultGetter(meth.flags))
1448
+ default.setPrivateWithin(meth.privateWithin)
1449
+ default.referenced = meth
1450
+ default.setInfo(ErrorType )
1451
+ if (meth.name == nme.apply && meth.hasAllFlags(CASE | SYNTHETIC )) {
1452
+ val att = meth.attachments.get[CaseApplyDefaultGetters ].getOrElse({
1453
+ val a = new CaseApplyDefaultGetters ()
1454
+ meth.updateAttachment(a)
1455
+ a
1456
+ })
1457
+ att.defaultGetters += default
1458
+ }
1459
+ if (default.owner.isTerm)
1460
+ saveDefaultGetter(meth, default)
1461
+ default
1462
+ }
1463
+ }
1464
+ posCounter += 1
1465
+ }
1466
+ }
1467
+
1422
1468
/**
1423
1469
* For every default argument, insert a method computing that default
1424
1470
*
@@ -1433,6 +1479,7 @@ trait Namers extends MethodSynthesis {
1433
1479
// in methods with multiple default parameters
1434
1480
def rtparams = rtparams0.map(_.duplicate)
1435
1481
def rvparamss = rvparamss0.map(_.map(_.duplicate))
1482
+ val search = DefaultGetterNamerSearch (context, meth, initCompanionModule = true )
1436
1483
val methOwner = meth.owner
1437
1484
val isConstr = meth.isConstructor
1438
1485
val overrides = overridden != NoSymbol && ! overridden.isOverloaded
@@ -1448,9 +1495,6 @@ trait Namers extends MethodSynthesis {
1448
1495
" " + meth.fullName + " , " + overridden.fullName
1449
1496
)
1450
1497
1451
- // cache the namer used for entering the default getter symbols
1452
- var ownerNamer : Option [Namer ] = None
1453
- var moduleNamer : Option [(ClassDef , Namer )] = None
1454
1498
var posCounter = 1
1455
1499
1456
1500
// For each value parameter, create the getter method if it has a
@@ -1490,80 +1534,46 @@ trait Namers extends MethodSynthesis {
1490
1534
val oflag = if (baseHasDefault) OVERRIDE else 0
1491
1535
val name = nme.defaultGetterName(meth.name, posCounter)
1492
1536
1493
- var defTparams = rtparams
1494
1537
val defVparamss = mmap(rvparamss.take(previous.length)){ rvp =>
1495
1538
copyValDef(rvp)(mods = rvp.mods &~ DEFAULTPARAM , rhs = EmptyTree )
1496
1539
}
1497
-
1498
- val parentNamer = if (isConstr) {
1499
- val (cdef, nmr) = moduleNamer.getOrElse {
1500
- val module = companionSymbolOf(methOwner, context)
1501
- module.initialize // call type completer (typedTemplate), adds the
1502
- // module's templateNamer to classAndNamerOfModule
1503
- module.attachments.get[ConstructorDefaultsAttachment ] match {
1504
- // by martin: the null case can happen in IDE; this is really an ugly hack on top of an ugly hack but it seems to work
1505
- case Some (cda) =>
1506
- if (cda.companionModuleClassNamer == null ) {
1507
- devWarning(s " scala/bug#6576 The companion module namer for $meth was unexpectedly null " )
1508
- return
1509
- }
1510
- val p = (cda.classWithDefault, cda.companionModuleClassNamer)
1511
- moduleNamer = Some (p)
1512
- p
1513
- case _ =>
1514
- return // fix #3649 (prevent crash in erroneous source code)
1540
+ search.addGetter(rtparams) {
1541
+ (parentNamer : Namer , defTparams : List [TypeDef ]) =>
1542
+ val defTpt =
1543
+ // don't mess with tpt's of case copy default getters, because assigning something other than TypeTree()
1544
+ // will break the carefully orchestrated naming/typing logic that involves copyMethodCompleter and caseClassCopyMeth
1545
+ if (meth.isCaseCopy) TypeTree ()
1546
+ else {
1547
+ // If the parameter type mentions any type parameter of the method, let the compiler infer the
1548
+ // return type of the default getter => allow "def foo[T](x: T = 1)" to compile.
1549
+ // This is better than always using Wildcard for inferring the result type, for example in
1550
+ // def f(i: Int, m: Int => Int = identity _) = m(i)
1551
+ // if we use Wildcard as expected, we get "Nothing => Nothing", and the default is not usable.
1552
+ // TODO: this is a very brittle approach; I sincerely hope that Denys's research into hygiene
1553
+ // will open the doors to a much better way of doing this kind of stuff
1554
+ val tparamNames = defTparams map { case TypeDef (_, name, _, _) => name }
1555
+ val eraseAllMentionsOfTparams = new TypeTreeSubstituter (tparamNames contains _)
1556
+ eraseAllMentionsOfTparams(rvparam.tpt match {
1557
+ // default getter for by-name params
1558
+ case AppliedTypeTree (_, List (arg)) if sym.hasFlag(BYNAMEPARAM ) => arg
1559
+ case t => t
1560
+ })
1561
+ }
1562
+ val defRhs = rvparam.rhs
1563
+
1564
+ val defaultTree = atPos(vparam.pos.focus) {
1565
+ DefDef (Modifiers (paramFlagsToDefaultGetter(meth.flags), ddef.mods.privateWithin) | oflag, name, defTparams, defVparamss, defTpt, defRhs)
1515
1566
}
1516
- }
1517
- val ClassDef (_, _, rtparams, _) = resetAttrs(deriveClassDef(cdef)(_ => Template (Nil , noSelfType, Nil )).duplicate)
1518
- defTparams = rtparams.map(rt => copyTypeDef(rt)(mods = rt.mods &~ (COVARIANT | CONTRAVARIANT )))
1519
- nmr
1520
- }
1521
- else ownerNamer getOrElse {
1522
- val ctx = context.nextEnclosing(c => c.scope.toList.contains(meth))
1523
- assert(ctx != NoContext , meth)
1524
- val nmr = newNamer(ctx)
1525
- ownerNamer = Some (nmr)
1526
- nmr
1527
- }
1528
-
1529
- val defTpt =
1530
- // don't mess with tpt's of case copy default getters, because assigning something other than TypeTree()
1531
- // will break the carefully orchestrated naming/typing logic that involves copyMethodCompleter and caseClassCopyMeth
1532
- if (meth.isCaseCopy) TypeTree ()
1533
- else {
1534
- // If the parameter type mentions any type parameter of the method, let the compiler infer the
1535
- // return type of the default getter => allow "def foo[T](x: T = 1)" to compile.
1536
- // This is better than always using Wildcard for inferring the result type, for example in
1537
- // def f(i: Int, m: Int => Int = identity _) = m(i)
1538
- // if we use Wildcard as expected, we get "Nothing => Nothing", and the default is not usable.
1539
- // TODO: this is a very brittle approach; I sincerely hope that Denys's research into hygiene
1540
- // will open the doors to a much better way of doing this kind of stuff
1541
- val tparamNames = defTparams map { case TypeDef (_, name, _, _) => name }
1542
- val eraseAllMentionsOfTparams = new TypeTreeSubstituter (tparamNames contains _)
1543
- eraseAllMentionsOfTparams(rvparam.tpt match {
1544
- // default getter for by-name params
1545
- case AppliedTypeTree (_, List (arg)) if sym.hasFlag(BYNAMEPARAM ) => arg
1546
- case t => t
1547
- })
1548
- }
1549
- val defRhs = rvparam.rhs
1550
-
1551
- val defaultTree = atPos(vparam.pos.focus) {
1552
- DefDef (Modifiers (paramFlagsToDefaultGetter(meth.flags), ddef.mods.privateWithin) | oflag, name, defTparams, defVparamss, defTpt, defRhs)
1553
- }
1554
- if (! isConstr)
1555
- methOwner.resetFlag(INTERFACE ) // there's a concrete member now
1556
- val default = parentNamer.enterSyntheticSym(defaultTree)
1557
- if (meth.name == nme.apply && meth.hasAllFlags(CASE | SYNTHETIC )) {
1558
- val att = meth.attachments.get[CaseApplyDefaultGetters ].getOrElse({
1559
- val a = new CaseApplyDefaultGetters ()
1560
- meth.updateAttachment(a)
1561
- a
1562
- })
1563
- att.defaultGetters += default
1567
+ def referencesThis (sym : Symbol ) = sym match {
1568
+ case term : TermSymbol => term.referenced == meth
1569
+ case _ => false
1570
+ }
1571
+ val defaultGetterSym = parentNamer.context.scope.lookup(name).filter(referencesThis)
1572
+ assert(defaultGetterSym != NoSymbol , (parentNamer.owner, name))
1573
+ defaultTree.setSymbol(defaultGetterSym)
1574
+ defaultGetterSym.setInfo(parentNamer.completerOf(defaultTree))
1575
+ defaultTree
1564
1576
}
1565
- if (default.owner.isTerm)
1566
- saveDefaultGetter(meth, default)
1567
1577
}
1568
1578
else if (baseHasDefault) {
1569
1579
// the parameter does not have a default itself, but the
@@ -1578,6 +1588,68 @@ trait Namers extends MethodSynthesis {
1578
1588
}
1579
1589
}
1580
1590
1591
+ private object DefaultGetterNamerSearch {
1592
+ def apply (c : Context , meth : Symbol , initCompanionModule : Boolean ) = if (meth.isConstructor) new DefaultGetterInCompanion (c, meth, initCompanionModule)
1593
+ else new DefaultMethodInOwningScope (c, meth)
1594
+ }
1595
+ private abstract class DefaultGetterNamerSearch {
1596
+ def addGetter (rtparams0 : List [TypeDef ])(create : (Namer , List [TypeDef ]) => Tree )
1597
+
1598
+ def createAndEnter (f : Symbol => Symbol ): Unit
1599
+ }
1600
+ private class DefaultGetterInCompanion (c : Context , meth : Symbol , initCompanionModule : Boolean ) extends DefaultGetterNamerSearch {
1601
+ private val module = companionSymbolOf(meth.owner, context)
1602
+ if (initCompanionModule) module.initialize
1603
+ private val cda : Option [ConstructorDefaultsAttachment ] = module.attachments.get[ConstructorDefaultsAttachment ]
1604
+ private val moduleNamer = cda.flatMap(x => Option (x.companionModuleClassNamer))
1605
+
1606
+ def createAndEnter (f : Symbol => Symbol ): Unit = {
1607
+ val default = f(module.moduleClass)
1608
+ moduleNamer match {
1609
+ case Some (namer) =>
1610
+ namer.enterInScope(default)
1611
+ case None =>
1612
+ cda match {
1613
+ case Some (attachment) =>
1614
+ // defer entry until the companion module body it type completed
1615
+ attachment.defaults += default
1616
+ case None =>
1617
+ // ignore error to fix #3649 (prevent crash in erroneous source code)
1618
+ }
1619
+ }
1620
+ }
1621
+ def addGetter (rtparams0 : List [TypeDef ])(create : (Namer , List [TypeDef ]) => Tree ): Unit = {
1622
+ cda match {
1623
+ case Some (attachment) =>
1624
+ moduleNamer match {
1625
+ case Some (namer) =>
1626
+ val cdef = attachment.classWithDefault
1627
+ val ClassDef (_, _, rtparams, _) = resetAttrs(deriveClassDef(cdef)(_ => Template (Nil , noSelfType, Nil )).duplicate)
1628
+ val defTparams = rtparams.map(rt => copyTypeDef(rt)(mods = rt.mods &~ (COVARIANT | CONTRAVARIANT )))
1629
+ val tree = create(namer, defTparams)
1630
+ namer.enterSyntheticSym(tree)
1631
+ case None =>
1632
+ }
1633
+ case None =>
1634
+ }
1635
+
1636
+ }
1637
+ }
1638
+ private class DefaultMethodInOwningScope (c : Context , meth : Symbol ) extends DefaultGetterNamerSearch {
1639
+ private lazy val ownerNamer : Namer = {
1640
+ val ctx = context.nextEnclosing(c => c.scope.toList.contains(meth)) // TODO use lookup rather than toList.contains
1641
+ assert(ctx != NoContext , meth)
1642
+ newNamer(ctx)
1643
+ }
1644
+ def createAndEnter (f : Symbol => Symbol ): Unit = {
1645
+ ownerNamer.enterInScope(f(ownerNamer.context.owner))
1646
+ }
1647
+ def addGetter (rtparams0 : List [TypeDef ])(create : (Namer , List [TypeDef ]) => Tree ): Unit = {
1648
+ val tree = create(ownerNamer, rtparams0)
1649
+ ownerNamer.enterSyntheticSym(tree)
1650
+ }
1651
+ }
1652
+
1581
1653
private def valDefSig (vdef : ValDef ) = {
1582
1654
val ValDef (_, _, tpt, rhs) = vdef
1583
1655
val result =
0 commit comments