diff options
-rw-r--r-- | src/compiler/scala/reflect/internal/Symbols.scala | 1 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala | 32 | ||||
-rw-r--r-- | test/files/neg/t4762.check | 7 | ||||
-rw-r--r-- | test/files/neg/t4762.flags | 1 | ||||
-rw-r--r-- | test/files/neg/t4762.scala | 51 |
5 files changed, 86 insertions, 6 deletions
diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index bd9164cfc4..00e9200076 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -1923,6 +1923,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => else if (owner.isRefinementClass) ExplicitFlags & ~OVERRIDE else ExplicitFlags + def accessString = hasFlagsToString(PRIVATE | PROTECTED | LOCAL) def defaultFlagString = hasFlagsToString(defaultFlagMask) private def defStringCompose(infoString: String) = compose( defaultFlagString, diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala index 0beb01cc71..8e00c850ef 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala @@ -191,13 +191,33 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT mayNeedProtectedAccessor(sel, args, false) case sel @ Select(qual @ This(_), name) => - // direct calls to aliases of param accessors to the superclass in order to avoid - // duplicating fields. - if (sym.isParamAccessor && sym.alias != NoSymbol) { + // warn if they are selecting a private[this] member which + // also exists in a superclass, because they may be surprised + // to find out that a constructor parameter will shadow a + // field. See SI-4762. + if (settings.lint.value) { + if (sym.isPrivateLocal && sym.paramss.isEmpty) { + qual.symbol.ancestors foreach { parent => + parent.info.decls filterNot (x => x.isPrivate || x.hasLocalFlag) foreach { m2 => + if (sym.name == m2.name && m2.isGetter && m2.accessed.isMutable) { + unit.warning(sel.pos, + sym.accessString + " " + sym.fullLocationString + " shadows mutable " + m2.name + + " inherited from " + m2.owner + ". Changes to " + m2.name + " will not be visible within " + + sym.owner + " - you may want to give them distinct names." + ) + } + } + } + } + } + + // direct calls to aliases of param accessors to the superclass in order to avoid + // duplicating fields. + if (sym.isParamAccessor && sym.alias != NoSymbol) { val result = localTyper.typed { - Select( - Super(qual, tpnme.EMPTY/*qual.symbol.info.parents.head.symbol.name*/) setPos qual.pos, - sym.alias) setPos tree.pos + Select( + Super(qual, tpnme.EMPTY/*qual.symbol.info.parents.head.symbol.name*/) setPos qual.pos, + sym.alias) setPos tree.pos } debuglog("alias replacement: " + tree + " ==> " + result);//debug localTyper.typed(gen.maybeMkAsInstanceOf(transformSuperSelect(result), sym.tpe, sym.alias.tpe, true)) diff --git a/test/files/neg/t4762.check b/test/files/neg/t4762.check new file mode 100644 index 0000000000..5e67f2022a --- /dev/null +++ b/test/files/neg/t4762.check @@ -0,0 +1,7 @@ +t4762.scala:15: error: private[this] value x in class B shadows mutable x inherited from class A. Changes to x will not be visible within class B - you may want to give them distinct names. + /* (99,99) */ (this.x, this.y), + ^ +t4762.scala:48: error: private[this] value x in class Derived shadows mutable x inherited from class Base. Changes to x will not be visible within class Derived - you may want to give them distinct names. + class Derived( x : Int ) extends Base( x ) { override def toString = x.toString } + ^ +two errors found diff --git a/test/files/neg/t4762.flags b/test/files/neg/t4762.flags new file mode 100644 index 0000000000..e93641e931 --- /dev/null +++ b/test/files/neg/t4762.flags @@ -0,0 +1 @@ +-Xlint -Xfatal-warnings
\ No newline at end of file diff --git a/test/files/neg/t4762.scala b/test/files/neg/t4762.scala new file mode 100644 index 0000000000..8757f4a103 --- /dev/null +++ b/test/files/neg/t4762.scala @@ -0,0 +1,51 @@ +// https://issues.scala-lang.org/browse/SI-4762 + +// In A, x and y are -1. +class A(var x: Int) { + val y: Int = -1 +} + +// In B, x and y are 99 and private[this], implicitly so +// in the case of x. +class B(x: Int) extends A(-1) { + private[this] def y: Int = 99 + + // Three distinct results. + def f = List( + /* (99,99) */ (this.x, this.y), + /* (-1,99) */ ((this: B).x, (this: B).y), + /* (-1,-1) */ ((this: A).x, (this: A).y) + ) + + // The 99s tell us we are reading the private[this] + // data of a different instance. + def g(b: B) = List( + /* (-1,99) */ (b.x, b.y), + /* (-1,99) */ ((b: B).x, (b: B).y), + /* (-1,-1) */ ((b: A).x, (b: A).y) + ) +} + +object Test { + def f(x: A) = /* -2 */ x.x + x.y + def g1(x: B) = /* -2 */ (x: A).x + (x: A).y + def g2(x: B) = (x: B).x + (x: B).y + // java.lang.IllegalAccessError: tried to access method B.y()I from class Test$ + + def main(args: Array[String]): Unit = { + val b = new B(99) + b.f foreach println + b.g(new B(99)) foreach println + + println(f(b)) + println(g1(b)) + println(g2(b)) + } +} + +class bug4762 { + class Base( var x : Int ) { def increment() { x = x + 1 } } + class Derived( x : Int ) extends Base( x ) { override def toString = x.toString } + + val derived = new Derived( 1 ) +} |