From b00a3e50da66086ef0f1a4c214866a591089b934 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Wed, 23 Nov 2016 15:18:55 +1000 Subject: 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 (): a = { a.super.(); () }; private[this] val x: Int = 42; def x: Int = a.this.x }; new a() } { class a extends scala.AnyRef { def () = { super.(); () }; val x = 42; // oops, the name is "x" rather than "x " and we've missing `private[this]`! 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. --- src/reflect/scala/reflect/internal/TreeInfo.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 61937958dd..1aef30819a 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -480,7 +480,8 @@ abstract class TreeInfo { } map { dd => val DefDef(dmods, dname, _, _, _, drhs) = dd // get access flags from DefDef - val vdMods = (vmods &~ Flags.AccessFlags) | (dmods & Flags.AccessFlags).flags + val defDefMask = Flags.AccessFlags | OVERRIDE | IMPLICIT | DEFERRED + val vdMods = (vmods &~ defDefMask) | (dmods & defDefMask).flags // for most cases lazy body should be taken from accessor DefDef val vdRhs = if (vmods.isLazy) lazyValDefRhs(drhs) else vrhs copyValDef(vd)(mods = vdMods, name = dname, rhs = vdRhs) -- cgit v1.2.3