@@ -417,9 +417,9 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
417
417
}
418
418
419
419
if (stat1 eq stat) {
420
- assert(ctorParams(genericClazz).length == constrInfo.constrParams .length)
420
+ assert(ctorParams(genericClazz).length == primaryConstrParams .length)
421
421
// this is just to make private fields public
422
- (new specializeTypes.ImplementationAdapter (ctorParams(genericClazz), constrInfo.constrParams , null , true ))(stat1)
422
+ (new specializeTypes.ImplementationAdapter (ctorParams(genericClazz), primaryConstrParams , null , true ))(stat1)
423
423
424
424
val stat2 = rewriteArrayUpdate(stat1)
425
425
// statements coming from the original class need retyping in the current context
@@ -456,16 +456,16 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
456
456
// postfix = postfix.tail
457
457
// }
458
458
459
- if (shouldGuard && usesSpecializedField && stats.nonEmpty) {
459
+ if (guardSpecializedFieldInit && usesSpecializedField && stats.nonEmpty) {
460
460
// save them for duplication in the specialized subclass
461
461
guardedCtorStats(clazz) = stats
462
- ctorParams(clazz) = constrInfo.constrParams
462
+ ctorParams(clazz) = primaryConstrParams
463
463
464
464
val tree =
465
465
If (
466
466
Apply (
467
467
CODE .NOT (
468
- Apply (gen.mkAttributedRef(specializedFlag ), List ())),
468
+ Apply (gen.mkAttributedRef(hasSpecializedFieldsSym ), List ())),
469
469
List ()),
470
470
Block (stats, Literal (Constant (()))),
471
471
EmptyTree )
@@ -493,32 +493,23 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
493
493
with OmittablesHelper
494
494
with GuardianOfCtorStmts {
495
495
496
- val clazz = impl.symbol.owner // the transformed class
497
- val inTrait = clazz.isTrait
498
- val stats = impl.body // the transformed template body
496
+ val clazz = impl.symbol.owner // the transformed class
497
+ val inTrait = clazz.isTrait
498
+ val stats = impl.body // the transformed template body
499
499
val localTyper = typer.atOwner(impl, clazz)
500
500
501
- val specializedFlag : Symbol = clazz.info.decl(nme.SPECIALIZED_INSTANCE )
502
- val shouldGuard = (specializedFlag != NoSymbol ) && ! clazz.hasFlag(SPECIALIZED )
501
+ val hasSpecializedFieldsSym = clazz.info.decl(nme.SPECIALIZED_INSTANCE )
502
+ // The constructor of non-specialized classes with specialized subclasses should guard
503
+ // the initialization of specialized fields on the result of the `hasSpecializedFieldsSym` method.
504
+ val guardSpecializedFieldInit = ! ((hasSpecializedFieldsSym == NoSymbol ) || clazz.hasFlag(SPECIALIZED ))
503
505
504
- val isDelayedInitSubclass = ( clazz isSubClass DelayedInitClass )
506
+ val isDelayedInitSubclass = clazz isSubClass DelayedInitClass
505
507
506
- case class ConstrInfo (
507
- constr : DefDef , // The primary constructor
508
- constrParams : List [Symbol ], // ... and its parameters
509
- constrBody : Block // ... and its body
510
- )
511
508
// decompose primary constructor into the three entities above.
512
- val constrInfo : ConstrInfo = {
513
- val ddef = (stats find (_.symbol.isPrimaryConstructor))
514
- ddef match {
515
- case Some (ddef @ DefDef (_, _, _, List (vparams), _, rhs @ Block (_, _))) =>
516
- ConstrInfo (ddef, vparams map (_.symbol), rhs)
517
- case x =>
518
- abort(" no constructor in template: impl = " + impl)
519
- }
520
- }
521
- import constrInfo ._
509
+ val (primaryConstr, primaryConstrParams, primaryConstrBody) = stats collectFirst {
510
+ case dd@ DefDef (_, _, _, vps :: Nil , _, rhs : Block ) if dd.symbol.isPrimaryConstructor => (dd, vps map (_.symbol), rhs)
511
+ } getOrElse abort(" no constructor in template: impl = " + impl)
512
+
522
513
523
514
// The parameter accessor fields which are members of the class
524
515
val paramAccessors = clazz.constrParamAccessors
@@ -531,19 +522,19 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
531
522
def parameterNamed (name : Name ): Symbol = {
532
523
def matchesName (param : Symbol ) = param.name == name || param.name.startsWith(name + nme.NAME_JOIN_STRING )
533
524
534
- (constrParams filter matchesName) match {
535
- case Nil => abort(name + " not in " + constrParams )
525
+ (primaryConstrParams filter matchesName) match {
526
+ case Nil => abort(name + " not in " + primaryConstrParams )
536
527
case p :: _ => p
537
528
}
538
529
}
539
530
540
531
/*
541
532
* `usesSpecializedField` makes a difference in deciding whether constructor-statements
542
- * should be guarded in a `shouldGuard ` class, ie in a class that's the generic super-class of
533
+ * should be guarded in a `guardSpecializedFieldInit ` class, ie in a class that's the generic super-class of
543
534
* one or more specialized sub-classes.
544
535
*
545
536
* Given that `usesSpecializedField` isn't read for any other purpose than the one described above,
546
- * we skip setting `usesSpecializedField` in case the current class isn't `shouldGuard ` to start with.
537
+ * we skip setting `usesSpecializedField` in case the current class isn't `guardSpecializedFieldInit ` to start with.
547
538
* That way, trips to a map in `specializeTypes` are saved.
548
539
*/
549
540
var usesSpecializedField : Boolean = false
@@ -588,10 +579,8 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
588
579
// references to parameter accessor field of own class become references to parameters
589
580
gen.mkAttributedIdent(parameter(tree.symbol)) setPos tree.pos
590
581
591
- case Select (_, _) if shouldGuard => // reasoning behind this guard in the docu of `usesSpecializedField`
592
- if (possiblySpecialized(tree.symbol)) {
593
- usesSpecializedField = true
594
- }
582
+ case Select (_, _) if guardSpecializedFieldInit && possiblySpecialized(tree.symbol) => // reasoning behind this guard in the docu of `usesSpecializedField`
583
+ usesSpecializedField = true
595
584
super .transform(tree)
596
585
597
586
case _ =>
@@ -604,7 +593,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
604
593
605
594
// Move tree into constructor, take care of changing owner from `oldowner` to constructor symbol
606
595
def intoConstructor (oldowner : Symbol , tree : Tree ) =
607
- intoConstructorTransformer transform tree.changeOwner(oldowner -> constr .symbol)
596
+ intoConstructorTransformer transform tree.changeOwner(oldowner -> primaryConstr .symbol)
608
597
609
598
private def needsCtorEffect (stat : ValOrDefDef ): Boolean = ! (stat.rhs == EmptyTree || stat.symbol.isLazy)
610
599
@@ -685,7 +674,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
685
674
val classInitStatBuf = new ListBuffer [Tree ]
686
675
687
676
// generate code to copy pre-initialized fields
688
- for (stat <- constrBody .stats) {
677
+ for (stat <- primaryConstrBody .stats) {
689
678
constrStatBuf += stat
690
679
stat match {
691
680
case ValDef (mods, name, _, _) if (mods hasFlag PRESUPER ) =>
@@ -700,57 +689,57 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
700
689
}
701
690
702
691
// Triage all template definitions to go into defBuf/auxConstructorBuf, constrStatBuf, or constrPrefixBuf.
703
- for (stat <- stats) stat match {
704
- case dd@ DefDef (_,_,_,_,_,rhs) =>
705
- // methods with constant result type get literals as their body
692
+
693
+ for (stat <- stats) {
694
+ val sym = stat.symbol
695
+ stat match {
696
+ // TODO what is this doing in Constructors? I'd expect it much earlier -- erasure? uncurry?
697
+ case dd@ DefDef (_,_,_,_,_,rhs) if sym.info.params.isEmpty && sym.info.resultType.isInstanceOf [ConstantType ] =>
698
+ defBuf += deriveDefDef(dd)(rhs => gen.mkAttributedQualifier(sym.info.resultType) setPos rhs.pos )
699
+
706
700
// all methods except the primary constructor go into template
707
- stat.symbol.tpe match {
708
- case MethodType (List (), tp @ ConstantType (c)) =>
709
- defBuf += deriveDefDef(stat)(Literal (c) setPos _.pos setType tp)
710
- case _ =>
711
- if (stat.symbol.isPrimaryConstructor) ()
712
- else if (stat.symbol.isConstructor) auxConstructorBuf += stat
713
- // a concrete getter's RHS is treated like a ValDef (the actual field isn't emitted until Mixin augments the class that inherits the trait)
714
- else if (inTrait) {
715
- // We can't mark as deferred from the start, as it will be implemented automatically in the subclass
716
- // it should be marked deferred in bytecode, though
717
-
718
- var stat_memoizedGetterLosesRhs = stat
719
-
720
- // a trait getter with an empty RHS is marked deferred from the start
721
- if (stat.symbol.isGetter && (rhs ne EmptyTree )) {
701
+ case _ : DefDef if sym.isConstructor => if (sym ne primaryConstr.symbol) auxConstructorBuf += stat
702
+
703
+ // a concrete getter's RHS is treated like a ValDef (the actual field isn't emitted until Mixin augments the class that inherits the trait)
704
+ // We can't mark as deferred from the start, as it will be implemented automatically in the subclass
705
+ // it should be marked deferred in bytecode, though
706
+ case dd@ DefDef (_,_,_,_,_,rhs) if inTrait && sym.isAccessor =>
707
+ // a trait getter with an empty RHS is marked deferred from the start
708
+ defBuf +=
709
+ if (sym.isGetter) {
710
+ if (rhs ne EmptyTree ) {
722
711
val memoized = moveEffectToCtor(dd)
723
712
if (memoized) {
724
- stat.symbol setFlag (DEFERRED | lateDEFERRED)
725
- stat_memoizedGetterLosesRhs = deriveDefDef(dd)(_ => EmptyTree )
726
- }
727
- } else if (stat.symbol.isSetter) {
728
- stat.symbol setFlag (DEFERRED | lateDEFERRED)
729
- }
730
-
731
- defBuf += stat_memoizedGetterLosesRhs
713
+ sym setFlag (DEFERRED | lateDEFERRED)
714
+ deriveDefDef(dd)(_ => EmptyTree )
715
+ } else stat
716
+ } else stat
717
+ } else {
718
+ sym setFlag (DEFERRED | lateDEFERRED)
719
+ stat
732
720
}
733
- else defBuf += stat
734
- }
735
- case vd@ ValDef (mods, _, _, rhs) if ! mods.hasStaticFlag =>
736
- // Move field's effect into the constructor (usually an assignment of rhs to field,
737
- // but it could also be the side-effect of the rhs when no storage is needed).
738
- val needsField = moveEffectToCtor(vd)
739
-
740
- // Only emit fields that actually need to be stored
741
- if (needsField) defBuf += deriveValDef(stat)(_ => EmptyTree )
742
-
743
- case ValDef (_, _, _, rhs) =>
744
- // Add static initializer statements to classInitStatBuf and remove the rhs from the val def.
745
- classInitStatBuf += mkAssign(stat.symbol, rhs)
746
- defBuf += deriveValDef(stat)(_ => EmptyTree )
747
-
748
- case ClassDef (_, _, _, _) =>
749
- // classes are treated recursively, and left in the template
750
- defBuf += new ConstructorTransformer (unit).transform(stat)
751
- case _ =>
752
- // all other statements go into the constructor
753
- constrStatBuf += intoConstructor(impl.symbol, stat)
721
+
722
+ case _ : DefDef => defBuf += stat
723
+ case vd@ ValDef (mods, _, _, rhs) if ! mods.hasStaticFlag =>
724
+ // Move field's effect into the constructor (usually an assignment of rhs to field,
725
+ // but it could also be the side-effect of the rhs when no storage is needed).
726
+ val needsField = moveEffectToCtor(vd)
727
+
728
+ // Only emit fields that actually need to be stored
729
+ if (needsField) defBuf += deriveValDef(stat)(_ => EmptyTree )
730
+
731
+ case ValDef (_, _, _, rhs) =>
732
+ // Add static initializer statements to classInitStatBuf and remove the rhs from the val def.
733
+ classInitStatBuf += mkAssign(sym, rhs)
734
+ defBuf += deriveValDef(stat)(_ => EmptyTree )
735
+
736
+ case ClassDef (_, _, _, _) =>
737
+ // classes are treated recursively, and left in the template
738
+ defBuf += new ConstructorTransformer (unit).transform(stat)
739
+ case _ =>
740
+ // all other statements go into the constructor
741
+ constrStatBuf += intoConstructor(impl.symbol, stat)
742
+ }
754
743
}
755
744
756
745
populateOmittables()
@@ -768,7 +757,7 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
768
757
copyParam(acc, parameter(acc))
769
758
}
770
759
771
- /* Return a pair consisting of (all statements up to and including superclass and trait constr calls, rest) */
760
+ /* Return a pair consisting of (all statements up to and including superclass and trait primaryConstr calls, rest) */
772
761
def splitAtSuper (stats : List [Tree ]) = {
773
762
def isConstr (tree : Tree ): Boolean = tree match {
774
763
case Block (_, expr) => isConstr(expr) // SI-6481 account for named argument blocks
@@ -785,12 +774,11 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
785
774
rewriteDelayedInit()
786
775
787
776
// Assemble final constructor
788
- defBuf += deriveDefDef(constr )(_ =>
777
+ defBuf += deriveDefDef(primaryConstr )(_ =>
789
778
treeCopy.Block (
790
- constrBody,
791
- paramInits ::: constrPrefixBuf.toList ::: uptoSuperStats :::
792
- guardSpecializedInitializer(remainingConstrStats),
793
- constrBody.expr))
779
+ primaryConstrBody,
780
+ paramInits ::: constrPrefixBuf.toList ::: uptoSuperStats ::: guardSpecializedInitializer(remainingConstrStats),
781
+ primaryConstrBody.expr))
794
782
795
783
// Followed by any auxiliary constructors
796
784
defBuf ++= auxConstructorBuf
0 commit comments