[FIR] Fix creating and substituting definitely not null types

#KT-36764 Fixed
This commit is contained in:
Dmitriy Novozhilov
2020-02-18 11:14:35 +03:00
parent bf11f1892d
commit c83244c8b5
6 changed files with 38 additions and 20 deletions
@@ -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|>()
@@ -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))
}
@@ -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|))
}