Skip to content

Commit 6555c74

Browse files
committed
bootstraps again by running info transform once per class...
not sure how this ever worked, as separate compilation would transform a trait's info multiple times, resulting in double defs...
1 parent 33ac5e0 commit 6555c74

File tree

2 files changed

+62
-77
lines changed

2 files changed

+62
-77
lines changed

src/compiler/scala/tools/nsc/transform/Fields.scala

Lines changed: 57 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
3838

3939
protected def newTransformer(unit: CompilationUnit): Transformer = new FieldsTransformer(unit)
4040
override def transformInfo(sym: Symbol, tp: Type): Type =
41-
if (!sym.isJavaDefined && !(sym hasFlag FINAL_TRAIT_ACCESSOR)) {
42-
sym setFlag FINAL_TRAIT_ACCESSOR // TODO: remove overloaded use of this flag, used to check hypothesis that info transformer is run re-entrantly?
41+
if (sym.isJavaDefined || sym.isClass && (sym hasFlag SYNTHESIZE_IMPL_IN_SUBCLASS)) tp
42+
else {
43+
// only synthesize members once! TODO: don't overload this flag...
44+
if (sym.isClass) sym setFlag SYNTHESIZE_IMPL_IN_SUBCLASS
4345
synthFieldsAndAccessors(tp)
44-
} else tp
46+
}
4547

4648

4749
// we leave lazy vars/accessors and early-init vals alone for now
@@ -56,9 +58,8 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
5658

5759
private def concreteOrSynthImpl(sym: Symbol): Boolean = !(sym hasFlag DEFERRED) || (sym hasFlag SYNTHESIZE_IMPL_IN_SUBCLASS)
5860

59-
private def setTraitAccessorFlags(accessor: Symbol): Unit = {
61+
private def setTraitAccessorFlags(accessor: Symbol): Unit =
6062
accessor setFlag lateDEFERRED | SYNTHESIZE_IMPL_IN_SUBCLASS
61-
}
6263

