Skip to content

Parameter untupling and automatic eta-expansion don't always mix #11185

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
Jasper-M opened this issue Jan 21, 2021 · 3 comments · Fixed by #12171
Closed

Parameter untupling and automatic eta-expansion don't always mix #11185

Jasper-M opened this issue Jan 21, 2021 · 3 comments · Fixed by #12171
Assignees
Milestone

Comments

@Jasper-M
Copy link
Contributor

Minimized code

def foo(a: Int, b: Int) = a + b

Map(1 -> 2).map(foo _) // ok: List(3)

Map(1 -> 2).map(foo) // error

Output

Map(1 -> 2).map(foo)
^^^^^^^^^^^^^^^
None of the overloaded alternatives of method map in trait IterableOps with types
 [B](f: ((Int, Int)) => B): scala.collection.immutable.Iterable[B]
 [K2, V2](f: ((Int, Int)) => (K2, V2)): Map[K2, V2]
match arguments ((foo : (a: Int, b: Int): Int))

Expectation

Since the compiler can pick the right overload with explicit eta-expansion, I don't see why he can't do that with automatic eta-expansion.

@som-snytt
Copy link
Contributor

som-snytt commented Jan 21, 2021

Looks like they forgot about the tuple adaptation while testing applicability during overload resolution.

f: (((Int, Int)) => Int) is fine. I can't tell from the docs about how function values are handled during overload resolution, whether they see (?, ?) => ? and give up.

I don't know Dotty's pronoun preference.

This doesn't work:

scala> val f2 = f
val f2: (Int, Int) => Int = Lambda$1686/0x00000008010b2ff8@ff03384

scala> xs.map(f2)
1 |xs.map(f2)
  |       ^^
  |       Found:    (f2 : (Int, Int) => Int)
  |       Required: ((Int, Int)) => <?>
1 |xs.map(f2)
  |^^^^^^
  |None of the overloaded alternatives of method map in trait IterableOps with types
  | [B](f: ((Int, Int)) => B): scala.collection.immutable.Iterable[B]
  | [K2, V2](f: ((Int, Int)) => (K2, V2)): Map[K2, V2]
  |match arguments ((f2 : (Int, Int) => Int))

scala> f(_,_): (((Int,Int)) => Int)
1 |f(_,_): (((Int,Int)) => Int)
  |  ^
  |  Missing parameter type
  |
  |  I could not infer the type of the parameter _$1.
1 |f(_,_): (((Int,Int)) => Int)
  |    ^
  |    Missing parameter type
  |
  |    I could not infer the type of the parameter _$2.

Actually that needs parens: (f(_,_)): (((Int,Int)) => Int)

@Jasper-M
Copy link
Contributor Author

Jasper-M commented Jan 22, 2021

Even weirder then that Map(1 -> 2).map(foo _) works while both val f = foo; Map(1 -> 2).map(f) and Map(1 -> 2).map(foo) don't work.

And without overloading, both foo and foo _ work but f still doesn't.

scala> def bar(f: ((Int, Int)) => Int) = "ok"
def bar(f: ((Int, Int)) => Int): String

scala> bar(foo)                                                                 
val res1: String = ok

scala> bar(foo _)                                                               
val res2: String = ok

scala> bar(f)                                                                   
1 |bar(f)
  |    ^
  |    Found:    (f : (Int, Int) => Int)
  |    Required: ((Int, Int)) => Int

Either way I would expect foo and foo _ to behave the same, with or without overloads. The cool thing is that foo.tupled actually works in Scala 3 without any extra ceremony, so it wouldn't be the end of the world if untupling only worked for lambda literals.

@liufengyun
Copy link
Contributor

The fact that the following program is rejected is expected:

  def foo(a: Int, b: Int) = a + b

  val f = foo
  Map(1 -> 2).map(f)           // error
  Map(1 -> 2).map(foo)         // ok after fix in #12171
  Map(1 -> 2).map(foo _)       // ok

The spec says that parameter untupling only works for a function literal but it composes with eta-expansion.

liufengyun added a commit to dotty-staging/dotty that referenced this issue Apr 23, 2021
liufengyun added a commit to dotty-staging/dotty that referenced this issue Apr 26, 2021
odersky added a commit that referenced this issue Apr 27, 2021
Fix #11185: cache pretyped argument with adaptation in FunProto
@Kordyjan Kordyjan added this to the 3.0.1 milestone Aug 2, 2023
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.

4 participants