From 42031708b25f7252fab9992fe444651f8c141e40 Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Fri, 21 Feb 2014 21:25:29 +0100 Subject: 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. --- test/files/neg/macro-bundle-whitebox-use.check | 17 ++++ .../neg/macro-bundle-whitebox-use/Macros_1.scala | 108 +++++++++++++++++++++ .../neg/macro-bundle-whitebox-use/Test_2.scala | 19 ++++ test/files/run/macro-bundle-whitebox-decl.check | 6 ++ .../Impls_Macros_1.scala | 26 +++++ .../run/macro-bundle-whitebox-decl/Test_2.scala | 8 ++ test/files/run/macro-bundle-whitebox-use.check | 5 + .../run/macro-bundle-whitebox-use/Macros_1.scala | 108 +++++++++++++++++++++ .../run/macro-bundle-whitebox-use/Test_2.scala | 19 ++++ test/files/run/macro-bundle-whitebox.check | 6 -- .../run/macro-bundle-whitebox/Impls_Macros_1.scala | 26 ----- test/files/run/macro-bundle-whitebox/Test_2.scala | 8 -- test/files/run/t8321.check | 1 + test/files/run/t8321/Macros_1.scala | 11 +++ test/files/run/t8321/Test_2.scala | 3 + 15 files changed, 331 insertions(+), 40 deletions(-) create mode 100644 test/files/neg/macro-bundle-whitebox-use.check create mode 100644 test/files/neg/macro-bundle-whitebox-use/Macros_1.scala create mode 100644 test/files/neg/macro-bundle-whitebox-use/Test_2.scala create mode 100644 test/files/run/macro-bundle-whitebox-decl.check create mode 100644 test/files/run/macro-bundle-whitebox-decl/Impls_Macros_1.scala create mode 100644 test/files/run/macro-bundle-whitebox-decl/Test_2.scala create mode 100644 test/files/run/macro-bundle-whitebox-use.check create mode 100644 test/files/run/macro-bundle-whitebox-use/Macros_1.scala create mode 100644 test/files/run/macro-bundle-whitebox-use/Test_2.scala delete mode 100644 test/files/run/macro-bundle-whitebox.check delete mode 100644 test/files/run/macro-bundle-whitebox/Impls_Macros_1.scala delete mode 100644 test/files/run/macro-bundle-whitebox/Test_2.scala create mode 100644 test/files/run/t8321.check create mode 100644 test/files/run/t8321/Macros_1.scala create mode 100644 test/files/run/t8321/Test_2.scala (limited to 'test') 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-decl.check b/test/files/run/macro-bundle-whitebox-decl.check new file mode 100644 index 0000000000..37c8eaf27a --- /dev/null +++ b/test/files/run/macro-bundle-whitebox-decl.check @@ -0,0 +1,6 @@ +() +Int +() +true +IntInt +true diff --git a/test/files/run/macro-bundle-whitebox-decl/Impls_Macros_1.scala b/test/files/run/macro-bundle-whitebox-decl/Impls_Macros_1.scala new file mode 100644 index 0000000000..5e1b11895d --- /dev/null +++ b/test/files/run/macro-bundle-whitebox-decl/Impls_Macros_1.scala @@ -0,0 +1,26 @@ +import scala.language.experimental.macros +import scala.reflect.macros.whitebox.Context + +class Impl(val c: Context) { + def mono = { import c.universe._; c.Expr[Unit](q"()") } + def poly[T: c.WeakTypeTag] = { import c.universe._; c.Expr[String](q"${c.weakTypeOf[T].toString}") } + def weird = macro mono +} + +object Macros { + def mono = macro Impl.mono + def poly[T] = macro Impl.poly[T] +} + +package pkg { + class Impl(val c: Context) { + def mono = { import c.universe._; c.Expr[Boolean](q"true") } + def poly[T: c.WeakTypeTag] = { import c.universe._; c.Expr[String](q"${c.weakTypeOf[T].toString + c.weakTypeOf[T].toString}") } + def weird = macro mono + } + + object Macros { + def mono = macro Impl.mono + def poly[T] = macro Impl.poly[T] + } +} \ No newline at end of file diff --git a/test/files/run/macro-bundle-whitebox-decl/Test_2.scala b/test/files/run/macro-bundle-whitebox-decl/Test_2.scala new file mode 100644 index 0000000000..195fb49262 --- /dev/null +++ b/test/files/run/macro-bundle-whitebox-decl/Test_2.scala @@ -0,0 +1,8 @@ +object Test extends App { + println(Macros.mono) + println(Macros.poly[Int]) + println(new Impl(???).weird) + println(pkg.Macros.mono) + println(pkg.Macros.poly[Int]) + println(new pkg.Impl(???).weird) +} \ No newline at end of file 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/macro-bundle-whitebox.check b/test/files/run/macro-bundle-whitebox.check deleted file mode 100644 index 37c8eaf27a..0000000000 --- a/test/files/run/macro-bundle-whitebox.check +++ /dev/null @@ -1,6 +0,0 @@ -() -Int -() -true -IntInt -true diff --git a/test/files/run/macro-bundle-whitebox/Impls_Macros_1.scala b/test/files/run/macro-bundle-whitebox/Impls_Macros_1.scala deleted file mode 100644 index 5e1b11895d..0000000000 --- a/test/files/run/macro-bundle-whitebox/Impls_Macros_1.scala +++ /dev/null @@ -1,26 +0,0 @@ -import scala.language.experimental.macros -import scala.reflect.macros.whitebox.Context - -class Impl(val c: Context) { - def mono = { import c.universe._; c.Expr[Unit](q"()") } - def poly[T: c.WeakTypeTag] = { import c.universe._; c.Expr[String](q"${c.weakTypeOf[T].toString}") } - def weird = macro mono -} - -object Macros { - def mono = macro Impl.mono - def poly[T] = macro Impl.poly[T] -} - -package pkg { - class Impl(val c: Context) { - def mono = { import c.universe._; c.Expr[Boolean](q"true") } - def poly[T: c.WeakTypeTag] = { import c.universe._; c.Expr[String](q"${c.weakTypeOf[T].toString + c.weakTypeOf[T].toString}") } - def weird = macro mono - } - - object Macros { - def mono = macro Impl.mono - def poly[T] = macro Impl.poly[T] - } -} \ No newline at end of file diff --git a/test/files/run/macro-bundle-whitebox/Test_2.scala b/test/files/run/macro-bundle-whitebox/Test_2.scala deleted file mode 100644 index 195fb49262..0000000000 --- a/test/files/run/macro-bundle-whitebox/Test_2.scala +++ /dev/null @@ -1,8 +0,0 @@ -object Test extends App { - println(Macros.mono) - println(Macros.poly[Int]) - println(new Impl(???).weird) - println(pkg.Macros.mono) - println(pkg.Macros.poly[Int]) - println(new pkg.Impl(???).weird) -} \ No newline at end of file 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 -- cgit v1.2.3