diff options
author | Martin Odersky <odersky@gmail.com> | 2017-03-08 22:06:22 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2017-03-08 22:06:35 +0100 |
commit | aa2f9078d76a21d828a06b8e324d31a502ee505c (patch) | |
tree | bf657e58c1a78357349def2309dd41c0cecdd9a1 | |
parent | 180dfdc7e81d632e599fb0a545025720e8000573 (diff) | |
download | dotty-aa2f9078d76a21d828a06b8e324d31a502ee505c.tar.gz dotty-aa2f9078d76a21d828a06b8e324d31a502ee505c.tar.bz2 dotty-aa2f9078d76a21d828a06b8e324d31a502ee505c.zip |
Drop special case around Function1
Now only Scala2 mode treats Function1's as implicit conversions. Instead we introduce
a new subclass ImplicitConverter of Function1, instances of which are turned into
implicit conversions.
-rw-r--r-- | compiler/src/dotty/tools/dotc/core/Definitions.scala | 2 | ||||
-rw-r--r-- | compiler/src/dotty/tools/dotc/typer/Implicits.scala | 30 | ||||
-rw-r--r-- | library/src/dotty/DottyPredef.scala | 20 | ||||
-rw-r--r-- | tests/pos-scala2/typerep-stephane.scala (renamed from tests/pos/typerep-stephane.scala) | 0 | ||||
-rw-r--r-- | tests/pos-scala2/viewtest1.scala (renamed from tests/pos/viewtest1.scala) | 0 | ||||
-rw-r--r-- | tests/pos/t0786.scala | 2 | ||||
-rw-r--r-- | tests/run/iterator-from.scala | 6 | ||||
-rw-r--r-- | tests/run/t8280.scala | 6 |
8 files changed, 40 insertions, 26 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index fcbb2f974..1be47c1da 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -338,6 +338,8 @@ class Definitions { def DottyPredefModule(implicit ctx: Context) = DottyPredefModuleRef.symbol def Predef_eqAny(implicit ctx: Context) = DottyPredefModule.requiredMethod(nme.eqAny) + lazy val Predef_ImplicitConverterR = DottyPredefModule.requiredClass("ImplicitConverter").typeRef + def Predef_ImplicitConverter(implicit ctx: Context) = Predef_ImplicitConverterR.symbol lazy val DottyArraysModuleRef = ctx.requiredModuleRef("dotty.runtime.Arrays") def DottyArraysModule(implicit ctx: Context) = DottyArraysModuleRef.symbol diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 6dbb2216c..ebbcbcc95 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -86,35 +86,25 @@ object Implicits { // However, Predef.$conforms is not eligible, because it is a no-op. // // In principle, it would be cleanest if only implicit methods qualified - // as implicit conversions. The reasons for deviating are as follows: - // Keeping Function1: It's still used quite often (for instance, view - // bounds map to implicits of function types) and there is no feasible workaround. - // One tempting workaround would be to add a global def - // - // implicit def convertIfFuntion1[A, B](x: A)(implicit ev: A => B): B = ev(a) - // - // But that would throw out the baby with the bathwater. Now, every subtype of - // function gives again rise to an implicit conversion. So it's better to just accept - // function types in their dual roles. - // - // The reason for the treatment of <:< and conforms is similar. We could - // avoid the clause by having a standard conversion like this in Predef: + // as implicit conversions. We could achieve that by having standard conversions like + // this in Predef: // // implicit def convertIfConforms[A, B](x: A)(implicit ev: A <:< B): B = ev(a) + // implicit def convertIfConverter[A, B](x: A)(implicit ev: ImplicitConverter[A, B]): B = ev(a) // - // But that would slow down implicit search a lot, because this conversion is - // eligible for all pairs of types, and therefore is tried a lot. So we - // emulate the existence of a such a conversion directly in the search. + // (Once `<:<` inherits from `ImplicitConverter` we only need the 2nd one.) + // But clauses like this currently slow down implicit search a lot, because + // they are eligible for all pairs of types, and therefore are tried too often. + // We emulate instead these conversions directly in the search. // The reason for leaving out `Predef_conforms` is that we know it adds // nothing since it only relates subtype with supertype. // // We keep the old behavior under -language:Scala2. - val isFunction = - if (ctx.scala2Mode) tpw.derivesFrom(defn.FunctionClass(1)) - else tpw.isRef(defn.FunctionClass(1)) + val isFunctionInS2 = ctx.scala2Mode && tpw.derivesFrom(defn.FunctionClass(1)) + val isImplicitConverter = tpw.derivesFrom(defn.Predef_ImplicitConverter) val isConforms = tpw.derivesFrom(defn.Predef_Conforms) && ref.symbol != defn.Predef_conforms - !(isFunction || isConforms) + !(isFunctionInS2 || isImplicitConverter || isConforms) } def discardForValueType(tpw: Type): Boolean = tpw match { diff --git a/library/src/dotty/DottyPredef.scala b/library/src/dotty/DottyPredef.scala index 12040e0f3..e78fa9239 100644 --- a/library/src/dotty/DottyPredef.scala +++ b/library/src/dotty/DottyPredef.scala @@ -36,4 +36,24 @@ object DottyPredef { implicit def eqNumFloat : Eq[Number, Float] = Eq implicit def eqDoubleNum: Eq[Double, Number] = Eq implicit def eqNumDouble: Eq[Number, Double] = Eq + + /** A class for implicit values that can serve as implicit conversions + * The implicit resolution algorithm will act as if there existed + * the additional implicit definition: + * + * def $implicitConversion[T, U](x: T)(c: ImplicitConverter[T, U]): U = c(x) + * + * However, the presence of this definition would slow down implicit search since + * its outermost type matches any pair of types. Therefore, implicit search + * contains a special case in `Implicits#discardForView` which emulates the + * conversion in a more efficient way. + * + * Note that this is a SAM class - function literals are automatically converted + * to `ImplicitConverter` values. + * + * Also note that in bootstrapped dotty, `Predef.<:<` should inherit from + * `ImplicitConverter`. This would cut the number of special cases in + * `discardForView` from two to one. + */ + abstract class ImplicitConverter[-T, +U] extends Function1[T, U] } diff --git a/tests/pos/typerep-stephane.scala b/tests/pos-scala2/typerep-stephane.scala index 2cb899591..2cb899591 100644 --- a/tests/pos/typerep-stephane.scala +++ b/tests/pos-scala2/typerep-stephane.scala diff --git a/tests/pos/viewtest1.scala b/tests/pos-scala2/viewtest1.scala index 38945ad2f..38945ad2f 100644 --- a/tests/pos/viewtest1.scala +++ b/tests/pos-scala2/viewtest1.scala diff --git a/tests/pos/t0786.scala b/tests/pos/t0786.scala index b320de0ed..9346afdff 100644 --- a/tests/pos/t0786.scala +++ b/tests/pos/t0786.scala @@ -15,7 +15,7 @@ object ImplicitProblem { def eval = f(nullval[T]).eval + 1 } - def depth[T](n: T)(implicit ev: T => Rep[T]) = n.eval + def depth[T](n: T)(implicit ev: T => Rep[T]) = ev(n).eval def main(args: Array[String]): Unit = { println(depth(nullval[M[Int]])) // (1) this works diff --git a/tests/run/iterator-from.scala b/tests/run/iterator-from.scala index 4f403680c..c7c0f9809 100644 --- a/tests/run/iterator-from.scala +++ b/tests/run/iterator-from.scala @@ -11,7 +11,9 @@ object Test extends dotty.runtime.LegacyApp { val maxKey = 50 val maxValue = 50 - def testSet[A <% Ordered[A]](set: SortedSet[A], list: List[A]): Unit = { + implicit def convertIfView[A](x: A)(implicit view: A => Ordered[A]): Ordered[A] = view(x) + + def testSet[A: Ordering](set: SortedSet[A], list: List[A]): Unit = { val distinctSorted = list.distinct.sorted assertEquals("Set size wasn't the same as list sze", set.size, distinctSorted.size) @@ -24,7 +26,7 @@ object Test extends dotty.runtime.LegacyApp { } } - def testMap[A <% Ordered[A], B](map: SortedMap[A, B], list: List[(A, B)]): Unit = { + def testMap[A: Ordering, B](map: SortedMap[A, B], list: List[(A, B)]): Unit = { val distinctSorted = distinctByKey(list).sortBy(_._1) assertEquals("Map size wasn't the same as list sze", map.size, distinctSorted.size) diff --git a/tests/run/t8280.scala b/tests/run/t8280.scala index 1d2c56b85..5fcbad0a3 100644 --- a/tests/run/t8280.scala +++ b/tests/run/t8280.scala @@ -74,14 +74,14 @@ object Moop3 { // Dotty deviation. This fails for Dotty with ambiguity error for similar reasons as ob1. } object ob2 { - implicit val f1: Int => String = _ => "Int" + implicit val f1: ImplicitConverter[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" + implicit val f1: ImplicitConverter[Int, String] = _ => "Int" + implicit val f2: ImplicitConverter[Long, String] = _ => "Long" println(5: String) } |