diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-01-03 02:32:45 -0800 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-01-03 02:32:45 -0800 |
commit | 64e214348a2d41cb278062fb471084cc191d9a9d (patch) | |
tree | c5fd5341e2cec33c55df6101a788f3df7f12900a | |
parent | 718b26baa6113bef9ce3ebc7c439e099615db78d (diff) | |
parent | 71a2102a2df3721e0b8d0a9a5e87d01eb849dadd (diff) | |
download | scala-64e214348a2d41cb278062fb471084cc191d9a9d.tar.gz scala-64e214348a2d41cb278062fb471084cc191d9a9d.tar.bz2 scala-64e214348a2d41cb278062fb471084cc191d9a9d.zip |
Merge pull request #3245 from densh/si/8047
SI-8047 change fresh name encoding in quasiquotes to avoid symbol owner corruption
-rw-r--r-- | src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala | 29 | ||||
-rw-r--r-- | src/reflect/scala/reflect/api/BuildUtils.scala | 4 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/BuildUtils.scala | 4 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/StdNames.scala | 2 | ||||
-rw-r--r-- | test/files/jvm/t5471.check (renamed from test/files/jvm/si5471.check) | 0 | ||||
-rw-r--r-- | test/files/jvm/t5471.scala (renamed from test/files/jvm/si5471.scala) | 0 | ||||
-rw-r--r-- | test/files/run/reify_renamed_term_t5841.check (renamed from test/files/run/reify_renamed_term_si5841.check) | 0 | ||||
-rw-r--r-- | test/files/run/reify_renamed_term_t5841.scala (renamed from test/files/run/reify_renamed_term_si5841.scala) | 0 | ||||
-rw-r--r-- | test/files/run/t4750.check (renamed from test/files/run/si4750.check) | 0 | ||||
-rw-r--r-- | test/files/run/t4750.scala (renamed from test/files/run/si4750.scala) | 0 | ||||
-rw-r--r-- | test/files/run/t5045.check (renamed from test/files/run/si5045.check) | 0 | ||||
-rw-r--r-- | test/files/run/t5045.scala (renamed from test/files/run/si5045.scala) | 0 | ||||
-rw-r--r-- | test/files/run/t8047.check | 7 | ||||
-rw-r--r-- | test/files/run/t8047.scala | 31 | ||||
-rw-r--r-- | test/files/scalacheck/t4147.scala (renamed from test/files/scalacheck/si4147.scala) | 0 |
15 files changed, 64 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala index 6d7aafe266..87ab52414c 100644 --- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala +++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala @@ -32,8 +32,16 @@ trait Reifiers { self: Quasiquotes => var nameMap = collection.mutable.HashMap.empty[Name, Set[TermName]].withDefault { _ => Set() } /** Wraps expressions into: - * a sequence of nested withFreshTermName/withFreshTypeName calls which are required - * to force regeneration of randomly generated names on every evaluation of quasiquote. + * a block which starts with a sequence of vals that correspond + * to fresh names that has to be created at evaluation of the quasiquote + * and ends with reified tree: + * + * { + * val name$1: universe.TermName = universe.build.freshTermName(prefix1) + * ... + * val name$N: universe.TermName = universe.build.freshTermName(prefixN) + * tree + * } * * Wraps patterns into: * a call into anonymous class' unapply method required by unapply macro expansion: @@ -50,15 +58,18 @@ trait Reifiers { self: Quasiquotes => */ def wrap(tree: Tree) = if (isReifyingExpressions) { - nameMap.foldLeft(tree) { - case (t, (origname, names)) => + val freshdefs = nameMap.iterator.map { + case (origname, names) => assert(names.size == 1) val FreshName(prefix) = origname - val ctor = TermName("withFresh" + (if (origname.isTermName) "TermName" else "TypeName")) - // q"$u.build.$ctor($prefix) { ${names.head} => $t }" - Apply(Apply(Select(Select(u, nme.build), ctor), List(Literal(Constant(prefix)))), - List(Function(List(ValDef(Modifiers(PARAM), names.head, TypeTree(), EmptyTree)), t))) - } + val nameTypeName = if (origname.isTermName) tpnme.TermName else tpnme.TypeName + val freshName = if (origname.isTermName) nme.freshTermName else nme.freshTypeName + // q"val ${names.head}: $u.$nameTypeName = $u.build.$freshName($prefix)" + ValDef(NoMods, names.head, Select(u, nameTypeName), + Apply(Select(Select(u, nme.build), freshName), Literal(Constant(prefix)) :: Nil)) + }.toList + // q"..$freshdefs; $tree" + SyntacticBlock(freshdefs :+ tree) } else { val freevars = holeMap.toList.map { case (name, _) => Ident(name) } val isVarPattern = tree match { case Bind(name, Ident(nme.WILDCARD)) => true case _ => false } diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index 9baf3ec179..6971175f88 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -90,9 +90,9 @@ private[reflect] trait BuildUtils { self: Universe => def RefTree(qual: Tree, sym: Symbol): Tree - def withFreshTermName[T](prefix: String)(f: TermName => T): T + def freshTermName(prefix: String): TermName - def withFreshTypeName[T](prefix: String)(f: TypeName => T): T + def freshTypeName(prefix: String): TypeName val ScalaDot: ScalaDotExtractor diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index 13c2268227..0a81bfa2a5 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -134,9 +134,9 @@ trait BuildUtils { self: SymbolTable => def RefTree(qual: Tree, sym: Symbol) = self.RefTree(qual, sym.name) setSymbol sym - def withFreshTermName[T](prefix: String)(f: TermName => T): T = f(freshTermName(prefix)) + def freshTermName(prefix: String): TermName = self.freshTermName(prefix) - def withFreshTypeName[T](prefix: String)(f: TypeName => T): T = f(freshTypeName(prefix)) + def freshTypeName(prefix: String): TypeName = self.freshTypeName(prefix) protected implicit def fresh: FreshNameCreator = self.currentFreshNameCreator diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 111adc1c28..ea6afa7349 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -674,6 +674,8 @@ trait StdNames { val find_ : NameType = "find" val flatMap: NameType = "flatMap" val foreach: NameType = "foreach" + val freshTermName: NameType = "freshTermName" + val freshTypeName: NameType = "freshTypeName" val get: NameType = "get" val hashCode_ : NameType = "hashCode" val hash_ : NameType = "hash" diff --git a/test/files/jvm/si5471.check b/test/files/jvm/t5471.check index bb101b641b..bb101b641b 100644 --- a/test/files/jvm/si5471.check +++ b/test/files/jvm/t5471.check diff --git a/test/files/jvm/si5471.scala b/test/files/jvm/t5471.scala index 2efd869b61..2efd869b61 100644 --- a/test/files/jvm/si5471.scala +++ b/test/files/jvm/t5471.scala diff --git a/test/files/run/reify_renamed_term_si5841.check b/test/files/run/reify_renamed_term_t5841.check index 6031277b76..6031277b76 100644 --- a/test/files/run/reify_renamed_term_si5841.check +++ b/test/files/run/reify_renamed_term_t5841.check diff --git a/test/files/run/reify_renamed_term_si5841.scala b/test/files/run/reify_renamed_term_t5841.scala index ef18d650bf..ef18d650bf 100644 --- a/test/files/run/reify_renamed_term_si5841.scala +++ b/test/files/run/reify_renamed_term_t5841.scala diff --git a/test/files/run/si4750.check b/test/files/run/t4750.check index bf55f70df3..bf55f70df3 100644 --- a/test/files/run/si4750.check +++ b/test/files/run/t4750.check diff --git a/test/files/run/si4750.scala b/test/files/run/t4750.scala index 96d2c4fec7..96d2c4fec7 100644 --- a/test/files/run/si4750.scala +++ b/test/files/run/t4750.scala diff --git a/test/files/run/si5045.check b/test/files/run/t5045.check index 7e9c1961b7..7e9c1961b7 100644 --- a/test/files/run/si5045.check +++ b/test/files/run/t5045.check diff --git a/test/files/run/si5045.scala b/test/files/run/t5045.scala index b0c3a4ddc4..b0c3a4ddc4 100644 --- a/test/files/run/si5045.scala +++ b/test/files/run/t5045.scala diff --git a/test/files/run/t8047.check b/test/files/run/t8047.check new file mode 100644 index 0000000000..a6b83a4a16 --- /dev/null +++ b/test/files/run/t8047.check @@ -0,0 +1,7 @@ +doWhile$1(){ + 1; + if (true) + doWhile$1() + else + () +} diff --git a/test/files/run/t8047.scala b/test/files/run/t8047.scala new file mode 100644 index 0000000000..f5660541e8 --- /dev/null +++ b/test/files/run/t8047.scala @@ -0,0 +1,31 @@ +object Test extends App { + import scala.reflect.runtime.universe._ + // + // x's owner is outer Test scope. Previosly the quasiquote expansion + // looked like: + // + // object Test { + // build.withFreshTermName("doWhile")(n => + // LabelDef(n, List(), + // Block( + // List({ val x = 1; x }), + // If(Literal(Constant(true)), Apply(Ident(n), List()), Literal(Constant(()))))) + // } + // + // Here the proper owner is anonymous function, not the Test. Hence + // symbol corruption. In new encoding this is represented as: + // + // object Test { + // { + // val n = build.freshTermName("doWhile") + // LabelDef(n, List(), + // Block( + // List({ val x = 1; x }), + // If(Literal(Constant(true)), Apply(Ident(n), List()), Literal(Constant(())))) + // } + // } + // + // Owner stays the same and life is good again. + // + println(q"do ${ val x = 1; x } while(true)") +} diff --git a/test/files/scalacheck/si4147.scala b/test/files/scalacheck/t4147.scala index 72f6e9afd5..72f6e9afd5 100644 --- a/test/files/scalacheck/si4147.scala +++ b/test/files/scalacheck/t4147.scala |