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.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
|
||||
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.config.*
|
||||
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
|
||||
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
|
||||
import org.jetbrains.kotlin.cli.jvm.repl.ReplFromTerminal
|
||||
@@ -106,11 +103,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
}
|
||||
}
|
||||
|
||||
val classpath = getClasspath(paths, arguments)
|
||||
configuration.addJvmClasspathRoots(classpath)
|
||||
for (modularRoot in arguments.javaModulePath?.split(File.pathSeparatorChar).orEmpty()) {
|
||||
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, JvmModulePathRoot(File(modularRoot)))
|
||||
}
|
||||
configureContentRoots(paths, arguments, configuration)
|
||||
|
||||
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) }
|
||||
}
|
||||
|
||||
private fun getClasspath(paths: KotlinPaths, arguments: K2JVMCompilerArguments): List<File> {
|
||||
val classpath = arrayListOf<File>()
|
||||
if (arguments.classpath != null) {
|
||||
classpath.addAll(arguments.classpath.split(File.pathSeparatorChar).map(::File))
|
||||
private fun configureContentRoots(paths: KotlinPaths, arguments: K2JVMCompilerArguments, configuration: CompilerConfiguration) {
|
||||
for (path in arguments.classpath?.split(File.pathSeparatorChar).orEmpty()) {
|
||||
configuration.add(JVMConfigurationKeys.CONTENT_ROOTS, JvmClasspathRoot(File(path)))
|
||||
}
|
||||
|
||||
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) {
|
||||
classpath.add(paths.runtimePath)
|
||||
classpath.add(paths.scriptRuntimePath)
|
||||
addRoot("kotlin.stdlib", paths.stdlibPath)
|
||||
addRoot("kotlin.script.runtime", paths.scriptRuntimePath)
|
||||
}
|
||||
// "-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"
|
||||
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 {
|
||||
|
||||
@@ -52,7 +52,7 @@ internal class ClasspathRootsResolver(
|
||||
private val additionalModules: List<String>,
|
||||
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)
|
||||
|
||||
data class RootsAndModules(val roots: List<JavaRoot>, val modules: List<JavaModule>)
|
||||
|
||||
@@ -229,7 +229,8 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
project.registerService(
|
||||
JavaModuleResolver::class.java,
|
||||
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules)
|
||||
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules,
|
||||
classpathRootsResolver.javaModuleFinder.systemModules.toList())
|
||||
)
|
||||
|
||||
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.JavaFileType
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
@@ -27,24 +28,31 @@ import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
|
||||
|
||||
class CliJavaModuleResolver(
|
||||
private val moduleGraph: JavaModuleGraph,
|
||||
private val javaModules: List<JavaModule>
|
||||
private val userModules: List<JavaModule>,
|
||||
private val systemModules: List<JavaModule.Explicit>
|
||||
) : JavaModuleResolver {
|
||||
init {
|
||||
assert(javaModules.count { !it.isBinary } <= 1) {
|
||||
"Modules computed by ClasspathRootsResolver cannot have more than one source module: $javaModules"
|
||||
assert(userModules.count { !it.isBinary } <= 1) {
|
||||
"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? =
|
||||
when (file.fileType) {
|
||||
KotlinFileType.INSTANCE, JavaFileType.INSTANCE -> sourceModule
|
||||
JavaClassFileType.INSTANCE -> javaModules.firstOrNull { module ->
|
||||
module.isBinary && VfsUtilCore.isAncestor(module.moduleRoot, file, false)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
private fun findJavaModule(file: VirtualFile): JavaModule? {
|
||||
if (file.fileSystem.protocol == StandardFileSystems.JRT_PROTOCOL) {
|
||||
return systemModules.firstOrNull { module -> file in module }
|
||||
}
|
||||
|
||||
return when (file.fileType) {
|
||||
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(
|
||||
fileFromOurModule: VirtualFile?, referencedFile: VirtualFile, referencedPackage: FqName?
|
||||
|
||||
+1
-3
@@ -68,9 +68,7 @@ class JvmModuleAccessibilityChecker(project: Project) : CallChecker {
|
||||
|
||||
return when (diagnostic) {
|
||||
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)
|
||||
null
|
||||
JAVA_MODULE_DOES_NOT_READ_UNNAMED_MODULE.on(reportOn)
|
||||
is ModuleDoesNotReadModule ->
|
||||
JAVA_MODULE_DOES_NOT_DEPEND_ON_MODULE.on(reportOn, diagnostic.dependencyModuleName)
|
||||
is ModuleDoesNotExportPackage ->
|
||||
|
||||
+2
-1
@@ -74,7 +74,8 @@ class JavaModuleInfo(
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.jvm.compiler
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
import java.util.jar.Manifest
|
||||
@@ -33,7 +34,7 @@ class Java9ModulesIntegrationTest : AbstractKotlinCompilerIntegrationTest() {
|
||||
): File {
|
||||
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(
|
||||
"-jdk-home", jdk9Home.path,
|
||||
@@ -245,4 +246,10 @@ class Java9ModulesIntegrationTest : AbstractKotlinCompilerIntegrationTest() {
|
||||
val d2 = module("dependency2")
|
||||
module("main", listOf(d1, d2))
|
||||
}
|
||||
|
||||
fun testDependencyOnStdlib() {
|
||||
module("unnamed")
|
||||
module("namedWithExplicitDependency")
|
||||
module("namedWithoutExplicitDependency")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user