Introduce not null type parameter capability
Java nullability annotations may generate types that currently are not denotable in Kotlin:
class Java {
void <F> foo(@NotNull F f) {}
}
Type of given value parameter should be not nullable under any substitution:
String/String?/String! because of annotation contract.
NB: Currently there is no full analogues for such types in pure kotlin
This commit is contained in:
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
// FILE: A.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
public interface A<T> {
|
||||
void foo(@NotNull T x);
|
||||
}
|
||||
|
||||
// FILE: B.java
|
||||
public class B<E> {
|
||||
public void foo(E x) {}
|
||||
}
|
||||
|
||||
// FILE: C.java
|
||||
public class C<F> extends B<F> implements A<F> {
|
||||
public static C<String> create() { return null; }
|
||||
public void foo(F x) {}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
fun test() {
|
||||
C.create().foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
C.create().foo("")
|
||||
|
||||
C<String>().foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
C<String?>().foo(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
C<String?>().foo("")
|
||||
}
|
||||
compiler/testData/diagnostics/tests/platformTypes/notNullTypeParameter/enhancementFromAnnotation.txt
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
package
|
||||
|
||||
public /*synthesized*/ fun </*0*/ T : kotlin.Any!> A(/*0*/ function: (T!) -> kotlin.Unit): A<T>
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public interface A</*0*/ T : kotlin.Any!> {
|
||||
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</*0*/ E : kotlin.Any!> {
|
||||
public constructor B</*0*/ E : kotlin.Any!>()
|
||||
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</*0*/ F : kotlin.Any!> : B<F!>, A<F!> {
|
||||
public constructor C</*0*/ F : kotlin.Any!>()
|
||||
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<kotlin.String!>!
|
||||
}
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
// FILE: A.kt
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
public interface A<T> {
|
||||
fun foo(x: T)
|
||||
}
|
||||
|
||||
// FILE: B.java
|
||||
public class B<E> {
|
||||
public void foo(E x) {}
|
||||
}
|
||||
|
||||
// FILE: C.java
|
||||
public class C<F> extends B<F> implements A<F> {
|
||||
public static C<String> create() { return null; }
|
||||
public void foo(F x) {}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
fun test() {
|
||||
C.create().foo(null)
|
||||
C.create().foo("")
|
||||
|
||||
C<String>().foo(null)
|
||||
C<String?>().foo(null)
|
||||
C<String?>().foo("")
|
||||
}
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
package
|
||||
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public interface A</*0*/ T> {
|
||||
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</*0*/ E : kotlin.Any!> {
|
||||
public constructor B</*0*/ E : kotlin.Any!>()
|
||||
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</*0*/ F : kotlin.Any!> : B<F!>, A<F!> {
|
||||
public constructor C</*0*/ F : kotlin.Any!>()
|
||||
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<kotlin.String!>!
|
||||
}
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
// FILE: A.java
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class A {
|
||||
public static <T> void bar(@NotNull T x, T y) { }
|
||||
public static String platformString() { return null; }
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
fun test() {
|
||||
A.<!TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
||||
|
||||
A.bar<String>(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
||||
A.bar<String?>(<!NULL_FOR_NONNULL_TYPE!>null<!>, "")
|
||||
A.<!TYPE_INFERENCE_INCORPORATION_ERROR!>bar<!>(<!NULL_FOR_NONNULL_TYPE!>null<!>, A.platformString())
|
||||
}
|
||||
Vendored
+14
@@ -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 </*0*/ T : kotlin.Any!> bar(/*0*/ @org.jetbrains.annotations.NotNull() x: T, /*1*/ y: T!): kotlin.Unit
|
||||
public open fun platformString(): kotlin.String!
|
||||
}
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
// FILE: A.java
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class A<T> {
|
||||
public static A<String> create() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public T bar() {
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
fun test() {
|
||||
A.create().bar()<!UNNECESSARY_SAFE_CALL!>?.<!>length
|
||||
A<String?>().bar()<!UNNECESSARY_SAFE_CALL!>?.<!>length
|
||||
}
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
package
|
||||
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public open class A</*0*/ T : kotlin.Any!> {
|
||||
public constructor A</*0*/ T : kotlin.Any!>()
|
||||
@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<kotlin.String!>!
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// FILE: A.java
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class A<T> {
|
||||
public static A<String> create() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void bar(@NotNull T x) {
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
fun test() {
|
||||
A.create().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
A.create().bar("")
|
||||
|
||||
A<String>().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
A<String?>().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
A<String?>().bar("")
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package
|
||||
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public open class A</*0*/ T : kotlin.Any!> {
|
||||
public constructor A</*0*/ T : kotlin.Any!>()
|
||||
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<kotlin.String!>!
|
||||
}
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
// FILE: A.java
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class A<T> {
|
||||
public void bar(@NotNull T x) {
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: B1.java
|
||||
public class B1 extends A<String> {
|
||||
// real override
|
||||
public void bar(String x) {
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: B2.java
|
||||
public class B2 extends A<String> {
|
||||
// fake override bar
|
||||
}
|
||||
|
||||
// FILE: k.kt
|
||||
|
||||
class C1 : A<String?>() {
|
||||
override fun bar(x: String) {}
|
||||
}
|
||||
|
||||
class C2 : A<String?>() {
|
||||
<!NOTHING_TO_OVERRIDE!>override<!> fun bar(x: String?) {}
|
||||
}
|
||||
|
||||
fun test() {
|
||||
B1().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
B2().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
|
||||
C1().bar(<!NULL_FOR_NONNULL_TYPE!>null<!>)
|
||||
}
|
||||
|
||||
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
package
|
||||
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public open class A</*0*/ T : kotlin.Any!> {
|
||||
public constructor A</*0*/ T : kotlin.Any!>()
|
||||
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<kotlin.String!> {
|
||||
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<kotlin.String!> {
|
||||
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<kotlin.String?> {
|
||||
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<kotlin.String?> {
|
||||
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
|
||||
}
|
||||
+1
-1
@@ -22,6 +22,6 @@ val doubleList: List<Double?> = null!!
|
||||
|
||||
fun main() {
|
||||
Test.rawField.foo("", doubleList)
|
||||
Test.rawField.foo(<!NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS!>null<!>, doubleList)
|
||||
Test.rawField.foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, doubleList)
|
||||
Test.DerivedRawA().foo(<!NULL_FOR_NONNULL_TYPE!>null<!>, doubleList)
|
||||
}
|
||||
|
||||
compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/saveAnnotationAfterSubstitution.kt
Vendored
+2
-6
@@ -24,12 +24,8 @@ public interface B2 extends A<String> {
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
public interface B3 extends A<String> {
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
package
|
||||
|
||||
public /*synthesized*/ fun </*0*/ T : kotlin.Any!> A(/*0*/ function: (T!, T!) -> kotlin.Unit): A<T>
|
||||
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<kotlin.String!> {
|
||||
|
||||
public interface B3 : A<kotlin.String!> {
|
||||
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<kotlin.String> {
|
||||
|
||||
public interface C2 : A<kotlin.String?> {
|
||||
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
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,6 +38,6 @@ fun main(a: A<String>, a1: A<String?>) {
|
||||
a.baz(<!NULL_FOR_NONNULL_TYPE!>null<!>)<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
a1.baz("")!!.length
|
||||
a1.baz(null)!!.length
|
||||
a1.baz(<!NULL_FOR_NONNULL_TYPE!>null<!>)!!.length
|
||||
}
|
||||
|
||||
|
||||
@@ -38,5 +38,5 @@ fun main(a: A<String>, a1: A<String?>) {
|
||||
a.baz(<!NULL_FOR_NONNULL_TYPE!>null<!>)<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
a1.baz("")!!.length
|
||||
a1.baz(null)!!.length
|
||||
a1.baz(<!NULL_FOR_NONNULL_TYPE!>null<!>)!!.length
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,5 +38,5 @@ fun main(a: A<String>, a1: A<String?>) {
|
||||
a.baz(<!NULL_FOR_NONNULL_TYPE!>null<!>)<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
a1.baz("")!!.length
|
||||
a1.baz(null)!!.length
|
||||
a1.baz(<!NULL_FOR_NONNULL_TYPE!>null<!>)!!.length
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -4,7 +4,7 @@ public interface TypeParamOfClass {
|
||||
|
||||
public interface Sub</*0*/ T : kotlin.Any!> : test.TypeParamOfClass.Super<T!> {
|
||||
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</*0*/ T : kotlin.Any!> {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ public interface TypeParamOfClassSubstituted {
|
||||
|
||||
public interface Sub : test.TypeParamOfClassSubstituted.Super<kotlin.String!> {
|
||||
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</*0*/ T : kotlin.Any!> {
|
||||
|
||||
@@ -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)
|
||||
|
||||
+35
-1
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
+34
-23
@@ -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<CustomTypeVariable>() is NotNullTypeParameterTypeCapability)
|
||||
}
|
||||
|
||||
private fun Annotations.extractQualifiers(): JavaTypeQualifiers {
|
||||
fun <T: Any> List<FqName>.ifPresent(qualifier: T) = if (any { findAnnotation(it) != null}) qualifier else null
|
||||
private fun KotlinType.extractQualifiersFromAnnotations(): JavaTypeQualifiers {
|
||||
fun <T: Any> List<FqName>.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 <T: Any> 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<Ko
|
||||
private fun KotlinType.computeQualifiersForOverride(fromSupertypes: Collection<KotlinType>, 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 <T : Any> Set<T>.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<K
|
||||
// and all qualifiers are discarded
|
||||
return effectiveSet.singleOrNull()
|
||||
}
|
||||
return JavaTypeQualifiers(
|
||||
return createJavaTypeQualifiers(
|
||||
nullabilityFromSupertypes.selectInvariantly(own.nullability),
|
||||
mutabilityFromSupertypes.selectInvariantly(own.mutability)
|
||||
)
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.types
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PossiblyInnerType
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
|
||||
interface TypeCapability
|
||||
|
||||
@@ -41,6 +40,14 @@ class SingletonTypeCapabilities(private val clazz: Class<*>, private val typeCap
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : TypeCapability> TypeCapabilities.addCapability(clazz: Class<T>, 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 <reified T : TypeCapability> KotlinType.getCapability(): T? = getCapability(T::class.java)
|
||||
|
||||
interface Specificity : TypeCapability {
|
||||
|
||||
@@ -117,11 +117,13 @@ fun KotlinType.computeNewSubstitution(
|
||||
return composedSubstitution
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun KotlinType.replace(
|
||||
newArguments: List<TypeProjection>,
|
||||
newAnnotations: Annotations = annotations
|
||||
newArguments: List<TypeProjection> = 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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user