diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt index c32515153c8..aa5b6a79b20 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/K2JVMCompiler.kt @@ -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() { } } - 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() { arguments.declarationsOutputPath?.let { configuration.put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) } } - private fun getClasspath(paths: KotlinPaths, arguments: K2JVMCompilerArguments): List { - val classpath = arrayListOf() - 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 { diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt index c5fd03a0fdb..95e4f3ca703 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/ClasspathRootsResolver.kt @@ -52,7 +52,7 @@ internal class ClasspathRootsResolver( private val additionalModules: List, 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, val modules: List) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index 72af831569c..55c7edc6bb0 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -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) diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleResolver.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleResolver.kt index 406f4a25fdf..a7e15343179 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleResolver.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/modules/CliJavaModuleResolver.kt @@ -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 + private val userModules: List, + private val systemModules: List ) : 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? diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmModuleAccessibilityChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmModuleAccessibilityChecker.kt index 80f563f83f1..b8279d76d15 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmModuleAccessibilityChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmModuleAccessibilityChecker.kt @@ -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 -> diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModuleInfo.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModuleInfo.kt index 58296b4e770..78cd5f959ff 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModuleInfo.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/modules/JavaModuleInfo.kt @@ -74,7 +74,8 @@ class JavaModuleInfo( } override fun visitExport(packageFqName: String, access: Int, modules: Array?) { - 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())) } } } diff --git a/compiler/testData/javaModules/dependencyOnStdlib/namedWithExplicitDependency.txt b/compiler/testData/javaModules/dependencyOnStdlib/namedWithExplicitDependency.txt new file mode 100644 index 00000000000..d86bac9de59 --- /dev/null +++ b/compiler/testData/javaModules/dependencyOnStdlib/namedWithExplicitDependency.txt @@ -0,0 +1 @@ +OK diff --git a/compiler/testData/javaModules/dependencyOnStdlib/namedWithExplicitDependency/module-info.java b/compiler/testData/javaModules/dependencyOnStdlib/namedWithExplicitDependency/module-info.java new file mode 100644 index 00000000000..4d349eda5f7 --- /dev/null +++ b/compiler/testData/javaModules/dependencyOnStdlib/namedWithExplicitDependency/module-info.java @@ -0,0 +1,3 @@ +module namedWithExplicitDependency { + requires kotlin.stdlib; +} diff --git a/compiler/testData/javaModules/dependencyOnStdlib/namedWithExplicitDependency/test.kt b/compiler/testData/javaModules/dependencyOnStdlib/namedWithExplicitDependency/test.kt new file mode 100644 index 00000000000..879c4b9d885 --- /dev/null +++ b/compiler/testData/javaModules/dependencyOnStdlib/namedWithExplicitDependency/test.kt @@ -0,0 +1,6 @@ +import kotlin.text.Regex + +fun f1(): List = emptyList() +fun f2(): Array> = arrayOf() +fun f3(map: Map): Collection = + map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values diff --git a/compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency.txt b/compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency.txt new file mode 100644 index 00000000000..e52f151b592 --- /dev/null +++ b/compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency.txt @@ -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 = 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> = 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> = 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): Collection = + ^ +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): Collection = + ^ +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 diff --git a/compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/module-info.java b/compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/module-info.java new file mode 100644 index 00000000000..4cb29443088 --- /dev/null +++ b/compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/module-info.java @@ -0,0 +1,2 @@ +module namedWithoutExplicitDependency { +} diff --git a/compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt b/compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt new file mode 100644 index 00000000000..879c4b9d885 --- /dev/null +++ b/compiler/testData/javaModules/dependencyOnStdlib/namedWithoutExplicitDependency/test.kt @@ -0,0 +1,6 @@ +import kotlin.text.Regex + +fun f1(): List = emptyList() +fun f2(): Array> = arrayOf() +fun f3(map: Map): Collection = + map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values diff --git a/compiler/testData/javaModules/dependencyOnStdlib/unnamed.txt b/compiler/testData/javaModules/dependencyOnStdlib/unnamed.txt new file mode 100644 index 00000000000..d86bac9de59 --- /dev/null +++ b/compiler/testData/javaModules/dependencyOnStdlib/unnamed.txt @@ -0,0 +1 @@ +OK diff --git a/compiler/testData/javaModules/dependencyOnStdlib/unnamed/test.kt b/compiler/testData/javaModules/dependencyOnStdlib/unnamed/test.kt new file mode 100644 index 00000000000..879c4b9d885 --- /dev/null +++ b/compiler/testData/javaModules/dependencyOnStdlib/unnamed/test.kt @@ -0,0 +1,6 @@ +import kotlin.text.Regex + +fun f1(): List = emptyList() +fun f2(): Array> = arrayOf() +fun f3(map: Map): Collection = + map.filterNot { (key, entry) -> "$key".equals(entry.toString(), ignoreCase = true) }.values diff --git a/compiler/tests-common/org/jetbrains/kotlin/codegen/forTestCompile/ForTestCompileRuntime.java b/compiler/tests-common/org/jetbrains/kotlin/codegen/forTestCompile/ForTestCompileRuntime.java index a1e6f676a5f..1360acb963e 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/codegen/forTestCompile/ForTestCompileRuntime.java +++ b/compiler/tests-common/org/jetbrains/kotlin/codegen/forTestCompile/ForTestCompileRuntime.java @@ -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 diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/Java9ModulesIntegrationTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/Java9ModulesIntegrationTest.kt index 0d4bbc4f66d..848c8d9adcc 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/Java9ModulesIntegrationTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/Java9ModulesIntegrationTest.kt @@ -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("") - 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") + } }