summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Typers.scala
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-01-22 13:18:35 +0300
committerEugene Burmako <xeno.by@gmail.com>2014-02-10 09:16:35 +0100
commita02e053a5dec134f7c7dc53a2c1091039218237d (patch)
tree13d71007d47b02b2dea80bcdc9d3609ad0aad9c6 /src/compiler/scala/tools/nsc/typechecker/Typers.scala
parentd2a1dd59c264947137669f4dbda20d89b26743af (diff)
downloadscala-a02e053a5dec134f7c7dc53a2c1091039218237d.tar.gz
scala-a02e053a5dec134f7c7dc53a2c1091039218237d.tar.bz2
scala-a02e053a5dec134f7c7dc53a2c1091039218237d.zip
SI-5920 enables default and named args in macros
When producing an initial spec for macros two years ago, we sort of glossed over named/default arguments in macro applications, leaving them for future work. Once the aforementioned future has come, I’ve made several attempts at making things operational (e.g. last summer), but it’s always been unclear how to marry the quite complex desugaring that tryNamesDefaults performs with the expectations of macro programmers to see unsugared trees in macro impl parameters. Here’s the list of problems that arise when trying to encode named/default arguments of macro applications: 1) When inside macro impls we don’t really care about synthetic vals that are typically introduced to preserve evaluation order in non-positional method applications. When we inline those synthetics, we lose information about evaluation order, which is something that we wouldn’t like to lose in the general case. 2) More importantly, it’s also not very exciting to see invocations of default getters that stand for unspecified default arguments. Ideally, we would like to provide macro programmers with right-hand sides of those default getters, but that is: a) impossible in the current implementation of default parameters, b) would anyway bring scoping problems that we’re not ready to deal with just yet. Being constantly unhappy with potential solutions to the aforementioned problems, I’ve been unable to nail this down until the last weekend, when I realized that: 1) even though we can’t express potential twists in evaluation order within linearly ordered macro impl params, we can use c.macroApplication to store all the named arguments we want, 2) even though we can’t get exactly what we want for default arguments, we can represent them with EmptyTree’s, which is not ideal, but pretty workable. That’s what has been put into life in this commit. As a pleasant side-effect, now the macro engine doesn’t have to reinvent the wheel wrt reporting errors about insufficient arg or arglist count. Since this logic is intertwined with the tryNamesDefaults desugaring, we previously couldn’t make use of it and had to roll our own logic that checked that the number of arguments and parameters of macro applications correspond to each other. Now it’s all deduplicated and consistent.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Typers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala19
1 files changed, 5 insertions, 14 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 10fe530445..020d26c712 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1155,7 +1155,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case mt: MethodType if mode.typingExprNotFunNotLhs && mt.isImplicit => // (4.1)
adaptToImplicitMethod(mt)
- case mt: MethodType if mode.typingExprNotFunNotLhs && !hasUndetsInMonoMode && !treeInfo.isMacroApplicationOrBlock(tree) =>
+ case mt: MethodType if mode.typingExprNotFunNotLhs && !hasUndetsInMonoMode =>
instantiateToMethodType(mt)
case _ =>
vanillaAdapt(tree)
@@ -3292,12 +3292,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
*/
def tryNamesDefaults: Tree = {
val lencmp = compareLengths(args, formals)
-
- def checkNotMacro() = {
- if (treeInfo.isMacroApplication(fun))
- tryTupleApply orElse duplErrorTree(NamedAndDefaultArgumentsNotSupportedForMacros(tree, fun))
- }
-
if (mt.isErroneous) duplErrTree
else if (mode.inPatternMode) {
// #2064
@@ -3316,18 +3310,15 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
else if (allArgsArePositional(argPos) && !isNamedApplyBlock(fun)) {
// if there's no re-ordering, and fun is not transformed, no need to transform
// more than an optimization, e.g. important in "synchronized { x = update-x }"
- checkNotMacro()
doTypedApply(tree, fun, namelessArgs, mode, pt)
} else {
- checkNotMacro()
- transformNamedApplication(Typer.this, mode, pt)(
- treeCopy.Apply(tree, fun, namelessArgs), argPos)
+ unsuppressMacroExpansion(transformNamedApplication(Typer.this, mode, pt)(
+ treeCopy.Apply(tree, suppressMacroExpansion(fun), namelessArgs), argPos))
}
} else {
// defaults are needed. they are added to the argument list in named style as
// calls to the default getters. Example:
// foo[Int](a)() ==> foo[Int](a)(b = foo$qual.foo$default$2[Int](a))
- checkNotMacro()
// SI-8111 transformNamedApplication eagerly shuffles around the application to preserve
// evaluation order. During this process, it calls `changeOwner` on symbols that
@@ -3350,7 +3341,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
symsOwnedByContextOwner foreach (_.owner = context.owner)
}
- val fun1 = transformNamedApplication(Typer.this, mode, pt)(fun, x => x)
+ val fun1 = transformNamedApplication(Typer.this, mode, pt)(suppressMacroExpansion(fun), x => x)
if (fun1.isErroneous) duplErrTree
else {
assert(isNamedApplyBlock(fun1), fun1)
@@ -3376,7 +3367,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// useful when a default doesn't match parameter type, e.g. def f[T](x:T="a"); f[Int]()
val note = "Error occurred in an application involving default arguments."
if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic
- doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt)
+ unsuppressMacroExpansion(doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt))
} else {
rollbackNamesDefaultsOwnerChanges()
tryTupleApply orElse duplErrorTree(NotEnoughArgsError(tree, fun, missing))