Skip to content

Commit

Permalink
static forwarders & private[this] val in trait
Browse files Browse the repository at this point in the history
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
  • Loading branch information
adriaanm committed Oct 11, 2015
1 parent ed7625f commit b56ca2f
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 96 deletions.
34 changes: 20 additions & 14 deletions src/compiler/scala/tools/nsc/transform/Fields.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
val pre = site.thisType
@tailrec def loop (bcs: List[Symbol]): Boolean = {
// println(s"checking ${bcs.head} for member overriding $member (of ${member.owner})")
bcs.head != member.owner && (matchingAccessor(pre, member, bcs.head) != NoSymbol || loop(bcs.tail))
bcs.nonEmpty && bcs.head != member.owner && (matchingAccessor(pre, member, bcs.head) != NoSymbol || loop(bcs.tail))
}

loop(site.info.baseClasses)
member.exists && loop(site.info.baseClasses)
}

class FieldMemoization(accessorOrField: Symbol, site: Symbol) {
Expand Down Expand Up @@ -120,21 +120,24 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
// strict, memoized accessors will receive an implementation in first real class to extend this trait
decls.foreach {
case accessor if accessor hasFlag ACCESSOR =>
// check flags before calling makeNotPrivate
val memoizedGetter = !(accessor hasFlag (DEFERRED | LAZY)) && fieldMemoizationIn(accessor, clazz).needsField
val finality = if (accessor hasFlag FINAL) FINAL_TRAIT_ACCESSOR else 0

// only affects private symbols, with a destructive update of their name, also sets flags
// required for private vals in traits
accessor.makeNotPrivate(clazz)

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

// derive trait setter after calling makeNotPrivate (so that names are mangled consistently)
if (memoizedGetter) {
// a memoized accessor in a trait is made deferred now (mixins will deal with non-memoized getters like any other method)
// can't mark getter as FINAL in trait, but remember for when we synthetisize the impl in the subclass to make it FINAL
val finality = if (accessor hasFlag FINAL) FINAL_TRAIT_ACCESSOR else 0
accessor setFlag (finality | lateFINAL | DEFERRED | SYNTHESIZE_IMPL_IN_SUBCLASS)

// trait members cannot be final (but the synthesized ones should be)
// LOCAL no longer applies (already made not-private)
accessor resetFlag (FINAL | LOCAL)
// (it'll receive an implementation in the first real class to extend this trait)
accessor setFlag (finality | DEFERRED | SYNTHESIZE_IMPL_IN_SUBCLASS)

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

// mix in fields & accessors for all mixed in traits

case tp@ClassInfoType(parents, oldDecls, clazz) if !clazz.isPackageClass =>
val site = clazz.thisType
// TODO (1): improve logic below, which is used to avoid mixing in anything that would result in an error in refchecks
Expand Down Expand Up @@ -265,6 +269,7 @@ abstract class Fields extends InfoTransform with ast.TreeDSL with TypingTransfor
mixedInFieldAndAccessors foreach newDecls.enter
newDecls
}
// println(s"new decls: $newDecls")

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

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

// println(s"accessorsAndFieldsNeedingTrees: $accessorsAndFieldsNeedingTrees")
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/scala/tools/nsc/typechecker/Namers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ trait Namers extends MethodSynthesis {
def deriveAccessors(vd: ValDef) = vd.mods.isLazy || (owner.isClass && deriveAccessorsInClass(vd))

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

Expand Down
199 changes: 118 additions & 81 deletions test/files/trait-defaults/fields.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,40 @@
// test mixin of getters / setters, and implementing abstract
// methods using @BeanProperty
class C extends T with BeanF {
def foo() {
setF("doch!")
setG(true)
this.getF()
}
}

trait T {
@scala.beans.BeanProperty var f = "nei"
@scala.beans.BooleanBeanProperty var g = false
}

trait BeanF {
def getF(): String
def setF(n: String): Unit

def isG(): Boolean
def setG(nb: Boolean): Unit
}

/*
@scala.beans.BeanProperty private[this] var f: String = "nei";
<accessor> def f: String = T.this.f;
<accessor> def f_=(x$1: String): Unit = T.this.f = x$1;
def setF(x$1: String): Unit = T.this.f = x$1;
@scala.beans.BooleanBeanProperty private[this] var g: Boolean = false;
<accessor> def g: Boolean = T.this.g;
<accessor> def g_=(x$1: Boolean): Unit = T.this.g = x$1;
def setG(x$1: Boolean): Unit = T.this.g = x$1;
def getF(): String = T.this.f;
def isG(): Boolean = T.this.g
*/


trait T { final val bla: Int = 123 }
class C extends T // bla should be final in C

Expand Down Expand Up @@ -135,29 +172,29 @@ class SUB extends IterableSplitter
// }
// }

// class Nest { val x = println(1)}
class Nest { val x = println(1)}

// package scala
//
// trait OneConcreteVal[T] {
// @deprecatedOverriding val x = 1 // : T = ???
// @volatile var vy = "a"
// println(x)
// def foo = x
// }
//
package scala

// trait OneOtherConcreteVal[T] {
// var y: T = ???
// }
//
// class C extends OneConcreteVal[Int] with OneOtherConcreteVal[String]
trait OneConcreteVal[T] {
@deprecatedOverriding val x = 1 // : T = ???
@volatile var vy = "a"
println(x)
def foo = x
}

// object T extends App {
// val c = new C
// println(c.x)
// println(c.y)
// }

trait OneOtherConcreteVal[T] {
var y: T = ???
}

class C extends OneConcreteVal[Int] with OneOtherConcreteVal[String]

object T extends App {
val c = new C
println(c.x)
println(c.y)
}
/*
old decls for trait trait OneOtherConcreteVal: Scope{
def y(): Object;
Expand Down Expand Up @@ -204,64 +241,64 @@ new decls for class C: Scope{
*/


// class Meh {
// final val x = 1
// def foo = x
// }
// class CE extends Empty
//
// trait T {
// val abs: String
// protected val protabs: String
// val pub = "public"
// protected val prot = "protected"
// private val privvy = "private"
// private[this] val privateThis = "private[this]"
// // TODO:
// // final val const = "const"
//
// trait Nested { println(abs + privateThis) }
//
// object NO {
// println(abs)
// println(pub)
// println(prot)
// println(protabs)
// println(privvy)
// println(privateThis)
// }
//
// trait NT {
// println(abs)
// println(pub)
// println(prot)
// println(protabs)
// println(privvy)
// println(privateThis)
// }
//
// class NC {
// println(abs)
// println(pub)
// println(prot)
// println(protabs)
// println(privvy)
// println(privateThis)
// }
// }
//
// class C extends AnyRef with T {
// println("x")
// val abs = "abstract"
// println("y")
// val protabs = "abstract protected"
// final val const = "const"
// println("z")
// }
//
// object Test extends C {
// def main(args: Array[String]): Unit = {
// NO
// new NT{}
// new NC
// }}
class Meh {
final val x = 1
def foo = x
}
class CE extends Empty

trait T {
val abs: String
protected val protabs: String
val pub = "public"
protected val prot = "protected"
private val privvy = "private"
private[this] val privateThis = "private[this]"
// TODO:
// final val const = "const"

trait Nested { println(abs + privateThis) }

object NO {
println(abs)
println(pub)
println(prot)
println(protabs)
println(privvy)
println(privateThis)
}

trait NT {
println(abs)
println(pub)
println(prot)
println(protabs)
println(privvy)
println(privateThis)
}

class NC {
println(abs)
println(pub)
println(prot)
println(protabs)
println(privvy)
println(privateThis)
}
}

class C extends AnyRef with T {
println("x")
val abs = "abstract"
println("y")
val protabs = "abstract protected"
final val const = "const"
println("z")
}

object Test extends C {
def main(args: Array[String]): Unit = {
NO
new NT{}
new NC
}}
5 changes: 5 additions & 0 deletions test/files/trait-defaults/private_this.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
trait Chars {
private[this] val char2uescapeArray: String = ???
}

object Chars extends Chars

0 comments on commit b56ca2f

Please sign in to comment.