FE: in NullMarked scope, enhance T! to at least T
#KT-44436 Fixed
This commit is contained in:
Vendored
+4
-4
@@ -34,8 +34,8 @@ public open class BK : B {
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|
||||||
@org.jspecify.nullness.NullMarked public open class C</*0*/ E : C<E!>> : SelfType<E> {
|
@org.jspecify.nullness.NullMarked public open class C</*0*/ E : C<E>> : SelfType<E> {
|
||||||
public constructor C</*0*/ E : C<E!>>()
|
public constructor C</*0*/ E : C<E>>()
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open override /*1*/ /*fake_override*/ fun foo(/*0*/ t: E): kotlin.Unit
|
public open override /*1*/ /*fake_override*/ fun foo(/*0*/ t: E): kotlin.Unit
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
@@ -58,8 +58,8 @@ public open class CKN : C<@org.jspecify.nullness.Nullable CK?> {
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|
||||||
@org.jspecify.nullness.NullMarked public open class SelfType</*0*/ T : SelfType<T!>> {
|
@org.jspecify.nullness.NullMarked public open class SelfType</*0*/ T : SelfType<T>> {
|
||||||
public constructor SelfType</*0*/ T : SelfType<T!>>()
|
public constructor SelfType</*0*/ T : SelfType<T>>()
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open fun foo(/*0*/ t: T): kotlin.Unit
|
public open fun foo(/*0*/ t: T): kotlin.Unit
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
|||||||
Vendored
+2
-1
@@ -82,5 +82,6 @@ public open class UtilGenericNullnessUnspecifiedBound {
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
// Static members
|
// Static members
|
||||||
public open fun </*0*/ K : @org.jspecify.nullness.NullnessUnspecified kotlin.Any!> getFooOfK(): Foo<K!>
|
public open fun </*0*/ K : @org.jspecify.nullness.NullnessUnspecified kotlin.Any!> getFooOfK(): Foo<K>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
-18
@@ -1,18 +0,0 @@
|
|||||||
// JSPECIFY_STATE: strict
|
|
||||||
// !LANGUAGE: +TypeEnhancementImprovementsInStrictMode
|
|
||||||
// MUTE_FOR_PSI_CLASS_FILES_READING
|
|
||||||
|
|
||||||
// FILE: Foo.java
|
|
||||||
import org.jspecify.nullness.*;
|
|
||||||
|
|
||||||
@NullMarked
|
|
||||||
public class Foo<T extends @Nullable Object> {
|
|
||||||
static <T extends Comparable> Foo<T> create() {
|
|
||||||
return new Foo<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FILE: main.kt
|
|
||||||
fun test(): Foo<String> {
|
|
||||||
return <!DEBUG_INFO_EXPRESSION_TYPE("Foo<kotlin.String>")!>Foo.create()<!>
|
|
||||||
}
|
|
||||||
Vendored
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// JSPECIFY_STATE: strict
|
// JSPECIFY_STATE: strict
|
||||||
// !LANGUAGE: +TypeEnhancementImprovementsInStrictMode
|
// !LANGUAGE: +TypeEnhancementImprovementsInStrictMode
|
||||||
// MUTE_FOR_PSI_CLASS_FILES_READING
|
// MUTE_FOR_PSI_CLASS_FILES_READING
|
||||||
@@ -14,5 +15,5 @@ public class Foo<T extends @Nullable Object> {
|
|||||||
|
|
||||||
// FILE: main.kt
|
// FILE: main.kt
|
||||||
fun test(): Foo<String> {
|
fun test(): Foo<String> {
|
||||||
return <!DEBUG_INFO_EXPRESSION_TYPE("Foo<(kotlin.String..kotlin.String?)>")!>Foo.create()<!>
|
return <!DEBUG_INFO_EXPRESSION_TYPE("Foo<kotlin.String>")!>Foo.create()<!>
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+2
-1
@@ -9,5 +9,6 @@ public fun test(): Foo<kotlin.String>
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
// Static members
|
// Static members
|
||||||
public/*package*/ open fun </*0*/ T : (kotlin.Comparable<(raw) kotlin.Any?>..kotlin.Comparable<kotlin.Nothing>?)> create(): Foo<T!>
|
public/*package*/ open fun </*0*/ T : (kotlin.Comparable<(raw) kotlin.Any?>..kotlin.Comparable<kotlin.Nothing>?)> create(): Foo<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -34,7 +34,7 @@ public open class BK : B {
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|
||||||
@org.jspecify.nullness.NullMarked public open class C</*0*/ E : C<E!>!> : SelfType<E!> {
|
@org.jspecify.nullness.NullMarked public open class C</*0*/ E : C<E!>!> : SelfType<E> {
|
||||||
public constructor C</*0*/ E : C<E!>!>()
|
public constructor C</*0*/ E : C<E!>!>()
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open override /*1*/ /*fake_override*/ fun foo(/*0*/ t: E!): kotlin.Unit
|
public open override /*1*/ /*fake_override*/ fun foo(/*0*/ t: E!): kotlin.Unit
|
||||||
|
|||||||
+2
-2
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
data class JavaDefaultQualifiers(
|
data class JavaDefaultQualifiers(
|
||||||
val nullabilityQualifier: NullabilityQualifierWithMigrationStatus,
|
val nullabilityQualifier: NullabilityQualifierWithMigrationStatus,
|
||||||
val qualifierApplicabilityTypes: Collection<AnnotationQualifierApplicabilityType>,
|
val qualifierApplicabilityTypes: Collection<AnnotationQualifierApplicabilityType>,
|
||||||
val affectsTypeParameterBasedTypes: Boolean = nullabilityQualifier.qualifier == NullabilityQualifier.NOT_NULL
|
val definitelyNotNull: Boolean = nullabilityQualifier.qualifier == NullabilityQualifier.NOT_NULL
|
||||||
)
|
)
|
||||||
|
|
||||||
val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
|
val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
|
||||||
@@ -33,7 +33,7 @@ val JSPECIFY_DEFAULT_ANNOTATIONS = mapOf(
|
|||||||
JSPECIFY_NULL_MARKED to JavaDefaultQualifiers(
|
JSPECIFY_NULL_MARKED to JavaDefaultQualifiers(
|
||||||
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
|
NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL),
|
||||||
DEFAULT_JSPECIFY_APPLICABILITY,
|
DEFAULT_JSPECIFY_APPLICABILITY,
|
||||||
affectsTypeParameterBasedTypes = false
|
definitelyNotNull = false
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+9
-15
@@ -104,7 +104,6 @@ abstract class AbstractSignatureParts<TAnnotation : Any> {
|
|||||||
else -> AnnotationQualifierApplicabilityType.TYPE_USE
|
else -> AnnotationQualifierApplicabilityType.TYPE_USE
|
||||||
}
|
}
|
||||||
val defaultTypeQualifier = defaultQualifiers?.get(applicabilityType)
|
val defaultTypeQualifier = defaultQualifiers?.get(applicabilityType)
|
||||||
?.takeIf { (it.affectsTypeParameterBasedTypes || typeParameterUse == null) }
|
|
||||||
|
|
||||||
val referencedParameterBoundsNullability = typeParameterUse?.boundsNullability
|
val referencedParameterBoundsNullability = typeParameterUse?.boundsNullability
|
||||||
// For type parameter uses, we have *three* options:
|
// For type parameter uses, we have *three* options:
|
||||||
@@ -112,7 +111,7 @@ abstract class AbstractSignatureParts<TAnnotation : Any> {
|
|||||||
// happens if T is bounded by @NotNull (technically !! is redundant) or context says unannotated
|
// happens if T is bounded by @NotNull (technically !! is redundant) or context says unannotated
|
||||||
// type parameters are non-null;
|
// type parameters are non-null;
|
||||||
// T - NOT_NULL, isNotNullTypeParameter = false
|
// T - NOT_NULL, isNotNullTypeParameter = false
|
||||||
// happens if T is bounded by @Nullable or context says unannotated types in general are non-null;
|
// happens if T is bounded by @Nullable (should it?) or context says unannotated types in general are non-null;
|
||||||
// T? - NULLABLE, isNotNullTypeParameter = false
|
// T? - NULLABLE, isNotNullTypeParameter = false
|
||||||
// happens if context says unannotated types in general are nullable.
|
// happens if context says unannotated types in general are nullable.
|
||||||
// For other types, this is more straightforward (just take nullability from the context).
|
// For other types, this is more straightforward (just take nullability from the context).
|
||||||
@@ -122,27 +121,22 @@ abstract class AbstractSignatureParts<TAnnotation : Any> {
|
|||||||
?: defaultTypeQualifier?.nullabilityQualifier
|
?: defaultTypeQualifier?.nullabilityQualifier
|
||||||
val definitelyNotNull =
|
val definitelyNotNull =
|
||||||
referencedParameterBoundsNullability?.qualifier == NullabilityQualifier.NOT_NULL ||
|
referencedParameterBoundsNullability?.qualifier == NullabilityQualifier.NOT_NULL ||
|
||||||
(typeParameterUse != null && defaultTypeQualifier?.nullabilityQualifier?.qualifier == NullabilityQualifier.NOT_NULL)
|
(typeParameterUse != null && defaultTypeQualifier?.definitelyNotNull == true)
|
||||||
|
|
||||||
// We should also enhance this type to satisfy the bound of the type parameter it is instantiating:
|
// We should also enhance this type to satisfy the bound of the type parameter it is instantiating:
|
||||||
// for C<T extends @NotNull V>, C<X!> becomes C<X!!> regardless of the above.
|
// for C<T extends @NotNull V>, C<X!> becomes C<X!!> regardless of the above.
|
||||||
val substitutedParameterBoundsNullability = typeParameterForArgument?.boundsNullability
|
val substitutedParameterBoundsNullability = typeParameterForArgument?.boundsNullability
|
||||||
val result = when {
|
?.let { if (it.qualifier == NullabilityQualifier.NULLABLE) it.copy(qualifier = NullabilityQualifier.FORCE_FLEXIBILITY) else it }
|
||||||
substitutedParameterBoundsNullability == null -> defaultNullability
|
val result = mostSpecific(substitutedParameterBoundsNullability, defaultNullability)
|
||||||
defaultNullability == null ->
|
|
||||||
if (substitutedParameterBoundsNullability.qualifier == NullabilityQualifier.NULLABLE)
|
|
||||||
substitutedParameterBoundsNullability.copy(qualifier = NullabilityQualifier.FORCE_FLEXIBILITY)
|
|
||||||
else
|
|
||||||
substitutedParameterBoundsNullability
|
|
||||||
else -> mostSpecific(substitutedParameterBoundsNullability, defaultNullability)
|
|
||||||
}
|
|
||||||
return JavaTypeQualifiers(result?.qualifier, annotationsMutability, definitelyNotNull, result?.isForWarningOnly == true)
|
return JavaTypeQualifiers(result?.qualifier, annotationsMutability, definitelyNotNull, result?.isForWarningOnly == true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun mostSpecific(
|
private fun mostSpecific(
|
||||||
a: NullabilityQualifierWithMigrationStatus,
|
a: NullabilityQualifierWithMigrationStatus?,
|
||||||
b: NullabilityQualifierWithMigrationStatus
|
b: NullabilityQualifierWithMigrationStatus?
|
||||||
): NullabilityQualifierWithMigrationStatus {
|
): NullabilityQualifierWithMigrationStatus? {
|
||||||
|
if (a == null) return b
|
||||||
|
if (b == null) return a
|
||||||
// TODO: this probably behaves really weirdly when some of those are warnings.
|
// TODO: this probably behaves really weirdly when some of those are warnings.
|
||||||
if (a.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return b
|
if (a.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return b
|
||||||
if (b.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return a
|
if (b.qualifier == NullabilityQualifier.FORCE_FLEXIBILITY) return a
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ enum class MutabilityQualifier {
|
|||||||
MUTABLE
|
MUTABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
class JavaTypeQualifiers constructor(
|
class JavaTypeQualifiers(
|
||||||
val nullability: NullabilityQualifier?,
|
val nullability: NullabilityQualifier?,
|
||||||
val mutability: MutabilityQualifier?,
|
val mutability: MutabilityQualifier?,
|
||||||
val definitelyNotNull: Boolean,
|
val definitelyNotNull: Boolean,
|
||||||
|
|||||||
Reference in New Issue
Block a user