diff --git a/compiler/testData/loadJava/compiledJava/mutability/ReadOnlyExtendsWildcard.java b/compiler/testData/loadJava/compiledJava/mutability/ReadOnlyExtendsWildcard.java new file mode 100644 index 00000000000..5d5824f48de --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/mutability/ReadOnlyExtendsWildcard.java @@ -0,0 +1,10 @@ +package test; + +import org.jetbrains.annotations.*; + +import java.util.*; + +public interface ReadOnlyExtendsWildcard { + void bar(); // Non-SAM + void foo(@ReadOnly List x, @NotNull Comparable y); +} diff --git a/compiler/testData/loadJava/compiledJava/mutability/ReadOnlyExtendsWildcard.txt b/compiler/testData/loadJava/compiledJava/mutability/ReadOnlyExtendsWildcard.txt new file mode 100644 index 00000000000..7db4a7b3627 --- /dev/null +++ b/compiler/testData/loadJava/compiledJava/mutability/ReadOnlyExtendsWildcard.txt @@ -0,0 +1,6 @@ +package test + +public interface ReadOnlyExtendsWildcard { + public abstract fun bar(): kotlin.Unit + public abstract fun foo(/*0*/ org.jetbrains.annotations.ReadOnly() p0: kotlin.List!, /*1*/ org.jetbrains.annotations.NotNull() p1: kotlin.Comparable): kotlin.Unit +} diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java index b8cf8d2c37a..5b280378d8f 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java @@ -1382,6 +1382,12 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledJava/mutability/LoadIterableWithPropagation.java"); doTestCompiledJava(fileName); } + + @TestMetadata("ReadOnlyExtendsWildcard.java") + public void testReadOnlyExtendsWildcard() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledJava/mutability/ReadOnlyExtendsWildcard.java"); + doTestCompiledJava(fileName); + } } @TestMetadata("compiler/testData/loadJava/compiledJava/notNull") diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java index 225d0edc8f4..20590cd13c7 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java @@ -3977,6 +3977,12 @@ public class JvmRuntimeDescriptorLoaderTestGenerated extends AbstractJvmRuntimeD String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledJava/mutability/LoadIterableWithPropagation.java"); doTest(fileName); } + + @TestMetadata("ReadOnlyExtendsWildcard.java") + public void testReadOnlyExtendsWildcard() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledJava/mutability/ReadOnlyExtendsWildcard.java"); + doTest(fileName); + } } @TestMetadata("compiler/testData/loadJava/compiledJava/notNull") 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 3e1ac5ef070..e9a196d11a0 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 @@ -41,6 +41,7 @@ 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.JetTypeChecker +import org.jetbrains.kotlin.types.typeUtil.createProjection import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations import org.jetbrains.kotlin.utils.sure import java.util.HashSet @@ -247,11 +248,11 @@ class LazyJavaTypeResolver( if (bound == null) makeStarProjection(typeParameter, attr) else { - var projectionKind = if (javaType.isExtends()) OUT_VARIANCE else IN_VARIANCE - if (projectionKind == typeParameter.getVariance()) { - projectionKind = Variance.INVARIANT - } - TypeProjectionImpl(projectionKind, transformJavaType(bound, UPPER_BOUND.toAttributes())) + createProjection( + type = transformJavaType(bound, UPPER_BOUND.toAttributes()), + projectionKind = if (javaType.isExtends()) OUT_VARIANCE else IN_VARIANCE, + typeParameterDescriptor = typeParameter + ) } } else -> TypeProjectionImpl(INVARIANT, transformJavaType(javaType, attr)) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhacement/typeEnhancement.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhacement/typeEnhancement.kt index 4bf5e469691..1d66d433c50 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhacement/typeEnhancement.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhacement/typeEnhancement.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.load.java.typeEnhacement.NullabilityQualifier.NULLAB import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.typeUtil.createProjection // The index in the lambda is the position of the type component: // Example: for `A>`, indices go as follows: `0 - A<...>, 1 - B, 2 - C, 3 - D, 4 - E`, @@ -74,6 +75,8 @@ private fun JetType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers, i val effectiveQualifiers = qualifiers(index) val (enhancedClassifier, enhancedMutabilityAnnotations) = originalClass.enhanceMutability(effectiveQualifiers, position) + val typeConstructor = enhancedClassifier.typeConstructor + var globalArgIndex = index + 1 val enhancedArguments = getArguments().mapIndexed { localArgIndex, arg -> @@ -84,10 +87,7 @@ private fun JetType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers, i else { val (enhancedType, subtreeSize) = arg.getType().enhancePossiblyFlexible(qualifiers, globalArgIndex) globalArgIndex += subtreeSize - TypeProjectionImpl( - arg.getProjectionKind(), - enhancedType - ) + createProjection(enhancedType, arg.projectionKind, typeParameterDescriptor = typeConstructor.parameters[localArgIndex]) } } @@ -99,12 +99,12 @@ private fun JetType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers, i ).filterNotNull().compositeAnnotationsOrSingle() val (newSubstitution, substitutedEnhancedArgs) = computeNewSubstitutionAndArguments( - enhancedClassifier.typeConstructor.parameters, enhancedArguments + typeConstructor.parameters, enhancedArguments ) val enhancedType = JetTypeImpl( newAnnotations, - enhancedClassifier.getTypeConstructor(), + typeConstructor, enhancedNullability, substitutedEnhancedArgs, newSubstitution, diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index 5cee83e56a4..16dd7c14493 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -136,3 +136,5 @@ public fun List.defaultProjections(): List = map { Type public fun JetType.isDefaultBound(): Boolean = KotlinBuiltIns.isDefaultBound(getSupertypeRepresentative()) +public fun createProjection(type: JetType, projectionKind: Variance, typeParameterDescriptor: TypeParameterDescriptor?): TypeProjection = + TypeProjectionImpl(if (typeParameterDescriptor?.variance == projectionKind) Variance.INVARIANT else projectionKind, type)