summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2014-02-09 20:49:48 +0100
committerEugene Burmako <xeno.by@gmail.com>2014-02-09 20:49:48 +0100
commit2606becba91fa3d31cdeb3069a5a35b0163a4cde (patch)
tree767e8a3a966a5d93e1e84875a7bbda2e8575ceb7
parent9dc60af28e2c17579c17e27168d1e29ef34efaef (diff)
downloadscala-2606becba91fa3d31cdeb3069a5a35b0163a4cde.tar.gz
scala-2606becba91fa3d31cdeb3069a5a35b0163a4cde.tar.bz2
scala-2606becba91fa3d31cdeb3069a5a35b0163a4cde.zip
changes the order of whitebox typechecks. yes, again.
My first attempt at SI-6992 was about having whitebox expansions first typecheck against outerPt and only then verify that the result is compatible with innerPt. That was a nice try, but soon after it went live in 2.11.0-M8, we've got multiple reports with problems - both shapeless and then in a week specs2 started having issues with their whitebox macros. In shapeless, typecheck against outerPt screwed up type inference, which was more or less fixable by explicit type annotations, so I decided to wait a bit before jumping to conclusions. However, in specs2 the problem was more insidious. After being typechecked against outerPt, expansions were being implicitly converted to a type that became incompatible with innerPt. This revealed a fatal flaw of the implemented approach - if allowed to typecheck against outerPt first, whitebox macros could never be robust. Now realizing that "outerPt > innerPt" doesn't work, I nevertheless wasn't looking forward to rolling that back to "innerPt > outerPt", because that would revive SI-6992 and SI-8048 that are highly unintuitive, especially the latter one. Therefore, this commit combines the permissiveness of "... > innerPt" approaches with the robustness of "innerPt > outerPt", introducing "WildcardType > innerPt > outerPt".
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala8
-rw-r--r--test/files/pos/t8209a.check0
-rw-r--r--test/files/pos/t8209a/Macros_1.scala17
-rw-r--r--test/files/pos/t8209a/Test_2.scala4
-rw-r--r--test/files/pos/t8209b.check0
-rw-r--r--test/files/pos/t8209b/Macros_1.scala17
-rw-r--r--test/files/pos/t8209b/Test_2.scala4
7 files changed, 47 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index cf82d6baac..677c94e063 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -620,9 +620,11 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
val expanded1 = atPos(enclosingMacroPosition.makeTransparent)(Typed(expanded0, TypeTree(innerPt)))
typecheck("blackbox typecheck", expanded1, outerPt)
} else {
- val expanded1 = expanded0
- val expanded2 = typecheck("whitebox typecheck #1", expanded1, outerPt)
- typecheck("whitebox typecheck #2", expanded2, innerPt)
+ // whitebox expansions need to be typechecked against WildcardType first in order to avoid SI-6992 and SI-8048
+ // then we typecheck against innerPt, not against outerPt in order to prevent SI-8209
+ val expanded1 = typecheck("whitebox typecheck #0", expanded0, WildcardType)
+ val expanded2 = typecheck("whitebox typecheck #1", expanded1, innerPt)
+ typecheck("whitebox typecheck #2", expanded2, outerPt)
}
}
override def onDelayed(delayed: Tree) = {
diff --git a/test/files/pos/t8209a.check b/test/files/pos/t8209a.check
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/files/pos/t8209a.check
diff --git a/test/files/pos/t8209a/Macros_1.scala b/test/files/pos/t8209a/Macros_1.scala
new file mode 100644
index 0000000000..17014b4744
--- /dev/null
+++ b/test/files/pos/t8209a/Macros_1.scala
@@ -0,0 +1,17 @@
+import scala.language.experimental.macros
+import scala.language.implicitConversions
+import scala.reflect.macros.blackbox.Context
+
+class A
+object A { implicit def a2b(a: A): B = ??? }
+class B
+class C extends A
+
+object Macros {
+ def impl(c: Context) = {
+ import c.universe._
+ q"new C"
+ }
+
+ def foo: A = macro impl
+} \ No newline at end of file
diff --git a/test/files/pos/t8209a/Test_2.scala b/test/files/pos/t8209a/Test_2.scala
new file mode 100644
index 0000000000..e19d572f55
--- /dev/null
+++ b/test/files/pos/t8209a/Test_2.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ val a: A = Macros.foo
+ val b: B = Macros.foo
+} \ No newline at end of file
diff --git a/test/files/pos/t8209b.check b/test/files/pos/t8209b.check
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/files/pos/t8209b.check
diff --git a/test/files/pos/t8209b/Macros_1.scala b/test/files/pos/t8209b/Macros_1.scala
new file mode 100644
index 0000000000..705f7d630c
--- /dev/null
+++ b/test/files/pos/t8209b/Macros_1.scala
@@ -0,0 +1,17 @@
+import scala.language.experimental.macros
+import scala.language.implicitConversions
+import scala.reflect.macros.whitebox.Context
+
+class A
+object A { implicit def a2b(a: A): B = ??? }
+class B
+class C extends A
+
+object Macros {
+ def impl(c: Context) = {
+ import c.universe._
+ q"new C"
+ }
+
+ def foo: A = macro impl
+} \ No newline at end of file
diff --git a/test/files/pos/t8209b/Test_2.scala b/test/files/pos/t8209b/Test_2.scala
new file mode 100644
index 0000000000..e19d572f55
--- /dev/null
+++ b/test/files/pos/t8209b/Test_2.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ val a: A = Macros.foo
+ val b: B = Macros.foo
+} \ No newline at end of file