Skip to content

unsafeNulls import doesn't work properly for java methods with generic return type #18775

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
rochala opened this issue Oct 27, 2023 · 1 comment

Comments

@rochala
Copy link
Contributor

rochala commented Oct 27, 2023

Compiler version

3.4.0-RC1-bin-20231024-15033c7-NIGHTLY

Java methods with generic return type fails when we return them inside anonymous functions and rely on type inference.

Minimized code

Test.scala

//> using scala 3.4.0-RC1-bin-20231024-15033c7-NIGHTLY
//> using option "-Yexplicit-nulls"
//> using file Test.java

import scala.language.unsafeNulls

object A {
  protected def decodeJson[T](test: Test): Option[T] =
    val x = Option(???).map(_ => test.fromJson[T]())
    x
}

Test.java

class Test {
  public <T> T fromJson() {
    return null;
  }
}

And it is working for:

//> using scala 3.4.0-RC1-bin-20231024-15033c7-NIGHTLY
//> using option "-Yexplicit-nulls"
//> using file Test.java

import scala.language.unsafeNulls

object A {
  protected def decodeJson[T](test: Test): Option[T] =
    Option(???).map(_ => test.fromJson[T]())
}

The origin problem was found in: https://github.com/scalameta/metals/blob/0d2739f6dfd96c455dadeca56dc85581e3bc48de/mtags-shared/src/main/scala/scala/meta/internal/mtags/CommonMtagsEnrichments.scala#L41-L60

Output

Compilation fails even with import scala.language.unsafeNulls

❯ scala-cli compile Test.scala Test.java
Compiling project (Scala 3.4.0-RC1-bin-20231024-15033c7-NIGHTLY, JVM)
[error] ./Test.scala:10:5
[error] Found:    (x : Option[T | Null])
[error] Required: Option[T]
[error]     x
[error]     ^
Error compiling project (Scala 3.4.0-RC1-bin-20231024-15033c7-NIGHTLY, JVM)
Compilation failed

Expectation

It should compile.

@noti0na1
Copy link
Member

These errors are expected according to rules of unsafeNulls. The inferred type arguments for map are different, which causes different behaviours.

  • In the first example, the type argument of map is inferred as T | Null. The type of test.fromJson[T] is T | Null, and the type of x is Option[T | Null]. The unsafeNulls only makes Null a subtype of all reference types in the scope. Since T is bound by >: Nothing <: Any, Null is still not a subtype of T.

  • In the seound example, the type argument of map is inferred as T, using the information from the result type. The expected return type of the closure is T, but the type of test.fromJson[T] is T | Null. When a type mismatch like this happens on calling java methods, unsafeNulls will try to mitigate the error by stripping the outmost Null and type check again. https://github.com/lampepfl/dotty/blob/c0eae68577f00f0e14c6331a173d8b8750b05107/compiler/src/dotty/tools/dotc/typer/Typer.scala#L4260-L4267

One workaround is to define the type parameter as T >: Null <: AnyRef | Null.

@nicolasstucki nicolasstucki removed the stat:needs triage Every issue needs to have an "area" and "itype" label label Oct 30, 2023
@sjrd sjrd closed this as not planned Won't fix, can't repro, duplicate, stale Oct 30, 2023
rochala added a commit that referenced this issue Nov 8, 2023
With a new definition of untyped trees, it is now required to have
`-Yexplicit-nulls` flag in modules that use them in order to have proper
type checking. This PR adds the missing flag.

Without the flag, it was possible to first assign untyped trees to typed
trees, and secondly use extension methods for typed trees which can be
seen at `KeywordsCompletions.scala` with usage of
`untpdTree.filterSubtrees`.

It is also blocked by: #18775

I can also make a workaround in the unmanaged module, but it will
require a dependency on nightly version / a new release from metals.
WojciechMazur pushed a commit that referenced this issue Jun 23, 2024
With a new definition of untyped trees, it is now required to have
`-Yexplicit-nulls` flag in modules that use them in order to have proper
type checking. This PR adds the missing flag.

Without the flag, it was possible to first assign untyped trees to typed
trees, and secondly use extension methods for typed trees which can be
seen at `KeywordsCompletions.scala` with usage of
`untpdTree.filterSubtrees`.

It is also blocked by: #18775

I can also make a workaround in the unmanaged module, but it will
require a dependency on nightly version / a new release from metals.
[Cherry-picked e149e4c]
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

4 participants