From 59186b261769e96b86d7f8c04abdfaaa6c59e911 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 17 Sep 2019 17:00:42 +0200 Subject: [PATCH] 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. --- .../kotlin/ir/util/ConstantValueGenerator.kt | 30 +++++++++++-------- .../library/a.kt | 4 +++ .../library/b.kt | 3 +- .../library/a.kt | 4 +++ .../library/b.kt | 3 +- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt index 1fe0977df3b..02810dcd83d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/ConstantValueGenerator.kt @@ -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 diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotation/library/a.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotation/library/a.kt index 2cb3794ad4c..17d7314b7bb 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotation/library/a.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotation/library/a.kt @@ -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<*>) diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotation/library/b.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotation/library/b.kt index fdac61bc93d..f006d4734f6 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotation/library/b.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotation/library/b.kt @@ -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 } diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotationIr/library/a.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotationIr/library/a.kt index 2cb3794ad4c..17d7314b7bb 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotationIr/library/a.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotationIr/library/a.kt @@ -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<*>) diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotationIr/library/b.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotationIr/library/b.kt index fdac61bc93d..f006d4734f6 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotationIr/library/b.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/missingDependencyNestedAnnotationIr/library/b.kt @@ -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 }