[FIR] Consider variance of type parameters during java type enhancement
#KT-41940 Fixed
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
// ISSUE: KT-41940
|
||||
|
||||
// FILE: Matcher.java
|
||||
|
||||
public interface Matcher<T> {}
|
||||
|
||||
// FILE: Matchers.java
|
||||
|
||||
public class Matchers {
|
||||
public static <T> Matcher<java.lang.Iterable<? super T>> hasItem(T item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> void assertThat(T actual, Matcher<? super T> matcher) {}
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
import Matchers.*
|
||||
|
||||
fun test(list: List<String>, string: String) {
|
||||
assertThat(list, <!DEBUG_INFO_EXPRESSION_TYPE("Matcher<kotlin.collections.MutableIterable<*>..kotlin.collections.Iterable<*>?!>..Matcher<kotlin.collections.MutableIterable<*>..kotlin.collections.Iterable<*>?!>?!")!>hasItem(string)<!>)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
FILE: main.kt
|
||||
public final fun test(list: R|kotlin/collections/List<kotlin/String>|, string: R|kotlin/String|): R|kotlin/Unit| {
|
||||
R|/Matchers.assertThat|<R|ft<kotlin/collections/List<kotlin/String>, kotlin/collections/List<kotlin/String>?>!|>(R|<local>/list|, R|/Matchers.hasItem|<R|ft<kotlin/String, kotlin/String?>!|>(R|<local>/string|))
|
||||
}
|
||||
Generated
+5
@@ -520,6 +520,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/javaArrayVariance.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt41940.kt")
|
||||
public void testKt41940() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/kt41940.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lambda.kt")
|
||||
public void testLambda() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/lambda.kt");
|
||||
|
||||
+5
@@ -520,6 +520,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/javaArrayVariance.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt41940.kt")
|
||||
public void testKt41940() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/kt41940.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lambda.kt")
|
||||
public void testLambda() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/lambda.kt");
|
||||
|
||||
@@ -196,7 +196,6 @@ class JavaSymbolProvider(
|
||||
isInline = false
|
||||
isFun = classKind == ClassKind.INTERFACE
|
||||
}
|
||||
addAnnotationsFrom(this@JavaSymbolProvider.session, javaClass, javaTypeParameterStack)
|
||||
// TODO: may be we can process fields & methods later.
|
||||
// However, they should be built up to override resolve stage
|
||||
for (javaField in javaClass.fields) {
|
||||
@@ -257,6 +256,7 @@ class JavaSymbolProvider(
|
||||
)
|
||||
}
|
||||
)
|
||||
firJavaClass.addAnnotationsFrom(this@JavaSymbolProvider.session, javaClass, javaTypeParameterStack)
|
||||
return firJavaClass
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
||||
import org.jetbrains.kotlin.fir.java.declarations.buildJavaValueParameter
|
||||
import org.jetbrains.kotlin.fir.java.enhancement.readOnlyToMutable
|
||||
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
||||
@@ -40,6 +41,7 @@ import org.jetbrains.kotlin.load.java.typeEnhancement.TypeComponentPosition
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.Variance.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
internal val JavaModifierListOwner.modality: Modality
|
||||
get() = when {
|
||||
@@ -70,7 +72,7 @@ internal fun FirTypeRef.toConeKotlinTypeProbablyFlexible(
|
||||
when (this) {
|
||||
is FirResolvedTypeRef -> type
|
||||
is FirJavaTypeRef -> {
|
||||
type.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack)
|
||||
type.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, isForSupertypes = false)
|
||||
}
|
||||
else -> ConeKotlinErrorType(
|
||||
ConeSimpleDiagnostic("Unexpected type reference in JavaClassUseSiteMemberScope: ${this::class.java}", DiagnosticKind.Java)
|
||||
@@ -93,9 +95,9 @@ internal fun JavaClassifierType.toFirResolvedTypeRef(
|
||||
): FirResolvedTypeRef {
|
||||
val coneType =
|
||||
if (isForSupertypes)
|
||||
toConeKotlinTypeForFlexibleBound(session, javaTypeParameterStack, isLowerBound = true, forTypeParameterBounds)
|
||||
toConeKotlinTypeForFlexibleBound(session, javaTypeParameterStack, isLowerBound = true, forTypeParameterBounds, isForSupertypes)
|
||||
else
|
||||
toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, forTypeParameterBounds)
|
||||
toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, forTypeParameterBounds, isForSupertypes)
|
||||
|
||||
return buildResolvedTypeRef {
|
||||
type = coneType
|
||||
@@ -106,7 +108,8 @@ internal fun JavaClassifierType.toFirResolvedTypeRef(
|
||||
internal fun JavaType?.toConeKotlinTypeWithoutEnhancement(
|
||||
session: FirSession,
|
||||
javaTypeParameterStack: JavaTypeParameterStack,
|
||||
forAnnotationValueParameter: Boolean = false
|
||||
forAnnotationValueParameter: Boolean = false,
|
||||
isForSupertypes: Boolean = false
|
||||
): ConeKotlinType {
|
||||
return when (this) {
|
||||
is JavaClassifierType -> {
|
||||
@@ -123,9 +126,9 @@ internal fun JavaType?.toConeKotlinTypeWithoutEnhancement(
|
||||
classId.toConeKotlinType(emptyArray(), isNullable = false)
|
||||
}
|
||||
is JavaArrayType -> {
|
||||
toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, forAnnotationValueParameter)
|
||||
toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, forAnnotationValueParameter, isForSupertypes)
|
||||
}
|
||||
is JavaWildcardType -> bound?.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack) ?: run {
|
||||
is JavaWildcardType -> bound?.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, isForSupertypes = isForSupertypes) ?: run {
|
||||
StandardClassIds.Any.toConeFlexibleType(emptyArray())
|
||||
}
|
||||
null -> {
|
||||
@@ -138,12 +141,13 @@ internal fun JavaType?.toConeKotlinTypeWithoutEnhancement(
|
||||
private fun JavaArrayType.toConeKotlinTypeWithoutEnhancement(
|
||||
session: FirSession,
|
||||
javaTypeParameterStack: JavaTypeParameterStack,
|
||||
forAnnotationValueParameter: Boolean = false
|
||||
forAnnotationValueParameter: Boolean = false,
|
||||
isForSupertypes: Boolean
|
||||
): ConeFlexibleType {
|
||||
val componentType = componentType
|
||||
return if (componentType !is JavaPrimitiveType) {
|
||||
val classId = StandardClassIds.Array
|
||||
val argumentType = componentType.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, forAnnotationValueParameter)
|
||||
val argumentType = componentType.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, forAnnotationValueParameter, isForSupertypes)
|
||||
classId.toConeFlexibleType(
|
||||
arrayOf(argumentType),
|
||||
typeArgumentsForUpper = arrayOf(ConeKotlinTypeProjectionOut(argumentType))
|
||||
@@ -168,6 +172,7 @@ private fun JavaClassifierType.toConeKotlinTypeWithoutEnhancement(
|
||||
session: FirSession,
|
||||
javaTypeParameterStack: JavaTypeParameterStack,
|
||||
forTypeParameterBounds: Boolean = false,
|
||||
isForSupertypes: Boolean = false,
|
||||
forAnnotationValueParameter: Boolean = false
|
||||
): ConeKotlinType {
|
||||
val lowerBound = toConeKotlinTypeForFlexibleBound(
|
||||
@@ -175,6 +180,7 @@ private fun JavaClassifierType.toConeKotlinTypeWithoutEnhancement(
|
||||
javaTypeParameterStack,
|
||||
isLowerBound = true,
|
||||
forTypeParameterBounds,
|
||||
isForSupertypes,
|
||||
forAnnotationValueParameter = forAnnotationValueParameter
|
||||
)
|
||||
val upperBound =
|
||||
@@ -183,6 +189,7 @@ private fun JavaClassifierType.toConeKotlinTypeWithoutEnhancement(
|
||||
javaTypeParameterStack,
|
||||
isLowerBound = false,
|
||||
forTypeParameterBounds,
|
||||
isForSupertypes,
|
||||
lowerBound,
|
||||
forAnnotationValueParameter = forAnnotationValueParameter
|
||||
)
|
||||
@@ -285,6 +292,7 @@ private fun JavaClassifierType.toConeKotlinTypeForFlexibleBound(
|
||||
javaTypeParameterStack: JavaTypeParameterStack,
|
||||
isLowerBound: Boolean,
|
||||
forTypeParameterBounds: Boolean,
|
||||
isForSupertypes: Boolean,
|
||||
lowerBound: ConeLookupTagBasedType? = null,
|
||||
forAnnotationValueParameter: Boolean = false
|
||||
): ConeLookupTagBasedType {
|
||||
@@ -308,8 +316,9 @@ private fun JavaClassifierType.toConeKotlinTypeForFlexibleBound(
|
||||
)
|
||||
}
|
||||
|
||||
val mappedTypeArguments = if (isRaw) {
|
||||
val classSymbol = session.firSymbolProvider.getClassLikeSymbolByFqName(classId) as? FirRegularClassSymbol
|
||||
|
||||
val mappedTypeArguments = if (isRaw) {
|
||||
val defaultArgs = (1..classifier.typeParameters.size).map { ConeStarProjection }
|
||||
|
||||
if (forTypeParameterBounds) {
|
||||
@@ -317,15 +326,18 @@ private fun JavaClassifierType.toConeKotlinTypeForFlexibleBound(
|
||||
// to create a proper raw type arguments, we should take class parameters some time
|
||||
defaultArgs
|
||||
} else {
|
||||
val classSymbol = session.firSymbolProvider.getClassLikeSymbolByFqName(classId) as? FirRegularClassSymbol
|
||||
val position = if (isLowerBound) TypeComponentPosition.FLEXIBLE_LOWER else TypeComponentPosition.FLEXIBLE_UPPER
|
||||
|
||||
classSymbol?.fir?.createRawArguments(defaultArgs, position) ?: defaultArgs
|
||||
}
|
||||
} else {
|
||||
typeArguments.map { argument ->
|
||||
val typeParameters = runIf(!forTypeParameterBounds && !isForSupertypes) { classSymbol?.fir?.typeParameters } ?: emptyList()
|
||||
|
||||
typeArguments.indices.map { index ->
|
||||
val argument = typeArguments[index]
|
||||
val parameter = typeParameters.getOrNull(index)?.symbol?.fir
|
||||
argument.toConeProjectionWithoutEnhancement(
|
||||
session, javaTypeParameterStack, boundTypeParameter = null
|
||||
session, javaTypeParameterStack, boundTypeParameter = parameter, isForSupertypes = isForSupertypes
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -371,9 +383,23 @@ internal fun JavaAnnotation.toFirAnnotationCall(
|
||||
@FirBuilderDsl
|
||||
internal fun FirAnnotationContainerBuilder.addAnnotationsFrom(
|
||||
session: FirSession, javaAnnotationOwner: JavaAnnotationOwner, javaTypeParameterStack: JavaTypeParameterStack
|
||||
) {
|
||||
annotations.addAnnotationsFrom(session, javaAnnotationOwner, javaTypeParameterStack)
|
||||
}
|
||||
|
||||
internal fun FirJavaClass.addAnnotationsFrom(
|
||||
session: FirSession, javaAnnotationOwner: JavaAnnotationOwner, javaTypeParameterStack: JavaTypeParameterStack
|
||||
) {
|
||||
annotations.addAnnotationsFrom(session, javaAnnotationOwner, javaTypeParameterStack)
|
||||
}
|
||||
|
||||
private fun MutableList<FirAnnotationCall>.addAnnotationsFrom(
|
||||
session: FirSession,
|
||||
javaAnnotationOwner: JavaAnnotationOwner,
|
||||
javaTypeParameterStack: JavaTypeParameterStack
|
||||
) {
|
||||
for (annotation in javaAnnotationOwner.annotations) {
|
||||
annotations += annotation.toFirAnnotationCall(session, javaTypeParameterStack)
|
||||
this += annotation.toFirAnnotationCall(session, javaTypeParameterStack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,7 +419,8 @@ internal fun JavaValueParameter.toFirValueParameter(
|
||||
private fun JavaType?.toConeProjectionWithoutEnhancement(
|
||||
session: FirSession,
|
||||
javaTypeParameterStack: JavaTypeParameterStack,
|
||||
boundTypeParameter: FirTypeParameter?
|
||||
boundTypeParameter: FirTypeParameter?,
|
||||
isForSupertypes: Boolean = false
|
||||
): ConeTypeProjection {
|
||||
return when (this) {
|
||||
null -> ConeStarProjection
|
||||
@@ -404,7 +431,7 @@ private fun JavaType?.toConeProjectionWithoutEnhancement(
|
||||
if (bound == null || parameterVariance != INVARIANT && parameterVariance != argumentVariance) {
|
||||
ConeStarProjection
|
||||
} else {
|
||||
val boundType = bound.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack)
|
||||
val boundType = bound.toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, isForSupertypes = isForSupertypes)
|
||||
if (argumentVariance == OUT_VARIANCE) {
|
||||
ConeKotlinTypeProjectionOut(boundType)
|
||||
} else {
|
||||
@@ -412,8 +439,8 @@ private fun JavaType?.toConeProjectionWithoutEnhancement(
|
||||
}
|
||||
}
|
||||
}
|
||||
is JavaClassifierType -> toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack)
|
||||
is JavaArrayType -> toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack)
|
||||
is JavaClassifierType -> toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, isForSupertypes)
|
||||
is JavaArrayType -> toConeKotlinTypeWithoutEnhancement(session, javaTypeParameterStack, isForSupertypes = isForSupertypes)
|
||||
else -> ConeClassErrorType(ConeSimpleDiagnostic("Unexpected type argument: $this", DiagnosticKind.Java))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,6 @@ class In<in F> {
|
||||
}
|
||||
|
||||
fun test() {
|
||||
A.foo().<!UNRESOLVED_REFERENCE!>x<!>() <!INAPPLICABLE_CANDIDATE!>checkType<!> { _<Any?>() }
|
||||
A.bar().<!UNRESOLVED_REFERENCE!>y<!>(null)
|
||||
A.foo().x() checkType { _<Any?>() }
|
||||
A.bar().<!INAPPLICABLE_CANDIDATE!>y<!>(null)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ FILE fqName:<root> fileName:/v8arrayToList.kt
|
||||
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.V8Array' type=<root>.V8Array origin=null
|
||||
VAR name:list type:kotlin.collections.List<kotlin.String> [val]
|
||||
TYPE_OP type=kotlin.collections.List<kotlin.String> origin=CAST typeOperand=kotlin.collections.List<kotlin.String>
|
||||
CALL 'public open fun toList (array: <root>.V8Array?): kotlin.collections.List<in kotlin.Any?>? declared in <root>.Utils' type=IrErrorType origin=null
|
||||
CALL 'public open fun toList (array: <root>.V8Array?): kotlin.collections.List<*>? declared in <root>.Utils' type=kotlin.collections.List<*>? origin=null
|
||||
array: GET_VAR 'val array: <root>.V8Array [val] declared in <root>.box' type=<root>.V8Array origin=null
|
||||
RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in <root>'
|
||||
CALL 'public abstract fun get (index: kotlin.Int): E of kotlin.collections.List [operator] declared in kotlin.collections.List' type=kotlin.String origin=null
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
public open class MethodWithMappedClasses : R|kotlin/Any| {
|
||||
public open fun <T : R|ft<kotlin/Any, kotlin/Any?>!|> copy(dest: R|ft<kotlin/collections/MutableList<in ft<T, T?>!>, kotlin/collections/List<in ft<T, T?>!>?>!|, src: R|ft<kotlin/collections/MutableList<ft<T, T?>!>, kotlin/collections/List<ft<T, T?>!>?>!|): R|kotlin/Unit|
|
||||
public open fun <T : R|ft<kotlin/Any, kotlin/Any?>!|> copy(dest: R|ft<kotlin/collections/MutableList<in ft<T, T?>!>, kotlin/collections/List<*>?>!|, src: R|ft<kotlin/collections/MutableList<ft<T, T?>!>, kotlin/collections/List<ft<T, T?>!>?>!|): R|kotlin/Unit|
|
||||
|
||||
public open fun <T : R|ft<kotlin/Any, kotlin/Any?>!|> copyMap(dest: R|ft<kotlin/collections/MutableMap<ft<kotlin/String, kotlin/String?>!, in ft<T, T?>!>, kotlin/collections/Map<ft<kotlin/String, kotlin/String?>!, in ft<T, T?>!>?>!|, src: R|ft<kotlin/collections/MutableMap<ft<kotlin/String, kotlin/String?>!, ft<T, T?>!>, kotlin/collections/Map<ft<kotlin/String, kotlin/String?>!, ft<T, T?>!>?>!|): R|kotlin/Unit|
|
||||
public open fun <T : R|ft<kotlin/Any, kotlin/Any?>!|> copyMap(dest: R|ft<kotlin/collections/MutableMap<ft<kotlin/String, kotlin/String?>!, in ft<T, T?>!>, kotlin/collections/Map<ft<kotlin/String, kotlin/String?>!, *>?>!|, src: R|ft<kotlin/collections/MutableMap<ft<kotlin/String, kotlin/String?>!, ft<T, T?>!>, kotlin/collections/Map<ft<kotlin/String, kotlin/String?>!, ft<T, T?>!>?>!|): R|kotlin/Unit|
|
||||
|
||||
public constructor(): R|test/MethodWithMappedClasses|
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
public open class MethodWithTypeParameters : R|kotlin/Any| {
|
||||
public open fun <A : R|ft<kotlin/Any, kotlin/Any?>!|, B : R|ft<java/lang/Runnable, java/lang/Runnable?>!|, R|ft<kotlin/collections/MutableList<ft<kotlin/Cloneable, kotlin/Cloneable?>!>, kotlin/collections/List<ft<kotlin/Cloneable, kotlin/Cloneable?>!>?>!|> foo(a: R|ft<A, A?>!|, b: R|ft<kotlin/collections/MutableList<out ft<B, B?>!>, kotlin/collections/List<out ft<B, B?>!>?>!|, list: R|ft<kotlin/collections/MutableList<in ft<kotlin/String, kotlin/String?>!>, kotlin/collections/List<in ft<kotlin/String, kotlin/String?>!>?>!|): R|kotlin/Unit|
|
||||
public open fun <A : R|ft<kotlin/Any, kotlin/Any?>!|, B : R|ft<java/lang/Runnable, java/lang/Runnable?>!|, R|ft<kotlin/collections/MutableList<ft<kotlin/Cloneable, kotlin/Cloneable?>!>, kotlin/collections/List<ft<kotlin/Cloneable, kotlin/Cloneable?>!>?>!|> foo(a: R|ft<A, A?>!|, b: R|ft<kotlin/collections/MutableList<out ft<B, B?>!>, kotlin/collections/List<out ft<B, B?>!>?>!|, list: R|ft<kotlin/collections/MutableList<in ft<kotlin/String, kotlin/String?>!>, kotlin/collections/List<*>?>!|): R|kotlin/Unit|
|
||||
|
||||
public constructor(): R|test/MethodWithTypeParameters|
|
||||
|
||||
|
||||
Reference in New Issue
Block a user