diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java index 9ad15d26a98..dbc0e3d507a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java @@ -47,6 +47,7 @@ import java.util.Set; import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.jet.codegen.CodegenUtil.isInterface; +import static org.jetbrains.jet.codegen.CodegenUtil.isNullableType; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; @@ -532,7 +533,7 @@ public class AsmUtil { for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) { JetType type = parameter.getReturnType(); - if (type == null || type.isNullable()) continue; + if (type == null || isNullableType(type)) continue; int index = frameMap.getIndex(parameter); Type asmType = state.getTypeMapper().mapReturnType(type); @@ -574,7 +575,7 @@ public class AsmUtil { if (!isDeclaredInJava(descriptor, state.getBindingContext())) return; JetType type = descriptor.getReturnType(); - if (type == null || type.isNullable()) return; + if (type == null || isNullableType(type)) return; Type asmType = state.getTypeMapper().mapReturnType(type); if (asmType.getSort() == Type.OBJECT || asmType.getSort() == Type.ARRAY) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java index 39ce35ba019..7249c9dba70 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodegenUtil.java @@ -41,6 +41,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import java.util.*; @@ -278,5 +279,16 @@ public class CodegenUtil { return ((MemberDescriptor) declaration).getModality() == ABSTRACT; } }); -} + } + + /** + * A work-around of the generic nullability problem in the type checker + * @return true if a value of this type can be null + */ + public static boolean isNullableType(@NotNull JetType type) { + if (type.getConstructor().getDeclarationDescriptor() instanceof TypeParameterDescriptor) { + return TypeUtils.hasNullableSuperType(type); + } + return type.isNullable(); + } } diff --git a/compiler/testData/codegen/box/functions/kt3313.kt b/compiler/testData/codegen/box/functions/kt3313.kt new file mode 100644 index 00000000000..e82df388a51 --- /dev/null +++ b/compiler/testData/codegen/box/functions/kt3313.kt @@ -0,0 +1,7 @@ +fun foo(t: T) { +} + +fun box(): String { + foo(null) + return "OK" +} diff --git a/compiler/testData/codegen/notNullAssertions/assertionForNotNullTypeParam.kt b/compiler/testData/codegen/notNullAssertions/assertionForNotNullTypeParam.kt new file mode 100644 index 00000000000..c3ea96443dd --- /dev/null +++ b/compiler/testData/codegen/notNullAssertions/assertionForNotNullTypeParam.kt @@ -0,0 +1 @@ +fun foo(t: T) = t diff --git a/compiler/testData/codegen/notNullAssertions/noAssertionForNullableGenericMethod.kt b/compiler/testData/codegen/notNullAssertions/noAssertionForNullableGenericMethod.kt new file mode 100644 index 00000000000..c7851178881 --- /dev/null +++ b/compiler/testData/codegen/notNullAssertions/noAssertionForNullableGenericMethod.kt @@ -0,0 +1,3 @@ +fun foo(a: List) { + val t: T = a.get(0) +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/GenerateNotNullAssertionsTest.java b/compiler/tests/org/jetbrains/jet/codegen/GenerateNotNullAssertionsTest.java index d2e0a1b53ef..9d3c0ec3745 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/GenerateNotNullAssertionsTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/GenerateNotNullAssertionsTest.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; +import jet.runtime.Intrinsics; import org.jetbrains.asm4.ClassReader; import org.jetbrains.asm4.ClassVisitor; import org.jetbrains.asm4.MethodVisitor; @@ -29,6 +30,7 @@ import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys; import org.jetbrains.jet.cli.jvm.compiler.CompileEnvironmentUtil; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; import org.jetbrains.jet.config.CompilerConfiguration; +import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -138,11 +140,28 @@ public class GenerateNotNullAssertionsTest extends CodegenTestCase { assertEquals(3, StringUtil.getOccurrenceCount(text, "checkParameterIsNotNull")); } + public void testAssertionForNotNullTypeParam() { + setUpEnvironment(true, true); + + loadFile("notNullAssertions/assertionForNotNullTypeParam.kt"); + + assertTrue(generateToText().contains("checkParameterIsNotNull")); + } + + public void testNoAssertionForNullableGenericMethod() { + setUpEnvironment(true, false); + + loadFile("notNullAssertions/noAssertionForNullableGenericMethod.kt"); + + assertNoIntrinsicsMethodIsCalled(PackageClassUtils.getPackageClassName(FqName.ROOT)); + } private void assertNoIntrinsicsMethodIsCalled(String className) { ClassFileFactory classes = generateClassesInFile(); ClassReader reader = new ClassReader(classes.asBytes(className + ".class")); + final String intrinsics = JvmClassName.byFqNameWithoutInnerClasses(Intrinsics.class.getName()).getInternalName(); + reader.accept(new ClassVisitor(Opcodes.ASM4) { @Override public MethodVisitor visitMethod( @@ -152,8 +171,8 @@ public class GenerateNotNullAssertionsTest extends CodegenTestCase { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { assertFalse( - "jet/Intrinsics method is called: " + name + desc + " Caller: " + callerName + callerDesc, - "jet/Intrinsics".equals(owner) + "Intrinsics method is called: " + name + desc + " Caller: " + callerName + callerDesc, + intrinsics.equals(owner) ); } }; diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index f474b2273dc..eb6abe1533e 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -1736,6 +1736,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { blackBoxFileByFullPath("compiler/testData/codegen/box/functions/kt2929.kt"); } + @TestMetadata("kt3313.kt") + public void testKt3313() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/box/functions/kt3313.kt"); + } + @TestMetadata("kt395.kt") public void testKt395() throws Exception { blackBoxFileByFullPath("compiler/testData/codegen/box/functions/kt395.kt");