Skip to content

Commit b56ca2f

Browse files
committed
static forwarders & private[this] val in trait
object Properties extends PropertiesTrait trait PropertiesTrait { // the protected member is not emitted as a static member of -- it works when dropping the access modifier // somehow, the module class member is considered deferred in BForwardersGen protected val propFilename: String = / } // [log jvm] No forwarder for 'getter propFilename' from Properties to 'module class Properties': false || m.isDeferred == true || false || false // the following method is missing compared to scalac // public final class Properties { // public static String propFilename() { // return Properties$.MODULE$.propFilename(); // } trait Chars { private[this] val char2uescapeArray = Array[Char]('\', 'u', 0, 0, 0, 0) } object Chars extends Chars // +++ w/reflect/scala/reflect/internal/Chars$.class // - private final [C scala83014char2uescapeArray
1 parent ed7625f commit b56ca2f

File tree

4 files changed

+144
-96
lines changed

4 files changed

+144
-96
lines changed

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

+20-14
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
5252
val pre = site.thisType
5353
@tailrec def loop (bcs: List[Symbol]): Boolean = {
5454
// println(s"checking ${bcs.head} for member overriding $member (of ${member.owner})")
55-
bcs.head != member.owner && (matchingAccessor(pre, member, bcs.head) != NoSymbol || loop(bcs.tail))
55+
bcs.nonEmpty && bcs.head != member.owner && (matchingAccessor(pre, member, bcs.head) != NoSymbol || loop(bcs.tail))
5656
}
5757

58-
loop(site.info.baseClasses)
58+
member.exists && loop(site.info.baseClasses)
5959
}
6060

