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:
+18
@@ -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)
|
||||
+12
@@ -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");
|
||||
|
||||
+9
-18
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user