From d36989d1ec1de3b5b75de41415c852b087974bc7 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Fri, 27 Sep 2013 17:22:03 +0200 Subject: advanced fresh name reification During parsing some names are generated artificially using freshTermName & freshTypeName (e.g. `x$1`). Such names should be reified in a different way because they are assumed to be always fresh and non-overlapping with the environment. So `x$1` should reify down to equivalent of `freshTermName("x$")` rather than `TermName("x$1")`. But this is not enough. One name can be used more than once in a tree. E.g. `q"_ + 1"` desugars into `q"x$1 => x$1 + 1"`. So we need to ensure that every place where `x$1` is used gets the same fresh name. Hence the need for `withFreshTermName` that lets q"_ + 1" quasiquote desugare into equivalent of `withFreshTermName("x$") { freshx => q"$freshx => $freshx + 1" }`. For pattern quasiquotes it's a bit different. Due to the fact that end-result must be a pattern we need to represent fresh names as patterns too. A natural way to express that something is fresh is to represent it as a free variable (e.g. any name will do in that place). But due to possible use of the same name in multiple places we need to make sure that all such places have the same values by adding a sequence of guards to the pattern. Previously such names were reified naively and it could have caused name collision problems and inability to properly much on trees that contain such names. --- src/reflect/scala/reflect/api/BuildUtils.scala | 4 ++++ src/reflect/scala/reflect/internal/BuildUtils.scala | 13 +++++++++++++ src/reflect/scala/reflect/internal/StdNames.scala | 1 + 3 files changed, 18 insertions(+) (limited to 'src/reflect') diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala index df126bed45..0dad78112b 100644 --- a/src/reflect/scala/reflect/api/BuildUtils.scala +++ b/src/reflect/scala/reflect/api/BuildUtils.scala @@ -90,6 +90,10 @@ private[reflect] trait BuildUtils { self: Universe => def RefTree(qual: Tree, sym: Symbol): Tree + def withFreshTermName[T](prefix: String)(f: TermName => T): T + + def withFreshTypeName[T](prefix: String)(f: TypeName => T): T + val ScalaDot: ScalaDotExtractor trait ScalaDotExtractor { diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala index a09715ec7c..3e04811f4d 100644 --- a/src/reflect/scala/reflect/internal/BuildUtils.scala +++ b/src/reflect/scala/reflect/internal/BuildUtils.scala @@ -131,6 +131,19 @@ 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(TermName(freshName(prefix))) + + def withFreshTypeName[T](prefix: String)(f: TypeName => T): T = f(TypeName(freshName(prefix))) + + object freshName { + private val counters = collection.mutable.HashMap[String, Int]() withDefaultValue 0 + def apply(prefix: String): String = { + val safePrefix = prefix.replaceAll("""[<>]""", """\$""") + counters(safePrefix) += 1 + safePrefix + counters(safePrefix) + } + } + object FlagsRepr extends FlagsReprExtractor { def apply(bits: Long): FlagSet = bits def unapply(flags: Long): Some[Long] = Some(flags) diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala index 7cfe194fd1..5cc3f911a4 100644 --- a/src/reflect/scala/reflect/internal/StdNames.scala +++ b/src/reflect/scala/reflect/internal/StdNames.scala @@ -320,6 +320,7 @@ trait StdNames { val REIFY_FREE_VALUE_SUFFIX: NameType = "$value" val REIFY_SYMDEF_PREFIX: NameType = "symdef$" val QUASIQUOTE_PREFIX: String = "qq$" + val QUASIQUOTE_NAME_PREFIX: String = "nn$" val QUASIQUOTE_FILE: String = "" val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$" val QUASIQUOTE_CASE: NameType = "$quasiquote$case$" -- cgit v1.2.3