6364
private def setClonedTraitSetterFlags(clazz: Symbol, correspondingGetter: Symbol, cloneInSubclass: Symbol): Unit = {
6465
val overridden = isOverriddenAccessor(correspondingGetter, clazz)
@@ -73,7 +74,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
7374
fieldInSubclass setFlag ( NEEDS_TREES |
7475
PrivateLocal
7576
| (accessor getFlag MUTABLE | LAZY)
76-
| (if (accessor.hasStableFlag) 0 else MUTABLE)
77+
| (if (accessor hasFlag STABLE) 0 else MUTABLE)
7778
)
7879

7980

@@ -120,10 +121,11 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
120121
private def fieldTypeForGetterIn(getter: Symbol, pre: Type): Type = getter.info.finalResultType.asSeenFrom(pre, getter.owner)
121122
private def fieldTypeForSetterIn(setter: Symbol, pre: Type): Type = setter.info.paramTypes.head.asSeenFrom(pre, setter.owner)
122123

123-
def fieldTypeOfAccessorIn(accessor: Symbol, pre: Type) = {
124-
// TODO: is there a more elegant way?
125-
if (accessor.isSetter) fieldTypeForSetterIn(accessor, pre) else fieldTypeForGetterIn(accessor, pre)
126-
}
124+
// TODO: is there a more elegant way?
125+
def fieldTypeOfAccessorIn(accessor: Symbol, pre: Type) =
126+
if (accessor.isSetter) fieldTypeForSetterIn(accessor, pre)
127+
else fieldTypeForGetterIn(accessor, pre)
128+
127129

128130
// Constant/unit typed vals are not memoized (their value is so cheap it doesn't make sense to store it in a field)
129131
// for a unit-typed getter, we perform the effect at the appropriate time (constructor for eager ones, lzyCompute for lazy),
@@ -158,41 +160,39 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
158160
// none of this is actually undone when travelling back in time using atPhase)
159161
case tp@ClassInfoType(parents, decls, clazz) if clazz.isTrait =>
160162
val newSetters = collection.mutable.ListBuffer[Symbol]()
163+
val origDecls = decls.toList
161164

162165
// strict, memoized accessors will receive an implementation in first real class to extend this trait
163-
decls.foreach {
164-
case accessor if accessor hasFlag ACCESSOR =>
165-
// check flags before calling makeNotPrivate
166-
val memoizedGetter = !(accessor hasFlag (DEFERRED | LAZY)) && fieldMemoizationIn(accessor, clazz).needsField
167-
168-
// only affects private symbols, with a destructive update of their name, also sets flags
169-
// required for private vals in traits
170-
accessor.makeNotPrivate(clazz)
171-
172-
// Need to mark as notPROTECTED, so that it's carried over to the synthesized member in subclasses,
173-
// since the trait member will receive this flag later in ExplicitOuter, but the synthetic subclass member will not.
174-
// If we don't add notPROTECTED to the synthesized one, the member will not be seen as overriding the trait member.
175-
// Therefore, addForwarders's call to membersBasedOnFlags would see the deferred member in the trait,
176-
// instead of the concrete (desired) one in the class
177-
if (accessor.isProtected) accessor setFlag notPROTECTED
178-
179-
// must not reset LOCAL, as we must maintain protected[this]ness to allow that variance hole
180-
// (not sure why this only problem only arose when we started setting the notPROTECTED flag)
181-
182-
// derive trait setter after calling makeNotPrivate (so that names are mangled consistently)
183-
if (memoizedGetter) {
184-
setTraitAccessorFlags(accessor)
185-
186-
if ((accessor hasFlag STABLE) && accessor.isGetter) // TODO: isGetter is probably redundant?
187-
newSetters += newTraitSetter(accessor, clazz)
188-
}
189-
190-
case _ =>
191-
}
166+
origDecls.foreach { accessor => if (accessor hasFlag ACCESSOR) {
167+
// check flags before calling makeNotPrivate
168+
val memoizedGetter = !(accessor hasFlag (DEFERRED | LAZY)) && fieldMemoizationIn(accessor, clazz).needsField
169+
170+
// destructively mangle accessor's name (which may cause rehashing of decls), also sets flags
171+
if (accessor hasFlag PRIVATE) accessor makeNotPrivate clazz
172+
173+
// Need to mark as notPROTECTED, so that it's carried over to the synthesized member in subclasses,
174+
// since the trait member will receive this flag later in ExplicitOuter, but the synthetic subclass member will not.
175+
// If we don't add notPROTECTED to the synthesized one, the member will not be seen as overriding the trait member.
176+
// Therefore, addForwarders's call to membersBasedOnFlags would see the deferred member in the trait,
177+
// instead of the concrete (desired) one in the class
178+
if (accessor hasFlag PROTECTED) accessor setFlag notPROTECTED
179+
180+
// must not reset LOCAL, as we must maintain protected[this]ness to allow that variance hole
181+
// (not sure why this only problem only arose when we started setting the notPROTECTED flag)
182+
183+
// derive trait setter after calling makeNotPrivate (so that names are mangled consistently)
184+
if (memoizedGetter) {
185+
setTraitAccessorFlags(accessor)
186+
187+
if (accessor hasFlag STABLE) // TODO: check isGetter?
188+
newSetters += newTraitSetter(accessor, clazz)
189+
}
190+
}}
192191

193192
if (newSetters nonEmpty) {
194193
// println(s"newSetters for $clazz = $newSetters")
195-
val newDecls = decls.cloneScope
194+
val newDecls = newScope
195+
origDecls foreach newDecls.enter
196196
newSetters foreach newDecls.enter
197197
ClassInfoType(parents, newDecls, clazz)
198198
} else tp
@@ -221,7 +221,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
221221
//
222222
// the setter for the immutable val in OneVal has already been synthesized above
223223

224-
// TODO (3): what should this produce?
224+
// TODO (3): which error should this produce?
225225
// trait OneVal[T] { val x: Int = 123 }
226226
// class OverridingVal extends OneVal[Int] { val x: Int }
227227

@@ -241,11 +241,6 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
241241
(existingGetter ne NoSymbol) && (tp matches (site memberInfo existingGetter)) // !existingGetter.isDeferred && -- see (3)
242242
}
243243

