Report warnings on overrides with wrong types nullability

^KT-48899 Fixed
This commit is contained in:
Denis.Zharkov
2021-09-24 16:33:07 +03:00
committed by TeamCityServer
parent ec97dab6cd
commit f7ef551f99
29 changed files with 672 additions and 42 deletions
@@ -445,9 +445,10 @@ object AbstractTypeChecker {
return true
}
@OptIn(ObsoleteTypeKind::class)
private fun TypeSystemContext.isCommonDenotableType(type: KotlinTypeMarker): Boolean =
type.typeConstructor().isDenotable() &&
!type.isDynamic() && !type.isDefinitelyNotNullType() &&
!type.isDynamic() && !type.isDefinitelyNotNullType() && !type.isNotNullTypeVariable() &&
type.lowerBoundIfFlexible().typeConstructor() == type.upperBoundIfFlexible().typeConstructor()
fun effectiveVariance(declared: TypeVariance, useSite: TypeVariance): TypeVariance? {
@@ -702,7 +703,8 @@ object AbstractNullabilityChecker {
if (superType.isMarkedNullable()) return true
// i.e. subType is definitely not null
if (subType.isDefinitelyNotNullType()) return true
@OptIn(ObsoleteTypeKind::class)
if (subType.isDefinitelyNotNullType() || subType.isNotNullTypeVariable()) return true
// i.e. subType is captured type, projection of which is marked not-null
if (subType is CapturedTypeMarker && subType.isProjectionNotNull()) return true
@@ -377,6 +377,11 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
fun KotlinTypeMarker.isDefinitelyNotNullType(): Boolean = asSimpleType()?.asDefinitelyNotNullType() != null
// This kind of types is obsolete (expected to be removed at 1.7) and shouldn't be used further in a new code
// Now, such types are being replaced with definitely non-nullable types
@ObsoleteTypeKind
fun KotlinTypeMarker.isNotNullTypeVariable(): Boolean = false
fun KotlinTypeMarker.hasFlexibleNullability() =
lowerBoundIfFlexible().isMarkedNullable() != upperBoundIfFlexible().isMarkedNullable()
@@ -495,3 +500,6 @@ fun requireOrDescribe(condition: Boolean, value: Any?) {
"Unexpected: value = '$value'$typeInfo"
}
}
@RequiresOptIn("This kinds of type is obsolete and should not be used until you really need it")
annotation class ObsoleteTypeKind
@@ -60,18 +60,23 @@ public class OverridingUtil {
};
static {
DEFAULT = new OverridingUtil(DEFAULT_TYPE_CONSTRUCTOR_EQUALITY, KotlinTypeRefiner.Default.INSTANCE);
}
@NotNull
public static OverridingUtil createWithEqualityAxioms(@NotNull KotlinTypeChecker.TypeConstructorEquality equalityAxioms) {
return new OverridingUtil(equalityAxioms, KotlinTypeRefiner.Default.INSTANCE);
DEFAULT = new OverridingUtil(
DEFAULT_TYPE_CONSTRUCTOR_EQUALITY, KotlinTypeRefiner.Default.INSTANCE, KotlinTypePreparator.Default.INSTANCE,
null
);
}
@NotNull
public static OverridingUtil createWithTypeRefiner(@NotNull KotlinTypeRefiner kotlinTypeRefiner) {
return new OverridingUtil(DEFAULT_TYPE_CONSTRUCTOR_EQUALITY, kotlinTypeRefiner);
return new OverridingUtil(DEFAULT_TYPE_CONSTRUCTOR_EQUALITY, kotlinTypeRefiner, KotlinTypePreparator.Default.INSTANCE, null);
}
@NotNull
public static OverridingUtil createWithTypePreparatorAndCustomSubtype(
@NotNull KotlinTypePreparator kotlinTypePreparator,
@NotNull Function2<KotlinType, KotlinType, Boolean> customSubtype
) {
return new OverridingUtil(DEFAULT_TYPE_CONSTRUCTOR_EQUALITY, KotlinTypeRefiner.Default.INSTANCE, kotlinTypePreparator, customSubtype);
}
@NotNull
@@ -79,18 +84,24 @@ public class OverridingUtil {
@NotNull KotlinTypeRefiner kotlinTypeRefiner,
@NotNull KotlinTypeChecker.TypeConstructorEquality equalityAxioms
) {
return new OverridingUtil(equalityAxioms, kotlinTypeRefiner);
return new OverridingUtil(equalityAxioms, kotlinTypeRefiner, KotlinTypePreparator.Default.INSTANCE, null);
}
private final KotlinTypeRefiner kotlinTypeRefiner;
private final KotlinTypePreparator kotlinTypePreparator;
private final KotlinTypeChecker.TypeConstructorEquality equalityAxioms;
private final Function2<KotlinType, KotlinType, Boolean> customSubtype;
private OverridingUtil(
@NotNull KotlinTypeChecker.TypeConstructorEquality axioms,
@NotNull KotlinTypeRefiner kotlinTypeRefiner
@NotNull KotlinTypeRefiner kotlinTypeRefiner,
@NotNull KotlinTypePreparator kotlinTypePreparator,
@Nullable Function2<KotlinType, KotlinType, Boolean> customSubtype
) {
equalityAxioms = axioms;
this.kotlinTypeRefiner = kotlinTypeRefiner;
this.kotlinTypePreparator = kotlinTypePreparator;
this.customSubtype = customSubtype;
}
/**
@@ -395,8 +406,9 @@ public class OverridingUtil {
"Should be the same number of type parameters: " + firstParameters + " vs " + secondParameters;
if (firstParameters.isEmpty()) {
return new OverridingUtilTypeSystemContext(null, equalityAxioms, kotlinTypeRefiner)
.newTypeCheckerState(true, true);
return new OverridingUtilTypeSystemContext(
null, equalityAxioms, kotlinTypeRefiner, kotlinTypePreparator, customSubtype
).newTypeCheckerState(true, true);
}
Map<TypeConstructor, TypeConstructor> matchingTypeConstructors = new HashMap<TypeConstructor, TypeConstructor>();
@@ -404,8 +416,9 @@ public class OverridingUtil {
matchingTypeConstructors.put(firstParameters.get(i).getTypeConstructor(), secondParameters.get(i).getTypeConstructor());
}
return new OverridingUtilTypeSystemContext(matchingTypeConstructors, equalityAxioms, kotlinTypeRefiner)
.newTypeCheckerState(true, true);
return new OverridingUtilTypeSystemContext(
matchingTypeConstructors, equalityAxioms, kotlinTypeRefiner, kotlinTypePreparator, customSubtype
).newTypeCheckerState(true, true);
}
@Nullable
@@ -5,18 +5,19 @@
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeCheckerState
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContext
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner
import org.jetbrains.kotlin.types.checker.createClassicTypeCheckerState
import org.jetbrains.kotlin.types.checker.*
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
class OverridingUtilTypeSystemContext(
val matchingTypeConstructors: Map<TypeConstructor, TypeConstructor>?,
private val equalityAxioms: KotlinTypeChecker.TypeConstructorEquality,
val kotlinTypeRefiner: KotlinTypeRefiner
private val kotlinTypeRefiner: KotlinTypeRefiner,
private val kotlinTypePreparator: KotlinTypePreparator,
private val customSubtype: ((KotlinType, KotlinType) -> Boolean)? = null,
) : ClassicTypeSystemContext {
override fun areEqualTypeConstructors(c1: TypeConstructorMarker, c2: TypeConstructorMarker): Boolean {
@@ -29,12 +30,27 @@ class OverridingUtilTypeSystemContext(
errorTypesEqualToAnything: Boolean,
stubTypesEqualToAnything: Boolean
): TypeCheckerState {
return createClassicTypeCheckerState(
errorTypesEqualToAnything,
stubTypesEqualToAnything,
if (customSubtype == null) {
return createClassicTypeCheckerState(
errorTypesEqualToAnything,
stubTypesEqualToAnything,
typeSystemContext = this,
kotlinTypeRefiner = kotlinTypeRefiner,
kotlinTypePreparator = kotlinTypePreparator,
)
}
return object : TypeCheckerState(
errorTypesEqualToAnything, stubTypesEqualToAnything, allowedTypeVariable = true,
typeSystemContext = this,
kotlinTypeRefiner = kotlinTypeRefiner
)
kotlinTypePreparator, kotlinTypeRefiner,
) {
override fun customIsSubtypeOf(subType: KotlinTypeMarker, superType: KotlinTypeMarker): Boolean {
require(subType is KotlinType)
require(superType is KotlinType)
return customSubtype.invoke(subType, superType)
}
}
}
private fun areEqualTypeConstructorsByAxioms(a: TypeConstructor, b: TypeConstructor): Boolean {
@@ -150,6 +150,9 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
return this as? DefinitelyNotNullType
}
@OptIn(ObsoleteTypeKind::class)
override fun KotlinTypeMarker.isNotNullTypeVariable(): Boolean = this is NotNullTypeVariable
override fun SimpleTypeMarker.isMarkedNullable(): Boolean {
require(this is SimpleType, this::errorMessage)
return this.isMarkedNullable