Skip to content

Type inference issue with generic method #10325

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
gaeljw opened this issue Nov 15, 2020 · 3 comments · Fixed by #10327
Closed

Type inference issue with generic method #10325

gaeljw opened this issue Nov 15, 2020 · 3 comments · Fixed by #10327

Comments

@gaeljw
Copy link

gaeljw commented Nov 15, 2020

Using Scala version 3.0.0-M1

Minimized code

def nullToNone[K, V](tuple: (K, V)): (K, Option[V]) = {                                                                                                                                                                                
    val (k, v) = tuple
    (k, Option(v))
}

val scalaMap: Map[String, String] = Map()

val m2: Map[String, Option[String]] = scalaMap.map(nullToNone).toMap

// For troubleshooting, does not work in Scala 2.x neither
val m3: Map[String, Option[String]] = scalaMap.map(nullToNone)

Output

1 |val m2: Map[String, Option[String]] = scalaMap.map(nullToNone).toMap
  |                                                                    ^
  |         Cannot prove that (Any, Option[Any]) <:< (String, V2)
  |
  |         where:    V2 is a type variable with constraint <: Option[String]
  |         .

1 |val m3: Map[String, Option[String]] = scalaMap.map(nullToNone)
  |                                                   ^^^^^^^^^^
  |                  Found:    ((Any, Any)) => (Any, Option[Any])
  |                  Required: ((String, String)) => (String, Option[String])

Expectation

I'm quite new to Scala 3 but there shouldn't be any need for more explicit types, isn't it?

val m2 should compile without error.

Notes

This is actually part of existing code: https://github.com/cucumber/cucumber-jvm-scala/blob/main/cucumber-scala/src/main/scala/io/cucumber/scala/Implicits.scala#L35

@smarter
Copy link
Member

smarter commented Nov 15, 2020

This is likely because map is overloaded in various collection types like Map since 2.13, so infering the types of the lambda arguments gets harder, there were quite a few tweaks to inference in 2.13 to make this sort of things work, in particular scala/scala#6871 is probably relevant here.

@smarter
Copy link
Member

smarter commented Nov 15, 2020

It does work when eta-expanding by hand:

val scalaMap: Map[String, String] = Map()
val z = scalaMap.map(nullToNone(_))

smarter added a commit to smarter/dotty that referenced this issue Nov 15, 2020
`pretypeArgs` allows arguments of overloaded methods to be typed with a
more precise expected type when the formal parameter types of each overload
are all compatible function types, but previously this logic only kicked
in for arguments which were syntactically known to be functions
themselves, which means that it worked when the argument was `foo(_)` or
`x => foo(x)`, but not when it was just `foo`. This commit simply
removes this restriction.

Fixes scala#10325.
@smarter smarter self-assigned this Nov 15, 2020
@gaeljw
Copy link
Author

gaeljw commented Nov 15, 2020

Thanks for the quick feedback @smarter. I'll go with the eta-expanding for now then.

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.

3 participants