Build type enhancement properly, by taking into account both bounds of the original flexible type

^KT-44420 Fixed
This commit is contained in:
Victor Petukhov
2021-01-22 17:57:57 +03:00
parent 293f2f9950
commit 83c93aca2e
5 changed files with 64 additions and 7 deletions
@@ -20852,6 +20852,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/typeEnhancement"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/typeEnhancement"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
} }
@Test
@TestMetadata("buildFlexibleEnhancement.kt")
public void testBuildFlexibleEnhancement() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/buildFlexibleEnhancement.kt");
}
@Test @Test
@TestMetadata("overriddenExtensions.kt") @TestMetadata("overriddenExtensions.kt")
public void testOverriddenExtensions() throws Exception { public void testOverriddenExtensions() throws Exception {
@@ -0,0 +1,35 @@
// FIR_IDENTICAL
// FULL_JDK
// WITH_RUNTIME
// WITH_REFLECT
// FILE: NonNullApi.java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.PACKAGE})
@javax.annotation.Nonnull
@javax.annotation.meta.TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface NonNullApi { }
// FILE: Foo.java
import java.util.Collection;
@NonNullApi
public class Foo<E> {
public Foo(Collection<? extends E> c) {}
}
// FILE: main.kt
fun test() {
val collection: Collection<Int> = listOf(1, 2, 3)
Foo(collection)
}
@@ -77,7 +77,7 @@ fun main(a: A) {
a.field?.length a.field?.length
a.field.length a.field.length
<!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS("MutableList<String!>?")!>a.baz()<!>.get(0) <!RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS("(Mutable)List<String!>?")!>a.baz()<!>.get(0)
a.baz()!!.get(0).get(0) a.baz()!!.get(0).get(0)
a.baz()!!.get(0)?.get(0) a.baz()!!.get(0)?.get(0)
} }
@@ -20858,6 +20858,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/typeEnhancement"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true); KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/typeEnhancement"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
} }
@Test
@TestMetadata("buildFlexibleEnhancement.kt")
public void testBuildFlexibleEnhancement() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/typeEnhancement/buildFlexibleEnhancement.kt");
}
@Test @Test
@TestMetadata("overriddenExtensions.kt") @TestMetadata("overriddenExtensions.kt")
public void testOverriddenExtensions() throws Exception { public void testOverriddenExtensions() throws Exception {
@@ -58,6 +58,15 @@ class JavaTypeEnhancement(private val javaResolverSettings: JavaResolverSettings
// For flexible types, both bounds are indexed in the same way: `(A<B>..C<D>)` gives `0 - (A<B>..C<D>), 1 - B and D`. // For flexible types, both bounds are indexed in the same way: `(A<B>..C<D>)` gives `0 - (A<B>..C<D>), 1 - B and D`.
fun KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = unwrap().enhancePossiblyFlexible(qualifiers, 0).typeIfChanged fun KotlinType.enhance(qualifiers: (Int) -> JavaTypeQualifiers) = unwrap().enhancePossiblyFlexible(qualifiers, 0).typeIfChanged
private fun buildEnhancementByFlexibleTypeBounds(lowerBound: KotlinType, upperBound: KotlinType): KotlinType? {
val upperEnhancement = upperBound.getEnhancement()
val lowerEnhancement = lowerBound.getEnhancement() ?: upperEnhancement ?: return null
if (upperEnhancement == null) return lowerEnhancement
return KotlinTypeFactory.flexibleType(lowerEnhancement.lowerIfFlexible(), upperEnhancement.upperIfFlexible())
}
private fun UnwrappedType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int): Result { private fun UnwrappedType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQualifiers, index: Int): Result {
if (isError) return Result(this, 1, false) if (isError) return Result(this, 1, false)
return when (this) { return when (this) {
@@ -72,12 +81,13 @@ class JavaTypeEnhancement(private val javaResolverSettings: JavaResolverSettings
} }
val wereChanges = lowerResult.wereChanges || upperResult.wereChanges val wereChanges = lowerResult.wereChanges || upperResult.wereChanges
val enhancement = lowerResult.type.getEnhancement() ?: upperResult.type.getEnhancement() val enhancement = buildEnhancementByFlexibleTypeBounds(lowerResult.type, upperResult.type)
val type = if (!wereChanges) this@enhancePossiblyFlexible val type = if (wereChanges) {
else when { when (this) {
this is RawTypeImpl -> RawTypeImpl(lowerResult.type, upperResult.type) is RawTypeImpl -> RawTypeImpl(lowerResult.type, upperResult.type)
else -> KotlinTypeFactory.flexibleType(lowerResult.type, upperResult.type) else -> KotlinTypeFactory.flexibleType(lowerResult.type, upperResult.type)
}.wrapEnhancement(enhancement) }.wrapEnhancement(enhancement)
} else this@enhancePossiblyFlexible
Result( Result(
type, type,