summaryrefslogtreecommitdiff
path: root/test/files/run
diff options
context:
space:
mode:
Diffstat (limited to 'test/files/run')
-rw-r--r--test/files/run/t5923a-fundep.check (renamed from test/files/run/t5923a.check)0
-rw-r--r--test/files/run/t5923a-fundep.flags1
-rw-r--r--test/files/run/t5923a-fundep/Macros_1.scala52
-rw-r--r--test/files/run/t5923a-fundep/Test_2.scala (renamed from test/files/run/t5923a/Test_2.scala)0
-rw-r--r--test/files/run/t5923a-nofundep.check3
-rw-r--r--test/files/run/t5923a-nofundep/Macros_1.scala (renamed from test/files/run/t5923a/Macros_1.scala)0
-rw-r--r--test/files/run/t5923a-nofundep/Test_2.scala5
-rw-r--r--test/files/run/t5923c.check1
-rw-r--r--test/files/run/t5923c.flags1
-rw-r--r--test/files/run/t5923c/Macros_1.scala39
-rw-r--r--test/files/run/t5923c/Test_2.scala12
-rw-r--r--test/files/run/t5923d.check0
-rw-r--r--test/files/run/t5923d/Macros_1.scala9
-rw-r--r--test/files/run/t5923d/Test_2.scala7
14 files changed, 130 insertions, 0 deletions
diff --git a/test/files/run/t5923a.check b/test/files/run/t5923a-fundep.check
index 7165b734ac..7165b734ac 100644
--- a/test/files/run/t5923a.check
+++ b/test/files/run/t5923a-fundep.check
diff --git a/test/files/run/t5923a-fundep.flags b/test/files/run/t5923a-fundep.flags
new file mode 100644
index 0000000000..c8b4511960
--- /dev/null
+++ b/test/files/run/t5923a-fundep.flags
@@ -0,0 +1 @@
+-Xfundep-materialization \ No newline at end of file
diff --git a/test/files/run/t5923a-fundep/Macros_1.scala b/test/files/run/t5923a-fundep/Macros_1.scala
new file mode 100644
index 0000000000..97076eb102
--- /dev/null
+++ b/test/files/run/t5923a-fundep/Macros_1.scala
@@ -0,0 +1,52 @@
+import scala.reflect.macros.Context
+import language.experimental.macros
+
+case class C[T](t: String)
+object C {
+ implicit def foo[T]: C[T] = macro Macros.impl[T]
+}
+
+object Macros {
+ def impl[T](c: Context)(ttag: c.WeakTypeTag[T]) = {
+ import c.universe._
+ val ttag0 = ttag;
+ {
+ // When we're expanding implicitly[C[Nothing]], the type inferencer will see
+ // that foo[T] returns C[T] and that we request an implicit of type C[Nothing].
+ //
+ // Then the type inferencer will try to match C[T] against C[Nothing] and infer everything it can infer
+ // from that match, but not more (e.g. if we were returning Iso[T, U] and the type we were looking at was Iso[Foo, L],
+ // we wouldn't want U to be auto-inferred to Nothing, as it usually happens with normal methods,
+ // but would rather want it to remain unknown, so that our macro could take a stab at inferring it:
+ // see the comments in this commit for more information).
+ //
+ // Equipped with common sense, in our case of C[T] and C[Nothing] we would expect T to be inferred as Nothing, and then we
+ // would expect T in the corresponding macro invocation to be Nothing. Unfortunately it is not that simple.
+ //
+ // Internally the type inferencer uses Nothing as a dummy value, which stands for "don't know how to
+ // infer this type parameter". In the Iso example, matching Iso[T, U] against Iso[Foo, L] would result in
+ // T being inferred as Foo and U being inferred as Nothing (!!). Then the type inferencer will think:
+ // "Aha! U ended up being Nothing. This means that I failed to infer it,
+ // therefore the result of my work is: T -> Foo, U -> still unknown".
+ //
+ // That's all very good and works very well until Nothing is a genuine result of type inference,
+ // as in our original example of inferring T in C[T] from C[Nothing]. In that case, the inferencer becomes confused
+ // and here in the macro implementation we get weakTypeOf[T] equal to some dummy type carrying a type parameter
+ // instead of Nothing.
+ //
+ // This eccentric behavior of the type inferencer is a long-standing problem in scalac,
+ // so the best one can do for now until it's fixed is to work around, manually converting
+ // suspicious T's into Nothings. Of course, this means that we would have to approximate,
+ // because there's no way to know whether having T here stands for a failed attempt to infer Nothing
+ // or for a failed attempt to infer anything, but at least we're in full control of making the best
+ // of this sad situation.
+ implicit def ttag: WeakTypeTag[T] = {
+ val tpe = ttag0.tpe
+ val sym = tpe.typeSymbol.asType
+ if (sym.isParameter && !sym.isSkolem) TypeTag.Nothing.asInstanceOf[TypeTag[T]]
+ else ttag0
+ }
+ reify(C[T](c.literal(weakTypeOf[T].toString).splice))
+ }
+ }
+} \ No newline at end of file
diff --git a/test/files/run/t5923a/Test_2.scala b/test/files/run/t5923a-fundep/Test_2.scala
index 001ff9aea8..001ff9aea8 100644
--- a/test/files/run/t5923a/Test_2.scala
+++ b/test/files/run/t5923a-fundep/Test_2.scala
diff --git a/test/files/run/t5923a-nofundep.check b/test/files/run/t5923a-nofundep.check
new file mode 100644
index 0000000000..7165b734ac
--- /dev/null
+++ b/test/files/run/t5923a-nofundep.check
@@ -0,0 +1,3 @@
+C(Int)
+C(String)
+C(Nothing)
diff --git a/test/files/run/t5923a/Macros_1.scala b/test/files/run/t5923a-nofundep/Macros_1.scala
index 6d21362c4d..6d21362c4d 100644
--- a/test/files/run/t5923a/Macros_1.scala
+++ b/test/files/run/t5923a-nofundep/Macros_1.scala
diff --git a/test/files/run/t5923a-nofundep/Test_2.scala b/test/files/run/t5923a-nofundep/Test_2.scala
new file mode 100644
index 0000000000..001ff9aea8
--- /dev/null
+++ b/test/files/run/t5923a-nofundep/Test_2.scala
@@ -0,0 +1,5 @@
+object Test extends App {
+ println(implicitly[C[Int]])
+ println(implicitly[C[String]])
+ println(implicitly[C[Nothing]])
+} \ No newline at end of file
diff --git a/test/files/run/t5923c.check b/test/files/run/t5923c.check
new file mode 100644
index 0000000000..bed7429108
--- /dev/null
+++ b/test/files/run/t5923c.check
@@ -0,0 +1 @@
+(23,foo,true)
diff --git a/test/files/run/t5923c.flags b/test/files/run/t5923c.flags
new file mode 100644
index 0000000000..c8b4511960
--- /dev/null
+++ b/test/files/run/t5923c.flags
@@ -0,0 +1 @@
+-Xfundep-materialization \ No newline at end of file
diff --git a/test/files/run/t5923c/Macros_1.scala b/test/files/run/t5923c/Macros_1.scala
new file mode 100644
index 0000000000..0b7a3399e2
--- /dev/null
+++ b/test/files/run/t5923c/Macros_1.scala
@@ -0,0 +1,39 @@
+import language.experimental.macros
+import scala.reflect.macros.Context
+
+trait Iso[T, U] {
+ def to(t : T) : U
+ // def from(u : U) : T
+}
+
+object Iso {
+ implicit def materializeIso[T, U]: Iso[T, U] = macro impl[T, U]
+ def impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: Context): c.Expr[Iso[T, U]] = {
+ import c.universe._
+ import definitions._
+ import Flag._
+
+ 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.typeSignature.declarations.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.typeSignature)))
+ }
+
+ 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("Iso")), List(Ident(sym), mkTpt()))),
+ emptyValDef,
+ List(
+ DefDef(Modifiers(), nme.CONSTRUCTOR, List(), List(List()), TypeTree(), Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), List())), Literal(Constant(())))),
+ DefDef(Modifiers(), newTermName("to"), List(), List(List(ValDef(Modifiers(PARAM), newTermName("f"), Ident(sym), EmptyTree))), TypeTree(), mkFrom()))))
+ c.Expr[Iso[T, U]](Block(List(evidenceClass), Apply(Select(New(Ident(newTypeName("$anon"))), nme.CONSTRUCTOR), List())))
+ }
+}
diff --git a/test/files/run/t5923c/Test_2.scala b/test/files/run/t5923c/Test_2.scala
new file mode 100644
index 0000000000..a00f4ed7db
--- /dev/null
+++ b/test/files/run/t5923c/Test_2.scala
@@ -0,0 +1,12 @@
+// see the comments for macroExpandApply.onDelayed for an explanation of what's tested here
+object Test extends App {
+ case class Foo(i: Int, s: String, b: Boolean)
+ def foo[C, L](c: C)(implicit iso: Iso[C, L]): L = iso.to(c)
+
+ {
+ val equiv = foo(Foo(23, "foo", true))
+ def typed[T](t: => T) {}
+ typed[(Int, String, Boolean)](equiv)
+ println(equiv)
+ }
+} \ No newline at end of file
diff --git a/test/files/run/t5923d.check b/test/files/run/t5923d.check
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/files/run/t5923d.check
diff --git a/test/files/run/t5923d/Macros_1.scala b/test/files/run/t5923d/Macros_1.scala
new file mode 100644
index 0000000000..f32d1af704
--- /dev/null
+++ b/test/files/run/t5923d/Macros_1.scala
@@ -0,0 +1,9 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.Context
+
+trait MappedRow
+trait RowMapper[T <: MappedRow]
+object RowMapper {
+ implicit def mapper[T <: MappedRow]: RowMapper[T] = macro impl[T]
+ def impl[T <: MappedRow : c.WeakTypeTag](c: Context) = c.universe.reify(new RowMapper[T]{})
+} \ No newline at end of file
diff --git a/test/files/run/t5923d/Test_2.scala b/test/files/run/t5923d/Test_2.scala
new file mode 100644
index 0000000000..6be10227c2
--- /dev/null
+++ b/test/files/run/t5923d/Test_2.scala
@@ -0,0 +1,7 @@
+class RowA extends MappedRow
+class RowB extends MappedRow
+
+object Test extends App {
+ implicitly[RowMapper[RowA]]
+ implicitly[RowMapper[RowB]]
+} \ No newline at end of file