summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-02-21 21:25:29 +0100
committerEugene Burmako <xeno.by@gmail.com>2014-02-21 21:33:19 +0100
commit42031708b25f7252fab9992fe444651f8c141e40 (patch)
tree574385abd44805d8475af206e0914a7fcf29b5c9
parent6ce573b491160c0998a35579cc83a4cee2592803 (diff)
downloadscala-42031708b25f7252fab9992fe444651f8c141e40.tar.gz
scala-42031708b25f7252fab9992fe444651f8c141e40.tar.bz2
scala-42031708b25f7252fab9992fe444651f8c141e40.zip
SI-8321 whitebox bundles are now recognized as such
whitebox.Context <: blackbox.Context, so in order to check for blackboxity it's not enough to check whether the context used is <: blackbox.Context.
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala8
-rw-r--r--test/files/neg/macro-bundle-whitebox-use.check17
-rw-r--r--test/files/neg/macro-bundle-whitebox-use/Macros_1.scala108
-rw-r--r--test/files/neg/macro-bundle-whitebox-use/Test_2.scala19
-rw-r--r--test/files/run/macro-bundle-whitebox-decl.check (renamed from test/files/run/macro-bundle-whitebox.check)0
-rw-r--r--test/files/run/macro-bundle-whitebox-decl/Impls_Macros_1.scala (renamed from test/files/run/macro-bundle-whitebox/Impls_Macros_1.scala)0
-rw-r--r--test/files/run/macro-bundle-whitebox-decl/Test_2.scala (renamed from test/files/run/macro-bundle-whitebox/Test_2.scala)0
-rw-r--r--test/files/run/macro-bundle-whitebox-use.check5
-rw-r--r--test/files/run/macro-bundle-whitebox-use/Macros_1.scala108
-rw-r--r--test/files/run/macro-bundle-whitebox-use/Test_2.scala19
-rw-r--r--test/files/run/t8321.check1
-rw-r--r--test/files/run/t8321/Macros_1.scala11
-rw-r--r--test/files/run/t8321/Test_2.scala3
13 files changed, 297 insertions, 2 deletions
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index e1d760a87a..20f6d51fcf 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -628,8 +628,12 @@ trait Definitions extends api.StandardDefinitions {
isContextCompatible && hasSingleConstructor && nonAbstract
}
- def isBlackboxMacroBundleType(tp: Type) =
- isMacroBundleType(tp) && (macroBundleParamInfo(tp) <:< BlackboxContextClass.tpe)
+ def isBlackboxMacroBundleType(tp: Type) = {
+ val isBundle = isMacroBundleType(tp)
+ val isBlackbox = (macroBundleParamInfo(tp) <:< BlackboxContextClass.tpe)
+ val notWhitebox = !(macroBundleParamInfo(tp) <:< WhiteboxContextClass.tpe)
+ isBundle && isBlackbox && notWhitebox
+ }
def isListType(tp: Type) = tp <:< classExistentialType(ListClass)
def isIterableType(tp: Type) = tp <:< classExistentialType(IterableClass)
diff --git a/test/files/neg/macro-bundle-whitebox-use.check b/test/files/neg/macro-bundle-whitebox-use.check
new file mode 100644
index 0000000000..5792e317a6
--- /dev/null
+++ b/test/files/neg/macro-bundle-whitebox-use.check
@@ -0,0 +1,17 @@
+Test_2.scala:2: error: value x is not a member of Any
+ println(ReturnTypeRefinement.foo.x)
+ ^
+Test_2.scala:7: error: type mismatch;
+ found : FundepMaterialization[Test.Foo,(Int, String, Boolean)]
+ required: FundepMaterialization[Test.Foo,Nothing]
+Note: (Int, String, Boolean) >: Nothing, but trait FundepMaterialization is invariant in type U.
+You may wish to define U as -U instead. (SLS 4.5)
+ val equiv = foo(Foo(23, "foo", true))
+ ^
+Test_2.scala:13: error: I don't like classes that contain integers
+ println(implicitly[DynamicMaterialization[C1]])
+ ^
+Test_2.scala:17: error: extractor macros can only be whitebox
+ case ExtractorMacro(x) => println(x)
+ ^
+four errors found
diff --git a/test/files/neg/macro-bundle-whitebox-use/Macros_1.scala b/test/files/neg/macro-bundle-whitebox-use/Macros_1.scala
new file mode 100644
index 0000000000..61bf73e481
--- /dev/null
+++ b/test/files/neg/macro-bundle-whitebox-use/Macros_1.scala
@@ -0,0 +1,108 @@
+import scala.reflect.macros.blackbox.Context
+import scala.language.experimental.macros
+
+// whitebox use case #1: return type refinement
+
+class ReturnTypeRefinementBundle(val c: Context) {
+ import c.universe._
+ def impl = {
+ q"""
+ trait Foo {
+ def x = 2
+ }
+ new Foo {}
+ """
+ }
+}
+
+object ReturnTypeRefinement {
+ def foo: Any = macro ReturnTypeRefinementBundle.impl
+}
+
+// whitebox use case #2: fundep materialization
+
+trait FundepMaterialization[T, U] {
+ def to(t : T) : U
+ // def from(u : U) : T
+}
+
+class FundepMaterializationBundle(val c: Context) {
+ import c.universe._
+ import definitions._
+ import Flag._
+
+ def impl[T: c.WeakTypeTag, U: c.WeakTypeTag]: c.Expr[FundepMaterialization[T, U]] = {
+ val sym = c.weakTypeOf[T].typeSymbol
+ if (!sym.isClass || !sym.asClass.isCaseClass) c.abort(c.enclosingPosition, s"$sym is not a case class")
+ val fields = sym.info.decls.toList.collect{ case x: TermSymbol if x.isVal && x.isCaseAccessor => x }
+
+ def mkTpt() = {
+ val core = Ident(TupleClass(fields.length) orElse UnitClass)
+ if (fields.length == 0) core
+ else AppliedTypeTree(core, fields map (f => TypeTree(f.info)))
+ }
+
+ def mkFrom() = {
+ if (fields.length == 0) Literal(Constant(Unit))
+ else Apply(Ident(newTermName("Tuple" + fields.length)), fields map (f => Select(Ident(newTermName("f")), newTermName(f.name.toString.trim))))
+ }
+
+ val evidenceClass = ClassDef(Modifiers(FINAL), newTypeName("$anon"), List(), Template(
+ List(AppliedTypeTree(Ident(newTypeName("FundepMaterialization")), List(Ident(sym), mkTpt()))),
+ emptyValDef,
+ List(
+ DefDef(Modifiers(), termNames.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(typeNames.EMPTY), typeNames.EMPTY), termNames.CONSTRUCTOR), List())), Literal(Constant(())))),
+ DefDef(Modifiers(), newTermName("to"), List(), List(List(ValDef(Modifiers(PARAM), newTermName("f"), Ident(sym), EmptyTree))), TypeTree(), mkFrom()))))
+ c.Expr[FundepMaterialization[T, U]](Block(List(evidenceClass), Apply(Select(New(Ident(newTypeName("$anon"))), termNames.CONSTRUCTOR), List())))
+ }
+}
+
+object FundepMaterialization {
+ implicit def materializeIso[T, U]: FundepMaterialization[T, U] = macro FundepMaterializationBundle.impl[T, U]
+}
+
+// whitebox use case #3: dynamic materialization
+
+trait DynamicMaterialization[T]
+
+class C1(val x: Int)
+class C2(val x: String)
+
+trait LowPriority {
+ implicit def lessSpecific[T]: DynamicMaterialization[T] = null
+}
+
+object DynamicMaterialization extends LowPriority {
+ implicit def moreSpecific[T]: DynamicMaterialization[T] = macro DynamicMaterializationBundle.impl[T]
+}
+
+class DynamicMaterializationBundle(val c: Context) {
+ import c.universe._
+ def impl[T: c.WeakTypeTag] = {
+ val tpe = weakTypeOf[T]
+ if (tpe.members.exists(_.info =:= typeOf[Int]))
+ c.abort(c.enclosingPosition, "I don't like classes that contain integers")
+ q"new DynamicMaterialization[$tpe]{ override def toString = ${tpe.toString} }"
+ }
+}
+
+// whitebox use case #4: extractor macros
+
+object ExtractorMacro {
+ def unapply(x: Int): Any = macro ExtractorBundle.unapplyImpl
+}
+
+class ExtractorBundle(val c: Context) {
+ import c.universe._
+ def unapplyImpl(x: Tree) = {
+ q"""
+ new {
+ class Match(x: Int) {
+ def isEmpty = false
+ def get = x
+ }
+ def unapply(x: Int) = new Match(x)
+ }.unapply($x)
+ """
+ }
+}
diff --git a/test/files/neg/macro-bundle-whitebox-use/Test_2.scala b/test/files/neg/macro-bundle-whitebox-use/Test_2.scala
new file mode 100644
index 0000000000..3a81700251
--- /dev/null
+++ b/test/files/neg/macro-bundle-whitebox-use/Test_2.scala
@@ -0,0 +1,19 @@
+object Test extends App {
+ println(ReturnTypeRefinement.foo.x)
+
+ case class Foo(i: Int, s: String, b: Boolean)
+ def foo[C, L](c: C)(implicit iso: FundepMaterialization[C, L]): L = iso.to(c)
+ locally {
+ val equiv = foo(Foo(23, "foo", true))
+ def typed[T](t: => T) {}
+ typed[(Int, String, Boolean)](equiv)
+ println(equiv)
+ }
+
+ println(implicitly[DynamicMaterialization[C1]])
+ println(implicitly[DynamicMaterialization[C2]])
+
+ 42 match {
+ case ExtractorMacro(x) => println(x)
+ }
+}
diff --git a/test/files/run/macro-bundle-whitebox.check b/test/files/run/macro-bundle-whitebox-decl.check
index 37c8eaf27a..37c8eaf27a 100644
--- a/test/files/run/macro-bundle-whitebox.check
+++ b/test/files/run/macro-bundle-whitebox-decl.check
diff --git a/test/files/run/macro-bundle-whitebox/Impls_Macros_1.scala b/test/files/run/macro-bundle-whitebox-decl/Impls_Macros_1.scala
index 5e1b11895d..5e1b11895d 100644
--- a/test/files/run/macro-bundle-whitebox/Impls_Macros_1.scala
+++ b/test/files/run/macro-bundle-whitebox-decl/Impls_Macros_1.scala
diff --git a/test/files/run/macro-bundle-whitebox/Test_2.scala b/test/files/run/macro-bundle-whitebox-decl/Test_2.scala
index 195fb49262..195fb49262 100644
--- a/test/files/run/macro-bundle-whitebox/Test_2.scala
+++ b/test/files/run/macro-bundle-whitebox-decl/Test_2.scala
diff --git a/test/files/run/macro-bundle-whitebox-use.check b/test/files/run/macro-bundle-whitebox-use.check
new file mode 100644
index 0000000000..5679c5faba
--- /dev/null
+++ b/test/files/run/macro-bundle-whitebox-use.check
@@ -0,0 +1,5 @@
+2
+(23,foo,true)
+null
+C2
+42
diff --git a/test/files/run/macro-bundle-whitebox-use/Macros_1.scala b/test/files/run/macro-bundle-whitebox-use/Macros_1.scala
new file mode 100644
index 0000000000..de1863418e
--- /dev/null
+++ b/test/files/run/macro-bundle-whitebox-use/Macros_1.scala
@@ -0,0 +1,108 @@
+import scala.reflect.macros.whitebox.Context
+import scala.language.experimental.macros
+
+// whitebox use case #1: return type refinement
+
+class ReturnTypeRefinementBundle(val c: Context) {
+ import c.universe._
+ def impl = {
+ q"""
+ trait Foo {
+ def x = 2
+ }
+ new Foo {}
+ """
+ }
+}
+
+object ReturnTypeRefinement {
+ def foo: Any = macro ReturnTypeRefinementBundle.impl
+}
+
+// whitebox use case #2: fundep materialization
+
+trait FundepMaterialization[T, U] {
+ def to(t : T) : U
+ // def from(u : U) : T
+}
+
+class FundepMaterializationBundle(val c: Context) {
+ import c.universe._
+ import definitions._
+ import Flag._
+
+ def impl[T: c.WeakTypeTag, U: c.WeakTypeTag]: c.Expr[FundepMaterialization[T, U]] = {
+ val sym = c.weakTypeOf[T].typeSymbol
+ if (!sym.isClass || !sym.asClass.isCaseClass) c.abort(c.enclosingPosition, s"$sym is not a case class")
+ val fields = sym.info.decls.toList.collect{ case x: TermSymbol if x.isVal && x.isCaseAccessor => x }
+
+ def mkTpt() = {
+ val core = Ident(TupleClass(fields.length) orElse UnitClass)
+ if (fields.length == 0) core
+ else AppliedTypeTree(core, fields map (f => TypeTree(f.info)))
+ }
+
+ def mkFrom() = {
+ if (fields.length == 0) Literal(Constant(Unit))
+ else Apply(Ident(newTermName("Tuple" + fields.length)), fields map (f => Select(Ident(newTermName("f")), newTermName(f.name.toString.trim))))
+ }
+
+ val evidenceClass = ClassDef(Modifiers(FINAL), newTypeName("$anon"), List(), Template(
+ List(AppliedTypeTree(Ident(newTypeName("FundepMaterialization")), List(Ident(sym), mkTpt()))),
+ emptyValDef,
+ List(
+ DefDef(Modifiers(), termNames.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(typeNames.EMPTY), typeNames.EMPTY), termNames.CONSTRUCTOR), List())), Literal(Constant(())))),
+ DefDef(Modifiers(), newTermName("to"), List(), List(List(ValDef(Modifiers(PARAM), newTermName("f"), Ident(sym), EmptyTree))), TypeTree(), mkFrom()))))
+ c.Expr[FundepMaterialization[T, U]](Block(List(evidenceClass), Apply(Select(New(Ident(newTypeName("$anon"))), termNames.CONSTRUCTOR), List())))
+ }
+}
+
+object FundepMaterialization {
+ implicit def materializeIso[T, U]: FundepMaterialization[T, U] = macro FundepMaterializationBundle.impl[T, U]
+}
+
+// whitebox use case #3: dynamic materialization
+
+trait DynamicMaterialization[T]
+
+class C1(val x: Int)
+class C2(val x: String)
+
+trait LowPriority {
+ implicit def lessSpecific[T]: DynamicMaterialization[T] = null
+}
+
+object DynamicMaterialization extends LowPriority {
+ implicit def moreSpecific[T]: DynamicMaterialization[T] = macro DynamicMaterializationBundle.impl[T]
+}
+
+class DynamicMaterializationBundle(val c: Context) {
+ import c.universe._
+ def impl[T: c.WeakTypeTag] = {
+ val tpe = weakTypeOf[T]
+ if (tpe.members.exists(_.info =:= typeOf[Int]))
+ c.abort(c.enclosingPosition, "I don't like classes that contain integers")
+ q"new DynamicMaterialization[$tpe]{ override def toString = ${tpe.toString} }"
+ }
+}
+
+// whitebox use case #4: extractor macros
+
+object ExtractorMacro {
+ def unapply(x: Int): Any = macro ExtractorBundle.unapplyImpl
+}
+
+class ExtractorBundle(val c: Context) {
+ import c.universe._
+ def unapplyImpl(x: Tree) = {
+ q"""
+ new {
+ class Match(x: Int) {
+ def isEmpty = false
+ def get = x
+ }
+ def unapply(x: Int) = new Match(x)
+ }.unapply($x)
+ """
+ }
+}
diff --git a/test/files/run/macro-bundle-whitebox-use/Test_2.scala b/test/files/run/macro-bundle-whitebox-use/Test_2.scala
new file mode 100644
index 0000000000..3a81700251
--- /dev/null
+++ b/test/files/run/macro-bundle-whitebox-use/Test_2.scala
@@ -0,0 +1,19 @@
+object Test extends App {
+ println(ReturnTypeRefinement.foo.x)
+
+ case class Foo(i: Int, s: String, b: Boolean)
+ def foo[C, L](c: C)(implicit iso: FundepMaterialization[C, L]): L = iso.to(c)
+ locally {
+ val equiv = foo(Foo(23, "foo", true))
+ def typed[T](t: => T) {}
+ typed[(Int, String, Boolean)](equiv)
+ println(equiv)
+ }
+
+ println(implicitly[DynamicMaterialization[C1]])
+ println(implicitly[DynamicMaterialization[C2]])
+
+ 42 match {
+ case ExtractorMacro(x) => println(x)
+ }
+}
diff --git a/test/files/run/t8321.check b/test/files/run/t8321.check
new file mode 100644
index 0000000000..0cfbf08886
--- /dev/null
+++ b/test/files/run/t8321.check
@@ -0,0 +1 @@
+2
diff --git a/test/files/run/t8321/Macros_1.scala b/test/files/run/t8321/Macros_1.scala
new file mode 100644
index 0000000000..70e44fc761
--- /dev/null
+++ b/test/files/run/t8321/Macros_1.scala
@@ -0,0 +1,11 @@
+import scala.reflect.macros.whitebox._
+import scala.language.experimental.macros
+
+class Bundle(val c: Context) {
+ import c.universe._
+ def impl = q"new { val x = 2 }"
+}
+
+object Macros {
+ def foo: Any = macro Bundle.impl
+} \ No newline at end of file
diff --git a/test/files/run/t8321/Test_2.scala b/test/files/run/t8321/Test_2.scala
new file mode 100644
index 0000000000..82ec32384e
--- /dev/null
+++ b/test/files/run/t8321/Test_2.scala
@@ -0,0 +1,3 @@
+object Test extends App {
+ println(Macros.foo.x)
+} \ No newline at end of file