Allow type variable fixation into intersection type if it isn't meaningless (i.e. has one or more final classes, or two or more open classes)

^KT-46186 Fixed
This commit is contained in:
Victor Petukhov
2021-04-20 14:41:13 +03:00
parent 310d98c4f7
commit 867d7b5bca
10 changed files with 312 additions and 4 deletions
@@ -29029,6 +29029,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42472.kt");
}
@Test
@TestMetadata("kt46186.kt")
public void testKt46186() throws Exception {
runTest("compiler/testData/diagnostics/tests/typeParameters/kt46186.kt");
}
@Test
@TestMetadata("misplacedConstraints.kt")
public void testMisplacedConstraints() throws Exception {
@@ -261,6 +261,10 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty
return this is ConeClassLikeLookupTag
}
override fun TypeConstructorMarker.isInterface(): Boolean {
return ((this as? ConeClassLikeLookupTag)?.toClassLikeSymbol()?.fir as? FirClass)?.classKind == ClassKind.INTERFACE
}
override fun TypeParameterMarker.getVariance(): TypeVariance {
require(this is ConeTypeParameterLookupTag)
return this.symbol.fir.variance.convertVariance()
@@ -158,6 +158,10 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
override fun TypeConstructorMarker.isClassTypeConstructor() = this is IrClassSymbol
override fun TypeConstructorMarker.isInterface(): Boolean {
return (this as? IrClassSymbol)?.owner?.isInterface == true
}
override fun TypeParameterMarker.getVariance() = (this as IrTypeParameterSymbol).owner.variance.convertVariance()
private fun getSuperTypes(typeParameterMarker: TypeParameterMarker) = (typeParameterMarker as IrTypeParameterSymbol).owner.superTypes
@@ -216,10 +216,18 @@ class ResultTypeResolver(
variableWithConstraints.constraints.filter { it.kind == ConstraintKind.UPPER && this@findSuperType.isProperTypeForFixation(it.type) }
if (upperConstraints.isNotEmpty()) {
val intersectionUpperType = intersectTypes(upperConstraints.map { it.type })
val isThereExpectedTypeConstraint = upperConstraints.any { it.isExpectedTypePosition() }
val nonExpectedTypeConstraints = upperConstraints.filterNot { it.isExpectedTypePosition() }
val resultIsActuallyIntersection = intersectionUpperType.typeConstructor().isIntersection()
val upperType = if (isThereExpectedTypeConstraint && nonExpectedTypeConstraints.isNotEmpty() && resultIsActuallyIntersection) {
val isThereUnwantedIntersectedTypes = if (resultIsActuallyIntersection) {
val intersectionSupertypes = intersectionUpperType.typeConstructor().supertypes()
val intersectionClasses = intersectionSupertypes.count {
it.typeConstructor().isClassTypeConstructor() && !it.typeConstructor().isInterface()
}
val areThereIntersectionFinalClasses = intersectionSupertypes.any { it.typeConstructor().isCommonFinalClassConstructor() }
intersectionClasses > 1 || areThereIntersectionFinalClasses
} else false
val upperType = if (isThereUnwantedIntersectedTypes) {
/*
* We shouldn't infer a type variable into the intersection type if there is an explicit expected type,
* otherwise it can lead to something like this:
@@ -227,7 +235,7 @@ class ResultTypeResolver(
* fun <T : String> materialize(): T = null as T
* val bar: Int = materialize() // no errors, T is inferred into String & Int
*/
intersectTypes(nonExpectedTypeConstraints.map { it.type })
intersectTypes(upperConstraints.filterNot { it.isExpectedTypePosition() }.map { it.type })
} else intersectionUpperType
return typeApproximator.approximateToSubType(
@@ -0,0 +1,83 @@
// !DIAGNOSTICS: -FINAL_UPPER_BOUND -CAST_NEVER_SUCCEEDS
interface I
class View1
open class View2
interface View3
abstract class View4
interface View5
fun <T: View1> findViewById1(): T = null as T
fun test1(): I = findViewById1()
fun <T: View2> findViewById2(): T = null as T
fun test2(): I = findViewById2()
inline fun <reified T: View1> findViewById3(): T = null as T
fun test3(): I = findViewById3()
inline fun <reified T: View2> findViewById4(): T = null as T
fun test4(): I = findViewById4()
fun <T: View3> findViewById5(): T = null as T
fun test5(): I = findViewById5()
inline fun <reified T: View3> findViewById6(): T = null as T
fun test6(): I = findViewById6()
fun <T: View4> findViewById7(): T = null as T
fun test7(): I = findViewById7()
inline fun <reified T: View4> findViewById8(): T = null as T
fun test8(): I = findViewById8()
fun <T> findViewById9(): T where T: View3, T: View5 = null as T
fun test9(): I = findViewById9()
inline fun <reified T> findViewById10(): T where T: View3, T: View5 = null as T
fun test10(): I = findViewById10()
fun <T: View2> findViewById11(): T = null as T
fun test11(): View4 = findViewById11()
object Obj {
fun <T: I> findViewById1(): T = null as T
fun test1(): View1 = findViewById1()
fun <T: I> findViewById2(): T = null as T
fun test2(): View2 = findViewById2()
inline fun <reified T: I> findViewById3(): T = null as T
fun test3(): View1 = findViewById3()
inline fun <reified T: I> findViewById4(): T = null as T
fun test4(): View2 = findViewById4()
fun <T: I> findViewById5(): T = null as T
fun test5(): View3 = findViewById5()
inline fun <reified T: I> findViewById6(): T = null as T
fun test6(): View3 = findViewById6()
fun <T: I> findViewById7(): T = null as T
fun test7(): View4 = findViewById7()
inline fun <reified T: I> findViewById8(): T = null as T
fun test8(): View4 = findViewById8()
fun <T> findViewById9(): T where T: View3, T: View5 = null as T
fun test9(): View1 = findViewById9()
inline fun <reified T> findViewById10(): T where T: View3, T: View5 = null as T
fun test10(): View1 = findViewById10()
fun <T: View2> findViewById11(): T = null as T
fun test11(): View4 = findViewById11()
}
interface A
open class B {
fun <T> f(): T where T : A, T : B = null as T
fun g(): A = f()
}
@@ -0,0 +1,83 @@
// !DIAGNOSTICS: -FINAL_UPPER_BOUND -CAST_NEVER_SUCCEEDS
interface I
class View1
open class View2
interface View3
abstract class View4
interface View5
fun <T: View1> findViewById1(): T = null as T
fun test1(): I = <!TYPE_MISMATCH!><!TYPE_MISMATCH!>findViewById1<!>()<!>
fun <T: View2> findViewById2(): T = null as T
fun test2(): I = findViewById2()
inline fun <reified T: View1> findViewById3(): T = null as T
fun test3(): I = <!TYPE_MISMATCH!><!TYPE_MISMATCH!>findViewById3<!>()<!>
inline fun <reified T: View2> findViewById4(): T = null as T
fun test4(): I = findViewById4()
fun <T: View3> findViewById5(): T = null as T
fun test5(): I = findViewById5()
inline fun <reified T: View3> findViewById6(): T = null as T
fun test6(): I = findViewById6()
fun <T: View4> findViewById7(): T = null as T
fun test7(): I = findViewById7()
inline fun <reified T: View4> findViewById8(): T = null as T
fun test8(): I = findViewById8()
fun <T> findViewById9(): T where T: View3, T: View5 = null as T
fun test9(): I = findViewById9()
inline fun <reified T> findViewById10(): T where T: View3, T: View5 = null as T
fun test10(): I = findViewById10()
fun <T: View2> findViewById11(): T = null as T
fun test11(): View4 = <!TYPE_MISMATCH!><!TYPE_MISMATCH!>findViewById11<!>()<!>
object Obj {
fun <T: I> findViewById1(): T = null as T
fun test1(): View1 = <!TYPE_MISMATCH!><!TYPE_MISMATCH!>findViewById1<!>()<!>
fun <T: I> findViewById2(): T = null as T
fun test2(): View2 = findViewById2()
inline fun <reified T: I> findViewById3(): T = null as T
fun test3(): View1 = <!TYPE_MISMATCH!><!TYPE_MISMATCH!>findViewById3<!>()<!>
inline fun <reified T: I> findViewById4(): T = null as T
fun test4(): View2 = findViewById4()
fun <T: I> findViewById5(): T = null as T
fun test5(): View3 = findViewById5()
inline fun <reified T: I> findViewById6(): T = null as T
fun test6(): View3 = findViewById6()
fun <T: I> findViewById7(): T = null as T
fun test7(): View4 = findViewById7()
inline fun <reified T: I> findViewById8(): T = null as T
fun test8(): View4 = findViewById8()
fun <T> findViewById9(): T where T: View3, T: View5 = null as T
fun test9(): View1 = <!TYPE_MISMATCH!><!TYPE_MISMATCH!>findViewById9<!>()<!>
inline fun <reified T> findViewById10(): T where T: View3, T: View5 = null as T
fun test10(): View1 = <!TYPE_MISMATCH!><!TYPE_MISMATCH!>findViewById10<!>()<!>
fun <T: View2> findViewById11(): T = null as T
fun test11(): View4 = <!TYPE_MISMATCH!><!TYPE_MISMATCH!>findViewById11<!>()<!>
}
interface A
open class B {
fun <T> f(): T where T : A, T : B = null as T
fun g(): A = f()
}
@@ -0,0 +1,107 @@
package
public fun </*0*/ T : View1> findViewById1(): T
public inline fun </*0*/ reified T : View3> findViewById10(): T where T : View5
public fun </*0*/ T : View2> findViewById11(): T
public fun </*0*/ T : View2> findViewById2(): T
public inline fun </*0*/ reified T : View1> findViewById3(): T
public inline fun </*0*/ reified T : View2> findViewById4(): T
public fun </*0*/ T : View3> findViewById5(): T
public inline fun </*0*/ reified T : View3> findViewById6(): T
public fun </*0*/ T : View4> findViewById7(): T
public inline fun </*0*/ reified T : View4> findViewById8(): T
public fun </*0*/ T : View3> findViewById9(): T where T : View5
public fun test1(): I
public fun test10(): I
public fun test11(): View4
public fun test2(): I
public fun test3(): I
public fun test4(): I
public fun test5(): I
public fun test6(): I
public fun test7(): I
public fun test8(): I
public fun test9(): I
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 open class B {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun </*0*/ T : A> f(): T where T : B
public final fun g(): A
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface I {
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 object Obj {
private constructor Obj()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun </*0*/ T : I> findViewById1(): T
public final inline fun </*0*/ reified T : View3> findViewById10(): T where T : View5
public final fun </*0*/ T : View2> findViewById11(): T
public final fun </*0*/ T : I> findViewById2(): T
public final inline fun </*0*/ reified T : I> findViewById3(): T
public final inline fun </*0*/ reified T : I> findViewById4(): T
public final fun </*0*/ T : I> findViewById5(): T
public final inline fun </*0*/ reified T : I> findViewById6(): T
public final fun </*0*/ T : I> findViewById7(): T
public final inline fun </*0*/ reified T : I> findViewById8(): T
public final fun </*0*/ T : View3> findViewById9(): T where T : View5
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test1(): View1
public final fun test10(): View1
public final fun test11(): View4
public final fun test2(): View2
public final fun test3(): View1
public final fun test4(): View2
public final fun test5(): View3
public final fun test6(): View3
public final fun test7(): View4
public final fun test8(): View4
public final fun test9(): View1
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class View1 {
public constructor View1()
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 open class View2 {
public constructor View2()
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 View3 {
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 abstract class View4 {
public constructor View4()
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 View5 {
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
}
@@ -29125,6 +29125,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42472.kt");
}
@Test
@TestMetadata("kt46186.kt")
public void testKt46186() throws Exception {
runTest("compiler/testData/diagnostics/tests/typeParameters/kt46186.kt");
}
@Test
@TestMetadata("misplacedConstraints.kt")
public void testMisplacedConstraints() throws Exception {
@@ -303,6 +303,7 @@ interface TypeSystemContext : TypeSystemOptimizationContext {
fun TypeConstructorMarker.supertypes(): Collection<KotlinTypeMarker>
fun TypeConstructorMarker.isIntersection(): Boolean
fun TypeConstructorMarker.isClassTypeConstructor(): Boolean
fun TypeConstructorMarker.isInterface(): Boolean
fun TypeConstructorMarker.isIntegerLiteralTypeConstructor(): Boolean
fun TypeConstructorMarker.isLocalType(): Boolean
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.descriptors.impl.AbstractTypeParameterDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.inference.CapturedType
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
import org.jetbrains.kotlin.resolve.descriptorUtil.*
@@ -237,6 +238,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy
return declarationDescriptor is ClassDescriptor
}
override fun TypeConstructorMarker.isInterface(): Boolean {
require(this is TypeConstructor, this::errorMessage)
return DescriptorUtils.isInterface(declarationDescriptor)
}
override fun TypeConstructorMarker.isCommonFinalClassConstructor(): Boolean {
require(this is TypeConstructor, this::errorMessage)
val classDescriptor = declarationDescriptor as? ClassDescriptor ?: return false