Don't use TypeIntersector when loading generic Java constructors

This is not entirely type-safe but this case is so rare that hardly anyone will
be able to spot the change
This commit is contained in:
Alexander Udalov
2015-10-23 20:18:10 +03:00
parent 86bc21da30
commit d6e87c50ab
4 changed files with 45 additions and 18 deletions
@@ -0,0 +1,18 @@
// FILE: J.java
import java.io.Serializable;
public class J {
public <T extends Cloneable & Serializable> J(T t) {}
}
// FILE: K.kt
import java.io.Serializable
// TODO: report TYPE_MISMATCH here as well
fun cloneable(c: Cloneable) = J(c)
fun serializable(s: Serializable) = J(<!TYPE_MISMATCH!>s<!>)
fun <T> both(t: T) where T : Cloneable, T : Serializable = J(t)
@@ -0,0 +1,12 @@
package
public fun </*0*/ T : kotlin.Cloneable> both(/*0*/ t: T): J where T : java.io.Serializable
public fun cloneable(/*0*/ c: kotlin.Cloneable): J
public fun serializable(/*0*/ s: java.io.Serializable): J
public open class J {
public constructor J(/*0*/ t: kotlin.Cloneable!)
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
}
@@ -9048,6 +9048,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("genericConstructorWithMultipleBounds.kt")
public void testGenericConstructorWithMultipleBounds() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/genericConstructorWithMultipleBounds.kt");
doTest(fileName);
}
@TestMetadata("GenericsInSupertypes.kt")
public void testGenericsInSupertypes() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/j+k/GenericsInSupertypes.kt");
@@ -28,22 +28,16 @@ import org.jetbrains.kotlin.load.java.components.TypeUsage.*
import org.jetbrains.kotlin.load.java.lazy.LazyJavaAnnotations
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.TypeParameterResolver
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeFlexibility.FLEXIBLE_LOWER_BOUND
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeFlexibility.FLEXIBLE_UPPER_BOUND
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeFlexibility.INFLEXIBLE
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeFlexibility.*
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.jvm.PLATFORM_TYPES
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.Variance.INVARIANT
import org.jetbrains.kotlin.types.Variance.IN_VARIANCE
import org.jetbrains.kotlin.types.Variance.OUT_VARIANCE
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.Variance.*
import org.jetbrains.kotlin.types.typeUtil.createProjection
import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations
import org.jetbrains.kotlin.utils.sure
import java.util.*
private val JAVA_LANG_CLASS_FQ_NAME: FqName = FqName("java.lang.Class")
@@ -168,19 +162,16 @@ class LazyJavaTypeResolver(
}
// We do not memoize the results of this method, because it would consume much memory, and the real gain is little:
// the case this method accounts for is very rare, not point in optimizing it
// the case this method accounts for is very rare, no point in optimizing it
private fun getConstructorTypeParameterSubstitute(): KotlinType {
// If a Java-constructor declares its own type parameters, we have no way of directly expressing them in Kotlin,
// so we replace them by intersections of their upper bounds
val supertypesJet = HashSet<KotlinType>()
for (supertype in (classifier() as JavaTypeParameter).getUpperBounds()) {
supertypesJet.add(transformJavaType(supertype, UPPER_BOUND.toAttributes()))
}
if (supertypesJet.isEmpty()) {
// If a Java constructor declares its own type parameters, we have no way of directly expressing them in Kotlin,
// so we replace each type parameter with its representative upper bound (which in Java is also the first bound)
val upperBounds = (classifier() as JavaTypeParameter).upperBounds
if (upperBounds.isEmpty()) {
return c.module.builtIns.nullableAnyType
}
return TypeIntersector.intersectTypes(KotlinTypeChecker.DEFAULT, supertypesJet)
?: ErrorUtils.createErrorType("Can't intersect upper bounds of " + javaType.getPresentableText())
return transformJavaType(upperBounds.first(), UPPER_BOUND.toAttributes())
}
private fun isRaw(): Boolean {