244-
// TODO: special dance when we're overriding a val
245-
// trait OneVal[T] { val x: Int = 123 }
246-
// class OverridingVal extends OneVal[Int] { override val x: Int = ??? }
247-
248-
249244
// mixin field accessors --
250245
// invariant: (accessorsMaybeNeedingImpl, mixedInAccessorAndFields).zipped.forall(case (acc, clone :: _) => `clone` is clone of `acc` case _ => true)
251246
val mixedInAccessorAndFields = accessorsMaybeNeedingImpl map { accessor =>
@@ -282,7 +277,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
282277

283278
setFieldFlags(accessor, field)
284279

285-
// TODO: filter getter's annotations to exclude those only meant for the field
280+
// filter getter's annotations to exclude those only meant for the field
286281
// we must keep them around long enough to see them here, though, when we create the field
287282
field setAnnotations (accessor.annotations filter AnnotationInfo.mkFilter(FieldTargetClass, defaultRetention = true))
288283

@@ -293,21 +288,25 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
293288
// println(s"new decls for $clazz: $mixedInAccessorAndFields")
294289

295290
// omit fields that are not memoized, retain all other members
296-
def omittableField(sym: Symbol) = sym.isValue && !sym.isMethod && fieldMemoizationIn(sym, clazz).effectOnly // TODO: not yet `needsField`, to produce same bytecode as M2
291+
def omittableField(sym: Symbol) =
292+
sym.isValue && !sym.isMethod &&
293+
fieldMemoizationIn(sym, clazz).effectOnly // TODO: not yet `needsField`, to produce same bytecode as 2.12.0-M3
297294

298295
val newDecls =
299296
if (mixedInAccessorAndFields.isEmpty) oldDecls.filterNot(omittableField)
300297
else { // must not alter `decls` directly
301-
val newDecls = newScope
302-
oldDecls foreach { d => if (!omittableField(d)) newDecls.enter(d) }
303-
val enter = { mixedin: Symbol => newDecls enter mixedin }
304-
mixedInAccessorAndFields foreach { _ foreach enter }
305-
306-
// subst from accessors to corresponding clonedAccessors in types in newDecls
307-
val (origs, mixedins) = (accessorsMaybeNeedingImpl, mixedInAccessorAndFields).zipped.collect {
298+
// compute subst from accessors to corresponding clonedAccessors in types in newDecls
299+
val (_origs, _mixedins) = (accessorsMaybeNeedingImpl, mixedInAccessorAndFields).zipped.collect {
308300
case (traitAccessor, mixedin :: _) => (traitAccessor, mixedin)
309301
}.unzip
310-
newDecls foreach { sym => sym.substInfo(origs.toList, mixedins.toList) }
302+
303+
val (origs, mixedins) = (_origs.toList, _mixedins.toList)
304+
305+
val newDecls = newScope
306+
val enterAndSubst = { sym: Symbol => newDecls enter sym.substInfo(origs, mixedins) }
307+
308+
oldDecls foreach { d => if (!omittableField(d)) enterAndSubst(d) }
309+
mixedInAccessorAndFields foreach { _ foreach enterAndSubst }
311310

312311
newDecls
313312
}
@@ -364,14 +363,15 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
364363
// println(s"transformStat $statSym in ${exprOwner.ownerChain}")
365364
// currentRun.trackerFactory.snapshot()
366365

367-
// TODO: which symbol should own `rhs`, as the expression is lifted from `statSym` to the class's template?
366+
// Which symbol should own `rhs`, as the expression is lifted from `statSym` to the class's template?
368367
// Normally, the local dummy (`exprOwner`) is the owner for stats in the template (not `clazz`!)
369368
// when we get owners wrong, the following fails:
370369
// - stackoverflow in uncurry when bootstrapping
371370
// - compiling scala.util.Properties,
372371
// where some references from the impl class are still pointing to the trait interface, not the impl class
373372
// - test/files/trait-defaults/ultimate-nesting.scala,
374373
// where a nested module class is separated from its module, as well as from the `settings` reference
374+
// (this was due to changeOwner not changing a module's moduleClass's owner in addition to the module's owner)
375375
def initEffect(rhs: Tree, assignSym: Symbol) = {
376376
// println(s"initEffect: owner $statSym --> $exprOwner (currentOwner= $currentOwner)")
377377
// println(s"initEffect for $assignSym is $rhs")
@@ -427,19 +427,3 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
427427
}
428428
}
429429
}
430-
431-
432-
// case Template(parents, self, body) =>
433-
// treeCopy.Template(tree, transformTrees(parents), transformValDef(self), transformStats(body, tree.symbol))
434-
// override def transformTemplate(tree: Template): Template = {
435-
//// println(s"transforming stats in ${currentOwner}")
436-
// // Skip interfaces (they have no concrete methods, so no work to be done)
437-
// else afterOwnPhase {
438-
// currentOwner.info // TODO remove -- for debugging
439-
// deriveTemplate(tree)(stats => {
440-
// val templateSym = tree.symbol
441-
// fieldsAndAccessors(templateSym) ++ stats.flatMap(transformStat(templateSym))
442-
// })
443-
// }
444-
// }
445-

