Skip to content

Commit eb84bdd

Browse files
Take into account the result type of inline implicit conversions unless they are transparent (#17924)
In the first commit, I add a failing test: ~~~ scala import scala.language.implicitConversions class Foo object Foo: inline implicit def toFoo(x: Int): Foo = Foo() object Usage: 1.asdf // error ~~~ We expect that code to not compile but the error reported by the compiler is confusing as it suggests importing `Foo.toFoo` to resolve the compilation error. You can see this in the [test report](https://github.com/lampepfl/dotty/actions/runs/5254687053/jobs/9493612604#step:9:1859). The problem comes from the fact that currently when the compiler checks whether an implicit conversion is applicable to an expression that fails to compile, it does not take into account the expected result type (here, `? { def asdf: ? }`) if the candidate is an `inline` definition. Instead, I believe the expected result type should be taken into account unless the candidate is a `transparent inline`. I make this change in the second commit, which makes the test pass. Fixes #9685
2 parents 9b70af9 + eb38e1f commit eb84bdd

File tree

5 files changed

+37
-4
lines changed

5 files changed

+37
-4
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Inferencing.*
1717
import ErrorReporting.*
1818
import util.SourceFile
1919
import TypeComparer.necessarySubType
20+
import dotty.tools.dotc.core.Flags.Transparent
2021

2122
import scala.annotation.internal.sharable
2223

@@ -105,14 +106,14 @@ object ProtoTypes {
105106
if !res then ctx.typerState.constraint = savedConstraint
106107
res
107108

108-
/** Constrain result with special case if `meth` is an inlineable method in an inlineable context.
109+
/** Constrain result with special case if `meth` is a transparent inlineable method in an inlineable context.
109110
* In that case, we should always succeed and not constrain type parameters in the expected type,
110111
* because the actual return type can be a subtype of the currently known return type.
111112
* However, we should constrain parameters of the declared return type. This distinction is
112113
* achieved by replacing expected type parameters with wildcards.
113114
*/
114115
def constrainResult(meth: Symbol, mt: Type, pt: Type)(using Context): Boolean =
115-
if (Inlines.isInlineable(meth)) {
116+
if (Inlines.isInlineable(meth) && meth.is(Transparent)) {
116117
constrainResult(mt, wildApprox(pt))
117118
true
118119
}

tests/neg-macros/i9685bis.check

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- [E008] Not Found Error: tests/neg-macros/i9685bis.scala:23:4 --------------------------------------------------------
2+
23 | 1.asdf // error
3+
| ^^^^^^
4+
| value asdf is not a member of Int, but could be made available as an extension method.
5+
|
6+
| The following import might make progress towards fixing the problem:
7+
|
8+
| import foo.Baz.toBaz
9+
|

tests/neg-macros/i9685bis.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package foo
2+
3+
import scala.language.implicitConversions
4+
5+
class Foo
6+
7+
object Foo:
8+
9+
inline implicit def toFoo(x: Int): Foo = Foo()
10+
11+
class Bar
12+
13+
object Bar:
14+
inline given Conversion[Int, Bar] with
15+
def apply(x: Int): Bar = Bar()
16+
17+
class Baz
18+
19+
object Baz:
20+
transparent inline implicit def toBaz(x: Int): Baz = Baz()
21+
22+
object Usage:
23+
1.asdf // error

0 commit comments

Comments
 (0)