Skip to content

Commit 97da3cb

Browse files
authored
Merge pull request #9998 from prolativ/warn-on-implicit-conversion-with-migration-flag
Fix #9408: Warn on implicit view resolved with -source:3.0-migration
2 parents 23fa75c + d52332e commit 97da3cb

File tree

6 files changed

+148
-1
lines changed

6 files changed

+148
-1
lines changed

compiler/src/dotty/tools/dotc/typer/Implicits.scala

+21-1
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,27 @@ trait Implicits:
779779
SelectionProto(name, memberProto, compat, privateOK = false)
780780
case tp => tp
781781
}
782-
try inferImplicit(adjust(to), from, from.span)
782+
783+
def isOldStyleFunctionConversion(tpe: Type): Boolean =
784+
tpe match {
785+
case PolyType(_, resType) => isOldStyleFunctionConversion(resType)
786+
case _ => tpe.derivesFrom(defn.FunctionClass(1)) && !tpe.derivesFrom(defn.ConversionClass) && !tpe.derivesFrom(defn.SubTypeClass)
787+
}
788+
789+
try
790+
val inferred = inferImplicit(adjust(to), from, from.span)
791+
792+
inferred match {
793+
case SearchSuccess(_, ref, _) =>
794+
if isOldStyleFunctionConversion(ref.underlying) then
795+
report.migrationWarning(
796+
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.",
797+
from
798+
)
799+
case _ =>
800+
}
801+
802+
inferred
783803
catch {
784804
case ex: AssertionError =>
785805
implicits.println(s"view $from ==> $to")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:16:20 ------------------------------------------------------
2+
16 | val length: Int = "qwerty" // error
3+
| ^^^^^^^^
4+
|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.
5+
-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:21:20 ------------------------------------------------------
6+
21 | val length: Int = "qwerty" // error
7+
| ^^^^^^^^
8+
|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.
9+
-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:26:20 ------------------------------------------------------
10+
26 | val length: Int = "qwerty" // error
11+
| ^^^^^^^^
12+
|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.
13+
-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:31:20 ------------------------------------------------------
14+
31 | val length: Int = "qwerty" // error
15+
| ^^^^^^^^
16+
|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.
17+
-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:35:60 ------------------------------------------------------
18+
35 | implicit def a2int[A](a: A)(implicit ev: A => Int): Int = a // error
19+
| ^
20+
|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.
21+
-- Error: tests/neg-custom-args/fatal-warnings/i9408a.scala:59:2 -------------------------------------------------------
22+
59 | 123.foo // error
23+
| ^^^
24+
|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.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import language.`3.0-migration`
2+
import scala.language.implicitConversions
3+
4+
object Test1 {
5+
implicit def implicitLength(s: String): Int = s.length
6+
val length: Int = "qwerty" // ok
7+
}
8+
9+
object Test2 {
10+
implicit val implicitLength: Conversion[String, Int] = _.length
11+
val length: Int = "qwerty" // ok
12+
}
13+
14+
object Test3 {
15+
implicit val implicitLength: String => Int = _.length
16+
val length: Int = "qwerty" // error
17+
}
18+
19+
object Test4 {
20+
implicit def implicitLength: String => Int = _.length
21+
val length: Int = "qwerty" // error
22+
}
23+
24+
object Test5 {
25+
implicit def implicitLength[A]: String => Int = _.length
26+
val length: Int = "qwerty" // error
27+
}
28+
29+
object Test6 {
30+
implicit val implicitLength: Map[String, Int] = Map("qwerty" -> 6)
31+
val length: Int = "qwerty" // error
32+
}
33+
34+
object Test7 {
35+
implicit def a2int[A](a: A)(implicit ev: A => Int): Int = a // error
36+
}
37+
38+
object Test8 {
39+
implicit def a2int[A](a: A)(implicit ev: A => Int): Int = ev(a) // ok
40+
}
41+
42+
object Test9 {
43+
implicit def a2int[A](a: A)(implicit ev: A <:< Int): Int = a // ok
44+
}
45+
46+
object Test10 {
47+
trait Foo {
48+
def foo = "foo"
49+
}
50+
implicit def a2foo[A](a: A): Foo = new Foo {}
51+
123.foo // ok
52+
}
53+
54+
object Test11 {
55+
trait Foo {
56+
def foo = "foo"
57+
}
58+
implicit def a2foo[A]: A => Foo = _ => new Foo {}
59+
123.foo // error
60+
}
61+
62+
object Test12 {
63+
implicit class FooOps(a: Any) {
64+
def foo = "foo"
65+
}
66+
123.foo // ok
67+
}
68+
69+
object Test13 {
70+
def foo()(implicit x: String => Int) = ???
71+
implicit val f: String => Int = _.size
72+
foo() // ok
73+
}
74+
75+
object Test14 {
76+
case class MySeq[A](underlying: Seq[A])
77+
78+
implicit def mySeq2seq[A](mySeq: MySeq[A]): Seq[A] = mySeq.underlying
79+
val s: Seq[Int] = MySeq(Seq(1, 2, 3)) // ok
80+
}
81+
82+
object Test15 {
83+
implicit def implicitSeq[A]: Seq[A] = ???
84+
def foo(implicit ev: Seq[Int]): Unit = ???
85+
foo
86+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
-- Error: tests/neg-custom-args/fatal-warnings/i9408b/Test_2.scala:6:20 ------------------------------------------------
3+
6 | val length: Int = "abc" // error
4+
| ^^^^^
5+
|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.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package test.conversions
2+
3+
object Conv {
4+
implicit val implicitLength: String => Int = _.length
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import language.`3.0-migration`
2+
import scala.language.implicitConversions
3+
4+
object Test {
5+
import test.conversions.Conv._
6+
val length: Int = "abc" // error
7+
}

0 commit comments

Comments
 (0)