question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Chaining Java functions using `-Yexplicit-nulls` and `scala.language.unsafeNulls` fails compilation

See original GitHub issue

Compiler version

Scala 3.1.1

Minimized code

Compiling this code with compiler option -Yexplicit-nulls results in a compilation error:

import scala.language.unsafeNulls

import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

val x = Files.getFileStore(Paths.get("")).name
val y = Thread.currentThread.getContextClassLoader

Output

The result of compiling the above code:

% scala3-compiler -version
Scala compiler version 3.1.1 -- Copyright 2002-2022, LAMP/EPFL
% scala3-compiler -Yexplicit-nulls test.scala 
-- Error: test.scala:7:8 -------------------------------------------------------
7 |val x = Files.getFileStore(Paths.get("")).name
  |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |undefined: java.nio.file.Files.getFileStore(
  |  java.nio.file.Paths.get("", [ : String | Null]*)
  |).name # -1: TermRef(OrType(TypeRef(ThisType(TypeRef(NoPrefix,module class file)),class FileStore),TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Null)),name) at sbt-api
-- Error: test.scala:8:8 -------------------------------------------------------
8 |val y = Thread.currentThread.getContextClassLoader
  |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |undefined: Thread.currentThread().getContextClassLoader # -1: TermRef(OrType(TypeRef(ThisType(TypeRef(NoPrefix,module class lang)),class Thread),TypeRef(ThisType(TypeRef(NoPrefix,module class scala)),class Null)),getContextClassLoader) at sbt-api
2 errors found

Expectation

The code should compile without error.

Additional comments

When compiling the above code, the compiler emits two errors. The error is only triggered when using compiler option -Yexplicit-nulls and also including import scala.language.unsafeNulls in the scope of the lines that fail compilation.

Any call to a Java function (returning T | Null for some type T) that is chained from a call to another Java function triggers this condition.

Making a similar chain of functions using code defined in Scala, like in the code below, does not trigger the compiler error:

import scala.language.unsafeNulls

object X:
    def f: Y | Null = ???
class Y:
    def g: Z | Null = ???
class Z

val z = X.f.g

Adding explicit .nn calls in the failing code works around the bug – with import scala.language.unsafeNulls still in place.

For example, this code compiles without error:

import scala.language.unsafeNulls

import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

val x = Files.getFileStore(Paths.get("")).nn.name
val y = Thread.currentThread.nn.getContextClassLoader

Another workaround is to split the chained calls as the bug is only triggered when chaining calls. This code compiles:

import scala.language.unsafeNulls

import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

val x = Files.getFileStore(Paths.get(""))
val xx = x.name
val y = Thread.currentThread
val yy = y.getContextClassLoader

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
som-snyttcommented, Mar 1, 2022

The fix, to “thread context” correctly, puns on this example, Thread.currentThread.getContextClassLoader. A test could prove quite punning.

0reactions
martingdcommented, Mar 2, 2022
Read more comments on GitHub >

github_iconTop Results From Across the Web

dotty/ScalaSettings.scala at main · lampepfl/dotty - GitHub
The Scala 3 compiler, also known as Dotty. Contribute to lampepfl/dotty development by creating an account on GitHub.
Read more >
How to refactor (if / elsif / elsif) chain in Scala? - Stack Overflow
I would like to extract each into its own function with a clear explanatory name and then chain those functions. How can I...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found