[FIR] Consider variance of type parameters during java type enhancement

#KT-41940 Fixed
This commit is contained in:
Dmitriy Novozhilov
2020-09-24 12:46:47 +03:00
parent a0db510e49
commit 4ef57c120f
10 changed files with 88 additions and 24 deletions
@@ -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|))
}
@@ -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");
@@ -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
@@ -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,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|