[FIR] Fix enhancement of java array type

This commit is contained in:
Dmitriy Novozhilov
2019-11-18 15:25:54 +03:00
parent d56412e397
commit 950d1f4fe4
21 changed files with 81 additions and 38 deletions
@@ -24,9 +24,7 @@ import org.jetbrains.kotlin.fir.java.toNotNullConeKotlinType
import org.jetbrains.kotlin.fir.java.types.FirJavaTypeRef
import org.jetbrains.kotlin.fir.references.impl.FirResolvedNamedReferenceImpl
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.resolve.constructType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.toTypeProjection
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
@@ -81,7 +79,7 @@ private fun JavaType?.enhancePossiblyFlexible(
): FirResolvedTypeRef {
val type = this
val arguments = this?.typeArguments().orEmpty()
return when (type) {
val enhanced = when (type) {
is JavaClassifierType -> {
val lowerResult = type.enhanceInflexibleType(
session, javaTypeParameterStack, annotations, arguments, TypeComponentPosition.FLEXIBLE_LOWER, qualifiers, index
@@ -90,20 +88,30 @@ private fun JavaType?.enhancePossiblyFlexible(
session, javaTypeParameterStack, annotations, arguments, TypeComponentPosition.FLEXIBLE_UPPER, qualifiers, index
)
FirResolvedTypeRefImpl(
source = null,
type = coneFlexibleOrSimpleType(session, lowerResult, upperResult)
).apply {
this.annotations += annotations
coneFlexibleOrSimpleType(session, lowerResult, upperResult)
}
is JavaArrayType -> {
val baseEnhanced = type.toNotNullConeKotlinType(session, javaTypeParameterStack)
val upperBound = if (baseEnhanced.typeArguments.isNotEmpty()) {
val typeArgument = baseEnhanced.typeArguments.first() as ConeKotlinType
baseEnhanced.withArguments(arrayOf(ConeKotlinTypeProjectionOut(typeArgument)))
} else {
baseEnhanced
}
ConeFlexibleType(
baseEnhanced,
upperBound.withNullability(ConeNullability.NULLABLE)
)
}
else -> {
val enhanced = type.toNotNullConeKotlinType(session, javaTypeParameterStack)
FirResolvedTypeRefImpl(source = null, type = enhanced).apply {
this.annotations += annotations
}
type.toNotNullConeKotlinType(session, javaTypeParameterStack)
}
}
return FirResolvedTypeRefImpl(source = null, type = enhanced).apply {
this.annotations += annotations
}
}
private fun JavaType?.subtreeSize(): Int {
@@ -15,8 +15,9 @@ import org.jetbrains.kotlin.fir.symbols.invoke
fun ConeKotlinType.createArrayOf(session: FirSession, nullable: Boolean = false): ConeKotlinType {
val symbolProvider: FirSymbolProvider = session.firSymbolProvider
if (this is ConeClassType) {
val primitiveArrayId = StandardClassIds.primitiveArrayTypeByElementType[lookupTag.classId]
val type = lowerBoundIfFlexible()
if (type is ConeClassType) {
val primitiveArrayId = StandardClassIds.primitiveArrayTypeByElementType[type.lookupTag.classId]
if (primitiveArrayId != null) {
return primitiveArrayId.invoke(symbolProvider).constructType(emptyArray(), nullable)
}
@@ -27,10 +28,11 @@ fun ConeKotlinType.createArrayOf(session: FirSession, nullable: Boolean = false)
fun ConeKotlinType.arrayElementType(session: FirSession): ConeKotlinType? {
if (this !is ConeClassType) return null
val classId = this.lookupTag.classId
val type = this.lowerBoundIfFlexible()
if (type !is ConeClassType) return null
val classId = type.lookupTag.classId
if (classId == StandardClassIds.Array)
return (typeArguments.first() as ConeTypedProjection).type
return (type.typeArguments.first() as ConeTypedProjection).type
val elementType = StandardClassIds.elementTypeByPrimitiveArrayType[classId]
if (elementType != null) {
return elementType.invoke(session.firSymbolProvider).constructType(emptyArray(), isNullable = false)
@@ -0,0 +1,18 @@
// FILE: A.java
public class A {
public static void take(A[] array) {}
}
// FILE: B.java
public class B extends A {}
// FILE: main.kt
fun takeA(array: Array<A>) {}
fun takeOutA(array: Array<out A>) {}
fun test(array: Array<B>) {
A.take(array)
<!INAPPLICABLE_CANDIDATE!>takeA<!>(array)
takeOutA(array)
}
@@ -0,0 +1,10 @@
FILE: main.kt
public final fun takeA(array: R|kotlin/Array<A>|): R|kotlin/Unit| {
}
public final fun takeOutA(array: R|kotlin/Array<out A>|): R|kotlin/Unit| {
}
public final fun test(array: R|kotlin/Array<B>|): R|kotlin/Unit| {
Q|A|.R|/A.take|(R|<local>/array|)
<Inapplicable(INAPPLICABLE): [/takeA]>#(R|<local>/array|)
R|/takeOutA|(R|<local>/array|)
}
@@ -255,6 +255,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/resolve/testData/resolve/arguments/invoke.kt");
}
@TestMetadata("javaArrayVariance.kt")
public void testJavaArrayVariance() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/arguments/javaArrayVariance.kt");
}
@TestMetadata("lambda.kt")
public void testLambda() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/arguments/lambda.kt");
@@ -1,8 +1,8 @@
FILE fqName:<root> fileName:/jdkClassSyntheticProperty.kt
PROPERTY name:test visibility:public modality:FINAL [val]
FUN name:<get-test> visibility:public modality:FINAL <> () returnType:kotlin.Array<java.lang.reflect.Field?>
FUN name:<get-test> visibility:public modality:FINAL <> () returnType:kotlin.Array<out java.lang.reflect.Field?>?
correspondingProperty: PROPERTY name:test visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-test> (): kotlin.Array<java.lang.reflect.Field?> declared in <root>'
CALL 'public open fun getDeclaredFields (): kotlin.Array<java.lang.reflect.Field?> declared in java.lang.Class' type=kotlin.Array<java.lang.reflect.Field?> origin=GET_PROPERTY
RETURN type=kotlin.Nothing from='public final fun <get-test> (): kotlin.Array<out java.lang.reflect.Field?>? declared in <root>'
CALL 'public open fun getDeclaredFields (): kotlin.Array<out java.lang.reflect.Field?>? declared in java.lang.Class' type=kotlin.Array<out java.lang.reflect.Field?>? origin=GET_PROPERTY
$this: ERROR_CALL 'Unresolved reference: this@R|/test|' type=java.lang.Class<*>
@@ -1,5 +1,5 @@
public final class ArrayTypeVariance : R|kotlin/Any| {
public final operator fun toArray(p0: R|kotlin/Array<ft<kotlin/Any, kotlin/Any?>!>|): R|kotlin/Array<ft<kotlin/Any, kotlin/Any?>!>|
public final operator fun toArray(p0: R|ft<kotlin/Array<ft<kotlin/Any, kotlin/Any?>!>, kotlin/Array<out ft<kotlin/Any, kotlin/Any?>!>?>!|): R|ft<kotlin/Array<ft<kotlin/Any, kotlin/Any?>!>, kotlin/Array<out ft<kotlin/Any, kotlin/Any?>!>?>!|
public constructor(): R|test/ArrayTypeVariance|
@@ -1,5 +1,5 @@
public open class FieldOfArrayType : R|kotlin/Any| {
public open field files: R|kotlin/Array<ft<java/io/File, java/io/File?>!>|
public open field files: R|ft<kotlin/Array<ft<java/io/File, java/io/File?>!>, kotlin/Array<out ft<java/io/File, java/io/File?>!>?>!|
public constructor(): R|test/FieldOfArrayType|
@@ -1,5 +1,5 @@
public open class ArrayType : R|kotlin/Any| {
public open operator fun foo(): R|kotlin/Array<ft<kotlin/String, kotlin/String?>!>|
public open operator fun foo(): R|ft<kotlin/Array<ft<kotlin/String, kotlin/String?>!>, kotlin/Array<out ft<kotlin/String, kotlin/String?>!>?>!|
public constructor(): R|test/ArrayType|
@@ -1,5 +1,5 @@
public open class MethodWithVararg : R|kotlin/Any| {
public open operator fun foo(vararg s: R|kotlin/Array<ft<kotlin/String, kotlin/String?>!>|): R|kotlin/Unit|
public open operator fun foo(vararg s: R|ft<kotlin/Array<ft<kotlin/String, kotlin/String?>!>, kotlin/Array<out ft<kotlin/String, kotlin/String?>!>?>!|): R|kotlin/Unit|
public constructor(): R|test/MethodWithVararg|
@@ -1,9 +1,9 @@
public open class PropertyArrayTypes<T> : R|kotlin/Any| {
public open field arrayOfArrays: R|kotlin/Array<ft<kotlin/Array<ft<kotlin/String, kotlin/String?>!>, kotlin/Array<ft<kotlin/String, kotlin/String?>!>?>!>|
public open field arrayOfArrays: R|ft<kotlin/Array<ft<kotlin/Array<ft<kotlin/String, kotlin/String?>!>, kotlin/Array<ft<kotlin/String, kotlin/String?>!>?>!>, kotlin/Array<out ft<kotlin/Array<ft<kotlin/String, kotlin/String?>!>, kotlin/Array<ft<kotlin/String, kotlin/String?>!>?>!>?>!|
public open field array: R|kotlin/Array<ft<kotlin/String, kotlin/String?>!>|
public open field array: R|ft<kotlin/Array<ft<kotlin/String, kotlin/String?>!>, kotlin/Array<out ft<kotlin/String, kotlin/String?>!>?>!|
public open field genericArray: R|kotlin/Array<ft<T, T?>!>|
public open field genericArray: R|ft<kotlin/Array<ft<T, T?>!>, kotlin/Array<out ft<T, T?>!>?>!|
public constructor<T>(): R|test/PropertyArrayTypes<T>|
@@ -1,5 +1,5 @@
public open class WrongProjectionKind : R|kotlin/Any| {
public open operator fun copy(from: R|kotlin/Array<ft<kotlin/Number, kotlin/Number?>!>|, to: R|kotlin/Array<ft<kotlin/Number, kotlin/Number?>!>|): R|ft<kotlin/collections/MutableList<ft<kotlin/Number, kotlin/Number?>!>, kotlin/collections/List<ft<kotlin/Number, kotlin/Number?>!>?>!|
public open operator fun copy(from: R|ft<kotlin/Array<ft<kotlin/Number, kotlin/Number?>!>, kotlin/Array<out ft<kotlin/Number, kotlin/Number?>!>?>!|, to: R|ft<kotlin/Array<ft<kotlin/Number, kotlin/Number?>!>, kotlin/Array<out ft<kotlin/Number, kotlin/Number?>!>?>!|): R|ft<kotlin/collections/MutableList<ft<kotlin/Number, kotlin/Number?>!>, kotlin/collections/List<ft<kotlin/Number, kotlin/Number?>!>?>!|
public constructor(): R|test/WrongProjectionKind|
@@ -1,5 +1,5 @@
public open class NotNullIntArray : R|kotlin/Any| {
@R|org/jetbrains/annotations/NotNull|() public open operator fun hi(): R|kotlin/IntArray|
@R|org/jetbrains/annotations/NotNull|() public open operator fun hi(): R|ft<kotlin/IntArray, kotlin/IntArray?>!|
public constructor(): R|test/NotNullIntArray|
@@ -1,5 +1,5 @@
public open class NotNullObjectArray : R|kotlin/Any| {
@R|org/jetbrains/annotations/NotNull|() public open operator fun hi(): R|kotlin/Array<ft<kotlin/Any, kotlin/Any?>!>|
@R|org/jetbrains/annotations/NotNull|() public open operator fun hi(): R|ft<kotlin/Array<ft<kotlin/Any, kotlin/Any?>!>, kotlin/Array<out ft<kotlin/Any, kotlin/Any?>!>?>!|
public constructor(): R|test/NotNullObjectArray|
@@ -1,4 +1,4 @@
public abstract interface GenericInterfaceParametersWithBounds<A : R|kotlin/Comparable<A>?|, R|kotlin/Cloneable?|, B : R|kotlin/collections/MutableList<A>?|> : R|kotlin/Any| {
public abstract operator fun method(a: R|kotlin/Array<ft<A, A?>!>|, b: R|ft<B, B?>!|): R|kotlin/Unit|
public abstract operator fun method(a: R|ft<kotlin/Array<ft<A, A?>!>, kotlin/Array<out ft<A, A?>!>?>!|, b: R|ft<B, B?>!|): R|kotlin/Unit|
}
@@ -1,4 +1,4 @@
public abstract interface GenericMethodParameters : R|kotlin/Any| {
public abstract operator fun <A : R|kotlin/CharSequence?|, B : R|kotlin/collections/MutableList<A>?|> method(a: R|kotlin/Array<ft<A, A?>!>|, b: R|ft<B, B?>!|): R|kotlin/Unit|
public abstract operator fun <A : R|kotlin/CharSequence?|, B : R|kotlin/collections/MutableList<A>?|> method(a: R|ft<kotlin/Array<ft<A, A?>!>, kotlin/Array<out ft<A, A?>!>?>!|, b: R|ft<B, B?>!|): R|kotlin/Unit|
}
@@ -1,4 +1,4 @@
public abstract interface VarargParameter : R|kotlin/Any| {
public abstract operator fun f(vararg strings: R|kotlin/Array<ft<kotlin/String, kotlin/String?>!>|): R|kotlin/Unit|
public abstract operator fun f(vararg strings: R|ft<kotlin/Array<ft<kotlin/String, kotlin/String?>!>, kotlin/Array<out ft<kotlin/String, kotlin/String?>!>?>!|): R|kotlin/Unit|
}
@@ -1,5 +1,5 @@
public open class VarargInt : R|kotlin/Any| {
public open operator fun vararg(vararg p: R|kotlin/IntArray|): R|kotlin/Unit|
public open operator fun vararg(vararg p: R|ft<kotlin/IntArray, kotlin/IntArray?>!|): R|kotlin/Unit|
public constructor(): R|test/VarargInt|
@@ -1,5 +1,5 @@
public open class VarargString : R|kotlin/Any| {
public open operator fun vararg(vararg strings: R|kotlin/Array<ft<kotlin/String, kotlin/String?>!>|): R|kotlin/Unit|
public open operator fun vararg(vararg strings: R|ft<kotlin/Array<ft<kotlin/String, kotlin/String?>!>, kotlin/Array<out ft<kotlin/String, kotlin/String?>!>?>!|): R|kotlin/Unit|
public constructor(): R|test/VarargString|
@@ -1,7 +1,7 @@
public open class Some : R|kotlin/Any| {
public open operator fun foo(param: R|kotlin/Int|): R|kotlin/Boolean|
public open operator fun bar(arr: R|kotlin/IntArray|): R|kotlin/Array<ft<kotlin/String, kotlin/String?>!>|
public open operator fun bar(arr: R|ft<kotlin/IntArray, kotlin/IntArray?>!|): R|ft<kotlin/Array<ft<kotlin/String, kotlin/String?>!>, kotlin/Array<out ft<kotlin/String, kotlin/String?>!>?>!|
public constructor(): R|Some|
@@ -7,7 +7,7 @@ FILE: jvm.kt
public final fun test(): R|kotlin/Unit| {
lval res1: R|kotlin/Boolean| = this@R|/Some|.R|/Some.foo|(Int(1))
lval res2: R|kotlin/Boolean| = this@R|/Some|.R|/Some.foo|(Int(1).R|kotlin/Int.unaryMinus|())
lval res3: R|kotlin/Array<ft<kotlin/String, kotlin/String?>!>| = this@R|/Some|.R|/Some.bar|(R|kotlin/intArrayOf|(Int(0), Int(2), Int(2).R|kotlin/Int.unaryMinus|()))
lval res3: R|ft<kotlin/Array<ft<kotlin/String, kotlin/String?>!>, kotlin/Array<out ft<kotlin/String, kotlin/String?>!>?>!| = this@R|/Some|.R|/Some.bar|(R|kotlin/intArrayOf|(Int(0), Int(2), Int(2).R|kotlin/Int.unaryMinus|()))
}
}