From 42d387925dce91a74dec0abaec44517788854a0d Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Tue, 27 Apr 2021 13:16:06 +0300 Subject: [PATCH] FIR: Refine makesSenseToBeDefinitelyNotNull Make it work just the same as the analogue from FE 1.0 This change is necessary since many tests start failing after we began reporting diagnostics after call completion --- .../deserialization/FirTypeDeserializer.kt | 3 +- .../fir/backend/jvm/FirJvmTypeMapper.kt | 5 +- .../kotlin/fir/backend/Fir2IrTypeConverter.kt | 7 +-- .../generators/CallAndReferenceGenerator.kt | 5 +- .../fir/java/enhancement/javaTypeUtils.kt | 6 +- .../kotlin/fir/resolve/ResolveUtils.kt | 11 +--- .../kotlin/fir/resolve/TypeExpansionUtils.kt | 6 +- .../kotlin/fir/resolve/calls/Arguments.kt | 2 +- .../fir/resolve/substitution/Substitutors.kt | 25 +++----- .../transformers/FirSyntheticCallGenerator.kt | 3 +- .../FirDeclarationsResolveTransformer.kt | 4 +- .../kotlin/fir/types/ConeInferenceContext.kt | 8 +-- .../kotlin/fir/types/ConeTypeContext.kt | 2 +- .../jetbrains/kotlin/fir/types/TypeUtils.kt | 62 ++++++++++++------- .../kotlin/fir/types/FirTypeUtils.kt | 34 ++++++++-- .../kotlin/idea/asJava/firLightUtils.kt | 8 +-- 16 files changed, 111 insertions(+), 80 deletions(-) diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt index 6de7f71c86d..f125aee59ad 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/FirTypeDeserializer.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol +import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl @@ -137,7 +138,7 @@ class FirTypeDeserializer( if (constructor is ConeTypeParameterLookupTag) { return ConeTypeParameterTypeImpl(constructor, isNullable = proto.nullable).let { if (Flags.DEFINITELY_NOT_NULL_TYPE.get(proto.flags)) - ConeDefinitelyNotNullType.create(it) + ConeDefinitelyNotNullType.create(it, moduleData.session.typeContext) else it } diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt index 64df548e312..7aa400a6b94 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt @@ -233,7 +233,10 @@ class ConeTypeSystemCommonBackendContextForTypeMapping( require(it is ConeKotlinType) } @Suppress("UNCHECKED_CAST") - return defaultType().withArguments((arguments as List).toTypedArray()) + return defaultType().withArguments( + (arguments as List).toTypedArray(), + session.typeContext, + ) } override fun TypeParameterMarker.representativeUpperBound(): ConeKotlinType { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt index 48ad011a667..2a2381ed5fb 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrTypeConverter.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.typeContext -import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.* import org.jetbrains.kotlin.ir.expressions.IrConstructorCall @@ -24,6 +23,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.types.TypeApproximatorConfiguration import org.jetbrains.kotlin.types.Variance @@ -230,10 +230,7 @@ class Fir2IrTypeConverter( private fun approximateType(type: ConeKotlinType): ConeKotlinType { if (type is ConeClassLikeType && type.typeArguments.isEmpty()) return type - val substitutor = object : AbstractConeSubstitutor() { - override val typeInferenceContext: ConeInferenceContext - get() = session.inferenceComponents.ctx - + val substitutor = object : AbstractConeSubstitutor(session.typeContext) { override fun substituteType(type: ConeKotlinType): ConeKotlinType? { return if (type is ConeIntersectionType) { type.alternativeType?.let { substituteOrSelf(it) } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt index e7ab3fc8b57..d46324ae97b 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/CallAndReferenceGenerator.kt @@ -664,10 +664,7 @@ class CallAndReferenceGenerator( return IrTypeOperatorCallImpl(this.startOffset, this.endOffset, samType, IrTypeOperator.SAM_CONVERSION, samType, this) } - private val starProjectionApproximator = object : AbstractConeSubstitutor() { - override val typeInferenceContext: ConeInferenceContext - get() = session.inferenceComponents.ctx - + private val starProjectionApproximator = object : AbstractConeSubstitutor(session.typeContext) { override fun substituteType(type: ConeKotlinType): ConeKotlinType? { if (type !is ConeClassLikeType || type.typeArguments.none { it == ConeStarProjection }) return null val fir = type.lookupTag.toSymbol(session)?.fir as? FirTypeParameterRefsOwner ?: return null diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt index 1c4daf33006..f258da85e48 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/enhancement/javaTypeUtils.kt @@ -128,7 +128,11 @@ private fun coneFlexibleOrSimpleType( type is ConeTypeParameterType || type.isNullable } ) { - return ConeDefinitelyNotNullType.create(lowerBound) ?: lowerBound + return ConeDefinitelyNotNullType.create( + lowerBound, + session.typeContext, + useCorrectedNullabilityForFlexibleTypeParameters = true + ) ?: lowerBound } } return lowerBound diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index e510e28564f..29420ee9e93 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -34,12 +34,8 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl -import org.jetbrains.kotlin.name.CallableId -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget import org.jetbrains.kotlin.name.* +import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget fun List.toTypeProjections(): Array = asReversed().flatMap { it.typeArgumentList.typeArguments.map { typeArgument -> typeArgument.toConeTypeProjection() } }.toTypedArray() @@ -326,9 +322,8 @@ fun FirCheckedSafeCallSubject.propagateTypeFromOriginalReceiver(nullableReceiver val expandedReceiverType = if (receiverType is ConeClassLikeType) receiverType.fullyExpandedType(session) else receiverType - val resolvedTypeRef = typeRef.resolvedTypeFromPrototype( - expandedReceiverType.makeConeTypeDefinitelyNotNullOrNotNull(session.inferenceComponents.ctx) - ) + val resolvedTypeRef = + typeRef.resolvedTypeFromPrototype(expandedReceiverType.makeConeTypeDefinitelyNotNullOrNotNull(session.typeContext)) replaceTypeRef(resolvedTypeRef) session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, source, null) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt index 05afa86d6c2..59cc552d97f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/TypeExpansionUtils.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.resolve import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.FirTypeAlias import org.jetbrains.kotlin.fir.declarations.expandedConeType -import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol import org.jetbrains.kotlin.fir.typeContext @@ -85,10 +84,7 @@ private fun mapTypeAliasArguments( } val typeAliasMap = typeAlias.typeParameters.map { it.symbol }.zip(abbreviatedType.typeArguments).toMap() - val substitutor = object : AbstractConeSubstitutor() { - override val typeInferenceContext: ConeInferenceContext - get() = useSiteSession.inferenceComponents.ctx - + val substitutor = object : AbstractConeSubstitutor(useSiteSession.typeContext) { override fun substituteType(type: ConeKotlinType): ConeKotlinType? { return null } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index 75593fd2a37..b7585eaa1ad 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -600,7 +600,7 @@ internal fun captureFromTypeParameterUpperBoundIfNeeded( val capturedType = context.captureFromExpression(chosenSupertype) as ConeKotlinType? ?: return argumentType return if (argumentType is ConeDefinitelyNotNullType) { - ConeDefinitelyNotNullType.create(capturedType) ?: capturedType + ConeDefinitelyNotNullType.create(capturedType, session.typeContext) ?: capturedType } else { capturedType } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt index 8c39c5fea37..ba03eca5cbc 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/substitution/Substitutors.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.substitution import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol +import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.types.TypeApproximatorConfiguration @@ -15,9 +16,7 @@ import org.jetbrains.kotlin.types.model.TypeConstructorMarker import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker import org.jetbrains.kotlin.types.model.typeConstructor -abstract class AbstractConeSubstitutor : ConeSubstitutor() { - abstract val typeInferenceContext: ConeInferenceContext - +abstract class AbstractConeSubstitutor(private val typeContext: ConeTypeContext) : ConeSubstitutor() { private fun wrapProjection(old: ConeTypeProjection, newType: ConeKotlinType): ConeTypeProjection { return when (old) { is ConeStarProjection -> old @@ -37,8 +36,8 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() { fun ConeKotlinType?.updateNullabilityIfNeeded(originalType: ConeKotlinType): ConeKotlinType? { return when { - originalType is ConeDefinitelyNotNullType -> this?.withNullability(ConeNullability.NOT_NULL, typeInferenceContext) - originalType.isMarkedNullable -> this?.withNullability(ConeNullability.NULLABLE, typeInferenceContext) + originalType is ConeDefinitelyNotNullType -> this?.withNullability(ConeNullability.NOT_NULL, typeContext) + originalType.isMarkedNullable -> this?.withNullability(ConeNullability.NULLABLE, typeContext) else -> this } } @@ -46,7 +45,7 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() { override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? { val newType = substituteType(type) if (newType != null && type is ConeDefinitelyNotNullType) { - return newType.makeConeTypeDefinitelyNotNullOrNotNull(typeInferenceContext) + return newType.makeConeTypeDefinitelyNotNullOrNotNull(typeContext) } return (newType ?: type.substituteRecursive()) } @@ -84,8 +83,8 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() { } private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeKotlinType? { - val substituted = substituteOrNull(original)?.withNullability(ConeNullability.NOT_NULL, typeInferenceContext) ?: return null - return ConeDefinitelyNotNullType.create(substituted) ?: substituted + val substituted = substituteOrNull(original)?.withNullability(ConeNullability.NOT_NULL, typeContext) ?: return null + return ConeDefinitelyNotNullType.create(substituted, typeContext) ?: substituted } private fun ConeFlexibleType.substituteBounds(): ConeFlexibleType? { @@ -158,10 +157,7 @@ fun ConeSubstitutor.chain(other: ConeSubstitutor): ConeSubstitutor { data class ConeSubstitutorByMap( val substitution: Map, val useSiteSession: FirSession -) : AbstractConeSubstitutor() { - override val typeInferenceContext: ConeInferenceContext - get() = useSiteSession.inferenceComponents.ctx - +) : AbstractConeSubstitutor(useSiteSession.typeContext) { override fun substituteType(type: ConeKotlinType): ConeKotlinType? { if (type !is ConeTypeParameterType) return null val result = substitution[type.lookupTag.symbol].updateNullabilityIfNeeded(type) ?: return null @@ -176,10 +172,7 @@ data class ConeSubstitutorByMap( fun createTypeSubstitutorByTypeConstructor(map: Map, context: ConeTypeContext): ConeSubstitutor { if (map.isEmpty()) return ConeSubstitutor.Empty - return object : AbstractConeSubstitutor(), TypeSubstitutorMarker { - override val typeInferenceContext: ConeInferenceContext - get() = context.session.inferenceComponents.ctx - + return object : AbstractConeSubstitutor(context), TypeSubstitutorMarker { override fun substituteType(type: ConeKotlinType): ConeKotlinType? { if (type !is ConeLookupTagBasedType && type !is ConeStubType) return null val new = map[type.typeConstructor(context)] ?: return null diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt index 989f468d177..80f5bc94a6b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirSyntheticCallGenerator.kt @@ -298,7 +298,8 @@ class FirSyntheticCallGenerator( val returnType = rightArgumentType.resolvedTypeFromPrototype( rightArgumentType.type.withAttributes( - ConeAttributes.create(listOf(CompilerConeAttributes.Exact)) + ConeAttributes.create(listOf(CompilerConeAttributes.Exact)), + session.typeContext, ) ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index edea9b82635..52cf5e9d2b6 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -517,6 +517,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor returnExpression.resultType.approximatedIfNeededOrSelf( inferenceComponents.approximator, simpleFunction?.visibilityForApproximation(), + transformer.session.typeContext, simpleFunction?.isInline == true ) ) @@ -843,7 +844,8 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor withExpectedType( expectedType.approximatedIfNeededOrSelf( inferenceComponents.approximator, - variable.visibilityForApproximation() + variable.visibilityForApproximation(), + inferenceComponents.session.typeContext, ) ) ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt index 1e1d532a482..a81566b2e94 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeInferenceContext.kt @@ -17,9 +17,9 @@ import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag -import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl +import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.model.* import org.jetbrains.kotlin.utils.DFS @@ -258,12 +258,12 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo override fun KotlinTypeMarker.removeAnnotations(): KotlinTypeMarker { require(this is ConeKotlinType) - return withAttributes(ConeAttributes.Empty) + return withAttributes(ConeAttributes.Empty, this@ConeInferenceContext) } override fun SimpleTypeMarker.replaceArguments(newArguments: List): SimpleTypeMarker { require(this is ConeKotlinType) - return this.withArguments(newArguments.cast>().toTypedArray()) + return this.withArguments(newArguments.cast>().toTypedArray(), this@ConeInferenceContext) } override fun KotlinTypeMarker.hasExactAnnotation(): Boolean { @@ -364,7 +364,7 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo override fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker { require(this is ConeKotlinType) - return withAttributes(attributes.remove(CompilerConeAttributes.Exact)) + return withAttributes(attributes.remove(CompilerConeAttributes.Exact), this@ConeInferenceContext) } override fun TypeConstructorMarker.toErrorType(): SimpleTypeMarker { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index 9a954c43779..5b2b6676fbe 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -415,7 +415,7 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty } private fun FirTypeParameterSymbol.allBoundsAreNullable(): Boolean { - return fir.bounds.all { it.coneType.isMarkedNullable } + return fir.bounds.all { it.coneType.isNullableType() } } private fun TypeConstructorMarker.toFirRegularClass(): FirRegularClass? { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt index fc5c1fc9fa5..adcbdd8926e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/TypeUtils.kt @@ -47,23 +47,32 @@ fun ConeInferenceContext.intersectTypesOrNull(types: List): Cone fun TypeCheckerProviderContext.equalTypes(a: ConeKotlinType, b: ConeKotlinType): Boolean = AbstractTypeChecker.equalTypes(this, a, b) -fun ConeDefinitelyNotNullType.Companion.create(original: ConeKotlinType): ConeDefinitelyNotNullType? { +fun ConeDefinitelyNotNullType.Companion.create( + original: ConeKotlinType, + typeContext: ConeTypeContext, + useCorrectedNullabilityForFlexibleTypeParameters: Boolean = false, +): ConeDefinitelyNotNullType? { return when { original is ConeDefinitelyNotNullType -> original - makesSenseToBeDefinitelyNotNull(original) -> - ConeDefinitelyNotNullType(original.lowerBoundIfFlexible()) + typeContext + .newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = false) + .makesSenseToBeDefinitelyNotNull(original, useCorrectedNullabilityForFlexibleTypeParameters) -> + + ConeDefinitelyNotNullType( + original.lowerBoundIfFlexible() + ) else -> null } } -fun ConeKotlinType.makeConeTypeDefinitelyNotNullOrNotNull(typeContext: ConeInferenceContext): ConeKotlinType { +fun ConeKotlinType.makeConeTypeDefinitelyNotNullOrNotNull(typeContext: ConeTypeContext): ConeKotlinType { if (this is ConeIntersectionType) { return ConeIntersectionType(intersectedTypes.map { it.makeConeTypeDefinitelyNotNullOrNotNull(typeContext) }) } - return ConeDefinitelyNotNullType.create(this) ?: this.withNullability(ConeNullability.NOT_NULL, typeContext) + return ConeDefinitelyNotNullType.create(this, typeContext) ?: this.withNullability(ConeNullability.NOT_NULL, typeContext) } -fun T.withArguments(arguments: Array): T { +fun T.withArguments(arguments: Array, typeSystemContext: ConeTypeContext): T { if (this.typeArguments === arguments) { return this } @@ -72,12 +81,15 @@ fun T.withArguments(arguments: Array this is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, arguments, nullability.isNullable) as T - is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType.create(original.withArguments(arguments))!! as T + is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType.create( + original.withArguments(arguments, typeSystemContext), + typeSystemContext + )!! as T else -> error("Not supported: $this: ${this.render()}") } } -fun T.withAttributes(attributes: ConeAttributes): T { +fun T.withAttributes(attributes: ConeAttributes, typeSystemContext: ConeTypeContext): T { if (this.attributes == attributes) { return this } @@ -86,16 +98,22 @@ fun T.withAttributes(attributes: ConeAttributes): T { return when (this) { is ConeClassErrorType -> this is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable, attributes) - is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType.create(original.withAttributes(attributes))!! + is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType.create( + original.withAttributes(attributes, typeSystemContext), + typeSystemContext + )!! is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable, attributes) - is ConeFlexibleType -> ConeFlexibleType(lowerBound.withAttributes(attributes), upperBound.withAttributes(attributes)) + is ConeFlexibleType -> ConeFlexibleType( + lowerBound.withAttributes(attributes, typeSystemContext), + upperBound.withAttributes(attributes, typeSystemContext) + ) else -> error("Not supported: $this: ${this.render()}") } as T } fun T.withNullability( nullability: ConeNullability, - typeContext: ConeInferenceContext, + typeContext: ConeTypeContext, attributes: ConeAttributes = this.attributes, ): T { if (this.nullability == nullability && this.attributes == attributes) { @@ -140,7 +158,7 @@ fun T.withNullability( } fun coneFlexibleOrSimpleType( - typeContext: ConeInferenceContext, + typeContext: ConeTypeContext, lowerBound: ConeKotlinType, upperBound: ConeKotlinType, ): ConeKotlinType { @@ -197,7 +215,7 @@ fun FirTypeRef.isUnsafeVarianceType(session: FirSession): Boolean { fun FirTypeRef.hasEnhancedNullability(): Boolean = coneTypeSafe()?.hasEnhancedNullability == true -fun FirTypeRef.withoutEnhancedNullability(): FirTypeRef { +fun FirTypeRef.withoutEnhancedNullability(typeSystemContext: ConeTypeContext): FirTypeRef { require(this is FirResolvedTypeRef) if (!hasEnhancedNullability()) return this return buildResolvedTypeRef { @@ -205,7 +223,8 @@ fun FirTypeRef.withoutEnhancedNullability(): FirTypeRef { type = this@withoutEnhancedNullability.type.withAttributes( ConeAttributes.create( this@withoutEnhancedNullability.type.attributes.filter { it != CompilerConeAttributes.EnhancedNullability } - ) + ), + typeSystemContext, ) annotations += this@withoutEnhancedNullability.annotations } @@ -263,13 +282,14 @@ fun FirTypeRef.approximated( fun FirTypeRef.approximatedIfNeededOrSelf( approximator: ConeTypeApproximator, containingCallableVisibility: Visibility?, - isInlineFunction: Boolean = false + typeSystemContext: ConeTypeContext, + isInlineFunction: Boolean = false, ): FirTypeRef { val approximated = if (containingCallableVisibility == Visibilities.Public || containingCallableVisibility == Visibilities.Protected) approximatedForPublicPosition(approximator) else this - return approximated.hideLocalTypeIfNeeded(containingCallableVisibility, isInlineFunction).withoutEnhancedNullability() + return approximated.hideLocalTypeIfNeeded(containingCallableVisibility, isInlineFunction).withoutEnhancedNullability(typeSystemContext) } fun FirTypeRef.approximatedForPublicPosition(approximator: ConeTypeApproximator): FirTypeRef = @@ -334,11 +354,11 @@ fun ConeTypeContext.captureFromArgumentsInternal(type: ConeKotlinType, status: C val capturedArguments = captureArguments(type, status) ?: return null return if (type is ConeFlexibleType) { ConeFlexibleType( - type.lowerBound.withArguments(capturedArguments), - type.upperBound.withArguments(capturedArguments), + type.lowerBound.withArguments(capturedArguments, this), + type.upperBound.withArguments(capturedArguments, this), ) } else { - type.withArguments(capturedArguments) + type.withArguments(capturedArguments, this) } } @@ -418,12 +438,12 @@ fun ConeTypeContext.captureFromExpressionInternal(type: ConeKotlinType): ConeKot typeToReplace.intersectedTypes.map { componentType -> val capturedArguments = findCorrespondingCapturedArgumentsForType(componentType) ?: return@map componentType - componentType.withArguments(capturedArguments) + componentType.withArguments(capturedArguments, this) } } else { val capturedArguments = findCorrespondingCapturedArgumentsForType(typeToReplace) ?: return listOf(typeToReplace) - listOf(typeToReplace.withArguments(capturedArguments)) + listOf(typeToReplace.withArguments(capturedArguments, this)) } } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt index 083e7e66842..fa9fc5fd62c 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/types/FirTypeUtils.kt @@ -10,9 +10,11 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall import org.jetbrains.kotlin.fir.expressions.FirConstExpression import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.render -import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.StandardClassIds +import org.jetbrains.kotlin.types.AbstractNullabilityChecker +import org.jetbrains.kotlin.types.AbstractTypeCheckerContext import org.jetbrains.kotlin.types.ConstantValueKind import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @@ -137,15 +139,37 @@ fun FirTypeProjection.toConeTypeProjection(): ConeTypeProjection = else -> error("!") } -fun makesSenseToBeDefinitelyNotNull(type: ConeKotlinType): Boolean = - type.canHaveUndefinedNullability() // TODO: also check nullability +fun AbstractTypeCheckerContext.makesSenseToBeDefinitelyNotNull( + type: ConeKotlinType, + useCorrectedNullabilityForFlexibleTypeParameters: Boolean +): Boolean { + if (!type.canHaveUndefinedNullability()) return false + + // Replacing `useCorrectedNullabilityForFlexibleTypeParameters` with true for all call-sites seems to be correct + // But it seems that it should be a new feature: KT-28785 would be automatically fixed then + // (see the tests org.jetbrains.kotlin.spec.checkers.DiagnosticsTestSpecGenerated.NotLinked.Dfa.Pos.test12/13) + // So it should be a language feature, but it's hard correctly identify language version settings for all call sites + // Thus, we have non-trivial value at org.jetbrains.kotlin.load.java.typeEnhancement.JavaTypeEnhancement.notNullTypeParameter + // that run under related language-feature only + if (useCorrectedNullabilityForFlexibleTypeParameters && type is ConeTypeParameterType) { + // Effectively checks if the type is flexible or has nullable bound + return with(typeSystemContext) { + type.isNullableType() + } + } + + // Actually, this code should work for type parameters as well, but it breaks some cases + // See KT-40114 + + return !AbstractNullabilityChecker.isSubtypeOfAny(this, type) +} fun ConeKotlinType.canHaveUndefinedNullability(): Boolean { return when (this) { is ConeTypeVariableType, - is ConeCapturedType + is ConeCapturedType, + is ConeTypeParameterType -> true - is ConeTypeParameterType -> type.isMarkedNullable || !hasNotNullUpperBound() else -> false } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt index e76d3795d23..cc70380ff97 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/asJava/firLightUtils.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol +import org.jetbrains.kotlin.fir.typeContext import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclaration @@ -79,11 +80,8 @@ internal fun KtNamedClassOrObjectSymbol.typeForClassSymbol(psiElement: PsiElemen private class AnonymousTypesSubstitutor( private val session: FirSession, - private val state: FirModuleResolveState -) : AbstractConeSubstitutor() { - override val typeInferenceContext: ConeInferenceContext - get() = session.inferenceComponents.ctx - + private val state: FirModuleResolveState, +) : AbstractConeSubstitutor(session.typeContext) { override fun substituteType(type: ConeKotlinType): ConeKotlinType? { if (type !is ConeClassLikeType) return null