diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-11-16 14:13:33 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-11-18 21:13:43 +0100 |
commit | 907d6ea06ee2e2116dc24838b73990dca3d4c651 (patch) | |
tree | 164959bc1c2fc2067526d699c183c39a961015bc | |
parent | 1a6c8597109a9eee122d01c142d8955a14f704c8 (diff) | |
download | scala-907d6ea06ee2e2116dc24838b73990dca3d4c651.tar.gz scala-907d6ea06ee2e2116dc24838b73990dca3d4c651.tar.bz2 scala-907d6ea06ee2e2116dc24838b73990dca3d4c651.zip |
SI-6673 fixes macro problems with eta expansions
Eta expansions previously caused the typer to disable macros. That was
done in order to detect eta expansion of macro defs and show the user
an appropriate error message.
Macros were disabled because to find out whether we're expanding
a macro def, we need to get its symbol, and to get a symbol of something
we need to typecheck that something. However typechecking automatically
expands macros, so, unless we disable macros, after a typecheck we won't
be able to analyze macro occurrences anymore.
Unfortunately this solution has a fatal flaw. By disabling macros we
not only prevent the eta-expandee from macro expanding, but also all
the subtrees of that eta-expandee (see SI-6673).
This commit adds a mechanism for fine-grained control over macro
expansion. Now it's possible to prohibit only the node, but not its
children from macro expanding.
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 9 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/StdAttachments.scala | 2 | ||||
-rw-r--r-- | test/files/run/t6673.check | 1 | ||||
-rw-r--r-- | test/files/run/t6673.scala | 5 |
4 files changed, 13 insertions, 4 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index df3731794a..789211fa98 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1113,7 +1113,8 @@ trait Typers extends Modes with Adaptations with Tags { adaptType() else if ( inExprModeButNot(mode, FUNmode) && !tree.isDef && // typechecking application - tree.symbol != null && tree.symbol.isTermMacro) // of a macro + tree.symbol != null && tree.symbol.isTermMacro && // of a macro + !tree.attachments.get[SuppressMacroExpansionAttachment.type].isDefined) macroExpand(this, tree, mode, pt) else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) adaptConstrPattern() @@ -5215,9 +5216,9 @@ trait Typers extends Modes with Adaptations with Tags { // find out whether the programmer is trying to eta-expand a macro def // to do that we need to typecheck the tree first (we need a symbol of the eta-expandee) // that typecheck must not trigger macro expansions, so we explicitly prohibit them - // Q: "but, " - you may ask - ", `typed1` doesn't call adapt, which does macro expansion, so why explicit check?" - // A: solely for robustness reasons. this mechanism might change in the future, which might break unprotected code - val exprTyped = context.withMacrosDisabled(typed1(expr, mode, pt)) + // however we cannot do `context.withMacrosDisabled` + // because `expr` might contain nested macro calls (see SI-6673) + val exprTyped = typed1(expr updateAttachment SuppressMacroExpansionAttachment, mode, pt) exprTyped match { case macroDef if macroDef.symbol != null && macroDef.symbol.isTermMacro && !macroDef.symbol.isErroneous => MacroEtaError(exprTyped) diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 9fe443bf50..c1ed33ee77 100644 --- a/src/reflect/scala/reflect/internal/StdAttachments.scala +++ b/src/reflect/scala/reflect/internal/StdAttachments.scala @@ -24,4 +24,6 @@ trait StdAttachments { case class CompoundTypeTreeOriginalAttachment(parents: List[Tree], stats: List[Tree]) case class MacroExpansionAttachment(original: Tree) + + case object SuppressMacroExpansionAttachment } diff --git a/test/files/run/t6673.check b/test/files/run/t6673.check new file mode 100644 index 0000000000..ef2aa551dc --- /dev/null +++ b/test/files/run/t6673.check @@ -0,0 +1 @@ +List(x) diff --git a/test/files/run/t6673.scala b/test/files/run/t6673.scala new file mode 100644 index 0000000000..115bbdf234 --- /dev/null +++ b/test/files/run/t6673.scala @@ -0,0 +1,5 @@ +object Test extends App { + def foo(f: String => Array[String])(s: String) = f(s) + val test = foo(Array(_)) _ + println(test("x").toList) +}
\ No newline at end of file |