[NI] Correctly compute definitely not null type for intersection one
{ T : Any? & Foo & Bar? }!! -> { T!! & Foo & Bar }
Also, fix bug with loosing non-representative number type.
For example, for type { Byte & SomeType } we lost type `Byte` because
`getDefaultPrimitiveNumberType` returns null for it
Fixes #KT-28334 for NI
This commit is contained in:
+6
-2
@@ -128,8 +128,12 @@ class ResultTypeResolver(
|
|||||||
newSupertypes.add(supertype)
|
newSupertypes.add(supertype)
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeUtils.getDefaultPrimitiveNumberType(numberSupertypes)?.let {
|
|
||||||
newSupertypes.add(it.unwrap())
|
val representativeNumberType = TypeUtils.getDefaultPrimitiveNumberType(numberSupertypes)
|
||||||
|
if (representativeNumberType != null) {
|
||||||
|
newSupertypes.add(representativeNumberType.unwrap())
|
||||||
|
} else {
|
||||||
|
newSupertypes.addAll(numberSupertypes.map { it.unwrap() })
|
||||||
}
|
}
|
||||||
|
|
||||||
intersectTypes(newSupertypes).makeNullableAsSpecified(commonSuperType.isMarkedNullable)
|
intersectTypes(newSupertypes).makeNullableAsSpecified(commonSuperType.isMarkedNullable)
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
// !LANGUAGE: +NewInference
|
||||||
|
|
||||||
|
fun simpleTypeAndNumberType(b: Comparable<*>?) {
|
||||||
|
if (b is Byte?) {
|
||||||
|
<!DEBUG_INFO_SMARTCAST!>b<!>!!.dec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> typeParmeterAndNumberType(b: T?) {
|
||||||
|
if (b is Byte?) {
|
||||||
|
b!!.dec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun anyAndNumberType(b: Any?) {
|
||||||
|
if (b is Byte?) {
|
||||||
|
<!DEBUG_INFO_SMARTCAST!>b<!>!!.dec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun comparableAndNumberType(b: Comparable<Byte>?) {
|
||||||
|
if (b is Byte?) {
|
||||||
|
<!DEBUG_INFO_SMARTCAST!>b<!>!!.dec()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object SeparateTypes {
|
||||||
|
interface A
|
||||||
|
interface B {
|
||||||
|
fun foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun separate(a: A?) {
|
||||||
|
if (a is B?) {
|
||||||
|
a!!.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun anyAndNumberType(/*0*/ b: kotlin.Any?): kotlin.Unit
|
||||||
|
public fun comparableAndNumberType(/*0*/ b: kotlin.Comparable<kotlin.Byte>?): kotlin.Unit
|
||||||
|
public fun simpleTypeAndNumberType(/*0*/ b: kotlin.Comparable<*>?): kotlin.Unit
|
||||||
|
public fun </*0*/ T> typeParmeterAndNumberType(/*0*/ b: T?): kotlin.Unit
|
||||||
|
|
||||||
|
public object SeparateTypes {
|
||||||
|
private constructor SeparateTypes()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final fun separate(/*0*/ a: SeparateTypes.A?): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
public interface A {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface B {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open fun foo(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8420,6 +8420,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/generics/nullability/functionalBound.kt");
|
runTest("compiler/testData/diagnostics/tests/generics/nullability/functionalBound.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inferNotNullTypeFromIntersectionOfNullableTypes.kt")
|
||||||
|
public void testInferNotNullTypeFromIntersectionOfNullableTypes() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/generics/nullability/inferNotNullTypeFromIntersectionOfNullableTypes.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nullToGeneric.kt")
|
@TestMetadata("nullToGeneric.kt")
|
||||||
public void testNullToGeneric() throws Exception {
|
public void testNullToGeneric() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/generics/nullability/nullToGeneric.kt");
|
runTest("compiler/testData/diagnostics/tests/generics/nullability/nullToGeneric.kt");
|
||||||
|
|||||||
Generated
+5
@@ -8420,6 +8420,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/generics/nullability/functionalBound.kt");
|
runTest("compiler/testData/diagnostics/tests/generics/nullability/functionalBound.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inferNotNullTypeFromIntersectionOfNullableTypes.kt")
|
||||||
|
public void testInferNotNullTypeFromIntersectionOfNullableTypes() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/generics/nullability/inferNotNullTypeFromIntersectionOfNullableTypes.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nullToGeneric.kt")
|
@TestMetadata("nullToGeneric.kt")
|
||||||
public void testNullToGeneric() throws Exception {
|
public void testNullToGeneric() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/generics/nullability/nullToGeneric.kt");
|
runTest("compiler/testData/diagnostics/tests/generics/nullability/nullToGeneric.kt");
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.TypeIntersectionScope
|
import org.jetbrains.kotlin.resolve.scopes.TypeIntersectionScope
|
||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class IntersectionTypeConstructor(typesToIntersect: Collection<KotlinType>) : TypeConstructor {
|
class IntersectionTypeConstructor(typesToIntersect: Collection<KotlinType>) : TypeConstructor {
|
||||||
@@ -63,3 +62,22 @@ class IntersectionTypeConstructor(typesToIntersect: Collection<KotlinType>) : Ty
|
|||||||
|
|
||||||
override fun hashCode(): Int = hashCode
|
override fun hashCode(): Int = hashCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun IntersectionTypeConstructor.transformComponents(
|
||||||
|
predicate: (KotlinType) -> Boolean = { true },
|
||||||
|
transform: (KotlinType) -> KotlinType
|
||||||
|
): IntersectionTypeConstructor? {
|
||||||
|
var changed = false
|
||||||
|
val newSupertypes = supertypes.map {
|
||||||
|
if (predicate(it)) {
|
||||||
|
changed = true
|
||||||
|
transform(it)
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed) return null
|
||||||
|
|
||||||
|
return IntersectionTypeConstructor(newSupertypes)
|
||||||
|
}
|
||||||
@@ -111,7 +111,28 @@ val KotlinType.isDefinitelyNotNullType: Boolean
|
|||||||
get() = unwrap() is DefinitelyNotNullType
|
get() = unwrap() is DefinitelyNotNullType
|
||||||
|
|
||||||
fun SimpleType.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleType =
|
fun SimpleType.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleType =
|
||||||
DefinitelyNotNullType.makeDefinitelyNotNull(this) ?: makeNullableAsSpecified(false)
|
DefinitelyNotNullType.makeDefinitelyNotNull(this)
|
||||||
|
?: makeIntersectionTypeDefinitelyNotNullOrNotNull()
|
||||||
|
?: makeNullableAsSpecified(false)
|
||||||
|
|
||||||
fun UnwrappedType.makeDefinitelyNotNullOrNotNull(): UnwrappedType =
|
fun UnwrappedType.makeDefinitelyNotNullOrNotNull(): UnwrappedType =
|
||||||
DefinitelyNotNullType.makeDefinitelyNotNull(this) ?: makeNullableAsSpecified(false)
|
DefinitelyNotNullType.makeDefinitelyNotNull(this)
|
||||||
|
?: makeIntersectionTypeDefinitelyNotNullOrNotNull()
|
||||||
|
?: makeNullableAsSpecified(false)
|
||||||
|
|
||||||
|
private fun KotlinType.makeIntersectionTypeDefinitelyNotNullOrNotNull(): SimpleType? {
|
||||||
|
val typeConstructor = constructor as? IntersectionTypeConstructor ?: return null
|
||||||
|
val definitelyNotNullConstructor = typeConstructor.makeDefinitelyNotNullOrNotNull() ?: return null
|
||||||
|
|
||||||
|
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||||
|
annotations,
|
||||||
|
definitelyNotNullConstructor,
|
||||||
|
listOf(),
|
||||||
|
false,
|
||||||
|
definitelyNotNullConstructor.createScopeForKotlinType()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IntersectionTypeConstructor.makeDefinitelyNotNullOrNotNull(): IntersectionTypeConstructor? {
|
||||||
|
return transformComponents({ TypeUtils.isNullableType(it) }, { it.unwrap().makeDefinitelyNotNullOrNotNull() })
|
||||||
|
}
|
||||||
|
|||||||
@@ -153,8 +153,7 @@ object NewKotlinTypeChecker : KotlinTypeChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is IntersectionTypeConstructor -> if (type.isMarkedNullable) {
|
is IntersectionTypeConstructor -> if (type.isMarkedNullable) {
|
||||||
val newSuperTypes = constructor.supertypes.map { it.makeNullable() }
|
val newConstructor = constructor.transformComponents(transform = { it.makeNullable() }) ?: constructor
|
||||||
val newConstructor = IntersectionTypeConstructor(newSuperTypes)
|
|
||||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(type.annotations, newConstructor, listOf(), false, newConstructor.createScopeForKotlinType())
|
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(type.annotations, newConstructor, listOf(), false, newConstructor.createScopeForKotlinType())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user