src/reflect/scala/reflect/internal/Flags.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,10 @@ class Flags extends ModifierFlags {
173173
final val SYNCHRONIZED = 1L << 45 // symbol is a method which should be marked ACC_SYNCHRONIZED
174174

175175
final val SYNTHESIZE_IMPL_IN_SUBCLASS = 1L << 50 // Like MIXEDIN, but used in Fields
176-
final val NEEDS_TREES = 1L << 59 // Communicate from Fields' info transform to its tree transform -- this symbol needs a tree. (distinct from SYNTHESIZE_IMPL_IN_SUBCLASS)
177-
final val OVERRIDDEN_TRAIT_SETTER = 1L << 60 // Communicate from Fields' info transform to its tree transform -- this setter gets a unit body.
178-
final val FINAL_TRAIT_ACCESSOR = 1L << 61 // Communicate from Fields' info transform to its tree transform -- this accessor's synthesized implementation should be final.
176+
177+
// flags used strictly internally in the Fields phase (info/tree transform):
178+
final val NEEDS_TREES = 1L << 59 // this symbol needs a tree. (distinct from SYNTHESIZE_IMPL_IN_SUBCLASS)
179+
final val OVERRIDDEN_TRAIT_SETTER = 1L << 60 // this setter gets a unit body.
179180

180181
// ------- shift definitions -------------------------------------------------------
181182
//
@@ -471,7 +472,7 @@ class Flags extends ModifierFlags {
471472
case `notPRIVATE` => "<notprivate>" // (1L << 58)
472473
case SYNTHESIZE_IMPL_IN_SUBCLASS => "<sub_synth>" // (1L << 59)
473474
case OVERRIDDEN_TRAIT_SETTER => "<overridden_trait_setter>" // (1L << 60)
474-
case FINAL_TRAIT_ACCESSOR => "<final_trait_acc>" // (1L << 61)
475+
case 0x2000000000000000L => "" // (1L << 61)
475476
case 0x4000000000000000L => "" // (1L << 62)
476477
case 0x8000000000000000L => "" // (1L << 63)
477478
case _ => ""

0 commit comments

Comments
 (0)