[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:
Mikhail Zarechenskiy
2018-11-21 16:07:00 +03:00
parent aa224558bd
commit c6712ff861
8 changed files with 124 additions and 7 deletions
@@ -128,8 +128,12 @@ class ResultTypeResolver(
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)
@@ -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()
}
}
}
@@ -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");
}
@TestMetadata("inferNotNullTypeFromIntersectionOfNullableTypes.kt")
public void testInferNotNullTypeFromIntersectionOfNullableTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/generics/nullability/inferNotNullTypeFromIntersectionOfNullableTypes.kt");
}
@TestMetadata("nullToGeneric.kt")
public void testNullToGeneric() throws Exception {
runTest("compiler/testData/diagnostics/tests/generics/nullability/nullToGeneric.kt");
@@ -8420,6 +8420,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
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")
public void testNullToGeneric() throws Exception {
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.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.TypeIntersectionScope
import java.util.*
class IntersectionTypeConstructor(typesToIntersect: Collection<KotlinType>) : TypeConstructor {
@@ -63,3 +62,22 @@ class IntersectionTypeConstructor(typesToIntersect: Collection<KotlinType>) : Ty
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
fun SimpleType.makeSimpleTypeDefinitelyNotNullOrNotNull(): SimpleType =
DefinitelyNotNullType.makeDefinitelyNotNull(this) ?: makeNullableAsSpecified(false)
DefinitelyNotNullType.makeDefinitelyNotNull(this)
?: makeIntersectionTypeDefinitelyNotNullOrNotNull()
?: makeNullableAsSpecified(false)
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) {
val newSuperTypes = constructor.supertypes.map { it.makeNullable() }
val newConstructor = IntersectionTypeConstructor(newSuperTypes)
val newConstructor = constructor.transformComponents(transform = { it.makeNullable() }) ?: constructor
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(type.annotations, newConstructor, listOf(), false, newConstructor.createScopeForKotlinType())
}
}