diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2013-07-10 14:52:45 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2013-07-10 17:50:47 +0200 |
commit | 114d52b1f8be07a95125397879b170e8496c0c2e (patch) | |
tree | af44d71e1ee4fd9d547150af7018f77ce71f960d | |
parent | aada28f92745b21b1fbed81d8c956d60b5d556b9 (diff) | |
download | scala-114d52b1f8be07a95125397879b170e8496c0c2e.tar.gz scala-114d52b1f8be07a95125397879b170e8496c0c2e.tar.bz2 scala-114d52b1f8be07a95125397879b170e8496c0c2e.zip |
macro impls can now return subtypes of c.Tree
10229316db allowed macro impls to take and return values of type c.Tree
in addition to the usual c.Expr. However it didn't take into account that
it is often useful to return subtypes of trees (e.g. with quasiquotes
that expand into expressions typed as precisely as possible). This patch
fixes that oversight.
-rw-r--r-- | src/compiler/scala/reflect/macros/compiler/Errors.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | 11 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Definitions.scala | 6 | ||||
-rw-r--r-- | test/files/neg/macro-quasiquotes.check | 7 | ||||
-rw-r--r-- | test/files/neg/macro-quasiquotes/Macros_1.scala | 15 | ||||
-rw-r--r-- | test/files/neg/macro-quasiquotes/Test_2.scala | 5 | ||||
-rw-r--r-- | test/files/run/macro-quasiquotes.check | 4 | ||||
-rw-r--r-- | test/files/run/macro-quasiquotes/Macros_1.scala | 15 | ||||
-rw-r--r-- | test/files/run/macro-quasiquotes/Test_2.scala | 5 |
9 files changed, 62 insertions, 10 deletions
diff --git a/src/compiler/scala/reflect/macros/compiler/Errors.scala b/src/compiler/scala/reflect/macros/compiler/Errors.scala index dd3142127e..a60a2c2306 100644 --- a/src/compiler/scala/reflect/macros/compiler/Errors.scala +++ b/src/compiler/scala/reflect/macros/compiler/Errors.scala @@ -60,8 +60,8 @@ trait Errors extends Traces { (rtpe, atpe) match { case _ if rtpe eq atpe => success() case (TypeRef(_, RepeatedParamClass, rtpe :: Nil), TypeRef(_, RepeatedParamClass, atpe :: Nil)) => check(rtpe, atpe) - case (ExprClassOf(_), TreeType()) => success() - case (TreeType(), ExprClassOf(_)) => success() + case (ExprClassOf(_), TreeType()) if rtpe.prefix =:= atpe.prefix => success() + case (SubtreeType(), ExprClassOf(_)) if rtpe.prefix =:= atpe.prefix => success() case _ => rtpe <:< atpe } } diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index f2a77b4333..81f5545695 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -697,7 +697,7 @@ trait ContextErrors { protected def macroExpansionError(expandee: Tree, msg: String, pos: Position = NoPosition) = { def msgForLog = if (msg != null && (msg contains "exception during macro expansion")) msg.split(EOL).drop(1).headOption.getOrElse("?") else msg macroLogLite("macro expansion has failed: %s".format(msgForLog)) - if (msg != null) context.error(pos, msg) // issueTypeError(PosAndMsgTypeError(..)) won't work => swallows positions + if (msg != null) context.error(if (pos.isDefined) pos else expandee.pos, msg) // issueTypeError(PosAndMsgTypeError(..)) won't work => swallows positions setError(expandee) throw MacroExpansionException } @@ -782,13 +782,16 @@ trait ContextErrors { } def MacroExpansionHasInvalidTypeError(expandee: Tree, expanded: Any) = { + def isUnaffiliatedExpr = expanded.isInstanceOf[scala.reflect.api.Exprs#Expr[_]] + def isUnaffiliatedTree = expanded.isInstanceOf[scala.reflect.api.Trees#TreeApi] val expected = "expr or tree" - val isPathMismatch = expanded != null && expanded.isInstanceOf[scala.reflect.api.Exprs#Expr[_]] + val actual = if (isUnaffiliatedExpr) "an expr" else if (isUnaffiliatedTree) "a tree" else "unexpected" + val isPathMismatch = expanded != null && (isUnaffiliatedExpr || isUnaffiliatedTree) macroExpansionError(expandee, s"macro must return a compiler-specific $expected; returned value is " + ( if (expanded == null) "null" - else if (isPathMismatch) s" $expected, but it doesn't belong to this compiler" - else " of " + expanded.getClass + else if (isPathMismatch) s"$actual, but it doesn't belong to this compiler's universe" + else "of " + expanded.getClass )) } diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index d3b9c38ee1..6a9fa9a884 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -492,10 +492,8 @@ trait Definitions extends api.StandardDefinitions { lazy val TreesClass = getClassIfDefined("scala.reflect.api.Trees") // defined in scala-reflect.jar, so we need to be careful lazy val TreesTreeType = TreesClass.map(sym => getTypeMember(sym, tpnme.Tree)) - object TreeType { - def unapply(tpe: Type): Boolean = unapply(tpe.typeSymbol) - def unapply(sym: Symbol): Boolean = sym.overrideChain contains TreesTreeType - } + object TreeType { def unapply(tpe: Type): Boolean = tpe.typeSymbol.overrideChain contains TreesTreeType } + object SubtreeType { def unapply(tpe: Type): Boolean = tpe.typeSymbol.overrideChain exists (_.tpe <:< TreesTreeType.tpe) } lazy val ExprsClass = getClassIfDefined("scala.reflect.api.Exprs") // defined in scala-reflect.jar, so we need to be careful lazy val ExprClass = ExprsClass.map(sym => getMemberClass(sym, tpnme.Expr)) diff --git a/test/files/neg/macro-quasiquotes.check b/test/files/neg/macro-quasiquotes.check new file mode 100644 index 0000000000..a2d48723b5 --- /dev/null +++ b/test/files/neg/macro-quasiquotes.check @@ -0,0 +1,7 @@ +Macros_1.scala:14: error: macro implementation has wrong shape: + required: (x: Impls.this.c.Expr[Int]): Impls.this.c.Expr[Any] + found : (x: Impls.this.c.universe.Block): Impls.this.c.universe.Apply +type mismatch for parameter x: Impls.this.c.Expr[Int] does not conform to Impls.this.c.universe.Block + def m3(x: Int) = macro Impls.impl3 + ^ +one error found diff --git a/test/files/neg/macro-quasiquotes/Macros_1.scala b/test/files/neg/macro-quasiquotes/Macros_1.scala new file mode 100644 index 0000000000..17c1034720 --- /dev/null +++ b/test/files/neg/macro-quasiquotes/Macros_1.scala @@ -0,0 +1,15 @@ +import language.experimental.macros +import scala.reflect.macros.Macro + +trait Impls extends Macro { + import c.universe._ + def impl1(x: Expr[Int]) = q"println(x)" + def impl2(x: Tree) = q"println(x)" + def impl3(x: Block) = q"println(x)" +} + +object Macros { + def m1(x: Int) = macro Impls.impl1 + def m2(x: Int) = macro Impls.impl2 + def m3(x: Int) = macro Impls.impl3 +}
\ No newline at end of file diff --git a/test/files/neg/macro-quasiquotes/Test_2.scala b/test/files/neg/macro-quasiquotes/Test_2.scala new file mode 100644 index 0000000000..c7b8948d79 --- /dev/null +++ b/test/files/neg/macro-quasiquotes/Test_2.scala @@ -0,0 +1,5 @@ +object Test extends App { + Macros.m1 + Macros.m2 + Macros.m3 +} diff --git a/test/files/run/macro-quasiquotes.check b/test/files/run/macro-quasiquotes.check new file mode 100644 index 0000000000..94ebaf9001 --- /dev/null +++ b/test/files/run/macro-quasiquotes.check @@ -0,0 +1,4 @@ +1 +2 +3 +4 diff --git a/test/files/run/macro-quasiquotes/Macros_1.scala b/test/files/run/macro-quasiquotes/Macros_1.scala new file mode 100644 index 0000000000..b64eec8743 --- /dev/null +++ b/test/files/run/macro-quasiquotes/Macros_1.scala @@ -0,0 +1,15 @@ +import language.experimental.macros +import scala.reflect.macros.Macro + +trait Impls extends Macro { + import c.universe._ + def impl1 = q"println(1)" + def impl2 = q"{ println(2); println(3) }" + def impl3 = q"4" +} + +object Macros { + def m1 = macro Impls.impl1 + def m2 = macro Impls.impl2 + def m3 = macro Impls.impl3 +}
\ No newline at end of file diff --git a/test/files/run/macro-quasiquotes/Test_2.scala b/test/files/run/macro-quasiquotes/Test_2.scala new file mode 100644 index 0000000000..4be193938f --- /dev/null +++ b/test/files/run/macro-quasiquotes/Test_2.scala @@ -0,0 +1,5 @@ +object Test extends App { + Macros.m1 + Macros.m2 + println(Macros.m3) +} |