Skip to content

Eta-expansion of methods with implicit and dependent arguments #5288

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
OlivierBlanvillain opened this issue Oct 18, 2018 · 5 comments · Fixed by #14855
Closed

Eta-expansion of methods with implicit and dependent arguments #5288

OlivierBlanvillain opened this issue Oct 18, 2018 · 5 comments · Fixed by #14855

Comments

@OlivierBlanvillain
Copy link
Contributor

OlivierBlanvillain commented Oct 18, 2018

They are some inconsistencies between eta-expansion of normal methods and methods with implicit arguments or dependent result type:

scala> def m4(implicit i: Int): Int = 4
def m4(implicit i: Int): Int

scala> val f4_Inferred = m4 _
1 |val f4_Inferred = m4 _
  |                  ^^^^
  |Only function types can be followed by _ but the current expression has type <error no implicit values were found that match expected type>

scala> val f4Inferred = m4
1 |val f4Inferred = m4
  |                   ^
  |   no implicit argument of type Int was found for parameter i of method m4

scala> val f4_Expected: implicit Int => Int = m4 _
1 |val f4_Expected: implicit Int => Int = m4 _
  |                                        ^^^^
  |Only function types can be followed by _ but the current expression has type Int

So, to turn methods with implicit arguments into function the only option is to give an explicit expected type and not use the underscore syntax:

scala> val f4Expected: implicit Int => Int = m4 // Works as expected
val f4Expected: implicit Int => Int = Lambda$1398/1407952056@437bd805

Dependent methods are also inconsistent, in a different way:

scala> trait C { type M; val m: M }
// defined trait C

scala> val f7Expected: (c: C) => c.M = m7
1 |val f7Expected: (c: C) => c.M = m7
  |                                ^^
  |                                missing arguments for method m7

scala> val f7_Exptected: (c: C) => c.M = m7 _
1 |val f7_Exptected: (c: C) => c.M = m7 _
  |                                  ^^^^
  |Only function types can be followed by _ but the current expression has type (c: C) => c.M

Eta-expansion fails in the presence of explicit return types. Both underscore and non underscore syntax work as expected:

scala> val f7_Inferred = m7 _
val f7_Inferred: (c: C) => c.M = Lambda$1408/127401209@16bd7ae1

scala> val f7Inferred = m7
val f7Inferred: (c: C) => c.M = Lambda$1409/1612539426@76216830

Eta-expansion of dependent methods with two arguments or curried arguments seems to also be broken as the dependency is lost entirely:

scala> def m9(c1: C, c2: C): c1.M | c2.M = c1.m
def m9(c1: C, c2: C): c1.M | c2.M

scala> val f9Inferred = m9 _
val f9Inferred: (C, C) => Any = Lambda$1457/1138992016@44aa91e2
scala> def mD(c1: C)(c2: C): c1.M | c2.M = c1.m
def mD(c1: C)(c2: C): c1.M | c2.M

scala> val fDInferred = mD
val fDInferred: C => C => Any = Lambda$1458/934352027@1187dc82

Here is the test case I wrote for eta-expansion of all combinations of normal/implicit/dependent methods up to arity 2.

@odersky
Copy link
Contributor

odersky commented Oct 18, 2018

The trailing underscore syntax is deprecated, so I would not invest a lot of work in upgrading it. The rest needs work, I agree. Any volunteers for this one?

@milessabin
Copy link
Contributor

If no one else has taken it by the time I'm done with by-name implicits then I will.

@OlivierBlanvillain
Copy link
Contributor Author

I think we might still need the m _ syntax for eta-expanding methods with implicits. Otherwise val v = m would mean something else than it currently does when m takes implicits parameters.

@b-studios
Copy link
Contributor

Actually, I ran into an instance of a combination that IIUC is missing in @OlivierBlanvillain's list of test cases:

trait A
trait B
type Eta = implicit (a: A) => implicit (b: B) => Unit
def implicitDependent: Eta = { implicitly[B]; implicitly[A]; () }

That is, recursive eta expansion on potentially dependent methods.

@odersky
Copy link
Contributor

odersky commented Apr 5, 2022

I think all fixable things are fixed by now. Adding a regression test that explains what does not work.

odersky added a commit to dotty-staging/dotty that referenced this issue Apr 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants