summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2013-08-31 21:44:34 +0200
committerEugene Burmako <xeno.by@gmail.com>2014-03-05 13:42:27 +0100
commitdb300d4d9e3eb1de4245ad3aeb686eb5302ae152 (patch)
treebc018d6ab9d7c3a74f999bbcde056fbe6830bfa2
parentb66a39653b9bccab72036ba58fec5fd7d596d313 (diff)
downloadscala-db300d4d9e3eb1de4245ad3aeb686eb5302ae152.tar.gz
scala-db300d4d9e3eb1de4245ad3aeb686eb5302ae152.tar.bz2
scala-db300d4d9e3eb1de4245ad3aeb686eb5302ae152.zip
[backport] no longer warns on calls to vampire macros
As eloquently elaborated and cleverly named by Travis Brown, macros defined in structural types are useful: http://meta.plasm.us/posts/2013/07/12/vampire-methods-for-structural-types/. However, since such macros are on the intersection of a number of language features, as usual, there are bugs. This commit fixes an unwanted interaction of macros defined in structural types with the scala.language.reflectiveCalls guard. Since macro calls aren't going to be carried to runtime, there's no need to warn about them.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala2
-rw-r--r--test/files/run/macro-vampire-false-warning.check2
-rw-r--r--test/files/run/macro-vampire-false-warning.flags1
-rw-r--r--test/files/run/macro-vampire-false-warning/Macros_1.scala52
-rw-r--r--test/files/run/macro-vampire-false-warning/Test_2.scala6
5 files changed, 62 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index e09a509839..8153766784 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4934,7 +4934,7 @@ trait Typers extends Modes with Adaptations with Tags {
if (tree.isInstanceOf[PostfixSelect])
checkFeature(tree.pos, PostfixOpsFeature, name.decode)
- if (tree1.symbol != null && tree1.symbol.isOnlyRefinementMember)
+ if (tree1.symbol != null && tree1.symbol.isOnlyRefinementMember && !tree1.symbol.isMacro)
checkFeature(tree1.pos, ReflectiveCallsFeature, tree1.symbol.toString)
if (qual1.hasSymbolWhich(_.isRootPackage)) treeCopy.Ident(tree1, name)
diff --git a/test/files/run/macro-vampire-false-warning.check b/test/files/run/macro-vampire-false-warning.check
new file mode 100644
index 0000000000..4792e70f33
--- /dev/null
+++ b/test/files/run/macro-vampire-false-warning.check
@@ -0,0 +1,2 @@
+2
+3
diff --git a/test/files/run/macro-vampire-false-warning.flags b/test/files/run/macro-vampire-false-warning.flags
new file mode 100644
index 0000000000..e8fb65d50c
--- /dev/null
+++ b/test/files/run/macro-vampire-false-warning.flags
@@ -0,0 +1 @@
+-Xfatal-warnings \ No newline at end of file
diff --git a/test/files/run/macro-vampire-false-warning/Macros_1.scala b/test/files/run/macro-vampire-false-warning/Macros_1.scala
new file mode 100644
index 0000000000..a1c40a5510
--- /dev/null
+++ b/test/files/run/macro-vampire-false-warning/Macros_1.scala
@@ -0,0 +1,52 @@
+// As per http://meta.plasm.us/posts/2013/08/31/feeding-our-vampires/
+
+import scala.annotation.StaticAnnotation
+import scala.reflect.macros.Context
+import scala.language.experimental.macros
+
+class body(tree: Any) extends StaticAnnotation
+
+object Macros {
+ def selFieldImpl(c: Context) = {
+ import c.universe._
+ val field = c.macroApplication.symbol
+ val bodyAnn = field.annotations.filter(_.tpe <:< typeOf[body]).head
+ c.Expr[Any](bodyAnn.scalaArgs.head)
+ }
+
+ def mkObjectImpl(c: Context)(xs: c.Expr[Any]*) = {
+ import c.universe._
+ import Flag._
+ // val kvps = xs.toList map { case q"${_}(${Literal(Constant(name: String))}).->[${_}]($value)" => name -> value }
+ val kvps = xs.map(_.tree).toList map { case Apply(TypeApply(Select(Apply(_, List(Literal(Constant(name: String)))), _), _), List(value)) => name -> value }
+ // val fields = kvps map { case (k, v) => q"@body($v) def ${TermName(k)} = macro Macros.selFieldImpl" }
+ val fields = kvps map { case (k, v) => DefDef(
+ Modifiers(MACRO, tpnme.EMPTY, List(Apply(Select(New(Ident(newTypeName("body"))), nme.CONSTRUCTOR), List(v)))),
+ newTermName(k), Nil, Nil, TypeTree(), Select(Ident(newTermName("Macros")), newTermName("selFieldImpl"))) }
+ // q"import scala.language.experimental.macros; class Workaround { ..$fields }; new Workaround{}"
+ c.Expr[Any](Block(
+ List(
+ Import(Select(Select(Ident(newTermName("scala")), newTermName("language")), newTermName("experimental")), List(ImportSelector(newTermName("macros"), 51, newTermName("macros"), 51))),
+ ClassDef(
+ NoMods, newTypeName("Workaround"), Nil,
+ Template(
+ List(Select(Ident(newTermName("scala")), newTypeName("AnyRef"))), emptyValDef,
+ DefDef(
+ NoMods, nme.CONSTRUCTOR, Nil, List(Nil), TypeTree(),
+ Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(()))))
+ +: fields)),
+ ClassDef(
+ Modifiers(FINAL), newTypeName("$anon"), Nil,
+ Template(
+ List(Ident(newTypeName("Workaround"))), emptyValDef,
+ List(
+ DefDef(
+ NoMods, nme.CONSTRUCTOR, Nil, List(Nil), TypeTree(),
+ Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())))))))),
+ Apply(Select(New(Ident(newTypeName("$anon"))), nme.CONSTRUCTOR), List())))
+ }
+}
+
+object mkObject {
+ def apply(xs: Any*) = macro Macros.mkObjectImpl
+}
diff --git a/test/files/run/macro-vampire-false-warning/Test_2.scala b/test/files/run/macro-vampire-false-warning/Test_2.scala
new file mode 100644
index 0000000000..6e44b68635
--- /dev/null
+++ b/test/files/run/macro-vampire-false-warning/Test_2.scala
@@ -0,0 +1,6 @@
+object Test extends App {
+ val foo = mkObject("x" -> "2", "y" -> 3)
+ println(foo.x)
+ println(foo.y)
+ // println(foo.z) => will result in a compilation error
+} \ No newline at end of file