Kapt+JVM_IR: support annotations with error types

This is a hack to implement KT-32596 in the JVM IR version of kapt.
Basically we allow psi2ir to generate annotations whose classifier is
error class, which happens when it's unresolved. Because there's no
physical IR for an error class, we create stub IR for it via
SyntheticDeclarationsGenerator in case we'll need it.

With this hack, annotations with unresolved classifiers magically
survive all the way until the codegen (with a minor change in
IrBasedDescriptors) where they are generated as
`@error.NonExistentClass`, which then gets corrected by the kapt's
"correct error types" mode as in all other cases of error types.
This commit is contained in:
Alexander Udalov
2023-01-04 23:44:09 +01:00
parent 4a91957ff0
commit 6d0628900e
8 changed files with 72 additions and 18 deletions
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.error.ErrorUtils
/* Descriptors that serve purely as a view into IR structures.
Created each time at the borderline between IR-based and descriptor-based code (such as inliner).
@@ -44,11 +45,21 @@ abstract class IrBasedDeclarationDescriptor<T : IrDeclaration>(val owner: T) : D
}
private fun IrConstructorCall.toAnnotationDescriptor(): AnnotationDescriptor {
assert(symbol.owner.parentAsClass.isAnnotationClass) {
val annotationClass = symbol.owner.parentAsClass
@OptIn(ObsoleteDescriptorBasedAPI::class)
if (annotationClass.symbol.descriptor == ErrorUtils.errorClass) {
// This should be possible only in case of KAPT3 where IR generated by psi2ir can have annotations with unresolved types.
// Apparently annotations with unresolved types is a useful feature for KAPT3 in the "correct error types mode", see kt32596.kt.
// This is a hack which should preferably be removed as soon as KAPT3 is no longer used.
return AnnotationDescriptorImpl(type.toKotlinType(), emptyMap(), source)
}
assert(annotationClass.isAnnotationClass) {
"Expected call to constructor of annotation class but was: ${this.dump()}"
}
return AnnotationDescriptorImpl(
symbol.owner.parentAsClass.defaultType.toIrBasedKotlinType(),
annotationClass.defaultType.toIrBasedKotlinType(),
symbol.owner.valueParameters.map { it.name to getValueArgument(it.index) }
.filter { it.second != null }
.associate { it.first to it.second!!.toConstantValue() },
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
import org.jetbrains.kotlin.types.error.ErrorClassDescriptor
import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.typeUtil.builtIns
@@ -28,6 +29,7 @@ abstract class ConstantValueGenerator(
private val moduleDescriptor: ModuleDescriptor,
private val symbolTable: ReferenceSymbolTable,
private val typeTranslator: TypeTranslator,
private val allowErrorTypeInAnnotations: Boolean,
) {
protected abstract fun extractAnnotationOffsets(annotationDescriptor: AnnotationDescriptor): Pair<Int, Int>
@@ -158,7 +160,10 @@ abstract class ConstantValueGenerator(
if (annotationClassDescriptor !is ClassDescriptor) return null
if (annotationClassDescriptor is NotFoundClasses.MockClassDescriptor) return null
assert(DescriptorUtils.isAnnotationClass(annotationClassDescriptor)) {
assert(
DescriptorUtils.isAnnotationClass(annotationClassDescriptor) ||
(allowErrorTypeInAnnotations && annotationClassDescriptor is ErrorClassDescriptor)
) {
"Annotation class expected: $annotationClassDescriptor"
}