Skip to content

Commit

Permalink
Take into account the result type of inline implicit conversions unle…
Browse files Browse the repository at this point in the history
…ss 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
  • Loading branch information
nicolasstucki committed Jun 19, 2023
2 parents 9b70af9 + eb38e1f commit eb84bdd
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 4 deletions.
2 changes: 1 addition & 1 deletion community-build/community-projects/munit
5 changes: 3 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Inferencing.*
import ErrorReporting.*
import util.SourceFile
import TypeComparer.necessarySubType
import dotty.tools.dotc.core.Flags.Transparent

import scala.annotation.internal.sharable

Expand Down Expand Up @@ -105,14 +106,14 @@ object ProtoTypes {
if !res then ctx.typerState.constraint = savedConstraint
res

/** Constrain result with special case if `meth` is an inlineable method in an inlineable context.
/** Constrain result with special case if `meth` is a transparent inlineable method in an inlineable context.
* In that case, we should always succeed and not constrain type parameters in the expected type,
* because the actual return type can be a subtype of the currently known return type.
* However, we should constrain parameters of the declared return type. This distinction is
* achieved by replacing expected type parameters with wildcards.
*/
def constrainResult(meth: Symbol, mt: Type, pt: Type)(using Context): Boolean =
if (Inlines.isInlineable(meth)) {
if (Inlines.isInlineable(meth) && meth.is(Transparent)) {
constrainResult(mt, wildApprox(pt))
true
}
Expand Down
9 changes: 9 additions & 0 deletions tests/neg-macros/i9685bis.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- [E008] Not Found Error: tests/neg-macros/i9685bis.scala:23:4 --------------------------------------------------------
23 | 1.asdf // error
| ^^^^^^
| value asdf is not a member of Int, but could be made available as an extension method.
|
| The following import might make progress towards fixing the problem:
|
| import foo.Baz.toBaz
|
23 changes: 23 additions & 0 deletions tests/neg-macros/i9685bis.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package foo

import scala.language.implicitConversions

class Foo

object Foo:

inline implicit def toFoo(x: Int): Foo = Foo()

class Bar

object Bar:
inline given Conversion[Int, Bar] with
def apply(x: Int): Bar = Bar()

class Baz

object Baz:
transparent inline implicit def toBaz(x: Int): Baz = Baz()

object Usage:
1.asdf // error

0 comments on commit eb84bdd

Please sign in to comment.