summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2014-02-13 10:31:03 -0800
committerPaul Phillips <paulp@improving.org>2014-02-13 10:46:28 -0800
commit1067e23506aca5083ca915f1dbd7dba689170b36 (patch)
treee2ff84b5b8a15957e812de204b968a1894e83679
parentc83e01d47d941265fa5415c0f29a884c904fdfa0 (diff)
downloadscala-1067e23506aca5083ca915f1dbd7dba689170b36.tar.gz
scala-1067e23506aca5083ca915f1dbd7dba689170b36.tar.bz2
scala-1067e23506aca5083ca915f1dbd7dba689170b36.zip
SI-8280 regression in implicit selection.
In 2fa2db7840 I fixed a bug where applicable implicit conversions would not be found for numeric types if one introduced any aliasing or singleton types, for the usual reasons involving the absence of uniform type normalization. See pos/t7228 for examples - that test case has 20 errors in 2.10.3 but compiles in master. An unintended side effect was making implicit search less oblivious. It turns out that in so doing I had created ambiguity where there was none before. Not because it was any more ambiguous, but because the compiler now had the wits to notice the ambiguity at an earlier time. The fix for this is not intuitive. The way the internal logic is, we need to keep the wool over implicit search's eyes, which leads to those unrecognized types being passed to adapt, where they are recognized and weak subtyping suffices to be more specific. It is sufficient for SI-7228 that weak subtyping be done correctly - the other change, which is reverted here, was exposing the type arguments of Function1 when a view exists as a subtype of Function1. It is also possible this could be remedied by calling weak_<:< somewhere which is presently <:<, but I don't know where and it has a far greater chance of affecting something else than does this, which is a straight reversion of a post-2.10.3 change.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala5
-rw-r--r--test/files/run/t8280.check9
-rw-r--r--test/files/run/t8280.scala82
3 files changed, 95 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 776920ed42..8f5778862d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -306,7 +306,10 @@ trait Implicits {
*/
object Function1 {
val Sym = FunctionClass(1)
- def unapply(tp: Type) = tp baseType Sym match {
+ // It is tempting to think that this should be inspecting "tp baseType Sym"
+ // rather than tp. See test case run/t8280 and the commit message which
+ // accompanies it for explanation why that isn't done.
+ def unapply(tp: Type) = tp match {
case TypeRef(_, Sym, arg1 :: arg2 :: _) => Some((arg1, arg2))
case _ => None
}
diff --git a/test/files/run/t8280.check b/test/files/run/t8280.check
new file mode 100644
index 0000000000..ed392841c7
--- /dev/null
+++ b/test/files/run/t8280.check
@@ -0,0 +1,9 @@
+Int
+Int
+Int
+Int
+Int
+Int
+Int
+Int
+Int
diff --git a/test/files/run/t8280.scala b/test/files/run/t8280.scala
new file mode 100644
index 0000000000..0734d63b6e
--- /dev/null
+++ b/test/files/run/t8280.scala
@@ -0,0 +1,82 @@
+import scala.language.implicitConversions
+
+object Test {
+ def main(args: Array[String]): Unit = {
+ Moop1.ob1
+ Moop1.ob2
+ Moop1.ob3
+ Moop2.ob1
+ Moop2.ob2
+ Moop2.ob3
+ Moop3.ob1
+ Moop3.ob2
+ Moop3.ob3
+ }
+}
+
+// int object vs.
+object Moop1 {
+ object ob1 {
+ implicit object f1 extends (Int => String) { def apply(x: Int): String = "Int" }
+ implicit object f2 extends (Long => String) { def apply(x: Long): String = "Long" }
+
+ println(5: String)
+ }
+ object ob2 {
+ implicit object f1 extends (Int => String) { def apply(x: Int): String = "Int" }
+ implicit def f2(x: Long): String = "Long"
+
+ println(5: String)
+ }
+ object ob3 {
+ implicit object f1 extends (Int => String) { def apply(x: Int): String = "Int" }
+ implicit val f2: Long => String = _ => "Long"
+
+ println(5: String)
+ }
+}
+
+// int def vs.
+object Moop2 {
+ object ob1 {
+ implicit def f1(x: Int): String = "Int"
+ implicit object f2 extends (Long => String) { def apply(x: Long): String = "Long" }
+
+ println(5: String)
+ }
+ object ob2 {
+ implicit def f1(x: Int): String = "Int"
+ implicit def f2(x: Long): String = "Long"
+
+ println(5: String)
+ }
+ object ob3 {
+ implicit def f1(x: Int): String = "Int"
+ implicit val f2: Long => String = _ => "Long"
+
+ println(5: String)
+ }
+}
+
+// int val vs.
+object Moop3 {
+ object ob1 {
+ implicit val f1: Int => String = _ => "Int"
+ implicit object f2 extends (Long => String) { def apply(x: Long): String = "Long" }
+
+ println(5: String)
+ }
+ object ob2 {
+ implicit val f1: Int => String = _ => "Int"
+ implicit def f2(x: Long): String = "Long"
+
+ println(5: String)
+ }
+ object ob3 {
+ implicit val f1: Int => String = _ => "Int"
+ implicit val f2: Long => String = _ => "Long"
+
+ println(5: String)
+ }
+}
+