diff options
-rw-r--r-- | src/compiler/scala/reflect/macros/contexts/Typers.scala | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/reflect/ToolBox.scala | 28 | ||||
-rw-r--r-- | src/compiler/scala/tools/reflect/ToolBoxFactory.scala | 13 | ||||
-rw-r--r-- | src/reflect/scala/reflect/macros/Typers.scala | 34 | ||||
-rw-r--r-- | test/files/run/t6814.check | 7 | ||||
-rw-r--r-- | test/files/run/t6814/Macros_1.scala | 24 | ||||
-rw-r--r-- | test/files/run/t6814/Test_2.scala | 3 |
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 |