diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java index d90971a1071..ebcd1b56111 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java @@ -18,6 +18,8 @@ package org.jetbrains.kotlin.codegen.state; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; +import kotlin.CollectionsKt; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.BuiltinsPackageFragment; @@ -595,6 +597,11 @@ public class JetTypeMapper { boolean projectionsAllowed ) { if (signatureVisitor != null) { + if (hasNothingInArguments(jetType)) { + signatureVisitor.writeAsmType(asmType); + return; + } + signatureVisitor.writeClassBegin(asmType); List arguments = jetType.getArguments(); @@ -622,6 +629,24 @@ public class JetTypeMapper { } } + private static boolean hasNothingInArguments(JetType jetType) { + boolean hasNothingInArguments = CollectionsKt.any(jetType.getArguments(), new Function1() { + @Override + public Boolean invoke(TypeProjection projection) { + return KotlinBuiltIns.isNothingOrNullableNothing(projection.getType()); + } + }); + + if (hasNothingInArguments) return true; + + return CollectionsKt.any(jetType.getArguments(), new Function1() { + @Override + public Boolean invoke(TypeProjection projection) { + return !projection.isStarProjection() && hasNothingInArguments(projection.getType()); + } + }); + } + private static Variance getEffectiveVariance(Variance parameterVariance, Variance projectionKind, Variance howThisTypeIsUsed) { // Return type must not contain wildcards if (howThisTypeIsUsed == Variance.OUT_VARIANCE) return projectionKind; diff --git a/compiler/testData/codegen/boxWithStdlib/typeMapping/genericTypeWithNothing.kt b/compiler/testData/codegen/boxWithStdlib/typeMapping/genericTypeWithNothing.kt new file mode 100644 index 00000000000..d682f34021e --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/typeMapping/genericTypeWithNothing.kt @@ -0,0 +1,81 @@ +package foo + +import kotlin.reflect.KClass + +class A +class B + +class TestRaw { + val a1: A = A() + val a2: A? = A() + val a3: A = A() + val a4: A? = A() + + var b1: B = B() + var b2: B = B() + + val l: List = listOf() + + fun test1(a: A, b: B>): A? = A() + fun test2(a: A?, b: B): B = B() +} + +class TestNotRaw { + val a1: A = A() + val a2: A>? = A() + val a3: A = A() + val a4: A? = A() + + var b1: B = B() + var b2: B, Int> = B() + + val l: List = listOf() + + fun test1(a: A, b: B>): A? = A() + fun test2(a: A?, b: B>): B = B() +} + +abstract class C { + abstract val foo: A + abstract fun bar(): A? +} + +class C1 : C() { + override val foo = A() + override fun bar() = foo +} +class C2 : C() { + override val foo = A() + override fun bar() = foo +} + +fun testAllDeclaredMembers(klass: KClass<*>, expectedIsRaw: Boolean): String? { + val clazz = klass.java + + for (it in clazz.declaredFields) { + if ((it.type == it.genericType) == expectedIsRaw) return "failed on field '${clazz.simpleName}::${it.name}'" + } + + for (m in clazz.declaredMethods) { + for (i in m.parameterTypes.indices) { + if ((m.parameterTypes[i] == m.genericParameterTypes[i]) == expectedIsRaw) return "failed on type of param#$i of method '${clazz.simpleName}::${m.name}'" + } + if (m.returnType != Void.TYPE && (m.returnType == m.genericReturnType) == expectedIsRaw) return "failed on return type of method '${clazz.simpleName}::${m.name}'" + } + + return null +} + +fun box(): String { + testAllDeclaredMembers(TestRaw::class, expectedIsRaw = true) ?: + testAllDeclaredMembers(TestNotRaw::class, expectedIsRaw = false)?.let { return it } + + if (C1::class.java.superclass != C1::class.java.genericSuperclass) return "failed on C1 superclass" + + if (C2::class.java.superclass == C2::class.java.genericSuperclass) return "failed on C2 superclass" + + testAllDeclaredMembers(C1::class, expectedIsRaw = true) ?: + testAllDeclaredMembers(C2::class, expectedIsRaw = false)?.let { return it } + + return "OK" +} diff --git a/compiler/testData/writeSignature/nothing/nothing.kt b/compiler/testData/writeSignature/nothing/nothing.kt index 0912e0bd844..24a1a9a2100 100644 --- a/compiler/testData/writeSignature/nothing/nothing.kt +++ b/compiler/testData/writeSignature/nothing/nothing.kt @@ -1,6 +1,6 @@ class C -fun f(p: Nothing, p1: C): Nothing = throw Exception() +fun f(p: Nothing, p1: C, p2: C>, p3: C>?): Nothing = throw Exception() // method: _DefaultPackage::f -// jvm signature: (Ljava/lang/Void;LC;)Ljava/lang/Void; -// generic signature: (Ljava/lang/Void;LC;)Ljava/lang/Void; +// jvm signature: (Ljava/lang/Void;LC;LC;LC;)Ljava/lang/Void; +// generic signature: null diff --git a/compiler/testData/writeSignature/nothing/nullableNothing.kt b/compiler/testData/writeSignature/nothing/nullableNothing.kt index 3eaecfbf5d3..e79e3847324 100644 --- a/compiler/testData/writeSignature/nothing/nullableNothing.kt +++ b/compiler/testData/writeSignature/nothing/nullableNothing.kt @@ -1,6 +1,6 @@ class C -fun f(p: Nothing?, p1: C): Nothing? = throw Exception() +fun f(p: Nothing?, p1: C, p2: C>, p3: C>?): Nothing? = throw Exception() // method: _DefaultPackage::f -// jvm signature: (Ljava/lang/Void;LC;)Ljava/lang/Void; -// generic signature: (Ljava/lang/Void;LC;)Ljava/lang/Void; +// jvm signature: (Ljava/lang/Void;LC;LC;LC;)Ljava/lang/Void; +// generic signature: null diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index b2d0e24752d..8e7c9c02243 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -4643,6 +4643,21 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/typeMapping") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class TypeMapping extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInTypeMapping() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/typeMapping"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("genericTypeWithNothing.kt") + public void testGenericTypeWithNothing() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/typeMapping/genericTypeWithNothing.kt"); + doTestWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/vararg") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)