Skip to content

Commit e020713

Browse files
committed
Fix #9408: Warn on implicit view resolved with -source:3.0-migration
1 parent d2a160e commit e020713

File tree

6 files changed

+128
-1
lines changed

6 files changed

+128
-1
lines changed

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

+22-1
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,28 @@ 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) =>
786+
isOldStyleFunctionConversion(resType)
787+
case _ => tpe.derivesFrom(defn.FunctionClass(1)) && !tpe.derivesFrom(defn.ConversionClass) && !tpe.derivesFrom(defn.SubTypeClass)
788+
}
789+
790+
try
791+
val inferred = inferImplicit(adjust(to), from, from.span)
792+
793+
inferred match {
794+
case SearchSuccess(_, ref, _) =>
795+
if isOldStyleFunctionConversion(ref.underlying) then
796+
report.migrationWarning(
797+
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.",
798+
from
799+
)
800+
case _ =>
801+
}
802+
803+
inferred
783804
catch {
784805
case ex: AssertionError =>
785806
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 (Test3a.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 (Test3b.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 (Test4.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:55:2 -------------------------------------------------------
22+
55 | 123.foo // error
23+
| ^^^
24+
|The conversion (Test8.a2foo : [A] => A => Test8.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,63 @@
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 Test3a {
20+
implicit def implicitLength: String => Int = _.length
21+
val length: Int = "qwerty" // error
22+
}
23+
24+
object Test3b {
25+
implicit def implicitLength[A]: String => Int = _.length
26+
val length: Int = "qwerty" // error
27+
}
28+
29+
object Test4 {
30+
implicit val implicitLength: Map[String, Int] = Map("qwerty" -> 6)
31+
val length: Int = "qwerty" // error
32+
}
33+
34+
object Test5 {
35+
implicit def a2int[A](a: A)(implicit ev: A => Int): Int = a // error
36+
}
37+
38+
object Test6 {
39+
implicit def a2int[A](a: A)(implicit ev: A => Int): Int = ev(a) // ok
40+
}
41+
42+
object Test7 {
43+
trait Foo {
44+
def foo = "foo"
45+
}
46+
implicit def a2foo[A](a: A): Foo = new Foo {}
47+
123.foo // ok
48+
}
49+
50+
object Test8 {
51+
trait Foo {
52+
def foo = "foo"
53+
}
54+
implicit def a2foo[A]: A => Foo = _ => new Foo {}
55+
123.foo // error
56+
}
57+
58+
object Test10 {
59+
implicit class FooOps(a: Any) {
60+
def foo = "foo"
61+
}
62+
123.foo // ok
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Error: tests/neg-custom-args/fatal-warnings/i9408b/Test.scala:6:20 --------------------------------------------------
2+
6 | val length: Int = "abc" // error
3+
| ^^^^^
4+
|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,8 @@
1+
package test.conversions
2+
3+
import language.`3.0-migration`
4+
import scala.language.implicitConversions
5+
6+
object Conv {
7+
implicit val implicitLength: String => Int = _.length
8+
}
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)