diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2013-12-27 18:43:56 +0300 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2013-12-27 18:45:10 +0300 |
commit | bbd03b26f1eeba5abf495f5e745c6623f0cc05b7 (patch) | |
tree | d988476af3851a7e682f853c4058fe77e4fb4564 | |
parent | 9f0594c57716ed551918e15be6da843982e8ba12 (diff) | |
download | scala-bbd03b26f1eeba5abf495f5e745c6623f0cc05b7.tar.gz scala-bbd03b26f1eeba5abf495f5e745c6623f0cc05b7.tar.bz2 scala-bbd03b26f1eeba5abf495f5e745c6623f0cc05b7.zip |
SI-7777 applyDynamic macro fails for nested application
Interplay between the insertApply desugaring and the invokeDynamic desugarings
is already quite brittle, but the real fun begins when macros crash the party.
The proposed patch enriches the `isDesugaredApply` check performed in
`mkInvoke`, the invokeDynamic desugarer, and makes sure that everything
is safe and sound in the macroland.
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 9 | ||||
-rw-r--r-- | test/files/run/t7777.check | 7 | ||||
-rw-r--r-- | test/files/run/t7777/Macros_1.scala | 17 | ||||
-rw-r--r-- | test/files/run/t7777/Test_2.scala | 6 |
5 files changed, 40 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala index 54c665fe56..86bf846f1c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala +++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala @@ -50,6 +50,10 @@ trait StdAttachments { case _ => false } + /** Returns the original tree of the macro expansion if the argument is a macro expansion or EmptyTree otherwise. + */ + def macroExpandee(tree: Tree): Tree = tree.attachments.get[MacroExpansionAttachment].map(_.expandee).getOrElse(EmptyTree) + /** After macro expansion is completed, links the expandee and the expansion result by annotating them both with a `MacroExpansionAttachment`. * The `expanded` parameter is of type `Any`, because macros can expand both into trees and into annotations. */ diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 5e89440bc0..7ff9e854b1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3953,9 +3953,12 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def mkInvoke(cxTree: Tree, tree: Tree, qual: Tree, name: Name): Option[Tree] = { debuglog(s"dyna.mkInvoke($cxTree, $tree, $qual, $name)") val treeInfo.Applied(treeSelection, _, _) = tree - def isDesugaredApply = treeSelection match { - case Select(`qual`, nme.apply) => true - case _ => false + def isDesugaredApply = { + val protoQual = macroExpandee(qual) orElse qual + treeSelection match { + case Select(`protoQual`, nme.apply) => true + case _ => false + } } acceptsApplyDynamicWithType(qual, name) map { tp => // If tp == NoType, pass only explicit type arguments to applyXXX. Not used at all diff --git a/test/files/run/t7777.check b/test/files/run/t7777.check new file mode 100644 index 0000000000..162ff2d2a2 --- /dev/null +++ b/test/files/run/t7777.check @@ -0,0 +1,7 @@ +foo(1, 2) +bar(4, 5) +foo(3) +bar(7) +apply(6) +apply(9) +foo(8) diff --git a/test/files/run/t7777/Macros_1.scala b/test/files/run/t7777/Macros_1.scala new file mode 100644 index 0000000000..459ab3edbb --- /dev/null +++ b/test/files/run/t7777/Macros_1.scala @@ -0,0 +1,17 @@ +import scala.language.experimental.macros +import scala.language.dynamics +import scala.reflect.macros.WhiteboxContext + +class DynMacro extends Dynamic { + def applyDynamic(s: String)(xs: Any*): DynMacro = + macro DynMacro.applyDynamicMacro +} + +object DynMacro extends DynMacro { + def applyDynamicMacro(c: WhiteboxContext)(s: c.Expr[String])(xs: c.Expr[Any]*): c.Expr[DynMacro] = { + import c.universe._ + val Literal(Constant(n: String)) = s.tree + val args = xs.map(_.tree.toString).mkString("(", ", ", ")") + c.Expr(q"println(${ n + args }); ${c.prefix.tree}") + } +}
\ No newline at end of file diff --git a/test/files/run/t7777/Test_2.scala b/test/files/run/t7777/Test_2.scala new file mode 100644 index 0000000000..1fe8b63bab --- /dev/null +++ b/test/files/run/t7777/Test_2.scala @@ -0,0 +1,6 @@ +object Test extends App { + DynMacro.foo(1, 2) // prints "foo(1, 2)" + DynMacro.foo(3).bar(4, 5) // prints "bar(4, 5)", then "foo(3)" + DynMacro(6).bar(7) // prints "bar(7)", then "apply(6)" + DynMacro.foo(8)(9) // Fails! +}
\ No newline at end of file |