NI: In subtyping do not intersect arguments for non-covariant types

It partially reverts 7898922066
because it's not obvious that it's a safe operation
for invariant/contravariant types.

Also, there's a necessary fix in prepareReceiverRegardingCaptureTypes
to make types order stable
Otherwise test bareTypesWithStarProjections becomes flaky.

Also, the changes in bareTypesWithStarProjections.kt are also expected
because the type of the expression `coneSymbol` after the second "if" is
FirVariableSymbol<*> & FirPropertySymbol & AbstractFirBasedSymbol<*>
thus we fix D in the call `coneSymbol.phasedFir()` to FirVariableSymbol<*>
because it's the first type in the list
(see the next line after the last changed in AbstractTypeChecker)
This commit is contained in:
Denis Zharkov
2020-01-14 12:35:17 +03:00
parent 4202c9c1a4
commit d6b01f1007
9 changed files with 38 additions and 12 deletions
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.prepareArgumentTypeRegardingCaptureTypes import org.jetbrains.kotlin.types.checker.prepareArgumentTypeRegardingCaptureTypes
import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize
// this receiver used only for resolution. see subtypes // this receiver used only for resolution. see subtypes
interface DetailedReceiver interface DetailedReceiver
@@ -48,7 +49,9 @@ fun ReceiverValueWithSmartCastInfo.prepareReceiverRegardingCaptureTypes(): Recei
val preparedBaseType = prepareArgumentTypeRegardingCaptureTypes(receiverValue.type.unwrap()) val preparedBaseType = prepareArgumentTypeRegardingCaptureTypes(receiverValue.type.unwrap())
if (preparedBaseType == null && possibleTypes.isEmpty()) return this if (preparedBaseType == null && possibleTypes.isEmpty()) return this
val newPossibleTypes = possibleTypes.mapTo(HashSet<KotlinType>()) { prepareArgumentTypeRegardingCaptureTypes(it.unwrap()) ?: it } val newPossibleTypes = possibleTypes.mapTo(newLinkedHashSetWithExpectedSize(possibleTypes.size)) {
prepareArgumentTypeRegardingCaptureTypes(it.unwrap()) ?: it
}
val newReceiver = if (preparedBaseType != null) receiverValue.replaceType(preparedBaseType) else receiverValue val newReceiver = if (preparedBaseType != null) receiverValue.replaceType(preparedBaseType) else receiverValue
return ReceiverValueWithSmartCastInfo(newReceiver, newPossibleTypes, isStable) return ReceiverValueWithSmartCastInfo(newReceiver, newPossibleTypes, isStable)
@@ -36,5 +36,5 @@ fun foo(coneSymbol: AbstractFirBasedSymbol<*>) {
coneSymbol.phasedFir() checkType { _<FirVariable<*>>() } coneSymbol.phasedFir() checkType { _<FirVariable<*>>() }
if (coneSymbol !is FirPropertySymbol) return if (coneSymbol !is FirPropertySymbol) return
coneSymbol.phasedFir() checkType { _<FirProperty>() } coneSymbol.phasedFir() checkType { _<FirVariable<*>>() }
} }
@@ -36,5 +36,5 @@ fun foo(coneSymbol: AbstractFirBasedSymbol<*>) {
coneSymbol.phasedFir() checkType { _<FirVariable<*>>() } coneSymbol.phasedFir() checkType { _<FirVariable<*>>() }
if (coneSymbol !is FirPropertySymbol) return if (coneSymbol !is FirPropertySymbol) return
coneSymbol.phasedFir() checkType { _<FirProperty>() } coneSymbol.phasedFir() checkType { _<FirVariable<*>>() }
} }
@@ -15,3 +15,13 @@ fun <E> main(a: A<E>) {
foo(a).b() foo(a).b()
} }
class AOut<out X>
fun <Y> foo(c: AOut<Y>): Y = TODO()
fun <E> mainOut(a: AOut<E>) {
a as AOut<B<*>>
foo(a).b()
}
@@ -15,3 +15,13 @@ fun <E> main(a: A<E>) {
foo(<!DEBUG_INFO_SMARTCAST!>a<!>).b() foo(<!DEBUG_INFO_SMARTCAST!>a<!>).b()
} }
class AOut<out X>
fun <Y> foo(c: AOut<Y>): Y = TODO()
fun <E> mainOut(a: AOut<E>) {
a <!UNCHECKED_CAST!>as AOut<B<*>><!>
foo(<!DEBUG_INFO_SMARTCAST!>a<!>).b()
}
@@ -20,7 +20,7 @@ fun <X> InvBase<X>.myLastInv(): X = TODO()
fun <T> fooInv(x: InvBase<T>) { fun <T> fooInv(x: InvBase<T>) {
if (x is InvDerived<*>) { if (x is InvDerived<*>) {
val l: T = x.myLastInv() // required T, found Cap(*). Only in NI val l: T = <!TYPE_MISMATCH!>x.<!TYPE_MISMATCH!>myLastInv()<!><!> // required T, found Cap(*). Only in NI
} }
} }
@@ -36,7 +36,7 @@ fun Number.num() {}
fun main(b: Base<out Number>) { fun main(b: Base<out Number>) {
b.foo().num() b.foo().num()
if (b is Derived<*>) { if (b is Derived<*>) {
b.foo().num() b.foo().<!DEBUG_INFO_UNRESOLVED_WITH_TARGET, UNRESOLVED_REFERENCE_WRONG_RECEIVER!>num<!>()
b.baz().length b.baz().length
} }
} }
@@ -19,7 +19,7 @@ fun case_1(x: Any) {
if (x is Interface1) { if (x is Interface1) {
if (x is Interface2) { if (x is Interface2) {
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & Interface2 & kotlin.Any")!>x<!> <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & Interface2 & kotlin.Any")!>x<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any"), DEBUG_INFO_SMARTCAST!>x<!>.itest() <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any"), DEBUG_INFO_SMARTCAST!>x<!>.itest()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any"), DEBUG_INFO_SMARTCAST!>x<!>.itest1() <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any"), DEBUG_INFO_SMARTCAST!>x<!>.itest1()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any"), DEBUG_INFO_SMARTCAST!>x<!>.itest2() <!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any"), DEBUG_INFO_SMARTCAST!>x<!>.itest2()
} }
@@ -1309,7 +1309,7 @@ fun case_71(t: Any?) {
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & Interface2 & kotlin.Any & kotlin.Any?")!>t<!> <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & Interface2 & kotlin.Any & kotlin.Any?")!>t<!>
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest1() <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest1()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest2() <!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest2()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest() <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.let { <!DEBUG_INFO_EXPRESSION_TYPE("{Any & Interface1 & Interface2}")!>it<!>.itest1(); <!DEBUG_INFO_EXPRESSION_TYPE("{Any & Interface1 & Interface2}")!>it<!>.itest2() } <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.let { <!DEBUG_INFO_EXPRESSION_TYPE("{Any & Interface1 & Interface2}")!>it<!>.itest1(); <!DEBUG_INFO_EXPRESSION_TYPE("{Any & Interface1 & Interface2}")!>it<!>.itest2() }
} }
@@ -1354,7 +1354,7 @@ fun case_73(t: Any?) {
if (t != <!DEBUG_INFO_CONSTANT!>`null`<!>) { if (t != <!DEBUG_INFO_CONSTANT!>`null`<!>) {
<!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest2() <!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest2()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest1() <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest1()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface3 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest() <!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test1() <!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test1()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test2() <!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test2()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel1 & ClassLevel2 & Interface1 & Interface2 & Interface3 & kotlin.Any & kotlin.Any?")!>t<!> <!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel1 & ClassLevel2 & Interface1 & Interface2 & Interface3 & kotlin.Any & kotlin.Any?")!>t<!>
@@ -1379,7 +1379,7 @@ fun case_74(t: Any?) {
if (t is Interface3?) { if (t is Interface3?) {
<!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest2() <!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest2()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest1() <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest1()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface3 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest() <!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test1() <!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test1()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test2() <!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test2()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel1 & ClassLevel2 & Interface1 & Interface2 & Interface3 & kotlin.Any & kotlin.Any?")!>t<!> <!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel1 & ClassLevel2 & Interface1 & Interface2 & Interface3 & kotlin.Any & kotlin.Any?")!>t<!>
@@ -1402,7 +1402,7 @@ fun case_75(t: Any?, z: Nothing?) {
if (t !is Interface2? || t !is Interface3?) {} else { if (t !is Interface2? || t !is Interface3?) {} else {
<!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest2() <!DEBUG_INFO_EXPRESSION_TYPE("Interface2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest2()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest1() <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest1()
<!DEBUG_INFO_EXPRESSION_TYPE("Interface3 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest() <!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.itest()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test1() <!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test1()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test2() <!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>.test2()
<!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!> <!DEBUG_INFO_EXPRESSION_TYPE("ClassLevel2 & kotlin.Any?"), DEBUG_INFO_SMARTCAST!>t<!>
@@ -270,7 +270,10 @@ object AbstractTypeChecker {
else -> { // at least 2 supertypes with same constructors. Such case is rare else -> { // at least 2 supertypes with same constructors. Such case is rare
val newArguments = ArgumentList(superConstructor.parametersCount()) val newArguments = ArgumentList(superConstructor.parametersCount())
var anyNonOutParameter = false
for (index in 0 until superConstructor.parametersCount()) { for (index in 0 until superConstructor.parametersCount()) {
anyNonOutParameter = anyNonOutParameter || superConstructor.getParameter(index).getVariance() != TypeVariance.OUT
if (anyNonOutParameter) continue
val allProjections = supertypesWithSameConstructor.map { val allProjections = supertypesWithSameConstructor.map {
it.getArgumentOrNull(index)?.takeIf { it.getVariance() == TypeVariance.INV }?.getType() it.getArgumentOrNull(index)?.takeIf { it.getVariance() == TypeVariance.INV }?.getType()
?: error("Incorrect type: $it, subType: $subType, superType: $superType") ?: error("Incorrect type: $it, subType: $subType, superType: $superType")
@@ -281,7 +284,7 @@ object AbstractTypeChecker {
newArguments.add(intersection) newArguments.add(intersection)
} }
if (isSubtypeForSameConstructor(newArguments, superType)) return true if (!anyNonOutParameter && isSubtypeForSameConstructor(newArguments, superType)) return true
return supertypesWithSameConstructor.any { isSubtypeForSameConstructor(it.asArgumentList(), superType) } return supertypesWithSameConstructor.any { isSubtypeForSameConstructor(it.asArgumentList(), superType) }
} }