summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-06-07 16:38:13 -0700
committerPaul Phillips <paulp@improving.org>2013-06-07 16:38:13 -0700
commitaefdbd3f923826c6efe87d6f5dbaa84095c090ce (patch)
tree5fda90b3f75949b5d947ceaef5f017e78f776bc2
parent5312d6305530eb14d369d0f4acaf7ca4e278ea72 (diff)
parenta45d3e5658a1ccb57d3b420eb36d84f7170404b5 (diff)
downloadscala-aefdbd3f923826c6efe87d6f5dbaa84095c090ce.tar.gz
scala-aefdbd3f923826c6efe87d6f5dbaa84095c090ce.tar.bz2
scala-aefdbd3f923826c6efe87d6f5dbaa84095c090ce.zip
Merge pull request #2622 from scalamacros/pullrequest/paradise
Backport from paradise/macros
-rw-r--r--src/compiler/scala/reflect/macros/util/Helpers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala27
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala48
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala7
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala38
-rw-r--r--test/files/neg/macro-invalidshape.check7
-rw-r--r--test/files/neg/macro-invalidshape/Macros_Test_2.scala5
-rw-r--r--test/files/run/macro-impl-relaxed.check4
-rw-r--r--test/files/run/macro-impl-relaxed/Macros_1.scala14
-rw-r--r--test/files/run/macro-impl-relaxed/Test_2.scala6
11 files changed, 107 insertions, 57 deletions
diff --git a/src/compiler/scala/reflect/macros/util/Helpers.scala b/src/compiler/scala/reflect/macros/util/Helpers.scala
index ada8efa833..9b7680717e 100644
--- a/src/compiler/scala/reflect/macros/util/Helpers.scala
+++ b/src/compiler/scala/reflect/macros/util/Helpers.scala
@@ -54,7 +54,7 @@ trait Helpers {
*
* @see Metalevels.scala for more information and examples about metalevels
*/
- def increaseMetalevel(pre: Type, tp: Type): Type = dealiasAndRewrap(tp) {
+ def increaseMetalevel(pre: Type, tp: Type): Type = transparentShallowTransform(RepeatedParamClass, tp) {
case tp => typeRef(pre, MacroContextExprClass, List(tp))
}
@@ -64,8 +64,8 @@ trait Helpers {
*
* @see Metalevels.scala for more information and examples about metalevels
*/
- def decreaseMetalevel(tp: Type): Type = dealiasAndRewrap(tp) {
+ def decreaseMetalevel(tp: Type): Type = transparentShallowTransform(RepeatedParamClass, tp) {
case ExprClassOf(runtimeType) => runtimeType
- case _ => AnyClass.tpe // so that macro impls with rhs = ??? don't screw up our inference
+ case _ => AnyTpe // so that macro impls with rhs = ??? don't screw up our inference
}
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index fe1607c631..7fa199afaf 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -782,7 +782,7 @@ trait ContextErrors {
}
def MacroExpansionHasInvalidTypeError(expandee: Tree, expanded: Any) = {
- val expected = "expr"
+ val expected = "expr or tree"
val isPathMismatch = expanded != null && expanded.isInstanceOf[scala.reflect.api.Exprs#Expr[_]]
macroExpansionError(expandee,
s"macro must return a compiler-specific $expected; returned value is " + (
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 6c4d1e20aa..86ba3d2164 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -92,11 +92,12 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
methName: String,
// flattens the macro impl's parameter lists having symbols replaced with their fingerprints
// currently fingerprints are calculated solely from types of the symbols:
- // * c.Expr[T] => IMPLPARAM_EXPR
- // * c.WeakTypeTag[T] => index of the type parameter corresponding to that type tag
- // * everything else (e.g. scala.reflect.macros.Context) => IMPLPARAM_OTHER
+ // * c.Expr[T] => LiftedTyped
+ // * c.Tree => LiftedUntyped
+ // * c.WeakTypeTag[T] => Tagged(index of the type parameter corresponding to that type tag)
+ // * everything else (e.g. scala.reflect.macros.Context) => Other
// f.ex. for: def impl[T: WeakTypeTag, U, V: WeakTypeTag](c: Context)(x: c.Expr[T], y: c.Tree): (U, V) = ???
- // `signature` will be equal to List(List(Other), List(Lifted, Other), List(Tagged(0), Tagged(2)))
+ // `signature` will be equal to List(List(Other), List(LiftedTyped, LiftedUntyped), List(Tagged(0), Tagged(2)))
signature: List[List[Fingerprint]],
// type arguments part of a macro impl ref (the right-hand side of a macro definition)
// these trees don't refer to a macro impl, so we can pickle them as is
@@ -124,7 +125,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
* "className" = "Macros$"))
*/
object MacroImplBinding {
- val versionFormat = 4.0
+ val versionFormat = 5.0
def pickleAtom(obj: Any): Tree =
obj match {
@@ -164,7 +165,8 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
def signature: List[List[Fingerprint]] = {
def fingerprint(tpe: Type): Fingerprint = tpe.dealiasWiden match {
case TypeRef(_, RepeatedParamClass, underlying :: Nil) => fingerprint(underlying)
- case ExprClassOf(_) => Lifted
+ case ExprClassOf(_) => LiftedTyped
+ case TreeType() => LiftedUntyped
case _ => Other
}
@@ -388,7 +390,8 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
val wrappedArgs = mapWithIndex(args)((arg, j) => {
val fingerprint = implParams(min(j, implParams.length - 1))
fingerprint match {
- case Lifted => context.Expr[Nothing](arg)(TypeTag.Nothing) // TODO: SI-5752
+ case LiftedTyped => context.Expr[Nothing](arg)(TypeTag.Nothing) // TODO: SI-5752
+ case LiftedUntyped => arg
case _ => abort(s"unexpected fingerprint $fingerprint in $binding with paramss being $paramss " +
s"corresponding to arg $arg in $argss")
}
@@ -690,6 +693,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
}
expanded match {
case expanded: Expr[_] if expandee.symbol.isTermMacro => validateResultingTree(expanded.tree)
+ case expanded: Tree if expandee.symbol.isTermMacro => validateResultingTree(expanded)
case _ => MacroExpansionHasInvalidTypeError(expandee, expanded)
}
} catch {
@@ -804,10 +808,12 @@ class Fingerprint(val value: Int) extends AnyVal {
def paramPos = { assert(isTag, this); value }
def isTag = value >= 0
def isOther = this == Other
- def isExpr = this == Lifted
+ def isExpr = this == LiftedTyped
+ def isTree = this == LiftedUntyped
override def toString = this match {
case Other => "Other"
- case Lifted => "Expr"
+ case LiftedTyped => "Expr"
+ case LiftedUntyped => "Tree"
case _ => s"Tag($value)"
}
}
@@ -815,5 +821,6 @@ class Fingerprint(val value: Int) extends AnyVal {
object Fingerprint {
def Tagged(tparamPos: Int) = new Fingerprint(tparamPos)
val Other = new Fingerprint(-1)
- val Lifted = new Fingerprint(-2)
+ val LiftedTyped = new Fingerprint(-2)
+ val LiftedUntyped = new Fingerprint(-3)
}
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 851fc98a32..4f2b7e2642 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -409,10 +409,6 @@ trait Definitions extends api.StandardDefinitions {
lazy val JavaRepeatedParamClass = specialPolyClass(tpnme.JAVA_REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => arrayType(tparam.tpe))
lazy val RepeatedParamClass = specialPolyClass(tpnme.REPEATED_PARAM_CLASS_NAME, COVARIANT)(tparam => seqType(tparam.tpe))
- def dropByName(tp: Type): Type = tp match {
- case TypeRef(_, ByNameParamClass, arg :: Nil) => arg
- case _ => tp
- }
def isByNameParamType(tp: Type) = tp.typeSymbol == ByNameParamClass
def isScalaRepeatedParamType(tp: Type) = tp.typeSymbol == RepeatedParamClass
def isJavaRepeatedParamType(tp: Type) = tp.typeSymbol == JavaRepeatedParamClass
@@ -433,29 +429,15 @@ trait Definitions extends api.StandardDefinitions {
case _ => false
}
- def repeatedToSingle(tp: Type): Type = tp match {
- case TypeRef(_, RepeatedParamClass, arg :: Nil) => arg
- case _ => tp
- }
-
- def repeatedToSeq(tp: Type): Type = (tp baseType RepeatedParamClass) match {
- case TypeRef(_, RepeatedParamClass, arg :: Nil) => seqType(arg)
- case _ => tp
- }
-
- def seqToRepeated(tp: Type): Type = (tp baseType SeqClass) match {
- case TypeRef(_, SeqClass, arg :: Nil) => scalaRepeatedType(arg)
- case _ => tp
- }
-
- def isReferenceArray(tp: Type) = tp match {
- case TypeRef(_, ArrayClass, arg :: Nil) => arg <:< AnyRefTpe
- case _ => false
- }
- def isArrayOfSymbol(tp: Type, elem: Symbol) = tp match {
- case TypeRef(_, ArrayClass, arg :: Nil) => arg.typeSymbol == elem
- case _ => false
- }
+ // wrapping and unwrapping
+ def dropByName(tp: Type): Type = elementExtract(ByNameParamClass, tp) orElse tp
+ def repeatedToSingle(tp: Type): Type = elementExtract(RepeatedParamClass, tp) orElse tp
+ def repeatedToSeq(tp: Type): Type = elementTransform(RepeatedParamClass, tp)(seqType) orElse tp
+ def seqToRepeated(tp: Type): Type = elementTransform(SeqClass, tp)(scalaRepeatedType) orElse tp
+ def isReferenceArray(tp: Type) = elementTest(ArrayClass, tp)(_ <:< AnyRefTpe)
+ def isArrayOfSymbol(tp: Type, elem: Symbol) = elementTest(ArrayClass, tp)(_.typeSymbol == elem)
+ def elementType(container: Symbol, tp: Type): Type = elementExtract(container, tp)
+ object ExprClassOf { def unapply(tp: Type): Option[Type] = elementExtractOption(ExprClass, tp) }
// collections classes
lazy val ConsClass = requiredClass[scala.collection.immutable.::[_]]
@@ -514,13 +496,6 @@ trait Definitions extends api.StandardDefinitions {
lazy val ExprClass = ExprsClass.map(sym => getMemberClass(sym, tpnme.Expr))
def ExprSplice = ExprClass.map(sym => getMemberMethod(sym, nme.splice))
def ExprValue = ExprClass.map(sym => getMemberMethod(sym, nme.value))
- object ExprClassOf {
- def unapply(tpe: Type): Option[Type] = tpe.dealias match {
- case ExistentialType(_, underlying) => unapply(underlying)
- case TypeRef(_, ExprClass, t :: Nil) => Some(t)
- case _ => None
- }
- }
lazy val ClassTagModule = requiredModule[scala.reflect.ClassTag[_]]
lazy val ClassTagClass = requiredClass[scala.reflect.ClassTag[_]]
@@ -709,11 +684,6 @@ trait Definitions extends api.StandardDefinitions {
(sym eq PartialFunctionClass) || (sym eq AbstractPartialFunctionClass)
}
- def elementType(container: Symbol, tp: Type): Type = tp match {
- case TypeRef(_, `container`, arg :: Nil) => arg
- case _ => NoType
- }
-
def arrayType(arg: Type) = appliedType(ArrayClass, arg)
def byNameType(arg: Type) = appliedType(ByNameParamClass, arg)
def iteratorOfType(tp: Type) = appliedType(IteratorClass, tp)
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index d1e8a04553..3a8d3fd460 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -837,11 +837,12 @@ abstract class TreeInfo {
def unapply(tree: Tree) = refPart(tree) match {
case ref: RefTree => {
- val isBundle = definitions.isMacroBundleType(ref.qualifier.tpe)
+ val qual = ref.qualifier
+ val isBundle = definitions.isMacroBundleType(qual.tpe)
val owner =
- if (isBundle) ref.qualifier.tpe.typeSymbol
+ if (isBundle) qual.tpe.typeSymbol
else {
- val sym = ref.qualifier.symbol
+ val sym = if (qual.hasSymbolField) qual.symbol else NoSymbol
if (sym.isModule) sym.moduleClass else sym
}
Some((isBundle, owner, ref.symbol, dissectApplied(tree).targs))
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 5c9665cdc7..d942c71619 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -2455,6 +2455,7 @@ trait Types
else
super.prefixString
)
+ def copy(pre: Type = this.pre, sym: Symbol = this.sym, args: List[Type] = this.args) = TypeRef(pre, sym, args)
override def kind = "TypeRef"
}
@@ -3718,6 +3719,43 @@ trait Types
object unwrapToStableClass extends ClassUnwrapper(existential = false) { }
object unwrapWrapperTypes extends TypeUnwrapper(true, true, true, true) { }
+ def elementExtract(container: Symbol, tp: Type): Type = {
+ assert(!container.isAliasType, container)
+ unwrapWrapperTypes(tp baseType container).dealiasWiden match {
+ case TypeRef(_, `container`, arg :: Nil) => arg
+ case _ => NoType
+ }
+ }
+ def elementExtractOption(container: Symbol, tp: Type): Option[Type] = {
+ elementExtract(container, tp) match {
+ case NoType => None
+ case tp => Some(tp)
+ }
+ }
+ def elementTest(container: Symbol, tp: Type)(f: Type => Boolean): Boolean = {
+ elementExtract(container, tp) match {
+ case NoType => false
+ case tp => f(tp)
+ }
+ }
+ def elementTransform(container: Symbol, tp: Type)(f: Type => Type): Type = {
+ elementExtract(container, tp) match {
+ case NoType => NoType
+ case tp => f(tp)
+ }
+ }
+
+ def transparentShallowTransform(container: Symbol, tp: Type)(f: Type => Type): Type = {
+ def loop(tp: Type): Type = tp match {
+ case tp @ AnnotatedType(_, underlying, _) => tp.copy(underlying = loop(underlying))
+ case tp @ ExistentialType(_, underlying) => tp.copy(underlying = loop(underlying))
+ case tp @ PolyType(_, resultType) => tp.copy(resultType = loop(resultType))
+ case tp @ NullaryMethodType(resultType) => tp.copy(resultType = loop(resultType))
+ case tp => elementTransform(container, tp)(el => appliedType(container, f(el))).orElse(f(tp))
+ }
+ loop(tp)
+ }
+
/** Repack existential types, otherwise they sometimes get unpacked in the
* wrong location (type inference comes up with an unexpected skolem)
*/
diff --git a/test/files/neg/macro-invalidshape.check b/test/files/neg/macro-invalidshape.check
index 40a2952569..1938f5ae47 100644
--- a/test/files/neg/macro-invalidshape.check
+++ b/test/files/neg/macro-invalidshape.check
@@ -12,4 +12,9 @@ Macros_Test_2.scala:4: error: missing arguments for method foo in object Impls;
follow this method with `_' if you want to treat it as a partially applied function
def foo3(x: Any) = macro {2; Impls.foo}
^
-three errors found
+Macros_Test_2.scala:7: error: macro implementation reference has wrong shape. required:
+macro [<static object>].<method name>[[<type args>]] or
+macro [<macro bundle>].<method name>[[<type args>]]
+ def foo = macro impl
+ ^
+four errors found
diff --git a/test/files/neg/macro-invalidshape/Macros_Test_2.scala b/test/files/neg/macro-invalidshape/Macros_Test_2.scala
index f39ad20c5d..cf37e14d8e 100644
--- a/test/files/neg/macro-invalidshape/Macros_Test_2.scala
+++ b/test/files/neg/macro-invalidshape/Macros_Test_2.scala
@@ -2,6 +2,11 @@ object Macros {
def foo1(x: Any) = macro 2
def foo2(x: Any) = macro Impls.foo(null)(null)
def foo3(x: Any) = macro {2; Impls.foo}
+ {
+ def impl(c: scala.reflect.macros.Context) = c.literalUnit
+ def foo = macro impl
+ foo
+ }
}
object Test extends App {
diff --git a/test/files/run/macro-impl-relaxed.check b/test/files/run/macro-impl-relaxed.check
new file mode 100644
index 0000000000..487b116534
--- /dev/null
+++ b/test/files/run/macro-impl-relaxed.check
@@ -0,0 +1,4 @@
+2
+2
+2
+2
diff --git a/test/files/run/macro-impl-relaxed/Macros_1.scala b/test/files/run/macro-impl-relaxed/Macros_1.scala
new file mode 100644
index 0000000000..af62646b4e
--- /dev/null
+++ b/test/files/run/macro-impl-relaxed/Macros_1.scala
@@ -0,0 +1,14 @@
+import language.experimental.macros
+import scala.reflect.macros.Context
+
+object Macros {
+ def implUU(c: Context)(x: c.Tree): c.Tree = x
+ def implTU(c: Context)(x: c.Expr[Int]): c.Tree = x.tree
+ def implUT(c: Context)(x: c.Tree): c.Expr[Int] = c.Expr[Int](x)
+ def implTT(c: Context)(x: c.Expr[Int]): c.Expr[Int] = x
+
+ def fooUU(x: Int): Int = macro implUU
+ def fooTU(x: Int): Int = macro implTU
+ def fooUT(x: Int): Int = macro implUT
+ def fooTT(x: Int): Int = macro implTT
+} \ No newline at end of file
diff --git a/test/files/run/macro-impl-relaxed/Test_2.scala b/test/files/run/macro-impl-relaxed/Test_2.scala
new file mode 100644
index 0000000000..2eaeef0fd0
--- /dev/null
+++ b/test/files/run/macro-impl-relaxed/Test_2.scala
@@ -0,0 +1,6 @@
+object Test extends App {
+ println(Macros.fooUU(2))
+ println(Macros.fooTU(2))
+ println(Macros.fooUT(2))
+ println(Macros.fooTT(2))
+} \ No newline at end of file