[FIR] Fix creating and substituting definitely not null types
#KT-36764 Fixed
This commit is contained in:
+2
-9
@@ -202,19 +202,12 @@ interface ConeInferenceContext : TypeSystemInferenceExtensionContext, ConeTypeCo
|
||||
|
||||
override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return makeDefinitelyNotNullOrNotNull()
|
||||
return makeConeTypeDefinitelyNotNullOrNotNull()
|
||||
}
|
||||
|
||||
override fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker {
|
||||
require(this is ConeKotlinType)
|
||||
return makeDefinitelyNotNullOrNotNull() as SimpleTypeMarker
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.makeDefinitelyNotNullOrNotNull(): ConeKotlinType {
|
||||
if (this is ConeIntersectionType) {
|
||||
return ConeIntersectionType(intersectedTypes.map { it.makeDefinitelyNotNullOrNotNull() })
|
||||
}
|
||||
return ConeDefinitelyNotNullType.create(this) ?: this.withNullability(false) as ConeKotlinType
|
||||
return makeConeTypeDefinitelyNotNullOrNotNull() as SimpleTypeMarker
|
||||
}
|
||||
|
||||
override fun createCapturedType(
|
||||
|
||||
@@ -38,6 +38,9 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() {
|
||||
|
||||
override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? {
|
||||
val newType = substituteType(type)
|
||||
if (newType != null && type is ConeDefinitelyNotNullType) {
|
||||
return newType.makeConeTypeDefinitelyNotNullOrNotNull()
|
||||
}
|
||||
return (newType ?: type.substituteRecursive())
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.types
|
||||
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ConeInferenceContext
|
||||
import org.jetbrains.kotlin.fir.resolve.withNullability
|
||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator.commonSuperType
|
||||
import org.jetbrains.kotlin.types.AbstractNullabilityChecker
|
||||
@@ -42,7 +43,8 @@ fun ConeInferenceContext.intersectTypesOrNull(types: List<ConeKotlinType>): Cone
|
||||
fun ConeDefinitelyNotNullType.Companion.create(original: ConeKotlinType): ConeDefinitelyNotNullType? {
|
||||
return when {
|
||||
original is ConeDefinitelyNotNullType -> original
|
||||
makesSenseToBeDefinitelyNotNull(original) -> ConeDefinitelyNotNullType(original.lowerBoundIfFlexible())
|
||||
makesSenseToBeDefinitelyNotNull(original) ->
|
||||
ConeDefinitelyNotNullType(original.lowerBoundIfFlexible())
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -50,7 +52,30 @@ fun ConeDefinitelyNotNullType.Companion.create(original: ConeKotlinType): ConeDe
|
||||
fun makesSenseToBeDefinitelyNotNull(type: ConeKotlinType): Boolean =
|
||||
type.canHaveUndefinedNullability() // TODO: also check nullability
|
||||
|
||||
fun ConeKotlinType.canHaveUndefinedNullability(): Boolean =
|
||||
this is ConeTypeVariableType ||
|
||||
this is ConeTypeParameterType ||
|
||||
this is ConeCapturedType
|
||||
fun ConeKotlinType.canHaveUndefinedNullability(): Boolean {
|
||||
return when (this) {
|
||||
is ConeTypeVariableType,
|
||||
is ConeCapturedType
|
||||
-> true
|
||||
is ConeTypeParameterType -> type.isMarkedNullable || !hasNotNullUpperBound()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeTypeParameterType.hasNotNullUpperBound(): Boolean {
|
||||
return lookupTag.typeParameterSymbol.fir.bounds.any {
|
||||
val boundType = it.coneTypeUnsafe<ConeKotlinType>()
|
||||
if (boundType is ConeTypeParameterType) {
|
||||
boundType.hasNotNullUpperBound()
|
||||
} else {
|
||||
boundType.nullability == ConeNullability.NOT_NULL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeKotlinType.makeConeTypeDefinitelyNotNullOrNotNull(): ConeKotlinType {
|
||||
if (this is ConeIntersectionType) {
|
||||
return ConeIntersectionType(intersectedTypes.map { it.makeConeTypeDefinitelyNotNullOrNotNull() })
|
||||
}
|
||||
return ConeDefinitelyNotNullType.create(this) ?: this.withNullability(ConeNullability.NOT_NULL)
|
||||
}
|
||||
@@ -10,7 +10,7 @@ FILE: test.kt
|
||||
R|/Fix.Fix|(R|<local>/element|)
|
||||
}
|
||||
public final fun <DE : R|DerivedElement|> createGeneric(d: R|Diagnostic<DE>|): R|kotlin/Unit| {
|
||||
lval element: R|DE!!| = R|<local>/d|.R|/Diagnostic.element|
|
||||
lval element: R|DE| = R|<local>/d|.R|/Diagnostic.element|
|
||||
R|/Fix.Fix|(R|<local>/element|)
|
||||
}
|
||||
private final val DERIVED_FACTORY: R|DiagnosticFactory0<DerivedElement>| = R|/DiagnosticFactory0.DiagnosticFactory0|<R|DerivedElement|>()
|
||||
|
||||
+1
-4
@@ -5,8 +5,5 @@ fun <X> id(x: Out<X>): Out<X> = TODO()
|
||||
fun <F : Any> foo(computable: Out<F?>)
|
||||
|
||||
fun <T : Any> bar(computable: Out<T?>) {
|
||||
// Should be resolved but fails during inference
|
||||
// Failed incorporated constraint: T? <: Any (from T? <: X!! and X!! <: F and F <: Any)
|
||||
// Hypothesis: DefinetelyNotNull(T?) = should just remove "?" while it actually gets created
|
||||
<!INAPPLICABLE_CANDIDATE!>foo<!>(id(computable))
|
||||
foo(id(computable))
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,5 +6,5 @@ FILE: definetelyNotNullForTypeParameter.kt
|
||||
}
|
||||
public final fun <F : R|kotlin/Any|> foo(computable: R|Out<F?>|): R|kotlin/Unit|
|
||||
public final fun <T : R|kotlin/Any|> bar(computable: R|Out<T?>|): R|kotlin/Unit| {
|
||||
<Inapplicable(INAPPLICABLE): [/foo]>#(R|/id|<R|T?|>(R|<local>/computable|))
|
||||
R|/foo|<R|T?!!|>(R|/id|<R|T?|>(R|<local>/computable|))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user