diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 62664e38df3b..6e7185d73bfb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -779,7 +779,27 @@ trait Implicits: SelectionProto(name, memberProto, compat, privateOK = false) case tp => tp } - try inferImplicit(adjust(to), from, from.span) + + def isOldStyleFunctionConversion(tpe: Type): Boolean = + tpe match { + case PolyType(_, resType) => isOldStyleFunctionConversion(resType) + case _ => tpe.derivesFrom(defn.FunctionClass(1)) && !tpe.derivesFrom(defn.ConversionClass) && !tpe.derivesFrom(defn.SubTypeClass) + } + + try + val inferred = inferImplicit(adjust(to), from, from.span) + + inferred match { + case SearchSuccess(_, ref, _) => + if isOldStyleFunctionConversion(ref.underlying) then + report.migrationWarning( + i"The conversion ${ref} will not be applied implicitly here in Scala 3 because only implicit methods and instances of Conversion class will continue to work as implicit views.", + from + ) + case _ => + } + + inferred catch { case ex: AssertionError => implicits.println(s"view $from ==> $to") diff --git a/tests/neg-custom-args/fatal-warnings/i9408a.check b/tests/neg-custom-args/fatal-warnings/i9408a.check new file mode 100644 index 000000000000..f3eceb070113 --- /dev/null +++ b/tests/neg-custom-args/fatal-warnings/i9408a.check @@ -0,0 +1,24 @@ +-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:16:20 ------------------------------------------------------ +16 | val length: Int = "qwerty" // error + | ^^^^^^^^ + |The conversion (Test3.implicitLength : String => Int) will not be applied implicitly here in Scala 3 because only implicit methods and instances of Conversion class will continue to work as implicit views. +-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:21:20 ------------------------------------------------------ +21 | val length: Int = "qwerty" // error + | ^^^^^^^^ + |The conversion (Test4.implicitLength : => String => Int) will not be applied implicitly here in Scala 3 because only implicit methods and instances of Conversion class will continue to work as implicit views. +-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:26:20 ------------------------------------------------------ +26 | val length: Int = "qwerty" // error + | ^^^^^^^^ + |The conversion (Test5.implicitLength : [A] => String => Int) will not be applied implicitly here in Scala 3 because only implicit methods and instances of Conversion class will continue to work as implicit views. +-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:31:20 ------------------------------------------------------ +31 | val length: Int = "qwerty" // error + | ^^^^^^^^ + |The conversion (Test6.implicitLength : Map[String, Int]) will not be applied implicitly here in Scala 3 because only implicit methods and instances of Conversion class will continue to work as implicit views. +-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:35:60 ------------------------------------------------------ +35 | implicit def a2int[A](a: A)(implicit ev: A => Int): Int = a // error + | ^ + |The conversion (ev : A => Int) will not be applied implicitly here in Scala 3 because only implicit methods and instances of Conversion class will continue to work as implicit views. +-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:59:2 ------------------------------------------------------- +59 | 123.foo // error + | ^^^ + |The conversion (Test11.a2foo : [A] => A => Test11.Foo) will not be applied implicitly here in Scala 3 because only implicit methods and instances of Conversion class will continue to work as implicit views. diff --git a/tests/neg-custom-args/fatal-warnings/i9408a.scala b/tests/neg-custom-args/fatal-warnings/i9408a.scala new file mode 100644 index 000000000000..754ca51b701a --- /dev/null +++ b/tests/neg-custom-args/fatal-warnings/i9408a.scala @@ -0,0 +1,86 @@ +import language.`3.0-migration` +import scala.language.implicitConversions + +object Test1 { + implicit def implicitLength(s: String): Int = s.length + val length: Int = "qwerty" // ok +} + +object Test2 { + implicit val implicitLength: Conversion[String, Int] = _.length + val length: Int = "qwerty" // ok +} + +object Test3 { + implicit val implicitLength: String => Int = _.length + val length: Int = "qwerty" // error +} + +object Test4 { + implicit def implicitLength: String => Int = _.length + val length: Int = "qwerty" // error +} + +object Test5 { + implicit def implicitLength[A]: String => Int = _.length + val length: Int = "qwerty" // error +} + +object Test6 { + implicit val implicitLength: Map[String, Int] = Map("qwerty" -> 6) + val length: Int = "qwerty" // error +} + +object Test7 { + implicit def a2int[A](a: A)(implicit ev: A => Int): Int = a // error +} + +object Test8 { + implicit def a2int[A](a: A)(implicit ev: A => Int): Int = ev(a) // ok +} + +object Test9 { + implicit def a2int[A](a: A)(implicit ev: A <:< Int): Int = a // ok +} + +object Test10 { + trait Foo { + def foo = "foo" + } + implicit def a2foo[A](a: A): Foo = new Foo {} + 123.foo // ok +} + +object Test11 { + trait Foo { + def foo = "foo" + } + implicit def a2foo[A]: A => Foo = _ => new Foo {} + 123.foo // error +} + +object Test12 { + implicit class FooOps(a: Any) { + def foo = "foo" + } + 123.foo // ok +} + +object Test13 { + def foo()(implicit x: String => Int) = ??? + implicit val f: String => Int = _.size + foo() // ok +} + +object Test14 { + case class MySeq[A](underlying: Seq[A]) + + implicit def mySeq2seq[A](mySeq: MySeq[A]): Seq[A] = mySeq.underlying + val s: Seq[Int] = MySeq(Seq(1, 2, 3)) // ok +} + +object Test15 { + implicit def implicitSeq[A]: Seq[A] = ??? + def foo(implicit ev: Seq[Int]): Unit = ??? + foo +} diff --git a/tests/neg-custom-args/fatal-warnings/i9408b.check b/tests/neg-custom-args/fatal-warnings/i9408b.check new file mode 100644 index 000000000000..55fed99ae3bb --- /dev/null +++ b/tests/neg-custom-args/fatal-warnings/i9408b.check @@ -0,0 +1,5 @@ + +-- Error: tests/neg-custom-args/fatal-warnings/i9408b/Test_2.scala:6:20 ------------------------------------------------ +6 | val length: Int = "abc" // error + | ^^^^^ + |The conversion (test.conversions.Conv.implicitLength : String => Int) will not be applied implicitly here in Scala 3 because only implicit methods and instances of Conversion class will continue to work as implicit views. diff --git a/tests/neg-custom-args/fatal-warnings/i9408b/Conv_1.scala b/tests/neg-custom-args/fatal-warnings/i9408b/Conv_1.scala new file mode 100644 index 000000000000..8ba9cf819e3c --- /dev/null +++ b/tests/neg-custom-args/fatal-warnings/i9408b/Conv_1.scala @@ -0,0 +1,5 @@ +package test.conversions + +object Conv { + implicit val implicitLength: String => Int = _.length +} diff --git a/tests/neg-custom-args/fatal-warnings/i9408b/Test_2.scala b/tests/neg-custom-args/fatal-warnings/i9408b/Test_2.scala new file mode 100644 index 000000000000..885126691cf8 --- /dev/null +++ b/tests/neg-custom-args/fatal-warnings/i9408b/Test_2.scala @@ -0,0 +1,7 @@ +import language.`3.0-migration` +import scala.language.implicitConversions + +object Test { + import test.conversions.Conv._ + val length: Int = "abc" // error +}