diff options
author | Lukas Rytz <lukas.rytz@epfl.ch> | 2013-02-08 00:05:55 +0100 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@epfl.ch> | 2013-02-08 09:33:16 +0100 |
commit | 5258b63740c9fb1be3c531e1dc1399fb0dc55569 (patch) | |
tree | 81c7aa0096e14512805187b319c07f6d5866d5f4 | |
parent | 0dd02d92a363ee13b13eb4536c938d24bb5dd98d (diff) | |
download | scala-5258b63740c9fb1be3c531e1dc1399fb0dc55569.tar.gz scala-5258b63740c9fb1be3c531e1dc1399fb0dc55569.tar.bz2 scala-5258b63740c9fb1be3c531e1dc1399fb0dc55569.zip |
SI-7096 SubstSymMap copies trees before modifying their symbols
I removed some strange code in a06d31f6a2 and replaced it by something
incorrect: SubstSymMap should never have side-effects: otherwise,
calling 'tpe1 <: tpe2' for instance would modify the symbols in
annotations of tpe2.
SubstSymMap now always creates new trees before changing them.
-rw-r--r-- | src/reflect/scala/reflect/internal/Types.scala | 42 | ||||
-rw-r--r-- | test/files/run/t7096.check | 2 | ||||
-rw-r--r-- | test/files/run/t7096.scala | 36 |
3 files changed, 67 insertions, 13 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala index 0dd98fb6ae..b06ab6c929 100644 --- a/src/reflect/scala/reflect/internal/Types.scala +++ b/src/reflect/scala/reflect/internal/Types.scala @@ -4698,23 +4698,39 @@ trait Types extends api.Types { self: SymbolTable => } } - override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { - object trans extends TypeMapTransformer { + object mapTreeSymbols extends TypeMapTransformer { + val strictCopy = newStrictTreeCopier - def termMapsTo(sym: Symbol) = from indexOf sym match { - case -1 => None - case idx => Some(to(idx)) - } + def termMapsTo(sym: Symbol) = from indexOf sym match { + case -1 => None + case idx => Some(to(idx)) + } - override def transform(tree: Tree) = { - termMapsTo(tree.symbol) match { - case Some(tosym) => tree.symbol = tosym - case None => () - } - super.transform(tree) + // if tree.symbol is mapped to another symbol, passes the new symbol into the + // constructor `trans` and sets the symbol and the type on the resulting tree. + def transformIfMapped(tree: Tree)(trans: Symbol => Tree) = termMapsTo(tree.symbol) match { + case Some(toSym) => trans(toSym) setSymbol toSym setType tree.tpe + case None => tree + } + + // changes trees which refer to one of the mapped symbols. trees are copied before attributes are modified. + override def transform(tree: Tree) = { + // super.transform maps symbol references in the types of `tree`. it also copies trees where necessary. + super.transform(tree) match { + case id @ Ident(_) => + transformIfMapped(id)(toSym => + strictCopy.Ident(id, toSym.name)) + + case sel @ Select(qual, name) => + transformIfMapped(sel)(toSym => + strictCopy.Select(sel, qual, toSym.name)) + + case tree => tree } } - trans.transform(tree) + } + override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = { + mapTreeSymbols.transform(tree) } } diff --git a/test/files/run/t7096.check b/test/files/run/t7096.check new file mode 100644 index 0000000000..6f1cef6c43 --- /dev/null +++ b/test/files/run/t7096.check @@ -0,0 +1,2 @@ +testing symbol List(method foo, class Base, package ano, package <root>), param value x, xRefs List(x) +testing symbol List(method foo, class Sub, package ano, package <root>), param value x, xRefs List(x) diff --git a/test/files/run/t7096.scala b/test/files/run/t7096.scala new file mode 100644 index 0000000000..e9c0323c2e --- /dev/null +++ b/test/files/run/t7096.scala @@ -0,0 +1,36 @@ +import scala.tools.partest._ +import scala.tools.nsc._ + +object Test extends CompilerTest { + import global._ + import definitions._ + + override def code = """ +package ano + +class ann(x: Any) extends annotation.TypeConstraint + +abstract class Base { + def foo(x: String): String @ann(x.trim()) +} + +class Sub extends Base { + def foo(x: String): String @ann(x.trim()) = x +} + """ + + object syms extends SymsInPackage("ano") + import syms._ + + def check(source: String, unit: global.CompilationUnit) { + afterTyper { + terms.filter(_.name.toString == "foo").foreach(sym => { + val xParam = sym.tpe.paramss.flatten.head + val annot = sym.tpe.finalResultType.annotations.head + val xRefs = annot.args.head.filter(t => t.symbol == xParam) + println(s"testing symbol ${sym.ownerChain}, param $xParam, xRefs $xRefs") + assert(xRefs.length == 1, xRefs) + }) + } + } +} |