scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
230 stars 21 forks source link

Using -release option instead of -target can break compilation #12824

Closed eejbyfeldt closed 11 months ago

eejbyfeldt commented 11 months ago

Reproduction steps

Scala version: 2.13.11 Java version: 17.0.7

$ cat import_sun.scala
import sun._
$ scalac -deprecation -target:8 import_sun.scala
warning: -target is deprecated: Use -release instead to compile against the correct platform API.
1 warning
$ scalac -release:8 import_sun.scala
import_sun.scala:1: error: not found: object sun
import sun._
       ^
1 error

Problem

Compiling with the -target flag gives a deprecation warning suggesting to use -release instead. But switching using -release means that the code no longer compiles.

If this is the intended behavior maybe the deprecation warnings/documentation should include more information of the differences between -target and -release.

lrytz commented 11 months ago

Compiling on JDK 17 with -target:8 is not safe

➜ sandbox cat Test.scala
object Test {
  def main(args: Array[String]): Unit = {
    println(">".indent(2))
  }
}

➜ sandbox java17
➜ sandbox scalac -target:8 Test.scala
warning: 1 deprecation; re-run with -deprecation for details
1 warning
➜ sandbox scala Test
  >

➜ sandbox java8
➜ sandbox scala Test
Exception in thread "main" java.lang.NoSuchMethodError: java.lang.String.indent(I)Ljava/lang/String;
    at Test$.main(Test.scala:3)
    at Test.main(Test.scala)

Using -release instead fixes that

➜ sandbox java17
➜ sandbox scalac -release:8 Test.scala
Test.scala:3: error: value indent is not a member of String
did you mean indexOf or intern?
    println(">".indent(2))
                ^

However, the corresponding classpath element that is used under -release instead of the JDK doesn't contain symbols for private API (such as sun._). So you need to build on JDK 8 in this case.

som-snytt commented 11 months ago

Duplicates https://github.com/scala/bug/issues/12643

The comment at the end of that ticket mentions -javabootclasspath and elsewhere:

To compile against a JDK 8 rt.jar, use -javabootclasspath rt.jar -nobootcp.

eejbyfeldt commented 11 months ago

Thanks for clarifying.

Is this expected that using --release 17 using sun.* classes compiles but fails at runtime?

$ cast use_sun.scala
import sun.nio.ch.DirectBuffer

object Test {
  def main(args: Array[String]): Unit = {
    println(classOf[sun.nio.ch.DirectBuffer])
  }
}
$ scalac -release 17 use_sun.scala 
$ scala -release 17 use_sun.scala 
Exception in thread "main" java.lang.IllegalAccessError: class Main$ (in unnamed module @0xe260766) cannot access class sun.nio.ch.DirectBuffer (in module java.base) because module java.base does not export sun.nio.ch to unnamed module @0xe260766
    at Main$.main(use_sun.scala:5)
    at Main.main(use_sun.scala)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at scala.reflect.internal.util.RichClassLoader$.$anonfun$run$extension$1(ScalaClassLoader.scala:101)
    at scala.reflect.internal.util.RichClassLoader$.asContext$extension(ScalaClassLoader.scala:36)
    at scala.reflect.internal.util.RichClassLoader$.run$extension(ScalaClassLoader.scala:101)
    at scala.tools.nsc.CommonRunner.run(ObjectRunner.scala:30)
    at scala.tools.nsc.CommonRunner.run$(ObjectRunner.scala:28)
    at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:45)
    at scala.tools.nsc.CommonRunner.runAndCatch(ObjectRunner.scala:37)
    at scala.tools.nsc.CommonRunner.runAndCatch$(ObjectRunner.scala:36)
    at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:45)
    at scala.tools.nsc.AbstractScriptRunner.runCompiled(ScriptRunner.scala:168)
    at scala.tools.nsc.AbstractScriptRunner.$anonfun$runScript$1(ScriptRunner.scala:177)
    at scala.tools.nsc.AbstractScriptRunner.$anonfun$withCompiledScript$9(ScriptRunner.scala:154)
    at scala.tools.nsc.util.package$.trackingThreads(package.scala:55)
    at scala.tools.nsc.util.package$.waitingForThreads(package.scala:32)
    at scala.tools.nsc.AbstractScriptRunner.withCompiledScript(ScriptRunner.scala:151)
    at scala.tools.nsc.AbstractScriptRunner.runScript(ScriptRunner.scala:177)
    at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:75)
    at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:92)
    at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:105)
    at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:113)
    at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
lrytz commented 11 months ago

Yeah, the Scala compiler doesn't do access checks according to the Java module system (https://github.com/scala/scala-dev/issues/529).

https://nipafx.dev/five-command-line-options-hack-java-module-system/ is a good article.