Skip to content

Commit 5bdfdde

Browse files
committed
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.
1 parent 07a0b70 commit 5bdfdde

File tree

5 files changed

+70
-7
lines changed

5 files changed

+70
-7
lines changed

src/compiler/scala/tools/nsc/typechecker/Macros.scala

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
588588
val nullaryArgsEmptyParams = exprArgs.isEmpty && macroDef.paramss == ListOfNil
589589
if (argcDoesntMatch && !nullaryArgsEmptyParams) { typer.TyperErrorGen.MacroPartialApplicationError(expandee) }
590590

591-
var argss: List[List[Any]] = exprArgs.toList
591+
val argss: List[List[Any]] = exprArgs.toList
592592
macroTraceVerbose("context: ")(context)
593593
macroTraceVerbose("argss: ")(argss)
594594

@@ -597,9 +597,6 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
597597
if (fastTrack(macroDef) validate context) argss
598598
else typer.TyperErrorGen.MacroPartialApplicationError(expandee)
599599
} else {
600-
val binding = loadMacroImplBinding(macroDef)
601-
macroTraceVerbose("binding: ")(binding)
602-
603600
// if paramss have typetag context bounds, add an arglist to argss if necessary and instantiate the corresponding evidences
604601
// consider the following example:
605602
//
@@ -616,6 +613,8 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
616613
// then T and U need to be inferred from the lexical scope of the call using `asSeenFrom`
617614
// whereas V won't be resolved by asSeenFrom and need to be loaded directly from `expandee` which needs to contain a TypeApply node
618615
// also, macro implementation reference may contain a regular type as a type argument, then we pass it verbatim
616+
val binding = loadMacroImplBinding(macroDef)
617+
macroTraceVerbose("binding: ")(binding)
619618
val tags = binding.signature filter (_ != -1) map (paramPos => {
620619
val targ = binding.targs(paramPos).tpe.typeSymbol
621620
val tpe = if (targ.isTypeParameterOrSkolem) {
@@ -633,14 +632,13 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
633632
targ.tpe
634633
if (tpe.isConcrete) context.TypeTag(tpe) else context.AbsTypeTag(tpe)
635634
})
636-
val hasImplicitParams = macroDef.paramss.flatten.lastOption exists (_.isImplicit)
637-
argss = if (hasImplicitParams) argss.dropRight(1) :+ (tags ++ argss.last) else argss :+ tags
635+
macroTraceVerbose("tags: ")(tags)
638636

639637
// transforms argss taking into account varargness of paramss
640638
// note that typetag context bounds are only declared on macroImpls
641639
// so this optional arglist might not match macroDef's paramlist
642640
// nb! varargs can apply to any parameter section, not necessarily to the last one
643-
mapWithIndex(argss)((as, i) => {
641+
mapWithIndex(argss :+ tags)((as, i) => {
644642
val mapsToParamss = macroDef.paramss.indices contains i
645643
if (mapsToParamss) {
646644
val ps = macroDef.paramss(i)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
List(1, 2, 3)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-language:experimental.macros
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import annotation.tailrec
2+
import scala.math.{min, max}
3+
import scala.{specialized => spec}
4+
5+
import language.experimental.macros
6+
7+
import scala.reflect.{ClassTag, TypeTag}
8+
import scala.reflect.macros.Context
9+
10+
object Macros {
11+
def alloc[@spec A:ClassTag](src:Array[A], s1:Int, len:Int) = {
12+
val as = Array.ofDim[A](len)
13+
System.arraycopy(src, s1, as, 0, len)
14+
as
15+
}
16+
17+
/**
18+
* Efficient alternative to Array.apply.
19+
*
20+
* "As seen on scala-internals!"
21+
*/
22+
def array[A](as:A*)(implicit ct: ClassTag[A]) = macro arrayMacro[A]
23+
24+
/**
25+
* Takes in something like:
26+
* ArrayUtil.alloc[Int](11, 22, 33, 44)(ct)
27+
*
28+
* and builds a tree like:
29+
* {
30+
* val arr:Array[Int] = ct.newArray(4)
31+
* arr.update(0, 11)
32+
* arr.update(1, 22)
33+
* arr.update(2, 33)
34+
* arr.update(3, 44)
35+
* arr
36+
* }
37+
*/
38+
def arrayMacro[A:c.AbsTypeTag](c:Context)(as:c.Expr[A]*)(ct: c.Expr[ClassTag[A]]): c.Expr[Array[A]] = {
39+
import c.mirror._
40+
import c.universe._
41+
def const(x:Int) = Literal(Constant(x))
42+
43+
val n = as.length
44+
val arr = newTermName("arr")
45+
46+
val create = Apply(Select(ct.tree, "newArray"), List(const(n)))
47+
val arrtpe = TypeTree(implicitly[c.AbsTypeTag[Array[A]]].tpe)
48+
val valdef = ValDef(Modifiers(), arr, arrtpe, create)
49+
50+
val updates = (0 until n).map {
51+
i => Apply(Select(Ident(arr), "update"), List(const(i), as(i).tree))
52+
}
53+
54+
val exprs = Seq(valdef) ++ updates ++ Seq(Ident(arr))
55+
val block = Block(exprs:_*)
56+
57+
c.Expr[Array[A]](block)
58+
}
59+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object Test extends App {
2+
import Macros._
3+
println(array(1, 2, 3).toList)
4+
}

0 commit comments

Comments
 (0)