Browse files

SI-6387 Clones accessor before name expansion

When a symbol's name is expanded due to a conflict during
composition (e.g. multiple traits with same-named members, but
which are not both visible at the language level in the concrete
class) the compiler renames some symbols with expanded names which
embed the full name of the declaring class to avoid clashes.

In the rare cases when the accessor overrides the member in base
class, such expansion either results in AbstractMethodError when
the base method is abstract, or, even worse, can change the
semantics of the program.

To avoid such issues, we clone the accessor symbol, clear its
ACCESSOR flag and enter the symbol with an unchanged name.
  • Loading branch information...
1 parent b7b4f87 commit 4e10b2c833fa846c68b81e94a08d867e7de656aa @vigdorchik vigdorchik committed with paulp Mar 17, 2013
Showing with 41 additions and 11 deletions.
  1. +24 −11 src/reflect/scala/reflect/internal/Symbols.scala
  2. +1 −0 test/files/run/t6387.check
  3. +16 −0 test/files/run/t6387.scala
View
35 src/reflect/scala/reflect/internal/Symbols.scala
@@ -2538,20 +2538,32 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** change name by appending $$<fully-qualified-name-of-class `base`>
- * Do the same for any accessed symbols or setters/getters
+ * Do the same for any accessed symbols or setters/getters.
+ * If the accessor to be renamed is overriding a base symbol, enter
+ * a cloned symbol with the original name but without ACCESSOR flag.
*/
override def expandName(base: Symbol) {
- if (!hasFlag(EXPANDEDNAME)) {
- setFlag(EXPANDEDNAME)
- if (hasAccessorFlag && !isDeferred) {
- accessed.expandName(base)
- }
- else if (hasGetter) {
- getter(owner).expandName(base)
- setter(owner).expandName(base)
- }
- name = nme.expandedName(name.toTermName, base)
+ def expand(sym: Symbol) {
+ if ((sym eq NoSymbol) || (sym hasFlag EXPANDEDNAME)) () // skip
+ else sym setFlag EXPANDEDNAME setName nme.expandedName(sym.name.toTermName, base)
+ }
+ def cloneAndExpand(accessor: Symbol) {
+ val clone = accessor.cloneSymbol(accessor.owner, (accessor.flags | ARTIFACT) & ~ACCESSOR)
+ expand(accessor)
+ log(s"Expanded overriding accessor to $accessor, but cloned $clone to preserve override")
+ accessor.owner.info.decls enter clone
+ }
+ def expandAccessor(accessor: Symbol) {
+ if (accessor.isOverridingSymbol) cloneAndExpand(accessor) else expand(accessor)
+ }
+ if (hasAccessorFlag && !isDeferred) {
+ expand(accessed)
+ }
+ else if (hasGetter) {
+ expandAccessor(getter(owner))
+ expandAccessor(setter(owner))
}
+ expand(this)
}
protected def doCookJavaRawInfo() {
@@ -3223,6 +3235,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def companionModule = NoSymbol
override def companionSymbol = NoSymbol
override def isSubClass(that: Symbol) = false
+ override def isOverridingSymbol = false
override def filter(cond: Symbol => Boolean) = this
override def defString: String = toString
override def locationString: String = ""
View
1 test/files/run/t6387.check
@@ -0,0 +1 @@
+1000
View
16 test/files/run/t6387.scala
@@ -0,0 +1,16 @@
+trait A {
+ def foo: Long
+}
+
+object Test {
+ def a(): A = new A {
+ var foo: Long = 1000L
+
+ val test = () => {
+ foo = 28
+ }
+ }
+ def main(args: Array[String]) {
+ println(a().foo)
+ }
+}

0 comments on commit 4e10b2c

Please sign in to comment.