Skip to content

Commit f11896a

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

File tree

6 files changed

+129
-1
lines changed

6 files changed

+129
-1
lines changed

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,11 @@ object Implicits:
174174
migrateTo3
175175
&& tpw.derivesFrom(defn.FunctionClass(1))
176176
&& ref.symbol != defn.Predef_conforms
177+
177178
val isImplicitConversion = tpw.derivesFrom(defn.ConversionClass)
178179
// An implementation of <:< counts as a view
179180
val isConforms = tpw.derivesFrom(defn.SubTypeClass)
181+
180182
val conversionKind =
181183
if (isFunctionInS2 || isImplicitConversion || isConforms) Candidate.Conversion
182184
else Candidate.None
@@ -779,7 +781,26 @@ trait Implicits:
779781
SelectionProto(name, memberProto, compat, privateOK = false)
780782
case tp => tp
781783
}
782-
try inferImplicit(adjust(to), from, from.span)
784+
try
785+
val inferred = inferImplicit(adjust(to), from, from.span)
786+
787+
def isOldStyleFunctionConversion(tpe: Type): Boolean =
788+
tpe match {
789+
case PolyType(_, resType) =>
790+
isOldStyleFunctionConversion(resType)
791+
case _ => tpe.derivesFrom(defn.FunctionClass(1)) && !tpe.derivesFrom(defn.ConversionClass) && !tpe.derivesFrom(defn.SubTypeClass)
792+
}
793+
794+
inferred match {
795+
case SearchSuccess(_, ref, _) =>
796+
if isOldStyleFunctionConversion(ref.underlying) then
797+
report.migrationWarning(
798+
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.",
799+
from
800+
)
801+
case _ =>
802+
}
803+
inferred
783804
catch {
784805
case ex: AssertionError =>
785806
implicits.println(s"view $from ==> $to")
Lines changed: 24 additions & 0 deletions
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.
Lines changed: 63 additions & 0 deletions
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+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Error: tests/neg-custom-args/fatal-warnings/i9408b/Test.scala:7:20 --------------------------------------------------
2+
7 | 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.
Lines changed: 8 additions & 0 deletions
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+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import language.`3.0-migration`
2+
import scala.language.implicitConversions
3+
4+
5+
object Test {
6+
import test.conversions.Conv._
7+
val length: Int = "abc" // error
8+
}

0 commit comments

Comments
 (0)