summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build/bnd/scala-compiler-doc.bnd6
-rw-r--r--src/build/bnd/scala-compiler-interactive.bnd6
-rw-r--r--src/build/maven/maven-deploy.xml23
-rw-r--r--src/build/maven/scala-compiler-doc-pom.xml69
-rw-r--r--src/build/maven/scala-compiler-interactive-pom.xml59
-rw-r--r--src/build/maven/scala-compiler-pom.xml17
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Errors.scala2
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Resolvers.scala20
-rw-r--r--src/compiler/scala/reflect/macros/compiler/Validators.scala16
-rw-r--r--src/compiler/scala/reflect/macros/contexts/Context.scala3
-rw-r--r--src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala2
-rw-r--r--src/compiler/scala/reflect/macros/util/Helpers.scala10
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeDSL.scala2
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala10
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala49
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala362
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala43
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala115
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala7
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/util/package.scala2
-rw-r--r--src/compiler/scala/tools/reflect/StdTags.scala2
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala33
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala8
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala1
-rw-r--r--src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala13
-rw-r--r--src/interactive/scala/tools/nsc/interactive/Global.scala8
-rw-r--r--src/interactive/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala10
-rw-r--r--src/library/scala/Predef.scala26
-rw-r--r--src/library/scala/collection/mutable/PriorityQueue.scala2
-rw-r--r--src/library/scala/concurrent/Future.scala28
-rw-r--r--src/library/scala/concurrent/duration/package.scala12
-rw-r--r--src/library/scala/concurrent/package.scala4
-rw-r--r--src/library/scala/util/Either.scala2
-rw-r--r--src/partest-extras/scala/tools/partest/Util.scala4
-rw-r--r--src/reflect/scala/reflect/api/BuildUtils.scala29
-rw-r--r--src/reflect/scala/reflect/api/Exprs.scala2
-rw-r--r--src/reflect/scala/reflect/api/Importers.scala2
-rw-r--r--src/reflect/scala/reflect/api/Mirrors.scala6
-rw-r--r--src/reflect/scala/reflect/api/Quasiquotes.scala1
-rw-r--r--src/reflect/scala/reflect/api/Universe.scala5
-rw-r--r--src/reflect/scala/reflect/internal/BuildUtils.scala303
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala56
-rw-r--r--src/reflect/scala/reflect/internal/Importers.scala14
-rw-r--r--src/reflect/scala/reflect/internal/StdAttachments.scala13
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala9
-rw-r--r--src/reflect/scala/reflect/internal/TreeGen.scala450
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala14
-rw-r--r--src/reflect/scala/reflect/internal/Trees.scala2
-rw-r--r--src/reflect/scala/reflect/macros/Aliases.scala4
-rw-r--r--src/reflect/scala/reflect/macros/Attachments.scala4
-rw-r--r--src/reflect/scala/reflect/macros/BlackboxContext.scala (renamed from src/reflect/scala/reflect/macros/Context.scala)36
-rw-r--r--src/reflect/scala/reflect/macros/BlackboxMacro.scala (renamed from src/reflect/scala/reflect/macros/Macro.scala)15
-rw-r--r--src/reflect/scala/reflect/macros/Enclosures.scala18
-rw-r--r--src/reflect/scala/reflect/macros/Evals.scala8
-rw-r--r--src/reflect/scala/reflect/macros/ExprUtils.scala4
-rw-r--r--src/reflect/scala/reflect/macros/FrontEnds.scala4
-rw-r--r--src/reflect/scala/reflect/macros/Infrastructure.scala4
-rw-r--r--src/reflect/scala/reflect/macros/Names.scala4
-rw-r--r--src/reflect/scala/reflect/macros/Parsers.scala4
-rw-r--r--src/reflect/scala/reflect/macros/Reifiers.scala4
-rw-r--r--src/reflect/scala/reflect/macros/Typers.scala27
-rw-r--r--src/reflect/scala/reflect/macros/WhiteboxContext.scala76
-rw-r--r--src/reflect/scala/reflect/macros/WhiteboxMacro.scala36
-rw-r--r--src/reflect/scala/reflect/macros/package.scala14
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala10
-rw-r--r--src/reflect/scala/reflect/runtime/package.scala2
-rw-r--r--src/repl/scala/tools/nsc/interpreter/IMain.scala64
-rw-r--r--src/repl/scala/tools/nsc/interpreter/Imports.scala12
71 files changed, 1487 insertions, 751 deletions
diff --git a/src/build/bnd/scala-compiler-doc.bnd b/src/build/bnd/scala-compiler-doc.bnd
new file mode 100644
index 0000000000..4910e5fcb0
--- /dev/null
+++ b/src/build/bnd/scala-compiler-doc.bnd
@@ -0,0 +1,6 @@
+Bundle-Name: Scala Documentation Generator
+Bundle-SymbolicName: org.scala-lang.modules.scala-compiler-doc_@SCALA_BINARY_VERSION@
+ver: @SCALA_COMPILER_DOC_VERSION@
+Bundle-Version: ${ver}
+Export-Package: *;version=${ver}
+Import-Package: *
diff --git a/src/build/bnd/scala-compiler-interactive.bnd b/src/build/bnd/scala-compiler-interactive.bnd
new file mode 100644
index 0000000000..34d2f2956d
--- /dev/null
+++ b/src/build/bnd/scala-compiler-interactive.bnd
@@ -0,0 +1,6 @@
+Bundle-Name: Scala Interactive Compiler
+Bundle-SymbolicName: org.scala-lang.modules.scala-compiler-interactive_@SCALA_BINARY_VERSION@
+ver: @SCALA_COMPILER_INTERACTIVE_VERSION@
+Bundle-Version: ${ver}
+Export-Package: *;version=${ver}
+Import-Package: *
diff --git a/src/build/maven/maven-deploy.xml b/src/build/maven/maven-deploy.xml
index 7cff0b457e..822cc1a25f 100644
--- a/src/build/maven/maven-deploy.xml
+++ b/src/build/maven/maven-deploy.xml
@@ -59,13 +59,18 @@
<copy file="${path}-pom.xml" tofile="${path}-pom-filtered.xml" overwrite="true">
<filterset>
- <filter token="VERSION" value="${maven.version.number}" />
- <filter token="SCALA_BINARY_VERSION" value="${scala.binary.version}" />
- <filter token="XML_VERSION" value="${scala-xml.version.number}" />
+ <filter token="VERSION" value="${maven.version.number}" />
+ <filter token="SCALA_BINARY_VERSION" value="${scala.binary.version}" />
+ <filter token="XML_VERSION" value="${scala-xml.version.number}" />
<filter token="PARSER_COMBINATORS_VERSION" value="${scala-parser-combinators.version.number}" />
- <filter token="RELEASE_REPOSITORY" value="${remote.release.repository}" />
- <filter token="SNAPSHOT_REPOSITORY" value="${remote.snapshot.repository}" />
- <filter token="JLINE_VERSION" value="${jline.version}" />
+ <filter token="RELEASE_REPOSITORY" value="${remote.release.repository}" />
+ <filter token="SNAPSHOT_REPOSITORY" value="${remote.snapshot.repository}" />
+ <filter token="JLINE_VERSION" value="${jline.version}" />
+
+ <!-- TODO modularize compiler.
+ <filter token="SCALA_COMPILER_DOC_VERSION" value="${scala-compiler-doc.version.number}" />
+ <filter token="SCALA_COMPILER_INTERACTIVE_VERSION" value="${scala-compiler-interactive.version.number}" />
+ -->
</filterset>
</copy>
<artifact:pom id="@{name}.pom" file="${path}-pom-filtered.xml" />
@@ -112,6 +117,12 @@
<deploy-one dir="@{dir}" name="scala-library" local="@{local}" signed="@{signed}"/>
<deploy-one dir="@{dir}" name="scala-reflect" local="@{local}" signed="@{signed}"/>
<deploy-one dir="@{dir}" name="scala-compiler" local="@{local}" signed="@{signed}"/>
+
+ <!-- TODO modularize compiler.
+ <deploy-one dir="@{dir}" name="scala-compiler-doc" local="@{local}" signed="@{signed}"/>
+ <deploy-one dir="@{dir}" name="scala-compiler-interactive" local="@{local}" signed="@{signed}"/>
+ -->
+
<deploy-one dir="@{dir}" name="scala-actors" local="@{local}" signed="@{signed}"/>
<deploy-one dir="@{dir}" name="scala-swing" local="@{local}" signed="@{signed}"/>
<deploy-one dir="@{dir}" name="scalap" local="@{local}" signed="@{signed}"/>
diff --git a/src/build/maven/scala-compiler-doc-pom.xml b/src/build/maven/scala-compiler-doc-pom.xml
new file mode 100644
index 0000000000..30161d2fea
--- /dev/null
+++ b/src/build/maven/scala-compiler-doc-pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.scala-lang.modules</groupId>
+ <artifactId>scala-compiler-doc_@SCALA_BINARY_VERSION@</artifactId>
+ <packaging>jar</packaging>
+ <version>@SCALA_COMPILER_DOC_VERSION@</version>
+ <name>Scala Documentation Generator</name>
+ <description>Documentation generator for the Scala Programming Language</description>
+ <url>http://www.scala-lang.org/</url>
+ <inceptionYear>2002</inceptionYear>
+ <organization>
+ <name>LAMP/EPFL</name>
+ <url>http://lamp.epfl.ch/</url>
+ </organization>
+ <licenses>
+ <license>
+ <name>BSD 3-Clause</name>
+ <url>http://www.scala-lang.org/license.html</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
+ </scm>
+ <issueManagement>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
+ </issueManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-compiler</artifactId>
+ <version>@VERSION@</version>
+ </dependency>
+ <dependency>
+ <groupId>org.scala-lang.modules</groupId>
+ <artifactId>scala-xml_@SCALA_BINARY_VERSION@</artifactId>
+ <version>@XML_VERSION@</version>
+ </dependency>
+ <dependency>
+ <groupId>org.scala-lang.modules</groupId>
+ <artifactId>scala-parser-combinators_@SCALA_BINARY_VERSION@</artifactId>
+ <version>@PARSER_COMBINATORS_VERSION@</version>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <repository>
+ <id>scala-tools.org</id>
+ <url>@RELEASE_REPOSITORY@</url>
+ </repository>
+ <snapshotRepository>
+ <id>scala-tools.org</id>
+ <url>@SNAPSHOT_REPOSITORY@</url>
+ <uniqueVersion>false</uniqueVersion>
+ </snapshotRepository>
+ </distributionManagement>
+ <developers>
+ <developer>
+ <id>lamp</id>
+ <name>EPFL LAMP</name>
+ </developer>
+ <developer>
+ <id>Typesafe</id>
+ <name>Typesafe, Inc.</name>
+ </developer>
+ </developers>
+</project>
diff --git a/src/build/maven/scala-compiler-interactive-pom.xml b/src/build/maven/scala-compiler-interactive-pom.xml
new file mode 100644
index 0000000000..d59f305a9f
--- /dev/null
+++ b/src/build/maven/scala-compiler-interactive-pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.scala-lang.modules</groupId>
+ <artifactId>scala-compiler-interactive_@SCALA_BINARY_VERSION@</artifactId>
+ <packaging>jar</packaging>
+ <version>@SCALA_COMPILER_INTERACTIVE_VERSION@</version>
+ <name>Scala Interactive Compiler</name>
+ <description>Interactive Compiler for the Scala Programming Language</description>
+ <url>http://www.scala-lang.org/</url>
+ <inceptionYear>2002</inceptionYear>
+ <organization>
+ <name>LAMP/EPFL</name>
+ <url>http://lamp.epfl.ch/</url>
+ </organization>
+ <licenses>
+ <license>
+ <name>BSD 3-Clause</name>
+ <url>http://www.scala-lang.org/license.html</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <connection>scm:git:git://github.com/scala/scala.git</connection>
+ <url>https://github.com/scala/scala.git</url>
+ </scm>
+ <issueManagement>
+ <system>JIRA</system>
+ <url>https://issues.scala-lang.org/</url>
+ </issueManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-compiler</artifactId>
+ <version>@VERSION@</version>
+ </dependency>
+ </dependencies>
+ <distributionManagement>
+ <repository>
+ <id>scala-tools.org</id>
+ <url>@RELEASE_REPOSITORY@</url>
+ </repository>
+ <snapshotRepository>
+ <id>scala-tools.org</id>
+ <url>@SNAPSHOT_REPOSITORY@</url>
+ <uniqueVersion>false</uniqueVersion>
+ </snapshotRepository>
+ </distributionManagement>
+ <developers>
+ <developer>
+ <id>lamp</id>
+ <name>EPFL LAMP</name>
+ </developer>
+ <developer>
+ <id>Typesafe</id>
+ <name>Typesafe, Inc.</name>
+ </developer>
+ </developers>
+</project>
diff --git a/src/build/maven/scala-compiler-pom.xml b/src/build/maven/scala-compiler-pom.xml
index 442fe6a8d5..a16fe22343 100644
--- a/src/build/maven/scala-compiler-pom.xml
+++ b/src/build/maven/scala-compiler-pom.xml
@@ -35,23 +35,22 @@
<version>@VERSION@</version>
</dependency>
<dependency>
- <!-- for scaladoc -->
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-reflect</artifactId>
+ <version>@VERSION@</version>
+ </dependency>
+ <!-- TODO modularize compiler: these dependencies will disappear then the compiler is modularized -->
+ <dependency> <!-- for scala-compiler-doc -->
<groupId>org.scala-lang.modules</groupId>
<artifactId>scala-xml_@SCALA_BINARY_VERSION@</artifactId>
<version>@XML_VERSION@</version>
</dependency>
- <dependency>
- <!-- for scaladoc -->
+ <dependency> <!-- for scala-compiler-doc -->
<groupId>org.scala-lang.modules</groupId>
<artifactId>scala-parser-combinators_@SCALA_BINARY_VERSION@</artifactId>
<version>@PARSER_COMBINATORS_VERSION@</version>
</dependency>
- <dependency>
- <groupId>org.scala-lang</groupId>
- <artifactId>scala-reflect</artifactId>
- <version>@VERSION@</version>
- </dependency>
- <dependency>
+ <dependency> <!-- for scala-compiler-repl-->
<groupId>jline</groupId>
<artifactId>jline</artifactId>
<version>@JLINE_VERSION@</version>
diff --git a/src/compiler/scala/reflect/macros/compiler/Errors.scala b/src/compiler/scala/reflect/macros/compiler/Errors.scala
index 30ba082a81..9799428b40 100644
--- a/src/compiler/scala/reflect/macros/compiler/Errors.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Errors.scala
@@ -33,7 +33,7 @@ trait Errors extends Traces {
def MacroBundleNonStaticError() = implRefError("macro bundles must be static")
- def MacroBundleWrongShapeError() = implRefError("macro bundles must be monomorphic traits extending scala.reflect.macros.Macro and not implementing its `val c: Context` member")
+ def MacroBundleWrongShapeError() = implRefError("macro bundles must be monomorphic traits extending either BlackboxMacro or WhiteboxMacro and not implementing their `val c: BlackboxContext/WhiteboxContext` member")
// compatibility errors
diff --git a/src/compiler/scala/reflect/macros/compiler/Resolvers.scala b/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
index 9c4db1990b..03d306f593 100644
--- a/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Resolvers.scala
@@ -15,10 +15,6 @@ trait Resolvers {
private val runDefinitions = currentRun.runDefinitions
import runDefinitions.{Predef_???, _}
- /** Determines the type of context implied by the macro def.
- */
- val ctxTpe = MacroContextClass.tpe
-
/** Resolves a macro impl reference provided in the right-hand side of the given macro definition.
*
* Acceptable shapes of the right-hand side:
@@ -44,14 +40,14 @@ trait Resolvers {
}
val untypedImplRef = typer.silent(_.typedTypeConstructor(maybeBundleRef)) match {
- case SilentResultValue(result) if result.tpe.baseClasses.contains(MacroClass) =>
+ case SilentResultValue(result) if mightBeMacroBundleType(result.tpe) =>
val bundleProto = result.tpe.typeSymbol
val bundlePkg = bundleProto.enclosingPackageClass
if (!isMacroBundleProtoType(bundleProto.tpe)) MacroBundleWrongShapeError()
if (!bundleProto.owner.isStaticOwner) MacroBundleNonStaticError()
// synthesize the bundle, i.e. given a static `trait Foo extends Macro { def expand = ... } `
- // create a top-level definition `class Foo$Bundle(val c: Context) extends Foo` in a package next to `Foo`
+ // create a top-level definition `class Foo$Bundle(val c: BlackboxContext/WhiteboxContext) extends Foo` in a package next to `Foo`
val bundlePid = gen.mkUnattributedRef(bundlePkg)
val bundlePrefix =
if (bundlePkg == EmptyPackageClass) bundleProto.fullName('$')
@@ -59,7 +55,8 @@ trait Resolvers {
val bundleName = TypeName(bundlePrefix + tpnme.MACRO_BUNDLE_SUFFIX)
val existingBundle = bundleProto.enclosingPackageClass.info.decl(bundleName)
if (!currentRun.compiles(existingBundle)) {
- def mkContextValDef(flags: Long) = ValDef(Modifiers(flags), nme.c, TypeTree(ctxTpe), EmptyTree)
+ val contextType = if (isBlackboxMacroBundleType(bundleProto.tpe)) BlackboxContextClass.tpe else WhiteboxContextClass.tpe
+ def mkContextValDef(flags: Long) = ValDef(Modifiers(flags), nme.c, TypeTree(contextType), EmptyTree)
val contextField = mkContextValDef(PARAMACCESSOR)
val contextParam = mkContextValDef(PARAM | PARAMACCESSOR)
val bundleCtor = DefDef(Modifiers(), nme.CONSTRUCTOR, Nil, List(List(contextParam)), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(()))))
@@ -88,12 +85,13 @@ trait Resolvers {
// lazy val (isImplBundle, macroImplOwner, macroImpl, macroImplTargs) =
private lazy val dissectedMacroImplRef =
macroImplRef match {
- case MacroImplReference(isBundle, owner, meth, targs) => (isBundle, owner, meth, targs)
+ case MacroImplReference(isBundle, isBlackbox, owner, meth, targs) => (isBundle, isBlackbox, owner, meth, targs)
case _ => MacroImplReferenceWrongShapeError()
}
lazy val isImplBundle = dissectedMacroImplRef._1
lazy val isImplMethod = !isImplBundle
- lazy val macroImplOwner = dissectedMacroImplRef._2
- lazy val macroImpl = dissectedMacroImplRef._3
- lazy val targs = dissectedMacroImplRef._4
+ lazy val isImplBlackbox = dissectedMacroImplRef._2
+ lazy val macroImplOwner = dissectedMacroImplRef._3
+ lazy val macroImpl = dissectedMacroImplRef._4
+ lazy val targs = dissectedMacroImplRef._5
}
diff --git a/src/compiler/scala/reflect/macros/compiler/Validators.scala b/src/compiler/scala/reflect/macros/compiler/Validators.scala
index 088b108844..e77c129c51 100644
--- a/src/compiler/scala/reflect/macros/compiler/Validators.scala
+++ b/src/compiler/scala/reflect/macros/compiler/Validators.scala
@@ -49,8 +49,8 @@ trait Validators {
map2(aparamss.flatten, rparamss.flatten)((aparam, rparam) => {
if (aparam.name != rparam.name && !rparam.isSynthetic) MacroImplParamNameMismatchError(aparam, rparam)
if (isRepeated(aparam) ^ isRepeated(rparam)) MacroImplVarargMismatchError(aparam, rparam)
- val aparamtpe = aparam.tpe.dealias match {
- case RefinedType(List(tpe), Scope(sym)) if tpe =:= ctxTpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe
+ val aparamtpe = aparam.tpe match {
+ case MacroContextType(tpe) => tpe
case tpe => tpe
}
checkMacroImplParamTypeMismatch(atpeToRtpe(aparamtpe), rparam)
@@ -93,20 +93,20 @@ trait Validators {
*
* For the following macro impl:
* def fooBar[T: c.WeakTypeTag]
- * (c: scala.reflect.macros.Context)
+ * (c: scala.reflect.macros.BlackboxContext)
* (xs: c.Expr[List[T]])
* : c.Expr[T] = ...
*
* This function will return:
- * (c: scala.reflect.macros.Context)(xs: c.Expr[List[T]])c.Expr[T]
+ * (c: scala.reflect.macros.BlackboxContext)(xs: c.Expr[List[T]])c.Expr[T]
*
* Note that type tag evidence parameters are not included into the result.
* Type tag context bounds for macro impl tparams are optional.
* Therefore compatibility checks ignore such parameters, and we don't need to bother about them here.
*
* This method cannot be reduced to just macroImpl.info, because macro implementations might
- * come in different shapes. If the implementation is an apply method of a Macro-compatible object,
- * then it won't have (c: Context) in its parameters, but will rather refer to Macro.c.
+ * come in different shapes. If the implementation is an apply method of a BlackboxMacro/WhiteboxMacro-compatible object,
+ * then it won't have (c: BlackboxContext/WhiteboxContext) in its parameters, but will rather refer to BlackboxMacro/WhiteboxMacro.c.
*
* @param macroImpl The macro implementation symbol
*/
@@ -123,7 +123,8 @@ trait Validators {
* def foo[T](xs: List[T]): T = macro fooBar
*
* This function will return:
- * (c: scala.reflect.macros.Context)(xs: c.Expr[List[T]])c.Expr[T]
+ * (c: scala.reflect.macros.BlackboxContext)(xs: c.Expr[List[T]])c.Expr[T] or
+ * (c: scala.reflect.macros.WhiteboxContext)(xs: c.Expr[List[T]])c.Expr[T]
*
* Note that type tag evidence parameters are not included into the result.
* Type tag context bounds for macro impl tparams are optional.
@@ -145,6 +146,7 @@ trait Validators {
// had to move method's body to an object because of the recursive dependencies between sigma and param
object SigGenerator {
val cache = scala.collection.mutable.Map[Symbol, Symbol]()
+ val ctxTpe = if (isImplBlackbox) BlackboxContextClass.tpe else WhiteboxContextClass.tpe
val ctxPrefix =
if (isImplMethod) singleType(NoPrefix, makeParam(nme.macroContext, macroDdef.pos, ctxTpe, SYNTHETIC))
else singleType(ThisType(macroImpl.owner), macroImpl.owner.tpe.member(nme.c))
diff --git a/src/compiler/scala/reflect/macros/contexts/Context.scala b/src/compiler/scala/reflect/macros/contexts/Context.scala
index 1355a839d9..7b79b52a18 100644
--- a/src/compiler/scala/reflect/macros/contexts/Context.scala
+++ b/src/compiler/scala/reflect/macros/contexts/Context.scala
@@ -3,7 +3,8 @@ package contexts
import scala.tools.nsc.Global
-abstract class Context extends scala.reflect.macros.Context
+abstract class Context extends scala.reflect.macros.BlackboxContext
+ with scala.reflect.macros.WhiteboxContext
with Aliases
with Enclosures
with Names
diff --git a/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala b/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala
index ffdbe11151..7de3341304 100644
--- a/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala
+++ b/src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala
@@ -45,7 +45,7 @@ trait MacroRuntimes extends JavaReflectionRuntimes with ScalaReflectionRuntimes
type MacroRuntime = MacroArgs => Any
class MacroRuntimeResolver(val macroDef: Symbol) extends JavaReflectionResolvers
with ScalaReflectionResolvers {
- val binding = loadMacroImplBinding(macroDef)
+ val binding = loadMacroImplBinding(macroDef).get
val isBundle = binding.isBundle
val className = binding.className
val methName = binding.methName
diff --git a/src/compiler/scala/reflect/macros/util/Helpers.scala b/src/compiler/scala/reflect/macros/util/Helpers.scala
index bb4f2055ad..ff03696524 100644
--- a/src/compiler/scala/reflect/macros/util/Helpers.scala
+++ b/src/compiler/scala/reflect/macros/util/Helpers.scala
@@ -27,13 +27,13 @@ trait Helpers {
import runDefinitions._
val MacroContextUniverse = definitions.MacroContextUniverse
- val treeInfo.MacroImplReference(isBundle, _, macroImpl, _) = macroImplRef
+ val treeInfo.MacroImplReference(isBundle, _, _, macroImpl, _) = macroImplRef
val paramss = macroImpl.paramss
val ContextParam = paramss match {
- case Nil | _ :+ Nil => NoSymbol // no implicit parameters in the signature => nothing to do
- case _ if isBundle => macroImpl.owner.tpe member nme.c
- case (cparam :: _) :: _ if cparam.tpe <:< MacroContextClass.tpe => cparam
- case _ => NoSymbol // no context parameter in the signature => nothing to do
+ case Nil | _ :+ Nil => NoSymbol // no implicit parameters in the signature => nothing to do
+ case _ if isBundle => macroImpl.owner.tpe member nme.c
+ case (cparam :: _) :: _ if isMacroContextType(cparam.tpe) => cparam
+ case _ => NoSymbol // no context parameter in the signature => nothing to do
}
def transformTag(param: Symbol): Symbol = param.tpe.dealias match {
case TypeRef(SingleType(SingleType(_, ContextParam), MacroContextUniverse), WeakTypeTagClass, targ :: Nil) => transform(param, targ.typeSymbol)
diff --git a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
index 0020528c5b..6dda30b5e7 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeDSL.scala
@@ -137,7 +137,7 @@ trait TreeDSL {
def IF(tree: Tree) = new IfStart(tree, EmptyTree)
def TRY(tree: Tree) = new TryStart(tree, Nil, EmptyTree)
def BLOCK(xs: Tree*) = Block(xs.init.toList, xs.last)
- def SOME(xs: Tree*) = Apply(SomeClass.companionSymbol, treeBuilder.makeTupleTerm(xs.toList, flattenUnary = true))
+ def SOME(xs: Tree*) = Apply(SomeClass.companionSymbol, gen.mkTuple(xs.toList))
/** Typed trees from symbols. */
def REF(sym: Symbol) = gen.mkAttributedRef(sym)
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 28b127698f..d4ac21a6b8 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -53,13 +53,6 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
NewFromConstructor(constructor, expr)
}
- // annotate the expression with @unchecked
- def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) {
- // This can't be "Annotated(New(UncheckedClass), expr)" because annotations
- // are very picky about things and it crashes the compiler with "unexpected new".
- Annotated(New(scalaDot(UncheckedClass.name), Nil), expr)
- }
-
// Builds a tree of the form "{ lhs = rhs ; lhs }"
def mkAssignAndReturn(lhs: Symbol, rhs: Tree): Tree = {
def lhsRef = if (lhs.owner.isClass) Select(This(lhs.owner), lhs) else Ident(lhs)
@@ -263,7 +256,4 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
val stats1 = if (stats.isEmpty) List(Literal(Constant(()))) else stats
mkNew(Nil, noSelfType, stats1, NoPosition, NoPosition)
}
-
- def mkSyntheticParam(pname: TermName) =
- ValDef(Modifiers(PARAM | SYNTHETIC), pname, TypeTree(), EmptyTree)
}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index cfa60cabc3..cd1869340a 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -861,7 +861,7 @@ self =>
atPos(start, in.skipToken()) { makeFunctionTypeTree(ts, typ()) }
else {
ts foreach checkNotByNameOrVarargs
- val tuple = atPos(start) { makeTupleType(ts, flattenUnary = true) }
+ val tuple = atPos(start) { makeTupleType(ts) }
infixTypeRest(
compoundTypeRest(
annotTypeRest(
@@ -923,7 +923,7 @@ self =>
def simpleType(): Tree = {
val start = in.offset
simpleTypeRest(in.token match {
- case LPAREN => atPos(start)(makeTupleType(inParens(types()), flattenUnary = true))
+ case LPAREN => atPos(start)(makeTupleType(inParens(types())))
case USCORE => wildcardType(in.skipToken())
case _ =>
path(thisOK = false, typeOK = true) match {
@@ -1394,9 +1394,9 @@ self =>
newLinesOpt()
if (in.token == YIELD) {
in.nextToken()
- makeForYield(enums, expr())
+ gen.mkFor(enums, gen.Yield(expr()))
} else {
- makeFor(enums, expr())
+ gen.mkFor(enums, expr())
}
}
def adjustStart(tree: Tree) =
@@ -1700,22 +1700,25 @@ self =>
* | val Pattern1 `=' Expr
* }}}
*/
- def enumerators(): List[Enumerator] = {
- val enums = new ListBuffer[Enumerator]
- generator(enums, eqOK = false)
+ def enumerators(): List[Tree] = {
+ val enums = new ListBuffer[Tree]
+ enums ++= enumerator(isFirst = true)
while (isStatSep) {
in.nextToken()
- if (in.token == IF) enums += makeFilter(in.offset, guard())
- else generator(enums, eqOK = true)
+ enums ++= enumerator(isFirst = false)
}
enums.toList
}
+ def enumerator(isFirst: Boolean, allowNestedIf: Boolean = true): List[Tree] =
+ if (in.token == IF && !isFirst) makeFilter(in.offset, guard()) :: Nil
+ else generator(!isFirst, allowNestedIf)
+
/** {{{
* Generator ::= Pattern1 (`<-' | `=') Expr [Guard]
* }}}
*/
- def generator(enums: ListBuffer[Enumerator], eqOK: Boolean) {
+ def generator(eqOK: Boolean, allowNestedIf: Boolean = true): List[Tree] = {
val start = in.offset
val hasVal = in.token == VAL
if (hasVal)
@@ -1733,13 +1736,22 @@ self =>
if (hasEq && eqOK) in.nextToken()
else accept(LARROW)
val rhs = expr()
- enums += makeGenerator(r2p(start, point, in.lastOffset max start), pat, hasEq, rhs)
- // why max above? IDE stress tests have shown that lastOffset could be less than start,
+
+ def loop(): List[Tree] =
+ if (in.token != IF) Nil
+ else makeFilter(in.offset, guard()) :: loop()
+
+ val tail =
+ if (allowNestedIf) loop()
+ else Nil
+
+ // why max? IDE stress tests have shown that lastOffset could be less than start,
// I guess this happens if instead if a for-expression we sit on a closing paren.
- while (in.token == IF) enums += makeFilter(in.offset, guard())
+ val genPos = r2p(start, point, in.lastOffset max start)
+ gen.mkGenerator(genPos, pat, hasEq, rhs) :: tail
}
- def makeFilter(start: Offset, tree: Tree) = Filter(r2p(start, tree.pos.point, tree.pos.end), tree)
+ def makeFilter(start: Offset, tree: Tree) = gen.Filter(tree).setPos(r2p(start, tree.pos.point, tree.pos.end))
/* -------- PATTERNS ------------------------------------------- */
@@ -2454,11 +2466,10 @@ self =>
EmptyTree
}
def mkDefs(p: Tree, tp: Tree, rhs: Tree): List[Tree] = {
- val trees =
- makePatDef(newmods,
- if (tp.isEmpty) p
- else Typed(p, tp) setPos (p.pos union tp.pos),
- rhs)
+ val trees = {
+ val pat = if (tp.isEmpty) p else Typed(p, tp) setPos (p.pos union tp.pos)
+ gen.mkPatDef(newmods, pat, rhs)
+ }
if (newmods.isDeferred) {
trees match {
case List(ValDef(_, _, _, EmptyTree)) =>
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
index 28d5aefc2b..d88470bd5e 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -31,88 +31,6 @@ abstract class TreeBuilder {
def convertToTypeName(t: Tree) = gen.convertToTypeName(t)
- /** Convert all occurrences of (lower-case) variables in a pattern as follows:
- * x becomes x @ _
- * x: T becomes x @ (_: T)
- */
- object patvarTransformer extends Transformer {
- override def transform(tree: Tree): Tree = tree match {
- case Ident(name) if (treeInfo.isVarPattern(tree) && name != nme.WILDCARD) =>
- atPos(tree.pos)(Bind(name, atPos(tree.pos.focus) (Ident(nme.WILDCARD))))
- case Typed(id @ Ident(name), tpt) if (treeInfo.isVarPattern(id) && name != nme.WILDCARD) =>
- atPos(tree.pos.withPoint(id.pos.point)) {
- Bind(name, atPos(tree.pos.withStart(tree.pos.point)) {
- Typed(Ident(nme.WILDCARD), tpt)
- })
- }
- case Apply(fn @ Apply(_, _), args) =>
- treeCopy.Apply(tree, transform(fn), transformTrees(args))
- case Apply(fn, args) =>
- treeCopy.Apply(tree, fn, transformTrees(args))
- case Typed(expr, tpt) =>
- treeCopy.Typed(tree, transform(expr), tpt)
- case Bind(name, body) =>
- treeCopy.Bind(tree, name, transform(body))
- case Alternative(_) | Star(_) =>
- super.transform(tree)
- case _ =>
- tree
- }
- }
-
- /** Traverse pattern and collect all variable names with their types in buffer
- * The variables keep their positions; whereas the pattern is converted to be
- * synthetic for all nodes that contain a variable position.
- */
- class GetVarTraverser extends Traverser {
- val buf = new ListBuffer[(Name, Tree, Position)]
-
- def namePos(tree: Tree, name: Name): Position =
- if (!tree.pos.isRange || name.containsName(nme.raw.DOLLAR)) tree.pos.focus
- else {
- val start = tree.pos.start
- val end = start + name.decode.length
- r2p(start, start, end)
- }
-
- override def traverse(tree: Tree): Unit = {
- def seenName(name: Name) = buf exists (_._1 == name)
- def add(name: Name, t: Tree) = if (!seenName(name)) buf += ((name, t, namePos(tree, name)))
- val bl = buf.length
-
- tree match {
- case Bind(nme.WILDCARD, _) =>
- super.traverse(tree)
-
- case Bind(name, Typed(tree1, tpt)) =>
- val newTree = if (treeInfo.mayBeTypePat(tpt)) TypeTree() else tpt.duplicate
- add(name, newTree)
- traverse(tree1)
-
- case Bind(name, tree1) =>
- // can assume only name range as position, as otherwise might overlap
- // with binds embedded in pattern tree1
- add(name, TypeTree())
- traverse(tree1)
-
- case _ =>
- super.traverse(tree)
- }
- if (buf.length > bl)
- tree setPos tree.pos.makeTransparent
- }
- def apply(tree: Tree) = {
- traverse(tree)
- buf.toList
- }
- }
-
- /** Returns list of all pattern variables, possibly with their types,
- * without duplicates
- */
- private def getVariables(tree: Tree): List[(Name, Tree, Position)] =
- new GetVarTraverser apply tree
-
def byNameApplication(tpe: Tree): Tree =
AppliedTypeTree(rootScalaDot(tpnme.BYNAME_PARAM_CLASS_NAME), List(tpe))
def repeatedApplication(tpe: Tree): Tree =
@@ -121,25 +39,12 @@ abstract class TreeBuilder {
def makeImportSelector(name: Name, nameOffset: Int): ImportSelector =
ImportSelector(name, nameOffset, name, nameOffset)
- private def makeTuple(trees: List[Tree], isType: Boolean): Tree = {
- val tupString = "Tuple" + trees.length
- Apply(scalaDot(if (isType) newTypeName(tupString) else newTermName(tupString)), trees)
- }
-
- def makeTupleTerm(trees: List[Tree], flattenUnary: Boolean): Tree = trees match {
- case Nil => Literal(Constant(()))
- case List(tree) if flattenUnary => tree
- case _ => makeTuple(trees, isType = false)
- }
+ def makeTupleTerm(elems: List[Tree]) = gen.mkTuple(elems)
- def makeTupleType(trees: List[Tree], flattenUnary: Boolean): Tree = trees match {
- case Nil => scalaUnitConstr
- case List(tree) if flattenUnary => tree
- case _ => AppliedTypeTree(scalaDot(newTypeName("Tuple" + trees.length)), trees)
- }
+ def makeTupleType(elems: List[Tree]) = gen.mkTupleType(elems)
def stripParens(t: Tree) = t match {
- case Parens(ts) => atPos(t.pos) { makeTupleTerm(ts, flattenUnary = true) }
+ case Parens(ts) => atPos(t.pos) { makeTupleTerm(ts) }
case _ => t
}
@@ -149,22 +54,6 @@ abstract class TreeBuilder {
def makeSelfDef(name: TermName, tpt: Tree): ValDef =
ValDef(Modifiers(PRIVATE), name, tpt, EmptyTree)
- /** If tree is a variable pattern, return Some("its name and type").
- * Otherwise return none */
- private def matchVarPattern(tree: Tree): Option[(Name, Tree)] = {
- def wildType(t: Tree): Option[Tree] = t match {
- case Ident(x) if x.toTermName == nme.WILDCARD => Some(TypeTree())
- case Typed(Ident(x), tpt) if x.toTermName == nme.WILDCARD => Some(tpt)
- case _ => None
- }
- tree match {
- case Ident(name) => Some((name, TypeTree()))
- case Bind(name, body) => wildType(body) map (x => (name, x))
- case Typed(Ident(name), tpt) => Some((name, tpt))
- case _ => None
- }
- }
-
/** Create tree representing (unencoded) binary operation expression or pattern. */
def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position): Tree = {
def mkNamed(args: List[Tree]) = if (isExpr) args map treeInfo.assignmentToMaybeNamedArg else args
@@ -214,173 +103,12 @@ abstract class TreeBuilder {
/** Create block of statements `stats` */
def makeBlock(stats: List[Tree]): Tree = gen.mkBlock(stats)
- def makeFilter(tree: Tree, condition: Tree, scrutineeName: String): Tree = {
- val cases = List(
- CaseDef(condition, EmptyTree, Literal(Constant(true))),
- CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))
- )
- val matchTree = makeVisitor(cases, checkExhaustive = false, scrutineeName)
-
- atPos(tree.pos)(Apply(Select(tree, nme.withFilter), matchTree :: Nil))
- }
-
- /** Create tree for for-comprehension generator <val pat0 <- rhs0> */
- def makeGenerator(pos: Position, pat: Tree, valeq: Boolean, rhs: Tree): Enumerator = {
- val pat1 = patvarTransformer.transform(pat)
- val rhs1 =
- if (valeq || treeInfo.isVarPatternDeep(pat)) rhs
- else makeFilter(rhs, pat1.duplicate, nme.CHECK_IF_REFUTABLE_STRING)
-
- if (valeq) ValEq(pos, pat1, rhs1)
- else ValFrom(pos, pat1, rhs1)
- }
-
def makeParam(pname: TermName, tpe: Tree) =
ValDef(Modifiers(PARAM), pname, tpe, EmptyTree)
def makeSyntheticTypeParam(pname: TypeName, bounds: Tree) =
TypeDef(Modifiers(DEFERRED | SYNTHETIC), pname, Nil, bounds)
- abstract class Enumerator { def pos: Position }
- case class ValFrom(pos: Position, pat: Tree, rhs: Tree) extends Enumerator
- case class ValEq(pos: Position, pat: Tree, rhs: Tree) extends Enumerator
- case class Filter(pos: Position, test: Tree) extends Enumerator
-
- /** Create tree for for-comprehension <for (enums) do body> or
- * <for (enums) yield body> where mapName and flatMapName are chosen
- * corresponding to whether this is a for-do or a for-yield.
- * The creation performs the following rewrite rules:
- *
- * 1.
- *
- * for (P <- G) E ==> G.foreach (P => E)
- *
- * Here and in the following (P => E) is interpreted as the function (P => E)
- * if P is a variable pattern and as the partial function { case P => E } otherwise.
- *
- * 2.
- *
- * for (P <- G) yield E ==> G.map (P => E)
- *
- * 3.
- *
- * for (P_1 <- G_1; P_2 <- G_2; ...) ...
- * ==>
- * G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
- *
- * 4.
- *
- * for (P <- G; E; ...) ...
- * =>
- * for (P <- G.filter (P => E); ...) ...
- *
- * 5. For N < MaxTupleArity:
- *
- * for (P_1 <- G; P_2 = E_2; val P_N = E_N; ...)
- * ==>
- * for (TupleN(P_1, P_2, ... P_N) <-
- * for (x_1 @ P_1 <- G) yield {
- * val x_2 @ P_2 = E_2
- * ...
- * val x_N & P_N = E_N
- * TupleN(x_1, ..., x_N)
- * } ...)
- *
- * If any of the P_i are variable patterns, the corresponding `x_i @ P_i' is not generated
- * and the variable constituting P_i is used instead of x_i
- *
- * @param mapName The name to be used for maps (either map or foreach)
- * @param flatMapName The name to be used for flatMaps (either flatMap or foreach)
- * @param enums The enumerators in the for expression
- * @param body The body of the for expression
- */
- private def makeFor(mapName: TermName, flatMapName: TermName, enums: List[Enumerator], body: Tree): Tree = {
-
- /* make a closure pat => body.
- * The closure is assigned a transparent position with the point at pos.point and
- * the limits given by pat and body.
- */
- def makeClosure(pos: Position, pat: Tree, body: Tree): Tree = {
- def splitpos = wrappingPos(List(pat, body)).withPoint(pos.point).makeTransparent
- matchVarPattern(pat) match {
- case Some((name, tpt)) =>
- Function(
- List(atPos(pat.pos) { ValDef(Modifiers(PARAM), name.toTermName, tpt, EmptyTree) }),
- body) setPos splitpos
- case None =>
- atPos(splitpos) {
- makeVisitor(List(CaseDef(pat, EmptyTree, body)), checkExhaustive = false)
- }
- }
- }
-
- /* Make an application qual.meth(pat => body) positioned at `pos`.
- */
- def makeCombination(pos: Position, meth: TermName, qual: Tree, pat: Tree, body: Tree): Tree =
- Apply(Select(qual, meth) setPos qual.pos, List(makeClosure(pos, pat, body))) setPos pos
-
- /* If `pat` is not yet a `Bind` wrap it in one with a fresh name */
- def makeBind(pat: Tree): Tree = pat match {
- case Bind(_, _) => pat
- case _ => Bind(freshTermName(), pat) setPos pat.pos
- }
-
- /* A reference to the name bound in Bind `pat`. */
- def makeValue(pat: Tree): Tree = pat match {
- case Bind(name, _) => Ident(name) setPos pat.pos.focus
- }
-
- /* The position of the closure that starts with generator at position `genpos`. */
- def closurePos(genpos: Position) = {
- val end = body.pos match {
- case NoPosition => genpos.point
- case bodypos => bodypos.end
- }
- r2p(genpos.start, genpos.point, end)
- }
-
-// val result =
- enums match {
- case ValFrom(pos, pat, rhs) :: Nil =>
- makeCombination(closurePos(pos), mapName, rhs, pat, body)
- case ValFrom(pos, pat, rhs) :: (rest @ (ValFrom(_, _, _) :: _)) =>
- makeCombination(closurePos(pos), flatMapName, rhs, pat,
- makeFor(mapName, flatMapName, rest, body))
- case ValFrom(pos, pat, rhs) :: Filter(_, test) :: rest =>
- makeFor(mapName, flatMapName,
- ValFrom(pos, pat, makeCombination(rhs.pos union test.pos, nme.withFilter, rhs, pat.duplicate, test)) :: rest,
- body)
- case ValFrom(pos, pat, rhs) :: rest =>
- val valeqs = rest.take(definitions.MaxTupleArity - 1).takeWhile(_.isInstanceOf[ValEq])
- assert(!valeqs.isEmpty)
- val rest1 = rest.drop(valeqs.length)
- val pats = valeqs map { case ValEq(_, pat, _) => pat }
- val rhss = valeqs map { case ValEq(_, _, rhs) => rhs }
- val defpat1 = makeBind(pat)
- val defpats = pats map makeBind
- val pdefs = (defpats, rhss).zipped flatMap makePatDef
- val ids = (defpat1 :: defpats) map makeValue
- val rhs1 = makeForYield(
- List(ValFrom(pos, defpat1, rhs)),
- Block(pdefs, atPos(wrappingPos(ids)) { makeTupleTerm(ids, flattenUnary = true) }) setPos wrappingPos(pdefs))
- val allpats = (pat :: pats) map (_.duplicate)
- val vfrom1 = ValFrom(r2p(pos.start, pos.point, rhs1.pos.end), atPos(wrappingPos(allpats)) { makeTuple(allpats, isType = false) } , rhs1)
- makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
- case _ =>
- EmptyTree //may happen for erroneous input
- }
-// println("made for "+result)
-// result
- }
-
- /** Create tree for for-do comprehension <for (enums) body> */
- def makeFor(enums: List[Enumerator], body: Tree): Tree =
- makeFor(nme.foreach, nme.foreach, enums, body)
-
- /** Create tree for for-yield comprehension <for (enums) yield body> */
- def makeForYield(enums: List[Enumerator], body: Tree): Tree =
- makeFor(nme.map, nme.flatMap, enums, body)
-
/** Create tree for a pattern alternative */
def makeAlternative(ts: List[Tree]): Tree = {
def alternatives(t: Tree): List[Tree] = t match {
@@ -390,21 +118,9 @@ abstract class TreeBuilder {
Alternative(ts flatMap alternatives)
}
- /** Create visitor <x => x match cases> */
- def makeVisitor(cases: List[CaseDef], checkExhaustive: Boolean): Tree =
- makeVisitor(cases, checkExhaustive, "x$")
-
- /** Create visitor <x => x match cases> */
- def makeVisitor(cases: List[CaseDef], checkExhaustive: Boolean, prefix: String): Tree = {
- val x = freshTermName(prefix)
- val id = Ident(x)
- val sel = if (checkExhaustive) id else gen.mkUnchecked(id)
- Function(List(gen.mkSyntheticParam(x)), Match(sel, cases))
- }
-
/** Create tree for case definition <case pat if guard => rhs> */
def makeCaseDef(pat: Tree, guard: Tree, rhs: Tree): CaseDef =
- CaseDef(patvarTransformer.transform(pat), guard, rhs)
+ CaseDef(gen.patvarTransformer.transform(pat), guard, rhs)
/** Creates tree representing:
* { case x: Throwable =>
@@ -428,76 +144,6 @@ abstract class TreeBuilder {
makeCaseDef(pat, EmptyTree, body)
}
- /** Create tree for pattern definition <val pat0 = rhs> */
- def makePatDef(pat: Tree, rhs: Tree): List[Tree] =
- makePatDef(Modifiers(0), pat, rhs)
-
- /** Create tree for pattern definition <mods val pat0 = rhs> */
- def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree): List[Tree] = matchVarPattern(pat) match {
- case Some((name, tpt)) =>
- List(atPos(pat.pos union rhs.pos) {
- ValDef(mods, name.toTermName, tpt, rhs)
- })
-
- case None =>
- // in case there is exactly one variable x_1 in pattern
- // val/var p = e ==> val/var x_1 = e.match (case p => (x_1))
- //
- // in case there are zero or more than one variables in pattern
- // val/var p = e ==> private synthetic val t$ = e.match (case p => (x_1, ..., x_N))
- // val/var x_1 = t$._1
- // ...
- // val/var x_N = t$._N
-
- val rhsUnchecked = gen.mkUnchecked(rhs)
-
- // TODO: clean this up -- there is too much information packked into makePatDef's `pat` argument
- // when it's a simple identifier (case Some((name, tpt)) -- above),
- // pat should have the type ascription that was specified by the user
- // however, in `case None` (here), we must be careful not to generate illegal pattern trees (such as `(a, b): Tuple2[Int, String]`)
- // i.e., this must hold: pat1 match { case Typed(expr, tp) => assert(expr.isInstanceOf[Ident]) case _ => }
- // if we encounter such an erroneous pattern, we strip off the type ascription from pat and propagate the type information to rhs
- val (pat1, rhs1) = patvarTransformer.transform(pat) match {
- // move the Typed ascription to the rhs
- case Typed(expr, tpt) if !expr.isInstanceOf[Ident] =>
- val rhsTypedUnchecked =
- if (tpt.isEmpty) rhsUnchecked
- else Typed(rhsUnchecked, tpt) setPos (rhs.pos union tpt.pos)
- (expr, rhsTypedUnchecked)
- case ok =>
- (ok, rhsUnchecked)
- }
- val vars = getVariables(pat1)
- val matchExpr = atPos((pat1.pos union rhs.pos).makeTransparent) {
- Match(
- rhs1,
- List(
- atPos(pat1.pos) {
- CaseDef(pat1, EmptyTree, makeTupleTerm(vars map (_._1) map Ident.apply, flattenUnary = true))
- }
- ))
- }
- vars match {
- case List((vname, tpt, pos)) =>
- List(atPos(pat.pos union pos union rhs.pos) {
- ValDef(mods, vname.toTermName, tpt, matchExpr)
- })
- case _ =>
- val tmp = freshTermName()
- val firstDef =
- atPos(matchExpr.pos) {
- ValDef(Modifiers(PrivateLocal | SYNTHETIC | ARTIFACT | (mods.flags & LAZY)),
- tmp, TypeTree(), matchExpr)
- }
- var cnt = 0
- val restDefs = for ((vname, tpt, pos) <- vars) yield atPos(pos) {
- cnt += 1
- ValDef(mods, vname.toTermName, tpt, Select(Ident(tmp), newTermName("_" + cnt)))
- }
- firstDef :: restDefs
- }
- }
-
/** Create a tree representing the function type (argtpes) => restpe */
def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = gen.mkFunctionTypeTree(argtpes, restpe)
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index b8ca4adc14..7568c789fb 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -174,6 +174,7 @@ trait ScalaSettings extends AbsScalaSettings
val Yreifycopypaste = BooleanSetting ("-Yreify-copypaste", "Dump the reified trees in copypasteable representation.")
val Ymacronoexpand = BooleanSetting ("-Ymacro-no-expand", "Don't expand macros. Might be useful for scaladoc and presentation compiler, but will crash anything which uses macros and gets past typer.")
val Yreplsync = BooleanSetting ("-Yrepl-sync", "Do not use asynchronous code for repl startup")
+ val Yreplclassbased = BooleanSetting ("-Yrepl-class-based", "Use classes to wrap REPL snippets instead of objects")
val Yreploutdir = StringSetting ("-Yrepl-outdir", "path", "Write repl-generated classfiles to given output directory (use \"\" to generate a temporary dir)" , "")
val YmethodInfer = BooleanSetting ("-Yinfer-argument-types", "Infer types for arguments of overriden methods.")
val etaExpandKeepsStar = BooleanSetting ("-Yeta-expand-keeps-star", "Eta-expand varargs methods to T* rather than Seq[T]. This is a temporary option to ease transition.").withDeprecationMessage(removalIn212)
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 92f95e282b..7ecc2be9be 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -527,6 +527,9 @@ trait ContextErrors {
def TooManyArgsPatternError(fun: Tree) =
NormalTypeError(fun, "too many arguments for unapply pattern, maximum = "+definitions.MaxTupleArity)
+ def BlackboxExtractorExpansion(fun: Tree) =
+ NormalTypeError(fun, "extractor macros can only be whitebox")
+
def WrongShapeExtractorExpansion(fun: Tree) =
NormalTypeError(fun, "extractor macros can only expand into extractor calls")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index b1a48f7478..01acbb8cc2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -596,7 +596,7 @@ trait Implicits {
// workaround for deficient context provided by ModelFactoryImplicitSupport#makeImplicitConstraints
val isScalaDoc = context.tree == EmptyTree
- val itree = atPos(pos.focus) {
+ val itree0 = atPos(pos.focus) {
if (isLocal && !isScalaDoc) {
// SI-4270 SI-5376 Always use an unattributed Ident for implicits in the local scope,
// rather than an attributed Select, to detect shadowing.
@@ -608,15 +608,16 @@ trait Implicits {
Select(gen.mkAttributedQualifier(info.pre), implicitMemberName)
}
}
- typingLog("considering", typeDebug.ptTree(itree))
+ val itree1 = if (isBlackbox(info.sym)) suppressMacroExpansion(itree0) else itree0
+ typingLog("considering", typeDebug.ptTree(itree1))
- def fail(reason: String): SearchResult = failure(itree, reason)
- def fallback = typed1(itree, EXPRmode, wildPt)
+ def fail(reason: String): SearchResult = failure(itree0, reason)
+ def fallback = typed1(itree1, EXPRmode, wildPt)
try {
- val itree1 = if (!isView) fallback else pt match {
+ val itree2 = if (!isView) fallback else pt match {
case Function1(arg1, arg2) =>
typed1(
- atPos(itree.pos)(Apply(itree, List(Ident("<argument>") setType approximate(arg1)))),
+ atPos(itree0.pos)(Apply(itree1, List(Ident("<argument>") setType approximate(arg1)))),
EXPRmode,
approximate(arg2)
) match {
@@ -647,10 +648,10 @@ trait Implicits {
if (Statistics.canEnable) Statistics.incCounter(typedImplicits)
- val itree2 = if (isView) treeInfo.dissectApplied(itree1).callee
- else adapt(itree1, EXPRmode, wildPt)
+ val itree3 = if (isView) treeInfo.dissectApplied(itree2).callee
+ else adapt(itree2, EXPRmode, wildPt)
- typingStack.showAdapt(itree, itree2, pt, context)
+ typingStack.showAdapt(itree0, itree3, pt, context)
def hasMatchingSymbol(tree: Tree): Boolean = (tree.symbol == info.sym) || {
tree match {
@@ -663,21 +664,21 @@ trait Implicits {
if (context.hasErrors)
fail("hasMatchingSymbol reported error: " + context.firstError.get.errMsg)
- else if (isLocal && !hasMatchingSymbol(itree1))
+ else if (isLocal && !hasMatchingSymbol(itree2))
fail("candidate implicit %s is shadowed by %s".format(
- info.sym.fullLocationString, itree1.symbol.fullLocationString))
+ info.sym.fullLocationString, itree2.symbol.fullLocationString))
else {
val tvars = undetParams map freshVar
def ptInstantiated = pt.instantiateTypeParams(undetParams, tvars)
- if (matchesPt(itree2.tpe, ptInstantiated, undetParams)) {
+ if (matchesPt(itree3.tpe, ptInstantiated, undetParams)) {
if (tvars.nonEmpty)
typingLog("solve", ptLine("tvars" -> tvars, "tvars.constr" -> tvars.map(_.constr)))
- val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt), upper = false, lubDepth(itree2.tpe :: pt :: Nil))
+ val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt), upper = false, lubDepth(itree3.tpe :: pt :: Nil))
// #2421: check that we correctly instantiated type parameters outside of the implicit tree:
- checkBounds(itree2, NoPrefix, NoSymbol, undetParams, targs, "inferred ")
+ checkBounds(itree3, NoPrefix, NoSymbol, undetParams, targs, "inferred ")
context.firstError match {
case Some(err) =>
return fail("type parameters weren't correctly instantiated outside of the implicit tree: " + err.errMsg)
@@ -693,7 +694,7 @@ trait Implicits {
if (okParams.isEmpty) EmptyTreeTypeSubstituter
else {
val subst = new TreeTypeSubstituter(okParams, okArgs)
- subst traverse itree2
+ subst traverse itree3
notifyUndetparamsInferred(okParams, okArgs)
subst
}
@@ -711,9 +712,9 @@ trait Implicits {
// This is just called for the side effect of error detection,
// see SI-6966 to see what goes wrong if we use the result of this
// as the SearchResult.
- itree2 match {
- case TypeApply(fun, args) => typedTypeApply(itree2, EXPRmode, fun, args)
- case Apply(TypeApply(fun, args), _) => typedTypeApply(itree2, EXPRmode, fun, args) // t2421c
+ itree3 match {
+ case TypeApply(fun, args) => typedTypeApply(itree3, EXPRmode, fun, args)
+ case Apply(TypeApply(fun, args), _) => typedTypeApply(itree3, EXPRmode, fun, args) // t2421c
case t => t
}
@@ -721,13 +722,13 @@ trait Implicits {
case Some(err) =>
fail("typing TypeApply reported errors for the implicit tree: " + err.errMsg)
case None =>
- val result = new SearchResult(itree2, subst)
+ val result = new SearchResult(unsuppressMacroExpansion(itree3), subst)
if (Statistics.canEnable) Statistics.incCounter(foundImplicits)
typingLog("success", s"inferred value of type $ptInstantiated is $result")
result
}
}
- else fail("incompatible: %s does not match expected type %s".format(itree2.tpe, ptInstantiated))
+ else fail("incompatible: %s does not match expected type %s".format(itree3.tpe, ptInstantiated))
}
}
catch {
@@ -1147,7 +1148,7 @@ trait Implicits {
gen.mkAttributedThis(thisSym)
case _ =>
// if `pre` is not a PDT, e.g. if someone wrote
- // implicitly[scala.reflect.macros.Context#TypeTag[Int]]
+ // implicitly[scala.reflect.macros.BlackboxContext#TypeTag[Int]]
// then we need to fail, because we don't know the prefix to use during type reification
// upd. we also need to fail silently, because this is a very common situation
// e.g. quite often we're searching for BaseUniverse#TypeTag, e.g. for a type tag in any universe
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 02fb70f3e5..27920dbd74 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -29,7 +29,7 @@ import Fingerprint._
* Then fooBar needs to point to a static method of the following form:
*
* def fooBar[T: c.WeakTypeTag] // type tag annotation is optional
- * (c: scala.reflect.macros.Context)
+ * (c: scala.reflect.macros.BlackboxContext)
* (xs: c.Expr[List[T]])
* : c.Expr[T] = {
* ...
@@ -67,7 +67,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
*
* This solution is very simple, but unfortunately it's also lacking. If we use it, then
* signatures of macro defs become transitively dependent on scala-reflect.jar
- * (because they refer to macro impls, and macro impls refer to scala.reflect.macros.Context defined in scala-reflect.jar).
+ * (because they refer to macro impls, and macro impls refer to scala.reflect.macros.BlackboxContext/WhiteboxContext defined in scala-reflect.jar).
* More details can be found in comments to https://issues.scala-lang.org/browse/SI-5940.
*
* Therefore we have to avoid putting macro impls into binding pickles and come up with our own serialization format.
@@ -81,40 +81,42 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
* and various accounting information necessary when composing an argument list for the reflective invocation.
*/
case class MacroImplBinding(
- // Is this macro impl a bundle (a trait extending Macro) or a vanilla def?
- val isBundle: Boolean,
- // Java class name of the class that contains the macro implementation
- // is used to load the corresponding object with Java reflection
- className: String,
- // method name of the macro implementation
- // `className` and `methName` are all we need to reflectively invoke a macro implementation
- // because macro implementations cannot be overloaded
- methName: String,
- // flattens the macro impl's parameter lists having symbols replaced with their fingerprints
- // currently fingerprints are calculated solely from types of the symbols:
- // * c.Expr[T] => LiftedTyped
- // * c.Tree => LiftedUntyped
- // * c.WeakTypeTag[T] => Tagged(index of the type parameter corresponding to that type tag)
- // * everything else (e.g. scala.reflect.macros.Context) => Other
- // f.ex. for: def impl[T: WeakTypeTag, U, V: WeakTypeTag](c: Context)(x: c.Expr[T], y: c.Tree): (U, V) = ???
- // `signature` will be equal to List(List(Other), List(LiftedTyped, LiftedUntyped), List(Tagged(0), Tagged(2)))
- signature: List[List[Fingerprint]],
- // type arguments part of a macro impl ref (the right-hand side of a macro definition)
- // these trees don't refer to a macro impl, so we can pickle them as is
- targs: List[Tree]) {
-
+ // Is this macro impl a bundle (a trait extending BlackboxMacro or WhiteboxMacro) or a vanilla def?
+ val isBundle: Boolean,
+ // Is this macro impl blackbox (i.e. having BlackboxContext in its signature)?
+ val isBlackbox: Boolean,
+ // Java class name of the class that contains the macro implementation
+ // is used to load the corresponding object with Java reflection
+ className: String,
+ // method name of the macro implementation
+ // `className` and `methName` are all we need to reflectively invoke a macro implementation
+ // because macro implementations cannot be overloaded
+ methName: String,
+ // flattens the macro impl's parameter lists having symbols replaced with their fingerprints
+ // currently fingerprints are calculated solely from types of the symbols:
+ // * c.Expr[T] => LiftedTyped
+ // * c.Tree => LiftedUntyped
+ // * c.WeakTypeTag[T] => Tagged(index of the type parameter corresponding to that type tag)
+ // * everything else (e.g. scala.reflect.macros.BlackboxContext/WhiteboxContext) => Other
+ // f.ex. for: def impl[T: WeakTypeTag, U, V: WeakTypeTag](c: BlackboxContext)(x: c.Expr[T], y: c.Tree): (U, V) = ???
+ // `signature` will be equal to List(List(Other), List(LiftedTyped, LiftedUntyped), List(Tagged(0), Tagged(2)))
+ signature: List[List[Fingerprint]],
+ // type arguments part of a macro impl ref (the right-hand side of a macro definition)
+ // these trees don't refer to a macro impl, so we can pickle them as is
+ targs: List[Tree]) {
// Was this binding derived from a `def ... = macro ???` definition?
def is_??? = {
val Predef_??? = currentRun.runDefinitions.Predef_???
className == Predef_???.owner.javaClassName && methName == Predef_???.name.encoded
}
+ def isWhitebox = !isBlackbox
}
/** Macro def -> macro impl bindings are serialized into a `macroImpl` annotation
* with synthetic content that carries the payload described in `MacroImplBinding`.
*
* For example, for a pair of macro definition and macro implementation:
- * def impl(c: scala.reflect.macros.Context): c.Expr[Unit] = ???
+ * def impl(c: scala.reflect.macros.BlackboxContext): c.Expr[Unit] = ???
* def foo: Unit = macro impl
*
* We will have the following annotation added on the macro definition `foo`:
@@ -122,13 +124,14 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
* @scala.reflect.macros.internal.macroImpl(
* `macro`(
* "isBundle" = false,
+ * "isBlackbox" = true,
* "signature" = List(Other),
* "methodName" = "impl",
* "versionFormat" = <current version format>,
* "className" = "Macros$"))
*/
object MacroImplBinding {
- val versionFormat = 5.0
+ val versionFormat = 6.0
def pickleAtom(obj: Any): Tree =
obj match {
@@ -151,7 +154,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
def pickle(macroImplRef: Tree): Tree = {
val runDefinitions = currentRun.runDefinitions
import runDefinitions._
- val MacroImplReference(isBundle, owner, macroImpl, targs) = macroImplRef
+ val MacroImplReference(isBundle, isBlackbox, owner, macroImpl, targs) = macroImplRef
// todo. refactor when fixing SI-5498
def className: String = {
@@ -182,6 +185,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
val payload = List[(String, Any)](
"versionFormat" -> versionFormat,
"isBundle" -> isBundle,
+ "isBlackbox" -> isBlackbox,
"className" -> className,
"methodName" -> macroImpl.name.toString,
"signature" -> signature
@@ -237,10 +241,11 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
if (versionFormat != pickleVersionFormat) fail(s"expected version format $versionFormat, actual $pickleVersionFormat")
val isBundle = unpickle("isBundle", classOf[Boolean])
+ val isBlackbox = unpickle("isBlackbox", classOf[Boolean])
val className = unpickle("className", classOf[String])
val methodName = unpickle("methodName", classOf[String])
val signature = unpickle("signature", classOf[List[List[Fingerprint]]])
- MacroImplBinding(isBundle, className, methodName, signature, targs)
+ MacroImplBinding(isBundle, isBlackbox, className, methodName, signature, targs)
}
}
@@ -249,14 +254,17 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
macroDef withAnnotation AnnotationInfo(MacroImplAnnotation.tpe, List(pickle), Nil)
}
- def loadMacroImplBinding(macroDef: Symbol): MacroImplBinding = {
- val Some(AnnotationInfo(_, List(pickle), _)) = macroDef.getAnnotation(MacroImplAnnotation)
- MacroImplBinding.unpickle(pickle)
- }
+ def loadMacroImplBinding(macroDef: Symbol): Option[MacroImplBinding] =
+ macroDef.getAnnotation(MacroImplAnnotation) collect {
+ case AnnotationInfo(_, List(pickle), _) => MacroImplBinding.unpickle(pickle)
+ }
+
+ def isBlackbox(expandee: Tree): Boolean = isBlackbox(dissectApplied(expandee).core.symbol)
+ def isBlackbox(macroDef: Symbol): Boolean = loadMacroImplBinding(macroDef).map(_.isBlackbox).getOrElse(false)
def computeMacroDefTypeFromMacroImplRef(macroDdef: DefDef, macroImplRef: Tree): Type = {
macroImplRef match {
- case MacroImplReference(_, _, macroImpl, targs) =>
+ case MacroImplReference(_, _, _, macroImpl, targs) =>
// Step I. Transform c.Expr[T] to T and everything else to Any
var runtimeType = decreaseMetalevel(macroImpl.info.finalResultType)
@@ -450,7 +458,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
(trees :+ tags).flatten
}
- val binding = loadMacroImplBinding(macroDef)
+ val binding = loadMacroImplBinding(macroDef).get
if (binding.is_???) Nil
else calculateMacroArgs(binding)
}
@@ -459,7 +467,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
}
/** Keeps track of macros in-flight.
- * See more informations in comments to `openMacros` in `scala.reflect.macros.Context`.
+ * See more informations in comments to `openMacros` in `scala.reflect.macros.WhiteboxContext`.
*/
private var _openMacros = List[MacroContext]()
def openMacros = _openMacros
@@ -596,21 +604,27 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
*/
def macroExpandApply(typer: Typer, expandee: Tree, mode: Mode, pt: Type): Tree = {
object expander extends TermMacroExpander(APPLY_ROLE, typer, expandee, mode, pt) {
- override def onSuccess(expanded: Tree) = {
+ override def onSuccess(expanded0: Tree) = {
+ def approximate(tp: Type) = {
+ // approximation is necessary for whitebox macros to guide type inference
+ // read more in the comments for onDelayed below
+ if (isBlackbox(expandee)) tp
+ else {
+ val undetparams = tp collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol }
+ deriveTypeWithWildcards(undetparams)(tp)
+ }
+ }
+ val macroPt = approximate(if (isNullaryInvocation(expandee)) expandee.tpe.finalResultType else expandee.tpe)
+ val expanded = if (isBlackbox(expandee)) atPos(enclosingMacroPosition.focus)(Typed(expanded0, TypeTree(macroPt))) else expanded0
+
// prematurely annotate the tree with a macro expansion attachment
// so that adapt called indirectly by typer.typed knows that it needs to apply the existential fixup
linkExpandeeAndExpanded(expandee, expanded)
- // approximation is necessary for whitebox macros to guide type inference
- // read more in the comments for onDelayed below
- def approximate(tp: Type) = {
- val undetparams = tp collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol }
- deriveTypeWithWildcards(undetparams)(tp)
- }
- val macroPtApprox = approximate(if (isNullaryInvocation(expandee)) expandee.tpe.finalResultType else expandee.tpe)
+
// `macroExpandApply` is called from `adapt`, where implicit conversions are disabled
// therefore we need to re-enable the conversions back temporarily
- if (macroDebugVerbose) println(s"typecheck #1 (against macroPtApprox = $macroPtApprox): $expanded")
- val expanded1 = typer.context.withImplicitsEnabled(typer.typed(expanded, mode, macroPtApprox))
+ if (macroDebugVerbose) println(s"typecheck #1 (against macroPt = $macroPt): $expanded")
+ val expanded1 = typer.context.withImplicitsEnabled(typer.typed(expanded, mode, macroPt))
if (expanded1.isErrorTyped) {
if (macroDebugVerbose) println(s"typecheck #1 has failed: ${typer.context.reportBuffer.errors}")
expanded1
@@ -664,7 +678,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
// e.g. for Foo it will be Int :: String :: Boolean :: HNil), there's no way to convey this information
// to the typechecker. Therefore the typechecker will infer Nothing for L, which is hardly what we want.
//
- // =========== THE SOLUTION ===========
+ // =========== THE SOLUTION (ENABLED ONLY FOR WHITEBOX MACROS) ===========
//
// To give materializers a chance to say their word before vanilla inference kicks in,
// we infer as much as possible (e.g. in the example above even though L is hopeless, C still can be inferred to Foo)
@@ -672,9 +686,12 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
// Thanks to that the materializer can take a look at what's going on and react accordingly.
val shouldInstantiate = typer.context.undetparams.nonEmpty && !mode.inPolyMode
if (shouldInstantiate) {
- forced += delayed
- typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), pt, keepNothings = false)
- macroExpandApply(typer, delayed, mode, pt)
+ if (isBlackbox(expandee)) typer.instantiatePossiblyExpectingUnit(delayed, mode, pt)
+ else {
+ forced += delayed
+ typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), pt, keepNothings = false)
+ macroExpandApply(typer, delayed, mode, pt)
+ }
} else delayed
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
index f69b8a9697..ba135d7d25 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
@@ -409,9 +409,10 @@ trait PatternTypers {
if (fun1.tpe.isErroneous)
duplErrTree
- else if (unapplyMethod.isMacro && !fun1.isInstanceOf[Apply])
- duplErrorTree(WrongShapeExtractorExpansion(tree))
- else
+ else if (unapplyMethod.isMacro && !fun1.isInstanceOf[Apply]) {
+ if (isBlackbox(unapplyMethod)) duplErrorTree(BlackboxExtractorExpansion(tree))
+ else duplErrorTree(WrongShapeExtractorExpansion(tree))
+ } else
makeTypedUnApply()
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index a9bb81c691..fa704adde2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1111,7 +1111,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
}
if (tree.isType)
adaptType()
- else if (mode.typingExprNotFun && treeInfo.isMacroApplication(tree))
+ else if (mode.typingExprNotFun && treeInfo.isMacroApplication(tree) && !isMacroExpansionSuppressed(tree))
macroExpandApply(this, tree, mode, pt)
else if (mode.typingConstructorPattern)
typedConstructorPattern(tree, pt)
diff --git a/src/compiler/scala/tools/nsc/util/package.scala b/src/compiler/scala/tools/nsc/util/package.scala
index 0db351f918..cb46004174 100644
--- a/src/compiler/scala/tools/nsc/util/package.scala
+++ b/src/compiler/scala/tools/nsc/util/package.scala
@@ -75,7 +75,7 @@ package object util {
s"$clazz$msg @ $frame"
}
- implicit class StackTraceOps(val e: Throwable) extends AnyVal with StackTracing {
+ implicit class StackTraceOps(private val e: Throwable) extends AnyVal with StackTracing {
/** Format the stack trace, returning the prefix consisting of frames that satisfy
* a given predicate.
* The format is similar to the typical case described in the JavaDoc
diff --git a/src/compiler/scala/tools/reflect/StdTags.scala b/src/compiler/scala/tools/reflect/StdTags.scala
index 6c1821f8aa..5c53c81e8b 100644
--- a/src/compiler/scala/tools/reflect/StdTags.scala
+++ b/src/compiler/scala/tools/reflect/StdTags.scala
@@ -49,7 +49,7 @@ object StdRuntimeTags extends StdTags {
}
abstract class StdContextTags extends StdTags {
- val tc: scala.reflect.macros.Context
+ val tc: scala.reflect.macros.contexts.Context
val u: tc.universe.type = tc.universe
val m = tc.mirror
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
index 0b5ade0b4c..3901184c25 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Parsers.scala
@@ -63,11 +63,11 @@ trait Parsers { self: Quasiquotes =>
override implicit def fresh: FreshNameCreator = parser.fresh
// q"(..$xs)"
- override def makeTupleTerm(trees: List[Tree], flattenUnary: Boolean): Tree =
+ override def makeTupleTerm(trees: List[Tree]): Tree =
Apply(Ident(nme.QUASIQUOTE_TUPLE), trees)
// tq"(..$xs)"
- override def makeTupleType(trees: List[Tree], flattenUnary: Boolean): Tree =
+ override def makeTupleType(trees: List[Tree]): Tree =
AppliedTypeTree(Ident(tpnme.QUASIQUOTE_TUPLE), trees)
// q"{ $x }"
@@ -152,6 +152,13 @@ trait Parsers { self: Quasiquotes =>
in.nextToken()
stats
}
+
+ override def enumerator(isFirst: Boolean, allowNestedIf: Boolean = true) =
+ if (isHole && lookingAhead { in.token == EOF || in.token == RPAREN || isStatSep }) {
+ val res = build.SyntacticValFrom(Bind(in.name, Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM)) :: Nil
+ in.nextToken()
+ res
+ } else super.enumerator(isFirst, allowNestedIf)
}
}
@@ -170,15 +177,29 @@ trait Parsers { self: Quasiquotes =>
object PatternParser extends Parser {
def entryPoint = { parser =>
val pat = parser.noSeq.pattern1()
- parser.treeBuilder.patvarTransformer.transform(pat)
+ gen.patvarTransformer.transform(pat)
+ }
+ }
+
+ object ForEnumeratorParser extends Parser {
+ def entryPoint = { parser =>
+ val enums = parser.enumerator(isFirst = false, allowNestedIf = false)
+ assert(enums.length == 1)
+ enums.head
}
}
+ // Extractor that matches names which were generated by call to
+ // freshTermName or freshTypeName within quasiquotes. Such names
+ // have qq$some$random$prefix$0 shape where qq$ part is added
+ // by modified fresh name creator in QuasiquoteParser.
object FreshName {
def unapply(name: Name): Option[String] =
- name.toString.split("\\$") match {
- case Array(qq, left, right) if qq + "$" == nme.QUASIQUOTE_PREFIX && Try(right.toInt).isSuccess =>
- Some(left + "$")
+ name.toString.split("\\$").toSeq match {
+ case qq +: (middle :+ last)
+ if qq + "$" == nme.QUASIQUOTE_PREFIX
+ && Try(last.toInt).isSuccess && middle.nonEmpty =>
+ Some(middle.mkString("", "$", "$"))
case _ =>
None
}
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
index c31d1fcd12..54be9123c7 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Placeholders.scala
@@ -161,4 +161,12 @@ trait Placeholders { self: Quasiquotes =>
case _ => None
}
}
+
+ object ForEnumPlaceholder {
+ def unapply(tree: Tree): Option[(Tree, Location, Cardinality)] = tree match {
+ case build.SyntacticValFrom(Bind(Placeholder(tree, location, card), Ident(nme.WILDCARD)), Ident(nme.QUASIQUOTE_FOR_ENUM)) =>
+ Some((tree, location, card))
+ case _ => None
+ }
+ }
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
index f4d6b39d02..7d777ef7d5 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Quasiquotes.scala
@@ -31,6 +31,7 @@ abstract class Quasiquotes extends Parsers
case nme.tq => TypeParser.parse(_)
case nme.cq => CaseParser.parse(_)
case nme.pq => PatternParser.parse(_)
+ case nme.fq => ForEnumeratorParser.parse(_)
case other => global.abort(s"Unknown quasiquote flavor: $other")
}
(universe0, args0, parts1, parse0, reify0, method0)
diff --git a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
index 3d1ecf95b2..b28c85cfc2 100644
--- a/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
+++ b/src/compiler/scala/tools/reflect/quasiquotes/Reifiers.scala
@@ -127,6 +127,7 @@ trait Reifiers { self: Quasiquotes =>
case RefineStatPlaceholder(tree, _, _) => reifyRefineStat(tree)
case EarlyDefPlaceholder(tree, _, _) => reifyEarlyDef(tree)
case PackageStatPlaceholder(tree, _, _) => reifyPackageStat(tree)
+ case ForEnumPlaceholder(tree, _, _) => tree
case _ => EmptyTree
}
@@ -148,6 +149,16 @@ trait Reifiers { self: Quasiquotes =>
reifyBuildCall(nme.SyntacticValDef, mods, name, tpt, rhs)
case SyntacticVarDef(mods, name, tpt, rhs) =>
reifyBuildCall(nme.SyntacticVarDef, mods, name, tpt, rhs)
+ case SyntacticValFrom(pat, rhs) =>
+ reifyBuildCall(nme.SyntacticValFrom, pat, rhs)
+ case SyntacticValEq(pat, rhs) =>
+ reifyBuildCall(nme.SyntacticValEq, pat, rhs)
+ case SyntacticFilter(cond) =>
+ reifyBuildCall(nme.SyntacticFilter, cond)
+ case SyntacticFor(enums, body) =>
+ reifyBuildCall(nme.SyntacticFor, enums, body)
+ case SyntacticForYield(enums, body) =>
+ reifyBuildCall(nme.SyntacticForYield, enums, body)
case SyntacticAssign(lhs, rhs) =>
reifyBuildCall(nme.SyntacticAssign, lhs, rhs)
case SyntacticApplied(fun, List(args))
@@ -275,7 +286,7 @@ trait Reifiers { self: Quasiquotes =>
case RefineStatPlaceholder(tree, _, DotDot) => reifyRefineStat(tree)
case EarlyDefPlaceholder(tree, _, DotDot) => reifyEarlyDef(tree)
case PackageStatPlaceholder(tree, _, DotDot) => reifyPackageStat(tree)
-
+ case ForEnumPlaceholder(tree, _, DotDot) => tree
case List(Placeholder(tree, _, DotDotDot)) => tree
} {
reify(_)
diff --git a/src/interactive/scala/tools/nsc/interactive/Global.scala b/src/interactive/scala/tools/nsc/interactive/Global.scala
index 736a1e68c4..94f9aef38b 100644
--- a/src/interactive/scala/tools/nsc/interactive/Global.scala
+++ b/src/interactive/scala/tools/nsc/interactive/Global.scala
@@ -13,7 +13,6 @@ import scala.tools.nsc.io.AbstractFile
import scala.reflect.internal.util.{ SourceFile, BatchSourceFile, Position, NoPosition }
import scala.tools.nsc.reporters._
import scala.tools.nsc.symtab._
-import scala.tools.nsc.doc.ScaladocAnalyzer
import scala.tools.nsc.typechecker.Analyzer
import symtab.Flags.{ACCESSOR, PARAMACCESSOR}
import scala.annotation.{ elidable, tailrec }
@@ -32,13 +31,6 @@ trait CommentPreservingTypers extends Typers {
override def resetDocComments() = {}
}
-trait InteractiveScaladocAnalyzer extends InteractiveAnalyzer with ScaladocAnalyzer {
- val global : Global
- override def newTyper(context: Context) = new Typer(context) with InteractiveTyper with ScaladocTyper {
- override def canAdaptConstantTypeToLiteral = false
- }
-}
-
trait InteractiveAnalyzer extends Analyzer {
val global : Global
import global._
diff --git a/src/interactive/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala b/src/interactive/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
index 9a2abd5139..29e546f9fe 100644
--- a/src/interactive/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
+++ b/src/interactive/scala/tools/nsc/interactive/tests/core/PresentationCompilerInstance.scala
@@ -7,22 +7,16 @@ import reporters.{Reporter => CompilerReporter}
/** Trait encapsulating the creation of a presentation compiler's instance.*/
private[tests] trait PresentationCompilerInstance extends TestSettings {
protected val settings = new Settings
- protected val withDocComments = false
protected val compilerReporter: CompilerReporter = new InteractiveReporter {
override def compiler = PresentationCompilerInstance.this.compiler
}
- private class ScaladocEnabledGlobal extends Global(settings, compilerReporter) {
- override lazy val analyzer = new {
- val global: ScaladocEnabledGlobal.this.type = ScaladocEnabledGlobal.this
- } with InteractiveScaladocAnalyzer
- }
+ protected def createGlobal: Global = new Global(settings, compilerReporter)
protected lazy val compiler: Global = {
prepareSettings(settings)
- if (withDocComments) new ScaladocEnabledGlobal
- else new Global(settings, compilerReporter)
+ createGlobal
}
/**
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala
index 3b588e261f..cd96b5182c 100644
--- a/src/library/scala/Predef.scala
+++ b/src/library/scala/Predef.scala
@@ -244,33 +244,33 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef {
// implicit classes -----------------------------------------------------
- implicit final class ArrowAssoc[A](val __leftOfArrow: A) extends AnyVal {
- @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(__leftOfArrow, y)
+ implicit final class ArrowAssoc[A](private val self: A) extends AnyVal {
+ @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y)
def →[B](y: B): Tuple2[A, B] = ->(y)
}
- implicit final class Ensuring[A](val __resultOfEnsuring: A) extends AnyVal {
- def ensuring(cond: Boolean): A = { assert(cond); __resultOfEnsuring }
- def ensuring(cond: Boolean, msg: => Any): A = { assert(cond, msg); __resultOfEnsuring }
- def ensuring(cond: A => Boolean): A = { assert(cond(__resultOfEnsuring)); __resultOfEnsuring }
- def ensuring(cond: A => Boolean, msg: => Any): A = { assert(cond(__resultOfEnsuring), msg); __resultOfEnsuring }
+ implicit final class Ensuring[A](private val self: A) extends AnyVal {
+ def ensuring(cond: Boolean): A = { assert(cond); self }
+ def ensuring(cond: Boolean, msg: => Any): A = { assert(cond, msg); self }
+ def ensuring(cond: A => Boolean): A = { assert(cond(self)); self }
+ def ensuring(cond: A => Boolean, msg: => Any): A = { assert(cond(self), msg); self }
}
- implicit final class StringFormat[A](val __stringToFormat: A) extends AnyVal {
+ implicit final class StringFormat[A](private val self: A) extends AnyVal {
/** Returns string formatted according to given `format` string.
* Format strings are as for `String.format`
* (@see java.lang.String.format).
*/
- @inline def formatted(fmtstr: String): String = fmtstr format __stringToFormat
+ @inline def formatted(fmtstr: String): String = fmtstr format self
}
- implicit final class StringAdd[A](val __thingToAdd: A) extends AnyVal {
- def +(other: String) = String.valueOf(__thingToAdd) + other
+ implicit final class StringAdd[A](private val self: A) extends AnyVal {
+ def +(other: String) = String.valueOf(self) + other
}
- implicit final class RichException(val __throwableToEnrich: Throwable) extends AnyVal {
+ implicit final class RichException(private val self: Throwable) extends AnyVal {
import scala.compat.Platform.EOL
- @deprecated("Use Throwable#getStackTrace", "2.11.0") def getStackTraceString = __throwableToEnrich.getStackTrace().mkString("", EOL, EOL)
+ @deprecated("Use Throwable#getStackTrace", "2.11.0") def getStackTraceString = self.getStackTrace().mkString("", EOL, EOL)
}
implicit final class SeqCharSequence(val __sequenceOfChars: scala.collection.IndexedSeq[Char]) extends CharSequence {
diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala
index 0220d33628..b949bec48a 100644
--- a/src/library/scala/collection/mutable/PriorityQueue.scala
+++ b/src/library/scala/collection/mutable/PriorityQueue.scala
@@ -43,7 +43,7 @@ class PriorityQueue[A](implicit val ord: Ordering[A])
{
import ord._
- private class ResizableArrayAccess[A] extends AbstractSeq[A] with ResizableArray[A] {
+ private class ResizableArrayAccess[A] extends AbstractSeq[A] with ResizableArray[A] with Serializable {
def p_size0 = size0
def p_size0_=(s: Int) = size0 = s
def p_array = array
diff --git a/src/library/scala/concurrent/Future.scala b/src/library/scala/concurrent/Future.scala
index b9f73c2872..dd86af0dd4 100644
--- a/src/library/scala/concurrent/Future.scala
+++ b/src/library/scala/concurrent/Future.scala
@@ -29,11 +29,11 @@ import scala.reflect.ClassTag
/** The trait that represents futures.
*
- * Asynchronous computations that yield futures are created with the `future` call:
+ * Asynchronous computations that yield futures are created with the `Future` call:
*
* {{{
* val s = "Hello"
- * val f: Future[String] = future {
+ * val f: Future[String] = Future {
* s + " future!"
* }
* f onSuccess {
@@ -67,8 +67,8 @@ import scala.reflect.ClassTag
* Example:
*
* {{{
- * val f = future { 5 }
- * val g = future { 3 }
+ * val f = Future { 5 }
+ * val g = Future { 3 }
* val h = for {
* x: Int <- f // returns Future(5)
* y: Int <- g // returns Future(3)
@@ -266,7 +266,7 @@ trait Future[+T] extends Awaitable[T] {
*
* Example:
* {{{
- * val f = future { 5 }
+ * val f = Future { 5 }
* val g = f filter { _ % 2 == 1 }
* val h = f filter { _ % 2 == 0 }
* Await.result(g, Duration.Zero) // evaluates to 5
@@ -291,7 +291,7 @@ trait Future[+T] extends Awaitable[T] {
*
* Example:
* {{{
- * val f = future { -5 }
+ * val f = Future { -5 }
* val g = f collect {
* case x if x < 0 => -x
* }
@@ -314,9 +314,9 @@ trait Future[+T] extends Awaitable[T] {
* Example:
*
* {{{
- * future (6 / 0) recover { case e: ArithmeticException => 0 } // result: 0
- * future (6 / 0) recover { case e: NotFoundException => 0 } // result: exception
- * future (6 / 2) recover { case e: ArithmeticException => 0 } // result: 3
+ * Future (6 / 0) recover { case e: ArithmeticException => 0 } // result: 0
+ * Future (6 / 0) recover { case e: NotFoundException => 0 } // result: exception
+ * Future (6 / 2) recover { case e: ArithmeticException => 0 } // result: 3
* }}}
*/
def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = {
@@ -334,8 +334,8 @@ trait Future[+T] extends Awaitable[T] {
* Example:
*
* {{{
- * val f = future { Int.MaxValue }
- * future (6 / 0) recoverWith { case e: ArithmeticException => f } // result: Int.MaxValue
+ * val f = Future { Int.MaxValue }
+ * Future (6 / 0) recoverWith { case e: ArithmeticException => f } // result: Int.MaxValue
* }}}
*/
def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = {
@@ -373,8 +373,8 @@ trait Future[+T] extends Awaitable[T] {
*
* Example:
* {{{
- * val f = future { sys.error("failed") }
- * val g = future { 5 }
+ * val f = Future { sys.error("failed") }
+ * val g = Future { 5 }
* val h = f fallbackTo g
* Await.result(h, Duration.Zero) // evaluates to 5
* }}}
@@ -416,7 +416,7 @@ trait Future[+T] extends Awaitable[T] {
* The following example prints out `5`:
*
* {{{
- * val f = future { 5 }
+ * val f = Future { 5 }
* f andThen {
* case r => sys.error("runtime exception")
* } andThen {
diff --git a/src/library/scala/concurrent/duration/package.scala b/src/library/scala/concurrent/duration/package.scala
index b32d2b20cb..d166975445 100644
--- a/src/library/scala/concurrent/duration/package.scala
+++ b/src/library/scala/concurrent/duration/package.scala
@@ -40,15 +40,15 @@ package object duration {
implicit def pairLongToDuration(p: (Long, TimeUnit)): FiniteDuration = Duration(p._1, p._2)
implicit def durationToPair(d: Duration): (Long, TimeUnit) = (d.length, d.unit)
- implicit final class DurationInt(val n: Int) extends AnyVal with DurationConversions {
+ implicit final class DurationInt(private val n: Int) extends AnyVal with DurationConversions {
override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n.toLong, unit)
}
- implicit final class DurationLong(val n: Long) extends AnyVal with DurationConversions {
+ implicit final class DurationLong(private val n: Long) extends AnyVal with DurationConversions {
override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit)
}
- implicit final class DurationDouble(val d: Double) extends AnyVal with DurationConversions {
+ implicit final class DurationDouble(private val d: Double) extends AnyVal with DurationConversions {
override protected def durationIn(unit: TimeUnit): FiniteDuration =
Duration(d, unit) match {
case f: FiniteDuration => f
@@ -59,17 +59,17 @@ package object duration {
/*
* Avoid reflection based invocation by using non-duck type
*/
- implicit final class IntMult(val i: Int) extends AnyVal {
+ implicit final class IntMult(private val i: Int) extends AnyVal {
def *(d: Duration) = d * i.toDouble
def *(d: FiniteDuration) = d * i.toLong
}
- implicit final class LongMult(val i: Long) extends AnyVal {
+ implicit final class LongMult(private val i: Long) extends AnyVal {
def *(d: Duration) = d * i.toDouble
def *(d: FiniteDuration) = d * i.toLong
}
- implicit final class DoubleMult(val f: Double) extends AnyVal {
+ implicit final class DoubleMult(private val f: Double) extends AnyVal {
def *(d: Duration) = d * f.toDouble
}
}
diff --git a/src/library/scala/concurrent/package.scala b/src/library/scala/concurrent/package.scala
index 2fe14a9c1a..cc1350f5a9 100644
--- a/src/library/scala/concurrent/package.scala
+++ b/src/library/scala/concurrent/package.scala
@@ -27,6 +27,8 @@ package object concurrent {
* @param executor the execution context on which the future is run
* @return the `Future` holding the result of the computation
*/
+ @deprecated("Use `Future { ... }` instead.", "2.11.0")
+ // removal planned for 2.13.0
def future[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = Future[T](body)
/** Creates a promise object which can be completed with a value or an exception.
@@ -34,6 +36,8 @@ package object concurrent {
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
+ @deprecated("Use `Promise[T]()` instead.", "2.11.0")
+ // removal planned for 2.13.0
def promise[T](): Promise[T] = Promise[T]()
/** Used to designate a piece of code which potentially blocks, allowing the current [[BlockContext]] to adjust
diff --git a/src/library/scala/util/Either.scala b/src/library/scala/util/Either.scala
index 523270b31c..b1a932be7e 100644
--- a/src/library/scala/util/Either.scala
+++ b/src/library/scala/util/Either.scala
@@ -216,7 +216,7 @@ object Either {
* r.merge: Seq[Int] // Vector(1)
* }}}
*/
- implicit class MergeableEither[A](val x: Either[A, A]) extends AnyVal {
+ implicit class MergeableEither[A](private val x: Either[A, A]) extends AnyVal {
def merge: A = x match {
case Left(a) => a
case Right(a) => a
diff --git a/src/partest-extras/scala/tools/partest/Util.scala b/src/partest-extras/scala/tools/partest/Util.scala
index 114658b0cd..8214396291 100644
--- a/src/partest-extras/scala/tools/partest/Util.scala
+++ b/src/partest-extras/scala/tools/partest/Util.scala
@@ -16,8 +16,8 @@ object Util {
*/
def trace[A](a: A) = macro traceImpl[A]
- import scala.reflect.macros.Context
- def traceImpl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]): c.Expr[A] = {
+ import scala.reflect.macros.BlackboxContext
+ def traceImpl[A: c.WeakTypeTag](c: BlackboxContext)(a: c.Expr[A]): c.Expr[A] = {
import c.universe._
import definitions._
diff --git a/src/reflect/scala/reflect/api/BuildUtils.scala b/src/reflect/scala/reflect/api/BuildUtils.scala
index 28551b1dcd..cf05aefe72 100644
--- a/src/reflect/scala/reflect/api/BuildUtils.scala
+++ b/src/reflect/scala/reflect/api/BuildUtils.scala
@@ -223,5 +223,34 @@ private[reflect] trait BuildUtils { self: Universe =>
def apply(lhs: Tree, rhs: Tree): Tree
def unapply(tree: Tree): Option[(Tree, Tree)]
}
+
+ val SyntacticValFrom: SyntacticValFromExtractor
+
+ trait SyntacticValFromExtractor {
+ def apply(pat: Tree, rhs: Tree): Tree
+ def unapply(tree: Tree): Option[(Tree, Tree)]
+ }
+
+ val SyntacticValEq: SyntacticValEqExtractor
+
+ trait SyntacticValEqExtractor {
+ def apply(pat: Tree, rhs: Tree): Tree
+ def unapply(tree: Tree): Option[(Tree, Tree)]
+ }
+
+ val SyntacticFilter: SyntacticFilterExtractor
+
+ trait SyntacticFilterExtractor {
+ def apply(test: Tree): Tree
+ def unapply(tree: Tree): Option[(Tree)]
+ }
+
+ val SyntacticFor: SyntacticForExtractor
+ val SyntacticForYield: SyntacticForExtractor
+
+ trait SyntacticForExtractor {
+ def apply(enums: List[Tree], body: Tree): Tree
+ def unapply(tree: Tree): Option[(List[Tree], Tree)]
+ }
}
}
diff --git a/src/reflect/scala/reflect/api/Exprs.scala b/src/reflect/scala/reflect/api/Exprs.scala
index 5b6ff2325c..50c8aa8779 100644
--- a/src/reflect/scala/reflect/api/Exprs.scala
+++ b/src/reflect/scala/reflect/api/Exprs.scala
@@ -106,7 +106,7 @@ trait Exprs { self: Universe =>
*
* The corresponding macro implementation should have the following signature (note how the return type denotes path-dependency on x):
* {{{
- * object Impls { def foo_impl(c: Context)(x: c.Expr[X]): c.Expr[x.value.T] = ... }
+ * object Impls { def foo_impl(c: BlackboxContext)(x: c.Expr[X]): c.Expr[x.value.T] = ... }
* }}}
*/
@compileTimeOnly("cannot use value except for signatures of macro implementations")
diff --git a/src/reflect/scala/reflect/api/Importers.scala b/src/reflect/scala/reflect/api/Importers.scala
index 4182b7d0ba..e239b86452 100644
--- a/src/reflect/scala/reflect/api/Importers.scala
+++ b/src/reflect/scala/reflect/api/Importers.scala
@@ -34,7 +34,7 @@ package api
* {{{
* def staticEval[T](x: T) = macro staticEval[T]
*
- * def staticEval[T](c: scala.reflect.macros.Context)(x: c.Expr[T]) = {
+ * def staticEval[T](c: scala.reflect.macros.BlackboxContext)(x: c.Expr[T]) = {
* // creates a runtime reflection universe to host runtime compilation
* import scala.reflect.runtime.{universe => ru}
* val mirror = ru.runtimeMirror(c.libraryClassLoader)
diff --git a/src/reflect/scala/reflect/api/Mirrors.scala b/src/reflect/scala/reflect/api/Mirrors.scala
index ec128e31a3..a4cd531053 100644
--- a/src/reflect/scala/reflect/api/Mirrors.scala
+++ b/src/reflect/scala/reflect/api/Mirrors.scala
@@ -29,19 +29,19 @@ package api
* Compile-time `Mirror`s make use of only classloader `Mirror`s to load `Symbol`s
* by name.
*
- * The entry point to classloader `Mirror`s is via [[scala.reflect.macros.Context#mirror]].
+ * The entry point to classloader `Mirror`s is via [[scala.reflect.macros.BlackboxContext#mirror]] or [[scala.reflect.macros.WhiteboxContext#mirror]].
* Typical methods which use classloader `Mirror`s include [[scala.reflect.api.Mirror#staticClass]],
* [[scala.reflect.api.Mirror#staticModule]], and [[scala.reflect.api.Mirror#staticPackage]]. For
* example:
* {{{
- * import scala.reflect.macros.Context
+ * import scala.reflect.macros.BlackboxContext
*
* case class Location(filename: String, line: Int, column: Int)
*
* object Macros {
* def currentLocation: Location = macro impl
*
- * def impl(c: Context): c.Expr[Location] = {
+ * def impl(c: BlackboxContext): c.Expr[Location] = {
* import c.universe._
* val pos = c.macroApplication.pos
* val clsLocation = c.mirror.staticModule("Location") // get symbol of "Location" object
diff --git a/src/reflect/scala/reflect/api/Quasiquotes.scala b/src/reflect/scala/reflect/api/Quasiquotes.scala
index 3687ccba63..fcf8edcec7 100644
--- a/src/reflect/scala/reflect/api/Quasiquotes.scala
+++ b/src/reflect/scala/reflect/api/Quasiquotes.scala
@@ -14,5 +14,6 @@ trait Quasiquotes { self: Universe =>
object tq extends api
object cq extends api
object pq extends api
+ object fq extends api
}
}
diff --git a/src/reflect/scala/reflect/api/Universe.scala b/src/reflect/scala/reflect/api/Universe.scala
index 77b4827eab..534f69a23e 100644
--- a/src/reflect/scala/reflect/api/Universe.scala
+++ b/src/reflect/scala/reflect/api/Universe.scala
@@ -41,10 +41,11 @@ package api
* res1: reflect.runtime.universe.Type = scala.Either[String,Int]
* }}}
*
- * To obtain a `Universe` for use within a Scala macro, use [[scala.reflect.macros.Context#universe]]. For example:
+ * To obtain a `Universe` for use within a Scala macro, use [[scala.reflect.macros.BlackboxContext#universe]].
+ * or [[scala.reflect.macros.WhiteboxContext#universe]]. For example:
* {{{
* def printf(format: String, params: Any*): Unit = macro impl
- * def impl(c: Context)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = {
+ * def impl(c: BlackboxContext)(format: c.Expr[String], params: c.Expr[Any]*): c.Expr[Unit] = {
* import c.universe._
* ...
* }
diff --git a/src/reflect/scala/reflect/internal/BuildUtils.scala b/src/reflect/scala/reflect/internal/BuildUtils.scala
index fc6b26db3f..8fc1869dd2 100644
--- a/src/reflect/scala/reflect/internal/BuildUtils.scala
+++ b/src/reflect/scala/reflect/internal/BuildUtils.scala
@@ -9,7 +9,6 @@ trait BuildUtils { self: SymbolTable =>
import definitions.{TupleClass, FunctionClass, ScalaPackage, UnitClass}
class BuildImpl extends BuildApi {
-
def selectType(owner: Symbol, name: String): TypeSymbol =
select(owner, newTypeName(name)).asType
@@ -19,7 +18,7 @@ trait BuildUtils { self: SymbolTable =>
else result
}
- private def select(owner: Symbol, name: Name): Symbol = {
+ protected def select(owner: Symbol, name: Name): Symbol = {
val result = owner.info decl name
if (result ne NoSymbol) result
else
@@ -135,7 +134,7 @@ trait BuildUtils { self: SymbolTable =>
def withFreshTypeName[T](prefix: String)(f: TypeName => T): T = f(freshTypeName(prefix))
- private implicit def fresh: FreshNameCreator = self.currentFreshNameCreator
+ protected implicit def fresh: FreshNameCreator = self.currentFreshNameCreator
object FlagsRepr extends FlagsReprExtractor {
def apply(bits: Long): FlagSet = bits
@@ -175,7 +174,8 @@ trait BuildUtils { self: SymbolTable =>
}
}
- private object UnCtor {
+ // recover constructor contents generated by gen.mkTemplate
+ protected object UnCtor {
def unapply(tree: Tree): Option[(Modifiers, List[List[ValDef]], List[Tree])] = tree match {
case DefDef(mods, nme.MIXIN_CONSTRUCTOR, _, _, _, Block(lvdefs, _)) =>
Some((mods | Flag.TRAIT, Nil, lvdefs))
@@ -185,7 +185,8 @@ trait BuildUtils { self: SymbolTable =>
}
}
- private object UnMkTemplate {
+ // undo gen.mkTemplate
+ protected object UnMkTemplate {
def unapply(templ: Template): Option[(List[Tree], ValDef, Modifiers, List[List[ValDef]], List[Tree], List[Tree])] = {
val Template(parents, selfType, tbody) = templ
def result(ctorMods: Modifiers, vparamss: List[List[ValDef]], edefs: List[Tree], body: List[Tree]) =
@@ -297,8 +298,8 @@ trait BuildUtils { self: SymbolTable =>
}
}
- private trait ScalaMemberRef {
- val symbols: Seq[Symbol]
+ // match references to `scala.$name`
+ protected class ScalaMemberRef(symbols: Seq[Symbol]) {
def result(name: Name): Option[Symbol] =
symbols.collect { case sym if sym.name == name => sym }.headOption
def unapply(tree: Tree): Option[Symbol] = tree match {
@@ -311,31 +312,23 @@ trait BuildUtils { self: SymbolTable =>
case _ => None
}
}
- private object TupleClassRef extends ScalaMemberRef {
- val symbols = TupleClass.seq
- }
- private object TupleCompanionRef extends ScalaMemberRef {
- val symbols = TupleClass.seq.map { _.companionModule }
- }
- private object UnitClassRef extends ScalaMemberRef {
- val symbols = Seq(UnitClass)
- }
- private object FunctionClassRef extends ScalaMemberRef {
- val symbols = FunctionClass.seq
- }
+ protected object TupleClassRef extends ScalaMemberRef(TupleClass.seq)
+ protected object TupleCompanionRef extends ScalaMemberRef(TupleClass.seq.map { _.companionModule })
+ protected object UnitClassRef extends ScalaMemberRef(Seq(UnitClass))
+ protected object FunctionClassRef extends ScalaMemberRef(FunctionClass.seq)
object SyntacticTuple extends SyntacticTupleExtractor {
- def apply(args: List[Tree]): Tree = args match {
- case Nil => Literal(Constant(()))
- case _ =>
- require(TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported")
- self.Apply(TupleClass(args.length).companionModule, args: _*)
+ def apply(args: List[Tree]): Tree = {
+ require(args.isEmpty || TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported")
+ gen.mkTuple(args, flattenUnary = false)
}
def unapply(tree: Tree): Option[List[Tree]] = tree match {
case Literal(Constant(())) =>
Some(Nil)
- case Apply(TupleCompanionRef(sym), args) if sym == TupleClass(args.length).companionModule =>
+ case Apply(MaybeTypeTreeOriginal(SyntacticTypeApplied(MaybeSelectApply(TupleCompanionRef(sym)), targs)), args)
+ if sym == TupleClass(args.length).companionModule
+ && (targs.isEmpty || targs.length == args.length) =>
Some(args)
case _ =>
None
@@ -343,17 +336,16 @@ trait BuildUtils { self: SymbolTable =>
}
object SyntacticTupleType extends SyntacticTupleExtractor {
- def apply(args: List[Tree]): Tree = args match {
- case Nil => self.Select(self.Ident(nme.scala_), tpnme.Unit)
- case _ =>
- require(TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported")
- AppliedTypeTree(Ident(TupleClass(args.length)), args)
+ def apply(args: List[Tree]): Tree = {
+ require(args.isEmpty || TupleClass(args.length).exists, s"Tuples with ${args.length} arity aren't supported")
+ gen.mkTupleType(args, flattenUnary = false)
}
- def unapply(tree: Tree): Option[List[Tree]] = tree match {
- case UnitClassRef(_) =>
+ def unapply(tree: Tree): Option[List[Tree]] = tree match {
+ case MaybeTypeTreeOriginal(UnitClassRef(_)) =>
Some(Nil)
- case AppliedTypeTree(TupleClassRef(sym), args) if sym == TupleClass(args.length) =>
+ case MaybeTypeTreeOriginal(AppliedTypeTree(TupleClassRef(sym), args))
+ if sym == TupleClass(args.length) =>
Some(args)
case _ =>
None
@@ -367,7 +359,8 @@ trait BuildUtils { self: SymbolTable =>
}
def unapply(tree: Tree): Option[(List[Tree], Tree)] = tree match {
- case AppliedTypeTree(FunctionClassRef(sym), args @ (argtpes :+ restpe)) if sym == FunctionClass(args.length - 1) =>
+ case MaybeTypeTreeOriginal(AppliedTypeTree(FunctionClassRef(sym), args @ (argtpes :+ restpe)))
+ if sym == FunctionClass(args.length - 1) =>
Some((argtpes, restpe))
case _ => None
}
@@ -423,9 +416,7 @@ trait BuildUtils { self: SymbolTable =>
}
}
- trait SyntacticValDefBase extends SyntacticValDefExtractor {
- val isMutable: Boolean
-
+ protected class SyntacticValDefBase(isMutable: Boolean) extends SyntacticValDefExtractor {
def apply(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree) = {
val mods1 = if (isMutable) mods | MUTABLE else mods
ValDef(mods1, name, tpt, rhs)
@@ -438,9 +429,8 @@ trait BuildUtils { self: SymbolTable =>
None
}
}
-
- object SyntacticValDef extends SyntacticValDefBase { val isMutable = false }
- object SyntacticVarDef extends SyntacticValDefBase { val isMutable = true }
+ object SyntacticValDef extends SyntacticValDefBase(isMutable = false)
+ object SyntacticVarDef extends SyntacticValDefBase(isMutable = true)
object SyntacticAssign extends SyntacticAssignExtractor {
def apply(lhs: Tree, rhs: Tree): Tree = gen.mkAssign(lhs, rhs)
@@ -451,7 +441,238 @@ trait BuildUtils { self: SymbolTable =>
case _ => None
}
}
+
+ object SyntacticValFrom extends SyntacticValFromExtractor {
+ def apply(pat: Tree, rhs: Tree): Tree = gen.ValFrom(pat, gen.mkCheckIfRefutable(pat, rhs))
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case gen.ValFrom(pat, UnCheckIfRefutable(pat1, rhs1)) if pat.equalsStructure(pat1) =>
+ Some((pat, rhs1))
+ case gen.ValFrom(pat, rhs) =>
+ Some((pat, rhs))
+ case _ => None
+ }
+ }
+
+ object SyntacticValEq extends SyntacticValEqExtractor {
+ def apply(pat: Tree, rhs: Tree): Tree = gen.ValEq(pat, rhs)
+ def unapply(tree: Tree): Option[(Tree, Tree)] = gen.ValEq.unapply(tree)
+ }
+
+ object SyntacticFilter extends SyntacticFilterExtractor {
+ def apply(tree: Tree): Tree = gen.Filter(tree)
+ def unapply(tree: Tree): Option[Tree] = gen.Filter.unapply(tree)
+ }
+
+ // abstract over possible alternative representations of no type in valdef
+ protected object EmptyTypTree {
+ def unapply(tree: Tree): Boolean = tree match {
+ case EmptyTree => true
+ case tt: TypeTree if (tt.original == null || tt.original.isEmpty) => true
+ case _ => false
+ }
+ }
+
+ // match a sequence of desugared `val $pat = $value`
+ protected object UnPatSeq {
+ def unapply(trees: List[Tree]): Option[List[(Tree, Tree)]] = trees match {
+ case Nil => Some(Nil)
+ // case q"$mods val ${_}: ${_} = ${MaybeUnchecked(value)} match { case $pat => (..$ids) }" :: tail
+ case ValDef(mods, _, _, Match(MaybeUnchecked(value), CaseDef(pat, EmptyTree, SyntacticTuple(ids)) :: Nil)) :: tail
+ if mods.hasFlag(SYNTHETIC) && mods.hasFlag(ARTIFACT) =>
+ tail.drop(ids.length) match {
+ case UnPatSeq(rest) => Some((pat, value) :: rest)
+ case _ => None
+ }
+ // case q"${_} val $name1: ${_} = ${MaybeUnchecked(value)} match { case $pat => ${Ident(name2)} }" :: UnPatSeq(rest)
+ case ValDef(_, name1, _, Match(MaybeUnchecked(value), CaseDef(pat, EmptyTree, Ident(name2)) :: Nil)) :: UnPatSeq(rest)
+ if name1 == name2 =>
+ Some((pat, value) :: rest)
+ // case q"${_} val $name: ${EmptyTypTree()} = $value" :: UnPatSeq(rest) =>
+ case ValDef(_, name, EmptyTypTree(), value) :: UnPatSeq(rest) =>
+ Some((Bind(name, self.Ident(nme.WILDCARD)), value) :: rest)
+ // case q"${_} val $name: $tpt = $value" :: UnPatSeq(rest) =>
+ case ValDef(_, name, tpt, value) :: UnPatSeq(rest) =>
+ Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), value) :: rest)
+ case _ => None
+ }
+ }
+
+ // match a sequence of desugared `val $pat = $value` with a tuple in the end
+ protected object UnPatSeqWithRes {
+ def unapply(tree: Tree): Option[(List[(Tree, Tree)], List[Tree])] = tree match {
+ case SyntacticBlock(UnPatSeq(trees) :+ SyntacticTuple(elems)) => Some((trees, elems))
+ case _ => None
+ }
+ }
+
+ // undo gen.mkSyntheticParam
+ protected object UnSyntheticParam {
+ def unapply(tree: Tree): Option[TermName] = tree match {
+ case ValDef(mods, name, _, EmptyTree)
+ if mods.hasFlag(SYNTHETIC) && mods.hasFlag(PARAM) =>
+ Some(name)
+ case _ => None
+ }
+ }
+
+ // undo gen.mkVisitor
+ protected object UnVisitor {
+ def unapply(tree: Tree): Option[(TermName, List[CaseDef])] = tree match {
+ case Function(UnSyntheticParam(x1) :: Nil, Match(MaybeUnchecked(Ident(x2)), cases))
+ if x1 == x2 =>
+ Some((x1, cases))
+ case _ => None
+ }
+ }
+
+ // undo gen.mkFor:makeClosure
+ protected object UnClosure {
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case Function(ValDef(Modifiers(PARAM, _, _), name, tpt, EmptyTree) :: Nil, body) =>
+ tpt match {
+ case EmptyTypTree() => Some((Bind(name, self.Ident(nme.WILDCARD)), body))
+ case _ => Some((Bind(name, Typed(self.Ident(nme.WILDCARD), tpt)), body))
+ }
+ case UnVisitor(_, CaseDef(pat, EmptyTree, body) :: Nil) =>
+ Some((pat, body))
+ case _ => None
+ }
+ }
+
+ // match call to either withFilter or filter
+ protected object FilterCall {
+ def unapply(tree: Tree): Option[(Tree,Tree)] = tree match {
+ case Apply(Select(obj, nme.withFilter | nme.filter), arg :: Nil) =>
+ Some(obj, arg)
+ case _ => None
+ }
+ }
+
+ // transform a chain of withFilter calls into a sequence of for filters
+ protected object UnFilter {
+ def unapply(tree: Tree): Some[(Tree, List[Tree])] = tree match {
+ case UnCheckIfRefutable(_, _) =>
+ Some((tree, Nil))
+ case FilterCall(UnFilter(rhs, rest), UnClosure(_, test)) =>
+ Some((rhs, rest :+ SyntacticFilter(test)))
+ case _ =>
+ Some((tree, Nil))
+ }
+ }
+
+ // undo gen.mkCheckIfRefutable
+ protected object UnCheckIfRefutable {
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case FilterCall(rhs, UnVisitor(name,
+ CaseDef(pat, EmptyTree, Literal(Constant(true))) ::
+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false))) :: Nil))
+ if name.toString.contains(nme.CHECK_IF_REFUTABLE_STRING) =>
+ Some((pat, rhs))
+ case _ => None
+ }
+ }
+
+ // undo gen.mkFor:makeCombination accounting for possible extra implicit argument
+ protected class UnForCombination(name: TermName) {
+ def unapply(tree: Tree) = tree match {
+ case SyntacticApplied(SyntacticTypeApplied(sel @ Select(lhs, meth), _), (f :: Nil) :: Nil)
+ if name == meth && sel.hasAttachment[ForAttachment.type] =>
+ Some(lhs, f)
+ case SyntacticApplied(SyntacticTypeApplied(sel @ Select(lhs, meth), _), (f :: Nil) :: _ :: Nil)
+ if name == meth && sel.hasAttachment[ForAttachment.type] =>
+ Some(lhs, f)
+ case _ => None
+ }
+ }
+ protected object UnMap extends UnForCombination(nme.map)
+ protected object UnForeach extends UnForCombination(nme.foreach)
+ protected object UnFlatMap extends UnForCombination(nme.flatMap)
+
+ // undo desugaring done in gen.mkFor
+ protected object UnFor {
+ def unapply(tree: Tree): Option[(List[Tree], Tree)] = {
+ val interm = tree match {
+ case UnFlatMap(UnFilter(rhs, filters), UnClosure(pat, UnFor(rest, body))) =>
+ Some(((pat, rhs), filters ::: rest, body))
+ case UnForeach(UnFilter(rhs, filters), UnClosure(pat, UnFor(rest, body))) =>
+ Some(((pat, rhs), filters ::: rest, body))
+ case UnMap(UnFilter(rhs, filters), UnClosure(pat, cbody)) =>
+ Some(((pat, rhs), filters, gen.Yield(cbody)))
+ case UnForeach(UnFilter(rhs, filters), UnClosure(pat, cbody)) =>
+ Some(((pat, rhs), filters, cbody))
+ case _ => None
+ }
+ interm.flatMap {
+ case ((Bind(_, SyntacticTuple(_)) | SyntacticTuple(_),
+ UnFor(SyntacticValFrom(pat, rhs) :: innerRest, gen.Yield(UnPatSeqWithRes(pats, elems2)))),
+ outerRest, fbody) =>
+ val valeqs = pats.map { case (pat, rhs) => SyntacticValEq(pat, rhs) }
+ Some((SyntacticValFrom(pat, rhs) :: innerRest ::: valeqs ::: outerRest, fbody))
+ case ((pat, rhs), filters, body) =>
+ Some((SyntacticValFrom(pat, rhs) :: filters, body))
+ }
+ }
+ }
+
+ // check that enumerators are valid
+ protected def mkEnumerators(enums: List[Tree]): List[Tree] = {
+ require(enums.nonEmpty, "enumerators can't be empty")
+ enums.head match {
+ case SyntacticValFrom(_, _) =>
+ case t => throw new IllegalArgumentException(s"$t is not a valid fist enumerator of for loop")
+ }
+ enums.tail.foreach {
+ case SyntacticValEq(_, _) | SyntacticValFrom(_, _) | SyntacticFilter(_) =>
+ case t => throw new IllegalArgumentException(s"$t is not a valid representation of a for loop enumerator")
+ }
+ enums
+ }
+
+ object SyntacticFor extends SyntacticForExtractor {
+ def apply(enums: List[Tree], body: Tree): Tree = gen.mkFor(mkEnumerators(enums), body)
+ def unapply(tree: Tree) = tree match {
+ case UnFor(enums, gen.Yield(body)) => None
+ case UnFor(enums, body) => Some((enums, body))
+ case _ => None
+ }
+ }
+
+ object SyntacticForYield extends SyntacticForExtractor {
+ def apply(enums: List[Tree], body: Tree): Tree = gen.mkFor(mkEnumerators(enums), gen.Yield(body))
+ def unapply(tree: Tree) = tree match {
+ case UnFor(enums, gen.Yield(body)) => Some((enums, body))
+ case _ => None
+ }
+ }
+
+ // use typetree's original instead of typetree itself
+ protected object MaybeTypeTreeOriginal {
+ def unapply(tree: Tree): Some[Tree] = tree match {
+ case tt: TypeTree => Some(tt.original)
+ case _ => Some(tree)
+ }
+ }
+
+ // drop potential extra call to .apply
+ protected object MaybeSelectApply {
+ def unapply(tree: Tree): Some[Tree] = tree match {
+ case Select(f, nme.apply) => Some(f)
+ case other => Some(other)
+ }
+ }
+
+ // drop potential @scala.unchecked annotation
+ protected object MaybeUnchecked {
+ def unapply(tree: Tree): Some[Tree] = tree match {
+ case Annotated(SyntacticNew(Nil, Apply(ScalaDot(tpnme.unchecked), Nil) :: Nil, noSelfType, Nil), annottee) =>
+ Some(annottee)
+ case Typed(annottee, MaybeTypeTreeOriginal(
+ Annotated(SyntacticNew(Nil, Apply(ScalaDot(tpnme.unchecked), Nil) :: Nil, noSelfType, Nil), _))) =>
+ Some(annottee)
+ case annottee => Some(annottee)
+ }
+ }
}
- val build: BuildApi = new BuildImpl
+ val build: BuildImpl = new BuildImpl
}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 7cb051c63d..563f23cb3b 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -495,15 +495,18 @@ trait Definitions extends api.StandardDefinitions {
lazy val TreeCreatorClass = getClassIfDefined("scala.reflect.api.TreeCreator") // defined in scala-reflect.jar, so we need to be careful
lazy val LiftableClass = getClassIfDefined("scala.reflect.api.Liftable") // defined in scala-reflect.jar, so we need to be careful
- lazy val MacroClass = getClassIfDefined("scala.reflect.macros.Macro") // defined in scala-reflect.jar, so we need to be careful
- def MacroContextValue = MacroClass.map(sym => getMemberValue(sym, nme.c))
- lazy val MacroContextClass = getClassIfDefined("scala.reflect.macros.Context") // defined in scala-reflect.jar, so we need to be careful
- def MacroContextPrefix = MacroContextClass.map(sym => getMemberMethod(sym, nme.prefix))
- def MacroContextPrefixType = MacroContextClass.map(sym => getTypeMember(sym, tpnme.PrefixType))
- def MacroContextUniverse = MacroContextClass.map(sym => getMemberMethod(sym, nme.universe))
- def MacroContextExprClass = MacroContextClass.map(sym => getTypeMember(sym, tpnme.Expr))
- def MacroContextWeakTypeTagClass = MacroContextClass.map(sym => getTypeMember(sym, tpnme.WeakTypeTag))
- def MacroContextTreeType = MacroContextClass.map(sym => getTypeMember(sym, tpnme.Tree))
+ lazy val BlackboxMacroClass = getClassIfDefined("scala.reflect.macros.BlackboxMacro") // defined in scala-reflect.jar, so we need to be careful
+ def BlackboxMacroContextValue = BlackboxMacroClass.map(sym => getMemberValue(sym, nme.c))
+ lazy val WhiteboxMacroClass = getClassIfDefined("scala.reflect.macros.WhiteboxMacro") // defined in scala-reflect.jar, so we need to be careful
+ def WhiteboxMacroContextValue = WhiteboxMacroClass.map(sym => getMemberValue(sym, nme.c))
+ lazy val BlackboxContextClass = getClassIfDefined("scala.reflect.macros.BlackboxContext") // defined in scala-reflect.jar, so we need to be careful
+ lazy val WhiteboxContextClass = getClassIfDefined("scala.reflect.macros.WhiteboxContext") // defined in scala-reflect.jar, so we need to be careful
+ def MacroContextPrefix = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.prefix))
+ def MacroContextPrefixType = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.PrefixType))
+ def MacroContextUniverse = BlackboxContextClass.map(sym => getMemberMethod(sym, nme.universe))
+ def MacroContextExprClass = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.Expr))
+ def MacroContextWeakTypeTagClass = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.WeakTypeTag))
+ def MacroContextTreeType = BlackboxContextClass.map(sym => getTypeMember(sym, tpnme.Tree))
lazy val MacroImplAnnotation = requiredClass[scala.reflect.macros.internal.macroImpl]
lazy val StringContextClass = requiredClass[scala.StringContext]
@@ -593,18 +596,47 @@ trait Definitions extends api.StandardDefinitions {
def unspecializedTypeArgs(tp: Type): List[Type] =
(tp baseType unspecializedSymbol(tp.typeSymbolDirect)).typeArgs
+ object MacroContextType {
+ def unapply(tp: Type) = {
+ def isOneOfContextTypes(tp: Type) =
+ tp =:= BlackboxContextClass.tpe || tp =:= WhiteboxContextClass.tpe
+ def isPrefix(sym: Symbol) =
+ sym.allOverriddenSymbols.contains(MacroContextPrefixType)
+
+ tp.dealias match {
+ case RefinedType(List(tp), Scope(sym)) if isOneOfContextTypes(tp) && isPrefix(sym) => Some(tp)
+ case tp if isOneOfContextTypes(tp) => Some(tp)
+ case _ => None
+ }
+ }
+ }
+
+ def isMacroContextType(tp: Type) = MacroContextType.unapply(tp).isDefined
+
+ def isWhiteboxContextType(tp: Type) =
+ isMacroContextType(tp) && (tp <:< WhiteboxContextClass.tpe)
+
+ def mightBeMacroBundleType(tp: Type) =
+ tp.baseClasses.contains(WhiteboxMacroClass) ||
+ tp.baseClasses.contains(BlackboxMacroClass)
+
def isMacroBundleType(tp: Type) = tp.baseClasses match {
case _ :: proto :: _ if isMacroBundleProtoType(proto.tpe) => true
case _ => false
}
+ def isBlackboxMacroBundleType(tp: Type) =
+ isMacroBundleType(tp) && (tp <:< BlackboxMacroClass.tpe) && !(tp <:< WhiteboxMacroClass.tpe)
+
def isMacroBundleProtoType(tp: Type) = {
val sym = tp.typeSymbol
val isNonTrivial = tp != ErrorType && tp != NothingTpe && tp != NullTpe
- val isMacroCompatible = MacroClass != NoSymbol && tp.baseClasses.contains(MacroClass)
- val isBundlePrototype = sym != MacroClass && sym.isTrait && {
+ def subclasses(sym: Symbol) = sym != NoSymbol && tp.baseClasses.contains(sym)
+ val isMacroCompatible = subclasses(BlackboxMacroClass) ^ subclasses(WhiteboxMacroClass)
+ val isBundlePrototype = sym != BlackboxMacroClass && sym != WhiteboxMacroClass && sym.isTrait && {
val c = sym.info.member(nme.c)
- val cIsOk = c.overrideChain.contains(MacroContextValue) && c.isDeferred
+ def overrides(sym: Symbol) = c.overrideChain.contains(sym)
+ val cIsOk = (overrides(BlackboxMacroContextValue) || overrides(WhiteboxMacroContextValue)) && c.isDeferred
cIsOk && sym.isMonomorphicType
}
isNonTrivial && isMacroCompatible && isBundlePrototype
diff --git a/src/reflect/scala/reflect/internal/Importers.scala b/src/reflect/scala/reflect/internal/Importers.scala
index 72c8ccfa62..cc6e55192f 100644
--- a/src/reflect/scala/reflect/internal/Importers.scala
+++ b/src/reflect/scala/reflect/internal/Importers.scala
@@ -8,6 +8,16 @@ import scala.ref.WeakReference
// SI-6241: move importers to a mirror
trait Importers extends api.Importers { to: SymbolTable =>
+ /** Attachment that knows how to import itself into another universe. */
+ trait ImportableAttachment {
+ def importAttachment(importer: Importer): this.type
+ }
+
+ /** Attachment that doesn't contain any reflection artificats and can be imported as-is. */
+ trait PlainAttachment extends ImportableAttachment {
+ def importAttachment(importer: Importer): this.type = this
+ }
+
def mkImporter(from0: api.Universe): Importer { val from: from0.type } = (
if (to eq from0) {
new Importer {
@@ -417,11 +427,15 @@ trait Importers extends api.Importers { to: SymbolTable =>
my.setPos(importPosition(their.pos))
}
}
+ importAttachments(their.attachments.all).foreach { my.updateAttachment(_) }
my
}
// ============== MISCELLANEOUS ==============
+ def importAttachments(attachments: Set[Any]): Set[Any] =
+ attachments.collect { case ia: ImportableAttachment => ia.importAttachment(this) }
+
def importAnnotationInfo(ann: from.AnnotationInfo): AnnotationInfo = {
val atp1 = importType(ann.atp)
val args1 = ann.args map importTree
diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala
index 9eb66db01e..46f241643b 100644
--- a/src/reflect/scala/reflect/internal/StdAttachments.scala
+++ b/src/reflect/scala/reflect/internal/StdAttachments.scala
@@ -14,6 +14,7 @@ trait StdAttachments {
def setAttachments(attachments: scala.reflect.macros.Attachments { type Pos = Position }): this.type = { rawatt = attachments; this }
def updateAttachment[T: ClassTag](attachment: T): this.type = { rawatt = rawatt.update(attachment); this }
def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this }
+ def hasAttachment[T: ClassTag]: Boolean = rawatt.contains[T]
// cannot be final due to SynchronizedSymbols
def pos: Position = rawatt.pos
@@ -21,13 +22,17 @@ trait StdAttachments {
def setPos(newpos: Position): this.type = { pos = newpos; this }
}
- /** When present, indicates that the host `Ident` has been created from a backquoted identifier.
- */
- case object BackquotedIdentifierAttachment
-
/** Stores the trees that give rise to a refined type to be used in reification.
* Unfortunately typed `CompoundTypeTree` is lacking essential info, and the reifier cannot use `CompoundTypeTree.tpe`.
* Therefore we need this hack (see `Reshape.toPreTyperTypeTree` for a detailed explanation).
*/
case class CompoundTypeTreeOriginalAttachment(parents: List[Tree], stats: List[Tree])
+
+ /** When present, indicates that the host `Ident` has been created from a backquoted identifier.
+ */
+ case object BackquotedIdentifierAttachment extends PlainAttachment
+
+ /** Identifies trees are either result or intermidiate value of for loop desugaring.
+ */
+ case object ForAttachment extends PlainAttachment
}
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 02f22a16f6..c26e815df1 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -229,6 +229,7 @@ trait StdNames {
final val Serializable: NameType = "Serializable"
final val Singleton: NameType = "Singleton"
final val Throwable: NameType = "Throwable"
+ final val unchecked: NameType = "unchecked"
final val api: NameType = "api"
final val Annotation: NameType = "Annotation"
@@ -326,6 +327,7 @@ trait StdNames {
val QUASIQUOTE_FILE: String = "<quasiquote>"
val QUASIQUOTE_TUPLE: NameType = "$quasiquote$tuple$"
val QUASIQUOTE_CASE: NameType = "$quasiquote$case$"
+ val QUASIQUOTE_FOR_ENUM: NameType = "$quasiquote$for$enum$"
val MIXIN_CONSTRUCTOR: NameType = "$init$"
val MODULE_INSTANCE_FIELD: NameType = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$"
val OUTER: NameType = "$outer"
@@ -591,6 +593,9 @@ trait StdNames {
val SyntacticBlock: NameType = "SyntacticBlock"
val SyntacticClassDef: NameType = "SyntacticClassDef"
val SyntacticDefDef: NameType = "SyntacticDefDef"
+ val SyntacticFilter: NameType = "SyntacticFilter"
+ val SyntacticFor: NameType = "SyntacticFor"
+ val SyntacticForYield: NameType = "SyntacticForYield"
val SyntacticFunction: NameType = "SyntacticFunction"
val SyntacticFunctionType: NameType = "SyntacticFunctionType"
val SyntacticPackageObjectDef: NameType = "SyntacticPackageObjectDef"
@@ -601,6 +606,8 @@ trait StdNames {
val SyntacticTupleType: NameType = "SyntacticTupleType"
val SyntacticTypeApplied: NameType = "SyntacticTypeApplied"
val SyntacticValDef: NameType = "SyntacticValDef"
+ val SyntacticValEq: NameType = "SyntacticValEq"
+ val SyntacticValFrom: NameType = "SyntacticValFrom"
val SyntacticVarDef: NameType = "SyntacticVarDef"
val This: NameType = "This"
val ThisType: NameType = "ThisType"
@@ -744,7 +751,6 @@ trait StdNames {
val typedProductIterator: NameType = "typedProductIterator"
val TypeName: NameType = "TypeName"
val typeTagToManifest: NameType = "typeTagToManifest"
-
val unapply: NameType = "unapply"
val unapplySeq: NameType = "unapplySeq"
val unbox: NameType = "unbox"
@@ -763,6 +769,7 @@ trait StdNames {
val tq: NameType = "tq"
val cq: NameType = "cq"
val pq: NameType = "pq"
+ val fq: NameType = "fq"
// unencoded operators
object raw {
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala
index cf7c729a6a..a0bd64f850 100644
--- a/src/reflect/scala/reflect/internal/TreeGen.scala
+++ b/src/reflect/scala/reflect/internal/TreeGen.scala
@@ -4,6 +4,7 @@ package internal
import Flags._
import util._
+import scala.collection.mutable.ListBuffer
abstract class TreeGen extends macros.TreeBuilder {
val global: SymbolTable
@@ -279,11 +280,23 @@ abstract class TreeGen extends macros.TreeBuilder {
def mkNamedArg(lhs: Tree, rhs: Tree): Tree = atPos(rhs.pos)(AssignOrNamedArg(lhs, rhs))
/** Builds a tuple */
- def mkTuple(elems: List[Tree]): Tree =
- if (elems.isEmpty) Literal(Constant(()))
- else Apply(
- Select(mkAttributedRef(TupleClass(elems.length).caseModule), nme.apply),
- elems)
+ def mkTuple(elems: List[Tree], flattenUnary: Boolean = true): Tree = elems match {
+ case Nil =>
+ Literal(Constant(()))
+ case tree :: Nil if flattenUnary =>
+ tree
+ case _ =>
+ Apply(scalaDot(TupleClass(elems.length).companionModule.name), elems)
+ }
+
+ def mkTupleType(elems: List[Tree], flattenUnary: Boolean = true): Tree = elems match {
+ case Nil =>
+ scalaDot(tpnme.Unit)
+ case List(tree) if flattenUnary =>
+ tree
+ case _ =>
+ AppliedTypeTree(scalaDot(TupleClass(elems.length).name), elems)
+ }
// tree1 AND tree2
def mkAnd(tree1: Tree, tree2: Tree): Tree =
@@ -299,7 +312,7 @@ abstract class TreeGen extends macros.TreeBuilder {
}
def mkSeqApply(arg: Tree): Apply = {
- val factory = Select(gen.mkAttributedRef(SeqModule), nme.apply)
+ val factory = Select(mkAttributedRef(SeqModule), nme.apply)
Apply(factory, List(arg))
}
@@ -436,17 +449,15 @@ abstract class TreeGen extends macros.TreeBuilder {
else Block(stats.init, stats.last)
def mkTreeOrBlock(stats: List[Tree]) = stats match {
- case Nil => EmptyTree
+ case Nil => EmptyTree
case head :: Nil => head
- case _ => gen.mkBlock(stats)
+ case _ => mkBlock(stats)
}
/** Create a tree representing an assignment <lhs = rhs> */
def mkAssign(lhs: Tree, rhs: Tree): Tree = lhs match {
- case Apply(fn, args) =>
- Apply(atPos(fn.pos)(Select(fn, nme.update)), args :+ rhs)
- case _ =>
- Assign(lhs, rhs)
+ case Apply(fn, args) => Apply(atPos(fn.pos)(Select(fn, nme.update)), args :+ rhs)
+ case _ => Assign(lhs, rhs)
}
def mkPackageObject(defn: ModuleDef, pidPos: Position = NoPosition, pkgPos: Position = NoPosition) = {
@@ -454,4 +465,419 @@ abstract class TreeGen extends macros.TreeBuilder {
val pid = atPos(pidPos)(Ident(defn.name))
atPos(pkgPos)(PackageDef(pid, module :: Nil))
}
+
+ // Following objects represent encoding of for loop enumerators
+ // into the regular trees. Such representations are used for:
+ //
+ // - as intermediate value of enumerators inside of the parser
+ // right before the mkFor desugaring is being called
+ //
+ // - as intermediate value of enumerators obtained after
+ // re-sugaring of for loops through build.SyntacticFor
+ // and build.SyntacticForYield (which are used by quasiquotes)
+ //
+ // The encoding uses regular trees with ForAttachment that helps
+ // to reliably differentiate them from normal trees that can have
+ // similar shape. fq"$pat <- $rhs" for example is represented in
+ // the same way as "`<-`($pat, $rhs)"" but with added attachment to
+ // the `<-` identifier.
+ //
+ // The primary rationale behind such representation in favor of
+ // simple case classes is a wish to re-use the same representation
+ // between quasiquotes and parser without exposing compiler internals.
+ // Opaque tree encoding can be changed/adapted at any time without
+ // breaking end users code.
+
+ /** Encode/decode fq"$pat <- $rhs" enumerator as q"`<-`($pat, $rhs)" */
+ object ValFrom {
+ def apply(pat: Tree, rhs: Tree): Tree =
+ Apply(Ident(nme.LARROWkw).updateAttachment(ForAttachment),
+ List(pat, rhs))
+
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case Apply(id @ Ident(nme.LARROWkw), List(pat, rhs))
+ if id.hasAttachment[ForAttachment.type] =>
+ Some((pat, rhs))
+ case _ => None
+ }
+ }
+
+ /** Encode/decode fq"$pat = $rhs" enumerator as q"$pat = $rhs" */
+ object ValEq {
+ def apply(pat: Tree, rhs: Tree): Tree =
+ Assign(pat, rhs).updateAttachment(ForAttachment)
+
+ def unapply(tree: Tree): Option[(Tree, Tree)] = tree match {
+ case Assign(pat, rhs)
+ if tree.hasAttachment[ForAttachment.type] =>
+ Some((pat, rhs))
+ case _ => None
+ }
+ }
+
+ /** Encode/decode fq"if $cond" enumerator as q"`if`($cond)" */
+ object Filter {
+ def apply(tree: Tree) =
+ Apply(Ident(nme.IFkw).updateAttachment(ForAttachment), List(tree))
+
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Apply(id @ Ident(nme.IFkw), List(cond))
+ if id.hasAttachment[ForAttachment.type] =>
+ Some((cond))
+ case _ => None
+ }
+ }
+
+ /** Encode/decode body of for yield loop as q"`yield`($tree)" */
+ object Yield {
+ def apply(tree: Tree): Tree =
+ Apply(Ident(nme.YIELDkw).updateAttachment(ForAttachment), List(tree))
+
+ def unapply(tree: Tree): Option[Tree] = tree match {
+ case Apply(id @ Ident(nme.YIELDkw), List(tree))
+ if id.hasAttachment[ForAttachment.type] =>
+ Some(tree)
+ case _ => None
+ }
+ }
+
+ /** Create tree for for-comprehension <for (enums) do body> or
+ * <for (enums) yield body> where mapName and flatMapName are chosen
+ * corresponding to whether this is a for-do or a for-yield.
+ * The creation performs the following rewrite rules:
+ *
+ * 1.
+ *
+ * for (P <- G) E ==> G.foreach (P => E)
+ *
+ * Here and in the following (P => E) is interpreted as the function (P => E)
+ * if P is a variable pattern and as the partial function { case P => E } otherwise.
+ *
+ * 2.
+ *
+ * for (P <- G) yield E ==> G.map (P => E)
+ *
+ * 3.
+ *
+ * for (P_1 <- G_1; P_2 <- G_2; ...) ...
+ * ==>
+ * G_1.flatMap (P_1 => for (P_2 <- G_2; ...) ...)
+ *
+ * 4.
+ *
+ * for (P <- G; E; ...) ...
+ * =>
+ * for (P <- G.filter (P => E); ...) ...
+ *
+ * 5. For N < MaxTupleArity:
+ *
+ * for (P_1 <- G; P_2 = E_2; val P_N = E_N; ...)
+ * ==>
+ * for (TupleN(P_1, P_2, ... P_N) <-
+ * for (x_1 @ P_1 <- G) yield {
+ * val x_2 @ P_2 = E_2
+ * ...
+ * val x_N & P_N = E_N
+ * TupleN(x_1, ..., x_N)
+ * } ...)
+ *
+ * If any of the P_i are variable patterns, the corresponding `x_i @ P_i' is not generated
+ * and the variable constituting P_i is used instead of x_i
+ *
+ * @param mapName The name to be used for maps (either map or foreach)
+ * @param flatMapName The name to be used for flatMaps (either flatMap or foreach)
+ * @param enums The enumerators in the for expression
+ * @param body The body of the for expression
+ */
+ def mkFor(enums: List[Tree], sugarBody: Tree)(implicit fresh: FreshNameCreator): Tree = {
+ val (mapName, flatMapName, body) = sugarBody match {
+ case Yield(tree) => (nme.map, nme.flatMap, tree)
+ case _ => (nme.foreach, nme.foreach, sugarBody)
+ }
+
+ /* make a closure pat => body.
+ * The closure is assigned a transparent position with the point at pos.point and
+ * the limits given by pat and body.
+ */
+ def makeClosure(pos: Position, pat: Tree, body: Tree): Tree = {
+ def wrapped = wrappingPos(List(pat, body))
+ def splitpos = (if (pos != NoPosition) wrapped.withPoint(pos.point) else pos).makeTransparent
+ matchVarPattern(pat) match {
+ case Some((name, tpt)) =>
+ Function(
+ List(atPos(pat.pos) { ValDef(Modifiers(PARAM), name.toTermName, tpt, EmptyTree) }),
+ body) setPos splitpos
+ case None =>
+ atPos(splitpos) {
+ mkVisitor(List(CaseDef(pat, EmptyTree, body)), checkExhaustive = false)
+ }
+ }
+ }
+
+ /* Make an application qual.meth(pat => body) positioned at `pos`.
+ */
+ def makeCombination(pos: Position, meth: TermName, qual: Tree, pat: Tree, body: Tree): Tree =
+ // ForAttachment on the method selection is used to differentiate
+ // result of for desugaring from a regular method call
+ Apply(Select(qual, meth) setPos qual.pos updateAttachment ForAttachment,
+ List(makeClosure(pos, pat, body))) setPos pos
+
+ /* If `pat` is not yet a `Bind` wrap it in one with a fresh name */
+ def makeBind(pat: Tree): Tree = pat match {
+ case Bind(_, _) => pat
+ case _ => Bind(freshTermName(), pat) setPos pat.pos
+ }
+
+ /* A reference to the name bound in Bind `pat`. */
+ def makeValue(pat: Tree): Tree = pat match {
+ case Bind(name, _) => Ident(name) setPos pat.pos.focus
+ }
+
+ /* The position of the closure that starts with generator at position `genpos`. */
+ def closurePos(genpos: Position) =
+ if (genpos == NoPosition) NoPosition
+ else {
+ val end = body.pos match {
+ case NoPosition => genpos.point
+ case bodypos => bodypos.end
+ }
+ rangePos(genpos.source, genpos.start, genpos.point, end)
+ }
+
+ enums match {
+ case (t @ ValFrom(pat, rhs)) :: Nil =>
+ makeCombination(closurePos(t.pos), mapName, rhs, pat, body)
+ case (t @ ValFrom(pat, rhs)) :: (rest @ (ValFrom(_, _) :: _)) =>
+ makeCombination(closurePos(t.pos), flatMapName, rhs, pat,
+ mkFor(rest, sugarBody))
+ case (t @ ValFrom(pat, rhs)) :: Filter(test) :: rest =>
+ mkFor(ValFrom(pat, makeCombination(rhs.pos union test.pos, nme.withFilter, rhs, pat.duplicate, test)).setPos(t.pos) :: rest, sugarBody)
+ case (t @ ValFrom(pat, rhs)) :: rest =>
+ val valeqs = rest.take(definitions.MaxTupleArity - 1).takeWhile { ValEq.unapply(_).nonEmpty }
+ assert(!valeqs.isEmpty)
+ val rest1 = rest.drop(valeqs.length)
+ val pats = valeqs map { case ValEq(pat, _) => pat }
+ val rhss = valeqs map { case ValEq(_, rhs) => rhs }
+ val defpat1 = makeBind(pat)
+ val defpats = pats map makeBind
+ val pdefs = (defpats, rhss).zipped flatMap mkPatDef
+ val ids = (defpat1 :: defpats) map makeValue
+ val rhs1 = mkFor(
+ List(ValFrom(defpat1, rhs).setPos(t.pos)),
+ Yield(Block(pdefs, atPos(wrappingPos(ids)) { mkTuple(ids) }) setPos wrappingPos(pdefs)))
+ val allpats = (pat :: pats) map (_.duplicate)
+ val pos1 =
+ if (t.pos == NoPosition) NoPosition
+ else rangePos(t.pos.source, t.pos.start, t.pos.point, rhs1.pos.end)
+ val vfrom1 = ValFrom(atPos(wrappingPos(allpats)) { mkTuple(allpats) }, rhs1).setPos(pos1)
+ mkFor(vfrom1 :: rest1, sugarBody)
+ case _ =>
+ EmptyTree //may happen for erroneous input
+
+ }
+ }
+
+ /** Create tree for pattern definition <val pat0 = rhs> */
+ def mkPatDef(pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[Tree] =
+ mkPatDef(Modifiers(0), pat, rhs)
+
+ /** Create tree for pattern definition <mods val pat0 = rhs> */
+ def mkPatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[Tree] = matchVarPattern(pat) match {
+ case Some((name, tpt)) =>
+ List(atPos(pat.pos union rhs.pos) {
+ ValDef(mods, name.toTermName, tpt, rhs)
+ })
+
+ case None =>
+ // in case there is exactly one variable x_1 in pattern
+ // val/var p = e ==> val/var x_1 = e.match (case p => (x_1))
+ //
+ // in case there are zero or more than one variables in pattern
+ // val/var p = e ==> private synthetic val t$ = e.match (case p => (x_1, ..., x_N))
+ // val/var x_1 = t$._1
+ // ...
+ // val/var x_N = t$._N
+
+ val rhsUnchecked = mkUnchecked(rhs)
+
+ // TODO: clean this up -- there is too much information packked into mkPatDef's `pat` argument
+ // when it's a simple identifier (case Some((name, tpt)) -- above),
+ // pat should have the type ascription that was specified by the user
+ // however, in `case None` (here), we must be careful not to generate illegal pattern trees (such as `(a, b): Tuple2[Int, String]`)
+ // i.e., this must hold: pat1 match { case Typed(expr, tp) => assert(expr.isInstanceOf[Ident]) case _ => }
+ // if we encounter such an erroneous pattern, we strip off the type ascription from pat and propagate the type information to rhs
+ val (pat1, rhs1) = patvarTransformer.transform(pat) match {
+ // move the Typed ascription to the rhs
+ case Typed(expr, tpt) if !expr.isInstanceOf[Ident] =>
+ val rhsTypedUnchecked =
+ if (tpt.isEmpty) rhsUnchecked
+ else Typed(rhsUnchecked, tpt) setPos (rhs.pos union tpt.pos)
+ (expr, rhsTypedUnchecked)
+ case ok =>
+ (ok, rhsUnchecked)
+ }
+ val vars = getVariables(pat1)
+ val matchExpr = atPos((pat1.pos union rhs.pos).makeTransparent) {
+ Match(
+ rhs1,
+ List(
+ atPos(pat1.pos) {
+ CaseDef(pat1, EmptyTree, mkTuple(vars map (_._1) map Ident.apply))
+ }
+ ))
+ }
+ vars match {
+ case List((vname, tpt, pos)) =>
+ List(atPos(pat.pos union pos union rhs.pos) {
+ ValDef(mods, vname.toTermName, tpt, matchExpr)
+ })
+ case _ =>
+ val tmp = freshTermName()
+ val firstDef =
+ atPos(matchExpr.pos) {
+ ValDef(Modifiers(PrivateLocal | SYNTHETIC | ARTIFACT | (mods.flags & LAZY)),
+ tmp, TypeTree(), matchExpr)
+ }
+ var cnt = 0
+ val restDefs = for ((vname, tpt, pos) <- vars) yield atPos(pos) {
+ cnt += 1
+ ValDef(mods, vname.toTermName, tpt, Select(Ident(tmp), newTermName("_" + cnt)))
+ }
+ firstDef :: restDefs
+ }
+ }
+
+ /** Create tree for for-comprehension generator <val pat0 <- rhs0> */
+ def mkGenerator(pos: Position, pat: Tree, valeq: Boolean, rhs: Tree)(implicit fresh: FreshNameCreator): Tree = {
+ val pat1 = patvarTransformer.transform(pat)
+ if (valeq) ValEq(pat1, rhs).setPos(pos)
+ else ValFrom(pat1, mkCheckIfRefutable(pat1, rhs)).setPos(pos)
+ }
+
+ def mkCheckIfRefutable(pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator) =
+ if (treeInfo.isVarPatternDeep(pat)) rhs
+ else {
+ val cases = List(
+ CaseDef(pat.duplicate, EmptyTree, Literal(Constant(true))),
+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(false)))
+ )
+ val visitor = mkVisitor(cases, checkExhaustive = false, nme.CHECK_IF_REFUTABLE_STRING)
+ atPos(rhs.pos)(Apply(Select(rhs, nme.withFilter), visitor :: Nil))
+ }
+
+ /** If tree is a variable pattern, return Some("its name and type").
+ * Otherwise return none */
+ private def matchVarPattern(tree: Tree): Option[(Name, Tree)] = {
+ def wildType(t: Tree): Option[Tree] = t match {
+ case Ident(x) if x.toTermName == nme.WILDCARD => Some(TypeTree())
+ case Typed(Ident(x), tpt) if x.toTermName == nme.WILDCARD => Some(tpt)
+ case _ => None
+ }
+ tree match {
+ case Ident(name) => Some((name, TypeTree()))
+ case Bind(name, body) => wildType(body) map (x => (name, x))
+ case Typed(Ident(name), tpt) => Some((name, tpt))
+ case _ => None
+ }
+ }
+
+ /** Create visitor <x => x match cases> */
+ def mkVisitor(cases: List[CaseDef], checkExhaustive: Boolean, prefix: String = "x$")(implicit fresh: FreshNameCreator): Tree = {
+ val x = freshTermName(prefix)
+ val id = Ident(x)
+ val sel = if (checkExhaustive) id else mkUnchecked(id)
+ Function(List(mkSyntheticParam(x)), Match(sel, cases))
+ }
+
+ /** Traverse pattern and collect all variable names with their types in buffer
+ * The variables keep their positions; whereas the pattern is converted to be
+ * synthetic for all nodes that contain a variable position.
+ */
+ class GetVarTraverser extends Traverser {
+ val buf = new ListBuffer[(Name, Tree, Position)]
+
+ def namePos(tree: Tree, name: Name): Position =
+ if (!tree.pos.isRange || name.containsName(nme.raw.DOLLAR)) tree.pos.focus
+ else {
+ val start = tree.pos.start
+ val end = start + name.decode.length
+ rangePos(tree.pos.source, start, start, end)
+ }
+
+ override def traverse(tree: Tree): Unit = {
+ def seenName(name: Name) = buf exists (_._1 == name)
+ def add(name: Name, t: Tree) = if (!seenName(name)) buf += ((name, t, namePos(tree, name)))
+ val bl = buf.length
+
+ tree match {
+ case Bind(nme.WILDCARD, _) =>
+ super.traverse(tree)
+
+ case Bind(name, Typed(tree1, tpt)) =>
+ val newTree = if (treeInfo.mayBeTypePat(tpt)) TypeTree() else tpt.duplicate
+ add(name, newTree)
+ traverse(tree1)
+
+ case Bind(name, tree1) =>
+ // can assume only name range as position, as otherwise might overlap
+ // with binds embedded in pattern tree1
+ add(name, TypeTree())
+ traverse(tree1)
+
+ case _ =>
+ super.traverse(tree)
+ }
+ if (buf.length > bl)
+ tree setPos tree.pos.makeTransparent
+ }
+ def apply(tree: Tree) = {
+ traverse(tree)
+ buf.toList
+ }
+ }
+
+ /** Returns list of all pattern variables, possibly with their types,
+ * without duplicates
+ */
+ private def getVariables(tree: Tree): List[(Name, Tree, Position)] =
+ new GetVarTraverser apply tree
+
+ /** Convert all occurrences of (lower-case) variables in a pattern as follows:
+ * x becomes x @ _
+ * x: T becomes x @ (_: T)
+ */
+ object patvarTransformer extends Transformer {
+ override def transform(tree: Tree): Tree = tree match {
+ case Ident(name) if (treeInfo.isVarPattern(tree) && name != nme.WILDCARD) =>
+ atPos(tree.pos)(Bind(name, atPos(tree.pos.focus) (Ident(nme.WILDCARD))))
+ case Typed(id @ Ident(name), tpt) if (treeInfo.isVarPattern(id) && name != nme.WILDCARD) =>
+ atPos(tree.pos.withPoint(id.pos.point)) {
+ Bind(name, atPos(tree.pos.withStart(tree.pos.point)) {
+ Typed(Ident(nme.WILDCARD), tpt)
+ })
+ }
+ case Apply(fn @ Apply(_, _), args) =>
+ treeCopy.Apply(tree, transform(fn), transformTrees(args))
+ case Apply(fn, args) =>
+ treeCopy.Apply(tree, fn, transformTrees(args))
+ case Typed(expr, tpt) =>
+ treeCopy.Typed(tree, transform(expr), tpt)
+ case Bind(name, body) =>
+ treeCopy.Bind(tree, name, transform(body))
+ case Alternative(_) | Star(_) =>
+ super.transform(tree)
+ case _ =>
+ tree
+ }
+ }
+
+ // annotate the expression with @unchecked
+ def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) {
+ // This can't be "Annotated(New(UncheckedClass), expr)" because annotations
+ // are very picky about things and it crashes the compiler with "unexpected new".
+ Annotated(New(scalaDot(tpnme.unchecked), Nil), expr)
+ }
+
+ def mkSyntheticParam(pname: TermName) =
+ ValDef(Modifiers(PARAM | SYNTHETIC), pname, TypeTree(), EmptyTree)
}
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index 025965ad47..8982fd4246 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -18,7 +18,7 @@ abstract class TreeInfo {
val global: SymbolTable
import global._
- import definitions.{ isTupleSymbol, isVarArgsList, isCastSymbol, ThrowableClass, TupleClass, MacroContextClass, MacroContextPrefixType, uncheckedStableClass }
+ import definitions.{ isTupleSymbol, isVarArgsList, isCastSymbol, ThrowableClass, TupleClass, uncheckedStableClass, isBlackboxMacroBundleType, isWhiteboxContextType }
/* Does not seem to be used. Not sure what it does anyway.
def isOwnerDefinition(tree: Tree): Boolean = tree match {
@@ -822,13 +822,19 @@ abstract class TreeInfo {
case ref: RefTree => {
val qual = ref.qualifier
val isBundle = definitions.isMacroBundleType(qual.tpe)
+ val isBlackbox =
+ if (isBundle) isBlackboxMacroBundleType(qual.tpe)
+ else ref.symbol.paramss match {
+ case (c :: Nil) :: _ if isWhiteboxContextType(c.info) => false
+ case _ => true
+ }
val owner =
if (isBundle) qual.tpe.typeSymbol
else {
- val sym = if (qual.hasSymbolField) qual.symbol else NoSymbol
- if (sym.isModule) sym.moduleClass else sym
+ val qualSym = if (qual.hasSymbolField) qual.symbol else NoSymbol
+ if (qualSym.isModule) qualSym.moduleClass else qualSym
}
- Some((isBundle, owner, ref.symbol, dissectApplied(tree).targs))
+ Some((isBundle, isBlackbox, owner, ref.symbol, dissectApplied(tree).targs))
}
case _ => None
}
diff --git a/src/reflect/scala/reflect/internal/Trees.scala b/src/reflect/scala/reflect/internal/Trees.scala
index 743c674eea..af0af8afe8 100644
--- a/src/reflect/scala/reflect/internal/Trees.scala
+++ b/src/reflect/scala/reflect/internal/Trees.scala
@@ -490,7 +490,7 @@ trait Trees extends api.Trees {
case class Ident(name: Name) extends RefTree with IdentContextApi {
def qualifier: Tree = EmptyTree
- def isBackquoted = this.attachments.get[BackquotedIdentifierAttachment.type].isDefined
+ def isBackquoted = this.hasAttachment[BackquotedIdentifierAttachment.type]
}
object Ident extends IdentExtractor
diff --git a/src/reflect/scala/reflect/macros/Aliases.scala b/src/reflect/scala/reflect/macros/Aliases.scala
index 9e05f343e6..ca599dbd49 100644
--- a/src/reflect/scala/reflect/macros/Aliases.scala
+++ b/src/reflect/scala/reflect/macros/Aliases.scala
@@ -5,11 +5,11 @@ package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that defines shorthands for the
+ * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that defines shorthands for the
* most frequently used types and functions of the underlying compiler universe.
*/
trait Aliases {
- self: Context =>
+ self: BlackboxContext =>
/** The type of symbols representing declarations. */
type Symbol = universe.Symbol
diff --git a/src/reflect/scala/reflect/macros/Attachments.scala b/src/reflect/scala/reflect/macros/Attachments.scala
index c1ab269268..039e75fbee 100644
--- a/src/reflect/scala/reflect/macros/Attachments.scala
+++ b/src/reflect/scala/reflect/macros/Attachments.scala
@@ -41,6 +41,10 @@ abstract class Attachments { self =>
def get[T: ClassTag]: Option[T] =
(all filter matchesTag[T]).headOption.asInstanceOf[Option[T]]
+ /** Check underlying payload contains an instance of type `T`. */
+ def contains[T: ClassTag]: Boolean =
+ all exists matchesTag[T]
+
/** Creates a copy of this attachment with the payload slot of T added/updated with the provided value.
* Replaces an existing payload of the same type, if exists.
*/
diff --git a/src/reflect/scala/reflect/macros/Context.scala b/src/reflect/scala/reflect/macros/BlackboxContext.scala
index b0c816f4ad..2c77289866 100644
--- a/src/reflect/scala/reflect/macros/Context.scala
+++ b/src/reflect/scala/reflect/macros/BlackboxContext.scala
@@ -2,14 +2,10 @@ package scala
package reflect
package macros
-// todo. introduce context hierarchy
-// the most lightweight context should just expose the stuff from the SIP
-// the full context should include all traits from scala.reflect.macros (and probably reside in scala-compiler.jar)
-
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * The Scala macros context.
+ * The blackbox Scala macros context.
*
* See [[scala.reflect.macros.package the overview page]] for a description of how macros work. This documentation
* entry provides information on the API available to macro writers.
@@ -27,17 +23,25 @@ package macros
* Other than that, macro contexts provide facilities for typechecking, exploring the compiler's symbol table and
* enclosing trees and compilation units, evaluating trees, logging warnings/errors and much more.
* Refer to the documentation of top-level traits in this package to learn the details.
+ *
+ * If a macro def refers to a macro impl that uses `BlackboxContext`, then this macro def becomes a blackbox macro,
+ * which means that its expansion will be upcast to its return type, enforcing faithfullness of that macro to its
+ * type signature. Whitebox macros, i.e. the ones defined with `WhiteboxContext`, aren't bound by this restriction,
+ * which enables a number of important use cases, but they are also going to enjoy less support than blackbox macros,
+ * so choose wisely. See the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]] for more information.
+ *
+ * @see `scala.reflect.macros.WhiteboxContext`
*/
-trait Context extends Aliases
- with Enclosures
- with Names
- with Reifiers
- with FrontEnds
- with Infrastructure
- with Typers
- with Parsers
- with Evals
- with ExprUtils {
+trait BlackboxContext extends Aliases
+ with Enclosures
+ with Names
+ with Reifiers
+ with FrontEnds
+ with Infrastructure
+ with Typers
+ with Parsers
+ with Evals
+ with ExprUtils {
/** The compile-time universe. */
val universe: Universe
@@ -59,7 +63,7 @@ trait Context extends Aliases
* scala> class Coll[T] {
* | def filter(p: T => Boolean): Coll[T] = macro M.filter[T]
* | }; object M {
- * | def filter[T](c: Context { type PrefixType = Coll[T] })
+ * | def filter[T](c: BlackboxContext { type PrefixType = Coll[T] })
* | (p: c.Expr[T => Boolean]): c.Expr[Coll[T]] =
* | {
* | println(c.prefix.tree)
diff --git a/src/reflect/scala/reflect/macros/Macro.scala b/src/reflect/scala/reflect/macros/BlackboxMacro.scala
index 44bedf483d..df142e9238 100644
--- a/src/reflect/scala/reflect/macros/Macro.scala
+++ b/src/reflect/scala/reflect/macros/BlackboxMacro.scala
@@ -6,15 +6,15 @@ package macros
*
* Traditionally macro implementations are defined as methods,
* but this trait provides an alternative way of encoding macro impls as
- * bundles, traits which extend `scala.reflect.macros.Macro`.
+ * bundles, traits which extend `scala.reflect.macros.BlackboxMacro` or`scala.reflect.macros.WhiteboxMacro` .
*
* Instead of:
*
- * def impl[T: c.WeakTypeTag](c: Context)(x: c.Expr[Int]) = ...
+ * def impl[T: c.WeakTypeTag](c: BlackboxContext)(x: c.Expr[Int]) = ...
*
* One can write:
*
- * trait Impl extends Macro {
+ * trait Impl extends BlackboxMacro {
* def apply[T: c.WeakTypeTag](x: c.Expr[Int]) = ...
* }
*
@@ -24,16 +24,13 @@ package macros
* are complex and need to be modularized. State of the art technique of addressing this need is quite heavyweight:
* http://docs.scala-lang.org/overviews/macros/overview.html#writing_bigger_macros.
*
- * However utility of this approach to writing macros isn't limited to just convenience.
- * When a macro implementation becomes not just a function, but a full-fledged module,
- * it can define callbacks that will be called by the compiler upon interesting events.
- * In subsequent commits I will add support for programmable type inference
+ * @see `scala.reflect.macros.WhiteboxMacro`
*/
-trait Macro {
+trait BlackboxMacro {
/** The context to be used by the macro implementation.
*
* Vanilla macro implementations have to carry it in their signatures, however when a macro is a full-fledged module,
* it can define the context next to the implementation, makes implementation signature more lightweight.
*/
- val c: Context
+ val c: BlackboxContext
}
diff --git a/src/reflect/scala/reflect/macros/Enclosures.scala b/src/reflect/scala/reflect/macros/Enclosures.scala
index d6ba5f39cd..31905c4739 100644
--- a/src/reflect/scala/reflect/macros/Enclosures.scala
+++ b/src/reflect/scala/reflect/macros/Enclosures.scala
@@ -7,13 +7,13 @@ import scala.language.existentials // SI-6541
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that exposes
+ * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that exposes
* enclosing trees (method, class, compilation unit and currently compiled application),
* the enclosing position of the macro expansion, as well as macros and implicits
* that are currently in-flight.
*/
trait Enclosures {
- self: Context =>
+ self: BlackboxContext =>
/** The tree that undergoes macro expansion.
* Can be useful to get an offset or a range position of the entire tree being processed.
@@ -43,19 +43,7 @@ trait Enclosures {
* Unlike `openMacros`, this is a val, which means that it gets initialized when the context is created
* and always stays the same regardless of whatever happens during macro expansion.
*/
- def enclosingMacros: List[Context]
-
- /** Information about one of the currently considered implicit candidates.
- * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
- * hence implicit searches can recursively trigger other implicit searches.
- *
- * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
- * If we're in an implicit macro being expanded, it's included in this list.
- *
- * Unlike `openImplicits`, this is a val, which means that it gets initialized when the context is created
- * and always stays the same regardless of whatever happens during macro expansion.
- */
- def enclosingImplicits: List[ImplicitCandidate]
+ def enclosingMacros: List[BlackboxContext]
/** Tries to guess a position for the enclosing application.
* But that is simple, right? Just dereference `pos` of `macroApplication`? Not really.
diff --git a/src/reflect/scala/reflect/macros/Evals.scala b/src/reflect/scala/reflect/macros/Evals.scala
index 70b2ab58d4..eb37e83cad 100644
--- a/src/reflect/scala/reflect/macros/Evals.scala
+++ b/src/reflect/scala/reflect/macros/Evals.scala
@@ -5,11 +5,11 @@ package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that provides
+ * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that provides
* a facility to evaluate trees.
*/
trait Evals {
- self: Context =>
+ self: BlackboxContext =>
/** Takes a typed wrapper for a tree of type `T` and evaluates it to a value of type `T`.
*
@@ -21,12 +21,12 @@ trait Evals {
* mutates the tree in place, therefore the conventional approach is to `duplicate` the tree first.
*
* {{{
- * scala> def impl(c: Context)(x: c.Expr[String]) = {
+ * scala> def impl(c: BlackboxContext)(x: c.Expr[String]) = {
* | val x1 = c.Expr[String](c.resetAllAttrs(x.tree.duplicate))
* | println(s"compile-time value is: \${c.eval(x1)}")
* | x
* | }
- * impl: (c: Context)(x: c.Expr[String])c.Expr[String]
+ * impl: (c: BlackboxContext)(x: c.Expr[String])c.Expr[String]
*
* scala> def test(x: String) = macro impl
* test: (x: String)String
diff --git a/src/reflect/scala/reflect/macros/ExprUtils.scala b/src/reflect/scala/reflect/macros/ExprUtils.scala
index 76a8392b9c..58b61e446a 100644
--- a/src/reflect/scala/reflect/macros/ExprUtils.scala
+++ b/src/reflect/scala/reflect/macros/ExprUtils.scala
@@ -5,11 +5,11 @@ package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that defines shorthands for the
+ * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that defines shorthands for the
* most common `Expr`-creating functions.
*/
trait ExprUtils {
- self: Context =>
+ self: BlackboxContext =>
/** Shorthand for `Literal(Constant(null))` in the underlying `universe`. */
@deprecated("Use quasiquotes instead", "2.11.0")
diff --git a/src/reflect/scala/reflect/macros/FrontEnds.scala b/src/reflect/scala/reflect/macros/FrontEnds.scala
index 6abd8c335b..3a910d89ad 100644
--- a/src/reflect/scala/reflect/macros/FrontEnds.scala
+++ b/src/reflect/scala/reflect/macros/FrontEnds.scala
@@ -5,12 +5,12 @@ package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that
* provides facilities to communicate with the compiler's front end
* (emit warnings, errors and other sorts of messages).
*/
trait FrontEnds {
- self: Context =>
+ self: BlackboxContext =>
/** For sending a message which should not be labeled as a warning/error,
* but also shouldn't require -verbose to be visible.
diff --git a/src/reflect/scala/reflect/macros/Infrastructure.scala b/src/reflect/scala/reflect/macros/Infrastructure.scala
index eb63fb7b7f..b6585f94d2 100644
--- a/src/reflect/scala/reflect/macros/Infrastructure.scala
+++ b/src/reflect/scala/reflect/macros/Infrastructure.scala
@@ -5,11 +5,11 @@ package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that
* provides facilities to communicate with the compiler's infrastructure.
*/
trait Infrastructure {
- self: Context =>
+ self: BlackboxContext =>
/** Exposes macro-specific settings as a list of strings.
* These settings are passed to the compiler via the "-Xmacro-settings:setting1,setting2...,settingN" command-line option.
diff --git a/src/reflect/scala/reflect/macros/Names.scala b/src/reflect/scala/reflect/macros/Names.scala
index 8773175561..6bd3e1a199 100644
--- a/src/reflect/scala/reflect/macros/Names.scala
+++ b/src/reflect/scala/reflect/macros/Names.scala
@@ -5,11 +5,11 @@ package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that
* provides functions that generate unique names.
*/
trait Names {
- self: Context =>
+ self: BlackboxContext =>
/** Creates a unique string. */
@deprecated("Use freshName instead", "2.11.0")
diff --git a/src/reflect/scala/reflect/macros/Parsers.scala b/src/reflect/scala/reflect/macros/Parsers.scala
index 4232b05f8c..cbfb30f022 100644
--- a/src/reflect/scala/reflect/macros/Parsers.scala
+++ b/src/reflect/scala/reflect/macros/Parsers.scala
@@ -5,12 +5,12 @@ package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that
* exposes functions to parse strings with Scala code into trees.
*/
@deprecated("Use quasiquotes instead", "2.11.0")
trait Parsers {
- self: Context =>
+ self: BlackboxContext =>
/** Parses a string with a Scala expression into an abstract syntax tree.
* Only works for expressions, i.e. parsing a package declaration will fail.
diff --git a/src/reflect/scala/reflect/macros/Reifiers.scala b/src/reflect/scala/reflect/macros/Reifiers.scala
index 6ebd2db730..67d10dc10a 100644
--- a/src/reflect/scala/reflect/macros/Reifiers.scala
+++ b/src/reflect/scala/reflect/macros/Reifiers.scala
@@ -5,11 +5,11 @@ package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that
* exposes functions to save reflection artifacts for runtime.
*/
trait Reifiers {
- self: Context =>
+ self: BlackboxContext =>
/** Given a tree, generate a tree that when compiled and executed produces the original tree.
* For more information and examples see the documentation for `Universe.reify`.
diff --git a/src/reflect/scala/reflect/macros/Typers.scala b/src/reflect/scala/reflect/macros/Typers.scala
index d7aec9b3ef..29c1af110b 100644
--- a/src/reflect/scala/reflect/macros/Typers.scala
+++ b/src/reflect/scala/reflect/macros/Typers.scala
@@ -5,11 +5,11 @@ package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
- * A slice of [[scala.reflect.macros.Context the Scala macros context]] that
+ * A slice of [[scala.reflect.macros.BlackboxContext the Scala macros context]] that
* partially exposes the type checker to macro writers.
*/
trait Typers {
- self: Context =>
+ self: BlackboxContext =>
/** Contexts that represent macros in-flight, including the current one. Very much like a stack trace, but for macros only.
* Can be useful for interoperating with other macros and for imposing compiler-friendly limits on macro expansion.
@@ -21,28 +21,7 @@ trait Typers {
* Unlike `enclosingMacros`, this is a def, which means that it gets recalculated on every invocation,
* so it might change depending on what is going on during macro expansion.
*/
- def openMacros: List[Context]
-
- /** Information about one of the currently considered implicit candidates.
- * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
- * hence implicit searches can recursively trigger other implicit searches.
- *
- * `pre` and `sym` provide information about the candidate itself.
- * `pt` and `tree` store the parameters of the implicit search the candidate is participating in.
- */
- case class ImplicitCandidate(pre: Type, sym: Symbol, pt: Type, tree: Tree)
-
- /** Information about one of the currently considered implicit candidates.
- * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
- * hence implicit searches can recursively trigger other implicit searches.
- *
- * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
- * If we're in an implicit macro being expanded, it's included in this list.
- *
- * Unlike `enclosingImplicits`, this is a def, which means that it gets recalculated on every invocation,
- * so it might change depending on what is going on during macro expansion.
- */
- def openImplicits: List[ImplicitCandidate]
+ def openMacros: List[BlackboxContext]
/** Typechecks the provided tree against the expected type `pt` in the macro callsite context.
*
diff --git a/src/reflect/scala/reflect/macros/WhiteboxContext.scala b/src/reflect/scala/reflect/macros/WhiteboxContext.scala
new file mode 100644
index 0000000000..9d65a5c16e
--- /dev/null
+++ b/src/reflect/scala/reflect/macros/WhiteboxContext.scala
@@ -0,0 +1,76 @@
+package scala
+package reflect
+package macros
+
+/**
+ * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
+ *
+ * The whitebox Scala macros context.
+ *
+ * See [[scala.reflect.macros.package the overview page]] for a description of how macros work. This documentation
+ * entry provides information on the API available to macro writers.
+ *
+ * A macro context wraps a compiler universe exposed in `universe` and having type [[scala.reflect.macros.Universe]].
+ * This type is a refinement over the generic reflection API provided in [[scala.reflect.api.Universe]]. The
+ * extended Universe provides mutability for reflection artifacts (e.g. macros can change types of compiler trees,
+ * add annotation to symbols representing definitions, etc) and exposes some internal compiler functionality
+ * such as `Symbol.deSkolemize` or `Tree.attachments`.
+ *
+ * Another fundamental part of a macro context is `macroApplication`, which provides access to the tree undergoing
+ * macro expansion. Parts of this tree can be found in arguments of the corresponding macro implementations and
+ * in `prefix`, but `macroApplication` gives the full picture.
+ *
+ * Other than that, macro contexts provide facilities for typechecking, exploring the compiler's symbol table and
+ * enclosing trees and compilation units, evaluating trees, logging warnings/errors and much more.
+ * Refer to the documentation of top-level traits in this package to learn the details.
+ *
+ * If a macro def refers to a macro impl that uses `WhiteboxContext`, then this macro def becomes a whitebox macro,
+ * gaining the ability to refine the type of its expansion beyond its official return type, which enables a number of important use cases.
+ * Blackbox macros, i.e. the ones defined with `BlackboxContext`, can't do that, so they are less powerful.
+ * However blackbox macros are also going to enjoy better support than whitebox macros, so choose wisely.
+ * See the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]] for more information.
+ *
+ * @see `scala.reflect.macros.BlackboxContext`
+ */
+trait WhiteboxContext extends BlackboxContext {
+ /** @inheritdoc
+ */
+ def openMacros: List[WhiteboxContext]
+
+ /** @inheritdoc
+ */
+ def enclosingMacros: List[WhiteboxContext]
+
+ /** Information about one of the currently considered implicit candidates.
+ * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
+ * hence implicit searches can recursively trigger other implicit searches.
+ *
+ * `pre` and `sym` provide information about the candidate itself.
+ * `pt` and `tree` store the parameters of the implicit search the candidate is participating in.
+ */
+ case class ImplicitCandidate(pre: Type, sym: Symbol, pt: Type, tree: Tree)
+
+ /** Information about one of the currently considered implicit candidates.
+ * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
+ * hence implicit searches can recursively trigger other implicit searches.
+ *
+ * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
+ * If we're in an implicit macro being expanded, it's included in this list.
+ *
+ * Unlike `enclosingImplicits`, this is a def, which means that it gets recalculated on every invocation,
+ * so it might change depending on what is going on during macro expansion.
+ */
+ def openImplicits: List[ImplicitCandidate]
+
+ /** Information about one of the currently considered implicit candidates.
+ * Candidates are used in plural form, because implicit parameters may themselves have implicit parameters,
+ * hence implicit searches can recursively trigger other implicit searches.
+ *
+ * Can be useful to get information about an application with an implicit parameter that is materialized during current macro expansion.
+ * If we're in an implicit macro being expanded, it's included in this list.
+ *
+ * Unlike `openImplicits`, this is a val, which means that it gets initialized when the context is created
+ * and always stays the same regardless of whatever happens during macro expansion.
+ */
+ def enclosingImplicits: List[ImplicitCandidate]
+} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/macros/WhiteboxMacro.scala b/src/reflect/scala/reflect/macros/WhiteboxMacro.scala
new file mode 100644
index 0000000000..1c581313eb
--- /dev/null
+++ b/src/reflect/scala/reflect/macros/WhiteboxMacro.scala
@@ -0,0 +1,36 @@
+package scala.reflect
+package macros
+
+/**
+ * <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
+ *
+ * Traditionally macro implementations are defined as methods,
+ * but this trait provides an alternative way of encoding macro impls as
+ * bundles, traits which extend `scala.reflect.macros.BlackboxMacro` or`scala.reflect.macros.WhiteboxMacro` .
+ *
+ * Instead of:
+ *
+ * def impl[T: c.WeakTypeTag](c: WhiteboxContext)(x: c.Expr[Int]) = ...
+ *
+ * One can write:
+ *
+ * trait Impl extends WhiteboxMacro {
+ * def apply[T: c.WeakTypeTag](x: c.Expr[Int]) = ...
+ * }
+ *
+ * Without changing anything else at all.
+ *
+ * This language feature is useful in itself in cases when macro implementations
+ * are complex and need to be modularized. State of the art technique of addressing this need is quite heavyweight:
+ * http://docs.scala-lang.org/overviews/macros/overview.html#writing_bigger_macros.
+ *
+ * @see `scala.reflect.macros.BlackboxMacro`
+ */
+trait WhiteboxMacro {
+ /** The context to be used by the macro implementation.
+ *
+ * Vanilla macro implementations have to carry it in their signatures, however when a macro is a full-fledged module,
+ * it can define the context next to the implementation, makes implementation signature more lightweight.
+ */
+ val c: WhiteboxContext
+}
diff --git a/src/reflect/scala/reflect/macros/package.scala b/src/reflect/scala/reflect/macros/package.scala
index 2e2e8e79f8..6a8434a163 100644
--- a/src/reflect/scala/reflect/macros/package.scala
+++ b/src/reflect/scala/reflect/macros/package.scala
@@ -7,10 +7,22 @@ package reflect
* The base package for Scala macros.
*
* Macros are functions that are called by the compiler during compilation.
- * Within these functions the programmer has access to compiler APIs exposed in [[scala.reflect.macros.Context]].
+ * Within these functions the programmer has access to compiler APIs.
* For example, it is possible to generate, analyze and typecheck code.
*
* See the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]] on how to get started with Scala macros.
*/
package object macros {
+ /** The Scala macros context.
+ *
+ * In Scala 2.11, macros that were once the one are split into blackbox and whitebox macros,
+ * with the former being better supported and the latter being more powerful. You can read about
+ * the details of the split and the associated trade-offs in the [[http://docs.scala-lang.org/overviews/macros.html Macros Guide]].
+ *
+ * `scala.reflect.macros.Context` follows this tendency and turns into `scala.reflect.macros.BlackboxContext`
+ * and `scala.reflect.macros.WhiteboxContext`. The original `Context` is left in place for compatibility reasons,
+ * but it is now deprecated, nudging the users to choose between blackbox and whitebox macros.
+ */
+ @deprecated("Use BlackboxContext or WhiteboxContext instead", "2.11.0")
+ type Context = WhiteboxContext
} \ No newline at end of file
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index 4d69a6673c..bce506ee0a 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -53,8 +53,9 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
this.perRunCaches
this.FixedMirrorTreeCreator
this.FixedMirrorTypeCreator
- this.BackquotedIdentifierAttachment
this.CompoundTypeTreeOriginalAttachment
+ this.BackquotedIdentifierAttachment
+ this.ForAttachment
this.noPrint
this.typeDebug
// inaccessible: this.maxFree
@@ -314,8 +315,10 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.TypeCreatorClass
definitions.TreeCreatorClass
definitions.LiftableClass
- definitions.MacroClass
- definitions.MacroContextClass
+ definitions.BlackboxMacroClass
+ definitions.WhiteboxMacroClass
+ definitions.BlackboxContextClass
+ definitions.WhiteboxContextClass
definitions.MacroImplAnnotation
definitions.StringContextClass
definitions.QuasiquoteClass
@@ -334,6 +337,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.TupleClass
definitions.FunctionClass
definitions.AbstractFunctionClass
+ definitions.MacroContextType
definitions.ProductRootClass
definitions.Any_$eq$eq
definitions.Any_$bang$eq
diff --git a/src/reflect/scala/reflect/runtime/package.scala b/src/reflect/scala/reflect/runtime/package.scala
index 41c1310e17..3a7688aa2c 100644
--- a/src/reflect/scala/reflect/runtime/package.scala
+++ b/src/reflect/scala/reflect/runtime/package.scala
@@ -26,7 +26,7 @@ package object runtime {
package runtime {
private[scala] object Macros {
- def currentMirror(c: scala.reflect.macros.Context): c.Expr[universe.Mirror] = {
+ def currentMirror(c: scala.reflect.macros.BlackboxContext): c.Expr[universe.Mirror] = {
import c.universe._
val runtimeClass = c.reifyEnclosingRuntimeClass
if (runtimeClass.isEmpty) c.abort(c.enclosingPosition, "call site does not have an enclosing class")
diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala
index e4a3416152..0d55423247 100644
--- a/src/repl/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala
@@ -272,6 +272,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
case s => s
} mkString "."
)
+ def readRootPath(readPath: String) = getModuleIfDefined(readPath)
abstract class PhaseDependentOps {
def shift[T](op: => T): T
@@ -700,7 +701,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
*
* Read! Eval! Print! Some of that not yet centralized here.
*/
- class ReadEvalPrint(lineId: Int) {
+ class ReadEvalPrint(val lineId: Int) {
def this() = this(freshLineId())
val packageName = sessionNames.line + lineId
@@ -777,7 +778,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
* following accessPath into the outer one.
*/
def resolvePathToSymbol(accessPath: String): Symbol = {
- val readRoot = getModuleIfDefined(readPath) // the outermost wrapper
+ val readRoot = readRootPath(readPath) // the outermost wrapper
(accessPath split '.').foldLeft(readRoot: Symbol) {
case (sym, "") => sym
case (sym, name) => exitingTyper(termMember(sym, name))
@@ -848,30 +849,69 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
/** Code to import bound names from previous lines - accessPath is code to
* append to objectName to access anything bound by request.
*/
- val ComputedImports(importsPreamble, importsTrailer, accessPath) =
- exitingTyper(importsCode(referencedNames.toSet))
+ lazy val ComputedImports(importsPreamble, importsTrailer, accessPath) =
+ exitingTyper(importsCode(referencedNames.toSet, ObjectSourceCode))
/** the line of code to compute */
def toCompute = line
- def fullPath(vname: String) = s"${lineRep.readPath}$accessPath.`$vname`"
+ /** The path of the value that contains the user code. */
+ def fullAccessPath = s"${lineRep.readPath}$accessPath"
+
+ /** The path of the given member of the wrapping instance. */
+ def fullPath(vname: String) = s"$fullAccessPath.`$vname`"
/** generate the source code for the object that computes this request */
- private object ObjectSourceCode extends IMain.CodeAssembler[MemberHandler] {
+ abstract class Wrapper extends IMain.CodeAssembler[MemberHandler] {
def path = originalPath("$intp")
def envLines = {
if (!isReplPower) Nil // power mode only for now
else List("def %s = %s".format("$line", tquoted(originalLine)), "def %s = Nil".format("$trees"))
}
-
- val preamble = """
- |object %s {
+ def preamble = s"""
+ |$preambleHeader
|%s%s%s
- """.stripMargin.format(lineRep.readName, envLines.map(" " + _ + ";\n").mkString, importsPreamble, indentCode(toCompute))
- val postamble = importsTrailer + "\n}"
+ """.stripMargin.format(lineRep.readName, envLines.map(" " + _ + ";\n").mkString,
+ importsPreamble, indentCode(toCompute))
+
val generate = (m: MemberHandler) => m extraCodeToEvaluate Request.this
+
+ /** A format string with %s for $read, specifying the wrapper definition. */
+ def preambleHeader: String
+
+ /** Like preambleHeader for an import wrapper. */
+ def prewrap: String = preambleHeader + "\n"
+
+ /** Like postamble for an import wrapper. */
+ def postwrap: String
+ }
+
+ private class ObjectBasedWrapper extends Wrapper {
+ def preambleHeader = "object %s {"
+
+ def postamble = importsTrailer + "\n}"
+
+ def postwrap = "}\n"
}
+ private class ClassBasedWrapper extends Wrapper {
+ def preambleHeader = "class %s extends Serializable {"
+
+ /** Adds an object that instantiates the outer wrapping class. */
+ def postamble = s"""$importsTrailer
+ |}
+ |object ${lineRep.readName} extends ${lineRep.readName}
+ |""".stripMargin
+
+ import nme.{ INTERPRETER_IMPORT_WRAPPER => iw }
+
+ /** Adds a val that instantiates the wrapping class. */
+ def postwrap = s"}\nval $iw = new $iw\n"
+ }
+
+ private lazy val ObjectSourceCode: Wrapper =
+ if (settings.Yreplclassbased) new ClassBasedWrapper else new ObjectBasedWrapper
+
private object ResultObjectSourceCode extends IMain.CodeAssembler[MemberHandler] {
/** We only want to generate this code when the result
* is a value which can be referred to as-is.
@@ -890,7 +930,7 @@ class IMain(@BeanProperty val factory: ScriptEngineFactory, initialSettings: Set
| (""
""".stripMargin.format(
lineRep.evalName, evalResult, lineRep.printName,
- executionWrapper, lineRep.readName + accessPath
+ executionWrapper, fullAccessPath
)
val postamble = """
diff --git a/src/repl/scala/tools/nsc/interpreter/Imports.scala b/src/repl/scala/tools/nsc/interpreter/Imports.scala
index ff7bfd432c..5244858a62 100644
--- a/src/repl/scala/tools/nsc/interpreter/Imports.scala
+++ b/src/repl/scala/tools/nsc/interpreter/Imports.scala
@@ -92,7 +92,7 @@ trait Imports {
* last one imported is actually usable.
*/
case class ComputedImports(prepend: String, append: String, access: String)
- protected def importsCode(wanted: Set[Name]): ComputedImports = {
+ protected def importsCode(wanted: Set[Name], wrapper: Request#Wrapper): ComputedImports = {
/** Narrow down the list of requests from which imports
* should be taken. Removes requests which cannot contribute
* useful imports for the specified set of wanted names.
@@ -130,13 +130,15 @@ trait Imports {
// add code for a new object to hold some imports
def addWrapper() {
- val impname = nme.INTERPRETER_IMPORT_WRAPPER
- code append "object %s {\n".format(impname)
- trailingBraces append "}\n"
- accessPath append ("." + impname)
+ import nme.{ INTERPRETER_IMPORT_WRAPPER => iw }
+ code append (wrapper.prewrap format iw)
+ trailingBraces append wrapper.postwrap
+ accessPath append s".$iw"
currentImps.clear()
}
+
def maybeWrap(names: Name*) = if (names exists currentImps) addWrapper()
+
def wrapBeforeAndAfter[T](op: => T): T = {
addWrapper()
try op finally addWrapper()