Psi2ir: ignore unresolved class literals in annotations

Similarly to 38536638, skip annotation arguments that reference classes
which are not found in our compilation classpath.

This fix is especially needed because of the way _nested_ classes are
currently referenced in annotations. Since we don't generate all needed
InnerClasses attributes yet (KT-27936), we can't unambiguously resolve a
reference to a nested class in annotation arguments. This leads to an
ErrorValue loaded in the annotation descriptor. The old backend doesn't
care, since it doesn't look at that annotation or its arguments, but
psi2ir tries to convert all annotation arguments and it crashed with CCE
here, trying to cast IrErrorType to IrSimpleType.
This commit is contained in:
Alexander Udalov
2019-09-17 17:00:42 +02:00
parent c69997491f
commit 59186b2617
5 changed files with 30 additions and 14 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -39,11 +40,11 @@ class ConstantValueGenerator(
constantValue: ConstantValue<*>,
varargElementType: KotlinType? = null
): IrExpression =
// Assertion is safe here because annotation calls are not allowed in constant initializers
// Assertion is safe here because annotation calls and class literals are not allowed in constant initializers
generateConstantOrAnnotationValueAsExpression(startOffset, endOffset, constantValue, varargElementType)!!
/**
* @return null if the constant value is an unresolved annotation
* @return null if the constant value is an unresolved annotation or an unresolved class literal
*/
private fun generateConstantOrAnnotationValueAsExpression(
startOffset: Int,
@@ -100,15 +101,18 @@ class ConstantValueGenerator(
is KClassValue -> {
val classifierKtType = constantValue.getArgumentType(moduleDescriptor)
val classifierDescriptor = classifierKtType.constructor.declarationDescriptor
?: throw AssertionError("Unexpected KClassValue: $classifierKtType")
if (classifierKtType.isError) null
else {
val classifierDescriptor = classifierKtType.constructor.declarationDescriptor
?: throw AssertionError("Unexpected KClassValue: $classifierKtType")
IrClassReferenceImpl(
startOffset, endOffset,
constantValue.getType(moduleDescriptor).toIrType(),
classifierDescriptor.defaultType.toIrType().classifierOrFail,
classifierKtType.toIrType()
)
IrClassReferenceImpl(
startOffset, endOffset,
constantValue.getType(moduleDescriptor).toIrType(),
classifierDescriptor.defaultType.toIrType().classifierOrFail,
classifierKtType.toIrType()
)
}
}
else -> TODO("Unexpected constant value: ${constantValue.javaClass.simpleName} $constantValue")
@@ -143,13 +147,15 @@ class ConstantValueGenerator(
for (valueParameter in primaryConstructorDescriptor.valueParameters) {
val argumentIndex = valueParameter.index
val argumentValue = annotationDescriptor.allValueArguments[valueParameter.name] ?: continue
val irArgument = generateConstantValueAsExpression(
val irArgument = generateConstantOrAnnotationValueAsExpression(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
argumentValue,
valueParameter.varargElementType
)
irCall.putValueArgument(argumentIndex, irArgument)
if (irArgument != null) {
irCall.putValueArgument(argumentIndex, irArgument)
}
}
return irCall
@@ -1,6 +1,10 @@
package a
import kotlin.reflect.KClass
interface A {
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPE_PARAMETER)
annotation class Anno(val value: String)
}
annotation class K(val klass: KClass<*>)
@@ -1,9 +1,10 @@
package b
import a.A
import a.*
@A.Anno("B")
interface B {
@A.Anno("foo")
@K(A.Anno::class)
fun <@A.Anno("T") T> foo(t: T) = t
}
@@ -1,6 +1,10 @@
package a
import kotlin.reflect.KClass
interface A {
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPE_PARAMETER)
annotation class Anno(val value: String)
}
annotation class K(val klass: KClass<*>)
@@ -1,9 +1,10 @@
package b
import a.A
import a.*
@A.Anno("B")
interface B {
@A.Anno("foo")
@K(A.Anno::class)
fun <@A.Anno("T") T> foo(t: T) = t
}