@@ -36,7 +36,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
36
36
val phaseName : String = " fields"
37
37
38
38
// used for internal communication between info and tree transform of this phase -- not pickled, not in initialflags
39
- override def phaseNewFlags : Long = NEEDS_TREES | OVERRIDDEN_TRAIT_SETTER
39
+ override def phaseNewFlags : Long = NEEDS_TREES | OVERRIDDEN_TRAIT_SETTER | FINAL_TRAIT_ACCESSOR
40
40
41
41
protected def newTransformer (unit : CompilationUnit ): Transformer =
42
42
new FieldsTransformer (unit)
@@ -91,25 +91,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
91
91
// NOTE: this only considers type, filter on flags first!
92
92
def fieldMemoizationIn (accessorOrField : Symbol , site : Symbol ) = new FieldMemoization (accessorOrField, site)
93
93
94
- def filterAccessorFieldAnnotations (sym : Symbol , tp : Type ) = {
95
- if ((sym.isAccessor || (sym.isValue && ! sym.isMethod)) && sym.owner.isTrait) {
96
- // TODO: beansetter/beangetters...
97
- val category = if (sym.isGetter) GetterTargetClass else if (sym.isSetter) SetterTargetClass else FieldTargetClass
98
- val defaultRetention = ! sym.isSetter // TODO: is this right? consider `@deprecated val x` --> in the trait: `@deprecated def x`
99
-
100
- val annotations = sym.annotations filter AnnotationInfo .mkFilter(category, defaultRetention)
101
-
102
- // TODO: does it matter at which phase we do this?
103
- // println(s"annotations for $sym: $annotations (out of ${sym.annotations})")
104
-
105
- sym setAnnotations annotations
106
- }
107
-
108
- tp
109
- }
110
-
111
-
112
- override def transformInfo (sym : Symbol , tp : Type ): Type = synthFieldsAndAccessors(filterAccessorFieldAnnotations(sym, tp))
94
+ override def transformInfo (sym : Symbol , tp : Type ): Type = synthFieldsAndAccessors(tp)
113
95
114
96
private def newTraitSetter (getter : Symbol , clazz : Symbol ) = {
115
97
// Add setter for an immutable, memoizing getter
@@ -125,7 +107,6 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
125
107
val fieldTp = fieldTypeForGetterIn(getter, clazz.thisType)
126
108
// println(s"newTraitSetter in $clazz for $getter = $setterName : $fieldTp")
127
109
setter setInfo MethodType (List (setter.newSyntheticValueParam(fieldTp)), UnitTpe )
128
- setter addAnnotation TraitSetterAnnotationClass
129
110
setter
130
111
}
131
112
@@ -146,7 +127,14 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
146
127
if (! (accessor hasFlag (DEFERRED | LAZY )) && fieldMemoizationIn(accessor, clazz).needsField) {
147
128
// in a trait, a memoized accessor becomes deferred
148
129
// (it'll receive an implementation in the first real class to extend this trait)
149
- markAccessorImplementedInSubclass(accessor)
130
+
131
+ // can't mark getter as FINAL in trait, but remember for when we synthetisize the impl in the subclass to make it FINAL
132
+ val finality = if (accessor hasFlag FINAL ) FINAL_TRAIT_ACCESSOR else 0
133
+ accessor setFlag (finality | lateFINAL | DEFERRED | SYNTHESIZE_IMPL_IN_SUBCLASS )
134
+
135
+ // trait members cannot be final (but the synthesized ones should be)
136
+ // LOCAL no longer applies (already made not-private)
137
+ accessor resetFlag (FINAL | LOCAL )
150
138
151
139
if ((accessor hasFlag STABLE ) && accessor.isGetter) // TODO: isGetter is probably redundant?
152
140
newSetters += newTraitSetter(accessor, clazz)
@@ -213,7 +201,10 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
213
201
// mixin field accessors
214
202
val mixedInFieldAndAccessors = accessorsMaybeNeedingImpl flatMap { accessor =>
215
203
def cloneAccessor () = {
216
- val clonedAccessor = (accessor cloneSymbol clazz) setPos clazz.pos setFlag NEEDS_TREES resetFlag DEFERRED | SYNTHESIZE_IMPL_IN_SUBCLASS
204
+ val clonedAccessor = (accessor cloneSymbol clazz) setPos clazz.pos setFlag NEEDS_TREES resetFlag DEFERRED | SYNTHESIZE_IMPL_IN_SUBCLASS | FINAL_TRAIT_ACCESSOR
205
+ if (accessor hasFlag FINAL_TRAIT_ACCESSOR ) {
206
+ clonedAccessor setFlag FINAL | lateFINAL // lateFINAL thrown in for good measure, by analogy to makeNotPrivate
207
+ }
217
208
// if we don't cloneInfo, method argument symbols are shared between trait and subclasses --> lambalift proxy crash
218
209
// TODO: use derive symbol variant?
219
210
val clonedInfo = accessor.info.cloneInfo(clonedAccessor)
@@ -226,13 +217,15 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
226
217
// a trait setter for an overridden val will receive a unit body in the tree transform
227
218
// (this is communicated using the DEFERRED flag)
228
219
if (nme.isTraitSetterName(accessor.name)) {
229
- val overridden = isOverriddenAccessor(accessor.getterIn(accessor.owner), clazz)
220
+ val getter = accessor.getterIn(accessor.owner)
221
+ val overridden = isOverriddenAccessor(getter, clazz)
230
222
// println(s"mixing in trait setter ${accessor.defString}: $overridden")
231
223
val clone = cloneAccessor()
232
224
233
225
clone filterAnnotations (ai => ! ai.matches(TraitSetterAnnotationClass )) // only supposed to be set in trait
234
226
235
227
if (overridden) clone setFlag OVERRIDDEN_TRAIT_SETTER
228
+ else if (getter.isEffectivelyFinal) clone setFlag FINAL // TODO: why isn't the FINAL_TRAIT_ACCESSOR carry-over from getter enough?
236
229
// println(s"mixed in trait setter ${clone.defString}")
237
230
238
231
List (clone)
@@ -250,6 +243,10 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
250
243
| (if (accessor.hasStableFlag) 0 else MUTABLE )
251
244
)
252
245
246
+ // TODO: filter getter's annotations to exclude those only meant for the field
247
+ // we must keep them around long enough to see them here, though, when we create the field
248
+ field setAnnotations (accessor.annotations filter AnnotationInfo .mkFilter(FieldTargetClass , defaultRetention = true ))
249
+
253
250
field setFlag newFlags
254
251
List (cloneAccessor(), field)
255
252
} else List (cloneAccessor())
@@ -276,9 +273,6 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
276
273
}
277
274
}
278
275
279
- private def markAccessorImplementedInSubclass (accessor : Symbol ): Symbol =
280
- accessor setFlag (DEFERRED | SYNTHESIZE_IMPL_IN_SUBCLASS ) resetFlag (FINAL | LOCAL ) // already made not-private
281
-
282
276
private def accessorImplementedInSubclass (accessor : Symbol ) =
283
277
accessor hasAllFlags (ACCESSOR | SYNTHESIZE_IMPL_IN_SUBCLASS )
284
278
0 commit comments