summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-08-25 11:04:37 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-08-25 11:04:37 +0200
commit5bdfddefd7ff13476185b67d869a92c6c9f94506 (patch)
treebffc3880864828ce34726e8d994f5a64e4c6c09a
parent07a0b702ab00223f6f849868f0982cdb7994af66 (diff)
downloadscala-5bdfddefd7ff13476185b67d869a92c6c9f94506.tar.gz
scala-5bdfddefd7ff13476185b67d869a92c6c9f94506.tar.bz2
scala-5bdfddefd7ff13476185b67d869a92c6c9f94506.zip
SI-6281 macroArgs for defs with implicit args
macroArgs now correctly calculates the argss in case when a macro def has implicit parameters. Macro impls can never have implicit parameters other than type tag evidences, so tags will always come in a separate parameter list w.r.t other parameters of macro impls (which are in 1-to-1 correspondence with the parameters of macro defs). Example 1: def w/o implicits: (params1)...(paramsN) impl w/o tags: (params1')...(paramsN') Example 2: def w/o implicits: (params1)...(paramsN) impl w tags: (params1')...(paramsN')(implicit tags) Example 3: def w implicits: (params1)...(paramsN)(implicit paramsN+1) impl w/o tags: (params1')...(paramsN')(paramsN+1') Note: paramsN+1' is not an implicit parameter list because impls cannot have implicit parameters other than tags Example 4: def w implicits: (params1)...(paramsN)(implicit paramsN+1) impl w tags: (params1')...(paramsN')(paramsN+1')(implicit tags) Therefore we don't need to merge the argss.last (that correspond to implicit parameters of macro defs) with tags, as it was incorrectly coded before. We just need to append tags to argss.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala12
-rw-r--r--test/files/run/macro-expand-implicit-argument.check1
-rw-r--r--test/files/run/macro-expand-implicit-argument.flags1
-rw-r--r--test/files/run/macro-expand-implicit-argument/Macros_1.scala59
-rw-r--r--test/files/run/macro-expand-implicit-argument/Test_2.scala4
5 files changed, 70 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index dbafd01ebc..01e773e528 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -588,7 +588,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
val nullaryArgsEmptyParams = exprArgs.isEmpty && macroDef.paramss == ListOfNil
if (argcDoesntMatch && !nullaryArgsEmptyParams) { typer.TyperErrorGen.MacroPartialApplicationError(expandee) }
- var argss: List[List[Any]] = exprArgs.toList
+ val argss: List[List[Any]] = exprArgs.toList
macroTraceVerbose("context: ")(context)
macroTraceVerbose("argss: ")(argss)
@@ -597,9 +597,6 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
if (fastTrack(macroDef) validate context) argss
else typer.TyperErrorGen.MacroPartialApplicationError(expandee)
} else {
- val binding = loadMacroImplBinding(macroDef)
- macroTraceVerbose("binding: ")(binding)
-
// if paramss have typetag context bounds, add an arglist to argss if necessary and instantiate the corresponding evidences
// consider the following example:
//
@@ -616,6 +613,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
// then T and U need to be inferred from the lexical scope of the call using `asSeenFrom`
// whereas V won't be resolved by asSeenFrom and need to be loaded directly from `expandee` which needs to contain a TypeApply node
// also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim
+ val binding = loadMacroImplBinding(macroDef)
+ macroTraceVerbose("binding: ")(binding)
val tags = binding.signature filter (_ != -1) map (paramPos => {
val targ = binding.targs(paramPos).tpe.typeSymbol
val tpe = if (targ.isTypeParameterOrSkolem) {
@@ -633,14 +632,13 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
targ.tpe
if (tpe.isConcrete) context.TypeTag(tpe) else context.AbsTypeTag(tpe)
})
- val hasImplicitParams = macroDef.paramss.flatten.lastOption exists (_.isImplicit)
- argss = if (hasImplicitParams) argss.dropRight(1) :+ (tags ++ argss.last) else argss :+ tags
+ macroTraceVerbose("tags: ")(tags)
// transforms argss taking into account varargness of paramss
// note that typetag context bounds are only declared on macroImpls
// so this optional arglist might not match macroDef's paramlist
// nb! varargs can apply to any parameter section, not necessarily to the last one
- mapWithIndex(argss)((as, i) => {
+ mapWithIndex(argss :+ tags)((as, i) => {
val mapsToParamss = macroDef.paramss.indices contains i
if (mapsToParamss) {
val ps = macroDef.paramss(i)
diff --git a/test/files/run/macro-expand-implicit-argument.check b/test/files/run/macro-expand-implicit-argument.check
new file mode 100644
index 0000000000..fb42345748
--- /dev/null
+++ b/test/files/run/macro-expand-implicit-argument.check
@@ -0,0 +1 @@
+List(1, 2, 3)
diff --git a/test/files/run/macro-expand-implicit-argument.flags b/test/files/run/macro-expand-implicit-argument.flags
new file mode 100644
index 0000000000..cd66464f2f
--- /dev/null
+++ b/test/files/run/macro-expand-implicit-argument.flags
@@ -0,0 +1 @@
+-language:experimental.macros \ No newline at end of file
diff --git a/test/files/run/macro-expand-implicit-argument/Macros_1.scala b/test/files/run/macro-expand-implicit-argument/Macros_1.scala
new file mode 100644
index 0000000000..7629c5a9e2
--- /dev/null
+++ b/test/files/run/macro-expand-implicit-argument/Macros_1.scala
@@ -0,0 +1,59 @@
+import annotation.tailrec
+import scala.math.{min, max}
+import scala.{specialized => spec}
+
+import language.experimental.macros
+
+import scala.reflect.{ClassTag, TypeTag}
+import scala.reflect.macros.Context
+
+object Macros {
+ def alloc[@spec A:ClassTag](src:Array[A], s1:Int, len:Int) = {
+ val as = Array.ofDim[A](len)
+ System.arraycopy(src, s1, as, 0, len)
+ as
+ }
+
+ /**
+ * Efficient alternative to Array.apply.
+ *
+ * "As seen on scala-internals!"
+ */
+ def array[A](as:A*)(implicit ct: ClassTag[A]) = macro arrayMacro[A]
+
+ /**
+ * Takes in something like:
+ * ArrayUtil.alloc[Int](11, 22, 33, 44)(ct)
+ *
+ * and builds a tree like:
+ * {
+ * val arr:Array[Int] = ct.newArray(4)
+ * arr.update(0, 11)
+ * arr.update(1, 22)
+ * arr.update(2, 33)
+ * arr.update(3, 44)
+ * arr
+ * }
+ */
+ def arrayMacro[A:c.AbsTypeTag](c:Context)(as:c.Expr[A]*)(ct: c.Expr[ClassTag[A]]): c.Expr[Array[A]] = {
+ import c.mirror._
+ import c.universe._
+ def const(x:Int) = Literal(Constant(x))
+
+ val n = as.length
+ val arr = newTermName("arr")
+
+ val create = Apply(Select(ct.tree, "newArray"), List(const(n)))
+ val arrtpe = TypeTree(implicitly[c.AbsTypeTag[Array[A]]].tpe)
+ val valdef = ValDef(Modifiers(), arr, arrtpe, create)
+
+ val updates = (0 until n).map {
+ i => Apply(Select(Ident(arr), "update"), List(const(i), as(i).tree))
+ }
+
+ val exprs = Seq(valdef) ++ updates ++ Seq(Ident(arr))
+ val block = Block(exprs:_*)
+
+ c.Expr[Array[A]](block)
+ }
+} \ No newline at end of file
diff --git a/test/files/run/macro-expand-implicit-argument/Test_2.scala b/test/files/run/macro-expand-implicit-argument/Test_2.scala
new file mode 100644
index 0000000000..ce8a068fb4
--- /dev/null
+++ b/test/files/run/macro-expand-implicit-argument/Test_2.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ import Macros._
+ println(array(1, 2, 3).toList)
+} \ No newline at end of file