scala / bug

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

Inconsistent behavior of -release (JEP 247) #13015

Open szeiger opened 3 days ago

szeiger commented 3 days ago

Given these equivalent Scala and Java sources, and compilers running on JDK 17:

$ cat Main.scala
import jdk.jfr.internal.Repository
class Main {}

$ cat Main.java
import jdk.jfr.internal.Repository;
public class Main {}

$ java -version
java version "17.0.11" 2024-04-16 LTS
Java(TM) SE Runtime Environment Oracle GraalVM 17.0.11+7.1 (build 17.0.11+7-LTS-jvmci-23.0-b34)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 17.0.11+7.1 (build 17.0.11+7-LTS-jvmci-23.0-b34, mixed mode, sharing)

javac does not allow the use of the the internal API, with or without an explicit --release 17 because it always limits access based on modules:

$ javac  Main.java
Main.java:1: error: package jdk.jfr.internal is not visible
import jdk.jfr.internal.Repository;
              ^
  (package jdk.jfr.internal is declared in module jdk.jfr, which does not export it)
1 error

$ javac --release 17  Main.java
Main.java:1: error: package jdk.jfr.internal is not visible
import jdk.jfr.internal.Repository;
              ^
  (package jdk.jfr.internal is declared in module jdk.jfr, which does not export it)
1 error

Without --release the module can be made accessible with --add-exports but this is rejected when used with --release (whether the requested version matches the current JDK version or not):

$ javac --add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED Main.java

$ javac --release 17 --add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED Main.java
error: exporting a package from system module jdk.jfr is not allowed with --release
1 error

$ javac --release 11 --add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED Main.java
error: exporting a package from system module jdk.jfr is not allowed with --release
1 error

Instead of using --release it is possible to manually set both -source and -target version and override the system module path (the module equivalent of the bootclasspath) to get the same effect as --release while allowing the use of --add-exports:

$ javac -source 11 -target 11  --system /Users/stefan.zeiger/.sdkman/candidates/java/11-zulu-local Main.java --add-exports=jdk.jfr/jdk.jfr.internal=ALL-UNNAMED

scalac has several inconsistencies with this scheme:

(This is about Scala 2; I tested it with 2.13.14 but AFAICT there are no changes in this area in any recent 2.13 or 2.12 version since the feature was added; I have not tried it with Scala 3)

som-snytt commented 3 days ago

The ticket for module support https://github.com/scala/scala-dev/issues/529

szeiger commented 3 days ago

Simply adding support for --system without touching any of the other stuff looks straight-forward.

$ /Users/stefan.zeiger/code/scala/build/quick/bin/scalac -target 11 --system /Users/stefan.zeiger/.sdkman/candidates/java/11-zulu-local  Main.scala

It still ignores module access but now you can compile against an older image version like with javac. Since javac does not support the combination of --add-exports and --release it is reasonable (and probably unavoidable) the scalac does the same, so if scalac ever gets full module support, module access will be enforced for the loaded image with or without --system and a new --add-exports option has to be added to allow exceptions.

(My prototype implementation closes the system image after each compilation which is probably not good for performance in long-running compile servers. I'll have to run some benchmarks and possibly add caching.)