From db300d4d9e3eb1de4245ad3aeb686eb5302ae152 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sat, 31 Aug 2013 21:44:34 +0200 Subject: [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. --- .../scala/tools/nsc/typechecker/Typers.scala | 2 +- test/files/run/macro-vampire-false-warning.check | 2 + test/files/run/macro-vampire-false-warning.flags | 1 + .../run/macro-vampire-false-warning/Macros_1.scala | 52 ++++++++++++++++++++++ .../run/macro-vampire-false-warning/Test_2.scala | 6 +++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 test/files/run/macro-vampire-false-warning.check create mode 100644 test/files/run/macro-vampire-false-warning.flags create mode 100644 test/files/run/macro-vampire-false-warning/Macros_1.scala create mode 100644 test/files/run/macro-vampire-false-warning/Test_2.scala 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 -- cgit v1.2.3