summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-11-23 15:18:55 +1000
committerJason Zaugg <jzaugg@gmail.com>2016-11-28 13:46:22 +1000
commitb00a3e50da66086ef0f1a4c214866a591089b934 (patch)
tree544cdd5ff1e6bffc7165b1a9739bbc9b7d3a493a /test
parent9c5d3f81a667917b6a3aed5098182623c417c137 (diff)
downloadscala-b00a3e50da66086ef0f1a4c214866a591089b934.tar.gz
scala-b00a3e50da66086ef0f1a4c214866a591089b934.tar.bz2
scala-b00a3e50da66086ef0f1a4c214866a591089b934.zip
SI-10009 Fields survive untypecheck/retypecheck
Some places in the compiler, and many places in macros, use `untypecheck` (aka `resetAttrs`) to strip types and local symbols from a tree before retypechecking it under some different context. The refactoring of the desugaring of vals and vars in Scala 2.12.0 broke an assumption in this facility. When a ValDef must be split into multiple members (e.g. a field and a getter, or a perhaps also a setter), the ValDef that was parsed assumes the role of the `field`, and the trees for other members are stached by `Namer` to the `synthetics` map of the compilation unit, in order to spliced into the right statement list by typechecking. See `enterGetterSetter` for more details. However, the parsed ValDef is now used verbatim, carrying the meaning (ie, the symbol) of the `private[this]` field. This tree now had an inconsistency between the flags in `tree.mods.flags` and `tree.symbol.flags`. `tree.name` also differed from `tree.symbol.name` (the latter was renamed to be a local name, ie one with a trailing space.) When `ResetAttrs` stripped off the symbol and we retypechecked, we'd end up with two symbols in scope with the same name. In the first from the `run` test: ``` ================================================================================ { class a extends scala.AnyRef { def <init>(): a = { a.super.<init>(); () }; private[this] val x: Int = 42; <stable> <accessor> def x: Int = a.this.x }; new a() } { class a extends scala.AnyRef { def <init>() = { super.<init>(); () }; val x = 42; // oops, the name is "x" rather than "x " and we've missing `private[this]`! <stable> <accessor> def x: Int = a.this.x }; new a() } scala.tools.reflect.ToolBoxError: reflective typecheck has failed: x is already defined as value x ``` This commit uses the flags and name of the symbol in `typedValDef`. I've also had to modify the internals of `CodePrinter` to use the implicit, override, and deferred flags from the modifiers of an accessor when recovering pre-typer tree for a ValDef.
Diffstat (limited to 'test')
-rw-r--r--test/files/pos/t10009.scala6
-rw-r--r--test/files/run/t10009.scala28
2 files changed, 34 insertions, 0 deletions
diff --git a/test/files/pos/t10009.scala b/test/files/pos/t10009.scala
new file mode 100644
index 0000000000..7cd96f0f3d
--- /dev/null
+++ b/test/files/pos/t10009.scala
@@ -0,0 +1,6 @@
+class C {
+ def c(a: Any, b: Any*) = a
+}
+object Test {
+ new C().c(b = new { val x = 42 }, a = 0)
+}
diff --git a/test/files/run/t10009.scala b/test/files/run/t10009.scala
new file mode 100644
index 0000000000..2a318752f1
--- /dev/null
+++ b/test/files/run/t10009.scala
@@ -0,0 +1,28 @@
+import scala.reflect.runtime.currentMirror
+import scala.reflect.runtime.universe._
+import scala.tools.reflect.ToolBox
+
+object Test {
+ def test(code: String, log: Boolean = false) {
+ val tb = currentMirror.mkToolBox()
+ val tree = tb.parse(code)
+ val typed = tb.typecheck(tree)
+ if (log) {
+ println("=" * 80)
+ println(typed)
+ }
+ val untyped = tb.untypecheck(typed)
+ if (log) println(untyped)
+ val retyped = tb.typecheck(untyped)
+ if (log) println(retyped)
+ }
+ def main(args: Array[String]): Unit = {
+ test("{ class a { val x = 42 }; new a }") // failed
+ test("{ trait a { val x = 42 }; new a {} }") // worked
+ test("{ abstract class a { val x: Int } }") // worked
+ test("{ abstract class a { val x: Int }; new a { val x = 42 } }") // failed
+ test("{ class a { private val x = 42 }; new a }") // failed
+ test("{ class a { protected val x = 42 }; new a { x } }") // failed
+ test("{ class a { protected[a] val x = 42 }; new a }") // failed
+ }
+} \ No newline at end of file