Skip to content
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

java interop: not auto box #8588

Closed
ohze opened this issue Mar 22, 2020 · 5 comments
Closed

java interop: not auto box #8588

ohze opened this issue Mar 22, 2020 · 5 comments
Assignees

Comments

@ohze
Copy link

ohze commented Mar 22, 2020

minimized code

  • ConfigFactory.java
import java.util.Map;
public class ConfigFactory {
    public static void parseMap(Map<String, ? extends Object> values) { }
}
  • Test.scala
import scala.jdk.CollectionConverters._
object Test {
  ConfigFactory.parseMap(Map("a" -> 1).asJava)
  ConfigFactory.parseMap(Map("a" -> "", "b" -> true).asJava)
}

Compilation output

[error] -- [E007] Type Mismatch Error: /Users/thanhbv/ohze/dotty-example/src/main/scala/Test.scala:3:39 
[error] 3 |  ConfigFactory.parseMap(Map("a" -> 1).asJava)
[error]   |                         ^^^^^^^^^^^^^^^^^^^^
[error]   |                         Found:    java.util.Map[String, Int]
[error]   |                         Required: java.util.Map[String, ? <: Object]
[error] -- [E007] Type Mismatch Error: /Users/thanhbv/ohze/dotty-example/src/main/scala/Test.scala:4:53 
[error] 4 |  ConfigFactory.parseMap(Map("a" -> "", "b" -> true).asJava)
[error]   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]   |                         Found:    java.util.Map[String, Any]
[error]   |                         Required: java.util.Map[String, ? <: Object]

expectation

Compile successfully as in scala 2
Use case: When using "com.typesafe" % "config" library

@ohze ohze added the itype:bug label Mar 22, 2020
@ohze
Copy link
Author

ohze commented Mar 22, 2020

Note: Call ConfigFactory.parseMap(m.asJava) with:

  • val m = Map("a" -> true) // => success in scala 2, fail in dotty
  • val m: Map[String, AnyRef] = Map("a" -> true) // => fail in scala 2, success in dotty
  • val m = Map("a" -> (true: java.lang.Boolean)) // => success in both cases but too verbose :(

@odersky
Copy link
Contributor

odersky commented Mar 22, 2020

@lrytz @SethTisue @szeiger Do you know how this is done in Scala 2? If I look at the signature for asJava

def asJava[K, V](m: Map[K, V]): java.util.Map[K, V]

it's not clear to me by what magic that turns a Map[String, Int] to a Java Map<String, Integer>.

@smarter
Copy link
Member

smarter commented Mar 22, 2020

I think the problem is that we get Required: java.util.Map[String, ? <: Object] when we want java.util.Map[String, ? <: Any]. I'm working on doing something similar to scala/scala#7966 in dotty which might fix this sort of things.

@odersky
Copy link
Contributor

odersky commented Mar 22, 2020

@smarter Yes, that makes sense. I'll assign this one to you for tracking then.

giabao added a commit to ohze/akka that referenced this issue Mar 27, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 28, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 28, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 28, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 29, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 29, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 30, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 31, 2020
giabao added a commit to ohze/akka that referenced this issue Mar 31, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 2, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 5, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 6, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 7, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 7, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 9, 2020
giabao added a commit to ohze/akka that referenced this issue Apr 9, 2020
smarter added a commit to dotty-staging/dotty that referenced this issue Aug 19, 2020
In Java unlike Scala, `Object` is the top type, this leads to various
usability problems when attempting to call or override a Java method
from Scala. So far, we relied mainly on one mechanism to improve the
situation: in the ClassfileParser, some references to `Object` in
signatures were replaced by `Any` (cf `objToAny`). But this had several
shortcomings:
- To compensate for this substitution,
  `TypeComparer#matchingMethodParams` had to special case Any in Java
  methods and treat it like Object
- There were various situation were this substitution was not applied,
  notably when using varargs (`Object... args`) or when jointly
  compiling .java sources since this is handled by JavaParser and not
  ClassfileParser.

This commit replaces all of this by a more systematic solution: all
references to `Object` in Java definitions (both in classfiles and .java
source files) are replaced by a special type `FromJavaObject` which is a
type alias of `Object` with one extra subtyping rule:

   tp <:< FromJavaObject

is equivalent to:

   tp <:< Any

See the documentation of `FromJavaObjectSymbol` for details on
why this makes sense.

This solution is very much inspired by
scala/scala#7966 (which was refined in
scala/scala#8049 and
scala/scala#8638) with two main differences:
- We use a type with its own symbol and name distinct from
  `java.lang.Object`, because this type can show up in inferred types
  and therefore needs to be preserved when pickling so that unpickled
  trees pass `-Ycheck`.
- Unlike in Scala 2, we cannot get rid of `JavaMethodType` because when
  calling `Type#signature` we need to know whether we're in a Java
  method or not, because signatures are based on erased types and erasure
  differs between Scala and Java (we cannot ignore this and always
  base signatures on the Scala erasure, because signatures are used
  to distinguish between overloads and overrides so they must agree
  with the actual JVM bytecode signature).

Fixes scala#7467, scala#7963, scala#8588, scala#8977.
smarter added a commit to dotty-staging/dotty that referenced this issue Aug 21, 2020
In Java unlike Scala, `Object` is the top type, this leads to various
usability problems when attempting to call or override a Java method
from Scala. So far, we relied mainly on one mechanism to improve the
situation: in the ClassfileParser, some references to `Object` in
signatures were replaced by `Any` (cf `objToAny`). But this had several
shortcomings:
- To compensate for this substitution,
  `TypeComparer#matchingMethodParams` had to special case Any in Java
  methods and treat it like Object
- There were various situation were this substitution was not applied,
  notably when using varargs (`Object... args`) or when jointly
  compiling .java sources since this is handled by JavaParser and not
  ClassfileParser.

This commit replaces all of this by a more systematic solution: all
references to `Object` in Java definitions (both in classfiles and .java
source files) are replaced by a special type `FromJavaObject` which is a
type alias of `Object` with one extra subtyping rule:

   tp <:< FromJavaObject

is equivalent to:

   tp <:< Any

See the documentation of `FromJavaObjectSymbol` for details on
why this makes sense.

This solution is very much inspired by
scala/scala#7966 (which was refined in
scala/scala#8049 and
scala/scala#8638) with two main differences:
- We use a type with its own symbol and name distinct from
  `java.lang.Object`, because this type can show up in inferred types
  and therefore needs to be preserved when pickling so that unpickled
  trees pass `-Ycheck`.
- Unlike in Scala 2, we cannot get rid of `JavaMethodType` because when
  calling `Type#signature` we need to know whether we're in a Java
  method or not, because signatures are based on erased types and erasure
  differs between Scala and Java (we cannot ignore this and always
  base signatures on the Scala erasure, because signatures are used
  to distinguish between overloads and overrides so they must agree
  with the actual JVM bytecode signature).

Fixes scala#7467, scala#7963, scala#8588, scala#8977.
@smarter
Copy link
Member

smarter commented Aug 24, 2020

Fixed in #9601.

@smarter smarter closed this as completed Aug 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants