summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-01-29 18:15:31 +0300
committerEugene Burmako <xeno.by@gmail.com>2014-02-14 14:19:44 +0100
commit2c05f0139758613fbe26a5c03d60a9da29f2f5e5 (patch)
tree7c64843ff5137539172fee6106282b8b7bda94e9
parent0268e03cb461b0c7e8ae2082894988395fc0994a (diff)
downloadscala-2c05f0139758613fbe26a5c03d60a9da29f2f5e5.tar.gz
scala-2c05f0139758613fbe26a5c03d60a9da29f2f5e5.tar.bz2
scala-2c05f0139758613fbe26a5c03d60a9da29f2f5e5.zip
SI-6814 adds typechecker modes to c.typecheck
As per multiple user requests, this commit introduces a shortcut to typecheck trees under multiple different modes: terms (EXPRmode, was exposed in Scala 2.10) and types (TYPEmode). Looking into the rest of a dozen of internal typechecker modes, to the best of my knowledge, I can’t find other modes that we could expose. FUNmode is useful, but very situational. PATTERNmode is useful, but also situational, because we don’t expand macros inside patterns except for whitebox extractor macros. The rest (e.g. POLYmode or TAPPmode) are too low-level.
-rw-r--r--src/compiler/scala/reflect/macros/contexts/Typers.scala11
-rw-r--r--src/compiler/scala/tools/reflect/ToolBox.scala28
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala13
-rw-r--r--src/reflect/scala/reflect/macros/Typers.scala34
-rw-r--r--test/files/run/t6814.check7
-rw-r--r--test/files/run/t6814/Macros_1.scala24
-rw-r--r--test/files/run/t6814/Test_2.scala3
7 files changed, 103 insertions, 17 deletions
diff --git a/src/compiler/scala/reflect/macros/contexts/Typers.scala b/src/compiler/scala/reflect/macros/contexts/Typers.scala
index c1ab17027f..0c3881fdcf 100644
--- a/src/compiler/scala/reflect/macros/contexts/Typers.scala
+++ b/src/compiler/scala/reflect/macros/contexts/Typers.scala
@@ -1,8 +1,6 @@
package scala.reflect.macros
package contexts
-import scala.reflect.internal.Mode
-
trait Typers {
self: Context =>
@@ -10,10 +8,15 @@ trait Typers {
def openImplicits: List[ImplicitCandidate] = callsiteTyper.context.openImplicits.map(_.toImplicitCandidate)
+ type TypecheckMode = scala.reflect.internal.Mode
+ val TypecheckMode = scala.reflect.internal.Mode
+ val TERMmode = TypecheckMode.EXPRmode
+ val TYPEmode = TypecheckMode.TYPEmode | TypecheckMode.FUNmode
+
/**
* @see [[scala.tools.reflect.ToolBox.typeCheck]]
*/
- def typecheck(tree: Tree, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = {
+ def typecheck(tree: Tree, mode: TypecheckMode = TERMmode, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree = {
macroLogVerbose("typechecking %s with expected type %s, implicit views = %s, macros = %s".format(tree, pt, !withImplicitViewsDisabled, !withMacrosDisabled))
val context = callsiteTyper.context
val wrapper1 = if (!withImplicitViewsDisabled) (context.withImplicitsEnabled[Tree] _) else (context.withImplicitsDisabled[Tree] _)
@@ -24,7 +27,7 @@ trait Typers {
// typechecking uses silent anyways (e.g. in typedSelect), so you'll only waste your time
// I'd advise fixing the root cause: finding why the context is not set to report errors
// (also see reflect.runtime.ToolBoxes.typeCheckExpr for a workaround that might work for you)
- wrapper(callsiteTyper.silent(_.typed(universe.duplicateAndKeepPositions(tree), pt), reportAmbiguousErrors = false) match {
+ wrapper(callsiteTyper.silent(_.typed(universe.duplicateAndKeepPositions(tree), mode, pt), reportAmbiguousErrors = false) match {
case universe.analyzer.SilentResultValue(result) =>
macroLogVerbose(result)
result
diff --git a/src/compiler/scala/tools/reflect/ToolBox.scala b/src/compiler/scala/tools/reflect/ToolBox.scala
index 4a3db09909..f47db49718 100644
--- a/src/compiler/scala/tools/reflect/ToolBox.scala
+++ b/src/compiler/scala/tools/reflect/ToolBox.scala
@@ -21,19 +21,35 @@ trait ToolBox[U <: scala.reflect.api.Universe] {
*/
def frontEnd: FrontEnd
+ /** Represents mode of operations of the typechecker underlying `c.typecheck` calls.
+ * Is necessary since the shape of the typechecked tree alone is not enough to guess how it should be typechecked.
+ * Can be EXPRmode (typecheck as a term) or TYPEmode (typecheck as a type).
+ */
+ type TypecheckMode
+
+ /** Indicates that an argument to `c.typecheck` should be typechecked as a term.
+ * This is the default typechecking mode in Scala 2.11 and the only one supported in Scala 2.10.
+ */
+ val TERMmode: TypecheckMode
+
+ /** Indicates that an argument to `c.typecheck` should be typechecked as a type.
+ */
+ val TYPEmode: TypecheckMode
+
/** @see `Typers.typecheck`
*/
@deprecated("Use `tb.typecheck` instead", "2.11.0")
def typeCheck(tree: u.Tree, pt: u.Type = u.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree =
- typecheck(tree, pt, silent, withImplicitViewsDisabled, withMacrosDisabled)
+ typecheck(tree, TERMmode, pt, silent, withImplicitViewsDisabled, withMacrosDisabled)
- /** Typechecks a tree using this ToolBox.
+ /** Typechecks a tree against the expected type `pt`
+ * under typechecking mode specified in `mode` with [[EXPRmode]] being default.
* This populates symbols and types of the tree and possibly transforms it to reflect certain desugarings.
*
* If the tree has unresolved type variables (represented as instances of `FreeTypeSymbol` symbols),
* then they all have to be resolved first using `Tree.substituteTypes`, or an error occurs.
*
- * If `silent` is false, `TypeError` will be thrown in case of a typecheck error.
+ * If `silent` is false, `ToolBoxError` will be thrown in case of a typecheck error.
* If `silent` is true, the typecheck is silent and will return `EmptyTree` if an error occurs.
* Such errors don't vanish and can be inspected by turning on -Ydebug.
*
@@ -41,7 +57,7 @@ trait ToolBox[U <: scala.reflect.api.Universe] {
* `withImplicitViewsDisabled` recursively prohibits implicit views (though, implicit vals will still be looked up and filled in), default value is false
* `withMacrosDisabled` recursively prohibits macro expansions and macro-based implicits, default value is false
*/
- def typecheck(tree: u.Tree, pt: u.Type = u.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree
+ def typecheck(tree: u.Tree, mode: TypecheckMode = TERMmode, pt: u.Type = u.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree
/** Infers an implicit value of the expected type `pt` in top-level context.
* Optional `pos` parameter provides a position that will be associated with the implicit search.
@@ -50,7 +66,7 @@ trait ToolBox[U <: scala.reflect.api.Universe] {
* this API won't take into account the lexical context of the callsite, because
* currently it's impossible to reify it.
*
- * If `silent` is false, `TypeError` will be thrown in case of an inference error.
+ * If `silent` is false, `ToolBoxError` will be thrown in case of an inference error.
* If `silent` is true, the typecheck is silent and will return `EmptyTree` if an error occurs.
* Such errors don't vanish and can be inspected by turning on -Xlog-implicits.
* Unlike in `typecheck`, `silent` is true by default.
@@ -64,7 +80,7 @@ trait ToolBox[U <: scala.reflect.api.Universe] {
* this API won't take into account the lexical context of the callsite, because
* currently it's impossible to reify it.
*
- * If `silent` is false, `TypeError` will be thrown in case of an inference error.
+ * If `silent` is false, `ToolBoxError` will be thrown in case of an inference error.
* If `silent` is true, the typecheck is silent and will return `EmptyTree` if an error occurs.
* Such errors don't vanish and can be inspected by turning on -Xlog-implicits.
* Unlike in `typecheck`, `silent` is true by default.
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index 7bae3203c2..b43b4653eb 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -171,11 +171,11 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
unwrapped
}
- def typecheck(expr: Tree, pt: Type, silent: Boolean, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean): Tree =
+ def typecheck(expr: Tree, pt: Type, mode: scala.reflect.internal.Mode, silent: Boolean, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean): Tree =
transformDuringTyper(expr, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)(
(currentTyper, expr) => {
trace("typing (implicit views = %s, macros = %s): ".format(!withImplicitViewsDisabled, !withMacrosDisabled))(showAttributed(expr, true, true, settings.Yshowsymkinds.value))
- currentTyper.silent(_.typed(expr, pt), reportAmbiguousErrors = false) match {
+ currentTyper.silent(_.typed(expr, mode, pt), reportAmbiguousErrors = false) match {
case analyzer.SilentResultValue(result) =>
trace("success: ")(showAttributed(result, true, true, settings.Yshowsymkinds.value))
result
@@ -361,7 +361,12 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
}
}
- def typecheck(tree: u.Tree, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = withCompilerApi { compilerApi =>
+ type TypecheckMode = scala.reflect.internal.Mode
+ val TypecheckMode = scala.reflect.internal.Mode
+ val TERMmode = TypecheckMode.EXPRmode
+ val TYPEmode = TypecheckMode.TYPEmode | TypecheckMode.FUNmode
+
+ def typecheck(tree: u.Tree, mode: TypecheckMode = TERMmode, expectedType: u.Type, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): u.Tree = withCompilerApi { compilerApi =>
import compilerApi._
if (compiler.settings.verbose) println("importing "+tree+", expectedType = "+expectedType)
@@ -369,7 +374,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
val cexpectedType: compiler.Type = importer.importType(expectedType)
if (compiler.settings.verbose) println("typing "+ctree+", expectedType = "+expectedType)
- val ttree: compiler.Tree = compiler.typecheck(ctree, cexpectedType, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)
+ val ttree: compiler.Tree = compiler.typecheck(ctree, cexpectedType, mode, silent = silent, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)
val uttree = exporter.importTree(ttree)
uttree
}
diff --git a/src/reflect/scala/reflect/macros/Typers.scala b/src/reflect/scala/reflect/macros/Typers.scala
index 6c077de1d2..f1d8575774 100644
--- a/src/reflect/scala/reflect/macros/Typers.scala
+++ b/src/reflect/scala/reflect/macros/Typers.scala
@@ -2,6 +2,8 @@ package scala
package reflect
package macros
+import scala.reflect.internal.{Mode => InternalMode}
+
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
@@ -23,13 +25,39 @@ trait Typers {
*/
def openMacros: List[blackbox.Context]
+ /** Represents mode of operations of the typechecker underlying `c.typecheck` calls.
+ * Is necessary since the shape of the typechecked tree alone is not enough to guess how it should be typechecked.
+ * Can be EXPRmode (typecheck as a term) or TYPEmode (typecheck as a type).
+ */
+ // I'd very much like to make use of https://github.com/dsl-paradise/dsl-paradise here!
+ type TypecheckMode
+
+ /** Indicates that an argument to `c.typecheck` should be typechecked as a term.
+ * This is the default typechecking mode in Scala 2.11 and the only one supported in Scala 2.10.
+ */
+ val TERMmode: TypecheckMode
+
+ /** Indicates that an argument to `c.typecheck` should be typechecked as a type.
+ */
+ val TYPEmode: TypecheckMode
+
+ /** @see `scala.reflect.macros.TypecheckException`
+ */
+ type TypecheckException = scala.reflect.macros.TypecheckException
+
+ /** @see `scala.reflect.macros.TypecheckException`
+ */
+ val TypecheckException = scala.reflect.macros.TypecheckException
+
/** @see `Typers.typecheck`
*/
@deprecated("Use `c.typecheck` instead", "2.11.0")
def typeCheck(tree: Tree, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree =
- typecheck(tree, pt, silent, withImplicitViewsDisabled, withMacrosDisabled)
+ typecheck(tree, TERMmode, pt, silent, withImplicitViewsDisabled, withMacrosDisabled)
- /** Typechecks the provided tree against the expected type `pt` in the macro callsite context.
+ /** Typechecks the provided tree against the expected type `pt` in the macro callsite context
+ * under typechecking mode specified in `mode` with [[EXPRmode]] being default.
+ * This populates symbols and types of the tree and possibly transforms it to reflect certain desugarings.
*
* If `silent` is false, `TypecheckException` will be thrown in case of a typecheck error.
* If `silent` is true, the typecheck is silent and will return `EmptyTree` if an error occurs.
@@ -42,7 +70,7 @@ trait Typers {
*
* @throws [[scala.reflect.macros.TypecheckException]]
*/
- def typecheck(tree: Tree, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree
+ def typecheck(tree: Tree, mode: TypecheckMode = TERMmode, pt: Type = universe.WildcardType, silent: Boolean = false, withImplicitViewsDisabled: Boolean = false, withMacrosDisabled: Boolean = false): Tree
/** Infers an implicit value of the expected type `pt` in the macro callsite context.
* Optional `pos` parameter provides a position that will be associated with the implicit search.
diff --git a/test/files/run/t6814.check b/test/files/run/t6814.check
new file mode 100644
index 0000000000..97ada77202
--- /dev/null
+++ b/test/files/run/t6814.check
@@ -0,0 +1,7 @@
+List[Int]
+scala.collection.immutable.List.type
+object java.lang.RuntimeException is not a value
+List[Int]
+List
+scala.collection.immutable.List.type
+scala.collection.immutable.List.type does not take parameters
diff --git a/test/files/run/t6814/Macros_1.scala b/test/files/run/t6814/Macros_1.scala
new file mode 100644
index 0000000000..0257f451d6
--- /dev/null
+++ b/test/files/run/t6814/Macros_1.scala
@@ -0,0 +1,24 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.blackbox.Context
+
+object Macros {
+ def impl(c: Context) = {
+ import c.universe._
+
+ def test(tree: Tree, mode: c.TypecheckMode): String = {
+ try c.typecheck(tree, mode, silent = false).tpe.toString
+ catch { case c.TypecheckException(_, msg) => msg }
+ }
+
+ q"""
+ println(${test(q"List(1, 2)", c.TERMmode)})
+ println(${test(q"List", c.TERMmode)})
+ println(${test(q"RuntimeException", c.TERMmode)})
+ println(${test(tq"List[Int]", c.TYPEmode)})
+ println(${test(tq"List", c.TYPEmode)})
+ println(${test(q"List", c.TYPEmode)})
+ println(${test(q"List(1, 2)", c.TYPEmode)})
+ """
+ }
+ def foo: Unit = macro impl
+} \ No newline at end of file
diff --git a/test/files/run/t6814/Test_2.scala b/test/files/run/t6814/Test_2.scala
new file mode 100644
index 0000000000..acfddae942
--- /dev/null
+++ b/test/files/run/t6814/Test_2.scala
@@ -0,0 +1,3 @@
+object Test extends App {
+ Macros.foo
+} \ No newline at end of file