summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2013-10-02 17:21:55 +0200
committerAdriaan Moors <adriaan.moors@typesafe.com>2013-11-12 18:40:01 -0800
commit6038bac3513a834e67ab4074c2c7b03aac11b1b3 (patch)
tree61a5fb1019fd24e69c8fca420b710f1235b27b50
parenta2b523a39b4e56eb9ab5d9a5639f5b59d425e354 (diff)
downloadscala-6038bac3513a834e67ab4074c2c7b03aac11b1b3.tar.gz
scala-6038bac3513a834e67ab4074c2c7b03aac11b1b3.tar.bz2
scala-6038bac3513a834e67ab4074c2c7b03aac11b1b3.zip
blackbox restriction #2: can't guide type inference
When an application of a blackbox macro still has undetermined type parameters after Scala’s type inference algorithm has finished working, these type parameters are inferred forcedly, in exactly the same manner as type inference happens for normal methods. This makes it impossible for blackbox macros to influence type inference, prohibiting fundep materialization.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala11
-rw-r--r--test/files/neg/macro-blackbox-fundep-materialization.check12
-rw-r--r--test/files/neg/macro-blackbox-fundep-materialization.flags1
-rw-r--r--test/files/neg/macro-blackbox-fundep-materialization/Macros_1.scala39
-rw-r--r--test/files/neg/macro-blackbox-fundep-materialization/Test_2.scala (renamed from test/files/run/t5923c/Test_2.scala)0
-rw-r--r--test/files/run/macro-blackbox-materialization.check3
-rw-r--r--test/files/run/macro-blackbox-materialization/Macros_1.scala16
-rw-r--r--test/files/run/macro-blackbox-materialization/Test_2.scala5
-rw-r--r--test/files/run/macro-whitebox-fundep-materialization.check (renamed from test/files/run/t5923c.check)0
-rw-r--r--test/files/run/macro-whitebox-fundep-materialization/Macros_1.scala (renamed from test/files/run/t5923c/Macros_1.scala)2
-rw-r--r--test/files/run/macro-whitebox-fundep-materialization/Test_2.scala12
-rw-r--r--test/files/run/t5923c.scala4
12 files changed, 100 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 57358f72f5..27920dbd74 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -678,7 +678,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
// e.g. for Foo it will be Int :: String :: Boolean :: HNil), there's no way to convey this information
// to the typechecker. Therefore the typechecker will infer Nothing for L, which is hardly what we want.
//
- // =========== THE SOLUTION ===========
+ // =========== THE SOLUTION (ENABLED ONLY FOR WHITEBOX MACROS) ===========
//
// To give materializers a chance to say their word before vanilla inference kicks in,
// we infer as much as possible (e.g. in the example above even though L is hopeless, C still can be inferred to Foo)
@@ -686,9 +686,12 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
// Thanks to that the materializer can take a look at what's going on and react accordingly.
val shouldInstantiate = typer.context.undetparams.nonEmpty && !mode.inPolyMode
if (shouldInstantiate) {
- forced += delayed
- typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), pt, keepNothings = false)
- macroExpandApply(typer, delayed, mode, pt)
+ if (isBlackbox(expandee)) typer.instantiatePossiblyExpectingUnit(delayed, mode, pt)
+ else {
+ forced += delayed
+ typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), pt, keepNothings = false)
+ macroExpandApply(typer, delayed, mode, pt)
+ }
} else delayed
}
}
diff --git a/test/files/neg/macro-blackbox-fundep-materialization.check b/test/files/neg/macro-blackbox-fundep-materialization.check
new file mode 100644
index 0000000000..a5a9b9a206
--- /dev/null
+++ b/test/files/neg/macro-blackbox-fundep-materialization.check
@@ -0,0 +1,12 @@
+Test_2.scala:7: Iso.materializeIso is not a valid implicit value for Iso[Test.Foo,L] because:
+hasMatchingSymbol reported error: type mismatch;
+ found : Iso[Test.Foo,(Int, String, Boolean)]
+ required: Iso[Test.Foo,Nothing]
+Note: (Int, String, Boolean) >: Nothing, but trait Iso 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:7: error: could not find implicit value for parameter iso: Iso[Test.Foo,L]
+ val equiv = foo(Foo(23, "foo", true))
+ ^
+one error found
diff --git a/test/files/neg/macro-blackbox-fundep-materialization.flags b/test/files/neg/macro-blackbox-fundep-materialization.flags
new file mode 100644
index 0000000000..4c6cdb71e2
--- /dev/null
+++ b/test/files/neg/macro-blackbox-fundep-materialization.flags
@@ -0,0 +1 @@
+-Xlog-implicits \ No newline at end of file
diff --git a/test/files/neg/macro-blackbox-fundep-materialization/Macros_1.scala b/test/files/neg/macro-blackbox-fundep-materialization/Macros_1.scala
new file mode 100644
index 0000000000..6bddef4b9d
--- /dev/null
+++ b/test/files/neg/macro-blackbox-fundep-materialization/Macros_1.scala
@@ -0,0 +1,39 @@
+import scala.language.experimental.macros
+import scala.reflect.macros.BlackboxContext
+
+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: BlackboxContext): 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/neg/macro-blackbox-fundep-materialization/Test_2.scala
index a00f4ed7db..a00f4ed7db 100644
--- a/test/files/run/t5923c/Test_2.scala
+++ b/test/files/neg/macro-blackbox-fundep-materialization/Test_2.scala
diff --git a/test/files/run/macro-blackbox-materialization.check b/test/files/run/macro-blackbox-materialization.check
new file mode 100644
index 0000000000..7165b734ac
--- /dev/null
+++ b/test/files/run/macro-blackbox-materialization.check
@@ -0,0 +1,3 @@
+C(Int)
+C(String)
+C(Nothing)
diff --git a/test/files/run/macro-blackbox-materialization/Macros_1.scala b/test/files/run/macro-blackbox-materialization/Macros_1.scala
new file mode 100644
index 0000000000..7c31dd7dc2
--- /dev/null
+++ b/test/files/run/macro-blackbox-materialization/Macros_1.scala
@@ -0,0 +1,16 @@
+// For the full version of the test, take a look at run/t5923a
+
+import scala.reflect.macros.BlackboxContext
+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.WeakTypeTag](c: BlackboxContext) = {
+ import c.universe._
+ reify(C[T](c.literal(weakTypeOf[T].toString).splice))
+ }
+} \ No newline at end of file
diff --git a/test/files/run/macro-blackbox-materialization/Test_2.scala b/test/files/run/macro-blackbox-materialization/Test_2.scala
new file mode 100644
index 0000000000..001ff9aea8
--- /dev/null
+++ b/test/files/run/macro-blackbox-materialization/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/macro-whitebox-fundep-materialization.check
index bed7429108..bed7429108 100644
--- a/test/files/run/t5923c.check
+++ b/test/files/run/macro-whitebox-fundep-materialization.check
diff --git a/test/files/run/t5923c/Macros_1.scala b/test/files/run/macro-whitebox-fundep-materialization/Macros_1.scala
index c86e14966b..671a4fff4e 100644
--- a/test/files/run/t5923c/Macros_1.scala
+++ b/test/files/run/macro-whitebox-fundep-materialization/Macros_1.scala
@@ -1,4 +1,4 @@
-import language.experimental.macros
+import scala.language.experimental.macros
import scala.reflect.macros.WhiteboxContext
trait Iso[T, U] {
diff --git a/test/files/run/macro-whitebox-fundep-materialization/Test_2.scala b/test/files/run/macro-whitebox-fundep-materialization/Test_2.scala
new file mode 100644
index 0000000000..a00f4ed7db
--- /dev/null
+++ b/test/files/run/macro-whitebox-fundep-materialization/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/t5923c.scala b/test/files/run/t5923c.scala
new file mode 100644
index 0000000000..956b256785
--- /dev/null
+++ b/test/files/run/t5923c.scala
@@ -0,0 +1,4 @@
+// see neg/macro-blackbox-fundep-materialization and run/macro-whitebox-fundep-materialization
+object Test extends App {
+ // do nothing
+} \ No newline at end of file