diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.kt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.kt new file mode 100644 index 00000000000..d0b9ad12f59 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.kt @@ -0,0 +1,28 @@ +// FILE: A.java + +import org.jetbrains.annotations.NotNull; +public interface A { + void foo(@NotNull T x); +} + +// FILE: B.java +public class B { + public void foo(E x) {} +} + +// FILE: C.java +public class C extends B implements A { + public static C create() { return null; } + public void foo(F x) {} +} + +// FILE: main.kt + +fun test() { + C.create().foo(null) + C.create().foo("") + + C().foo(null) + C().foo(null) + C().foo("") +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.txt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.txt new file mode 100644 index 00000000000..669fcc06979 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.txt @@ -0,0 +1,30 @@ +package + +public /*synthesized*/ fun A(/*0*/ function: (T!) -> kotlin.Unit): A +public fun test(): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(/*0*/ @org.jetbrains.annotations.NotNull() x: T): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class B { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ x: E!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class C : B, A { + public constructor C() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun foo(/*0*/ x: F): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public open fun create(): C! +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromKotlin.kt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromKotlin.kt new file mode 100644 index 00000000000..c86b1711a17 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromKotlin.kt @@ -0,0 +1,28 @@ +// FILE: A.kt + +import org.jetbrains.annotations.NotNull; +public interface A { + fun foo(x: T) +} + +// FILE: B.java +public class B { + public void foo(E x) {} +} + +// FILE: C.java +public class C extends B implements A { + public static C create() { return null; } + public void foo(F x) {} +} + +// FILE: main.kt + +fun test() { + C.create().foo(null) + C.create().foo("") + + C().foo(null) + C().foo(null) + C().foo("") +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromKotlin.txt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromKotlin.txt new file mode 100644 index 00000000000..79507fa9974 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromKotlin.txt @@ -0,0 +1,29 @@ +package + +public fun test(): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(/*0*/ x: T): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class B { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(/*0*/ x: E!): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class C : B, A { + public constructor C() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun foo(/*0*/ x: F!): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public open fun create(): C! +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/methodTypeParameter.kt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/methodTypeParameter.kt new file mode 100644 index 00000000000..4733007abc5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/methodTypeParameter.kt @@ -0,0 +1,18 @@ +// FILE: A.java + +import org.jetbrains.annotations.NotNull; + +public class A { + public static void bar(@NotNull T x, T y) { } + public static String platformString() { return null; } +} + +// FILE: k.kt + +fun test() { + A.bar(null, "") + + A.bar(null, "") + A.bar(null, "") + A.bar(null, A.platformString()) +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/methodTypeParameter.txt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/methodTypeParameter.txt new file mode 100644 index 00000000000..9971c5dbe45 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/methodTypeParameter.txt @@ -0,0 +1,14 @@ +package + +public fun test(): kotlin.Unit + +public open class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public open fun bar(/*0*/ @org.jetbrains.annotations.NotNull() x: T, /*1*/ y: T!): kotlin.Unit + public open fun platformString(): kotlin.String! +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceReturnType.kt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceReturnType.kt new file mode 100644 index 00000000000..36063274c75 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceReturnType.kt @@ -0,0 +1,23 @@ +// FILE: A.java + +import java.util.*; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class A { + public static A create() { + return null; + } + + @NotNull + public T bar() { + } +} + +// FILE: k.kt + +fun test() { + A.create().bar()?.length + A().bar()?.length +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceReturnType.txt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceReturnType.txt new file mode 100644 index 00000000000..86b3288122a --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceReturnType.txt @@ -0,0 +1,14 @@ +package + +public fun test(): kotlin.Unit + +public open class A { + public constructor A() + @org.jetbrains.annotations.NotNull() public open fun bar(): T + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public open fun create(): A! +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceValueParameter.kt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceValueParameter.kt new file mode 100644 index 00000000000..dd8a96e1d1c --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceValueParameter.kt @@ -0,0 +1,26 @@ +// FILE: A.java + +import java.util.*; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class A { + public static A create() { + return null; + } + + public void bar(@NotNull T x) { + } +} + +// FILE: k.kt + +fun test() { + A.create().bar(null) + A.create().bar("") + + A().bar(null) + A().bar(null) + A().bar("") +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceValueParameter.txt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceValueParameter.txt new file mode 100644 index 00000000000..7b31cb3b406 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceValueParameter.txt @@ -0,0 +1,14 @@ +package + +public fun test(): kotlin.Unit + +public open class A { + public constructor A() + public open fun bar(/*0*/ @org.jetbrains.annotations.NotNull() x: T): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + // Static members + public open fun create(): A! +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/substitutionInSuperType.kt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/substitutionInSuperType.kt new file mode 100644 index 00000000000..53bddd424f0 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/substitutionInSuperType.kt @@ -0,0 +1,41 @@ +// FILE: A.java + +import java.util.*; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class A { + public void bar(@NotNull T x) { + } +} + +// FILE: B1.java +public class B1 extends A { + // real override + public void bar(String x) { + } +} + +// FILE: B2.java +public class B2 extends A { + // fake override bar +} + +// FILE: k.kt + +class C1 : A() { + override fun bar(x: String) {} +} + +class C2 : A() { + override fun bar(x: String?) {} +} + +fun test() { + B1().bar(null) + B2().bar(null) + + C1().bar(null) +} + diff --git a/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/substitutionInSuperType.txt b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/substitutionInSuperType.txt new file mode 100644 index 00000000000..85dc38a7cc5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/substitutionInSuperType.txt @@ -0,0 +1,44 @@ +package + +public fun test(): kotlin.Unit + +public open class A { + public constructor A() + public open fun bar(/*0*/ @org.jetbrains.annotations.NotNull() x: T): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class B1 : A { + public constructor B1() + public open override /*1*/ fun bar(/*0*/ x: kotlin.String): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class B2 : A { + public constructor B2() + public open override /*1*/ /*fake_override*/ fun bar(/*0*/ @org.jetbrains.annotations.NotNull() x: kotlin.String): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class C1 : A { + public constructor C1() + public open override /*1*/ fun bar(/*0*/ x: kotlin.String): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class C2 : A { + public constructor C2() + public open override /*1*/ /*fake_override*/ fun bar(/*0*/ @org.jetbrains.annotations.NotNull() x: kotlin.String): kotlin.Unit + public open fun bar(/*0*/ x: kotlin.String?): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/typeEnhancement.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/typeEnhancement.kt index 61b0b4a793e..e1f70eac605 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/typeEnhancement.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/typeEnhancement.kt @@ -22,6 +22,6 @@ val doubleList: List = null!! fun main() { Test.rawField.foo("", doubleList) - Test.rawField.foo(null, doubleList) + Test.rawField.foo(null, doubleList) Test.DerivedRawA().foo(null, doubleList) } diff --git a/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.kt b/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.kt index eec3e23f4a8..80b2e1e08bb 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.kt @@ -24,12 +24,8 @@ public interface B2 extends A { import org.jetbrains.annotations.*; public interface B3 extends A { - // inconsistent override, second parameter type is platform - // TODO: first one should be platform too, but it's not because when substituting T -> String!, - // value parameter type becomes platform and it can be overridden with @NotNull String. - // Conceptual problem: we can use type parameter as T?, but there is no way to specify same semantics as in Java `@NotNull T`. - - // override /*1*/ fun foo(/*0*/ org.jetbrains.annotations.Nullable() x: kotlin.String?, /*1*/ org.jetbrains.annotations.NotNull() y: kotlin.String!): kotlin.Unit + // inconsistent override, both parameters are platform + // override /*1*/ fun foo(/*0*/ org.jetbrains.annotations.Nullable() x: kotlin.String!, /*1*/ org.jetbrains.annotations.NotNull() y: kotlin.String!): kotlin.Unit void foo(@Nullable String x, @NotNull String y); } diff --git a/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.txt b/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.txt index bf1f673f3a5..dfa37ea45d8 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.txt +++ b/compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.txt @@ -1,7 +1,7 @@ package public /*synthesized*/ fun A(/*0*/ function: (T!, T!) -> kotlin.Unit): A -public /*synthesized*/ fun B1(/*0*/ function: (kotlin.String!, kotlin.String?) -> kotlin.Unit): B1 +public /*synthesized*/ fun B1(/*0*/ function: (kotlin.String, kotlin.String?) -> kotlin.Unit): B1 public /*synthesized*/ fun B2(/*0*/ function: (kotlin.String!, kotlin.String!) -> kotlin.Unit): B2 public /*synthesized*/ fun B3(/*0*/ function: (kotlin.String!, kotlin.String!) -> kotlin.Unit): B3 @@ -28,7 +28,7 @@ public interface B2 : A { public interface B3 : A { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public abstract override /*1*/ fun foo(/*0*/ @org.jetbrains.annotations.Nullable() x: kotlin.String?, /*1*/ @org.jetbrains.annotations.NotNull() y: kotlin.String!): kotlin.Unit + public abstract override /*1*/ fun foo(/*0*/ @org.jetbrains.annotations.Nullable() x: kotlin.String!, /*1*/ @org.jetbrains.annotations.NotNull() y: kotlin.String!): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -42,7 +42,7 @@ public interface C1 : A { public interface C2 : A { public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public abstract override /*1*/ /*fake_override*/ fun foo(/*0*/ @org.jetbrains.annotations.NotNull() x: kotlin.String?, /*1*/ @org.jetbrains.annotations.Nullable() y: kotlin.String?): kotlin.Unit + public abstract override /*1*/ /*fake_override*/ fun foo(/*0*/ @org.jetbrains.annotations.NotNull() x: kotlin.String, /*1*/ @org.jetbrains.annotations.Nullable() y: kotlin.String?): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/testData/foreignAnnotations/tests/android.kt b/compiler/testData/foreignAnnotations/tests/android.kt index 5b285b83830..a68833667d6 100644 --- a/compiler/testData/foreignAnnotations/tests/android.kt +++ b/compiler/testData/foreignAnnotations/tests/android.kt @@ -38,6 +38,6 @@ fun main(a: A, a1: A) { a.baz(null).length a1.baz("")!!.length - a1.baz(null)!!.length + a1.baz(null)!!.length } diff --git a/compiler/testData/foreignAnnotations/tests/checkerFramework.kt b/compiler/testData/foreignAnnotations/tests/checkerFramework.kt index b89e1aeb1d2..c4d52161313 100644 --- a/compiler/testData/foreignAnnotations/tests/checkerFramework.kt +++ b/compiler/testData/foreignAnnotations/tests/checkerFramework.kt @@ -38,5 +38,5 @@ fun main(a: A, a1: A) { a.baz(null).length a1.baz("")!!.length - a1.baz(null)!!.length + a1.baz(null)!!.length } diff --git a/compiler/testData/foreignAnnotations/tests/eclipse.kt b/compiler/testData/foreignAnnotations/tests/eclipse.kt index c7877f822ce..86c6c7bae33 100644 --- a/compiler/testData/foreignAnnotations/tests/eclipse.kt +++ b/compiler/testData/foreignAnnotations/tests/eclipse.kt @@ -38,5 +38,5 @@ fun main(a: A, a1: A) { a.baz(null).length a1.baz("")!!.length - a1.baz(null)!!.length + a1.baz(null)!!.length } diff --git a/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/TypeParamOfClass.txt b/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/TypeParamOfClass.txt index 92fd6b57107..d91a48764d2 100644 --- a/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/TypeParamOfClass.txt +++ b/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/TypeParamOfClass.txt @@ -4,7 +4,7 @@ public interface TypeParamOfClass { public interface Sub : test.TypeParamOfClass.Super { public abstract override /*1*/ /*fake_override*/ fun dummy(): kotlin.Unit - public abstract override /*1*/ fun foo(): T! + public abstract override /*1*/ fun foo(): T } public interface Super { diff --git a/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/TypeParamOfClassSubstituted.txt b/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/TypeParamOfClassSubstituted.txt index fcc419fd651..be0a4bd8dae 100644 --- a/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/TypeParamOfClassSubstituted.txt +++ b/compiler/testData/loadJava/compiledJava/kotlinSignature/propagation/return/TypeParamOfClassSubstituted.txt @@ -4,7 +4,7 @@ public interface TypeParamOfClassSubstituted { public interface Sub : test.TypeParamOfClassSubstituted.Super { public abstract override /*1*/ /*fake_override*/ fun dummy(): kotlin.Unit - public abstract override /*1*/ fun foo(): kotlin.String! + public abstract override /*1*/ fun foo(): kotlin.String } public interface Super { diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index bfb1e69f79a..ea2cbd03ea7 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -12435,6 +12435,51 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { } } + @TestMetadata("compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class NotNullTypeParameter extends AbstractDiagnosticsTest { + public void testAllFilesPresentInNotNullTypeParameter() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("enhancementFromAnnotation.kt") + public void testEnhancementFromAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.kt"); + doTest(fileName); + } + + @TestMetadata("enhancementFromKotlin.kt") + public void testEnhancementFromKotlin() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromKotlin.kt"); + doTest(fileName); + } + + @TestMetadata("methodTypeParameter.kt") + public void testMethodTypeParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/methodTypeParameter.kt"); + doTest(fileName); + } + + @TestMetadata("noInheritanceReturnType.kt") + public void testNoInheritanceReturnType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceReturnType.kt"); + doTest(fileName); + } + + @TestMetadata("noInheritanceValueParameter.kt") + public void testNoInheritanceValueParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/noInheritanceValueParameter.kt"); + doTest(fileName); + } + + @TestMetadata("substitutionInSuperType.kt") + public void testSubstitutionInSuperType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/substitutionInSuperType.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt index 865331d97dd..929463ddcb2 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt @@ -31,6 +31,8 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.createProjection +import org.jetbrains.kotlin.types.typeUtil.isTypeParameter +import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.utils.toReadOnlyList // The index in the lambda is the position of the type component: @@ -104,6 +106,12 @@ private fun KotlinType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers typeConstructor, enhancedArguments ) + val newCapabilities = + if (effectiveQualifiers.isNotNullTypeParameter) + capabilities.addCapability(CustomTypeVariable::class.java, NotNullTypeParameterTypeCapability) + else + capabilities + val enhancedType = KotlinTypeImpl.create( newAnnotations, typeConstructor, @@ -113,7 +121,7 @@ private fun KotlinType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers if (enhancedClassifier is ClassDescriptor) enhancedClassifier.getMemberScope(newSubstitution) else enhancedClassifier.getDefaultType().getMemberScope(), - capabilities + newCapabilities ) return Result(enhancedType, globalArgIndex - index) } @@ -192,3 +200,29 @@ private object EnhancedTypeAnnotationDescriptor : AnnotationDescriptor { override fun getSource() = throwError() override fun toString() = "[EnhancedType]" } + +internal object NotNullTypeParameterTypeCapability : CustomTypeVariable { + override val isTypeVariable: Boolean + get() = true + + override fun substitutionResult(replacement: KotlinType): KotlinType { + if (!TypeUtils.isNullableType(replacement) && !replacement.isTypeParameter()) return replacement + + if (replacement.isFlexible()) { + with(replacement.flexibility()) { + return DelegatingFlexibleType.create(lowerBound.prepareReplacement(), upperBound.prepareReplacement(), extraCapabilities) + } + } + + return replacement.prepareReplacement() + } + + private fun KotlinType.prepareReplacement(): KotlinType { + val result = makeNotNullable() + if (!this.isTypeParameter()) return result + + return result.replace( + newCapabilities = capabilities.addCapability( + CustomTypeVariable::class.java, NotNullTypeParameterTypeCapability)) + } +} diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeQualifiers.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeQualifiers.kt index 2c47062bc13..d688f4c0b6c 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeQualifiers.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeQualifiers.kt @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.load.java.typeEnhancement import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.load.java.* import org.jetbrains.kotlin.load.java.typeEnhancement.MutabilityQualifier.MUTABLE import org.jetbrains.kotlin.load.java.typeEnhancement.MutabilityQualifier.READ_ONLY @@ -25,11 +24,10 @@ import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier.NOT_N import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier.NULLABLE import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.platform.JavaToKotlinClassMap -import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.KotlinTypeChecker -import org.jetbrains.kotlin.types.flexibility -import org.jetbrains.kotlin.types.isFlexible -import java.util.ArrayList +import org.jetbrains.kotlin.types.typeUtil.isTypeParameter +import java.util.* enum class NullabilityQualifier { NULLABLE, @@ -41,12 +39,13 @@ enum class MutabilityQualifier { MUTABLE } -class JavaTypeQualifiers( +class JavaTypeQualifiers internal constructor( val nullability: NullabilityQualifier?, - val mutability: MutabilityQualifier? + val mutability: MutabilityQualifier?, + internal val isNotNullTypeParameter: Boolean ) { companion object { - val NONE = JavaTypeQualifiers(null, null) + val NONE = JavaTypeQualifiers(null, null, false) } } @@ -58,13 +57,13 @@ private fun KotlinType.extractQualifiers(): JavaTypeQualifiers { val mapping = JavaToKotlinClassMap.INSTANCE return JavaTypeQualifiers( - if (lower.isMarkedNullable()) NULLABLE else if (!upper.isMarkedNullable()) NOT_NULL else null, - if (mapping.isReadOnly(lower)) READ_ONLY else if (mapping.isMutable(upper)) MUTABLE else null - ) + if (lower.isMarkedNullable) NULLABLE else if (!upper.isMarkedNullable) NOT_NULL else null, + if (mapping.isReadOnly(lower)) READ_ONLY else if (mapping.isMutable(upper)) MUTABLE else null, + isNotNullTypeParameter = getCapability() is NotNullTypeParameterTypeCapability) } -private fun Annotations.extractQualifiers(): JavaTypeQualifiers { - fun List.ifPresent(qualifier: T) = if (any { findAnnotation(it) != null}) qualifier else null +private fun KotlinType.extractQualifiersFromAnnotations(): JavaTypeQualifiers { + fun List.ifPresent(qualifier: T) = if (any { annotations.findAnnotation(it) != null}) qualifier else null // These two overloads are just for sake of optimization as in most cases last parameter in second overload is null fun uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null @@ -76,7 +75,7 @@ private fun Annotations.extractQualifiers(): JavaTypeQualifiers { // Javax/FundBugs NonNull annotation has parameter `when` that determines actual nullability fun FqName.extractQualifierFromAnnotationWithWhen(): NullabilityQualifier? { - val annotationDescriptor = findAnnotation(this) ?: return null + val annotationDescriptor = annotations.findAnnotation(this) ?: return null return annotationDescriptor.allValueArguments.values.singleOrNull()?.value?.let { enumEntryDescriptor -> if (enumEntryDescriptor !is ClassDescriptor) return@let null @@ -84,13 +83,15 @@ private fun Annotations.extractQualifiers(): JavaTypeQualifiers { } ?: NOT_NULL } + val nullability = uniqueNotNull( + NULLABLE_ANNOTATIONS.ifPresent(NULLABLE), + NOT_NULL_ANNOTATIONS.ifPresent(NOT_NULL), + JAVAX_NONNULL_ANNOTATION.extractQualifierFromAnnotationWithWhen() + ) return JavaTypeQualifiers( - uniqueNotNull( - NULLABLE_ANNOTATIONS.ifPresent(NULLABLE), - NOT_NULL_ANNOTATIONS.ifPresent(NOT_NULL), - JAVAX_NONNULL_ANNOTATION.extractQualifierFromAnnotationWithWhen() - ), - uniqueNotNull(READ_ONLY_ANNOTATIONS.ifPresent(READ_ONLY), MUTABLE_ANNOTATIONS.ifPresent(MUTABLE)) + nullability, + uniqueNotNull(READ_ONLY_ANNOTATIONS.ifPresent(READ_ONLY), MUTABLE_ANNOTATIONS.ifPresent(MUTABLE)), + isNotNullTypeParameter = nullability == NOT_NULL && isTypeParameter() ) } @@ -143,14 +144,24 @@ fun KotlinType.computeIndexedQualifiersForOverride(fromSupertypes: Collection, isCovariant: Boolean): JavaTypeQualifiers { val nullabilityFromSupertypes = fromSupertypes.map { it.extractQualifiers().nullability }.filterNotNull().toSet() val mutabilityFromSupertypes = fromSupertypes.map { it.extractQualifiers().mutability }.filterNotNull().toSet() - val own = getAnnotations().extractQualifiers() + + val own = extractQualifiersFromAnnotations() + + val isAnyNonNullTypeParameter = own.isNotNullTypeParameter || fromSupertypes.any { it.extractQualifiers().isNotNullTypeParameter } + + fun createJavaTypeQualifiers(nullability: NullabilityQualifier?, mutability: MutabilityQualifier?): JavaTypeQualifiers { + if (!isAnyNonNullTypeParameter || nullability != NOT_NULL) return JavaTypeQualifiers(nullability, mutability, false) + return JavaTypeQualifiers( + nullability, mutability, + isNotNullTypeParameter = true) + } if (isCovariant) { fun Set.selectCovariantly(low: T, high: T, own: T?): T? { val supertypeQualifier = if (low in this) low else if (high in this) high else null return if (supertypeQualifier == low && own == high) null else own ?: supertypeQualifier } - return JavaTypeQualifiers( + return createJavaTypeQualifiers( nullabilityFromSupertypes.selectCovariantly(NOT_NULL, NULLABLE, own.nullability), mutabilityFromSupertypes.selectCovariantly(MUTABLE, READ_ONLY, own.mutability) ) @@ -163,7 +174,7 @@ private fun KotlinType.computeQualifiersForOverride(fromSupertypes: Collection, private val typeCap } } +fun TypeCapabilities.addCapability(clazz: Class, typeCapability: T): TypeCapabilities { + if (getCapability(clazz) === typeCapability) return this + val newCapabilities = SingletonTypeCapabilities(clazz, typeCapability) + if (this === TypeCapabilities.NONE) return newCapabilities + + return CompositeTypeCapabilities(this, newCapabilities) +} + inline fun KotlinType.getCapability(): T? = getCapability(T::class.java) interface Specificity : TypeCapability { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt index d8c0d699e6d..c0db900c625 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitution.kt @@ -117,11 +117,13 @@ fun KotlinType.computeNewSubstitution( return composedSubstitution } +@JvmOverloads fun KotlinType.replace( - newArguments: List, - newAnnotations: Annotations = annotations + newArguments: List = arguments, + newAnnotations: Annotations = annotations, + newCapabilities: TypeCapabilities = capabilities ): KotlinType { - if (newArguments.isEmpty() && newAnnotations === annotations) return this + if (newArguments.isEmpty() && newAnnotations === annotations && newCapabilities === capabilities) return this if (newArguments.isEmpty()) { return KotlinTypeImpl.create( @@ -131,7 +133,7 @@ fun KotlinType.replace( arguments, substitution, memberScope, - capabilities + newCapabilities ) } @@ -150,7 +152,7 @@ fun KotlinType.replace( newArguments, newSubstitution, newScope, - capabilities + newCapabilities ) } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index c7a557ad062..1254c806ffd 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -57,6 +57,8 @@ fun KotlinType.isNullableAny(): Boolean = KotlinBuiltIns.isNullableAny(this) fun KotlinType.isBoolean(): Boolean = KotlinBuiltIns.isBoolean(this) fun KotlinType.isBooleanOrNullableBoolean(): Boolean = KotlinBuiltIns.isBooleanOrNullableBoolean(this) +fun KotlinType.isTypeParameter(): Boolean = TypeUtils.isTypeParameter(this) + fun KotlinType?.isArrayOfNothing(): Boolean { if (this == null || !KotlinBuiltIns.isArray(this)) return false