Generic type with Nothing in arguments compiles to raw type

This commit is contained in:
Zalim Bashorov
2015-10-12 22:41:05 +03:00
parent 8e9f1ac31a
commit 9acf3e40de
5 changed files with 127 additions and 6 deletions
@@ -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<TypeProjection> arguments = jetType.getArguments();
@@ -622,6 +629,24 @@ public class JetTypeMapper {
}
}
private static boolean hasNothingInArguments(JetType jetType) {
boolean hasNothingInArguments = CollectionsKt.any(jetType.getArguments(), new Function1<TypeProjection, Boolean>() {
@Override
public Boolean invoke(TypeProjection projection) {
return KotlinBuiltIns.isNothingOrNullableNothing(projection.getType());
}
});
if (hasNothingInArguments) return true;
return CollectionsKt.any(jetType.getArguments(), new Function1<TypeProjection, Boolean>() {
@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;
@@ -0,0 +1,81 @@
package foo
import kotlin.reflect.KClass
class A<T>
class B<T, Y, U>
class TestRaw {
val a1: A<Nothing> = A()
val a2: A<Nothing>? = A()
val a3: A<Nothing?> = A()
val a4: A<Nothing?>? = A()
var b1: B<Nothing, Int, Int> = B()
var b2: B<String, Nothing, Int> = B()
val l: List<Nothing> = listOf()
fun test1(a: A<Nothing?>, b: B<Nothing, String, A<Int>>): A<Nothing>? = A()
fun test2(a: A<Nothing?>?, b: B<Int, String, Nothing>): B<Int?, Int?, Nothing?> = B()
}
class TestNotRaw {
val a1: A<String> = A()
val a2: A<B<Nothing, Int, Int>>? = A()
val a3: A<Int?> = A()
val a4: A<Int?>? = A()
var b1: B<Int, Int, Int> = B()
var b2: B<String, A<String>, Int> = B()
val l: List<String> = listOf()
fun test1(a: A<Int?>, b: B<Int, String, A<Int>>): A<Int>? = A()
fun test2(a: A<Int>?, b: B<Int, String, A<Nothing>>): B<Int?, Int?, Int> = B()
}
abstract class C<T> {
abstract val foo: A<T>
abstract fun bar(): A<T>?
}
class C1 : C<Nothing>() {
override val foo = A<Nothing>()
override fun bar() = foo
}
class C2 : C<String>() {
override val foo = A<String>()
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"
}
+3 -3
View File
@@ -1,6 +1,6 @@
class C<T>
fun f(p: Nothing, p1: C<Nothing>): Nothing = throw Exception()
fun f(p: Nothing, p1: C<Nothing>, p2: C<C<Nothing>>, p3: C<C<Nothing>>?): Nothing = throw Exception()
// method: _DefaultPackage::f
// jvm signature: (Ljava/lang/Void;LC;)Ljava/lang/Void;
// generic signature: (Ljava/lang/Void;LC<Ljava/lang/Void;>;)Ljava/lang/Void;
// jvm signature: (Ljava/lang/Void;LC;LC;LC;)Ljava/lang/Void;
// generic signature: null
@@ -1,6 +1,6 @@
class C<T>
fun f(p: Nothing?, p1: C<Nothing?>): Nothing? = throw Exception()
fun f(p: Nothing?, p1: C<Nothing?>, p2: C<C<Nothing?>>, p3: C<C<Nothing?>>?): Nothing? = throw Exception()
// method: _DefaultPackage::f
// jvm signature: (Ljava/lang/Void;LC;)Ljava/lang/Void;
// generic signature: (Ljava/lang/Void;LC<Ljava/lang/Void;>;)Ljava/lang/Void;
// jvm signature: (Ljava/lang/Void;LC;LC;LC;)Ljava/lang/Void;
// generic signature: null
@@ -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)