Fix null Java type argument problem & add relevant test

This commit is contained in:
Mikhail Glukhikh
2019-03-01 12:10:05 +03:00
parent 7563a98999
commit fb788dc4c0
14 changed files with 52 additions and 18 deletions
@@ -68,7 +68,7 @@ internal fun FirTypeRef.toNotNullConeKotlinType(): ConeKotlinType =
else -> ConeKotlinErrorType("Unexpected type reference in JavaClassUseSiteScope: ${this::class.java}") else -> ConeKotlinErrorType("Unexpected type reference in JavaClassUseSiteScope: ${this::class.java}")
} }
internal fun JavaType.toNotNullConeKotlinType(session: FirSession): ConeLookupTagBasedType { internal fun JavaType?.toNotNullConeKotlinType(session: FirSession): ConeLookupTagBasedType {
return toConeKotlinTypeWithNullability(session, isNullable = false) return toConeKotlinTypeWithNullability(session, isNullable = false)
} }
@@ -85,7 +85,7 @@ internal fun JavaClassifierType.toFirResolvedTypeRef(session: FirSession): FirRe
) )
} }
internal fun JavaType.toConeKotlinTypeWithNullability(session: FirSession, isNullable: Boolean): ConeLookupTagBasedType { internal fun JavaType?.toConeKotlinTypeWithNullability(session: FirSession, isNullable: Boolean): ConeLookupTagBasedType {
return when (this) { return when (this) {
is JavaClassifierType -> { is JavaClassifierType -> {
toConeKotlinTypeWithNullability(session, isNullable) toConeKotlinTypeWithNullability(session, isNullable)
@@ -118,6 +118,10 @@ internal fun JavaType.toConeKotlinTypeWithNullability(session: FirSession, isNul
val classId = ClassId(FqName("kotlin"), FqName("Any"), false) val classId = ClassId(FqName("kotlin"), FqName("Any"), false)
classId.toConeKotlinType(emptyArray(), isNullable) classId.toConeKotlinType(emptyArray(), isNullable)
} }
null -> {
val classId = ClassId(FqName("kotlin"), FqName("Any"), false)
classId.toConeKotlinType(emptyArray(), isNullable)
}
else -> error("Strange JavaType: ${this::class.java}") else -> error("Strange JavaType: ${this::class.java}")
} }
} }
@@ -172,8 +176,9 @@ internal fun FirAbstractAnnotatedElement.addAnnotationsFrom(javaAnnotationOwner:
} }
} }
internal fun JavaType.toConeProjection(session: FirSession, boundTypeParameter: FirTypeParameter?): ConeKotlinTypeProjection { internal fun JavaType?.toConeProjection(session: FirSession, boundTypeParameter: FirTypeParameter?): ConeKotlinTypeProjection {
return when (this) { return when (this) {
null -> ConeStarProjection
is JavaWildcardType -> { is JavaWildcardType -> {
val bound = this.bound val bound = this.bound
val argumentVariance = if (isExtends) OUT_VARIANCE else IN_VARIANCE val argumentVariance = if (isExtends) OUT_VARIANCE else IN_VARIANCE
@@ -95,8 +95,8 @@ internal class EnhancementSignatureParts(
if (type is FirJavaTypeRef) { if (type is FirJavaTypeRef) {
for (arg in type.type.typeArguments()) { for (arg in type.type.typeArguments()) {
if (arg is JavaWildcardType) { if (arg is JavaWildcardType || arg == null) {
// TODO: wildcards // TODO: wildcards / raw types
} else { } else {
add(arg.toFirJavaTypeRef(context.session)) add(arg.toFirJavaTypeRef(context.session))
} }
@@ -46,14 +46,14 @@ internal fun FirJavaTypeRef.enhance(
// Example: for `A<B, C<D, E>>`, indices go as follows: `0 - A<...>, 1 - B, 2 - C<D, E>, 3 - D, 4 - E`, // Example: for `A<B, C<D, E>>`, indices go as follows: `0 - A<...>, 1 - B, 2 - C<D, E>, 3 - D, 4 - E`,
// which corresponds to the left-to-right breadth-first walk of the tree representation of the type. // which corresponds to the left-to-right breadth-first walk of the tree representation of the type.
// For flexible types, both bounds are indexed in the same way: `(A<B>..C<D>)` gives `0 - (A<B>..C<D>), 1 - B and D`. // For flexible types, both bounds are indexed in the same way: `(A<B>..C<D>)` gives `0 - (A<B>..C<D>), 1 - B and D`.
private fun JavaType.enhancePossiblyFlexible( private fun JavaType?.enhancePossiblyFlexible(
session: FirSession, session: FirSession,
annotations: List<FirAnnotationCall>, annotations: List<FirAnnotationCall>,
qualifiers: (Int) -> JavaTypeQualifiers, qualifiers: (Int) -> JavaTypeQualifiers,
index: Int index: Int
): FirResolvedTypeRef { ): FirResolvedTypeRef {
val type = this val type = this
val arguments = typeArguments() val arguments = this?.typeArguments().orEmpty()
return when (type) { return when (type) {
is JavaClassifierType -> { is JavaClassifierType -> {
val lowerResult = type.enhanceInflexibleType( val lowerResult = type.enhanceInflexibleType(
@@ -76,9 +76,9 @@ private fun JavaType.enhancePossiblyFlexible(
} }
} }
private fun JavaType.subtreeSize(): Int { private fun JavaType?.subtreeSize(): Int {
if (this !is JavaClassifierType) return 1 if (this !is JavaClassifierType) return 1
return 1 + typeArguments.sumBy { it.subtreeSize() } return 1 + typeArguments.sumBy { it?.subtreeSize() ?: 0 }
} }
private val KOTLIN_COLLECTIONS = FqName("kotlin.collections") private val KOTLIN_COLLECTIONS = FqName("kotlin.collections")
@@ -102,7 +102,7 @@ private fun ClassId.mutableToReadOnly(): ClassId? {
private fun JavaClassifierType.enhanceInflexibleType( private fun JavaClassifierType.enhanceInflexibleType(
session: FirSession, session: FirSession,
annotations: List<FirAnnotationCall>, annotations: List<FirAnnotationCall>,
arguments: List<JavaType>, arguments: List<JavaType?>,
position: TypeComponentPosition, position: TypeComponentPosition,
qualifiers: (Int) -> JavaTypeQualifiers, qualifiers: (Int) -> JavaTypeQualifiers,
index: Int index: Int
@@ -199,7 +199,7 @@ internal data class TypeAndDefaultQualifiers(
internal fun FirTypeRef.typeArguments(): List<FirTypeProjection> = internal fun FirTypeRef.typeArguments(): List<FirTypeProjection> =
(this as? FirUserTypeRef)?.qualifier?.lastOrNull()?.typeArguments.orEmpty() (this as? FirUserTypeRef)?.qualifier?.lastOrNull()?.typeArguments.orEmpty()
internal fun JavaType.typeArguments(): List<JavaType> = (this as? JavaClassifierType)?.typeArguments.orEmpty() internal fun JavaType.typeArguments(): List<JavaType?> = (this as? JavaClassifierType)?.typeArguments.orEmpty()
fun FirValueParameter.getDefaultValueFromAnnotation(): AnnotationDefaultValue? { fun FirValueParameter.getDefaultValueFromAnnotation(): AnnotationDefaultValue? {
annotations.find { it.resolvedFqName == JvmAnnotationNames.DEFAULT_VALUE_FQ_NAME } annotations.find { it.resolvedFqName == JvmAnnotationNames.DEFAULT_VALUE_FQ_NAME }
@@ -102,7 +102,7 @@ class JavaClassEnhancementScope(
original: ConeFunctionSymbol, original: ConeFunctionSymbol,
name: Name name: Name
): FirFunctionSymbol { ): FirFunctionSymbol {
val firMethod = (original as FirBasedSymbol<*>).fir as? FirJavaMethod ?: error("Can't make enhancement for $original") val firMethod = (original as FirFunctionSymbol).fir as? FirJavaMethod ?: return original
val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firMethod.annotations) val memberContext = context.copyWithNewDefaultTypeQualifiers(typeQualifierResolver, jsr305State, firMethod.annotations)
@@ -136,7 +136,7 @@ sealed class TreeBasedClassifierType<out T : JCTree>(
override val presentableText: String override val presentableText: String
get() = classifierQualifiedName get() = classifierQualifiedName
override val typeArguments: List<JavaType> override val typeArguments: List<JavaType?>
get() { get() {
var tree: JCTree = tree var tree: JCTree = tree
if (tree is JCTree.JCTypeApply) { if (tree is JCTree.JCTypeApply) {
@@ -230,9 +230,9 @@ class TreeBasedGenericClassifierType(
?: super.annotations ?: super.annotations
} }
override val typeArguments: List<JavaType> override val typeArguments: List<JavaType?>
get() = tree.arguments.map { create(it, compilationUnit, javac, emptyList(), containingElement) } get() = tree.arguments.map { create(it, compilationUnit, javac, emptyList(), containingElement) }
.toMutableList() .toMutableList<JavaType?>()
.apply { addAll(super.typeArguments) } .apply { addAll(super.typeArguments) }
override val isRaw: Boolean override val isRaw: Boolean
@@ -42,7 +42,7 @@ class JavaTypeResolver(
private val typeParameterResolver: TypeParameterResolver private val typeParameterResolver: TypeParameterResolver
) { ) {
fun transformJavaType(javaType: JavaType, attr: JavaTypeAttributes): KotlinType { fun transformJavaType(javaType: JavaType?, attr: JavaTypeAttributes): KotlinType {
return when (javaType) { return when (javaType) {
is JavaPrimitiveType -> { is JavaPrimitiveType -> {
val primitiveType = javaType.type val primitiveType = javaType.type
@@ -53,6 +53,7 @@ class JavaTypeResolver(
is JavaArrayType -> transformArrayType(javaType, attr) is JavaArrayType -> transformArrayType(javaType, attr)
// Top level type can be a wildcard only in case of broken Java code, but we should not fail with exceptions in such cases // Top level type can be a wildcard only in case of broken Java code, but we should not fail with exceptions in such cases
is JavaWildcardType -> javaType.bound?.let { transformJavaType(it, attr) } ?: c.module.builtIns.defaultBound is JavaWildcardType -> javaType.bound?.let { transformJavaType(it, attr) } ?: c.module.builtIns.defaultBound
null -> c.module.builtIns.defaultBound
else -> throw UnsupportedOperationException("Unsupported type: " + javaType) else -> throw UnsupportedOperationException("Unsupported type: " + javaType)
} }
} }
@@ -247,7 +248,7 @@ class JavaTypeResolver(
} }
private fun transformToTypeProjection( private fun transformToTypeProjection(
javaType: JavaType, javaType: JavaType?,
attr: JavaTypeAttributes, attr: JavaTypeAttributes,
typeParameter: TypeParameterDescriptor typeParameter: TypeParameterDescriptor
): TypeProjection { ): TypeProjection {
@@ -26,7 +26,7 @@ interface JavaArrayType : JavaType {
interface JavaClassifierType : JavaType, JavaAnnotationOwner { interface JavaClassifierType : JavaType, JavaAnnotationOwner {
val classifier: JavaClassifier? val classifier: JavaClassifier?
val typeArguments: List<JavaType> val typeArguments: List<JavaType?>
val isRaw: Boolean val isRaw: Boolean
@@ -0,0 +1,4 @@
public open class Some : R|java/lang/Object|, R|Strange<*>| {
public open operator function foo(): R|ft<kotlin/Any, kotlin/Any>|
}
@@ -0,0 +1 @@
class Derived : Some()
@@ -0,0 +1,5 @@
FILE: Derived.kt
public final class Derived : R|Some| {
public constructor(): super<R|Some|>()
}
@@ -0,0 +1,5 @@
public class Some implements Strange {
public Object foo() {
return "";
}
}
@@ -0,0 +1,3 @@
interface Strange<out T> {
fun foo(): T
}
@@ -0,0 +1,5 @@
FILE: Strange.kt
<out T> public abstract interface Strange {
public abstract function foo(): R|T|
}
@@ -59,6 +59,11 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe
runTest("idea/testData/fir/multiModule/basicWithPrimitiveJava/"); runTest("idea/testData/fir/multiModule/basicWithPrimitiveJava/");
} }
@TestMetadata("javaInheritsRawKotlin")
public void testJavaInheritsRawKotlin() throws Exception {
runTest("idea/testData/fir/multiModule/javaInheritsRawKotlin/");
}
@TestMetadata("mppFakeOverrides") @TestMetadata("mppFakeOverrides")
public void testMppFakeOverrides() throws Exception { public void testMppFakeOverrides() throws Exception {
runTest("idea/testData/fir/multiModule/mppFakeOverrides/"); runTest("idea/testData/fir/multiModule/mppFakeOverrides/");