[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 {
|
override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker {
|
||||||
require(this is ConeKotlinType)
|
require(this is ConeKotlinType)
|
||||||
return makeDefinitelyNotNullOrNotNull()
|
return makeConeTypeDefinitelyNotNullOrNotNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker {
|
override fun SimpleTypeMarker.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleTypeMarker {
|
||||||
require(this is ConeKotlinType)
|
require(this is ConeKotlinType)
|
||||||
return makeDefinitelyNotNullOrNotNull() as SimpleTypeMarker
|
return makeConeTypeDefinitelyNotNullOrNotNull() 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createCapturedType(
|
override fun createCapturedType(
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ abstract class AbstractConeSubstitutor : ConeSubstitutor() {
|
|||||||
|
|
||||||
override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? {
|
override fun substituteOrNull(type: ConeKotlinType): ConeKotlinType? {
|
||||||
val newType = substituteType(type)
|
val newType = substituteType(type)
|
||||||
|
if (newType != null && type is ConeDefinitelyNotNullType) {
|
||||||
|
return newType.makeConeTypeDefinitelyNotNullOrNotNull()
|
||||||
|
}
|
||||||
return (newType ?: type.substituteRecursive())
|
return (newType ?: type.substituteRecursive())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir.types
|
package org.jetbrains.kotlin.fir.types
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ConeInferenceContext
|
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
|
||||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator.commonSuperType
|
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator.commonSuperType
|
||||||
import org.jetbrains.kotlin.types.AbstractNullabilityChecker
|
import org.jetbrains.kotlin.types.AbstractNullabilityChecker
|
||||||
@@ -42,7 +43,8 @@ fun ConeInferenceContext.intersectTypesOrNull(types: List<ConeKotlinType>): Cone
|
|||||||
fun ConeDefinitelyNotNullType.Companion.create(original: ConeKotlinType): ConeDefinitelyNotNullType? {
|
fun ConeDefinitelyNotNullType.Companion.create(original: ConeKotlinType): ConeDefinitelyNotNullType? {
|
||||||
return when {
|
return when {
|
||||||
original is ConeDefinitelyNotNullType -> original
|
original is ConeDefinitelyNotNullType -> original
|
||||||
makesSenseToBeDefinitelyNotNull(original) -> ConeDefinitelyNotNullType(original.lowerBoundIfFlexible())
|
makesSenseToBeDefinitelyNotNull(original) ->
|
||||||
|
ConeDefinitelyNotNullType(original.lowerBoundIfFlexible())
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,7 +52,30 @@ fun ConeDefinitelyNotNullType.Companion.create(original: ConeKotlinType): ConeDe
|
|||||||
fun makesSenseToBeDefinitelyNotNull(type: ConeKotlinType): Boolean =
|
fun makesSenseToBeDefinitelyNotNull(type: ConeKotlinType): Boolean =
|
||||||
type.canHaveUndefinedNullability() // TODO: also check nullability
|
type.canHaveUndefinedNullability() // TODO: also check nullability
|
||||||
|
|
||||||
fun ConeKotlinType.canHaveUndefinedNullability(): Boolean =
|
fun ConeKotlinType.canHaveUndefinedNullability(): Boolean {
|
||||||
this is ConeTypeVariableType ||
|
return when (this) {
|
||||||
this is ConeTypeParameterType ||
|
is ConeTypeVariableType,
|
||||||
this is ConeCapturedType
|
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|)
|
R|/Fix.Fix|(R|<local>/element|)
|
||||||
}
|
}
|
||||||
public final fun <DE : R|DerivedElement|> createGeneric(d: R|Diagnostic<DE>|): R|kotlin/Unit| {
|
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|)
|
R|/Fix.Fix|(R|<local>/element|)
|
||||||
}
|
}
|
||||||
private final val DERIVED_FACTORY: R|DiagnosticFactory0<DerivedElement>| = R|/DiagnosticFactory0.DiagnosticFactory0|<R|DerivedElement|>()
|
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 <F : Any> foo(computable: Out<F?>)
|
||||||
|
|
||||||
fun <T : Any> bar(computable: Out<T?>) {
|
fun <T : Any> bar(computable: Out<T?>) {
|
||||||
// Should be resolved but fails during inference
|
foo(id(computable))
|
||||||
// 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))
|
|
||||||
}
|
}
|
||||||
|
|||||||
+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 <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| {
|
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