diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java index e302df6a9e1..1b86df6a198 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java @@ -25,7 +25,6 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.Annotated; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationArgumentVisitor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.jet.lang.evaluate.EvaluatePackage; import org.jetbrains.jet.lang.psi.JetAnnotationEntry; import org.jetbrains.jet.lang.psi.JetClass; import org.jetbrains.jet.lang.psi.JetModifierList; @@ -36,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.constants.*; import org.jetbrains.jet.lang.resolve.constants.StringValue; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import java.lang.annotation.Retention; @@ -123,6 +123,14 @@ public abstract class AnnotationCodegen { private void generateNullabilityAnnotation(@Nullable JetType type, @NotNull Set annotationDescriptorsAlreadyPresent) { if (type == null) return; + if (isBareTypeParameterWithNullableUpperBound(type)) { + // This is to account for the case of, say + // class Function { fun invoke(): R } + // it would be a shame to put @Nullable on the return type of the function, and force all callers to check for null, + // so we put no annotations + return; + } + boolean isNullableType = CodegenUtil.isNullableType(type); if (!isNullableType && KotlinBuiltIns.getInstance().isPrimitiveType(type)) return; @@ -134,6 +142,11 @@ public abstract class AnnotationCodegen { } } + private static boolean isBareTypeParameterWithNullableUpperBound(@NotNull JetType type) { + ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor(); + return !type.isNullable() && classifier instanceof TypeParameterDescriptor && TypeUtils.hasNullableSuperType(type); + } + private static boolean isVolatile(@NotNull AnnotationDescriptor annotationDescriptor) { ClassifierDescriptor classDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor(); return KotlinBuiltIns.getInstance().getVolatileAnnotationClass().equals(classDescriptor); diff --git a/compiler/testData/asJava/nullabilityAnnotations/Generic.java b/compiler/testData/asJava/nullabilityAnnotations/Generic.java new file mode 100644 index 00000000000..3c79a6cfc57 --- /dev/null +++ b/compiler/testData/asJava/nullabilityAnnotations/Generic.java @@ -0,0 +1,12 @@ +public interface Generic extends jet.JetObject { + N a(@jet.runtime.typeinfo.JetValueParameter(name = "n") N n); + + @org.jetbrains.annotations.NotNull + NN b(@org.jetbrains.annotations.NotNull @jet.runtime.typeinfo.JetValueParameter(name = "nn") NN nn); + + @org.jetbrains.annotations.Nullable + N a1(@org.jetbrains.annotations.Nullable @jet.runtime.typeinfo.JetValueParameter(name = "n", type = "?") N n); + + @org.jetbrains.annotations.Nullable + NN b1(@org.jetbrains.annotations.Nullable @jet.runtime.typeinfo.JetValueParameter(name = "nn", type = "?") NN nn); +} \ No newline at end of file diff --git a/compiler/testData/asJava/nullabilityAnnotations/Generic.kt b/compiler/testData/asJava/nullabilityAnnotations/Generic.kt new file mode 100644 index 00000000000..4b440dbb0c3 --- /dev/null +++ b/compiler/testData/asJava/nullabilityAnnotations/Generic.kt @@ -0,0 +1,7 @@ +trait Generic { + fun a(n: N): N + fun b(nn: NN): NN + + fun a1(n: N?): N? + fun b1(nn: NN?): NN? +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/asJava/NullabilityAnnotationsTest.java b/compiler/tests/org/jetbrains/jet/asJava/NullabilityAnnotationsTest.java index fb9e8ed0afb..b7e7ad62532 100644 --- a/compiler/tests/org/jetbrains/jet/asJava/NullabilityAnnotationsTest.java +++ b/compiler/tests/org/jetbrains/jet/asJava/NullabilityAnnotationsTest.java @@ -86,6 +86,10 @@ public class NullabilityAnnotationsTest extends KotlinAsJavaTestBase { doTest(getTestName(false)); } + public void testGeneric() throws Exception { + doTest(getTestName(false)); + } + private void doTest(@NotNull String fqName) { PsiClass psiClass = finder.findClass(fqName, GlobalSearchScope.allScope(getProject())); if (!(psiClass instanceof KotlinLightClass)) {