diff --git a/compiler/testData/diagnostics/tests/j+k/genericConstructorWithMultipleBounds.kt b/compiler/testData/diagnostics/tests/j+k/genericConstructorWithMultipleBounds.kt new file mode 100644 index 00000000000..46824a24cda --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/genericConstructorWithMultipleBounds.kt @@ -0,0 +1,18 @@ +// FILE: J.java + +import java.io.Serializable; + +public class J { + public 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(s) + +fun both(t: T) where T : Cloneable, T : Serializable = J(t) diff --git a/compiler/testData/diagnostics/tests/j+k/genericConstructorWithMultipleBounds.txt b/compiler/testData/diagnostics/tests/j+k/genericConstructorWithMultipleBounds.txt new file mode 100644 index 00000000000..4642ace35df --- /dev/null +++ b/compiler/testData/diagnostics/tests/j+k/genericConstructorWithMultipleBounds.txt @@ -0,0 +1,12 @@ +package + +public fun 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 58e0db3afeb..8af0bc22834 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -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"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/LazyJavaTypeResolver.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/LazyJavaTypeResolver.kt index e4ba5c36074..7837b464ad1 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/LazyJavaTypeResolver.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/types/LazyJavaTypeResolver.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() - 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 {