Fix primitive override with inline class in Kotlin-Java inheritance

This commit is contained in:
Dmitry Petrov
2018-08-22 11:00:57 +03:00
parent 01eca8bac8
commit 34548a0667
15 changed files with 241 additions and 28 deletions
@@ -1361,11 +1361,21 @@ public class KotlinTypeMapper {
if (isBoxMethodForInlineClass(descriptor)) return true;
//noinspection ConstantConditions
if (!KotlinBuiltIns.isPrimitiveType(descriptor.getReturnType())) return false;
if (!isJvmPrimitive(descriptor.getReturnType())) return false;
for (FunctionDescriptor overridden : getAllOverriddenDescriptors(descriptor)) {
//noinspection ConstantConditions
if (!KotlinBuiltIns.isPrimitiveType(overridden.getReturnType())) return true;
if (!isJvmPrimitive(overridden.getReturnType())) return true;
}
return false;
}
private static boolean isJvmPrimitive(@NotNull KotlinType kotlinType) {
if (KotlinBuiltIns.isPrimitiveType(kotlinType)) return true;
if (InlineClassesUtilsKt.isInlineClassType(kotlinType)) {
return AsmUtil.isPrimitive(mapInlineClassType(kotlinType));
}
return false;
@@ -0,0 +1,4 @@
package test;
class JExtendsKFooZ extends KFooZ {
}
@@ -0,0 +1,13 @@
// !LANGUAGE: +InlineClasses
package test
inline class Z(val value: Int)
interface IFoo<T> {
fun foo(): T
}
open class KFooZ : IFoo<Z> {
override fun foo(): Z = Z(42)
}
@@ -0,0 +1,20 @@
package test
public interface IFoo</*0*/ T> {
public abstract fun foo(): T
}
public/*package*/ open class JExtendsKFooZ : test.KFooZ {
public/*package*/ constructor JExtendsKFooZ()
public open /*fake_override*/ fun foo(): test.Z
}
public open class KFooZ : test.IFoo<test.Z> {
public constructor KFooZ()
public open fun foo(): test.Z
}
public final inline class Z {
public constructor Z(/*0*/ kotlin.Int)
public final val value: kotlin.Int
}
@@ -0,0 +1,29 @@
// !LANGUAGE: +InlineClasses
// FILE: kt1.kt
package kt
inline class Z(val value: Int)
interface IFoo<T> {
fun foo(): T
}
open class KFooZ : IFoo<Z> {
override fun foo(): Z = Z(42)
}
// FILE: j/J.java
package j;
import kt.Z;
import kt.KFooZ;
public class J extends KFooZ {
}
// FILE: kt2.kt
package kt
import j.J
fun jfoo(x: J) = x.foo()
@@ -0,0 +1,39 @@
package
package j {
public open class J : kt.KFooZ {
public constructor J()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun foo(): kt.Z
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
package kt {
public fun jfoo(/*0*/ x: j.J): kt.Z
public interface IFoo</*0*/ T> {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract fun foo(): T
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public open class KFooZ : kt.IFoo<kt.Z> {
public constructor KFooZ()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ fun foo(): kt.Z
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final inline class Z {
public constructor Z(/*0*/ value: kotlin.Int)
public final val value: kotlin.Int
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
}
}
@@ -9,8 +9,9 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.junit.Assert
import java.util.*
import java.io.File
import java.util.regex.Pattern
import kotlin.collections.HashMap
const val LANGUAGE_DIRECTIVE = "LANGUAGE"
const val API_VERSION_DIRECTIVE = "API_VERSION"
@@ -80,6 +81,14 @@ fun parseLanguageVersionSettings(directiveMap: Map<String, String>): CompilerTes
fun defaultLanguageVersionSettings(): CompilerTestLanguageVersionSettings =
CompilerTestLanguageVersionSettings(emptyMap(), ApiVersion.LATEST_STABLE, LanguageVersion.LATEST_STABLE)
fun setupLanguageVersionSettingsForMultifileCompilerTests(files: List<File>, environment: KotlinCoreEnvironment) {
val allDirectives = HashMap<String, String>()
for (file in files) {
allDirectives.putAll(KotlinTestUtils.parseDirectives(file.readText()))
}
environment.configuration.languageVersionSettings = parseLanguageVersionSettingsOrDefault(allDirectives)
}
fun setupLanguageVersionSettingsForCompilerTests(originalFileText: String, environment: KotlinCoreEnvironment) {
val directives = KotlinTestUtils.parseDirectives(originalFileText)
val languageVersionSettings = parseLanguageVersionSettingsOrDefault(directives)
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.jvm.compiler
import com.intellij.openapi.Disposable
import org.jetbrains.kotlin.checkers.setupLanguageVersionSettingsForCompilerTests
import org.jetbrains.kotlin.checkers.setupLanguageVersionSettingsForMultifileCompilerTests
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
@@ -62,22 +64,27 @@ abstract class AbstractCompileJavaAgainstKotlinTest : TestCaseWithTmpdir() {
val out = File(tmpdir, "out")
val compiledSuccessfully = if (useJavac) {
compileKotlinWithJava(listOf(javaFile),
listOf(ktFile),
out, testRootDisposable)
compileKotlinWithJava(
listOf(javaFile),
listOf(ktFile),
out, testRootDisposable
)
} else {
KotlinTestUtils.compileKotlinWithJava(listOf(javaFile),
listOf(ktFile),
out, testRootDisposable, javaErrorFile)
KotlinTestUtils.compileKotlinWithJava(
listOf(javaFile),
listOf(ktFile),
out, testRootDisposable, javaErrorFile
)
}
if (!compiledSuccessfully) return
val environment = KotlinCoreEnvironment.createForTests(
testRootDisposable,
newConfiguration(ConfigurationKind.ALL, TestJdkKind.FULL_JDK, getAnnotationsJar(), out),
EnvironmentConfigFiles.JVM_CONFIG_FILES
testRootDisposable,
newConfiguration(ConfigurationKind.ALL, TestJdkKind.FULL_JDK, getAnnotationsJar(), out),
EnvironmentConfigFiles.JVM_CONFIG_FILES
)
setupLanguageVersionSettingsForCompilerTests(ktFile.readText(), environment)
val analysisResult = JvmResolveUtil.analyze(environment)
val packageView = analysisResult.moduleDescriptor.getPackage(LoadDescriptorUtil.TEST_PACKAGE_FQNAME)
@@ -89,22 +96,24 @@ abstract class AbstractCompileJavaAgainstKotlinTest : TestCaseWithTmpdir() {
@Throws(IOException::class)
fun compileKotlinWithJava(
javaFiles: List<File>,
ktFiles: List<File>,
outDir: File,
disposable: Disposable
javaFiles: List<File>,
ktFiles: List<File>,
outDir: File,
disposable: Disposable
): Boolean {
val environment = createEnvironmentWithMockJdkAndIdeaAnnotations(disposable)
setupLanguageVersionSettingsForMultifileCompilerTests(ktFiles, environment)
environment.configuration.put(JVMConfigurationKeys.USE_JAVAC, true)
environment.configuration.put(JVMConfigurationKeys.COMPILE_JAVA, true)
environment.configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, outDir)
environment.configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
environment.registerJavac(javaFiles = javaFiles,
kotlinFiles = listOf(KotlinTestUtils.loadJetFile(environment.project, ktFiles.first())))
environment.registerJavac(
javaFiles = javaFiles,
kotlinFiles = listOf(KotlinTestUtils.loadJetFile(environment.project, ktFiles.first()))
)
if (!ktFiles.isEmpty()) {
LoadDescriptorUtil.compileKotlinToDirAndGetModule(ktFiles, outDir, environment)
}
else {
} else {
val mkdirs = outDir.mkdirs()
assert(mkdirs) { "Not created: $outDir" }
}
@@ -116,14 +125,14 @@ abstract class AbstractCompileJavaAgainstKotlinTest : TestCaseWithTmpdir() {
// Do not render parameter names because there are test cases where classes inherit from JDK collections,
// and some versions of JDK have debug information in the class files (including parameter names), and some don't
private val CONFIGURATION = AbstractLoadJavaTest.COMPARATOR_CONFIGURATION.withRenderer(
DescriptorRenderer.withOptions {
withDefinedIn = false
parameterNameRenderingPolicy = ParameterNameRenderingPolicy.NONE
verbose = true
annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY
excludedAnnotationClasses = setOf(FqName(Retention::class.java.name))
modifiers = DescriptorRendererModifier.ALL
}
DescriptorRenderer.withOptions {
withDefinedIn = false
parameterNameRenderingPolicy = ParameterNameRenderingPolicy.NONE
verbose = true
annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY
excludedAnnotationClasses = setOf(FqName(Retention::class.java.name))
modifiers = DescriptorRendererModifier.ALL
}
)
}
}
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.builtins.DefaultBuiltIns;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
@@ -681,6 +682,7 @@ public class KotlinTestUtils {
) throws IOException {
if (!ktFiles.isEmpty()) {
KotlinCoreEnvironment environment = createEnvironmentWithFullJdkAndIdeaAnnotations(disposable);
CompilerTestLanguageVersionSettingsKt.setupLanguageVersionSettingsForMultifileCompilerTests(ktFiles, environment);
LoadDescriptorUtil.compileKotlinToDirAndGetModule(ktFiles, outDir, environment);
}
else {
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.builtins.DefaultBuiltIns;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
@@ -680,6 +681,7 @@ public class KotlinTestUtils {
) throws IOException {
if (!ktFiles.isEmpty()) {
KotlinCoreEnvironment environment = createEnvironmentWithFullJdkAndIdeaAnnotations(disposable);
CompilerTestLanguageVersionSettingsKt.setupLanguageVersionSettingsForMultifileCompilerTests(ktFiles, environment);
LoadDescriptorUtil.compileKotlinToDirAndGetModule(ktFiles, outDir, environment);
}
else {
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.builtins.DefaultBuiltIns;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
@@ -680,6 +681,7 @@ public class KotlinTestUtils {
) throws IOException {
if (!ktFiles.isEmpty()) {
KotlinCoreEnvironment environment = createEnvironmentWithFullJdkAndIdeaAnnotations(disposable);
CompilerTestLanguageVersionSettingsKt.setupLanguageVersionSettingsForMultifileCompilerTests(ktFiles, environment);
LoadDescriptorUtil.compileKotlinToDirAndGetModule(ktFiles, outDir, environment);
}
else {
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.builtins.DefaultBuiltIns;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt;
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
@@ -680,6 +681,7 @@ public class KotlinTestUtils {
) throws IOException {
if (!ktFiles.isEmpty()) {
KotlinCoreEnvironment environment = createEnvironmentWithFullJdkAndIdeaAnnotations(disposable);
CompilerTestLanguageVersionSettingsKt.setupLanguageVersionSettingsForMultifileCompilerTests(ktFiles, environment);
LoadDescriptorUtil.compileKotlinToDirAndGetModule(ktFiles, outDir, environment);
}
else {
@@ -11853,6 +11853,24 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
}
}
@TestMetadata("compiler/testData/diagnostics/tests/j+k/primitiveOverridesWithInlineClass")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PrimitiveOverridesWithInlineClass extends AbstractDiagnosticsTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInPrimitiveOverridesWithInlineClass() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/j+k/primitiveOverridesWithInlineClass"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineClassErasedToPrimitiveInt.kt")
public void testInlineClassErasedToPrimitiveInt() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/primitiveOverridesWithInlineClass/inlineClassErasedToPrimitiveInt.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/tests/j+k/properties")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -11853,6 +11853,24 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
}
}
@TestMetadata("compiler/testData/diagnostics/tests/j+k/primitiveOverridesWithInlineClass")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PrimitiveOverridesWithInlineClass extends AbstractDiagnosticsUsingJavacTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInPrimitiveOverridesWithInlineClass() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/j+k/primitiveOverridesWithInlineClass"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inlineClassErasedToPrimitiveInt.kt")
public void testInlineClassErasedToPrimitiveInt() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/primitiveOverridesWithInlineClass/inlineClassErasedToPrimitiveInt.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/tests/j+k/properties")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -391,6 +391,24 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
}
}
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverrideWithInlineClass")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PrimitiveOverrideWithInlineClass extends AbstractCompileJavaAgainstKotlinTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTestWithoutJavac, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInPrimitiveOverrideWithInlineClass() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverrideWithInlineClass"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("InlineIntOverridesObject.kt")
public void testInlineIntOverridesObject() throws Exception {
runTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverrideWithInlineClass/InlineIntOverridesObject.kt");
}
}
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method/throws")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -998,6 +1016,24 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
}
}
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverrideWithInlineClass")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PrimitiveOverrideWithInlineClass extends AbstractCompileJavaAgainstKotlinTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTestWithJavac, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInPrimitiveOverrideWithInlineClass() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverrideWithInlineClass"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("InlineIntOverridesObject.kt")
public void testInlineIntOverridesObject() throws Exception {
runTest("compiler/testData/compileJavaAgainstKotlin/method/primitiveOverrideWithInlineClass/InlineIntOverridesObject.kt");
}
}
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/method/throws")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)