Permalink
Browse files

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.
  • Loading branch information...
1 parent 9f0594c commit bbd03b26f1eeba5abf495f5e745c6623f0cc05b7 @xeno-by xeno-by committed Dec 27, 2013
@@ -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.
*/
@@ -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
@@ -0,0 +1,7 @@
+foo(1, 2)
+bar(4, 5)
+foo(3)
+bar(7)
+apply(6)
+apply(9)
+foo(8)
@@ -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}")
+ }
+}
@@ -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!
+}

0 comments on commit bbd03b2

Please sign in to comment.