6161
class FieldMemoization(accessorOrField: Symbol, site: Symbol) {
@@ -120,21 +120,24 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
120120
// strict, memoized accessors will receive an implementation in first real class to extend this trait
121121
decls.foreach {
122122
case accessor if accessor hasFlag ACCESSOR =>
123+
// check flags before calling makeNotPrivate
124+
val memoizedGetter = !(accessor hasFlag (DEFERRED | LAZY)) && fieldMemoizationIn(accessor, clazz).needsField
125+
val finality = if (accessor hasFlag FINAL) FINAL_TRAIT_ACCESSOR else 0
126+
123127
// only affects private symbols, with a destructive update of their name, also sets flags
124128
// required for private vals in traits
125129
accessor.makeNotPrivate(clazz)
126130

127-
if (!(accessor hasFlag (DEFERRED | LAZY)) && fieldMemoizationIn(accessor, clazz).needsField) {
128-
// in a trait, a memoized accessor becomes deferred
129-
// (it'll receive an implementation in the first real class to extend this trait)
131+
// trait members cannot be final (but the synthesized ones should be)
132+
// LOCAL no longer applies (already made not-private)
133+
accessor resetFlag (FINAL | LOCAL)
130134

135+
// derive trait setter after calling makeNotPrivate (so that names are mangled consistently)
136+
if (memoizedGetter) {
137+
// a memoized accessor in a trait is made deferred now (mixins will deal with non-memoized getters like any other method)
131138
// 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)
139+
// (it'll receive an implementation in the first real class to extend this trait)
140+
accessor setFlag (finality | DEFERRED | SYNTHESIZE_IMPL_IN_SUBCLASS)
138141

139142
if ((accessor hasFlag STABLE) && accessor.isGetter) // TODO: isGetter is probably redundant?
140143
newSetters += newTraitSetter(accessor, clazz)
@@ -151,6 +154,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
151154
} else tp
152155

153156
// mix in fields & accessors for all mixed in traits
157+
154158
case tp@ClassInfoType(parents, oldDecls, clazz) if !clazz.isPackageClass =>
155159
val site = clazz.thisType
156160
// TODO (1): improve logic below, which is used to avoid mixing in anything that would result in an error in refchecks
@@ -265,6 +269,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
265269
mixedInFieldAndAccessors foreach newDecls.enter
266270
newDecls
267271
}
272+
// println(s"new decls: $newDecls")
268273

269274
if (newDecls eq oldDecls) tp
270275
else ClassInfoType(parents, newDecls, clazz)
@@ -285,12 +290,13 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
285290
def fieldsAndAccessors(templateSym: Symbol): List[ValOrDefDef] = {
286291
val clazz = templateSym.owner
287292
def fieldAccess(accessor: Symbol) = {
288-
val field = accessor.accessed
289-
assert(field.exists, s"No field for $accessor in $clazz")
293+
val fieldName = accessor.localName
294+
val field = clazz.info.decl(fieldName)
295+
assert(field.exists, s"Field '$fieldName' not found in ${clazz.info.decls}")
290296
Select(This(clazz), field)
291297
}
292298

293-
val accessorsAndFieldsNeedingTrees = afterOwnPhase{ clazz.info }.decls.toList.filter(_ hasFlag NEEDS_TREES)
299+
val accessorsAndFieldsNeedingTrees = clazz.info.decls.toList.filter(_ hasFlag NEEDS_TREES)
294300
accessorsAndFieldsNeedingTrees foreach (_ resetFlag NEEDS_TREES) // emitting the needed trees now
295301

296302
// println(s"accessorsAndFieldsNeedingTrees: $accessorsAndFieldsNeedingTrees")

src/compiler/scala/tools/nsc/typechecker/Namers.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ trait Namers extends MethodSynthesis {
120120
def deriveAccessors(vd: ValDef) = vd.mods.isLazy || (owner.isClass && deriveAccessorsInClass(vd))
121121

122122
private def deriveAccessorsInClass(vd: ValDef) =
123-
!vd.mods.isPrivateLocal && // note, private[this] lazy vals do get accessors -- see outer disjunction of deriveAccessors
123+
(!vd.mods.isPrivateLocal || owner.isTrait) && // note, private[this] lazy vals do get accessors -- see outer disjunction of deriveAccessors
124124
!(vd.name startsWith nme.OUTER) && // outer accessors are added later, in explicitouter
125125
!isEnumConstant(vd) // enums can only occur in classes, so only check here
126126

test/files/trait-defaults/fields.scala

+118-81
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,40 @@
1+
// test mixin of getters / setters, and implementing abstract
2+
// methods using @BeanProperty
3+
class C extends T with BeanF {
4+
def foo() {
5+
setF("doch!")
6+
setG(true)
7+
this.getF()
8+
}
9+
}
10+
11+
trait T {
12+
@scala.beans.BeanProperty var f = "nei"
13+
@scala.beans.BooleanBeanProperty var g = false
14+
}
15+
16+
trait BeanF {
17+
def getF(): String
18+
def setF(n: String): Unit
19+
20+
def isG(): Boolean
21+
def setG(nb: Boolean): Unit
22+
}
23+
24+
/*
25+
@scala.beans.BeanProperty private[this] var f: String = "nei";
26+
<accessor> def f: String = T.this.f;
27+
<accessor> def f_=(x$1: String): Unit = T.this.f = x$1;
28+
def setF(x$1: String): Unit = T.this.f = x$1;
29+
@scala.beans.BooleanBeanProperty private[this] var g: Boolean = false;
30+
<accessor> def g: Boolean = T.this.g;
31+
<accessor> def g_=(x$1: Boolean): Unit = T.this.g = x$1;
32+
def setG(x$1: Boolean): Unit = T.this.g = x$1;
33+
def getF(): String = T.this.f;
34+
def isG(): Boolean = T.this.g
35+
*/
36+
37+
138
trait T { final val bla: Int = 123 }
239
class C extends T // bla should be final in C
340

@@ -135,29 +172,29 @@ class SUB extends IterableSplitter
135172
// }
136173
// }
137174

138-
// class Nest { val x = println(1)}
175+
class Nest { val x = println(1)}
139176

140-
// package scala
141-
//
142-
// trait OneConcreteVal[T] {
143-
// @deprecatedOverriding val x = 1 // : T = ???
144-
// @volatile var vy = "a"
145-
// println(x)
146-
// def foo = x
147-
// }
148-
//
177+
package scala
149178

150-
// trait OneOtherConcreteVal[T] {
151-
// var y: T = ???
152-
// }
153-
//
154-
// class C extends OneConcreteVal[Int] with OneOtherConcreteVal[String]
179+
trait OneConcreteVal[T] {
180+
@deprecatedOverriding val x = 1 // : T = ???
181+
@volatile var vy = "a"
182+
println(x)
183+
def foo = x
184+
}
155185

156-
// object T extends App {
157-
// val c = new C
158-
// println(c.x)
159-
// println(c.y)
160-
// }
186+
187+
trait OneOtherConcreteVal[T] {
188+
var y: T = ???
189+
}
190+
191+
class C extends OneConcreteVal[Int] with OneOtherConcreteVal[String]
192+
193+
object T extends App {
194+
val c = new C
195+
println(c.x)
196+
println(c.y)
197+
}
161198
/*
162199
old decls for trait trait OneOtherConcreteVal: Scope{
163200
def y(): Object;
@@ -204,64 +241,64 @@ new decls for class C: Scope{
204241
*/
205242

206243

207-
// class Meh {
208-
// final val x = 1
209-
// def foo = x
210-
// }
211-
// class CE extends Empty
212-
//
213-
// trait T {
214-
// val abs: String
215-
// protected val protabs: String
216-
// val pub = "public"
217-
// protected val prot = "protected"
218-
// private val privvy = "private"
219-
// private[this] val privateThis = "private[this]"
220-
// // TODO:
221-
// // final val const = "const"
222-
//
223-
// trait Nested { println(abs + privateThis) }
224-
//
225-
// object NO {
226-
// println(abs)
227-
// println(pub)
228-
// println(prot)
229-
// println(protabs)
230-
// println(privvy)
231-
// println(privateThis)
232-
// }
233-
//
234-
// trait NT {
235-
// println(abs)
236-
// println(pub)
237-
// println(prot)
238-
// println(protabs)
239-
// println(privvy)
240-
// println(privateThis)
241-
// }
242-
//
243-
// class NC {
244-
// println(abs)
245-
// println(pub)
246-
// println(prot)
247-
// println(protabs)
248-
// println(privvy)
249-
// println(privateThis)
250-
// }
251-
// }
252-
//
253-
// class C extends AnyRef with T {
254-
// println("x")
255-
// val abs = "abstract"
256-
// println("y")
257-
// val protabs = "abstract protected"
258-
// final val const = "const"
259-
// println("z")
260-
// }
261-
//
262-
// object Test extends C {
263-
// def main(args: Array[String]): Unit = {
264-
// NO
265-
// new NT{}
266-
// new NC
267-
// }}
244+
class Meh {
245+
final val x = 1
246+
def foo = x
247+
}
248+
class CE extends Empty
249+
250+
trait T {
251+
val abs: String
252+
protected val protabs: String
253+
val pub = "public"
254+
protected val prot = "protected"
255+
private val privvy = "private"
256+
private[this] val privateThis = "private[this]"
257+
// TODO:
258+
// final val const = "const"
259+
260+
trait Nested { println(abs + privateThis) }
261+
262+
object NO {
263+
println(abs)
264+
println(pub)
265+
println(prot)
266+
println(protabs)
267+
println(privvy)
268+
println(privateThis)
269+
}
270+
271+
trait NT {
272+
println(abs)
273+
println(pub)
274+
println(prot)
275+
println(protabs)
276+
println(privvy)
277+
println(privateThis)
278+
}
279+
280+
class NC {
281+
println(abs)
282+
println(pub)
283+
println(prot)
284+
println(protabs)
285+
println(privvy)
286+
println(privateThis)
287+
}
288+
}
289+
290+
class C extends AnyRef with T {
291+
println("x")
292+
val abs = "abstract"
293+
println("y")
294+
val protabs = "abstract protected"
295+
final val const = "const"
296+
println("z")
297+
}
298+
299+
object Test extends C {
300+
def main(args: Array[String]): Unit = {
301+
NO
302+
new NT{}
303+
new NC
304+
}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
trait Chars {
2+
private[this] val char2uescapeArray: String = ???
3+
}
4+
5+
object Chars extends Chars

0 commit comments

Comments
 (0)