Use module path instead of class path for stdlib on Java 9
Also report the "named does not read unnamed" error, which was not possible previously because we wouldn't be able to read anything from kotlin-stdlib (because it was added to the unnamed module by default)
This commit is contained in:
@@ -30,10 +30,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.CompileEnvironmentUtil
|
|||||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
|
import org.jetbrains.kotlin.cli.jvm.config.*
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
|
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
|
||||||
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
|
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
|
||||||
import org.jetbrains.kotlin.cli.jvm.repl.ReplFromTerminal
|
import org.jetbrains.kotlin.cli.jvm.repl.ReplFromTerminal
|
||||||
@@ -106,11 +103,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val classpath = getClasspath(paths, arguments)
|
configureContentRoots(paths, arguments, configuration)
|
||||||
configuration.addJvmClasspathRoots(classpath)
|
|
||||||
for (modularRoot in arguments.javaModulePath?.split(File.pathSeparatorChar).orEmpty()) {
|
|
||||||
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, JvmModulePathRoot(File(modularRoot)))
|
|
||||||
}
|
|
||||||
|
|
||||||
configuration.put(CommonConfigurationKeys.MODULE_NAME, arguments.moduleName ?: JvmAbi.DEFAULT_MODULE_NAME)
|
configuration.put(CommonConfigurationKeys.MODULE_NAME, arguments.moduleName ?: JvmAbi.DEFAULT_MODULE_NAME)
|
||||||
|
|
||||||
@@ -383,21 +376,35 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
|||||||
arguments.declarationsOutputPath?.let { configuration.put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) }
|
arguments.declarationsOutputPath?.let { configuration.put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getClasspath(paths: KotlinPaths, arguments: K2JVMCompilerArguments): List<File> {
|
private fun configureContentRoots(paths: KotlinPaths, arguments: K2JVMCompilerArguments, configuration: CompilerConfiguration) {
|
||||||
val classpath = arrayListOf<File>()
|
for (path in arguments.classpath?.split(File.pathSeparatorChar).orEmpty()) {
|
||||||
if (arguments.classpath != null) {
|
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, JvmClasspathRoot(File(path)))
|
||||||
classpath.addAll(arguments.classpath.split(File.pathSeparatorChar).map(::File))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (modularRoot in arguments.javaModulePath?.split(File.pathSeparatorChar).orEmpty()) {
|
||||||
|
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, JvmModulePathRoot(File(modularRoot)))
|
||||||
|
}
|
||||||
|
|
||||||
|
val isModularJava = configuration.get(JVMConfigurationKeys.JDK_HOME).let { it != null && CoreJrtFileSystem.isModularJdk(it) }
|
||||||
|
fun addRoot(moduleName: String, file: File) {
|
||||||
|
if (isModularJava) {
|
||||||
|
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, JvmModulePathRoot(file))
|
||||||
|
configuration.add(JVMConfigurationKeys.ADDITIONAL_JAVA_MODULES, moduleName)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, JvmClasspathRoot(file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!arguments.noStdlib) {
|
if (!arguments.noStdlib) {
|
||||||
classpath.add(paths.runtimePath)
|
addRoot("kotlin.stdlib", paths.stdlibPath)
|
||||||
classpath.add(paths.scriptRuntimePath)
|
addRoot("kotlin.script.runtime", paths.scriptRuntimePath)
|
||||||
}
|
}
|
||||||
// "-no-stdlib" implies "-no-reflect": otherwise we would be able to transitively read stdlib classes through kotlin-reflect,
|
// "-no-stdlib" implies "-no-reflect": otherwise we would be able to transitively read stdlib classes through kotlin-reflect,
|
||||||
// which is likely not what user wants since s/he manually provided "-no-stdlib"
|
// which is likely not what user wants since s/he manually provided "-no-stdlib"
|
||||||
if (!arguments.noReflect && !arguments.noStdlib) {
|
if (!arguments.noReflect && !arguments.noStdlib) {
|
||||||
classpath.add(paths.reflectPath)
|
addRoot("kotlin.reflect", paths.reflectPath)
|
||||||
}
|
}
|
||||||
return classpath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupJdkClasspathRoots(arguments: K2JVMCompilerArguments, configuration: CompilerConfiguration, messageCollector: MessageCollector): ExitCode {
|
private fun setupJdkClasspathRoots(arguments: K2JVMCompilerArguments, configuration: CompilerConfiguration, messageCollector: MessageCollector): ExitCode {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ internal class ClasspathRootsResolver(
|
|||||||
private val additionalModules: List<String>,
|
private val additionalModules: List<String>,
|
||||||
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?
|
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?
|
||||||
) {
|
) {
|
||||||
private val javaModuleFinder = CliJavaModuleFinder(VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL))
|
val javaModuleFinder = CliJavaModuleFinder(VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL))
|
||||||
val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
|
val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
|
||||||
|
|
||||||
data class RootsAndModules(val roots: List<JavaRoot>, val modules: List<JavaModule>)
|
data class RootsAndModules(val roots: List<JavaRoot>, val modules: List<JavaModule>)
|
||||||
|
|||||||
@@ -229,7 +229,8 @@ class KotlinCoreEnvironment private constructor(
|
|||||||
|
|
||||||
project.registerService(
|
project.registerService(
|
||||||
JavaModuleResolver::class.java,
|
JavaModuleResolver::class.java,
|
||||||
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules)
|
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules,
|
||||||
|
classpathRootsResolver.javaModuleFinder.systemModules.toList())
|
||||||
)
|
)
|
||||||
|
|
||||||
val finderFactory = CliVirtualFileFinderFactory(rootsIndex)
|
val finderFactory = CliVirtualFileFinderFactory(rootsIndex)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.cli.jvm.modules
|
|||||||
|
|
||||||
import com.intellij.ide.highlighter.JavaClassFileType
|
import com.intellij.ide.highlighter.JavaClassFileType
|
||||||
import com.intellij.ide.highlighter.JavaFileType
|
import com.intellij.ide.highlighter.JavaFileType
|
||||||
|
import com.intellij.openapi.vfs.StandardFileSystems
|
||||||
import com.intellij.openapi.vfs.VfsUtilCore
|
import com.intellij.openapi.vfs.VfsUtilCore
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
@@ -27,24 +28,31 @@ import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
|
|||||||
|
|
||||||
class CliJavaModuleResolver(
|
class CliJavaModuleResolver(
|
||||||
private val moduleGraph: JavaModuleGraph,
|
private val moduleGraph: JavaModuleGraph,
|
||||||
private val javaModules: List<JavaModule>
|
private val userModules: List<JavaModule>,
|
||||||
|
private val systemModules: List<JavaModule.Explicit>
|
||||||
) : JavaModuleResolver {
|
) : JavaModuleResolver {
|
||||||
init {
|
init {
|
||||||
assert(javaModules.count { !it.isBinary } <= 1) {
|
assert(userModules.count { !it.isBinary } <= 1) {
|
||||||
"Modules computed by ClasspathRootsResolver cannot have more than one source module: $javaModules"
|
"Modules computed by ClasspathRootsResolver cannot have more than one source module: $userModules"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val sourceModule = javaModules.firstOrNull { !it.isBinary }
|
private val sourceModule: JavaModule? = userModules.firstOrNull { !it.isBinary }
|
||||||
|
|
||||||
private fun findJavaModule(file: VirtualFile): JavaModule? =
|
private fun findJavaModule(file: VirtualFile): JavaModule? {
|
||||||
when (file.fileType) {
|
if (file.fileSystem.protocol == StandardFileSystems.JRT_PROTOCOL) {
|
||||||
KotlinFileType.INSTANCE, JavaFileType.INSTANCE -> sourceModule
|
return systemModules.firstOrNull { module -> file in module }
|
||||||
JavaClassFileType.INSTANCE -> javaModules.firstOrNull { module ->
|
}
|
||||||
module.isBinary && VfsUtilCore.isAncestor(module.moduleRoot, file, false)
|
|
||||||
}
|
return when (file.fileType) {
|
||||||
else -> null
|
KotlinFileType.INSTANCE, JavaFileType.INSTANCE -> sourceModule
|
||||||
}
|
JavaClassFileType.INSTANCE -> userModules.firstOrNull { module -> module.isBinary && file in module }
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private operator fun JavaModule.contains(file: VirtualFile): Boolean =
|
||||||
|
VfsUtilCore.isAncestor(moduleRoot, file, false)
|
||||||
|
|
||||||
override fun checkAccessibility(
|
override fun checkAccessibility(
|
||||||
fileFromOurModule: VirtualFile?, referencedFile: VirtualFile, referencedPackage: FqName?
|
fileFromOurModule: VirtualFile?, referencedFile: VirtualFile, referencedPackage: FqName?
|
||||||
|
|||||||
+1
-3
@@ -68,9 +68,7 @@ class JvmModuleAccessibilityChecker(project: Project) : CallChecker {
|
|||||||
|
|
||||||
return when (diagnostic) {
|
return when (diagnostic) {
|
||||||
is ModuleDoesNotReadUnnamedModule ->
|
is ModuleDoesNotReadUnnamedModule ->
|
||||||
// TODO: report this error as soon as module path is used instead of class path for modular compilation
|
JAVA_MODULE_DOES_NOT_READ_UNNAMED_MODULE.on(reportOn)
|
||||||
// JAVA_MODULE_DOES_NOT_READ_UNNAMED_MODULE.on(reportOn)
|
|
||||||
null
|
|
||||||
is ModuleDoesNotReadModule ->
|
is ModuleDoesNotReadModule ->
|
||||||
JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE.on(reportOn, diagnostic.dependencyModuleName)
|
JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE.on(reportOn, diagnostic.dependencyModuleName)
|
||||||
is ModuleDoesNotExportPackage ->
|
is ModuleDoesNotExportPackage ->
|
||||||
|
|||||||
+2
-1
@@ -74,7 +74,8 @@ class JavaModuleInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitExport(packageFqName: String, access: Int, modules: Array<String>?) {
|
override fun visitExport(packageFqName: String, access: Int, modules: Array<String>?) {
|
||||||
exports.add(Exports(FqName(packageFqName), modules?.toList().orEmpty()))
|
// For some reason, '/' is the delimiter in packageFqName here
|
||||||
|
exports.add(Exports(FqName(packageFqName.replace('/', '.')), modules?.toList().orEmpty()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
OK
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
module namedWithExplicitDependency {
|
||||||
|
requires kotlin.stdlib;
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
import kotlin.text.Regex
|
||||||
|
|
||||||
|
fun f1(): List<String?> = emptyList()
|
||||||
|
fun f2(): Array<Lazy<Unit>> = arrayOf()
|
||||||
|
fun f3(map: Map<Int, Regex>): Collection<Regex> =
|
||||||
|
map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:1:20: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
import kotlin.text.Regex
|
||||||
|
^
|
||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:3:27: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
fun f1(): List<String?> = emptyList()
|
||||||
|
^
|
||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:4:17: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
fun f2(): Array<Lazy<Unit>> = arrayOf()
|
||||||
|
^
|
||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:4:22: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
fun f2(): Array<Lazy<Unit>> = arrayOf()
|
||||||
|
^
|
||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:5:22: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
fun f3(map: Map<Int, Regex>): Collection<Regex> =
|
||||||
|
^
|
||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:5:42: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
fun f3(map: Map<Int, Regex>): Collection<Regex> =
|
||||||
|
^
|
||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:6:13: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values
|
||||||
|
^
|
||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:6:26: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values
|
||||||
|
^
|
||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:6:31: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values
|
||||||
|
^
|
||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:6:48: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values
|
||||||
|
^
|
||||||
|
compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt:6:61: error: symbol is declared in module 'kotlin.stdlib' which current module does not depend on
|
||||||
|
map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values
|
||||||
|
^
|
||||||
|
COMPILATION_ERROR
|
||||||
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
module namedWithoutExplicitDependency {
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
import kotlin.text.Regex
|
||||||
|
|
||||||
|
fun f1(): List<String?> = emptyList()
|
||||||
|
fun f2(): Array<Lazy<Unit>> = arrayOf()
|
||||||
|
fun f3(map: Map<Int, Regex>): Collection<Regex> =
|
||||||
|
map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
OK
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import kotlin.text.Regex
|
||||||
|
|
||||||
|
fun f1(): List<String?> = emptyList()
|
||||||
|
fun f2(): Array<Lazy<Unit>> = arrayOf()
|
||||||
|
fun f3(map: Map<Int, Regex>): Collection<Regex> =
|
||||||
|
map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values
|
||||||
+1
-1
@@ -33,7 +33,7 @@ public class ForTestCompileRuntime {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static File runtimeJarForTests() {
|
public static File runtimeJarForTests() {
|
||||||
return assertExists(new File("dist/kotlinc/lib/kotlin-runtime.jar"));
|
return assertExists(new File("dist/kotlinc/lib/kotlin-stdlib.jar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.jvm.compiler
|
package org.jetbrains.kotlin.jvm.compiler
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.jar.Manifest
|
import java.util.jar.Manifest
|
||||||
@@ -33,7 +34,7 @@ class Java9ModulesIntegrationTest : AbstractKotlinCompilerIntegrationTest() {
|
|||||||
): File {
|
): File {
|
||||||
val jdk9Home = KotlinTestUtils.getJdk9HomeIfPossible() ?: return File("<test-skipped>")
|
val jdk9Home = KotlinTestUtils.getJdk9HomeIfPossible() ?: return File("<test-skipped>")
|
||||||
|
|
||||||
val paths = modulePath.joinToString(separator = File.pathSeparator) { it.path }
|
val paths = (modulePath + ForTestCompileRuntime.runtimeJarForTests()).joinToString(separator = File.pathSeparator) { it.path }
|
||||||
|
|
||||||
val kotlinOptions = mutableListOf(
|
val kotlinOptions = mutableListOf(
|
||||||
"-jdk-home", jdk9Home.path,
|
"-jdk-home", jdk9Home.path,
|
||||||
@@ -245,4 +246,10 @@ class Java9ModulesIntegrationTest : AbstractKotlinCompilerIntegrationTest() {
|
|||||||
val d2 = module("dependency2")
|
val d2 = module("dependency2")
|
||||||
module("main", listOf(d1, d2))
|
module("main", listOf(d1, d2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testDependencyOnStdlib() {
|
||||||
|
module("unnamed")
|
||||||
|
module("namedWithExplicitDependency")
|
||||||
|
module("namedWithoutExplicitDependency")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user